#include #include #include "mach.h" /* * i386-specific debugger interface * also amd64 extensions */ static char *i386excep(Map*, Rgetter); static int i386trace(Map*, uvlong, uvlong, uvlong, Tracer); static uvlong i386frame(Map*, uvlong, uvlong, uvlong, uvlong); static int i386foll(Map*, uvlong, Rgetter, uvlong*); static int i386inst(Map*, uvlong, char, char*, int); static int i386das(Map*, uvlong, char*, int); static int i386instlen(Map*, uvlong); static char STARTSYM[] = "_main"; static char PROFSYM[] = "_mainp"; static char FRAMENAME[] = ".frame"; static char *excname[65] = { /*[0]*/ "divide error", /*[1]*/ "debug exception", /*[2]*/ nil, /*[3]*/ nil, /*[4]*/ "overflow", /*[5]*/ "bounds check", /*[6]*/ "invalid opcode", /*[7]*/ "math coprocessor emulation", /*[8]*/ "double fault", /*[9]*/ "math coprocessor overrun", /*[10]*/ "invalid TSS", /*[11]*/ "segment not present", /*[12]*/ "stack exception", /*[13]*/ "general protection violation", /*[14]*/ "page fault", /*[15]*/ nil, /*[16]*/ "math coprocessor error", /*[17]*/ "alignment check", /*[18]*/ "machine check", /*[19]*/ "floating-point exception", /*[20]*/ nil, /*[21]*/ nil, /*[22]*/ nil, /*[23]*/ nil, /*[24]*/ "clock", /*[25]*/ "keyboard", /*[26]*/ nil, /*[27]*/ "modem status", /*[28]*/ "serial line status", /*[29]*/ nil, /*[30]*/ "floppy disk", /*[31]*/ nil, /*[32]*/ nil, /*[33]*/ nil, /*[34]*/ nil, /*[35]*/ nil, /*[36]*/ "mouse", /*[37]*/ "math coprocessor", /*[38]*/ "hard disk", 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 39-54 */ 0,0,0,0,0,0,0,0,0, /* 55-63 */ /*[64]*/ "system call", }; Machdata i386mach = { {0xCC, 0, 0, 0}, /* break point: INT 3 */ 1, /* break point size */ leswab, /* convert short to local byte order */ leswal, /* convert long to local byte order */ leswav, /* convert vlong to local byte order */ i386trace, /* C traceback */ i386frame, /* frame finder */ i386excep, /* print exception */ 0, /* breakpoint fixup */ leieeesftos, /* single precision float printer */ leieeedftos, /* double precision float printer */ i386foll, /* following addresses */ i386inst, /* print instruction */ i386das, /* dissembler */ i386instlen, /* instruction size calculation */ }; static char* i386excep(Map *map, Rgetter rget) { ulong c; uvlong pc; static char buf[16]; c = (*rget)(map, "TRAP"); if(c > 64 || excname[c] == 0) { if (c == 3) { pc = (*rget)(map, "PC"); if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0) if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0) return "breakpoint"; } snprint(buf, sizeof(buf), "exception %ld", c); return buf; } else return excname[c]; } static int i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace) { int i; uvlong osp; Symbol s, f; USED(link); i = 0; osp = 0; while(findsym(pc, CTEXT, &s)) { if (osp == sp) break; osp = sp; if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) break; if(pc != s.value) { /* not at first instruction */ if(findlocal(&s, FRAMENAME, &f) == 0) break; sp += f.value-mach->szaddr; } if (geta(map, sp, &pc) < 0) break; if(pc == 0) break; (*trace)(map, pc, sp, &s); sp += mach->szaddr; if(++i > 1000) break; } return i; } static uvlong i386frame(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link) { Symbol s, f; USED(link); while (findsym(pc, CTEXT, &s)) { if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0) break; if(pc != s.value) { /* not first instruction */ if(findlocal(&s, FRAMENAME, &f) == 0) break; sp += f.value-mach->szaddr; } if (s.value == addr) return sp; if (geta(map, sp, &pc) < 0) break; sp += mach->szaddr; } return 0; } /* I386/486 - Disassembler and related functions */ /* * an instruction */ typedef struct Instr Instr; struct Instr { uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */ uvlong addr; /* address of start of instruction */ int n; /* number of bytes in instruction */ char *prefix; /* instr prefix */ char *segment; /* segment override */ uchar jumptype; /* set to the operand type for jump/ret/call */ uchar amd64; uchar rex; /* REX prefix (or zero) */ char osize; /* 'W' or 'L' (or 'Q' on amd64) */ char asize; /* address size 'W' or 'L' (or 'Q' or amd64) */ uchar mod; /* bits 6-7 of mod r/m field */ uchar reg; /* bits 3-5 of mod r/m field */ char ss; /* bits 6-7 of SIB */ char index; /* bits 3-5 of SIB */ char base; /* bits 0-2 of SIB */ char rip; /* RIP-relative in amd64 mode */ uchar opre; /* f2/f3 could introduce media */ short seg; /* segment of far address */ ulong disp; /* displacement */ ulong imm; /* immediate */ ulong imm2; /* second immediate operand */ uvlong imm64; /* big immediate */ char *curr; /* fill level in output buffer */ char *end; /* end of output buffer */ char *err; /* error message */ }; /* 386 register (ha!) set */ enum{ AX=0, CX, DX, BX, SP, BP, SI, DI, /* amd64 */ R8, R9, R10, R11, R12, R13, R14, R15 }; /* amd64 rex extension byte */ enum{ REXW = 1<<3, /* =1, 64-bit operand size */ REXR = 1<<2, /* extend modrm reg */ REXX = 1<<1, /* extend sib index */ REXB = 1<<0 /* extend modrm r/m, sib base, or opcode reg */ }; /* Operand Format codes */ /* %A - address size register modifier (!asize -> 'E') %C - Control register CR0/CR1/CR2 %D - Debug register DR0/DR1/DR2/DR3/DR6/DR7 %I - second immediate operand %O - Operand size register modifier (!osize -> 'E') %T - Test register TR6/TR7 %S - size code ('W' or 'L') %W - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE" %d - displacement 16-32 bits %e - effective address - Mod R/M value %f - floating point register F0-F7 - from Mod R/M register %g - segment register %i - immediate operand 8-32 bits %p - PC-relative - signed displacement in immediate field %r - Reg from Mod R/M %w - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ" */ typedef struct Optable Optable; struct Optable { int x; char operand[2]; void *proto; /* actually either (char*) or (Optable*) */ }; /* Operand decoding codes */ enum { Ib = 1, /* 8-bit immediate - (no sign extension)*/ Ibs, /* 8-bit immediate (sign extended) */ Jbs, /* 8-bit sign-extended immediate in jump or call */ Iw, /* 16-bit immediate -> imm */ Iw2, /* 16-bit immediate -> imm2 */ Iwd, /* Operand-sized immediate (no sign extension)*/ Iwdq, /* Operand-sized immediate, possibly 64 bits */ Awd, /* Address offset */ Iwds, /* Operand-sized immediate (sign extended) */ RM, /* Word or long R/M field with register (/r) */ RMB, /* Byte R/M field with register (/r) */ RMOP, /* Word or long R/M field with op code (/digit) */ RMOPB, /* Byte R/M field with op code (/digit) */ RMR, /* R/M register only (mod = 11) */ RMM, /* R/M memory only (mod = 0/1/2) */ R0, /* Base reg of Mod R/M is literal 0x00 */ R1, /* Base reg of Mod R/M is literal 0x01 */ FRMOP, /* Floating point R/M field with opcode */ FRMEX, /* Extended floating point R/M field with opcode */ JUMP, /* Jump or Call flag - no operand */ RET, /* Return flag - no operand */ OA, /* literal 0x0a byte */ PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */ AUX, /* Multi-byte op code - Auxiliary table */ AUXMM, /* multi-byte op code - auxiliary table chosen by prefix */ PRE, /* Instr Prefix */ OPRE, /* Instr Prefix or media op extension */ SEG, /* Segment Prefix */ OPOVER, /* Operand size override */ ADDOVER, /* Address size override */ }; static Optable optab0F00[8]= { 0x00, 0,0, "MOVW LDT,%e", 0x01, 0,0, "MOVW TR,%e", 0x02, 0,0, "MOVW %e,LDT", 0x03, 0,0, "MOVW %e,TR", 0x04, 0,0, "VERR %e", 0x05, 0,0, "VERW %e", }; static Optable optab0F01[8]= { 0x00, 0,0, "MOVL GDTR,%e", 0x01, 0,0, "MOVL IDTR,%e", 0x02, 0,0, "MOVL %e,GDTR", 0x03, 0,0, "MOVL %e,IDTR", 0x04, 0,0, "MOVW MSW,%e", /* word */ 0x06, 0,0, "MOVW %e,MSW", /* word */ 0x07, 0,0, "INVLPG %e", /* or SWAPGS */ }; static Optable optab0F01F8[1]= { 0x00, 0,0, "SWAPGS", }; /* 0F71 */ /* 0F72 */ /* 0F73 */ static Optable optab0FAE[8]= { 0x00, 0,0, "FXSAVE %e", 0x01, 0,0, "FXRSTOR %e", 0x02, 0,0, "LDMXCSR %e", 0x03, 0,0, "STMXCSR %e", 0x05, 0,0, "LFENCE", 0x06, 0,0, "MFENCE", 0x07, 0,0, "SFENCE", }; /* 0F18 */ /* 0F0D */ static Optable optab0FBA[8]= { 0x04, Ib,0, "BT%S %i,%e", 0x05, Ib,0, "BTS%S %i,%e", 0x06, Ib,0, "BTR%S %i,%e", 0x07, Ib,0, "BTC%S %i,%e", }; static Optable optab0F0F[256]= { 0x0c, 0,0, "PI2FW %m,%M", 0x0d, 0,0, "PI2L %m,%M", 0x1c, 0,0, "PF2IW %m,%M", 0x1d, 0,0, "PF2IL %m,%M", 0x8a, 0,0, "PFNACC %m,%M", 0x8e, 0,0, "PFPNACC %m,%M", 0x90, 0,0, "PFCMPGE %m,%M", 0x94, 0,0, "PFMIN %m,%M", 0x96, 0,0, "PFRCP %m,%M", 0x97, 0,0, "PFRSQRT %m,%M", 0x9a, 0,0, "PFSUB %m,%M", 0x9e, 0,0, "PFADD %m,%M", 0xa0, 0,0, "PFCMPGT %m,%M", 0xa4, 0,0, "PFMAX %m,%M", 0xa6, 0,0, "PFRCPIT1 %m,%M", 0xa7, 0,0, "PFRSQIT1 %m,%M", 0xaa, 0,0, "PFSUBR %m,%M", 0xae, 0,0, "PFACC %m,%M", 0xb0, 0,0, "PFCMPEQ %m,%M", 0xb4, 0,0, "PFMUL %m,%M", 0xb6, 0,0, "PFRCPI2T %m,%M", 0xb7, 0,0, "PMULHRW %m,%M", 0xbb, 0,0, "PSWAPL %m,%M", }; static Optable optab0FC7[8]= { 0x01, 0,0, "CMPXCHG8B %e", }; static Optable optab660F71[8]= { 0x02, Ib,0, "PSRLW %i,%X", 0x04, Ib,0, "PSRAW %i,%X", 0x06, Ib,0, "PSLLW %i,%X", }; static Optable optab660F72[8]= { 0x02, Ib,0, "PSRLL %i,%X", 0x04, Ib,0, "PSRAL %i,%X", 0x06, Ib,0, "PSLLL %i,%X", }; static Optable optab660F73[8]= { 0x02, Ib,0, "PSRLQ %i,%X", 0x03, Ib,0, "PSRLO %i,%X", 0x06, Ib,0, "PSLLQ %i,%X", 0x07, Ib,0, "PSLLO %i,%X", }; static Optable optab660F[256]= { 0x2B, RM,0, "MOVNTPD %x,%e", 0x2E, RM,0, "UCOMISD %x,%X", 0x2F, RM,0, "COMISD %x,%X", 0x5A, RM,0, "CVTPD2PS %x,%X", 0x5B, RM,0, "CVTPS2PL %x,%X", 0x6A, RM,0, "PUNPCKHLQ %x,%X", 0x6B, RM,0, "PACKSSLW %x,%X", 0x6C, RM,0, "PUNPCKLQDQ %x,%X", 0x6D, RM,0, "PUNPCKHQDQ %x,%X", 0x6E, RM,0, "MOV%S %e,%X", 0x6F, RM,0, "MOVO %x,%X", /* MOVDQA */ 0x70, RM,Ib, "PSHUFL %i,%x,%X", 0x71, RMOP,0, optab660F71, 0x72, RMOP,0, optab660F72, 0x73, RMOP,0, optab660F73, 0x7E, RM,0, "MOV%S %X,%e", 0x7F, RM,0, "MOVO %X,%x", 0xC4, RM,Ib, "PINSRW %i,%e,%X", 0xC5, RMR,Ib, "PEXTRW %i,%X,%e", 0xD4, RM,0, "PADDQ %x,%X", 0xD5, RM,0, "PMULLW %x,%X", 0xD6, RM,0, "MOVQ %X,%x", 0xE6, RM,0, "CVTTPD2PL %x,%X", 0xE7, RM,0, "MOVNTO %X,%e", 0xF7, RM,0, "MASKMOVOU %x,%X", }; static Optable optabF20F[256]= { 0x10, RM,0, "MOVSD %x,%X", 0x11, RM,0, "MOVSD %X,%x", 0x2A, RM,0, "CVTS%S2SD %e,%X", 0x2C, RM,0, "CVTTSD2S%S %x,%r", 0x2D, RM,0, "CVTSD2S%S %x,%r", 0x5A, RM,0, "CVTSD2SS %x,%X", 0x6F, RM,0, "MOVOU %x,%X", 0x70, RM,Ib, "PSHUFLW %i,%x,%X", 0x7F, RM,0, "MOVOU %X,%x", 0xD6, RM,0, "MOVQOZX %M,%X", 0xE6, RM,0, "CVTPD2PL %x,%X", }; static Optable optabF30F[256]= { 0x10, RM,0, "MOVSS %x,%X", 0x11, RM,0, "MOVSS %X,%x", 0x2A, RM,0, "CVTS%S2SS %e,%X", 0x2C, RM,0, "CVTTSS2S%S %x,%r", 0x2D, RM,0, "CVTSS2S%S %x,%r", 0x5A, RM,0, "CVTSS2SD %x,%X", 0x5B, RM,0, "CVTTPS2PL %x,%X", 0x6F, RM,0, "MOVOU %x,%X", 0x70, RM,Ib, "PSHUFHW %i,%x,%X", 0x7E, RM,0, "MOVQOZX %x,%X", 0x7F, RM,0, "MOVOU %X,%x", 0xD6, RM,0, "MOVQOZX %m*,%X", 0xE6, RM,0, "CVTPL2PD %x,%X", }; static Optable optab0F[256]= { 0x00, RMOP,0, optab0F00, 0x01, RMOP,0, optab0F01, 0x02, RM,0, "LAR %e,%r", 0x03, RM,0, "LSL %e,%r", 0x05, 0,0, "SYSCALL", 0x06, 0,0, "CLTS", 0x07, 0,0, "SYSRET", 0x08, 0,0, "INVD", 0x09, 0,0, "WBINVD", 0x0B, 0,0, "UD2", 0x0F, RM,AUX, optab0F0F, /* 3DNow! */ 0x10, RM,0, "MOVU%s %x,%X", 0x11, RM,0, "MOVU%s %X,%x", 0x12, RM,0, "MOV[H]L%s %x,%X", /* TO DO: H if source is XMM */ 0x13, RM,0, "MOVL%s %X,%e", 0x14, RM,0, "UNPCKL%s %x,%X", 0x15, RM,0, "UNPCKH%s %x,%X", 0x16, RM,0, "MOV[L]H%s %x,%X", /* TO DO: L if source is XMM */ 0x17, RM,0, "MOVH%s %X,%x", 0x20, RMR,0, "MOVL %C,%e", 0x21, RMR,0, "MOVL %D,%e", 0x22, RMR,0, "MOVL %e,%C", 0x23, RMR,0, "MOVL %e,%D", 0x24, RMR,0, "MOVL %T,%e", 0x26, RMR,0, "MOVL %e,%T", 0x28, RM,0, "MOVA%s %x,%X", 0x29, RM,0, "MOVA%s %X,%x", 0x2A, RM,0, "CVTPL2%s %m*,%X", 0x2B, RM,0, "MOVNT%s %X,%e", 0x2C, RM,0, "CVTT%s2PL %x,%M", 0x2D, RM,0, "CVT%s2PL %x,%M", 0x2E, RM,0, "UCOMISS %x,%X", 0x2F, RM,0, "COMISS %x,%X", 0x30, 0,0, "WRMSR", 0x31, 0,0, "RDTSC", 0x32, 0,0, "RDMSR", 0x33, 0,0, "RDPMC", 0x42, RM,0, "CMOVC %e,%r", /* CF */ 0x43, RM,0, "CMOVNC %e,%r", /* ¬ CF */ 0x44, RM,0, "CMOVZ %e,%r", /* ZF */ 0x45, RM,0, "CMOVNZ %e,%r", /* ¬ ZF */ 0x46, RM,0, "CMOVBE %e,%r", /* CF ∨ ZF */ 0x47, RM,0, "CMOVA %e,%r", /* ¬CF ∧ ¬ZF */ 0x48, RM,0, "CMOVS %e,%r", /* SF */ 0x49, RM,0, "CMOVNS %e,%r", /* ¬ SF */ 0x4A, RM,0, "CMOVP %e,%r", /* PF */ 0x4B, RM,0, "CMOVNP %e,%r", /* ¬ PF */ 0x4C, RM,0, "CMOVLT %e,%r", /* LT ≡ OF ≠ SF */ 0x4D, RM,0, "CMOVGE %e,%r", /* GE ≡ ZF ∨ SF */ 0x4E, RM,0, "CMOVLE %e,%r", /* LE ≡ ZF ∨ LT */ 0x4F, RM,0, "CMOVGT %e,%r", /* GT ≡ ¬ZF ∧ GE */ 0x50, RM,0, "MOVMSK%s %X,%r", /* TO DO: check */ 0x51, RM,0, "SQRT%s %x,%X", 0x52, RM,0, "RSQRT%s %x,%X", 0x53, RM,0, "RCP%s %x,%X", 0x54, RM,0, "AND%s %x,%X", 0x55, RM,0, "ANDN%s %x,%X", 0x56, RM,0, "OR%s %x,%X", /* TO DO: S/D */ 0x57, RM,0, "XOR%s %x,%X", /* S/D */ 0x58, RM,0, "ADD%s %x,%X", /* S/P S/D */ 0x59, RM,0, "MUL%s %x,%X", 0x5A, RM,0, "CVTPS2PD %x,%X", 0x5B, RM,0, "CVTPL2PS %x,%X", 0x5C, RM,0, "SUB%s %x,%X", 0x5D, RM,0, "MIN%s %x,%X", 0x5E, RM,0, "DIV%s %x,%X", /* TO DO: S/P S/D */ 0x5F, RM,0, "MAX%s %x,%X", 0x60, RM,0, "PUNPCKLBW %m,%M", 0x61, RM,0, "PUNPCKLWL %m,%M", 0x62, RM,0, "PUNPCKLLQ %m,%M", 0x63, RM,0, "PACKSSWB %m,%M", 0x64, RM,0, "PCMPGTB %m,%M", 0x65, RM,0, "PCMPGTW %m,%M", 0x66, RM,0, "PCMPGTL %m,%M", 0x67, RM,0, "PACKUSWB %m,%M", 0x68, RM,0, "PUNPCKHBW %m,%M", 0x69, RM,0, "PUNPCKHWL %m,%M", 0x6A, RM,0, "PUNPCKHLQ %m,%M", 0x6B, RM,0, "PACKSSLW %m,%M", 0x6E, RM,0, "MOV%S %e,%M", 0x6F, RM,0, "MOVQ %m,%M", 0x70, RM,Ib, "PSHUFW %i,%m,%M", 0x74, RM,0, "PCMPEQB %m,%M", 0x75, RM,0, "PCMPEQW %m,%M", 0x76, RM,0, "PCMPEQL %m,%M", 0x7E, RM,0, "MOV%S %M,%e", 0x7F, RM,0, "MOVQ %M,%m", 0xAE, RMOP,0, optab0FAE, 0xAA, 0,0, "RSM", 0xB0, RM,0, "CMPXCHGB %r,%e", 0xB1, RM,0, "CMPXCHG%S %r,%e", 0xC0, RMB,0, "XADDB %r,%e", 0xC1, RM,0, "XADD%S %r,%e", 0xC2, RM,Ib, "CMP%s %i,%x,%X", 0xC3, RM,0, "MOVNTI%S %r,%e", 0xC6, RM,Ib, "SHUF%s %i,%x,%X", 0xC8, 0,0, "BSWAP AX", 0xC9, 0,0, "BSWAP CX", 0xCA, 0,0, "BSWAP DX", 0xCB, 0,0, "BSWAP BX", 0xCC, 0,0, "BSWAP SP", 0xCD, 0,0, "BSWAP BP", 0xCE, 0,0, "BSWAP SI", 0xCF, 0,0, "BSWAP DI", 0xD1, RM,0, "PSRLW %m,%M", 0xD2, RM,0, "PSRLL %m,%M", 0xD3, RM,0, "PSRLQ %m,%M", 0xD5, RM,0, "PMULLW %m,%M", 0xD6, RM,0, "MOVQOZX %m*,%X", 0xD7, RM,0, "PMOVMSKB %m,%r", 0xD8, RM,0, "PSUBUSB %m,%M", 0xD9, RM,0, "PSUBUSW %m,%M", 0xDA, RM,0, "PMINUB %m,%M", 0xDB, RM,0, "PAND %m,%M", 0xDC, RM,0, "PADDUSB %m,%M", 0xDD, RM,0, "PADDUSW %m,%M", 0xDE, RM,0, "PMAXUB %m,%M", 0xDF, RM,0, "PANDN %m,%M", 0xE0, RM,0, "PAVGB %m,%M", 0xE1, RM,0, "PSRAW %m,%M", 0xE2, RM,0, "PSRAL %m,%M", 0xE3, RM,0, "PAVGW %m,%M", 0xE4, RM,0, "PMULHUW %m,%M", 0xE5, RM,0, "PMULHW %m,%M", 0xE7, RM,0, "MOVNTQ %M,%e", 0xE8, RM,0, "PSUBSB %m,%M", 0xE9, RM,0, "PSUBSW %m,%M", 0xEA, RM,0, "PMINSW %m,%M", 0xEB, RM,0, "POR %m,%M", 0xEC, RM,0, "PADDSB %m,%M", 0xED, RM,0, "PADDSW %m,%M", 0xEE, RM,0, "PMAXSW %m,%M", 0xEF, RM,0, "PXOR %m,%M", 0xF1, RM,0, "PSLLW %m,%M", 0xF2, RM,0, "PSLLL %m,%M", 0xF3, RM,0, "PSLLQ %m,%M", 0xF4, RM,0, "PMULULQ %m,%M", 0xF5, RM,0, "PMADDWL %m,%M", 0xF6, RM,0, "PSADBW %m,%M", 0xF7, RMR,0, "MASKMOVQ %m,%M", 0xF8, RM,0, "PSUBB %m,%M", 0xF9, RM,0, "PSUBW %m,%M", 0xFA, RM,0, "PSUBL %m,%M", 0xFC, RM,0, "PADDB %m,%M", 0xFD, RM,0, "PADDW %m,%M", 0xFE, RM,0, "PADDL %m,%M", 0x80, Iwds,0, "JOS %p", 0x81, Iwds,0, "JOC %p", 0x82, Iwds,0, "JCS %p", 0x83, Iwds,0, "JCC %p", 0x84, Iwds,0, "JEQ %p", 0x85, Iwds,0, "JNE %p", 0x86, Iwds,0, "JLS %p", 0x87, Iwds,0, "JHI %p", 0x88, Iwds,0, "JMI %p", 0x89, Iwds,0, "JPL %p", 0x8a, Iwds,0, "JPS %p", 0x8b, Iwds,0, "JPC %p", 0x8c, Iwds,0, "JLT %p", 0x8d, Iwds,0, "JGE %p", 0x8e, Iwds,0, "JLE %p", 0x8f, Iwds,0, "JGT %p", 0x90, RMB,0, "SETOS %e", 0x91, RMB,0, "SETOC %e", 0x92, RMB,0, "SETCS %e", 0x93, RMB,0, "SETCC %e", 0x94, RMB,0, "SETEQ %e", 0x95, RMB,0, "SETNE %e", 0x96, RMB,0, "SETLS %e", 0x97, RMB,0, "SETHI %e", 0x98, RMB,0, "SETMI %e", 0x99, RMB,0, "SETPL %e", 0x9a, RMB,0, "SETPS %e", 0x9b, RMB,0, "SETPC %e", 0x9c, RMB,0, "SETLT %e", 0x9d, RMB,0, "SETGE %e", 0x9e, RMB,0, "SETLE %e", 0x9f, RMB,0, "SETGT %e", 0xa0, 0,0, "PUSHL FS", 0xa1, 0,0, "POPL FS", 0xa2, 0,0, "CPUID", 0xa3, RM,0, "BT%S %r,%e", 0xa4, RM,Ib, "SHLD%S %r,%i,%e", 0xa5, RM,0, "SHLD%S %r,CL,%e", 0xa8, 0,0, "PUSHL GS", 0xa9, 0,0, "POPL GS", 0xab, RM,0, "BTS%S %r,%e", 0xac, RM,Ib, "SHRD%S %r,%i,%e", 0xad, RM,0, "SHRD%S %r,CL,%e", 0xaf, RM,0, "IMUL%S %e,%r", 0xb2, RMM,0, "LSS %e,%r", 0xb3, RM,0, "BTR%S %r,%e", 0xb4, RMM,0, "LFS %e,%r", 0xb5, RMM,0, "LGS %e,%r", 0xb6, RMB,0, "MOVBZX %e,%R", 0xb7, RM,0, "MOVWZX %e,%R", 0xba, RMOP,0, optab0FBA, 0xbb, RM,0, "BTC%S %e,%r", 0xbc, RM,0, "BSF%S %e,%r", 0xbd, RM,0, "BSR%S %e,%r", 0xbe, RMB,0, "MOVBSX %e,%R", 0xbf, RM,0, "MOVWSX %e,%R", 0xc7, RMOP,0, optab0FC7, }; static Optable optab80[8]= { 0x00, Ib,0, "ADDB %i,%e", 0x01, Ib,0, "ORB %i,%e", 0x02, Ib,0, "ADCB %i,%e", 0x03, Ib,0, "SBBB %i,%e", 0x04, Ib,0, "ANDB %i,%e", 0x05, Ib,0, "SUBB %i,%e", 0x06, Ib,0, "XORB %i,%e", 0x07, Ib,0, "CMPB %e,%i", }; static Optable optab81[8]= { 0x00, Iwd,0, "ADD%S %i,%e", 0x01, Iwd,0, "OR%S %i,%e", 0x02, Iwd,0, "ADC%S %i,%e", 0x03, Iwd,0, "SBB%S %i,%e", 0x04, Iwd,0, "AND%S %i,%e", 0x05, Iwd,0, "SUB%S %i,%e", 0x06, Iwd,0, "XOR%S %i,%e", 0x07, Iwd,0, "CMP%S %e,%i", }; static Optable optab83[8]= { 0x00, Ibs,0, "ADD%S %i,%e", 0x01, Ibs,0, "OR%S %i,%e", 0x02, Ibs,0, "ADC%S %i,%e", 0x03, Ibs,0, "SBB%S %i,%e", 0x04, Ibs,0, "AND%S %i,%e", 0x05, Ibs,0, "SUB%S %i,%e", 0x06, Ibs,0, "XOR%S %i,%e", 0x07, Ibs,0, "CMP%S %e,%i", }; static Optable optabC0[8] = { 0x00, Ib,0, "ROLB %i,%e", 0x01, Ib,0, "RORB %i,%e", 0x02, Ib,0, "RCLB %i,%e", 0x03, Ib,0, "RCRB %i,%e", 0x04, Ib,0, "SHLB %i,%e", 0x05, Ib,0, "SHRB %i,%e", 0x07, Ib,0, "SARB %i,%e", }; static Optable optabC1[8] = { 0x00, Ib,0, "ROL%S %i,%e", 0x01, Ib,0, "ROR%S %i,%e", 0x02, Ib,0, "RCL%S %i,%e", 0x03, Ib,0, "RCR%S %i,%e", 0x04, Ib,0, "SHL%S %i,%e", 0x05, Ib,0, "SHR%S %i,%e", 0x07, Ib,0, "SAR%S %i,%e", }; static Optable optabD0[8] = { 0x00, 0,0, "ROLB %e", 0x01, 0,0, "RORB %e", 0x02, 0,0, "RCLB %e", 0x03, 0,0, "RCRB %e", 0x04, 0,0, "SHLB %e", 0x05, 0,0, "SHRB %e", 0x07, 0,0, "SARB %e", }; static Optable optabD1[8] = { 0x00, 0,0, "ROL%S %e", 0x01, 0,0, "ROR%S %e", 0x02, 0,0, "RCL%S %e", 0x03, 0,0, "RCR%S %e", 0x04, 0,0, "SHL%S %e", 0x05, 0,0, "SHR%S %e", 0x07, 0,0, "SAR%S %e", }; static Optable optabD2[8] = { 0x00, 0,0, "ROLB CL,%e", 0x01, 0,0, "RORB CL,%e", 0x02, 0,0, "RCLB CL,%e", 0x03, 0,0, "RCRB CL,%e", 0x04, 0,0, "SHLB CL,%e", 0x05, 0,0, "SHRB CL,%e", 0x07, 0,0, "SARB CL,%e", }; static Optable optabD3[8] = { 0x00, 0,0, "ROL%S CL,%e", 0x01, 0,0, "ROR%S CL,%e", 0x02, 0,0, "RCL%S CL,%e", 0x03, 0,0, "RCR%S CL,%e", 0x04, 0,0, "SHL%S CL,%e", 0x05, 0,0, "SHR%S CL,%e", 0x07, 0,0, "SAR%S CL,%e", }; static Optable optabD8[8+8] = { 0x00, 0,0, "FADDF %e,F0", 0x01, 0,0, "FMULF %e,F0", 0x02, 0,0, "FCOMF %e,F0", 0x03, 0,0, "FCOMFP %e,F0", 0x04, 0,0, "FSUBF %e,F0", 0x05, 0,0, "FSUBRF %e,F0", 0x06, 0,0, "FDIVF %e,F0", 0x07, 0,0, "FDIVRF %e,F0", 0x08, 0,0, "FADDD %f,F0", 0x09, 0,0, "FMULD %f,F0", 0x0a, 0,0, "FCOMD %f,F0", 0x0b, 0,0, "FCOMPD %f,F0", 0x0c, 0,0, "FSUBD %f,F0", 0x0d, 0,0, "FSUBRD %f,F0", 0x0e, 0,0, "FDIVD %f,F0", 0x0f, 0,0, "FDIVRD %f,F0", }; /* * optabD9 and optabDB use the following encoding: * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07]; * else instruction = optabDx[(modrm&0x3f)+8]; * * the instructions for MOD == 3, follow the 8 instructions * for the other MOD values stored at the front of the table. */ static Optable optabD9[64+8] = { 0x00, 0,0, "FMOVF %e,F0", 0x02, 0,0, "FMOVF F0,%e", 0x03, 0,0, "FMOVFP F0,%e", 0x04, 0,0, "FLDENV%S %e", 0x05, 0,0, "FLDCW %e", 0x06, 0,0, "FSTENV%S %e", 0x07, 0,0, "FSTCW %e", 0x08, 0,0, "FMOVD F0,F0", /* Mod R/M = 11xx xxxx*/ 0x09, 0,0, "FMOVD F1,F0", 0x0a, 0,0, "FMOVD F2,F0", 0x0b, 0,0, "FMOVD F3,F0", 0x0c, 0,0, "FMOVD F4,F0", 0x0d, 0,0, "FMOVD F5,F0", 0x0e, 0,0, "FMOVD F6,F0", 0x0f, 0,0, "FMOVD F7,F0", 0x10, 0,0, "FXCHD F0,F0", 0x11, 0,0, "FXCHD F1,F0", 0x12, 0,0, "FXCHD F2,F0", 0x13, 0,0, "FXCHD F3,F0", 0x14, 0,0, "FXCHD F4,F0", 0x15, 0,0, "FXCHD F5,F0", 0x16, 0,0, "FXCHD F6,F0", 0x17, 0,0, "FXCHD F7,F0", 0x18, 0,0, "FNOP", 0x28, 0,0, "FCHS", 0x29, 0,0, "FABS", 0x2c, 0,0, "FTST", 0x2d, 0,0, "FXAM", 0x30, 0,0, "FLD1", 0x31, 0,0, "FLDL2T", 0x32, 0,0, "FLDL2E", 0x33, 0,0, "FLDPI", 0x34, 0,0, "FLDLG2", 0x35, 0,0, "FLDLN2", 0x36, 0,0, "FLDZ", 0x38, 0,0, "F2XM1", 0x39, 0,0, "FYL2X", 0x3a, 0,0, "FPTAN", 0x3b, 0,0, "FPATAN", 0x3c, 0,0, "FXTRACT", 0x3d, 0,0, "FPREM1", 0x3e, 0,0, "FDECSTP", 0x3f, 0,0, "FNCSTP", 0x40, 0,0, "FPREM", 0x41, 0,0, "FYL2XP1", 0x42, 0,0, "FSQRT", 0x43, 0,0, "FSINCOS", 0x44, 0,0, "FRNDINT", 0x45, 0,0, "FSCALE", 0x46, 0,0, "FSIN", 0x47, 0,0, "FCOS", }; static Optable optabDA[8+8] = { 0x00, 0,0, "FADDL %e,F0", 0x01, 0,0, "FMULL %e,F0", 0x02, 0,0, "FCOML %e,F0", 0x03, 0,0, "FCOMLP %e,F0", 0x04, 0,0, "FSUBL %e,F0", 0x05, 0,0, "FSUBRL %e,F0", 0x06, 0,0, "FDIVL %e,F0", 0x07, 0,0, "FDIVRL %e,F0", 0x0d, R1,0, "FUCOMPP", }; static Optable optabDB[8+64] = { 0x00, 0,0, "FMOVL %e,F0", 0x02, 0,0, "FMOVL F0,%e", 0x03, 0,0, "FMOVLP F0,%e", 0x05, 0,0, "FMOVX %e,F0", 0x07, 0,0, "FMOVXP F0,%e", 0x2a, 0,0, "FCLEX", 0x2b, 0,0, "FINIT", }; static Optable optabDC[8+8] = { 0x00, 0,0, "FADDD %e,F0", 0x01, 0,0, "FMULD %e,F0", 0x02, 0,0, "FCOMD %e,F0", 0x03, 0,0, "FCOMDP %e,F0", 0x04, 0,0, "FSUBD %e,F0", 0x05, 0,0, "FSUBRD %e,F0", 0x06, 0,0, "FDIVD %e,F0", 0x07, 0,0, "FDIVRD %e,F0", 0x08, 0,0, "FADDD F0,%f", 0x09, 0,0, "FMULD F0,%f", 0x0c, 0,0, "FSUBRD F0,%f", 0x0d, 0,0, "FSUBD F0,%f", 0x0e, 0,0, "FDIVRD F0,%f", 0x0f, 0,0, "FDIVD F0,%f", }; static Optable optabDD[8+8] = { 0x00, 0,0, "FMOVD %e,F0", 0x02, 0,0, "FMOVD F0,%e", 0x03, 0,0, "FMOVDP F0,%e", 0x04, 0,0, "FRSTOR%S %e", 0x06, 0,0, "FSAVE%S %e", 0x07, 0,0, "FSTSW %e", 0x08, 0,0, "FFREED %f", 0x0a, 0,0, "FMOVD %f,F0", 0x0b, 0,0, "FMOVDP %f,F0", 0x0c, 0,0, "FUCOMD %f,F0", 0x0d, 0,0, "FUCOMDP %f,F0", }; static Optable optabDE[8+8] = { 0x00, 0,0, "FADDW %e,F0", 0x01, 0,0, "FMULW %e,F0", 0x02, 0,0, "FCOMW %e,F0", 0x03, 0,0, "FCOMWP %e,F0", 0x04, 0,0, "FSUBW %e,F0", 0x05, 0,0, "FSUBRW %e,F0", 0x06, 0,0, "FDIVW %e,F0", 0x07, 0,0, "FDIVRW %e,F0", 0x08, 0,0, "FADDDP F0,%f", 0x09, 0,0, "FMULDP F0,%f", 0x0b, R1,0, "FCOMPDP", 0x0c, 0,0, "FSUBRDP F0,%f", 0x0d, 0,0, "FSUBDP F0,%f", 0x0e, 0,0, "FDIVRDP F0,%f", 0x0f, 0,0, "FDIVDP F0,%f", }; static Optable optabDF[8+8] = { 0x00, 0,0, "FMOVW %e,F0", 0x02, 0,0, "FMOVW F0,%e", 0x03, 0,0, "FMOVWP F0,%e", 0x04, 0,0, "FBLD %e", 0x05, 0,0, "FMOVL %e,F0", 0x06, 0,0, "FBSTP %e", 0x07, 0,0, "FMOVLP F0,%e", 0x0c, R0,0, "FSTSW %OAX", }; static Optable optabF6[8] = { 0x00, Ib,0, "TESTB %i,%e", 0x02, 0,0, "NOTB %e", 0x03, 0,0, "NEGB %e", 0x04, 0,0, "MULB AL,%e", 0x05, 0,0, "IMULB AL,%e", 0x06, 0,0, "DIVB AL,%e", 0x07, 0,0, "IDIVB AL,%e", }; static Optable optabF7[8] = { 0x00, Iwd,0, "TEST%S %i,%e", 0x02, 0,0, "NOT%S %e", 0x03, 0,0, "NEG%S %e", 0x04, 0,0, "MUL%S %OAX,%e", 0x05, 0,0, "IMUL%S %OAX,%e", 0x06, 0,0, "DIV%S %OAX,%e", 0x07, 0,0, "IDIV%S %OAX,%e", }; static Optable optabFE[8] = { 0x00, 0,0, "INCB %e", 0x01, 0,0, "DECB %e", }; static Optable optabFF[8] = { 0x00, 0,0, "INC%S %e", 0x01, 0,0, "DEC%S %e", 0x02, JUMP,0, "CALL* %e", 0x03, JUMP,0, "CALLF* %e", 0x04, JUMP,0, "JMP* %e", 0x05, JUMP,0, "JMPF* %e", 0x06, 0,0, "PUSHL %e", }; static Optable optable[256+1] = { 0x00, RMB,0, "ADDB %r,%e", 0x01, RM,0, "ADD%S %r,%e", 0x02, RMB,0, "ADDB %e,%r", 0x03, RM,0, "ADD%S %e,%r", 0x04, Ib,0, "ADDB %i,AL", 0x05, Iwd,0, "ADD%S %i,%OAX", 0x06, 0,0, "PUSHL ES", 0x07, 0,0, "POPL ES", 0x08, RMB,0, "ORB %r,%e", 0x09, RM,0, "OR%S %r,%e", 0x0a, RMB,0, "ORB %e,%r", 0x0b, RM,0, "OR%S %e,%r", 0x0c, Ib,0, "ORB %i,AL", 0x0d, Iwd,0, "OR%S %i,%OAX", 0x0e, 0,0, "PUSHL CS", 0x0f, AUXMM,0, optab0F, 0x10, RMB,0, "ADCB %r,%e", 0x11, RM,0, "ADC%S %r,%e", 0x12, RMB,0, "ADCB %e,%r", 0x13, RM,0, "ADC%S %e,%r", 0x14, Ib,0, "ADCB %i,AL", 0x15, Iwd,0, "ADC%S %i,%OAX", 0x16, 0,0, "PUSHL SS", 0x17, 0,0, "POPL SS", 0x18, RMB,0, "SBBB %r,%e", 0x19, RM,0, "SBB%S %r,%e", 0x1a, RMB,0, "SBBB %e,%r", 0x1b, RM,0, "SBB%S %e,%r", 0x1c, Ib,0, "SBBB %i,AL", 0x1d, Iwd,0, "SBB%S %i,%OAX", 0x1e, 0,0, "PUSHL DS", 0x1f, 0,0, "POPL DS", 0x20, RMB,0, "ANDB %r,%e", 0x21, RM,0, "AND%S %r,%e", 0x22, RMB,0, "ANDB %e,%r", 0x23, RM,0, "AND%S %e,%r", 0x24, Ib,0, "ANDB %i,AL", 0x25, Iwd,0, "AND%S %i,%OAX", 0x26, SEG,0, "ES:", 0x27, 0,0, "DAA", 0x28, RMB,0, "SUBB %r,%e", 0x29, RM,0, "SUB%S %r,%e", 0x2a, RMB,0, "SUBB %e,%r", 0x2b, RM,0, "SUB%S %e,%r", 0x2c, Ib,0, "SUBB %i,AL", 0x2d, Iwd,0, "SUB%S %i,%OAX", 0x2e, SEG,0, "CS:", 0x2f, 0,0, "DAS", 0x30, RMB,0, "XORB %r,%e", 0x31, RM,0, "XOR%S %r,%e", 0x32, RMB,0, "XORB %e,%r", 0x33, RM,0, "XOR%S %e,%r", 0x34, Ib,0, "XORB %i,AL", 0x35, Iwd,0, "XOR%S %i,%OAX", 0x36, SEG,0, "SS:", 0x37, 0,0, "AAA", 0x38, RMB,0, "CMPB %r,%e", 0x39, RM,0, "CMP%S %r,%e", 0x3a, RMB,0, "CMPB %e,%r", 0x3b, RM,0, "CMP%S %e,%r", 0x3c, Ib,0, "CMPB %i,AL", 0x3d, Iwd,0, "CMP%S %i,%OAX", 0x3e, SEG,0, "DS:", 0x3f, 0,0, "AAS", 0x40, 0,0, "INC%S %OAX", 0x41, 0,0, "INC%S %OCX", 0x42, 0,0, "INC%S %ODX", 0x43, 0,0, "INC%S %OBX", 0x44, 0,0, "INC%S %OSP", 0x45, 0,0, "INC%S %OBP", 0x46, 0,0, "INC%S %OSI", 0x47, 0,0, "INC%S %ODI", 0x48, 0,0, "DEC%S %OAX", 0x49, 0,0, "DEC%S %OCX", 0x4a, 0,0, "DEC%S %ODX", 0x4b, 0,0, "DEC%S %OBX", 0x4c, 0,0, "DEC%S %OSP", 0x4d, 0,0, "DEC%S %OBP", 0x4e, 0,0, "DEC%S %OSI", 0x4f, 0,0, "DEC%S %ODI", 0x50, 0,0, "PUSH%S %OAX", 0x51, 0,0, "PUSH%S %OCX", 0x52, 0,0, "PUSH%S %ODX", 0x53, 0,0, "PUSH%S %OBX", 0x54, 0,0, "PUSH%S %OSP", 0x55, 0,0, "PUSH%S %OBP", 0x56, 0,0, "PUSH%S %OSI", 0x57, 0,0, "PUSH%S %ODI", 0x58, 0,0, "POP%S %OAX", 0x59, 0,0, "POP%S %OCX", 0x5a, 0,0, "POP%S %ODX", 0x5b, 0,0, "POP%S %OBX", 0x5c, 0,0, "POP%S %OSP", 0x5d, 0,0, "POP%S %OBP", 0x5e, 0,0, "POP%S %OSI", 0x5f, 0,0, "POP%S %ODI", 0x60, 0,0, "PUSHA%S", 0x61, 0,0, "POPA%S", 0x62, RMM,0, "BOUND %e,%r", 0x63, RM,0, "ARPL %r,%e", 0x64, SEG,0, "FS:", 0x65, SEG,0, "GS:", 0x66, OPOVER,0, "", 0x67, ADDOVER,0, "", 0x68, Iwd,0, "PUSH%S %i", 0x69, RM,Iwd, "IMUL%S %e,%i,%r", 0x6a, Ib,0, "PUSH%S %i", 0x6b, RM,Ibs, "IMUL%S %e,%i,%r", 0x6c, 0,0, "INSB DX,(%ODI)", 0x6d, 0,0, "INS%S DX,(%ODI)", 0x6e, 0,0, "OUTSB (%ASI),DX", 0x6f, 0,0, "OUTS%S (%ASI),DX", 0x70, Jbs,0, "JOS %p", 0x71, Jbs,0, "JOC %p", 0x72, Jbs,0, "JCS %p", 0x73, Jbs,0, "JCC %p", 0x74, Jbs,0, "JEQ %p", 0x75, Jbs,0, "JNE %p", 0x76, Jbs,0, "JLS %p", 0x77, Jbs,0, "JHI %p", 0x78, Jbs,0, "JMI %p", 0x79, Jbs,0, "JPL %p", 0x7a, Jbs,0, "JPS %p", 0x7b, Jbs,0, "JPC %p", 0x7c, Jbs,0, "JLT %p", 0x7d, Jbs,0, "JGE %p", 0x7e, Jbs,0, "JLE %p", 0x7f, Jbs,0, "JGT %p", 0x80, RMOPB,0, optab80, 0x81, RMOP,0, optab81, 0x83, RMOP,0, optab83, 0x84, RMB,0, "TESTB %r,%e", 0x85, RM,0, "TEST%S %r,%e", 0x86, RMB,0, "XCHGB %r,%e", 0x87, RM,0, "XCHG%S %r,%e", 0x88, RMB,0, "MOVB %r,%e", 0x89, RM,0, "MOV%S %r,%e", 0x8a, RMB,0, "MOVB %e,%r", 0x8b, RM,0, "MOV%S %e,%r", 0x8c, RM,0, "MOVW %g,%e", 0x8d, RM,0, "LEA%S %e,%r", 0x8e, RM,0, "MOVW %e,%g", 0x8f, RM,0, "POP%S %e", 0x90, 0,0, "NOP", 0x91, 0,0, "XCHG %OCX,%OAX", 0x92, 0,0, "XCHG %ODX,%OAX", 0x93, 0,0, "XCHG %OBX,%OAX", 0x94, 0,0, "XCHG %OSP,%OAX", 0x95, 0,0, "XCHG %OBP,%OAX", 0x96, 0,0, "XCHG %OSI,%OAX", 0x97, 0,0, "XCHG %ODI,%OAX", 0x98, 0,0, "%W", /* miserable CBW or CWDE */ 0x99, 0,0, "%w", /* idiotic CWD or CDQ */ 0x9a, PTR,0, "CALL%S %d", 0x9b, 0,0, "WAIT", 0x9c, 0,0, "PUSHF", 0x9d, 0,0, "POPF", 0x9e, 0,0, "SAHF", 0x9f, 0,0, "LAHF", 0xa0, Awd,0, "MOVB %i,AL", 0xa1, Awd,0, "MOV%S %i,%OAX", 0xa2, Awd,0, "MOVB AL,%i", 0xa3, Awd,0, "MOV%S %OAX,%i", 0xa4, 0,0, "MOVSB (%ASI),(%ADI)", 0xa5, 0,0, "MOVS%S (%ASI),(%ADI)", 0xa6, 0,0, "CMPSB (%ASI),(%ADI)", 0xa7, 0,0, "CMPS%S (%ASI),(%ADI)", 0xa8, Ib,0, "TESTB %i,AL", 0xa9, Iwd,0, "TEST%S %i,%OAX", 0xaa, 0,0, "STOSB AL,(%ADI)", 0xab, 0,0, "STOS%S %OAX,(%ADI)", 0xac, 0,0, "LODSB (%ASI),AL", 0xad, 0,0, "LODS%S (%ASI),%OAX", 0xae, 0,0, "SCASB (%ADI),AL", 0xaf, 0,0, "SCAS%S (%ADI),%OAX", 0xb0, Ib,0, "MOVB %i,AL", 0xb1, Ib,0, "MOVB %i,CL", 0xb2, Ib,0, "MOVB %i,DL", 0xb3, Ib,0, "MOVB %i,BL", 0xb4, Ib,0, "MOVB %i,AH", 0xb5, Ib,0, "MOVB %i,CH", 0xb6, Ib,0, "MOVB %i,DH", 0xb7, Ib,0, "MOVB %i,BH", 0xb8, Iwdq,0, "MOV%S %i,%OAX", 0xb9, Iwdq,0, "MOV%S %i,%OCX", 0xba, Iwdq,0, "MOV%S %i,%ODX", 0xbb, Iwdq,0, "MOV%S %i,%OBX", 0xbc, Iwdq,0, "MOV%S %i,%OSP", 0xbd, Iwdq,0, "MOV%S %i,%OBP", 0xbe, Iwdq,0, "MOV%S %i,%OSI", 0xbf, Iwdq,0, "MOV%S %i,%ODI", 0xc0, RMOPB,0, optabC0, 0xc1, RMOP,0, optabC1, 0xc2, Iw,0, "RET %i", 0xc3, RET,0, "RET", 0xc4, RM,0, "LES %e,%r", 0xc5, RM,0, "LDS %e,%r", 0xc6, RMB,Ib, "MOVB %i,%e", 0xc7, RM,Iwd, "MOV%S %i,%e", 0xc8, Iw2,Ib, "ENTER %i,%I", /* loony ENTER */ 0xc9, RET,0, "LEAVE", /* bizarre LEAVE */ 0xca, Iw,0, "RETF %i", 0xcb, RET,0, "RETF", 0xcc, 0,0, "INT 3", 0xcd, Ib,0, "INTB %i", 0xce, 0,0, "INTO", 0xcf, 0,0, "IRET", 0xd0, RMOPB,0, optabD0, 0xd1, RMOP,0, optabD1, 0xd2, RMOPB,0, optabD2, 0xd3, RMOP,0, optabD3, 0xd4, OA,0, "AAM", 0xd5, OA,0, "AAD", 0xd7, 0,0, "XLAT", 0xd8, FRMOP,0, optabD8, 0xd9, FRMEX,0, optabD9, 0xda, FRMOP,0, optabDA, 0xdb, FRMEX,0, optabDB, 0xdc, FRMOP,0, optabDC, 0xdd, FRMOP,0, optabDD, 0xde, FRMOP,0, optabDE, 0xdf, FRMOP,0, optabDF, 0xe0, Jbs,0, "LOOPNE %p", 0xe1, Jbs,0, "LOOPE %p", 0xe2, Jbs,0, "LOOP %p", 0xe3, Jbs,0, "JCXZ %p", 0xe4, Ib,0, "INB %i,AL", 0xe5, Ib,0, "IN%S %i,%OAX", 0xe6, Ib,0, "OUTB AL,%i", 0xe7, Ib,0, "OUT%S %OAX,%i", 0xe8, Iwds,0, "CALL %p", 0xe9, Iwds,0, "JMP %p", 0xea, PTR,0, "JMP %d", 0xeb, Jbs,0, "JMP %p", 0xec, 0,0, "INB DX,AL", 0xed, 0,0, "IN%S DX,%OAX", 0xee, 0,0, "OUTB AL,DX", 0xef, 0,0, "OUT%S %OAX,DX", 0xf0, PRE,0, "LOCK", 0xf2, OPRE,0, "REPNE", 0xf3, OPRE,0, "REP", 0xf4, 0,0, "HLT", 0xf5, 0,0, "CMC", 0xf6, RMOPB,0, optabF6, 0xf7, RMOP,0, optabF7, 0xf8, 0,0, "CLC", 0xf9, 0,0, "STC", 0xfa, 0,0, "CLI", 0xfb, 0,0, "STI", 0xfc, 0,0, "CLD", 0xfd, 0,0, "STD", 0xfe, RMOPB,0, optabFE, 0xff, RMOP,0, optabFF, 0x100, RM,0, "MOVLQSX %r,%e", }; static struct { Optable *tab; uint nel; } optabtab[] = { optab0F00, nelem(optab0F00), optab0F01, nelem(optab0F01), optab0F01F8, nelem(optab0F01F8), optab0FAE, nelem(optab0FAE), optab0FBA, nelem(optab0FBA), optab0F0F, nelem(optab0F0F), optab0FC7, nelem(optab0FC7), optab660F71, nelem(optab660F71), optab660F72, nelem(optab660F72), optab660F73, nelem(optab660F73), optab660F, nelem(optab660F), optabF20F, nelem(optabF20F), optabF30F, nelem(optabF30F), optab0F, nelem(optab0F), optab80, nelem(optab80), optab81, nelem(optab81), optab83, nelem(optab83), optabC0, nelem(optabC0), optabC1, nelem(optabC1), optabD0, nelem(optabD0), optabD1, nelem(optabD1), optabD2, nelem(optabD2), optabD3, nelem(optabD3), optabD8, nelem(optabD8), optabD9, nelem(optabD9), optabDA, nelem(optabDA), optabDB, nelem(optabDB), optabDC, nelem(optabDC), optabDD, nelem(optabDD), optabDE, nelem(optabDE), optabDF, nelem(optabDF), optabF6, nelem(optabF6), optabF7, nelem(optabF7), optabFE, nelem(optabFE), optabFF, nelem(optabFF), optable, nelem(optable), }; /* * compensate for Microsoft's ageing compilers */ static void ordertab(Optable *tab, int nel) { int i, x; static Optable empty; for(i = nel; --i >= 0;){ x = tab[i].x; if(x != i){ tab[x] = tab[i]; tab[i] = empty; } } } static void soptoms(void) { int i; static int reordered; /* assumes non-concurrent use */ if(reordered) return; reordered = 1; for(i = 0; i < nelem(optabtab); i++) ordertab(optabtab[i].tab, optabtab[i].nel); } /* * get a byte of the instruction */ static int igetc(Map *map, Instr *ip, uchar *c) { if(ip->n+1 > sizeof(ip->mem)){ werrstr("instruction too long"); return -1; } if (get1(map, ip->addr+ip->n, c, 1) < 0) { werrstr("can't read instruction: %r"); return -1; } ip->mem[ip->n++] = *c; return 1; } /* * get two bytes of the instruction */ static int igets(Map *map, Instr *ip, ushort *sp) { uchar c; ushort s; if (igetc(map, ip, &c) < 0) return -1; s = c; if (igetc(map, ip, &c) < 0) return -1; s |= (c<<8); *sp = s; return 1; } /* * get 4 bytes of the instruction */ static int igetl(Map *map, Instr *ip, ulong *lp) { ushort s; long l; if (igets(map, ip, &s) < 0) return -1; l = s; if (igets(map, ip, &s) < 0) return -1; l |= (s<<16); *lp = l; return 1; } /* * get 8 bytes of the instruction */ static int igetq(Map *map, Instr *ip, vlong *qp) { ulong l; uvlong q; if (igetl(map, ip, &l) < 0) return -1; q = l; if (igetl(map, ip, &l) < 0) return -1; q |= ((uvlong)l<<32); *qp = q; return 1; } static int getdisp(Map *map, Instr *ip, int mod, int rm, int code, int pcrel) { uchar c; ushort s; if (mod > 2) return 1; if (mod == 1) { if (igetc(map, ip, &c) < 0) return -1; if (c&0x80) ip->disp = c|0xffffff00; else ip->disp = c&0xff; } else if (mod == 2 || rm == code) { if (ip->asize == 'E') { if (igetl(map, ip, &ip->disp) < 0) return -1; if (mod == 0) ip->rip = pcrel; } else { if (igets(map, ip, &s) < 0) return -1; if (s&0x8000) ip->disp = s|0xffff0000; else ip->disp = s; } if (mod == 0) ip->base = -1; } return 1; } static int modrm(Map *map, Instr *ip, uchar c) { uchar rm, mod; mod = (c>>6)&3; rm = c&7; ip->mod = mod; ip->base = rm; ip->reg = (c>>3)&7; ip->rip = 0; if (mod == 3) /* register */ return 1; if (ip->asize == 0) { /* 16-bit mode */ switch(rm) { case 0: ip->base = BX; ip->index = SI; break; case 1: ip->base = BX; ip->index = DI; break; case 2: ip->base = BP; ip->index = SI; break; case 3: ip->base = BP; ip->index = DI; break; case 4: ip->base = SI; break; case 5: ip->base = DI; break; case 6: ip->base = BP; break; case 7: ip->base = BX; break; default: break; } return getdisp(map, ip, mod, rm, 6, 0); } if (rm == 4) { /* scummy sib byte */ if (igetc(map, ip, &c) < 0) return -1; ip->ss = (c>>6)&0x03; ip->index = (c>>3)&0x07; if (ip->index == 4) ip->index = -1; ip->base = c&0x07; return getdisp(map, ip, mod, ip->base, 5, 0); } return getdisp(map, ip, mod, rm, 5, ip->amd64); } static Optable * mkinstr(Map *map, Instr *ip, uvlong pc) { int i, n, norex; uchar c; ushort s; Optable *op, *obase; char buf[128]; soptoms(); memset(ip, 0, sizeof(*ip)); norex = 1; ip->base = -1; ip->index = -1; if(asstype == AI8086) ip->osize = 'W'; else { ip->osize = 'L'; ip->asize = 'E'; ip->amd64 = asstype != AI386; norex = 0; } ip->addr = pc; if (igetc(map, ip, &c) < 0) return 0; obase = optable; newop: if(ip->amd64 && !norex){ if(c >= 0x40 && c <= 0x4f) { ip->rex = c; if(igetc(map, ip, &c) < 0) return 0; } if(c == 0x63){ op = &obase[0x100]; /* MOVLQSX */ goto hack; } } op = &obase[c]; hack: if (op->proto == 0) { badop: n = snprint(buf, sizeof(buf), "opcode: ??"); for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2) _hexify(buf+n, ip->mem[i], 1); strcpy(buf+n, "??"); werrstr(buf); return 0; } for(i = 0; i < 2 && op->operand[i]; i++) { switch(op->operand[i]) { case Ib: /* 8-bit immediate - (no sign extension)*/ if (igetc(map, ip, &c) < 0) return 0; ip->imm = c&0xff; ip->imm64 = ip->imm; break; case Jbs: /* 8-bit jump immediate (sign extended) */ if (igetc(map, ip, &c) < 0) return 0; if (c&0x80) ip->imm = c|0xffffff00; else ip->imm = c&0xff; ip->imm64 = (long)ip->imm; ip->jumptype = Jbs; break; case Ibs: /* 8-bit immediate (sign extended) */ if (igetc(map, ip, &c) < 0) return 0; if (c&0x80) if (ip->osize == 'L') ip->imm = c|0xffffff00; else ip->imm = c|0xff00; else ip->imm = c&0xff; ip->imm64 = (long)ip->imm; break; case Iw: /* 16-bit immediate -> imm */ if (igets(map, ip, &s) < 0) return 0; ip->imm = s&0xffff; ip->imm64 = ip->imm; ip->jumptype = Iw; break; case Iw2: /* 16-bit immediate -> in imm2*/ if (igets(map, ip, &s) < 0) return 0; ip->imm2 = s&0xffff; break; case Iwd: /* Operand-sized immediate (no sign extension unless 64 bits)*/ if (ip->osize == 'L') { if (igetl(map, ip, &ip->imm) < 0) return 0; ip->imm64 = ip->imm; if(ip->rex&REXW && (ip->imm & (1<<31)) != 0) ip->imm64 |= (vlong)~0 << 32; } else { if (igets(map, ip, &s)< 0) return 0; ip->imm = s&0xffff; ip->imm64 = ip->imm; } break; case Iwdq: /* Operand-sized immediate, possibly big */ if (ip->osize == 'L') { if (igetl(map, ip, &ip->imm) < 0) return 0; ip->imm64 = ip->imm; if (ip->rex & REXW) { ulong l; if (igetl(map, ip, &l) < 0) return 0; ip->imm64 |= (uvlong)l << 32; } } else { if (igets(map, ip, &s)< 0) return 0; ip->imm = s&0xffff; } break; case Awd: /* Address-sized immediate (no sign extension)*/ if (ip->asize == 'E') { if (igetl(map, ip, &ip->imm) < 0) return 0; /* TO DO: REX */ } else { if (igets(map, ip, &s)< 0) return 0; ip->imm = s&0xffff; } break; case Iwds: /* Operand-sized immediate (sign extended) */ if (ip->osize == 'L') { if (igetl(map, ip, &ip->imm) < 0) return 0; } else { if (igets(map, ip, &s)< 0) return 0; if (s&0x8000) ip->imm = s|0xffff0000; else ip->imm = s&0xffff; } ip->jumptype = Iwds; break; case OA: /* literal 0x0a byte */ if (igetc(map, ip, &c) < 0) return 0; if (c != 0x0a) goto badop; break; case R0: /* base register must be R0 */ if (ip->base != 0) goto badop; break; case R1: /* base register must be R1 */ if (ip->base != 1) goto badop; break; case RMB: /* R/M field with byte register (/r)*/ if (igetc(map, ip, &c) < 0) return 0; if (modrm(map, ip, c) < 0) return 0; ip->osize = 'B'; break; case RM: /* R/M field with register (/r) */ if (igetc(map, ip, &c) < 0) return 0; if (modrm(map, ip, c) < 0) return 0; break; case RMOPB: /* R/M field with op code (/digit) */ if (igetc(map, ip, &c) < 0) return 0; if (modrm(map, ip, c) < 0) return 0; c = ip->reg; /* secondary op code */ obase = (Optable*)op->proto; ip->osize = 'B'; goto newop; case RMOP: /* R/M field with op code (/digit) */ if (igetc(map, ip, &c) < 0) return 0; if (modrm(map, ip, c) < 0) return 0; obase = (Optable*)op->proto; if(ip->amd64 && obase == optab0F01 && c == 0xF8) return optab0F01F8; c = ip->reg; goto newop; case FRMOP: /* FP R/M field with op code (/digit) */ if (igetc(map, ip, &c) < 0) return 0; if (modrm(map, ip, c) < 0) return 0; if ((c&0xc0) == 0xc0) c = ip->reg+8; /* 16 entry table */ else c = ip->reg; obase = (Optable*)op->proto; goto newop; case FRMEX: /* Extended FP R/M field with op code (/digit) */ if (igetc(map, ip, &c) < 0) return 0; if (modrm(map, ip, c) < 0) return 0; if ((c&0xc0) == 0xc0) c = (c&0x3f)+8; /* 64-entry table */ else c = ip->reg; obase = (Optable*)op->proto; goto newop; case RMR: /* R/M register only (mod = 11) */ if (igetc(map, ip, &c) < 0) return 0; if ((c&0xc0) != 0xc0) { werrstr("invalid R/M register: %x", c); return 0; } if (modrm(map, ip, c) < 0) return 0; break; case RMM: /* R/M register only (mod = 11) */ if (igetc(map, ip, &c) < 0) return 0; if ((c&0xc0) == 0xc0) { werrstr("invalid R/M memory mode: %x", c); return 0; } if (modrm(map, ip, c) < 0) return 0; break; case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */ if (ip->osize == 'L') { if (igetl(map, ip, &ip->disp) < 0) return 0; } else { if (igets(map, ip, &s)< 0) return 0; ip->disp = s&0xffff; } if (igets(map, ip, (ushort*)&ip->seg) < 0) return 0; ip->jumptype = PTR; break; case AUXMM: /* Multi-byte op code; prefix determines table selection */ if (igetc(map, ip, &c) < 0) return 0; obase = (Optable*)op->proto; switch (ip->opre) { case 0x66: op = optab660F; break; case 0xF2: op = optabF20F; break; case 0xF3: op = optabF30F; break; default: op = nil; break; } if(op != nil && op[c].proto != nil) obase = op; norex = 1; /* no more rex prefixes */ /* otherwise the optab entry captures it */ goto newop; case AUX: /* Multi-byte op code - Auxiliary table */ obase = (Optable*)op->proto; if (igetc(map, ip, &c) < 0) return 0; goto newop; case OPRE: /* Instr Prefix or media op */ ip->opre = c; /* fall through */ case PRE: /* Instr Prefix */ ip->prefix = (char*)op->proto; if (igetc(map, ip, &c) < 0) return 0; if (ip->opre && c == 0x0F) ip->prefix = 0; goto newop; case SEG: /* Segment Prefix */ ip->segment = (char*)op->proto; if (igetc(map, ip, &c) < 0) return 0; goto newop; case OPOVER: /* Operand size override */ ip->opre = c; ip->osize = 'W'; if (igetc(map, ip, &c) < 0) return 0; if (c == 0x0F) ip->osize = 'L'; else if (ip->amd64 && (c&0xF0) == 0x40) ip->osize = 'Q'; goto newop; case ADDOVER: /* Address size override */ ip->asize = 0; if (igetc(map, ip, &c) < 0) return 0; goto newop; case JUMP: /* mark instruction as JUMP or RET */ case RET: ip->jumptype = op->operand[i]; break; default: werrstr("bad operand type %d", op->operand[i]); return 0; } } return op; } #pragma varargck argpos bprint 2 static void bprint(Instr *ip, char *fmt, ...) { va_list arg; va_start(arg, fmt); ip->curr = vseprint(ip->curr, ip->end, fmt, arg); va_end(arg); } /* * if we want to call 16 bit regs AX,BX,CX,... * and 32 bit regs EAX,EBX,ECX,... then * change the defs of ANAME and ONAME to: * #define ANAME(ip) ((ip->asize == 'E' ? "E" : "") * #define ONAME(ip) ((ip)->osize == 'L' ? "E" : "") */ #define ANAME(ip) "" #define ONAME(ip) "" static char *reg[] = { "AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI", /* amd64 */ "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", }; static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" }; static char *breg64[] = { "AL", "CL", "DL", "BL", "SPB", "BPB", "SIB", "DIB", "R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B" }; static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" }; static void plocal(Instr *ip) { int ret; long offset; Symbol s; char *reg; offset = ip->disp; if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) { bprint(ip, "%lux(SP)", offset); return; } if (s.value > ip->disp) { ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s); reg = "(SP)"; } else { offset -= s.value; ret = getauto(&s, offset, CPARAM, &s); reg = "(FP)"; } if (ret) bprint(ip, "%s+", s.name); else offset = ip->disp; bprint(ip, "%lux%s", offset, reg); } static int isjmp(Instr *ip) { switch(ip->jumptype){ case Iwds: case Jbs: case JUMP: return 1; default: return 0; } } /* * This is too smart for its own good, but it really is nice * to have accurate translations when debugging, and it * helps us identify which code is different in binaries that * are changed on sources. */ static int issymref(Instr *ip, Symbol *s, long w, long val) { Symbol next, tmp; long isstring, size; if (isjmp(ip)) return 1; if (s->class==CTEXT && w==0) return 1; if (s->class==CDATA) { /* use first bss symbol (or "end") rather than edata */ if (s->name[0]=='e' && strcmp(s->name, "edata") == 0){ if((s ->index >= 0 && globalsym(&tmp, s->index+1) && tmp.value==s->value) || (s->index > 0 && globalsym(&tmp, s->index-1) && tmp.value==s->value)) *s = tmp; } if (w == 0) return 1; for (next=*s; next.value==s->value; next=tmp) if (!globalsym(&tmp, next.index+1)) break; size = next.value - s->value; if (w >= size) return 0; if (w > size-w) w = size-w; /* huge distances are usually wrong except in .string */ isstring = (s->name[0]=='.' && strcmp(s->name, ".string") == 0); if (w > 8192 && !isstring) return 0; /* medium distances are tricky - look for constants */ /* near powers of two */ if ((val&(val-1)) == 0 || (val&(val+1)) == 0) return 0; return 1; } return 0; } static void immediate(Instr *ip, vlong val) { Symbol s; long w; if (findsym(val, CANY, &s)) { /* TO DO */ w = val - s.value; if (w < 0) w = -w; if (issymref(ip, &s, w, val)) { if (w) bprint(ip, "%s+%lux(SB)", s.name, w); else bprint(ip, "%s(SB)", s.name); return; } /* if (s.class==CDATA && globalsym(&s, s.index+1)) { w = s.value - val; if (w < 0) w = -w; if (w < 4096) { bprint(ip, "%s-%lux(SB)", s.name, w); return; } } */ } if((ip->rex & REXW) == 0) bprint(ip, "%lux", (long)val); else bprint(ip, "%llux", val); } static void pea(Instr *ip) { if (ip->mod == 3) { if (ip->osize == 'B') bprint(ip, (ip->rex & REXB? breg64: breg)[ip->base]); else if(ip->rex & REXB) bprint(ip, "%s%s", ANAME(ip), reg[ip->base+8]); else bprint(ip, "%s%s", ANAME(ip), reg[ip->base]); return; } if (ip->segment) bprint(ip, ip->segment); if (ip->asize == 'E' && ip->base == SP) plocal(ip); else { if (ip->base < 0) immediate(ip, ip->disp); else { bprint(ip, "%lux", ip->disp); if(ip->rip) bprint(ip, "(RIP)"); bprint(ip,"(%s%s)", ANAME(ip), reg[ip->rex&REXB? ip->base+8: ip->base]); } } if (ip->index >= 0) bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->rex&REXX? ip->index+8: ip->index], 1<ss); } static void prinstr(Instr *ip, char *fmt) { vlong v; if (ip->prefix) bprint(ip, "%s ", ip->prefix); for (; *fmt && ip->curr < ip->end; fmt++) { if (*fmt != '%'){ *ip->curr++ = *fmt; continue; } switch(*++fmt){ case '%': *ip->curr++ = '%'; break; case 'A': bprint(ip, "%s", ANAME(ip)); break; case 'C': bprint(ip, "CR%d", ip->reg); break; case 'D': if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7) bprint(ip, "DR%d",ip->reg); else bprint(ip, "?"); break; case 'I': bprint(ip, "$"); immediate(ip, ip->imm2); break; case 'O': bprint(ip,"%s", ONAME(ip)); break; case 'i': bprint(ip, "$"); v = ip->imm; if(ip->rex & REXW) v = ip->imm64; immediate(ip, v); break; case 'R': bprint(ip, "%s%s", ONAME(ip), reg[ip->rex&REXR? ip->reg+8: ip->reg]); break; case 'S': if(ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW) bprint(ip, "Q"); else bprint(ip, "%c", ip->osize); break; case 's': if(ip->opre == 0 || ip->opre == 0x66) bprint(ip, "P"); else bprint(ip, "S"); if(ip->opre == 0xf2 || ip->opre == 0x66) bprint(ip, "D"); else bprint(ip, "S"); break; case 'T': if (ip->reg == 6 || ip->reg == 7) bprint(ip, "TR%d",ip->reg); else bprint(ip, "?"); break; case 'W': if (ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW) bprint(ip, "CDQE"); else if (ip->osize == 'L') bprint(ip,"CWDE"); else bprint(ip, "CBW"); break; case 'd': bprint(ip,"%ux:%lux",ip->seg,ip->disp); break; case 'm': if (ip->mod == 3 && ip->osize != 'B') { if(fmt[1] != '*'){ if(ip->opre != 0) { bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base); break; } } else fmt++; bprint(ip, "M%d", ip->base); break; } pea(ip); break; case 'e': pea(ip); break; case 'f': bprint(ip, "F%d", ip->base); break; case 'g': if (ip->reg < 6) bprint(ip,"%s",sreg[ip->reg]); else bprint(ip,"?"); break; case 'p': /* * signed immediate in the ulong ip->imm. */ v = (long)ip->imm; immediate(ip, v+ip->addr+ip->n); break; case 'r': if (ip->osize == 'B') bprint(ip,"%s", (ip->rex? breg64: breg)[ip->rex&REXR? ip->reg+8: ip->reg]); else bprint(ip, reg[ip->rex&REXR? ip->reg+8: ip->reg]); break; case 'w': if (ip->osize == 'Q' || ip->rex & REXW) bprint(ip, "CQO"); else if (ip->osize == 'L') bprint(ip,"CDQ"); else bprint(ip, "CWD"); break; case 'M': if(ip->opre != 0) bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg); else bprint(ip, "M%d", ip->reg); break; case 'x': if (ip->mod == 3 && ip->osize != 'B') { bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base); break; } pea(ip); break; case 'X': bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg); break; default: bprint(ip, "%%%c", *fmt); break; } } *ip->curr = 0; /* there's always room for 1 byte */ } static int i386inst(Map *map, uvlong pc, char modifier, char *buf, int n) { Instr instr; Optable *op; USED(modifier); op = mkinstr(map, &instr, pc); if (op == 0) { errstr(buf, n); return -1; } instr.curr = buf; instr.end = buf+n-1; prinstr(&instr, op->proto); return instr.n; } static int i386das(Map *map, uvlong pc, char *buf, int n) { Instr instr; int i; if (mkinstr(map, &instr, pc) == 0) { errstr(buf, n); return -1; } for(i = 0; i < instr.n && n > 2; i++) { _hexify(buf, instr.mem[i], 1); buf += 2; n -= 2; } *buf = 0; return instr.n; } static int i386instlen(Map *map, uvlong pc) { Instr i; if (mkinstr(map, &i, pc)) return i.n; return -1; } static int i386foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll) { Instr i; Optable *op; ushort s; uvlong l, addr; vlong v; int n; op = mkinstr(map, &i, pc); if (!op) return -1; n = 0; switch(i.jumptype) { case RET: /* RETURN or LEAVE */ case Iw: /* RETURN */ if (strcmp(op->proto, "LEAVE") == 0) { if (geta(map, (*rget)(map, "BP"), &l) < 0) return -1; } else if (geta(map, (*rget)(map, mach->sp), &l) < 0) return -1; foll[0] = l; return 1; case Iwds: /* pc relative JUMP or CALL*/ case Jbs: /* pc relative JUMP or CALL */ v = (long)i.imm; foll[0] = pc+v+i.n; n = 1; break; case PTR: /* seg:displacement JUMP or CALL */ foll[0] = (i.seg<<4)+i.disp; return 1; case JUMP: /* JUMP or CALL EA */ if(i.mod == 3) { foll[0] = (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]); return 1; } /* calculate the effective address */ addr = i.disp; if (i.base >= 0) { if (geta(map, (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]), &l) < 0) return -1; addr += l; } if (i.index >= 0) { if (geta(map, (*rget)(map, reg[i.rex&REXX? i.index+8: i.index]), &l) < 0) return -1; addr += l*(1<proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0) return 1; foll[n++] = pc+i.n; return n; }