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