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