|
|
1.1 root 1: /*
2: * db/i386/i386db2.c
3: * A debugger.
4: * i386 disassembler.
5: * Table-driven, using tables in i386db4.c.
6: * A hearty thank-you to the architectural geniuses at Intel Corporation
7: * who produced this simple and elegant design -- NOT.
8: */
9:
10: #include "i386db.h"
11:
12: #define MAX_INST_LEN 50 /* Max expanded opcode string length */
13: #define MAX_DISP_SIZE 6 /* Max displacement size in bytes */
14:
15: /* Instruction prefix codes. */
16: #define ESC2 0x0F /* Escape to 2-byte opcode */
17: #define REP 0xF3
18: #define REPNE 0xF2
19: #define LOCK 0xF0
20: #define AD_PRE 0x67 /* Address size prefix */
21: #define OP_PRE 0x66 /* Operand size prefix */
22: #define CS_PRE 0x2E /* CS: segment override prefix */
23: #define DS_PRE 0x3E
24: #define ES_PRE 0x26
25: #define FS_PRE 0x64
26: #define GS_PRE 0x65
27: #define SS_PRE 0x36
28:
29: #define EBP_SIB 5
30:
31: /* Is_signed arg for get_value() et al.: unsigned or signed displacement. */
32: #define UNSIGNED 0
33: #define SIGNED 1
34:
35: /* Flag arg for get_value(): absolute or PC-relative address. */
36: #define ABSOLUTE 0
37: #define PCREL 1
38:
39: #define ADDRINDEX(x) (x==32 ? 1 : 0) /* first index for modRMtab[] */
40: #define TOLSYM 0x100 /* print symbol if greater */
41: #define TOLHEX 0x10 /* print hexidecimal if greater */
42: /* print decimal if less */
43:
44: /* Disassembler static data. */
45: static int ad_pre_flag; /* address size prefix flag */
46: static long delta; /* displacement */
47: static unsigned char ibp[MAX_DISP_SIZE]; /* input buffer */
48: static unsigned char m; /* "Mod" field of ModR/M byte */
49: static unsigned char mRM; /* "R/M" field of ModR/M byte */
50: static unsigned char mReg; /* "REG" field of ModR/M byte */
51: static int modRM_flag; /* ModR/M byte has been loaded */
52: static char *obp; /* output buffer pointer */
53: static int op_pre_flag; /* operand size prefix flag */
54: static char outbuf[MAX_INST_LEN]; /* output buffer */
55: static int segn; /* segment number */
56: static unsigned char seg_prefix; /* segment prefix, e.g. "cs:" */
57: static int sib_flag; /* SIB byte has been loaded */
58: static unsigned char sb; /* "base" field of SIB byte */
59: static unsigned char sss; /* "ss" field of SIB byte */
60: static unsigned char sx; /* "index" field of SIB byte */
61:
62: /*
63: * Return the current address size.
64: * With no address prefix flag, the address size is aop_size (16 or 32);
65: * with address prefix flag, it is the other (32 or 16).
66: */
67: int
68: ad_size()
69: {
70: return (ad_pre_flag) ? 48 - aop_size : aop_size;
71: }
72:
73: /*
74: * Adjust argument according to specified operand size (possibly escaped).
75: */
76: int
77: adj_op_size(c2) int c2;
78: {
79: if (op_size()==16) {
80: switch(c2) { /* set to addr16 lengths */
81: case 'a': c2 = 'w'; break;
82: case 'p': c2 = 'f'; break;
83: case 'v': c2 = 'w'; break;
84: }
85: } else {
86: switch(c2) { /* set to addr32 lengths */
87: case 'a': c2 = 'd'; break;
88: case 'p': c2 = 'l'; break;
89: case 'v': c2 = 'd'; break;
90: }
91: }
92: return c2;
93: }
94:
95: /*
96: * Disassemble from segment 's' to string 'dest'.
97: * Return a pointer to its terminator.
98: */
99: char *
100: disassemble(dest, s) char *dest; int s;
101: {
102: char is[MAX_INST_LEN]; /* formatted instruction buffer */
103: char *isp, *cp;
104: int loop, useMap2;
105:
106: /*
107: * Initialize.
108: */
109: segn = s;
110: modRM_flag = sib_flag = ad_pre_flag = op_pre_flag = seg_prefix = 0;
111: isp = is;
112:
113: /*
114: * Check whether any prefixes are present.
115: * Treat each prefix like a separate instruction.
116: */
117: for (loop = 1, useMap2 = 0; loop; ) {
118: if (get_code(1) == 0)
119: return NULL;
120: switch (ibp[0]) {
121: case REP:
122: case REPNE:
123: case LOCK:
124: loop = 0;
125: break;
126: case AD_PRE:
127: ++ad_pre_flag;
128: continue;
129: case OP_PRE:
130: ++op_pre_flag;
131: continue;
132: case CS_PRE:
133: case DS_PRE:
134: case ES_PRE:
135: case FS_PRE:
136: case GS_PRE:
137: case SS_PRE:
138: seg_prefix = ibp[0];
139: break;
140: case ESC2: /* opcode info is in the next byte */
141: useMap2 = 1;
142: if (get_code(1) == 0)
143: return NULL;
144: loop = 0;
145: break;
146: default:
147: loop = 0;
148: }
149: }
150:
151: /* Get formatted opcode string from op_map[12] and store in is[]. */
152: if ((cp = (useMap2) ? op_map_2[ibp[0]] : op_map_1[ibp[0]]) == NULL) {
153: sprintf(dest, "Invalid instruction byte = %02x (op_map_%d)\n",
154: ibp[0], useMap2 ? 2 : 1);
155: return strchr(dest, '\0') ;
156: }
157: strcpy(isp, cp);
158:
159: /*
160: * Expand the formatted opcode string pointed at by isp to produce an
161: * assembler mnemonic string.
162: * Make sure dest is pointing to the current
163: * end-of-string after each loop.
164: */
165: for ( ; isp[0]; isp++) {
166: switch (isp[0]) {
167: case '%':
168: if ((isp = format(isp, dest)) == NULL) {
169: printr("Invalid opcode string");
170: return NULL;
171: }
172: dest = strchr(dest, '\0'); /* point to end of string */
173: break;
174: case ' ':
175: *dest++ = '\t';
176: *dest = '\0';
177: break;
178: case ',':
179: *dest++ = isp[0];
180: *dest++ = ' ';
181: *dest = '\0';
182: break;
183: default:
184: *dest++ = isp[0];
185: *dest = '\0';
186: break;
187: }
188: }
189: return dest;
190: }
191:
192: /*
193: * Evalute "%c1c2" and store the expanded results in outbuf[].
194: * Then copy outbuf[] into dest[] and return isp pointing
195: * to the next character of the formatted instruction string.
196: * When doing string manipulations, make sure that obp
197: * is pointing at '\0' before breaking from switch statement!
198: */
199: char *
200: format(isp, dest) char *isp, *dest;
201: {
202: unsigned char c1, c2; /* 1st & 2nd char after '%' */
203: ADDR_T val;
204: char **cpp;
205: char *s1; /* temporary string pointer */
206:
207: c1 = *++isp;
208: c2 = *++isp;
209: obp = outbuf;
210: *obp = '\0';
211:
212: switch (c1) {
213:
214: case 'A':
215: c2 = adj_op_size(c2);
216: val = get_value(c2, UNSIGNED, ABSOLUTE);
217: out_disp('a', UNSIGNED, val);
218: break;
219:
220: case 'C':
221: cpp = ctrlReg;
222: outreg:
223: get_modRM();
224: output(cpp[mReg]);
225: break;
226:
227: case 'D':
228: cpp = dbgReg;
229: goto outreg;
230: break;
231:
232: case 'E':
233: case 'M':
234: case 'R':
235: if (ad_size() == 16)
236: out_modRM16(c2);
237: else
238: out_modRM32(c2);
239: break;
240:
241: case 'G':
242: cpp = &genReg[genRegIndex(c2)][0];
243: goto outreg;
244: break;
245:
246: case 'H':
247: case 'I':
248: *obp++ = '$';
249: c2 = adj_op_size(c2);
250: val = get_value(c2, SIGNED, ABSOLUTE);
251: if (c1 == 'I') {
252: switch (get_nbytes(c2)) {
253: case 1: val &= 0xFF; break;
254: case 2: val &= 0xFFFF; break;
255: }
256: }
257: out_disp('x', SIGNED, val);
258: break;
259:
260: case 'J':
261: case 'K':
262: out_segpre();
263: c2 = adj_op_size(c2);
264: val = get_value(c2, SIGNED, PCREL);
265: seg_prefix = CS_PRE; /* CS-relative disp */
266: out_disp((c1=='J') ? 'a': 's', SIGNED, val);
267: break;
268:
269: /* case 'M': see case 'E' */
270:
271: case 'O':
272: out_segpre();
273: c2 = ad_size() == 16 ? 'w' : 'd';
274: val = get_value(c2, SIGNED, ABSOLUTE);
275: out_disp('s', SIGNED, val);
276: break;
277: /* case 'R': see case 'E' */
278:
279: case 'S':
280: cpp = segReg;
281: goto outreg;
282:
283: case 'T':
284: cpp = tstReg;
285: goto outreg;
286: break;
287:
288: case 'X':
289: #if 0
290: sprintf(obp, (ad_size()==16) ? "ds:(%%si)" : "ds:(%%esi)");
291: obp = strchr(obp, '\0');
292: #endif
293: break;
294:
295: case 'Y':
296: #if 0
297: sprintf(obp, (ad_size()==16) ? "es:(%%di)" : "es:(%%edi)");
298: obp = strchr(obp, '\0');
299: #endif
300: break;
301:
302: case 'Z':
303: c2 = adj_op_size(c2);
304: switch(c2) {
305: case 'b': *obp++ = 'b'; break;
306: case 'd': *obp++ = 'l'; break;
307: case 'w': *obp++ = 'w'; break;
308: case 'z': *obp++ = (op_size()==16 ? 'w': 'l'); break;
309: }
310: *obp = '\0';
311: break;
312:
313: case 'e':
314: *obp++ = '%';
315: if (op_size()!=16)
316: *obp++ = 'e';
317: *obp++ = c2;
318: *obp = '\0';
319: break;
320:
321: case 'f':
322: /* Handle NDP opcodes. */
323: get_modRM();
324: *obp++ = 'f'; /* leading 'f' implicit in opcode tables */
325: if (m==3) {
326: register NDPMTAB *mtp;
327: register int val;
328:
329: /* NDP_op_3 gives opcodes with NDP register args. */
330: if ((s1 = NDP_op_3[c2-'0'][mReg]) != NULL) {
331: /* Leading 1, 2 or 3 indicates operand type. */
332: if ((c1 = *s1)=='1' || c1=='2' || c1=='3')
333: s1++;
334: else
335: c1 = 0;
336: output(s1);
337: if (!c1)
338: break;
339: *obp++ = '\t';
340: /* Output the NDP operand[s]. */
341: switch(c1) {
342: case '1':
343: output(NDPReg[mRM]);
344: break;
345: case '2':
346: output(NDPReg[0]);
347: *obp++ = ',';
348: *obp++ = ' ';
349: output(NDPReg[mRM]);
350: break;
351: case '3':
352: output(NDPReg[mRM]);
353: *obp++ = ',';
354: *obp++ = ' ';
355: output(NDPReg[0]);
356: break;
357: }
358: break;
359: }
360: /* Look for opcode in NDP_misc_op[]. */
361: val = (c2-'0'+0xD8)*0x100 + ibp[0];
362: for (mtp = NDP_misc_op; mtp->ndpm_val != 0; ++mtp) {
363: if (mtp->ndpm_val >= val)
364: break;
365: }
366: if (mtp->ndpm_val == val) {
367: output(mtp->ndpm_op);
368: break;
369: }
370: } else if ((s1 = NDP_op[c2-'0'][mReg]) != NULL) {
371: /* NDP opcode with memory operand from mod r/m byte. */
372: output(s1);
373: *obp++ = '\t';
374: if (ad_size() == 16)
375: out_modRM16(c2);
376: else
377: out_modRM32(c2);
378: break;
379: }
380: printr("Invalid NDP instruction %02x %02x",
381: c2-'0'+0xD8, ibp[0]);
382: break;
383:
384: case 'g': /* just inserting the group string into isp */
385: get_modRM();
386: if (grp_map[c2-'0'][mReg] == NULL) {
387: sprintf(obp, "\nInvalid instruction byte = %02x (grp_map[%d][%d])\n",
388: ibp[0], c2-'0', mReg);
389: return strchr(obp, '\0');
390: }
391: {
392: char buf[MAX_INST_LEN];
393:
394: s1 = isp+1; /* save current pointer */
395: strcpy(buf, s1); /* save rest of fmt */
396: strcpy(s1, grp_map[c2-'0'][mReg]);
397: s1 = strchr(s1, '\0'); /* copy group string */
398: strcpy(s1, buf); /* add remainder */
399: *obp = '\0';
400: }
401: break;
402:
403: case 'r':
404: if (get_code(1) == 0)
405: return NULL;
406: break;
407:
408: default:
409: *obp++ = c1;
410: *obp++ = c2;
411: *obp = '\0';
412: }
413: strcpy(dest, outbuf);
414: return isp;
415: }
416:
417: /*
418: * Return the appropriate first index into genreg[][]:
419: * 0 byte
420: * 1 word
421: * 2 dword
422: */
423: int
424: genRegIndex(c2) int c2;
425: {
426: switch(c2) {
427: case 'a': return (op_size() == 16) ? 1 : 2;
428: case 'b': return 0;
429: case 'd': return 2;
430: case 'v': return (op_size() == 16) ? 1 : 2;
431: case 'w': return 1;
432: }
433: return printr("Invalid c2 = %c; a 1 byte reg is shown by default", c2);
434: }
435:
436: #if 0 /* covered by macro in i386db.h */
437: /*
438: * Read nbytes of code to ibp.
439: */
440: int
441: get_code(nbytes) int nbytes;
442: {
443: return getb(segn, ibp, nbytes);
444: }
445: #endif
446:
447: /*
448: * Read and decode a mod r/m byte.
449: */
450: #define mod(x) (((x)>>6)&3)
451: #define modR(x) (((x)>>3)&7)
452: #define modRM(x) ((x)&7)
453: int
454: get_modRM()
455: {
456: if (!modRM_flag) {
457: if (get_code(1) == 0)
458: return 0;
459: m = mod(ibp[0]);
460: mRM = modRM(ibp[0]);
461: mReg = modR(ibp[0]);
462: modRM_flag = 1;
463: }
464: return 1;
465: }
466:
467: /*
468: * Convert a size character to an actual size in bytes.
469: */
470: int
471: get_nbytes(mysize) int mysize;
472: {
473: switch(mysize) {
474: case 'b': return 1;
475: case 'd': return 4;
476: case 'f': return 4;
477: case 'l': return 6;
478: case 'w': return 2;
479: case '\0': return 0;
480: }
481: printr("Invalid nbytes=%c; 1 byte size is chosen by default", mysize);
482: return 1;
483: }
484:
485: /*
486: * Read and decode a SIB byte.
487: */
488: #define sibss(x) (((x)>>6)&3)
489: #define sibx(x) (((x)>>3)&7)
490: #define sibb(x) ((x)&7)
491: int
492: get_sib()
493: {
494: if (!sib_flag) {
495: if ((get_code(1)) == 0)
496: return 0;
497: sss = sibss(ibp[0]);
498: sx = sibx(ibp[0]);
499: sb = sibb(ibp[0]);
500: sib_flag = 1;
501: }
502: return 1;
503: }
504:
505: /*
506: * Get displacement or immediate data and sign- or zero-extend it.
507: * Return the number of bytes read, or 0 on failure.
508: */
509: int
510: getValData(is_signed, mysize) int is_signed, mysize;
511: {
512: register int nbytes, i;
513:
514: if ((nbytes = get_nbytes(mysize)) == 0)
515: return 0;
516: else if ((get_code(nbytes)) == 0)
517: return printr("Cannot read displacement or immediate data");
518:
519: for (i = nbytes; i < MAX_DISP_SIZE; i++)
520: ibp[i] = (is_signed && (ibp[i-1] & 0x80)) ? 0xFF : 0;
521: return nbytes;
522: }
523:
524: /*
525: * Get immediate or displacement value.
526: */
527: ADDR_T
528: get_value(mysize, is_signed, flag) int mysize, is_signed, flag;
529: {
530: register ADDR_T base;
531: int nbytes;
532:
533: if ((nbytes = getValData(is_signed, mysize)) == 0)
534: return (ADDR_T)0;
535: base = (flag) ? add : (ADDR_T)0;
536: if (mysize == 'f' || mysize == 'l') {
537: /* Output 32-bit or 48-bit pointer segment. */
538: sprintf(obp, "0x%02x%02x:", ibp[nbytes-1], ibp[nbytes-2]);
539: obp = strchr(obp, '\0');
540: nbytes -= 2;
541: }
542: switch (nbytes) {
543: case 1:
544: delta = (is_signed) ? *(char *)ibp : *(unsigned char *)ibp;
545: break;
546: case 2:
547: delta = (is_signed) ? *(short *)ibp : *(unsigned short *)ibp;
548: break;
549: case 4:
550: delta = *(long *)ibp;
551: break;
552: }
553: return base + (ADDR_T)delta;
554: }
555:
556: /*
557: * Return the current operand size.
558: * With no operand prefix flag, the address size is aop_size (16 or 32);
559: * with address prefix flag, it is the other (32 or 16).
560: */
561: int
562: op_size()
563: {
564: return (op_pre_flag) ? 48 - aop_size : aop_size;
565: }
566:
567: /*
568: * Output an address.
569: */
570: void
571: out_addr(v) ADDR_T v;
572: {
573: sprintf(obp, "0x%lX", v);
574: obp = strchr(obp, '\0');
575: }
576:
577: /*
578: * Output a displacement.
579: */
580: void
581: out_disp(fmt, is_signed, val) int fmt; int is_signed; ADDR_T val;
582: {
583: dbprintf(("out_disp(%c, %d, %lX):\n", fmt, is_signed, val));
584: if (is_signed && delta < 0)
585: delta = -delta;
586: switch(fmt) {
587:
588: case 'd': /* print decimal */
589: if (val == (ADDR_T)0)
590: break; /* huh? */
591: sprintf(obp, "%ld", val);
592: break;
593:
594: case 'x': /* print hex */
595: sprintf(obp, (delta > TOLHEX) ? "0x%lX" : "%ld", val);
596: break;
597:
598: case 'a': /* print address */
599: if (delta <= TOLSYM) {
600: out_addr(val); /* print address in hex */
601: break;
602: }
603: /* else fall through to print symbolic address... */
604:
605: case 's': /* print symbol if possible; otherwise print address */
606: cvt_addr(obp, (seg_prefix == CS_PRE) ? ISEG : DSEG, val);
607: break;
608:
609: default:
610: printr("Invalid fmt=%c in out_disp", fmt);
611: }
612: obp = strchr(obp, '\0');
613: }
614:
615: /*
616: * Output mod r/m info.
617: */
618: void
619: out_modRM(dispsize, fmt, addrsize, is_signed) int dispsize, fmt, addrsize, is_signed;
620: {
621: unsigned long val;
622:
623: out_segpre();
624: val = get_value(dispsize, is_signed, ABSOLUTE);
625: out_disp(fmt, is_signed, val);
626: output(modRMtab[ADDRINDEX(addrsize)][mRM]);
627: }
628:
629: /*
630: * Output 1b-bit mod r/m info.
631: */
632: void
633: out_modRM16(c2) int c2;
634: {
635: unsigned long val;
636:
637: get_modRM();
638: c2 = adj_op_size(c2);
639:
640: switch(m) {
641: case 0:
642: out_segpre();
643: if (mRM==6) {
644: val = get_value('w', SIGNED, ABSOLUTE);
645: out_disp('s', SIGNED, val);
646: break;
647: }
648: output(modRMtab[ADDRINDEX(16)][mRM]);
649: break;
650: case 1:
651: case 2:
652: out_modRM((m==1) ? 'b' : 'w', 'd', 16, SIGNED);
653: break;
654: case 3:
655: output(genReg[genRegIndex(c2)][mRM]);
656: break;
657: }
658: }
659:
660: /*
661: * Output 32-bit mod r/m info.
662: */
663: void
664: out_modRM32(c2) int c2;
665: {
666: unsigned long val;
667: char c;
668:
669: get_modRM();
670: c2 = adj_op_size(c2);
671:
672: switch(m) {
673: case 0:
674: if (mRM==4) {
675: out_sib('\0', m);
676: break;
677: }
678: out_segpre();
679: if (mRM==5) {
680: val = get_value('d', SIGNED, ABSOLUTE);
681: out_disp('s', SIGNED, val);
682: break;
683: }
684: output(modRMtab[ADDRINDEX(32)][mRM]);
685: break;
686: case 1:
687: case 2:
688: c = (m==1) ? 'b' : 'd';
689: if (mRM==4)
690: out_sib(c, m);
691: else
692: out_modRM(c, 'd', 32, 1);
693: break;
694: case 3:
695: output(genReg[genRegIndex(c2)][mRM]);
696: break;
697: }
698: }
699:
700: /*
701: * Copy src to output buffer outbuf,
702: * updating the output buffer pointer accordingly.
703: */
704: void
705: output(src) char *src;
706: {
707: strcpy(obp, src);
708: obp = strchr(obp, '\0');
709: }
710:
711: /*
712: * Write a segment escape prefix.
713: */
714: void
715: out_segpre()
716: {
717: if (seg_prefix != 0)
718: output(op_map_1[seg_prefix]);
719: }
720:
721: /*
722: * Output a SIB indirect address.
723: */
724: void
725: out_sib(dispsize, m) int dispsize, m;
726: {
727: unsigned long val;
728:
729: get_sib();
730: switch(m) {
731: case 0:
732: out_segpre();
733: if (sb == EBP_SIB) {
734: val = get_value('d', SIGNED, ABSOLUTE);
735: out_disp('d', SIGNED, val);
736: } else
737: output(modRMtab[ADDRINDEX(32)][sb]);
738: break;
739: case 1:
740: case 2:
741: out_segpre();
742: val = get_value(dispsize, SIGNED, ABSOLUTE);
743: out_disp('d', SIGNED, val);
744: output(modRMtab[ADDRINDEX(32)][sb]);
745: break;
746: }
747: if (sibtab[sss][sx] != NULL)
748: output(sibtab[sss][sx]);
749: }
750:
751: /* end of db/i386/i386db2.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.