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 <linux/stringify.h>
|
||||
#include <linux/objtool.h>
|
||||
|
||||
#ifndef CONFIG_DEBUG_BUGVERBOSE
|
||||
#define _BUGVERBOSE_LOCATION(file, line)
|
||||
@ -33,25 +34,25 @@
|
||||
|
||||
#define ASM_BUG_FLAGS(flags) \
|
||||
__BUG_ENTRY(flags) \
|
||||
break BRK_BUG
|
||||
break BRK_BUG;
|
||||
|
||||
#define ASM_BUG() ASM_BUG_FLAGS(0)
|
||||
|
||||
#define __BUG_FLAGS(flags) \
|
||||
asm_inline volatile (__stringify(ASM_BUG_FLAGS(flags)));
|
||||
#define __BUG_FLAGS(flags, extra) \
|
||||
asm_inline volatile (__stringify(ASM_BUG_FLAGS(flags)) \
|
||||
extra);
|
||||
|
||||
#define __WARN_FLAGS(flags) \
|
||||
do { \
|
||||
instrumentation_begin(); \
|
||||
__BUG_FLAGS(BUGFLAG_WARNING|(flags)); \
|
||||
annotate_reachable(); \
|
||||
__BUG_FLAGS(BUGFLAG_WARNING|(flags), ANNOTATE_REACHABLE(10001b));\
|
||||
instrumentation_end(); \
|
||||
} while (0)
|
||||
|
||||
#define BUG() \
|
||||
do { \
|
||||
instrumentation_begin(); \
|
||||
__BUG_FLAGS(0); \
|
||||
__BUG_FLAGS(0, ""); \
|
||||
unreachable(); \
|
||||
} while (0)
|
||||
|
||||
|
@ -308,10 +308,9 @@ SYM_CODE_END(xen_error_entry)
|
||||
movq $-1, ORIG_RAX(%rsp) /* no syscall to restart */
|
||||
.endif
|
||||
|
||||
call \cfunc
|
||||
|
||||
/* For some configurations \cfunc ends up being a noreturn. */
|
||||
REACHABLE
|
||||
ANNOTATE_REACHABLE
|
||||
call \cfunc
|
||||
|
||||
jmp error_return
|
||||
.endm
|
||||
@ -529,10 +528,10 @@ SYM_CODE_START(\asmsym)
|
||||
movq %rsp, %rdi /* pt_regs pointer into first argument */
|
||||
movq ORIG_RAX(%rsp), %rsi /* get error code into 2nd argument*/
|
||||
movq $-1, ORIG_RAX(%rsp) /* no syscall to restart */
|
||||
call \cfunc
|
||||
|
||||
/* For some configurations \cfunc ends up being a noreturn. */
|
||||
REACHABLE
|
||||
ANNOTATE_REACHABLE
|
||||
call \cfunc
|
||||
|
||||
jmp paranoid_exit
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/objtool.h>
|
||||
#include <asm/asm.h>
|
||||
|
||||
#define ALT_FLAGS_SHIFT 16
|
||||
@ -54,16 +55,6 @@
|
||||
#define LOCK_PREFIX ""
|
||||
#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
|
||||
* specifying them. The split is currently like this:
|
||||
@ -310,17 +301,6 @@ void nop_func(void);
|
||||
.endm
|
||||
#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
|
||||
* the section .altinstructions, see below). This entry contains
|
||||
|
@ -92,7 +92,7 @@ do { \
|
||||
do { \
|
||||
__auto_type __flags = BUGFLAG_WARNING|(flags); \
|
||||
instrumentation_begin(); \
|
||||
_BUG_FLAGS(ASM_UD2, __flags, ASM_REACHABLE); \
|
||||
_BUG_FLAGS(ASM_UD2, __flags, ANNOTATE_REACHABLE(1b)); \
|
||||
instrumentation_end(); \
|
||||
} while (0)
|
||||
|
||||
|
@ -100,8 +100,8 @@
|
||||
}
|
||||
|
||||
#define ASM_CALL_ARG0 \
|
||||
"call %c[__func] \n" \
|
||||
ASM_REACHABLE
|
||||
"1: call %c[__func] \n" \
|
||||
ANNOTATE_REACHABLE(1b)
|
||||
|
||||
#define ASM_CALL_ARG1 \
|
||||
"movq %[arg1], %%rdi \n" \
|
||||
|
@ -179,18 +179,6 @@
|
||||
|
||||
#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
|
||||
* vs RETBleed validation.
|
||||
@ -350,12 +338,6 @@
|
||||
|
||||
#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];
|
||||
extern retpoline_thunk_t __x86_indirect_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
|
||||
if (smp_ops.stop_this_cpu) {
|
||||
smp_ops.stop_this_cpu();
|
||||
unreachable();
|
||||
BUG();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -883,7 +883,7 @@ static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
|
||||
|
||||
if (smp_ops.stop_this_cpu) {
|
||||
smp_ops.stop_this_cpu();
|
||||
unreachable();
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* Assume hlt works */
|
||||
|
@ -3820,7 +3820,7 @@ next_range:
|
||||
goto next_range;
|
||||
}
|
||||
|
||||
unreachable();
|
||||
BUG();
|
||||
}
|
||||
|
||||
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,
|
||||
, [arg1] "r" (regs), [arg2] "r" (address), [arg3] "r" (&info));
|
||||
|
||||
unreachable();
|
||||
BUG();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -52,18 +52,6 @@
|
||||
*/
|
||||
#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)
|
||||
#define __HAVE_BUILTIN_BSWAP32__
|
||||
#define __HAVE_BUILTIN_BSWAP64__
|
||||
|
@ -109,44 +109,21 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
|
||||
|
||||
/* Unreachable code */
|
||||
#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 */
|
||||
#define __annotate_jump_table __section(".rodata..c_jump_table,\"a\",@progbits #")
|
||||
|
||||
#else /* !CONFIG_OBJTOOL */
|
||||
#define annotate_reachable()
|
||||
#define annotate_unreachable()
|
||||
#define __annotate_jump_table
|
||||
#endif /* CONFIG_OBJTOOL */
|
||||
|
||||
#ifndef unreachable
|
||||
# define unreachable() do { \
|
||||
annotate_unreachable(); \
|
||||
/*
|
||||
* 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 { \
|
||||
barrier_before_unreachable(); \
|
||||
__builtin_unreachable(); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* KENTRY - kernel entry point
|
||||
|
@ -4,14 +4,14 @@
|
||||
|
||||
#ifdef CONFIG_NOINSTR_VALIDATION
|
||||
|
||||
#include <linux/objtool.h>
|
||||
#include <linux/stringify.h>
|
||||
|
||||
/* Begin/end of an instrumentation safe region */
|
||||
#define __instrumentation_begin(c) ({ \
|
||||
asm volatile(__stringify(c) ": nop\n\t" \
|
||||
".pushsection .discard.instr_begin\n\t" \
|
||||
".long " __stringify(c) "b - .\n\t" \
|
||||
".popsection\n\t" : : "i" (c)); \
|
||||
ANNOTATE_INSTR_BEGIN(__ASM_BREF(c)) \
|
||||
: : "i" (c)); \
|
||||
})
|
||||
#define instrumentation_begin() __instrumentation_begin(__COUNTER__)
|
||||
|
||||
@ -48,9 +48,8 @@
|
||||
*/
|
||||
#define __instrumentation_end(c) ({ \
|
||||
asm volatile(__stringify(c) ": nop\n\t" \
|
||||
".pushsection .discard.instr_end\n\t" \
|
||||
".long " __stringify(c) "b - .\n\t" \
|
||||
".popsection\n\t" : : "i" (c)); \
|
||||
ANNOTATE_INSTR_END(__ASM_BREF(c)) \
|
||||
: : "i" (c)); \
|
||||
})
|
||||
#define instrumentation_end() __instrumentation_end(__COUNTER__)
|
||||
#else /* !CONFIG_NOINSTR_VALIDATION */
|
||||
|
@ -45,29 +45,25 @@
|
||||
#define STACK_FRAME_NON_STANDARD_FP(func)
|
||||
#endif
|
||||
|
||||
#define ANNOTATE_NOENDBR \
|
||||
"986: \n\t" \
|
||||
".pushsection .discard.noendbr\n\t" \
|
||||
".long 986b\n\t" \
|
||||
".popsection\n\t"
|
||||
|
||||
#define ASM_REACHABLE \
|
||||
"998:\n\t" \
|
||||
".pushsection .discard.reachable\n\t" \
|
||||
".long 998b\n\t" \
|
||||
".popsection\n\t"
|
||||
|
||||
#else /* __ASSEMBLY__ */
|
||||
#define __ASM_BREF(label) label ## b
|
||||
|
||||
/*
|
||||
* 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 \
|
||||
999: \
|
||||
.pushsection .discard.intra_function_calls; \
|
||||
.long 999b; \
|
||||
.popsection;
|
||||
#define __ASM_ANNOTATE(label, type) \
|
||||
".pushsection .discard.annotate_insn,\"M\",@progbits,8\n\t" \
|
||||
".long " __stringify(label) " - .\n\t" \
|
||||
".long " __stringify(type) "\n\t" \
|
||||
".popsection\n\t"
|
||||
|
||||
#define ASM_ANNOTATE(type) \
|
||||
"911:\n\t" \
|
||||
__ASM_ANNOTATE(911b, type)
|
||||
|
||||
#else /* __ASSEMBLY__ */
|
||||
|
||||
/*
|
||||
* In asm, there are two kinds of code: normal C-type callable functions and
|
||||
@ -115,34 +111,11 @@
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro ANNOTATE_NOENDBR
|
||||
.macro ANNOTATE type:req
|
||||
.Lhere_\@:
|
||||
.pushsection .discard.noendbr
|
||||
.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
|
||||
.pushsection .discard.annotate_insn,"M",@progbits,8
|
||||
.long .Lhere_\@ - .
|
||||
.popsection
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro REACHABLE
|
||||
.Lhere_\@:
|
||||
.pushsection .discard.reachable
|
||||
.long .Lhere_\@
|
||||
.long \type
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
@ -155,20 +128,77 @@
|
||||
#define UNWIND_HINT(type, sp_reg, sp_offset, signal) "\n\t"
|
||||
#define STACK_FRAME_NON_STANDARD(func)
|
||||
#define STACK_FRAME_NON_STANDARD_FP(func)
|
||||
#define ANNOTATE_NOENDBR
|
||||
#define ASM_REACHABLE
|
||||
#define __ASM_ANNOTATE(label, type)
|
||||
#define ASM_ANNOTATE(type)
|
||||
#else
|
||||
#define ANNOTATE_INTRA_FUNCTION_CALL
|
||||
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0
|
||||
.endm
|
||||
.macro STACK_FRAME_NON_STANDARD func:req
|
||||
.endm
|
||||
.macro ANNOTATE_NOENDBR
|
||||
.endm
|
||||
.macro REACHABLE
|
||||
.macro ANNOTATE type:req
|
||||
.endm
|
||||
#endif
|
||||
|
||||
#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 */
|
||||
|
@ -54,4 +54,16 @@ struct unwind_hint {
|
||||
#define UNWIND_HINT_TYPE_SAVE 6
|
||||
#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 */
|
||||
|
@ -54,4 +54,16 @@ struct unwind_hint {
|
||||
#define UNWIND_HINT_TYPE_SAVE 6
|
||||
#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 */
|
||||
|
@ -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 instruction *insn)
|
||||
struct instruction *insn,
|
||||
unsigned long *table_size)
|
||||
{
|
||||
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 instruction *insn)
|
||||
struct instruction *insn,
|
||||
unsigned long *table_size)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
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 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)
|
||||
file->ignore_unreachables = true;
|
||||
|
||||
*table_size = 0;
|
||||
return rodata_reloc;
|
||||
}
|
||||
|
@ -150,6 +150,15 @@ static inline struct reloc *insn_jump_table(struct instruction *insn)
|
||||
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)
|
||||
{
|
||||
struct alt_group *alt_group = insn->alt_group;
|
||||
@ -614,108 +623,6 @@ static int init_pv_ops(struct objtool_file *file)
|
||||
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)
|
||||
{
|
||||
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
|
||||
* 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,
|
||||
struct reloc *next_table)
|
||||
{
|
||||
unsigned long table_size = insn_jump_table_size(insn);
|
||||
struct symbol *pfunc = insn_func(insn)->pfunc;
|
||||
struct reloc *table = insn_jump_table(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) {
|
||||
|
||||
/* 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)
|
||||
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
|
||||
* associated with it.
|
||||
*/
|
||||
static struct reloc *find_jump_table(struct objtool_file *file,
|
||||
struct symbol *func,
|
||||
struct instruction *insn)
|
||||
static void find_jump_table(struct objtool_file *file, struct symbol *func,
|
||||
struct instruction *insn)
|
||||
{
|
||||
struct reloc *table_reloc;
|
||||
struct instruction *dest_insn, *orig_insn = insn;
|
||||
unsigned long table_size;
|
||||
|
||||
/*
|
||||
* 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))
|
||||
break;
|
||||
|
||||
table_reloc = arch_find_switch_table(file, insn);
|
||||
table_reloc = arch_find_switch_table(file, insn, &table_size);
|
||||
if (!table_reloc)
|
||||
continue;
|
||||
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)
|
||||
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 instruction *insn, *last = NULL;
|
||||
struct reloc *reloc;
|
||||
|
||||
func_for_each_insn(file, func, insn) {
|
||||
if (!last)
|
||||
@ -2201,9 +2076,7 @@ static void mark_func_jump_tables(struct objtool_file *file,
|
||||
if (insn->type != INSN_JUMP_DYNAMIC)
|
||||
continue;
|
||||
|
||||
reloc = find_jump_table(file, func, insn);
|
||||
if (reloc)
|
||||
insn->_jump_table = reloc;
|
||||
find_jump_table(file, func, insn);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2373,52 +2246,109 @@ static int read_unwind_hints(struct objtool_file *file)
|
||||
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 section *rsec;
|
||||
struct reloc *reloc;
|
||||
uint64_t offset;
|
||||
int type, ret;
|
||||
|
||||
rsec = find_section_by_name(file->elf, ".rela.discard.noendbr");
|
||||
if (!rsec)
|
||||
sec = find_section_by_name(file->elf, ".discard.annotate_insn");
|
||||
if (!sec)
|
||||
return 0;
|
||||
|
||||
for_each_reloc(rsec, reloc) {
|
||||
insn = find_insn(file, reloc->sym->sec,
|
||||
reloc->sym->offset + reloc_addend(reloc));
|
||||
if (!sec->rsec)
|
||||
return 0;
|
||||
|
||||
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) {
|
||||
WARN("bad .discard.noendbr entry");
|
||||
WARN("bad .discard.annotate_insn entry: %d of type %d", reloc_idx(reloc), type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
insn->noendbr = 1;
|
||||
ret = func(file, type, insn);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
struct instruction *insn;
|
||||
struct reloc *reloc;
|
||||
switch (type) {
|
||||
case ANNOTYPE_IGNORE_ALTS:
|
||||
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;
|
||||
|
||||
for_each_reloc(rsec, reloc) {
|
||||
if (reloc->sym->type != STT_SECTION) {
|
||||
WARN("unexpected relocation symbol type in %s", rsec->name);
|
||||
return -1;
|
||||
}
|
||||
if (insn->type != INSN_CALL) {
|
||||
WARN_INSN(insn, "intra_function_call not a direct call");
|
||||
return -1;
|
||||
}
|
||||
|
||||
insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
|
||||
if (!insn) {
|
||||
WARN("bad .discard.retpoline_safe entry");
|
||||
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;
|
||||
}
|
||||
|
||||
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 &&
|
||||
insn->type != INSN_CALL_DYNAMIC &&
|
||||
insn->type != INSN_RETURN &&
|
||||
@ -2428,130 +2358,35 @@ static int read_retpoline_hints(struct objtool_file *file)
|
||||
}
|
||||
|
||||
insn->retpoline_safe = true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case ANNOTYPE_INSTR_BEGIN:
|
||||
insn->instr++;
|
||||
}
|
||||
break;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case ANNOTYPE_INSTR_END:
|
||||
insn->instr--;
|
||||
break;
|
||||
|
||||
static int read_validate_unret_hints(struct objtool_file *file)
|
||||
{
|
||||
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;
|
||||
}
|
||||
case ANNOTYPE_UNRET_BEGIN:
|
||||
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)
|
||||
{
|
||||
struct instruction *insn;
|
||||
struct section *rsec;
|
||||
struct reloc *reloc;
|
||||
case ANNOTYPE_REACHABLE:
|
||||
insn->dead_end = false;
|
||||
break;
|
||||
|
||||
rsec = find_section_by_name(file->elf, ".rela.discard.intra_function_calls");
|
||||
if (!rsec)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
default:
|
||||
WARN_INSN(insn, "Unknown annotation type: %d", type);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2666,14 +2501,7 @@ static int decode_sections(struct objtool_file *file)
|
||||
add_ignores(file);
|
||||
add_uaccess_safe(file);
|
||||
|
||||
ret = add_ignore_alternatives(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Must be before read_unwind_hints() since that needs insn->noendbr.
|
||||
*/
|
||||
ret = read_noendbr_hints(file);
|
||||
ret = read_annotate(file, __annotate_early);
|
||||
if (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
|
||||
* INSN_JUMP.
|
||||
*/
|
||||
ret = read_intra_function_calls(file);
|
||||
ret = read_annotate(file, __annotate_ifc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -2703,14 +2531,6 @@ static int decode_sections(struct objtool_file *file)
|
||||
if (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);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -2719,15 +2539,11 @@ static int decode_sections(struct objtool_file *file)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = read_retpoline_hints(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = read_instr_hints(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = read_validate_unret_hints(file);
|
||||
/*
|
||||
* Must be after add_call_destinations() such that it can override
|
||||
* dead_end_function() marks.
|
||||
*/
|
||||
ret = read_annotate(file, __annotate_late);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -71,7 +71,10 @@ struct instruction {
|
||||
struct instruction *first_jump_src;
|
||||
union {
|
||||
struct symbol *_call_dest;
|
||||
struct reloc *_jump_table;
|
||||
struct {
|
||||
struct reloc *_jump_table;
|
||||
unsigned long _jump_table_size;
|
||||
};
|
||||
};
|
||||
struct alternative *alts;
|
||||
struct symbol *sym;
|
||||
|
@ -38,5 +38,6 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
|
||||
struct instruction *insn,
|
||||
struct reloc *reloc);
|
||||
struct reloc *arch_find_switch_table(struct objtool_file *file,
|
||||
struct instruction *insn);
|
||||
struct instruction *insn,
|
||||
unsigned long *table_size);
|
||||
#endif /* _SPECIAL_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user