DISASM.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:42k
源码类别:

Windows编程

开发平台:

Visual C++

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