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