svn commit: r239879 - stable/9/sys/amd64/amd64
John Baldwin
jhb at FreeBSD.org
Wed Aug 29 19:47:19 UTC 2012
Author: jhb
Date: Wed Aug 29 19:47:19 2012
New Revision: 239879
URL: http://svn.freebsd.org/changeset/base/239879
Log:
MFC 238109,238166:
Several fixes to the amd64 disassembler:
- Decode the 'xsave', 'xrstor', 'xsaveopt', 'xgetbv', 'xsetbv', and
'rdtscp' instructions.
- Add generic support for opcodes that are escape bytes used for
multi-byte opcodes (such as the 0x0f prefix). Use this to replace
the hard-coded 0x0f special case and add support for three-byte
opcodes that use the 0x0f38 prefix.
- Decode all Intel VMX instructions. invept and invvpid in particular are
three-byte opcodes that use the 0x0f38 escape prefix.
- Rework how the special 'SDEP' size flag works such that the default
instruction name (i_name) is the instruction when the data size
prefix (0x66) is not specified, and the alternate name in i_extra is
used when the prefix is included.
- Add a new 'ADEP' size flag similar to 'SDEP' except that it chooses
between i_name and i_extra based on the address size prefix (0x67).
Use this to fix the decoding for jrcxz vs jecxz which is determined
by the address size prefix, not the operand size prefix. Also, jcxz
is not possible in 64-bit mode, but jrcxz is the default instruction
for that opcode.
- Add support for handling instructions that have a mandatory 'rep'
prefix (this means not outputting the 'repe ' prefix until determining
if it is used as part of an opcode). Make 'pause' less of a special
case this way.
- Decode 'cmpxchg16b' and 'cdqe' which are variants of other instructions
but with a REX.W prefix.
Modified:
stable/9/sys/amd64/amd64/db_disasm.c
Directory Properties:
stable/9/sys/ (props changed)
stable/9/sys/amd64/include/xen/ (props changed)
stable/9/sys/boot/ (props changed)
stable/9/sys/boot/i386/efi/ (props changed)
stable/9/sys/boot/ia64/efi/ (props changed)
stable/9/sys/boot/ia64/ski/ (props changed)
stable/9/sys/boot/powerpc/boot1.chrp/ (props changed)
stable/9/sys/boot/powerpc/ofw/ (props changed)
stable/9/sys/cddl/contrib/opensolaris/ (props changed)
stable/9/sys/conf/ (props changed)
stable/9/sys/contrib/dev/acpica/ (props changed)
stable/9/sys/contrib/octeon-sdk/ (props changed)
stable/9/sys/contrib/pf/ (props changed)
stable/9/sys/contrib/x86emu/ (props changed)
stable/9/sys/dev/ (props changed)
stable/9/sys/dev/e1000/ (props changed)
stable/9/sys/dev/isp/ (props changed)
stable/9/sys/dev/ixgbe/ (props changed)
stable/9/sys/fs/ (props changed)
stable/9/sys/fs/ntfs/ (props changed)
stable/9/sys/modules/ (props changed)
Modified: stable/9/sys/amd64/amd64/db_disasm.c
==============================================================================
--- stable/9/sys/amd64/amd64/db_disasm.c Wed Aug 29 19:34:46 2012 (r239878)
+++ stable/9/sys/amd64/amd64/db_disasm.c Wed Aug 29 19:47:19 2012 (r239879)
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
* Instruction disassembler.
*/
#include <sys/param.h>
+#include <sys/libkern.h>
#include <ddb/ddb.h>
#include <ddb/db_access.h>
@@ -47,7 +48,9 @@ __FBSDID("$FreeBSD$");
#define DBLR 5
#define EXTR 6
#define SDEP 7
-#define NONE 8
+#define ADEP 8
+#define ESC 9
+#define NONE 10
/*
* REX prefix and bits
@@ -67,6 +70,7 @@ __FBSDID("$FreeBSD$");
#define Eb 4 /* address, byte size */
#define R 5 /* register, in 'reg' field */
#define Rw 6 /* word register, in 'reg' field */
+#define Rq 39 /* quad register, in 'reg' field */
#define Ri 7 /* register in instruction */
#define S 8 /* segment reg, in 'reg' field */
#define Si 9 /* segment reg, in instruction */
@@ -120,6 +124,45 @@ struct finst {
(or pointer to table) */
};
+static const struct inst db_inst_0f388x[] = {
+/*80*/ { "", TRUE, SDEP, op2(E, Rq), "invept" },
+/*81*/ { "", TRUE, SDEP, op2(E, Rq), "invvpid" },
+/*82*/ { "", FALSE, NONE, 0, 0 },
+/*83*/ { "", FALSE, NONE, 0, 0 },
+/*84*/ { "", FALSE, NONE, 0, 0 },
+/*85*/ { "", FALSE, NONE, 0, 0 },
+/*86*/ { "", FALSE, NONE, 0, 0 },
+/*87*/ { "", FALSE, NONE, 0, 0 },
+
+/*88*/ { "", FALSE, NONE, 0, 0 },
+/*89*/ { "", FALSE, NONE, 0, 0 },
+/*8a*/ { "", FALSE, NONE, 0, 0 },
+/*8b*/ { "", FALSE, NONE, 0, 0 },
+/*8c*/ { "", FALSE, NONE, 0, 0 },
+/*8d*/ { "", FALSE, NONE, 0, 0 },
+/*8e*/ { "", FALSE, NONE, 0, 0 },
+/*8f*/ { "", FALSE, NONE, 0, 0 },
+};
+
+static const struct inst * const db_inst_0f38[] = {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ db_inst_0f388x,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
static const char * const db_Grp6[] = {
"sldt",
"str",
@@ -160,8 +203,8 @@ static const char * const db_Grp9[] = {
"",
"",
"",
- "",
- ""
+ "vmptrld",
+ "vmptrst"
};
static const char * const db_Grp15[] = {
@@ -169,9 +212,9 @@ static const char * const db_Grp15[] = {
"fxrstor",
"ldmxcsr",
"stmxcsr",
- "",
- "",
- "",
+ "xsave",
+ "xrstor",
+ "xsaveopt",
"clflush"
};
@@ -236,7 +279,7 @@ static const struct inst db_inst_0f3x[]
/*36*/ { "", FALSE, NONE, 0, 0 },
/*37*/ { "getsec",FALSE, NONE, 0, 0 },
-/*38*/ { "", FALSE, NONE, 0, 0 },
+/*38*/ { "", FALSE, ESC, 0, db_inst_0f38 },
/*39*/ { "", FALSE, NONE, 0, 0 },
/*3a*/ { "", FALSE, NONE, 0, 0 },
/*3b*/ { "", FALSE, NONE, 0, 0 },
@@ -266,6 +309,26 @@ static const struct inst db_inst_0f4x[]
/*4f*/ { "cmovnle",TRUE, NONE, op2(E, R), 0 },
};
+static const struct inst db_inst_0f7x[] = {
+/*70*/ { "", FALSE, NONE, 0, 0 },
+/*71*/ { "", FALSE, NONE, 0, 0 },
+/*72*/ { "", FALSE, NONE, 0, 0 },
+/*73*/ { "", FALSE, NONE, 0, 0 },
+/*74*/ { "", FALSE, NONE, 0, 0 },
+/*75*/ { "", FALSE, NONE, 0, 0 },
+/*76*/ { "", FALSE, NONE, 0, 0 },
+/*77*/ { "", FALSE, NONE, 0, 0 },
+
+/*78*/ { "vmread", TRUE, NONE, op2(Rq, E), 0 },
+/*79*/ { "vmwrite",TRUE, NONE, op2(E, Rq), 0 },
+/*7a*/ { "", FALSE, NONE, 0, 0 },
+/*7b*/ { "", FALSE, NONE, 0, 0 },
+/*7c*/ { "", FALSE, NONE, 0, 0 },
+/*7d*/ { "", FALSE, NONE, 0, 0 },
+/*7e*/ { "", FALSE, NONE, 0, 0 },
+/*7f*/ { "", FALSE, NONE, 0, 0 },
+};
+
static const struct inst db_inst_0f8x[] = {
/*80*/ { "jo", FALSE, NONE, op1(Dl), 0 },
/*81*/ { "jno", FALSE, NONE, op1(Dl), 0 },
@@ -373,7 +436,7 @@ static const struct inst * const db_inst
db_inst_0f4x,
0,
0,
- 0,
+ db_inst_0f7x,
db_inst_0f8x,
db_inst_0f9x,
db_inst_0fax,
@@ -582,7 +645,7 @@ static const struct inst db_inst_table[2
/*0c*/ { "or", FALSE, BYTE, op2(I, A), 0 },
/*0d*/ { "or", FALSE, LONG, op2(I, A), 0 },
/*0e*/ { "push", FALSE, NONE, op1(Si), 0 },
-/*0f*/ { "", FALSE, NONE, 0, 0 },
+/*0f*/ { "", FALSE, ESC, 0, db_inst_0f },
/*10*/ { "adc", TRUE, BYTE, op2(R, E), 0 },
/*11*/ { "adc", TRUE, LONG, op2(R, E), 0 },
@@ -738,8 +801,8 @@ static const struct inst db_inst_table[2
/*96*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
/*97*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
-/*98*/ { "cbw", FALSE, SDEP, 0, "cwde" }, /* cbw/cwde */
-/*99*/ { "cwd", FALSE, SDEP, 0, "cdq" }, /* cwd/cdq */
+/*98*/ { "cwde", FALSE, SDEP, 0, "cbw" },
+/*99*/ { "cdq", FALSE, SDEP, 0, "cwd" },
/*9a*/ { "lcall", FALSE, NONE, op1(OS), 0 },
/*9b*/ { "wait", FALSE, NONE, 0, 0 },
/*9c*/ { "pushf", FALSE, LONG, 0, 0 },
@@ -822,7 +885,7 @@ static const struct inst db_inst_table[2
/*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 },
/*e1*/ { "loope", FALSE, NONE, op1(Db), 0 },
/*e2*/ { "loop", FALSE, NONE, op1(Db), 0 },
-/*e3*/ { "jcxz", FALSE, SDEP, op1(Db), "jecxz" },
+/*e3*/ { "jrcxz", FALSE, ADEP, op1(Db), "jecxz" },
/*e4*/ { "in", FALSE, BYTE, op2(Ib, A), 0 },
/*e5*/ { "in", FALSE, LONG, op2(Ib, A) , 0 },
/*e6*/ { "out", FALSE, BYTE, op2(A, Ib), 0 },
@@ -1208,14 +1271,6 @@ 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) {
@@ -1224,9 +1279,10 @@ db_disasm(loc, altfmt)
return (loc);
}
- if (inst == 0x0f) {
+ ip = &db_inst_table[inst];
+ while (ip->i_size == ESC) {
get_value_inc(inst, loc, 1, FALSE);
- ip = db_inst_0f[inst>>4];
+ ip = ((const struct inst * const *)ip->i_extra)[inst>>4];
if (ip == 0) {
ip = &db_bad_inst;
}
@@ -1234,8 +1290,6 @@ db_disasm(loc, altfmt)
ip = &ip[inst&0xf];
}
}
- else
- ip = &db_inst_table[inst];
if (ip->i_has_modrm) {
get_value_inc(regmodrm, loc, 1, FALSE);
@@ -1269,6 +1323,26 @@ db_disasm(loc, altfmt)
/* Special cases that don't fit well in the tables. */
if (ip->i_extra == db_Grp7 && f_mod(rex, regmodrm) == 3) {
switch (regmodrm) {
+ case 0xc1:
+ i_name = "vmcall";
+ i_size = NONE;
+ i_mode = 0;
+ break;
+ case 0xc2:
+ i_name = "vmlaunch";
+ i_size = NONE;
+ i_mode = 0;
+ break;
+ case 0xc3:
+ i_name = "vmresume";
+ i_size = NONE;
+ i_mode = 0;
+ break;
+ case 0xc4:
+ i_name = "vmxoff";
+ i_size = NONE;
+ i_mode = 0;
+ break;
case 0xc8:
i_name = "monitor";
i_size = NONE;
@@ -1279,11 +1353,26 @@ db_disasm(loc, altfmt)
i_size = NONE;
i_mode = 0;
break;
+ case 0xd0:
+ i_name = "xgetbv";
+ i_size = NONE;
+ i_mode = 0;
+ break;
+ case 0xd1:
+ i_name = "xsetbv";
+ i_size = NONE;
+ i_mode = 0;
+ break;
case 0xf8:
i_name = "swapgs";
i_size = NONE;
i_mode = 0;
break;
+ case 0xf9:
+ i_name = "rdtscp";
+ i_size = NONE;
+ i_mode = 0;
+ break;
}
}
if (ip->i_extra == db_Grp15 && f_mod(rex, regmodrm) == 3) {
@@ -1292,8 +1381,42 @@ db_disasm(loc, altfmt)
i_mode = 0;
}
+ /* Handle instructions identified by mandatory prefixes. */
+ if (rep == TRUE) {
+ if (inst == 0x90) {
+ i_name = "pause";
+ i_size = NONE;
+ i_mode = 0;
+ rep = FALSE;
+ } else if (ip->i_extra == db_Grp9 && f_mod(rex, regmodrm) != 3 &&
+ f_reg(rex, regmodrm) == 0x6) {
+ i_name = "vmxon";
+ rep = FALSE;
+ }
+ }
+ if (size == WORD) {
+ if (ip->i_extra == db_Grp9 && f_mod(rex, regmodrm) != 3 &&
+ f_reg(rex, regmodrm) == 0x6) {
+ i_name = "vmclear";
+ }
+ }
+ if (rex & REX_W) {
+ if (strcmp(i_name, "cwde") == 0)
+ i_name = "cdqe";
+ else if (strcmp(i_name, "cmpxchg8b") == 0)
+ i_name = "cmpxchg16b";
+ }
+
+ if (rep == TRUE)
+ db_printf("repe "); /* XXX repe VS rep */
+
if (i_size == SDEP) {
- if (size == WORD)
+ if (size == LONG)
+ db_printf("%s", i_name);
+ else
+ db_printf("%s", (const char *)ip->i_extra);
+ } else if (i_size == ADEP) {
+ if (short_addr == FALSE)
db_printf("%s", i_name);
else
db_printf("%s", (const char *)ip->i_extra);
@@ -1366,6 +1489,10 @@ db_disasm(loc, altfmt)
db_printf("%s", db_reg[rex != 0 ? 1 : 0][WORD][f_reg(rex, regmodrm)]);
break;
+ case Rq:
+ db_printf("%s", db_reg[rex != 0 ? 1 : 0][QUAD][f_reg(rex, regmodrm)]);
+ break;
+
case Ri:
db_printf("%s", db_reg[0][QUAD][f_rm(rex, inst)]);
break;
More information about the svn-src-stable
mailing list