|
|
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.