Objtool changes for v6.15:

- The biggest change is the new option to automatically fail
    the build on objtool warnings: CONFIG_OBJTOOL_WERROR.
 
    While there are no currently known unfixed false positives
    left, such an expansion in the severity of objtool warnings
    inevitably creates a risk of build failures, so it's disabled by
    default and depends on !COMPILE_TEST, so it shouldn't be enabled
    on allyesconfig/allmodconfig builds and won't be forced on people
    who just accept build-time defaults in 'make oldconfig'.
 
    While the option is strongly recommended, only people who enable
    it explicitly should see it.
 
    (Josh Poimboeuf)
 
  - Disable branch profiling in noinstr code with a broad
    brush that includes all of arch/x86/ and kernel/sched/. (Josh Poimboeuf)
 
  - Create backup object files on objtool errors and print exact
    objtool arguments to make failure analysis easier (Josh Poimboeuf)
 
  - Improve noreturn handling (Josh Poimboeuf)
 
  - Improve rodata handling (Tiezhu Yang)
 
  - Support jump tables, switch tables and goto tables on LoongArch (Tiezhu Yang)
 
  - Misc cleanups and fixes (Josh Poimboeuf, David Engraf, Ingo Molnar)
 
 Signed-off-by: Ingo Molnar <mingo@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmfefkARHG1pbmdvQGtl
 cm5lbC5vcmcACgkQEnMQ0APhK1inlRAAvd9Hom2qh9Iu+KYYF58vsg9zsxWZA6I1
 blouKI4SUA8Xjuw6Nihx+emaPaMW1boGSLTNsFzrCa3S1+4UHTTp/Y8snZWJ/Mc/
 Peg52N6u/LIcoQM+vNJYRtd9y4wabX87vl0qTxte0kB0Neps3/yQvxtUa2K1srXp
 8nwHK+PdzNsgPuIrIiNc9ymsPvbqFHmVIRRVNVKX4BlPJi2kJs9kx43kszweQR/X
 kW/bs1315m1HS5i02K0Zs/XdOZHLsk9ERu+aviBJV1txrgZIukATIqbODiI+3RZX
 0oa3KxfzEVFN2k3OukrezV2INzETkN+oOSTAZIUOqwSVe+8rdQVBSdYT6svYn/yy
 aS8Bi5Mm1nfizTU+cRrzU7FxWCmwsxm9r4fHPTV8Owjxg0uoGk/E/qlvERuR2rpA
 p2tHMo1lp2Yo+VZBZPfm5KDHFG4tSGhF9eav2bqSI7/Kf5AWxRl8kBs5iLrcxsXh
 4qk3FalnuM7A+1McAUcBJAvM897Yie0s2G83ZipyYyA6U3LSBhBMWh9FlIiAjuIh
 YnX6IFkW9tVzVZpJFEGQn+2Ewl5Y2Go5bokKk03vkWCZCgg+hEUsVh6Cnm1ocZpO
 Ll3/UF4i8XjjyuAuHDn6mzyHIgch2xRN02v7dJSb09+O9b8vIoPoSqbWSLJUOBqf
 r6UesXDG8mY=
 =iswJ
 -----END PGP SIGNATURE-----

Merge tag 'objtool-core-2025-03-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool updates from Ingo Molnar:

 - The biggest change is the new option to automatically fail the build
   on objtool warnings: CONFIG_OBJTOOL_WERROR.

   While there are no currently known unfixed false positives left, such
   an expansion in the severity of objtool warnings inevitably creates a
   risk of build failures, so it's disabled by default and depends on
   !COMPILE_TEST, so it shouldn't be enabled on
   allyesconfig/allmodconfig builds and won't be forced on people who
   just accept build-time defaults in 'make oldconfig'.

   While the option is strongly recommended, only people who enable it
   explicitly should see it.

   (Josh Poimboeuf)

 - Disable branch profiling in noinstr code with a broad brush that
   includes all of arch/x86/ and kernel/sched/. (Josh Poimboeuf)

 - Create backup object files on objtool errors and print exact objtool
   arguments to make failure analysis easier (Josh Poimboeuf)

 - Improve noreturn handling (Josh Poimboeuf)

 - Improve rodata handling (Tiezhu Yang)

 - Support jump tables, switch tables and goto tables on LoongArch
   (Tiezhu Yang)

 - Misc cleanups and fixes (Josh Poimboeuf, David Engraf, Ingo Molnar)

* tag 'objtool-core-2025-03-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (22 commits)
  tracing: Disable branch profiling in noinstr code
  objtool: Use O_CREAT with explicit mode mask
  objtool: Add CONFIG_OBJTOOL_WERROR
  objtool: Create backup on error and print args
  objtool: Change "warning:" to "error:" for --Werror
  objtool: Add --Werror option
  objtool: Add --output option
  objtool: Upgrade "Linked object detected" warning to error
  objtool: Consolidate option validation
  objtool: Remove --unret dependency on --rethunk
  objtool: Increase per-function WARN_FUNC() rate limit
  objtool: Update documentation
  objtool: Improve __noreturn annotation warning
  objtool: Fix error handling inconsistencies in check()
  x86/traps: Make exc_double_fault() consistently noreturn
  LoongArch: Enable jump table for objtool
  objtool/LoongArch: Add support for goto table
  objtool/LoongArch: Add support for switch table
  objtool: Handle PC relative relocation type
  objtool: Handle different entry size of rodata
  ...
This commit is contained in:
Linus Torvalds 2025-03-24 21:18:05 -07:00
commit 5a658afd46
35 changed files with 573 additions and 254 deletions

View File

@ -291,6 +291,9 @@ config AS_HAS_LBT_EXTENSION
config AS_HAS_LVZ_EXTENSION
def_bool $(as-instr,hvcl 0)
config CC_HAS_ANNOTATE_TABLEJUMP
def_bool $(cc-option,-mannotate-tablejump)
menu "Kernel type and options"
source "kernel/Kconfig.hz"

View File

@ -101,7 +101,11 @@ KBUILD_AFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)
KBUILD_CFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)-mthin-add-sub)
ifdef CONFIG_OBJTOOL
KBUILD_CFLAGS += -fno-jump-tables
ifdef CONFIG_CC_HAS_ANNOTATE_TABLEJUMP
KBUILD_CFLAGS += -mannotate-tablejump
else
KBUILD_CFLAGS += -fno-jump-tables # keep compatibility with older compilers
endif
endif
KBUILD_RUSTFLAGS += --target=loongarch64-unknown-none-softfloat -Ccode-model=small

View File

@ -1,4 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
# Branch profiling isn't noinstr-safe. Disable it for arch/x86/*
subdir-ccflags-$(CONFIG_TRACE_BRANCH_PROFILING) += -DDISABLE_BRANCH_PROFILING
obj-$(CONFIG_ARCH_HAS_CC_PLATFORM) += coco/
obj-y += entry/

View File

@ -9,8 +9,6 @@
#define pr_fmt(fmt) "SEV: " fmt
#define DISABLE_BRANCH_PROFILING
#include <linux/sched/debug.h> /* For show_regs() */
#include <linux/percpu-defs.h>
#include <linux/cc_platform.h>

View File

@ -5,8 +5,6 @@
* Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
*/
#define DISABLE_BRANCH_PROFILING
/* cpu_feature_enabled() cannot be used this early */
#define USE_EARLY_PGTABLE_L5

View File

@ -379,6 +379,21 @@ __visible void __noreturn handle_stack_overflow(struct pt_regs *regs,
}
#endif
/*
* Prevent the compiler and/or objtool from marking the !CONFIG_X86_ESPFIX64
* version of exc_double_fault() as noreturn. Otherwise the noreturn mismatch
* between configs triggers objtool warnings.
*
* This is a temporary hack until we have compiler or plugin support for
* annotating noreturns.
*/
#ifdef CONFIG_X86_ESPFIX64
#define always_true() true
#else
bool always_true(void);
bool __weak always_true(void) { return true; }
#endif
/*
* Runs on an IST stack for x86_64 and on a special task stack for x86_32.
*
@ -514,7 +529,8 @@ DEFINE_IDTENTRY_DF(exc_double_fault)
pr_emerg("PANIC: double fault, error_code: 0x%lx\n", error_code);
die("double fault", regs, error_code);
panic("Machine halted.");
if (always_true())
panic("Machine halted.");
instrumentation_end();
}

View File

@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
#define DISABLE_BRANCH_PROFILING
#define pr_fmt(fmt) "kasan: " fmt
/* cpu_feature_enabled() cannot be used this early */

View File

@ -7,8 +7,6 @@
* Author: Tom Lendacky <thomas.lendacky@amd.com>
*/
#define DISABLE_BRANCH_PROFILING
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/mm.h>

View File

@ -7,8 +7,6 @@
* Author: Tom Lendacky <thomas.lendacky@amd.com>
*/
#define DISABLE_BRANCH_PROFILING
/*
* Since we're dealing with identity mappings, physical and virtual
* addresses are the same, so override these defines which are ultimately

View File

@ -5,6 +5,10 @@
ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT
ifdef CONFIG_TRACE_BRANCH_PROFILING
CFLAGS_processor_idle.o += -DDISABLE_BRANCH_PROFILING
endif
#
# ACPI Boot-Time Table Parsing
#

View File

@ -3,6 +3,9 @@
# Makefile for cpuidle.
#
# Branch profiling isn't noinstr-safe
ccflags-$(CONFIG_TRACE_BRANCH_PROFILING) += -DDISABLE_BRANCH_PROFILING
obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
obj-$(CONFIG_DT_IDLE_STATES) += dt_idle_states.o

View File

@ -1,3 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_INTEL_IDLE) += intel_idle.o
# Branch profiling isn't noinstr-safe
ccflags-$(CONFIG_TRACE_BRANCH_PROFILING) += -DDISABLE_BRANCH_PROFILING
obj-$(CONFIG_INTEL_IDLE) += intel_idle.o

View File

@ -21,6 +21,11 @@ ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_irq_work.o = $(CC_FLAGS_FTRACE)
endif
# Branch profiling isn't noinstr-safe
ifdef CONFIG_TRACE_BRANCH_PROFILING
CFLAGS_context_tracking.o += -DDISABLE_BRANCH_PROFILING
endif
# Prevents flicker of uninteresting __do_softirq()/__local_bh_disable_ip()
# in coverage traces.
KCOV_INSTRUMENT_softirq.o := n

View File

@ -6,6 +6,9 @@ KASAN_SANITIZE := n
UBSAN_SANITIZE := n
KCOV_INSTRUMENT := n
# Branch profiling isn't noinstr-safe
ccflags-$(CONFIG_TRACE_BRANCH_PROFILING) += -DDISABLE_BRANCH_PROFILING
CFLAGS_REMOVE_common.o = -fstack-protector -fstack-protector-strong
CFLAGS_common.o += -fno-stack-protector

View File

@ -22,6 +22,11 @@ ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer
endif
# Branch profiling isn't noinstr-safe
ifdef CONFIG_TRACE_BRANCH_PROFILING
CFLAGS_build_policy.o += -DDISABLE_BRANCH_PROFILING
CFLAGS_build_utility.o += -DDISABLE_BRANCH_PROFILING
endif
#
# Build efficiency:
#

View File

@ -1,4 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
# Branch profiling isn't noinstr-safe
ifdef CONFIG_TRACE_BRANCH_PROFILING
CFLAGS_sched_clock.o += -DDISABLE_BRANCH_PROFILING
endif
obj-y += time.o timer.o hrtimer.o sleep_timeout.o
obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
obj-y += timeconv.o timecounter.o alarmtimer.o

View File

@ -545,6 +545,17 @@ config FRAME_POINTER
config OBJTOOL
bool
config OBJTOOL_WERROR
bool "Upgrade objtool warnings to errors"
depends on OBJTOOL && !COMPILE_TEST
help
Fail the build on objtool warnings.
Objtool warnings can indicate kernel instability, including boot
failures. This option is highly recommended.
If unsure, say Y.
config STACK_VALIDATION
bool "Compile-time stack metadata validation"
depends on HAVE_STACK_VALIDATION && UNWINDER_FRAME_POINTER

View File

@ -5,6 +5,11 @@
ccflags-remove-$(CONFIG_FUNCTION_TRACER) += $(CC_FLAGS_FTRACE)
# Branch profiling isn't noinstr-safe
ifdef CONFIG_TRACE_BRANCH_PROFILING
CFLAGS_smp_processor_id.o += -DDISABLE_BRANCH_PROFILING
endif
# These files are disabled because they produce lots of non-interesting and/or
# flaky coverage that is not a function of syscall inputs. For example,
# rbtree can be global and individual rotations don't correlate with inputs.

View File

@ -277,6 +277,7 @@ objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE) += --static-call
objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) += --uaccess
objtool-args-$(CONFIG_GCOV_KERNEL) += --no-unreachable
objtool-args-$(CONFIG_PREFIX_SYMBOLS) += --prefix=$(CONFIG_FUNCTION_PADDING_BYTES)
objtool-args-$(CONFIG_OBJTOOL_WERROR) += --Werror --backtrace
objtool-args = $(objtool-args-y) \
$(if $(delay-objtool), --link) \

View File

@ -28,6 +28,15 @@ Objtool has the following features:
sites, enabling the kernel to patch them inline, to prevent "thunk
funneling" for both security and performance reasons
- Return thunk validation -- validates return thunks are used for
certain CPU mitigations including Retbleed and SRSO
- Return thunk annotation -- annotates all return thunk sites so kernel
can patch them inline, depending on enabled mitigations
- Return thunk training valiation -- validate that all entry paths
untrain a "safe return" before the first return (or call)
- Non-instrumentation validation -- validates non-instrumentable
("noinstr") code rules, preventing instrumentation in low-level C
entry code
@ -53,6 +62,9 @@ Objtool has the following features:
- Function entry annotation -- annotates function entries, enabling
kernel function tracing
- Function preamble (prefix) annotation and/or symbol generation -- used
for FineIBT and call depth tracking
- Other toolchain hacks which will go unmentioned at this time...
Each feature can be enabled individually or in combination using the
@ -197,19 +209,17 @@ To achieve the validation, objtool enforces the following rules:
1. Each callable function must be annotated as such with the ELF
function type. In asm code, this is typically done using the
ENTRY/ENDPROC macros. If objtool finds a return instruction
SYM_FUNC_{START,END} macros. If objtool finds a return instruction
outside of a function, it flags an error since that usually indicates
callable code which should be annotated accordingly.
This rule is needed so that objtool can properly identify each
callable function in order to analyze its stack metadata.
2. Conversely, each section of code which is *not* callable should *not*
be annotated as an ELF function. The ENDPROC macro shouldn't be used
in this case.
This rule is needed so that objtool can ignore non-callable code.
Such code doesn't have to follow any of the other rules.
2. Conversely, each section of code which is *not* callable, or is
otherwise doing funny things with the stack or registers, should
*not* be annotated as an ELF function. Rather, SYM_CODE_{START,END}
should be used along with unwind hints.
3. Each callable function which calls another function must have the
correct frame pointer logic, if required by CONFIG_FRAME_POINTER or
@ -221,7 +231,7 @@ To achieve the validation, objtool enforces the following rules:
function B, the _caller_ of function A will be skipped on the stack
trace.
4. Dynamic jumps and jumps to undefined symbols are only allowed if:
4. Indirect jumps and jumps to undefined symbols are only allowed if:
a) the jump is part of a switch statement; or
@ -304,29 +314,29 @@ the objtool maintainers.
001e 2823e: 80 ce 02 or $0x2,%dh
...
2. file.o: warning: objtool: .text+0x53: unreachable instruction
Objtool couldn't find a code path to reach the instruction.
If the error is for an asm file, and the instruction is inside (or
reachable from) a callable function, the function should be annotated
with the ENTRY/ENDPROC macros (ENDPROC is the important one).
Otherwise, the code should probably be annotated with the unwind hint
macros in asm/unwind_hints.h so objtool and the unwinder can know the
stack state associated with the code.
with the SYM_FUNC_START and SYM_FUNC_END macros.
If you're 100% sure the code won't affect stack traces, or if you're
a just a bad person, you can tell objtool to ignore it. See the
"Adding exceptions" section below.
Otherwise, SYM_CODE_START can be used. In that case the code needs
to be annotated with unwind hint macros.
If it's not actually in a callable function (e.g. kernel entry code),
change ENDPROC to END.
If you're sure the code won't affect the reliability of runtime stack
traces and want objtool to ignore it, see "Adding exceptions" below.
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.
3. file.o: warning: objtool: foo+0x48c: bar() missing __noreturn in .c/.h or NORETURN() in noreturns.h
The call from foo() to bar() doesn't return, but bar() is incorrectly
annotated. A noreturn function must be marked __noreturn in both its
declaration and its definition, and must have a NORETURN() annotation
in tools/objtool/noreturns.h.
4. file.o: warning: objtool: func(): can't find starting instruction
or
@ -341,23 +351,21 @@ the objtool maintainers.
This is a kernel entry/exit instruction like sysenter or iret. Such
instructions aren't allowed in a callable function, and are most
likely part of the kernel entry code. They should usually not have
the callable function annotation (ENDPROC) and should always be
annotated with the unwind hint macros in asm/unwind_hints.h.
likely part of the kernel entry code. Such code should probably be
placed in a SYM_FUNC_CODE block with unwind hints.
6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame
This is a dynamic jump or a jump to an undefined symbol. Objtool
assumed it's a sibling call and detected that the frame pointer
wasn't first restored to its original state.
This is a branch to an UNDEF symbol. Objtool assumed it's a
sibling call and detected that the stack wasn't first restored to its
original state.
If it's not really a sibling call, you may need to move the
destination code to the local file.
If it's not really a sibling call, you may need to use unwind hints
and/or move the destination code to the local file.
If the instruction is not actually in a callable function (e.g.
kernel entry code), change ENDPROC to END and annotate manually with
the unwind hint macros in asm/unwind_hints.h.
kernel entry code), use SYM_CODE_{START,END} and unwind hints.
7. file: warning: objtool: func()+0x5c: stack state mismatch
@ -373,8 +381,8 @@ the objtool maintainers.
Another possibility is that the code has some asm or inline asm which
does some unusual things to the stack or the frame pointer. In such
cases it's probably appropriate to use the unwind hint macros in
asm/unwind_hints.h.
cases it's probably appropriate to use SYM_FUNC_CODE with unwind
hints.
8. file.o: warning: objtool: funcA() falls through to next function funcB()
@ -384,17 +392,16 @@ the objtool maintainers.
can fall through into the next function. There could be different
reasons for this:
1) funcA()'s last instruction is a call to a "noreturn" function like
a) funcA()'s last instruction is a call to a "noreturn" function like
panic(). In this case the noreturn function needs to be added to
objtool's hard-coded global_noreturns array. Feel free to bug the
objtool maintainer, or you can submit a patch.
2) funcA() uses the unreachable() annotation in a section of code
b) funcA() uses the unreachable() annotation in a section of code
that is actually reachable.
3) If funcA() calls an inline function, the object code for funcA()
might be corrupt due to a gcc bug. For more details, see:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646
c) Some undefined behavior like divide by zero.
9. file.o: warning: objtool: funcA() call to funcB() with UACCESS enabled
@ -432,24 +439,26 @@ the objtool maintainers.
This limitation can be overcome by massaging the alternatives with
NOPs to shift the stack changes around so they no longer conflict.
11. file.o: warning: unannotated intra-function call
This warning means that a direct call is done to a destination which
is not at the beginning of a function. If this is a legit call, you
can remove this warning by putting the ANNOTATE_INTRA_FUNCTION_CALL
directive right before the call.
This warning means that a direct call is done to a destination which
is not at the beginning of a function. If this is a legit call, you
can remove this warning by putting the ANNOTATE_INTRA_FUNCTION_CALL
directive right before the call.
12. file.o: warning: func(): not an indirect call target
This means that objtool is running with --ibt and a function expected
to be an indirect call target is not. In particular, this happens for
init_module() or cleanup_module() if a module relies on these special
names and does not use module_init() / module_exit() macros to create
them.
This means that objtool is running with --ibt and a function
expected to be an indirect call target is not. In particular, this
happens for init_module() or cleanup_module() if a module relies on
these special names and does not use module_init() / module_exit()
macros to create them.
If the error doesn't seem to make sense, it could be a bug in objtool.
Feel free to ask the objtool maintainer for help.
Feel free to ask objtool maintainers for help.
Adding exceptions

View File

@ -37,7 +37,7 @@ OBJTOOL_CFLAGS := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBE
OBJTOOL_LDFLAGS := $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS)
# Allow old libelf to be used:
elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - | grep elf_getshdr)
elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - 2>/dev/null | grep elf_getshdr)
OBJTOOL_CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED)
# Always want host compilation.

View File

@ -5,10 +5,7 @@
#include <asm/inst.h>
#include <asm/orc_types.h>
#include <linux/objtool_types.h>
#ifndef EM_LOONGARCH
#define EM_LOONGARCH 258
#endif
#include <arch/elf.h>
int arch_ftrace_match(char *name)
{
@ -363,3 +360,26 @@ void arch_initial_func_cfi_state(struct cfi_init_state *state)
state->cfa.base = CFI_SP;
state->cfa.offset = 0;
}
unsigned int arch_reloc_size(struct reloc *reloc)
{
switch (reloc_type(reloc)) {
case R_LARCH_32:
case R_LARCH_32_PCREL:
return 4;
default:
return 8;
}
}
unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table)
{
switch (reloc_type(reloc)) {
case R_LARCH_32_PCREL:
case R_LARCH_64_PCREL:
return reloc->sym->offset + reloc_addend(reloc) -
(reloc_offset(reloc) - reloc_offset(table));
default:
return reloc->sym->offset + reloc_addend(reloc);
}
}

View File

@ -18,6 +18,13 @@
#ifndef R_LARCH_32_PCREL
#define R_LARCH_32_PCREL 99
#endif
#ifndef R_LARCH_64_PCREL
#define R_LARCH_64_PCREL 109
#endif
#ifndef EM_LOONGARCH
#define EM_LOONGARCH 258
#endif
#define R_NONE R_LARCH_NONE
#define R_ABS32 R_LARCH_32

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <string.h>
#include <objtool/special.h>
#include <objtool/warn.h>
bool arch_support_alt_relocation(struct special_alt *special_alt,
struct instruction *insn,
@ -8,9 +10,164 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
return false;
}
struct table_info {
struct list_head jump_info;
unsigned long insn_offset;
unsigned long rodata_offset;
};
static void get_rodata_table_size_by_table_annotate(struct objtool_file *file,
struct instruction *insn,
unsigned long *table_size)
{
struct section *rsec;
struct reloc *reloc;
struct list_head table_list;
struct table_info *orig_table;
struct table_info *next_table;
unsigned long tmp_insn_offset;
unsigned long tmp_rodata_offset;
rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
if (!rsec)
return;
INIT_LIST_HEAD(&table_list);
for_each_reloc(rsec, reloc) {
orig_table = malloc(sizeof(struct table_info));
if (!orig_table) {
WARN("malloc failed");
return;
}
orig_table->insn_offset = reloc->sym->offset + reloc_addend(reloc);
reloc++;
orig_table->rodata_offset = reloc->sym->offset + reloc_addend(reloc);
list_add_tail(&orig_table->jump_info, &table_list);
if (reloc_idx(reloc) + 1 == sec_num_entries(rsec))
break;
}
list_for_each_entry(orig_table, &table_list, jump_info) {
next_table = list_next_entry(orig_table, jump_info);
list_for_each_entry_from(next_table, &table_list, jump_info) {
if (next_table->rodata_offset < orig_table->rodata_offset) {
tmp_insn_offset = next_table->insn_offset;
tmp_rodata_offset = next_table->rodata_offset;
next_table->insn_offset = orig_table->insn_offset;
next_table->rodata_offset = orig_table->rodata_offset;
orig_table->insn_offset = tmp_insn_offset;
orig_table->rodata_offset = tmp_rodata_offset;
}
}
}
list_for_each_entry(orig_table, &table_list, jump_info) {
if (insn->offset == orig_table->insn_offset) {
next_table = list_next_entry(orig_table, jump_info);
if (&next_table->jump_info == &table_list) {
*table_size = 0;
return;
}
while (next_table->rodata_offset == orig_table->rodata_offset) {
next_table = list_next_entry(next_table, jump_info);
if (&next_table->jump_info == &table_list) {
*table_size = 0;
return;
}
}
*table_size = next_table->rodata_offset - orig_table->rodata_offset;
}
}
}
static struct reloc *find_reloc_by_table_annotate(struct objtool_file *file,
struct instruction *insn,
unsigned long *table_size)
{
struct section *rsec;
struct reloc *reloc;
unsigned long offset;
rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
if (!rsec)
return NULL;
for_each_reloc(rsec, reloc) {
if (reloc->sym->sec->rodata)
continue;
if (strcmp(insn->sec->name, reloc->sym->sec->name))
continue;
offset = reloc->sym->offset + reloc_addend(reloc);
if (insn->offset == offset) {
get_rodata_table_size_by_table_annotate(file, insn, table_size);
reloc++;
return reloc;
}
}
return NULL;
}
static struct reloc *find_reloc_of_rodata_c_jump_table(struct section *sec,
unsigned long offset,
unsigned long *table_size)
{
struct section *rsec;
struct reloc *reloc;
rsec = sec->rsec;
if (!rsec)
return NULL;
for_each_reloc(rsec, reloc) {
if (reloc_offset(reloc) > offset)
break;
if (!strcmp(reloc->sym->sec->name, C_JUMP_TABLE_SECTION)) {
*table_size = 0;
return reloc;
}
}
return NULL;
}
struct reloc *arch_find_switch_table(struct objtool_file *file,
struct instruction *insn,
unsigned long *table_size)
{
return NULL;
struct reloc *annotate_reloc;
struct reloc *rodata_reloc;
struct section *table_sec;
unsigned long table_offset;
annotate_reloc = find_reloc_by_table_annotate(file, insn, table_size);
if (!annotate_reloc) {
annotate_reloc = find_reloc_of_rodata_c_jump_table(
insn->sec, insn->offset, table_size);
if (!annotate_reloc)
return NULL;
}
table_sec = annotate_reloc->sym->sec;
table_offset = annotate_reloc->sym->offset + reloc_addend(annotate_reloc);
/*
* Each table entry has a rela associated with it. The rela
* should reference text in the same function as the original
* instruction.
*/
rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset);
if (!rodata_reloc)
return NULL;
return rodata_reloc;
}

View File

@ -106,3 +106,17 @@ void arch_initial_func_cfi_state(struct cfi_init_state *state)
state->regs[CFI_RA].base = CFI_CFA;
state->regs[CFI_RA].offset = 0;
}
unsigned int arch_reloc_size(struct reloc *reloc)
{
switch (reloc_type(reloc)) {
case R_PPC_REL32:
case R_PPC_ADDR32:
case R_PPC_UADDR32:
case R_PPC_PLT32:
case R_PPC_PLTREL32:
return 4;
default:
return 8;
}
}

View File

@ -852,3 +852,16 @@ bool arch_is_embedded_insn(struct symbol *sym)
return !strcmp(sym->name, "retbleed_return_thunk") ||
!strcmp(sym->name, "srso_safe_ret");
}
unsigned int arch_reloc_size(struct reloc *reloc)
{
switch (reloc_type(reloc)) {
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_PC32:
case R_X86_64_PLT32:
return 4;
default:
return 8;
}
}

View File

@ -6,6 +6,10 @@
#include <subcmd/parse-options.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <objtool/builtin.h>
#include <objtool/objtool.h>
@ -14,6 +18,8 @@
"error: objtool: " format "\n", \
##__VA_ARGS__)
const char *objname;
struct opts opts;
static const char * const check_usage[] = {
@ -71,7 +77,7 @@ static const struct option check_options[] = {
OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),
OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"),
OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"),
OPT_BOOLEAN(0, "orc", &opts.orc, "generate ORC metadata"),
OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
OPT_BOOLEAN(0, "rethunk", &opts.rethunk, "validate and annotate rethunk usage"),
OPT_BOOLEAN(0, "unret", &opts.unret, "validate entry unret placement"),
@ -84,16 +90,17 @@ static const struct option check_options[] = {
OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump),
OPT_GROUP("Options:"),
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modification"),
OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),
OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
OPT_BOOLEAN(0, "mnop", &opts.mnop, "nop out mcount call sites"),
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, "stats", &opts.stats, "print statistics"),
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"),
OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
OPT_BOOLEAN(0, "mnop", &opts.mnop, "nop out mcount call sites"),
OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"),
OPT_STRING('o', "output", &opts.output, "file", "output file name"),
OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"),
OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"),
OPT_BOOLEAN('v', "verbose", &opts.verbose, "verbose warnings"),
OPT_BOOLEAN(0, "Werror", &opts.werror, "return error on warnings"),
OPT_END(),
};
@ -131,6 +138,26 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])
static bool opts_valid(void)
{
if (opts.mnop && !opts.mcount) {
ERROR("--mnop requires --mcount");
return false;
}
if (opts.noinstr && !opts.link) {
ERROR("--noinstr requires --link");
return false;
}
if (opts.ibt && !opts.link) {
ERROR("--ibt requires --link");
return false;
}
if (opts.unret && !opts.link) {
ERROR("--unret requires --link");
return false;
}
if (opts.hack_jump_label ||
opts.hack_noinstr ||
opts.ibt ||
@ -151,11 +178,6 @@ static bool opts_valid(void)
return true;
}
if (opts.unret && !opts.rethunk) {
ERROR("--unret requires --rethunk");
return false;
}
if (opts.dump_orc)
return true;
@ -163,76 +185,156 @@ static bool opts_valid(void)
return false;
}
static bool mnop_opts_valid(void)
static int copy_file(const char *src, const char *dst)
{
if (opts.mnop && !opts.mcount) {
ERROR("--mnop requires --mcount");
return false;
size_t to_copy, copied;
int dst_fd, src_fd;
struct stat stat;
off_t offset = 0;
src_fd = open(src, O_RDONLY);
if (src_fd == -1) {
ERROR("can't open '%s' for reading", src);
return 1;
}
return true;
dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0400);
if (dst_fd == -1) {
ERROR("can't open '%s' for writing", dst);
return 1;
}
if (fstat(src_fd, &stat) == -1) {
perror("fstat");
return 1;
}
if (fchmod(dst_fd, stat.st_mode) == -1) {
perror("fchmod");
return 1;
}
for (to_copy = stat.st_size; to_copy > 0; to_copy -= copied) {
copied = sendfile(dst_fd, src_fd, &offset, to_copy);
if (copied == -1) {
perror("sendfile");
return 1;
}
}
close(dst_fd);
close(src_fd);
return 0;
}
static bool link_opts_valid(struct objtool_file *file)
static char **save_argv(int argc, const char **argv)
{
if (opts.link)
return true;
char **orig_argv;
if (has_multiple_files(file->elf)) {
ERROR("Linked object detected, forcing --link");
opts.link = true;
return true;
orig_argv = calloc(argc, sizeof(char *));
if (!orig_argv) {
perror("calloc");
return NULL;
}
if (opts.noinstr) {
ERROR("--noinstr requires --link");
return false;
}
for (int i = 0; i < argc; i++) {
orig_argv[i] = strdup(argv[i]);
if (!orig_argv[i]) {
perror("strdup");
return NULL;
}
};
if (opts.ibt) {
ERROR("--ibt requires --link");
return false;
}
if (opts.unret) {
ERROR("--unret requires --link");
return false;
}
return true;
return orig_argv;
}
#define ORIG_SUFFIX ".orig"
int objtool_run(int argc, const char **argv)
{
const char *objname;
struct objtool_file *file;
int ret;
char *backup = NULL;
char **orig_argv;
int ret = 0;
argc = cmd_parse_options(argc, argv, check_usage);
objname = argv[0];
orig_argv = save_argv(argc, argv);
if (!orig_argv)
return 1;
cmd_parse_options(argc, argv, check_usage);
if (!opts_valid())
return 1;
objname = argv[0];
if (opts.dump_orc)
return orc_dump(objname);
if (!opts.dryrun && opts.output) {
/* copy original .o file to output file */
if (copy_file(objname, opts.output))
return 1;
/* from here on, work directly on the output file */
objname = opts.output;
}
file = objtool_open_read(objname);
if (!file)
return 1;
goto err;
if (!mnop_opts_valid())
return 1;
if (!link_opts_valid(file))
return 1;
if (!opts.link && has_multiple_files(file->elf)) {
ERROR("Linked object requires --link");
goto err;
}
ret = check(file);
if (ret)
return ret;
goto err;
if (file->elf->changed)
return elf_write(file->elf);
if (!opts.dryrun && file->elf->changed && elf_write(file->elf))
goto err;
return 0;
err:
if (opts.dryrun)
goto err_msg;
if (opts.output) {
unlink(opts.output);
goto err_msg;
}
/*
* Make a backup before kbuild deletes the file so the error
* can be recreated without recompiling or relinking.
*/
backup = malloc(strlen(objname) + strlen(ORIG_SUFFIX) + 1);
if (!backup) {
perror("malloc");
return 1;
}
strcpy(backup, objname);
strcat(backup, ORIG_SUFFIX);
if (copy_file(objname, backup))
return 1;
err_msg:
fprintf(stderr, "%s", orig_argv[0]);
for (int i = 1; i < argc; i++) {
char *arg = orig_argv[i];
if (backup && !strcmp(arg, objname))
fprintf(stderr, " %s -o %s", backup, objname);
else
fprintf(stderr, " %s", arg);
}
fprintf(stderr, "\n");
return 1;
}

View File

@ -1944,6 +1944,11 @@ out:
return ret;
}
__weak unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table)
{
return reloc->sym->offset + reloc_addend(reloc);
}
static int add_jump_table(struct objtool_file *file, struct instruction *insn,
struct reloc *next_table)
{
@ -1954,6 +1959,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
unsigned int prev_offset = 0;
struct reloc *reloc = table;
struct alternative *alt;
unsigned long sym_offset;
/*
* Each @reloc is a switch table relocation which points to the target
@ -1968,12 +1974,13 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
break;
/* Make sure the table entries are consecutive: */
if (prev_offset && reloc_offset(reloc) != prev_offset + 8)
if (prev_offset && reloc_offset(reloc) != prev_offset + arch_reloc_size(reloc))
break;
sym_offset = arch_jump_table_sym_offset(reloc, table);
/* Detect function pointers from contiguous objects: */
if (reloc->sym->sec == pfunc->sec &&
reloc_addend(reloc) == pfunc->offset)
if (reloc->sym->sec == pfunc->sec && sym_offset == pfunc->offset)
break;
/*
@ -1981,10 +1988,10 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
* which point to the end of the function. Ignore them.
*/
if (reloc->sym->sec == pfunc->sec &&
reloc_addend(reloc) == pfunc->offset + pfunc->len)
sym_offset == pfunc->offset + pfunc->len)
goto next;
dest_insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
dest_insn = find_insn(file, reloc->sym->sec, sym_offset);
if (!dest_insn)
break;
@ -2023,6 +2030,7 @@ static void find_jump_table(struct objtool_file *file, struct symbol *func,
struct reloc *table_reloc;
struct instruction *dest_insn, *orig_insn = insn;
unsigned long table_size;
unsigned long sym_offset;
/*
* Backward search using the @first_jump_src links, these help avoid
@ -2046,7 +2054,10 @@ static void find_jump_table(struct objtool_file *file, struct symbol *func,
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));
sym_offset = table_reloc->sym->offset + reloc_addend(table_reloc);
dest_insn = find_insn(file, table_reloc->sym->sec, sym_offset);
if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
continue;
@ -4449,35 +4460,6 @@ static int validate_sls(struct objtool_file *file)
return warnings;
}
static bool ignore_noreturn_call(struct instruction *insn)
{
struct symbol *call_dest = insn_call_dest(insn);
/*
* FIXME: hack, we need a real noreturn solution
*
* Problem is, exc_double_fault() may or may not return, depending on
* whether CONFIG_X86_ESPFIX64 is set. But objtool has no visibility
* to the kernel config.
*
* Other potential ways to fix it:
*
* - have compiler communicate __noreturn functions somehow
* - remove CONFIG_X86_ESPFIX64
* - read the .config file
* - add a cmdline option
* - create a generic objtool annotation format (vs a bunch of custom
* formats) and annotate it
*/
if (!strcmp(call_dest->name, "exc_double_fault")) {
/* prevent further unreachable warnings for the caller */
insn->sym->warned = 1;
return true;
}
return false;
}
static int validate_reachable_instructions(struct objtool_file *file)
{
struct instruction *insn, *prev_insn;
@ -4494,8 +4476,8 @@ static int validate_reachable_instructions(struct objtool_file *file)
prev_insn = prev_insn_same_sec(file, insn);
if (prev_insn && prev_insn->dead_end) {
call_dest = insn_call_dest(prev_insn);
if (call_dest && !ignore_noreturn_call(prev_insn)) {
WARN_INSN(insn, "%s() is missing a __noreturn annotation",
if (call_dest) {
WARN_INSN(insn, "%s() missing __noreturn in .c/.h or NORETURN() in noreturns.h",
call_dest->name);
warnings++;
continue;
@ -4565,7 +4547,7 @@ static int disas_warned_funcs(struct objtool_file *file)
char *funcs = NULL, *tmp;
for_each_sym(file, sym) {
if (sym->warned) {
if (sym->warnings) {
if (!funcs) {
funcs = malloc(strlen(sym->name) + 1);
strcpy(funcs, sym->name);
@ -4623,8 +4605,10 @@ int check(struct objtool_file *file)
init_cfi_state(&force_undefined_cfi);
force_undefined_cfi.force_undefined = true;
if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3)))
if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) {
ret = -1;
goto out;
}
cfi_hash_add(&init_cfi);
cfi_hash_add(&func_cfi);
@ -4641,7 +4625,7 @@ int check(struct objtool_file *file)
if (opts.retpoline) {
ret = validate_retpoline(file);
if (ret < 0)
return ret;
goto out;
warnings += ret;
}
@ -4677,7 +4661,7 @@ int check(struct objtool_file *file)
*/
ret = validate_unrets(file);
if (ret < 0)
return ret;
goto out;
warnings += ret;
}
@ -4740,7 +4724,7 @@ int check(struct objtool_file *file)
if (opts.prefix) {
ret = add_prefix_symbols(file);
if (ret < 0)
return ret;
goto out;
warnings += ret;
}
@ -4772,9 +4756,18 @@ int check(struct objtool_file *file)
out:
/*
* For now, don't fail the kernel build on fatal warnings. These
* errors are still fairly common due to the growing matrix of
* supported toolchains and their recent pace of change.
* CONFIG_OBJTOOL_WERROR upgrades all warnings (and errors) to actual
* errors.
*
* Note that even "fatal" type errors don't actually return an error
* without CONFIG_OBJTOOL_WERROR. That probably needs improved at some
* point.
*/
if (opts.werror && (ret || warnings)) {
if (warnings)
WARN("%d warning(s) upgraded to errors", warnings);
return 1;
}
return 0;
}

View File

@ -1302,9 +1302,6 @@ int elf_write(struct elf *elf)
struct section *sec;
Elf_Scn *s;
if (opts.dryrun)
return 0;
/* Update changed relocation sections and section headers: */
list_for_each_entry(sec, &elf->sections, list) {
if (sec->truncate)

View File

@ -97,4 +97,7 @@ int arch_rewrite_retpolines(struct objtool_file *file);
bool arch_pc_relative_reloc(struct reloc *reloc);
unsigned int arch_reloc_size(struct reloc *reloc);
unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table);
#endif /* _ARCH_H */

View File

@ -29,15 +29,16 @@ struct opts {
/* options: */
bool backtrace;
bool backup;
bool dryrun;
bool link;
bool mnop;
bool module;
bool no_unreachable;
const char *output;
bool sec_address;
bool stats;
bool verbose;
bool werror;
};
extern struct opts opts;

View File

@ -65,10 +65,10 @@ struct symbol {
u8 return_thunk : 1;
u8 fentry : 1;
u8 profiling_func : 1;
u8 warned : 1;
u8 embedded_insn : 1;
u8 local_label : 1;
u8 frame_pointer : 1;
u8 warnings : 2;
struct list_head pv_target;
struct reloc *relocs;
};

View File

@ -43,8 +43,10 @@ static inline char *offstr(struct section *sec, unsigned long offset)
#define WARN(format, ...) \
fprintf(stderr, \
"%s: warning: objtool: " format "\n", \
objname, ##__VA_ARGS__)
"%s: %s: objtool: " format "\n", \
objname, \
opts.werror ? "error" : "warning", \
##__VA_ARGS__)
#define WARN_FUNC(format, sec, offset, ...) \
({ \
@ -53,14 +55,22 @@ static inline char *offstr(struct section *sec, unsigned long offset)
free(_str); \
})
#define WARN_LIMIT 2
#define WARN_INSN(insn, format, ...) \
({ \
struct instruction *_insn = (insn); \
if (!_insn->sym || !_insn->sym->warned) \
BUILD_BUG_ON(WARN_LIMIT > 2); \
if (!_insn->sym || _insn->sym->warnings < WARN_LIMIT) { \
WARN_FUNC(format, _insn->sec, _insn->offset, \
##__VA_ARGS__); \
if (_insn->sym) \
_insn->sym->warned = 1; \
if (_insn->sym) \
_insn->sym->warnings++; \
} else if (_insn->sym && _insn->sym->warnings == WARN_LIMIT) { \
WARN_FUNC("skipping duplicate warning(s)", \
_insn->sec, _insn->offset); \
_insn->sym->warnings++; \
} \
})
#define BT_INSN(insn, format, ...) \

View File

@ -18,87 +18,19 @@
bool help;
const char *objname;
static struct objtool_file file;
static bool objtool_create_backup(const char *_objname)
struct objtool_file *objtool_open_read(const char *filename)
{
int len = strlen(_objname);
char *buf, *base, *name = malloc(len+6);
int s, d, l, t;
if (!name) {
perror("failed backup name malloc");
return false;
if (file.elf) {
WARN("won't handle more than one file at a time");
return NULL;
}
strcpy(name, _objname);
strcpy(name + len, ".orig");
d = open(name, O_CREAT|O_WRONLY|O_TRUNC, 0644);
if (d < 0) {
perror("failed to create backup file");
return false;
}
s = open(_objname, O_RDONLY);
if (s < 0) {
perror("failed to open orig file");
return false;
}
buf = malloc(4096);
if (!buf) {
perror("failed backup data malloc");
return false;
}
while ((l = read(s, buf, 4096)) > 0) {
base = buf;
do {
t = write(d, base, l);
if (t < 0) {
perror("failed backup write");
return false;
}
base += t;
l -= t;
} while (l);
}
if (l < 0) {
perror("failed backup read");
return false;
}
free(name);
free(buf);
close(d);
close(s);
return true;
}
struct objtool_file *objtool_open_read(const char *_objname)
{
if (objname) {
if (strcmp(objname, _objname)) {
WARN("won't handle more than one file at a time");
return NULL;
}
return &file;
}
objname = _objname;
file.elf = elf_open_read(objname, O_RDWR);
file.elf = elf_open_read(filename, O_RDWR);
if (!file.elf)
return NULL;
if (opts.backup && !objtool_create_backup(objname)) {
WARN("can't create backup file");
return NULL;
}
hash_init(file.insn_hash);
INIT_LIST_HEAD(&file.retpoline_call_list);
INIT_LIST_HEAD(&file.return_thunk_list);

View File

@ -10,7 +10,7 @@
#include <objtool/warn.h>
#include <objtool/endianness.h>
int orc_dump(const char *_objname)
int orc_dump(const char *filename)
{
int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0;
struct orc_entry *orc = NULL;
@ -26,12 +26,9 @@ int orc_dump(const char *_objname)
Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL;
struct elf dummy_elf = {};
objname = _objname;
elf_version(EV_CURRENT);
fd = open(objname, O_RDONLY);
fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("open");
return -1;