1 #include <lib9.h> 2 #include <bio.h> 3 #include "mach.h" 4 5 /* 6 * i386-specific debugger interface 7 * also amd64 extensions 8 */ 9 10 static char *i386excep(Map*, Rgetter); 11 12 static int i386trace(Map*, uvlong, uvlong, uvlong, Tracer); 13 static uvlong i386frame(Map*, uvlong, uvlong, uvlong, uvlong); 14 static int i386foll(Map*, uvlong, Rgetter, uvlong*); 15 static int i386inst(Map*, uvlong, char, char*, int); 16 static int i386das(Map*, uvlong, char*, int); 17 static int i386instlen(Map*, uvlong); 18 19 static char STARTSYM[] = "_main"; 20 static char PROFSYM[] = "_mainp"; 21 static char FRAMENAME[] = ".frame"; 22 static char *excname[65] = 23 { 24 /*[0]*/ "divide error", 25 /*[1]*/ "debug exception", 26 /*[2]*/ nil, 27 /*[3]*/ nil, 28 /*[4]*/ "overflow", 29 /*[5]*/ "bounds check", 30 /*[6]*/ "invalid opcode", 31 /*[7]*/ "math coprocessor emulation", 32 /*[8]*/ "double fault", 33 /*[9]*/ "math coprocessor overrun", 34 /*[10]*/ "invalid TSS", 35 /*[11]*/ "segment not present", 36 /*[12]*/ "stack exception", 37 /*[13]*/ "general protection violation", 38 /*[14]*/ "page fault", 39 /*[15]*/ nil, 40 /*[16]*/ "math coprocessor error", 41 /*[17]*/ "alignment check", 42 /*[18]*/ "machine check", 43 /*[19]*/ "floating-point exception", 44 /*[20]*/ nil, 45 /*[21]*/ nil, 46 /*[22]*/ nil, 47 /*[23]*/ nil, 48 /*[24]*/ "clock", 49 /*[25]*/ "keyboard", 50 /*[26]*/ nil, 51 /*[27]*/ "modem status", 52 /*[28]*/ "serial line status", 53 /*[29]*/ nil, 54 /*[30]*/ "floppy disk", 55 /*[31]*/ nil, 56 /*[32]*/ nil, 57 /*[33]*/ nil, 58 /*[34]*/ nil, 59 /*[35]*/ nil, 60 /*[36]*/ "mouse", 61 /*[37]*/ "math coprocessor", 62 /*[38]*/ "hard disk", 63 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 39-54 */ 64 0,0,0,0,0,0,0,0,0, /* 55-63 */ 65 /*[64]*/ "system call", 66 }; 67 68 Machdata i386mach = 69 { 70 {0xCC, 0, 0, 0}, /* break point: INT 3 */ 71 1, /* break point size */ 72 73 leswab, /* convert short to local byte order */ 74 leswal, /* convert long to local byte order */ 75 leswav, /* convert vlong to local byte order */ 76 i386trace, /* C traceback */ 77 i386frame, /* frame finder */ 78 i386excep, /* print exception */ 79 0, /* breakpoint fixup */ 80 leieeesftos, /* single precision float printer */ 81 leieeedftos, /* double precision float printer */ 82 i386foll, /* following addresses */ 83 i386inst, /* print instruction */ 84 i386das, /* dissembler */ 85 i386instlen, /* instruction size calculation */ 86 }; 87 88 static char* 89 i386excep(Map *map, Rgetter rget) 90 { 91 ulong c; 92 uvlong pc; 93 static char buf[16]; 94 95 c = (*rget)(map, "TRAP"); 96 if(c > 64 || excname[c] == 0) { 97 if (c == 3) { 98 pc = (*rget)(map, "PC"); 99 if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0) 100 if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0) 101 return "breakpoint"; 102 } 103 snprint(buf, sizeof(buf), "exception %ld", c); 104 return buf; 105 } else 106 return excname[c]; 107 } 108 109 static int 110 i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace) 111 { 112 int i; 113 uvlong osp; 114 Symbol s, f; 115 116 USED(link); 117 i = 0; 118 osp = 0; 119 while(findsym(pc, CTEXT, &s)) { 120 if (osp == sp) 121 break; 122 osp = sp; 123 124 if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) 125 break; 126 127 if(pc != s.value) { /* not at first instruction */ 128 if(findlocal(&s, FRAMENAME, &f) == 0) 129 break; 130 sp += f.value-mach->szaddr; 131 } 132 133 if (geta(map, sp, &pc) < 0) 134 break; 135 136 if(pc == 0) 137 break; 138 139 (*trace)(map, pc, sp, &s); 140 sp += mach->szaddr; 141 142 if(++i > 1000) 143 break; 144 } 145 return i; 146 } 147 148 static uvlong 149 i386frame(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link) 150 { 151 Symbol s, f; 152 153 USED(link); 154 while (findsym(pc, CTEXT, &s)) { 155 if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) 156 break; 157 158 if(pc != s.value) { /* not first instruction */ 159 if(findlocal(&s, FRAMENAME, &f) == 0) 160 break; 161 sp += f.value-mach->szaddr; 162 } 163 164 if (s.value == addr) 165 return sp; 166 167 if (geta(map, sp, &pc) < 0) 168 break; 169 sp += mach->szaddr; 170 } 171 return 0; 172 } 173 174 /* I386/486 - Disassembler and related functions */ 175 176 /* 177 * an instruction 178 */ 179 typedef struct Instr Instr; 180 struct Instr 181 { 182 uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */ 183 uvlong addr; /* address of start of instruction */ 184 int n; /* number of bytes in instruction */ 185 char *prefix; /* instr prefix */ 186 char *segment; /* segment override */ 187 uchar jumptype; /* set to the operand type for jump/ret/call */ 188 uchar amd64; 189 uchar rex; /* REX prefix (or zero) */ 190 char osize; /* 'W' or 'L' (or 'Q' on amd64) */ 191 char asize; /* address size 'W' or 'L' (or 'Q' or amd64) */ 192 uchar mod; /* bits 6-7 of mod r/m field */ 193 uchar reg; /* bits 3-5 of mod r/m field */ 194 char ss; /* bits 6-7 of SIB */ 195 char index; /* bits 3-5 of SIB */ 196 char base; /* bits 0-2 of SIB */ 197 char rip; /* RIP-relative in amd64 mode */ 198 uchar opre; /* f2/f3 could introduce media */ 199 short seg; /* segment of far address */ 200 ulong disp; /* displacement */ 201 ulong imm; /* immediate */ 202 ulong imm2; /* second immediate operand */ 203 uvlong imm64; /* big immediate */ 204 char *curr; /* fill level in output buffer */ 205 char *end; /* end of output buffer */ 206 char *err; /* error message */ 207 }; 208 209 /* 386 register (ha!) set */ 210 enum{ 211 AX=0, 212 CX, 213 DX, 214 BX, 215 SP, 216 BP, 217 SI, 218 DI, 219 220 /* amd64 */ 221 R8, 222 R9, 223 R10, 224 R11, 225 R12, 226 R13, 227 R14, 228 R15 229 }; 230 231 /* amd64 rex extension byte */ 232 enum{ 233 REXW = 1<<3, /* =1, 64-bit operand size */ 234 REXR = 1<<2, /* extend modrm reg */ 235 REXX = 1<<1, /* extend sib index */ 236 REXB = 1<<0 /* extend modrm r/m, sib base, or opcode reg */ 237 }; 238 239 /* Operand Format codes */ 240 /* 241 %A - address size register modifier (!asize -> 'E') 242 %C - Control register CR0/CR1/CR2 243 %D - Debug register DR0/DR1/DR2/DR3/DR6/DR7 244 %I - second immediate operand 245 %O - Operand size register modifier (!osize -> 'E') 246 %T - Test register TR6/TR7 247 %S - size code ('W' or 'L') 248 %W - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE" 249 %d - displacement 16-32 bits 250 %e - effective address - Mod R/M value 251 %f - floating point register F0-F7 - from Mod R/M register 252 %g - segment register 253 %i - immediate operand 8-32 bits 254 %p - PC-relative - signed displacement in immediate field 255 %r - Reg from Mod R/M 256 %w - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ" 257 */ 258 259 typedef struct Optable Optable; 260 struct Optable 261 { 262 int x; 263 char operand[2]; 264 void *proto; /* actually either (char*) or (Optable*) */ 265 }; 266 /* Operand decoding codes */ 267 enum { 268 Ib = 1, /* 8-bit immediate - (no sign extension)*/ 269 Ibs, /* 8-bit immediate (sign extended) */ 270 Jbs, /* 8-bit sign-extended immediate in jump or call */ 271 Iw, /* 16-bit immediate -> imm */ 272 Iw2, /* 16-bit immediate -> imm2 */ 273 Iwd, /* Operand-sized immediate (no sign extension)*/ 274 Iwdq, /* Operand-sized immediate, possibly 64 bits */ 275 Awd, /* Address offset */ 276 Iwds, /* Operand-sized immediate (sign extended) */ 277 RM, /* Word or long R/M field with register (/r) */ 278 RMB, /* Byte R/M field with register (/r) */ 279 RMOP, /* Word or long R/M field with op code (/digit) */ 280 RMOPB, /* Byte R/M field with op code (/digit) */ 281 RMR, /* R/M register only (mod = 11) */ 282 RMM, /* R/M memory only (mod = 0/1/2) */ 283 R0, /* Base reg of Mod R/M is literal 0x00 */ 284 R1, /* Base reg of Mod R/M is literal 0x01 */ 285 FRMOP, /* Floating point R/M field with opcode */ 286 FRMEX, /* Extended floating point R/M field with opcode */ 287 JUMP, /* Jump or Call flag - no operand */ 288 RET, /* Return flag - no operand */ 289 OA, /* literal 0x0a byte */ 290 PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */ 291 AUX, /* Multi-byte op code - Auxiliary table */ 292 AUXMM, /* multi-byte op code - auxiliary table chosen by prefix */ 293 PRE, /* Instr Prefix */ 294 OPRE, /* Instr Prefix or media op extension */ 295 SEG, /* Segment Prefix */ 296 OPOVER, /* Operand size override */ 297 ADDOVER, /* Address size override */ 298 }; 299 300 static Optable optab0F00[8]= 301 { 302 0x00, 0,0, "MOVW LDT,%e", 303 0x01, 0,0, "MOVW TR,%e", 304 0x02, 0,0, "MOVW %e,LDT", 305 0x03, 0,0, "MOVW %e,TR", 306 0x04, 0,0, "VERR %e", 307 0x05, 0,0, "VERW %e", 308 }; 309 310 static Optable optab0F01[8]= 311 { 312 0x00, 0,0, "MOVL GDTR,%e", 313 0x01, 0,0, "MOVL IDTR,%e", 314 0x02, 0,0, "MOVL %e,GDTR", 315 0x03, 0,0, "MOVL %e,IDTR", 316 0x04, 0,0, "MOVW MSW,%e", /* word */ 317 0x06, 0,0, "MOVW %e,MSW", /* word */ 318 0x07, 0,0, "INVLPG %e", /* or SWAPGS */ 319 }; 320 321 static Optable optab0F01F8[1]= 322 { 323 0x00, 0,0, "SWAPGS", 324 }; 325 326 /* 0F71 */ 327 /* 0F72 */ 328 /* 0F73 */ 329 330 static Optable optab0FAE[8]= 331 { 332 0x00, 0,0, "FXSAVE %e", 333 0x01, 0,0, "FXRSTOR %e", 334 0x02, 0,0, "LDMXCSR %e", 335 0x03, 0,0, "STMXCSR %e", 336 0x05, 0,0, "LFENCE", 337 0x06, 0,0, "MFENCE", 338 0x07, 0,0, "SFENCE", 339 }; 340 341 /* 0F18 */ 342 /* 0F0D */ 343 344 static Optable optab0FBA[8]= 345 { 346 0x04, Ib,0, "BT%S %i,%e", 347 0x05, Ib,0, "BTS%S %i,%e", 348 0x06, Ib,0, "BTR%S %i,%e", 349 0x07, Ib,0, "BTC%S %i,%e", 350 }; 351 352 static Optable optab0F0F[256]= 353 { 354 0x0c, 0,0, "PI2FW %m,%M", 355 0x0d, 0,0, "PI2L %m,%M", 356 0x1c, 0,0, "PF2IW %m,%M", 357 0x1d, 0,0, "PF2IL %m,%M", 358 0x8a, 0,0, "PFNACC %m,%M", 359 0x8e, 0,0, "PFPNACC %m,%M", 360 0x90, 0,0, "PFCMPGE %m,%M", 361 0x94, 0,0, "PFMIN %m,%M", 362 0x96, 0,0, "PFRCP %m,%M", 363 0x97, 0,0, "PFRSQRT %m,%M", 364 0x9a, 0,0, "PFSUB %m,%M", 365 0x9e, 0,0, "PFADD %m,%M", 366 0xa0, 0,0, "PFCMPGT %m,%M", 367 0xa4, 0,0, "PFMAX %m,%M", 368 0xa6, 0,0, "PFRCPIT1 %m,%M", 369 0xa7, 0,0, "PFRSQIT1 %m,%M", 370 0xaa, 0,0, "PFSUBR %m,%M", 371 0xae, 0,0, "PFACC %m,%M", 372 0xb0, 0,0, "PFCMPEQ %m,%M", 373 0xb4, 0,0, "PFMUL %m,%M", 374 0xb6, 0,0, "PFRCPI2T %m,%M", 375 0xb7, 0,0, "PMULHRW %m,%M", 376 0xbb, 0,0, "PSWAPL %m,%M", 377 }; 378 379 static Optable optab0FC7[8]= 380 { 381 0x01, 0,0, "CMPXCHG8B %e", 382 }; 383 384 static Optable optab660F71[8]= 385 { 386 0x02, Ib,0, "PSRLW %i,%X", 387 0x04, Ib,0, "PSRAW %i,%X", 388 0x06, Ib,0, "PSLLW %i,%X", 389 }; 390 391 static Optable optab660F72[8]= 392 { 393 0x02, Ib,0, "PSRLL %i,%X", 394 0x04, Ib,0, "PSRAL %i,%X", 395 0x06, Ib,0, "PSLLL %i,%X", 396 }; 397 398 static Optable optab660F73[8]= 399 { 400 0x02, Ib,0, "PSRLQ %i,%X", 401 0x03, Ib,0, "PSRLO %i,%X", 402 0x06, Ib,0, "PSLLQ %i,%X", 403 0x07, Ib,0, "PSLLO %i,%X", 404 }; 405 406 static Optable optab660F[256]= 407 { 408 0x2B, RM,0, "MOVNTPD %x,%e", 409 0x2E, RM,0, "UCOMISD %x,%X", 410 0x2F, RM,0, "COMISD %x,%X", 411 0x5A, RM,0, "CVTPD2PS %x,%X", 412 0x5B, RM,0, "CVTPS2PL %x,%X", 413 0x6A, RM,0, "PUNPCKHLQ %x,%X", 414 0x6B, RM,0, "PACKSSLW %x,%X", 415 0x6C, RM,0, "PUNPCKLQDQ %x,%X", 416 0x6D, RM,0, "PUNPCKHQDQ %x,%X", 417 0x6E, RM,0, "MOV%S %e,%X", 418 0x6F, RM,0, "MOVO %x,%X", /* MOVDQA */ 419 0x70, RM,Ib, "PSHUFL %i,%x,%X", 420 0x71, RMOP,0, optab660F71, 421 0x72, RMOP,0, optab660F72, 422 0x73, RMOP,0, optab660F73, 423 0x7E, RM,0, "MOV%S %X,%e", 424 0x7F, RM,0, "MOVO %X,%x", 425 0xC4, RM,Ib, "PINSRW %i,%e,%X", 426 0xC5, RMR,Ib, "PEXTRW %i,%X,%e", 427 0xD4, RM,0, "PADDQ %x,%X", 428 0xD5, RM,0, "PMULLW %x,%X", 429 0xD6, RM,0, "MOVQ %X,%x", 430 0xE6, RM,0, "CVTTPD2PL %x,%X", 431 0xE7, RM,0, "MOVNTO %X,%e", 432 0xF7, RM,0, "MASKMOVOU %x,%X", 433 }; 434 435 static Optable optabF20F[256]= 436 { 437 0x10, RM,0, "MOVSD %x,%X", 438 0x11, RM,0, "MOVSD %X,%x", 439 0x2A, RM,0, "CVTS%S2SD %e,%X", 440 0x2C, RM,0, "CVTTSD2S%S %x,%r", 441 0x2D, RM,0, "CVTSD2S%S %x,%r", 442 0x5A, RM,0, "CVTSD2SS %x,%X", 443 0x6F, RM,0, "MOVOU %x,%X", 444 0x70, RM,Ib, "PSHUFLW %i,%x,%X", 445 0x7F, RM,0, "MOVOU %X,%x", 446 0xD6, RM,0, "MOVQOZX %M,%X", 447 0xE6, RM,0, "CVTPD2PL %x,%X", 448 }; 449 450 static Optable optabF30F[256]= 451 { 452 0x10, RM,0, "MOVSS %x,%X", 453 0x11, RM,0, "MOVSS %X,%x", 454 0x2A, RM,0, "CVTS%S2SS %e,%X", 455 0x2C, RM,0, "CVTTSS2S%S %x,%r", 456 0x2D, RM,0, "CVTSS2S%S %x,%r", 457 0x5A, RM,0, "CVTSS2SD %x,%X", 458 0x5B, RM,0, "CVTTPS2PL %x,%X", 459 0x6F, RM,0, "MOVOU %x,%X", 460 0x70, RM,Ib, "PSHUFHW %i,%x,%X", 461 0x7E, RM,0, "MOVQOZX %x,%X", 462 0x7F, RM,0, "MOVOU %X,%x", 463 0xD6, RM,0, "MOVQOZX %m*,%X", 464 0xE6, RM,0, "CVTPL2PD %x,%X", 465 }; 466 467 static Optable optab0F[256]= 468 { 469 0x00, RMOP,0, optab0F00, 470 0x01, RMOP,0, optab0F01, 471 0x02, RM,0, "LAR %e,%r", 472 0x03, RM,0, "LSL %e,%r", 473 0x05, 0,0, "SYSCALL", 474 0x06, 0,0, "CLTS", 475 0x07, 0,0, "SYSRET", 476 0x08, 0,0, "INVD", 477 0x09, 0,0, "WBINVD", 478 0x0B, 0,0, "UD2", 479 0x0F, RM,AUX, optab0F0F, /* 3DNow! */ 480 0x10, RM,0, "MOVU%s %x,%X", 481 0x11, RM,0, "MOVU%s %X,%x", 482 0x12, RM,0, "MOV[H]L%s %x,%X", /* TO DO: H if source is XMM */ 483 0x13, RM,0, "MOVL%s %X,%e", 484 0x14, RM,0, "UNPCKL%s %x,%X", 485 0x15, RM,0, "UNPCKH%s %x,%X", 486 0x16, RM,0, "MOV[L]H%s %x,%X", /* TO DO: L if source is XMM */ 487 0x17, RM,0, "MOVH%s %X,%x", 488 0x20, RMR,0, "MOVL %C,%e", 489 0x21, RMR,0, "MOVL %D,%e", 490 0x22, RMR,0, "MOVL %e,%C", 491 0x23, RMR,0, "MOVL %e,%D", 492 0x24, RMR,0, "MOVL %T,%e", 493 0x26, RMR,0, "MOVL %e,%T", 494 0x28, RM,0, "MOVA%s %x,%X", 495 0x29, RM,0, "MOVA%s %X,%x", 496 0x2A, RM,0, "CVTPL2%s %m*,%X", 497 0x2B, RM,0, "MOVNT%s %X,%e", 498 0x2C, RM,0, "CVTT%s2PL %x,%M", 499 0x2D, RM,0, "CVT%s2PL %x,%M", 500 0x2E, RM,0, "UCOMISS %x,%X", 501 0x2F, RM,0, "COMISS %x,%X", 502 0x30, 0,0, "WRMSR", 503 0x31, 0,0, "RDTSC", 504 0x32, 0,0, "RDMSR", 505 0x33, 0,0, "RDPMC", 506 0x42, RM,0, "CMOVC %e,%r", /* CF */ 507 0x43, RM,0, "CMOVNC %e,%r", /* ¬ CF */ 508 0x44, RM,0, "CMOVZ %e,%r", /* ZF */ 509 0x45, RM,0, "CMOVNZ %e,%r", /* ¬ ZF */ 510 0x46, RM,0, "CMOVBE %e,%r", /* CF ∨ ZF */ 511 0x47, RM,0, "CMOVA %e,%r", /* ¬CF ∧ ¬ZF */ 512 0x48, RM,0, "CMOVS %e,%r", /* SF */ 513 0x49, RM,0, "CMOVNS %e,%r", /* ¬ SF */ 514 0x4A, RM,0, "CMOVP %e,%r", /* PF */ 515 0x4B, RM,0, "CMOVNP %e,%r", /* ¬ PF */ 516 0x4C, RM,0, "CMOVLT %e,%r", /* LT ≡ OF ≠SF */ 517 0x4D, RM,0, "CMOVGE %e,%r", /* GE ≡ ZF ∨ SF */ 518 0x4E, RM,0, "CMOVLE %e,%r", /* LE ≡ ZF ∨ LT */ 519 0x4F, RM,0, "CMOVGT %e,%r", /* GT ≡ ¬ZF ∧ GE */ 520 0x50, RM,0, "MOVMSK%s %X,%r", /* TO DO: check */ 521 0x51, RM,0, "SQRT%s %x,%X", 522 0x52, RM,0, "RSQRT%s %x,%X", 523 0x53, RM,0, "RCP%s %x,%X", 524 0x54, RM,0, "AND%s %x,%X", 525 0x55, RM,0, "ANDN%s %x,%X", 526 0x56, RM,0, "OR%s %x,%X", /* TO DO: S/D */ 527 0x57, RM,0, "XOR%s %x,%X", /* S/D */ 528 0x58, RM,0, "ADD%s %x,%X", /* S/P S/D */ 529 0x59, RM,0, "MUL%s %x,%X", 530 0x5A, RM,0, "CVTPS2PD %x,%X", 531 0x5B, RM,0, "CVTPL2PS %x,%X", 532 0x5C, RM,0, "SUB%s %x,%X", 533 0x5D, RM,0, "MIN%s %x,%X", 534 0x5E, RM,0, "DIV%s %x,%X", /* TO DO: S/P S/D */ 535 0x5F, RM,0, "MAX%s %x,%X", 536 0x60, RM,0, "PUNPCKLBW %m,%M", 537 0x61, RM,0, "PUNPCKLWL %m,%M", 538 0x62, RM,0, "PUNPCKLLQ %m,%M", 539 0x63, RM,0, "PACKSSWB %m,%M", 540 0x64, RM,0, "PCMPGTB %m,%M", 541 0x65, RM,0, "PCMPGTW %m,%M", 542 0x66, RM,0, "PCMPGTL %m,%M", 543 0x67, RM,0, "PACKUSWB %m,%M", 544 0x68, RM,0, "PUNPCKHBW %m,%M", 545 0x69, RM,0, "PUNPCKHWL %m,%M", 546 0x6A, RM,0, "PUNPCKHLQ %m,%M", 547 0x6B, RM,0, "PACKSSLW %m,%M", 548 0x6E, RM,0, "MOV%S %e,%M", 549 0x6F, RM,0, "MOVQ %m,%M", 550 0x70, RM,Ib, "PSHUFW %i,%m,%M", 551 0x74, RM,0, "PCMPEQB %m,%M", 552 0x75, RM,0, "PCMPEQW %m,%M", 553 0x76, RM,0, "PCMPEQL %m,%M", 554 0x7E, RM,0, "MOV%S %M,%e", 555 0x7F, RM,0, "MOVQ %M,%m", 556 0xAE, RMOP,0, optab0FAE, 557 0xAA, 0,0, "RSM", 558 0xB0, RM,0, "CMPXCHGB %r,%e", 559 0xB1, RM,0, "CMPXCHG%S %r,%e", 560 0xC0, RMB,0, "XADDB %r,%e", 561 0xC1, RM,0, "XADD%S %r,%e", 562 0xC2, RM,Ib, "CMP%s %i,%x,%X", 563 0xC3, RM,0, "MOVNTI%S %r,%e", 564 0xC6, RM,Ib, "SHUF%s %i,%x,%X", 565 0xC8, 0,0, "BSWAP AX", 566 0xC9, 0,0, "BSWAP CX", 567 0xCA, 0,0, "BSWAP DX", 568 0xCB, 0,0, "BSWAP BX", 569 0xCC, 0,0, "BSWAP SP", 570 0xCD, 0,0, "BSWAP BP", 571 0xCE, 0,0, "BSWAP SI", 572 0xCF, 0,0, "BSWAP DI", 573 0xD1, RM,0, "PSRLW %m,%M", 574 0xD2, RM,0, "PSRLL %m,%M", 575 0xD3, RM,0, "PSRLQ %m,%M", 576 0xD5, RM,0, "PMULLW %m,%M", 577 0xD6, RM,0, "MOVQOZX %m*,%X", 578 0xD7, RM,0, "PMOVMSKB %m,%r", 579 0xD8, RM,0, "PSUBUSB %m,%M", 580 0xD9, RM,0, "PSUBUSW %m,%M", 581 0xDA, RM,0, "PMINUB %m,%M", 582 0xDB, RM,0, "PAND %m,%M", 583 0xDC, RM,0, "PADDUSB %m,%M", 584 0xDD, RM,0, "PADDUSW %m,%M", 585 0xDE, RM,0, "PMAXUB %m,%M", 586 0xDF, RM,0, "PANDN %m,%M", 587 0xE0, RM,0, "PAVGB %m,%M", 588 0xE1, RM,0, "PSRAW %m,%M", 589 0xE2, RM,0, "PSRAL %m,%M", 590 0xE3, RM,0, "PAVGW %m,%M", 591 0xE4, RM,0, "PMULHUW %m,%M", 592 0xE5, RM,0, "PMULHW %m,%M", 593 0xE7, RM,0, "MOVNTQ %M,%e", 594 0xE8, RM,0, "PSUBSB %m,%M", 595 0xE9, RM,0, "PSUBSW %m,%M", 596 0xEA, RM,0, "PMINSW %m,%M", 597 0xEB, RM,0, "POR %m,%M", 598 0xEC, RM,0, "PADDSB %m,%M", 599 0xED, RM,0, "PADDSW %m,%M", 600 0xEE, RM,0, "PMAXSW %m,%M", 601 0xEF, RM,0, "PXOR %m,%M", 602 0xF1, RM,0, "PSLLW %m,%M", 603 0xF2, RM,0, "PSLLL %m,%M", 604 0xF3, RM,0, "PSLLQ %m,%M", 605 0xF4, RM,0, "PMULULQ %m,%M", 606 0xF5, RM,0, "PMADDWL %m,%M", 607 0xF6, RM,0, "PSADBW %m,%M", 608 0xF7, RMR,0, "MASKMOVQ %m,%M", 609 0xF8, RM,0, "PSUBB %m,%M", 610 0xF9, RM,0, "PSUBW %m,%M", 611 0xFA, RM,0, "PSUBL %m,%M", 612 0xFC, RM,0, "PADDB %m,%M", 613 0xFD, RM,0, "PADDW %m,%M", 614 0xFE, RM,0, "PADDL %m,%M", 615 616 0x80, Iwds,0, "JOS %p", 617 0x81, Iwds,0, "JOC %p", 618 0x82, Iwds,0, "JCS %p", 619 0x83, Iwds,0, "JCC %p", 620 0x84, Iwds,0, "JEQ %p", 621 0x85, Iwds,0, "JNE %p", 622 0x86, Iwds,0, "JLS %p", 623 0x87, Iwds,0, "JHI %p", 624 0x88, Iwds,0, "JMI %p", 625 0x89, Iwds,0, "JPL %p", 626 0x8a, Iwds,0, "JPS %p", 627 0x8b, Iwds,0, "JPC %p", 628 0x8c, Iwds,0, "JLT %p", 629 0x8d, Iwds,0, "JGE %p", 630 0x8e, Iwds,0, "JLE %p", 631 0x8f, Iwds,0, "JGT %p", 632 0x90, RMB,0, "SETOS %e", 633 0x91, RMB,0, "SETOC %e", 634 0x92, RMB,0, "SETCS %e", 635 0x93, RMB,0, "SETCC %e", 636 0x94, RMB,0, "SETEQ %e", 637 0x95, RMB,0, "SETNE %e", 638 0x96, RMB,0, "SETLS %e", 639 0x97, RMB,0, "SETHI %e", 640 0x98, RMB,0, "SETMI %e", 641 0x99, RMB,0, "SETPL %e", 642 0x9a, RMB,0, "SETPS %e", 643 0x9b, RMB,0, "SETPC %e", 644 0x9c, RMB,0, "SETLT %e", 645 0x9d, RMB,0, "SETGE %e", 646 0x9e, RMB,0, "SETLE %e", 647 0x9f, RMB,0, "SETGT %e", 648 0xa0, 0,0, "PUSHL FS", 649 0xa1, 0,0, "POPL FS", 650 0xa2, 0,0, "CPUID", 651 0xa3, RM,0, "BT%S %r,%e", 652 0xa4, RM,Ib, "SHLD%S %r,%i,%e", 653 0xa5, RM,0, "SHLD%S %r,CL,%e", 654 0xa8, 0,0, "PUSHL GS", 655 0xa9, 0,0, "POPL GS", 656 0xab, RM,0, "BTS%S %r,%e", 657 0xac, RM,Ib, "SHRD%S %r,%i,%e", 658 0xad, RM,0, "SHRD%S %r,CL,%e", 659 0xaf, RM,0, "IMUL%S %e,%r", 660 0xb2, RMM,0, "LSS %e,%r", 661 0xb3, RM,0, "BTR%S %r,%e", 662 0xb4, RMM,0, "LFS %e,%r", 663 0xb5, RMM,0, "LGS %e,%r", 664 0xb6, RMB,0, "MOVBZX %e,%R", 665 0xb7, RM,0, "MOVWZX %e,%R", 666 0xba, RMOP,0, optab0FBA, 667 0xbb, RM,0, "BTC%S %e,%r", 668 0xbc, RM,0, "BSF%S %e,%r", 669 0xbd, RM,0, "BSR%S %e,%r", 670 0xbe, RMB,0, "MOVBSX %e,%R", 671 0xbf, RM,0, "MOVWSX %e,%R", 672 0xc7, RMOP,0, optab0FC7, 673 }; 674 675 static Optable optab80[8]= 676 { 677 0x00, Ib,0, "ADDB %i,%e", 678 0x01, Ib,0, "ORB %i,%e", 679 0x02, Ib,0, "ADCB %i,%e", 680 0x03, Ib,0, "SBBB %i,%e", 681 0x04, Ib,0, "ANDB %i,%e", 682 0x05, Ib,0, "SUBB %i,%e", 683 0x06, Ib,0, "XORB %i,%e", 684 0x07, Ib,0, "CMPB %e,%i", 685 }; 686 687 static Optable optab81[8]= 688 { 689 0x00, Iwd,0, "ADD%S %i,%e", 690 0x01, Iwd,0, "OR%S %i,%e", 691 0x02, Iwd,0, "ADC%S %i,%e", 692 0x03, Iwd,0, "SBB%S %i,%e", 693 0x04, Iwd,0, "AND%S %i,%e", 694 0x05, Iwd,0, "SUB%S %i,%e", 695 0x06, Iwd,0, "XOR%S %i,%e", 696 0x07, Iwd,0, "CMP%S %e,%i", 697 }; 698 699 static Optable optab83[8]= 700 { 701 0x00, Ibs,0, "ADD%S %i,%e", 702 0x01, Ibs,0, "OR%S %i,%e", 703 0x02, Ibs,0, "ADC%S %i,%e", 704 0x03, Ibs,0, "SBB%S %i,%e", 705 0x04, Ibs,0, "AND%S %i,%e", 706 0x05, Ibs,0, "SUB%S %i,%e", 707 0x06, Ibs,0, "XOR%S %i,%e", 708 0x07, Ibs,0, "CMP%S %e,%i", 709 }; 710 711 static Optable optabC0[8] = 712 { 713 0x00, Ib,0, "ROLB %i,%e", 714 0x01, Ib,0, "RORB %i,%e", 715 0x02, Ib,0, "RCLB %i,%e", 716 0x03, Ib,0, "RCRB %i,%e", 717 0x04, Ib,0, "SHLB %i,%e", 718 0x05, Ib,0, "SHRB %i,%e", 719 0x07, Ib,0, "SARB %i,%e", 720 }; 721 722 static Optable optabC1[8] = 723 { 724 0x00, Ib,0, "ROL%S %i,%e", 725 0x01, Ib,0, "ROR%S %i,%e", 726 0x02, Ib,0, "RCL%S %i,%e", 727 0x03, Ib,0, "RCR%S %i,%e", 728 0x04, Ib,0, "SHL%S %i,%e", 729 0x05, Ib,0, "SHR%S %i,%e", 730 0x07, Ib,0, "SAR%S %i,%e", 731 }; 732 733 static Optable optabD0[8] = 734 { 735 0x00, 0,0, "ROLB %e", 736 0x01, 0,0, "RORB %e", 737 0x02, 0,0, "RCLB %e", 738 0x03, 0,0, "RCRB %e", 739 0x04, 0,0, "SHLB %e", 740 0x05, 0,0, "SHRB %e", 741 0x07, 0,0, "SARB %e", 742 }; 743 744 static Optable optabD1[8] = 745 { 746 0x00, 0,0, "ROL%S %e", 747 0x01, 0,0, "ROR%S %e", 748 0x02, 0,0, "RCL%S %e", 749 0x03, 0,0, "RCR%S %e", 750 0x04, 0,0, "SHL%S %e", 751 0x05, 0,0, "SHR%S %e", 752 0x07, 0,0, "SAR%S %e", 753 }; 754 755 static Optable optabD2[8] = 756 { 757 0x00, 0,0, "ROLB CL,%e", 758 0x01, 0,0, "RORB CL,%e", 759 0x02, 0,0, "RCLB CL,%e", 760 0x03, 0,0, "RCRB CL,%e", 761 0x04, 0,0, "SHLB CL,%e", 762 0x05, 0,0, "SHRB CL,%e", 763 0x07, 0,0, "SARB CL,%e", 764 }; 765 766 static Optable optabD3[8] = 767 { 768 0x00, 0,0, "ROL%S CL,%e", 769 0x01, 0,0, "ROR%S CL,%e", 770 0x02, 0,0, "RCL%S CL,%e", 771 0x03, 0,0, "RCR%S CL,%e", 772 0x04, 0,0, "SHL%S CL,%e", 773 0x05, 0,0, "SHR%S CL,%e", 774 0x07, 0,0, "SAR%S CL,%e", 775 }; 776 777 static Optable optabD8[8+8] = 778 { 779 0x00, 0,0, "FADDF %e,F0", 780 0x01, 0,0, "FMULF %e,F0", 781 0x02, 0,0, "FCOMF %e,F0", 782 0x03, 0,0, "FCOMFP %e,F0", 783 0x04, 0,0, "FSUBF %e,F0", 784 0x05, 0,0, "FSUBRF %e,F0", 785 0x06, 0,0, "FDIVF %e,F0", 786 0x07, 0,0, "FDIVRF %e,F0", 787 0x08, 0,0, "FADDD %f,F0", 788 0x09, 0,0, "FMULD %f,F0", 789 0x0a, 0,0, "FCOMD %f,F0", 790 0x0b, 0,0, "FCOMPD %f,F0", 791 0x0c, 0,0, "FSUBD %f,F0", 792 0x0d, 0,0, "FSUBRD %f,F0", 793 0x0e, 0,0, "FDIVD %f,F0", 794 0x0f, 0,0, "FDIVRD %f,F0", 795 }; 796 /* 797 * optabD9 and optabDB use the following encoding: 798 * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07]; 799 * else instruction = optabDx[(modrm&0x3f)+8]; 800 * 801 * the instructions for MOD == 3, follow the 8 instructions 802 * for the other MOD values stored at the front of the table. 803 */ 804 static Optable optabD9[64+8] = 805 { 806 0x00, 0,0, "FMOVF %e,F0", 807 0x02, 0,0, "FMOVF F0,%e", 808 0x03, 0,0, "FMOVFP F0,%e", 809 0x04, 0,0, "FLDENV%S %e", 810 0x05, 0,0, "FLDCW %e", 811 0x06, 0,0, "FSTENV%S %e", 812 0x07, 0,0, "FSTCW %e", 813 0x08, 0,0, "FMOVD F0,F0", /* Mod R/M = 11xx xxxx*/ 814 0x09, 0,0, "FMOVD F1,F0", 815 0x0a, 0,0, "FMOVD F2,F0", 816 0x0b, 0,0, "FMOVD F3,F0", 817 0x0c, 0,0, "FMOVD F4,F0", 818 0x0d, 0,0, "FMOVD F5,F0", 819 0x0e, 0,0, "FMOVD F6,F0", 820 0x0f, 0,0, "FMOVD F7,F0", 821 0x10, 0,0, "FXCHD F0,F0", 822 0x11, 0,0, "FXCHD F1,F0", 823 0x12, 0,0, "FXCHD F2,F0", 824 0x13, 0,0, "FXCHD F3,F0", 825 0x14, 0,0, "FXCHD F4,F0", 826 0x15, 0,0, "FXCHD F5,F0", 827 0x16, 0,0, "FXCHD F6,F0", 828 0x17, 0,0, "FXCHD F7,F0", 829 0x18, 0,0, "FNOP", 830 0x28, 0,0, "FCHS", 831 0x29, 0,0, "FABS", 832 0x2c, 0,0, "FTST", 833 0x2d, 0,0, "FXAM", 834 0x30, 0,0, "FLD1", 835 0x31, 0,0, "FLDL2T", 836 0x32, 0,0, "FLDL2E", 837 0x33, 0,0, "FLDPI", 838 0x34, 0,0, "FLDLG2", 839 0x35, 0,0, "FLDLN2", 840 0x36, 0,0, "FLDZ", 841 0x38, 0,0, "F2XM1", 842 0x39, 0,0, "FYL2X", 843 0x3a, 0,0, "FPTAN", 844 0x3b, 0,0, "FPATAN", 845 0x3c, 0,0, "FXTRACT", 846 0x3d, 0,0, "FPREM1", 847 0x3e, 0,0, "FDECSTP", 848 0x3f, 0,0, "FNCSTP", 849 0x40, 0,0, "FPREM", 850 0x41, 0,0, "FYL2XP1", 851 0x42, 0,0, "FSQRT", 852 0x43, 0,0, "FSINCOS", 853 0x44, 0,0, "FRNDINT", 854 0x45, 0,0, "FSCALE", 855 0x46, 0,0, "FSIN", 856 0x47, 0,0, "FCOS", 857 }; 858 859 static Optable optabDA[8+8] = 860 { 861 0x00, 0,0, "FADDL %e,F0", 862 0x01, 0,0, "FMULL %e,F0", 863 0x02, 0,0, "FCOML %e,F0", 864 0x03, 0,0, "FCOMLP %e,F0", 865 0x04, 0,0, "FSUBL %e,F0", 866 0x05, 0,0, "FSUBRL %e,F0", 867 0x06, 0,0, "FDIVL %e,F0", 868 0x07, 0,0, "FDIVRL %e,F0", 869 0x0d, R1,0, "FUCOMPP", 870 }; 871 872 static Optable optabDB[8+64] = 873 { 874 0x00, 0,0, "FMOVL %e,F0", 875 0x02, 0,0, "FMOVL F0,%e", 876 0x03, 0,0, "FMOVLP F0,%e", 877 0x05, 0,0, "FMOVX %e,F0", 878 0x07, 0,0, "FMOVXP F0,%e", 879 0x2a, 0,0, "FCLEX", 880 0x2b, 0,0, "FINIT", 881 }; 882 883 static Optable optabDC[8+8] = 884 { 885 0x00, 0,0, "FADDD %e,F0", 886 0x01, 0,0, "FMULD %e,F0", 887 0x02, 0,0, "FCOMD %e,F0", 888 0x03, 0,0, "FCOMDP %e,F0", 889 0x04, 0,0, "FSUBD %e,F0", 890 0x05, 0,0, "FSUBRD %e,F0", 891 0x06, 0,0, "FDIVD %e,F0", 892 0x07, 0,0, "FDIVRD %e,F0", 893 0x08, 0,0, "FADDD F0,%f", 894 0x09, 0,0, "FMULD F0,%f", 895 0x0c, 0,0, "FSUBRD F0,%f", 896 0x0d, 0,0, "FSUBD F0,%f", 897 0x0e, 0,0, "FDIVRD F0,%f", 898 0x0f, 0,0, "FDIVD F0,%f", 899 }; 900 901 static Optable optabDD[8+8] = 902 { 903 0x00, 0,0, "FMOVD %e,F0", 904 0x02, 0,0, "FMOVD F0,%e", 905 0x03, 0,0, "FMOVDP F0,%e", 906 0x04, 0,0, "FRSTOR%S %e", 907 0x06, 0,0, "FSAVE%S %e", 908 0x07, 0,0, "FSTSW %e", 909 0x08, 0,0, "FFREED %f", 910 0x0a, 0,0, "FMOVD %f,F0", 911 0x0b, 0,0, "FMOVDP %f,F0", 912 0x0c, 0,0, "FUCOMD %f,F0", 913 0x0d, 0,0, "FUCOMDP %f,F0", 914 }; 915 916 static Optable optabDE[8+8] = 917 { 918 0x00, 0,0, "FADDW %e,F0", 919 0x01, 0,0, "FMULW %e,F0", 920 0x02, 0,0, "FCOMW %e,F0", 921 0x03, 0,0, "FCOMWP %e,F0", 922 0x04, 0,0, "FSUBW %e,F0", 923 0x05, 0,0, "FSUBRW %e,F0", 924 0x06, 0,0, "FDIVW %e,F0", 925 0x07, 0,0, "FDIVRW %e,F0", 926 0x08, 0,0, "FADDDP F0,%f", 927 0x09, 0,0, "FMULDP F0,%f", 928 0x0b, R1,0, "FCOMPDP", 929 0x0c, 0,0, "FSUBRDP F0,%f", 930 0x0d, 0,0, "FSUBDP F0,%f", 931 0x0e, 0,0, "FDIVRDP F0,%f", 932 0x0f, 0,0, "FDIVDP F0,%f", 933 }; 934 935 static Optable optabDF[8+8] = 936 { 937 0x00, 0,0, "FMOVW %e,F0", 938 0x02, 0,0, "FMOVW F0,%e", 939 0x03, 0,0, "FMOVWP F0,%e", 940 0x04, 0,0, "FBLD %e", 941 0x05, 0,0, "FMOVL %e,F0", 942 0x06, 0,0, "FBSTP %e", 943 0x07, 0,0, "FMOVLP F0,%e", 944 0x0c, R0,0, "FSTSW %OAX", 945 }; 946 947 static Optable optabF6[8] = 948 { 949 0x00, Ib,0, "TESTB %i,%e", 950 0x02, 0,0, "NOTB %e", 951 0x03, 0,0, "NEGB %e", 952 0x04, 0,0, "MULB AL,%e", 953 0x05, 0,0, "IMULB AL,%e", 954 0x06, 0,0, "DIVB AL,%e", 955 0x07, 0,0, "IDIVB AL,%e", 956 }; 957 958 static Optable optabF7[8] = 959 { 960 0x00, Iwd,0, "TEST%S %i,%e", 961 0x02, 0,0, "NOT%S %e", 962 0x03, 0,0, "NEG%S %e", 963 0x04, 0,0, "MUL%S %OAX,%e", 964 0x05, 0,0, "IMUL%S %OAX,%e", 965 0x06, 0,0, "DIV%S %OAX,%e", 966 0x07, 0,0, "IDIV%S %OAX,%e", 967 }; 968 969 static Optable optabFE[8] = 970 { 971 0x00, 0,0, "INCB %e", 972 0x01, 0,0, "DECB %e", 973 }; 974 975 static Optable optabFF[8] = 976 { 977 0x00, 0,0, "INC%S %e", 978 0x01, 0,0, "DEC%S %e", 979 0x02, JUMP,0, "CALL* %e", 980 0x03, JUMP,0, "CALLF* %e", 981 0x04, JUMP,0, "JMP* %e", 982 0x05, JUMP,0, "JMPF* %e", 983 0x06, 0,0, "PUSHL %e", 984 }; 985 986 static Optable optable[256+1] = 987 { 988 0x00, RMB,0, "ADDB %r,%e", 989 0x01, RM,0, "ADD%S %r,%e", 990 0x02, RMB,0, "ADDB %e,%r", 991 0x03, RM,0, "ADD%S %e,%r", 992 0x04, Ib,0, "ADDB %i,AL", 993 0x05, Iwd,0, "ADD%S %i,%OAX", 994 0x06, 0,0, "PUSHL ES", 995 0x07, 0,0, "POPL ES", 996 0x08, RMB,0, "ORB %r,%e", 997 0x09, RM,0, "OR%S %r,%e", 998 0x0a, RMB,0, "ORB %e,%r", 999 0x0b, RM,0, "OR%S %e,%r", 1000 0x0c, Ib,0, "ORB %i,AL", 1001 0x0d, Iwd,0, "OR%S %i,%OAX", 1002 0x0e, 0,0, "PUSHL CS", 1003 0x0f, AUXMM,0, optab0F, 1004 0x10, RMB,0, "ADCB %r,%e", 1005 0x11, RM,0, "ADC%S %r,%e", 1006 0x12, RMB,0, "ADCB %e,%r", 1007 0x13, RM,0, "ADC%S %e,%r", 1008 0x14, Ib,0, "ADCB %i,AL", 1009 0x15, Iwd,0, "ADC%S %i,%OAX", 1010 0x16, 0,0, "PUSHL SS", 1011 0x17, 0,0, "POPL SS", 1012 0x18, RMB,0, "SBBB %r,%e", 1013 0x19, RM,0, "SBB%S %r,%e", 1014 0x1a, RMB,0, "SBBB %e,%r", 1015 0x1b, RM,0, "SBB%S %e,%r", 1016 0x1c, Ib,0, "SBBB %i,AL", 1017 0x1d, Iwd,0, "SBB%S %i,%OAX", 1018 0x1e, 0,0, "PUSHL DS", 1019 0x1f, 0,0, "POPL DS", 1020 0x20, RMB,0, "ANDB %r,%e", 1021 0x21, RM,0, "AND%S %r,%e", 1022 0x22, RMB,0, "ANDB %e,%r", 1023 0x23, RM,0, "AND%S %e,%r", 1024 0x24, Ib,0, "ANDB %i,AL", 1025 0x25, Iwd,0, "AND%S %i,%OAX", 1026 0x26, SEG,0, "ES:", 1027 0x27, 0,0, "DAA", 1028 0x28, RMB,0, "SUBB %r,%e", 1029 0x29, RM,0, "SUB%S %r,%e", 1030 0x2a, RMB,0, "SUBB %e,%r", 1031 0x2b, RM,0, "SUB%S %e,%r", 1032 0x2c, Ib,0, "SUBB %i,AL", 1033 0x2d, Iwd,0, "SUB%S %i,%OAX", 1034 0x2e, SEG,0, "CS:", 1035 0x2f, 0,0, "DAS", 1036 0x30, RMB,0, "XORB %r,%e", 1037 0x31, RM,0, "XOR%S %r,%e", 1038 0x32, RMB,0, "XORB %e,%r", 1039 0x33, RM,0, "XOR%S %e,%r", 1040 0x34, Ib,0, "XORB %i,AL", 1041 0x35, Iwd,0, "XOR%S %i,%OAX", 1042 0x36, SEG,0, "SS:", 1043 0x37, 0,0, "AAA", 1044 0x38, RMB,0, "CMPB %r,%e", 1045 0x39, RM,0, "CMP%S %r,%e", 1046 0x3a, RMB,0, "CMPB %e,%r", 1047 0x3b, RM,0, "CMP%S %e,%r", 1048 0x3c, Ib,0, "CMPB %i,AL", 1049 0x3d, Iwd,0, "CMP%S %i,%OAX", 1050 0x3e, SEG,0, "DS:", 1051 0x3f, 0,0, "AAS", 1052 0x40, 0,0, "INC%S %OAX", 1053 0x41, 0,0, "INC%S %OCX", 1054 0x42, 0,0, "INC%S %ODX", 1055 0x43, 0,0, "INC%S %OBX", 1056 0x44, 0,0, "INC%S %OSP", 1057 0x45, 0,0, "INC%S %OBP", 1058 0x46, 0,0, "INC%S %OSI", 1059 0x47, 0,0, "INC%S %ODI", 1060 0x48, 0,0, "DEC%S %OAX", 1061 0x49, 0,0, "DEC%S %OCX", 1062 0x4a, 0,0, "DEC%S %ODX", 1063 0x4b, 0,0, "DEC%S %OBX", 1064 0x4c, 0,0, "DEC%S %OSP", 1065 0x4d, 0,0, "DEC%S %OBP", 1066 0x4e, 0,0, "DEC%S %OSI", 1067 0x4f, 0,0, "DEC%S %ODI", 1068 0x50, 0,0, "PUSH%S %OAX", 1069 0x51, 0,0, "PUSH%S %OCX", 1070 0x52, 0,0, "PUSH%S %ODX", 1071 0x53, 0,0, "PUSH%S %OBX", 1072 0x54, 0,0, "PUSH%S %OSP", 1073 0x55, 0,0, "PUSH%S %OBP", 1074 0x56, 0,0, "PUSH%S %OSI", 1075 0x57, 0,0, "PUSH%S %ODI", 1076 0x58, 0,0, "POP%S %OAX", 1077 0x59, 0,0, "POP%S %OCX", 1078 0x5a, 0,0, "POP%S %ODX", 1079 0x5b, 0,0, "POP%S %OBX", 1080 0x5c, 0,0, "POP%S %OSP", 1081 0x5d, 0,0, "POP%S %OBP", 1082 0x5e, 0,0, "POP%S %OSI", 1083 0x5f, 0,0, "POP%S %ODI", 1084 0x60, 0,0, "PUSHA%S", 1085 0x61, 0,0, "POPA%S", 1086 0x62, RMM,0, "BOUND %e,%r", 1087 0x63, RM,0, "ARPL %r,%e", 1088 0x64, SEG,0, "FS:", 1089 0x65, SEG,0, "GS:", 1090 0x66, OPOVER,0, "", 1091 0x67, ADDOVER,0, "", 1092 0x68, Iwd,0, "PUSH%S %i", 1093 0x69, RM,Iwd, "IMUL%S %e,%i,%r", 1094 0x6a, Ib,0, "PUSH%S %i", 1095 0x6b, RM,Ibs, "IMUL%S %e,%i,%r", 1096 0x6c, 0,0, "INSB DX,(%ODI)", 1097 0x6d, 0,0, "INS%S DX,(%ODI)", 1098 0x6e, 0,0, "OUTSB (%ASI),DX", 1099 0x6f, 0,0, "OUTS%S (%ASI),DX", 1100 0x70, Jbs,0, "JOS %p", 1101 0x71, Jbs,0, "JOC %p", 1102 0x72, Jbs,0, "JCS %p", 1103 0x73, Jbs,0, "JCC %p", 1104 0x74, Jbs,0, "JEQ %p", 1105 0x75, Jbs,0, "JNE %p", 1106 0x76, Jbs,0, "JLS %p", 1107 0x77, Jbs,0, "JHI %p", 1108 0x78, Jbs,0, "JMI %p", 1109 0x79, Jbs,0, "JPL %p", 1110 0x7a, Jbs,0, "JPS %p", 1111 0x7b, Jbs,0, "JPC %p", 1112 0x7c, Jbs,0, "JLT %p", 1113 0x7d, Jbs,0, "JGE %p", 1114 0x7e, Jbs,0, "JLE %p", 1115 0x7f, Jbs,0, "JGT %p", 1116 0x80, RMOPB,0, optab80, 1117 0x81, RMOP,0, optab81, 1118 0x83, RMOP,0, optab83, 1119 0x84, RMB,0, "TESTB %r,%e", 1120 0x85, RM,0, "TEST%S %r,%e", 1121 0x86, RMB,0, "XCHGB %r,%e", 1122 0x87, RM,0, "XCHG%S %r,%e", 1123 0x88, RMB,0, "MOVB %r,%e", 1124 0x89, RM,0, "MOV%S %r,%e", 1125 0x8a, RMB,0, "MOVB %e,%r", 1126 0x8b, RM,0, "MOV%S %e,%r", 1127 0x8c, RM,0, "MOVW %g,%e", 1128 0x8d, RM,0, "LEA%S %e,%r", 1129 0x8e, RM,0, "MOVW %e,%g", 1130 0x8f, RM,0, "POP%S %e", 1131 0x90, 0,0, "NOP", 1132 0x91, 0,0, "XCHG %OCX,%OAX", 1133 0x92, 0,0, "XCHG %ODX,%OAX", 1134 0x93, 0,0, "XCHG %OBX,%OAX", 1135 0x94, 0,0, "XCHG %OSP,%OAX", 1136 0x95, 0,0, "XCHG %OBP,%OAX", 1137 0x96, 0,0, "XCHG %OSI,%OAX", 1138 0x97, 0,0, "XCHG %ODI,%OAX", 1139 0x98, 0,0, "%W", /* miserable CBW or CWDE */ 1140 0x99, 0,0, "%w", /* idiotic CWD or CDQ */ 1141 0x9a, PTR,0, "CALL%S %d", 1142 0x9b, 0,0, "WAIT", 1143 0x9c, 0,0, "PUSHF", 1144 0x9d, 0,0, "POPF", 1145 0x9e, 0,0, "SAHF", 1146 0x9f, 0,0, "LAHF", 1147 0xa0, Awd,0, "MOVB %i,AL", 1148 0xa1, Awd,0, "MOV%S %i,%OAX", 1149 0xa2, Awd,0, "MOVB AL,%i", 1150 0xa3, Awd,0, "MOV%S %OAX,%i", 1151 0xa4, 0,0, "MOVSB (%ASI),(%ADI)", 1152 0xa5, 0,0, "MOVS%S (%ASI),(%ADI)", 1153 0xa6, 0,0, "CMPSB (%ASI),(%ADI)", 1154 0xa7, 0,0, "CMPS%S (%ASI),(%ADI)", 1155 0xa8, Ib,0, "TESTB %i,AL", 1156 0xa9, Iwd,0, "TEST%S %i,%OAX", 1157 0xaa, 0,0, "STOSB AL,(%ADI)", 1158 0xab, 0,0, "STOS%S %OAX,(%ADI)", 1159 0xac, 0,0, "LODSB (%ASI),AL", 1160 0xad, 0,0, "LODS%S (%ASI),%OAX", 1161 0xae, 0,0, "SCASB (%ADI),AL", 1162 0xaf, 0,0, "SCAS%S (%ADI),%OAX", 1163 0xb0, Ib,0, "MOVB %i,AL", 1164 0xb1, Ib,0, "MOVB %i,CL", 1165 0xb2, Ib,0, "MOVB %i,DL", 1166 0xb3, Ib,0, "MOVB %i,BL", 1167 0xb4, Ib,0, "MOVB %i,AH", 1168 0xb5, Ib,0, "MOVB %i,CH", 1169 0xb6, Ib,0, "MOVB %i,DH", 1170 0xb7, Ib,0, "MOVB %i,BH", 1171 0xb8, Iwdq,0, "MOV%S %i,%OAX", 1172 0xb9, Iwdq,0, "MOV%S %i,%OCX", 1173 0xba, Iwdq,0, "MOV%S %i,%ODX", 1174 0xbb, Iwdq,0, "MOV%S %i,%OBX", 1175 0xbc, Iwdq,0, "MOV%S %i,%OSP", 1176 0xbd, Iwdq,0, "MOV%S %i,%OBP", 1177 0xbe, Iwdq,0, "MOV%S %i,%OSI", 1178 0xbf, Iwdq,0, "MOV%S %i,%ODI", 1179 0xc0, RMOPB,0, optabC0, 1180 0xc1, RMOP,0, optabC1, 1181 0xc2, Iw,0, "RET %i", 1182 0xc3, RET,0, "RET", 1183 0xc4, RM,0, "LES %e,%r", 1184 0xc5, RM,0, "LDS %e,%r", 1185 0xc6, RMB,Ib, "MOVB %i,%e", 1186 0xc7, RM,Iwd, "MOV%S %i,%e", 1187 0xc8, Iw2,Ib, "ENTER %i,%I", /* loony ENTER */ 1188 0xc9, RET,0, "LEAVE", /* bizarre LEAVE */ 1189 0xca, Iw,0, "RETF %i", 1190 0xcb, RET,0, "RETF", 1191 0xcc, 0,0, "INT 3", 1192 0xcd, Ib,0, "INTB %i", 1193 0xce, 0,0, "INTO", 1194 0xcf, 0,0, "IRET", 1195 0xd0, RMOPB,0, optabD0, 1196 0xd1, RMOP,0, optabD1, 1197 0xd2, RMOPB,0, optabD2, 1198 0xd3, RMOP,0, optabD3, 1199 0xd4, OA,0, "AAM", 1200 0xd5, OA,0, "AAD", 1201 0xd7, 0,0, "XLAT", 1202 0xd8, FRMOP,0, optabD8, 1203 0xd9, FRMEX,0, optabD9, 1204 0xda, FRMOP,0, optabDA, 1205 0xdb, FRMEX,0, optabDB, 1206 0xdc, FRMOP,0, optabDC, 1207 0xdd, FRMOP,0, optabDD, 1208 0xde, FRMOP,0, optabDE, 1209 0xdf, FRMOP,0, optabDF, 1210 0xe0, Jbs,0, "LOOPNE %p", 1211 0xe1, Jbs,0, "LOOPE %p", 1212 0xe2, Jbs,0, "LOOP %p", 1213 0xe3, Jbs,0, "JCXZ %p", 1214 0xe4, Ib,0, "INB %i,AL", 1215 0xe5, Ib,0, "IN%S %i,%OAX", 1216 0xe6, Ib,0, "OUTB AL,%i", 1217 0xe7, Ib,0, "OUT%S %OAX,%i", 1218 0xe8, Iwds,0, "CALL %p", 1219 0xe9, Iwds,0, "JMP %p", 1220 0xea, PTR,0, "JMP %d", 1221 0xeb, Jbs,0, "JMP %p", 1222 0xec, 0,0, "INB DX,AL", 1223 0xed, 0,0, "IN%S DX,%OAX", 1224 0xee, 0,0, "OUTB AL,DX", 1225 0xef, 0,0, "OUT%S %OAX,DX", 1226 0xf0, PRE,0, "LOCK", 1227 0xf2, OPRE,0, "REPNE", 1228 0xf3, OPRE,0, "REP", 1229 0xf4, 0,0, "HLT", 1230 0xf5, 0,0, "CMC", 1231 0xf6, RMOPB,0, optabF6, 1232 0xf7, RMOP,0, optabF7, 1233 0xf8, 0,0, "CLC", 1234 0xf9, 0,0, "STC", 1235 0xfa, 0,0, "CLI", 1236 0xfb, 0,0, "STI", 1237 0xfc, 0,0, "CLD", 1238 0xfd, 0,0, "STD", 1239 0xfe, RMOPB,0, optabFE, 1240 0xff, RMOP,0, optabFF, 1241 0x100, RM,0, "MOVLQSX %r,%e", 1242 }; 1243 1244 static struct { 1245 Optable *tab; 1246 uint nel; 1247 } optabtab[] = { 1248 optab0F00, nelem(optab0F00), 1249 optab0F01, nelem(optab0F01), 1250 optab0F01F8, nelem(optab0F01F8), 1251 optab0FAE, nelem(optab0FAE), 1252 optab0FBA, nelem(optab0FBA), 1253 optab0F0F, nelem(optab0F0F), 1254 optab0FC7, nelem(optab0FC7), 1255 optab660F71, nelem(optab660F71), 1256 optab660F72, nelem(optab660F72), 1257 optab660F73, nelem(optab660F73), 1258 optab660F, nelem(optab660F), 1259 optabF20F, nelem(optabF20F), 1260 optabF30F, nelem(optabF30F), 1261 optab0F, nelem(optab0F), 1262 optab80, nelem(optab80), 1263 optab81, nelem(optab81), 1264 optab83, nelem(optab83), 1265 optabC0, nelem(optabC0), 1266 optabC1, nelem(optabC1), 1267 optabD0, nelem(optabD0), 1268 optabD1, nelem(optabD1), 1269 optabD2, nelem(optabD2), 1270 optabD3, nelem(optabD3), 1271 optabD8, nelem(optabD8), 1272 optabD9, nelem(optabD9), 1273 optabDA, nelem(optabDA), 1274 optabDB, nelem(optabDB), 1275 optabDC, nelem(optabDC), 1276 optabDD, nelem(optabDD), 1277 optabDE, nelem(optabDE), 1278 optabDF, nelem(optabDF), 1279 optabF6, nelem(optabF6), 1280 optabF7, nelem(optabF7), 1281 optabFE, nelem(optabFE), 1282 optabFF, nelem(optabFF), 1283 optable, nelem(optable), 1284 }; 1285 1286 /* 1287 * compensate for Microsoft's ageing compilers 1288 */ 1289 static void 1290 ordertab(Optable *tab, int nel) 1291 { 1292 int i, x; 1293 static Optable empty; 1294 1295 for(i = nel; --i >= 0;){ 1296 x = tab[i].x; 1297 if(x != i){ 1298 tab[x] = tab[i]; 1299 tab[i] = empty; 1300 } 1301 } 1302 } 1303 1304 static void 1305 soptoms(void) 1306 { 1307 int i; 1308 static int reordered; /* assumes non-concurrent use */ 1309 1310 if(reordered) 1311 return; 1312 reordered = 1; 1313 for(i = 0; i < nelem(optabtab); i++) 1314 ordertab(optabtab[i].tab, optabtab[i].nel); 1315 } 1316 1317 /* 1318 * get a byte of the instruction 1319 */ 1320 static int 1321 igetc(Map *map, Instr *ip, uchar *c) 1322 { 1323 if(ip->n+1 > sizeof(ip->mem)){ 1324 werrstr("instruction too long"); 1325 return -1; 1326 } 1327 if (get1(map, ip->addr+ip->n, c, 1) < 0) { 1328 werrstr("can't read instruction: %r"); 1329 return -1; 1330 } 1331 ip->mem[ip->n++] = *c; 1332 return 1; 1333 } 1334 1335 /* 1336 * get two bytes of the instruction 1337 */ 1338 static int 1339 igets(Map *map, Instr *ip, ushort *sp) 1340 { 1341 uchar c; 1342 ushort s; 1343 1344 if (igetc(map, ip, &c) < 0) 1345 return -1; 1346 s = c; 1347 if (igetc(map, ip, &c) < 0) 1348 return -1; 1349 s |= (c<<8); 1350 *sp = s; 1351 return 1; 1352 } 1353 1354 /* 1355 * get 4 bytes of the instruction 1356 */ 1357 static int 1358 igetl(Map *map, Instr *ip, ulong *lp) 1359 { 1360 ushort s; 1361 long l; 1362 1363 if (igets(map, ip, &s) < 0) 1364 return -1; 1365 l = s; 1366 if (igets(map, ip, &s) < 0) 1367 return -1; 1368 l |= (s<<16); 1369 *lp = l; 1370 return 1; 1371 } 1372 1373 /* 1374 * get 8 bytes of the instruction 1375 */ 1376 static int 1377 igetq(Map *map, Instr *ip, vlong *qp) 1378 { 1379 ulong l; 1380 uvlong q; 1381 1382 if (igetl(map, ip, &l) < 0) 1383 return -1; 1384 q = l; 1385 if (igetl(map, ip, &l) < 0) 1386 return -1; 1387 q |= ((uvlong)l<<32); 1388 *qp = q; 1389 return 1; 1390 } 1391 1392 static int 1393 getdisp(Map *map, Instr *ip, int mod, int rm, int code, int pcrel) 1394 { 1395 uchar c; 1396 ushort s; 1397 1398 if (mod > 2) 1399 return 1; 1400 if (mod == 1) { 1401 if (igetc(map, ip, &c) < 0) 1402 return -1; 1403 if (c&0x80) 1404 ip->disp = c|0xffffff00; 1405 else 1406 ip->disp = c&0xff; 1407 } else if (mod == 2 || rm == code) { 1408 if (ip->asize == 'E') { 1409 if (igetl(map, ip, &ip->disp) < 0) 1410 return -1; 1411 if (mod == 0) 1412 ip->rip = pcrel; 1413 } else { 1414 if (igets(map, ip, &s) < 0) 1415 return -1; 1416 if (s&0x8000) 1417 ip->disp = s|0xffff0000; 1418 else 1419 ip->disp = s; 1420 } 1421 if (mod == 0) 1422 ip->base = -1; 1423 } 1424 return 1; 1425 } 1426 1427 static int 1428 modrm(Map *map, Instr *ip, uchar c) 1429 { 1430 uchar rm, mod; 1431 1432 mod = (c>>6)&3; 1433 rm = c&7; 1434 ip->mod = mod; 1435 ip->base = rm; 1436 ip->reg = (c>>3)&7; 1437 ip->rip = 0; 1438 if (mod == 3) /* register */ 1439 return 1; 1440 if (ip->asize == 0) { /* 16-bit mode */ 1441 switch(rm) { 1442 case 0: 1443 ip->base = BX; ip->index = SI; 1444 break; 1445 case 1: 1446 ip->base = BX; ip->index = DI; 1447 break; 1448 case 2: 1449 ip->base = BP; ip->index = SI; 1450 break; 1451 case 3: 1452 ip->base = BP; ip->index = DI; 1453 break; 1454 case 4: 1455 ip->base = SI; 1456 break; 1457 case 5: 1458 ip->base = DI; 1459 break; 1460 case 6: 1461 ip->base = BP; 1462 break; 1463 case 7: 1464 ip->base = BX; 1465 break; 1466 default: 1467 break; 1468 } 1469 return getdisp(map, ip, mod, rm, 6, 0); 1470 } 1471 if (rm == 4) { /* scummy sib byte */ 1472 if (igetc(map, ip, &c) < 0) 1473 return -1; 1474 ip->ss = (c>>6)&0x03; 1475 ip->index = (c>>3)&0x07; 1476 if (ip->index == 4) 1477 ip->index = -1; 1478 ip->base = c&0x07; 1479 return getdisp(map, ip, mod, ip->base, 5, 0); 1480 } 1481 return getdisp(map, ip, mod, rm, 5, ip->amd64); 1482 } 1483 1484 static Optable * 1485 mkinstr(Map *map, Instr *ip, uvlong pc) 1486 { 1487 int i, n, norex; 1488 uchar c; 1489 ushort s; 1490 Optable *op, *obase; 1491 char buf[128]; 1492 1493 soptoms(); 1494 memset(ip, 0, sizeof(*ip)); 1495 norex = 1; 1496 ip->base = -1; 1497 ip->index = -1; 1498 if(asstype == AI8086) 1499 ip->osize = 'W'; 1500 else { 1501 ip->osize = 'L'; 1502 ip->asize = 'E'; 1503 ip->amd64 = asstype != AI386; 1504 norex = 0; 1505 } 1506 ip->addr = pc; 1507 if (igetc(map, ip, &c) < 0) 1508 return 0; 1509 obase = optable; 1510 newop: 1511 if(ip->amd64 && !norex){ 1512 if(c >= 0x40 && c <= 0x4f) { 1513 ip->rex = c; 1514 if(igetc(map, ip, &c) < 0) 1515 return 0; 1516 } 1517 if(c == 0x63){ 1518 op = &obase[0x100]; /* MOVLQSX */ 1519 goto hack; 1520 } 1521 } 1522 op = &obase[c]; 1523 hack: 1524 if (op->proto == 0) { 1525 badop: 1526 n = snprint(buf, sizeof(buf), "opcode: ??"); 1527 for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2) 1528 _hexify(buf+n, ip->mem[i], 1); 1529 strcpy(buf+n, "??"); 1530 werrstr(buf); 1531 return 0; 1532 } 1533 for(i = 0; i < 2 && op->operand[i]; i++) { 1534 switch(op->operand[i]) { 1535 case Ib: /* 8-bit immediate - (no sign extension)*/ 1536 if (igetc(map, ip, &c) < 0) 1537 return 0; 1538 ip->imm = c&0xff; 1539 ip->imm64 = ip->imm; 1540 break; 1541 case Jbs: /* 8-bit jump immediate (sign extended) */ 1542 if (igetc(map, ip, &c) < 0) 1543 return 0; 1544 if (c&0x80) 1545 ip->imm = c|0xffffff00; 1546 else 1547 ip->imm = c&0xff; 1548 ip->imm64 = (long)ip->imm; 1549 ip->jumptype = Jbs; 1550 break; 1551 case Ibs: /* 8-bit immediate (sign extended) */ 1552 if (igetc(map, ip, &c) < 0) 1553 return 0; 1554 if (c&0x80) 1555 if (ip->osize == 'L') 1556 ip->imm = c|0xffffff00; 1557 else 1558 ip->imm = c|0xff00; 1559 else 1560 ip->imm = c&0xff; 1561 ip->imm64 = (long)ip->imm; 1562 break; 1563 case Iw: /* 16-bit immediate -> imm */ 1564 if (igets(map, ip, &s) < 0) 1565 return 0; 1566 ip->imm = s&0xffff; 1567 ip->imm64 = ip->imm; 1568 ip->jumptype = Iw; 1569 break; 1570 case Iw2: /* 16-bit immediate -> in imm2*/ 1571 if (igets(map, ip, &s) < 0) 1572 return 0; 1573 ip->imm2 = s&0xffff; 1574 break; 1575 case Iwd: /* Operand-sized immediate (no sign extension unless 64 bits)*/ 1576 if (ip->osize == 'L') { 1577 if (igetl(map, ip, &ip->imm) < 0) 1578 return 0; 1579 ip->imm64 = ip->imm; 1580 if(ip->rex&REXW && (ip->imm & (1<<31)) != 0) 1581 ip->imm64 |= (vlong)~0 << 32; 1582 } else { 1583 if (igets(map, ip, &s)< 0) 1584 return 0; 1585 ip->imm = s&0xffff; 1586 ip->imm64 = ip->imm; 1587 } 1588 break; 1589 case Iwdq: /* Operand-sized immediate, possibly big */ 1590 if (ip->osize == 'L') { 1591 if (igetl(map, ip, &ip->imm) < 0) 1592 return 0; 1593 ip->imm64 = ip->imm; 1594 if (ip->rex & REXW) { 1595 ulong l; 1596 if (igetl(map, ip, &l) < 0) 1597 return 0; 1598 ip->imm64 |= (uvlong)l << 32; 1599 } 1600 } else { 1601 if (igets(map, ip, &s)< 0) 1602 return 0; 1603 ip->imm = s&0xffff; 1604 } 1605 break; 1606 case Awd: /* Address-sized immediate (no sign extension)*/ 1607 if (ip->asize == 'E') { 1608 if (igetl(map, ip, &ip->imm) < 0) 1609 return 0; 1610 /* TO DO: REX */ 1611 } else { 1612 if (igets(map, ip, &s)< 0) 1613 return 0; 1614 ip->imm = s&0xffff; 1615 } 1616 break; 1617 case Iwds: /* Operand-sized immediate (sign extended) */ 1618 if (ip->osize == 'L') { 1619 if (igetl(map, ip, &ip->imm) < 0) 1620 return 0; 1621 } else { 1622 if (igets(map, ip, &s)< 0) 1623 return 0; 1624 if (s&0x8000) 1625 ip->imm = s|0xffff0000; 1626 else 1627 ip->imm = s&0xffff; 1628 } 1629 ip->jumptype = Iwds; 1630 break; 1631 case OA: /* literal 0x0a byte */ 1632 if (igetc(map, ip, &c) < 0) 1633 return 0; 1634 if (c != 0x0a) 1635 goto badop; 1636 break; 1637 case R0: /* base register must be R0 */ 1638 if (ip->base != 0) 1639 goto badop; 1640 break; 1641 case R1: /* base register must be R1 */ 1642 if (ip->base != 1) 1643 goto badop; 1644 break; 1645 case RMB: /* R/M field with byte register (/r)*/ 1646 if (igetc(map, ip, &c) < 0) 1647 return 0; 1648 if (modrm(map, ip, c) < 0) 1649 return 0; 1650 ip->osize = 'B'; 1651 break; 1652 case RM: /* R/M field with register (/r) */ 1653 if (igetc(map, ip, &c) < 0) 1654 return 0; 1655 if (modrm(map, ip, c) < 0) 1656 return 0; 1657 break; 1658 case RMOPB: /* R/M field with op code (/digit) */ 1659 if (igetc(map, ip, &c) < 0) 1660 return 0; 1661 if (modrm(map, ip, c) < 0) 1662 return 0; 1663 c = ip->reg; /* secondary op code */ 1664 obase = (Optable*)op->proto; 1665 ip->osize = 'B'; 1666 goto newop; 1667 case RMOP: /* R/M field with op code (/digit) */ 1668 if (igetc(map, ip, &c) < 0) 1669 return 0; 1670 if (modrm(map, ip, c) < 0) 1671 return 0; 1672 obase = (Optable*)op->proto; 1673 if(ip->amd64 && obase == optab0F01 && c == 0xF8) 1674 return optab0F01F8; 1675 c = ip->reg; 1676 goto newop; 1677 case FRMOP: /* FP R/M field with op code (/digit) */ 1678 if (igetc(map, ip, &c) < 0) 1679 return 0; 1680 if (modrm(map, ip, c) < 0) 1681 return 0; 1682 if ((c&0xc0) == 0xc0) 1683 c = ip->reg+8; /* 16 entry table */ 1684 else 1685 c = ip->reg; 1686 obase = (Optable*)op->proto; 1687 goto newop; 1688 case FRMEX: /* Extended FP R/M field with op code (/digit) */ 1689 if (igetc(map, ip, &c) < 0) 1690 return 0; 1691 if (modrm(map, ip, c) < 0) 1692 return 0; 1693 if ((c&0xc0) == 0xc0) 1694 c = (c&0x3f)+8; /* 64-entry table */ 1695 else 1696 c = ip->reg; 1697 obase = (Optable*)op->proto; 1698 goto newop; 1699 case RMR: /* R/M register only (mod = 11) */ 1700 if (igetc(map, ip, &c) < 0) 1701 return 0; 1702 if ((c&0xc0) != 0xc0) { 1703 werrstr("invalid R/M register: %x", c); 1704 return 0; 1705 } 1706 if (modrm(map, ip, c) < 0) 1707 return 0; 1708 break; 1709 case RMM: /* R/M register only (mod = 11) */ 1710 if (igetc(map, ip, &c) < 0) 1711 return 0; 1712 if ((c&0xc0) == 0xc0) { 1713 werrstr("invalid R/M memory mode: %x", c); 1714 return 0; 1715 } 1716 if (modrm(map, ip, c) < 0) 1717 return 0; 1718 break; 1719 case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */ 1720 if (ip->osize == 'L') { 1721 if (igetl(map, ip, &ip->disp) < 0) 1722 return 0; 1723 } else { 1724 if (igets(map, ip, &s)< 0) 1725 return 0; 1726 ip->disp = s&0xffff; 1727 } 1728 if (igets(map, ip, (ushort*)&ip->seg) < 0) 1729 return 0; 1730 ip->jumptype = PTR; 1731 break; 1732 case AUXMM: /* Multi-byte op code; prefix determines table selection */ 1733 if (igetc(map, ip, &c) < 0) 1734 return 0; 1735 obase = (Optable*)op->proto; 1736 switch (ip->opre) { 1737 case 0x66: op = optab660F; break; 1738 case 0xF2: op = optabF20F; break; 1739 case 0xF3: op = optabF30F; break; 1740 default: op = nil; break; 1741 } 1742 if(op != nil && op[c].proto != nil) 1743 obase = op; 1744 norex = 1; /* no more rex prefixes */ 1745 /* otherwise the optab entry captures it */ 1746 goto newop; 1747 case AUX: /* Multi-byte op code - Auxiliary table */ 1748 obase = (Optable*)op->proto; 1749 if (igetc(map, ip, &c) < 0) 1750 return 0; 1751 goto newop; 1752 case OPRE: /* Instr Prefix or media op */ 1753 ip->opre = c; 1754 /* fall through */ 1755 case PRE: /* Instr Prefix */ 1756 ip->prefix = (char*)op->proto; 1757 if (igetc(map, ip, &c) < 0) 1758 return 0; 1759 if (ip->opre && c == 0x0F) 1760 ip->prefix = 0; 1761 goto newop; 1762 case SEG: /* Segment Prefix */ 1763 ip->segment = (char*)op->proto; 1764 if (igetc(map, ip, &c) < 0) 1765 return 0; 1766 goto newop; 1767 case OPOVER: /* Operand size override */ 1768 ip->opre = c; 1769 ip->osize = 'W'; 1770 if (igetc(map, ip, &c) < 0) 1771 return 0; 1772 if (c == 0x0F) 1773 ip->osize = 'L'; 1774 else if (ip->amd64 && (c&0xF0) == 0x40) 1775 ip->osize = 'Q'; 1776 goto newop; 1777 case ADDOVER: /* Address size override */ 1778 ip->asize = 0; 1779 if (igetc(map, ip, &c) < 0) 1780 return 0; 1781 goto newop; 1782 case JUMP: /* mark instruction as JUMP or RET */ 1783 case RET: 1784 ip->jumptype = op->operand[i]; 1785 break; 1786 default: 1787 werrstr("bad operand type %d", op->operand[i]); 1788 return 0; 1789 } 1790 } 1791 return op; 1792 } 1793 1794 #pragma varargck argpos bprint 2 1795 1796 static void 1797 bprint(Instr *ip, char *fmt, ...) 1798 { 1799 va_list arg; 1800 1801 va_start(arg, fmt); 1802 ip->curr = vseprint(ip->curr, ip->end, fmt, arg); 1803 va_end(arg); 1804 } 1805 1806 /* 1807 * if we want to call 16 bit regs AX,BX,CX,... 1808 * and 32 bit regs EAX,EBX,ECX,... then 1809 * change the defs of ANAME and ONAME to: 1810 * #define ANAME(ip) ((ip->asize == 'E' ? "E" : "") 1811 * #define ONAME(ip) ((ip)->osize == 'L' ? "E" : "") 1812 */ 1813 #define ANAME(ip) "" 1814 #define ONAME(ip) "" 1815 1816 static char *reg[] = { 1817 "AX", 1818 "CX", 1819 "DX", 1820 "BX", 1821 "SP", 1822 "BP", 1823 "SI", 1824 "DI", 1825 1826 /* amd64 */ 1827 "R8", 1828 "R9", 1829 "R10", 1830 "R11", 1831 "R12", 1832 "R13", 1833 "R14", 1834 "R15", 1835 }; 1836 1837 static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" }; 1838 static char *breg64[] = { "AL", "CL", "DL", "BL", "SPB", "BPB", "SIB", "DIB", 1839 "R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B" }; 1840 static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" }; 1841 1842 static void 1843 plocal(Instr *ip) 1844 { 1845 int ret; 1846 long offset; 1847 Symbol s; 1848 char *reg; 1849 1850 offset = ip->disp; 1851 if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) { 1852 bprint(ip, "%lux(SP)", offset); 1853 return; 1854 } 1855 1856 if (s.value > ip->disp) { 1857 ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s); 1858 reg = "(SP)"; 1859 } else { 1860 offset -= s.value; 1861 ret = getauto(&s, offset, CPARAM, &s); 1862 reg = "(FP)"; 1863 } 1864 if (ret) 1865 bprint(ip, "%s+", s.name); 1866 else 1867 offset = ip->disp; 1868 bprint(ip, "%lux%s", offset, reg); 1869 } 1870 1871 static int 1872 isjmp(Instr *ip) 1873 { 1874 switch(ip->jumptype){ 1875 case Iwds: 1876 case Jbs: 1877 case JUMP: 1878 return 1; 1879 default: 1880 return 0; 1881 } 1882 } 1883 1884 /* 1885 * This is too smart for its own good, but it really is nice 1886 * to have accurate translations when debugging, and it 1887 * helps us identify which code is different in binaries that 1888 * are changed on sources. 1889 */ 1890 static int 1891 issymref(Instr *ip, Symbol *s, long w, long val) 1892 { 1893 Symbol next, tmp; 1894 long isstring, size; 1895 1896 if (isjmp(ip)) 1897 return 1; 1898 if (s->class==CTEXT && w==0) 1899 return 1; 1900 if (s->class==CDATA) { 1901 /* use first bss symbol (or "end") rather than edata */ 1902 if (s->name[0]=='e' && strcmp(s->name, "edata") == 0){ 1903 if((s ->index >= 0 && globalsym(&tmp, s->index+1) && tmp.value==s->value) 1904 || (s->index > 0 && globalsym(&tmp, s->index-1) && tmp.value==s->value)) 1905 *s = tmp; 1906 } 1907 if (w == 0) 1908 return 1; 1909 for (next=*s; next.value==s->value; next=tmp) 1910 if (!globalsym(&tmp, next.index+1)) 1911 break; 1912 size = next.value - s->value; 1913 if (w >= size) 1914 return 0; 1915 if (w > size-w) 1916 w = size-w; 1917 /* huge distances are usually wrong except in .string */ 1918 isstring = (s->name[0]=='.' && strcmp(s->name, ".string") == 0); 1919 if (w > 8192 && !isstring) 1920 return 0; 1921 /* medium distances are tricky - look for constants */ 1922 /* near powers of two */ 1923 if ((val&(val-1)) == 0 || (val&(val+1)) == 0) 1924 return 0; 1925 return 1; 1926 } 1927 return 0; 1928 } 1929 1930 static void 1931 immediate(Instr *ip, vlong val) 1932 { 1933 Symbol s; 1934 long w; 1935 1936 if (findsym(val, CANY, &s)) { /* TO DO */ 1937 w = val - s.value; 1938 if (w < 0) 1939 w = -w; 1940 if (issymref(ip, &s, w, val)) { 1941 if (w) 1942 bprint(ip, "%s+%lux(SB)", s.name, w); 1943 else 1944 bprint(ip, "%s(SB)", s.name); 1945 return; 1946 } 1947 /* 1948 if (s.class==CDATA && globalsym(&s, s.index+1)) { 1949 w = s.value - val; 1950 if (w < 0) 1951 w = -w; 1952 if (w < 4096) { 1953 bprint(ip, "%s-%lux(SB)", s.name, w); 1954 return; 1955 } 1956 } 1957 */ 1958 } 1959 if((ip->rex & REXW) == 0) 1960 bprint(ip, "%lux", (long)val); 1961 else 1962 bprint(ip, "%llux", val); 1963 } 1964 1965 static void 1966 pea(Instr *ip) 1967 { 1968 if (ip->mod == 3) { 1969 if (ip->osize == 'B') 1970 bprint(ip, (ip->rex & REXB? breg64: breg)[ip->base]); 1971 else if(ip->rex & REXB) 1972 bprint(ip, "%s%s", ANAME(ip), reg[ip->base+8]); 1973 else 1974 bprint(ip, "%s%s", ANAME(ip), reg[ip->base]); 1975 return; 1976 } 1977 if (ip->segment) 1978 bprint(ip, ip->segment); 1979 if (ip->asize == 'E' && ip->base == SP) 1980 plocal(ip); 1981 else { 1982 if (ip->base < 0) 1983 immediate(ip, ip->disp); 1984 else { 1985 bprint(ip, "%lux", ip->disp); 1986 if(ip->rip) 1987 bprint(ip, "(RIP)"); 1988 bprint(ip,"(%s%s)", ANAME(ip), reg[ip->rex&REXB? ip->base+8: ip->base]); 1989 } 1990 } 1991 if (ip->index >= 0) 1992 bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->rex&REXX? ip->index+8: ip->index], 1<<ip->ss); 1993 } 1994 1995 static void 1996 prinstr(Instr *ip, char *fmt) 1997 { 1998 vlong v; 1999 2000 if (ip->prefix) 2001 bprint(ip, "%s ", ip->prefix); 2002 for (; *fmt && ip->curr < ip->end; fmt++) { 2003 if (*fmt != '%'){ 2004 *ip->curr++ = *fmt; 2005 continue; 2006 } 2007 switch(*++fmt){ 2008 case '%': 2009 *ip->curr++ = '%'; 2010 break; 2011 case 'A': 2012 bprint(ip, "%s", ANAME(ip)); 2013 break; 2014 case 'C': 2015 bprint(ip, "CR%d", ip->reg); 2016 break; 2017 case 'D': 2018 if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7) 2019 bprint(ip, "DR%d",ip->reg); 2020 else 2021 bprint(ip, "?"); 2022 break; 2023 case 'I': 2024 bprint(ip, "$"); 2025 immediate(ip, ip->imm2); 2026 break; 2027 case 'O': 2028 bprint(ip,"%s", ONAME(ip)); 2029 break; 2030 case 'i': 2031 bprint(ip, "$"); 2032 v = ip->imm; 2033 if(ip->rex & REXW) 2034 v = ip->imm64; 2035 immediate(ip, v); 2036 break; 2037 case 'R': 2038 bprint(ip, "%s%s", ONAME(ip), reg[ip->rex&REXR? ip->reg+8: ip->reg]); 2039 break; 2040 case 'S': 2041 if(ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW) 2042 bprint(ip, "Q"); 2043 else 2044 bprint(ip, "%c", ip->osize); 2045 break; 2046 case 's': 2047 if(ip->opre == 0 || ip->opre == 0x66) 2048 bprint(ip, "P"); 2049 else 2050 bprint(ip, "S"); 2051 if(ip->opre == 0xf2 || ip->opre == 0x66) 2052 bprint(ip, "D"); 2053 else 2054 bprint(ip, "S"); 2055 break; 2056 case 'T': 2057 if (ip->reg == 6 || ip->reg == 7) 2058 bprint(ip, "TR%d",ip->reg); 2059 else 2060 bprint(ip, "?"); 2061 break; 2062 case 'W': 2063 if (ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW) 2064 bprint(ip, "CDQE"); 2065 else if (ip->osize == 'L') 2066 bprint(ip,"CWDE"); 2067 else 2068 bprint(ip, "CBW"); 2069 break; 2070 case 'd': 2071 bprint(ip,"%ux:%lux",ip->seg,ip->disp); 2072 break; 2073 case 'm': 2074 if (ip->mod == 3 && ip->osize != 'B') { 2075 if(fmt[1] != '*'){ 2076 if(ip->opre != 0) { 2077 bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base); 2078 break; 2079 } 2080 } else 2081 fmt++; 2082 bprint(ip, "M%d", ip->base); 2083 break; 2084 } 2085 pea(ip); 2086 break; 2087 case 'e': 2088 pea(ip); 2089 break; 2090 case 'f': 2091 bprint(ip, "F%d", ip->base); 2092 break; 2093 case 'g': 2094 if (ip->reg < 6) 2095 bprint(ip,"%s",sreg[ip->reg]); 2096 else 2097 bprint(ip,"?"); 2098 break; 2099 case 'p': 2100 /* 2101 * signed immediate in the ulong ip->imm. 2102 */ 2103 v = (long)ip->imm; 2104 immediate(ip, v+ip->addr+ip->n); 2105 break; 2106 case 'r': 2107 if (ip->osize == 'B') 2108 bprint(ip,"%s", (ip->rex? breg64: breg)[ip->rex&REXR? ip->reg+8: ip->reg]); 2109 else 2110 bprint(ip, reg[ip->rex&REXR? ip->reg+8: ip->reg]); 2111 break; 2112 case 'w': 2113 if (ip->osize == 'Q' || ip->rex & REXW) 2114 bprint(ip, "CQO"); 2115 else if (ip->osize == 'L') 2116 bprint(ip,"CDQ"); 2117 else 2118 bprint(ip, "CWD"); 2119 break; 2120 case 'M': 2121 if(ip->opre != 0) 2122 bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg); 2123 else 2124 bprint(ip, "M%d", ip->reg); 2125 break; 2126 case 'x': 2127 if (ip->mod == 3 && ip->osize != 'B') { 2128 bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base); 2129 break; 2130 } 2131 pea(ip); 2132 break; 2133 case 'X': 2134 bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg); 2135 break; 2136 default: 2137 bprint(ip, "%%%c", *fmt); 2138 break; 2139 } 2140 } 2141 *ip->curr = 0; /* there's always room for 1 byte */ 2142 } 2143 2144 static int 2145 i386inst(Map *map, uvlong pc, char modifier, char *buf, int n) 2146 { 2147 Instr instr; 2148 Optable *op; 2149 2150 USED(modifier); 2151 op = mkinstr(map, &instr, pc); 2152 if (op == 0) { 2153 errstr(buf, n); 2154 return -1; 2155 } 2156 instr.curr = buf; 2157 instr.end = buf+n-1; 2158 prinstr(&instr, op->proto); 2159 return instr.n; 2160 } 2161 2162 static int 2163 i386das(Map *map, uvlong pc, char *buf, int n) 2164 { 2165 Instr instr; 2166 int i; 2167 2168 if (mkinstr(map, &instr, pc) == 0) { 2169 errstr(buf, n); 2170 return -1; 2171 } 2172 for(i = 0; i < instr.n && n > 2; i++) { 2173 _hexify(buf, instr.mem[i], 1); 2174 buf += 2; 2175 n -= 2; 2176 } 2177 *buf = 0; 2178 return instr.n; 2179 } 2180 2181 static int 2182 i386instlen(Map *map, uvlong pc) 2183 { 2184 Instr i; 2185 2186 if (mkinstr(map, &i, pc)) 2187 return i.n; 2188 return -1; 2189 } 2190 2191 static int 2192 i386foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll) 2193 { 2194 Instr i; 2195 Optable *op; 2196 ushort s; 2197 uvlong l, addr; 2198 vlong v; 2199 int n; 2200 2201 op = mkinstr(map, &i, pc); 2202 if (!op) 2203 return -1; 2204 2205 n = 0; 2206 2207 switch(i.jumptype) { 2208 case RET: /* RETURN or LEAVE */ 2209 case Iw: /* RETURN */ 2210 if (strcmp(op->proto, "LEAVE") == 0) { 2211 if (geta(map, (*rget)(map, "BP"), &l) < 0) 2212 return -1; 2213 } else if (geta(map, (*rget)(map, mach->sp), &l) < 0) 2214 return -1; 2215 foll[0] = l; 2216 return 1; 2217 case Iwds: /* pc relative JUMP or CALL*/ 2218 case Jbs: /* pc relative JUMP or CALL */ 2219 v = (long)i.imm; 2220 foll[0] = pc+v+i.n; 2221 n = 1; 2222 break; 2223 case PTR: /* seg:displacement JUMP or CALL */ 2224 foll[0] = (i.seg<<4)+i.disp; 2225 return 1; 2226 case JUMP: /* JUMP or CALL EA */ 2227 2228 if(i.mod == 3) { 2229 foll[0] = (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]); 2230 return 1; 2231 } 2232 /* calculate the effective address */ 2233 addr = i.disp; 2234 if (i.base >= 0) { 2235 if (geta(map, (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]), &l) < 0) 2236 return -1; 2237 addr += l; 2238 } 2239 if (i.index >= 0) { 2240 if (geta(map, (*rget)(map, reg[i.rex&REXX? i.index+8: i.index]), &l) < 0) 2241 return -1; 2242 addr += l*(1<<i.ss); 2243 } 2244 /* now retrieve a seg:disp value at that address */ 2245 if (get2(map, addr, &s) < 0) /* seg */ 2246 return -1; 2247 foll[0] = s<<4; 2248 addr += 2; 2249 if (i.asize == 'L') { 2250 if (geta(map, addr, &l) < 0) /* disp32 */ 2251 return -1; 2252 foll[0] += l; 2253 } else { /* disp16 */ 2254 if (get2(map, addr, &s) < 0) 2255 return -1; 2256 foll[0] += s; 2257 } 2258 return 1; 2259 default: 2260 break; 2261 } 2262 if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0) 2263 return 1; 2264 foll[n++] = pc+i.n; 2265 return n; 2266 } 2267