| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | |
| 3 * Use of this source code is governed by a BSD-style license that can be | |
| 4 * found in the LICENSE file. | |
| 5 */ | |
| 6 | |
| 7 /* | |
| 8 * ncdecode_verbose.c - Print routines for validator that are | |
| 9 * not to be loaded into sel_ldr. | |
| 10 */ | |
| 11 | |
| 12 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode_verbose
.h" | |
| 13 | |
| 14 #include <stdio.h> | |
| 15 #include <stdlib.h> | |
| 16 #include <string.h> | |
| 17 | |
| 18 #include "native_client/src/shared/gio/gio.h" | |
| 19 #include "native_client/src/shared/platform/nacl_log.h" | |
| 20 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h" | |
| 21 | |
| 22 #include "native_client/src/trusted/validator/x86/x86_insts_inl.c" | |
| 23 | |
| 24 #if NACL_TARGET_SUBARCH == 64 | |
| 25 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdisasmtab_
64.h" | |
| 26 #else | |
| 27 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdisasmtab_
32.h" | |
| 28 #endif | |
| 29 | |
| 30 /* To turn on debugging of instruction decoding, change value of | |
| 31 * DEBUGGING to 1. | |
| 32 */ | |
| 33 #define DEBUGGING 0 | |
| 34 | |
| 35 #include "native_client/src/shared/utils/debugging.h" | |
| 36 | |
| 37 /* The following are conditionally added since they only have meaning | |
| 38 * if we are processing 64-bit instructions. | |
| 39 */ | |
| 40 #if NACL_TARGET_SUBARCH == 64 | |
| 41 | |
| 42 /* Returns true if REX.W is defined in the REX prefix byte. */ | |
| 43 static INLINE uint8_t GetRexPrefixW(const NCDecoderInst* dinst) { | |
| 44 /* Note: the field rexprefix is non-zero only if a rexprefix was found. */ | |
| 45 return 0 != NaClRexW(dinst->inst.rexprefix); | |
| 46 } | |
| 47 | |
| 48 /* Returns true if REX.R is defined in the REX prefix byte. */ | |
| 49 static INLINE uint8_t GetRexPrefixR(const NCDecoderInst* dinst) { | |
| 50 /* Note: the field rexprefix is non-zero only if a rexprefix was found. */ | |
| 51 return 0 != NaClRexR(dinst->inst.rexprefix); | |
| 52 } | |
| 53 | |
| 54 #endif | |
| 55 | |
| 56 /* Returns the index into the general purpose registers based on the | |
| 57 * value in the modrm.rm field of the instruction (taking into account | |
| 58 * the REX prefix if it appears). | |
| 59 */ | |
| 60 static INLINE uint32_t state_modrm_reg(const NCDecoderInst* dinst) { | |
| 61 /* TODO(karl) This is no where near close to being correct. Currently, | |
| 62 * It only models r/m64 entry for instructions in the Intel documentation, | |
| 63 * which requires the W bit to be set (r/m32 entries do not use REX.w, | |
| 64 * and a different set of registers). | |
| 65 */ | |
| 66 uint32_t index = modrm_regInline(dinst->inst.mrm); | |
| 67 #if NACL_TARGET_SUBARCH == 64 | |
| 68 if (GetRexPrefixW(dinst) && GetRexPrefixR(dinst)) { | |
| 69 index += 8; | |
| 70 } | |
| 71 #endif | |
| 72 return index; | |
| 73 } | |
| 74 | |
| 75 /* Returns the index for the first instruction opcode byte. */ | |
| 76 static INLINE int NCOpcodeOffset(const NCDecoderInst* dinst) { | |
| 77 return dinst->inst.prefixbytes; | |
| 78 } | |
| 79 | |
| 80 /* Returns the index for the modrm byte. */ | |
| 81 static INLINE int NCMrmOffset(const NCDecoderInst* dinst) { | |
| 82 return NCOpcodeOffset(dinst) + dinst->inst.num_opbytes; | |
| 83 } | |
| 84 | |
| 85 /* Returns the index of the sib byte (if it has one). */ | |
| 86 static INLINE int NCSibOffset(const NCDecoderInst* dinst) { | |
| 87 /* Note: The sib byte follows the mrm byte. */ | |
| 88 return NCMrmOffset(dinst) + 1; | |
| 89 } | |
| 90 | |
| 91 /* Returns the beginning index for the displacement (if it has one). */ | |
| 92 static int NCDispOffset(const NCDecoderInst* dinst) { | |
| 93 if (dinst->opinfo->hasmrmbyte) { | |
| 94 if (dinst->inst.hassibbyte) { | |
| 95 return NCSibOffset(dinst) + 1; | |
| 96 } else { | |
| 97 return NCMrmOffset(dinst) + 1; | |
| 98 } | |
| 99 } else { | |
| 100 return NCOpcodeOffset(dinst) + dinst->inst.num_opbytes; | |
| 101 } | |
| 102 } | |
| 103 | |
| 104 /* Returns the beginning index for the immediate value. */ | |
| 105 static INLINE int NCImmedOffset(const NCDecoderInst* dinst) { | |
| 106 return NCDispOffset(dinst) + dinst->inst.dispbytes; | |
| 107 } | |
| 108 | |
| 109 /* later this will make decoding x87 instructions a bit more concise. */ | |
| 110 static const char** kDisasmX87Op[8] = {kDisasm87D8, | |
| 111 kDisasm87D9, | |
| 112 kDisasm87DA, | |
| 113 kDisasm87DB, | |
| 114 kDisasm87DC, | |
| 115 kDisasm87DD, | |
| 116 kDisasm87DE, | |
| 117 kDisasm87DF}; | |
| 118 | |
| 119 const char** kDummyUsesToAvoidCompilerWarning[] = {kDisasm660F38Op, | |
| 120 kDisasmF20F38Op, | |
| 121 kDisasm660F3AOp}; | |
| 122 | |
| 123 /* disassembler stuff */ | |
| 124 static const char* DisFmt(const NCDecoderInst *dinst) { | |
| 125 NCInstBytesPtr opbyte; | |
| 126 uint8_t opbyte0; | |
| 127 uint8_t opbyte1; | |
| 128 uint8_t pm = dinst->inst.opcode_prefixmask; | |
| 129 NCInstBytesPtrInitInc(&opbyte, &dinst->inst_bytes, NCOpcodeOffset(dinst)); | |
| 130 opbyte0 = NCInstBytesByte(&opbyte, 0); | |
| 131 | |
| 132 if (dinst->opinfo->insttype == NACLi_X87 || | |
| 133 dinst->opinfo->insttype == NACLi_X87_FSINCOS) { | |
| 134 if (opbyte0 != kWAITOp) { | |
| 135 return kDisasmX87Op[opbyte0 - kFirstX87Opcode][dinst->inst.mrm]; | |
| 136 } | |
| 137 } | |
| 138 if (dinst->opinfo->insttype == NACLi_FCMOV) { | |
| 139 return kDisasmX87Op[opbyte0 - kFirstX87Opcode][dinst->inst.mrm]; | |
| 140 } | |
| 141 if (dinst->opinfo->insttype == NACLi_NOP) return "nop"; | |
| 142 if (opbyte0 != kTwoByteOpcodeByte1) return kDisasm1ByteOp[opbyte0]; | |
| 143 opbyte1 = NCInstBytesByte(&opbyte, 1); | |
| 144 if (opbyte1 == 0x0f) { | |
| 145 return kDisasm0F0FOp[ | |
| 146 NCInstBytesByte(&opbyte, dinst->inst.bytes.length - 1)]; | |
| 147 } | |
| 148 if (opbyte1 == 0x38) { | |
| 149 return kDisasm0F38Op[NCInstBytesByte(&opbyte, 2)]; | |
| 150 } | |
| 151 if (opbyte1 == 0x3A) { | |
| 152 return kDisasm0F3AOp[NCInstBytesByte(&opbyte, 2)]; | |
| 153 } | |
| 154 if (! (pm & (kPrefixDATA16 | kPrefixREPNE | kPrefixREP))) { | |
| 155 return kDisasm0FXXOp[opbyte1]; | |
| 156 } | |
| 157 if (pm & kPrefixDATA16) return kDisasm660FXXOp[opbyte1]; | |
| 158 if (pm & kPrefixREPNE) return kDisasmF20FXXOp[opbyte1]; | |
| 159 if (pm & kPrefixREP) return kDisasmF30FXXOp[opbyte1]; | |
| 160 | |
| 161 /* no update; should be invalid */ | |
| 162 return "internal error"; | |
| 163 } | |
| 164 | |
| 165 /* Returns the (sign extended) 32-bit integer immediate value. */ | |
| 166 static int32_t ImmedValue32(const NCDecoderInst* dinst) { | |
| 167 NCInstBytesPtr addr; | |
| 168 NCInstBytesPtrInitInc(&addr, &dinst->inst_bytes, | |
| 169 NCImmedOffset(dinst)); | |
| 170 return NCInstBytesInt32(&addr, dinst->inst.immbytes); | |
| 171 } | |
| 172 | |
| 173 /* Returns the (sign extended) 64-bit integer immediate value. */ | |
| 174 static int64_t ImmedValue64(const NCDecoderInst* dinst) { | |
| 175 NCInstBytesPtr addr; | |
| 176 NCInstBytesPtrInitInc(&addr, &dinst->inst_bytes, | |
| 177 NCImmedOffset(dinst)); | |
| 178 return NCInstBytesInt64(&addr, dinst->inst.immbytes); | |
| 179 } | |
| 180 | |
| 181 /* Returns the (sign extended) 32-bit integer displacement value. */ | |
| 182 static int32_t DispValue32(const NCDecoderInst* dinst) { | |
| 183 NCInstBytesPtr addr; | |
| 184 NCInstBytesPtrInitInc(&addr, &dinst->inst_bytes, | |
| 185 NCDispOffset(dinst)); | |
| 186 return NCInstBytesInt32(&addr, dinst->inst.dispbytes); | |
| 187 } | |
| 188 | |
| 189 /* Defines the set of available general purpose registers. */ | |
| 190 static const char* gp_regs[] = { | |
| 191 #if NACL_TARGET_SUBARCH == 64 | |
| 192 /* TODO(karl) - Depending on whether the instruction uses r/m32 | |
| 193 * of r/m64 forms (according to the Intel document), the list of | |
| 194 * (16) registers is different. Currently, we are only handling | |
| 195 * the r/m64 case. | |
| 196 */ | |
| 197 "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", | |
| 198 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" | |
| 199 #else | |
| 200 "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" | |
| 201 #endif | |
| 202 }; | |
| 203 | |
| 204 | |
| 205 static const char* mmx_regs[] = { | |
| 206 "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" | |
| 207 }; | |
| 208 | |
| 209 static const char* xmm_regs[] = { | |
| 210 "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" | |
| 211 }; | |
| 212 | |
| 213 static const char* seg_regs[] = { | |
| 214 "%es", "%cs", "%ss", "%ds", "%fs", "%gs" | |
| 215 }; | |
| 216 | |
| 217 /* Print out the sib byte of the parsed instruction in the given decoder state | |
| 218 * to the given file. | |
| 219 */ | |
| 220 static void SibPrint(const NCDecoderInst* dinst, struct Gio* fp) { | |
| 221 uint8_t sib = NCInstBytesByte(&dinst->inst_bytes, NCSibOffset(dinst)); | |
| 222 | |
| 223 if (!dinst->inst.hassibbyte) { | |
| 224 /* This should not happen. */ | |
| 225 gprintf(fp, "?"); | |
| 226 } else if (sib_ss(sib) == 0) { | |
| 227 if (sib_base(sib) == 5) { | |
| 228 /* This code is JUST WRONG!. However, I am not fixing since | |
| 229 * the decoder printer is broken in so many other ways!. See tables | |
| 230 * 2-1 and 2-2 of "Intel 64 and IA-32 Architectures Software Developer's | |
| 231 * Manual" for details of what should be done (there are | |
| 232 * 3 cases, depending on the value of the mod field of the modrm | |
| 233 * byte). | |
| 234 * Note: While the changes here are not correct, they at least make | |
| 235 * sure that we process bytes that are actually in the instruction. | |
| 236 * That is, the code doesn't accidentally walk off the end of the | |
| 237 * parsed instruction. | |
| 238 */ | |
| 239 gprintf(fp, "[0x%x]", DispValue32(dinst)); | |
| 240 } else { | |
| 241 /* Has a base register */ | |
| 242 if (sib_index(sib) == 4) { | |
| 243 /* No index */ | |
| 244 gprintf(fp, "[%s]", gp_regs[sib_base(sib)]); | |
| 245 } else { | |
| 246 gprintf(fp, "[%s + %s]", | |
| 247 gp_regs[sib_base(sib)], | |
| 248 gp_regs[sib_index(sib)]); | |
| 249 } | |
| 250 } | |
| 251 } else { | |
| 252 if (sib_index(sib) == 4) { | |
| 253 /* No index */ | |
| 254 gprintf(fp, "[%s]", gp_regs[sib_base(sib)]); | |
| 255 } else { | |
| 256 gprintf(fp, "[%s + %d * %s]", | |
| 257 gp_regs[sib_base(sib)], | |
| 258 1 << sib_ss(sib), | |
| 259 gp_regs[sib_index(sib)]); | |
| 260 } | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 static void SegPrefixPrint(const NCDecoderInst *dinst, struct Gio* fp) { | |
| 265 uint8_t pm = dinst->inst.prefixmask; | |
| 266 if (pm & kPrefixSEGCS) { | |
| 267 gprintf(fp, "cs:"); | |
| 268 } else if (pm & kPrefixSEGSS) { | |
| 269 gprintf(fp, "ss:"); | |
| 270 } else if (pm & kPrefixSEGFS) { | |
| 271 gprintf(fp, "fs:"); | |
| 272 } else if (pm & kPrefixSEGGS) { | |
| 273 gprintf(fp, "gs:"); | |
| 274 } | |
| 275 } | |
| 276 | |
| 277 /* Append that we don't bother to translate the instruction argument, | |
| 278 * since it is NaCl illegal. Used to handle cases where we don't implement | |
| 279 * 16-bit modrm effective addresses. | |
| 280 */ | |
| 281 static INLINE void NaClIllegalOp(struct Gio* fp) { | |
| 282 gprintf(fp, "*NaClIllegal*"); | |
| 283 } | |
| 284 | |
| 285 /* Print out the register (from the list of register names), | |
| 286 * that is referenced by the decoded instruction in the | |
| 287 * decoder state. If is_gp_regs is true, the register names | |
| 288 * correspond to general purpose register names. Otherwise, | |
| 289 * they are some other set, such as MMX or XMM. | |
| 290 */ | |
| 291 static void RegMemPrint(const NCDecoderInst *dinst, | |
| 292 const char* reg_names[], | |
| 293 const uint8_t is_gp_regs, | |
| 294 struct Gio* fp) { | |
| 295 DEBUG( printf( | |
| 296 "reg mem print: sib_offset = %d, " | |
| 297 "disp_offset = %d, mrm.mod = %02x\n", | |
| 298 NCSibOffset(dinst), (int) NCDispOffset(dinst), | |
| 299 modrm_modInline(dinst->inst.mrm)) ); | |
| 300 switch (modrm_modInline(dinst->inst.mrm)) { | |
| 301 case 0: | |
| 302 SegPrefixPrint(dinst, fp); | |
| 303 if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) { | |
| 304 NaClIllegalOp(fp); | |
| 305 } else { | |
| 306 if (4 == modrm_rmInline(dinst->inst.mrm)) { | |
| 307 SibPrint(dinst, fp); | |
| 308 } else if (5 == modrm_rmInline(dinst->inst.mrm)) { | |
| 309 gprintf(fp, "[0x%x]", DispValue32(dinst)); | |
| 310 } else { | |
| 311 gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]); | |
| 312 } | |
| 313 } | |
| 314 break; | |
| 315 case 1: | |
| 316 SegPrefixPrint(dinst, fp); | |
| 317 if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) { | |
| 318 NaClIllegalOp(fp); | |
| 319 } else { | |
| 320 gprintf(fp, "0x%x", DispValue32(dinst)); | |
| 321 if (4 == modrm_rmInline(dinst->inst.mrm)) { | |
| 322 SibPrint(dinst, fp); | |
| 323 } else { | |
| 324 gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]); | |
| 325 } | |
| 326 } | |
| 327 break; | |
| 328 case 2: | |
| 329 SegPrefixPrint(dinst, fp); | |
| 330 if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) { | |
| 331 NaClIllegalOp(fp); | |
| 332 } else { | |
| 333 gprintf(fp, "0x%x", DispValue32(dinst)); | |
| 334 if (4 == modrm_rmInline(dinst->inst.mrm)) { | |
| 335 SibPrint(dinst, fp); | |
| 336 } else { | |
| 337 gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]); | |
| 338 } | |
| 339 } | |
| 340 break; | |
| 341 case 3: | |
| 342 if (is_gp_regs) { | |
| 343 gprintf(fp, "%s", reg_names[state_modrm_reg(dinst)]); | |
| 344 } else { | |
| 345 gprintf(fp, "%s", reg_names[modrm_rmInline(dinst->inst.mrm)]); | |
| 346 } | |
| 347 break; | |
| 348 } | |
| 349 } | |
| 350 | |
| 351 /* Parses the group name in token. Returns NOGROUP(0) if unable to parse. */ | |
| 352 static NaClMRMGroups ParseGroupName(const char* token) { | |
| 353 if (!strncmp(token, "group", 5)) { | |
| 354 /* Matched group name prefix, recognize last two characters explicitly.*/ | |
| 355 const char* suffix = token + 5; | |
| 356 switch (strlen(suffix)) { | |
| 357 case 1: | |
| 358 switch (suffix[0]) { | |
| 359 case '1': | |
| 360 return GROUP1; | |
| 361 case '2': | |
| 362 return GROUP2; | |
| 363 case '3': | |
| 364 return GROUP3; | |
| 365 case '4': | |
| 366 return GROUP4; | |
| 367 case '5': | |
| 368 return GROUP5; | |
| 369 case '6': | |
| 370 return GROUP6; | |
| 371 case '7': | |
| 372 return GROUP7; | |
| 373 case '8': | |
| 374 return GROUP8; | |
| 375 case '9': | |
| 376 return GROUP9; | |
| 377 case 'p': | |
| 378 return GROUPP; | |
| 379 default: | |
| 380 break; | |
| 381 } | |
| 382 break; | |
| 383 case 2: | |
| 384 if (suffix[0] == '1') { | |
| 385 switch(suffix[1]) { | |
| 386 case '0': | |
| 387 return GROUP10; | |
| 388 case '1': | |
| 389 return GROUP11; | |
| 390 case '2': | |
| 391 return GROUP12; | |
| 392 case '3': | |
| 393 return GROUP13; | |
| 394 case '4': | |
| 395 return GROUP14; | |
| 396 case '5': | |
| 397 return GROUP15; | |
| 398 case '6': | |
| 399 return GROUP16; | |
| 400 case '7': | |
| 401 return GROUP17; | |
| 402 case 'a': | |
| 403 return GROUP1A; | |
| 404 default: | |
| 405 break; | |
| 406 } | |
| 407 } | |
| 408 break; | |
| 409 default: | |
| 410 break; | |
| 411 } | |
| 412 } | |
| 413 return 0; | |
| 414 } | |
| 415 | |
| 416 static void InstFormat(const char* format, | |
| 417 const NCDecoderInst *dinst, | |
| 418 struct Gio* fp) { | |
| 419 char token_buf[128]; | |
| 420 char* fmt = token_buf; | |
| 421 int pos = 0; | |
| 422 | |
| 423 strncpy(token_buf, format, sizeof(token_buf)); | |
| 424 | |
| 425 while (1) { | |
| 426 char* token = strtok(fmt, " ,\n"); | |
| 427 DEBUG( printf("\ntoken = '%s'\n", token) ); | |
| 428 if (NULL == token) { | |
| 429 break; | |
| 430 } | |
| 431 if (pos > 1) { | |
| 432 gprintf(fp, ", "); | |
| 433 } else if (pos > 0) { | |
| 434 gprintf(fp, " "); | |
| 435 } | |
| 436 if ('$' == token[0]) { | |
| 437 NaClMRMGroups group = ParseGroupName(token+1); | |
| 438 if (NOGROUP != group) { | |
| 439 int mrm = modrm_regInline(dinst->inst.mrm); | |
| 440 const char* opname = kDisasmModRMOp[group][mrm]; | |
| 441 DEBUG( printf("case: group %d, opname = %s\n", group, opname) ); | |
| 442 gprintf(fp, "%s", opname); | |
| 443 } else { | |
| 444 /* Tokens starting with a $ but not $group need formatting */ | |
| 445 DEBUG( printf("case: $ and not group\n") ); | |
| 446 switch (token[1]) { | |
| 447 case 'A': | |
| 448 gprintf(fp, "$A"); | |
| 449 break; | |
| 450 case 'C': | |
| 451 gprintf(fp, "%%cr%d", modrm_regInline(dinst->inst.mrm)); | |
| 452 break; | |
| 453 case 'D': | |
| 454 gprintf(fp, "%%dr%d", modrm_regInline(dinst->inst.mrm)); | |
| 455 break; | |
| 456 case 'E': | |
| 457 case 'M': /* mod should never be 3 for 'M' */ | |
| 458 /* TODO(sehr): byte and word accesses */ | |
| 459 RegMemPrint(dinst, gp_regs, 1, fp); | |
| 460 break; | |
| 461 case 'F': | |
| 462 gprintf(fp, "eflags"); | |
| 463 break; | |
| 464 case 'G': | |
| 465 gprintf(fp, "%s", gp_regs[modrm_regInline(dinst->inst.mrm)]); | |
| 466 break; | |
| 467 case 'I': | |
| 468 gprintf(fp, "0x%"NACL_PRIx64, ImmedValue64(dinst)); | |
| 469 break; | |
| 470 case 'J': | |
| 471 gprintf(fp, "0x%"NACL_PRIxNaClPcAddress, | |
| 472 NCPrintableInstructionAddress(dinst) | |
| 473 + dinst->inst.bytes.length | |
| 474 + ImmedValue32(dinst)); | |
| 475 break; | |
| 476 case 'O': | |
| 477 gprintf(fp, "[0x%"NACL_PRIx64"]", ImmedValue64(dinst)); | |
| 478 break; | |
| 479 case 'P': | |
| 480 if ('R' == token[2]) { | |
| 481 gprintf(fp, "%%mm%d", modrm_rmInline(dinst->inst.mrm)); | |
| 482 } else { | |
| 483 gprintf(fp, "%%mm%d", modrm_regInline(dinst->inst.mrm)); | |
| 484 } | |
| 485 break; | |
| 486 case 'Q': | |
| 487 RegMemPrint(dinst, mmx_regs, 0, fp); | |
| 488 break; | |
| 489 case 'R': | |
| 490 gprintf(fp, "%s", gp_regs[modrm_rmInline(dinst->inst.mrm)]); | |
| 491 break; | |
| 492 case 'S': | |
| 493 gprintf(fp, "%s", seg_regs[modrm_regInline(dinst->inst.mrm)]); | |
| 494 break; | |
| 495 case 'V': | |
| 496 if ('R' == token[2]) { | |
| 497 gprintf(fp, "%%xmm%d", modrm_rmInline(dinst->inst.mrm)); | |
| 498 } else { | |
| 499 gprintf(fp, "%%xmm%d", modrm_regInline(dinst->inst.mrm)); | |
| 500 } | |
| 501 break; | |
| 502 case 'W': | |
| 503 RegMemPrint(dinst, xmm_regs, 0, fp); | |
| 504 break; | |
| 505 case 'X': | |
| 506 gprintf(fp, "ds:[esi]"); | |
| 507 break; | |
| 508 case 'Y': | |
| 509 gprintf(fp, "es:[edi]"); | |
| 510 break; | |
| 511 default: | |
| 512 gprintf(fp, "token('%s')", token); | |
| 513 break; | |
| 514 } | |
| 515 } | |
| 516 } else { | |
| 517 /* Print the token as is */ | |
| 518 gprintf(fp, "%s", token); | |
| 519 } | |
| 520 fmt = NULL; | |
| 521 ++pos; | |
| 522 } | |
| 523 } | |
| 524 | |
| 525 static void NCPrintInstTextUsingFormat(const char* format, | |
| 526 const NCDecoderInst *dinst, | |
| 527 struct Gio* fp) { | |
| 528 InstFormat(format, dinst, fp); | |
| 529 gprintf(fp, "\n"); | |
| 530 } | |
| 531 | |
| 532 void NCPrintInstWithoutHex(const NCDecoderInst *dinst, struct Gio* fp) { | |
| 533 DEBUG( printf("use format: %s\n", DisFmt(dinst)) ); | |
| 534 NCPrintInstTextUsingFormat(DisFmt(dinst), dinst, fp); | |
| 535 } | |
| 536 | |
| 537 void NCPrintInstWithHex(const NCDecoderInst *dinst, struct Gio *fp) { | |
| 538 int i; | |
| 539 DEBUG( printf("use format: %s\n", DisFmt(dinst)) ); | |
| 540 gprintf(fp, " %"NACL_PRIxNaClPcAddress":\t%02x", | |
| 541 NCPrintableInstructionAddress(dinst), | |
| 542 NCInstBytesByte(&dinst->inst_bytes, 0)); | |
| 543 for (i = 1; i < dinst->inst.bytes.length; i++) { | |
| 544 gprintf(fp, " %02x", NCInstBytesByte(&dinst->inst_bytes, i)); | |
| 545 } | |
| 546 for (i = dinst->inst.bytes.length; i < 7; i++) gprintf(fp, " "); | |
| 547 gprintf(fp, "\t"); | |
| 548 NCPrintInstWithoutHex(dinst, fp); | |
| 549 } | |
| 550 | |
| 551 static Bool PrintInstLogGio(const NCDecoderInst *dinst) { | |
| 552 NCPrintInstWithHex(dinst, NaClLogGetGio()); | |
| 553 return TRUE; | |
| 554 } | |
| 555 | |
| 556 /* Defines a buffer size big enough to hold an instruction. */ | |
| 557 #define MAX_INST_TEXT_SIZE 256 | |
| 558 | |
| 559 /* Defines an instruction print function. */ | |
| 560 typedef void (*inst_print_fn)(const struct NCDecoderInst* inst, | |
| 561 struct Gio *file); | |
| 562 | |
| 563 /* Print out the given instruction, using the given instruction print function, | |
| 564 * and return the printed text as a (malloc allocated) string. | |
| 565 */ | |
| 566 static char* InstToStringConvert(const NCDecoderInst* dinst, | |
| 567 inst_print_fn print_fn) { | |
| 568 /* Print to a memory buffer, and then duplicate. */ | |
| 569 struct GioMemoryFile filemem; | |
| 570 struct Gio *file = (struct Gio*) &filemem; | |
| 571 char buffer[MAX_INST_TEXT_SIZE]; | |
| 572 char* result; | |
| 573 | |
| 574 /* Note: Be sure to leave an extra byte to add the null character to | |
| 575 * the end of the string. | |
| 576 */ | |
| 577 GioMemoryFileCtor(&filemem, buffer, MAX_INST_TEXT_SIZE - 1); | |
| 578 print_fn(dinst, file); | |
| 579 buffer[filemem.curpos < MAX_INST_TEXT_SIZE | |
| 580 ? filemem.curpos : MAX_INST_TEXT_SIZE] ='\0'; | |
| 581 result = strdup(buffer); | |
| 582 GioMemoryFileDtor(file); | |
| 583 return result; | |
| 584 } | |
| 585 | |
| 586 char* NCInstWithHexToString(const NCDecoderInst* dinst) { | |
| 587 return InstToStringConvert(dinst, NCPrintInstWithHex); | |
| 588 } | |
| 589 | |
| 590 char* NCInstWithoutHexToString(const NCDecoderInst* dinst) { | |
| 591 return InstToStringConvert(dinst, NCPrintInstWithoutHex); | |
| 592 } | |
| 593 | |
| 594 void NCDecodeSegment(uint8_t* mbase, NaClPcAddress vbase, | |
| 595 NaClMemorySize size) { | |
| 596 NCDecoderInst inst; | |
| 597 NCDecoderState dstate; | |
| 598 NCDecoderStateConstruct(&dstate, mbase, vbase, size, &inst, 1); | |
| 599 NCDecoderStateSetErrorReporter(&dstate, &kNCVerboseErrorReporter); | |
| 600 /* TODO(karl): Fix this so that we don't need to override the | |
| 601 * action function. | |
| 602 */ | |
| 603 dstate.action_fn = PrintInstLogGio; | |
| 604 NCDecoderStateDecode(&dstate); | |
| 605 NCDecoderStateDestruct(&dstate); | |
| 606 } | |
| 607 | |
| 608 static void NCVerboseErrorPrintInst(NaClErrorReporter* self, | |
| 609 NCDecoderInst* dinst) { | |
| 610 PrintInstLogGio(dinst); | |
| 611 } | |
| 612 | |
| 613 NaClErrorReporter kNCVerboseErrorReporter = { | |
| 614 NCDecoderInstErrorReporter, | |
| 615 NaClVerboseErrorPrintf, | |
| 616 NaClVerboseErrorPrintfV, | |
| 617 (NaClPrintInst) NCVerboseErrorPrintInst | |
| 618 }; | |
| OLD | NEW |