mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-15 02:05:33 +00:00
Merge branch into tip/master: 'objtool/core'
# New commits in objtool/core: 41a1e976623e ("x86/mm: Convert unreachable() to BUG()") c3cb6c158c64 ("objtool: Allow arch code to discover jump table size") e7e0eb53c2f0 ("objtool: Warn about unknown annotation types") 87116ae6da03 ("objtool: Fix ANNOTATE_REACHABLE to be a normal annotation") e7a174fb43d2 ("objtool: Convert {.UN}REACHABLE to ANNOTATE") 06e24745985c ("objtool: Remove annotate_{,un}reachable()") 624bde3465f6 ("loongarch: Use ASM_REACHABLE") 2190966fbc14 ("x86: Convert unreachable() to BUG()") c837de381098 ("unreachable: Unify") bb8170067470 ("objtool: Collect more annotations in objtool.h") a8a330dd9900 ("objtool: Collapse annotate sequences") 112765ca1cb9 ("objtool: Convert ANNOTATE_INTRA_FUNCTION_CALL to ANNOTATE") f0cd57c35a75 ("objtool: Convert ANNOTATE_IGNORE_ALTERNATIVE to ANNOTATE") 18aa6118a168 ("objtool: Convert VALIDATE_UNRET_BEGIN to ANNOTATE") 317f2a64618c ("objtool: Convert instrumentation_{begin,end}() to ANNOTATE") bf5febebd99f ("objtool: Convert ANNOTATE_RETPOLINE_SAFE to ANNOTATE") 22c3d5807968 ("objtool: Convert ANNOTATE_NOENDBR to ANNOTATE") 2116b349e29a ("objtool: Generic annotation infrastructure") Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
8d020ac092
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <asm/break.h>
|
#include <asm/break.h>
|
||||||
#include <linux/stringify.h>
|
#include <linux/stringify.h>
|
||||||
|
#include <linux/objtool.h>
|
||||||
|
|
||||||
#ifndef CONFIG_DEBUG_BUGVERBOSE
|
#ifndef CONFIG_DEBUG_BUGVERBOSE
|
||||||
#define _BUGVERBOSE_LOCATION(file, line)
|
#define _BUGVERBOSE_LOCATION(file, line)
|
||||||
@ -33,25 +34,25 @@
|
|||||||
|
|
||||||
#define ASM_BUG_FLAGS(flags) \
|
#define ASM_BUG_FLAGS(flags) \
|
||||||
__BUG_ENTRY(flags) \
|
__BUG_ENTRY(flags) \
|
||||||
break BRK_BUG
|
break BRK_BUG;
|
||||||
|
|
||||||
#define ASM_BUG() ASM_BUG_FLAGS(0)
|
#define ASM_BUG() ASM_BUG_FLAGS(0)
|
||||||
|
|
||||||
#define __BUG_FLAGS(flags) \
|
#define __BUG_FLAGS(flags, extra) \
|
||||||
asm_inline volatile (__stringify(ASM_BUG_FLAGS(flags)));
|
asm_inline volatile (__stringify(ASM_BUG_FLAGS(flags)) \
|
||||||
|
extra);
|
||||||
|
|
||||||
#define __WARN_FLAGS(flags) \
|
#define __WARN_FLAGS(flags) \
|
||||||
do { \
|
do { \
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
__BUG_FLAGS(BUGFLAG_WARNING|(flags)); \
|
__BUG_FLAGS(BUGFLAG_WARNING|(flags), ANNOTATE_REACHABLE(10001b));\
|
||||||
annotate_reachable(); \
|
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define BUG() \
|
#define BUG() \
|
||||||
do { \
|
do { \
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
__BUG_FLAGS(0); \
|
__BUG_FLAGS(0, ""); \
|
||||||
unreachable(); \
|
unreachable(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -308,10 +308,9 @@ SYM_CODE_END(xen_error_entry)
|
|||||||
movq $-1, ORIG_RAX(%rsp) /* no syscall to restart */
|
movq $-1, ORIG_RAX(%rsp) /* no syscall to restart */
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
call \cfunc
|
|
||||||
|
|
||||||
/* For some configurations \cfunc ends up being a noreturn. */
|
/* For some configurations \cfunc ends up being a noreturn. */
|
||||||
REACHABLE
|
ANNOTATE_REACHABLE
|
||||||
|
call \cfunc
|
||||||
|
|
||||||
jmp error_return
|
jmp error_return
|
||||||
.endm
|
.endm
|
||||||
@ -529,10 +528,10 @@ SYM_CODE_START(\asmsym)
|
|||||||
movq %rsp, %rdi /* pt_regs pointer into first argument */
|
movq %rsp, %rdi /* pt_regs pointer into first argument */
|
||||||
movq ORIG_RAX(%rsp), %rsi /* get error code into 2nd argument*/
|
movq ORIG_RAX(%rsp), %rsi /* get error code into 2nd argument*/
|
||||||
movq $-1, ORIG_RAX(%rsp) /* no syscall to restart */
|
movq $-1, ORIG_RAX(%rsp) /* no syscall to restart */
|
||||||
call \cfunc
|
|
||||||
|
|
||||||
/* For some configurations \cfunc ends up being a noreturn. */
|
/* For some configurations \cfunc ends up being a noreturn. */
|
||||||
REACHABLE
|
ANNOTATE_REACHABLE
|
||||||
|
call \cfunc
|
||||||
|
|
||||||
jmp paranoid_exit
|
jmp paranoid_exit
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/stringify.h>
|
#include <linux/stringify.h>
|
||||||
|
#include <linux/objtool.h>
|
||||||
#include <asm/asm.h>
|
#include <asm/asm.h>
|
||||||
|
|
||||||
#define ALT_FLAGS_SHIFT 16
|
#define ALT_FLAGS_SHIFT 16
|
||||||
@ -54,16 +55,6 @@
|
|||||||
#define LOCK_PREFIX ""
|
#define LOCK_PREFIX ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* objtool annotation to ignore the alternatives and only consider the original
|
|
||||||
* instruction(s).
|
|
||||||
*/
|
|
||||||
#define ANNOTATE_IGNORE_ALTERNATIVE \
|
|
||||||
"999:\n\t" \
|
|
||||||
".pushsection .discard.ignore_alts\n\t" \
|
|
||||||
".long 999b\n\t" \
|
|
||||||
".popsection\n\t"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The patching flags are part of the upper bits of the @ft_flags parameter when
|
* The patching flags are part of the upper bits of the @ft_flags parameter when
|
||||||
* specifying them. The split is currently like this:
|
* specifying them. The split is currently like this:
|
||||||
@ -310,17 +301,6 @@ void nop_func(void);
|
|||||||
.endm
|
.endm
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* objtool annotation to ignore the alternatives and only consider the original
|
|
||||||
* instruction(s).
|
|
||||||
*/
|
|
||||||
.macro ANNOTATE_IGNORE_ALTERNATIVE
|
|
||||||
.Lannotate_\@:
|
|
||||||
.pushsection .discard.ignore_alts
|
|
||||||
.long .Lannotate_\@
|
|
||||||
.popsection
|
|
||||||
.endm
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Issue one struct alt_instr descriptor entry (need to put it into
|
* Issue one struct alt_instr descriptor entry (need to put it into
|
||||||
* the section .altinstructions, see below). This entry contains
|
* the section .altinstructions, see below). This entry contains
|
||||||
|
@ -92,7 +92,7 @@ do { \
|
|||||||
do { \
|
do { \
|
||||||
__auto_type __flags = BUGFLAG_WARNING|(flags); \
|
__auto_type __flags = BUGFLAG_WARNING|(flags); \
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
_BUG_FLAGS(ASM_UD2, __flags, ASM_REACHABLE); \
|
_BUG_FLAGS(ASM_UD2, __flags, ANNOTATE_REACHABLE(1b)); \
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -100,8 +100,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define ASM_CALL_ARG0 \
|
#define ASM_CALL_ARG0 \
|
||||||
"call %c[__func] \n" \
|
"1: call %c[__func] \n" \
|
||||||
ASM_REACHABLE
|
ANNOTATE_REACHABLE(1b)
|
||||||
|
|
||||||
#define ASM_CALL_ARG1 \
|
#define ASM_CALL_ARG1 \
|
||||||
"movq %[arg1], %%rdi \n" \
|
"movq %[arg1], %%rdi \n" \
|
||||||
|
@ -179,18 +179,6 @@
|
|||||||
|
|
||||||
#ifdef __ASSEMBLY__
|
#ifdef __ASSEMBLY__
|
||||||
|
|
||||||
/*
|
|
||||||
* This should be used immediately before an indirect jump/call. It tells
|
|
||||||
* objtool the subsequent indirect jump/call is vouched safe for retpoline
|
|
||||||
* builds.
|
|
||||||
*/
|
|
||||||
.macro ANNOTATE_RETPOLINE_SAFE
|
|
||||||
.Lhere_\@:
|
|
||||||
.pushsection .discard.retpoline_safe
|
|
||||||
.long .Lhere_\@
|
|
||||||
.popsection
|
|
||||||
.endm
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (ab)use RETPOLINE_SAFE on RET to annotate away 'bare' RET instructions
|
* (ab)use RETPOLINE_SAFE on RET to annotate away 'bare' RET instructions
|
||||||
* vs RETBleed validation.
|
* vs RETBleed validation.
|
||||||
@ -350,12 +338,6 @@
|
|||||||
|
|
||||||
#else /* __ASSEMBLY__ */
|
#else /* __ASSEMBLY__ */
|
||||||
|
|
||||||
#define ANNOTATE_RETPOLINE_SAFE \
|
|
||||||
"999:\n\t" \
|
|
||||||
".pushsection .discard.retpoline_safe\n\t" \
|
|
||||||
".long 999b\n\t" \
|
|
||||||
".popsection\n\t"
|
|
||||||
|
|
||||||
typedef u8 retpoline_thunk_t[RETPOLINE_THUNK_SIZE];
|
typedef u8 retpoline_thunk_t[RETPOLINE_THUNK_SIZE];
|
||||||
extern retpoline_thunk_t __x86_indirect_thunk_array[];
|
extern retpoline_thunk_t __x86_indirect_thunk_array[];
|
||||||
extern retpoline_thunk_t __x86_indirect_call_thunk_array[];
|
extern retpoline_thunk_t __x86_indirect_call_thunk_array[];
|
||||||
|
@ -838,7 +838,7 @@ void __noreturn stop_this_cpu(void *dummy)
|
|||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
if (smp_ops.stop_this_cpu) {
|
if (smp_ops.stop_this_cpu) {
|
||||||
smp_ops.stop_this_cpu();
|
smp_ops.stop_this_cpu();
|
||||||
unreachable();
|
BUG();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -883,7 +883,7 @@ static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
|
|||||||
|
|
||||||
if (smp_ops.stop_this_cpu) {
|
if (smp_ops.stop_this_cpu) {
|
||||||
smp_ops.stop_this_cpu();
|
smp_ops.stop_this_cpu();
|
||||||
unreachable();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assume hlt works */
|
/* Assume hlt works */
|
||||||
|
@ -3820,7 +3820,7 @@ next_range:
|
|||||||
goto next_range;
|
goto next_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
unreachable();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __sev_snp_update_protected_guest_state(struct kvm_vcpu *vcpu)
|
static int __sev_snp_update_protected_guest_state(struct kvm_vcpu *vcpu)
|
||||||
|
@ -678,7 +678,7 @@ page_fault_oops(struct pt_regs *regs, unsigned long error_code,
|
|||||||
ASM_CALL_ARG3,
|
ASM_CALL_ARG3,
|
||||||
, [arg1] "r" (regs), [arg2] "r" (address), [arg3] "r" (&info));
|
, [arg1] "r" (regs), [arg2] "r" (address), [arg3] "r" (&info));
|
||||||
|
|
||||||
unreachable();
|
BUG();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -52,18 +52,6 @@
|
|||||||
*/
|
*/
|
||||||
#define barrier_before_unreachable() asm volatile("")
|
#define barrier_before_unreachable() asm volatile("")
|
||||||
|
|
||||||
/*
|
|
||||||
* Mark a position in code as unreachable. This can be used to
|
|
||||||
* suppress control flow warnings after asm blocks that transfer
|
|
||||||
* control elsewhere.
|
|
||||||
*/
|
|
||||||
#define unreachable() \
|
|
||||||
do { \
|
|
||||||
annotate_unreachable(); \
|
|
||||||
barrier_before_unreachable(); \
|
|
||||||
__builtin_unreachable(); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#if defined(CONFIG_ARCH_USE_BUILTIN_BSWAP)
|
#if defined(CONFIG_ARCH_USE_BUILTIN_BSWAP)
|
||||||
#define __HAVE_BUILTIN_BSWAP32__
|
#define __HAVE_BUILTIN_BSWAP32__
|
||||||
#define __HAVE_BUILTIN_BSWAP64__
|
#define __HAVE_BUILTIN_BSWAP64__
|
||||||
|
@ -109,44 +109,21 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
|
|||||||
|
|
||||||
/* Unreachable code */
|
/* Unreachable code */
|
||||||
#ifdef CONFIG_OBJTOOL
|
#ifdef CONFIG_OBJTOOL
|
||||||
/*
|
|
||||||
* These macros help objtool understand GCC code flow for unreachable code.
|
|
||||||
* The __COUNTER__ based labels are a hack to make each instance of the macros
|
|
||||||
* unique, to convince GCC not to merge duplicate inline asm statements.
|
|
||||||
*/
|
|
||||||
#define __stringify_label(n) #n
|
|
||||||
|
|
||||||
#define __annotate_reachable(c) ({ \
|
|
||||||
asm volatile(__stringify_label(c) ":\n\t" \
|
|
||||||
".pushsection .discard.reachable\n\t" \
|
|
||||||
".long " __stringify_label(c) "b - .\n\t" \
|
|
||||||
".popsection\n\t"); \
|
|
||||||
})
|
|
||||||
#define annotate_reachable() __annotate_reachable(__COUNTER__)
|
|
||||||
|
|
||||||
#define __annotate_unreachable(c) ({ \
|
|
||||||
asm volatile(__stringify_label(c) ":\n\t" \
|
|
||||||
".pushsection .discard.unreachable\n\t" \
|
|
||||||
".long " __stringify_label(c) "b - .\n\t" \
|
|
||||||
".popsection\n\t" : : "i" (c)); \
|
|
||||||
})
|
|
||||||
#define annotate_unreachable() __annotate_unreachable(__COUNTER__)
|
|
||||||
|
|
||||||
/* Annotate a C jump table to allow objtool to follow the code flow */
|
/* Annotate a C jump table to allow objtool to follow the code flow */
|
||||||
#define __annotate_jump_table __section(".rodata..c_jump_table,\"a\",@progbits #")
|
#define __annotate_jump_table __section(".rodata..c_jump_table,\"a\",@progbits #")
|
||||||
|
|
||||||
#else /* !CONFIG_OBJTOOL */
|
#else /* !CONFIG_OBJTOOL */
|
||||||
#define annotate_reachable()
|
|
||||||
#define annotate_unreachable()
|
|
||||||
#define __annotate_jump_table
|
#define __annotate_jump_table
|
||||||
#endif /* CONFIG_OBJTOOL */
|
#endif /* CONFIG_OBJTOOL */
|
||||||
|
|
||||||
#ifndef unreachable
|
/*
|
||||||
# define unreachable() do { \
|
* Mark a position in code as unreachable. This can be used to
|
||||||
annotate_unreachable(); \
|
* suppress control flow warnings after asm blocks that transfer
|
||||||
|
* control elsewhere.
|
||||||
|
*/
|
||||||
|
#define unreachable() do { \
|
||||||
|
barrier_before_unreachable(); \
|
||||||
__builtin_unreachable(); \
|
__builtin_unreachable(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* KENTRY - kernel entry point
|
* KENTRY - kernel entry point
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_NOINSTR_VALIDATION
|
#ifdef CONFIG_NOINSTR_VALIDATION
|
||||||
|
|
||||||
|
#include <linux/objtool.h>
|
||||||
#include <linux/stringify.h>
|
#include <linux/stringify.h>
|
||||||
|
|
||||||
/* Begin/end of an instrumentation safe region */
|
/* Begin/end of an instrumentation safe region */
|
||||||
#define __instrumentation_begin(c) ({ \
|
#define __instrumentation_begin(c) ({ \
|
||||||
asm volatile(__stringify(c) ": nop\n\t" \
|
asm volatile(__stringify(c) ": nop\n\t" \
|
||||||
".pushsection .discard.instr_begin\n\t" \
|
ANNOTATE_INSTR_BEGIN(__ASM_BREF(c)) \
|
||||||
".long " __stringify(c) "b - .\n\t" \
|
: : "i" (c)); \
|
||||||
".popsection\n\t" : : "i" (c)); \
|
|
||||||
})
|
})
|
||||||
#define instrumentation_begin() __instrumentation_begin(__COUNTER__)
|
#define instrumentation_begin() __instrumentation_begin(__COUNTER__)
|
||||||
|
|
||||||
@ -48,9 +48,8 @@
|
|||||||
*/
|
*/
|
||||||
#define __instrumentation_end(c) ({ \
|
#define __instrumentation_end(c) ({ \
|
||||||
asm volatile(__stringify(c) ": nop\n\t" \
|
asm volatile(__stringify(c) ": nop\n\t" \
|
||||||
".pushsection .discard.instr_end\n\t" \
|
ANNOTATE_INSTR_END(__ASM_BREF(c)) \
|
||||||
".long " __stringify(c) "b - .\n\t" \
|
: : "i" (c)); \
|
||||||
".popsection\n\t" : : "i" (c)); \
|
|
||||||
})
|
})
|
||||||
#define instrumentation_end() __instrumentation_end(__COUNTER__)
|
#define instrumentation_end() __instrumentation_end(__COUNTER__)
|
||||||
#else /* !CONFIG_NOINSTR_VALIDATION */
|
#else /* !CONFIG_NOINSTR_VALIDATION */
|
||||||
|
@ -45,29 +45,25 @@
|
|||||||
#define STACK_FRAME_NON_STANDARD_FP(func)
|
#define STACK_FRAME_NON_STANDARD_FP(func)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ANNOTATE_NOENDBR \
|
|
||||||
"986: \n\t" \
|
|
||||||
".pushsection .discard.noendbr\n\t" \
|
|
||||||
".long 986b\n\t" \
|
|
||||||
".popsection\n\t"
|
|
||||||
|
|
||||||
#define ASM_REACHABLE \
|
#define ASM_REACHABLE \
|
||||||
"998:\n\t" \
|
"998:\n\t" \
|
||||||
".pushsection .discard.reachable\n\t" \
|
".pushsection .discard.reachable\n\t" \
|
||||||
".long 998b\n\t" \
|
".long 998b\n\t" \
|
||||||
".popsection\n\t"
|
".popsection\n\t"
|
||||||
|
|
||||||
#else /* __ASSEMBLY__ */
|
#define __ASM_BREF(label) label ## b
|
||||||
|
|
||||||
/*
|
#define __ASM_ANNOTATE(label, type) \
|
||||||
* This macro indicates that the following intra-function call is valid.
|
".pushsection .discard.annotate_insn,\"M\",@progbits,8\n\t" \
|
||||||
* Any non-annotated intra-function call will cause objtool to issue a warning.
|
".long " __stringify(label) " - .\n\t" \
|
||||||
*/
|
".long " __stringify(type) "\n\t" \
|
||||||
#define ANNOTATE_INTRA_FUNCTION_CALL \
|
".popsection\n\t"
|
||||||
999: \
|
|
||||||
.pushsection .discard.intra_function_calls; \
|
#define ASM_ANNOTATE(type) \
|
||||||
.long 999b; \
|
"911:\n\t" \
|
||||||
.popsection;
|
__ASM_ANNOTATE(911b, type)
|
||||||
|
|
||||||
|
#else /* __ASSEMBLY__ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In asm, there are two kinds of code: normal C-type callable functions and
|
* In asm, there are two kinds of code: normal C-type callable functions and
|
||||||
@ -115,34 +111,11 @@
|
|||||||
#endif
|
#endif
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro ANNOTATE_NOENDBR
|
.macro ANNOTATE type:req
|
||||||
.Lhere_\@:
|
.Lhere_\@:
|
||||||
.pushsection .discard.noendbr
|
.pushsection .discard.annotate_insn,"M",@progbits,8
|
||||||
.long .Lhere_\@
|
|
||||||
.popsection
|
|
||||||
.endm
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use objtool to validate the entry requirement that all code paths do
|
|
||||||
* VALIDATE_UNRET_END before RET.
|
|
||||||
*
|
|
||||||
* NOTE: The macro must be used at the beginning of a global symbol, otherwise
|
|
||||||
* it will be ignored.
|
|
||||||
*/
|
|
||||||
.macro VALIDATE_UNRET_BEGIN
|
|
||||||
#if defined(CONFIG_NOINSTR_VALIDATION) && \
|
|
||||||
(defined(CONFIG_MITIGATION_UNRET_ENTRY) || defined(CONFIG_MITIGATION_SRSO))
|
|
||||||
.Lhere_\@:
|
|
||||||
.pushsection .discard.validate_unret
|
|
||||||
.long .Lhere_\@ - .
|
.long .Lhere_\@ - .
|
||||||
.popsection
|
.long \type
|
||||||
#endif
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro REACHABLE
|
|
||||||
.Lhere_\@:
|
|
||||||
.pushsection .discard.reachable
|
|
||||||
.long .Lhere_\@
|
|
||||||
.popsection
|
.popsection
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
@ -155,20 +128,77 @@
|
|||||||
#define UNWIND_HINT(type, sp_reg, sp_offset, signal) "\n\t"
|
#define UNWIND_HINT(type, sp_reg, sp_offset, signal) "\n\t"
|
||||||
#define STACK_FRAME_NON_STANDARD(func)
|
#define STACK_FRAME_NON_STANDARD(func)
|
||||||
#define STACK_FRAME_NON_STANDARD_FP(func)
|
#define STACK_FRAME_NON_STANDARD_FP(func)
|
||||||
#define ANNOTATE_NOENDBR
|
#define __ASM_ANNOTATE(label, type)
|
||||||
#define ASM_REACHABLE
|
#define ASM_ANNOTATE(type)
|
||||||
#else
|
#else
|
||||||
#define ANNOTATE_INTRA_FUNCTION_CALL
|
|
||||||
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0
|
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0
|
||||||
.endm
|
.endm
|
||||||
.macro STACK_FRAME_NON_STANDARD func:req
|
.macro STACK_FRAME_NON_STANDARD func:req
|
||||||
.endm
|
.endm
|
||||||
.macro ANNOTATE_NOENDBR
|
.macro ANNOTATE type:req
|
||||||
.endm
|
|
||||||
.macro REACHABLE
|
|
||||||
.endm
|
.endm
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* CONFIG_OBJTOOL */
|
#endif /* CONFIG_OBJTOOL */
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLY__
|
||||||
|
/*
|
||||||
|
* Annotate away the various 'relocation to !ENDBR` complaints; knowing that
|
||||||
|
* these relocations will never be used for indirect calls.
|
||||||
|
*/
|
||||||
|
#define ANNOTATE_NOENDBR ASM_ANNOTATE(ANNOTYPE_NOENDBR)
|
||||||
|
/*
|
||||||
|
* This should be used immediately before an indirect jump/call. It tells
|
||||||
|
* objtool the subsequent indirect jump/call is vouched safe for retpoline
|
||||||
|
* builds.
|
||||||
|
*/
|
||||||
|
#define ANNOTATE_RETPOLINE_SAFE ASM_ANNOTATE(ANNOTYPE_RETPOLINE_SAFE)
|
||||||
|
/*
|
||||||
|
* See linux/instrumentation.h
|
||||||
|
*/
|
||||||
|
#define ANNOTATE_INSTR_BEGIN(label) __ASM_ANNOTATE(label, ANNOTYPE_INSTR_BEGIN)
|
||||||
|
#define ANNOTATE_INSTR_END(label) __ASM_ANNOTATE(label, ANNOTYPE_INSTR_END)
|
||||||
|
/*
|
||||||
|
* objtool annotation to ignore the alternatives and only consider the original
|
||||||
|
* instruction(s).
|
||||||
|
*/
|
||||||
|
#define ANNOTATE_IGNORE_ALTERNATIVE ASM_ANNOTATE(ANNOTYPE_IGNORE_ALTS)
|
||||||
|
/*
|
||||||
|
* This macro indicates that the following intra-function call is valid.
|
||||||
|
* Any non-annotated intra-function call will cause objtool to issue a warning.
|
||||||
|
*/
|
||||||
|
#define ANNOTATE_INTRA_FUNCTION_CALL ASM_ANNOTATE(ANNOTYPE_INTRA_FUNCTION_CALL)
|
||||||
|
/*
|
||||||
|
* Use objtool to validate the entry requirement that all code paths do
|
||||||
|
* VALIDATE_UNRET_END before RET.
|
||||||
|
*
|
||||||
|
* NOTE: The macro must be used at the beginning of a global symbol, otherwise
|
||||||
|
* it will be ignored.
|
||||||
|
*/
|
||||||
|
#define ANNOTATE_UNRET_BEGIN ASM_ANNOTATE(ANNOTYPE_UNRET_BEGIN)
|
||||||
|
/*
|
||||||
|
* This should be used to refer to an instruction that is considered
|
||||||
|
* terminating, like a noreturn CALL or UD2 when we know they are not -- eg
|
||||||
|
* WARN using UD2.
|
||||||
|
*/
|
||||||
|
#define ANNOTATE_REACHABLE(label) __ASM_ANNOTATE(label, ANNOTYPE_REACHABLE)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define ANNOTATE_NOENDBR ANNOTATE type=ANNOTYPE_NOENDBR
|
||||||
|
#define ANNOTATE_RETPOLINE_SAFE ANNOTATE type=ANNOTYPE_RETPOLINE_SAFE
|
||||||
|
/* ANNOTATE_INSTR_BEGIN ANNOTATE type=ANNOTYPE_INSTR_BEGIN */
|
||||||
|
/* ANNOTATE_INSTR_END ANNOTATE type=ANNOTYPE_INSTR_END */
|
||||||
|
#define ANNOTATE_IGNORE_ALTERNATIVE ANNOTATE type=ANNOTYPE_IGNORE_ALTS
|
||||||
|
#define ANNOTATE_INTRA_FUNCTION_CALL ANNOTATE type=ANNOTYPE_INTRA_FUNCTION_CALL
|
||||||
|
#define ANNOTATE_UNRET_BEGIN ANNOTATE type=ANNOTYPE_UNRET_BEGIN
|
||||||
|
#define ANNOTATE_REACHABLE ANNOTATE type=ANNOTYPE_REACHABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_NOINSTR_VALIDATION) && \
|
||||||
|
(defined(CONFIG_MITIGATION_UNRET_ENTRY) || defined(CONFIG_MITIGATION_SRSO))
|
||||||
|
#define VALIDATE_UNRET_BEGIN ANNOTATE_UNRET_BEGIN
|
||||||
|
#else
|
||||||
|
#define VALIDATE_UNRET_BEGIN
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _LINUX_OBJTOOL_H */
|
#endif /* _LINUX_OBJTOOL_H */
|
||||||
|
@ -54,4 +54,16 @@ struct unwind_hint {
|
|||||||
#define UNWIND_HINT_TYPE_SAVE 6
|
#define UNWIND_HINT_TYPE_SAVE 6
|
||||||
#define UNWIND_HINT_TYPE_RESTORE 7
|
#define UNWIND_HINT_TYPE_RESTORE 7
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotate types
|
||||||
|
*/
|
||||||
|
#define ANNOTYPE_NOENDBR 1
|
||||||
|
#define ANNOTYPE_RETPOLINE_SAFE 2
|
||||||
|
#define ANNOTYPE_INSTR_BEGIN 3
|
||||||
|
#define ANNOTYPE_INSTR_END 4
|
||||||
|
#define ANNOTYPE_UNRET_BEGIN 5
|
||||||
|
#define ANNOTYPE_IGNORE_ALTS 6
|
||||||
|
#define ANNOTYPE_INTRA_FUNCTION_CALL 7
|
||||||
|
#define ANNOTYPE_REACHABLE 8
|
||||||
|
|
||||||
#endif /* _LINUX_OBJTOOL_TYPES_H */
|
#endif /* _LINUX_OBJTOOL_TYPES_H */
|
||||||
|
@ -54,4 +54,16 @@ struct unwind_hint {
|
|||||||
#define UNWIND_HINT_TYPE_SAVE 6
|
#define UNWIND_HINT_TYPE_SAVE 6
|
||||||
#define UNWIND_HINT_TYPE_RESTORE 7
|
#define UNWIND_HINT_TYPE_RESTORE 7
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Annotate types
|
||||||
|
*/
|
||||||
|
#define ANNOTYPE_NOENDBR 1
|
||||||
|
#define ANNOTYPE_RETPOLINE_SAFE 2
|
||||||
|
#define ANNOTYPE_INSTR_BEGIN 3
|
||||||
|
#define ANNOTYPE_INSTR_END 4
|
||||||
|
#define ANNOTYPE_UNRET_BEGIN 5
|
||||||
|
#define ANNOTYPE_IGNORE_ALTS 6
|
||||||
|
#define ANNOTYPE_INTRA_FUNCTION_CALL 7
|
||||||
|
#define ANNOTYPE_REACHABLE 8
|
||||||
|
|
||||||
#endif /* _LINUX_OBJTOOL_TYPES_H */
|
#endif /* _LINUX_OBJTOOL_TYPES_H */
|
||||||
|
@ -9,7 +9,8 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct reloc *arch_find_switch_table(struct objtool_file *file,
|
struct reloc *arch_find_switch_table(struct objtool_file *file,
|
||||||
struct instruction *insn)
|
struct instruction *insn,
|
||||||
|
unsigned long *table_size)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,8 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct reloc *arch_find_switch_table(struct objtool_file *file,
|
struct reloc *arch_find_switch_table(struct objtool_file *file,
|
||||||
struct instruction *insn)
|
struct instruction *insn,
|
||||||
|
unsigned long *table_size)
|
||||||
{
|
{
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,8 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
|
|||||||
* NOTE: MITIGATION_RETPOLINE made it harder still to decode dynamic jumps.
|
* NOTE: MITIGATION_RETPOLINE made it harder still to decode dynamic jumps.
|
||||||
*/
|
*/
|
||||||
struct reloc *arch_find_switch_table(struct objtool_file *file,
|
struct reloc *arch_find_switch_table(struct objtool_file *file,
|
||||||
struct instruction *insn)
|
struct instruction *insn,
|
||||||
|
unsigned long *table_size)
|
||||||
{
|
{
|
||||||
struct reloc *text_reloc, *rodata_reloc;
|
struct reloc *text_reloc, *rodata_reloc;
|
||||||
struct section *table_sec;
|
struct section *table_sec;
|
||||||
@ -158,5 +159,6 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,
|
|||||||
if (reloc_type(text_reloc) == R_X86_64_PC32)
|
if (reloc_type(text_reloc) == R_X86_64_PC32)
|
||||||
file->ignore_unreachables = true;
|
file->ignore_unreachables = true;
|
||||||
|
|
||||||
|
*table_size = 0;
|
||||||
return rodata_reloc;
|
return rodata_reloc;
|
||||||
}
|
}
|
||||||
|
@ -150,6 +150,15 @@ static inline struct reloc *insn_jump_table(struct instruction *insn)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned long insn_jump_table_size(struct instruction *insn)
|
||||||
|
{
|
||||||
|
if (insn->type == INSN_JUMP_DYNAMIC ||
|
||||||
|
insn->type == INSN_CALL_DYNAMIC)
|
||||||
|
return insn->_jump_table_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_jump_table_jump(struct instruction *insn)
|
static bool is_jump_table_jump(struct instruction *insn)
|
||||||
{
|
{
|
||||||
struct alt_group *alt_group = insn->alt_group;
|
struct alt_group *alt_group = insn->alt_group;
|
||||||
@ -614,108 +623,6 @@ static int init_pv_ops(struct objtool_file *file)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct instruction *find_last_insn(struct objtool_file *file,
|
|
||||||
struct section *sec)
|
|
||||||
{
|
|
||||||
struct instruction *insn = NULL;
|
|
||||||
unsigned int offset;
|
|
||||||
unsigned int end = (sec->sh.sh_size > 10) ? sec->sh.sh_size - 10 : 0;
|
|
||||||
|
|
||||||
for (offset = sec->sh.sh_size - 1; offset >= end && !insn; offset--)
|
|
||||||
insn = find_insn(file, sec, offset);
|
|
||||||
|
|
||||||
return insn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mark "ud2" instructions and manually annotated dead ends.
|
|
||||||
*/
|
|
||||||
static int add_dead_ends(struct objtool_file *file)
|
|
||||||
{
|
|
||||||
struct section *rsec;
|
|
||||||
struct reloc *reloc;
|
|
||||||
struct instruction *insn;
|
|
||||||
uint64_t offset;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for manually annotated dead ends.
|
|
||||||
*/
|
|
||||||
rsec = find_section_by_name(file->elf, ".rela.discard.unreachable");
|
|
||||||
if (!rsec)
|
|
||||||
goto reachable;
|
|
||||||
|
|
||||||
for_each_reloc(rsec, reloc) {
|
|
||||||
if (reloc->sym->type == STT_SECTION) {
|
|
||||||
offset = reloc_addend(reloc);
|
|
||||||
} else if (reloc->sym->local_label) {
|
|
||||||
offset = reloc->sym->offset;
|
|
||||||
} else {
|
|
||||||
WARN("unexpected relocation symbol type in %s", rsec->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
insn = find_insn(file, reloc->sym->sec, offset);
|
|
||||||
if (insn)
|
|
||||||
insn = prev_insn_same_sec(file, insn);
|
|
||||||
else if (offset == reloc->sym->sec->sh.sh_size) {
|
|
||||||
insn = find_last_insn(file, reloc->sym->sec);
|
|
||||||
if (!insn) {
|
|
||||||
WARN("can't find unreachable insn at %s+0x%" PRIx64,
|
|
||||||
reloc->sym->sec->name, offset);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
WARN("can't find unreachable insn at %s+0x%" PRIx64,
|
|
||||||
reloc->sym->sec->name, offset);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
insn->dead_end = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
reachable:
|
|
||||||
/*
|
|
||||||
* These manually annotated reachable checks are needed for GCC 4.4,
|
|
||||||
* where the Linux unreachable() macro isn't supported. In that case
|
|
||||||
* GCC doesn't know the "ud2" is fatal, so it generates code as if it's
|
|
||||||
* not a dead end.
|
|
||||||
*/
|
|
||||||
rsec = find_section_by_name(file->elf, ".rela.discard.reachable");
|
|
||||||
if (!rsec)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for_each_reloc(rsec, reloc) {
|
|
||||||
if (reloc->sym->type == STT_SECTION) {
|
|
||||||
offset = reloc_addend(reloc);
|
|
||||||
} else if (reloc->sym->local_label) {
|
|
||||||
offset = reloc->sym->offset;
|
|
||||||
} else {
|
|
||||||
WARN("unexpected relocation symbol type in %s", rsec->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
insn = find_insn(file, reloc->sym->sec, offset);
|
|
||||||
if (insn)
|
|
||||||
insn = prev_insn_same_sec(file, insn);
|
|
||||||
else if (offset == reloc->sym->sec->sh.sh_size) {
|
|
||||||
insn = find_last_insn(file, reloc->sym->sec);
|
|
||||||
if (!insn) {
|
|
||||||
WARN("can't find reachable insn at %s+0x%" PRIx64,
|
|
||||||
reloc->sym->sec->name, offset);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
WARN("can't find reachable insn at %s+0x%" PRIx64,
|
|
||||||
reloc->sym->sec->name, offset);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
insn->dead_end = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int create_static_call_sections(struct objtool_file *file)
|
static int create_static_call_sections(struct objtool_file *file)
|
||||||
{
|
{
|
||||||
struct static_call_site *site;
|
struct static_call_site *site;
|
||||||
@ -1309,40 +1216,6 @@ static void add_uaccess_safe(struct objtool_file *file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: For now, just ignore any alternatives which add retpolines. This is
|
|
||||||
* a temporary hack, as it doesn't allow ORC to unwind from inside a retpoline.
|
|
||||||
* But it at least allows objtool to understand the control flow *around* the
|
|
||||||
* retpoline.
|
|
||||||
*/
|
|
||||||
static int add_ignore_alternatives(struct objtool_file *file)
|
|
||||||
{
|
|
||||||
struct section *rsec;
|
|
||||||
struct reloc *reloc;
|
|
||||||
struct instruction *insn;
|
|
||||||
|
|
||||||
rsec = find_section_by_name(file->elf, ".rela.discard.ignore_alts");
|
|
||||||
if (!rsec)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for_each_reloc(rsec, reloc) {
|
|
||||||
if (reloc->sym->type != STT_SECTION) {
|
|
||||||
WARN("unexpected relocation symbol type in %s", rsec->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
|
|
||||||
if (!insn) {
|
|
||||||
WARN("bad .discard.ignore_alts entry");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
insn->ignore_alts = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Symbols that replace INSN_CALL_DYNAMIC, every (tail) call to such a symbol
|
* Symbols that replace INSN_CALL_DYNAMIC, every (tail) call to such a symbol
|
||||||
* will be added to the .retpoline_sites section.
|
* will be added to the .retpoline_sites section.
|
||||||
@ -2073,6 +1946,7 @@ out:
|
|||||||
static int add_jump_table(struct objtool_file *file, struct instruction *insn,
|
static int add_jump_table(struct objtool_file *file, struct instruction *insn,
|
||||||
struct reloc *next_table)
|
struct reloc *next_table)
|
||||||
{
|
{
|
||||||
|
unsigned long table_size = insn_jump_table_size(insn);
|
||||||
struct symbol *pfunc = insn_func(insn)->pfunc;
|
struct symbol *pfunc = insn_func(insn)->pfunc;
|
||||||
struct reloc *table = insn_jump_table(insn);
|
struct reloc *table = insn_jump_table(insn);
|
||||||
struct instruction *dest_insn;
|
struct instruction *dest_insn;
|
||||||
@ -2087,6 +1961,8 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
|
|||||||
for_each_reloc_from(table->sec, reloc) {
|
for_each_reloc_from(table->sec, reloc) {
|
||||||
|
|
||||||
/* Check for the end of the table: */
|
/* Check for the end of the table: */
|
||||||
|
if (table_size && reloc_offset(reloc) - reloc_offset(table) >= table_size)
|
||||||
|
break;
|
||||||
if (reloc != table && reloc == next_table)
|
if (reloc != table && reloc == next_table)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2131,12 +2007,12 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
|
|||||||
* find_jump_table() - Given a dynamic jump, find the switch jump table
|
* find_jump_table() - Given a dynamic jump, find the switch jump table
|
||||||
* associated with it.
|
* associated with it.
|
||||||
*/
|
*/
|
||||||
static struct reloc *find_jump_table(struct objtool_file *file,
|
static void find_jump_table(struct objtool_file *file, struct symbol *func,
|
||||||
struct symbol *func,
|
struct instruction *insn)
|
||||||
struct instruction *insn)
|
|
||||||
{
|
{
|
||||||
struct reloc *table_reloc;
|
struct reloc *table_reloc;
|
||||||
struct instruction *dest_insn, *orig_insn = insn;
|
struct instruction *dest_insn, *orig_insn = insn;
|
||||||
|
unsigned long table_size;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Backward search using the @first_jump_src links, these help avoid
|
* Backward search using the @first_jump_src links, these help avoid
|
||||||
@ -2157,17 +2033,17 @@ static struct reloc *find_jump_table(struct objtool_file *file,
|
|||||||
insn->jump_dest->offset > orig_insn->offset))
|
insn->jump_dest->offset > orig_insn->offset))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
table_reloc = arch_find_switch_table(file, insn);
|
table_reloc = arch_find_switch_table(file, insn, &table_size);
|
||||||
if (!table_reloc)
|
if (!table_reloc)
|
||||||
continue;
|
continue;
|
||||||
dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc));
|
dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc));
|
||||||
if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
|
if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
return table_reloc;
|
orig_insn->_jump_table = table_reloc;
|
||||||
|
orig_insn->_jump_table_size = table_size;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2178,7 +2054,6 @@ static void mark_func_jump_tables(struct objtool_file *file,
|
|||||||
struct symbol *func)
|
struct symbol *func)
|
||||||
{
|
{
|
||||||
struct instruction *insn, *last = NULL;
|
struct instruction *insn, *last = NULL;
|
||||||
struct reloc *reloc;
|
|
||||||
|
|
||||||
func_for_each_insn(file, func, insn) {
|
func_for_each_insn(file, func, insn) {
|
||||||
if (!last)
|
if (!last)
|
||||||
@ -2201,9 +2076,7 @@ static void mark_func_jump_tables(struct objtool_file *file,
|
|||||||
if (insn->type != INSN_JUMP_DYNAMIC)
|
if (insn->type != INSN_JUMP_DYNAMIC)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
reloc = find_jump_table(file, func, insn);
|
find_jump_table(file, func, insn);
|
||||||
if (reloc)
|
|
||||||
insn->_jump_table = reloc;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2373,52 +2246,109 @@ static int read_unwind_hints(struct objtool_file *file)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_noendbr_hints(struct objtool_file *file)
|
static int read_annotate(struct objtool_file *file,
|
||||||
|
int (*func)(struct objtool_file *file, int type, struct instruction *insn))
|
||||||
{
|
{
|
||||||
|
struct section *sec;
|
||||||
struct instruction *insn;
|
struct instruction *insn;
|
||||||
struct section *rsec;
|
|
||||||
struct reloc *reloc;
|
struct reloc *reloc;
|
||||||
|
uint64_t offset;
|
||||||
|
int type, ret;
|
||||||
|
|
||||||
rsec = find_section_by_name(file->elf, ".rela.discard.noendbr");
|
sec = find_section_by_name(file->elf, ".discard.annotate_insn");
|
||||||
if (!rsec)
|
if (!sec)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for_each_reloc(rsec, reloc) {
|
if (!sec->rsec)
|
||||||
insn = find_insn(file, reloc->sym->sec,
|
return 0;
|
||||||
reloc->sym->offset + reloc_addend(reloc));
|
|
||||||
|
if (sec->sh.sh_entsize != 8) {
|
||||||
|
static bool warned = false;
|
||||||
|
if (!warned) {
|
||||||
|
WARN("%s: dodgy linker, sh_entsize != 8", sec->name);
|
||||||
|
warned = true;
|
||||||
|
}
|
||||||
|
sec->sh.sh_entsize = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_reloc(sec->rsec, reloc) {
|
||||||
|
type = *(u32 *)(sec->data->d_buf + (reloc_idx(reloc) * sec->sh.sh_entsize) + 4);
|
||||||
|
|
||||||
|
offset = reloc->sym->offset + reloc_addend(reloc);
|
||||||
|
insn = find_insn(file, reloc->sym->sec, offset);
|
||||||
|
|
||||||
if (!insn) {
|
if (!insn) {
|
||||||
WARN("bad .discard.noendbr entry");
|
WARN("bad .discard.annotate_insn entry: %d of type %d", reloc_idx(reloc), type);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
insn->noendbr = 1;
|
ret = func(file, type, insn);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_retpoline_hints(struct objtool_file *file)
|
static int __annotate_early(struct objtool_file *file, int type, struct instruction *insn)
|
||||||
{
|
{
|
||||||
struct section *rsec;
|
switch (type) {
|
||||||
struct instruction *insn;
|
case ANNOTYPE_IGNORE_ALTS:
|
||||||
struct reloc *reloc;
|
insn->ignore_alts = true;
|
||||||
|
break;
|
||||||
|
|
||||||
rsec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe");
|
/*
|
||||||
if (!rsec)
|
* Must be before read_unwind_hints() since that needs insn->noendbr.
|
||||||
|
*/
|
||||||
|
case ANNOTYPE_NOENDBR:
|
||||||
|
insn->noendbr = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __annotate_ifc(struct objtool_file *file, int type, struct instruction *insn)
|
||||||
|
{
|
||||||
|
unsigned long dest_off;
|
||||||
|
|
||||||
|
if (type != ANNOTYPE_INTRA_FUNCTION_CALL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for_each_reloc(rsec, reloc) {
|
if (insn->type != INSN_CALL) {
|
||||||
if (reloc->sym->type != STT_SECTION) {
|
WARN_INSN(insn, "intra_function_call not a direct call");
|
||||||
WARN("unexpected relocation symbol type in %s", rsec->name);
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
|
/*
|
||||||
if (!insn) {
|
* Treat intra-function CALLs as JMPs, but with a stack_op.
|
||||||
WARN("bad .discard.retpoline_safe entry");
|
* See add_call_destinations(), which strips stack_ops from
|
||||||
return -1;
|
* normal CALLs.
|
||||||
}
|
*/
|
||||||
|
insn->type = INSN_JUMP_UNCONDITIONAL;
|
||||||
|
|
||||||
|
dest_off = arch_jump_destination(insn);
|
||||||
|
insn->jump_dest = find_insn(file, insn->sec, dest_off);
|
||||||
|
if (!insn->jump_dest) {
|
||||||
|
WARN_INSN(insn, "can't find call dest at %s+0x%lx",
|
||||||
|
insn->sec->name, dest_off);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __annotate_late(struct objtool_file *file, int type, struct instruction *insn)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case ANNOTYPE_NOENDBR:
|
||||||
|
/* early */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ANNOTYPE_RETPOLINE_SAFE:
|
||||||
if (insn->type != INSN_JUMP_DYNAMIC &&
|
if (insn->type != INSN_JUMP_DYNAMIC &&
|
||||||
insn->type != INSN_CALL_DYNAMIC &&
|
insn->type != INSN_CALL_DYNAMIC &&
|
||||||
insn->type != INSN_RETURN &&
|
insn->type != INSN_RETURN &&
|
||||||
@ -2428,130 +2358,35 @@ static int read_retpoline_hints(struct objtool_file *file)
|
|||||||
}
|
}
|
||||||
|
|
||||||
insn->retpoline_safe = true;
|
insn->retpoline_safe = true;
|
||||||
}
|
break;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_instr_hints(struct objtool_file *file)
|
|
||||||
{
|
|
||||||
struct section *rsec;
|
|
||||||
struct instruction *insn;
|
|
||||||
struct reloc *reloc;
|
|
||||||
|
|
||||||
rsec = find_section_by_name(file->elf, ".rela.discard.instr_end");
|
|
||||||
if (!rsec)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for_each_reloc(rsec, reloc) {
|
|
||||||
if (reloc->sym->type != STT_SECTION) {
|
|
||||||
WARN("unexpected relocation symbol type in %s", rsec->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
|
|
||||||
if (!insn) {
|
|
||||||
WARN("bad .discard.instr_end entry");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
insn->instr--;
|
|
||||||
}
|
|
||||||
|
|
||||||
rsec = find_section_by_name(file->elf, ".rela.discard.instr_begin");
|
|
||||||
if (!rsec)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for_each_reloc(rsec, reloc) {
|
|
||||||
if (reloc->sym->type != STT_SECTION) {
|
|
||||||
WARN("unexpected relocation symbol type in %s", rsec->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
|
|
||||||
if (!insn) {
|
|
||||||
WARN("bad .discard.instr_begin entry");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
case ANNOTYPE_INSTR_BEGIN:
|
||||||
insn->instr++;
|
insn->instr++;
|
||||||
}
|
break;
|
||||||
|
|
||||||
return 0;
|
case ANNOTYPE_INSTR_END:
|
||||||
}
|
insn->instr--;
|
||||||
|
break;
|
||||||
|
|
||||||
static int read_validate_unret_hints(struct objtool_file *file)
|
case ANNOTYPE_UNRET_BEGIN:
|
||||||
{
|
|
||||||
struct section *rsec;
|
|
||||||
struct instruction *insn;
|
|
||||||
struct reloc *reloc;
|
|
||||||
|
|
||||||
rsec = find_section_by_name(file->elf, ".rela.discard.validate_unret");
|
|
||||||
if (!rsec)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for_each_reloc(rsec, reloc) {
|
|
||||||
if (reloc->sym->type != STT_SECTION) {
|
|
||||||
WARN("unexpected relocation symbol type in %s", rsec->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
|
|
||||||
if (!insn) {
|
|
||||||
WARN("bad .discard.instr_end entry");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
insn->unret = 1;
|
insn->unret = 1;
|
||||||
}
|
break;
|
||||||
|
|
||||||
return 0;
|
case ANNOTYPE_IGNORE_ALTS:
|
||||||
}
|
/* early */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ANNOTYPE_INTRA_FUNCTION_CALL:
|
||||||
|
/* ifc */
|
||||||
|
break;
|
||||||
|
|
||||||
static int read_intra_function_calls(struct objtool_file *file)
|
case ANNOTYPE_REACHABLE:
|
||||||
{
|
insn->dead_end = false;
|
||||||
struct instruction *insn;
|
break;
|
||||||
struct section *rsec;
|
|
||||||
struct reloc *reloc;
|
|
||||||
|
|
||||||
rsec = find_section_by_name(file->elf, ".rela.discard.intra_function_calls");
|
default:
|
||||||
if (!rsec)
|
WARN_INSN(insn, "Unknown annotation type: %d", type);
|
||||||
return 0;
|
break;
|
||||||
|
|
||||||
for_each_reloc(rsec, reloc) {
|
|
||||||
unsigned long dest_off;
|
|
||||||
|
|
||||||
if (reloc->sym->type != STT_SECTION) {
|
|
||||||
WARN("unexpected relocation symbol type in %s",
|
|
||||||
rsec->name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
|
|
||||||
if (!insn) {
|
|
||||||
WARN("bad .discard.intra_function_call entry");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (insn->type != INSN_CALL) {
|
|
||||||
WARN_INSN(insn, "intra_function_call not a direct call");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Treat intra-function CALLs as JMPs, but with a stack_op.
|
|
||||||
* See add_call_destinations(), which strips stack_ops from
|
|
||||||
* normal CALLs.
|
|
||||||
*/
|
|
||||||
insn->type = INSN_JUMP_UNCONDITIONAL;
|
|
||||||
|
|
||||||
dest_off = arch_jump_destination(insn);
|
|
||||||
insn->jump_dest = find_insn(file, insn->sec, dest_off);
|
|
||||||
if (!insn->jump_dest) {
|
|
||||||
WARN_INSN(insn, "can't find call dest at %s+0x%lx",
|
|
||||||
insn->sec->name, dest_off);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2666,14 +2501,7 @@ static int decode_sections(struct objtool_file *file)
|
|||||||
add_ignores(file);
|
add_ignores(file);
|
||||||
add_uaccess_safe(file);
|
add_uaccess_safe(file);
|
||||||
|
|
||||||
ret = add_ignore_alternatives(file);
|
ret = read_annotate(file, __annotate_early);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Must be before read_unwind_hints() since that needs insn->noendbr.
|
|
||||||
*/
|
|
||||||
ret = read_noendbr_hints(file);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -2695,7 +2523,7 @@ static int decode_sections(struct objtool_file *file)
|
|||||||
* Must be before add_call_destination(); it changes INSN_CALL to
|
* Must be before add_call_destination(); it changes INSN_CALL to
|
||||||
* INSN_JUMP.
|
* INSN_JUMP.
|
||||||
*/
|
*/
|
||||||
ret = read_intra_function_calls(file);
|
ret = read_annotate(file, __annotate_ifc);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -2703,14 +2531,6 @@ static int decode_sections(struct objtool_file *file)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/*
|
|
||||||
* Must be after add_call_destinations() such that it can override
|
|
||||||
* dead_end_function() marks.
|
|
||||||
*/
|
|
||||||
ret = add_dead_ends(file);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = add_jump_table_alts(file);
|
ret = add_jump_table_alts(file);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@ -2719,15 +2539,11 @@ static int decode_sections(struct objtool_file *file)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = read_retpoline_hints(file);
|
/*
|
||||||
if (ret)
|
* Must be after add_call_destinations() such that it can override
|
||||||
return ret;
|
* dead_end_function() marks.
|
||||||
|
*/
|
||||||
ret = read_instr_hints(file);
|
ret = read_annotate(file, __annotate_late);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = read_validate_unret_hints(file);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -71,7 +71,10 @@ struct instruction {
|
|||||||
struct instruction *first_jump_src;
|
struct instruction *first_jump_src;
|
||||||
union {
|
union {
|
||||||
struct symbol *_call_dest;
|
struct symbol *_call_dest;
|
||||||
struct reloc *_jump_table;
|
struct {
|
||||||
|
struct reloc *_jump_table;
|
||||||
|
unsigned long _jump_table_size;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
struct alternative *alts;
|
struct alternative *alts;
|
||||||
struct symbol *sym;
|
struct symbol *sym;
|
||||||
|
@ -38,5 +38,6 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
|
|||||||
struct instruction *insn,
|
struct instruction *insn,
|
||||||
struct reloc *reloc);
|
struct reloc *reloc);
|
||||||
struct reloc *arch_find_switch_table(struct objtool_file *file,
|
struct reloc *arch_find_switch_table(struct objtool_file *file,
|
||||||
struct instruction *insn);
|
struct instruction *insn,
|
||||||
|
unsigned long *table_size);
|
||||||
#endif /* _SPECIAL_H */
|
#endif /* _SPECIAL_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user