1 /*
2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 * 3. Neither the name of The DragonFly Project nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific, prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * --
32 *
33 * Mach Operating System
34 * Copyright (c) 1991,1990 Carnegie Mellon University
35 * All Rights Reserved.
36 *
37 * Permission to use, copy, modify and distribute this software and its
38 * documentation is hereby granted, provided that both the copyright
39 * notice and this permission notice appear in all copies of the
40 * software, derivative works or modified versions, and any portions
41 * thereof, and that both notices appear in supporting documentation.
42 *
43 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
44 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
45 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 *
47 * Carnegie Mellon requests users of this software to return to
48 *
49 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
50 * School of Computer Science
51 * Carnegie Mellon University
52 * Pittsburgh PA 15213-3890
53 *
54 * any improvements or extensions that they make and grant Carnegie the
55 * rights to redistribute these changes.
56 */
57
58 /*
59 * Instruction disassembler.
60 */
61 #include <sys/param.h>
62
63 #include <ddb/ddb.h>
64 #include <ddb/db_access.h>
65 #include <ddb/db_output.h>
66 #include <ddb/db_sym.h>
67
68 /*
69 * Size attributes
70 */
71 #define BYTE 0
72 #define WORD 1
73 #define LONG 2
74 #define QUAD 3
75 #define SNGL 4
76 #define DBLR 5
77 #define EXTR 6
78 #define SDEP 7
79 #define NONE 8
80
81 /*
82 * REX prefix and bits
83 */
84 #define REX_B 1
85 #define REX_X 2
86 #define REX_R 4
87 #define REX_W 8
88 #define REX 0x40
89
90 /*
91 * Addressing modes
92 */
93 #define E 1 /* general effective address */
94 #define Eind 2 /* indirect address (jump, call) */
95 #define Ew 3 /* address, word size */
96 #define Eb 4 /* address, byte size */
97 #define R 5 /* register, in 'reg' field */
98 #define Rw 6 /* word register, in 'reg' field */
99 #define Ri 7 /* register in instruction */
100 #define S 8 /* segment reg, in 'reg' field */
101 #define Si 9 /* segment reg, in instruction */
102 #define A 10 /* accumulator */
103 #define BX 11 /* (bx) */
104 #define CL 12 /* cl, for shifts */
105 #define DX 13 /* dx, for IO */
106 #define SI 14 /* si */
107 #define DI 15 /* di */
108 #define CR 16 /* control register */
109 #define DR 17 /* debug register */
110 #define TR 18 /* test register */
111 #define I 19 /* immediate, unsigned */
112 #define Is 20 /* immediate, signed */
113 #define Ib 21 /* byte immediate, unsigned */
114 #define Ibs 22 /* byte immediate, signed */
115 #define Iw 23 /* word immediate, unsigned */
116 #define Ilq 24 /* long/quad immediate, unsigned */
117 #define O 25 /* direct address */
118 #define Db 26 /* byte displacement from EIP */
119 #define Dl 27 /* long displacement from EIP */
120 #define o1 28 /* constant 1 */
121 #define o3 29 /* constant 3 */
122 #define OS 30 /* immediate offset/segment */
123 #define ST 31 /* FP stack top */
124 #define STI 32 /* FP stack */
125 #define X 33 /* extended FP op */
126 #define XA 34 /* for 'fstcw %ax' */
127 #define El 35 /* address, long/quad size */
128 #define Ril 36 /* long register in instruction */
129 #define Iba 37 /* byte immediate, don't print if 0xa */
130 #define EL 38 /* address, explicitly long size */
131
132 struct inst {
133 const char * i_name; /* name */
134 short i_has_modrm; /* has regmodrm byte */
135 short i_size; /* operand size */
136 int i_mode; /* addressing modes */
137 const void * i_extra; /* pointer to extra opcode table */
138 };
139
140 #define op1(x) (x)
141 #define op2(x,y) ((x)|((y)<<8))
142 #define op3(x,y,z) ((x)|((y)<<8)|((z)<<16))
143
144 struct finst {
145 const char * f_name; /* name for memory instruction */
146 int f_size; /* size for memory instruction */
147 int f_rrmode; /* mode for rr instruction */
148 const void * f_rrname; /* name for rr instruction
149 (or pointer to table) */
150 };
151
152 static const char * const db_Grp6[] = {
153 "sldt",
154 "str",
155 "lldt",
156 "ltr",
157 "verr",
158 "verw",
159 "",
160 ""
161 };
162
163 static const char * const db_Grp7[] = {
164 "sgdt",
165 "sidt",
166 "lgdt",
167 "lidt",
168 "smsw",
169 "",
170 "lmsw",
171 "invlpg"
172 };
173
174 static const char * const db_Grp7_11_000[] = {
175 "",
176 "vmcall",
177 "vmlaunch",
178 "vmresume",
179 "vmxoff",
180 };
181
182 static const char * const db_Grp7_11_001[] = {
183 "monitor",
184 "mwait",
185 "clac",
186 "stac",
187 };
188
189 static const char * const db_Grp7_11_010[] = {
190 "xgetbv",
191 "xsetbv",
192 "",
193 "",
194 "vmfunc",
195 "xend",
196 "xtest",
197 };
198
199 static const char * const db_Grp7_11_111[] = {
200 "swapgs",
201 "rdtscp",
202 };
203
204 static const char * const* db_Grp7_11[] = {
205 db_Grp7_11_000,
206 db_Grp7_11_001,
207 db_Grp7_11_010,
208 NULL,
209 NULL,
210 db_Grp7_11_111,
211 };
212
213 static const char * const db_Grp8[] = {
214 "",
215 "",
216 "",
217 "",
218 "bt",
219 "bts",
220 "btr",
221 "btc"
222 };
223
224 static const char * const db_Grp9[] = {
225 "",
226 "cmpxchg8b",
227 "",
228 "",
229 "",
230 "",
231 "",
232 ""
233 };
234
235 static const struct inst db_inst_0f0x[] = {
236 /*00*/ { "", TRUE, NONE, op1(Ew), db_Grp6 },
237 /*01*/ { "", TRUE, NONE, op1(Ew), db_Grp7 },
238 /*02*/ { "lar", TRUE, LONG, op2(E,R), 0 },
239 /*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 },
240 /*04*/ { "", FALSE, NONE, 0, 0 },
241 /*05*/ { "", FALSE, NONE, 0, 0 },
242 /*06*/ { "clts", FALSE, NONE, 0, 0 },
243 /*07*/ { "", FALSE, NONE, 0, 0 },
244
245 /*08*/ { "invd", FALSE, NONE, 0, 0 },
246 /*09*/ { "wbinvd",FALSE, NONE, 0, 0 },
247 /*0a*/ { "", FALSE, NONE, 0, 0 },
248 /*0b*/ { "", FALSE, NONE, 0, 0 },
249 /*0c*/ { "", FALSE, NONE, 0, 0 },
250 /*0d*/ { "", FALSE, NONE, 0, 0 },
251 /*0e*/ { "", FALSE, NONE, 0, 0 },
252 /*0f*/ { "", FALSE, NONE, 0, 0 },
253 };
254
255 static const struct inst db_inst_0f2x[] = {
256 /*20*/ { "mov", TRUE, LONG, op2(CR,El), 0 },
257 /*21*/ { "mov", TRUE, LONG, op2(DR,El), 0 },
258 /*22*/ { "mov", TRUE, LONG, op2(El,CR), 0 },
259 /*23*/ { "mov", TRUE, LONG, op2(El,DR), 0 },
260 /*24*/ { "mov", TRUE, LONG, op2(TR,El), 0 },
261 /*25*/ { "", FALSE, NONE, 0, 0 },
262 /*26*/ { "mov", TRUE, LONG, op2(El,TR), 0 },
263 /*27*/ { "", FALSE, NONE, 0, 0 },
264
265 /*28*/ { "", FALSE, NONE, 0, 0 },
266 /*29*/ { "", FALSE, NONE, 0, 0 },
267 /*2a*/ { "", FALSE, NONE, 0, 0 },
268 /*2b*/ { "", FALSE, NONE, 0, 0 },
269 /*2c*/ { "", FALSE, NONE, 0, 0 },
270 /*2d*/ { "", FALSE, NONE, 0, 0 },
271 /*2e*/ { "", FALSE, NONE, 0, 0 },
272 /*2f*/ { "", FALSE, NONE, 0, 0 },
273 };
274
275 static const struct inst db_inst_0f3x[] = {
276 /*30*/ { "wrmsr", FALSE, NONE, 0, 0 },
277 /*31*/ { "rdtsc", FALSE, NONE, 0, 0 },
278 /*32*/ { "rdmsr", FALSE, NONE, 0, 0 },
279 /*33*/ { "rdpmc", FALSE, NONE, 0, 0 },
280 /*34*/ { "", FALSE, NONE, 0, 0 },
281 /*35*/ { "", FALSE, NONE, 0, 0 },
282 /*36*/ { "", FALSE, NONE, 0, 0 },
283 /*37*/ { "", FALSE, NONE, 0, 0 },
284
285 /*38*/ { "", FALSE, NONE, 0, 0 },
286 /*39*/ { "", FALSE, NONE, 0, 0 },
287 /*3a*/ { "", FALSE, NONE, 0, 0 },
288 /*3b*/ { "", FALSE, NONE, 0, 0 },
289 /*3c*/ { "", FALSE, NONE, 0, 0 },
290 /*3d*/ { "", FALSE, NONE, 0, 0 },
291 /*3e*/ { "", FALSE, NONE, 0, 0 },
292 /*3f*/ { "", FALSE, NONE, 0, 0 },
293 };
294
295 static const struct inst db_inst_0f4x[] = {
296 /*40*/ { "cmovo", TRUE, NONE, op2(E, R), 0 },
297 /*41*/ { "cmovno", TRUE, NONE, op2(E, R), 0 },
298 /*42*/ { "cmovb", TRUE, NONE, op2(E, R), 0 },
299 /*43*/ { "cmovnb", TRUE, NONE, op2(E, R), 0 },
300 /*44*/ { "cmovz", TRUE, NONE, op2(E, R), 0 },
301 /*45*/ { "cmovnz", TRUE, NONE, op2(E, R), 0 },
302 /*46*/ { "cmovbe", TRUE, NONE, op2(E, R), 0 },
303 /*47*/ { "cmovnbe",TRUE, NONE, op2(E, R), 0 },
304
305 /*48*/ { "cmovs", TRUE, NONE, op2(E, R), 0 },
306 /*49*/ { "cmovns", TRUE, NONE, op2(E, R), 0 },
307 /*4a*/ { "cmovp", TRUE, NONE, op2(E, R), 0 },
308 /*4b*/ { "cmovnp", TRUE, NONE, op2(E, R), 0 },
309 /*4c*/ { "cmovl", TRUE, NONE, op2(E, R), 0 },
310 /*4d*/ { "cmovnl", TRUE, NONE, op2(E, R), 0 },
311 /*4e*/ { "cmovle", TRUE, NONE, op2(E, R), 0 },
312 /*4f*/ { "cmovnle",TRUE, NONE, op2(E, R), 0 },
313 };
314
315 static const struct inst db_inst_0f8x[] = {
316 /*80*/ { "jo", FALSE, NONE, op1(Dl), 0 },
317 /*81*/ { "jno", FALSE, NONE, op1(Dl), 0 },
318 /*82*/ { "jb", FALSE, NONE, op1(Dl), 0 },
319 /*83*/ { "jnb", FALSE, NONE, op1(Dl), 0 },
320 /*84*/ { "jz", FALSE, NONE, op1(Dl), 0 },
321 /*85*/ { "jnz", FALSE, NONE, op1(Dl), 0 },
322 /*86*/ { "jbe", FALSE, NONE, op1(Dl), 0 },
323 /*87*/ { "jnbe", FALSE, NONE, op1(Dl), 0 },
324
325 /*88*/ { "js", FALSE, NONE, op1(Dl), 0 },
326 /*89*/ { "jns", FALSE, NONE, op1(Dl), 0 },
327 /*8a*/ { "jp", FALSE, NONE, op1(Dl), 0 },
328 /*8b*/ { "jnp", FALSE, NONE, op1(Dl), 0 },
329 /*8c*/ { "jl", FALSE, NONE, op1(Dl), 0 },
330 /*8d*/ { "jnl", FALSE, NONE, op1(Dl), 0 },
331 /*8e*/ { "jle", FALSE, NONE, op1(Dl), 0 },
332 /*8f*/ { "jnle", FALSE, NONE, op1(Dl), 0 },
333 };
334
335 static const struct inst db_inst_0f9x[] = {
336 /*90*/ { "seto", TRUE, NONE, op1(Eb), 0 },
337 /*91*/ { "setno", TRUE, NONE, op1(Eb), 0 },
338 /*92*/ { "setb", TRUE, NONE, op1(Eb), 0 },
339 /*93*/ { "setnb", TRUE, NONE, op1(Eb), 0 },
340 /*94*/ { "setz", TRUE, NONE, op1(Eb), 0 },
341 /*95*/ { "setnz", TRUE, NONE, op1(Eb), 0 },
342 /*96*/ { "setbe", TRUE, NONE, op1(Eb), 0 },
343 /*97*/ { "setnbe",TRUE, NONE, op1(Eb), 0 },
344
345 /*98*/ { "sets", TRUE, NONE, op1(Eb), 0 },
346 /*99*/ { "setns", TRUE, NONE, op1(Eb), 0 },
347 /*9a*/ { "setp", TRUE, NONE, op1(Eb), 0 },
348 /*9b*/ { "setnp", TRUE, NONE, op1(Eb), 0 },
349 /*9c*/ { "setl", TRUE, NONE, op1(Eb), 0 },
350 /*9d*/ { "setnl", TRUE, NONE, op1(Eb), 0 },
351 /*9e*/ { "setle", TRUE, NONE, op1(Eb), 0 },
352 /*9f*/ { "setnle",TRUE, NONE, op1(Eb), 0 },
353 };
354
355 static const struct inst db_inst_0fax[] = {
356 /*a0*/ { "push", FALSE, NONE, op1(Si), 0 },
357 /*a1*/ { "pop", FALSE, NONE, op1(Si), 0 },
358 /*a2*/ { "cpuid", FALSE, NONE, 0, 0 },
359 /*a3*/ { "bt", TRUE, LONG, op2(R,E), 0 },
360 /*a4*/ { "shld", TRUE, LONG, op3(Ib,R,E), 0 },
361 /*a5*/ { "shld", TRUE, LONG, op3(CL,R,E), 0 },
362 /*a6*/ { "", FALSE, NONE, 0, 0 },
363 /*a7*/ { "", FALSE, NONE, 0, 0 },
364
365 /*a8*/ { "push", FALSE, NONE, op1(Si), 0 },
366 /*a9*/ { "pop", FALSE, NONE, op1(Si), 0 },
367 /*aa*/ { "rsm", FALSE, NONE, 0, 0 },
368 /*ab*/ { "bts", TRUE, LONG, op2(R,E), 0 },
369 /*ac*/ { "shrd", TRUE, LONG, op3(Ib,R,E), 0 },
370 /*ad*/ { "shrd", TRUE, LONG, op3(CL,R,E), 0 },
371 /*a6*/ { "", FALSE, NONE, 0, 0 },
372 /*a7*/ { "imul", TRUE, LONG, op2(E,R), 0 },
373 };
374
375 static const struct inst db_inst_0fbx[] = {
376 /*b0*/ { "cmpxchg",TRUE, BYTE, op2(R, E), 0 },
377 /*b0*/ { "cmpxchg",TRUE, LONG, op2(R, E), 0 },
378 /*b2*/ { "lss", TRUE, LONG, op2(E, R), 0 },
379 /*b3*/ { "btr", TRUE, LONG, op2(R, E), 0 },
380 /*b4*/ { "lfs", TRUE, LONG, op2(E, R), 0 },
381 /*b5*/ { "lgs", TRUE, LONG, op2(E, R), 0 },
382 /*b6*/ { "movzb", TRUE, LONG, op2(Eb, R), 0 },
383 /*b7*/ { "movzw", TRUE, LONG, op2(Ew, R), 0 },
384
385 /*b8*/ { "", FALSE, NONE, 0, 0 },
386 /*b9*/ { "", FALSE, NONE, 0, 0 },
387 /*ba*/ { "", TRUE, LONG, op2(Ib, E), db_Grp8 },
388 /*bb*/ { "btc", TRUE, LONG, op2(R, E), 0 },
389 /*bc*/ { "bsf", TRUE, LONG, op2(E, R), 0 },
390 /*bd*/ { "bsr", TRUE, LONG, op2(E, R), 0 },
391 /*be*/ { "movsb", TRUE, LONG, op2(Eb, R), 0 },
392 /*bf*/ { "movsw", TRUE, LONG, op2(Ew, R), 0 },
393 };
394
395 static const struct inst db_inst_0fcx[] = {
396 /*c0*/ { "xadd", TRUE, BYTE, op2(R, E), 0 },
397 /*c1*/ { "xadd", TRUE, LONG, op2(R, E), 0 },
398 /*c2*/ { "", FALSE, NONE, 0, 0 },
399 /*c3*/ { "", FALSE, NONE, 0, 0 },
400 /*c4*/ { "", FALSE, NONE, 0, 0 },
401 /*c5*/ { "", FALSE, NONE, 0, 0 },
402 /*c6*/ { "", FALSE, NONE, 0, 0 },
403 /*c7*/ { "", TRUE, NONE, op1(E), db_Grp9 },
404 /*c8*/ { "bswap", FALSE, LONG, op1(Ril), 0 },
405 /*c9*/ { "bswap", FALSE, LONG, op1(Ril), 0 },
406 /*ca*/ { "bswap", FALSE, LONG, op1(Ril), 0 },
407 /*cb*/ { "bswap", FALSE, LONG, op1(Ril), 0 },
408 /*cc*/ { "bswap", FALSE, LONG, op1(Ril), 0 },
409 /*cd*/ { "bswap", FALSE, LONG, op1(Ril), 0 },
410 /*ce*/ { "bswap", FALSE, LONG, op1(Ril), 0 },
411 /*cf*/ { "bswap", FALSE, LONG, op1(Ril), 0 },
412 };
413
414 static const struct inst * const db_inst_0f[] = {
415 db_inst_0f0x,
416 0,
417 db_inst_0f2x,
418 db_inst_0f3x,
419 db_inst_0f4x,
420 0,
421 0,
422 0,
423 db_inst_0f8x,
424 db_inst_0f9x,
425 db_inst_0fax,
426 db_inst_0fbx,
427 db_inst_0fcx,
428 0,
429 0,
430 0
431 };
432
433 static const char * const db_Esc92[] = {
434 "fnop", "", "", "", "", "", "", ""
435 };
436 static const char * const db_Esc94[] = {
437 "fchs", "fabs", "", "", "ftst", "fxam", "", ""
438 };
439 static const char * const db_Esc95[] = {
440 "fld1", "fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz",""
441 };
442 static const char * const db_Esc96[] = {
443 "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp",
444 "fincstp"
445 };
446 static const char * const db_Esc97[] = {
447 "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"
448 };
449
450 static const char * const db_Esca5[] = {
451 "", "fucompp","", "", "", "", "", ""
452 };
453
454 static const char * const db_Escb4[] = {
455 "fneni","fndisi", "fnclex","fninit","fsetpm", "", "", ""
456 };
457
458 static const char * const db_Esce3[] = {
459 "", "fcompp","", "", "", "", "", ""
460 };
461
462 static const char * const db_Escf4[] = {
463 "fnstsw","", "", "", "", "", "", ""
464 };
465
466 static const struct finst db_Esc8[] = {
467 /*0*/ { "fadd", SNGL, op2(STI,ST), 0 },
468 /*1*/ { "fmul", SNGL, op2(STI,ST), 0 },
469 /*2*/ { "fcom", SNGL, op2(STI,ST), 0 },
470 /*3*/ { "fcomp", SNGL, op2(STI,ST), 0 },
471 /*4*/ { "fsub", SNGL, op2(STI,ST), 0 },
472 /*5*/ { "fsubr", SNGL, op2(STI,ST), 0 },
473 /*6*/ { "fdiv", SNGL, op2(STI,ST), 0 },
474 /*7*/ { "fdivr", SNGL, op2(STI,ST), 0 },
475 };
476
477 static const struct finst db_Esc9[] = {
478 /*0*/ { "fld", SNGL, op1(STI), 0 },
479 /*1*/ { "", NONE, op1(STI), "fxch" },
480 /*2*/ { "fst", SNGL, op1(X), db_Esc92 },
481 /*3*/ { "fstp", SNGL, 0, 0 },
482 /*4*/ { "fldenv", NONE, op1(X), db_Esc94 },
483 /*5*/ { "fldcw", NONE, op1(X), db_Esc95 },
484 /*6*/ { "fnstenv",NONE, op1(X), db_Esc96 },
485 /*7*/ { "fnstcw", NONE, op1(X), db_Esc97 },
486 };
487
488 static const struct finst db_Esca[] = {
489 /*0*/ { "fiadd", LONG, 0, 0 },
490 /*1*/ { "fimul", LONG, 0, 0 },
491 /*2*/ { "ficom", LONG, 0, 0 },
492 /*3*/ { "ficomp", LONG, 0, 0 },
493 /*4*/ { "fisub", LONG, 0, 0 },
494 /*5*/ { "fisubr", LONG, op1(X), db_Esca5 },
495 /*6*/ { "fidiv", LONG, 0, 0 },
496 /*7*/ { "fidivr", LONG, 0, 0 }
497 };
498
499 static const struct finst db_Escb[] = {
500 /*0*/ { "fild", LONG, 0, 0 },
501 /*1*/ { "", NONE, 0, 0 },
502 /*2*/ { "fist", LONG, 0, 0 },
503 /*3*/ { "fistp", LONG, 0, 0 },
504 /*4*/ { "", WORD, op1(X), db_Escb4 },
505 /*5*/ { "fld", EXTR, 0, 0 },
506 /*6*/ { "", WORD, 0, 0 },
507 /*7*/ { "fstp", EXTR, 0, 0 },
508 };
509
510 static const struct finst db_Escc[] = {
511 /*0*/ { "fadd", DBLR, op2(ST,STI), 0 },
512 /*1*/ { "fmul", DBLR, op2(ST,STI), 0 },
513 /*2*/ { "fcom", DBLR, 0, 0 },
514 /*3*/ { "fcomp", DBLR, 0, 0 },
515 /*4*/ { "fsub", DBLR, op2(ST,STI), "fsubr" },
516 /*5*/ { "fsubr", DBLR, op2(ST,STI), "fsub" },
517 /*6*/ { "fdiv", DBLR, op2(ST,STI), "fdivr" },
518 /*7*/ { "fdivr", DBLR, op2(ST,STI), "fdiv" },
519 };
520
521 static const struct finst db_Escd[] = {
522 /*0*/ { "fld", DBLR, op1(STI), "ffree" },
523 /*1*/ { "", NONE, 0, 0 },
524 /*2*/ { "fst", DBLR, op1(STI), 0 },
525 /*3*/ { "fstp", DBLR, op1(STI), 0 },
526 /*4*/ { "frstor", NONE, op1(STI), "fucom" },
527 /*5*/ { "", NONE, op1(STI), "fucomp" },
528 /*6*/ { "fnsave", NONE, 0, 0 },
529 /*7*/ { "fnstsw", NONE, 0, 0 },
530 };
531
532 static const struct finst db_Esce[] = {
533 /*0*/ { "fiadd", WORD, op2(ST,STI), "faddp" },
534 /*1*/ { "fimul", WORD, op2(ST,STI), "fmulp" },
535 /*2*/ { "ficom", WORD, 0, 0 },
536 /*3*/ { "ficomp", WORD, op1(X), db_Esce3 },
537 /*4*/ { "fisub", WORD, op2(ST,STI), "fsubrp" },
538 /*5*/ { "fisubr", WORD, op2(ST,STI), "fsubp" },
539 /*6*/ { "fidiv", WORD, op2(ST,STI), "fdivrp" },
540 /*7*/ { "fidivr", WORD, op2(ST,STI), "fdivp" },
541 };
542
543 static const struct finst db_Escf[] = {
544 /*0*/ { "fild", WORD, 0, 0 },
545 /*1*/ { "", NONE, 0, 0 },
546 /*2*/ { "fist", WORD, 0, 0 },
547 /*3*/ { "fistp", WORD, 0, 0 },
548 /*4*/ { "fbld", NONE, op1(XA), db_Escf4 },
549 /*5*/ { "fild", QUAD, 0, 0 },
550 /*6*/ { "fbstp", NONE, 0, 0 },
551 /*7*/ { "fistp", QUAD, 0, 0 },
552 };
553
554 static const struct finst * const db_Esc_inst[] = {
555 db_Esc8, db_Esc9, db_Esca, db_Escb,
556 db_Escc, db_Escd, db_Esce, db_Escf
557 };
558
559 static const char * const db_Grp1[] = {
560 "add",
561 "or",
562 "adc",
563 "sbb",
564 "and",
565 "sub",
566 "xor",
567 "cmp"
568 };
569
570 static const char * const db_Grp2[] = {
571 "rol",
572 "ror",
573 "rcl",
574 "rcr",
575 "shl",
576 "shr",
577 "shl",
578 "sar"
579 };
580
581 static const struct inst db_Grp3[] = {
582 { "test", TRUE, NONE, op2(I,E), 0 },
583 { "test", TRUE, NONE, op2(I,E), 0 },
584 { "not", TRUE, NONE, op1(E), 0 },
585 { "neg", TRUE, NONE, op1(E), 0 },
586 { "mul", TRUE, NONE, op2(E,A), 0 },
587 { "imul", TRUE, NONE, op2(E,A), 0 },
588 { "div", TRUE, NONE, op2(E,A), 0 },
589 { "idiv", TRUE, NONE, op2(E,A), 0 },
590 };
591
592 static const struct inst db_Grp4[] = {
593 { "inc", TRUE, BYTE, op1(E), 0 },
594 { "dec", TRUE, BYTE, op1(E), 0 },
595 { "", TRUE, NONE, 0, 0 },
596 { "", TRUE, NONE, 0, 0 },
597 { "", TRUE, NONE, 0, 0 },
598 { "", TRUE, NONE, 0, 0 },
599 { "", TRUE, NONE, 0, 0 },
600 { "", TRUE, NONE, 0, 0 }
601 };
602
603 static const struct inst db_Grp5[] = {
604 { "inc", TRUE, LONG, op1(E), 0 },
605 { "dec", TRUE, LONG, op1(E), 0 },
606 { "call", TRUE, LONG, op1(Eind),0 },
607 { "lcall", TRUE, LONG, op1(Eind),0 },
608 { "jmp", TRUE, LONG, op1(Eind),0 },
609 { "ljmp", TRUE, LONG, op1(Eind),0 },
610 { "push", TRUE, LONG, op1(E), 0 },
611 { "", TRUE, NONE, 0, 0 }
612 };
613
614 static const struct inst db_inst_table[256] = {
615 /*00*/ { "add", TRUE, BYTE, op2(R, E), 0 },
616 /*01*/ { "add", TRUE, LONG, op2(R, E), 0 },
617 /*02*/ { "add", TRUE, BYTE, op2(E, R), 0 },
618 /*03*/ { "add", TRUE, LONG, op2(E, R), 0 },
619 /*04*/ { "add", FALSE, BYTE, op2(I, A), 0 },
620 /*05*/ { "add", FALSE, LONG, op2(Is, A), 0 },
621 /*06*/ { "push", FALSE, NONE, op1(Si), 0 },
622 /*07*/ { "pop", FALSE, NONE, op1(Si), 0 },
623
624 /*08*/ { "or", TRUE, BYTE, op2(R, E), 0 },
625 /*09*/ { "or", TRUE, LONG, op2(R, E), 0 },
626 /*0a*/ { "or", TRUE, BYTE, op2(E, R), 0 },
627 /*0b*/ { "or", TRUE, LONG, op2(E, R), 0 },
628 /*0c*/ { "or", FALSE, BYTE, op2(I, A), 0 },
629 /*0d*/ { "or", FALSE, LONG, op2(I, A), 0 },
630 /*0e*/ { "push", FALSE, NONE, op1(Si), 0 },
631 /*0f*/ { "", FALSE, NONE, 0, 0 },
632
633 /*10*/ { "adc", TRUE, BYTE, op2(R, E), 0 },
634 /*11*/ { "adc", TRUE, LONG, op2(R, E), 0 },
635 /*12*/ { "adc", TRUE, BYTE, op2(E, R), 0 },
636 /*13*/ { "adc", TRUE, LONG, op2(E, R), 0 },
637 /*14*/ { "adc", FALSE, BYTE, op2(I, A), 0 },
638 /*15*/ { "adc", FALSE, LONG, op2(Is, A), 0 },
639 /*16*/ { "push", FALSE, NONE, op1(Si), 0 },
640 /*17*/ { "pop", FALSE, NONE, op1(Si), 0 },
641
642 /*18*/ { "sbb", TRUE, BYTE, op2(R, E), 0 },
643 /*19*/ { "sbb", TRUE, LONG, op2(R, E), 0 },
644 /*1a*/ { "sbb", TRUE, BYTE, op2(E, R), 0 },
645 /*1b*/ { "sbb", TRUE, LONG, op2(E, R), 0 },
646 /*1c*/ { "sbb", FALSE, BYTE, op2(I, A), 0 },
647 /*1d*/ { "sbb", FALSE, LONG, op2(Is, A), 0 },
648 /*1e*/ { "push", FALSE, NONE, op1(Si), 0 },
649 /*1f*/ { "pop", FALSE, NONE, op1(Si), 0 },
650
651 /*20*/ { "and", TRUE, BYTE, op2(R, E), 0 },
652 /*21*/ { "and", TRUE, LONG, op2(R, E), 0 },
653 /*22*/ { "and", TRUE, BYTE, op2(E, R), 0 },
654 /*23*/ { "and", TRUE, LONG, op2(E, R), 0 },
655 /*24*/ { "and", FALSE, BYTE, op2(I, A), 0 },
656 /*25*/ { "and", FALSE, LONG, op2(I, A), 0 },
657 /*26*/ { "", FALSE, NONE, 0, 0 },
658 /*27*/ { "daa", FALSE, NONE, 0, 0 },
659
660 /*28*/ { "sub", TRUE, BYTE, op2(R, E), 0 },
661 /*29*/ { "sub", TRUE, LONG, op2(R, E), 0 },
662 /*2a*/ { "sub", TRUE, BYTE, op2(E, R), 0 },
663 /*2b*/ { "sub", TRUE, LONG, op2(E, R), 0 },
664 /*2c*/ { "sub", FALSE, BYTE, op2(I, A), 0 },
665 /*2d*/ { "sub", FALSE, LONG, op2(Is, A), 0 },
666 /*2e*/ { "", FALSE, NONE, 0, 0 },
667 /*2f*/ { "das", FALSE, NONE, 0, 0 },
668
669 /*30*/ { "xor", TRUE, BYTE, op2(R, E), 0 },
670 /*31*/ { "xor", TRUE, LONG, op2(R, E), 0 },
671 /*32*/ { "xor", TRUE, BYTE, op2(E, R), 0 },
672 /*33*/ { "xor", TRUE, LONG, op2(E, R), 0 },
673 /*34*/ { "xor", FALSE, BYTE, op2(I, A), 0 },
674 /*35*/ { "xor", FALSE, LONG, op2(I, A), 0 },
675 /*36*/ { "", FALSE, NONE, 0, 0 },
676 /*37*/ { "aaa", FALSE, NONE, 0, 0 },
677
678 /*38*/ { "cmp", TRUE, BYTE, op2(R, E), 0 },
679 /*39*/ { "cmp", TRUE, LONG, op2(R, E), 0 },
680 /*3a*/ { "cmp", TRUE, BYTE, op2(E, R), 0 },
681 /*3b*/ { "cmp", TRUE, LONG, op2(E, R), 0 },
682 /*3c*/ { "cmp", FALSE, BYTE, op2(I, A), 0 },
683 /*3d*/ { "cmp", FALSE, LONG, op2(Is, A), 0 },
684 /*3e*/ { "", FALSE, NONE, 0, 0 },
685 /*3f*/ { "aas", FALSE, NONE, 0, 0 },
686
687 /*40*/ { "rex", FALSE, NONE, 0, 0 },
688 /*41*/ { "rex.b", FALSE, NONE, 0, 0 },
689 /*42*/ { "rex.x", FALSE, NONE, 0, 0 },
690 /*43*/ { "rex.xb", FALSE, NONE, 0, 0 },
691 /*44*/ { "rex.r", FALSE, NONE, 0, 0 },
692 /*45*/ { "rex.rb", FALSE, NONE, 0, 0 },
693 /*46*/ { "rex.rx", FALSE, NONE, 0, 0 },
694 /*47*/ { "rex.rxb", FALSE, NONE, 0, 0 },
695
696 /*48*/ { "rex.w", FALSE, NONE, 0, 0 },
697 /*49*/ { "rex.wb", FALSE, NONE, 0, 0 },
698 /*4a*/ { "rex.wx", FALSE, NONE, 0, 0 },
699 /*4b*/ { "rex.wxb", FALSE, NONE, 0, 0 },
700 /*4c*/ { "rex.wr", FALSE, NONE, 0, 0 },
701 /*4d*/ { "rex.wrb", FALSE, NONE, 0, 0 },
702 /*4e*/ { "rex.wrx", FALSE, NONE, 0, 0 },
703 /*4f*/ { "rex.wrxb", FALSE, NONE, 0, 0 },
704
705 /*50*/ { "push", FALSE, LONG, op1(Ri), 0 },
706 /*51*/ { "push", FALSE, LONG, op1(Ri), 0 },
707 /*52*/ { "push", FALSE, LONG, op1(Ri), 0 },
708 /*53*/ { "push", FALSE, LONG, op1(Ri), 0 },
709 /*54*/ { "push", FALSE, LONG, op1(Ri), 0 },
710 /*55*/ { "push", FALSE, LONG, op1(Ri), 0 },
711 /*56*/ { "push", FALSE, LONG, op1(Ri), 0 },
712 /*57*/ { "push", FALSE, LONG, op1(Ri), 0 },
713
714 /*58*/ { "pop", FALSE, LONG, op1(Ri), 0 },
715 /*59*/ { "pop", FALSE, LONG, op1(Ri), 0 },
716 /*5a*/ { "pop", FALSE, LONG, op1(Ri), 0 },
717 /*5b*/ { "pop", FALSE, LONG, op1(Ri), 0 },
718 /*5c*/ { "pop", FALSE, LONG, op1(Ri), 0 },
719 /*5d*/ { "pop", FALSE, LONG, op1(Ri), 0 },
720 /*5e*/ { "pop", FALSE, LONG, op1(Ri), 0 },
721 /*5f*/ { "pop", FALSE, LONG, op1(Ri), 0 },
722
723 /*60*/ { "pusha", FALSE, LONG, 0, 0 },
724 /*61*/ { "popa", FALSE, LONG, 0, 0 },
725 /*62*/ { "bound", TRUE, LONG, op2(E, R), 0 },
726 /*63*/ { "movslq", TRUE, NONE, op2(EL,R), 0 },
727
728 /*64*/ { "", FALSE, NONE, 0, 0 },
729 /*65*/ { "", FALSE, NONE, 0, 0 },
730 /*66*/ { "", FALSE, NONE, 0, 0 },
731 /*67*/ { "", FALSE, NONE, 0, 0 },
732
733 /*68*/ { "push", FALSE, LONG, op1(I), 0 },
734 /*69*/ { "imul", TRUE, LONG, op3(I,E,R), 0 },
735 /*6a*/ { "push", FALSE, LONG, op1(Ibs), 0 },
736 /*6b*/ { "imul", TRUE, LONG, op3(Ibs,E,R),0 },
737 /*6c*/ { "ins", FALSE, BYTE, op2(DX, DI), 0 },
738 /*6d*/ { "ins", FALSE, LONG, op2(DX, DI), 0 },
739 /*6e*/ { "outs", FALSE, BYTE, op2(SI, DX), 0 },
740 /*6f*/ { "outs", FALSE, LONG, op2(SI, DX), 0 },
741
742 /*70*/ { "jo", FALSE, NONE, op1(Db), 0 },
743 /*71*/ { "jno", FALSE, NONE, op1(Db), 0 },
744 /*72*/ { "jb", FALSE, NONE, op1(Db), 0 },
745 /*73*/ { "jnb", FALSE, NONE, op1(Db), 0 },
746 /*74*/ { "jz", FALSE, NONE, op1(Db), 0 },
747 /*75*/ { "jnz", FALSE, NONE, op1(Db), 0 },
748 /*76*/ { "jbe", FALSE, NONE, op1(Db), 0 },
749 /*77*/ { "jnbe", FALSE, NONE, op1(Db), 0 },
750
751 /*78*/ { "js", FALSE, NONE, op1(Db), 0 },
752 /*79*/ { "jns", FALSE, NONE, op1(Db), 0 },
753 /*7a*/ { "jp", FALSE, NONE, op1(Db), 0 },
754 /*7b*/ { "jnp", FALSE, NONE, op1(Db), 0 },
755 /*7c*/ { "jl", FALSE, NONE, op1(Db), 0 },
756 /*7d*/ { "jnl", FALSE, NONE, op1(Db), 0 },
757 /*7e*/ { "jle", FALSE, NONE, op1(Db), 0 },
758 /*7f*/ { "jnle", FALSE, NONE, op1(Db), 0 },
759
760 /*80*/ { "", TRUE, BYTE, op2(I, E), db_Grp1 },
761 /*81*/ { "", TRUE, LONG, op2(I, E), db_Grp1 },
762 /*82*/ { "", TRUE, BYTE, op2(I, E), db_Grp1 },
763 /*83*/ { "", TRUE, LONG, op2(Ibs,E), db_Grp1 },
764 /*84*/ { "test", TRUE, BYTE, op2(R, E), 0 },
765 /*85*/ { "test", TRUE, LONG, op2(R, E), 0 },
766 /*86*/ { "xchg", TRUE, BYTE, op2(R, E), 0 },
767 /*87*/ { "xchg", TRUE, LONG, op2(R, E), 0 },
768
769 /*88*/ { "mov", TRUE, BYTE, op2(R, E), 0 },
770 /*89*/ { "mov", TRUE, LONG, op2(R, E), 0 },
771 /*8a*/ { "mov", TRUE, BYTE, op2(E, R), 0 },
772 /*8b*/ { "mov", TRUE, LONG, op2(E, R), 0 },
773 /*8c*/ { "mov", TRUE, NONE, op2(S, Ew), 0 },
774 /*8d*/ { "lea", TRUE, LONG, op2(E, R), 0 },
775 /*8e*/ { "mov", TRUE, NONE, op2(Ew, S), 0 },
776 /*8f*/ { "pop", TRUE, LONG, op1(E), 0 },
777
778 /*90*/ { "nop", FALSE, NONE, 0, 0 },
779 /*91*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
780 /*92*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
781 /*93*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
782 /*94*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
783 /*95*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
784 /*96*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
785 /*97*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
786
787 /*98*/ { "cbw", FALSE, SDEP, 0, "cwde" }, /* cbw/cwde */
788 /*99*/ { "cwd", FALSE, SDEP, 0, "cdq" }, /* cwd/cdq */
789 /*9a*/ { "lcall", FALSE, NONE, op1(OS), 0 },
790 /*9b*/ { "wait", FALSE, NONE, 0, 0 },
791 /*9c*/ { "pushf", FALSE, LONG, 0, 0 },
792 /*9d*/ { "popf", FALSE, LONG, 0, 0 },
793 /*9e*/ { "sahf", FALSE, NONE, 0, 0 },
794 /*9f*/ { "lahf", FALSE, NONE, 0, 0 },
795
796 /*a0*/ { "mov", FALSE, BYTE, op2(O, A), 0 },
797 /*a1*/ { "mov", FALSE, LONG, op2(O, A), 0 },
798 /*a2*/ { "mov", FALSE, BYTE, op2(A, O), 0 },
799 /*a3*/ { "mov", FALSE, LONG, op2(A, O), 0 },
800 /*a4*/ { "movs", FALSE, BYTE, op2(SI,DI), 0 },
801 /*a5*/ { "movs", FALSE, LONG, op2(SI,DI), 0 },
802 /*a6*/ { "cmps", FALSE, BYTE, op2(SI,DI), 0 },
803 /*a7*/ { "cmps", FALSE, LONG, op2(SI,DI), 0 },
804
805 /*a8*/ { "test", FALSE, BYTE, op2(I, A), 0 },
806 /*a9*/ { "test", FALSE, LONG, op2(I, A), 0 },
807 /*aa*/ { "stos", FALSE, BYTE, op1(DI), 0 },
808 /*ab*/ { "stos", FALSE, LONG, op1(DI), 0 },
809 /*ac*/ { "lods", FALSE, BYTE, op1(SI), 0 },
810 /*ad*/ { "lods", FALSE, LONG, op1(SI), 0 },
811 /*ae*/ { "scas", FALSE, BYTE, op1(SI), 0 },
812 /*af*/ { "scas", FALSE, LONG, op1(SI), 0 },
813
814 /*b0*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
815 /*b1*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
816 /*b2*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
817 /*b3*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
818 /*b4*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
819 /*b5*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
820 /*b6*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
821 /*b7*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
822
823 /*b8*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 },
824 /*b9*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 },
825 /*ba*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 },
826 /*bb*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 },
827 /*bc*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 },
828 /*bd*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 },
829 /*be*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 },
830 /*bf*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 },
831
832 /*c0*/ { "", TRUE, BYTE, op2(Ib, E), db_Grp2 },
833 /*c1*/ { "", TRUE, LONG, op2(Ib, E), db_Grp2 },
834 /*c2*/ { "ret", FALSE, NONE, op1(Iw), 0 },
835 /*c3*/ { "ret", FALSE, NONE, 0, 0 },
836 /*c4*/ { "les", TRUE, LONG, op2(E, R), 0 },
837 /*c5*/ { "lds", TRUE, LONG, op2(E, R), 0 },
838 /*c6*/ { "mov", TRUE, BYTE, op2(I, E), 0 },
839 /*c7*/ { "mov", TRUE, LONG, op2(I, E), 0 },
840
841 /*c8*/ { "enter", FALSE, NONE, op2(Iw, Ib), 0 },
842 /*c9*/ { "leave", FALSE, NONE, 0, 0 },
843 /*ca*/ { "lret", FALSE, NONE, op1(Iw), 0 },
844 /*cb*/ { "lret", FALSE, NONE, 0, 0 },
845 /*cc*/ { "int", FALSE, NONE, op1(o3), 0 },
846 /*cd*/ { "int", FALSE, NONE, op1(Ib), 0 },
847 /*ce*/ { "into", FALSE, NONE, 0, 0 },
848 /*cf*/ { "iret", FALSE, NONE, 0, 0 },
849
850 /*d0*/ { "", TRUE, BYTE, op2(o1, E), db_Grp2 },
851 /*d1*/ { "", TRUE, LONG, op2(o1, E), db_Grp2 },
852 /*d2*/ { "", TRUE, BYTE, op2(CL, E), db_Grp2 },
853 /*d3*/ { "", TRUE, LONG, op2(CL, E), db_Grp2 },
854 /*d4*/ { "aam", FALSE, NONE, op1(Iba), 0 },
855 /*d5*/ { "aad", FALSE, NONE, op1(Iba), 0 },
856 /*d6*/ { ".byte\t0xd6", FALSE, NONE, 0, 0 },
857 /*d7*/ { "xlat", FALSE, BYTE, op1(BX), 0 },
858
859 /*d8*/ { "", TRUE, NONE, 0, db_Esc8 },
860 /*d9*/ { "", TRUE, NONE, 0, db_Esc9 },
861 /*da*/ { "", TRUE, NONE, 0, db_Esca },
862 /*db*/ { "", TRUE, NONE, 0, db_Escb },
863 /*dc*/ { "", TRUE, NONE, 0, db_Escc },
864 /*dd*/ { "", TRUE, NONE, 0, db_Escd },
865 /*de*/ { "", TRUE, NONE, 0, db_Esce },
866 /*df*/ { "", TRUE, NONE, 0, db_Escf },
867
868 /*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 },
869 /*e1*/ { "loope", FALSE, NONE, op1(Db), 0 },
870 /*e2*/ { "loop", FALSE, NONE, op1(Db), 0 },
871 /*e3*/ { "jcxz", FALSE, SDEP, op1(Db), "jecxz" },
872 /*e4*/ { "in", FALSE, BYTE, op2(Ib, A), 0 },
873 /*e5*/ { "in", FALSE, LONG, op2(Ib, A) , 0 },
874 /*e6*/ { "out", FALSE, BYTE, op2(A, Ib), 0 },
875 /*e7*/ { "out", FALSE, LONG, op2(A, Ib) , 0 },
876
877 /*e8*/ { "call", FALSE, NONE, op1(Dl), 0 },
878 /*e9*/ { "jmp", FALSE, NONE, op1(Dl), 0 },
879 /*ea*/ { "ljmp", FALSE, NONE, op1(OS), 0 },
880 /*eb*/ { "jmp", FALSE, NONE, op1(Db), 0 },
881 /*ec*/ { "in", FALSE, BYTE, op2(DX, A), 0 },
882 /*ed*/ { "in", FALSE, LONG, op2(DX, A) , 0 },
883 /*ee*/ { "out", FALSE, BYTE, op2(A, DX), 0 },
884 /*ef*/ { "out", FALSE, LONG, op2(A, DX) , 0 },
885
886 /*f0*/ { "", FALSE, NONE, 0, 0 },
887 /*f1*/ { ".byte\t0xf1", FALSE, NONE, 0, 0 },
888 /*f2*/ { "", FALSE, NONE, 0, 0 },
889 /*f3*/ { "", FALSE, NONE, 0, 0 },
890 /*f4*/ { "hlt", FALSE, NONE, 0, 0 },
891 /*f5*/ { "cmc", FALSE, NONE, 0, 0 },
892 /*f6*/ { "", TRUE, BYTE, 0, db_Grp3 },
893 /*f7*/ { "", TRUE, LONG, 0, db_Grp3 },
894
895 /*f8*/ { "clc", FALSE, NONE, 0, 0 },
896 /*f9*/ { "stc", FALSE, NONE, 0, 0 },
897 /*fa*/ { "cli", FALSE, NONE, 0, 0 },
898 /*fb*/ { "sti", FALSE, NONE, 0, 0 },
899 /*fc*/ { "cld", FALSE, NONE, 0, 0 },
900 /*fd*/ { "std", FALSE, NONE, 0, 0 },
901 /*fe*/ { "", TRUE, NONE, 0, db_Grp4 },
902 /*ff*/ { "", TRUE, NONE, 0, db_Grp5 },
903 };
904
905 static const struct inst db_bad_inst = { "???", FALSE, NONE, 0, 0 };
906
907 #define f_mod(rex, byte) ((byte)>>6)
908 #define f_reg(rex, byte) ((((byte)>>3)&0x7) | (rex & REX_R ? 0x8 : 0x0))
909 #define f_rm(rex, byte) (((byte)&0x7) | (rex & REX_B ? 0x8 : 0x0))
910
911 #define sib_ss(rex, byte) ((byte)>>6)
912 #define sib_index(rex, byte) ((((byte)>>3)&0x7) | (rex & REX_X ? 0x8 : 0x0))
913 #define sib_base(rex, byte) (((byte)&0x7) | (rex & REX_B ? 0x8 : 0x0))
914
915 struct i_addr {
916 int is_reg; /* if reg, reg number is in 'disp' */
917 int disp;
918 const char * base;
919 const char * index;
920 int ss;
921 };
922
923 static const char * const db_reg[2][4][16] = {
924
925 {{"%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh",
926 "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" },
927 { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
928 "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" },
929 { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
930 "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" },
931 { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
932 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" }},
933
934 {{"%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil",
935 "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" },
936 { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
937 "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" },
938 { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
939 "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" },
940 { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
941 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" }}
942 };
943
944 static const char * const db_seg_reg[8] = {
945 "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "", ""
946 };
947
948 /*
949 * lengths for size attributes
950 */
951 static const int db_lengths[] = {
952 1, /* BYTE */
953 2, /* WORD */
954 4, /* LONG */
955 8, /* QUAD */
956 4, /* SNGL */
957 8, /* DBLR */
958 10, /* EXTR */
959 };
960
961 #define get_value_inc(result, loc, size, is_signed) \
962 result = db_get_value((loc), (size), (is_signed)); \
963 (loc) += (size);
964
965 static db_addr_t
966 db_disasm_esc(db_addr_t loc, int inst, int rex, int short_addr,
967 int size, const char *seg);
968 static void db_print_address(const char *seg, int size, int rex,
969 struct i_addr *addrp);
970 static db_addr_t
971 db_read_address(db_addr_t loc, int short_addr, int rex, int regmodrm,
972 struct i_addr *addrp);
973
974 /*
975 * Read address at location and return updated location.
976 */
977 static db_addr_t
db_read_address(db_addr_t loc,int short_addr,int rex,int regmodrm,struct i_addr * addrp)978 db_read_address(db_addr_t loc, int short_addr, int rex, int regmodrm,
979 struct i_addr *addrp)
980 {
981 int mod, rm, sib, index, disp, size, have_sib;
982
983 mod = f_mod(rex, regmodrm);
984 rm = f_rm(rex, regmodrm);
985
986 if (mod == 3) {
987 addrp->is_reg = TRUE;
988 addrp->disp = rm;
989 return (loc);
990 }
991 addrp->is_reg = FALSE;
992 addrp->index = NULL;
993
994 if (short_addr)
995 size = LONG;
996 else
997 size = QUAD;
998
999 if ((rm & 0x7) == 4) {
1000 get_value_inc(sib, loc, 1, FALSE);
1001 rm = sib_base(rex, sib);
1002 index = sib_index(rex, sib);
1003 if (index != 4)
1004 addrp->index = db_reg[1][size][index];
1005 addrp->ss = sib_ss(rex, sib);
1006 have_sib = 1;
1007 } else
1008 have_sib = 0;
1009
1010 switch (mod) {
1011 case 0:
1012 if (rm == 5) {
1013 get_value_inc(addrp->disp, loc, 4, FALSE);
1014 if (have_sib)
1015 addrp->base = NULL;
1016 else if (short_addr)
1017 addrp->base = "%eip";
1018 else
1019 addrp->base = "%rip";
1020 } else {
1021 addrp->disp = 0;
1022 addrp->base = db_reg[1][size][rm];
1023 }
1024 break;
1025
1026 case 1:
1027 get_value_inc(disp, loc, 1, TRUE);
1028 addrp->disp = disp;
1029 addrp->base = db_reg[1][size][rm];
1030 break;
1031
1032 case 2:
1033 get_value_inc(disp, loc, 4, FALSE);
1034 addrp->disp = disp;
1035 addrp->base = db_reg[1][size][rm];
1036 break;
1037 }
1038 return (loc);
1039 }
1040
1041 static void
db_print_address(const char * seg,int size,int rex,struct i_addr * addrp)1042 db_print_address(const char *seg, int size, int rex, struct i_addr *addrp)
1043 {
1044 if (addrp->is_reg) {
1045 db_printf("%s", db_reg[rex != 0 ? 1 : 0][(size == LONG && (rex & REX_W)) ? QUAD : size][addrp->disp]);
1046 return;
1047 }
1048
1049 if (seg) {
1050 db_printf("%s:", seg);
1051 }
1052
1053 if (addrp->disp != 0 || (addrp->base == NULL && addrp->index == NULL))
1054 db_printsym((db_addr_t)addrp->disp, DB_STGY_ANY);
1055 if (addrp->base != NULL || addrp->index != NULL) {
1056 db_printf("(");
1057 if (addrp->base)
1058 db_printf("%s", addrp->base);
1059 if (addrp->index)
1060 db_printf(",%s,%d", addrp->index, 1<<addrp->ss);
1061 db_printf(")");
1062 }
1063 }
1064
1065 /*
1066 * Disassemble floating-point ("escape") instruction
1067 * and return updated location.
1068 */
1069 static db_addr_t
db_disasm_esc(db_addr_t loc,int inst,int rex,int short_addr,int size,const char * seg)1070 db_disasm_esc(db_addr_t loc, int inst, int rex, int short_addr, int size,
1071 const char *seg)
1072 {
1073 int regmodrm;
1074 const struct finst * fp;
1075 int mod;
1076 struct i_addr address = { 0 };
1077 const char * name;
1078
1079 get_value_inc(regmodrm, loc, 1, FALSE);
1080 fp = &db_Esc_inst[inst - 0xd8][f_reg(rex, regmodrm)];
1081 mod = f_mod(rex, regmodrm);
1082 if (mod != 3) {
1083 if (*fp->f_name == '\0') {
1084 db_printf("<bad instruction>");
1085 return (loc);
1086 }
1087 /*
1088 * Normal address modes.
1089 */
1090 loc = db_read_address(loc, short_addr, rex, regmodrm, &address);
1091 db_printf("%s", fp->f_name);
1092 switch(fp->f_size) {
1093 case SNGL:
1094 db_printf("s");
1095 break;
1096 case DBLR:
1097 db_printf("l");
1098 break;
1099 case EXTR:
1100 db_printf("t");
1101 break;
1102 case WORD:
1103 db_printf("s");
1104 break;
1105 case LONG:
1106 db_printf("l");
1107 break;
1108 case QUAD:
1109 db_printf("q");
1110 break;
1111 default:
1112 break;
1113 }
1114 db_printf("\t");
1115 db_print_address(seg, BYTE, rex, &address);
1116 }
1117 else {
1118 /*
1119 * 'reg-reg' - special formats
1120 */
1121 switch (fp->f_rrmode) {
1122 case op2(ST,STI):
1123 name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
1124 db_printf("%s\t%%st,%%st(%d)",name,f_rm(rex, regmodrm));
1125 break;
1126 case op2(STI,ST):
1127 name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
1128 db_printf("%s\t%%st(%d),%%st",name, f_rm(rex, regmodrm));
1129 break;
1130 case op1(STI):
1131 name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
1132 db_printf("%s\t%%st(%d)",name, f_rm(rex, regmodrm));
1133 break;
1134 case op1(X):
1135 name = ((const char * const *)fp->f_rrname)[f_rm(rex, regmodrm)];
1136 if (*name == '\0')
1137 goto bad;
1138 db_printf("%s", name);
1139 break;
1140 case op1(XA):
1141 name = ((const char * const *)fp->f_rrname)[f_rm(rex, regmodrm)];
1142 if (*name == '\0')
1143 goto bad;
1144 db_printf("%s\t%%ax", name);
1145 break;
1146 default:
1147 bad:
1148 db_printf("<bad instruction>");
1149 break;
1150 }
1151 }
1152
1153 return (loc);
1154 }
1155
1156 /*
1157 * Disassemble instruction at 'loc'. 'altfmt' specifies an
1158 * (optional) alternate format. Return address of start of
1159 * next instruction.
1160 */
1161 db_addr_t
db_disasm(db_addr_t loc,boolean_t altfmt,db_regs_t * dummy)1162 db_disasm(db_addr_t loc, boolean_t altfmt, db_regs_t *dummy)
1163 {
1164 int inst;
1165 int size;
1166 int short_addr;
1167 const char * seg;
1168 const struct inst * ip;
1169 const char * i_name;
1170 int i_size;
1171 int i_mode;
1172 int rex = 0;
1173 int regmodrm = 0;
1174 boolean_t first;
1175 int displ;
1176 int prefix;
1177 int imm;
1178 int imm2;
1179 long imm64;
1180 int len;
1181 struct i_addr address = { 0 };
1182
1183 get_value_inc(inst, loc, 1, FALSE);
1184 short_addr = FALSE;
1185 size = LONG;
1186 seg = NULL;
1187
1188 /*
1189 * Get prefixes
1190 */
1191 prefix = TRUE;
1192 do {
1193 switch (inst) {
1194 case 0x66: /* data16 */
1195 size = WORD;
1196 break;
1197 case 0x67:
1198 short_addr = TRUE;
1199 break;
1200 case 0x26:
1201 seg = "%es";
1202 break;
1203 case 0x36:
1204 seg = "%ss";
1205 break;
1206 case 0x2e:
1207 seg = "%cs";
1208 break;
1209 case 0x3e:
1210 seg = "%ds";
1211 break;
1212 case 0x64:
1213 seg = "%fs";
1214 break;
1215 case 0x65:
1216 seg = "%gs";
1217 break;
1218 case 0xf0:
1219 db_printf("lock ");
1220 break;
1221 case 0xf2:
1222 db_printf("repne ");
1223 break;
1224 case 0xf3:
1225 db_printf("repe "); /* XXX repe VS rep */
1226 break;
1227 default:
1228 prefix = FALSE;
1229 break;
1230 }
1231 if (inst >= 0x40 && inst < 0x50) {
1232 rex = inst;
1233 prefix = TRUE;
1234 }
1235 if (prefix) {
1236 get_value_inc(inst, loc, 1, FALSE);
1237 }
1238 } while (prefix);
1239
1240 if (inst >= 0xd8 && inst <= 0xdf) {
1241 loc = db_disasm_esc(loc, inst, rex, short_addr, size, seg);
1242 db_printf("\n");
1243 return (loc);
1244 }
1245
1246 if (inst == 0x0f) {
1247 get_value_inc(inst, loc, 1, FALSE);
1248 ip = db_inst_0f[inst>>4];
1249 if (ip == NULL) {
1250 ip = &db_bad_inst;
1251 }
1252 else {
1253 ip = &ip[inst&0xf];
1254 }
1255 }
1256 else
1257 ip = &db_inst_table[inst];
1258
1259 if (ip->i_has_modrm) {
1260 get_value_inc(regmodrm, loc, 1, FALSE);
1261 loc = db_read_address(loc, short_addr, rex, regmodrm, &address);
1262 }
1263
1264 i_name = ip->i_name;
1265 i_size = ip->i_size;
1266 i_mode = ip->i_mode;
1267
1268 if (ip->i_extra == db_Grp1 || ip->i_extra == db_Grp2 ||
1269 ip->i_extra == db_Grp6 || ip->i_extra == db_Grp8 ||
1270 ip->i_extra == db_Grp9) {
1271 i_name = ((const char * const *)ip->i_extra)[f_reg(rex, regmodrm)];
1272 }
1273 else if (ip->i_extra == db_Grp7) {
1274 if((regmodrm & 0xC0) == 0xC0) {
1275 i_name = db_Grp7_11[f_reg(rex, regmodrm)][regmodrm &0x7];
1276 i_mode = 0;
1277 }
1278 else {
1279 i_name = ((const char * const *)ip->i_extra)[f_reg(rex, regmodrm)];
1280 }
1281 }
1282 else if (ip->i_extra == db_Grp3) {
1283 ip = ip->i_extra;
1284 ip = &ip[f_reg(rex, regmodrm)];
1285 i_name = ip->i_name;
1286 i_mode = ip->i_mode;
1287 }
1288 else if (ip->i_extra == db_Grp4 || ip->i_extra == db_Grp5) {
1289 ip = ip->i_extra;
1290 ip = &ip[f_reg(rex, regmodrm)];
1291 i_name = ip->i_name;
1292 i_mode = ip->i_mode;
1293 i_size = ip->i_size;
1294 }
1295
1296 if (i_size == SDEP) {
1297 if (size == WORD)
1298 db_printf("%s", i_name);
1299 else
1300 db_printf("%s", (const char *)ip->i_extra);
1301 }
1302 else {
1303 db_printf("%s", i_name);
1304 if ((inst >= 0x50 && inst <= 0x5f) || inst == 0x68 || inst == 0x6a) {
1305 i_size = NONE;
1306 db_printf("q");
1307 }
1308 if (i_size != NONE) {
1309 if (i_size == BYTE) {
1310 db_printf("b");
1311 size = BYTE;
1312 }
1313 else if (i_size == WORD) {
1314 db_printf("w");
1315 size = WORD;
1316 }
1317 else if (size == WORD)
1318 db_printf("w");
1319 else {
1320 if (rex & REX_W)
1321 db_printf("q");
1322 else
1323 db_printf("l");
1324 }
1325 }
1326 }
1327 db_printf("\t");
1328 for (first = TRUE;
1329 i_mode != 0;
1330 i_mode >>= 8, first = FALSE)
1331 {
1332 char tbuf[24];
1333
1334 if (!first)
1335 db_printf(",");
1336
1337 switch (i_mode & 0xFF) {
1338
1339 case E:
1340 db_print_address(seg, size, rex, &address);
1341 break;
1342
1343 case Eind:
1344 db_printf("*");
1345 db_print_address(seg, size, rex, &address);
1346 break;
1347
1348 case El:
1349 db_print_address(seg, (rex & REX_W) ? QUAD : LONG, rex, &address);
1350 break;
1351
1352 case EL:
1353 db_print_address(seg, LONG, 0, &address);
1354 break;
1355
1356 case Ew:
1357 db_print_address(seg, WORD, rex, &address);
1358 break;
1359
1360 case Eb:
1361 db_print_address(seg, BYTE, rex, &address);
1362 break;
1363
1364 case R:
1365 db_printf("%s", db_reg[rex != 0 ? 1 : 0][(size == LONG && (rex & REX_W)) ? QUAD : size][f_reg(rex, regmodrm)]);
1366 break;
1367
1368 case Rw:
1369 db_printf("%s", db_reg[rex != 0 ? 1 : 0][WORD][f_reg(rex, regmodrm)]);
1370 break;
1371
1372 case Ri:
1373 db_printf("%s", db_reg[0][QUAD][f_rm(rex, inst)]);
1374 break;
1375
1376 case Ril:
1377 db_printf("%s", db_reg[rex != 0 ? 1 : 0][(rex & REX_R) ? QUAD : LONG][f_rm(rex, inst)]);
1378 break;
1379
1380 case S:
1381 db_printf("%s", db_seg_reg[f_reg(rex, regmodrm)]);
1382 break;
1383
1384 case Si:
1385 db_printf("%s", db_seg_reg[f_reg(rex, inst)]);
1386 break;
1387
1388 case A:
1389 db_printf("%s", db_reg[rex != 0 ? 1 : 0][size][0]); /* acc */
1390 break;
1391
1392 case BX:
1393 if (seg)
1394 db_printf("%s:", seg);
1395 db_printf("(%s)", short_addr ? "%bx" : "%ebx");
1396 break;
1397
1398 case CL:
1399 db_printf("%%cl");
1400 break;
1401
1402 case DX:
1403 db_printf("%%dx");
1404 break;
1405
1406 case SI:
1407 if (seg)
1408 db_printf("%s:", seg);
1409 db_printf("(%s)", short_addr ? "%si" : "%rsi");
1410 break;
1411
1412 case DI:
1413 db_printf("%%es:(%s)", short_addr ? "%di" : "%rdi");
1414 break;
1415
1416 case CR:
1417 db_printf("%%cr%d", f_reg(rex, regmodrm));
1418 break;
1419
1420 case DR:
1421 db_printf("%%dr%d", f_reg(rex, regmodrm));
1422 break;
1423
1424 case TR:
1425 db_printf("%%tr%d", f_reg(rex, regmodrm));
1426 break;
1427
1428 case I:
1429 len = db_lengths[size];
1430 get_value_inc(imm, loc, len, FALSE); /* unsigned */
1431 db_format_radix(tbuf, 24, (unsigned int)imm, true);
1432 db_printf("$%s", tbuf);
1433 break;
1434
1435 case Is:
1436 len = db_lengths[(size == LONG && (rex & REX_W)) ? QUAD : size];
1437 get_value_inc(imm, loc, len, TRUE); /* signed */
1438 db_format_radix(tbuf, 24, imm, TRUE);
1439 db_printf("$%s", tbuf);
1440 break;
1441
1442 case Ib:
1443 get_value_inc(imm, loc, 1, FALSE); /* unsigned */
1444 db_format_radix(tbuf, 24, (unsigned int)imm, TRUE);
1445 db_printf("$%s", tbuf);
1446 break;
1447
1448 case Iba:
1449 get_value_inc(imm, loc, 1, FALSE);
1450 if (imm != 0x0a) {
1451 db_format_radix(tbuf, 24, (unsigned int)imm, TRUE);
1452 db_printf("$%s", tbuf);
1453 }
1454 break;
1455
1456 case Ibs:
1457 get_value_inc(imm, loc, 1, TRUE); /* signed */
1458 if (size == WORD)
1459 imm &= 0xFFFF;
1460 db_format_radix(tbuf, 24, imm, TRUE);
1461 db_printf("$%s", tbuf);
1462 break;
1463
1464 case Iw:
1465 get_value_inc(imm, loc, 2, FALSE); /* unsigned */
1466 db_format_radix(tbuf, 24, (unsigned int)imm, TRUE);
1467 db_printf("$%s", tbuf);
1468 break;
1469
1470 case Ilq:
1471 len = db_lengths[rex & REX_W ? QUAD : LONG];
1472 get_value_inc(imm64, loc, len, FALSE);
1473 db_format_radix(tbuf, 24, imm64, TRUE);
1474 db_printf("$%s", tbuf);
1475 break;
1476
1477 case O:
1478 len = (short_addr ? 2 : 4);
1479 get_value_inc(displ, loc, len, FALSE);
1480 if (seg) {
1481 db_format_radix(tbuf, 24, displ, TRUE);
1482 db_printf("%s:%s", seg, tbuf);
1483 }
1484 else
1485 db_printsym((db_addr_t)displ, DB_STGY_ANY);
1486 break;
1487
1488 case Db:
1489 get_value_inc(displ, loc, 1, TRUE);
1490 displ += loc;
1491 if (size == WORD)
1492 displ &= 0xFFFF;
1493 db_printsym((db_addr_t)displ, DB_STGY_XTRN);
1494 break;
1495
1496 case Dl:
1497 len = db_lengths[(size == LONG && (rex & REX_W)) ? QUAD : size];
1498 get_value_inc(displ, loc, len, FALSE);
1499 displ += loc;
1500 if (size == WORD)
1501 displ &= 0xFFFF;
1502 db_printsym((db_addr_t)displ, DB_STGY_XTRN);
1503 break;
1504
1505 case o1:
1506 db_printf("$1");
1507 break;
1508
1509 case o3:
1510 db_printf("$3");
1511 break;
1512
1513 case OS:
1514 len = db_lengths[size];
1515 get_value_inc(imm, loc, len, FALSE); /* offset */
1516 get_value_inc(imm2, loc, 2, FALSE); /* segment */
1517 db_format_radix(tbuf, 24, (unsigned int)imm, TRUE);
1518 db_printf("$%s", tbuf);
1519 db_format_radix(tbuf, 24, (unsigned int)imm2, TRUE);
1520 db_printf(",%s", tbuf);
1521 break;
1522 }
1523 }
1524 db_printf("\n");
1525 return (loc);
1526 }
1527