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