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