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