/* The output function for note sections. The format of a note section * varies with the type of note, the only constant part being that it * starts with an Elf*_Nhdr struct, and is usually followed by a * string. However, each subpart is guaranteed to be a multiple of 4 * bytes, so notes are displayed as arrays of 32-bit values. Line * breaks are inserted to indicate the beginning of a note header. * Note sections in core files are rather different, so in that case a * completely different function is called instead. */ void outnote(void const *ptr, long size, int ndx) { Elf64_Word const *words = ptr; long count = size / sizeof *words; long i; int namesize, descsize, tag; (void)ndx; if (iscorefile()) { iself64() ? outnote64(ptr, size, ndx) : outnote32(ptr, size, ndx); return; } beginblock(TRUE); i = 0; while (i < count) { namesize = (words[i] + 3) / 4; descsize = (words[i + 1] + 3) / 4; linebreak(); outdec(words[i++]); outdec(words[i++]); tag = words[i++]; outdefint(tag, "NT_GNU_"); while (namesize-- && i < count) outhex(words[i++]); if (descsize == 0) continue; #ifdef NT_GNU_ABI_TAG if (tag == NT_GNU_ABI_TAG) { outdefint(words[i++], "ELF_NOTE_OS_"); --descsize; } #endif while (descsize-- && i < count) outhex(words[i++]); } endblock(); }
/*------------------------------------------------------------------------*/ static void do_sib(int m) { int s, i, b; s = SCALE(sib()); i = INDEX(sib()); b = BASE(sib()); switch (b) { /* pick base */ case 0: ua_str("%p:[eax"); break; case 1: ua_str("%p:[ecx"); break; case 2: ua_str("%p:[edx"); break; case 3: ua_str("%p:[ebx"); break; case 4: ua_str("%p:[esp"); break; case 5: if (m == 0) { ua_str("%p:["); //Flags already set outhex('d', 4, 0, addrsize, 0); } else { ua_str("%p:[ebp"); } break; case 6: ua_str("%p:[esi"); break; case 7: ua_str("%p:[edi"); break; } switch (i) { /* and index */ case 0: uprintf("+eax"); break; case 1: uprintf("+ecx"); break; case 2: uprintf("+edx"); break; case 3: uprintf("+ebx"); break; case 4: break; case 5: uprintf("+ebp"); break; case 6: uprintf("+esi"); break; case 7: uprintf("+edi"); break; } if (i != 4) switch (s) { /* and scale */ case 0: uprintf(""); break; case 1: uprintf("*2"); break; case 2: uprintf("*4"); break; case 3: uprintf("*8"); break; } }
static void do_sib(int m) { int s, i, b; s = SCALE(sib()); i = INDEX(sib()); b = BASE(sib()); switch(b) { /* Pick base */ case 0: ua_str("%p:[EAX"); break; case 1: ua_str("%p:[ECX"); break; case 2: ua_str("%p:[EDX"); break; case 3: ua_str("%p:[EBX"); break; case 4: ua_str("%p:[ESP"); break; case 5: if(m == 0) { ua_str("%p:["); outhex('d', 4, 0, addrsize, 0); } else { ua_str("%p:[EBP"); } break; case 6: ua_str("%p:[ESI"); break; case 7: ua_str("%p:[EDI"); break; } switch(i) { /* and index */ case 0: uprintf("+EAX"); break; case 1: uprintf("+ECX"); break; case 2: uprintf("+EDX"); break; case 3: uprintf("+EBX"); break; case 4: break; case 5: uprintf("+EBP"); break; case 6: uprintf("+ESI"); break; case 7: uprintf("+EDI"); break; } if(i != 4) { switch(s) { /* and scale */ case 0: uprintf(""); break; case 1: uprintf("*2"); break; case 2: uprintf("*4"); break; case 3: uprintf("*8"); break; } } }
/* Main table driver */ static void percent( char type, char subtype ) { DWORD vofs; int extend = (addrsize == 32) ? 4 : 2; BYTE c; switch (type) { case 'A': /* direct address */ SET_FLAG( Info->CurrentFlags,DISASM_FL_CODE ); outhex(subtype, extend, 0, addrsize, 0); CLR_FLAG( Info->CurrentFlags,DISASM_FL_CODE ); break; case 'C': /* reg(r/m) picks control reg */ uprintf("C%d", REG(modrm())); must_do_size = 0; break; case 'D': /* reg(r/m) picks debug reg */ uprintf("D%d", REG(modrm())); must_do_size = 0; break; case 'E': /* r/m picks operand */ do_modrm(subtype); break; case 'G': /* reg(r/m) picks register */ if (subtype == 'F') /* 80*87 operand? */ reg_name(RM(modrm()), subtype); else reg_name(REG(modrm()), subtype); must_do_size = 0; break; case 'I': /* immed data */ SET_FLAG( Info->CurrentFlags,DISASM_FL_DATA ); outhex(subtype, 0, 0, opsize, 0); CLR_FLAG( Info->CurrentFlags,DISASM_FL_DATA ); break; case 'J': /* relative IP offset */ vofs = 0; switch(bytes(subtype)) { /* sizeof offset value */ case 1: vofs = (DWORD)getbyte(); break; case 2: vofs = (DWORD)getbyte(); vofs |= (DWORD)getbyte() << 8; vofs &= 0xFFFFu; break; case 4: vofs = (DWORD)getbyte(); /* yuk! */ vofs |= (DWORD)getbyte() << 8; vofs |= (DWORD)getbyte() << 16; vofs |= (DWORD)getbyte() << 24; break; } SET_FLAG( Info->CurrentFlags,DISASM_FL_CODE|DISASM_FL_OFFSET ); uprintf("%s", addr_to_hex(vofs + Info->instruction_length,1,bytes(subtype)) ); CLR_FLAG( Info->CurrentFlags,DISASM_FL_CODE|DISASM_FL_OFFSET ); break; case 'K': if (do_distance==0) break; switch (subtype) { case 'f': uprintf( Info->GetStringName(DISASM_ID_FAR) ); uputchar(' '); break; case 'n': uprintf( Info->GetStringName(DISASM_ID_NEAR) ); uputchar(' '); break; case 's': uprintf( Info->GetStringName(DISASM_ID_SHORT) ); uputchar(' '); break; } break; case 'M': /* r/m picks memory */ do_modrm(subtype); break; case 'O': /* offset only */ ua_str("%p:["); SET_FLAG( Info->CurrentFlags,DISASM_FL_REF ); outhex(subtype, extend, 0, addrsize, 0); CLR_FLAG( Info->CurrentFlags,DISASM_FL_REF ); uputchar(']'); break; case 'P': /* prefix byte (rh) */ ua_str("%p:"); break; case 'R': /* mod(r/m) picks register */ reg_name(REG(modrm()), subtype); /* rh */ must_do_size = 0; break; case 'S': /* reg(r/m) picks segment reg */ uputchar("ecsdfg"[REG(modrm())]); uputchar('s'); must_do_size = 0; break; case 'T': /* reg(r/m) picks T reg */ uprintf("tr%d", REG(modrm())); must_do_size = 0; break; case 'X': /* ds:si type operator */ uprintf("ds:["); if (addrsize == 32) uputchar('e'); uprintf("si]"); break; case 'Y': /* es:di type operator */ uprintf("es:["); if (addrsize == 32) uputchar('e'); uprintf("di]"); break; case '2': /* old [pop cs]! now indexes */ ua_str(second[getbyte()]); /* instructions in 386/486 */ break; case 'g': /* modrm group `subtype' (0--7) */ ua_str( GetOPGroup(subtype) ); break; case 'd': /* sizeof operand==dword? */ if (opsize == 32) uputchar('d'); uputchar(subtype); break; case 'w': /* insert explicit size specifier */ if (opsize == 32) uputchar('d'); else uputchar('w'); uputchar(subtype); break; case 'e': /* extended reg name */ if (opsize == 32) { if (subtype == 'w') uputchar('d'); else { uputchar('e'); uputchar(subtype); } } else uputchar(subtype); break; case 'f': /* '87 opcode */ floating_point(subtype-'0'); break; case 'j': if (addrsize==32 || opsize==32) /* both of them?! */ uputchar('e'); break; case 'p': /* prefix byte */ switch (subtype) { case 'c': case 'd': case 'e': case 'f': case 'g': case 's': prefix = subtype; c = getbyte(); wordop = c & 1; ua_str( GetOP(c) ); break; case ':': if (prefix) uprintf("%cs:", prefix); break; case ' ': c = getbyte(); wordop = c & 1; ua_str( GetOP(c) ); break; } break; case 's': /* size override */ switch (subtype) { case 'a': addrsize = 48 - addrsize; c = getbyte(); wordop = c & 1; ua_str( GetOP(c) ); break; case 'o': opsize = 48 - opsize; c = getbyte(); wordop = c & 1; ua_str( GetOP(c) ); break; } break; } }
/*------------------------------------------------------------------------*/ static void do_modrm(char subtype) { int mod = MOD(modrm()); int rm = RM(modrm()); int extend = (addrsize == 32) ? 4 : 2; /* specifies two registers */ if (mod == 3) { reg_name(rm, subtype); return; } if (must_do_size) { if (wordop) { if (addrsize==32 || opsize==32) /* then must specify size */ uprintf( Info->GetStringName(DISASM_ID_DWORD_PTR) ); else uprintf( Info->GetStringName(DISASM_ID_WORD_PTR) ); } else uprintf( Info->GetStringName(DISASM_ID_BYTE_PTR) ); uputchar(' '); } /* mem operand with 32 bit ofs */ if ((mod == 0) && (rm == 5) && (addrsize == 32)) { ua_str("%p:["); SET_FLAG( Info->CurrentFlags,DISASM_FL_REF ); outhex('d', extend, 0, addrsize, 0); CLR_FLAG( Info->CurrentFlags,DISASM_FL_REF ); uputchar(']'); } else /* 16 bit dsplcmnt */ if ((mod == 0) && (rm == 6) && (addrsize == 16)) { ua_str("%p:["); SET_FLAG( Info->CurrentFlags,DISASM_FL_REF ); outhex('w', extend, 0, addrsize, 0); CLR_FLAG( Info->CurrentFlags,DISASM_FL_REF ); uputchar(']'); } else { /*All other*/ if ( (addrsize != 32) || (rm != 4) ) ua_str("%p:["); SET_FLAG( Info->CurrentFlags,DISASM_FL_REF | DISASM_FL_REFADD ); if (addrsize == 16) switch (rm) { case 0: uprintf("bx+si"); break; case 1: uprintf("bx+di"); break; case 2: uprintf("bp+si"); break; case 3: uprintf("bp+di"); break; case 4: uprintf("si"); break; case 5: uprintf("di"); break; case 6: uprintf("bp"); break; case 7: uprintf("bx"); break; } else switch (rm) { case 0: uprintf("eax"); break; case 1: uprintf("ecx"); break; case 2: uprintf("edx"); break; case 3: uprintf("ebx"); break; case 4: do_sib(mod); break; case 5: uprintf("ebp"); break; case 6: uprintf("esi"); break; case 7: uprintf("edi"); break; } switch (mod) { case 1: outhex('b', extend, 1, addrsize, 0); break; case 2: outhex('v', extend, 1, addrsize, 1); break; } CLR_FLAG( Info->CurrentFlags,DISASM_FL_REF | DISASM_FL_REFADD ); uputchar(']'); } }
static void percent(char type, char subtype) { unsigned int vofs = 0; char *name; int extend = (addrsize == 32) ? 4 : 2; unsigned char c; switch(type) { case 'A': /* Direct address */ outhex(subtype, extend, 0, addrsize, 0); break; case 'C': /* reg(r/m) picks control reg */ uprintf("CR%d", REG(modrm())); must_do_size = 0; break; case 'D': /* reg(r/m) picks debug reg */ uprintf("DR%d", REG(modrm())); must_do_size = 0; break; case 'E': /* r/m picks operand */ do_modrm(subtype); break; case 'G': /* reg(r/m) picks register */ if(subtype == 'f') reg_name(RM(modrm()), subtype); else reg_name(REG(modrm()), subtype); must_do_size = 0; break; case 'I': /* Immediate data */ outhex(subtype, 0, 0, opsize, 0); break; case 'J': /* Relative IP offset */ switch(bytes(subtype)) {/* Size of offset value */ case 1: vofs = (unsigned int) (signed char) getbyte(); break; case 2: vofs = getbyte(); vofs += getbyte() << 8; vofs = (unsigned int) (signed short) vofs; break; case 4: vofs = (unsigned int) getbyte(); vofs |= (unsigned int) getbyte() << 8; vofs |= (unsigned int) getbyte() << 16; vofs |= (unsigned int) getbyte() << 24; break; } name = addr_to_hex((int) (vofs + inst_offset)); uprintf("%s", name); break; case 'K': switch(subtype) { case 'f': ua_str("FAR@"); break; case 'n': ua_str("NEAR@"); break; case 's': ua_str("SHORT@"); break; } break; case 'M': /* r/m picks memory */ do_modrm(subtype); break; case 'O': /* Offset only */ ua_str("%p:["); outhex(subtype, extend, 0, addrsize, 0); uputchar(']'); break; case 'P': /* Prefix byte */ ua_str("%p:"); break; case 'R': /* mod(r/m) picks register */ reg_name(REG(modrm()), subtype); must_do_size = 0; break; case 'S': /* reg(r/m) picks segment register */ uputchar("ECSDFG"[REG(modrm())]); uputchar('S'); must_do_size = 0; break; case 'T': /* reg(r/m) picks T reg */ uprintf("TR%d", REG(modrm())); must_do_size = 0; break; case 'X': /* DS:SI type operator */ uprintf("DS:["); if(addrsize == 32) uputchar('E'); uprintf("SI]"); break; case 'Y': /* ES:DI type operator */ uprintf("ES:["); if(addrsize == 32) uputchar('E'); uprintf("DI]"); break; case '2': /* Extended decode with second byte */ ua_str(second[getbyte()]); break; case 'g': /* modrm group 'subtype' (0--7) */ ua_str(groups[subtype-'0'][REG(modrm())]); break; case 'd': /* Size of operand == dword? */ if(opsize == 32) uputchar('D'); uputchar(subtype);/* No real subtype; following char */ break; case 'w': /* Insert explicit size specifier */ if(opsize == 32) uputchar('D'); else uputchar('W'); uputchar(subtype);/* No real subtype; following char */ break; case 'e': /* Extended reg name */ if(opsize == 32) { if(subtype == 'w') uputchar('D'); else { uputchar('E'); uputchar(subtype); } } else uputchar(subtype); break; case 'f': /* 80x87 opcode */ floating_point(subtype-'0'); break; case 'j': if(addrsize == 32 || opsize == 32) /* both of them?! */ uputchar('E'); break; case 'p': /* Prefix byte */ switch(subtype) { case 'C': case 'D': case 'E': case 'F': case 'G': case 'S': prefix = subtype; c = getbyte(); wordop = c & 1; ua_str(opmap1[c]); break; case ':': if(prefix) uprintf("%cS:", prefix); break; case ' ': c = getbyte(); wordop = c & 1; ua_str(opmap1[c]); break; } break; case 's': /* Size override */ switch(subtype) { case 'a': addrsize = 48 - addrsize; c = getbyte(); wordop = c & 1; ua_str(opmap1[c]); /* ua_str(opmap1[getbyte()]); */ break; case 'o': opsize = 48 - opsize; c = getbyte(); wordop = c & 1; ua_str(opmap1[c]); /* ua_str(opmap1[getbyte()]); */ break; } break; } }
static void do_modrm(char subtype) { int mod = MOD(modrm()); int rm = RM(modrm()); int extend = (addrsize == 32) ? 4 : 2; if(mod == 3) { /* Specifies two registers */ reg_name(rm, subtype); return; } if(must_do_size) { if(wordop) { if(addrsize == 32 || opsize == 32) ua_str("DWORD@PTR@"); else ua_str("WORD@PTR@"); } else ua_str("BYTE@PTR@"); } if((mod == 0) && (rm == 5) && (addrsize == 32)) { /* Mem operand with 32 bit offset */ ua_str("%p:["); outhex('d', extend, 0, addrsize, 0); uputchar(']'); return; } if((mod == 0) && (rm == 6) && (addrsize == 16)) { /* 16 bit displacement */ ua_str("%p:["); outhex('w', extend, 0, addrsize, 0); uputchar(']'); return; } if((addrsize != 32) || (rm != 4)) ua_str("%p:["); if(addrsize == 16) { switch(rm) { case 0: uprintf("BX+SI"); break; case 1: uprintf("BX+DI"); break; case 2: uprintf("BP+SI"); break; case 3: uprintf("BP+DI"); break; case 4: uprintf("SI"); break; case 5: uprintf("DI"); break; case 6: uprintf("BP"); break; case 7: uprintf("BX"); break; } } else { switch(rm) { case 0: uprintf("EAX"); break; case 1: uprintf("ECX"); break; case 2: uprintf("EDX"); break; case 3: uprintf("EBX"); break; case 4: do_sib(mod); break; case 5: uprintf("EBP"); break; case 6: uprintf("ESI"); break; case 7: uprintf("EDI"); break; } } switch(mod) { case 1: outhex('b', extend, 1, addrsize, 0); break; case 2: outhex('v', extend, 1, addrsize, 1); break; } uputchar(']'); }
/* Main table driver */ static void percent(char type, char subtype) { int32 vofs; char *name; int extend = (addrsize == 32) ? 4 : 2; char c; switch (type) { case 'A': /* direct address */ outhex(subtype, extend, 0, addrsize, 0); break; case 'C': /* reg(r/m) picks control reg */ uprintf("C%d", REG(modrm())); must_do_size = 0; break; case 'D': /* reg(r/m) picks debug reg */ uprintf("D%d", REG(modrm())); must_do_size = 0; break; case 'E': /* r/m picks operand */ do_modrm(subtype); break; case 'G': /* reg(r/m) picks register */ if (subtype == 'F') /* 80*87 operand? */ reg_name(RM(modrm()), subtype); else reg_name(REG(modrm()), subtype); must_do_size = 0; break; case 'I': /* immed data */ outhex(subtype, 0, 0, opsize, 0); break; case 'J': /* relative IP offset */ switch(bytes(subtype)) { /* sizeof offset value */ case 1: vofs = (int8)getbyte(); break; case 2: vofs = getbyte(); vofs += getbyte()<<8; vofs = (int16)vofs; break; case 4: vofs = (word32)getbyte(); /* yuk! */ vofs |= (word32)getbyte() << 8; vofs |= (word32)getbyte() << 16; vofs |= (word32)getbyte() << 24; break; } name = addr_to_hex(vofs+instruction_offset,1); uprintf("%s", name); break; case 'K': if (do_distance==0) break; switch (subtype) { case 'f': ua_str("far "); break; case 'n': ua_str("near "); break; case 's': ua_str("short "); break; } break; case 'M': /* r/m picks memory */ do_modrm(subtype); break; case 'O': /* offset only */ ua_str("%p:["); outhex(subtype, extend, 0, addrsize, 0); uputchar(']'); break; case 'P': /* prefix byte (rh) */ ua_str("%p:"); break; case 'R': /* mod(r/m) picks register */ reg_name(REG(modrm()), subtype); /* rh */ must_do_size = 0; break; case 'S': /* reg(r/m) picks segment reg */ uputchar("ecsdfg"[REG(modrm())]); uputchar('s'); must_do_size = 0; break; case 'T': /* reg(r/m) picks T reg */ uprintf("tr%d", REG(modrm())); must_do_size = 0; break; case 'X': /* ds:si type operator */ uprintf("ds:["); if (addrsize == 32) uputchar('e'); uprintf("si]"); break; case 'Y': /* es:di type operator */ uprintf("es:["); if (addrsize == 32) uputchar('e'); uprintf("di]"); break; case '2': /* old [pop cs]! now indexes */ ua_str(second[getbyte()]); /* instructions in 386/486 */ break; case 'g': /* modrm group `subtype' (0--7) */ ua_str(groups[subtype-'0'][REG(modrm())]); break; case 'd': /* sizeof operand==dword? */ if (opsize == 32) uputchar('d'); uputchar(subtype); break; case 'w': /* insert explicit size specifier */ if (opsize == 32) uputchar('d'); else uputchar('w'); uputchar(subtype); break; case 'e': /* extended reg name */ if (opsize == 32) { if (subtype == 'w') uputchar('d'); else { uputchar('e'); uputchar(subtype); } } else uputchar(subtype); break; case 'f': /* '87 opcode */ floating_point(subtype-'0'); break; case 'j': if (addrsize==32 || opsize==32) /* both of them?! */ uputchar('e'); break; case 'p': /* prefix byte */ switch (subtype) { case 'c': case 'd': case 'e': case 'f': case 'g': case 's': prefix = subtype; c = getbyte(); wordop = c & 1; ua_str(opmap1[(unsigned char)c]); break; case ':': if (prefix) uprintf("%cs:", prefix); break; case ' ': c = getbyte(); wordop = c & 1; ua_str(opmap1[(unsigned char)c]); break; } break; case 's': /* size override */ switch (subtype) { case 'a': addrsize = 48 - addrsize; c = getbyte(); wordop = c & 1; ua_str(opmap1[(unsigned char)c]); /* ua_str(opmap1[getbyte()]); */ break; case 'o': opsize = 48 - opsize; c = getbyte(); wordop = c & 1; ua_str(opmap1[(unsigned char)c]); /* ua_str(opmap1[getbyte()]); */ break; } break; } }
/*------------------------------------------------------------------------*/ static void do_modrm(char subtype) { int mod = MOD(modrm()); int rm = RM(modrm()); int extend = (addrsize == 32) ? 4 : 2; if (mod == 3) { /* specifies two registers */ reg_name(rm, subtype); return; } if (must_do_size) { if (wordop) { if (addrsize==32 || opsize==32) { /* then must specify size */ ua_str("dword ptr "); } else { ua_str("word ptr "); } } else { ua_str("byte ptr "); } } if ((mod == 0) && (rm == 5) && (addrsize == 32)) {/* mem operand with 32 bit ofs */ ua_str("%p:["); outhex('d', extend, 0, addrsize, 0); uputchar(']'); return; } if ((mod == 0) && (rm == 6) && (addrsize == 16)) { /* 16 bit dsplcmnt */ ua_str("%p:["); outhex('w', extend, 0, addrsize, 0); uputchar(']'); return; } if ((addrsize != 32) || (rm != 4)) ua_str("%p:["); if (addrsize == 16) { switch (rm) { case 0: uprintf("bx+si"); break; case 1: uprintf("bx+di"); break; case 2: uprintf("bp+si"); break; case 3: uprintf("bp+di"); break; case 4: uprintf("si"); break; case 5: uprintf("di"); break; case 6: uprintf("bp"); break; case 7: uprintf("bx"); break; } } else { switch (rm) { case 0: uprintf("eax"); break; case 1: uprintf("ecx"); break; case 2: uprintf("edx"); break; case 3: uprintf("ebx"); break; case 4: do_sib(mod); break; case 5: uprintf("ebp"); break; case 6: uprintf("esi"); break; case 7: uprintf("edi"); break; } } switch (mod) { case 1: outhex('b', extend, 1, addrsize, 0); break; case 2: outhex('v', extend, 1, addrsize, 1); break; } uputchar(']'); }