|
|
1.1 root 1: #include <u.h>
2: #include <libc.h>
3: #include <bio.h>
4: #include <mach.h>
5:
6: /*
7: * i386-specific debugger interface
8: */
9:
10: static char *i386excep(Map*, Rgetter);
11:
12: static int i386trace(Map*, ulong, ulong, ulong, Tracer);
13: static ulong i386frame(Map*, ulong, ulong, ulong, ulong);
14: static int i386foll(Map*, ulong, Rgetter, ulong*);
15: static int i386inst(Map*, ulong, char, char*, int);
16: static int i386das(Map*, ulong, char*, int);
17: static int i386instlen(Map*, ulong);
18:
19: static char STARTSYM[] = "_main";
20: static char PROFSYM[] = "_mainp";
21: static char FRAMENAME[] = ".frame";
22: static char *excname[] =
23: {
24: [0] "divide error",
25: [1] "debug exception",
26: [4] "overflow",
27: [5] "bounds check",
28: [6] "invalid opcode",
29: [7] "math coprocessor emulation",
30: [8] "double fault",
31: [9] "math coprocessor overrun",
32: [10] "invalid TSS",
33: [11] "segment not present",
34: [12] "stack exception",
35: [13] "general protection violation",
36: [14] "page fault",
37: [16] "math coprocessor error",
38: [24] "clock",
39: [25] "keyboard",
40: [27] "modem status",
41: [28] "serial line status",
42: [30] "floppy disk",
43: [36] "mouse",
44: [37] "math coprocessor",
45: [38] "hard disk",
46: [64] "system call",
47: };
48:
49: Machdata i386mach =
50: {
51: {0xCC, 0, 0, 0}, /* break point: INT 3 */
52: 1, /* break point size */
53:
54: leswab, /* convert short to local byte order */
55: leswal, /* convert long to local byte order */
56: i386trace, /* C traceback */
57: i386frame, /* frame finder */
58: 0, /* ublock fixup */
59: i386excep, /* print exception */
60: 0, /* breakpoint fixup */
61: leieeesftos, /* single precision float printer */
62: leieeedftos, /* double precision float printer */
63: i386foll, /* following addresses */
64: i386inst, /* print instruction */
65: i386das, /* dissembler */
66: i386instlen, /* instruction size calculation */
67: };
68:
69: static char*
70: i386excep(Map *map, Rgetter rget)
71: {
72: ulong c;
73: ulong pc;
74: static char buf[16];
75:
76: c = (*rget)(map, "TRAP");
77: if(c > 64 || excname[c] == 0) {
78: if (c == 3) {
79: pc = (*rget)(map, "PC");
80: if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0)
81: if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0)
82: return "breakpoint";
83: }
84: sprint(buf, "exception %d", c);
85: return buf;
86: } else
87: return excname[c];
88: }
89:
90: static int
91: i386trace(Map *map, ulong pc, ulong sp, ulong link, Tracer trace)
92: {
93: int i;
94: Symbol s, f;
95: ulong osp;
96:
97: USED(link);
98: i = 0;
99: osp = 0;
100: while(findsym(pc, CTEXT, &s)) {
101: if(osp == sp)
102: break;
103: osp = sp;
104: if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
105: break;
106:
107: if(pc != s.value) { /* not at first instruction */
108: if(findlocal(&s, FRAMENAME, &f) == 0)
109: break;
110: sp += f.value-mach->szaddr;
111: }
112:
113: if (get4(map, sp, (long *) &pc) < 0)
114: break;
115:
116: if(pc == 0)
117: break;
118:
119: (*trace)(map, pc, sp, &s);
120: sp += mach->szaddr;
121:
122: if(++i > 40)
123: break;
124: }
125: return i;
126: }
127:
128: static ulong
129: i386frame(Map *map, ulong addr, ulong pc, ulong sp, ulong link)
130: {
131: Symbol s, f;
132:
133: USED(link);
134: while (findsym(pc, CTEXT, &s)) {
135: if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
136: break;
137:
138: if(pc != s.value) { /* not first instruction */
139: if(findlocal(&s, FRAMENAME, &f) == 0)
140: break;
141: sp += f.value-mach->szaddr;
142: }
143:
144: if (s.value == addr)
145: return sp;
146:
147: if (get4(map, sp, (long *)&pc) < 0)
148: break;
149: sp += mach->szaddr;
150: }
151: return 0;
152: }
153:
154: /* I386/486 - Disassembler and related functions */
155:
156: /*
157: * an instruction
158: */
159: typedef struct Instr Instr;
160: struct Instr
161: {
162: uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */
163: ulong addr; /* address of start of instruction */
164: int n; /* number of bytes in instruction */
165: char *prefix; /* instr prefix */
166: char *segment; /* segment override */
167: uchar jumptype; /* set to the operand type for jump/ret/call */
168: char osize; /* 'W' or 'L' */
169: char asize; /* address size 'W' or 'L' */
170: uchar mod; /* bits 6-7 of mod r/m field */
171: uchar reg; /* bits 3-5 of mod r/m field */
172: char ss; /* bits 6-7 of SIB */
173: char index; /* bits 3-5 of SIB */
174: char base; /* bits 0-2 of SIB */
175: short seg; /* segment of far address */
176: ulong disp; /* displacement */
177: ulong imm; /* immediate */
178: ulong imm2; /* second immediate operand */
179: char *curr; /* fill level in output buffer */
180: char *end; /* end of output buffer */
181: char *err; /* error message */
182: };
183:
184: /* 386 register (ha!) set */
185: enum{
186: AX=0,
187: CX,
188: DX,
189: BX,
190: SP,
191: BP,
192: SI,
193: DI,
194: };
195: /* Operand Format codes */
196: /*
197: %A - address size register modifier (!asize -> 'E')
198: %C - Control register CR0/CR1/CR2
199: %D - Debug register DR0/DR1/DR2/DR3/DR6/DR7
200: %I - second immediate operand
201: %O - Operand size register modifier (!osize -> 'E')
202: %T - Test register TR6/TR7
203: %S - size code ('W' or 'L')
204: %X - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
205: %d - displacement 16-32 bits
206: %e - effective address - Mod R/M value
207: %f - floating point register F0-F7 - from Mod R/M register
208: %g - segment register
209: %i - immediate operand 8-32 bits
210: %p - PC-relative - signed displacement in immediate field
211: %r - Reg from Mod R/M
212: %x - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
213: */
214:
215: typedef struct Optable Optable;
216: struct Optable
217: {
218: char operand[2];
219: void *proto; /* actually either (char*) or (Optable*) */
220: };
221: /* Operand decoding codes */
222: enum {
223: Ib = 1, /* 8-bit immediate - (no sign extension)*/
224: Ibs, /* 8-bit immediate (sign extended) */
225: Jbs, /* 8-bit sign-extended immediate in jump or call */
226: Iw, /* 16-bit immediate -> imm */
227: Iw2, /* 16-bit immediate -> imm2 */
228: Iwd, /* Operand-sized immediate (no sign extension)*/
229: Awd, /* Address offset */
230: Iwds, /* Operand-sized immediate (sign extended) */
231: RM, /* Word or long R/M field with register (/r) */
232: RMB, /* Byte R/M field with register (/r) */
233: RMOP, /* Word or long R/M field with op code (/digit) */
234: RMOPB, /* Byte R/M field with op code (/digit) */
235: RMR, /* R/M register only (mod = 11) */
236: RMM, /* R/M memory only (mod = 0/1/2) */
237: R0, /* Base reg of Mod R/M is literal 0x00 */
238: R1, /* Base reg of Mod R/M is literal 0x01 */
239: FRMOP, /* Floating point R/M field with opcode */
240: FRMEX, /* Extended floating point R/M field with opcode */
241: JUMP, /* Jump or Call flag - no operand */
242: RET, /* Return flag - no operand */
243: OA, /* literal 0x0a byte */
244: PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
245: AUX, /* Multi-byte op code - Auxiliary table */
246: PRE, /* Instr Prefix */
247: SEG, /* Segment Prefix */
248: OPOVER, /* Operand size override */
249: ADDOVER, /* Address size override */
250: };
251:
252: static Optable optab0F00[8]=
253: {
254: [0x00] 0,0, "MOVW LDT,%e",
255: [0x01] 0,0, "MOVW TR,%e",
256: [0x02] 0,0, "MOVW %e,LDT",
257: [0x03] 0,0, "MOVW %e,TR",
258: [0x04] 0,0, "VERR %e",
259: [0x05] 0,0, "VERW %e",
260: };
261:
262: static Optable optab0F01[8]=
263: {
264: [0x00] 0,0, "MOVL GDTR,%e",
265: [0x01] 0,0, "MOVL IDTR,%e",
266: [0x02] 0,0, "MOVL %e,GDTR",
267: [0x03] 0,0, "MOVL %e,IDTR",
268: [0x04] 0,0, "MOVW MSW,%e", /* word */
269: [0x06] 0,0, "MOVW %e,MSW", /* word */
270: };
271:
272: static Optable optab0FBA[8]=
273: {
274: [0x04] Ib,0, "BT%S %i,%e",
275: [0x05] Ib,0, "BTS%S %i,%e",
276: [0x06] Ib,0, "BTR%S %i,%e",
277: [0x07] Ib,0, "BTC%S %i,%e",
278: };
279:
280: static Optable optab0F[256]=
281: {
282: [0x00] RMOP,0, optab0F00,
283: [0x01] RMOP,0, optab0F01,
284: [0x02] RM,0, "LAR %e,%r",
285: [0x03] RM,0, "LSL %e,%r",
286: [0x06] 0,0, "CLTS",
287: [0x08] 0,0, "INVD",
288: [0x09] 0,0, "WBINVD",
289: [0x20] RMR,0, "MOVL %C,%e",
290: [0x21] RMR,0, "MOVL %D,%e",
291: [0x22] RMR,0, "MOVL %e,%C",
292: [0x23] RMR,0, "MOVL %e,%D",
293: [0x24] RMR,0, "MOVL %T,%e",
294: [0x26] RMR,0, "MOVL %e,%T",
295: [0x30] 0,0, "WRMSR",
296: [0x31] 0,0, "RDTSC",
297: [0x32] 0,0, "RDMSR",
298: [0x80] Iwds,0, "JOS %p",
299: [0x81] Iwds,0, "JOC %p",
300: [0x82] Iwds,0, "JCS %p",
301: [0x83] Iwds,0, "JCC %p",
302: [0x84] Iwds,0, "JEQ %p",
303: [0x85] Iwds,0, "JNE %p",
304: [0x86] Iwds,0, "JLS %p",
305: [0x87] Iwds,0, "JHI %p",
306: [0x88] Iwds,0, "JMI %p",
307: [0x89] Iwds,0, "JPL %p",
308: [0x8a] Iwds,0, "JPS %p",
309: [0x8b] Iwds,0, "JPC %p",
310: [0x8c] Iwds,0, "JLT %p",
311: [0x8d] Iwds,0, "JGE %p",
312: [0x8e] Iwds,0, "JLE %p",
313: [0x8f] Iwds,0, "JGT %p",
314: [0x90] RMB,0, "SETOS %e",
315: [0x91] RMB,0, "SETOC %e",
316: [0x92] RMB,0, "SETCS %e",
317: [0x93] RMB,0, "SETCC %e",
318: [0x94] RMB,0, "SETEQ %e",
319: [0x95] RMB,0, "SETNE %e",
320: [0x96] RMB,0, "SETLS %e",
321: [0x97] RMB,0, "SETHI %e",
322: [0x98] RMB,0, "SETMI %e",
323: [0x99] RMB,0, "SETPL %e",
324: [0x9a] RMB,0, "SETPS %e",
325: [0x9b] RMB,0, "SETPC %e",
326: [0x9c] RMB,0, "SETLT %e",
327: [0x9d] RMB,0, "SETGE %e",
328: [0x9e] RMB,0, "SETLE %e",
329: [0x9f] RMB,0, "SETGT %e",
330: [0xa0] 0,0, "PUSHL FS",
331: [0xa1] 0,0, "POPL FS",
332: [0xa2] 0,0, "CPUID",
333: [0xa3] RM,0, "BT%S %r,%e",
334: [0xa4] RM,Ib, "SHLD%S %r,%i,%e",
335: [0xa5] RM,0, "SHLD%S %r,CL,%e",
336: [0xa8] 0,0, "PUSHL GS",
337: [0xa9] 0,0, "POPL GS",
338: [0xab] RM,0, "BTS%S %r,%e",
339: [0xac] RM,Ib, "SHRD%S %r,%i,%e",
340: [0xad] RM,0, "SHRD%S %r,CL,%e",
341: [0xaf] RM,0, "IMUL%S %e,%r",
342: [0xb2] RMM,0, "LSS %e,%r",
343: [0xb3] RM,0, "BTR%S %r,%e",
344: [0xb4] RMM,0, "LFS %e,%r",
345: [0xb5] RMM,0, "LGS %e,%r",
346: [0xb6] RMB,0, "MOVBZX %e,%R",
347: [0xb7] RM,0, "MOVWZX %e,%R",
348: [0xba] RMOP,0, optab0FBA,
349: [0xbb] RM,0, "BTC%S %e,%r",
350: [0xbc] RM,0, "BSF%S %e,%r",
351: [0xbd] RM,0, "BSR%S %e,%r",
352: [0xbe] RMB,0, "MOVBSX %e,%R",
353: [0xbf] RM,0, "MOVWSX %e,%R",
354: };
355:
356: static Optable optab80[8]=
357: {
358: [0x00] Ib,0, "ADDB %i,%e",
359: [0x01] Ib,0, "ORB %i,%e",
360: [0x02] Ib,0, "ADCB %i,%e",
361: [0x03] Ib,0, "SBBB %i,%e",
362: [0x04] Ib,0, "ANDB %i,%e",
363: [0x05] Ib,0, "SUBB %i,%e",
364: [0x06] Ib,0, "XORB %i,%e",
365: [0x07] Ib,0, "CMPB %e,%i",
366: };
367:
368: static Optable optab81[8]=
369: {
370: [0x00] Iwd,0, "ADD%S %i,%e",
371: [0x01] Iwd,0, "OR%S %i,%e",
372: [0x02] Iwd,0, "ADC%S %i,%e",
373: [0x03] Iwd,0, "SBB%S %i,%e",
374: [0x04] Iwd,0, "AND%S %i,%e",
375: [0x05] Iwd,0, "SUB%S %i,%e",
376: [0x06] Iwd,0, "XOR%S %i,%e",
377: [0x07] Iwd,0, "CMP%S %e,%i",
378: };
379:
380: static Optable optab83[8]=
381: {
382: [0x00] Ibs,0, "ADD%S %i,%e",
383: [0x01] Ibs,0, "OR%S %i,%e",
384: [0x02] Ibs,0, "ADC%S %i,%e",
385: [0x03] Ibs,0, "SBB%S %i,%e",
386: [0x04] Ibs,0, "AND%S %i,%e",
387: [0x05] Ibs,0, "SUB%S %i,%e",
388: [0x06] Ibs,0, "XOR%S %i,%e",
389: [0x07] Ibs,0, "CMP%S %e,%i",
390: };
391:
392: static Optable optabC0[8] =
393: {
394: [0x00] Ib,0, "ROLB %i,%e",
395: [0x01] Ib,0, "RORB %i,%e",
396: [0x02] Ib,0, "RCLB %i,%e",
397: [0x03] Ib,0, "RCRB %i,%e",
398: [0x04] Ib,0, "SHLB %i,%e",
399: [0x05] Ib,0, "SHRB %i,%e",
400: [0x07] Ib,0, "SARB %i,%e",
401: };
402:
403: static Optable optabC1[8] =
404: {
405: [0x00] Ib,0, "ROL%S %i,%e",
406: [0x01] Ib,0, "ROR%S %i,%e",
407: [0x02] Ib,0, "RCL%S %i,%e",
408: [0x03] Ib,0, "RCR%S %i,%e",
409: [0x04] Ib,0, "SHL%S %i,%e",
410: [0x05] Ib,0, "SHR%S %i,%e",
411: [0x07] Ib,0, "SAR%S %i,%e",
412: };
413:
414: static Optable optabD0[8] =
415: {
416: [0x00] 0,0, "ROLB %e",
417: [0x01] 0,0, "RORB %e",
418: [0x02] 0,0, "RCLB %e",
419: [0x03] 0,0, "RCRB %e",
420: [0x04] 0,0, "SHLB %e",
421: [0x05] 0,0, "SHRB %e",
422: [0x07] 0,0, "SARB %e",
423: };
424:
425: static Optable optabD1[8] =
426: {
427: [0x00] 0,0, "ROL%S %e",
428: [0x01] 0,0, "ROR%S %e",
429: [0x02] 0,0, "RCL%S %e",
430: [0x03] 0,0, "RCR%S %e",
431: [0x04] 0,0, "SHL%S %e",
432: [0x05] 0,0, "SHR%S %e",
433: [0x07] 0,0, "SAR%S %e",
434: };
435:
436: static Optable optabD2[8] =
437: {
438: [0x00] 0,0, "ROLB CL,%e",
439: [0x01] 0,0, "RORB CL,%e",
440: [0x02] 0,0, "RCLB CL,%e",
441: [0x03] 0,0, "RCRB CL,%e",
442: [0x04] 0,0, "SHLB CL,%e",
443: [0x05] 0,0, "SHRB CL,%e",
444: [0x07] 0,0, "SARB CL,%e",
445: };
446:
447: static Optable optabD3[8] =
448: {
449: [0x00] 0,0, "ROL%S CL,%e",
450: [0x01] 0,0, "ROR%S CL,%e",
451: [0x02] 0,0, "RCL%S CL,%e",
452: [0x03] 0,0, "RCR%S CL,%e",
453: [0x04] 0,0, "SHL%S CL,%e",
454: [0x05] 0,0, "SHR%S CL,%e",
455: [0x07] 0,0, "SAR%S CL,%e",
456: };
457:
458: static Optable optabD8[8+8] =
459: {
460: [0x00] 0,0, "FADDF %e,F0",
461: [0x01] 0,0, "FMULF %e,F0",
462: [0x02] 0,0, "FCOMF %e,F0",
463: [0x03] 0,0, "FCOMFP %e,F0",
464: [0x04] 0,0, "FSUBF %e,F0",
465: [0x05] 0,0, "FSUBRF %e,F0",
466: [0x06] 0,0, "FDIVF %e,F0",
467: [0x07] 0,0, "FDIVRF %e,F0",
468: [0x08] 0,0, "FADDD %f,F0",
469: [0x09] 0,0, "FMULD %f,F0",
470: [0x0a] 0,0, "FCOMD %f,F0",
471: [0x0b] 0,0, "FCOMPD %f,F0",
472: [0x0c] 0,0, "FSUBD %f,F0",
473: [0x0d] 0,0, "FSUBRD %f,F0",
474: [0x0e] 0,0, "FDIVD %f,F0",
475: [0x0f] 0,0, "FDIVRD %f,F0",
476: };
477: /*
478: * optabD9 and optabDB use the following encoding:
479: * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
480: * else instruction = optabDx[(modrm&0x3f)+8];
481: *
482: * the instructions for MOD == 3, follow the 8 instructions
483: * for the other MOD values stored at the front of the table.
484: */
485: static Optable optabD9[64+8] =
486: {
487: [0x00] 0,0, "FMOVF %e,F0",
488: [0x02] 0,0, "FMOVF F0,%e",
489: [0x03] 0,0, "FMOVFP F0,%e",
490: [0x04] 0,0, "FLDENV%S %e",
491: [0x05] 0,0, "FLDCW %e",
492: [0x06] 0,0, "FSTENV%S %e",
493: [0x07] 0,0, "FSTCW %e",
494: [0x08] 0,0, "FMOVD F0,F0", /* Mod R/M = 11xx xxxx*/
495: [0x09] 0,0, "FMOVD F1,F0",
496: [0x0a] 0,0, "FMOVD F2,F0",
497: [0x0b] 0,0, "FMOVD F3,F0",
498: [0x0c] 0,0, "FMOVD F4,F0",
499: [0x0d] 0,0, "FMOVD F5,F0",
500: [0x0e] 0,0, "FMOVD F6,F0",
501: [0x0f] 0,0, "FMOVD F7,F0",
502: [0x10] 0,0, "FXCHD F0,F0",
503: [0x11] 0,0, "FXCHD F1,F0",
504: [0x12] 0,0, "FXCHD F2,F0",
505: [0x13] 0,0, "FXCHD F3,F0",
506: [0x14] 0,0, "FXCHD F4,F0",
507: [0x15] 0,0, "FXCHD F5,F0",
508: [0x16] 0,0, "FXCHD F6,F0",
509: [0x17] 0,0, "FXCHD F7,F0",
510: [0x18] 0,0, "FNOP",
511: [0x28] 0,0, "FCHS",
512: [0x29] 0,0, "FABS",
513: [0x2c] 0,0, "FTST",
514: [0x2d] 0,0, "FXAM",
515: [0x30] 0,0, "FLD1",
516: [0x31] 0,0, "FLDL2T",
517: [0x32] 0,0, "FLDL2E",
518: [0x33] 0,0, "FLDPI",
519: [0x34] 0,0, "FLDLG2",
520: [0x35] 0,0, "FLDLN2",
521: [0x36] 0,0, "FLDZ",
522: [0x38] 0,0, "F2XM1",
523: [0x39] 0,0, "FYL2X",
524: [0x3a] 0,0, "FPTAN",
525: [0x3b] 0,0, "FPATAN",
526: [0x3c] 0,0, "FXTRACT",
527: [0x3d] 0,0, "FPREM1",
528: [0x3e] 0,0, "FDECSTP",
529: [0x3f] 0,0, "FNCSTP",
530: [0x40] 0,0, "FPREM",
531: [0x41] 0,0, "FYL2XP1",
532: [0x42] 0,0, "FSQRT",
533: [0x43] 0,0, "FSINCOS",
534: [0x44] 0,0, "FRNDINT",
535: [0x45] 0,0, "FSCALE",
536: [0x46] 0,0, "FSIN",
537: [0x47] 0,0, "FCOS",
538: };
539:
540: static Optable optabDA[8+8] =
541: {
542: [0x00] 0,0, "FADDL %e,F0",
543: [0x01] 0,0, "FMULL %e,F0",
544: [0x02] 0,0, "FCOML %e,F0",
545: [0x03] 0,0, "FCOMLP %e,F0",
546: [0x04] 0,0, "FSUBL %e,F0",
547: [0x05] 0,0, "FSUBRL %e,F0",
548: [0x06] 0,0, "FDIVL %e,F0",
549: [0x07] 0,0, "FDIVRL %e,F0",
550: [0x0d] R1,0, "FUCOMPP",
551: };
552:
553: static Optable optabDB[8+64] =
554: {
555: [0x00] 0,0, "FMOVL %e,F0",
556: [0x02] 0,0, "FMOVL F0,%e",
557: [0x03] 0,0, "FMOVLP F0,%e",
558: [0x05] 0,0, "FMOVX %e,F0",
559: [0x07] 0,0, "FMOVXP F0,%e",
560: [0x2a] 0,0, "FCLEX",
561: [0x2b] 0,0, "FINIT",
562: };
563:
564: static Optable optabDC[8+8] =
565: {
566: [0x00] 0,0, "FADDD %e,F0",
567: [0x01] 0,0, "FMULD %e,F0",
568: [0x02] 0,0, "FCOMD %e,F0",
569: [0x03] 0,0, "FCOMDP %e,F0",
570: [0x04] 0,0, "FSUBD %e,F0",
571: [0x05] 0,0, "FSUBRD %e,F0",
572: [0x06] 0,0, "FDIVD %e,F0",
573: [0x07] 0,0, "FDIVRD %e,F0",
574: [0x08] 0,0, "FADDD F0,%f",
575: [0x09] 0,0, "FMULD F0,%f",
576: [0x0c] 0,0, "FSUBRD F0,%f",
577: [0x0d] 0,0, "FSUBD F0,%f",
578: [0x0e] 0,0, "FDIVRD F0,%f",
579: [0x0f] 0,0, "FDIVD F0,%f",
580: };
581:
582: static Optable optabDD[8+8] =
583: {
584: [0x00] 0,0, "FMOVD %e,F0",
585: [0x02] 0,0, "FMOVD F0,%e",
586: [0x03] 0,0, "FMOVDP F0,%e",
587: [0x04] 0,0, "FRSTOR%S %e",
588: [0x06] 0,0, "FSAVE%S %e",
589: [0x07] 0,0, "FSTSW %e",
590: [0x08] 0,0, "FFREED %f",
591: [0x0a] 0,0, "FMOVD %f,F0",
592: [0x0b] 0,0, "FMOVDP %f,F0",
593: [0x0c] 0,0, "FUCOMD %f,F0",
594: [0x0d] 0,0, "FUCOMDP %f,F0",
595: };
596:
597: static Optable optabDE[8+8] =
598: {
599: [0x00] 0,0, "FADDW %e,F0",
600: [0x01] 0,0, "FMULW %e,F0",
601: [0x02] 0,0, "FCOMW %e,F0",
602: [0x03] 0,0, "FCOMWP %e,F0",
603: [0x04] 0,0, "FSUBW %e,F0",
604: [0x05] 0,0, "FSUBRW %e,F0",
605: [0x06] 0,0, "FDIVW %e,F0",
606: [0x07] 0,0, "FDIVRW %e,F0",
607: [0x08] 0,0, "FADDDP F0,%f",
608: [0x09] 0,0, "FMULDP F0,%f",
609: [0x0b] R1,0, "FCOMPDP",
610: [0x0c] 0,0, "FSUBRDP F0,%f",
611: [0x0d] 0,0, "FSUBDP F0,%f",
612: [0x0e] 0,0, "FDIVRDP F0,%f",
613: [0x0f] 0,0, "FDIVDP F0,%f",
614: };
615:
616: static Optable optabDF[8+8] =
617: {
618: [0x00] 0,0, "FMOVW %e,F0",
619: [0x02] 0,0, "FMOVW F0,%e",
620: [0x03] 0,0, "FMOVWP F0,%e",
621: [0x04] 0,0, "FBLD %e",
622: [0x05] 0,0, "FMOVL %e,F0",
623: [0x06] 0,0, "FBSTP %e",
624: [0x07] 0,0, "FMOVLP F0,%e",
625: [0x0c] R0,0, "FSTSW %OAX",
626: };
627:
628: static Optable optabF6[8] =
629: {
630: [0x00] Ib,0, "TESTB %i,%e",
631: [0x02] 0,0, "NOTB %e",
632: [0x03] 0,0, "NEGB %e",
633: [0x04] 0,0, "MULB AL,%e",
634: [0x05] 0,0, "IMULB AL,%e",
635: [0x06] 0,0, "DIVB AL,%e",
636: [0x07] 0,0, "IDIVB AL,%e",
637: };
638:
639: static Optable optabF7[8] =
640: {
641: [0x00] Iwd,0, "TEST%S %i,%e",
642: [0x02] 0,0, "NOT%S %e",
643: [0x03] 0,0, "NEG%S %e",
644: [0x04] 0,0, "MUL%S %OAX,%e",
645: [0x05] 0,0, "IMUL%S %OAX,%e",
646: [0x06] 0,0, "DIV%S %OAX,%e",
647: [0x07] 0,0, "IDIV%S %OAX,%e",
648: };
649:
650: static Optable optabFE[8] =
651: {
652: [0x00] 0,0, "INCB %e",
653: [0x01] 0,0, "DECB %e",
654: };
655:
656: static Optable optabFF[8] =
657: {
658: [0x00] 0,0, "INC%S %e",
659: [0x01] 0,0, "DEC%S %e",
660: [0x02] JUMP,0, "CALL*%S %e",
661: [0x03] JUMP,0, "CALLF*%S %e",
662: [0x04] JUMP,0, "JMP*%S %e",
663: [0x05] JUMP,0, "JMPF*%S %e",
664: [0x06] 0,0, "PUSHL %e",
665: };
666:
667: static Optable optable[256] =
668: {
669: [0x00] RMB,0, "ADDB %r,%e",
670: [0x01] RM,0, "ADD%S %r,%e",
671: [0x02] RMB,0, "ADDB %e,%r",
672: [0x03] RM,0, "ADD%S %e,%r",
673: [0x04] Ib,0, "ADDB %i,AL",
674: [0x05] Iwd,0, "ADD%S %i,%OAX",
675: [0x06] 0,0, "PUSHL ES",
676: [0x07] 0,0, "POPL ES",
677: [0x08] RMB,0, "ORB %r,%e",
678: [0x09] RM,0, "OR%S %r,%e",
679: [0x0a] RMB,0, "ORB %e,%r",
680: [0x0b] RM,0, "OR%S %e,%r",
681: [0x0c] Ib,0, "ORB %i,AL",
682: [0x0d] Iwd,0, "OR%S %i,%OAX",
683: [0x0e] 0,0, "PUSHL CS",
684: [0x0f] AUX,0, optab0F,
685: [0x10] RMB,0, "ADCB %r,%e",
686: [0x11] RM,0, "ADC%S %r,%e",
687: [0x12] RMB,0, "ADCB %e,%r",
688: [0x13] RM,0, "ADC%S %e,%r",
689: [0x14] Ib,0, "ADCB %i,AL",
690: [0x15] Iwd,0, "ADC%S %i,%OAX",
691: [0x16] 0,0, "PUSHL SS",
692: [0x17] 0,0, "POPL SS",
693: [0x18] RMB,0, "SBBB %r,%e",
694: [0x19] RM,0, "SBB%S %r,%e",
695: [0x1a] RMB,0, "SBBB %e,%r",
696: [0x1b] RM,0, "SBB%S %e,%r",
697: [0x1c] Ib,0, "SBBB %i,AL",
698: [0x1d] Iwd,0, "SBB%S %i,%OAX",
699: [0x1e] 0,0, "PUSHL DS",
700: [0x1f] 0,0, "POPL DS",
701: [0x20] RMB,0, "ANDB %r,%e",
702: [0x21] RM,0, "AND%S %r,%e",
703: [0x22] RMB,0, "ANDB %e,%r",
704: [0x23] RM,0, "AND%S %e,%r",
705: [0x24] Ib,0, "ANDB %i,AL",
706: [0x25] Iwd,0, "AND%S %i,%OAX",
707: [0x26] SEG,0, "ES:",
708: [0x27] 0,0, "DAA",
709: [0x28] RMB,0, "SUBB %r,%e",
710: [0x29] RM,0, "SUB%S %r,%e",
711: [0x2a] RMB,0, "SUBB %e,%r",
712: [0x2b] RM,0, "SUB%S %e,%r",
713: [0x2c] Ib,0, "SUBB %i,AL",
714: [0x2d] Iwd,0, "SUB%S %i,%OAX",
715: [0x2e] SEG,0, "CS:",
716: [0x2f] 0,0, "DAS",
717: [0x30] RMB,0, "XORB %r,%e",
718: [0x31] RM,0, "XOR%S %r,%e",
719: [0x32] RMB,0, "XORB %e,%r",
720: [0x33] RM,0, "XOR%S %e,%r",
721: [0x34] Ib,0, "XORB %i,AL",
722: [0x35] Iwd,0, "XOR%S %i,%OAX",
723: [0x36] SEG,0, "SS:",
724: [0x37] 0,0, "AAA",
725: [0x38] RMB,0, "CMPB %r,%e",
726: [0x39] RM,0, "CMP%S %r,%e",
727: [0x3a] RMB,0, "CMPB %e,%r",
728: [0x3b] RM,0, "CMP%S %e,%r",
729: [0x3c] Ib,0, "CMPB %i,AL",
730: [0x3d] Iwd,0, "CMP%S %i,%OAX",
731: [0x3e] SEG,0, "DS:",
732: [0x3f] 0,0, "AAS",
733: [0x40] 0,0, "INC%S %OAX",
734: [0x41] 0,0, "INC%S %OCX",
735: [0x42] 0,0, "INC%S %ODX",
736: [0x43] 0,0, "INC%S %OBX",
737: [0x44] 0,0, "INC%S %OSP",
738: [0x45] 0,0, "INC%S %OBP",
739: [0x46] 0,0, "INC%S %OSI",
740: [0x47] 0,0, "INC%S %ODI",
741: [0x48] 0,0, "DEC%S %OAX",
742: [0x49] 0,0, "DEC%S %OCX",
743: [0x4a] 0,0, "DEC%S %ODX",
744: [0x4b] 0,0, "DEC%S %OBX",
745: [0x4c] 0,0, "DEC%S %OSP",
746: [0x4d] 0,0, "DEC%S %OBP",
747: [0x4e] 0,0, "DEC%S %OSI",
748: [0x4f] 0,0, "DEC%S %ODI",
749: [0x50] 0,0, "PUSH%S %OAX",
750: [0x51] 0,0, "PUSH%S %OCX",
751: [0x52] 0,0, "PUSH%S %ODX",
752: [0x53] 0,0, "PUSH%S %OBX",
753: [0x54] 0,0, "PUSH%S %OSP",
754: [0x55] 0,0, "PUSH%S %OBP",
755: [0x56] 0,0, "PUSH%S %OSI",
756: [0x57] 0,0, "PUSH%S %ODI",
757: [0x58] 0,0, "POP%S %OAX",
758: [0x59] 0,0, "POP%S %OCX",
759: [0x5a] 0,0, "POP%S %ODX",
760: [0x5b] 0,0, "POP%S %OBX",
761: [0x5c] 0,0, "POP%S %OSP",
762: [0x5d] 0,0, "POP%S %OBP",
763: [0x5e] 0,0, "POP%S %OSI",
764: [0x5f] 0,0, "POP%S %ODI",
765: [0x60] 0,0, "PUSHA%S",
766: [0x61] 0,0, "POPA%S",
767: [0x62] RMM,0, "BOUND %e,%r",
768: [0x63] RM,0, "ARPL %r,%e",
769: [0x64] SEG,0, "FS:",
770: [0x65] SEG,0, "GS:",
771: [0x66] OPOVER,0, "",
772: [0x67] ADDOVER,0, "",
773: [0x68] Iwd,0, "PUSH%S %i",
774: [0x69] RM,Iwd, "IMUL%S %e,%i,%r",
775: [0x6a] Ib,0, "PUSH%S %i",
776: [0x6b] RM,Ibs, "IMUL%S %e,%i,%r",
777: [0x6c] 0,0, "INSB DX,(%ODI)",
778: [0x6d] 0,0, "INS%S DX,(%ODI)",
779: [0x6e] 0,0, "OUTSB (%ASI),DX",
780: [0x6f] 0,0, "OUTS%S (%ASI),DX",
781: [0x70] Jbs,0, "JOS %p",
782: [0x71] Jbs,0, "JOC %p",
783: [0x72] Jbs,0, "JCS %p",
784: [0x73] Jbs,0, "JCC %p",
785: [0x74] Jbs,0, "JEQ %p",
786: [0x75] Jbs,0, "JNE %p",
787: [0x76] Jbs,0, "JLS %p",
788: [0x77] Jbs,0, "JHI %p",
789: [0x78] Jbs,0, "JMI %p",
790: [0x79] Jbs,0, "JPL %p",
791: [0x7a] Jbs,0, "JPS %p",
792: [0x7b] Jbs,0, "JPC %p",
793: [0x7c] Jbs,0, "JLT %p",
794: [0x7d] Jbs,0, "JGE %p",
795: [0x7e] Jbs,0, "JLE %p",
796: [0x7f] Jbs,0, "JGT %p",
797: [0x80] RMOPB,0, optab80,
798: [0x81] RMOP,0, optab81,
799: [0x83] RMOP,0, optab83,
800: [0x84] RMB,0, "TESTB %r,%e",
801: [0x85] RM,0, "TEST%S %r,%e",
802: [0x86] RMB,0, "XCHGB %r,%e",
803: [0x87] RM,0, "XCHG%S %r,%e",
804: [0x88] RMB,0, "MOVB %r,%e",
805: [0x89] RM,0, "MOV%S %r,%e",
806: [0x8a] RMB,0, "MOVB %e,%r",
807: [0x8b] RM,0, "MOV%S %e,%r",
808: [0x8c] RM,0, "MOVW %g,%e",
809: [0x8d] RM,0, "LEA %e,%r",
810: [0x8e] RM,0, "MOVW %e,%g",
811: [0x8f] RM,0, "POP%S %e",
812: [0x90] 0,0, "NOP",
813: [0x91] 0,0, "XCHG %OCX,%OAX",
814: [0x92] 0,0, "XCHG %OCX,%OAX",
815: [0x93] 0,0, "XCHG %OCX,%OAX",
816: [0x94] 0,0, "XCHG %OSP,%OAX",
817: [0x95] 0,0, "XCHG %OBP,%OAX",
818: [0x96] 0,0, "XCHG %OSI,%OAX",
819: [0x97] 0,0, "XCHG %ODI,%OAX",
820: [0x98] 0,0, "%X", /* miserable CBW or CWDE */
821: [0x99] 0,0, "%x", /* idiotic CWD or CDQ */
822: [0x9a] PTR,0, "CALL%S %d",
823: [0x9b] 0,0, "WAIT",
824: [0x9c] 0,0, "PUSH FLAGS",
825: [0x9d] 0,0, "POP FLAGS",
826: [0x9f] 0,0, "LAHF",
827: [0xa0] Awd,0, "MOVB %i,AL",
828: [0xa1] Awd,0, "MOV%S %i,%OAX",
829: [0xa2] Awd,0, "MOVB AL,%i",
830: [0xa3] Awd,0, "MOV%S %OAX,%i",
831: [0xa4] 0,0, "MOVSB (%ASI),(%ADI)",
832: [0xa5] 0,0, "MOVS%S (%ASI),(%ADI)",
833: [0xa6] 0,0, "CMPSB (%ASI),(%ADI)",
834: [0xa7] 0,0, "CMPS%S (%ASI),(%ADI)",
835: [0xa8] Ib,0, "TESTB %i,AL",
836: [0xa9] Iwd,0, "TEST%S %i,%OAX",
837: [0xaa] 0,0, "STOSB AL,(%ADI)",
838: [0xab] 0,0, "STOS%S %OAX,(%ADI)",
839: [0xac] 0,0, "LODSB (%ASI),AL",
840: [0xad] 0,0, "LODS%S (%ASI),%OAX",
841: [0xae] 0,0, "SCASB (%ADI),AL",
842: [0xaf] 0,0, "SCAS%S (%ADI),%OAX",
843: [0xb0] Ib,0, "MOVB %i,AL",
844: [0xb1] Ib,0, "MOVB %i,CL",
845: [0xb2] Ib,0, "MOVB %i,DL",
846: [0xb3] Ib,0, "MOVB %i,BL",
847: [0xb4] Ib,0, "MOVB %i,AH",
848: [0xb5] Ib,0, "MOVB %i,CH",
849: [0xb6] Ib,0, "MOVB %i,DH",
850: [0xb7] Ib,0, "MOVB %i,BH",
851: [0xb8] Iwd,0, "MOV%S %i,%OAX",
852: [0xb9] Iwd,0, "MOV%S %i,%OCX",
853: [0xba] Iwd,0, "MOV%S %i,%ODX",
854: [0xbb] Iwd,0, "MOV%S %i,%OBX",
855: [0xbc] Iwd,0, "MOV%S %i,%OSP",
856: [0xbd] Iwd,0, "MOV%S %i,%OBP",
857: [0xbe] Iwd,0, "MOV%S %i,%OSI",
858: [0xbf] Iwd,0, "MOV%S %i,%ODI",
859: [0xc0] RMOPB,0, optabC0,
860: [0xc1] RMOP,0, optabC1,
861: [0xc2] Iw,0, "RET %i",
862: [0xc3] RET,0, "RET",
863: [0xc4] RM,0, "LES %e,%r",
864: [0xc5] RM,0, "LDS %e,%r",
865: [0xc6] RMB,Ib, "MOVB %i,%e",
866: [0xc7] RM,Iwd, "MOV%S %i,%e",
867: [0xc8] Iw2,Ib, "ENTER %i,%I", /* loony ENTER */
868: [0xc9] RET,0, "LEAVE", /* bizarre LEAVE */
869: [0xca] Iw,0, "RETF %i",
870: [0xcb] RET,0, "RETF",
871: [0xcc] 0,0, "INT 3",
872: [0xcd] Ib,0, "INTB %i",
873: [0xce] 0,0, "INTO",
874: [0xcf] 0,0, "IRET",
875: [0xd0] RMOPB,0, optabD0,
876: [0xd1] RMOP,0, optabD1,
877: [0xd2] RMOPB,0, optabD2,
878: [0xd3] RMOP,0, optabD3,
879: [0xd4] OA,0, "AAM",
880: [0xd5] OA,0, "AAD",
881: [0xd7] 0,0, "XLAT",
882: [0xd8] FRMOP,0, optabD8,
883: [0xd9] FRMEX,0, optabD9,
884: [0xda] FRMOP,0, optabDA,
885: [0xdb] FRMEX,0, optabDB,
886: [0xdc] FRMOP,0, optabDC,
887: [0xdd] FRMOP,0, optabDD,
888: [0xde] FRMOP,0, optabDE,
889: [0xdf] FRMOP,0, optabDF,
890: [0xe0] Jbs,0, "LOOPNE %p",
891: [0xe1] Jbs,0, "LOOPE %p",
892: [0xe2] Jbs,0, "LOOP %p",
893: [0xe3] Jbs,0, "JCXZ %p",
894: [0xe4] Ib,0, "INB %i,AL",
895: [0xe5] Ib,0, "IN%S %i,%OAX",
896: [0xe6] Ib,0, "OUTB AL,%i",
897: [0xe7] Ib,0, "OUT%S %OAX,%i",
898: [0xe8] Iwds,0, "CALL %p",
899: [0xe9] Iwds,0, "JMP %p",
900: [0xea] PTR,0, "JMP %d",
901: [0xeb] Jbs,0, "JMP %p",
902: [0xec] 0,0, "INB DX,AL",
903: [0xed] 0,0, "IN%S DX,%OAX",
904: [0xee] 0,0, "OUTB AL,DX",
905: [0xef] 0,0, "OUT%S %OAX,DX",
906: [0xf0] PRE,0, "LOCK",
907: [0xf2] PRE,0, "REPNE",
908: [0xf3] PRE,0, "REP",
909: [0xf4] 0,0, "HALT",
910: [0xf5] 0,0, "CMC",
911: [0xf6] RMOPB,0, optabF6,
912: [0xf7] RMOP,0, optabF7,
913: [0xf8] 0,0, "CLC",
914: [0xf9] 0,0, "STC",
915: [0xfa] 0,0, "CLI",
916: [0xfb] 0,0, "STI",
917: [0xfc] 0,0, "CLD",
918: [0xfd] 0,0, "STD",
919: [0xfe] RMOPB,0, optabFE,
920: [0xff] RMOP,0, optabFF,
921: };
922:
923: /*
924: * get a byte of the instruction
925: */
926: static int
927: igetc(Map * map, Instr *ip, uchar *c)
928: {
929: if(ip->n+1 > sizeof(ip->mem)){
930: werrstr("instruction too long");
931: return -1;
932: }
933: if (get1(map, ip->addr+ip->n, c, 1) < 0) {
934: werrstr("can't read instruction: %r");
935: return -1;
936: }
937: ip->mem[ip->n++] = *c;
938: return 1;
939: }
940:
941: /*
942: * get two bytes of the instruction
943: */
944: static int
945: igets(Map *map, Instr *ip, ushort *sp)
946: {
947: uchar c;
948: ushort s;
949:
950: if (igetc(map, ip, &c) < 0)
951: return -1;
952: s = c;
953: if (igetc(map, ip, &c) < 0)
954: return -1;
955: s |= (c<<8);
956: *sp = s;
957: return 1;
958: }
959:
960: /*
961: * get 4 bytes of the instruction
962: */
963: static int
964: igetl(Map *map, Instr *ip, ulong *lp)
965: {
966: ushort s;
967: long l;
968:
969: if (igets(map, ip, &s) < 0)
970: return -1;
971: l = s;
972: if (igets(map, ip, &s) < 0)
973: return -1;
974: l |= (s<<16);
975: *lp = l;
976: return 1;
977: }
978:
979: static int
980: getdisp(Map *map, Instr *ip, int mod, int rm, int code)
981: {
982: uchar c;
983: ushort s;
984:
985: if (mod > 2)
986: return 1;
987: if (mod == 1) {
988: if (igetc(map, ip, &c) < 0)
989: return -1;
990: if (c&0x80)
991: ip->disp = c|0xffffff00;
992: else
993: ip->disp = c&0xff;
994: } else if (mod == 2 || rm == code) {
995: if (ip->asize == 'E') {
996: if (igetl(map, ip, &ip->disp) < 0)
997: return -1;
998: } else {
999: if (igets(map, ip, &s) < 0)
1000: return -1;
1001: if (s&0x8000)
1002: ip->disp = s|0xffff0000;
1003: else
1004: ip->disp = s;
1005: }
1006: if (mod == 0)
1007: ip->base = -1;
1008: }
1009: return 1;
1010: }
1011:
1012: static int
1013: modrm(Map *map, Instr *ip, uchar c)
1014: {
1015: uchar rm, mod;
1016:
1017: mod = (c>>6)&3;
1018: rm = c&7;
1019: ip->mod = mod;
1020: ip->base = rm;
1021: ip->reg = (c>>3)&7;
1022: if (mod == 3) /* register */
1023: return 1;
1024: if (ip->asize == 0) { /* 16-bit mode */
1025: switch(rm)
1026: {
1027: case 0:
1028: ip->base = BX; ip->index = SI;
1029: break;
1030: case 1:
1031: ip->base = BX; ip->index = DI;
1032: break;
1033: case 2:
1034: ip->base = BP; ip->index = SI;
1035: break;
1036: case 3:
1037: ip->base = BP; ip->index = DI;
1038: break;
1039: case 4:
1040: ip->base = SI;
1041: break;
1042: case 5:
1043: ip->base = DI;
1044: break;
1045: case 6:
1046: ip->base = BP;
1047: break;
1048: case 7:
1049: ip->base = BX;
1050: break;
1051: default:
1052: break;
1053: }
1054: return getdisp(map, ip, mod, rm, 6);
1055: }
1056: if (rm == 4) { /* scummy sib byte */
1057: if (igetc(map, ip, &c) < 0)
1058: return -1;
1059: ip->ss = (c>>6)&0x03;
1060: ip->index = (c>>3)&0x07;
1061: if (ip->index == 4)
1062: ip->index = -1;
1063: ip->base = c&0x07;
1064: return getdisp(map, ip, mod, ip->base, 5);
1065: }
1066: return getdisp(map, ip, mod, rm, 5);
1067: }
1068:
1069: static Optable *
1070: mkinstr(Map *map, Instr *ip, ulong pc)
1071: {
1072: int i, n;
1073: uchar c;
1074: ushort s;
1075: Optable *op, *obase;
1076: char buf[128];
1077:
1078: memset(ip, 0, sizeof(*ip));
1079: ip->base = -1;
1080: ip->index = -1;
1081: if(asstype == AI8086)
1082: ip->osize = 'W';
1083: else {
1084: ip->osize = 'L';
1085: ip->asize = 'E';
1086: }
1087: ip->addr = pc;
1088: if (igetc(map, ip, &c) < 0)
1089: return 0;
1090: obase = optable;
1091: newop:
1092: op = &obase[c];
1093: if (op->proto == 0) {
1094: badop:
1095: n = snprint(buf, sizeof(buf), "opcode: ??");
1096: for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
1097: _hexify(buf+n, ip->mem[i], 1);
1098: strcpy(buf+n, "??");
1099: werrstr(buf);
1100: return 0;
1101: }
1102: for(i = 0; i < 2 && op->operand[i]; i++) {
1103: switch(op->operand[i])
1104: {
1105: case Ib: /* 8-bit immediate - (no sign extension)*/
1106: if (igetc(map, ip, &c) < 0)
1107: return 0;
1108: ip->imm = c&0xff;
1109: break;
1110: case Jbs: /* 8-bit jump immediate (sign extended) */
1111: if (igetc(map, ip, &c) < 0)
1112: return 0;
1113: if (c&0x80)
1114: ip->imm = c|0xffffff00;
1115: else
1116: ip->imm = c&0xff;
1117: ip->jumptype = Jbs;
1118: break;
1119: case Ibs: /* 8-bit immediate (sign extended) */
1120: if (igetc(map, ip, &c) < 0)
1121: return 0;
1122: if (c&0x80)
1123: if (ip->osize == 'L')
1124: ip->imm = c|0xffffff00;
1125: else
1126: ip->imm = c|0xff00;
1127: else
1128: ip->imm = c&0xff;
1129: break;
1130: case Iw: /* 16-bit immediate -> imm */
1131: if (igets(map, ip, &s) < 0)
1132: return 0;
1133: ip->imm = s&0xffff;
1134: ip->jumptype = Iw;
1135: break;
1136: case Iw2: /* 16-bit immediate -> in imm2*/
1137: if (igets(map, ip, &s) < 0)
1138: return 0;
1139: ip->imm2 = s&0xffff;
1140: break;
1141: case Iwd: /* Operand-sized immediate (no sign extension)*/
1142: if (ip->osize == 'L') {
1143: if (igetl(map, ip, &ip->imm) < 0)
1144: return 0;
1145: } else {
1146: if (igets(map, ip, &s)< 0)
1147: return 0;
1148: ip->imm = s&0xffff;
1149: }
1150: break;
1151: case Awd: /* Address-sized immediate (no sign extension)*/
1152: if (ip->asize == 'E') {
1153: if (igetl(map, ip, &ip->imm) < 0)
1154: return 0;
1155: } else {
1156: if (igets(map, ip, &s)< 0)
1157: return 0;
1158: ip->imm = s&0xffff;
1159: }
1160: break;
1161: case Iwds: /* Operand-sized immediate (sign extended) */
1162: if (ip->osize == 'L') {
1163: if (igetl(map, ip, &ip->imm) < 0)
1164: return 0;
1165: } else {
1166: if (igets(map, ip, &s)< 0)
1167: return 0;
1168: if (s&0x8000)
1169: ip->imm = s|0xffff0000;
1170: else
1171: ip->imm = s&0xffff;
1172: }
1173: ip->jumptype = Iwds;
1174: break;
1175: case OA: /* literal 0x0a byte */
1176: if (igetc(map, ip, &c) < 0)
1177: return 0;
1178: if (c != 0x0a)
1179: goto badop;
1180: break;
1181: case R0: /* base register must be R0 */
1182: if (ip->base != 0)
1183: goto badop;
1184: break;
1185: case R1: /* base register must be R1 */
1186: if (ip->base != 1)
1187: goto badop;
1188: break;
1189: case RMB: /* R/M field with byte register (/r)*/
1190: if (igetc(map, ip, &c) < 0)
1191: return 0;
1192: if (modrm(map, ip, c) < 0)
1193: return 0;
1194: ip->osize = 'B';
1195: break;
1196: case RM: /* R/M field with register (/r) */
1197: if (igetc(map, ip, &c) < 0)
1198: return 0;
1199: if (modrm(map, ip, c) < 0)
1200: return 0;
1201: break;
1202: case RMOPB: /* R/M field with op code (/digit) */
1203: if (igetc(map, ip, &c) < 0)
1204: return 0;
1205: if (modrm(map, ip, c) < 0)
1206: return 0;
1207: c = ip->reg; /* secondary op code */
1208: obase = (Optable*)op->proto;
1209: ip->osize = 'B';
1210: goto newop;
1211: case RMOP: /* R/M field with op code (/digit) */
1212: if (igetc(map, ip, &c) < 0)
1213: return 0;
1214: if (modrm(map, ip, c) < 0)
1215: return 0;
1216: c = ip->reg;
1217: obase = (Optable*)op->proto;
1218: goto newop;
1219: case FRMOP: /* FP R/M field with op code (/digit) */
1220: if (igetc(map, ip, &c) < 0)
1221: return 0;
1222: if (modrm(map, ip, c) < 0)
1223: return 0;
1224: if ((c&0xc0) == 0xc0)
1225: c = ip->reg+8; /* 16 entry table */
1226: else
1227: c = ip->reg;
1228: obase = (Optable*)op->proto;
1229: goto newop;
1230: case FRMEX: /* Extended FP R/M field with op code (/digit) */
1231: if (igetc(map, ip, &c) < 0)
1232: return 0;
1233: if (modrm(map, ip, c) < 0)
1234: return 0;
1235: if ((c&0xc0) == 0xc0)
1236: c = (c&0x3f)+8; /* 64-entry table */
1237: else
1238: c = ip->reg;
1239: obase = (Optable*)op->proto;
1240: goto newop;
1241: case RMR: /* R/M register only (mod = 11) */
1242: if (igetc(map, ip, &c) < 0)
1243: return 0;
1244: if ((c&0xc0) != 0xc0) {
1245: werrstr("invalid R/M register: %x", c);
1246: return 0;
1247: }
1248: if (modrm(map, ip, c) < 0)
1249: return 0;
1250: break;
1251: case RMM: /* R/M register only (mod = 11) */
1252: if (igetc(map, ip, &c) < 0)
1253: return 0;
1254: if ((c&0xc0) == 0xc0) {
1255: werrstr("invalid R/M memory mode: %x", c);
1256: return 0;
1257: }
1258: if (modrm(map, ip, c) < 0)
1259: return 0;
1260: break;
1261: case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
1262: if (igets(map, ip, (ushort*)&ip->seg) < 0)
1263: return 0;
1264: if (ip->osize == 'L') {
1265: if (igetl(map, ip, &ip->disp) < 0)
1266: return 0;
1267: } else {
1268: if (igets(map, ip, &s)< 0)
1269: return 0;
1270: ip->disp = s&0xffff;
1271: }
1272: ip->jumptype = PTR;
1273: break;
1274: case AUX: /* Multi-byte op code - Auxiliary table */
1275: obase = (Optable*)op->proto;
1276: if (igetc(map, ip, &c) < 0)
1277: return 0;
1278: goto newop;
1279: case PRE: /* Instr Prefix */
1280: ip->prefix = (char*)op->proto;
1281: if (igetc(map, ip, &c) < 0)
1282: return 0;
1283: goto newop;
1284: case SEG: /* Segment Prefix */
1285: ip->segment = (char*)op->proto;
1286: if (igetc(map, ip, &c) < 0)
1287: return 0;
1288: goto newop;
1289: case OPOVER: /* Operand size override */
1290: ip->osize = 'W';
1291: if (igetc(map, ip, &c) < 0)
1292: return 0;
1293: goto newop;
1294: case ADDOVER: /* Address size override */
1295: ip->asize = 0;
1296: if (igetc(map, ip, &c) < 0)
1297: return 0;
1298: goto newop;
1299: case JUMP: /* mark instruction as JUMP or RET */
1300: case RET:
1301: ip->jumptype = op->operand[i];
1302: break;
1303: default:
1304: werrstr("bad operand type %d", op->operand[i]);
1305: return 0;
1306: }
1307: }
1308: return op;
1309: }
1310:
1311: static void
1312: bprint(Instr *ip, char *fmt, ...)
1313: {
1314: ip->curr = doprint(ip->curr, ip->end, fmt, (&fmt+1));
1315: }
1316:
1317: /*
1318: * if 32-bit registers are to be named E<rr>, macro ANAME should
1319: * always return ip->asize and ONAME should return a 'E' when
1320: * when ip->osize == 'L'. The macros should return a null character
1321: * when 32-bit registers are ddesignated by <rr>.
1322: */
1323: #define ANAME(ip) 0
1324: #define ONAME(ip) ((ip)->osize == 'L' ? 0 : 0)
1325:
1326: static char *reg[] = {
1327: [AX] "AX",
1328: [CX] "CX",
1329: [DX] "DX",
1330: [BX] "BX",
1331: [SP] "SP",
1332: [BP] "BP",
1333: [SI] "SI",
1334: [DI] "DI",
1335: };
1336:
1337: static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
1338: static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
1339:
1340: static void
1341: plocal(Instr *ip)
1342: {
1343: int ret, offset;
1344: Symbol s;
1345: char *reg;
1346:
1347: offset = ip->disp;
1348: if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) {
1349: bprint(ip, "%lux(SP)", offset);
1350: return;
1351: }
1352:
1353: if (s.value > ip->disp) {
1354: ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s);
1355: reg = "(SP)";
1356: } else {
1357: offset -= s.value;
1358: ret = getauto(&s, offset, CPARAM, &s);
1359: reg = "(FP)";
1360: }
1361: if (ret)
1362: bprint(ip, "%s+", s.name);
1363: else
1364: offset = ip->disp;
1365: bprint(ip, "%lux%s", offset, reg);
1366: }
1367:
1368: static void
1369: pea(Instr *ip)
1370: {
1371: if (ip->mod == 3) {
1372: if (ip->osize == 'B')
1373: bprint(ip, breg[ip->base]);
1374: else
1375: bprint(ip, "%c%s", ANAME(ip), reg[ip->base]);
1376: return;
1377: }
1378: if (ip->segment)
1379: bprint(ip, ip->segment);
1380: if (ip->asize == 'E' && ip->base == SP)
1381: plocal(ip);
1382: else {
1383: bprint(ip,"%lux", ip->disp);
1384: if (ip->base >= 0)
1385: bprint(ip,"(%c%s)", ANAME(ip), reg[ip->base]);
1386: }
1387: if (ip->index >= 0)
1388: bprint(ip,"(%c%s*%d)", ANAME(ip), reg[ip->index], 1<<ip->ss);
1389: }
1390:
1391: static void
1392: immediate(Instr *ip, long val)
1393: {
1394: Symbol s;
1395: long w;
1396:
1397: if (findsym(val, CANY, &s)) {
1398: w = val - s.value;
1399: if (w < 0)
1400: w = -w;
1401: if (w < 4096) {
1402: if (w)
1403: bprint(ip, "%s+%lux(SB)", s.name, w);
1404: else
1405: bprint(ip, "%s(SB)", s.name);
1406: return;
1407: }
1408: }
1409: bprint(ip, "%lux", val);
1410: }
1411:
1412: static void
1413: prinstr(Instr *ip, char *fmt)
1414: {
1415: if (ip->prefix)
1416: bprint(ip, "%s ", ip->prefix);
1417: for (; *fmt && ip->curr < ip->end; fmt++) {
1418: if (*fmt != '%')
1419: *ip->curr++ = *fmt;
1420: else switch(*++fmt)
1421: {
1422: case '%':
1423: *ip->curr++ = '%';
1424: break;
1425: case 'A':
1426: bprint(ip, "%c", ANAME(ip));
1427: break;
1428: case 'C':
1429: bprint(ip, "CR%d", ip->reg);
1430: break;
1431: case 'D':
1432: if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
1433: bprint(ip, "DR%d",ip->reg);
1434: else
1435: bprint(ip, "???");
1436: break;
1437: case 'I':
1438: bprint(ip, "$");
1439: immediate(ip, ip->imm2);
1440: break;
1441: case 'O':
1442: bprint(ip,"%c", ONAME(ip));
1443: break;
1444: case 'i':
1445: bprint(ip, "$");
1446: immediate(ip,ip->imm);
1447: break;
1448: case 'R':
1449: bprint(ip, "%c%s", ONAME(ip), reg[ip->reg]);
1450: break;
1451: case 'S':
1452: bprint(ip, "%c", ip->osize);
1453: break;
1454: case 'T':
1455: if (ip->reg == 6 || ip->reg == 7)
1456: bprint(ip, "TR%d",ip->reg);
1457: else
1458: bprint(ip, "???");
1459: break;
1460: case 'X':
1461: if (ip->osize == 'L')
1462: bprint(ip,"CWDE");
1463: else
1464: bprint(ip, "CBW");
1465: break;
1466: case 'd':
1467: bprint(ip,"%lux:%lux",ip->seg,ip->disp);
1468: break;
1469: case 'e':
1470: pea(ip);
1471: break;
1472: case 'f':
1473: bprint(ip, "F%d", ip->base);
1474: break;
1475: case 'g':
1476: if (ip->reg < 6)
1477: bprint(ip,"%s",sreg[ip->reg]);
1478: else
1479: bprint(ip,"???");
1480: break;
1481: case 'p':
1482: immediate(ip, ip->imm+ip->addr+ip->n);
1483: break;
1484: case 'r':
1485: if (ip->osize == 'B')
1486: bprint(ip,"%s",breg[ip->reg]);
1487: else
1488: bprint(ip, reg[ip->reg]);
1489: break;
1490: case 'x':
1491: if (ip->osize == 'L')
1492: bprint(ip,"CDQ");
1493: else
1494: bprint(ip, "CWD");
1495: break;
1496: default:
1497: bprint(ip, "%%%c", *fmt);
1498: break;
1499: }
1500: }
1501: *ip->curr = 0; /* there's always room for 1 byte */
1502: }
1503:
1504: static int
1505: i386inst(Map *map, ulong pc, char modifier, char *buf, int n)
1506: {
1507: Instr instr;
1508: Optable *op;
1509:
1510: USED(modifier);
1511: op = mkinstr(map, &instr, pc);
1512: if (op == 0) {
1513: if (n >= ERRLEN)
1514: errstr(buf);
1515: else
1516: snprint(buf,n,"%r");
1517: return -1;
1518: }
1519: instr.curr = buf;
1520: instr.end = buf+n-1;
1521: prinstr(&instr, op->proto);
1522: return instr.n;
1523: }
1524:
1525: static int
1526: i386das(Map *map, ulong pc, char *buf, int n)
1527: {
1528: Instr instr;
1529: int i;
1530:
1531: if (mkinstr(map, &instr, pc) == 0) {
1532: if (n >= ERRLEN)
1533: errstr(buf);
1534: else
1535: snprint(buf,n,"%r");
1536: return -1;
1537: }
1538: for(i = 0; i < instr.n && n > 2; i++) {
1539: _hexify(buf, instr.mem[i], 1);
1540: buf += 2;
1541: n -= 2;
1542: }
1543: *buf = 0;
1544: return instr.n;
1545: }
1546:
1547: static int
1548: i386instlen(Map *map, ulong pc)
1549: {
1550: Instr i;
1551:
1552: if (mkinstr(map, &i, pc))
1553: return i.n;
1554: return -1;
1555: }
1556:
1557: static int
1558: i386foll(Map *map, ulong pc, Rgetter rget, ulong *foll)
1559: {
1560: Instr i;
1561: Optable *op;
1562: ushort s;
1563: ulong l, addr;
1564: int n;
1565:
1566: op = mkinstr(map, &i, pc);
1567: if (!op)
1568: return -1;
1569:
1570: n = 0;
1571: switch(i.jumptype)
1572: {
1573: case RET: /* RETURN or LEAVE */
1574: case Iw: /* RETURN */
1575: if (strcmp(op->proto, "LEAVE") == 0) {
1576: if (get4(map, (*rget)(map, "BP"), (long*)&l) < 0)
1577: return -1;
1578: } else if (get4(map, (*rget)(map, mach->sp), (long*)&l) < 0)
1579: return -1;
1580: foll[0] = l;
1581: return 1;
1582: case Iwds: /* pc relative JUMP or CALL*/
1583: case Jbs: /* pc relative JUMP or CALL */
1584: foll[0] = pc+i.imm+i.n;
1585: n = 1;
1586: break;
1587: case PTR: /* seg:displacement JUMP or CALL */
1588: foll[0] = (i.seg<<4)+i.disp;
1589: return 1;
1590: case JUMP: /* JUMP or CALL EA */
1591: /* calculate the effective address */
1592: addr = i.disp;
1593: if (i.base >= 0) {
1594: if (get4(map, (*rget)(map, reg[i.base]), (long*)&l) < 0)
1595: return -1;
1596: addr += l;
1597: }
1598: if (i.index >= 0) {
1599: if (get4(map, (*rget)(map, reg[i.index]), (long*)&l) < 0)
1600: return -1;
1601: addr += l*(1<<i.ss);
1602: }
1603: /* now retrieve a seg:disp value at that address */
1604: if (get2(map, addr, &s) < 0) /* seg */
1605: return -1;
1606: foll[0] = s<<4;
1607: addr += 2;
1608: if (i.asize == 'L') {
1609: if (get4(map, addr, (long*)&l) < 0) /* disp32 */
1610: return -1;
1611: foll[0] += l;
1612: } else { /* disp16 */
1613: if (get2(map, addr, &s) < 0)
1614: return -1;
1615: foll[0] += s;
1616: }
1617: return 1;
1618: default:
1619: break;
1620: }
1621: if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)
1622: return 1;
1623: foll[n++] = pc+i.n;
1624: return n;
1625: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.