Commit 228ffba2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull misc fixes from Thomas Gleixner:
 "This update contains:

   - a fix for stomp-machine so the nmi_watchdog wont trigger on the cpu
     waiting for the others to execute the callback

   - various fixes and updates to objtool including an resync of the
     instruction decoder to match the kernel's decoder"

* 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  objtool: Un-capitalize "Warning" for out-of-sync instruction decoder
  objtool: Resync x86 instruction decoder with the kernel's
  objtool: Support new GCC 6 switch jump table pattern
  stop_machine: Touch_nmi_watchdog() after MULTI_STOP_PREPARE
  objtool: Add 'fixdep' to objtool/.gitignore
parents f64d6e2a 2af04ea5
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/smpboot.h> #include <linux/smpboot.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/lglock.h> #include <linux/lglock.h>
#include <linux/nmi.h>
/* /*
* Structure to determine completion condition and record errors. May * Structure to determine completion condition and record errors. May
...@@ -209,6 +210,13 @@ static int multi_cpu_stop(void *data) ...@@ -209,6 +210,13 @@ static int multi_cpu_stop(void *data)
break; break;
} }
ack_state(msdata); ack_state(msdata);
} else if (curstate > MULTI_STOP_PREPARE) {
/*
* At this stage all other CPUs we depend on must spin
* in the same loop. Any reason for hard-lockup should
* be detected and reported on their side.
*/
touch_nmi_watchdog();
} }
} while (curstate != MULTI_STOP_EXIT); } while (curstate != MULTI_STOP_EXIT);
......
arch/x86/insn/inat-tables.c arch/x86/insn/inat-tables.c
objtool objtool
fixdep
...@@ -51,7 +51,7 @@ $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) ...@@ -51,7 +51,7 @@ $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN)
diff -I'^#include' arch/x86/insn/insn.h ../../arch/x86/include/asm/insn.h >/dev/null && \ diff -I'^#include' arch/x86/insn/insn.h ../../arch/x86/include/asm/insn.h >/dev/null && \
diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \ diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \
diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \ diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \
|| echo "Warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true || echo "warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true
$(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@
......
...@@ -72,12 +72,14 @@ BEGIN { ...@@ -72,12 +72,14 @@ BEGIN {
lprefix_expr = "\\((66|F2|F3)\\)" lprefix_expr = "\\((66|F2|F3)\\)"
max_lprefix = 4 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 # accepts VEX prefix
vexok_opcode_expr = "^v.*" vexok_opcode_expr = "^[vk].*"
vexok_expr = "\\(v1\\)" vexok_expr = "\\(v1\\)"
# All opcodes with (v) superscript supports *only* VEX prefix # All opcodes with (v) superscript supports *only* VEX prefix
vexonly_expr = "\\(v\\)" vexonly_expr = "\\(v\\)"
# All opcodes with (ev) superscript supports *only* EVEX prefix
evexonly_expr = "\\(ev\\)"
prefix_expr = "\\(Prefix\\)" prefix_expr = "\\(Prefix\\)"
prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
...@@ -95,6 +97,7 @@ BEGIN { ...@@ -95,6 +97,7 @@ BEGIN {
prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
prefix_num["EVEX"] = "INAT_PFX_EVEX"
clear_vars() clear_vars()
} }
...@@ -319,7 +322,9 @@ function convert_operands(count,opnd, i,j,imm,mod) ...@@ -319,7 +322,9 @@ function convert_operands(count,opnd, i,j,imm,mod)
flags = add_flags(flags, "INAT_MODRM") flags = add_flags(flags, "INAT_MODRM")
# check VEX codes # 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") flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
flags = add_flags(flags, "INAT_VEXOK") flags = add_flags(flags, "INAT_VEXOK")
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
/* AVX VEX prefixes */ /* AVX VEX prefixes */
#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ #define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */
#define INAT_PFX_VEX3 14 /* 3-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_LSTPFX_MAX 3
#define INAT_LGCPFX_MAX 11 #define INAT_LGCPFX_MAX 11
...@@ -89,6 +90,7 @@ ...@@ -89,6 +90,7 @@
#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) #define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4))
#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) #define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5))
#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) #define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6))
#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7))
/* Attribute making macros for attribute tables */ /* Attribute making macros for attribute tables */
#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) #define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) #define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
...@@ -141,7 +143,13 @@ static inline int inat_last_prefix_id(insn_attr_t attr) ...@@ -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) static inline int inat_is_vex_prefix(insn_attr_t attr)
{ {
attr &= INAT_PFX_MASK; 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) static inline int inat_is_vex3_prefix(insn_attr_t attr)
...@@ -216,6 +224,11 @@ static inline int inat_accept_vex(insn_attr_t attr) ...@@ -216,6 +224,11 @@ static inline int inat_accept_vex(insn_attr_t attr)
static inline int inat_must_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 #endif
...@@ -155,14 +155,24 @@ void insn_get_prefixes(struct insn *insn) ...@@ -155,14 +155,24 @@ void insn_get_prefixes(struct insn *insn)
/* /*
* In 32-bits mode, if the [7:6] bits (mod bits of * In 32-bits mode, if the [7:6] bits (mod bits of
* ModRM) on the second byte are not 11b, it is * ModRM) on the second byte are not 11b, it is
* LDS or LES. * LDS or LES or BOUND.
*/ */
if (X86_MODRM_MOD(b2) != 3) if (X86_MODRM_MOD(b2) != 3)
goto vex_end; goto vex_end;
} }
insn->vex_prefix.bytes[0] = b; insn->vex_prefix.bytes[0] = b;
insn->vex_prefix.bytes[1] = b2; 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); b2 = peek_nbyte_next(insn_byte_t, insn, 2);
insn->vex_prefix.bytes[2] = b2; insn->vex_prefix.bytes[2] = b2;
insn->vex_prefix.nbytes = 3; insn->vex_prefix.nbytes = 3;
...@@ -221,7 +231,9 @@ void insn_get_opcode(struct insn *insn) ...@@ -221,7 +231,9 @@ void insn_get_opcode(struct insn *insn)
m = insn_vex_m_bits(insn); m = insn_vex_m_bits(insn);
p = insn_vex_p_bits(insn); p = insn_vex_p_bits(insn);
insn->attr = inat_get_avx_attribute(op, m, p); 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 */ insn->attr = 0; /* This instruction is bad */
goto end; /* VEX has only 1 byte for opcode */ goto end; /* VEX has only 1 byte for opcode */
} }
......
...@@ -91,6 +91,7 @@ struct insn { ...@@ -91,6 +91,7 @@ struct insn {
#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ #define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */
#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ #define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */
/* VEX bit fields */ /* VEX bit fields */
#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */
#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ #define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */
#define X86_VEX2_M 1 /* VEX2.M always 1 */ #define X86_VEX2_M 1 /* VEX2.M always 1 */
#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ #define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */
...@@ -133,6 +134,13 @@ static inline int insn_is_avx(struct insn *insn) ...@@ -133,6 +134,13 @@ static inline int insn_is_avx(struct insn *insn)
return (insn->vex_prefix.value != 0); 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 */ /* Ensure this instruction is decoded completely */
static inline int insn_complete(struct insn *insn) static inline int insn_complete(struct insn *insn)
{ {
...@@ -144,8 +152,10 @@ static inline insn_byte_t insn_vex_m_bits(struct insn *insn) ...@@ -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 */ if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */
return X86_VEX2_M; return X86_VEX2_M;
else else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */
return X86_VEX3_M(insn->vex_prefix.bytes[1]); 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) static inline insn_byte_t insn_vex_p_bits(struct insn *insn)
......
...@@ -107,6 +107,12 @@ static struct instruction *next_insn_same_sec(struct objtool_file *file, ...@@ -107,6 +107,12 @@ static struct instruction *next_insn_same_sec(struct objtool_file *file,
insn->offset < func->offset + func->len; \ insn->offset < func->offset + func->len; \
insn = list_next_entry(insn, list)) insn = list_next_entry(insn, list))
#define func_for_each_insn_continue_reverse(file, func, insn) \
for (insn = list_prev_entry(insn, list); \
&insn->list != &file->insn_list && \
insn->sec == func->sec && insn->offset >= func->offset; \
insn = list_prev_entry(insn, list))
#define sec_for_each_insn_from(file, insn) \ #define sec_for_each_insn_from(file, insn) \
for (; insn; insn = next_insn_same_sec(file, insn)) for (; insn; insn = next_insn_same_sec(file, insn))
...@@ -664,65 +670,95 @@ static int add_switch_table(struct objtool_file *file, struct symbol *func, ...@@ -664,65 +670,95 @@ static int add_switch_table(struct objtool_file *file, struct symbol *func,
return 0; return 0;
} }
static int add_func_switch_tables(struct objtool_file *file, /*
struct symbol *func) * find_switch_table() - Given a dynamic jump, find the switch jump table in
{ * .rodata associated with it.
struct instruction *insn, *prev_jump; *
struct rela *text_rela, *rodata_rela, *prev_rela = NULL; * There are 3 basic patterns:
int ret;
prev_jump = NULL;
func_for_each_insn(file, func, insn) {
if (insn->type != INSN_JUMP_DYNAMIC)
continue;
text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
insn->len);
if (!text_rela || text_rela->sym != file->rodata->sym)
continue;
/* common case: jmpq *[addr](,%rax,8) */
rodata_rela = find_rela_by_dest(file->rodata,
text_rela->addend);
/*
* rare case: jmpq *[addr](%rip)
* *
* This check is for a rare gcc quirk, currently only seen in * 1. jmpq *[rodata addr](,%reg,8)
* three driver functions in the kernel, only with certain
* obscure non-distro configs.
* *
* As part of an optimization, gcc makes a copy of an existing * This is the most common case by far. It jumps to an address in a simple
* switch jump table, modifies it, and then hard-codes the jump * jump table which is stored in .rodata.
* (albeit with an indirect jump) to use a single entry in the
* table. The rest of the jump table and some of its jump
* targets remain as dead code.
* *
* In such a case we can just crudely ignore all unreachable * 2. jmpq *[rodata addr](%rip)
* instruction warnings for the entire object file. Ideally we
* would just ignore them for the function, but that would
* require redesigning the code quite a bit. And honestly
* that's just not worth doing: unreachable instruction
* warnings are of questionable value anyway, and this is such
* a rare issue.
* *
* kbuild reports: * This is caused by a rare GCC quirk, currently only seen in three driver
* - https://lkml.kernel.org/r/201603231906.LWcVUpxm%25fengguang.wu@intel.com * functions in the kernel, only with certain obscure non-distro configs.
* - https://lkml.kernel.org/r/201603271114.K9i45biy%25fengguang.wu@intel.com
* - https://lkml.kernel.org/r/201603291058.zuJ6ben1%25fengguang.wu@intel.com
* *
* gcc bug: * As part of an optimization, GCC makes a copy of an existing switch jump
* - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70604 * table, modifies it, and then hard-codes the jump (albeit with an indirect
* jump) to use a single entry in the table. The rest of the jump table and
* some of its jump targets remain as dead code.
*
* In such a case we can just crudely ignore all unreachable instruction
* warnings for the entire object file. Ideally we would just ignore them
* for the function, but that would require redesigning the code quite a
* bit. And honestly that's just not worth doing: unreachable instruction
* warnings are of questionable value anyway, and this is such a rare issue.
*
* 3. mov [rodata addr],%reg1
* ... some instructions ...
* jmpq *(%reg1,%reg2,8)
*
* This is a fairly uncommon pattern which is new for GCC 6. As of this
* writing, there are 11 occurrences of it in the allmodconfig kernel.
*
* TODO: Once we have DWARF CFI and smarter instruction decoding logic,
* ensure the same register is used in the mov and jump instructions.
*/ */
if (!rodata_rela) { static struct rela *find_switch_table(struct objtool_file *file,
struct symbol *func,
struct instruction *insn)
{
struct rela *text_rela, *rodata_rela;
text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
if (text_rela && text_rela->sym == file->rodata->sym) {
/* case 1 */
rodata_rela = find_rela_by_dest(file->rodata, rodata_rela = find_rela_by_dest(file->rodata,
text_rela->addend + 4); text_rela->addend);
if (rodata_rela) if (rodata_rela)
return rodata_rela;
/* case 2 */
rodata_rela = find_rela_by_dest(file->rodata,
text_rela->addend + 4);
if (!rodata_rela)
return NULL;
file->ignore_unreachables = true; file->ignore_unreachables = true;
return rodata_rela;
} }
if (!rodata_rela) /* case 3 */
func_for_each_insn_continue_reverse(file, func, insn) {
if (insn->type == INSN_JUMP_UNCONDITIONAL ||
insn->type == INSN_JUMP_DYNAMIC)
break;
text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
insn->len);
if (text_rela && text_rela->sym == file->rodata->sym)
return find_rela_by_dest(file->rodata,
text_rela->addend);
}
return NULL;
}
static int add_func_switch_tables(struct objtool_file *file,
struct symbol *func)
{
struct instruction *insn, *prev_jump = NULL;
struct rela *rela, *prev_rela = NULL;
int ret;
func_for_each_insn(file, func, insn) {
if (insn->type != INSN_JUMP_DYNAMIC)
continue;
rela = find_switch_table(file, func, insn);
if (!rela)
continue; continue;
/* /*
...@@ -732,13 +768,13 @@ static int add_func_switch_tables(struct objtool_file *file, ...@@ -732,13 +768,13 @@ static int add_func_switch_tables(struct objtool_file *file,
*/ */
if (prev_jump) { if (prev_jump) {
ret = add_switch_table(file, func, prev_jump, prev_rela, ret = add_switch_table(file, func, prev_jump, prev_rela,
rodata_rela); rela);
if (ret) if (ret)
return ret; return ret;
} }
prev_jump = insn; prev_jump = insn;
prev_rela = rodata_rela; prev_rela = rela;
} }
if (prev_jump) { if (prev_jump) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment