/*++ Copyright (c) 1995 Microsoft Corporation Module Name: disasm.c Abstract: This file contains the x86 disassmbler invoked by "!bde.u <16:16 address>" Author: Barry Bond (BarryBo) Revision History: 09-May-1995 Barry Bond (BarryBo) Created 15-Jan-1996 Neil Sandlin (NeilSa) Merged with vdmexts 32 bit segments fixes --*/ #include #pragma hdrstop WORD gSelector = 0; ULONG gOffset = 0; VOID u( CMD_ARGLIST ) { VDMCONTEXT ThreadContext; WORD selector; ULONG offset; int mode; char rgchOutput[128]; char rgchExtra[128]; BYTE rgbInstruction[64]; CHAR sym_text[255]; CHAR sym_prev[255] = ""; DWORD dist; int cb; int i; int j; int count=10; ULONG Base; SELECTORINFO si; CMD_INIT(); mode = GetContext( &ThreadContext ); if (!GetNextToken()) { if (!gSelector && !gOffset) { selector = (WORD) ThreadContext.SegCs; offset = ThreadContext.Eip; } else { selector = gSelector; offset = gOffset; } } else if (!ParseIntelAddress(&mode, &selector, &offset)) { return; } if (GetNextToken()) { count = (int) EXPRESSION(lpArgumentString); } if ( mode != PROT_MODE && mode != V86_MODE) { PRINTF(" Disassembly of flat mode code not allowed.\n"); return; } Base = GetInfoFromSelector( selector, mode, &si ) + GetIntelBase(); for (i=0; i= si.Limit) cb -= offset+cb-si.Limit; if (!READMEM((LPVOID)(Base+offset), rgbInstruction, cb)) { PRINTF("%04x:%08x: \n", selector, offset); return; } cb = unassemble_one(rgbInstruction, si.bBig, selector, offset, rgchOutput, rgchExtra, &ThreadContext, mode); if (offset > 0xffff) { PRINTF("%04x:%08x ", selector, offset); } else { PRINTF("%04x:%04x ", selector, offset); } for (j=0; j 0xdf))) { /* fwait not followed by floating point instruction */ AppendString("fwait"); return (1); } pInstr++; pData = pInstr; if (pszDecode->szName < 0) { // found a GROUP_ or FLOAT entry... i = (-pszDecode->szName)-1; if (i == FLOATCODE) { //Later: mputs("Floating point instructions NYI\n"); return 1; } else { pszDecode = &dis386_groups[i][(*pInstr>>3)&7]; } } AppendString(szInstructions[pszDecode->szName]); if (pszDecode->iPart1) { AppendChar('\t'); i = (*(rgpfn[pszDecode->iPart1].pfn))(pInstr); if (pszDecode->iPart2) { AppendString(", "); i+=(*(rgpfn[pszDecode->iPart2].pfn))(pInstr); if (pszDecode->iPart3) { AppendString(", "); i+=(*(rgpfn[pszDecode->iPart3].pfn))(pInstr); } } pInstr+=i; } AppendChar('\0'); cb = pInstr - pInstrStart; // return length of instruction gSelector = wInstrSeg; gOffset = dwInstrOff + cb; return cb; } BOOL safe_read_byte( ADDR addr, BYTE *pb ) { ULONG Base; *pb = 0xbb; Base = GetInfoFromSelector( addr.sSeg, g_mode, NULL ); if (Base == (ULONG)-1 || Base == 0) { return FALSE; } Base += GetIntelBase(); return READMEM((LPVOID)(Base+(ULONG)addr.sOff), pb, 1); } BOOL safe_read_short( ADDR addr, SHORT *ps ) { ULONG Base; Base = GetInfoFromSelector( addr.sSeg, g_mode, NULL ); if (Base == (ULONG)-1 || Base == 0) { return FALSE; } Base += GetIntelBase(); return READMEM((LPVOID)(Base+(ULONG)addr.sOff), ps, 2); } BOOL safe_read_long( ADDR addr, LONG *pl ) { ULONG Base; Base = GetInfoFromSelector( addr.sSeg, g_mode, NULL ); if (Base == (ULONG)-1 || Base == 0) { return FALSE; } Base += GetIntelBase(); return READMEM((LPVOID)(Base+(ULONG)addr.sOff), pl, 4); } int Dreg1B(LPBYTE lpB) { BYTE b = (*lpB >> 3) & 7; AppendString(szRegsB[b]); return 0; } int Dreg1W(LPBYTE lpB) { BYTE b = (*lpB >> 3) & 7; if (OPERAND_32) AppendString(szRegsD[b]); else AppendString(szRegsW[b]); return 0; } int Dreg2B(LPBYTE lpB) { BYTE b = *lpB & 7; AppendString(szRegsB[b]); return 0; } int Dreg2W(LPBYTE lpB) { BYTE b = *lpB & 7; if (OPERAND_32) AppendString(szRegsD[b]); else AppendString(szRegsW[b]); return 0; } int DmodrmB(LPBYTE lpB) { BYTE rm = *lpB & 0x07; BYTE mod = *lpB >> 6; unsigned short num; int iRet; pData++; // skip past mod r/m if (mod == 3) { AppendPrefixes(); AppendString(szRegsB[rm]); return 1; } iRet = 0; AppendString("byte ptr "); AppendPrefixes(); AppendString(szMod[rm]); AppendChar('+'); switch (mod) { case 0: if (rm == 6) { g_pchOutput-=3; // back up over the 'BP+' num = *((UNALIGNED USHORT*)pData); AppendNumber(num); pData+=2; iRet = 3; } else { num = 0; g_pchOutput--; iRet = 1; } break; case 1: num = *pData; AppendNumber(num); pData++; iRet = 2; break; case 2: num = *((UNALIGNED USHORT*)pData); AppendNumber(num); pData += 2; iRet = 3; break; } AppendChar(']'); DisplayAddress(mod, rm, num, 1); return iRet; } int DmodrmW(LPBYTE lpB) { BYTE rm = *lpB & 0x07; BYTE mod = *lpB >> 6; unsigned short num; int iRet; pData++; // skip past mod r/m if (mod == 3) { AppendPrefixes(); if (OPERAND_32) AppendString(szRegsD[rm]); else AppendString(szRegsW[rm]); return 1; } if (OPERAND_32) { AppendString("dword ptr "); AppendPrefixes(); AppendChar('['); AppendString(szRegsD[rm]); } else { AppendString("word ptr "); AppendPrefixes(); AppendString(szMod[rm]); } AppendChar('+'); switch (mod) { case 0: if (rm == 6) { g_pchOutput-=3; // back up over 'BP+' num = *((UNALIGNED USHORT*)pData); AppendNumber(num); pData+=2; iRet = 3; } else { g_pchOutput--; // else back up over '+' alone num=0; iRet = 1; } break; case 1: num = *pData; AppendNumber(num); pData++; iRet = 2; break; case 2: num = *((UNALIGNED USHORT *)pData); AppendNumber(num); pData+=2; iRet = 3; break; } AppendChar(']'); if (OPERAND_32) DisplayAddress(mod, rm, num, 4); else DisplayAddress(mod, rm, num, 2); return iRet; } void DisplayAddress(int mod, int rm, int sOff, int size) { ADDR addr; // if caller of unassemble_one() didn't want extra info, return now if (g_pchExtra == NULL) return; // no memory reference if (mod == 3) return; // display prefix if (prefixes & PREFIX_DS) { ExtraChar('D'); addr.sSeg = (USHORT)g_pThreadContext->SegDs; } else if (prefixes & PREFIX_ES) { ExtraChar('E'); addr.sSeg = (USHORT)g_pThreadContext->SegEs; } else if (prefixes & PREFIX_FS) { ExtraChar('F'); addr.sSeg = (USHORT)g_pThreadContext->SegFs; } else if (prefixes & PREFIX_GS) { ExtraChar('G'); addr.sSeg = (USHORT)g_pThreadContext->SegGs; } else if (prefixes & PREFIX_CS) { ExtraChar('C'); addr.sSeg = (USHORT)g_pThreadContext->SegCs; } else if ( (prefixes & PREFIX_SS) || rm==2 || rm == 3) { ExtraChar('S'); addr.sSeg = (USHORT)g_pThreadContext->SegSs; } else if (rm == 6 && mod != 0) { ExtraChar('S'); addr.sSeg = (USHORT)g_pThreadContext->SegSs; } else { ExtraChar('D'); addr.sSeg = (USHORT)g_pThreadContext->SegDs; } ExtraString("S:["); switch (rm) { case 0: addr.sOff = (USHORT)(g_pThreadContext->Ebx + g_pThreadContext->Esi); break; case 1: addr.sOff = (USHORT)(g_pThreadContext->Ebx + g_pThreadContext->Edi); break; case 2: addr.sOff = (USHORT)(g_pThreadContext->Ebp + g_pThreadContext->Esi); break; case 3: addr.sOff = (USHORT)(g_pThreadContext->Ebp + g_pThreadContext->Edi); break; case 4: addr.sOff = (USHORT)g_pThreadContext->Esi; break; case 5: addr.sOff = (USHORT)g_pThreadContext->Edi; break; case 6: if (mod == 0) addr.sOff = 0; else addr.sOff = (USHORT)g_pThreadContext->Ebp; break; default: addr.sOff = (USHORT)g_pThreadContext->Ebx; } addr.sOff += sOff; ExtraNumber(addr.sOff); ExtraString("]="); if (size == 2) { SHORT s; if (safe_read_short(addr, &s)) { ExtraNumber( s ); } else { ExtraString("????"); } } else if (size == 1) { BYTE b; if (safe_read_byte(addr, &b)) { ExtraNumber( b ); } else { ExtraString("??"); } } else if (size == 4) { LONG l; if (safe_read_long(addr, &l)) { ExtraNumber( l ); } else { ExtraString("????????"); } } else { ExtraString("Unknown size!"); } } int DALreg(LPBYTE lpB) { AppendString("al"); return 0; } int DAHreg(LPBYTE lpB) { AppendString("ah"); return 0; } int DBLreg(LPBYTE lpB) { AppendString("bl"); return 0; } int DBHreg(LPBYTE lpB) { AppendString("bh"); return 0; } int DCLreg(LPBYTE lpB) { AppendString("cl"); return 0; } int DCHreg(LPBYTE lpB) { AppendString("ch"); return 0; } int DDLreg(LPBYTE lpB) { AppendString("dl"); return 0; } int DDHreg(LPBYTE lpB) { AppendString("dh"); return 0; } int DAXreg(LPBYTE lpB) { if (OPERAND_32) AppendChar('e'); AppendString("ax"); return 0; } int DBXreg(LPBYTE lpB) { if (OPERAND_32) AppendChar('e'); AppendString("bx"); return 0; } int DCXreg(LPBYTE lpB) { if (OPERAND_32) AppendChar('e'); AppendString("cx"); return 0; } int DDXreg(LPBYTE lpB) { if (OPERAND_32) AppendChar('e'); AppendString("dx"); return 0; } int DBPreg(LPBYTE lpB) { if (OPERAND_32) AppendChar('e'); AppendString("bp"); return 0; } int DSPreg(LPBYTE lpB) { if (OPERAND_32) AppendChar('e'); AppendString("sp"); return 0; } int DSIreg(LPBYTE lpB) { if (OPERAND_32) AppendChar('e'); AppendString("si"); return 0; } int DDIreg(LPBYTE lpB) { if (OPERAND_32) AppendChar('e'); AppendString("di"); return 0; } int DCSreg(LPBYTE lpB) { AppendString("cs"); return 0; } int DDSreg(LPBYTE lpB) { AppendString("ds"); return 0; } int DSSreg(LPBYTE lpB) { AppendString("es"); return 0; } int DESreg(LPBYTE lpB) { AppendString("es"); return 0; } int DFSreg(LPBYTE lpB) { AppendString("fs"); return 0; } int DGSreg(LPBYTE lpB) { AppendString("gs"); return 0; } int DImmB(LPBYTE lpB) { AppendNumber(*((UCHAR *)pData)); pData++; return 1; } int DImmBEnter(LPBYTE lpB) { AppendNumber(*((UCHAR *)pData)); pData++; return 1; } int DImmBS(LPBYTE lpB) // sign-extend 8-bit value to 16 bits { int i = (signed char)*(pData); AppendNumber((USHORT)i); pData++; return 1; } int DImmW(LPBYTE lpB) { if (OPERAND_32) { AppendNumber( *((UNALIGNED ULONG*)pData) ); pData+=4; return 4; } else { AppendNumber( *((UNALIGNED USHORT*)pData) ); pData+=2; return 2; } } int DImmW1(LPBYTE lpB) { AppendNumber( *((UNALIGNED SHORT*)(pData)) ); pData++; return 2; } int DjmpB(LPBYTE lpB) { ULONG Dest = g_InstrAddr.sOff + (LONG)*((UNALIGNED CHAR *)lpB) + OpcodeSize + 1; if (OPERAND_32) { AppendNumber(Dest); } else { AppendNumber((USHORT)Dest); } return 1; } int DjmpW(LPBYTE lpB) { ULONG Dest = g_InstrAddr.sOff + (ULONG)*((UNALIGNED USHORT *)lpB) + OpcodeSize + 2; if (OPERAND_32) { AppendNumber(Dest); } else { AppendNumber((USHORT)Dest); } return 2; } int DregSeg(LPBYTE lpB) { BYTE b = (*lpB >> 3) & 7; AppendString(szRegsSeg[b]); return 0; } int DmemB(LPBYTE lpB) { ADDR addr; addr.sOff = *(lpB+1); AppendChar('['); AppendNumber( addr.sOff ); AppendChar(']'); if (g_pchExtra) { BYTE b; if (prefixes & PREFIX_DS) { ExtraChar('D'); addr.sSeg = (USHORT)g_pThreadContext->SegDs; } else if (prefixes & PREFIX_ES) { ExtraChar('E'); addr.sSeg = (USHORT)g_pThreadContext->SegEs; } else if (prefixes & PREFIX_FS) { ExtraChar('F'); addr.sSeg = (USHORT)g_pThreadContext->SegFs; } else if (prefixes & PREFIX_GS) { ExtraChar('G'); addr.sSeg = (USHORT)g_pThreadContext->SegGs; } else if (prefixes & PREFIX_CS) { ExtraChar('C'); addr.sSeg = (USHORT)g_pThreadContext->SegCs; } else if (prefixes & PREFIX_SS) { ExtraChar('S'); addr.sSeg = (USHORT)g_pThreadContext->SegSs; } else { ExtraChar('D'); addr.sSeg = (USHORT)g_pThreadContext->SegDs; } ExtraString("S:["); ExtraNumber( addr.sOff ); ExtraString("]="); if (safe_read_byte(addr, &b)) { ExtraNumber( b ); } else { ExtraString("??"); } } return 1; } int DmemB1(LPBYTE lpB) { AppendNumber( *lpB ); return 1; } int DmemW(LPBYTE lpB) { int i; ADDR addr; addr.sOff = *(lpB+1); AppendChar('['); if (OPERAND_32) { AppendNumber( *((UNALIGNED long*)lpB) ); i=4; } else { addr.sOff = *((UNALIGNED short *)lpB); AppendNumber( addr.sOff ); i=2; } AppendChar(']'); if (g_pchExtra) { if (prefixes & PREFIX_DS) { ExtraChar('D'); addr.sSeg = (USHORT)g_pThreadContext->SegDs; } else if (prefixes & PREFIX_ES) { ExtraChar('E'); addr.sSeg = (USHORT)g_pThreadContext->SegEs; } else if (prefixes & PREFIX_FS) { ExtraChar('F'); addr.sSeg = (USHORT)g_pThreadContext->SegFs; } else if (prefixes & PREFIX_GS) { ExtraChar('G'); addr.sSeg = (USHORT)g_pThreadContext->SegGs; } else if (prefixes & PREFIX_CS) { ExtraChar('C'); addr.sSeg = (USHORT)g_pThreadContext->SegCs; } else if (prefixes & PREFIX_SS) { ExtraChar('S'); addr.sSeg = (USHORT)g_pThreadContext->SegSs; } else { ExtraChar('D'); addr.sSeg = (USHORT)g_pThreadContext->SegDs; } ExtraString("S:["); ExtraNumber( addr.sOff ); ExtraString("]="); if (i == 2) { SHORT s; if (safe_read_short(addr, &s)) { ExtraNumber( s ); } else { ExtraString( "????" ); } } else { LONG l; if (safe_read_long(addr, &l)) { ExtraNumber( l ); } else { ExtraString( "????????" ); } } } return i; } int DmemD(LPBYTE lpB) { int i; if (OPERAND_32) { AppendNumber( *(((UNALIGNED SHORT*)lpB)+2) ); AppendChar(':'); AppendNumber( *((UNALIGNED long*)lpB) ); i=6; } else { USHORT sel, off; sel = *(((UNALIGNED SHORT*)lpB)+1); off = *((UNALIGNED SHORT*)lpB); AppendNumber( sel ); AppendChar(':'); AppendNumber( off ); i=4; if (g_pchExtra) { char sym_text[1000]; LONG dist; // if the exact symbol name was found, print it if (FindSymbol( sel, off, sym_text, &dist, BEFORE, g_mode)) { ExtraString("= "); ExtraString(sym_text); if (dist) { ExtraString(" + "); ExtraNumber( dist ); } } } } return i; } int DindirmodrmW(LPBYTE lpB) { int i; AppendString("FAR PTR "); i = DmodrmW(lpB); AppendChar(']'); return i; } int DindirFARmodrmW(LPBYTE lpB) { int i; AppendString("FAR PTR "); i = DmodrmW(lpB); AppendChar(']'); return i; } int DeeeControl(LPBYTE lpB) { AppendChar('c'); AppendChar('r'); AppendChar('0'+ ((*lpB >> 3) & 7) ); return 1; } int DeeeDebug(LPBYTE lpB) { AppendChar('d'); AppendChar('r'); AppendChar('0'+ ((*lpB >> 3) & 7) ); return 1; } int DeeeTest(LPBYTE lpB) { AppendChar('t'); AppendChar('r'); AppendChar('0'+ ((*lpB >> 3) & 7) ); return 1; } LPBYTE checkprefixes(LPBYTE lpB) { prefixes = 0; for (;;) { switch (*lpB) { case 0xf3: prefixes |= PREFIX_REPZ; break; case 0xf2: prefixes |= PREFIX_REPNZ; break; case 0xf0: prefixes |= PREFIX_LOCK; break; case 0x2e: prefixes |= PREFIX_CS; break; case 0x36: prefixes |= PREFIX_SS; break; case 0x3e: prefixes |= PREFIX_DS; break; case 0x26: prefixes |= PREFIX_ES; break; case 0x64: prefixes |= PREFIX_FS; break; case 0x65: prefixes |= PREFIX_GS; break; case 0x66: prefixes |= PREFIX_DATA; break; case 0x67: prefixes |= PREFIX_ADR; break; case 0x9b: prefixes |= PREFIX_FWAIT; break; default: return lpB; } lpB++; } } void AppendPrefixes(void) { if (prefixes & PREFIX_CS) AppendString("cs:"); if (prefixes & PREFIX_DS) AppendString("ds:"); if (prefixes & PREFIX_SS) AppendString("ss:"); if (prefixes & PREFIX_ES) AppendString("es:"); if (prefixes & PREFIX_FS) AppendString("fs:"); if (prefixes & PREFIX_GS) AppendString("gs:"); }