Commit e72e58fa 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 objtool fixes from Ingo Molnar:
 "A handful of objtool fixes related to unreachable code, plus a build
  fix for out of tree modules"

* 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  objtool: Enclose contents of unreachable() macro in a block
  objtool: Prevent GCC from merging annotate_unreachable()
  objtool: Improve detection of BUG() and other dead ends
  objtool: Fix CONFIG_STACK_VALIDATION=y warning for out-of-tree modules
parents 74e3f63c 4e4636cf
...@@ -910,6 +910,18 @@ mod_sign_cmd = true ...@@ -910,6 +910,18 @@ mod_sign_cmd = true
endif endif
export mod_sign_cmd export mod_sign_cmd
ifdef CONFIG_STACK_VALIDATION
has_libelf := $(call try-run,\
echo "int main() {}" | $(HOSTCC) -xc -o /dev/null -lelf -,1,0)
ifeq ($(has_libelf),1)
objtool_target := tools/objtool FORCE
else
$(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
SKIP_STACK_VALIDATION := 1
export SKIP_STACK_VALIDATION
endif
endif
ifeq ($(KBUILD_EXTMOD),) ifeq ($(KBUILD_EXTMOD),)
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
...@@ -1037,18 +1049,6 @@ prepare0: archprepare gcc-plugins ...@@ -1037,18 +1049,6 @@ prepare0: archprepare gcc-plugins
# All the preparing.. # All the preparing..
prepare: prepare0 prepare-objtool prepare: prepare0 prepare-objtool
ifdef CONFIG_STACK_VALIDATION
has_libelf := $(call try-run,\
echo "int main() {}" | $(HOSTCC) -xc -o /dev/null -lelf -,1,0)
ifeq ($(has_libelf),1)
objtool_target := tools/objtool FORCE
else
$(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
SKIP_STACK_VALIDATION := 1
export SKIP_STACK_VALIDATION
endif
endif
PHONY += prepare-objtool PHONY += prepare-objtool
prepare-objtool: $(objtool_target) prepare-objtool: $(objtool_target)
......
...@@ -346,6 +346,7 @@ SECTIONS ...@@ -346,6 +346,7 @@ SECTIONS
/DISCARD/ : { /DISCARD/ : {
*(.eh_frame) *(.eh_frame)
*(__func_stack_frame_non_standard) *(__func_stack_frame_non_standard)
*(__unreachable)
} }
} }
......
...@@ -197,6 +197,17 @@ ...@@ -197,6 +197,17 @@
#endif #endif
#endif #endif
#ifdef CONFIG_STACK_VALIDATION
#define annotate_unreachable() ({ \
asm("%c0:\t\n" \
".pushsection __unreachable, \"a\"\t\n" \
".long %c0b\t\n" \
".popsection\t\n" : : "i" (__LINE__)); \
})
#else
#define annotate_unreachable()
#endif
/* /*
* Mark a position in code as unreachable. This can be used to * Mark a position in code as unreachable. This can be used to
* suppress control flow warnings after asm blocks that transfer * suppress control flow warnings after asm blocks that transfer
...@@ -206,7 +217,8 @@ ...@@ -206,7 +217,8 @@
* this in the preprocessor, but we can live with this because they're * this in the preprocessor, but we can live with this because they're
* unreleased. Really, we need to have autoconf for the kernel. * unreleased. Really, we need to have autoconf for the kernel.
*/ */
#define unreachable() __builtin_unreachable() #define unreachable() \
do { annotate_unreachable(); __builtin_unreachable(); } while (0)
/* Mark a function definition as prohibited from being cloned. */ /* Mark a function definition as prohibited from being cloned. */
#define __noclone __attribute__((__noclone__, __optimize__("no-tracer"))) #define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))
......
...@@ -31,9 +31,8 @@ ...@@ -31,9 +31,8 @@
#define INSN_CALL_DYNAMIC 8 #define INSN_CALL_DYNAMIC 8
#define INSN_RETURN 9 #define INSN_RETURN 9
#define INSN_CONTEXT_SWITCH 10 #define INSN_CONTEXT_SWITCH 10
#define INSN_BUG 11 #define INSN_NOP 11
#define INSN_NOP 12 #define INSN_OTHER 12
#define INSN_OTHER 13
#define INSN_LAST INSN_OTHER #define INSN_LAST INSN_OTHER
int arch_decode_instruction(struct elf *elf, struct section *sec, int arch_decode_instruction(struct elf *elf, struct section *sec,
......
...@@ -118,9 +118,6 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, ...@@ -118,9 +118,6 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
op2 == 0x35) op2 == 0x35)
/* sysenter, sysret */ /* sysenter, sysret */
*type = INSN_CONTEXT_SWITCH; *type = INSN_CONTEXT_SWITCH;
else if (op2 == 0x0b || op2 == 0xb9)
/* ud2 */
*type = INSN_BUG;
else if (op2 == 0x0d || op2 == 0x1f) else if (op2 == 0x0d || op2 == 0x1f)
/* nopl/nopw */ /* nopl/nopw */
*type = INSN_NOP; *type = INSN_NOP;
......
...@@ -51,7 +51,7 @@ struct instruction { ...@@ -51,7 +51,7 @@ struct instruction {
unsigned int len, state; unsigned int len, state;
unsigned char type; unsigned char type;
unsigned long immediate; unsigned long immediate;
bool alt_group, visited; bool alt_group, visited, dead_end;
struct symbol *call_dest; struct symbol *call_dest;
struct instruction *jump_dest; struct instruction *jump_dest;
struct list_head alts; struct list_head alts;
...@@ -329,6 +329,54 @@ static int decode_instructions(struct objtool_file *file) ...@@ -329,6 +329,54 @@ static int decode_instructions(struct objtool_file *file)
return 0; return 0;
} }
/*
* Find all uses of the unreachable() macro, which are code path dead ends.
*/
static int add_dead_ends(struct objtool_file *file)
{
struct section *sec;
struct rela *rela;
struct instruction *insn;
bool found;
sec = find_section_by_name(file->elf, ".rela__unreachable");
if (!sec)
return 0;
list_for_each_entry(rela, &sec->rela_list, list) {
if (rela->sym->type != STT_SECTION) {
WARN("unexpected relocation symbol type in .rela__unreachable");
return -1;
}
insn = find_insn(file, rela->sym->sec, rela->addend);
if (insn)
insn = list_prev_entry(insn, list);
else if (rela->addend == rela->sym->sec->len) {
found = false;
list_for_each_entry_reverse(insn, &file->insn_list, list) {
if (insn->sec == rela->sym->sec) {
found = true;
break;
}
}
if (!found) {
WARN("can't find unreachable insn at %s+0x%x",
rela->sym->sec->name, rela->addend);
return -1;
}
} else {
WARN("can't find unreachable insn at %s+0x%x",
rela->sym->sec->name, rela->addend);
return -1;
}
insn->dead_end = true;
}
return 0;
}
/* /*
* Warnings shouldn't be reported for ignored functions. * Warnings shouldn't be reported for ignored functions.
*/ */
...@@ -843,6 +891,10 @@ static int decode_sections(struct objtool_file *file) ...@@ -843,6 +891,10 @@ static int decode_sections(struct objtool_file *file)
if (ret) if (ret)
return ret; return ret;
ret = add_dead_ends(file);
if (ret)
return ret;
add_ignores(file); add_ignores(file);
ret = add_jump_destinations(file); ret = add_jump_destinations(file);
...@@ -1037,13 +1089,13 @@ static int validate_branch(struct objtool_file *file, ...@@ -1037,13 +1089,13 @@ static int validate_branch(struct objtool_file *file,
return 0; return 0;
case INSN_BUG:
return 0;
default: default:
break; break;
} }
if (insn->dead_end)
return 0;
insn = next_insn_same_sec(file, insn); insn = next_insn_same_sec(file, insn);
if (!insn) { if (!insn) {
WARN("%s: unexpected end of section", sec->name); WARN("%s: unexpected end of section", sec->name);
......
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