diff options
author | jhb <jhb@FreeBSD.org> | 2008-08-11 20:19:42 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-08-11 20:19:42 +0000 |
commit | 7109016dfefb93289c49d2b57bc01804c1ceaf04 (patch) | |
tree | 1ca977ac3788d5ff41fd77d4be63895765b59d49 | |
parent | 4c2ecbd8bd352951ebc3b34777ff61daf6b3f219 (diff) | |
download | FreeBSD-src-7109016dfefb93289c49d2b57bc01804c1ceaf04.zip FreeBSD-src-7109016dfefb93289c49d2b57bc01804c1ceaf04.tar.gz |
Decode some more "exotic" instructions including: fxsave, fxrstor, ldmxcsr,
stmxcsr, clflush, lfence, mfence, sfence, syscall, sysret, sysenter,
sysexit, pause, monitor, mwait, and swapgs (amd64 only).
MFC after: 1 week
-rw-r--r-- | sys/amd64/amd64/db_disasm.c | 77 | ||||
-rw-r--r-- | sys/i386/i386/db_disasm.c | 72 |
2 files changed, 131 insertions, 18 deletions
diff --git a/sys/amd64/amd64/db_disasm.c b/sys/amd64/amd64/db_disasm.c index ab7aa49..a6dbf69 100644 --- a/sys/amd64/amd64/db_disasm.c +++ b/sys/amd64/amd64/db_disasm.c @@ -164,15 +164,37 @@ static const char * const db_Grp9[] = { "" }; +static const char * const db_Grp15[] = { + "fxsave", + "fxrstor", + "ldmxcsr", + "stmxcsr", + "", + "", + "", + "clflush" +}; + +static const char * const db_Grp15b[] = { + "", + "", + "", + "", + "", + "lfence", + "mfence", + "sfence" +}; + static const struct inst db_inst_0f0x[] = { /*00*/ { "", TRUE, NONE, op1(Ew), db_Grp6 }, /*01*/ { "", TRUE, NONE, op1(Ew), db_Grp7 }, /*02*/ { "lar", TRUE, LONG, op2(E,R), 0 }, /*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 }, /*04*/ { "", FALSE, NONE, 0, 0 }, -/*05*/ { "", FALSE, NONE, 0, 0 }, +/*05*/ { "syscall",FALSE,NONE, 0, 0 }, /*06*/ { "clts", FALSE, NONE, 0, 0 }, -/*07*/ { "", FALSE, NONE, 0, 0 }, +/*07*/ { "sysret",FALSE, NONE, 0, 0 }, /*08*/ { "invd", FALSE, NONE, 0, 0 }, /*09*/ { "wbinvd",FALSE, NONE, 0, 0 }, @@ -209,10 +231,10 @@ static const struct inst db_inst_0f3x[] = { /*31*/ { "rdtsc", FALSE, NONE, 0, 0 }, /*32*/ { "rdmsr", FALSE, NONE, 0, 0 }, /*33*/ { "rdpmc", FALSE, NONE, 0, 0 }, -/*34*/ { "", FALSE, NONE, 0, 0 }, -/*35*/ { "", FALSE, NONE, 0, 0 }, +/*34*/ { "sysenter",FALSE,NONE, 0, 0 }, +/*35*/ { "sysexit",FALSE,NONE, 0, 0 }, /*36*/ { "", FALSE, NONE, 0, 0 }, -/*37*/ { "", FALSE, NONE, 0, 0 }, +/*37*/ { "getsec",FALSE, NONE, 0, 0 }, /*38*/ { "", FALSE, NONE, 0, 0 }, /*39*/ { "", FALSE, NONE, 0, 0 }, @@ -300,8 +322,8 @@ static const struct inst db_inst_0fax[] = { /*ab*/ { "bts", TRUE, LONG, op2(R,E), 0 }, /*ac*/ { "shrd", TRUE, LONG, op3(Ib,R,E), 0 }, /*ad*/ { "shrd", TRUE, LONG, op3(CL,R,E), 0 }, -/*a6*/ { "", FALSE, NONE, 0, 0 }, -/*a7*/ { "imul", TRUE, LONG, op2(E,R), 0 }, +/*ae*/ { "", TRUE, LONG, op1(E), db_Grp15 }, +/*af*/ { "imul", TRUE, LONG, op2(E,R), 0 }, }; static const struct inst db_inst_0fbx[] = { @@ -1123,6 +1145,7 @@ db_disasm(loc, altfmt) boolean_t first; int displ; int prefix; + int rep; int imm; int imm2; long imm64; @@ -1137,6 +1160,7 @@ db_disasm(loc, altfmt) /* * Get prefixes */ + rep = FALSE; prefix = TRUE; do { switch (inst) { @@ -1171,7 +1195,7 @@ db_disasm(loc, altfmt) db_printf("repne "); break; case 0xf3: - db_printf("repe "); /* XXX repe VS rep */ + rep = TRUE; break; default: prefix = FALSE; @@ -1184,6 +1208,14 @@ db_disasm(loc, altfmt) if (prefix) { get_value_inc(inst, loc, 1, FALSE); } + if (rep == TRUE) { + if (inst == 0x90) { + db_printf("pause\n"); + return (loc); + } + db_printf("repe "); /* XXX repe VS rep */ + rep = FALSE; + } } while (prefix); if (inst >= 0xd8 && inst <= 0xdf) { @@ -1216,7 +1248,8 @@ db_disasm(loc, altfmt) if (ip->i_extra == db_Grp1 || ip->i_extra == db_Grp2 || ip->i_extra == db_Grp6 || ip->i_extra == db_Grp7 || - ip->i_extra == db_Grp8 || ip->i_extra == db_Grp9) { + ip->i_extra == db_Grp8 || ip->i_extra == db_Grp9 || + ip->i_extra == db_Grp15) { i_name = ((const char * const *)ip->i_extra)[f_reg(rex, regmodrm)]; } else if (ip->i_extra == db_Grp3) { @@ -1233,6 +1266,32 @@ db_disasm(loc, altfmt) i_size = ip->i_size; } + /* Special cases that don't fit well in the tables. */ + if (ip->i_extra == db_Grp7 && f_mod(rex, regmodrm) == 3) { + switch (regmodrm) { + case 0xc8: + i_name = "monitor"; + i_size = NONE; + i_mode = 0; + break; + case 0xc9: + i_name = "mwait"; + i_size = NONE; + i_mode = 0; + break; + case 0xf8: + i_name = "swapgs"; + i_size = NONE; + i_mode = 0; + break; + } + } + if (ip->i_extra == db_Grp15 && f_mod(rex, regmodrm) == 3) { + i_name = db_Grp15b[f_reg(rex, regmodrm)]; + i_size = NONE; + i_mode = 0; + } + if (i_size == SDEP) { if (size == WORD) db_printf("%s", i_name); diff --git a/sys/i386/i386/db_disasm.c b/sys/i386/i386/db_disasm.c index b193314..719c9f7 100644 --- a/sys/i386/i386/db_disasm.c +++ b/sys/i386/i386/db_disasm.c @@ -153,15 +153,37 @@ static const char * const db_Grp9[] = { "" }; +static const char * const db_Grp15[] = { + "fxsave", + "fxrstor", + "ldmxcsr", + "stmxcsr", + "", + "", + "", + "clflush" +}; + +static const char * const db_Grp15b[] = { + "", + "", + "", + "", + "", + "lfence", + "mfence", + "sfence" +}; + static const struct inst db_inst_0f0x[] = { /*00*/ { "", TRUE, NONE, op1(Ew), db_Grp6 }, /*01*/ { "", TRUE, NONE, op1(Ew), db_Grp7 }, /*02*/ { "lar", TRUE, LONG, op2(E,R), 0 }, /*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 }, /*04*/ { "", FALSE, NONE, 0, 0 }, -/*05*/ { "", FALSE, NONE, 0, 0 }, +/*05*/ { "syscall",FALSE,NONE, 0, 0 }, /*06*/ { "clts", FALSE, NONE, 0, 0 }, -/*07*/ { "", FALSE, NONE, 0, 0 }, +/*07*/ { "sysret",FALSE, NONE, 0, 0 }, /*08*/ { "invd", FALSE, NONE, 0, 0 }, /*09*/ { "wbinvd",FALSE, NONE, 0, 0 }, @@ -198,10 +220,10 @@ static const struct inst db_inst_0f3x[] = { /*31*/ { "rdtsc", FALSE, NONE, 0, 0 }, /*32*/ { "rdmsr", FALSE, NONE, 0, 0 }, /*33*/ { "rdpmc", FALSE, NONE, 0, 0 }, -/*34*/ { "", FALSE, NONE, 0, 0 }, -/*35*/ { "", FALSE, NONE, 0, 0 }, +/*34*/ { "sysenter",FALSE,NONE, 0, 0 }, +/*35*/ { "sysexit",FALSE,NONE, 0, 0 }, /*36*/ { "", FALSE, NONE, 0, 0 }, -/*37*/ { "", FALSE, NONE, 0, 0 }, +/*37*/ { "getsec",FALSE, NONE, 0, 0 }, /*38*/ { "", FALSE, NONE, 0, 0 }, /*39*/ { "", FALSE, NONE, 0, 0 }, @@ -289,8 +311,8 @@ static const struct inst db_inst_0fax[] = { /*ab*/ { "bts", TRUE, LONG, op2(R,E), 0 }, /*ac*/ { "shrd", TRUE, LONG, op3(Ib,R,E), 0 }, /*ad*/ { "shrd", TRUE, LONG, op3(CL,R,E), 0 }, -/*a6*/ { "", FALSE, NONE, 0, 0 }, -/*a7*/ { "imul", TRUE, LONG, op2(E,R), 0 }, +/*ae*/ { "", TRUE, LONG, op1(E), db_Grp15 }, +/*af*/ { "imul", TRUE, LONG, op2(E,R), 0 }, }; static const struct inst db_inst_0fbx[] = { @@ -1122,6 +1144,7 @@ db_disasm(loc, altfmt) boolean_t first; int displ; int prefix; + int rep; int imm; int imm2; int len; @@ -1135,6 +1158,7 @@ db_disasm(loc, altfmt) /* * Get prefixes */ + rep = FALSE; prefix = TRUE; do { switch (inst) { @@ -1169,7 +1193,7 @@ db_disasm(loc, altfmt) db_printf("repne "); break; case 0xf3: - db_printf("repe "); /* XXX repe VS rep */ + rep = TRUE; break; default: prefix = FALSE; @@ -1178,6 +1202,14 @@ db_disasm(loc, altfmt) if (prefix) { get_value_inc(inst, loc, 1, FALSE); } + if (rep == TRUE) { + if (inst == 0x90) { + db_printf("pause\n"); + return (loc); + } + db_printf("repe "); /* XXX repe VS rep */ + rep = FALSE; + } } while (prefix); if (inst >= 0xd8 && inst <= 0xdf) { @@ -1210,7 +1242,8 @@ db_disasm(loc, altfmt) if (ip->i_extra == db_Grp1 || ip->i_extra == db_Grp2 || ip->i_extra == db_Grp6 || ip->i_extra == db_Grp7 || - ip->i_extra == db_Grp8 || ip->i_extra == db_Grp9) { + ip->i_extra == db_Grp8 || ip->i_extra == db_Grp9 || + ip->i_extra == db_Grp15) { i_name = ((const char * const *)ip->i_extra)[f_reg(regmodrm)]; } else if (ip->i_extra == db_Grp3) { @@ -1227,6 +1260,27 @@ db_disasm(loc, altfmt) i_size = ip->i_size; } + /* Special cases that don't fit well in the tables. */ + if (ip->i_extra == db_Grp7 && f_mod(regmodrm) == 3) { + switch (regmodrm) { + case 0xc8: + i_name = "monitor"; + i_size = NONE; + i_mode = 0; + break; + case 0xc9: + i_name = "mwait"; + i_size = NONE; + i_mode = 0; + break; + } + } + if (ip->i_extra == db_Grp15 && f_mod(regmodrm) == 3) { + i_name = db_Grp15b[f_reg(regmodrm)]; + i_size = NONE; + i_mode = 0; + } + if (i_size == SDEP) { if (size == WORD) db_printf("%s", i_name); |