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