Update dis_tables.c to the latest Illumos version.

This includes decodes of recent Intel instructions, in particular
VT-x and related instructions. This allows the FBT provider to
locate the exit points of routines that include these new
instructions.

Illumos issues:
 3414 Need a new word of AT_SUN_HWCAP bits
 3415 Add isainfo support for f16c and rdrand
 3416 Need disassembler support for rdrand and f16c
 3413 isainfo -v overflows 80 columns
 3417 mdb disassembler confuses rdtscp for invlpg
 1518 dis should support AMD SVM/AMD-V/Pacifica instructions
 1096 i386 disassembler should understand complex nops
 1362 add kvmstat for monitoring of KVM statistics
 1363 add vmregs[] variable to DTrace
 1364 need disassembler support for VMX instructions
 1365 mdb needs 16-bit disassembler support

This corresponds to Illumos-gate (github) version
eb23829ff08a873c612ac45d191d559394b4b408

Reviewed by:	markj
MFC after:	1 week
This commit is contained in:
Peter Grehan 2014-05-15 01:06:27 +00:00
parent f3db4c53e6
commit c3ddb60e2d

View File

@ -21,6 +21,7 @@
*/
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
/*
@ -104,16 +105,18 @@ enum {
Mv,
Mw,
M, /* register or memory */
MG9, /* register or memory in group 9 (prefix optional) */
Mb, /* register or memory, always byte sized */
MO, /* memory only (no registers) */
PREF,
SWAPGS,
SWAPGS_RDTSCP,
MONITOR_MWAIT,
R,
RA,
SEG,
MR,
RM,
RM_66r, /* RM, but with a required 0x66 prefix */
IA,
MA,
SD,
@ -228,7 +231,10 @@ enum {
VEX_RRi, /* VEX mod_rm, imm8 -> mod_reg */
VEX_RM, /* VEX mod_reg -> mod_rm */
VEX_RRM, /* VEX VEX.vvvv, mod_reg -> mod_rm */
VEX_RMX /* VEX VEX.vvvv, mod_rm -> mod_reg */
VEX_RMX, /* VEX VEX.vvvv, mod_rm -> mod_reg */
VMx, /* vmcall/vmlaunch/vmresume/vmxoff */
VMxo, /* VMx instruction with optional prefix */
SVM /* AMD SVM instructions */
};
/*
@ -496,8 +502,8 @@ const instable_t dis_op0F00[8] = {
*/
const instable_t dis_op0F01[8] = {
/* [0] */ TNSZ("sgdt",MO,6), TNSZ("sidt",MONITOR_MWAIT,6), TNSZ("lgdt",XGETBV_XSETBV,6), TNSZ("lidt",MO,6),
/* [4] */ TNSZ("smsw",M,2), INVALID, TNSZ("lmsw",M,2), TNS("invlpg",SWAPGS),
/* [0] */ TNSZ("sgdt",VMx,6), TNSZ("sidt",MONITOR_MWAIT,6), TNSZ("lgdt",XGETBV_XSETBV,6), TNSZ("lidt",SVM,6),
/* [4] */ TNSZ("smsw",M,2), INVALID, TNSZ("lmsw",M,2), TNS("invlpg",SWAPGS_RDTSCP),
};
/*
@ -528,15 +534,44 @@ const instable_t dis_op0FBA[8] = {
};
/*
* Decode table for 0x0FC7 opcode
* Decode table for 0x0FC7 opcode (group 9)
*/
const instable_t dis_op0FC7[8] = {
/* [0] */ INVALID, TNS("cmpxchg8b",M), INVALID, INVALID,
/* [4] */ INVALID, INVALID, INVALID, INVALID,
/* [4] */ INVALID, INVALID, TNS("vmptrld",MG9), TNS("vmptrst",MG9),
};
/*
* Decode table for 0x0FC7 opcode (group 9) mode 3
*/
const instable_t dis_op0FC7m3[8] = {
/* [0] */ INVALID, INVALID, INVALID, INVALID,
/* [4] */ INVALID, INVALID, TNS("rdrand",MG9), INVALID,
};
/*
* Decode table for 0x0FC7 opcode with 0x66 prefix
*/
const instable_t dis_op660FC7[8] = {
/* [0] */ INVALID, INVALID, INVALID, INVALID,
/* [4] */ INVALID, INVALID, TNS("vmclear",M), INVALID,
};
/*
* Decode table for 0x0FC7 opcode with 0xF3 prefix
*/
const instable_t dis_opF30FC7[8] = {
/* [0] */ INVALID, INVALID, INVALID, INVALID,
/* [4] */ INVALID, INVALID, TNS("vmxon",M), INVALID,
};
/*
* Decode table for 0x0FC8 opcode -- 486 bswap instruction
@ -1147,7 +1182,7 @@ const instable_t dis_op0F38[256] = {
/* [78] */ INVALID, INVALID, INVALID, INVALID,
/* [7C] */ INVALID, INVALID, INVALID, INVALID,
/* [80] */ INVALID, INVALID, INVALID, INVALID,
/* [80] */ TNSy("invept", RM_66r), TNSy("invvpid", RM_66r),INVALID, INVALID,
/* [84] */ INVALID, INVALID, INVALID, INVALID,
/* [88] */ INVALID, INVALID, INVALID, INVALID,
/* [8C] */ INVALID, INVALID, INVALID, INVALID,
@ -1193,7 +1228,7 @@ const instable_t dis_opAVX660F38[256] = {
/* [08] */ TNSZ("vpsignb",VEX_RMrX,16),TNSZ("vpsignw",VEX_RMrX,16),TNSZ("vpsignd",VEX_RMrX,16),TNSZ("vpmulhrsw",VEX_RMrX,16),
/* [0C] */ TNSZ("vpermilps",VEX_RMrX,8),TNSZ("vpermilpd",VEX_RMrX,16),TNSZ("vtestps",VEX_RRI,8), TNSZ("vtestpd",VEX_RRI,16),
/* [10] */ INVALID, INVALID, INVALID, INVALID,
/* [10] */ INVALID, INVALID, INVALID, TNSZ("vcvtph2ps",VEX_MX,16),
/* [14] */ INVALID, INVALID, INVALID, TNSZ("vptest",VEX_RRI,16),
/* [18] */ TNSZ("vbroadcastss",VEX_MX,4),TNSZ("vbroadcastsd",VEX_MX,8),TNSZ("vbroadcastf128",VEX_MX,16),INVALID,
/* [1C] */ TNSZ("vpabsb",VEX_MX,16),TNSZ("vpabsw",VEX_MX,16),TNSZ("vpabsd",VEX_MX,16),INVALID,
@ -1359,7 +1394,7 @@ const instable_t dis_opAVX660F3A[256] = {
/* [10] */ INVALID, INVALID, INVALID, INVALID,
/* [14] */ TNSZ("vpextrb",VEX_RRi,8),TNSZ("vpextrw",VEX_RRi,16),TNSZ("vpextrd",VEX_RRi,16),TNSZ("vextractps",VEX_RM,16),
/* [18] */ TNSZ("vinsertf128",VEX_RMRX,16),TNSZ("vextractf128",VEX_RX,16),INVALID, INVALID,
/* [1C] */ INVALID, INVALID, INVALID, INVALID,
/* [1C] */ INVALID, TNSZ("vcvtps2ph",VEX_RX,16), INVALID, INVALID,
/* [20] */ TNSZ("vpinsrb",VEX_RMRX,8),TNSZ("vinsertps",VEX_RMRX,16),TNSZ("vpinsrd",VEX_RMRX,16),INVALID,
/* [24] */ INVALID, INVALID, INVALID, INVALID,
@ -1446,7 +1481,7 @@ const instable_t dis_op0F[16][16] = {
/* [10] */ TNSZ("movups",XMMO,16), TNSZ("movups",XMMOS,16),TNSZ("movlps",XMMO,8), TNSZ("movlps",XMMOS,8),
/* [14] */ TNSZ("unpcklps",XMMO,16),TNSZ("unpckhps",XMMO,16),TNSZ("movhps",XMMOM,8),TNSZ("movhps",XMMOMS,8),
/* [18] */ IND(dis_op0F18), INVALID, INVALID, INVALID,
/* [1C] */ INVALID, INVALID, INVALID, TS("nopw", Mw),
/* [1C] */ INVALID, INVALID, INVALID, TS("nop",Mw),
}, {
/* [20] */ TSy("mov",SREG), TSy("mov",SREG), TSy("mov",SREG), TSy("mov",SREG),
/* [24] */ TSx("mov",SREG), INVALID, TSx("mov",SREG), INVALID,
@ -1475,7 +1510,7 @@ const instable_t dis_op0F[16][16] = {
}, {
/* [70] */ TNSZ("pshufw",MMOPM,8), TNS("psrXXX",MR), TNS("psrXXX",MR), TNS("psrXXX",MR),
/* [74] */ TNSZ("pcmpeqb",MMO,8), TNSZ("pcmpeqw",MMO,8), TNSZ("pcmpeqd",MMO,8), TNS("emms",NORM),
/* [78] */ TNS("INVALID",XMMO), TNS("INVALID",XMMO), INVALID, INVALID,
/* [78] */ TNSy("vmread",RM), TNSy("vmwrite",MR), INVALID, INVALID,
/* [7C] */ INVALID, INVALID, TNSZ("movd",MMOS,4), TNSZ("movq",MMOS,8),
}, {
/* [80] */ TNS("jo",D), TNS("jno",D), TNS("jb",D), TNS("jae",D),
@ -1859,14 +1894,14 @@ const instable_t dis_distable[16][16] = {
/* [1,C] */ TNS("sbbb",IA), TS("sbb",IA), TSx("push",SEG), TSx("pop",SEG),
}, {
/* [2,0] */ TNS("andb",RMw), TS("and",RMw), TNS("andb",MRw), TS("and",MRw),
/* [2,4] */ TNS("andb",IA), TS("and",IA), TNS("%es:",OVERRIDE), TNSx("daa",NORM),
/* [2,4] */ TNS("andb",IA), TS("and",IA), TNSx("%es:",OVERRIDE), TNSx("daa",NORM),
/* [2,8] */ TNS("subb",RMw), TS("sub",RMw), TNS("subb",MRw), TS("sub",MRw),
/* [2,C] */ TNS("subb",IA), TS("sub",IA), TNS("%cs:",OVERRIDE), TNSx("das",NORM),
}, {
/* [3,0] */ TNS("xorb",RMw), TS("xor",RMw), TNS("xorb",MRw), TS("xor",MRw),
/* [3,4] */ TNS("xorb",IA), TS("xor",IA), TNS("%ss:",OVERRIDE), TNSx("aaa",NORM),
/* [3,4] */ TNS("xorb",IA), TS("xor",IA), TNSx("%ss:",OVERRIDE), TNSx("aaa",NORM),
/* [3,8] */ TNS("cmpb",RMw), TS("cmp",RMw), TNS("cmpb",MRw), TS("cmp",MRw),
/* [3,C] */ TNS("cmpb",IA), TS("cmp",IA), TNS("%ds:",OVERRIDE), TNSx("aas",NORM),
/* [3,C] */ TNS("cmpb",IA), TS("cmp",IA), TNSx("%ds:",OVERRIDE), TNSx("aas",NORM),
}, {
/* [4,0] */ TSx("inc",R), TSx("inc",R), TSx("inc",R), TSx("inc",R),
/* [4,4] */ TSx("inc",R), TSx("inc",R), TSx("inc",R), TSx("inc",R),
@ -2905,6 +2940,7 @@ dtrace_disx86(dis86_t *x, uint_t cpu_mode)
goto error;
#endif
switch (dp->it_adrmode) {
case RM_66r:
case XMM_66r:
case XMMM_66r:
if (opnd_size_prefix == 0) {
@ -3054,6 +3090,59 @@ dtrace_disx86(dis86_t *x, uint_t cpu_mode)
}
break;
case MG9:
/*
* More horribleness: the group 9 (0xF0 0xC7) instructions are
* allowed an optional prefix of 0x66 or 0xF3. This is similar
* to the SIMD business described above, but with a different
* addressing mode (and an indirect table), so we deal with it
* separately (if similarly).
*
* Intel further complicated this with the release of Ivy Bridge
* where they overloaded these instructions based on the ModR/M
* bytes. The VMX instructions have a mode of 0 since they are
* memory instructions but rdrand instructions have a mode of
* 0b11 (REG_ONLY) because they only operate on registers. While
* there are different prefix formats, for now it is sufficient
* to use a single different table.
*/
/*
* Calculate our offset in dis_op0FC7 (the group 9 table)
*/
if ((uintptr_t)dp - (uintptr_t)dis_op0FC7 > sizeof (dis_op0FC7))
goto error;
off = ((uintptr_t)dp - (uintptr_t)dis_op0FC7) /
sizeof (instable_t);
/*
* If we have a mode of 0b11 then we have to rewrite this.
*/
dtrace_get_modrm(x, &mode, &reg, &r_m);
if (mode == REG_ONLY) {
dp = (instable_t *)&dis_op0FC7m3[off];
break;
}
/*
* Rewrite if this instruction used one of the magic prefixes.
*/
if (rep_prefix) {
if (rep_prefix == 0xf3)
dp = (instable_t *)&dis_opF30FC7[off];
else
goto error;
rep_prefix = 0;
} else if (opnd_size_prefix) {
dp = (instable_t *)&dis_op660FC7[off];
opnd_size_prefix = 0;
if (opnd_size == SIZE16)
opnd_size = SIZE32;
}
break;
case MMOSH:
/*
* As with the "normal" SIMD instructions, the MMX
@ -3434,14 +3523,21 @@ dtrace_disx86(dis86_t *x, uint_t cpu_mode)
dtrace_get_operand(x, mode, r_m, wbit, 0);
break;
case SWAPGS:
case SWAPGS_RDTSCP:
if (cpu_mode == SIZE64 && mode == 3 && r_m == 0) {
#ifdef DIS_TEXT
(void) strncpy(x->d86_mnem, "swapgs", OPLEN);
#endif
NOMEM;
break;
} else if (mode == 3 && r_m == 1) {
#ifdef DIS_TEXT
(void) strncpy(x->d86_mnem, "rdtscp", OPLEN);
#endif
NOMEM;
break;
}
/*FALLTHROUGH*/
/* prefetch instruction - memory operand, but no memory acess */
@ -3451,6 +3547,7 @@ dtrace_disx86(dis86_t *x, uint_t cpu_mode)
/* single memory or register operand */
case M:
case MG9:
wbit = LONG_OPND;
goto just_mem;
@ -3459,6 +3556,76 @@ dtrace_disx86(dis86_t *x, uint_t cpu_mode)
wbit = BYTE_OPND;
goto just_mem;
case VMx:
if (mode == 3) {
#ifdef DIS_TEXT
char *vminstr;
switch (r_m) {
case 1:
vminstr = "vmcall";
break;
case 2:
vminstr = "vmlaunch";
break;
case 3:
vminstr = "vmresume";
break;
case 4:
vminstr = "vmxoff";
break;
default:
goto error;
}
(void) strncpy(x->d86_mnem, vminstr, OPLEN);
#else
if (r_m < 1 || r_m > 4)
goto error;
#endif
NOMEM;
break;
}
/*FALLTHROUGH*/
case SVM:
if (mode == 3) {
#ifdef DIS_TEXT
char *vinstr;
switch (r_m) {
case 0:
vinstr = "vmrun";
break;
case 1:
vinstr = "vmmcall";
break;
case 2:
vinstr = "vmload";
break;
case 3:
vinstr = "vmsave";
break;
case 4:
vinstr = "stgi";
break;
case 5:
vinstr = "clgi";
break;
case 6:
vinstr = "skinit";
break;
case 7:
vinstr = "invlpga";
break;
}
(void) strncpy(x->d86_mnem, vinstr, OPLEN);
#endif
NOMEM;
break;
}
/*FALLTHROUGH*/
case MONITOR_MWAIT:
if (mode == 3) {
if (r_m == 0) {
@ -3597,6 +3764,7 @@ dtrace_disx86(dis86_t *x, uint_t cpu_mode)
break;
case RM:
case RM_66r:
wbit = LONG_OPND;
STANDARD_MODRM(x, mode, reg, r_m, rex_prefix, wbit, 1);
break;
@ -4300,7 +4468,8 @@ dtrace_disx86(dis86_t *x, uint_t cpu_mode)
dtrace_get_operand(x, REG_ONLY, reg, XMM_OPND, 1);
dtrace_get_operand(x, mode, r_m, wbit, 0);
} else if ((dp == &dis_opAVXF30F[0xE6]) ||
(dp == &dis_opAVX0F[0x5][0xA])) {
(dp == &dis_opAVX0F[0x5][0xA]) ||
(dp == &dis_opAVX660F38[0x13])) {
/* vcvtdq2pd <xmm>, <ymm> */
/* or vcvtps2pd <xmm>, <ymm> */
dtrace_get_operand(x, REG_ONLY, reg, wbit, 1);
@ -4385,7 +4554,9 @@ dtrace_disx86(dis86_t *x, uint_t cpu_mode)
case VEX_RX:
/* ModR/M.rm := op(ModR/M.reg) */
if (dp == &dis_opAVX660F3A[0x19]) { /* vextractf128 */
/* vextractf128 || vcvtps2ph */
if (dp == &dis_opAVX660F3A[0x19] ||
dp == &dis_opAVX660F3A[0x1d]) {
x->d86_numopnds = 3;
dtrace_get_modrm(x, &mode, &reg, &r_m);