xref: /inferno-os/utils/libmach/8db.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include <lib9.h>
2 #include <bio.h>
3 #include "mach.h"
4 
5 /*
6  * i386-specific debugger interface
7  * also amd64 extensions
8  */
9 
10 static	char	*i386excep(Map*, Rgetter);
11 
12 static	int	i386trace(Map*, uvlong, uvlong, uvlong, Tracer);
13 static	uvlong	i386frame(Map*, uvlong, uvlong, uvlong, uvlong);
14 static	int	i386foll(Map*, uvlong, Rgetter, uvlong*);
15 static	int	i386inst(Map*, uvlong, char, char*, int);
16 static	int	i386das(Map*, uvlong, char*, int);
17 static	int	i386instlen(Map*, uvlong);
18 
19 static	char	STARTSYM[] =	"_main";
20 static	char	PROFSYM[] =	"_mainp";
21 static	char	FRAMENAME[] =	".frame";
22 static char *excname[65] =
23 {
24 /*[0]*/	"divide error",
25 /*[1]*/	"debug exception",
26 /*[2]*/	nil,
27 /*[3]*/	nil,
28 /*[4]*/	"overflow",
29 /*[5]*/	"bounds check",
30 /*[6]*/	"invalid opcode",
31 /*[7]*/	"math coprocessor emulation",
32 /*[8]*/	"double fault",
33 /*[9]*/	"math coprocessor overrun",
34 /*[10]*/	"invalid TSS",
35 /*[11]*/	"segment not present",
36 /*[12]*/	"stack exception",
37 /*[13]*/	"general protection violation",
38 /*[14]*/	"page fault",
39 /*[15]*/	nil,
40 /*[16]*/	"math coprocessor error",
41 /*[17]*/	"alignment check",
42 /*[18]*/	"machine check",
43 /*[19]*/	"floating-point exception",
44 /*[20]*/	nil,
45 /*[21]*/	nil,
46 /*[22]*/	nil,
47 /*[23]*/	nil,
48 /*[24]*/	"clock",
49 /*[25]*/	"keyboard",
50 /*[26]*/	nil,
51 /*[27]*/	"modem status",
52 /*[28]*/	"serial line status",
53 /*[29]*/	nil,
54 /*[30]*/	"floppy disk",
55 /*[31]*/	nil,
56 /*[32]*/	nil,
57 /*[33]*/	nil,
58 /*[34]*/	nil,
59 /*[35]*/	nil,
60 /*[36]*/	"mouse",
61 /*[37]*/	"math coprocessor",
62 /*[38]*/	"hard disk",
63 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/* 39-54 */
64 	0,0,0,0,0,0,0,0,0,		/* 55-63 */
65 /*[64]*/	"system call",
66 };
67 
68 Machdata i386mach =
69 {
70 	{0xCC, 0, 0, 0},	/* break point: INT 3 */
71 	1,			/* break point size */
72 
73 	leswab,			/* convert short to local byte order */
74 	leswal,			/* convert long to local byte order */
75 	leswav,			/* convert vlong to local byte order */
76 	i386trace,		/* C traceback */
77 	i386frame,		/* frame finder */
78 	i386excep,		/* print exception */
79 	0,			/* breakpoint fixup */
80 	leieeesftos,		/* single precision float printer */
81 	leieeedftos,		/* double precision float printer */
82 	i386foll,		/* following addresses */
83 	i386inst,		/* print instruction */
84 	i386das,		/* dissembler */
85 	i386instlen,		/* instruction size calculation */
86 };
87 
88 static char*
89 i386excep(Map *map, Rgetter rget)
90 {
91 	ulong c;
92 	uvlong pc;
93 	static char buf[16];
94 
95 	c = (*rget)(map, "TRAP");
96 	if(c > 64 || excname[c] == 0) {
97 		if (c == 3) {
98 			pc = (*rget)(map, "PC");
99 			if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0)
100 			if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0)
101 				return "breakpoint";
102 		}
103 		snprint(buf, sizeof(buf), "exception %ld", c);
104 		return buf;
105 	} else
106 		return excname[c];
107 }
108 
109 static int
110 i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
111 {
112 	int i;
113 	uvlong osp;
114 	Symbol s, f;
115 
116 	USED(link);
117 	i = 0;
118 	osp = 0;
119 	while(findsym(pc, CTEXT, &s)) {
120 		if (osp == sp)
121 			break;
122 		osp = sp;
123 
124 		if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
125 			break;
126 
127 		if(pc != s.value) {	/* not at first instruction */
128 			if(findlocal(&s, FRAMENAME, &f) == 0)
129 				break;
130 			sp += f.value-mach->szaddr;
131 		}
132 
133 		if (geta(map, sp, &pc) < 0)
134 			break;
135 
136 		if(pc == 0)
137 			break;
138 
139 		(*trace)(map, pc, sp, &s);
140 		sp += mach->szaddr;
141 
142 		if(++i > 1000)
143 			break;
144 	}
145 	return i;
146 }
147 
148 static uvlong
149 i386frame(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
150 {
151 	Symbol s, f;
152 
153 	USED(link);
154 	while (findsym(pc, CTEXT, &s)) {
155 		if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
156 			break;
157 
158 		if(pc != s.value) {	/* not first instruction */
159 			if(findlocal(&s, FRAMENAME, &f) == 0)
160 				break;
161 			sp += f.value-mach->szaddr;
162 		}
163 
164 		if (s.value == addr)
165 			return sp;
166 
167 		if (geta(map, sp, &pc) < 0)
168 			break;
169 		sp += mach->szaddr;
170 	}
171 	return 0;
172 }
173 
174 	/* I386/486 - Disassembler and related functions */
175 
176 /*
177  *  an instruction
178  */
179 typedef struct Instr Instr;
180 struct	Instr
181 {
182 	uchar	mem[1+1+1+1+2+1+1+4+4];		/* raw instruction */
183 	uvlong	addr;		/* address of start of instruction */
184 	int	n;		/* number of bytes in instruction */
185 	char	*prefix;	/* instr prefix */
186 	char	*segment;	/* segment override */
187 	uchar	jumptype;	/* set to the operand type for jump/ret/call */
188 	uchar	amd64;
189 	uchar	rex;		/* REX prefix (or zero) */
190 	char	osize;		/* 'W' or 'L' (or 'Q' on amd64) */
191 	char	asize;		/* address size 'W' or 'L' (or 'Q' or amd64) */
192 	uchar	mod;		/* bits 6-7 of mod r/m field */
193 	uchar	reg;		/* bits 3-5 of mod r/m field */
194 	char	ss;		/* bits 6-7 of SIB */
195 	char	index;		/* bits 3-5 of SIB */
196 	char	base;		/* bits 0-2 of SIB */
197 	char	rip;		/* RIP-relative in amd64 mode */
198 	uchar	opre;		/* f2/f3 could introduce media */
199 	short	seg;		/* segment of far address */
200 	ulong	disp;		/* displacement */
201 	ulong 	imm;		/* immediate */
202 	ulong 	imm2;		/* second immediate operand */
203 	uvlong	imm64;		/* big immediate */
204 	char	*curr;		/* fill level in output buffer */
205 	char	*end;		/* end of output buffer */
206 	char	*err;		/* error message */
207 };
208 
209 	/* 386 register (ha!) set */
210 enum{
211 	AX=0,
212 	CX,
213 	DX,
214 	BX,
215 	SP,
216 	BP,
217 	SI,
218 	DI,
219 
220 	/* amd64 */
221 	R8,
222 	R9,
223 	R10,
224 	R11,
225 	R12,
226 	R13,
227 	R14,
228 	R15
229 };
230 
231 	/* amd64 rex extension byte */
232 enum{
233 	REXW		= 1<<3,	/* =1, 64-bit operand size */
234 	REXR		= 1<<2,	/* extend modrm reg */
235 	REXX		= 1<<1,	/* extend sib index */
236 	REXB		= 1<<0	/* extend modrm r/m, sib base, or opcode reg */
237 };
238 
239 	/* Operand Format codes */
240 /*
241 %A	-	address size register modifier (!asize -> 'E')
242 %C	-	Control register CR0/CR1/CR2
243 %D	-	Debug register DR0/DR1/DR2/DR3/DR6/DR7
244 %I	-	second immediate operand
245 %O	-	Operand size register modifier (!osize -> 'E')
246 %T	-	Test register TR6/TR7
247 %S	-	size code ('W' or 'L')
248 %W	-	Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
249 %d	-	displacement 16-32 bits
250 %e	-	effective address - Mod R/M value
251 %f	-	floating point register F0-F7 - from Mod R/M register
252 %g	-	segment register
253 %i	-	immediate operand 8-32 bits
254 %p	-	PC-relative - signed displacement in immediate field
255 %r	-	Reg from Mod R/M
256 %w	-	Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
257 */
258 
259 typedef struct Optable Optable;
260 struct Optable
261 {
262 	int	x;
263 	char	operand[2];
264 	void	*proto;		/* actually either (char*) or (Optable*) */
265 };
266 	/* Operand decoding codes */
267 enum {
268 	Ib = 1,			/* 8-bit immediate - (no sign extension)*/
269 	Ibs,			/* 8-bit immediate (sign extended) */
270 	Jbs,			/* 8-bit sign-extended immediate in jump or call */
271 	Iw,			/* 16-bit immediate -> imm */
272 	Iw2,			/* 16-bit immediate -> imm2 */
273 	Iwd,			/* Operand-sized immediate (no sign extension)*/
274 	Iwdq,			/* Operand-sized immediate, possibly 64 bits */
275 	Awd,			/* Address offset */
276 	Iwds,			/* Operand-sized immediate (sign extended) */
277 	RM,			/* Word or long R/M field with register (/r) */
278 	RMB,			/* Byte R/M field with register (/r) */
279 	RMOP,			/* Word or long R/M field with op code (/digit) */
280 	RMOPB,			/* Byte R/M field with op code (/digit) */
281 	RMR,			/* R/M register only (mod = 11) */
282 	RMM,			/* R/M memory only (mod = 0/1/2) */
283 	R0,			/* Base reg of Mod R/M is literal 0x00 */
284 	R1,			/* Base reg of Mod R/M is literal 0x01 */
285 	FRMOP,			/* Floating point R/M field with opcode */
286 	FRMEX,			/* Extended floating point R/M field with opcode */
287 	JUMP,			/* Jump or Call flag - no operand */
288 	RET,			/* Return flag - no operand */
289 	OA,			/* literal 0x0a byte */
290 	PTR,			/* Seg:Displacement addr (ptr16:16 or ptr16:32) */
291 	AUX,			/* Multi-byte op code - Auxiliary table */
292 	AUXMM,			/* multi-byte op code - auxiliary table chosen by prefix */
293 	PRE,			/* Instr Prefix */
294 	OPRE,			/* Instr Prefix or media op extension */
295 	SEG,			/* Segment Prefix */
296 	OPOVER,			/* Operand size override */
297 	ADDOVER,		/* Address size override */
298 };
299 
300 static Optable optab0F00[8]=
301 {
302 0x00,	0,0,		"MOVW	LDT,%e",
303 0x01,	0,0,		"MOVW	TR,%e",
304 0x02,	0,0,		"MOVW	%e,LDT",
305 0x03,	0,0,		"MOVW	%e,TR",
306 0x04,	0,0,		"VERR	%e",
307 0x05,	0,0,		"VERW	%e",
308 };
309 
310 static Optable optab0F01[8]=
311 {
312 0x00,	0,0,		"MOVL	GDTR,%e",
313 0x01,	0,0,		"MOVL	IDTR,%e",
314 0x02,	0,0,		"MOVL	%e,GDTR",
315 0x03,	0,0,		"MOVL	%e,IDTR",
316 0x04,	0,0,		"MOVW	MSW,%e",	/* word */
317 0x06,	0,0,		"MOVW	%e,MSW",	/* word */
318 0x07,	0,0,		"INVLPG	%e",		/* or SWAPGS */
319 };
320 
321 static Optable optab0F01F8[1]=
322 {
323 0x00,	0,0,		"SWAPGS",
324 };
325 
326 /* 0F71 */
327 /* 0F72 */
328 /* 0F73 */
329 
330 static Optable optab0FAE[8]=
331 {
332 0x00,	0,0,		"FXSAVE	%e",
333 0x01,	0,0,		"FXRSTOR	%e",
334 0x02,	0,0,		"LDMXCSR	%e",
335 0x03,	0,0,		"STMXCSR	%e",
336 0x05,	0,0,		"LFENCE",
337 0x06,	0,0,		"MFENCE",
338 0x07,	0,0,		"SFENCE",
339 };
340 
341 /* 0F18 */
342 /* 0F0D */
343 
344 static Optable optab0FBA[8]=
345 {
346 0x04,	Ib,0,		"BT%S	%i,%e",
347 0x05,	Ib,0,		"BTS%S	%i,%e",
348 0x06,	Ib,0,		"BTR%S	%i,%e",
349 0x07,	Ib,0,		"BTC%S	%i,%e",
350 };
351 
352 static Optable optab0F0F[256]=
353 {
354 0x0c,	0,0,		"PI2FW	%m,%M",
355 0x0d,	0,0,		"PI2L	%m,%M",
356 0x1c,	0,0,		"PF2IW	%m,%M",
357 0x1d,	0,0,		"PF2IL	%m,%M",
358 0x8a,	0,0,		"PFNACC	%m,%M",
359 0x8e,	0,0,		"PFPNACC	%m,%M",
360 0x90,	0,0,		"PFCMPGE	%m,%M",
361 0x94,	0,0,		"PFMIN	%m,%M",
362 0x96,	0,0,		"PFRCP	%m,%M",
363 0x97,	0,0,		"PFRSQRT	%m,%M",
364 0x9a,	0,0,		"PFSUB	%m,%M",
365 0x9e,	0,0,		"PFADD	%m,%M",
366 0xa0,	0,0,		"PFCMPGT	%m,%M",
367 0xa4,	0,0,		"PFMAX	%m,%M",
368 0xa6,	0,0,		"PFRCPIT1	%m,%M",
369 0xa7,	0,0,		"PFRSQIT1	%m,%M",
370 0xaa,	0,0,		"PFSUBR	%m,%M",
371 0xae,	0,0,		"PFACC	%m,%M",
372 0xb0,	0,0,		"PFCMPEQ	%m,%M",
373 0xb4,	0,0,		"PFMUL	%m,%M",
374 0xb6,	0,0,		"PFRCPI2T	%m,%M",
375 0xb7,	0,0,		"PMULHRW	%m,%M",
376 0xbb,	0,0,		"PSWAPL	%m,%M",
377 };
378 
379 static Optable optab0FC7[8]=
380 {
381 0x01,	0,0,		"CMPXCHG8B	%e",
382 };
383 
384 static Optable optab660F71[8]=
385 {
386 0x02,	Ib,0,		"PSRLW	%i,%X",
387 0x04,	Ib,0,		"PSRAW	%i,%X",
388 0x06,	Ib,0,		"PSLLW	%i,%X",
389 };
390 
391 static Optable optab660F72[8]=
392 {
393 0x02,	Ib,0,		"PSRLL	%i,%X",
394 0x04,	Ib,0,		"PSRAL	%i,%X",
395 0x06,	Ib,0,		"PSLLL	%i,%X",
396 };
397 
398 static Optable optab660F73[8]=
399 {
400 0x02,	Ib,0,		"PSRLQ	%i,%X",
401 0x03,	Ib,0,		"PSRLO	%i,%X",
402 0x06,	Ib,0,		"PSLLQ	%i,%X",
403 0x07,	Ib,0,		"PSLLO	%i,%X",
404 };
405 
406 static Optable optab660F[256]=
407 {
408 0x2B,	RM,0,		"MOVNTPD	%x,%e",
409 0x2E,	RM,0,		"UCOMISD	%x,%X",
410 0x2F,	RM,0,		"COMISD	%x,%X",
411 0x5A,	RM,0,		"CVTPD2PS	%x,%X",
412 0x5B,	RM,0,		"CVTPS2PL	%x,%X",
413 0x6A,	RM,0,		"PUNPCKHLQ %x,%X",
414 0x6B,	RM,0,		"PACKSSLW %x,%X",
415 0x6C,	RM,0,		"PUNPCKLQDQ %x,%X",
416 0x6D,	RM,0,		"PUNPCKHQDQ %x,%X",
417 0x6E,	RM,0,		"MOV%S	%e,%X",
418 0x6F,	RM,0,		"MOVO	%x,%X",		/* MOVDQA */
419 0x70,	RM,Ib,		"PSHUFL	%i,%x,%X",
420 0x71,	RMOP,0,		optab660F71,
421 0x72,	RMOP,0,		optab660F72,
422 0x73,	RMOP,0,		optab660F73,
423 0x7E,	RM,0,		"MOV%S	%X,%e",
424 0x7F,	RM,0,		"MOVO	%X,%x",
425 0xC4,	RM,Ib,		"PINSRW	%i,%e,%X",
426 0xC5,	RMR,Ib,		"PEXTRW	%i,%X,%e",
427 0xD4,	RM,0,		"PADDQ	%x,%X",
428 0xD5,	RM,0,		"PMULLW	%x,%X",
429 0xD6,	RM,0,		"MOVQ	%X,%x",
430 0xE6,	RM,0,		"CVTTPD2PL	%x,%X",
431 0xE7,	RM,0,		"MOVNTO	%X,%e",
432 0xF7,	RM,0,		"MASKMOVOU	%x,%X",
433 };
434 
435 static Optable optabF20F[256]=
436 {
437 0x10,	RM,0,		"MOVSD	%x,%X",
438 0x11,	RM,0,		"MOVSD	%X,%x",
439 0x2A,	RM,0,		"CVTS%S2SD	%e,%X",
440 0x2C,	RM,0,		"CVTTSD2S%S	%x,%r",
441 0x2D,	RM,0,		"CVTSD2S%S	%x,%r",
442 0x5A,	RM,0,		"CVTSD2SS	%x,%X",
443 0x6F,	RM,0,		"MOVOU	%x,%X",
444 0x70,	RM,Ib,		"PSHUFLW	%i,%x,%X",
445 0x7F,	RM,0,		"MOVOU	%X,%x",
446 0xD6,	RM,0,		"MOVQOZX	%M,%X",
447 0xE6,	RM,0,		"CVTPD2PL	%x,%X",
448 };
449 
450 static Optable optabF30F[256]=
451 {
452 0x10,	RM,0,		"MOVSS	%x,%X",
453 0x11,	RM,0,		"MOVSS	%X,%x",
454 0x2A,	RM,0,		"CVTS%S2SS	%e,%X",
455 0x2C,	RM,0,		"CVTTSS2S%S	%x,%r",
456 0x2D,	RM,0,		"CVTSS2S%S	%x,%r",
457 0x5A,	RM,0,		"CVTSS2SD	%x,%X",
458 0x5B,	RM,0,		"CVTTPS2PL	%x,%X",
459 0x6F,	RM,0,		"MOVOU	%x,%X",
460 0x70,	RM,Ib,		"PSHUFHW	%i,%x,%X",
461 0x7E,	RM,0,		"MOVQOZX	%x,%X",
462 0x7F,	RM,0,		"MOVOU	%X,%x",
463 0xD6,	RM,0,		"MOVQOZX	%m*,%X",
464 0xE6,	RM,0,		"CVTPL2PD	%x,%X",
465 };
466 
467 static Optable optab0F[256]=
468 {
469 0x00,	RMOP,0,		optab0F00,
470 0x01,	RMOP,0,		optab0F01,
471 0x02,	RM,0,		"LAR	%e,%r",
472 0x03,	RM,0,		"LSL	%e,%r",
473 0x05,	0,0,		"SYSCALL",
474 0x06,	0,0,		"CLTS",
475 0x07,	0,0,		"SYSRET",
476 0x08,	0,0,		"INVD",
477 0x09,	0,0,		"WBINVD",
478 0x0B,	0,0,		"UD2",
479 0x0F,	RM,AUX,		optab0F0F,		/* 3DNow! */
480 0x10,	RM,0,		"MOVU%s	%x,%X",
481 0x11,	RM,0,		"MOVU%s	%X,%x",
482 0x12,	RM,0,		"MOV[H]L%s	%x,%X",	/* TO DO: H if source is XMM */
483 0x13,	RM,0,		"MOVL%s	%X,%e",
484 0x14,	RM,0,		"UNPCKL%s	%x,%X",
485 0x15,	RM,0,		"UNPCKH%s	%x,%X",
486 0x16,	RM,0,		"MOV[L]H%s	%x,%X",	/* TO DO: L if source is XMM */
487 0x17,	RM,0,		"MOVH%s	%X,%x",
488 0x20,	RMR,0,		"MOVL	%C,%e",
489 0x21,	RMR,0,		"MOVL	%D,%e",
490 0x22,	RMR,0,		"MOVL	%e,%C",
491 0x23,	RMR,0,		"MOVL	%e,%D",
492 0x24,	RMR,0,		"MOVL	%T,%e",
493 0x26,	RMR,0,		"MOVL	%e,%T",
494 0x28,	RM,0,		"MOVA%s	%x,%X",
495 0x29,	RM,0,		"MOVA%s	%X,%x",
496 0x2A,	RM,0,		"CVTPL2%s	%m*,%X",
497 0x2B,	RM,0,		"MOVNT%s	%X,%e",
498 0x2C,	RM,0,		"CVTT%s2PL	%x,%M",
499 0x2D,	RM,0,		"CVT%s2PL	%x,%M",
500 0x2E,	RM,0,		"UCOMISS	%x,%X",
501 0x2F,	RM,0,		"COMISS	%x,%X",
502 0x30,	0,0,		"WRMSR",
503 0x31,	0,0,		"RDTSC",
504 0x32,	0,0,		"RDMSR",
505 0x33,	0,0,		"RDPMC",
506 0x42,	RM,0,		"CMOVC	%e,%r",		/* CF */
507 0x43,	RM,0,		"CMOVNC	%e,%r",		/* ¬ CF */
508 0x44,	RM,0,		"CMOVZ	%e,%r",		/* ZF */
509 0x45,	RM,0,		"CMOVNZ	%e,%r",		/* ¬ ZF */
510 0x46,	RM,0,		"CMOVBE	%e,%r",		/* CF ∨ ZF */
511 0x47,	RM,0,		"CMOVA	%e,%r",		/* ¬CF ∧ ¬ZF */
512 0x48,	RM,0,		"CMOVS	%e,%r",		/* SF */
513 0x49,	RM,0,		"CMOVNS	%e,%r",		/* ¬ SF */
514 0x4A,	RM,0,		"CMOVP	%e,%r",		/* PF */
515 0x4B,	RM,0,		"CMOVNP	%e,%r",		/* ¬ PF */
516 0x4C,	RM,0,		"CMOVLT	%e,%r",		/* LT ≡ OF ≠ SF */
517 0x4D,	RM,0,		"CMOVGE	%e,%r",		/* GE ≡ ZF ∨ SF */
518 0x4E,	RM,0,		"CMOVLE	%e,%r",		/* LE ≡ ZF ∨ LT */
519 0x4F,	RM,0,		"CMOVGT	%e,%r",		/* GT ≡ ¬ZF ∧ GE */
520 0x50,	RM,0,		"MOVMSK%s	%X,%r",	/* TO DO: check */
521 0x51,	RM,0,		"SQRT%s	%x,%X",
522 0x52,	RM,0,		"RSQRT%s	%x,%X",
523 0x53,	RM,0,		"RCP%s	%x,%X",
524 0x54,	RM,0,		"AND%s	%x,%X",
525 0x55,	RM,0,		"ANDN%s	%x,%X",
526 0x56,	RM,0,		"OR%s	%x,%X",		/* TO DO: S/D */
527 0x57,	RM,0,		"XOR%s	%x,%X",		/* S/D */
528 0x58,	RM,0,		"ADD%s	%x,%X",		/* S/P S/D */
529 0x59,	RM,0,		"MUL%s	%x,%X",
530 0x5A,	RM,0,		"CVTPS2PD	%x,%X",
531 0x5B,	RM,0,		"CVTPL2PS	%x,%X",
532 0x5C,	RM,0,		"SUB%s	%x,%X",
533 0x5D,	RM,0,		"MIN%s	%x,%X",
534 0x5E,	RM,0,		"DIV%s	%x,%X",		/* TO DO: S/P S/D */
535 0x5F,	RM,0,		"MAX%s	%x,%X",
536 0x60,	RM,0,		"PUNPCKLBW %m,%M",
537 0x61,	RM,0,		"PUNPCKLWL %m,%M",
538 0x62,	RM,0,		"PUNPCKLLQ %m,%M",
539 0x63,	RM,0,		"PACKSSWB %m,%M",
540 0x64,	RM,0,		"PCMPGTB %m,%M",
541 0x65,	RM,0,		"PCMPGTW %m,%M",
542 0x66,	RM,0,		"PCMPGTL %m,%M",
543 0x67,	RM,0,		"PACKUSWB %m,%M",
544 0x68,	RM,0,		"PUNPCKHBW %m,%M",
545 0x69,	RM,0,		"PUNPCKHWL %m,%M",
546 0x6A,	RM,0,		"PUNPCKHLQ %m,%M",
547 0x6B,	RM,0,		"PACKSSLW %m,%M",
548 0x6E,	RM,0,		"MOV%S %e,%M",
549 0x6F,	RM,0,		"MOVQ %m,%M",
550 0x70,	RM,Ib,		"PSHUFW	%i,%m,%M",
551 0x74,	RM,0,		"PCMPEQB %m,%M",
552 0x75,	RM,0,		"PCMPEQW %m,%M",
553 0x76,	RM,0,		"PCMPEQL %m,%M",
554 0x7E,	RM,0,		"MOV%S %M,%e",
555 0x7F,	RM,0,		"MOVQ %M,%m",
556 0xAE,	RMOP,0,		optab0FAE,
557 0xAA,	0,0,		"RSM",
558 0xB0,	RM,0,		"CMPXCHGB	%r,%e",
559 0xB1,	RM,0,		"CMPXCHG%S	%r,%e",
560 0xC0,	RMB,0,		"XADDB	%r,%e",
561 0xC1,	RM,0,		"XADD%S	%r,%e",
562 0xC2,	RM,Ib,		"CMP%s	%i,%x,%X",
563 0xC3,	RM,0,		"MOVNTI%S	%r,%e",
564 0xC6,	RM,Ib,		"SHUF%s	%i,%x,%X",
565 0xC8,	0,0,		"BSWAP	AX",
566 0xC9,	0,0,		"BSWAP	CX",
567 0xCA,	0,0,		"BSWAP	DX",
568 0xCB,	0,0,		"BSWAP	BX",
569 0xCC,	0,0,		"BSWAP	SP",
570 0xCD,	0,0,		"BSWAP	BP",
571 0xCE,	0,0,		"BSWAP	SI",
572 0xCF,	0,0,		"BSWAP	DI",
573 0xD1,	RM,0,		"PSRLW %m,%M",
574 0xD2,	RM,0,		"PSRLL %m,%M",
575 0xD3,	RM,0,		"PSRLQ %m,%M",
576 0xD5,	RM,0,		"PMULLW %m,%M",
577 0xD6,	RM,0,		"MOVQOZX	%m*,%X",
578 0xD7,	RM,0,		"PMOVMSKB %m,%r",
579 0xD8,	RM,0,		"PSUBUSB %m,%M",
580 0xD9,	RM,0,		"PSUBUSW %m,%M",
581 0xDA,	RM,0,		"PMINUB %m,%M",
582 0xDB,	RM,0,		"PAND %m,%M",
583 0xDC,	RM,0,		"PADDUSB %m,%M",
584 0xDD,	RM,0,		"PADDUSW %m,%M",
585 0xDE,	RM,0,		"PMAXUB %m,%M",
586 0xDF,	RM,0,		"PANDN %m,%M",
587 0xE0,	RM,0,		"PAVGB %m,%M",
588 0xE1,	RM,0,		"PSRAW %m,%M",
589 0xE2,	RM,0,		"PSRAL %m,%M",
590 0xE3,	RM,0,		"PAVGW %m,%M",
591 0xE4,	RM,0,		"PMULHUW %m,%M",
592 0xE5,	RM,0,		"PMULHW %m,%M",
593 0xE7,	RM,0,		"MOVNTQ	%M,%e",
594 0xE8,	RM,0,		"PSUBSB %m,%M",
595 0xE9,	RM,0,		"PSUBSW %m,%M",
596 0xEA,	RM,0,		"PMINSW %m,%M",
597 0xEB,	RM,0,		"POR %m,%M",
598 0xEC,	RM,0,		"PADDSB %m,%M",
599 0xED,	RM,0,		"PADDSW %m,%M",
600 0xEE,	RM,0,		"PMAXSW %m,%M",
601 0xEF,	RM,0,		"PXOR %m,%M",
602 0xF1,	RM,0,		"PSLLW %m,%M",
603 0xF2,	RM,0,		"PSLLL %m,%M",
604 0xF3,	RM,0,		"PSLLQ %m,%M",
605 0xF4,	RM,0,		"PMULULQ	%m,%M",
606 0xF5,	RM,0,		"PMADDWL %m,%M",
607 0xF6,	RM,0,		"PSADBW %m,%M",
608 0xF7,	RMR,0,		"MASKMOVQ	%m,%M",
609 0xF8,	RM,0,		"PSUBB %m,%M",
610 0xF9,	RM,0,		"PSUBW %m,%M",
611 0xFA,	RM,0,		"PSUBL %m,%M",
612 0xFC,	RM,0,		"PADDB %m,%M",
613 0xFD,	RM,0,		"PADDW %m,%M",
614 0xFE,	RM,0,		"PADDL %m,%M",
615 
616 0x80,	Iwds,0,		"JOS	%p",
617 0x81,	Iwds,0,		"JOC	%p",
618 0x82,	Iwds,0,		"JCS	%p",
619 0x83,	Iwds,0,		"JCC	%p",
620 0x84,	Iwds,0,		"JEQ	%p",
621 0x85,	Iwds,0,		"JNE	%p",
622 0x86,	Iwds,0,		"JLS	%p",
623 0x87,	Iwds,0,		"JHI	%p",
624 0x88,	Iwds,0,		"JMI	%p",
625 0x89,	Iwds,0,		"JPL	%p",
626 0x8a,	Iwds,0,		"JPS	%p",
627 0x8b,	Iwds,0,		"JPC	%p",
628 0x8c,	Iwds,0,		"JLT	%p",
629 0x8d,	Iwds,0,		"JGE	%p",
630 0x8e,	Iwds,0,		"JLE	%p",
631 0x8f,	Iwds,0,		"JGT	%p",
632 0x90,	RMB,0,		"SETOS	%e",
633 0x91,	RMB,0,		"SETOC	%e",
634 0x92,	RMB,0,		"SETCS	%e",
635 0x93,	RMB,0,		"SETCC	%e",
636 0x94,	RMB,0,		"SETEQ	%e",
637 0x95,	RMB,0,		"SETNE	%e",
638 0x96,	RMB,0,		"SETLS	%e",
639 0x97,	RMB,0,		"SETHI	%e",
640 0x98,	RMB,0,		"SETMI	%e",
641 0x99,	RMB,0,		"SETPL	%e",
642 0x9a,	RMB,0,		"SETPS	%e",
643 0x9b,	RMB,0,		"SETPC	%e",
644 0x9c,	RMB,0,		"SETLT	%e",
645 0x9d,	RMB,0,		"SETGE	%e",
646 0x9e,	RMB,0,		"SETLE	%e",
647 0x9f,	RMB,0,		"SETGT	%e",
648 0xa0,	0,0,		"PUSHL	FS",
649 0xa1,	0,0,		"POPL	FS",
650 0xa2,	0,0,		"CPUID",
651 0xa3,	RM,0,		"BT%S	%r,%e",
652 0xa4,	RM,Ib,		"SHLD%S	%r,%i,%e",
653 0xa5,	RM,0,		"SHLD%S	%r,CL,%e",
654 0xa8,	0,0,		"PUSHL	GS",
655 0xa9,	0,0,		"POPL	GS",
656 0xab,	RM,0,		"BTS%S	%r,%e",
657 0xac,	RM,Ib,		"SHRD%S	%r,%i,%e",
658 0xad,	RM,0,		"SHRD%S	%r,CL,%e",
659 0xaf,		RM,0,		"IMUL%S	%e,%r",
660 0xb2,	RMM,0,		"LSS	%e,%r",
661 0xb3,	RM,0,		"BTR%S	%r,%e",
662 0xb4,	RMM,0,		"LFS	%e,%r",
663 0xb5,	RMM,0,		"LGS	%e,%r",
664 0xb6,	RMB,0,		"MOVBZX	%e,%R",
665 0xb7,	RM,0,		"MOVWZX	%e,%R",
666 0xba,	RMOP,0,		optab0FBA,
667 0xbb,	RM,0,		"BTC%S	%e,%r",
668 0xbc,	RM,0,		"BSF%S	%e,%r",
669 0xbd,	RM,0,		"BSR%S	%e,%r",
670 0xbe,	RMB,0,		"MOVBSX	%e,%R",
671 0xbf,	RM,0,		"MOVWSX	%e,%R",
672 0xc7,	RMOP,0,		optab0FC7,
673 };
674 
675 static Optable optab80[8]=
676 {
677 0x00,	Ib,0,		"ADDB	%i,%e",
678 0x01,	Ib,0,		"ORB	%i,%e",
679 0x02,	Ib,0,		"ADCB	%i,%e",
680 0x03,	Ib,0,		"SBBB	%i,%e",
681 0x04,	Ib,0,		"ANDB	%i,%e",
682 0x05,	Ib,0,		"SUBB	%i,%e",
683 0x06,	Ib,0,		"XORB	%i,%e",
684 0x07,	Ib,0,		"CMPB	%e,%i",
685 };
686 
687 static Optable optab81[8]=
688 {
689 0x00,	Iwd,0,		"ADD%S	%i,%e",
690 0x01,	Iwd,0,		"OR%S	%i,%e",
691 0x02,	Iwd,0,		"ADC%S	%i,%e",
692 0x03,	Iwd,0,		"SBB%S	%i,%e",
693 0x04,	Iwd,0,		"AND%S	%i,%e",
694 0x05,	Iwd,0,		"SUB%S	%i,%e",
695 0x06,	Iwd,0,		"XOR%S	%i,%e",
696 0x07,	Iwd,0,		"CMP%S	%e,%i",
697 };
698 
699 static Optable optab83[8]=
700 {
701 0x00,	Ibs,0,		"ADD%S	%i,%e",
702 0x01,	Ibs,0,		"OR%S	%i,%e",
703 0x02,	Ibs,0,		"ADC%S	%i,%e",
704 0x03,	Ibs,0,		"SBB%S	%i,%e",
705 0x04,	Ibs,0,		"AND%S	%i,%e",
706 0x05,	Ibs,0,		"SUB%S	%i,%e",
707 0x06,	Ibs,0,		"XOR%S	%i,%e",
708 0x07,	Ibs,0,		"CMP%S	%e,%i",
709 };
710 
711 static Optable optabC0[8] =
712 {
713 0x00,	Ib,0,		"ROLB	%i,%e",
714 0x01,	Ib,0,		"RORB	%i,%e",
715 0x02,	Ib,0,		"RCLB	%i,%e",
716 0x03,	Ib,0,		"RCRB	%i,%e",
717 0x04,	Ib,0,		"SHLB	%i,%e",
718 0x05,	Ib,0,		"SHRB	%i,%e",
719 0x07,	Ib,0,		"SARB	%i,%e",
720 };
721 
722 static Optable optabC1[8] =
723 {
724 0x00,	Ib,0,		"ROL%S	%i,%e",
725 0x01,	Ib,0,		"ROR%S	%i,%e",
726 0x02,	Ib,0,		"RCL%S	%i,%e",
727 0x03,	Ib,0,		"RCR%S	%i,%e",
728 0x04,	Ib,0,		"SHL%S	%i,%e",
729 0x05,	Ib,0,		"SHR%S	%i,%e",
730 0x07,	Ib,0,		"SAR%S	%i,%e",
731 };
732 
733 static Optable optabD0[8] =
734 {
735 0x00,	0,0,		"ROLB	%e",
736 0x01,	0,0,		"RORB	%e",
737 0x02,	0,0,		"RCLB	%e",
738 0x03,	0,0,		"RCRB	%e",
739 0x04,	0,0,		"SHLB	%e",
740 0x05,	0,0,		"SHRB	%e",
741 0x07,	0,0,		"SARB	%e",
742 };
743 
744 static Optable optabD1[8] =
745 {
746 0x00,	0,0,		"ROL%S	%e",
747 0x01,	0,0,		"ROR%S	%e",
748 0x02,	0,0,		"RCL%S	%e",
749 0x03,	0,0,		"RCR%S	%e",
750 0x04,	0,0,		"SHL%S	%e",
751 0x05,	0,0,		"SHR%S	%e",
752 0x07,	0,0,		"SAR%S	%e",
753 };
754 
755 static Optable optabD2[8] =
756 {
757 0x00,	0,0,		"ROLB	CL,%e",
758 0x01,	0,0,		"RORB	CL,%e",
759 0x02,	0,0,		"RCLB	CL,%e",
760 0x03,	0,0,		"RCRB	CL,%e",
761 0x04,	0,0,		"SHLB	CL,%e",
762 0x05,	0,0,		"SHRB	CL,%e",
763 0x07,	0,0,		"SARB	CL,%e",
764 };
765 
766 static Optable optabD3[8] =
767 {
768 0x00,	0,0,		"ROL%S	CL,%e",
769 0x01,	0,0,		"ROR%S	CL,%e",
770 0x02,	0,0,		"RCL%S	CL,%e",
771 0x03,	0,0,		"RCR%S	CL,%e",
772 0x04,	0,0,		"SHL%S	CL,%e",
773 0x05,	0,0,		"SHR%S	CL,%e",
774 0x07,	0,0,		"SAR%S	CL,%e",
775 };
776 
777 static Optable optabD8[8+8] =
778 {
779 0x00,	0,0,		"FADDF	%e,F0",
780 0x01,	0,0,		"FMULF	%e,F0",
781 0x02,	0,0,		"FCOMF	%e,F0",
782 0x03,	0,0,		"FCOMFP	%e,F0",
783 0x04,	0,0,		"FSUBF	%e,F0",
784 0x05,	0,0,		"FSUBRF	%e,F0",
785 0x06,	0,0,		"FDIVF	%e,F0",
786 0x07,	0,0,		"FDIVRF	%e,F0",
787 0x08,	0,0,		"FADDD	%f,F0",
788 0x09,	0,0,		"FMULD	%f,F0",
789 0x0a,	0,0,		"FCOMD	%f,F0",
790 0x0b,	0,0,		"FCOMPD	%f,F0",
791 0x0c,	0,0,		"FSUBD	%f,F0",
792 0x0d,	0,0,		"FSUBRD	%f,F0",
793 0x0e,	0,0,		"FDIVD	%f,F0",
794 0x0f,	0,0,		"FDIVRD	%f,F0",
795 };
796 /*
797  *	optabD9 and optabDB use the following encoding:
798  *	if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
799  *	else instruction = optabDx[(modrm&0x3f)+8];
800  *
801  *	the instructions for MOD == 3, follow the 8 instructions
802  *	for the other MOD values stored at the front of the table.
803  */
804 static Optable optabD9[64+8] =
805 {
806 0x00,	0,0,		"FMOVF	%e,F0",
807 0x02,	0,0,		"FMOVF	F0,%e",
808 0x03,	0,0,		"FMOVFP	F0,%e",
809 0x04,	0,0,		"FLDENV%S %e",
810 0x05,	0,0,		"FLDCW	%e",
811 0x06,	0,0,		"FSTENV%S %e",
812 0x07,	0,0,		"FSTCW	%e",
813 0x08,	0,0,		"FMOVD	F0,F0",		/* Mod R/M = 11xx xxxx*/
814 0x09,	0,0,		"FMOVD	F1,F0",
815 0x0a,	0,0,		"FMOVD	F2,F0",
816 0x0b,	0,0,		"FMOVD	F3,F0",
817 0x0c,	0,0,		"FMOVD	F4,F0",
818 0x0d,	0,0,		"FMOVD	F5,F0",
819 0x0e,	0,0,		"FMOVD	F6,F0",
820 0x0f,	0,0,		"FMOVD	F7,F0",
821 0x10,	0,0,		"FXCHD	F0,F0",
822 0x11,	0,0,		"FXCHD	F1,F0",
823 0x12,	0,0,		"FXCHD	F2,F0",
824 0x13,	0,0,		"FXCHD	F3,F0",
825 0x14,	0,0,		"FXCHD	F4,F0",
826 0x15,	0,0,		"FXCHD	F5,F0",
827 0x16,	0,0,		"FXCHD	F6,F0",
828 0x17,	0,0,		"FXCHD	F7,F0",
829 0x18,	0,0,		"FNOP",
830 0x28,	0,0,		"FCHS",
831 0x29,	0,0,		"FABS",
832 0x2c,	0,0,		"FTST",
833 0x2d,	0,0,		"FXAM",
834 0x30,	0,0,		"FLD1",
835 0x31,	0,0,		"FLDL2T",
836 0x32,	0,0,		"FLDL2E",
837 0x33,	0,0,		"FLDPI",
838 0x34,	0,0,		"FLDLG2",
839 0x35,	0,0,		"FLDLN2",
840 0x36,	0,0,		"FLDZ",
841 0x38,	0,0,		"F2XM1",
842 0x39,	0,0,		"FYL2X",
843 0x3a,	0,0,		"FPTAN",
844 0x3b,	0,0,		"FPATAN",
845 0x3c,	0,0,		"FXTRACT",
846 0x3d,	0,0,		"FPREM1",
847 0x3e,	0,0,		"FDECSTP",
848 0x3f,	0,0,		"FNCSTP",
849 0x40,	0,0,		"FPREM",
850 0x41,	0,0,		"FYL2XP1",
851 0x42,	0,0,		"FSQRT",
852 0x43,	0,0,		"FSINCOS",
853 0x44,	0,0,		"FRNDINT",
854 0x45,	0,0,		"FSCALE",
855 0x46,	0,0,		"FSIN",
856 0x47,	0,0,		"FCOS",
857 };
858 
859 static Optable optabDA[8+8] =
860 {
861 0x00,	0,0,		"FADDL	%e,F0",
862 0x01,	0,0,		"FMULL	%e,F0",
863 0x02,	0,0,		"FCOML	%e,F0",
864 0x03,	0,0,		"FCOMLP	%e,F0",
865 0x04,	0,0,		"FSUBL	%e,F0",
866 0x05,	0,0,		"FSUBRL	%e,F0",
867 0x06,	0,0,		"FDIVL	%e,F0",
868 0x07,	0,0,		"FDIVRL	%e,F0",
869 0x0d,	R1,0,		"FUCOMPP",
870 };
871 
872 static Optable optabDB[8+64] =
873 {
874 0x00,	0,0,		"FMOVL	%e,F0",
875 0x02,	0,0,		"FMOVL	F0,%e",
876 0x03,	0,0,		"FMOVLP	F0,%e",
877 0x05,	0,0,		"FMOVX	%e,F0",
878 0x07,	0,0,		"FMOVXP	F0,%e",
879 0x2a,	0,0,		"FCLEX",
880 0x2b,	0,0,		"FINIT",
881 };
882 
883 static Optable optabDC[8+8] =
884 {
885 0x00,	0,0,		"FADDD	%e,F0",
886 0x01,	0,0,		"FMULD	%e,F0",
887 0x02,	0,0,		"FCOMD	%e,F0",
888 0x03,	0,0,		"FCOMDP	%e,F0",
889 0x04,	0,0,		"FSUBD	%e,F0",
890 0x05,	0,0,		"FSUBRD	%e,F0",
891 0x06,	0,0,		"FDIVD	%e,F0",
892 0x07,	0,0,		"FDIVRD	%e,F0",
893 0x08,	0,0,		"FADDD	F0,%f",
894 0x09,	0,0,		"FMULD	F0,%f",
895 0x0c,	0,0,		"FSUBRD	F0,%f",
896 0x0d,	0,0,		"FSUBD	F0,%f",
897 0x0e,	0,0,		"FDIVRD	F0,%f",
898 0x0f,	0,0,		"FDIVD	F0,%f",
899 };
900 
901 static Optable optabDD[8+8] =
902 {
903 0x00,	0,0,		"FMOVD	%e,F0",
904 0x02,	0,0,		"FMOVD	F0,%e",
905 0x03,	0,0,		"FMOVDP	F0,%e",
906 0x04,	0,0,		"FRSTOR%S %e",
907 0x06,	0,0,		"FSAVE%S %e",
908 0x07,	0,0,		"FSTSW	%e",
909 0x08,	0,0,		"FFREED	%f",
910 0x0a,	0,0,		"FMOVD	%f,F0",
911 0x0b,	0,0,		"FMOVDP	%f,F0",
912 0x0c,	0,0,		"FUCOMD	%f,F0",
913 0x0d,	0,0,		"FUCOMDP %f,F0",
914 };
915 
916 static Optable optabDE[8+8] =
917 {
918 0x00,	0,0,		"FADDW	%e,F0",
919 0x01,	0,0,		"FMULW	%e,F0",
920 0x02,	0,0,		"FCOMW	%e,F0",
921 0x03,	0,0,		"FCOMWP	%e,F0",
922 0x04,	0,0,		"FSUBW	%e,F0",
923 0x05,	0,0,		"FSUBRW	%e,F0",
924 0x06,	0,0,		"FDIVW	%e,F0",
925 0x07,	0,0,		"FDIVRW	%e,F0",
926 0x08,	0,0,		"FADDDP	F0,%f",
927 0x09,	0,0,		"FMULDP	F0,%f",
928 0x0b,	R1,0,		"FCOMPDP",
929 0x0c,	0,0,		"FSUBRDP F0,%f",
930 0x0d,	0,0,		"FSUBDP	F0,%f",
931 0x0e,	0,0,		"FDIVRDP F0,%f",
932 0x0f,	0,0,		"FDIVDP	F0,%f",
933 };
934 
935 static Optable optabDF[8+8] =
936 {
937 0x00,	0,0,		"FMOVW	%e,F0",
938 0x02,	0,0,		"FMOVW	F0,%e",
939 0x03,	0,0,		"FMOVWP	F0,%e",
940 0x04,	0,0,		"FBLD	%e",
941 0x05,	0,0,		"FMOVL	%e,F0",
942 0x06,	0,0,		"FBSTP	%e",
943 0x07,	0,0,		"FMOVLP	F0,%e",
944 0x0c,	R0,0,		"FSTSW	%OAX",
945 };
946 
947 static Optable optabF6[8] =
948 {
949 0x00,	Ib,0,		"TESTB	%i,%e",
950 0x02,	0,0,		"NOTB	%e",
951 0x03,	0,0,		"NEGB	%e",
952 0x04,	0,0,		"MULB	AL,%e",
953 0x05,	0,0,		"IMULB	AL,%e",
954 0x06,	0,0,		"DIVB	AL,%e",
955 0x07,	0,0,		"IDIVB	AL,%e",
956 };
957 
958 static Optable optabF7[8] =
959 {
960 0x00,	Iwd,0,		"TEST%S	%i,%e",
961 0x02,	0,0,		"NOT%S	%e",
962 0x03,	0,0,		"NEG%S	%e",
963 0x04,	0,0,		"MUL%S	%OAX,%e",
964 0x05,	0,0,		"IMUL%S	%OAX,%e",
965 0x06,	0,0,		"DIV%S	%OAX,%e",
966 0x07,	0,0,		"IDIV%S	%OAX,%e",
967 };
968 
969 static Optable optabFE[8] =
970 {
971 0x00,	0,0,		"INCB	%e",
972 0x01,	0,0,		"DECB	%e",
973 };
974 
975 static Optable optabFF[8] =
976 {
977 0x00,	0,0,		"INC%S	%e",
978 0x01,	0,0,		"DEC%S	%e",
979 0x02,	JUMP,0,		"CALL*	%e",
980 0x03,	JUMP,0,		"CALLF*	%e",
981 0x04,	JUMP,0,		"JMP*	%e",
982 0x05,	JUMP,0,		"JMPF*	%e",
983 0x06,	0,0,		"PUSHL	%e",
984 };
985 
986 static Optable optable[256+1] =
987 {
988 0x00,	RMB,0,		"ADDB	%r,%e",
989 0x01,	RM,0,		"ADD%S	%r,%e",
990 0x02,	RMB,0,		"ADDB	%e,%r",
991 0x03,	RM,0,		"ADD%S	%e,%r",
992 0x04,	Ib,0,		"ADDB	%i,AL",
993 0x05,	Iwd,0,		"ADD%S	%i,%OAX",
994 0x06,	0,0,		"PUSHL	ES",
995 0x07,	0,0,		"POPL	ES",
996 0x08,	RMB,0,		"ORB	%r,%e",
997 0x09,	RM,0,		"OR%S	%r,%e",
998 0x0a,	RMB,0,		"ORB	%e,%r",
999 0x0b,	RM,0,		"OR%S	%e,%r",
1000 0x0c,	Ib,0,		"ORB	%i,AL",
1001 0x0d,	Iwd,0,		"OR%S	%i,%OAX",
1002 0x0e,	0,0,		"PUSHL	CS",
1003 0x0f,	AUXMM,0,	optab0F,
1004 0x10,	RMB,0,		"ADCB	%r,%e",
1005 0x11,	RM,0,		"ADC%S	%r,%e",
1006 0x12,	RMB,0,		"ADCB	%e,%r",
1007 0x13,	RM,0,		"ADC%S	%e,%r",
1008 0x14,	Ib,0,		"ADCB	%i,AL",
1009 0x15,	Iwd,0,		"ADC%S	%i,%OAX",
1010 0x16,	0,0,		"PUSHL	SS",
1011 0x17,	0,0,		"POPL	SS",
1012 0x18,	RMB,0,		"SBBB	%r,%e",
1013 0x19,	RM,0,		"SBB%S	%r,%e",
1014 0x1a,	RMB,0,		"SBBB	%e,%r",
1015 0x1b,	RM,0,		"SBB%S	%e,%r",
1016 0x1c,	Ib,0,		"SBBB	%i,AL",
1017 0x1d,	Iwd,0,		"SBB%S	%i,%OAX",
1018 0x1e,	0,0,		"PUSHL	DS",
1019 0x1f,	0,0,		"POPL	DS",
1020 0x20,	RMB,0,		"ANDB	%r,%e",
1021 0x21,	RM,0,		"AND%S	%r,%e",
1022 0x22,	RMB,0,		"ANDB	%e,%r",
1023 0x23,	RM,0,		"AND%S	%e,%r",
1024 0x24,	Ib,0,		"ANDB	%i,AL",
1025 0x25,	Iwd,0,		"AND%S	%i,%OAX",
1026 0x26,	SEG,0,		"ES:",
1027 0x27,	0,0,		"DAA",
1028 0x28,	RMB,0,		"SUBB	%r,%e",
1029 0x29,	RM,0,		"SUB%S	%r,%e",
1030 0x2a,	RMB,0,		"SUBB	%e,%r",
1031 0x2b,	RM,0,		"SUB%S	%e,%r",
1032 0x2c,	Ib,0,		"SUBB	%i,AL",
1033 0x2d,	Iwd,0,		"SUB%S	%i,%OAX",
1034 0x2e,	SEG,0,		"CS:",
1035 0x2f,	0,0,		"DAS",
1036 0x30,	RMB,0,		"XORB	%r,%e",
1037 0x31,	RM,0,		"XOR%S	%r,%e",
1038 0x32,	RMB,0,		"XORB	%e,%r",
1039 0x33,	RM,0,		"XOR%S	%e,%r",
1040 0x34,	Ib,0,		"XORB	%i,AL",
1041 0x35,	Iwd,0,		"XOR%S	%i,%OAX",
1042 0x36,	SEG,0,		"SS:",
1043 0x37,	0,0,		"AAA",
1044 0x38,	RMB,0,		"CMPB	%r,%e",
1045 0x39,	RM,0,		"CMP%S	%r,%e",
1046 0x3a,	RMB,0,		"CMPB	%e,%r",
1047 0x3b,	RM,0,		"CMP%S	%e,%r",
1048 0x3c,	Ib,0,		"CMPB	%i,AL",
1049 0x3d,	Iwd,0,		"CMP%S	%i,%OAX",
1050 0x3e,	SEG,0,		"DS:",
1051 0x3f,	0,0,		"AAS",
1052 0x40,	0,0,		"INC%S	%OAX",
1053 0x41,	0,0,		"INC%S	%OCX",
1054 0x42,	0,0,		"INC%S	%ODX",
1055 0x43,	0,0,		"INC%S	%OBX",
1056 0x44,	0,0,		"INC%S	%OSP",
1057 0x45,	0,0,		"INC%S	%OBP",
1058 0x46,	0,0,		"INC%S	%OSI",
1059 0x47,	0,0,		"INC%S	%ODI",
1060 0x48,	0,0,		"DEC%S	%OAX",
1061 0x49,	0,0,		"DEC%S	%OCX",
1062 0x4a,	0,0,		"DEC%S	%ODX",
1063 0x4b,	0,0,		"DEC%S	%OBX",
1064 0x4c,	0,0,		"DEC%S	%OSP",
1065 0x4d,	0,0,		"DEC%S	%OBP",
1066 0x4e,	0,0,		"DEC%S	%OSI",
1067 0x4f,	0,0,		"DEC%S	%ODI",
1068 0x50,	0,0,		"PUSH%S	%OAX",
1069 0x51,	0,0,		"PUSH%S	%OCX",
1070 0x52,	0,0,		"PUSH%S	%ODX",
1071 0x53,	0,0,		"PUSH%S	%OBX",
1072 0x54,	0,0,		"PUSH%S	%OSP",
1073 0x55,	0,0,		"PUSH%S	%OBP",
1074 0x56,	0,0,		"PUSH%S	%OSI",
1075 0x57,	0,0,		"PUSH%S	%ODI",
1076 0x58,	0,0,		"POP%S	%OAX",
1077 0x59,	0,0,		"POP%S	%OCX",
1078 0x5a,	0,0,		"POP%S	%ODX",
1079 0x5b,	0,0,		"POP%S	%OBX",
1080 0x5c,	0,0,		"POP%S	%OSP",
1081 0x5d,	0,0,		"POP%S	%OBP",
1082 0x5e,	0,0,		"POP%S	%OSI",
1083 0x5f,	0,0,		"POP%S	%ODI",
1084 0x60,	0,0,		"PUSHA%S",
1085 0x61,	0,0,		"POPA%S",
1086 0x62,	RMM,0,		"BOUND	%e,%r",
1087 0x63,	RM,0,		"ARPL	%r,%e",
1088 0x64,	SEG,0,		"FS:",
1089 0x65,	SEG,0,		"GS:",
1090 0x66,	OPOVER,0,	"",
1091 0x67,	ADDOVER,0,	"",
1092 0x68,	Iwd,0,		"PUSH%S	%i",
1093 0x69,	RM,Iwd,		"IMUL%S	%e,%i,%r",
1094 0x6a,	Ib,0,		"PUSH%S	%i",
1095 0x6b,	RM,Ibs,		"IMUL%S	%e,%i,%r",
1096 0x6c,	0,0,		"INSB	DX,(%ODI)",
1097 0x6d,	0,0,		"INS%S	DX,(%ODI)",
1098 0x6e,	0,0,		"OUTSB	(%ASI),DX",
1099 0x6f,	0,0,		"OUTS%S	(%ASI),DX",
1100 0x70,	Jbs,0,		"JOS	%p",
1101 0x71,	Jbs,0,		"JOC	%p",
1102 0x72,	Jbs,0,		"JCS	%p",
1103 0x73,	Jbs,0,		"JCC	%p",
1104 0x74,	Jbs,0,		"JEQ	%p",
1105 0x75,	Jbs,0,		"JNE	%p",
1106 0x76,	Jbs,0,		"JLS	%p",
1107 0x77,	Jbs,0,		"JHI	%p",
1108 0x78,	Jbs,0,		"JMI	%p",
1109 0x79,	Jbs,0,		"JPL	%p",
1110 0x7a,	Jbs,0,		"JPS	%p",
1111 0x7b,	Jbs,0,		"JPC	%p",
1112 0x7c,	Jbs,0,		"JLT	%p",
1113 0x7d,	Jbs,0,		"JGE	%p",
1114 0x7e,	Jbs,0,		"JLE	%p",
1115 0x7f,	Jbs,0,		"JGT	%p",
1116 0x80,	RMOPB,0,	optab80,
1117 0x81,	RMOP,0,		optab81,
1118 0x83,	RMOP,0,		optab83,
1119 0x84,	RMB,0,		"TESTB	%r,%e",
1120 0x85,	RM,0,		"TEST%S	%r,%e",
1121 0x86,	RMB,0,		"XCHGB	%r,%e",
1122 0x87,	RM,0,		"XCHG%S	%r,%e",
1123 0x88,	RMB,0,		"MOVB	%r,%e",
1124 0x89,	RM,0,		"MOV%S	%r,%e",
1125 0x8a,	RMB,0,		"MOVB	%e,%r",
1126 0x8b,	RM,0,		"MOV%S	%e,%r",
1127 0x8c,	RM,0,		"MOVW	%g,%e",
1128 0x8d,	RM,0,		"LEA%S	%e,%r",
1129 0x8e,	RM,0,		"MOVW	%e,%g",
1130 0x8f,	RM,0,		"POP%S	%e",
1131 0x90,	0,0,		"NOP",
1132 0x91,	0,0,		"XCHG	%OCX,%OAX",
1133 0x92,	0,0,		"XCHG	%ODX,%OAX",
1134 0x93,	0,0,		"XCHG	%OBX,%OAX",
1135 0x94,	0,0,		"XCHG	%OSP,%OAX",
1136 0x95,	0,0,		"XCHG	%OBP,%OAX",
1137 0x96,	0,0,		"XCHG	%OSI,%OAX",
1138 0x97,	0,0,		"XCHG	%ODI,%OAX",
1139 0x98,	0,0,		"%W",			/* miserable CBW or CWDE */
1140 0x99,	0,0,		"%w",			/* idiotic CWD or CDQ */
1141 0x9a,	PTR,0,		"CALL%S	%d",
1142 0x9b,	0,0,		"WAIT",
1143 0x9c,	0,0,		"PUSHF",
1144 0x9d,	0,0,		"POPF",
1145 0x9e,	0,0,		"SAHF",
1146 0x9f,	0,0,		"LAHF",
1147 0xa0,	Awd,0,		"MOVB	%i,AL",
1148 0xa1,	Awd,0,		"MOV%S	%i,%OAX",
1149 0xa2,	Awd,0,		"MOVB	AL,%i",
1150 0xa3,	Awd,0,		"MOV%S	%OAX,%i",
1151 0xa4,	0,0,		"MOVSB	(%ASI),(%ADI)",
1152 0xa5,	0,0,		"MOVS%S	(%ASI),(%ADI)",
1153 0xa6,	0,0,		"CMPSB	(%ASI),(%ADI)",
1154 0xa7,	0,0,		"CMPS%S	(%ASI),(%ADI)",
1155 0xa8,	Ib,0,		"TESTB	%i,AL",
1156 0xa9,	Iwd,0,		"TEST%S	%i,%OAX",
1157 0xaa,	0,0,		"STOSB	AL,(%ADI)",
1158 0xab,	0,0,		"STOS%S	%OAX,(%ADI)",
1159 0xac,	0,0,		"LODSB	(%ASI),AL",
1160 0xad,	0,0,		"LODS%S	(%ASI),%OAX",
1161 0xae,	0,0,		"SCASB	(%ADI),AL",
1162 0xaf,	0,0,		"SCAS%S	(%ADI),%OAX",
1163 0xb0,	Ib,0,		"MOVB	%i,AL",
1164 0xb1,	Ib,0,		"MOVB	%i,CL",
1165 0xb2,	Ib,0,		"MOVB	%i,DL",
1166 0xb3,	Ib,0,		"MOVB	%i,BL",
1167 0xb4,	Ib,0,		"MOVB	%i,AH",
1168 0xb5,	Ib,0,		"MOVB	%i,CH",
1169 0xb6,	Ib,0,		"MOVB	%i,DH",
1170 0xb7,	Ib,0,		"MOVB	%i,BH",
1171 0xb8,	Iwdq,0,		"MOV%S	%i,%OAX",
1172 0xb9,	Iwdq,0,		"MOV%S	%i,%OCX",
1173 0xba,	Iwdq,0,		"MOV%S	%i,%ODX",
1174 0xbb,	Iwdq,0,		"MOV%S	%i,%OBX",
1175 0xbc,	Iwdq,0,		"MOV%S	%i,%OSP",
1176 0xbd,	Iwdq,0,		"MOV%S	%i,%OBP",
1177 0xbe,	Iwdq,0,		"MOV%S	%i,%OSI",
1178 0xbf,	Iwdq,0,		"MOV%S	%i,%ODI",
1179 0xc0,	RMOPB,0,	optabC0,
1180 0xc1,	RMOP,0,		optabC1,
1181 0xc2,	Iw,0,		"RET	%i",
1182 0xc3,	RET,0,		"RET",
1183 0xc4,	RM,0,		"LES	%e,%r",
1184 0xc5,	RM,0,		"LDS	%e,%r",
1185 0xc6,	RMB,Ib,		"MOVB	%i,%e",
1186 0xc7,	RM,Iwd,		"MOV%S	%i,%e",
1187 0xc8,	Iw2,Ib,		"ENTER	%i,%I",		/* loony ENTER */
1188 0xc9,	RET,0,		"LEAVE",		/* bizarre LEAVE */
1189 0xca,	Iw,0,		"RETF	%i",
1190 0xcb,	RET,0,		"RETF",
1191 0xcc,	0,0,		"INT	3",
1192 0xcd,	Ib,0,		"INTB	%i",
1193 0xce,	0,0,		"INTO",
1194 0xcf,	0,0,		"IRET",
1195 0xd0,	RMOPB,0,	optabD0,
1196 0xd1,	RMOP,0,		optabD1,
1197 0xd2,	RMOPB,0,	optabD2,
1198 0xd3,	RMOP,0,		optabD3,
1199 0xd4,	OA,0,		"AAM",
1200 0xd5,	OA,0,		"AAD",
1201 0xd7,	0,0,		"XLAT",
1202 0xd8,	FRMOP,0,	optabD8,
1203 0xd9,	FRMEX,0,	optabD9,
1204 0xda,	FRMOP,0,	optabDA,
1205 0xdb,	FRMEX,0,	optabDB,
1206 0xdc,	FRMOP,0,	optabDC,
1207 0xdd,	FRMOP,0,	optabDD,
1208 0xde,	FRMOP,0,	optabDE,
1209 0xdf,	FRMOP,0,	optabDF,
1210 0xe0,	Jbs,0,		"LOOPNE	%p",
1211 0xe1,	Jbs,0,		"LOOPE	%p",
1212 0xe2,	Jbs,0,		"LOOP	%p",
1213 0xe3,	Jbs,0,		"JCXZ	%p",
1214 0xe4,	Ib,0,		"INB	%i,AL",
1215 0xe5,	Ib,0,		"IN%S	%i,%OAX",
1216 0xe6,	Ib,0,		"OUTB	AL,%i",
1217 0xe7,	Ib,0,		"OUT%S	%OAX,%i",
1218 0xe8,	Iwds,0,		"CALL	%p",
1219 0xe9,	Iwds,0,		"JMP	%p",
1220 0xea,	PTR,0,		"JMP	%d",
1221 0xeb,	Jbs,0,		"JMP	%p",
1222 0xec,	0,0,		"INB	DX,AL",
1223 0xed,	0,0,		"IN%S	DX,%OAX",
1224 0xee,	0,0,		"OUTB	AL,DX",
1225 0xef,	0,0,		"OUT%S	%OAX,DX",
1226 0xf0,	PRE,0,		"LOCK",
1227 0xf2,	OPRE,0,		"REPNE",
1228 0xf3,	OPRE,0,		"REP",
1229 0xf4,	0,0,		"HLT",
1230 0xf5,	0,0,		"CMC",
1231 0xf6,	RMOPB,0,	optabF6,
1232 0xf7,	RMOP,0,		optabF7,
1233 0xf8,	0,0,		"CLC",
1234 0xf9,	0,0,		"STC",
1235 0xfa,	0,0,		"CLI",
1236 0xfb,	0,0,		"STI",
1237 0xfc,	0,0,		"CLD",
1238 0xfd,	0,0,		"STD",
1239 0xfe,	RMOPB,0,	optabFE,
1240 0xff,	RMOP,0,		optabFF,
1241 0x100,	RM,0,		"MOVLQSX	%r,%e",
1242 };
1243 
1244 static struct {
1245 	Optable	*tab;
1246 	uint	nel;
1247 } optabtab[] = {
1248 	optab0F00, nelem(optab0F00),
1249 	optab0F01, nelem(optab0F01),
1250 	optab0F01F8, nelem(optab0F01F8),
1251 	optab0FAE, nelem(optab0FAE),
1252 	optab0FBA, nelem(optab0FBA),
1253 	optab0F0F, nelem(optab0F0F),
1254 	optab0FC7, nelem(optab0FC7),
1255 	optab660F71, nelem(optab660F71),
1256 	optab660F72, nelem(optab660F72),
1257 	optab660F73, nelem(optab660F73),
1258 	optab660F, nelem(optab660F),
1259 	optabF20F, nelem(optabF20F),
1260 	optabF30F, nelem(optabF30F),
1261 	optab0F, nelem(optab0F),
1262 	optab80, nelem(optab80),
1263 	optab81, nelem(optab81),
1264 	optab83, nelem(optab83),
1265 	optabC0, nelem(optabC0),
1266 	optabC1, nelem(optabC1),
1267 	optabD0, nelem(optabD0),
1268 	optabD1, nelem(optabD1),
1269 	optabD2, nelem(optabD2),
1270 	optabD3, nelem(optabD3),
1271 	optabD8, nelem(optabD8),
1272 	optabD9, nelem(optabD9),
1273 	optabDA, nelem(optabDA),
1274 	optabDB, nelem(optabDB),
1275 	optabDC, nelem(optabDC),
1276 	optabDD, nelem(optabDD),
1277 	optabDE, nelem(optabDE),
1278 	optabDF, nelem(optabDF),
1279 	optabF6, nelem(optabF6),
1280 	optabF7, nelem(optabF7),
1281 	optabFE, nelem(optabFE),
1282 	optabFF, nelem(optabFF),
1283 	optable, nelem(optable),
1284 };
1285 
1286 /*
1287  * compensate for Microsoft's ageing compilers
1288  */
1289 static void
1290 ordertab(Optable *tab, int nel)
1291 {
1292 	int i, x;
1293 	static Optable empty;
1294 
1295 	for(i = nel; --i >= 0;){
1296 		x = tab[i].x;
1297 		if(x != i){
1298 			tab[x] = tab[i];
1299 			tab[i] = empty;
1300 		}
1301 	}
1302 }
1303 
1304 static void
1305 soptoms(void)
1306 {
1307 	int i;
1308 	static int reordered;	/* assumes non-concurrent use */
1309 
1310 	if(reordered)
1311 		return;
1312 	reordered = 1;
1313 	for(i = 0; i < nelem(optabtab); i++)
1314 		ordertab(optabtab[i].tab, optabtab[i].nel);
1315 }
1316 
1317 /*
1318  *  get a byte of the instruction
1319  */
1320 static int
1321 igetc(Map *map, Instr *ip, uchar *c)
1322 {
1323 	if(ip->n+1 > sizeof(ip->mem)){
1324 		werrstr("instruction too long");
1325 		return -1;
1326 	}
1327 	if (get1(map, ip->addr+ip->n, c, 1) < 0) {
1328 		werrstr("can't read instruction: %r");
1329 		return -1;
1330 	}
1331 	ip->mem[ip->n++] = *c;
1332 	return 1;
1333 }
1334 
1335 /*
1336  *  get two bytes of the instruction
1337  */
1338 static int
1339 igets(Map *map, Instr *ip, ushort *sp)
1340 {
1341 	uchar c;
1342 	ushort s;
1343 
1344 	if (igetc(map, ip, &c) < 0)
1345 		return -1;
1346 	s = c;
1347 	if (igetc(map, ip, &c) < 0)
1348 		return -1;
1349 	s |= (c<<8);
1350 	*sp = s;
1351 	return 1;
1352 }
1353 
1354 /*
1355  *  get 4 bytes of the instruction
1356  */
1357 static int
1358 igetl(Map *map, Instr *ip, ulong *lp)
1359 {
1360 	ushort s;
1361 	long	l;
1362 
1363 	if (igets(map, ip, &s) < 0)
1364 		return -1;
1365 	l = s;
1366 	if (igets(map, ip, &s) < 0)
1367 		return -1;
1368 	l |= (s<<16);
1369 	*lp = l;
1370 	return 1;
1371 }
1372 
1373 /*
1374  *  get 8 bytes of the instruction
1375  */
1376 static int
1377 igetq(Map *map, Instr *ip, vlong *qp)
1378 {
1379 	ulong	l;
1380 	uvlong q;
1381 
1382 	if (igetl(map, ip, &l) < 0)
1383 		return -1;
1384 	q = l;
1385 	if (igetl(map, ip, &l) < 0)
1386 		return -1;
1387 	q |= ((uvlong)l<<32);
1388 	*qp = q;
1389 	return 1;
1390 }
1391 
1392 static int
1393 getdisp(Map *map, Instr *ip, int mod, int rm, int code, int pcrel)
1394 {
1395 	uchar c;
1396 	ushort s;
1397 
1398 	if (mod > 2)
1399 		return 1;
1400 	if (mod == 1) {
1401 		if (igetc(map, ip, &c) < 0)
1402 			return -1;
1403 		if (c&0x80)
1404 			ip->disp = c|0xffffff00;
1405 		else
1406 			ip->disp = c&0xff;
1407 	} else if (mod == 2 || rm == code) {
1408 		if (ip->asize == 'E') {
1409 			if (igetl(map, ip, &ip->disp) < 0)
1410 				return -1;
1411 			if (mod == 0)
1412 				ip->rip = pcrel;
1413 		} else {
1414 			if (igets(map, ip, &s) < 0)
1415 				return -1;
1416 			if (s&0x8000)
1417 				ip->disp = s|0xffff0000;
1418 			else
1419 				ip->disp = s;
1420 		}
1421 		if (mod == 0)
1422 			ip->base = -1;
1423 	}
1424 	return 1;
1425 }
1426 
1427 static int
1428 modrm(Map *map, Instr *ip, uchar c)
1429 {
1430 	uchar rm, mod;
1431 
1432 	mod = (c>>6)&3;
1433 	rm = c&7;
1434 	ip->mod = mod;
1435 	ip->base = rm;
1436 	ip->reg = (c>>3)&7;
1437 	ip->rip = 0;
1438 	if (mod == 3)			/* register */
1439 		return 1;
1440 	if (ip->asize == 0) {		/* 16-bit mode */
1441 		switch(rm) {
1442 		case 0:
1443 			ip->base = BX; ip->index = SI;
1444 			break;
1445 		case 1:
1446 			ip->base = BX; ip->index = DI;
1447 			break;
1448 		case 2:
1449 			ip->base = BP; ip->index = SI;
1450 			break;
1451 		case 3:
1452 			ip->base = BP; ip->index = DI;
1453 			break;
1454 		case 4:
1455 			ip->base = SI;
1456 			break;
1457 		case 5:
1458 			ip->base = DI;
1459 			break;
1460 		case 6:
1461 			ip->base = BP;
1462 			break;
1463 		case 7:
1464 			ip->base = BX;
1465 			break;
1466 		default:
1467 			break;
1468 		}
1469 		return getdisp(map, ip, mod, rm, 6, 0);
1470 	}
1471 	if (rm == 4) {	/* scummy sib byte */
1472 		if (igetc(map, ip, &c) < 0)
1473 			return -1;
1474 		ip->ss = (c>>6)&0x03;
1475 		ip->index = (c>>3)&0x07;
1476 		if (ip->index == 4)
1477 			ip->index = -1;
1478 		ip->base = c&0x07;
1479 		return getdisp(map, ip, mod, ip->base, 5, 0);
1480 	}
1481 	return getdisp(map, ip, mod, rm, 5, ip->amd64);
1482 }
1483 
1484 static Optable *
1485 mkinstr(Map *map, Instr *ip, uvlong pc)
1486 {
1487 	int i, n, norex;
1488 	uchar c;
1489 	ushort s;
1490 	Optable *op, *obase;
1491 	char buf[128];
1492 
1493 	soptoms();
1494 	memset(ip, 0, sizeof(*ip));
1495 	norex = 1;
1496 	ip->base = -1;
1497 	ip->index = -1;
1498 	if(asstype == AI8086)
1499 		ip->osize = 'W';
1500 	else {
1501 		ip->osize = 'L';
1502 		ip->asize = 'E';
1503 		ip->amd64 = asstype != AI386;
1504 		norex = 0;
1505 	}
1506 	ip->addr = pc;
1507 	if (igetc(map, ip, &c) < 0)
1508 		return 0;
1509 	obase = optable;
1510 newop:
1511 	if(ip->amd64 && !norex){
1512 		if(c >= 0x40 && c <= 0x4f) {
1513 			ip->rex = c;
1514 			if(igetc(map, ip, &c) < 0)
1515 				return 0;
1516 		}
1517 		if(c == 0x63){
1518 			op = &obase[0x100];	/* MOVLQSX */
1519 			goto hack;
1520 		}
1521 	}
1522 	op = &obase[c];
1523 hack:
1524 	if (op->proto == 0) {
1525 badop:
1526 		n = snprint(buf, sizeof(buf), "opcode: ??");
1527 		for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
1528 			_hexify(buf+n, ip->mem[i], 1);
1529 		strcpy(buf+n, "??");
1530 		werrstr(buf);
1531 		return 0;
1532 	}
1533 	for(i = 0; i < 2 && op->operand[i]; i++) {
1534 		switch(op->operand[i]) {
1535 		case Ib:	/* 8-bit immediate - (no sign extension)*/
1536 			if (igetc(map, ip, &c) < 0)
1537 				return 0;
1538 			ip->imm = c&0xff;
1539 			ip->imm64 = ip->imm;
1540 			break;
1541 		case Jbs:	/* 8-bit jump immediate (sign extended) */
1542 			if (igetc(map, ip, &c) < 0)
1543 				return 0;
1544 			if (c&0x80)
1545 				ip->imm = c|0xffffff00;
1546 			else
1547 				ip->imm = c&0xff;
1548 			ip->imm64 = (long)ip->imm;
1549 			ip->jumptype = Jbs;
1550 			break;
1551 		case Ibs:	/* 8-bit immediate (sign extended) */
1552 			if (igetc(map, ip, &c) < 0)
1553 				return 0;
1554 			if (c&0x80)
1555 				if (ip->osize == 'L')
1556 					ip->imm = c|0xffffff00;
1557 				else
1558 					ip->imm = c|0xff00;
1559 			else
1560 				ip->imm = c&0xff;
1561 			ip->imm64 = (long)ip->imm;
1562 			break;
1563 		case Iw:	/* 16-bit immediate -> imm */
1564 			if (igets(map, ip, &s) < 0)
1565 				return 0;
1566 			ip->imm = s&0xffff;
1567 			ip->imm64 = ip->imm;
1568 			ip->jumptype = Iw;
1569 			break;
1570 		case Iw2:	/* 16-bit immediate -> in imm2*/
1571 			if (igets(map, ip, &s) < 0)
1572 				return 0;
1573 			ip->imm2 = s&0xffff;
1574 			break;
1575 		case Iwd:	/* Operand-sized immediate (no sign extension unless 64 bits)*/
1576 			if (ip->osize == 'L') {
1577 				if (igetl(map, ip, &ip->imm) < 0)
1578 					return 0;
1579 				ip->imm64 = ip->imm;
1580 				if(ip->rex&REXW && (ip->imm & (1<<31)) != 0)
1581 					ip->imm64 |= (vlong)~0 << 32;
1582 			} else {
1583 				if (igets(map, ip, &s)< 0)
1584 					return 0;
1585 				ip->imm = s&0xffff;
1586 				ip->imm64 = ip->imm;
1587 			}
1588 			break;
1589 		case Iwdq:	/* Operand-sized immediate, possibly big */
1590 			if (ip->osize == 'L') {
1591 				if (igetl(map, ip, &ip->imm) < 0)
1592 					return 0;
1593 				ip->imm64 = ip->imm;
1594 				if (ip->rex & REXW) {
1595 					ulong l;
1596 					if (igetl(map, ip, &l) < 0)
1597 						return 0;
1598 					ip->imm64 |= (uvlong)l << 32;
1599 				}
1600 			} else {
1601 				if (igets(map, ip, &s)< 0)
1602 					return 0;
1603 				ip->imm = s&0xffff;
1604 			}
1605 			break;
1606 		case Awd:	/* Address-sized immediate (no sign extension)*/
1607 			if (ip->asize == 'E') {
1608 				if (igetl(map, ip, &ip->imm) < 0)
1609 					return 0;
1610 				/* TO DO: REX */
1611 			} else {
1612 				if (igets(map, ip, &s)< 0)
1613 					return 0;
1614 				ip->imm = s&0xffff;
1615 			}
1616 			break;
1617 		case Iwds:	/* Operand-sized immediate (sign extended) */
1618 			if (ip->osize == 'L') {
1619 				if (igetl(map, ip, &ip->imm) < 0)
1620 					return 0;
1621 			} else {
1622 				if (igets(map, ip, &s)< 0)
1623 					return 0;
1624 				if (s&0x8000)
1625 					ip->imm = s|0xffff0000;
1626 				else
1627 					ip->imm = s&0xffff;
1628 			}
1629 			ip->jumptype = Iwds;
1630 			break;
1631 		case OA:	/* literal 0x0a byte */
1632 			if (igetc(map, ip, &c) < 0)
1633 				return 0;
1634 			if (c != 0x0a)
1635 				goto badop;
1636 			break;
1637 		case R0:	/* base register must be R0 */
1638 			if (ip->base != 0)
1639 				goto badop;
1640 			break;
1641 		case R1:	/* base register must be R1 */
1642 			if (ip->base != 1)
1643 				goto badop;
1644 			break;
1645 		case RMB:	/* R/M field with byte register (/r)*/
1646 			if (igetc(map, ip, &c) < 0)
1647 				return 0;
1648 			if (modrm(map, ip, c) < 0)
1649 				return 0;
1650 			ip->osize = 'B';
1651 			break;
1652 		case RM:	/* R/M field with register (/r) */
1653 			if (igetc(map, ip, &c) < 0)
1654 				return 0;
1655 			if (modrm(map, ip, c) < 0)
1656 				return 0;
1657 			break;
1658 		case RMOPB:	/* R/M field with op code (/digit) */
1659 			if (igetc(map, ip, &c) < 0)
1660 				return 0;
1661 			if (modrm(map, ip, c) < 0)
1662 				return 0;
1663 			c = ip->reg;		/* secondary op code */
1664 			obase = (Optable*)op->proto;
1665 			ip->osize = 'B';
1666 			goto newop;
1667 		case RMOP:	/* R/M field with op code (/digit) */
1668 			if (igetc(map, ip, &c) < 0)
1669 				return 0;
1670 			if (modrm(map, ip, c) < 0)
1671 				return 0;
1672 			obase = (Optable*)op->proto;
1673 			if(ip->amd64 && obase == optab0F01 && c == 0xF8)
1674 				return optab0F01F8;
1675 			c = ip->reg;
1676 			goto newop;
1677 		case FRMOP:	/* FP R/M field with op code (/digit) */
1678 			if (igetc(map, ip, &c) < 0)
1679 				return 0;
1680 			if (modrm(map, ip, c) < 0)
1681 				return 0;
1682 			if ((c&0xc0) == 0xc0)
1683 				c = ip->reg+8;		/* 16 entry table */
1684 			else
1685 				c = ip->reg;
1686 			obase = (Optable*)op->proto;
1687 			goto newop;
1688 		case FRMEX:	/* Extended FP R/M field with op code (/digit) */
1689 			if (igetc(map, ip, &c) < 0)
1690 				return 0;
1691 			if (modrm(map, ip, c) < 0)
1692 				return 0;
1693 			if ((c&0xc0) == 0xc0)
1694 				c = (c&0x3f)+8;		/* 64-entry table */
1695 			else
1696 				c = ip->reg;
1697 			obase = (Optable*)op->proto;
1698 			goto newop;
1699 		case RMR:	/* R/M register only (mod = 11) */
1700 			if (igetc(map, ip, &c) < 0)
1701 				return 0;
1702 			if ((c&0xc0) != 0xc0) {
1703 				werrstr("invalid R/M register: %x", c);
1704 				return 0;
1705 			}
1706 			if (modrm(map, ip, c) < 0)
1707 				return 0;
1708 			break;
1709 		case RMM:	/* R/M register only (mod = 11) */
1710 			if (igetc(map, ip, &c) < 0)
1711 				return 0;
1712 			if ((c&0xc0) == 0xc0) {
1713 				werrstr("invalid R/M memory mode: %x", c);
1714 				return 0;
1715 			}
1716 			if (modrm(map, ip, c) < 0)
1717 				return 0;
1718 			break;
1719 		case PTR:	/* Seg:Displacement addr (ptr16:16 or ptr16:32) */
1720 			if (ip->osize == 'L') {
1721 				if (igetl(map, ip, &ip->disp) < 0)
1722 					return 0;
1723 			} else {
1724 				if (igets(map, ip, &s)< 0)
1725 					return 0;
1726 				ip->disp = s&0xffff;
1727 			}
1728 			if (igets(map, ip, (ushort*)&ip->seg) < 0)
1729 				return 0;
1730 			ip->jumptype = PTR;
1731 			break;
1732 		case AUXMM:	/* Multi-byte op code; prefix determines table selection */
1733 			if (igetc(map, ip, &c) < 0)
1734 				return 0;
1735 			obase = (Optable*)op->proto;
1736 			switch (ip->opre) {
1737 			case 0x66:	op = optab660F; break;
1738 			case 0xF2:	op = optabF20F; break;
1739 			case 0xF3:	op = optabF30F; break;
1740 			default:	op = nil; break;
1741 			}
1742 			if(op != nil && op[c].proto != nil)
1743 				obase = op;
1744 			norex = 1;	/* no more rex prefixes */
1745 			/* otherwise the optab entry captures it */
1746 			goto newop;
1747 		case AUX:	/* Multi-byte op code - Auxiliary table */
1748 			obase = (Optable*)op->proto;
1749 			if (igetc(map, ip, &c) < 0)
1750 				return 0;
1751 			goto newop;
1752 		case OPRE:	/* Instr Prefix or media op */
1753 			ip->opre = c;
1754 			/* fall through */
1755 		case PRE:	/* Instr Prefix */
1756 			ip->prefix = (char*)op->proto;
1757 			if (igetc(map, ip, &c) < 0)
1758 				return 0;
1759 			if (ip->opre && c == 0x0F)
1760 				ip->prefix = 0;
1761 			goto newop;
1762 		case SEG:	/* Segment Prefix */
1763 			ip->segment = (char*)op->proto;
1764 			if (igetc(map, ip, &c) < 0)
1765 				return 0;
1766 			goto newop;
1767 		case OPOVER:	/* Operand size override */
1768 			ip->opre = c;
1769 			ip->osize = 'W';
1770 			if (igetc(map, ip, &c) < 0)
1771 				return 0;
1772 			if (c == 0x0F)
1773 				ip->osize = 'L';
1774 			else if (ip->amd64 && (c&0xF0) == 0x40)
1775 				ip->osize = 'Q';
1776 			goto newop;
1777 		case ADDOVER:	/* Address size override */
1778 			ip->asize = 0;
1779 			if (igetc(map, ip, &c) < 0)
1780 				return 0;
1781 			goto newop;
1782 		case JUMP:	/* mark instruction as JUMP or RET */
1783 		case RET:
1784 			ip->jumptype = op->operand[i];
1785 			break;
1786 		default:
1787 			werrstr("bad operand type %d", op->operand[i]);
1788 			return 0;
1789 		}
1790 	}
1791 	return op;
1792 }
1793 
1794 #pragma	varargck	argpos	bprint		2
1795 
1796 static void
1797 bprint(Instr *ip, char *fmt, ...)
1798 {
1799 	va_list arg;
1800 
1801 	va_start(arg, fmt);
1802 	ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
1803 	va_end(arg);
1804 }
1805 
1806 /*
1807  *  if we want to call 16 bit regs AX,BX,CX,...
1808  *  and 32 bit regs EAX,EBX,ECX,... then
1809  *  change the defs of ANAME and ONAME to:
1810  *  #define	ANAME(ip)	((ip->asize == 'E' ? "E" : "")
1811  *  #define	ONAME(ip)	((ip)->osize == 'L' ? "E" : "")
1812  */
1813 #define	ANAME(ip)	""
1814 #define	ONAME(ip)	""
1815 
1816 static char *reg[] =  {
1817 	"AX",
1818 	"CX",
1819 	"DX",
1820 	"BX",
1821 	"SP",
1822 	"BP",
1823 	"SI",
1824 	"DI",
1825 
1826 	/* amd64 */
1827 	"R8",
1828 	"R9",
1829 	"R10",
1830 	"R11",
1831 	"R12",
1832 	"R13",
1833 	"R14",
1834 	"R15",
1835 };
1836 
1837 static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
1838 static char *breg64[] = { "AL", "CL", "DL", "BL", "SPB", "BPB", "SIB", "DIB",
1839 	"R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B" };
1840 static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
1841 
1842 static void
1843 plocal(Instr *ip)
1844 {
1845 	int ret;
1846 	long offset;
1847 	Symbol s;
1848 	char *reg;
1849 
1850 	offset = ip->disp;
1851 	if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) {
1852 		bprint(ip, "%lux(SP)", offset);
1853 		return;
1854 	}
1855 
1856 	if (s.value > ip->disp) {
1857 		ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s);
1858 		reg = "(SP)";
1859 	} else {
1860 		offset -= s.value;
1861 		ret = getauto(&s, offset, CPARAM, &s);
1862 		reg = "(FP)";
1863 	}
1864 	if (ret)
1865 		bprint(ip, "%s+", s.name);
1866 	else
1867 		offset = ip->disp;
1868 	bprint(ip, "%lux%s", offset, reg);
1869 }
1870 
1871 static int
1872 isjmp(Instr *ip)
1873 {
1874 	switch(ip->jumptype){
1875 	case Iwds:
1876 	case Jbs:
1877 	case JUMP:
1878 		return 1;
1879 	default:
1880 		return 0;
1881 	}
1882 }
1883 
1884 /*
1885  * This is too smart for its own good, but it really is nice
1886  * to have accurate translations when debugging, and it
1887  * helps us identify which code is different in binaries that
1888  * are changed on sources.
1889  */
1890 static int
1891 issymref(Instr *ip, Symbol *s, long w, long val)
1892 {
1893 	Symbol next, tmp;
1894 	long isstring, size;
1895 
1896 	if (isjmp(ip))
1897 		return 1;
1898 	if (s->class==CTEXT && w==0)
1899 		return 1;
1900 	if (s->class==CDATA) {
1901 		/* use first bss symbol (or "end") rather than edata */
1902 		if (s->name[0]=='e' && strcmp(s->name, "edata") == 0){
1903 			if((s ->index >= 0 && globalsym(&tmp, s->index+1) && tmp.value==s->value)
1904 			|| (s->index > 0 && globalsym(&tmp, s->index-1) && tmp.value==s->value))
1905 				*s = tmp;
1906 		}
1907 		if (w == 0)
1908 			return 1;
1909 		for (next=*s; next.value==s->value; next=tmp)
1910 			if (!globalsym(&tmp, next.index+1))
1911 				break;
1912 		size = next.value - s->value;
1913 		if (w >= size)
1914 			return 0;
1915 		if (w > size-w)
1916 			w = size-w;
1917 		/* huge distances are usually wrong except in .string */
1918 		isstring = (s->name[0]=='.' && strcmp(s->name, ".string") == 0);
1919 		if (w > 8192 && !isstring)
1920 			return 0;
1921 		/* medium distances are tricky - look for constants */
1922 		/* near powers of two */
1923 		if ((val&(val-1)) == 0 || (val&(val+1)) == 0)
1924 			return 0;
1925 		return 1;
1926 	}
1927 	return 0;
1928 }
1929 
1930 static void
1931 immediate(Instr *ip, vlong val)
1932 {
1933 	Symbol s;
1934 	long w;
1935 
1936 	if (findsym(val, CANY, &s)) {		/* TO DO */
1937 		w = val - s.value;
1938 		if (w < 0)
1939 			w = -w;
1940 		if (issymref(ip, &s, w, val)) {
1941 			if (w)
1942 				bprint(ip, "%s+%lux(SB)", s.name, w);
1943 			else
1944 				bprint(ip, "%s(SB)", s.name);
1945 			return;
1946 		}
1947 /*
1948 		if (s.class==CDATA && globalsym(&s, s.index+1)) {
1949 			w = s.value - val;
1950 			if (w < 0)
1951 				w = -w;
1952 			if (w < 4096) {
1953 				bprint(ip, "%s-%lux(SB)", s.name, w);
1954 				return;
1955 			}
1956 		}
1957 */
1958 	}
1959 	if((ip->rex & REXW) == 0)
1960 		bprint(ip, "%lux", (long)val);
1961 	else
1962 		bprint(ip, "%llux", val);
1963 }
1964 
1965 static void
1966 pea(Instr *ip)
1967 {
1968 	if (ip->mod == 3) {
1969 		if (ip->osize == 'B')
1970 			bprint(ip, (ip->rex & REXB? breg64: breg)[ip->base]);
1971 		else if(ip->rex & REXB)
1972 			bprint(ip, "%s%s", ANAME(ip), reg[ip->base+8]);
1973 		else
1974 			bprint(ip, "%s%s", ANAME(ip), reg[ip->base]);
1975 		return;
1976 	}
1977 	if (ip->segment)
1978 		bprint(ip, ip->segment);
1979 	if (ip->asize == 'E' && ip->base == SP)
1980 		plocal(ip);
1981 	else {
1982 		if (ip->base < 0)
1983 			immediate(ip, ip->disp);
1984 		else {
1985 			bprint(ip, "%lux", ip->disp);
1986 			if(ip->rip)
1987 				bprint(ip, "(RIP)");
1988 			bprint(ip,"(%s%s)", ANAME(ip), reg[ip->rex&REXB? ip->base+8: ip->base]);
1989 		}
1990 	}
1991 	if (ip->index >= 0)
1992 		bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->rex&REXX? ip->index+8: ip->index], 1<<ip->ss);
1993 }
1994 
1995 static void
1996 prinstr(Instr *ip, char *fmt)
1997 {
1998 	vlong v;
1999 
2000 	if (ip->prefix)
2001 		bprint(ip, "%s ", ip->prefix);
2002 	for (; *fmt && ip->curr < ip->end; fmt++) {
2003 		if (*fmt != '%'){
2004 			*ip->curr++ = *fmt;
2005 			continue;
2006 		}
2007 		switch(*++fmt){
2008 		case '%':
2009 			*ip->curr++ = '%';
2010 			break;
2011 		case 'A':
2012 			bprint(ip, "%s", ANAME(ip));
2013 			break;
2014 		case 'C':
2015 			bprint(ip, "CR%d", ip->reg);
2016 			break;
2017 		case 'D':
2018 			if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
2019 				bprint(ip, "DR%d",ip->reg);
2020 			else
2021 				bprint(ip, "?");
2022 			break;
2023 		case 'I':
2024 			bprint(ip, "$");
2025 			immediate(ip, ip->imm2);
2026 			break;
2027 		case 'O':
2028 			bprint(ip,"%s", ONAME(ip));
2029 			break;
2030 		case 'i':
2031 			bprint(ip, "$");
2032 			v = ip->imm;
2033 			if(ip->rex & REXW)
2034 				v = ip->imm64;
2035 			immediate(ip, v);
2036 			break;
2037 		case 'R':
2038 			bprint(ip, "%s%s", ONAME(ip), reg[ip->rex&REXR? ip->reg+8: ip->reg]);
2039 			break;
2040 		case 'S':
2041 			if(ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
2042 				bprint(ip, "Q");
2043 			else
2044 				bprint(ip, "%c", ip->osize);
2045 			break;
2046 		case 's':
2047 			if(ip->opre == 0 || ip->opre == 0x66)
2048 				bprint(ip, "P");
2049 			else
2050 				bprint(ip, "S");
2051 			if(ip->opre == 0xf2 || ip->opre == 0x66)
2052 				bprint(ip, "D");
2053 			else
2054 				bprint(ip, "S");
2055 			break;
2056 		case 'T':
2057 			if (ip->reg == 6 || ip->reg == 7)
2058 				bprint(ip, "TR%d",ip->reg);
2059 			else
2060 				bprint(ip, "?");
2061 			break;
2062 		case 'W':
2063 			if (ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
2064 				bprint(ip, "CDQE");
2065 			else if (ip->osize == 'L')
2066 				bprint(ip,"CWDE");
2067 			else
2068 				bprint(ip, "CBW");
2069 			break;
2070 		case 'd':
2071 			bprint(ip,"%ux:%lux",ip->seg,ip->disp);
2072 			break;
2073 		case 'm':
2074 			if (ip->mod == 3 && ip->osize != 'B') {
2075 				if(fmt[1] != '*'){
2076 					if(ip->opre != 0) {
2077 						bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
2078 						break;
2079 					}
2080 				} else
2081 					fmt++;
2082 				bprint(ip, "M%d", ip->base);
2083 				break;
2084 			}
2085 			pea(ip);
2086 			break;
2087 		case 'e':
2088 			pea(ip);
2089 			break;
2090 		case 'f':
2091 			bprint(ip, "F%d", ip->base);
2092 			break;
2093 		case 'g':
2094 			if (ip->reg < 6)
2095 				bprint(ip,"%s",sreg[ip->reg]);
2096 			else
2097 				bprint(ip,"?");
2098 			break;
2099 		case 'p':
2100 			/*
2101 			 * signed immediate in the ulong ip->imm.
2102 			 */
2103 			v = (long)ip->imm;
2104 			immediate(ip, v+ip->addr+ip->n);
2105 			break;
2106 		case 'r':
2107 			if (ip->osize == 'B')
2108 				bprint(ip,"%s", (ip->rex? breg64: breg)[ip->rex&REXR? ip->reg+8: ip->reg]);
2109 			else
2110 				bprint(ip, reg[ip->rex&REXR? ip->reg+8: ip->reg]);
2111 			break;
2112 		case 'w':
2113 			if (ip->osize == 'Q' || ip->rex & REXW)
2114 				bprint(ip, "CQO");
2115 			else if (ip->osize == 'L')
2116 				bprint(ip,"CDQ");
2117 			else
2118 				bprint(ip, "CWD");
2119 			break;
2120 		case 'M':
2121 			if(ip->opre != 0)
2122 				bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
2123 			else
2124 				bprint(ip, "M%d", ip->reg);
2125 			break;
2126 		case 'x':
2127 			if (ip->mod == 3 && ip->osize != 'B') {
2128 				bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
2129 				break;
2130 			}
2131 			pea(ip);
2132 			break;
2133 		case 'X':
2134 			bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
2135 			break;
2136 		default:
2137 			bprint(ip, "%%%c", *fmt);
2138 			break;
2139 		}
2140 	}
2141 	*ip->curr = 0;		/* there's always room for 1 byte */
2142 }
2143 
2144 static int
2145 i386inst(Map *map, uvlong pc, char modifier, char *buf, int n)
2146 {
2147 	Instr instr;
2148 	Optable *op;
2149 
2150 	USED(modifier);
2151 	op = mkinstr(map, &instr, pc);
2152 	if (op == 0) {
2153 		errstr(buf, n);
2154 		return -1;
2155 	}
2156 	instr.curr = buf;
2157 	instr.end = buf+n-1;
2158 	prinstr(&instr, op->proto);
2159 	return instr.n;
2160 }
2161 
2162 static int
2163 i386das(Map *map, uvlong pc, char *buf, int n)
2164 {
2165 	Instr instr;
2166 	int i;
2167 
2168 	if (mkinstr(map, &instr, pc) == 0) {
2169 		errstr(buf, n);
2170 		return -1;
2171 	}
2172 	for(i = 0; i < instr.n && n > 2; i++) {
2173 		_hexify(buf, instr.mem[i], 1);
2174 		buf += 2;
2175 		n -= 2;
2176 	}
2177 	*buf = 0;
2178 	return instr.n;
2179 }
2180 
2181 static int
2182 i386instlen(Map *map, uvlong pc)
2183 {
2184 	Instr i;
2185 
2186 	if (mkinstr(map, &i, pc))
2187 		return i.n;
2188 	return -1;
2189 }
2190 
2191 static int
2192 i386foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
2193 {
2194 	Instr i;
2195 	Optable *op;
2196 	ushort s;
2197 	uvlong l, addr;
2198 	vlong v;
2199 	int n;
2200 
2201 	op = mkinstr(map, &i, pc);
2202 	if (!op)
2203 		return -1;
2204 
2205 	n = 0;
2206 
2207 	switch(i.jumptype) {
2208 	case RET:		/* RETURN or LEAVE */
2209 	case Iw:		/* RETURN */
2210 		if (strcmp(op->proto, "LEAVE") == 0) {
2211 			if (geta(map, (*rget)(map, "BP"), &l) < 0)
2212 				return -1;
2213 		} else if (geta(map, (*rget)(map, mach->sp), &l) < 0)
2214 			return -1;
2215 		foll[0] = l;
2216 		return 1;
2217 	case Iwds:		/* pc relative JUMP or CALL*/
2218 	case Jbs:		/* pc relative JUMP or CALL */
2219 		v = (long)i.imm;
2220 		foll[0] = pc+v+i.n;
2221 		n = 1;
2222 		break;
2223 	case PTR:		/* seg:displacement JUMP or CALL */
2224 		foll[0] = (i.seg<<4)+i.disp;
2225 		return 1;
2226 	case JUMP:		/* JUMP or CALL EA */
2227 
2228 		if(i.mod == 3) {
2229 			foll[0] = (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]);
2230 			return 1;
2231 		}
2232 			/* calculate the effective address */
2233 		addr = i.disp;
2234 		if (i.base >= 0) {
2235 			if (geta(map, (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]), &l) < 0)
2236 				return -1;
2237 			addr += l;
2238 		}
2239 		if (i.index >= 0) {
2240 			if (geta(map, (*rget)(map, reg[i.rex&REXX? i.index+8: i.index]), &l) < 0)
2241 				return -1;
2242 			addr += l*(1<<i.ss);
2243 		}
2244 			/* now retrieve a seg:disp value at that address */
2245 		if (get2(map, addr, &s) < 0)			/* seg */
2246 			return -1;
2247 		foll[0] = s<<4;
2248 		addr += 2;
2249 		if (i.asize == 'L') {
2250 			if (geta(map, addr, &l) < 0)		/* disp32 */
2251 				return -1;
2252 			foll[0] += l;
2253 		} else {					/* disp16 */
2254 			if (get2(map, addr, &s) < 0)
2255 				return -1;
2256 			foll[0] += s;
2257 		}
2258 		return 1;
2259 	default:
2260 		break;
2261 	}
2262 	if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)
2263 		return 1;
2264 	foll[n++] = pc+i.n;
2265 	return n;
2266 }
2267