xref: /inferno-os/libinterp/das-386.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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