Commit 6f612579 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'objtool-core-2023-06-27' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool updates from Ingo Molar:
 "Build footprint & performance improvements:

   - Reduce memory usage with CONFIG_DEBUG_INFO=y

     In the worst case of an allyesconfig+CONFIG_DEBUG_INFO=y kernel,
     DWARF creates almost 200 million relocations, ballooning objtool's
     peak heap usage to 53GB. These patches reduce that to 25GB.

     On a distro-type kernel with kernel IBT enabled, they reduce
     objtool's peak heap usage from 4.2GB to 2.8GB.

     These changes also improve the runtime significantly.

  Debuggability improvements:

   - Add the unwind_debug command-line option, for more extend unwinding
     debugging output
   - Limit unreachable warnings to once per function
   - Add verbose option for disassembling affected functions
   - Include backtrace in verbose mode
   - Detect missing __noreturn annotations
   - Ignore exc_double_fault() __noreturn warnings
   - Remove superfluous global_noreturns entries
   - Move noreturn function list to separate file
   - Add __kunit_abort() to noreturns

  Unwinder improvements:

   - Allow stack operations in UNWIND_HINT_UNDEFINED regions
   - drm/vmwgfx: Add unwind hints around RBP clobber

  Cleanups:

   - Move the x86 entry thunk restore code into thunk functions
   - x86/unwind/orc: Use swap() instead of open coding it
   - Remove unnecessary/unused variables

  Fixes for modern stack canary handling"

* tag 'objtool-core-2023-06-27' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (42 commits)
  x86/orc: Make the is_callthunk() definition depend on CONFIG_BPF_JIT=y
  objtool: Skip reading DWARF section data
  objtool: Free insns when done
  objtool: Get rid of reloc->rel[a]
  objtool: Shrink elf hash nodes
  objtool: Shrink reloc->sym_reloc_entry
  objtool: Get rid of reloc->jump_table_start
  objtool: Get rid of reloc->addend
  objtool: Get rid of reloc->type
  objtool: Get rid of reloc->offset
  objtool: Get rid of reloc->idx
  objtool: Get rid of reloc->list
  objtool: Allocate relocs in advance for new rela sections
  objtool: Add for_each_reloc()
  objtool: Don't free memory in elf_close()
  objtool: Keep GElf_Rel[a] structs synced
  objtool: Add elf_create_section_pair()
  objtool: Add mark_sec_changed()
  objtool: Fix reloc_hash size
  objtool: Consolidate rel/rela handling
  ...
parents 4d675181 301cf77e
...@@ -6598,6 +6598,12 @@ ...@@ -6598,6 +6598,12 @@
unknown_nmi_panic unknown_nmi_panic
[X86] Cause panic on unknown NMI. [X86] Cause panic on unknown NMI.
unwind_debug [X86-64]
Enable unwinder debug output. This can be
useful for debugging certain unwinder error
conditions, including corrupt stacks and
bad/missing unwinder metadata.
usbcore.authorized_default= usbcore.authorized_default=
[USB] Default USB device authorization: [USB] Default USB device authorization:
(default -1 = authorized except for wireless USB, (default -1 = authorized except for wireless USB,
......
...@@ -1605,6 +1605,7 @@ static void add_cpu_to_masks(int cpu) ...@@ -1605,6 +1605,7 @@ static void add_cpu_to_masks(int cpu)
} }
/* Activate a secondary processor. */ /* Activate a secondary processor. */
__no_stack_protector
void start_secondary(void *unused) void start_secondary(void *unused)
{ {
unsigned int cpu = raw_smp_processor_id(); unsigned int cpu = raw_smp_processor_id();
......
...@@ -26,17 +26,7 @@ SYM_FUNC_START(\name) ...@@ -26,17 +26,7 @@ SYM_FUNC_START(\name)
pushq %r11 pushq %r11
call \func call \func
jmp __thunk_restore
SYM_FUNC_END(\name)
_ASM_NOKPROBE(\name)
.endm
THUNK preempt_schedule_thunk, preempt_schedule
THUNK preempt_schedule_notrace_thunk, preempt_schedule_notrace
EXPORT_SYMBOL(preempt_schedule_thunk)
EXPORT_SYMBOL(preempt_schedule_notrace_thunk)
SYM_CODE_START_LOCAL(__thunk_restore)
popq %r11 popq %r11
popq %r10 popq %r10
popq %r9 popq %r9
...@@ -48,5 +38,11 @@ SYM_CODE_START_LOCAL(__thunk_restore) ...@@ -48,5 +38,11 @@ SYM_CODE_START_LOCAL(__thunk_restore)
popq %rdi popq %rdi
popq %rbp popq %rbp
RET RET
_ASM_NOKPROBE(__thunk_restore) SYM_FUNC_END(\name)
SYM_CODE_END(__thunk_restore) _ASM_NOKPROBE(\name)
.endm
THUNK preempt_schedule_thunk, preempt_schedule
THUNK preempt_schedule_notrace_thunk, preempt_schedule_notrace
EXPORT_SYMBOL(preempt_schedule_thunk)
EXPORT_SYMBOL(preempt_schedule_notrace_thunk)
...@@ -113,7 +113,6 @@ extern void callthunks_patch_builtin_calls(void); ...@@ -113,7 +113,6 @@ extern void callthunks_patch_builtin_calls(void);
extern void callthunks_patch_module_calls(struct callthunk_sites *sites, extern void callthunks_patch_module_calls(struct callthunk_sites *sites,
struct module *mod); struct module *mod);
extern void *callthunks_translate_call_dest(void *dest); extern void *callthunks_translate_call_dest(void *dest);
extern bool is_callthunk(void *addr);
extern int x86_call_depth_emit_accounting(u8 **pprog, void *func); extern int x86_call_depth_emit_accounting(u8 **pprog, void *func);
#else #else
static __always_inline void callthunks_patch_builtin_calls(void) {} static __always_inline void callthunks_patch_builtin_calls(void) {}
...@@ -124,10 +123,6 @@ static __always_inline void *callthunks_translate_call_dest(void *dest) ...@@ -124,10 +123,6 @@ static __always_inline void *callthunks_translate_call_dest(void *dest)
{ {
return dest; return dest;
} }
static __always_inline bool is_callthunk(void *addr)
{
return false;
}
static __always_inline int x86_call_depth_emit_accounting(u8 **pprog, static __always_inline int x86_call_depth_emit_accounting(u8 **pprog,
void *func) void *func)
{ {
......
...@@ -76,9 +76,18 @@ ...@@ -76,9 +76,18 @@
#else #else
#define UNWIND_HINT_UNDEFINED \
UNWIND_HINT(UNWIND_HINT_TYPE_UNDEFINED, 0, 0, 0)
#define UNWIND_HINT_FUNC \ #define UNWIND_HINT_FUNC \
UNWIND_HINT(UNWIND_HINT_TYPE_FUNC, ORC_REG_SP, 8, 0) UNWIND_HINT(UNWIND_HINT_TYPE_FUNC, ORC_REG_SP, 8, 0)
#define UNWIND_HINT_SAVE \
UNWIND_HINT(UNWIND_HINT_TYPE_SAVE, 0, 0, 0)
#define UNWIND_HINT_RESTORE \
UNWIND_HINT(UNWIND_HINT_TYPE_RESTORE, 0, 0, 0)
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* _ASM_X86_UNWIND_HINTS_H */ #endif /* _ASM_X86_UNWIND_HINTS_H */
...@@ -293,7 +293,8 @@ void *callthunks_translate_call_dest(void *dest) ...@@ -293,7 +293,8 @@ void *callthunks_translate_call_dest(void *dest)
return target ? : dest; return target ? : dest;
} }
bool is_callthunk(void *addr) #ifdef CONFIG_BPF_JIT
static bool is_callthunk(void *addr)
{ {
unsigned int tmpl_size = SKL_TMPL_SIZE; unsigned int tmpl_size = SKL_TMPL_SIZE;
void *tmpl = skl_call_thunk_template; void *tmpl = skl_call_thunk_template;
...@@ -306,7 +307,6 @@ bool is_callthunk(void *addr) ...@@ -306,7 +307,6 @@ bool is_callthunk(void *addr)
return !bcmp((void *)(dest - tmpl_size), tmpl, tmpl_size); return !bcmp((void *)(dest - tmpl_size), tmpl, tmpl_size);
} }
#ifdef CONFIG_BPF_JIT
int x86_call_depth_emit_accounting(u8 **pprog, void *func) int x86_call_depth_emit_accounting(u8 **pprog, void *func)
{ {
unsigned int tmpl_size = SKL_TMPL_SIZE; unsigned int tmpl_size = SKL_TMPL_SIZE;
......
...@@ -16,8 +16,14 @@ ORC_HEADER; ...@@ -16,8 +16,14 @@ ORC_HEADER;
#define orc_warn_current(args...) \ #define orc_warn_current(args...) \
({ \ ({ \
if (state->task == current && !state->error) \ static bool dumped_before; \
if (state->task == current && !state->error) { \
orc_warn(args); \ orc_warn(args); \
if (unwind_debug && !dumped_before) { \
dumped_before = true; \
unwind_dump(state); \
} \
} \
}) })
extern int __start_orc_unwind_ip[]; extern int __start_orc_unwind_ip[];
...@@ -26,8 +32,49 @@ extern struct orc_entry __start_orc_unwind[]; ...@@ -26,8 +32,49 @@ extern struct orc_entry __start_orc_unwind[];
extern struct orc_entry __stop_orc_unwind[]; extern struct orc_entry __stop_orc_unwind[];
static bool orc_init __ro_after_init; static bool orc_init __ro_after_init;
static bool unwind_debug __ro_after_init;
static unsigned int lookup_num_blocks __ro_after_init; static unsigned int lookup_num_blocks __ro_after_init;
static int __init unwind_debug_cmdline(char *str)
{
unwind_debug = true;
return 0;
}
early_param("unwind_debug", unwind_debug_cmdline);
static void unwind_dump(struct unwind_state *state)
{
static bool dumped_before;
unsigned long word, *sp;
struct stack_info stack_info = {0};
unsigned long visit_mask = 0;
if (dumped_before)
return;
dumped_before = true;
printk_deferred("unwind stack type:%d next_sp:%p mask:0x%lx graph_idx:%d\n",
state->stack_info.type, state->stack_info.next_sp,
state->stack_mask, state->graph_idx);
for (sp = __builtin_frame_address(0); sp;
sp = PTR_ALIGN(stack_info.next_sp, sizeof(long))) {
if (get_stack_info(sp, state->task, &stack_info, &visit_mask))
break;
for (; sp < stack_info.end; sp++) {
word = READ_ONCE_NOCHECK(*sp);
printk_deferred("%0*lx: %0*lx (%pB)\n", BITS_PER_LONG/4,
(unsigned long)sp, BITS_PER_LONG/4,
word, (void *)word);
}
}
}
static inline unsigned long orc_ip(const int *ip) static inline unsigned long orc_ip(const int *ip)
{ {
return (unsigned long)ip + *ip; return (unsigned long)ip + *ip;
...@@ -139,21 +186,6 @@ static struct orc_entry null_orc_entry = { ...@@ -139,21 +186,6 @@ static struct orc_entry null_orc_entry = {
.type = ORC_TYPE_CALL .type = ORC_TYPE_CALL
}; };
#ifdef CONFIG_CALL_THUNKS
static struct orc_entry *orc_callthunk_find(unsigned long ip)
{
if (!is_callthunk((void *)ip))
return NULL;
return &null_orc_entry;
}
#else
static struct orc_entry *orc_callthunk_find(unsigned long ip)
{
return NULL;
}
#endif
/* Fake frame pointer entry -- used as a fallback for generated code */ /* Fake frame pointer entry -- used as a fallback for generated code */
static struct orc_entry orc_fp_entry = { static struct orc_entry orc_fp_entry = {
.type = ORC_TYPE_CALL, .type = ORC_TYPE_CALL,
...@@ -206,11 +238,7 @@ static struct orc_entry *orc_find(unsigned long ip) ...@@ -206,11 +238,7 @@ static struct orc_entry *orc_find(unsigned long ip)
if (orc) if (orc)
return orc; return orc;
orc = orc_ftrace_find(ip); return orc_ftrace_find(ip);
if (orc)
return orc;
return orc_callthunk_find(ip);
} }
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
...@@ -222,7 +250,6 @@ static struct orc_entry *cur_orc_table = __start_orc_unwind; ...@@ -222,7 +250,6 @@ static struct orc_entry *cur_orc_table = __start_orc_unwind;
static void orc_sort_swap(void *_a, void *_b, int size) static void orc_sort_swap(void *_a, void *_b, int size)
{ {
struct orc_entry *orc_a, *orc_b; struct orc_entry *orc_a, *orc_b;
struct orc_entry orc_tmp;
int *a = _a, *b = _b, tmp; int *a = _a, *b = _b, tmp;
int delta = _b - _a; int delta = _b - _a;
...@@ -234,9 +261,7 @@ static void orc_sort_swap(void *_a, void *_b, int size) ...@@ -234,9 +261,7 @@ static void orc_sort_swap(void *_a, void *_b, int size)
/* Swap the corresponding .orc_unwind entries: */ /* Swap the corresponding .orc_unwind entries: */
orc_a = cur_orc_table + (a - cur_orc_ip_table); orc_a = cur_orc_table + (a - cur_orc_ip_table);
orc_b = cur_orc_table + (b - cur_orc_ip_table); orc_b = cur_orc_table + (b - cur_orc_ip_table);
orc_tmp = *orc_a; swap(*orc_a, *orc_b);
*orc_a = *orc_b;
*orc_b = orc_tmp;
} }
static int orc_sort_cmp(const void *_a, const void *_b) static int orc_sort_cmp(const void *_a, const void *_b)
......
...@@ -105,10 +105,14 @@ ...@@ -105,10 +105,14 @@
flags, magic, bp, \ flags, magic, bp, \
eax, ebx, ecx, edx, si, di) \ eax, ebx, ecx, edx, si, di) \
({ \ ({ \
asm volatile ("push %%rbp;" \ asm volatile ( \
UNWIND_HINT_SAVE \
"push %%rbp;" \
UNWIND_HINT_UNDEFINED \
"mov %12, %%rbp;" \ "mov %12, %%rbp;" \
VMWARE_HYPERCALL_HB_OUT \ VMWARE_HYPERCALL_HB_OUT \
"pop %%rbp;" : \ "pop %%rbp;" \
UNWIND_HINT_RESTORE : \
"=a"(eax), \ "=a"(eax), \
"=b"(ebx), \ "=b"(ebx), \
"=c"(ecx), \ "=c"(ecx), \
...@@ -130,10 +134,14 @@ ...@@ -130,10 +134,14 @@
flags, magic, bp, \ flags, magic, bp, \
eax, ebx, ecx, edx, si, di) \ eax, ebx, ecx, edx, si, di) \
({ \ ({ \
asm volatile ("push %%rbp;" \ asm volatile ( \
UNWIND_HINT_SAVE \
"push %%rbp;" \
UNWIND_HINT_UNDEFINED \
"mov %12, %%rbp;" \ "mov %12, %%rbp;" \
VMWARE_HYPERCALL_HB_IN \ VMWARE_HYPERCALL_HB_IN \
"pop %%rbp" : \ "pop %%rbp;" \
UNWIND_HINT_RESTORE : \
"=a"(eax), \ "=a"(eax), \
"=b"(ebx), \ "=b"(ebx), \
"=c"(ecx), \ "=c"(ecx), \
......
...@@ -487,6 +487,7 @@ static void lkdtm_UNSET_SMEP(void) ...@@ -487,6 +487,7 @@ static void lkdtm_UNSET_SMEP(void)
* the cr4 writing instruction. * the cr4 writing instruction.
*/ */
insn = (unsigned char *)native_write_cr4; insn = (unsigned char *)native_write_cr4;
OPTIMIZER_HIDE_VAR(insn);
for (i = 0; i < MOV_CR4_DEPTH; i++) { for (i = 0; i < MOV_CR4_DEPTH; i++) {
/* mov %rdi, %cr4 */ /* mov %rdi, %cr4 */
if (insn[i] == 0x0f && insn[i+1] == 0x22 && insn[i+2] == 0xe7) if (insn[i] == 0x0f && insn[i+1] == 0x22 && insn[i+2] == 0xe7)
......
...@@ -255,6 +255,18 @@ ...@@ -255,6 +255,18 @@
*/ */
#define __noreturn __attribute__((__noreturn__)) #define __noreturn __attribute__((__noreturn__))
/*
* Optional: only supported since GCC >= 11.1, clang >= 7.0.
*
* gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-no_005fstack_005fprotector-function-attribute
* clang: https://clang.llvm.org/docs/AttributeReference.html#no-stack-protector-safebuffers
*/
#if __has_attribute(__no_stack_protector__)
# define __no_stack_protector __attribute__((__no_stack_protector__))
#else
# define __no_stack_protector
#endif
/* /*
* Optional: not supported by gcc. * Optional: not supported by gcc.
* *
......
...@@ -873,7 +873,8 @@ static void __init print_unknown_bootoptions(void) ...@@ -873,7 +873,8 @@ static void __init print_unknown_bootoptions(void)
memblock_free(unknown_options, len); memblock_free(unknown_options, len);
} }
asmlinkage __visible void __init __no_sanitize_address __noreturn start_kernel(void) asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
void start_kernel(void)
{ {
char *command_line; char *command_line;
char *after_dashes; char *after_dashes;
...@@ -1073,7 +1074,13 @@ asmlinkage __visible void __init __no_sanitize_address __noreturn start_kernel(v ...@@ -1073,7 +1074,13 @@ asmlinkage __visible void __init __no_sanitize_address __noreturn start_kernel(v
/* Do the rest non-__init'ed, we're now alive */ /* Do the rest non-__init'ed, we're now alive */
arch_call_rest_init(); arch_call_rest_init();
/*
* Avoid stack canaries in callers of boot_init_stack_canary for gcc-10
* and older.
*/
#if !__has_attribute(__no_stack_protector__)
prevent_tail_call_optimization(); prevent_tail_call_optimization();
#endif
} }
/* Call all constructor functions linked into the kernel. */ /* Call all constructor functions linked into the kernel. */
......
...@@ -6,10 +6,6 @@ ...@@ -6,10 +6,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#ifndef NORETURN
#define NORETURN __attribute__((__noreturn__))
#endif
enum parse_opt_type { enum parse_opt_type {
/* special types */ /* special types */
OPTION_END, OPTION_END,
...@@ -183,9 +179,9 @@ extern int parse_options_subcommand(int argc, const char **argv, ...@@ -183,9 +179,9 @@ extern int parse_options_subcommand(int argc, const char **argv,
const char *const subcommands[], const char *const subcommands[],
const char *usagestr[], int flags); const char *usagestr[], int flags);
extern NORETURN void usage_with_options(const char * const *usagestr, extern __noreturn void usage_with_options(const char * const *usagestr,
const struct option *options); const struct option *options);
extern NORETURN __attribute__((format(printf,3,4))) extern __noreturn __attribute__((format(printf,3,4)))
void usage_with_options_msg(const char * const *usagestr, void usage_with_options_msg(const char * const *usagestr,
const struct option *options, const struct option *options,
const char *fmt, ...); const char *fmt, ...);
......
...@@ -5,8 +5,7 @@ ...@@ -5,8 +5,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <linux/compiler.h>
#define NORETURN __attribute__((__noreturn__))
static inline void report(const char *prefix, const char *err, va_list params) static inline void report(const char *prefix, const char *err, va_list params)
{ {
...@@ -15,7 +14,7 @@ static inline void report(const char *prefix, const char *err, va_list params) ...@@ -15,7 +14,7 @@ static inline void report(const char *prefix, const char *err, va_list params)
fprintf(stderr, " %s%s\n", prefix, msg); fprintf(stderr, " %s%s\n", prefix, msg);
} }
static NORETURN inline void die(const char *err, ...) static __noreturn inline void die(const char *err, ...)
{ {
va_list params; va_list params;
......
...@@ -244,6 +244,11 @@ To achieve the validation, objtool enforces the following rules: ...@@ -244,6 +244,11 @@ To achieve the validation, objtool enforces the following rules:
Objtool warnings Objtool warnings
---------------- ----------------
NOTE: When requesting help with an objtool warning, please recreate with
OBJTOOL_VERBOSE=1 (e.g., "make OBJTOOL_VERBOSE=1") and send the full
output, including any disassembly or backtrace below the warning, to the
objtool maintainers.
For asm files, if you're getting an error which doesn't make sense, For asm files, if you're getting an error which doesn't make sense,
first make sure that the affected code follows the above rules. first make sure that the affected code follows the above rules.
...@@ -298,6 +303,11 @@ the objtool maintainers. ...@@ -298,6 +303,11 @@ the objtool maintainers.
If it's not actually in a callable function (e.g. kernel entry code), If it's not actually in a callable function (e.g. kernel entry code),
change ENDPROC to END. change ENDPROC to END.
3. file.o: warning: objtool: foo+0x48c: bar() is missing a __noreturn annotation
The call from foo() to bar() doesn't return, but bar() is missing the
__noreturn annotation. NOTE: In addition to annotating the function
with __noreturn, please also add it to tools/objtool/noreturns.h.
4. file.o: warning: objtool: func(): can't find starting instruction 4. file.o: warning: objtool: func(): can't find starting instruction
or or
......
/* SPDX-License-Identifier: GPL-2.0-or-later */ /* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _OBJTOOL_ARCH_ELF #ifndef _OBJTOOL_ARCH_ELF
#define _OBJTOOL_ARCH_ELF #define _OBJTOOL_ARCH_ELF
#define R_NONE R_PPC_NONE #define R_NONE R_PPC_NONE
#define R_ABS64 R_PPC64_ADDR64 #define R_ABS64 R_PPC64_ADDR64
#define R_ABS32 R_PPC_ADDR32 #define R_ABS32 R_PPC_ADDR32
#define R_DATA32 R_PPC_REL32
#define R_DATA64 R_PPC64_REL64
#define R_TEXT32 R_PPC_REL32
#define R_TEXT64 R_PPC64_REL32
#endif /* _OBJTOOL_ARCH_ELF */ #endif /* _OBJTOOL_ARCH_ELF */
...@@ -84,7 +84,7 @@ bool arch_pc_relative_reloc(struct reloc *reloc) ...@@ -84,7 +84,7 @@ bool arch_pc_relative_reloc(struct reloc *reloc)
* All relocation types where P (the address of the target) * All relocation types where P (the address of the target)
* is included in the computation. * is included in the computation.
*/ */
switch (reloc->type) { switch (reloc_type(reloc)) {
case R_X86_64_PC8: case R_X86_64_PC8:
case R_X86_64_PC16: case R_X86_64_PC16:
case R_X86_64_PC32: case R_X86_64_PC32:
...@@ -623,11 +623,11 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec ...@@ -623,11 +623,11 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
if (!immr || strcmp(immr->sym->name, "pv_ops")) if (!immr || strcmp(immr->sym->name, "pv_ops"))
break; break;
idx = (immr->addend + 8) / sizeof(void *); idx = (reloc_addend(immr) + 8) / sizeof(void *);
func = disp->sym; func = disp->sym;
if (disp->sym->type == STT_SECTION) if (disp->sym->type == STT_SECTION)
func = find_symbol_by_offset(disp->sym->sec, disp->addend); func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp));
if (!func) { if (!func) {
WARN("no func for pv_ops[]"); WARN("no func for pv_ops[]");
return -1; return -1;
......
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _OBJTOOL_ARCH_ELF #ifndef _OBJTOOL_ARCH_ELF
#define _OBJTOOL_ARCH_ELF #define _OBJTOOL_ARCH_ELF
#define R_NONE R_X86_64_NONE #define R_NONE R_X86_64_NONE
#define R_ABS64 R_X86_64_64
#define R_ABS32 R_X86_64_32 #define R_ABS32 R_X86_64_32
#define R_ABS64 R_X86_64_64
#define R_DATA32 R_X86_64_PC32
#define R_DATA64 R_X86_64_PC32
#define R_TEXT32 R_X86_64_PC32
#define R_TEXT64 R_X86_64_PC32
#endif /* _OBJTOOL_ARCH_ELF */ #endif /* _OBJTOOL_ARCH_ELF */
...@@ -99,10 +99,10 @@ struct reloc *arch_find_switch_table(struct objtool_file *file, ...@@ -99,10 +99,10 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,
!text_reloc->sym->sec->rodata) !text_reloc->sym->sec->rodata)
return NULL; return NULL;
table_offset = text_reloc->addend; table_offset = reloc_addend(text_reloc);
table_sec = text_reloc->sym->sec; table_sec = text_reloc->sym->sec;
if (text_reloc->type == R_X86_64_PC32) if (reloc_type(text_reloc) == R_X86_64_PC32)
table_offset += 4; table_offset += 4;
/* /*
...@@ -132,7 +132,7 @@ struct reloc *arch_find_switch_table(struct objtool_file *file, ...@@ -132,7 +132,7 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,
* indicates a rare GCC quirk/bug which can leave dead * indicates a rare GCC quirk/bug which can leave dead
* code behind. * code behind.
*/ */
if (text_reloc->type == R_X86_64_PC32) if (reloc_type(text_reloc) == R_X86_64_PC32)
file->ignore_unreachables = true; file->ignore_unreachables = true;
return rodata_reloc; return rodata_reloc;
......
...@@ -93,6 +93,7 @@ static const struct option check_options[] = { ...@@ -93,6 +93,7 @@ static const struct option check_options[] = {
OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"), OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"),
OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"), OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"),
OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"), OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"),
OPT_BOOLEAN('v', "verbose", &opts.verbose, "verbose warnings"),
OPT_END(), OPT_END(),
}; };
...@@ -118,6 +119,10 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[]) ...@@ -118,6 +119,10 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])
parse_options(envc, envv, check_options, env_usage, 0); parse_options(envc, envv, check_options, env_usage, 0);
} }
env = getenv("OBJTOOL_VERBOSE");
if (env && !strcmp(env, "1"))
opts.verbose = true;
argc = parse_options(argc, argv, check_options, usage, 0); argc = parse_options(argc, argv, check_options, usage, 0);
if (argc != 1) if (argc != 1)
usage_with_options(usage, check_options); usage_with_options(usage, check_options);
......
This diff is collapsed.
This diff is collapsed.
...@@ -37,6 +37,7 @@ struct opts { ...@@ -37,6 +37,7 @@ struct opts {
bool no_unreachable; bool no_unreachable;
bool sec_address; bool sec_address;
bool stats; bool stats;
bool verbose;
}; };
extern struct opts opts; extern struct opts opts;
......
...@@ -36,6 +36,7 @@ struct cfi_state { ...@@ -36,6 +36,7 @@ struct cfi_state {
bool drap; bool drap;
bool signal; bool signal;
bool end; bool end;
bool force_undefined;
}; };
#endif /* _OBJTOOL_CFI_H */ #endif /* _OBJTOOL_CFI_H */
This diff is collapsed.
...@@ -55,15 +55,22 @@ static inline char *offstr(struct section *sec, unsigned long offset) ...@@ -55,15 +55,22 @@ static inline char *offstr(struct section *sec, unsigned long offset)
#define WARN_INSN(insn, format, ...) \ #define WARN_INSN(insn, format, ...) \
({ \ ({ \
WARN_FUNC(format, insn->sec, insn->offset, ##__VA_ARGS__); \ struct instruction *_insn = (insn); \
if (!_insn->sym || !_insn->sym->warned) \
WARN_FUNC(format, _insn->sec, _insn->offset, \
##__VA_ARGS__); \
if (_insn->sym) \
_insn->sym->warned = 1; \
}) })
#define BT_FUNC(format, insn, ...) \ #define BT_INSN(insn, format, ...) \
({ \ ({ \
if (opts.verbose || opts.backtrace) { \
struct instruction *_insn = (insn); \ struct instruction *_insn = (insn); \
char *_str = offstr(_insn->sec, _insn->offset); \ char *_str = offstr(_insn->sec, _insn->offset); \
WARN(" %s: " format, _str, ##__VA_ARGS__); \ WARN(" %s: " format, _str, ##__VA_ARGS__); \
free(_str); \ free(_str); \
} \
}) })
#define WARN_ELF(format, ...) \ #define WARN_ELF(format, ...) \
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This is a (sorted!) list of all known __noreturn functions in the kernel.
* It's needed for objtool to properly reverse-engineer the control flow graph.
*
* Yes, this is unfortunate. A better solution is in the works.
*/
NORETURN(__invalid_creds)
NORETURN(__kunit_abort)
NORETURN(__module_put_and_kthread_exit)
NORETURN(__reiserfs_panic)
NORETURN(__stack_chk_fail)
NORETURN(__ubsan_handle_builtin_unreachable)
NORETURN(arch_call_rest_init)
NORETURN(arch_cpu_idle_dead)
NORETURN(btrfs_assertfail)
NORETURN(cpu_bringup_and_idle)
NORETURN(cpu_startup_entry)
NORETURN(do_exit)
NORETURN(do_group_exit)
NORETURN(do_task_dead)
NORETURN(ex_handler_msr_mce)
NORETURN(fortify_panic)
NORETURN(hlt_play_dead)
NORETURN(hv_ghcb_terminate)
NORETURN(kthread_complete_and_exit)
NORETURN(kthread_exit)
NORETURN(kunit_try_catch_throw)
NORETURN(machine_real_restart)
NORETURN(make_task_dead)
NORETURN(mpt_halt_firmware)
NORETURN(nmi_panic_self_stop)
NORETURN(panic)
NORETURN(panic_smp_self_stop)
NORETURN(rest_init)
NORETURN(rewind_stack_and_make_dead)
NORETURN(sev_es_terminate)
NORETURN(snp_abort)
NORETURN(start_kernel)
NORETURN(stop_this_cpu)
NORETURN(usercopy_abort)
NORETURN(x86_64_start_kernel)
NORETURN(x86_64_start_reservations)
NORETURN(xen_cpu_bringup_again)
NORETURN(xen_start_kernel)
...@@ -118,7 +118,7 @@ static int write_orc_entry(struct elf *elf, struct section *orc_sec, ...@@ -118,7 +118,7 @@ static int write_orc_entry(struct elf *elf, struct section *orc_sec,
orc->bp_offset = bswap_if_needed(elf, orc->bp_offset); orc->bp_offset = bswap_if_needed(elf, orc->bp_offset);
/* populate reloc for ip */ /* populate reloc for ip */
if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_X86_64_PC32, if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx,
insn_sec, insn_off)) insn_sec, insn_off))
return -1; return -1;
...@@ -237,12 +237,12 @@ int orc_create(struct objtool_file *file) ...@@ -237,12 +237,12 @@ int orc_create(struct objtool_file *file)
WARN("file already has .orc_unwind section, skipping"); WARN("file already has .orc_unwind section, skipping");
return -1; return -1;
} }
orc_sec = elf_create_section(file->elf, ".orc_unwind", 0, orc_sec = elf_create_section(file->elf, ".orc_unwind",
sizeof(struct orc_entry), nr); sizeof(struct orc_entry), nr);
if (!orc_sec) if (!orc_sec)
return -1; return -1;
sec = elf_create_section(file->elf, ".orc_unwind_ip", 0, sizeof(int), nr); sec = elf_create_section_pair(file->elf, ".orc_unwind_ip", sizeof(int), nr, nr);
if (!sec) if (!sec)
return -1; return -1;
......
...@@ -62,7 +62,7 @@ static void reloc_to_sec_off(struct reloc *reloc, struct section **sec, ...@@ -62,7 +62,7 @@ static void reloc_to_sec_off(struct reloc *reloc, struct section **sec,
unsigned long *off) unsigned long *off)
{ {
*sec = reloc->sym->sec; *sec = reloc->sym->sec;
*off = reloc->sym->offset + reloc->addend; *off = reloc->sym->offset + reloc_addend(reloc);
} }
static int get_alt_entry(struct elf *elf, const struct special_entry *entry, static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
...@@ -126,7 +126,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry, ...@@ -126,7 +126,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
sec, offset + entry->key); sec, offset + entry->key);
return -1; return -1;
} }
alt->key_addend = key_reloc->addend; alt->key_addend = reloc_addend(key_reloc);
} }
return 0; return 0;
......
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