forked from Minki/linux
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
This commit is contained in:
commit
e72e58faa7
24
Makefile
24
Makefile
@ -910,6 +910,18 @@ mod_sign_cmd = true
|
||||
endif
|
||||
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),)
|
||||
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
|
||||
@ -1037,18 +1049,6 @@ prepare0: archprepare gcc-plugins
|
||||
# All the preparing..
|
||||
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
|
||||
prepare-objtool: $(objtool_target)
|
||||
|
||||
|
@ -346,6 +346,7 @@ SECTIONS
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame)
|
||||
*(__func_stack_frame_non_standard)
|
||||
*(__unreachable)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,6 +197,17 @@
|
||||
#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
|
||||
* suppress control flow warnings after asm blocks that transfer
|
||||
@ -206,7 +217,8 @@
|
||||
* this in the preprocessor, but we can live with this because they're
|
||||
* 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. */
|
||||
#define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))
|
||||
|
@ -31,9 +31,8 @@
|
||||
#define INSN_CALL_DYNAMIC 8
|
||||
#define INSN_RETURN 9
|
||||
#define INSN_CONTEXT_SWITCH 10
|
||||
#define INSN_BUG 11
|
||||
#define INSN_NOP 12
|
||||
#define INSN_OTHER 13
|
||||
#define INSN_NOP 11
|
||||
#define INSN_OTHER 12
|
||||
#define INSN_LAST INSN_OTHER
|
||||
|
||||
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)
|
||||
/* sysenter, sysret */
|
||||
*type = INSN_CONTEXT_SWITCH;
|
||||
else if (op2 == 0x0b || op2 == 0xb9)
|
||||
/* ud2 */
|
||||
*type = INSN_BUG;
|
||||
else if (op2 == 0x0d || op2 == 0x1f)
|
||||
/* nopl/nopw */
|
||||
*type = INSN_NOP;
|
||||
|
@ -51,7 +51,7 @@ struct instruction {
|
||||
unsigned int len, state;
|
||||
unsigned char type;
|
||||
unsigned long immediate;
|
||||
bool alt_group, visited;
|
||||
bool alt_group, visited, dead_end;
|
||||
struct symbol *call_dest;
|
||||
struct instruction *jump_dest;
|
||||
struct list_head alts;
|
||||
@ -329,6 +329,54 @@ static int decode_instructions(struct objtool_file *file)
|
||||
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.
|
||||
*/
|
||||
@ -843,6 +891,10 @@ static int decode_sections(struct objtool_file *file)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = add_dead_ends(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
add_ignores(file);
|
||||
|
||||
ret = add_jump_destinations(file);
|
||||
@ -1037,13 +1089,13 @@ static int validate_branch(struct objtool_file *file,
|
||||
|
||||
return 0;
|
||||
|
||||
case INSN_BUG:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (insn->dead_end)
|
||||
return 0;
|
||||
|
||||
insn = next_insn_same_sec(file, insn);
|
||||
if (!insn) {
|
||||
WARN("%s: unexpected end of section", sec->name);
|
||||
|
Loading…
Reference in New Issue
Block a user