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