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