|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: disasm.c ! 8: ! 9: Abstract: ! 10: ! 11: This file provides support disassembly ( x86 ). ! 12: ! 13: Author: ! 14: ! 15: Gerd Immeyer 19-Oct-1989 ! 16: Wesley Witt (wesw) 1-May-1993 ( ported from ntsd to drwatson) ! 17: ! 18: Environment: ! 19: ! 20: User Mode ! 21: ! 22: --*/ ! 23: ! 24: #include <windows.h> ! 25: #include <stddef.h> ! 26: #include <string.h> ! 27: #include "regs.h" ! 28: #include "disasm.h" ! 29: #include "drwatson.h" ! 30: #include "proto.h" ! 31: ! 32: /***** macros and defines *****/ ! 33: ! 34: #define BIT20(b) (b & 0x07) ! 35: #define BIT53(b) (b >> 3 & 0x07) ! 36: #define BIT76(b) (b >> 6 & 0x03) ! 37: #define MAXL 16 ! 38: #define MAXOPLEN 10 ! 39: ! 40: #define OBOFFSET 26 ! 41: #define OBOPERAND 34 ! 42: #define OBLINEEND 77 ! 43: ! 44: /***** static tables and variables *****/ ! 45: ! 46: static char regtab[] = "alcldlblahchdhbhaxcxdxbxspbpsidi"; /* reg table */ ! 47: static char *mrmtb16[] = { "bx+si", /* modRM string table (16-bit) */ ! 48: "bx+di", ! 49: "bp+si", ! 50: "bp+di", ! 51: "si", ! 52: "di", ! 53: "bp", ! 54: "bx" ! 55: }; ! 56: ! 57: static char *mrmtb32[] = { "eax", /* modRM string table (32-bit) */ ! 58: "ecx", ! 59: "edx", ! 60: "ebx", ! 61: "esp", ! 62: "ebp", ! 63: "esi", ! 64: "edi" ! 65: }; ! 66: ! 67: static char seg16[8] = { REGDS, REGDS, REGSS, REGSS, ! 68: REGDS, REGDS, REGSS, REGDS }; ! 69: static char reg16[8] = { REGEBX, REGEBX, REGEBP, REGEBP, ! 70: REGESI, REGEDI, REGEBP, REGEBX }; ! 71: static char reg16_2[4] = { REGESI, REGEDI, REGESI, REGEDI }; ! 72: ! 73: static char seg32[8] = { REGDS, REGDS, REGDS, REGDS, ! 74: REGSS, REGSS, REGDS, REGDS }; ! 75: static char reg32[8] = { REGEAX, REGECX, REGEDX, REGEBX, ! 76: REGESP, REGEBP, REGESI, REGEDI }; ! 77: ! 78: static char sregtab[] = "ecsdfg"; // first letter of ES, CS, SS, DS, FS, GS ! 79: ! 80: char hexdigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', ! 81: '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; ! 82: ! 83: static int mod; /* mod of mod/rm byte */ ! 84: static int rm; /* rm of mod/rm byte */ ! 85: static int ttt; /* return reg value (of mod/rm) */ ! 86: static unsigned char *pMem; /* current position in instruction */ ! 87: static int mode_32; /* local addressing mode indicator */ ! 88: static int opsize_32; /* operand size flag */ ! 89: ! 90: ULONG EAaddr[2]; // offset of effective address ! 91: static int EAsize[2]; // size of effective address item ! 92: static char *pchEAseg[2]; // normal segment for operand ! 93: ! 94: int G_mode_32 = 1; /* global address mode indicator */ ! 95: ! 96: static BOOLEAN fMovX; // indicates a MOVSX or MOVZX ! 97: ! 98: // internal function definitions ! 99: ! 100: BOOLEAN disasm(PDEBUGPACKET, PULONG, PUCHAR, BOOLEAN); ! 101: void DIdoModrm(PDEBUGPACKET dp,char **, int, BOOLEAN); ! 102: ! 103: void OutputHexString(char **, char *, int); ! 104: void OutputHexValue(char **, char *, int, int); ! 105: void OutputHexCode(char **, char *, int); ! 106: void OutputString(char **, char *); ! 107: void OutputSymbol(PDEBUGPACKET, char **, char *, int, int); ! 108: ! 109: void GetNextOffset(PDEBUGPACKET, PULONG, BOOLEAN); ! 110: void OutputHexAddr(PUCHAR *, ULONG); ! 111: USHORT GetSegRegValue(PDEBUGPACKET,int); ! 112: ! 113: /**** disasm - disassemble an 80x86/80x87 instruction ! 114: * ! 115: * Input: ! 116: * pOffset = pointer to offset to start disassembly ! 117: * fEAout = if set, include EA (effective address) ! 118: * ! 119: * Output: ! 120: * pOffset = pointer to offset of next instruction ! 121: * pchDst = pointer to result string ! 122: * ! 123: ***************************************************************************/ ! 124: ! 125: BOOLEAN ! 126: disasm( PDEBUGPACKET dp, PULONG pOffset, PUCHAR pchDst, BOOLEAN fEAout ) ! 127: { ! 128: int opcode; /* current opcode */ ! 129: int olen = 2; /* operand length */ ! 130: int alen = 2; /* address length */ ! 131: int end = FALSE; /* end of instruction flag */ ! 132: int mrm = FALSE; /* indicator that modrm is generated*/ ! 133: unsigned char *action; /* action for operand interpretation*/ ! 134: long tmp; /* temporary storage field */ ! 135: int indx; /* temporary index */ ! 136: int action2; /* secondary action */ ! 137: int instlen; /* instruction length */ ! 138: int cBytes; // bytes read into instr buffer ! 139: int segOvr = 0; /* segment override opcode */ ! 140: char membuf[MAXL]; /* current instruction buffer */ ! 141: char *pEAlabel = ""; // optional label for operand ! 142: ! 143: char *pchResultBuf = pchDst; // working copy of pchDst pointer ! 144: char RepPrefixBuffer[32]; // rep prefix buffer ! 145: char *pchRepPrefixBuf = RepPrefixBuffer; // pointer to prefix buffer ! 146: char OpcodeBuffer[8]; // opcode buffer ! 147: char *pchOpcodeBuf = OpcodeBuffer; // pointer to opcode buffer ! 148: char OperandBuffer[80]; // operand buffer ! 149: char *pchOperandBuf = OperandBuffer; // pointer to operand buffer ! 150: char ModrmBuffer[80]; // modRM buffer ! 151: char *pchModrmBuf = ModrmBuffer; // pointer to modRM buffer ! 152: char EABuffer[42]; // effective address buffer ! 153: char *pchEABuf = EABuffer; // pointer to EA buffer ! 154: ! 155: int obOpcode = OBOFFSET; ! 156: int obOpcodeMin; ! 157: int obOpcodeMax; ! 158: ! 159: int obOperand = OBOPERAND; ! 160: int obOperandMin; ! 161: int obOperandMax; ! 162: ! 163: int cbOpcode; ! 164: int cbOperand; ! 165: int cbOffset; ! 166: int cbEAddr; ! 167: ! 168: int fTwoLines = FALSE; ! 169: ! 170: fMovX = FALSE; ! 171: EAsize[0] = EAsize[1] = 0; // no effective address ! 172: pchEAseg[0] = dszDS_; ! 173: pchEAseg[1] = dszES_; ! 174: ! 175: mode_32 = opsize_32 = (G_mode_32 == 1); /* local addressing mode */ ! 176: olen = alen = (1 + mode_32) << 1; // set operand/address lengths ! 177: // 2 for 16-bit and 4 for 32-bit ! 178: ! 179: OutputHexAddr(&pchResultBuf, *pOffset); ! 180: ! 181: *pchResultBuf++ = ' '; ! 182: ! 183: ReadProcessMemory( dp->hProcess, ! 184: (LPVOID)*pOffset, ! 185: (LPVOID)membuf, ! 186: MAXL, ! 187: &cBytes ! 188: ); ! 189: ! 190: /* move full inst to local buffer */ ! 191: pMem = membuf; /* point to begin of instruction */ ! 192: opcode = *pMem++; /* get opcode */ ! 193: OutputString(&pchOpcodeBuf, distbl[opcode].instruct); ! 194: action = actiontbl + distbl[opcode].opr; /* get operand action */ ! 195: ! 196: /***** loop through all operand actions *****/ ! 197: ! 198: do { ! 199: action2 = (*action) & 0xc0; ! 200: switch((*action++) & 0x3f) { ! 201: case ALT: /* alter the opcode if 32-bit */ ! 202: if (opsize_32) { ! 203: indx = *action++; ! 204: pchOpcodeBuf = &OpcodeBuffer[indx]; ! 205: if (indx == 0) ! 206: OutputString(&pchOpcodeBuf, dszCWDE); ! 207: else { ! 208: *pchOpcodeBuf++ = 'd'; ! 209: if (indx == 1) ! 210: *pchOpcodeBuf++ = 'q'; ! 211: } ! 212: } ! 213: break; ! 214: ! 215: case STROP: ! 216: // compute size of operands in indx ! 217: // also if dword operands, change fifth ! 218: // opcode letter from 'w' to 'd'. ! 219: ! 220: if (opcode & 1) { ! 221: if (opsize_32) { ! 222: indx = 4; ! 223: OpcodeBuffer[4] = 'd'; ! 224: } ! 225: else ! 226: indx = 2; ! 227: } ! 228: else ! 229: indx = 1; ! 230: ! 231: if (*action & 1) { ! 232: if (fEAout) { ! 233: EAaddr[0] = GetRegValue(dp, REGESI); ! 234: EAsize[0] = indx; ! 235: } ! 236: } ! 237: if (*action++ & 2) { ! 238: if (fEAout) { ! 239: EAaddr[1] = GetRegValue(dp, REGEDI); ! 240: EAsize[1] = indx; ! 241: } ! 242: } ! 243: break; ! 244: ! 245: case CHR: /* insert a character */ ! 246: *pchOperandBuf++ = *action++; ! 247: break; ! 248: ! 249: case CREG: /* set debug, test or control reg */ ! 250: if ((opcode - 231) & 0x04) // remove bias from opcode ! 251: *pchOperandBuf++ = 't'; ! 252: else if ((opcode - 231) & 0x01) ! 253: *pchOperandBuf++ = 'd'; ! 254: else ! 255: *pchOperandBuf++ = 'c'; ! 256: *pchOperandBuf++ = 'r'; ! 257: *pchOperandBuf++ = (char)('0' + ttt); ! 258: break; ! 259: ! 260: case SREG2: /* segment register */ ! 261: ttt = BIT53(opcode); // set value to fall through ! 262: ! 263: case SREG3: /* segment register */ ! 264: *pchOperandBuf++ = sregtab[ttt]; // reg is part of modrm ! 265: *pchOperandBuf++ = 's'; ! 266: break; ! 267: ! 268: case BRSTR: /* get index to register string */ ! 269: ttt = *action++; /* from action table */ ! 270: goto BREGlabel; ! 271: ! 272: case BOREG: /* byte register (in opcode) */ ! 273: ttt = BIT20(opcode); /* register is part of opcode */ ! 274: goto BREGlabel; ! 275: ! 276: case ALSTR: ! 277: ttt = 0; /* point to AL register */ ! 278: BREGlabel: ! 279: case BREG: /* general register */ ! 280: *pchOperandBuf++ = regtab[ttt * 2]; ! 281: *pchOperandBuf++ = regtab[ttt * 2 + 1]; ! 282: break; ! 283: ! 284: case WRSTR: /* get index to register string */ ! 285: ttt = *action++; /* from action table */ ! 286: goto WREGlabel; ! 287: ! 288: case VOREG: /* register is part of opcode */ ! 289: ttt = BIT20(opcode); ! 290: goto VREGlabel; ! 291: ! 292: case AXSTR: ! 293: ttt = 0; /* point to eAX register */ ! 294: VREGlabel: ! 295: case VREG: /* general register */ ! 296: if (opsize_32) /* test for 32bit mode */ ! 297: *pchOperandBuf++ = 'e'; ! 298: WREGlabel: ! 299: case WREG: /* register is word size */ ! 300: *pchOperandBuf++ = regtab[ttt * 2 + 16]; ! 301: *pchOperandBuf++ = regtab[ttt * 2 + 17]; ! 302: break; ! 303: ! 304: case IST_ST: ! 305: OutputString(&pchOperandBuf, "st(0),st"); ! 306: *(pchOperandBuf - 5) += rm; ! 307: break; ! 308: ! 309: case ST_IST: ! 310: OutputString(&pchOperandBuf, "st,"); ! 311: case IST: ! 312: OutputString(&pchOperandBuf, "st(0)"); ! 313: *(pchOperandBuf - 2) += rm; ! 314: break; ! 315: ! 316: case xBYTE: /* set instruction to byte only */ ! 317: EAsize[0] = 1; ! 318: pEAlabel = "byte ptr "; ! 319: break; ! 320: ! 321: case VAR: ! 322: if (opsize_32) ! 323: goto DWORDlabel; ! 324: ! 325: case xWORD: ! 326: EAsize[0] = 2; ! 327: pEAlabel = "word ptr "; ! 328: break; ! 329: ! 330: case EDWORD: ! 331: opsize_32 = 1; // for control reg move, use eRegs ! 332: case xDWORD: ! 333: DWORDlabel: ! 334: EAsize[0] = 4; ! 335: pEAlabel = "dword ptr "; ! 336: break; ! 337: ! 338: case QWORD: ! 339: EAsize[0] = 8; ! 340: pEAlabel = "qword ptr "; ! 341: break; ! 342: ! 343: case TTBYTE: ! 344: EAsize[0] = 10; ! 345: pEAlabel = "tbyte ptr "; ! 346: break; ! 347: ! 348: case FARPTR: ! 349: if (opsize_32) { ! 350: EAsize[0] = 6; ! 351: pEAlabel = "fword ptr "; ! 352: } ! 353: else { ! 354: EAsize[0] = 4; ! 355: pEAlabel = "dword ptr "; ! 356: } ! 357: break; ! 358: ! 359: case LMODRM: // output modRM data type ! 360: if (mod != 3) ! 361: OutputString(&pchOperandBuf, pEAlabel); ! 362: else ! 363: EAsize[0] = 0; ! 364: ! 365: case MODRM: /* output modrm string */ ! 366: if (segOvr) /* in case of segment override */ ! 367: OutputString(&pchOperandBuf, distbl[segOvr].instruct); ! 368: *pchModrmBuf = '\0'; ! 369: OutputString(&pchOperandBuf, ModrmBuffer); ! 370: break; ! 371: ! 372: case ADDRP: /* address pointer */ ! 373: OutputHexString(&pchOperandBuf, pMem + olen, 2); // segment ! 374: *pchOperandBuf++ = ':'; ! 375: OutputSymbol(dp, &pchOperandBuf, pMem, olen, segOvr); ! 376: pMem += olen + 2; ! 377: break; ! 378: ! 379: case REL8: /* relative address 8-bit */ ! 380: if (opcode == 0xe3 && mode_32) { ! 381: pchOpcodeBuf = OpcodeBuffer; ! 382: OutputString(&pchOpcodeBuf, dszJECXZ); ! 383: } ! 384: tmp = (long)*(char *)pMem++; /* get the 8-bit rel offset */ ! 385: goto DoRelDispl; ! 386: ! 387: case REL16: /* relative address 16-/32-bit */ ! 388: tmp = 0; ! 389: memmove(&tmp,pMem,sizeof(long)); ! 390: pMem += alen; /* skip over offset */ ! 391: DoRelDispl: ! 392: tmp += *pOffset + (pMem - membuf); /* calculate address */ ! 393: OutputSymbol(dp, &pchOperandBuf, (char *) &tmp, alen, segOvr); ! 394: // address ! 395: break; ! 396: ! 397: case UBYTE: // unsigned byte for int/in/out ! 398: OutputHexString(&pchOperandBuf, pMem, 1); // ubyte ! 399: pMem++; ! 400: break; ! 401: ! 402: case IB: /* operand is immediate byte */ ! 403: if ((opcode & ~1) == 0xd4) { // postop for AAD/AAM is 0x0a ! 404: if (*pMem++ != 0x0a) // test post-opcode byte ! 405: OutputString(&pchOperandBuf, dszRESERVED); ! 406: break; ! 407: } ! 408: olen = 1; /* set operand length */ ! 409: goto DoImmed; ! 410: ! 411: case IW: /* operand is immediate word */ ! 412: olen = 2; /* set operand length */ ! 413: ! 414: case IV: /* operand is word or dword */ ! 415: DoImmed: ! 416: OutputHexValue(&pchOperandBuf, pMem, olen, FALSE); ! 417: pMem += olen; ! 418: break; ! 419: ! 420: case OFFS: /* operand is offset */ ! 421: EAsize[0] = (opcode & 1) ? olen : 1; ! 422: ! 423: if (segOvr) /* in case of segment override */ ! 424: OutputString(&pchOperandBuf, distbl[segOvr].instruct); ! 425: ! 426: *pchOperandBuf++ = '['; ! 427: OutputSymbol(dp,&pchOperandBuf, pMem, alen, segOvr); // offset ! 428: pMem += alen; ! 429: *pchOperandBuf++ = ']'; ! 430: break; ! 431: ! 432: case GROUP: /* operand is of group 1,2,4,6 or 8 */ ! 433: /* output opcode symbol */ ! 434: OutputString(&pchOpcodeBuf, group[*action++][ttt]); ! 435: break; ! 436: ! 437: case GROUPT: /* operand is of group 3,5 or 7 */ ! 438: indx = *action; /* get indx into group from action */ ! 439: goto doGroupT; ! 440: ! 441: case EGROUPT: /* x87 ESC (D8-DF) group index */ ! 442: indx = BIT20(opcode) * 2; /* get group index from opcode */ ! 443: if (mod == 3) { /* some operand variations exists */ ! 444: /* for x87 and mod == 3 */ ! 445: ++indx; /* take the next group table entry */ ! 446: if (indx == 3) { /* for x87 ESC==D9 and mod==3 */ ! 447: if (ttt > 3) { /* for those D9 instructions */ ! 448: indx = 12 + ttt; /* offset index to table by 12 */ ! 449: ttt = rm; /* set secondary index to rm */ ! 450: } ! 451: } ! 452: else if (indx == 7) { /* for x87 ESC==DB and mod==3 */ ! 453: if (ttt == 4) /* only valid if ttt==4 */ ! 454: ttt = rm; /* set secondary group table index */ ! 455: else ! 456: ttt = 7; /* no an x87 instruction */ ! 457: } ! 458: } ! 459: doGroupT: ! 460: /* handle group with different types of operands */ ! 461: ! 462: OutputString(&pchOpcodeBuf, groupt[indx][ttt].instruct); ! 463: action = actiontbl + groupt[indx][ttt].opr; ! 464: /* get new action */ ! 465: break; ! 466: ! 467: case OPC0F: /* secondary opcode table (opcode 0F) */ ! 468: opcode = *pMem++; /* get real opcode */ ! 469: fMovX = (BOOLEAN)(opcode == 0xBF || opcode == 0xB7); ! 470: if (opcode < 7) /* for the first 7 opcodes */ ! 471: opcode += 256; /* point begin of secondary opcode tab. */ ! 472: else if (opcode > 0x1f && opcode < 0x27) ! 473: opcode += 231; /* adjust for non-existing opcodes */ ! 474: else if (opcode > 0x2f && opcode < 0x33) ! 475: opcode += 222; /* adjust for non-existing opcodes */ ! 476: else if (opcode > 0x7e && opcode < 0xd0) ! 477: opcode += 148; /* adjust for non-existing opcodes */ ! 478: else ! 479: opcode = 260; /* all non-existing opcodes */ ! 480: goto getNxtByte1; ! 481: ! 482: case ADR_OVR: /* address override */ ! 483: mode_32 = !G_mode_32; /* override addressing mode */ ! 484: alen = (mode_32 + 1) << 1; /* toggle address length */ ! 485: goto getNxtByte; ! 486: ! 487: case OPR_OVR: /* operand size override */ ! 488: opsize_32 = !G_mode_32; /* override operand size */ ! 489: olen = (opsize_32 + 1) << 1; /* toggle operand length */ ! 490: goto getNxtByte; ! 491: ! 492: case SEG_OVR: /* handle segment override */ ! 493: segOvr = opcode; /* save segment override opcode */ ! 494: pchOpcodeBuf = OpcodeBuffer; // restart the opcode string ! 495: goto getNxtByte; ! 496: ! 497: case REP: /* handle rep/lock prefixes */ ! 498: *pchOpcodeBuf = '\0'; ! 499: if (pchRepPrefixBuf != RepPrefixBuffer) ! 500: *pchRepPrefixBuf++ = ' '; ! 501: OutputString(&pchRepPrefixBuf, OpcodeBuffer); ! 502: pchOpcodeBuf = OpcodeBuffer; ! 503: getNxtByte: ! 504: opcode = *pMem++; /* next byte is opcode */ ! 505: getNxtByte1: ! 506: action = actiontbl + distbl[opcode].opr; ! 507: OutputString(&pchOpcodeBuf, distbl[opcode].instruct); ! 508: ! 509: default: /* opcode has no operand */ ! 510: break; ! 511: } ! 512: switch (action2) { /* secondary action */ ! 513: case MRM: /* generate modrm for later use */ ! 514: if (!mrm) { /* ignore if it has been generated */ ! 515: DIdoModrm(dp, &pchModrmBuf, segOvr, fEAout); ! 516: /* generate modrm */ ! 517: mrm = TRUE; /* remember its generation */ ! 518: } ! 519: break; ! 520: ! 521: case COM: /* insert a comma after operand */ ! 522: *pchOperandBuf++ = ','; ! 523: break; ! 524: ! 525: case END: /* end of instruction */ ! 526: end = TRUE; ! 527: break; ! 528: } ! 529: } while (!end); /* loop til end of instruction */ ! 530: ! 531: /***** prepare disassembled instruction for output *****/ ! 532: ! 533: instlen = pMem - membuf; ! 534: ! 535: if (instlen < cBytes) ! 536: cBytes = instlen; ! 537: ! 538: OutputHexCode(&pchResultBuf, membuf, cBytes); ! 539: ! 540: if (instlen > cBytes) { ! 541: *pchResultBuf++ = '?'; ! 542: *pchResultBuf++ = '?'; ! 543: (*pOffset)++; // point past unread byte ! 544: } ! 545: ! 546: *pOffset += instlen; /* set instruction length */ ! 547: ! 548: if (instlen > cBytes) { ! 549: do ! 550: *pchResultBuf++ = ' '; ! 551: while (pchResultBuf < pchDst + OBOFFSET); ! 552: OutputString(&pchResultBuf, "???"); ! 553: *pchResultBuf++ = '\0'; ! 554: return FALSE; ! 555: } ! 556: ! 557: // if fEAout is set, build each EA with trailing space in EABuf ! 558: // point back over final trailing space if buffer nonnull ! 559: ! 560: if (fEAout) { ! 561: ! 562: for (indx = 0; indx < 2; indx++) ! 563: if (EAsize[indx]) { ! 564: OutputString(&pchEABuf, segOvr ? distbl[segOvr].instruct ! 565: : pchEAseg[indx]); ! 566: OutputHexAddr(&pchEABuf, EAaddr[indx]); ! 567: *pchEABuf++ = '='; ! 568: ! 569: ReadProcessMemory( dp->hProcess, ! 570: (LPVOID)EAaddr[indx], ! 571: (LPVOID)membuf, ! 572: EAsize[indx], ! 573: &tmp ! 574: ); ! 575: ! 576: if (tmp == EAsize[indx]) ! 577: OutputHexString(&pchEABuf, (char *)membuf, ! 578: EAsize[indx]); ! 579: else ! 580: while (EAsize[indx]--) { ! 581: *pchEABuf++ = '?'; ! 582: *pchEABuf++ = '?'; ! 583: } ! 584: *pchEABuf++ = ' '; ! 585: } ! 586: if (pchEABuf != EABuffer) ! 587: pchEABuf--; ! 588: } ! 589: ! 590: // compute lengths of component strings. ! 591: // if the rep string is nonnull, ! 592: // add the opcode string length to the operand ! 593: // make the rep string the opcode string ! 594: ! 595: cbOffset = pchResultBuf - pchDst; ! 596: cbOperand = pchOperandBuf - OperandBuffer; ! 597: cbOpcode = pchOpcodeBuf - OpcodeBuffer; ! 598: if (pchRepPrefixBuf != RepPrefixBuffer) { ! 599: cbOperand += cbOpcode + (cbOperand != 0); ! 600: cbOpcode = pchRepPrefixBuf - RepPrefixBuffer; ! 601: } ! 602: cbEAddr = pchEABuf - EABuffer; ! 603: ! 604: // for really long strings, where the opcode and operand ! 605: // will not fit on a 77-character line, make two lines ! 606: // with the opcode on offset 0 on the second line with ! 607: // the operand following after one space ! 608: ! 609: if (cbOpcode + cbOperand > OBLINEEND - 1) { ! 610: fTwoLines = TRUE; ! 611: obOpcode = 0; ! 612: obOperand = cbOpcode + 1; ! 613: } ! 614: else { ! 615: ! 616: // compute the minimum and maximum offset values for ! 617: // opcode and operand strings. ! 618: // if strings are nonnull, add extra for separating space ! 619: ! 620: obOpcodeMin = cbOffset + 1; ! 621: obOperandMin = obOpcodeMin + cbOpcode + 1; ! 622: obOperandMax = OBLINEEND - cbEAddr - (cbEAddr != 0) - cbOperand; ! 623: obOpcodeMax = obOperandMax - (cbOperand != 0) - cbOpcode; ! 624: ! 625: // if minimum offset is more than the maximum, the strings ! 626: // will not fit on one line. recompute the min/max ! 627: // values with no offset and EA strings. ! 628: ! 629: if (obOpcodeMin > obOpcodeMax) { ! 630: fTwoLines = TRUE; ! 631: obOpcodeMin = 0; ! 632: obOperandMin = cbOpcode + 1; ! 633: obOperandMax = OBLINEEND - cbOperand; ! 634: obOpcodeMax = obOperandMax - (cbOperand != 0) - cbOpcode; ! 635: } ! 636: ! 637: // compute the opcode and operand offsets. set offset as ! 638: // close to the default values as possible. ! 639: ! 640: if (obOpcodeMin > OBOFFSET) ! 641: obOpcode = obOpcodeMin; ! 642: else if (obOpcodeMax < OBOFFSET) ! 643: obOpcode = obOpcodeMax; ! 644: ! 645: obOperandMin = obOpcode + cbOpcode + 1; ! 646: ! 647: if (obOperandMin > OBOPERAND) ! 648: obOperand = obOperandMin; ! 649: else if (obOperandMax < OBOPERAND) ! 650: obOperand = obOperandMax; ! 651: } ! 652: ! 653: // build the resultant string with the offsets computed ! 654: ! 655: // if two lines are to be output, ! 656: // append the EAddr string ! 657: // output a new line and reset the pointer ! 658: ! 659: if (fTwoLines) { ! 660: if (pchEABuf != EABuffer) { ! 661: do ! 662: *pchResultBuf++ = ' '; ! 663: while (pchResultBuf < pchDst + OBLINEEND - cbEAddr); ! 664: *pchEABuf = '\0'; ! 665: OutputString(&pchResultBuf, EABuffer); ! 666: } ! 667: pchDst = pchResultBuf; ! 668: } ! 669: ! 670: // output rep, opcode, and operand strings ! 671: ! 672: do ! 673: *pchResultBuf++ = ' '; ! 674: while (pchResultBuf < pchDst + obOpcode); ! 675: ! 676: if (pchRepPrefixBuf != RepPrefixBuffer) { ! 677: *pchRepPrefixBuf = '\0'; ! 678: OutputString(&pchResultBuf, RepPrefixBuffer); ! 679: do ! 680: *pchResultBuf++ = ' '; ! 681: while (pchResultBuf < pchDst + obOperand); ! 682: } ! 683: ! 684: *pchOpcodeBuf = '\0'; ! 685: OutputString(&pchResultBuf, OpcodeBuffer); ! 686: ! 687: if (pchOperandBuf != OperandBuffer) { ! 688: do ! 689: *pchResultBuf++ = ' '; ! 690: while (pchResultBuf < pchDst + obOperand); ! 691: *pchOperandBuf = '\0'; ! 692: OutputString(&pchResultBuf, OperandBuffer); ! 693: } ! 694: ! 695: // if one line is to be output, append the EAddr string ! 696: ! 697: if (!fTwoLines && pchEABuf != EABuffer) { ! 698: *pchEABuf = '\0'; ! 699: do ! 700: *pchResultBuf++ = ' '; ! 701: while (pchResultBuf < pchDst + OBLINEEND - cbEAddr); ! 702: OutputString(&pchResultBuf, EABuffer); ! 703: } ! 704: ! 705: *pchResultBuf = '\0'; ! 706: return TRUE; ! 707: } ! 708: ! 709: /*...........................internal function..............................*/ ! 710: /* */ ! 711: /* generate a mod/rm string */ ! 712: /* */ ! 713: ! 714: void ! 715: DIdoModrm (PDEBUGPACKET dp, char **ppchBuf, int segOvr, BOOLEAN fEAout) ! 716: { ! 717: int mrm; /* modrm byte */ ! 718: char *src; /* source string */ ! 719: int sib; ! 720: int ss; ! 721: int ind; ! 722: int oldrm; ! 723: ! 724: mrm = *pMem++; /* get the mrm byte from instruction */ ! 725: mod = BIT76(mrm); /* get mod */ ! 726: ttt = BIT53(mrm); /* get reg - used outside routine */ ! 727: rm = BIT20(mrm); /* get rm */ ! 728: ! 729: if (mod == 3) { /* register only mode */ ! 730: src = ®tab[rm * 2]; /* point to 16-bit register */ ! 731: if (EAsize[0] > 1) { ! 732: src += 16; /* point to 16-bit register */ ! 733: if (opsize_32 && !fMovX) ! 734: *(*ppchBuf)++ = 'e'; /* make it a 32-bit register */ ! 735: } ! 736: *(*ppchBuf)++ = *src++; /* copy register name */ ! 737: *(*ppchBuf)++ = *src; ! 738: EAsize[0] = 0; // no EA value to output ! 739: return; ! 740: } ! 741: ! 742: if (mode_32) { /* 32-bit addressing mode */ ! 743: oldrm = rm; ! 744: if (rm == 4) { /* rm == 4 implies sib byte */ ! 745: sib = *pMem++; /* get s_i_b byte */ ! 746: rm = BIT20(sib); /* return base */ ! 747: } ! 748: ! 749: *(*ppchBuf)++ = '['; ! 750: if (mod == 0 && rm == 5) { ! 751: OutputSymbol(dp,ppchBuf, pMem, 4, segOvr); // offset ! 752: pMem += 4; ! 753: } ! 754: else { ! 755: if (fEAout) { ! 756: if (segOvr) { ! 757: EAaddr[0] = GetRegValue(dp, reg32[rm]); ! 758: pchEAseg[0] = distbl[segOvr].instruct; ! 759: } ! 760: else if (reg32[rm] == REGEBP || reg32[rm] == REGESP) { ! 761: EAaddr[0] = GetRegValue(dp, reg32[rm]); ! 762: pchEAseg[0] = dszSS_; ! 763: } ! 764: else ! 765: EAaddr[0] = GetRegValue(dp, reg32[rm]); ! 766: } ! 767: OutputString(ppchBuf, mrmtb32[rm]); ! 768: } ! 769: ! 770: if (oldrm == 4) { // finish processing sib ! 771: ind = BIT53(sib); ! 772: if (ind != 4) { ! 773: *(*ppchBuf)++ = '+'; ! 774: OutputString(ppchBuf, mrmtb32[ind]); ! 775: ss = 1 << BIT76(sib); ! 776: if (ss != 1) { ! 777: *(*ppchBuf)++ = '*'; ! 778: *(*ppchBuf)++ = (char)(ss + '0'); ! 779: } ! 780: if (fEAout) ! 781: EAaddr[0] = GetRegValue(dp, reg32[ind]); ! 782: } ! 783: } ! 784: } ! 785: else { // 16-bit addressing mode ! 786: *(*ppchBuf)++ = '['; ! 787: if (mod == 0 && rm == 6) { ! 788: OutputSymbol(dp,ppchBuf, pMem, 2, segOvr); // 16-bit offset ! 789: pMem += 2; ! 790: } ! 791: else { ! 792: if (fEAout) { ! 793: if (segOvr) { ! 794: EAaddr[0] = GetRegValue(dp, reg16[rm]); ! 795: pchEAseg[0] = distbl[segOvr].instruct; ! 796: } ! 797: else if (reg16[rm] == REGEBP) { ! 798: EAaddr[0] = GetRegValue(dp, reg16[rm]); ! 799: pchEAseg[0] = dszSS_; ! 800: } ! 801: else ! 802: EAaddr[0] = GetRegValue(dp, reg16[rm]); ! 803: if (rm < 4) ! 804: EAaddr[0] += GetRegValue(dp, reg16_2[rm]); ! 805: } ! 806: OutputString(ppchBuf, mrmtb16[rm]); ! 807: } ! 808: } ! 809: ! 810: // output any displacement ! 811: ! 812: if (mod == 1) { ! 813: if (fEAout) ! 814: EAaddr[0] += (ULONG)pMem; ! 815: OutputHexValue(ppchBuf, pMem, 1, TRUE); ! 816: pMem++; ! 817: } ! 818: else if (mod == 2) { ! 819: long tmp = 0; ! 820: if (mode_32) { ! 821: memmove(&tmp,pMem,sizeof(long)); ! 822: if (fEAout) ! 823: EAaddr[0] += (ULONG)tmp; ! 824: OutputHexValue(ppchBuf, pMem, 4, TRUE); ! 825: pMem += 4; ! 826: } ! 827: else { ! 828: memmove(&tmp,pMem,sizeof(short)); ! 829: if (fEAout) ! 830: EAaddr[0] += tmp; ! 831: OutputHexValue(ppchBuf, pMem, 2, TRUE); ! 832: pMem += 2; ! 833: } ! 834: } ! 835: ! 836: if (!mode_32 && fEAout) { ! 837: EAaddr[0] &= 0xffff; ! 838: EAaddr[1] &= 0xffff; ! 839: } ! 840: ! 841: *(*ppchBuf)++ = ']'; ! 842: } ! 843: ! 844: /*** OutputHexValue - output hex value ! 845: * ! 846: * Purpose: ! 847: * Output the value pointed by *ppchBuf of the specified ! 848: * length. The value is treated as signed and leading ! 849: * zeroes are not printed. The string is prefaced by a ! 850: * '+' or '-' sign as appropriate. ! 851: * ! 852: * Input: ! 853: * *ppchBuf - pointer to text buffer to fill ! 854: * *pchMemBuf - pointer to memory buffer to extract value ! 855: * length - length in bytes of value (1, 2, and 4 supported) ! 856: * fDisp - set if displacement to output '+' ! 857: * ! 858: * Output: ! 859: * *ppchBuf - pointer updated to next text character ! 860: * ! 861: *************************************************************************/ ! 862: ! 863: void OutputHexValue (char **ppchBuf, char *pchMemBuf, int length, int fDisp) ! 864: { ! 865: long value; ! 866: int index; ! 867: char digit[8]; ! 868: ! 869: value = 0; ! 870: if (length == 1) ! 871: value = (long)(*(char *)pchMemBuf); ! 872: else if (length == 2) ! 873: memmove(&value,pchMemBuf,2); ! 874: else ! 875: memmove(&value,pchMemBuf,sizeof(long)); ! 876: ! 877: length <<= 1; // shift once to get hex length ! 878: ! 879: if (value != 0 || !fDisp) { ! 880: if (fDisp) ! 881: if (value < 0 && length == 2) { // use neg value for byte ! 882: value = -value; // displacement ! 883: *(*ppchBuf)++ = '-'; ! 884: } ! 885: else ! 886: *(*ppchBuf)++ = '+'; ! 887: ! 888: *(*ppchBuf)++ = '0'; ! 889: *(*ppchBuf)++ = 'x'; ! 890: for (index = length - 1; index != -1; index--) { ! 891: digit[index] = (char)(value & 0xf); ! 892: value >>= 4; ! 893: } ! 894: index = 0; ! 895: while (digit[index] == 0 && index < length - 1) ! 896: index++; ! 897: while (index < length) ! 898: *(*ppchBuf)++ = hexdigit[digit[index++]]; ! 899: } ! 900: } ! 901: ! 902: /*** OutputHexString - output hex string ! 903: * ! 904: * Purpose: ! 905: * Output the value pointed by *ppchMemBuf of the specified ! 906: * length. The value is treated as unsigned and leading ! 907: * zeroes are printed. ! 908: * ! 909: * Input: ! 910: * *ppchBuf - pointer to text buffer to fill ! 911: * *pchValue - pointer to memory buffer to extract value ! 912: * length - length in bytes of value ! 913: * ! 914: * Output: ! 915: * *ppchBuf - pointer updated to next text character ! 916: * *ppchMemBuf - pointer update to next memory byte ! 917: * ! 918: *************************************************************************/ ! 919: ! 920: void ! 921: OutputHexString (char **ppchBuf, char *pchValue, int length) ! 922: { ! 923: unsigned char chMem; ! 924: ! 925: pchValue += length; ! 926: while (length--) { ! 927: chMem = *--pchValue; ! 928: *(*ppchBuf)++ = hexdigit[chMem >> 4]; ! 929: *(*ppchBuf)++ = hexdigit[chMem & 0x0f]; ! 930: } ! 931: } ! 932: ! 933: /*** OutputHexCode - output hex code ! 934: * ! 935: * Purpose: ! 936: * Output the code pointed by pchMemBuf of the specified ! 937: * length. The value is treated as unsigned and leading ! 938: * zeroes are printed. This differs from OutputHexString ! 939: * in that bytes are printed from low to high addresses. ! 940: * ! 941: * Input: ! 942: * *ppchBuf - pointer to text buffer to fill ! 943: * pchMemBuf - pointer to memory buffer to extract value ! 944: * length - length in bytes of value ! 945: * ! 946: * Output: ! 947: * *ppchBuf - pointer updated to next text character ! 948: * ! 949: *************************************************************************/ ! 950: ! 951: void ! 952: OutputHexCode (char **ppchBuf, char *pchMemBuf, int length) ! 953: { ! 954: unsigned char chMem; ! 955: ! 956: while (length--) { ! 957: chMem = *pchMemBuf++; ! 958: *(*ppchBuf)++ = hexdigit[chMem >> 4]; ! 959: *(*ppchBuf)++ = hexdigit[chMem & 0x0f]; ! 960: } ! 961: } ! 962: ! 963: /*** OutputString - output string ! 964: * ! 965: * Purpose: ! 966: * Copy the string into the buffer pointed by *ppBuf. ! 967: * ! 968: * Input: ! 969: * *pStr - pointer to string ! 970: * ! 971: * Output: ! 972: * *ppBuf points to next character in buffer. ! 973: * ! 974: *************************************************************************/ ! 975: ! 976: void ! 977: OutputString (char **ppBuf, char *pStr) ! 978: { ! 979: while (*pStr) ! 980: *(*ppBuf)++ = *pStr++; ! 981: } ! 982: ! 983: /*** OutputSymbol - output symbolic value ! 984: * ! 985: * Purpose: ! 986: * Output the value in outvalue into the buffer ! 987: * pointed by *pBuf. Express the value as a ! 988: * symbol plus displacment, if possible. ! 989: * ! 990: * Input: ! 991: * *ppBuf - pointer to text buffer to fill ! 992: * *pValue - pointer to memory buffer to extract value ! 993: * length - length in bytes of value ! 994: * ! 995: * Output: ! 996: * *ppBuf - pointer updated to next text character ! 997: * ! 998: *************************************************************************/ ! 999: ! 1000: void ! 1001: OutputSymbol (PDEBUGPACKET dp, char **ppBuf, char *pValue, int length, int segOvr) ! 1002: { ! 1003: ULONG displacement; ! 1004: ULONG value; ! 1005: PSYMBOL sym; ! 1006: char *szSymName; ! 1007: ! 1008: value = 0; ! 1009: if (length == 1) ! 1010: value = (long)(*(char *)pValue); ! 1011: else if (length == 2) ! 1012: memmove(&value,pValue,sizeof(short)); ! 1013: else ! 1014: memmove(&value,pValue,sizeof(long)); ! 1015: ! 1016: EAaddr[0] = value; ! 1017: ! 1018: sym = GetSymFromAddrAllContexts( value, &displacement, dp ); ! 1019: if (sym) { ! 1020: szSymName = UnDName( &sym->szName[1] ); ! 1021: OutputString(ppBuf, szSymName); ! 1022: OutputHexValue(ppBuf, (char *)&displacement, length, TRUE); ! 1023: *(*ppBuf)++ = ' '; ! 1024: *(*ppBuf)++ = '('; ! 1025: OutputHexString(ppBuf, pValue, length); ! 1026: *(*ppBuf)++ = ')'; ! 1027: } ! 1028: else ! 1029: OutputHexString(ppBuf, pValue, length); ! 1030: } ! 1031: ! 1032: /*** X86GetNextOffset - compute offset for trace or step ! 1033: * ! 1034: * Purpose: ! 1035: * From a limited disassembly of the instruction pointed ! 1036: * by the FIR register, compute the offset of the next ! 1037: * instruction for either a trace or step operation. ! 1038: * ! 1039: * Input: ! 1040: * fStep - TRUE if step offset returned - FALSE for trace offset ! 1041: * ! 1042: * Returns: ! 1043: * step or trace offset if input is TRUE or FALSE, respectively ! 1044: * -1 returned for trace flag to be used ! 1045: * ! 1046: *************************************************************************/ ! 1047: ! 1048: void ! 1049: GetNextOffset (PDEBUGPACKET dp, PULONG pcaddr, BOOLEAN fStep) ! 1050: { ! 1051: int mode_32; ! 1052: int opsize_32; ! 1053: int cBytes; ! 1054: char membuf[MAXL]; // current instruction buffer ! 1055: ULONG addrReturn; ! 1056: USHORT retAddr[3]; // return address buffer ! 1057: char *pMem; ! 1058: UCHAR opcode; ! 1059: int fPrefix = TRUE; ! 1060: int fRepPrefix = FALSE; ! 1061: int ttt; ! 1062: int rm; ! 1063: ULONG instroffset; ! 1064: ! 1065: // read instruction stream bytes into membuf and set mode and ! 1066: // opcode size flags ! 1067: ! 1068: *pcaddr = GetRegValue(dp,REGEIP); ! 1069: instroffset = *pcaddr; ! 1070: G_mode_32 = TRUE; ! 1071: mode_32 = opsize_32 = (G_mode_32 == 1); /* local addressing mode */ ! 1072: ReadProcessMemory( dp->hProcess, ! 1073: (LPVOID)*pcaddr, ! 1074: (LPVOID)membuf, ! 1075: MAXL, ! 1076: &cBytes ! 1077: ); ! 1078: /* move full inst to local buffer */ ! 1079: pMem = membuf; /* point to begin of instruction */ ! 1080: ! 1081: // read and process any prefixes first ! 1082: ! 1083: do { ! 1084: opcode = (UCHAR)*pMem++; /* get opcode */ ! 1085: if (opcode == 0x66) ! 1086: opsize_32 = !G_mode_32; ! 1087: else if (opcode == 0x67) ! 1088: mode_32 = !G_mode_32; ! 1089: else if ((opcode & ~1) == 0xf2) ! 1090: fRepPrefix = TRUE; ! 1091: else if (opcode != 0xf0 && (opcode & ~0x18) != 0x26 ! 1092: && (opcode & ~1) != 0x64) ! 1093: fPrefix = FALSE; ! 1094: } ! 1095: while (fPrefix); ! 1096: ! 1097: // for instructions that alter the TF (trace flag), return the ! 1098: // offset of the next instruction despite the flag of fStep ! 1099: ! 1100: if (((opcode & ~0x3) == 0x9c)) ! 1101: // 9c-9f, pushf, popf, sahf, lahf ! 1102: ; ! 1103: ! 1104: else if (opcode == 0xcf) { // cf - iret - get RA from stack ! 1105: ! 1106: addrReturn = GetRegValue(dp, REGESP); ! 1107: ReadProcessMemory( dp->hProcess, ! 1108: (LPVOID)addrReturn, ! 1109: (LPVOID)retAddr, ! 1110: sizeof(retAddr), ! 1111: NULL ! 1112: ); ! 1113: ! 1114: *pcaddr = retAddr[2]; ! 1115: return; ! 1116: } ! 1117: ! 1118: // repeated string/port instructions ! 1119: ! 1120: if (opcode == 0xe8) // near direct jump ! 1121: pMem += (1 + opsize_32) * 2; ! 1122: ! 1123: else if (opcode == 0x9a) // far direct jump ! 1124: pMem += (2 + opsize_32) * 2; ! 1125: ! 1126: else if (opcode == 0xcd || ! 1127: (opcode >= 0xe0 && opcode <= 0xe2)) // loop / int nn instrs ! 1128: pMem++; ! 1129: ! 1130: else if (opcode == 0xff) { // indirect call - compute length ! 1131: opcode = *pMem++; // get modRM ! 1132: ttt = BIT53(opcode); ! 1133: if ((ttt & ~1) == 2) { ! 1134: mod = BIT76(opcode); ! 1135: if (mod != 3) { // nonregister operand ! 1136: rm = BIT20(opcode); ! 1137: if (mode_32) { ! 1138: if (rm == 4) ! 1139: rm = BIT20(*pMem++); // get base from SIB ! 1140: if (mod == 0) { ! 1141: if (rm == 5) ! 1142: pMem += 4; // long direct address ! 1143: } // else register ! 1144: else if (mod == 1) ! 1145: pMem++; // register with byte offset ! 1146: else ! 1147: pMem += 4; // register with long offset ! 1148: } ! 1149: else { // 16-bit mode ! 1150: if (mod == 0) { ! 1151: if (rm == 6) ! 1152: pMem += 2; // short direct address ! 1153: } ! 1154: else ! 1155: pMem += mod; // reg, byte, word offset ! 1156: } ! 1157: } ! 1158: } ! 1159: else ! 1160: instroffset = (ULONG)-1; // 0xff, but not call ! 1161: } ! 1162: ! 1163: else if (!((fRepPrefix && ((opcode & ~3) == 0x6c || ! 1164: (opcode & ~3) == 0xa4 || ! 1165: (opcode & ~1) == 0xaa || ! 1166: (opcode & ~3) == 0xac)) || ! 1167: opcode == 0xcc || opcode == 0xce)) ! 1168: instroffset = (ULONG)-1; // not repeated string op ! 1169: // or int 3 / into ! 1170: ! 1171: // if not enough bytes were read for instruction parse, ! 1172: // just give up and trace the instruction ! 1173: ! 1174: if (cBytes < pMem - membuf) ! 1175: instroffset = (ULONG)-1; ! 1176: ! 1177: // if not tracing, compute the new instruction offset ! 1178: ! 1179: if (instroffset != (ULONG)-1) ! 1180: instroffset += pMem - membuf; ! 1181: ! 1182: *pcaddr = instroffset; ! 1183: } ! 1184: ! 1185: void ! 1186: OutputHexAddr (PUCHAR *ppBuffer, ULONG offset) ! 1187: { ! 1188: OutputHexString(ppBuffer, (char *)&offset, sizeof(ULONG)); ! 1189: } ! 1190: ! 1191: USHORT ! 1192: GetSegRegValue (PDEBUGPACKET dp, int segOpcode) ! 1193: { ! 1194: ULONG regnum; ! 1195: ! 1196: switch (segOpcode) { ! 1197: case 0x26: ! 1198: regnum = REGES; ! 1199: break; ! 1200: case 0x2e: ! 1201: regnum = REGCS; ! 1202: break; ! 1203: case 0x36: ! 1204: regnum = REGSS; ! 1205: break; ! 1206: case 0x64: ! 1207: regnum = REGFS; ! 1208: break; ! 1209: case 0x65: ! 1210: regnum = REGGS; ! 1211: break; ! 1212: case 0x3e: ! 1213: default: ! 1214: regnum = REGDS; ! 1215: } ! 1216: ! 1217: return (USHORT)GetRegValue(dp,regnum); ! 1218: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.