Skip to content

Commit

Permalink
objtool: Resync x86 instruction decoder with the kernel's
Browse files Browse the repository at this point in the history
This fixes the following warning:

  Warning: objtool: x86 instruction decoder differs from kernel

Unfortunately we have three identical copies of the x86 instruction
decoder in the kernel tree that have to be manually kept in sync.

It's on my TODO list to at least library-ize the ones in the tools
subdir so we'd only have two of them instead of three.  In the meantime,
here's another manual sync.

Reported-by: Linus Torvalds <[email protected]>
Signed-off-by: Josh Poimboeuf <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Brian Gerst <[email protected]>
Cc: Denys Vlasenko <[email protected]>
Cc: H. Peter Anvin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Fixes: c61f4d5 ("perf tools: Add AVX-512 support to the instruction decoder used by Intel PT")
Link: http://lkml.kernel.org/r/d7f74b4d91fed25b0be33cd5c86f5131fa1a7529.1469751119.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
jpoimboe authored and Ingo Molnar committed Jul 29, 2016
1 parent 6d01f28 commit 8d94c2f
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 101 deletions.
11 changes: 8 additions & 3 deletions tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,14 @@ BEGIN {
lprefix_expr = "\\((66|F2|F3)\\)"
max_lprefix = 4

# All opcodes starting with lower-case 'v' or with (v1) superscript
# All opcodes starting with lower-case 'v', 'k' or with (v1) superscript
# accepts VEX prefix
vexok_opcode_expr = "^v.*"
vexok_opcode_expr = "^[vk].*"
vexok_expr = "\\(v1\\)"
# All opcodes with (v) superscript supports *only* VEX prefix
vexonly_expr = "\\(v\\)"
# All opcodes with (ev) superscript supports *only* EVEX prefix
evexonly_expr = "\\(ev\\)"

prefix_expr = "\\(Prefix\\)"
prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
Expand All @@ -95,6 +97,7 @@ BEGIN {
prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
prefix_num["EVEX"] = "INAT_PFX_EVEX"

clear_vars()
}
Expand Down Expand Up @@ -319,7 +322,9 @@ function convert_operands(count,opnd, i,j,imm,mod)
flags = add_flags(flags, "INAT_MODRM")

# check VEX codes
if (match(ext, vexonly_expr))
if (match(ext, evexonly_expr))
flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY")
else if (match(ext, vexonly_expr))
flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
flags = add_flags(flags, "INAT_VEXOK")
Expand Down
17 changes: 15 additions & 2 deletions tools/objtool/arch/x86/insn/inat.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
/* AVX VEX prefixes */
#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */
#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */
#define INAT_PFX_EVEX 15 /* EVEX prefix */

#define INAT_LSTPFX_MAX 3
#define INAT_LGCPFX_MAX 11
Expand Down Expand Up @@ -89,6 +90,7 @@
#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4))
#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5))
#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6))
#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7))
/* Attribute making macros for attribute tables */
#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
Expand Down Expand Up @@ -141,7 +143,13 @@ static inline int inat_last_prefix_id(insn_attr_t attr)
static inline int inat_is_vex_prefix(insn_attr_t attr)
{
attr &= INAT_PFX_MASK;
return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3;
return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 ||
attr == INAT_PFX_EVEX;
}

static inline int inat_is_evex_prefix(insn_attr_t attr)
{
return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX;
}

static inline int inat_is_vex3_prefix(insn_attr_t attr)
Expand Down Expand Up @@ -216,6 +224,11 @@ static inline int inat_accept_vex(insn_attr_t attr)

static inline int inat_must_vex(insn_attr_t attr)
{
return attr & INAT_VEXONLY;
return attr & (INAT_VEXONLY | INAT_EVEXONLY);
}

static inline int inat_must_evex(insn_attr_t attr)
{
return attr & INAT_EVEXONLY;
}
#endif
18 changes: 15 additions & 3 deletions tools/objtool/arch/x86/insn/insn.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,24 @@ void insn_get_prefixes(struct insn *insn)
/*
* In 32-bits mode, if the [7:6] bits (mod bits of
* ModRM) on the second byte are not 11b, it is
* LDS or LES.
* LDS or LES or BOUND.
*/
if (X86_MODRM_MOD(b2) != 3)
goto vex_end;
}
insn->vex_prefix.bytes[0] = b;
insn->vex_prefix.bytes[1] = b2;
if (inat_is_vex3_prefix(attr)) {
if (inat_is_evex_prefix(attr)) {
b2 = peek_nbyte_next(insn_byte_t, insn, 2);
insn->vex_prefix.bytes[2] = b2;
b2 = peek_nbyte_next(insn_byte_t, insn, 3);
insn->vex_prefix.bytes[3] = b2;
insn->vex_prefix.nbytes = 4;
insn->next_byte += 4;
if (insn->x86_64 && X86_VEX_W(b2))
/* VEX.W overrides opnd_size */
insn->opnd_bytes = 8;
} else if (inat_is_vex3_prefix(attr)) {
b2 = peek_nbyte_next(insn_byte_t, insn, 2);
insn->vex_prefix.bytes[2] = b2;
insn->vex_prefix.nbytes = 3;
Expand Down Expand Up @@ -221,7 +231,9 @@ void insn_get_opcode(struct insn *insn)
m = insn_vex_m_bits(insn);
p = insn_vex_p_bits(insn);
insn->attr = inat_get_avx_attribute(op, m, p);
if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr))
if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) ||
(!inat_accept_vex(insn->attr) &&
!inat_is_group(insn->attr)))
insn->attr = 0; /* This instruction is bad */
goto end; /* VEX has only 1 byte for opcode */
}
Expand Down
12 changes: 11 additions & 1 deletion tools/objtool/arch/x86/insn/insn.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ struct insn {
#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */
#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */
/* VEX bit fields */
#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */
#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */
#define X86_VEX2_M 1 /* VEX2.M always 1 */
#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */
Expand Down Expand Up @@ -133,6 +134,13 @@ static inline int insn_is_avx(struct insn *insn)
return (insn->vex_prefix.value != 0);
}

static inline int insn_is_evex(struct insn *insn)
{
if (!insn->prefixes.got)
insn_get_prefixes(insn);
return (insn->vex_prefix.nbytes == 4);
}

/* Ensure this instruction is decoded completely */
static inline int insn_complete(struct insn *insn)
{
Expand All @@ -144,8 +152,10 @@ static inline insn_byte_t insn_vex_m_bits(struct insn *insn)
{
if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */
return X86_VEX2_M;
else
else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */
return X86_VEX3_M(insn->vex_prefix.bytes[1]);
else /* EVEX */
return X86_EVEX_M(insn->vex_prefix.bytes[1]);
}

static inline insn_byte_t insn_vex_p_bits(struct insn *insn)
Expand Down
Loading

0 comments on commit 8d94c2f

Please sign in to comment.