This is i386_disasm.c in view mode; [Download] [Up]
/* * This file contains the i386 disassembler routine used at NeXT Computer, Inc. * to match the the assembler used at NeXT. It was adapted from a set of * source files with the following copyright which is retained below. */ /* Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appears in all copies and that both the copyright notice and this permission notice appear in supporting documentation, and that the name of Intel not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <stdio.h> #include <string.h> #include <mach-o/loader.h> #include <mach-o/nlist.h> #include <mach-o/reloc.h> #include "bytesex.h" #include "otool.h" #include "defs.h" #include "symtab.h" #include "dis-asm.h" #define MAX_MNEMONIC 9 /* Maximum number of chars per mnemonic */ #define MAX_RESULT 14 /* Maximum number of char in a register */ /* result expression "(%ebx,%ecx,8)" */ #define WBIT(x) (x & 0x1) /* to get w bit */ #define REGNO(x) (x & 0x7) /* to get 3 bit register */ #define VBIT(x) ((x)>>1 & 0x1) /* to get 'v' bit */ #define OPSIZE(data16, wbit) ((wbit) ? ((data16) ? 2 : 4) : 1) #define REG_ONLY 3 /* mode indicates a single register with */ /* no displacement is an operand */ #define BYTEOPERAND 0 /* value of the w-bit indicating a byte */ /* operand (1-byte) */ #define LONGOPERAND 1 /* value of the w-bit indicating a long */ /* operand (2-bytes or 4-bytes) */ #define EBP 5 #define ESP 4 /* * This is the structure that is used for storing all the op code information. */ struct instable { char name[MAX_MNEMONIC]; const struct instable *indirect; unsigned adr_mode; int suffix; /* for instructions which may have a 'w' or 'l' suffix */ }; #define TERM 0 /* used to indicate that the 'indirect' field of the */ /* 'instable' terminates - no pointer. */ #define INVALID {"", TERM, UNKNOWN, 0} /* #define value dis_value */ static void get_operand( const char **symbol, unsigned long *value, unsigned long *value_size, char *result, const unsigned long mode, const unsigned long r_m, const unsigned long wbit, const enum bool data16, const enum bool addr16, const char *sect, unsigned long *length, unsigned long *left, const unsigned long addr, const struct relocation_info *sorted_relocs, const unsigned long nsorted_relocs, const struct nlist *symbols, const unsigned long nsymbols, const char *strings, const unsigned long strings_size, const struct nlist *sorted_symbols, const unsigned long nsorted_symbols, const enum bool verbose); static void immediate( const char **symbol, unsigned long *value, const unsigned long value_size, const char *sect, unsigned long *length, unsigned long *left, const unsigned long addr, const struct relocation_info *sorted_relocs, const unsigned long nsorted_relocs, const struct nlist *symbols, const unsigned long nsymbols, const char *strings, const unsigned long strings_size, const struct nlist *sorted_symbols, const unsigned long nsorted_symbols, const enum bool verbose); static void displacement( const char **symbol, unsigned long *value, const unsigned long value_size, const char *sect, unsigned long *length, unsigned long *left, const unsigned long addr, const struct relocation_info *sorted_relocs, const unsigned long nsorted_relocs, const struct nlist *symbols, const unsigned long nsymbols, const char *strings, const unsigned long strings_size, const struct nlist *sorted_symbols, const unsigned long nsorted_symbols, const enum bool verbose); static const char * get_symbol( const unsigned long sect_offset, const struct relocation_info *sorted_relocs, const unsigned long nsorted_relocs, const struct nlist *symbols, const unsigned long nsymbols, const char *strings, const unsigned long strings_size, const enum bool verbose); static const char * guess_symbol( const unsigned long value, const struct nlist *sorted_symbols, const unsigned long nsorted_symbols, const enum bool verbose); static void print_operand( FILE *stream, const char *seg, const char *symbol, const unsigned int value, const unsigned int value_size, const char *result, const char *tail); static unsigned long get_value( const unsigned long size, const char *sect, unsigned long *length, unsigned long *left); static void modrm_byte( unsigned long *mode, unsigned long *reg, unsigned long *r_m, unsigned char byte); static const char * gdb_get_symbol( const unsigned long sect_offset); static const char * gdb_guess_symbol( const unsigned long value); #define GET_OPERAND(symbol, value, value_size, result) \ get_operand((symbol), (value), (value_size), (result), mode, r_m, \ wbit, data16, addr16, sect, &length, &left, addr, \ sorted_relocs, nsorted_relocs, symbols, nsymbols, \ strings, strings_size, sorted_symbols, \ nsorted_symbols, verbose) #define DISPLACEMENT(symbol, value, value_size) \ displacement((symbol), (value), (value_size), sect, &length, \ &left, addr, sorted_relocs, nsorted_relocs, symbols, \ nsymbols, strings, strings_size, sorted_symbols, \ nsorted_symbols, verbose) #define IMMEDIATE(symbol, value, value_size) \ immediate((symbol), (value), (value_size), sect, &length, &left, addr,\ sorted_relocs, nsorted_relocs, symbols, nsymbols, strings, \ strings_size, sorted_symbols, nsorted_symbols, verbose) #if 0 #define GET_SYMBOL(sect_offset) \ get_symbol((sect_offset), sorted_relocs, nsorted_relocs, symbols, \ nsymbols, strings, strings_size, verbose) #define GUESS_SYMBOL(value) \ guess_symbol((value), sorted_symbols, nsorted_symbols, verbose) #else #define GET_SYMBOL(sect_offset) gdb_get_symbol(sect_offset) #define GUESS_SYMBOL(value) gdb_guess_symbol(value) #endif /* * These are the instruction formats as they appear in the disassembly tables. * Here they are given numerical values for use in the actual disassembly of * an instruction. */ #define UNKNOWN 0 #define MRw 2 #define IMlw 3 #define IMw 4 #define IR 5 #define OA 6 #define AO 7 #define MS 8 #define SM 9 #define Mv 10 #define Mw 11 #define M 12 #define R 13 #define RA 14 #define SEG 15 #define MR 16 #define IA 17 #define MA 18 #define SD 19 #define AD 20 #define SA 21 #define D 22 #define INM 23 #define SO 24 #define BD 25 #define I 26 #define P 27 #define V 28 #define DSHIFT 29 /* for double shift that has an 8-bit immediate */ #define U 30 #define OVERRIDE 31 #define GO_ON 32 #define O 33 /* for call */ #define JTAB 34 /* jump table (not used at NeXT) */ #define IMUL 35 /* for 186 iimul instr */ #define CBW 36 /* so that data16 can be evaluated for cbw and its variants */ #define MvI 37 /* for 186 logicals */ #define ENTER 38 /* for 186 enter instr */ #define RMw 39 /* for 286 arpl instr */ #define Ib 40 /* for push immediate byte */ #define F 41 /* for 287 instructions */ #define FF 42 /* for 287 instructions */ #define DM 43 /* 16-bit data */ #define AM 44 /* 16-bit addr */ #define LSEG 45 /* for 3-bit seg reg encoding */ #define MIb 46 /* for 386 logicals */ #define SREG 47 /* for 386 special registers */ #define PREFIX 48 /* an instruction prefix like REP, LOCK */ #define INT3 49 /* The int 3 instruction, which has a fake operand */ #define DSHIFTcl 50 /* for double shift that implicitly uses %cl */ #define CWD 51 /* so that data16 can be evaluated for cwd and vars */ #define RET 52 /* single immediate 16-bit operand */ #define MOVZ 53 /* for movs and movz, with different size operands */ #define XINST 54 /* for cmpxchg and xadd */ #define BSWAP 55 /* for bswap */ #define Pi 56 #define Po 57 #define Vi 58 #define Vo 59 #define Mb 60 #define INMl 61 /* * In 16-bit addressing mode: * Register operands may be indicated by a distinguished field. * An '8' bit register is selected if the 'w' bit is equal to 0, * and a '16' bit register is selected if the 'w' bit is equal to * 1 and also if there is no 'w' bit. */ static const char * const REG16[8][2] = { /* w bit 0 1 */ /* reg bits */ /* 000 */ "%al", "%ax", /* 001 */ "%cl", "%cx", /* 010 */ "%dl", "%dx", /* 011 */ "%bl", "%bx", /* 100 */ "%ah", "%sp", /* 101 */ "%ch", "%bp", /* 110 */ "%dh", "%si", /* 111 */ "%bh", "%di", }; /* * In 32-bit addressing mode: * Register operands may be indicated by a distinguished field. * An '8' bit register is selected if the 'w' bit is equal to 0, * and a '32' bit register is selected if the 'w' bit is equal to * 1 and also if there is no 'w' bit. */ static const char * const REG32[8][2] = { /* w bit 0 1 */ /* reg bits */ /* 000 */ "%al", "%eax", /* 001 */ "%cl", "%ecx", /* 010 */ "%dl", "%edx", /* 011 */ "%bl", "%ebx", /* 100 */ "%ah", "%esp", /* 101 */ "%ch", "%ebp", /* 110 */ "%dh", "%esi", /* 111 */ "%bh", "%edi", }; /* * In 16-bit mode: * This initialized array will be indexed by the 'r/m' and 'mod' * fields, to determine the size of the displacement in each mode. */ static const char dispsize16 [8][4] = { /* mod 00 01 10 11 */ /* r/m */ /* 000 */ 0, 1, 2, 0, /* 001 */ 0, 1, 2, 0, /* 010 */ 0, 1, 2, 0, /* 011 */ 0, 1, 2, 0, /* 100 */ 0, 1, 2, 0, /* 101 */ 0, 1, 2, 0, /* 110 */ 2, 1, 2, 0, /* 111 */ 0, 1, 2, 0 }; /* * In 32-bit mode: * This initialized array will be indexed by the 'r/m' and 'mod' * fields, to determine the size of the displacement in this mode. */ static const char dispsize32 [8][4] = { /* mod 00 01 10 11 */ /* r/m */ /* 000 */ 0, 1, 4, 0, /* 001 */ 0, 1, 4, 0, /* 010 */ 0, 1, 4, 0, /* 011 */ 0, 1, 4, 0, /* 100 */ 0, 1, 4, 0, /* 101 */ 4, 1, 4, 0, /* 110 */ 0, 1, 4, 0, /* 111 */ 0, 1, 4, 0 }; /* * When data16 has been specified, the following array specifies the registers * for the different addressing modes. Indexed first by mode, then by register * number. */ static const char * const regname16[4][8] = { /*reg 000 001 010 011 100 101 110 111 */ /*mod*/ /*00*/ "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "", "%bx", /*01*/ "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx", /*10*/ "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx", /*11*/ "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" }; /* * When data16 has not been specified, fields, to determine the * addressing mode, and will also provide strings for printing. */ static const char * const regname32[4][8] = { /*reg 000 001 010 011 100 101 110 111 */ /*mod*/ /*00 */ "%eax", "%ecx", "%edx", "%ebx", "%esp", "", "%esi", "%edi", /*01 */ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", /*10 */ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", /*11 */ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" }; /* * If r/m==100 then the following byte (the s-i-b byte) must be decoded */ static const char * const scale_factor[4] = { "1", "2", "4", "8" }; static const char * const indexname[8] = { ",%eax", ",%ecx", ",%edx", ",%ebx", "", ",%ebp", ",%esi", ",%edi" }; /* * Segment registers are selected by a two or three bit field. */ static const char * const SEGREG[6] = { /* 000 */ "%es", /* 001 */ "%cs", /* 010 */ "%ss", /* 011 */ "%ds", /* 100 */ "%fs", /* 101 */ "%gs", }; /* * Special Registers */ static const char * const DEBUGREG[8] = { "%db0", "%db1", "%db2", "%db3", "%db4", "%db5", "%db6", "%db7" }; static const char * const CONTROLREG[8] = { "%cr0", "%cr1", "%cr2", "%cr3", "%cr4?", "%cr5?", "%cr6?", "%cr7?" }; static const char * const TESTREG[8] = { "%tr0?", "%tr1?", "%tr2?", "%tr3", "%tr4", "%tr5", "%tr6", "%tr7" }; /* * Decode table for 0x0F00 opcodes */ static const struct instable op0F00[8] = { /* [0] */ {"sldt",TERM,M,1}, {"str",TERM,M,1}, {"lldt",TERM,M,1}, {"ltr",TERM,M,1}, /* [4] */ {"verr",TERM,M,1}, {"verw",TERM,M,1}, INVALID, INVALID, }; /* * Decode table for 0x0F01 opcodes */ static const struct instable op0F01[8] = { /* [0] */ {"sgdt",TERM,M,1}, {"sidt",TERM,M,1}, {"lgdt",TERM,M,1}, {"lidt",TERM,M,1}, /* [4] */ {"smsw",TERM,M,1}, INVALID, {"lmsw",TERM,M,1}, {"invlpg",TERM,M,1}, }; /* * Decode table for 0x0FBA opcodes */ static const struct instable op0FBA[8] = { /* [0] */ INVALID, INVALID, INVALID, INVALID, /* [4] */ {"bt",TERM,MIb,1}, {"bts",TERM,MIb,1}, {"btr",TERM,MIb,1}, {"btc",TERM,MIb,1}, }; /* * Decode table for 0x0F opcodes */ static const struct instable op0F[13][16] = { /* [00] */ { {"",op0F00,TERM,0}, {"",op0F01,TERM,0}, {"lar",TERM,MR,0}, {"lsl",TERM,MR,0}, /* [04] */ INVALID, INVALID, {"clts",TERM,GO_ON,0}, INVALID, /* [08] */ {"invd",TERM,GO_ON,0}, {"wbinvd",TERM,GO_ON,0}, INVALID, INVALID, /* [0C] */ INVALID, INVALID, INVALID, INVALID }, /* [10] */ { INVALID, INVALID, INVALID, INVALID, /* [14] */ INVALID, INVALID, INVALID, INVALID, /* [18] */ INVALID, INVALID, INVALID, INVALID, /* [1C] */ INVALID, INVALID, INVALID, INVALID }, /* [20] */ { {"mov",TERM,SREG,1}, {"mov",TERM,SREG,1}, {"mov",TERM,SREG,1}, {"mov",TERM,SREG,1}, /* [24] */ {"mov",TERM,SREG,1}, INVALID, {"mov",TERM,SREG,1}, INVALID, /* [28] */ INVALID, INVALID, INVALID, INVALID, /* [2C] */ INVALID, INVALID, INVALID, INVALID }, /* [30] */ { {"wrmsr",TERM,GO_ON,0}, {"rdtsc",TERM,GO_ON,0}, {"rdmsr",TERM,GO_ON,0}, INVALID, /* [34] */ INVALID, INVALID, INVALID, INVALID, /* [38] */ INVALID, INVALID, INVALID, INVALID, /* [3C] */ INVALID, INVALID, INVALID, INVALID }, /* [40] */ { INVALID, INVALID, INVALID, INVALID, /* [44] */ INVALID, INVALID, INVALID, INVALID, /* [48] */ INVALID, INVALID, INVALID, INVALID, /* [4C] */ INVALID, INVALID, INVALID, INVALID }, /* [50] */ { INVALID, INVALID, INVALID, INVALID, /* [54] */ INVALID, INVALID, INVALID, INVALID, /* [58] */ INVALID, INVALID, INVALID, INVALID, /* [5C] */ INVALID, INVALID, INVALID, INVALID }, /* [60] */ { INVALID, INVALID, INVALID, INVALID, /* [64] */ INVALID, INVALID, INVALID, INVALID, /* [68] */ INVALID, INVALID, INVALID, INVALID, /* [6C] */ INVALID, INVALID, INVALID, INVALID }, /* [70] */ { INVALID, INVALID, INVALID, INVALID, /* [74] */ INVALID, INVALID, INVALID, INVALID, /* [78] */ INVALID, INVALID, INVALID, INVALID, /* [7C] */ INVALID, INVALID, INVALID, INVALID }, /* [80] */ { {"jo",TERM,D,1}, {"jno",TERM,D,1}, {"jb",TERM,D,1}, {"jae",TERM,D,1}, /* [84] */ {"je",TERM,D,1}, {"jne",TERM,D,1}, {"jbe",TERM,D,1}, {"ja",TERM,D,1}, /* [88] */ {"js",TERM,D,1}, {"jns",TERM,D,1}, {"jp",TERM,D,1}, {"jnp",TERM,D,1}, /* [8C] */ {"jl",TERM,D,1}, {"jge",TERM,D,1}, {"jle",TERM,D,1}, {"jg",TERM,D,1} }, /* [90] */ { {"seto",TERM,Mb,1}, {"setno",TERM,Mb,1}, {"setb",TERM,Mb,1}, {"setae",TERM,Mb,1}, /* [94] */ {"sete",TERM,Mb,1}, {"setne",TERM,Mb,1}, {"setbe",TERM,Mb,1}, {"seta",TERM,Mb,1}, /* [98] */ {"sets",TERM,Mb,1}, {"setns",TERM,Mb,1}, {"setp",TERM,Mb,1}, {"setnp",TERM,Mb,1}, /* [9C] */ {"setl",TERM,Mb,1}, {"setge",TERM,Mb,1}, {"setle",TERM,Mb,1}, {"setg",TERM,Mb,1} }, /* [A0] */ { {"push",TERM,LSEG,1}, {"pop",TERM,LSEG,1}, {"cpuid",TERM,GO_ON,0}, {"bt",TERM,RMw,1}, /* [A4] */ {"shld",TERM,DSHIFT,1}, {"shld",TERM,DSHIFTcl,1}, {"cmpxchgb",TERM,XINST,0}, {"cmpxchg",TERM,XINST,1}, /* [A8] */ {"push",TERM,LSEG,1}, {"pop",TERM,LSEG,1}, {"rsm",TERM,GO_ON,0}, {"bts",TERM,RMw,1}, /* [AC] */ {"shrd",TERM,DSHIFT,1}, {"shrd",TERM,DSHIFTcl,1}, INVALID, {"imul",TERM,MRw,1} }, /* [B0] */ { INVALID, INVALID, {"lss",TERM,MR,0}, {"btr",TERM,RMw,1}, /* [B4] */ {"lfs",TERM,MR,0}, {"lgs",TERM,MR,0}, {"movzb",TERM,MOVZ,1}, {"movzwl",TERM,MOVZ,0}, /* [B8] */ INVALID, INVALID, {"",op0FBA,TERM,0}, {"btc",TERM,RMw,1}, /* [BC] */ {"bsf",TERM,MRw,1}, {"bsr",TERM,MRw,1}, {"movsb",TERM,MOVZ,1}, {"movswl",TERM,MOVZ,0} }, /* [C0] */ { {"xaddb",TERM,XINST,0}, {"xadd",TERM,XINST,1}, INVALID, INVALID, /* [C4] */ INVALID, INVALID, INVALID, {"cmpxchg8b",TERM,M,1}, /* [C8] */ {"bswap",TERM,BSWAP,0}, {"bswap",TERM,BSWAP,0}, {"bswap",TERM,BSWAP,0}, {"bswap",TERM,BSWAP,0}, /* [CC] */ {"bswap",TERM,BSWAP,0}, {"bswap",TERM,BSWAP,0}, {"bswap",TERM,BSWAP,0}, {"bswap",TERM,BSWAP,0} }, }; /* * Decode table for 0x80 opcodes */ static const struct instable op80[8] = { /* [0] */ {"addb",TERM,IMlw,0}, {"orb",TERM,IMw,0}, {"adcb",TERM,IMlw,0}, {"sbbb",TERM,IMlw,0}, /* [4] */ {"andb",TERM,IMw,0}, {"subb",TERM,IMlw,0}, {"xorb",TERM,IMw,0}, {"cmpb",TERM,IMlw,0}, }; /* * Decode table for 0x81 opcodes. */ static const struct instable op81[8] = { /* [0] */ {"add",TERM,IMlw,1}, {"or",TERM,IMw,1}, {"adc",TERM,IMlw,1}, {"sbb",TERM,IMlw,1}, /* [4] */ {"and",TERM,IMw,1}, {"sub",TERM,IMlw,1}, {"xor",TERM,IMw,1}, {"cmp",TERM,IMlw,1}, }; /* * Decode table for 0x82 opcodes. */ static const struct instable op82[8] = { /* [0] */ {"addb",TERM,IMlw,0}, INVALID, {"adcb",TERM,IMlw,0}, {"sbbb",TERM,IMlw,0}, /* [4] */ INVALID, {"subb",TERM,IMlw,0}, INVALID, {"cmpb",TERM,IMlw,0}, }; /* * Decode table for 0x83 opcodes. */ static const struct instable op83[8] = { /* [0] */ {"add",TERM,IMlw,1}, {"or",TERM,IMlw,1}, {"adc",TERM,IMlw,1}, {"sbb",TERM,IMlw,1}, /* [4] */ {"and",TERM,IMlw,1}, {"sub",TERM,IMlw,1}, {"xor",TERM,IMlw,1}, {"cmp",TERM,IMlw,1}, }; /* * Decode table for 0xC0 opcodes. */ static const struct instable opC0[8] = { /* [0] */ {"rolb",TERM,MvI,0}, {"rorb",TERM,MvI,0}, {"rclb",TERM,MvI,0}, {"rcrb",TERM,MvI,0}, /* [4] */ {"shlb",TERM,MvI,0}, {"shrb",TERM,MvI,0}, INVALID, {"sarb",TERM,MvI,0}, }; /* * Decode table for 0xD0 opcodes. */ static const struct instable opD0[8] = { /* [0] */ {"rolb",TERM,Mv,0}, {"rorb",TERM,Mv,0}, {"rclb",TERM,Mv,0}, {"rcrb",TERM,Mv,0}, /* [4] */ {"shlb",TERM,Mv,0}, {"shrb",TERM,Mv,0}, INVALID, {"sarb",TERM,Mv,0}, }; /* * Decode table for 0xC1 opcodes. * 186 instruction set */ static const struct instable opC1[8] = { /* [0] */ {"rol",TERM,MvI,1}, {"ror",TERM,MvI,1}, {"rcl",TERM,MvI,1}, {"rcr",TERM,MvI,1}, /* [4] */ {"shl",TERM,MvI,1}, {"shr",TERM,MvI,1}, INVALID, {"sar",TERM,MvI,1}, }; /* * Decode table for 0xD1 opcodes. */ static const struct instable opD1[8] = { /* [0] */ {"rol",TERM,Mv,1}, {"ror",TERM,Mv,1}, {"rcl",TERM,Mv,1}, {"rcr",TERM,Mv,1}, /* [4] */ {"shl",TERM,Mv,1}, {"shr",TERM,Mv,1}, INVALID, {"sar",TERM,Mv,1}, }; /* * Decode table for 0xD2 opcodes. */ static const struct instable opD2[8] = { /* [0] */ {"rolb",TERM,Mv,0}, {"rorb",TERM,Mv,0}, {"rclb",TERM,Mv,0}, {"rcrb",TERM,Mv,0}, /* [4] */ {"shlb",TERM,Mv,0}, {"shrb",TERM,Mv,0}, INVALID, {"sarb",TERM,Mv,0}, }; /* * Decode table for 0xD3 opcodes. */ static const struct instable opD3[8] = { /* [0] */ {"rol",TERM,Mv,1}, {"ror",TERM,Mv,1}, {"rcl",TERM,Mv,1}, {"rcr",TERM,Mv,1}, /* [4] */ {"shl",TERM,Mv,1}, {"shr",TERM,Mv,1}, INVALID, {"sar",TERM,Mv,1}, }; /* * Decode table for 0xF6 opcodes. */ static const struct instable opF6[8] = { /* [0] */ {"testb",TERM,IMw,0}, INVALID, {"notb",TERM,Mw,0}, {"negb",TERM,Mw,0}, /* [4] */ {"mulb",TERM,MA,0}, {"imulb",TERM,MA,0}, {"divb",TERM,MA,0}, {"idivb",TERM,MA,0}, }; /* * Decode table for 0xF7 opcodes. */ static const struct instable opF7[8] = { /* [0] */ {"test",TERM,IMw,1}, INVALID, {"not",TERM,Mw,1}, {"neg",TERM,Mw,1}, /* [4] */ {"mul",TERM,MA,1}, {"imul",TERM,MA,1}, {"div",TERM,MA,1}, {"idiv",TERM,MA,1}, }; /* * Decode table for 0xFE opcodes. */ static const struct instable opFE[8] = { /* [0] */ {"incb",TERM,Mw,0}, {"decb",TERM,Mw,0}, INVALID, INVALID, /* [4] */ INVALID, INVALID, INVALID, INVALID, }; /* * Decode table for 0xFF opcodes. */ static const struct instable opFF[8] = { /* [0] */ {"inc",TERM,Mw,1}, {"dec",TERM,Mw,1}, {"call",TERM,INM,1}, {"lcall",TERM,INMl,1}, /* [4] */ {"jmp",TERM,INM,1}, {"ljmp",TERM,INMl,1}, {"push",TERM,M,1}, INVALID, }; /* for 287 instructions, which are a mess to decode */ static const struct instable opFP1n2[8][8] = { /* bit pattern: 1101 1xxx MODxx xR/M */ /* [0,0] */ { {"fadds",TERM,M,1}, {"fmuls",TERM,M,1}, {"fcoms",TERM,M,1}, {"fcomps",TERM,M,1}, /* [0,4] */ {"fsubs",TERM,M,1}, {"fsubrs",TERM,M,1}, {"fdivs",TERM,M,1}, {"fdivrs",TERM,M,1} }, /* [1,0] */ { {"flds",TERM,M,1}, INVALID, {"fsts",TERM,M,1}, {"fstps",TERM,M,1}, /* [1,4] */ {"fldenv",TERM,M,1}, {"fldcw",TERM,M,1}, {"fnstenv",TERM,M,1}, {"fnstcw",TERM,M,1} }, /* [2,0] */ { {"fiaddl",TERM,M,1}, {"fimull",TERM,M,1}, {"ficoml",TERM,M,1}, {"ficompl",TERM,M,1}, /* [2,4] */ {"fisubl",TERM,M,1}, {"fisubrl",TERM,M,1}, {"fidivl",TERM,M,1}, {"fidivrl",TERM,M,1} }, /* [3,0] */ { {"fildl",TERM,M,1}, INVALID, {"fistl",TERM,M,1}, {"fistpl",TERM,M,1}, /* [3,4] */ INVALID, {"fldt",TERM,M,1}, INVALID, {"fstpt",TERM,M,1} }, /* [4,0] */ { {"faddl",TERM,M,1}, {"fmull",TERM,M,1}, {"fcoml",TERM,M,1}, {"fcompl",TERM,M,1}, /* [4,1] */ {"fsubl",TERM,M,1}, {"fsubrl",TERM,M,1}, {"fdivl",TERM,M,1}, {"fdivrl",TERM,M,1} }, /* [5,0] */ { {"fldl",TERM,M,1}, INVALID, {"fstl",TERM,M,1}, {"fstpl",TERM,M,1}, /* [5,4] */ {"frstor",TERM,M,1}, INVALID, {"fnsave",TERM,M,1}, {"fnstsw",TERM,M,1} }, /* [6,0] */ { {"fiadds",TERM,M,1}, {"fimuls",TERM,M,1}, {"ficoms",TERM,M,1}, {"ficomps",TERM,M,1}, /* [6,4] */ {"fisubs",TERM,M,1}, {"fisubrs",TERM,M,1}, {"fidivs",TERM,M,1}, {"fidivrs",TERM,M,1} }, /* [7,0] */ { {"filds",TERM,M,1}, INVALID, {"fists",TERM,M,1}, {"fistps",TERM,M,1}, /* [7,4] */ {"fbld",TERM,M,1}, {"fildq",TERM,M,1}, {"fbstp",TERM,M,1}, {"fistpq",TERM,M,1} }, }; static const struct instable opFP3[8][8] = { /* bit pattern: 1101 1xxx 11xx xREG */ /* [0,0] */ { {"fadd",TERM,FF,0}, {"fmul",TERM,FF,0}, {"fcom",TERM,F,0}, {"fcomp",TERM,F,0}, /* [0,4] */ {"fsub",TERM,FF,0}, {"fsubr",TERM,FF,0}, {"fdiv",TERM,FF,0}, {"fdivr",TERM,FF,0} }, /* [1,0] */ { {"fld",TERM,F,0}, {"fxch",TERM,F,0}, {"fnop",TERM,GO_ON,0}, {"fstp",TERM,F,0}, /* [1,4] */ INVALID, INVALID, INVALID, INVALID }, /* [2,0] */ { INVALID, INVALID, INVALID, INVALID, /* [2,4] */ INVALID, {"fucompp",TERM,GO_ON,0}, INVALID, INVALID }, /* [3,0] */ { INVALID, INVALID, INVALID, INVALID, /* [3,4] */ INVALID, INVALID, INVALID, INVALID }, /* [4,0] */ { {"fadd",TERM,FF,0}, {"fmul",TERM,FF,0}, {"fcom",TERM,F,0}, {"fcomp",TERM,F,0}, /* [4,4] */ {"fsub",TERM,FF,0}, {"fsubr",TERM,FF,0}, {"fdiv",TERM,FF,0}, {"fdivr",TERM,FF,0} }, /* [5,0] */ { {"ffree",TERM,F,0}, {"fxch",TERM,F,0}, {"fst",TERM,F,0}, {"fstp",TERM,F,0}, /* [5,4] */ {"fucom",TERM,F,0}, {"fucomp",TERM,F,0}, INVALID, INVALID }, /* [6,0] */ { {"faddp",TERM,FF,0}, {"fmulp",TERM,FF,0}, {"fcomp",TERM,F,0}, {"fcompp",TERM,GO_ON,0}, /* [6,4] */ {"fsubp",TERM,FF,0}, {"fsubrp",TERM,FF,0}, {"fdivp",TERM,FF,0}, {"fdivrp",TERM,FF,0} }, /* [7,0] */ { {"ffree",TERM,F,0}, {"fxch",TERM,F,0}, {"fstp",TERM,F,0}, {"fstp",TERM,F,0}, /* [7,4] */ {"fnstsw",TERM,M,1}, INVALID, INVALID, INVALID }, }; static const struct instable opFP4[4][8] = { /* bit pattern: 1101 1001 111x xxxx */ /* [0,0] */ { {"fchs",TERM,GO_ON,0}, {"fabs",TERM,GO_ON,0}, INVALID, INVALID, /* [0,4] */ {"ftst",TERM,GO_ON,0}, {"fxam",TERM,GO_ON,0}, INVALID, INVALID }, /* [1,0] */ { {"fld1",TERM,GO_ON,0}, {"fldl2t",TERM,GO_ON,0}, {"fldl2e",TERM,GO_ON,0},{"fldpi",TERM,GO_ON,0}, /* [1,4] */ {"fldlg2",TERM,GO_ON,0},{"fldln2",TERM,GO_ON,0}, {"fldz",TERM,GO_ON,0}, INVALID }, /* [2,0] */ { {"f2xm1",TERM,GO_ON,0}, {"fyl2x",TERM,GO_ON,0}, {"fptan",TERM,GO_ON,0}, {"fpatan",TERM,GO_ON,0}, /* [2,4] */ {"fxtract",TERM,GO_ON,0},{"fprem1",TERM,GO_ON,0}, {"fdecstp",TERM,GO_ON,0},{"fincstp",TERM,GO_ON,0} }, /* [3,0] */ { {"fprem",TERM,GO_ON,0}, {"fyl2xp1",TERM,GO_ON,0}, {"fsqrt",TERM,GO_ON,0}, {"fsincos",TERM,GO_ON,0}, /* [3,4] */ {"frndint",TERM,GO_ON,0},{"fscale",TERM,GO_ON,0}, {"fsin",TERM,GO_ON,0}, {"fcos",TERM,GO_ON,0} }, }; static const struct instable opFP5[8] = { /* bit pattern: 1101 1011 1110 0xxx */ /* [0] */ INVALID, INVALID, {"fnclex",TERM,GO_ON,0},{"fninit",TERM,GO_ON,0}, /* [4] */ {"fsetpm",TERM,GO_ON,0},INVALID, INVALID, INVALID, }; /* * Main decode table for the op codes. The first two nibbles * will be used as an index into the table. If there is a * a need to further decode an instruction, the array to be * referenced is indicated with the other two entries being * empty. */ static const struct instable distable[16][16] = { /* [0,0] */ { {"addb",TERM,RMw,0}, {"add",TERM,RMw,1}, {"addb",TERM,MRw,0}, {"add",TERM,MRw,1}, /* [0,4] */ {"addb",TERM,IA,0}, {"add",TERM,IA,1}, {"push",TERM,SEG,1}, {"pop",TERM,SEG,1}, /* [0,8] */ {"orb",TERM,RMw,0}, {"or",TERM,RMw,1}, {"orb",TERM,MRw,0}, {"or",TERM,MRw,1}, /* [0,C] */ {"orb",TERM,IA,0}, {"or",TERM,IA,1}, {"push",TERM,SEG,1}, {"",(const struct instable *)op0F,TERM,0} }, /* [1,0] */ { {"adcb",TERM,RMw,0}, {"adc",TERM,RMw,1}, {"adcb",TERM,MRw,0}, {"adc",TERM,MRw,1}, /* [1,4] */ {"adcb",TERM,IA,0}, {"adc",TERM,IA,1}, {"push",TERM,SEG,1}, {"pop",TERM,SEG,1}, /* [1,8] */ {"sbbb",TERM,RMw,0}, {"sbb",TERM,RMw,1}, {"sbbb",TERM,MRw,0}, {"sbb",TERM,MRw,1}, /* [1,C] */ {"sbbb",TERM,IA,0}, {"sbb",TERM,IA,1}, {"push",TERM,SEG,1}, {"pop",TERM,SEG,1} }, /* [2,0] */ { {"andb",TERM,RMw,0}, {"and",TERM,RMw,1}, {"andb",TERM,MRw,0}, {"and",TERM,MRw,1}, /* [2,4] */ {"andb",TERM,IA,0}, {"and",TERM,IA,1}, {"%es:",TERM,OVERRIDE,0}, {"daa",TERM,GO_ON,0}, /* [2,8] */ {"subb",TERM,RMw,0}, {"sub",TERM,RMw,1}, {"subb",TERM,MRw,0}, {"sub",TERM,MRw,1}, /* [2,C] */ {"subb",TERM,IA,0}, {"sub",TERM,IA,1}, {"%cs:",TERM,OVERRIDE,0}, {"das",TERM,GO_ON,0} }, /* [3,0] */ { {"xorb",TERM,RMw,0}, {"xor",TERM,RMw,1}, {"xorb",TERM,MRw,0}, {"xor",TERM,MRw,1}, /* [3,4] */ {"xorb",TERM,IA,0}, {"xor",TERM,IA,1}, {"%ss:",TERM,OVERRIDE,0}, {"aaa",TERM,GO_ON,0}, /* [3,8] */ {"cmpb",TERM,RMw,0}, {"cmp",TERM,RMw,1}, {"cmpb",TERM,MRw,0}, {"cmp",TERM,MRw,1}, /* [3,C] */ {"cmpb",TERM,IA,0}, {"cmp",TERM,IA,1}, {"%ds:",TERM,OVERRIDE,0}, {"aas",TERM,GO_ON,0} }, /* [4,0] */ { {"inc",TERM,R,1}, {"inc",TERM,R,1}, {"inc",TERM,R,1}, {"inc",TERM,R,1}, /* [4,4] */ {"inc",TERM,R,1}, {"inc",TERM,R,1}, {"inc",TERM,R,1}, {"inc",TERM,R,1}, /* [4,8] */ {"dec",TERM,R,1}, {"dec",TERM,R,1}, {"dec",TERM,R,1}, {"dec",TERM,R,1}, /* [4,C] */ {"dec",TERM,R,1}, {"dec",TERM,R,1}, {"dec",TERM,R,1}, {"dec",TERM,R,1} }, /* [5,0] */ { {"push",TERM,R,1}, {"push",TERM,R,1}, {"push",TERM,R,1}, {"push",TERM,R,1}, /* [5,4] */ {"push",TERM,R,1}, {"push",TERM,R,1}, {"push",TERM,R,1}, {"push",TERM,R,1}, /* [5,8] */ {"pop",TERM,R,1}, {"pop",TERM,R,1}, {"pop",TERM,R,1}, {"pop",TERM,R,1}, /* [5,C] */ {"pop",TERM,R,1}, {"pop",TERM,R,1}, {"pop",TERM,R,1}, {"pop",TERM,R,1} }, /* [6,0] */ { {"pusha",TERM,GO_ON,1}, {"popa",TERM,GO_ON,1}, {"bound",TERM,MR,1}, {"arpl",TERM,RMw,0}, /* [6,4] */ {"%fs:",TERM,OVERRIDE,0}, {"%gs:",TERM,OVERRIDE,0}, {"data16",TERM,DM,0}, {"addr16",TERM,AM,0}, /* [6,8] */ {"push",TERM,I,1}, {"imul",TERM,IMUL,1}, {"push",TERM,Ib,1}, {"imul",TERM,IMUL,1}, /* [6,C] */ {"insb",TERM,GO_ON,0}, {"ins",TERM,GO_ON,1}, {"outsb",TERM,GO_ON,0}, {"outs",TERM,GO_ON,1} }, /* [7,0] */ { {"jo",TERM,BD,0}, {"jno",TERM,BD,0}, {"jb",TERM,BD,0}, {"jae",TERM,BD,0}, /* [7,4] */ {"je",TERM,BD,0}, {"jne",TERM,BD,0}, {"jbe",TERM,BD,0}, {"ja",TERM,BD,0}, /* [7,8] */ {"js",TERM,BD,0}, {"jns",TERM,BD,0}, {"jp",TERM,BD,0}, {"jnp",TERM,BD,0}, /* [7,C] */ {"jl",TERM,BD,0}, {"jge",TERM,BD,0}, {"jle",TERM,BD,0}, {"jg",TERM,BD,0} }, /* [8,0] */ { {"",op80,TERM,0}, {"",op81,TERM,0}, {"",op82,TERM,0}, {"",op83,TERM,0}, /* [8,4] */ {"testb",TERM,MRw,0}, {"test",TERM,MRw,1}, {"xchgb",TERM,MRw,0}, {"xchg",TERM,MRw,1}, /* [8,8] */ {"movb",TERM,RMw,0}, {"mov",TERM,RMw,1}, {"movb",TERM,MRw,0}, {"mov",TERM,MRw,1}, /* [8,C] */ {"mov",TERM,SM,1}, {"lea",TERM,MR,1}, {"mov",TERM,MS,1}, {"pop",TERM,M,1} }, /* [9,0] */ { {"nop",TERM,GO_ON,0}, {"xchg",TERM,RA,1}, {"xchg",TERM,RA,1}, {"xchg",TERM,RA,1}, /* [9,4] */ {"xchg",TERM,RA,1}, {"xchg",TERM,RA,1}, {"xchg",TERM,RA,1}, {"xchg",TERM,RA,1}, /* [9,8] */ {"",TERM,CBW,0}, {"",TERM,CWD,0}, {"lcall",TERM,SO,0}, {"wait/",TERM,PREFIX,0}, /* [9,C] */ {"pushf",TERM,GO_ON,1}, {"popf",TERM,GO_ON,1}, {"sahf",TERM,GO_ON,0}, {"lahf",TERM,GO_ON,0} }, /* [A,0] */ { {"movb",TERM,OA,0}, {"mov",TERM,OA,1}, {"movb",TERM,AO,0}, {"mov",TERM,AO,1}, /* [A,4] */ {"movsb",TERM,SD,0}, {"movs",TERM,SD,1}, {"cmpsb",TERM,SD,0}, {"cmps",TERM,SD,1}, /* [A,8] */ {"testb",TERM,IA,0}, {"test",TERM,IA,1}, {"stosb",TERM,AD,0}, {"stos",TERM,AD,1}, /* [A,C] */ {"lodsb",TERM,SA,0}, {"lods",TERM,SA,1}, {"scasb",TERM,AD,0}, {"scas",TERM,AD,1} }, /* [B,0] */ { {"movb",TERM,IR,0}, {"movb",TERM,IR,0}, {"movb",TERM,IR,0}, {"movb",TERM,IR,0}, /* [B,4] */ {"movb",TERM,IR,0}, {"movb",TERM,IR,0}, {"movb",TERM,IR,0}, {"movb",TERM,IR,0}, /* [B,8] */ {"mov",TERM,IR,1}, {"mov",TERM,IR,1}, {"mov",TERM,IR,1}, {"mov",TERM,IR,1}, /* [B,C] */ {"mov",TERM,IR,1}, {"mov",TERM,IR,1}, {"mov",TERM,IR,1}, {"mov",TERM,IR,1} }, /* [C,0] */ { {"",opC0,TERM,0}, {"",opC1,TERM,0}, {"ret",TERM,RET,0}, {"ret",TERM,GO_ON,0}, /* [C,4] */ {"les",TERM,MR,0}, {"lds",TERM,MR,0}, {"movb",TERM,IMw,0}, {"mov",TERM,IMw,1}, /* [C,8] */ {"enter",TERM,ENTER,0}, {"leave",TERM,GO_ON,0}, {"lret",TERM,RET,0}, {"lret",TERM,GO_ON,0}, /* [C,C] */ {"int",TERM,INT3,0}, {"int",TERM,Ib,0}, {"into",TERM,GO_ON,0}, {"iret",TERM,GO_ON,0} }, /* [D,0] */ { {"",opD0,TERM,0}, {"",opD1,TERM,0}, {"",opD2,TERM,0}, {"",opD3,TERM,0}, /* [D,4] */ {"aam",TERM,U,0}, {"aad",TERM,U,0}, {"falc",TERM,GO_ON,0}, {"xlat",TERM,GO_ON,0}, /* 287 instructions. Note that although the indirect field */ /* indicates opFP1n2 for further decoding, this is not necessarily */ /* the case since the opFP arrays are not partitioned according to key1 */ /* and key2. opFP1n2 is given only to indicate that we haven't */ /* finished decoding the instruction. */ /* [D,8] */ {"",(const struct instable *)opFP1n2,TERM,0}, {"",(const struct instable *)opFP1n2,TERM,0}, {"",(const struct instable *)opFP1n2,TERM,0}, {"",(const struct instable *)opFP1n2,TERM,0}, /* [D,C] */ {"",(const struct instable *)opFP1n2,TERM,0}, {"",(const struct instable *)opFP1n2,TERM,0}, {"",(const struct instable *)opFP1n2,TERM,0}, {"",(const struct instable *)opFP1n2,TERM,0} }, /* [E,0] */ { {"loopnz",TERM,BD,0}, {"loopz",TERM,BD,0}, {"loop",TERM,BD,0}, {"jcxz",TERM,BD,0}, /* [E,4] */ {"inb",TERM,Pi,0}, {"in",TERM,Pi,1}, {"outb",TERM,Po,0}, {"out",TERM,Po,1}, /* [E,8] */ {"call",TERM,D,1}, {"jmp",TERM,D,1}, {"ljmp",TERM,SO,0}, {"jmp",TERM,BD,0}, /* [E,C] */ {"inb",TERM,Vi,0}, {"in",TERM,Vi,1}, {"outb",TERM,Vo,0}, {"out",TERM,Vo,1} }, /* [F,0] */ { {"lock/",TERM,PREFIX,0}, INVALID, {"repnz/",TERM,PREFIX,0}, {"repz/",TERM,PREFIX,0}, /* [F,4] */ {"hlt",TERM,GO_ON,0}, {"cmc",TERM,GO_ON,0}, {"",opF6,TERM,0}, {"",opF7,TERM,0}, /* [F,8] */ {"clc",TERM,GO_ON,0}, {"stc",TERM,GO_ON,0}, {"cli",TERM,GO_ON,0}, {"sti",TERM,GO_ON,0}, /* [F,C] */ {"cld",TERM,GO_ON,0}, {"std",TERM,GO_ON,0}, {"",opFE,TERM,0}, {"",opFF,TERM,0} }, }; /* * i386_disassemble() */ unsigned long i386_disassemble( char *sect, unsigned long left, unsigned long addr, enum byte_sex object_byte_sex, struct relocation_info *sorted_relocs, unsigned long nsorted_relocs, struct nlist *symbols, unsigned long nsymbols, struct nlist *sorted_symbols, unsigned long nsorted_symbols, char *strings, unsigned long strings_size, enum bool verbose, FILE *stream) { char mnemonic[MAX_MNEMONIC+2]; /* one extra for suffix */ const char *seg; const char *symbol0, *symbol1; unsigned long value0, value1; unsigned long value0_size, value1_size; char result0[MAX_RESULT], result1[MAX_RESULT]; unsigned long length; unsigned char byte; /* nibbles (4 bits) of the opcode */ unsigned long opcode1, opcode2, opcode3, opcode4, opcode5; const struct instable *dp; unsigned long wbit, vbit; enum bool got_modrm_byte; unsigned long mode, reg, r_m; const char *reg_name; enum bool data16; /* 16- or 32-bit data */ enum bool addr16; /* 16- or 32-bit addressing */ if(left == 0) { fprintf_filtered(stream, "(end of section)"); return(0); } memset(mnemonic, '\0', sizeof(mnemonic)); seg = ""; symbol0 = NULL; symbol1 = NULL; value0 = 0; value1 = 0; value0_size = 0; value1_size = 0; memset(result0, '\0', sizeof(result0)); memset(result1, '\0', sizeof(result1)); data16 = FALSE; addr16 = FALSE; reg_name = NULL; length = 0; byte = 0; opcode4 = 0; /* to remove a compiler warning only */ opcode5 = 0; /* to remove a compiler warning only */ /* * As long as there is a prefix, the default segment register, * addressing-mode, or data-mode in the instruction will be overridden. * This may be more general than the chip actually is. */ for(;;) { byte = get_value(sizeof(char), sect, &length, &left); opcode1 = byte >> 4 & 0xf; opcode2 = byte & 0xf; dp = &distable[opcode1][opcode2]; if(dp->adr_mode == PREFIX) fprintf_filtered(stream, dp->name); else if(dp->adr_mode == AM) addr16 = !addr16; else if(dp->adr_mode == DM) data16 = !data16; else if(dp->adr_mode == OVERRIDE) seg = dp->name; else break; } /* * Some 386 instructions have 2 bytes of opcode before the mod_r/m * byte so we need to perform a table indirection. */ if(dp->indirect == (const struct instable *) op0F) { byte = get_value(sizeof(char), sect, &length, &left); opcode4 = byte >> 4 & 0xf; opcode5 = byte & 0xf; if(opcode4 > 12) { fprintf_filtered(stream, ".byte 0x%01x%01x, 0x%01x%01x #bad opcode", (unsigned int)opcode1, (unsigned int)opcode2, (unsigned int)opcode4, (unsigned int)opcode5); return(length); } dp = &op0F[opcode4][opcode5]; } got_modrm_byte = FALSE; if(dp->indirect != TERM) { /* * This must have been an opcode for which several instructions * exist. The opcode3 field further decodes the instruction. */ got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, &opcode3, &r_m, byte); /* * decode 287 instructions (D8-DF) from opcodeN */ if(opcode1 == 0xD && opcode2 >= 0x8) { /* instruction form 5 */ if(opcode2 == 0xB && mode == 0x3 && opcode3 == 4) dp = &opFP5[r_m]; else if(opcode2 == 0xB && mode == 0x3 && opcode3 > 4) { fprintf_filtered(stream, ".byte 0x%01x%01x, 0x%01x%01x 0x%02x #bad opcode", (unsigned int)opcode1, (unsigned int)opcode2, (unsigned int)opcode4, (unsigned int)opcode5, (unsigned int)byte); return(length); } /* instruction form 4 */ else if(opcode2 == 0x9 && mode == 0x3 && opcode3 >= 4) dp = &opFP4[opcode3-4][r_m]; /* instruction form 3 */ else if(mode == 0x3) dp = &opFP3[opcode2-8][opcode3]; else /* instruction form 1 and 2 */ dp = &opFP1n2[opcode2-8][opcode3]; } else dp = dp->indirect + opcode3; /* now dp points the proper subdecode table entry */ } if(dp->indirect != TERM) { fprintf_filtered(stream, ".byte 0x%02x #bad opcode", (unsigned int)byte); return(length); } /* setup the mnemonic with a possible suffix */ if(dp->adr_mode != CBW && dp->adr_mode != CWD){ if(dp->suffix) { if(data16 == TRUE) sprintf(mnemonic, "%sw", dp->name); else sprintf(mnemonic, "%sl", dp->name); } else { sprintf(mnemonic, "%s", dp->name); } } /* * Each instruction has a particular instruction syntax format * stored in the disassembly tables. The assignment of formats * to instructions was made by the author. Individual formats * are explained as they are encountered in the following * switch construct. */ switch(dp -> adr_mode) { case BSWAP: reg_name = REG32[(opcode5 & 0x7)][1]; fprintf_filtered(stream, "%s\t%s", mnemonic, reg_name); return(length); case XINST: wbit = WBIT(opcode5); if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } GET_OPERAND(&symbol0, &value0, &value0_size, result0); if(data16 == TRUE) reg_name = REG16[reg][wbit]; else reg_name = REG32[reg][wbit]; fprintf_filtered(stream, "%s\t%s,", mnemonic, reg_name); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); /* movsbl movsbw (0x0FBE) or movswl (0x0FBF) */ /* movzbl movzbw (0x0FB6) or mobzwl (0x0FB7) */ /* wbit lives in 2nd byte, note that operands are different sized */ case MOVZ: /* Get second operand first so data16 can be destroyed */ if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } if(data16 == TRUE) reg_name = REG16[reg][LONGOPERAND]; else reg_name = REG32[reg][LONGOPERAND]; wbit = WBIT(opcode5); data16 = 1; GET_OPERAND(&symbol0, &value0, &value0_size, result0); fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, result0, ","); fprintf_filtered(stream, "%s", reg_name); return(length); /* imul instruction, with either 8-bit or longer immediate */ case IMUL: if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } wbit = LONGOPERAND; GET_OPERAND(&symbol1, &value1, &value1_size, result1); /* opcode 0x6B for byte, sign-extended displacement, 0x69 for word(s) */ value0_size = OPSIZE(data16, opcode2 == 0x9); IMMEDIATE(&symbol0, &value0, value0_size); if(data16 == TRUE) reg_name = REG16[reg][wbit]; else reg_name = REG32[reg][wbit]; fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol0, value0, value0_size, "", ","); print_operand(stream, seg, symbol1, value1, value1_size, result1, ","); fprintf_filtered(stream, "%s", reg_name); return(length); /* memory or register operand to register, with 'w' bit */ case MRw: wbit = WBIT(opcode2); if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } GET_OPERAND(&symbol0, &value0, &value0_size, result0); if(data16 == TRUE) reg_name = REG16[reg][wbit]; else reg_name = REG32[reg][wbit]; fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, result0, ","); fprintf_filtered(stream, "%s", reg_name); return(length); /* register to memory or register operand, with 'w' bit */ /* arpl happens to fit here also because it is odd */ case RMw: wbit = WBIT(opcode2); if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } GET_OPERAND(&symbol0, &value0, &value0_size, result0); if(data16 == TRUE) reg_name = REG16[reg][wbit]; else reg_name = REG32[reg][wbit]; fprintf_filtered(stream, "%s\t%s,", mnemonic, reg_name); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); /* Double shift. Has immediate operand specifying the shift. */ case DSHIFT: if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } wbit = LONGOPERAND; GET_OPERAND(&symbol1, &value1, &value1_size, result1); value0_size = sizeof(char); IMMEDIATE(&symbol0, &value0, value0_size); if(data16 == TRUE) reg_name = REG16[reg][wbit]; else reg_name = REG32[reg][wbit]; fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol0, value0, value0_size, "", ","); fprintf_filtered(stream, "%s,", reg_name); print_operand(stream, seg, symbol1, value1, value1_size, result1, ""); return(length); /* Double shift. With no immediate operand, specifies using %cl. */ case DSHIFTcl: if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } wbit = LONGOPERAND; GET_OPERAND(&symbol0, &value0, &value0_size, result0); if(data16 == TRUE) reg_name = REG16[reg][wbit]; else reg_name = REG32[reg][wbit]; fprintf_filtered(stream, "%s\t%%cl,%s,", mnemonic, reg_name); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); /* immediate to memory or register operand */ case IMlw: wbit = WBIT(opcode2); GET_OPERAND(&symbol1, &value1, &value1_size, result1); /* A long immediate is expected for opcode 0x81, not 0x80 & 0x83 */ value0_size = OPSIZE(data16, opcode2 == 1); IMMEDIATE(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol0, value0, value0_size, "", ","); print_operand(stream, seg, symbol1, value1, value1_size, result1, ""); return(length); /* immediate to memory or register operand with the 'w' bit present */ case IMw: if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } wbit = WBIT(opcode2); GET_OPERAND(&symbol1, &value1, &value1_size, result1); value0_size = OPSIZE(data16, wbit); IMMEDIATE(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol0, value0, value0_size, "", ","); print_operand(stream, seg, symbol1, value1, value1_size, result1, ""); return(length); /* immediate to register with register in low 3 bits of op code */ case IR: wbit = (opcode2 >> 3) & 0x1; /* w-bit here (with regs) is bit 3 */ reg = REGNO(opcode2); value0_size = OPSIZE(data16, wbit); IMMEDIATE(&symbol0, &value0, value0_size); if(data16 == TRUE) reg_name = REG16[reg][wbit]; else reg_name = REG32[reg][wbit]; fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol0, value0, value0_size, "", ","); fprintf_filtered(stream, "%s", reg_name); return(length); /* memory operand to accumulator */ case OA: value0_size = OPSIZE(data16, LONGOPERAND); IMMEDIATE(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, "", ","); wbit = WBIT(opcode2); reg_name = (data16 ? REG16 : REG32)[0][wbit]; fprintf_filtered(stream, "%s", reg_name); return(length); /* accumulator to memory operand */ case AO: value0_size = OPSIZE(data16, LONGOPERAND); IMMEDIATE(&symbol0, &value0, value0_size); wbit = WBIT(opcode2); reg_name = (data16 ? REG16 : REG32)[0][wbit]; fprintf_filtered(stream, "%s\t%s,", mnemonic, reg_name); print_operand(stream, seg, symbol0, value0, value0_size, "", ""); return(length); /* memory or register operand to segment register */ case MS: if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } wbit = LONGOPERAND; GET_OPERAND(&symbol0, &value0, &value0_size, result0); fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, result0, ","); fprintf_filtered(stream, "%s", SEGREG[reg]); return(length); /* segment register to memory or register operand */ case SM: /* UNTESTED */ if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } wbit = LONGOPERAND; GET_OPERAND(&symbol0, &value0, &value0_size, result0); fprintf_filtered(stream, "%s\t%s,", mnemonic, SEGREG[reg]); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); /* rotate or shift instrutions, which may shift by 1 or */ /* consult the cl register, depending on the 'v' bit */ case Mv: vbit = VBIT(opcode2); wbit = WBIT(opcode2); GET_OPERAND(&symbol0, &value0, &value0_size, result0); /* When vbit is set, register is an operand, otherwise just $0x1 */ reg_name = vbit ? "%cl," : "" ; fprintf_filtered(stream, "%s\t%s", mnemonic, reg_name); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); /* immediate rotate or shift instrutions, which may or */ /* may not consult the cl register, depending on the 'v' bit */ case MvI: vbit = VBIT(opcode2); wbit = WBIT(opcode2); GET_OPERAND(&symbol0, &value0, &value0_size, result0); value1_size = sizeof(char); IMMEDIATE(&symbol1, &value1, value1_size); /* When vbit is set, register is an operand, otherwise just $0x1 */ reg_name = vbit ? "%cl," : "" ; fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol1, value1, value1_size, "", ","); fprintf_filtered(stream, "%s", reg_name); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); case MIb: wbit = LONGOPERAND; GET_OPERAND(&symbol0, &value0, &value0_size, result0); value1_size = sizeof(char); IMMEDIATE(&symbol1, &value1, value1_size); fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol1, value1, value1_size, "", ","); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); /* single memory or register operand with 'w' bit present */ case Mw: wbit = WBIT(opcode2); GET_OPERAND(&symbol0, &value0, &value0_size, result0); fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); /* single memory or register operand */ case M: if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } wbit = LONGOPERAND; GET_OPERAND(&symbol0, &value0, &value0_size, result0); fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); /* single memory or register operand */ case Mb: if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } wbit = BYTEOPERAND; GET_OPERAND(&symbol0, &value0, &value0_size, result0); fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); case SREG: /* special register */ byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); vbit = 0; switch(opcode5) { case 2: vbit = 1; /* fall thru */ case 0: reg_name = CONTROLREG[reg]; break; case 3: vbit = 1; /* fall thru */ case 1: reg_name = DEBUGREG[reg]; break; case 6: vbit = 1; /* fall thru */ case 4: reg_name = TESTREG[reg]; break; } if(vbit) fprintf_filtered(stream, "%s\t%s,%s", mnemonic, REG32[r_m][1], reg_name); else fprintf_filtered(stream, "%s\t%s,%s", mnemonic, reg_name, REG32[r_m][1]); return(length); /* single register operand with register in the low 3 */ /* bits of op code */ case R: reg = REGNO(opcode2); if(data16 == TRUE) reg_name = REG16[reg][LONGOPERAND]; else reg_name = REG32[reg][LONGOPERAND]; fprintf_filtered(stream, "%s\t%s", mnemonic, reg_name); return(length); /* register to accumulator with register in the low 3 */ /* bits of op code, xchg instructions */ case RA: reg = REGNO(opcode2); if(data16 == TRUE) { reg_name = REG16[reg][LONGOPERAND]; fprintf_filtered(stream, "%s\t%s,%%ax", mnemonic, reg_name); } else { reg_name = REG32[reg][LONGOPERAND]; fprintf_filtered(stream, "%s\t%s,%%eax", mnemonic, reg_name); } return(length); /* single segment register operand, with reg in bits 3-4 of op code */ case SEG: reg = byte >> 3 & 0x3; /* segment register */ fprintf_filtered(stream, "%s\t%s", mnemonic, SEGREG[reg]); return(length); /* single segment register operand, with register in */ /* bits 3-5 of op code */ case LSEG: reg = byte >> 3 & 0x7; /* long seg reg from opcode */ fprintf_filtered(stream, "%s\t%s", mnemonic, SEGREG[reg]); return(length); /* memory or register operand to register */ case MR: if(got_modrm_byte == FALSE) { got_modrm_byte = TRUE; byte = get_value(sizeof(char), sect, &length, &left); modrm_byte(&mode, ®, &r_m, byte); } wbit = LONGOPERAND; GET_OPERAND(&symbol0, &value0, &value0_size, result0); if(data16 == TRUE) reg_name = REG16[reg][wbit]; else reg_name = REG32[reg][wbit]; fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, result0, ","); fprintf_filtered(stream, "%s", reg_name); return(length); /* immediate operand to accumulator */ case IA: value0_size = OPSIZE(data16, WBIT(opcode2)); switch(value0_size) { case 1: reg_name = "%al"; break; case 2: reg_name = "%ax"; break; case 4: reg_name = "%eax"; break; } IMMEDIATE(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol0, value0, value0_size, "", ","); fprintf_filtered(stream, "%s", reg_name); return(length); /* memory or register operand to accumulator */ case MA: wbit = WBIT(opcode2); GET_OPERAND(&symbol0, &value0, &value0_size, result0); fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); /* si register to di register */ case SD: if(addr16 == TRUE) fprintf_filtered(stream, "%s\t%s(%%si),(%%di)", mnemonic, seg); else fprintf_filtered(stream, "%s\t%s(%%esi),(%%edi)", mnemonic, seg); return(length); /* accumulator to di register */ case AD: wbit = WBIT(opcode2); reg_name = (data16 ? REG16 : REG32)[0][wbit]; if(addr16 == TRUE) fprintf_filtered(stream, "%s\t%s,%s(%%di)", mnemonic, reg_name, seg); else fprintf_filtered(stream, "%s\t%s,%s(%%edi)", mnemonic, reg_name, seg); return(length); /* si register to accumulator */ case SA: wbit = WBIT(opcode2); reg_name = (data16 ? REG16 : REG32)[0][wbit]; if(addr16 == TRUE) fprintf_filtered(stream, "%s\t%s(%%si),%s", mnemonic, seg, reg_name); else fprintf_filtered(stream, "%s\t%s(%%esi),%s", mnemonic, seg, reg_name); return(length); /* single operand, a 16/32 bit displacement */ case D: value0_size = OPSIZE(data16, LONGOPERAND); DISPLACEMENT(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, "", ""); return(length); /* indirect to memory or register operand */ case INM: wbit = LONGOPERAND; GET_OPERAND(&symbol0, &value0, &value0_size, result0); if((mode == 0 && (r_m == 5 || r_m == 4)) || mode == 1 || mode == 2) fprintf_filtered(stream, "%s\t*", mnemonic); else fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); /* indirect to memory or register operand (for lcall and ljmp) */ case INMl: wbit = LONGOPERAND; GET_OPERAND(&symbol0, &value0, &value0_size, result0); fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, result0, ""); return(length); /* * For long jumps and long calls -- a new code segment * register and an offset in IP -- stored in object * code in reverse order */ case SO: value1_size = OPSIZE(data16, LONGOPERAND); IMMEDIATE(&symbol1, &value1, value1_size); value0_size = sizeof(short); IMMEDIATE(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol0, value0, value0_size, "", ",$"); print_operand(stream, seg, symbol1, value1, value1_size, "", ""); return(length); /* jmp/call. single operand, 8 bit displacement */ case BD: value0_size = sizeof(char); DISPLACEMENT(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t", mnemonic); print_operand(stream, seg, symbol0, value0, sizeof(long), "", ""); return(length); /* single 32/16 bit immediate operand */ case I: value0_size = OPSIZE(data16, LONGOPERAND); IMMEDIATE(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol0, value0, value0_size, "", ""); return(length); /* single 8 bit immediate operand */ case Ib: value0_size = sizeof(char); IMMEDIATE(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol0, value0, value0_size, "", ""); return(length); case ENTER: value0_size = sizeof(short); IMMEDIATE(&symbol0, &value0, value0_size); value1_size = sizeof(char); IMMEDIATE(&symbol1, &value1, value1_size); fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol0, value0, value0_size, "", ",$"); print_operand(stream, "", symbol1, value1, value1_size, "", ""); return(length); /* 16-bit immediate operand */ case RET: value0_size = sizeof(short); IMMEDIATE(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, "", symbol0, value0, value0_size, "", ""); return(length); /* single 8 bit port operand */ case P: value0_size = sizeof(char); IMMEDIATE(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, "", ""); return(length); /* single 8 bit (input) port operand */ case Pi: value0_size = sizeof(char); IMMEDIATE(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t$", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, "", ",%eax"); return(length); /* single 8 bit (output) port operand */ case Po: value0_size = sizeof(char); IMMEDIATE(&symbol0, &value0, value0_size); fprintf_filtered(stream, "%s\t%%eax,$", mnemonic); print_operand(stream, seg, symbol0, value0, value0_size, "", ""); return(length); /* single operand, dx register (variable port instruction) */ case V: fprintf_filtered(stream, "%s\t%s(%%dx)", mnemonic, seg); return(length); /* single operand, dx register (variable (input) port instruction) */ case Vi: fprintf_filtered(stream, "%s\t%s%%dx,%%eax", mnemonic, seg); return(length); /* single operand, dx register (variable (output) port instruction)*/ case Vo: fprintf_filtered(stream, "%s\t%s%%eax,%%dx", mnemonic, seg); return(length); /* The int instruction, which has two forms: int 3 (breakpoint) or */ /* int n, where n is indicated in the subsequent byte (format Ib). */ /* The int 3 instruction (opcode 0xCC), where, although the 3 looks */ /* like an operand, it is implied by the opcode. It must be converted */ /* to the correct base and output. */ case INT3: fprintf_filtered(stream, "%s\t$0x3", mnemonic); return(length); /* just an opcode and an unused byte that must be discarded */ case U: byte = get_value(sizeof(char), sect, &length, &left); fprintf_filtered(stream, "%s", mnemonic); return(length); case CBW: if(data16 == TRUE) fprintf_filtered(stream, "cbtw"); else fprintf_filtered(stream, "cwtl"); return(length); case CWD: if(data16 == TRUE) fprintf_filtered(stream, "cwtd"); else fprintf_filtered(stream, "cltd"); return(length); /* no disassembly, the mnemonic was all there was so go on */ case GO_ON: fprintf_filtered(stream, "%s", mnemonic); return(length); /* float reg */ case F: fprintf_filtered(stream, "%s\t%%st(%1.1lu)", mnemonic, r_m); return(length); /* float reg to float reg, with ret bit present */ case FF: /* return result bit for 287 instructions */ if((opcode2 >> 2) & 0x1) fprintf_filtered(stream, "%s\t%%st,%%st(%1.1lu)", mnemonic, r_m); else fprintf_filtered(stream, "%s\t%%st(%1.1lu),%%st", mnemonic, r_m); return(length); /* an invalid op code */ case AM: case DM: case OVERRIDE: case PREFIX: case UNKNOWN: default: fprintf_filtered(stream, ".byte 0x%02x #bad opcode", (unsigned int)byte); return(length); } /* end switch */ } /* * get_operand() is used to return the symbolic operand for an operand that is * encoded with a mod r/m byte. */ static void get_operand( const char **symbol, unsigned long *value, unsigned long *value_size, char *result, const unsigned long mode, const unsigned long r_m, const unsigned long wbit, const enum bool data16, const enum bool addr16, const char *sect, unsigned long *length, unsigned long *left, const unsigned long addr, const struct relocation_info *sorted_relocs, const unsigned long nsorted_relocs, const struct nlist *symbols, const unsigned long nsymbols, const char *strings, const unsigned long strings_size, const struct nlist *sorted_symbols, const unsigned long nsorted_symbols, const enum bool verbose) { enum bool s_i_b; /* flag presence of scale-index-byte */ unsigned char byte; /* the scale-index-byte */ unsigned long ss; /* scale-factor from scale-index-byte */ unsigned long index; /* index register number from scale-index-byte*/ unsigned long base; /* base register number from scale-index-byte */ *symbol = NULL; *value = 0; *result = '\0'; /* check for the presence of the s-i-b byte */ if (r_m == ESP && mode != REG_ONLY && addr16 == FALSE) { s_i_b = TRUE; byte = get_value(sizeof(char), sect, length, left); modrm_byte(&ss, &index, &base, byte); } else s_i_b = FALSE; if (addr16) *value_size = dispsize16[r_m][mode]; else *value_size = dispsize32[r_m][mode]; if (s_i_b == TRUE && mode == 0 && base == EBP) *value_size = sizeof(long); if (*value_size != 0) { *symbol = GET_SYMBOL(addr + *length); *value = get_value(*value_size, sect, length, left); if (*symbol == NULL) { *symbol = GUESS_SYMBOL(*value); if (*symbol != NULL) *value = 0; } } if (s_i_b == TRUE) { sprintf(result, "(%s%s,%s)", regname32[mode][base], indexname[index], scale_factor[ss]); } else { /* no s-i-b */ if (mode == REG_ONLY){ if (data16 == TRUE) strcpy(result, REG16[r_m][wbit]); else strcpy(result, REG32[r_m][wbit]); } else { /* Modes 00, 01, or 10 */ if (r_m == EBP && mode == 0){ /* displacement only */ *result = '\0'; } else { /* Modes 00, 01, or 10, not displacement only, no s-i-b */ if (addr16 == TRUE) sprintf(result, "(%s)", regname16[mode][r_m]); else sprintf(result, "(%s)", regname32[mode][r_m]); } } } } /* * immediate() is used to return the symbolic operand for an immediate operand. */ static void immediate( const char **symbol, unsigned long *value, const unsigned long value_size, const char *sect, unsigned long *length, unsigned long *left, const unsigned long addr, const struct relocation_info *sorted_relocs, const unsigned long nsorted_relocs, const struct nlist *symbols, const unsigned long nsymbols, const char *strings, const unsigned long strings_size, const struct nlist *sorted_symbols, const unsigned long nsorted_symbols, const enum bool verbose) { *symbol = GET_SYMBOL(addr + *length); *value = get_value(value_size, sect, length, left); if(*symbol == NULL) { *symbol = GUESS_SYMBOL(*value); if(*symbol != NULL) *value = 0; } } /* * displacement() is used to return the symbolic operand for an operand that is * encoded as a displacement from the program counter. */ static void displacement( const char **symbol, unsigned long *value, const unsigned long value_size, const char *sect, unsigned long *length, unsigned long *left, const unsigned long addr, const struct relocation_info *sorted_relocs, const unsigned long nsorted_relocs, const struct nlist *symbols, const unsigned long nsymbols, const char *strings, const unsigned long strings_size, const struct nlist *sorted_symbols, const unsigned long nsorted_symbols, const enum bool verbose) { *symbol = GET_SYMBOL(addr + *length); *value = get_value(value_size, sect, length, left); switch(value_size) { case 1: if((*value) & 0x80) *value = *value | 0xffffff00; break; case 2: if((*value) & 0x8000) *value = *value | 0xffff0000; break; } *value += addr + *length; if(*symbol == NULL) { *symbol = GUESS_SYMBOL(*value); if(*symbol != NULL) *value = 0; } } /* * get_symbol() returns the name of a symbol (or NULL) based on the relocation * information at the specified address. */ static const char * get_symbol( const unsigned long sect_offset, const struct relocation_info *sorted_relocs, const unsigned long nsorted_relocs, const struct nlist *symbols, const unsigned long nsymbols, const char *strings, const unsigned long strings_size, const enum bool verbose) { long high, low, mid; struct scattered_relocation_info *sreloc; unsigned long r_address; unsigned int r_symbolnum; long n_strx; if(verbose == FALSE) return(NULL); low = 0; high = nsorted_relocs - 1; mid = (high - low) / 2; while(high >= low) { if(((sorted_relocs[mid].r_address) & R_SCATTERED) != 0) { sreloc = (struct scattered_relocation_info *) (sorted_relocs + mid); r_address = sreloc->r_address; } else { if(sorted_relocs[mid].r_address == sect_offset) { r_symbolnum = sorted_relocs[mid].r_symbolnum; if(sorted_relocs[mid].r_extern){ if(r_symbolnum >= nsymbols) return(NULL); n_strx = symbols[r_symbolnum].n_un.n_strx; if(n_strx <= 0 || n_strx >= strings_size) return(NULL); return(strings + n_strx); } break; } r_address = sorted_relocs[mid].r_address; } if(r_address > sect_offset){ high = mid - 1; mid = (high + low) / 2; } else { low = mid + 1; mid = (high + low) / 2; } } return(NULL); } /* * guess_symbol() guesses the name for a symbol based on the specified value. * It returns the name of symbol or NULL. It only returns a symbol name if * a a symbol with that exact value exists. */ static const char * guess_symbol( const unsigned long value, /* the value of this symbol (in) */ const struct nlist *sorted_symbols, const unsigned long nsorted_symbols, const enum bool verbose) { long high, low, mid; if(verbose == FALSE) return(NULL); low = 0; high = nsorted_symbols - 1; mid = (high - low) / 2; while(high >= low) { if(sorted_symbols[mid].n_value == value) { return(sorted_symbols[mid].n_un.n_name); } if(sorted_symbols[mid].n_value > value) { high = mid - 1; mid = (high + low) / 2; } else { low = mid + 1; mid = (high + low) / 2; } } return(NULL); } /* * print_operand() prints an operand from it's broken out symbolic * representation. */ static void print_operand( FILE *stream, const char *seg, const char *symbol, const unsigned int value, const unsigned int value_size, const char *result, const char *tail) { if(symbol != NULL) { if(value_size != 0) { if(value != 0) fprintf_filtered(stream, "%s%s+0x%0*x%s%s", seg, symbol, (int) value_size * 2, value, result, tail); else fprintf_filtered(stream, "%s%s%s%s", seg, symbol, result, tail); } else { fprintf_filtered(stream, "%s%s%s%s", seg, symbol, result, tail); } } else { if(value_size != 0) { fprintf_filtered(stream, "%s0x%0*x%s%s", seg, (int) value_size * 2, value, result,tail); } else { fprintf_filtered(stream, "%s%s%s", seg, result, tail); } } } /* * get_value() gets a value of size from sect + length and decrease left by the * size and increase length by size. The size of the value can be 1, 2 or 4 * bytes and the value is in little endian byte order. The value is always * returned as a unsigned long and is not sign extended. */ static unsigned long get_value( const unsigned long size, /* number of bytes to get */ const char *sect, /* pointer to the raw data */ unsigned long *length, /* number of bytes actually gotten */ unsigned long *left) /* number of bytes left in the sect */ { unsigned long i, value; unsigned char byte; if(left == 0) return(0); value = 0; for(i = 0; i < size; i++) { byte = 0; if(*left > 0){ byte = sect[*length]; (*length)++; (*left)--; } value |= (unsigned long)byte << (8*i); } return(value); } /* * modrm_byte() breaks a byte out in to it's mode, reg and r/m bits. */ static void modrm_byte( unsigned long *mode, unsigned long *reg, unsigned long *r_m, unsigned char byte) { *r_m = byte & 0x7; /* r/m field from the byte */ *reg = byte >> 3 & 0x7; /* register field from the byte */ *mode = byte >> 6 & 0x3; /* mode field from the byte */ } static const char * gdb_get_symbol( const unsigned long sect_offset) { return NULL; } static CORE_ADDR get_branch( CORE_ADDR pc) { unsigned char jmp_slot[5]; read_memory(pc, jmp_slot, 5); return pc + 5 + *(CORE_ADDR *)(jmp_slot + 1); } static const char * gdb_guess_symbol( const unsigned long value) { struct minimal_symbol *minSym; unsigned long address = value; if (isShlibJump(value)) address = get_branch(value); minSym = lookup_minimal_symbol_by_pc(address); if (minSym && SYMBOL_VALUE_ADDRESS(minSym) == address) { return SYMBOL_NAME(minSym); } else return NULL; } #define MAXLEN 20 int print_insn_i386 (memaddr, info) CORE_ADDR memaddr; disassemble_info *info; { unsigned char buffer[MAXLEN]; read_memory (memaddr, buffer, MAXLEN); return i386_disassemble(buffer, 20, (unsigned)memaddr, LITTLE_ENDIAN_BYTE_SEX, NULL, 0, NULL, 0, NULL, 0, NULL, 0, 1, info->stream); /* return (i386dis ((int)memaddr, buffer, stream)); */ }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.