Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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
...

+573 -254
+3
arch/loongarch/Kconfig
··· 291 291 config AS_HAS_LVZ_EXTENSION 292 292 def_bool $(as-instr,hvcl 0) 293 293 294 + config CC_HAS_ANNOTATE_TABLEJUMP 295 + def_bool $(cc-option,-mannotate-tablejump) 296 + 294 297 menu "Kernel type and options" 295 298 296 299 source "kernel/Kconfig.hz"
+5 -1
arch/loongarch/Makefile
··· 101 101 KBUILD_CFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)-mthin-add-sub) 102 102 103 103 ifdef CONFIG_OBJTOOL 104 - KBUILD_CFLAGS += -fno-jump-tables 104 + ifdef CONFIG_CC_HAS_ANNOTATE_TABLEJUMP 105 + KBUILD_CFLAGS += -mannotate-tablejump 106 + else 107 + KBUILD_CFLAGS += -fno-jump-tables # keep compatibility with older compilers 108 + endif 105 109 endif 106 110 107 111 KBUILD_RUSTFLAGS += --target=loongarch64-unknown-none-softfloat -Ccode-model=small
+4
arch/x86/Kbuild
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 + 3 + # Branch profiling isn't noinstr-safe. Disable it for arch/x86/* 4 + subdir-ccflags-$(CONFIG_TRACE_BRANCH_PROFILING) += -DDISABLE_BRANCH_PROFILING 5 + 2 6 obj-$(CONFIG_ARCH_HAS_CC_PLATFORM) += coco/ 3 7 4 8 obj-y += entry/
-2
arch/x86/coco/sev/core.c
··· 9 9 10 10 #define pr_fmt(fmt) "SEV: " fmt 11 11 12 - #define DISABLE_BRANCH_PROFILING 13 - 14 12 #include <linux/sched/debug.h> /* For show_regs() */ 15 13 #include <linux/percpu-defs.h> 16 14 #include <linux/cc_platform.h>
-2
arch/x86/kernel/head64.c
··· 5 5 * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE 6 6 */ 7 7 8 - #define DISABLE_BRANCH_PROFILING 9 - 10 8 /* cpu_feature_enabled() cannot be used this early */ 11 9 #define USE_EARLY_PGTABLE_L5 12 10
+17 -1
arch/x86/kernel/traps.c
··· 380 380 #endif 381 381 382 382 /* 383 + * Prevent the compiler and/or objtool from marking the !CONFIG_X86_ESPFIX64 384 + * version of exc_double_fault() as noreturn. Otherwise the noreturn mismatch 385 + * between configs triggers objtool warnings. 386 + * 387 + * This is a temporary hack until we have compiler or plugin support for 388 + * annotating noreturns. 389 + */ 390 + #ifdef CONFIG_X86_ESPFIX64 391 + #define always_true() true 392 + #else 393 + bool always_true(void); 394 + bool __weak always_true(void) { return true; } 395 + #endif 396 + 397 + /* 383 398 * Runs on an IST stack for x86_64 and on a special task stack for x86_32. 384 399 * 385 400 * On x86_64, this is more or less a normal kernel entry. Notwithstanding the ··· 529 514 530 515 pr_emerg("PANIC: double fault, error_code: 0x%lx\n", error_code); 531 516 die("double fault", regs, error_code); 532 - panic("Machine halted."); 517 + if (always_true()) 518 + panic("Machine halted."); 533 519 instrumentation_end(); 534 520 } 535 521
-1
arch/x86/mm/kasan_init_64.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 - #define DISABLE_BRANCH_PROFILING 3 2 #define pr_fmt(fmt) "kasan: " fmt 4 3 5 4 /* cpu_feature_enabled() cannot be used this early */
-2
arch/x86/mm/mem_encrypt_amd.c
··· 7 7 * Author: Tom Lendacky <thomas.lendacky@amd.com> 8 8 */ 9 9 10 - #define DISABLE_BRANCH_PROFILING 11 - 12 10 #include <linux/linkage.h> 13 11 #include <linux/init.h> 14 12 #include <linux/mm.h>
-2
arch/x86/mm/mem_encrypt_identity.c
··· 7 7 * Author: Tom Lendacky <thomas.lendacky@amd.com> 8 8 */ 9 9 10 - #define DISABLE_BRANCH_PROFILING 11 - 12 10 /* 13 11 * Since we're dealing with identity mappings, physical and virtual 14 12 * addresses are the same, so override these defines which are ultimately
+4
drivers/acpi/Makefile
··· 5 5 6 6 ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT 7 7 8 + ifdef CONFIG_TRACE_BRANCH_PROFILING 9 + CFLAGS_processor_idle.o += -DDISABLE_BRANCH_PROFILING 10 + endif 11 + 8 12 # 9 13 # ACPI Boot-Time Table Parsing 10 14 #
+3
drivers/cpuidle/Makefile
··· 3 3 # Makefile for cpuidle. 4 4 # 5 5 6 + # Branch profiling isn't noinstr-safe 7 + ccflags-$(CONFIG_TRACE_BRANCH_PROFILING) += -DDISABLE_BRANCH_PROFILING 8 + 6 9 obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ 7 10 obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o 8 11 obj-$(CONFIG_DT_IDLE_STATES) += dt_idle_states.o
+4 -1
drivers/idle/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 - obj-$(CONFIG_INTEL_IDLE) += intel_idle.o 3 2 3 + # Branch profiling isn't noinstr-safe 4 + ccflags-$(CONFIG_TRACE_BRANCH_PROFILING) += -DDISABLE_BRANCH_PROFILING 5 + 6 + obj-$(CONFIG_INTEL_IDLE) += intel_idle.o
+5
kernel/Makefile
··· 21 21 CFLAGS_REMOVE_irq_work.o = $(CC_FLAGS_FTRACE) 22 22 endif 23 23 24 + # Branch profiling isn't noinstr-safe 25 + ifdef CONFIG_TRACE_BRANCH_PROFILING 26 + CFLAGS_context_tracking.o += -DDISABLE_BRANCH_PROFILING 27 + endif 28 + 24 29 # Prevents flicker of uninteresting __do_softirq()/__local_bh_disable_ip() 25 30 # in coverage traces. 26 31 KCOV_INSTRUMENT_softirq.o := n
+3
kernel/entry/Makefile
··· 6 6 UBSAN_SANITIZE := n 7 7 KCOV_INSTRUMENT := n 8 8 9 + # Branch profiling isn't noinstr-safe 10 + ccflags-$(CONFIG_TRACE_BRANCH_PROFILING) += -DDISABLE_BRANCH_PROFILING 11 + 9 12 CFLAGS_REMOVE_common.o = -fstack-protector -fstack-protector-strong 10 13 CFLAGS_common.o += -fno-stack-protector 11 14
+5
kernel/sched/Makefile
··· 22 22 CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer 23 23 endif 24 24 25 + # Branch profiling isn't noinstr-safe 26 + ifdef CONFIG_TRACE_BRANCH_PROFILING 27 + CFLAGS_build_policy.o += -DDISABLE_BRANCH_PROFILING 28 + CFLAGS_build_utility.o += -DDISABLE_BRANCH_PROFILING 29 + endif 25 30 # 26 31 # Build efficiency: 27 32 #
+6
kernel/time/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 + 3 + # Branch profiling isn't noinstr-safe 4 + ifdef CONFIG_TRACE_BRANCH_PROFILING 5 + CFLAGS_sched_clock.o += -DDISABLE_BRANCH_PROFILING 6 + endif 7 + 2 8 obj-y += time.o timer.o hrtimer.o sleep_timeout.o 3 9 obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o 4 10 obj-y += timeconv.o timecounter.o alarmtimer.o
+11
lib/Kconfig.debug
··· 545 545 config OBJTOOL 546 546 bool 547 547 548 + config OBJTOOL_WERROR 549 + bool "Upgrade objtool warnings to errors" 550 + depends on OBJTOOL && !COMPILE_TEST 551 + help 552 + Fail the build on objtool warnings. 553 + 554 + Objtool warnings can indicate kernel instability, including boot 555 + failures. This option is highly recommended. 556 + 557 + If unsure, say Y. 558 + 548 559 config STACK_VALIDATION 549 560 bool "Compile-time stack metadata validation" 550 561 depends on HAVE_STACK_VALIDATION && UNWINDER_FRAME_POINTER
+5
lib/Makefile
··· 5 5 6 6 ccflags-remove-$(CONFIG_FUNCTION_TRACER) += $(CC_FLAGS_FTRACE) 7 7 8 + # Branch profiling isn't noinstr-safe 9 + ifdef CONFIG_TRACE_BRANCH_PROFILING 10 + CFLAGS_smp_processor_id.o += -DDISABLE_BRANCH_PROFILING 11 + endif 12 + 8 13 # These files are disabled because they produce lots of non-interesting and/or 9 14 # flaky coverage that is not a function of syscall inputs. For example, 10 15 # rbtree can be global and individual rotations don't correlate with inputs.
+1
scripts/Makefile.lib
··· 277 277 objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) += --uaccess 278 278 objtool-args-$(CONFIG_GCOV_KERNEL) += --no-unreachable 279 279 objtool-args-$(CONFIG_PREFIX_SYMBOLS) += --prefix=$(CONFIG_FUNCTION_PADDING_BYTES) 280 + objtool-args-$(CONFIG_OBJTOOL_WERROR) += --Werror --backtrace 280 281 281 282 objtool-args = $(objtool-args-y) \ 282 283 $(if $(delay-objtool), --link) \
+57 -48
tools/objtool/Documentation/objtool.txt
··· 28 28 sites, enabling the kernel to patch them inline, to prevent "thunk 29 29 funneling" for both security and performance reasons 30 30 31 + - Return thunk validation -- validates return thunks are used for 32 + certain CPU mitigations including Retbleed and SRSO 33 + 34 + - Return thunk annotation -- annotates all return thunk sites so kernel 35 + can patch them inline, depending on enabled mitigations 36 + 37 + - Return thunk training valiation -- validate that all entry paths 38 + untrain a "safe return" before the first return (or call) 39 + 31 40 - Non-instrumentation validation -- validates non-instrumentable 32 41 ("noinstr") code rules, preventing instrumentation in low-level C 33 42 entry code ··· 61 52 62 53 - Function entry annotation -- annotates function entries, enabling 63 54 kernel function tracing 55 + 56 + - Function preamble (prefix) annotation and/or symbol generation -- used 57 + for FineIBT and call depth tracking 64 58 65 59 - Other toolchain hacks which will go unmentioned at this time... 66 60 ··· 209 197 210 198 1. Each callable function must be annotated as such with the ELF 211 199 function type. In asm code, this is typically done using the 212 - ENTRY/ENDPROC macros. If objtool finds a return instruction 200 + SYM_FUNC_{START,END} macros. If objtool finds a return instruction 213 201 outside of a function, it flags an error since that usually indicates 214 202 callable code which should be annotated accordingly. 215 203 216 204 This rule is needed so that objtool can properly identify each 217 205 callable function in order to analyze its stack metadata. 218 206 219 - 2. Conversely, each section of code which is *not* callable should *not* 220 - be annotated as an ELF function. The ENDPROC macro shouldn't be used 221 - in this case. 222 - 223 - This rule is needed so that objtool can ignore non-callable code. 224 - Such code doesn't have to follow any of the other rules. 207 + 2. Conversely, each section of code which is *not* callable, or is 208 + otherwise doing funny things with the stack or registers, should 209 + *not* be annotated as an ELF function. Rather, SYM_CODE_{START,END} 210 + should be used along with unwind hints. 225 211 226 212 3. Each callable function which calls another function must have the 227 213 correct frame pointer logic, if required by CONFIG_FRAME_POINTER or ··· 231 221 function B, the _caller_ of function A will be skipped on the stack 232 222 trace. 233 223 234 - 4. Dynamic jumps and jumps to undefined symbols are only allowed if: 224 + 4. Indirect jumps and jumps to undefined symbols are only allowed if: 235 225 236 226 a) the jump is part of a switch statement; or 237 227 ··· 314 304 001e 2823e: 80 ce 02 or $0x2,%dh 315 305 ... 316 306 307 + 317 308 2. file.o: warning: objtool: .text+0x53: unreachable instruction 318 309 319 310 Objtool couldn't find a code path to reach the instruction. 320 311 321 312 If the error is for an asm file, and the instruction is inside (or 322 313 reachable from) a callable function, the function should be annotated 323 - with the ENTRY/ENDPROC macros (ENDPROC is the important one). 324 - Otherwise, the code should probably be annotated with the unwind hint 325 - macros in asm/unwind_hints.h so objtool and the unwinder can know the 326 - stack state associated with the code. 314 + with the SYM_FUNC_START and SYM_FUNC_END macros. 327 315 328 - If you're 100% sure the code won't affect stack traces, or if you're 329 - a just a bad person, you can tell objtool to ignore it. See the 330 - "Adding exceptions" section below. 316 + Otherwise, SYM_CODE_START can be used. In that case the code needs 317 + to be annotated with unwind hint macros. 331 318 332 - If it's not actually in a callable function (e.g. kernel entry code), 333 - change ENDPROC to END. 319 + If you're sure the code won't affect the reliability of runtime stack 320 + traces and want objtool to ignore it, see "Adding exceptions" below. 334 321 335 - 3. file.o: warning: objtool: foo+0x48c: bar() is missing a __noreturn annotation 336 322 337 - The call from foo() to bar() doesn't return, but bar() is missing the 338 - __noreturn annotation. NOTE: In addition to annotating the function 339 - with __noreturn, please also add it to tools/objtool/noreturns.h. 323 + 3. file.o: warning: objtool: foo+0x48c: bar() missing __noreturn in .c/.h or NORETURN() in noreturns.h 324 + 325 + The call from foo() to bar() doesn't return, but bar() is incorrectly 326 + annotated. A noreturn function must be marked __noreturn in both its 327 + declaration and its definition, and must have a NORETURN() annotation 328 + in tools/objtool/noreturns.h. 329 + 340 330 341 331 4. file.o: warning: objtool: func(): can't find starting instruction 342 332 or ··· 351 341 352 342 This is a kernel entry/exit instruction like sysenter or iret. Such 353 343 instructions aren't allowed in a callable function, and are most 354 - likely part of the kernel entry code. They should usually not have 355 - the callable function annotation (ENDPROC) and should always be 356 - annotated with the unwind hint macros in asm/unwind_hints.h. 344 + likely part of the kernel entry code. Such code should probably be 345 + placed in a SYM_FUNC_CODE block with unwind hints. 357 346 358 347 359 348 6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame 360 349 361 - This is a dynamic jump or a jump to an undefined symbol. Objtool 362 - assumed it's a sibling call and detected that the frame pointer 363 - wasn't first restored to its original state. 350 + This is a branch to an UNDEF symbol. Objtool assumed it's a 351 + sibling call and detected that the stack wasn't first restored to its 352 + original state. 364 353 365 - If it's not really a sibling call, you may need to move the 366 - destination code to the local file. 354 + If it's not really a sibling call, you may need to use unwind hints 355 + and/or move the destination code to the local file. 367 356 368 357 If the instruction is not actually in a callable function (e.g. 369 - kernel entry code), change ENDPROC to END and annotate manually with 370 - the unwind hint macros in asm/unwind_hints.h. 358 + kernel entry code), use SYM_CODE_{START,END} and unwind hints. 371 359 372 360 373 361 7. file: warning: objtool: func()+0x5c: stack state mismatch ··· 381 373 382 374 Another possibility is that the code has some asm or inline asm which 383 375 does some unusual things to the stack or the frame pointer. In such 384 - cases it's probably appropriate to use the unwind hint macros in 385 - asm/unwind_hints.h. 376 + cases it's probably appropriate to use SYM_FUNC_CODE with unwind 377 + hints. 386 378 387 379 388 380 8. file.o: warning: objtool: funcA() falls through to next function funcB() ··· 392 384 can fall through into the next function. There could be different 393 385 reasons for this: 394 386 395 - 1) funcA()'s last instruction is a call to a "noreturn" function like 387 + a) funcA()'s last instruction is a call to a "noreturn" function like 396 388 panic(). In this case the noreturn function needs to be added to 397 389 objtool's hard-coded global_noreturns array. Feel free to bug the 398 390 objtool maintainer, or you can submit a patch. 399 391 400 - 2) funcA() uses the unreachable() annotation in a section of code 392 + b) funcA() uses the unreachable() annotation in a section of code 401 393 that is actually reachable. 402 394 403 - 3) If funcA() calls an inline function, the object code for funcA() 404 - might be corrupt due to a gcc bug. For more details, see: 405 - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646 395 + c) Some undefined behavior like divide by zero. 396 + 406 397 407 398 9. file.o: warning: objtool: funcA() call to funcB() with UACCESS enabled 408 399 ··· 439 432 This limitation can be overcome by massaging the alternatives with 440 433 NOPs to shift the stack changes around so they no longer conflict. 441 434 435 + 442 436 11. file.o: warning: unannotated intra-function call 443 437 444 - This warning means that a direct call is done to a destination which 445 - is not at the beginning of a function. If this is a legit call, you 446 - can remove this warning by putting the ANNOTATE_INTRA_FUNCTION_CALL 447 - directive right before the call. 438 + This warning means that a direct call is done to a destination which 439 + is not at the beginning of a function. If this is a legit call, you 440 + can remove this warning by putting the ANNOTATE_INTRA_FUNCTION_CALL 441 + directive right before the call. 442 + 448 443 449 444 12. file.o: warning: func(): not an indirect call target 450 445 451 - This means that objtool is running with --ibt and a function expected 452 - to be an indirect call target is not. In particular, this happens for 453 - init_module() or cleanup_module() if a module relies on these special 454 - names and does not use module_init() / module_exit() macros to create 455 - them. 446 + This means that objtool is running with --ibt and a function 447 + expected to be an indirect call target is not. In particular, this 448 + happens for init_module() or cleanup_module() if a module relies on 449 + these special names and does not use module_init() / module_exit() 450 + macros to create them. 456 451 457 452 458 453 If the error doesn't seem to make sense, it could be a bug in objtool. 459 - Feel free to ask the objtool maintainer for help. 454 + Feel free to ask objtool maintainers for help. 460 455 461 456 462 457 Adding exceptions
+1 -1
tools/objtool/Makefile
··· 37 37 OBJTOOL_LDFLAGS := $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS) 38 38 39 39 # Allow old libelf to be used: 40 - elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - | grep elf_getshdr) 40 + elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - 2>/dev/null | grep elf_getshdr) 41 41 OBJTOOL_CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) 42 42 43 43 # Always want host compilation.
+24 -4
tools/objtool/arch/loongarch/decode.c
··· 5 5 #include <asm/inst.h> 6 6 #include <asm/orc_types.h> 7 7 #include <linux/objtool_types.h> 8 - 9 - #ifndef EM_LOONGARCH 10 - #define EM_LOONGARCH 258 11 - #endif 8 + #include <arch/elf.h> 12 9 13 10 int arch_ftrace_match(char *name) 14 11 { ··· 359 362 /* initial CFA (call frame address) */ 360 363 state->cfa.base = CFI_SP; 361 364 state->cfa.offset = 0; 365 + } 366 + 367 + unsigned int arch_reloc_size(struct reloc *reloc) 368 + { 369 + switch (reloc_type(reloc)) { 370 + case R_LARCH_32: 371 + case R_LARCH_32_PCREL: 372 + return 4; 373 + default: 374 + return 8; 375 + } 376 + } 377 + 378 + unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table) 379 + { 380 + switch (reloc_type(reloc)) { 381 + case R_LARCH_32_PCREL: 382 + case R_LARCH_64_PCREL: 383 + return reloc->sym->offset + reloc_addend(reloc) - 384 + (reloc_offset(reloc) - reloc_offset(table)); 385 + default: 386 + return reloc->sym->offset + reloc_addend(reloc); 387 + } 362 388 }
+7
tools/objtool/arch/loongarch/include/arch/elf.h
··· 18 18 #ifndef R_LARCH_32_PCREL 19 19 #define R_LARCH_32_PCREL 99 20 20 #endif 21 + #ifndef R_LARCH_64_PCREL 22 + #define R_LARCH_64_PCREL 109 23 + #endif 24 + 25 + #ifndef EM_LOONGARCH 26 + #define EM_LOONGARCH 258 27 + #endif 21 28 22 29 #define R_NONE R_LARCH_NONE 23 30 #define R_ABS32 R_LARCH_32
+158 -1
tools/objtool/arch/loongarch/special.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 + #include <string.h> 2 3 #include <objtool/special.h> 4 + #include <objtool/warn.h> 3 5 4 6 bool arch_support_alt_relocation(struct special_alt *special_alt, 5 7 struct instruction *insn, ··· 10 8 return false; 11 9 } 12 10 11 + struct table_info { 12 + struct list_head jump_info; 13 + unsigned long insn_offset; 14 + unsigned long rodata_offset; 15 + }; 16 + 17 + static void get_rodata_table_size_by_table_annotate(struct objtool_file *file, 18 + struct instruction *insn, 19 + unsigned long *table_size) 20 + { 21 + struct section *rsec; 22 + struct reloc *reloc; 23 + struct list_head table_list; 24 + struct table_info *orig_table; 25 + struct table_info *next_table; 26 + unsigned long tmp_insn_offset; 27 + unsigned long tmp_rodata_offset; 28 + 29 + rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate"); 30 + if (!rsec) 31 + return; 32 + 33 + INIT_LIST_HEAD(&table_list); 34 + 35 + for_each_reloc(rsec, reloc) { 36 + orig_table = malloc(sizeof(struct table_info)); 37 + if (!orig_table) { 38 + WARN("malloc failed"); 39 + return; 40 + } 41 + 42 + orig_table->insn_offset = reloc->sym->offset + reloc_addend(reloc); 43 + reloc++; 44 + orig_table->rodata_offset = reloc->sym->offset + reloc_addend(reloc); 45 + 46 + list_add_tail(&orig_table->jump_info, &table_list); 47 + 48 + if (reloc_idx(reloc) + 1 == sec_num_entries(rsec)) 49 + break; 50 + } 51 + 52 + list_for_each_entry(orig_table, &table_list, jump_info) { 53 + next_table = list_next_entry(orig_table, jump_info); 54 + list_for_each_entry_from(next_table, &table_list, jump_info) { 55 + if (next_table->rodata_offset < orig_table->rodata_offset) { 56 + tmp_insn_offset = next_table->insn_offset; 57 + tmp_rodata_offset = next_table->rodata_offset; 58 + next_table->insn_offset = orig_table->insn_offset; 59 + next_table->rodata_offset = orig_table->rodata_offset; 60 + orig_table->insn_offset = tmp_insn_offset; 61 + orig_table->rodata_offset = tmp_rodata_offset; 62 + } 63 + } 64 + } 65 + 66 + list_for_each_entry(orig_table, &table_list, jump_info) { 67 + if (insn->offset == orig_table->insn_offset) { 68 + next_table = list_next_entry(orig_table, jump_info); 69 + if (&next_table->jump_info == &table_list) { 70 + *table_size = 0; 71 + return; 72 + } 73 + 74 + while (next_table->rodata_offset == orig_table->rodata_offset) { 75 + next_table = list_next_entry(next_table, jump_info); 76 + if (&next_table->jump_info == &table_list) { 77 + *table_size = 0; 78 + return; 79 + } 80 + } 81 + 82 + *table_size = next_table->rodata_offset - orig_table->rodata_offset; 83 + } 84 + } 85 + } 86 + 87 + static struct reloc *find_reloc_by_table_annotate(struct objtool_file *file, 88 + struct instruction *insn, 89 + unsigned long *table_size) 90 + { 91 + struct section *rsec; 92 + struct reloc *reloc; 93 + unsigned long offset; 94 + 95 + rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate"); 96 + if (!rsec) 97 + return NULL; 98 + 99 + for_each_reloc(rsec, reloc) { 100 + if (reloc->sym->sec->rodata) 101 + continue; 102 + 103 + if (strcmp(insn->sec->name, reloc->sym->sec->name)) 104 + continue; 105 + 106 + offset = reloc->sym->offset + reloc_addend(reloc); 107 + if (insn->offset == offset) { 108 + get_rodata_table_size_by_table_annotate(file, insn, table_size); 109 + reloc++; 110 + return reloc; 111 + } 112 + } 113 + 114 + return NULL; 115 + } 116 + 117 + static struct reloc *find_reloc_of_rodata_c_jump_table(struct section *sec, 118 + unsigned long offset, 119 + unsigned long *table_size) 120 + { 121 + struct section *rsec; 122 + struct reloc *reloc; 123 + 124 + rsec = sec->rsec; 125 + if (!rsec) 126 + return NULL; 127 + 128 + for_each_reloc(rsec, reloc) { 129 + if (reloc_offset(reloc) > offset) 130 + break; 131 + 132 + if (!strcmp(reloc->sym->sec->name, C_JUMP_TABLE_SECTION)) { 133 + *table_size = 0; 134 + return reloc; 135 + } 136 + } 137 + 138 + return NULL; 139 + } 140 + 13 141 struct reloc *arch_find_switch_table(struct objtool_file *file, 14 142 struct instruction *insn, 15 143 unsigned long *table_size) 16 144 { 17 - return NULL; 145 + struct reloc *annotate_reloc; 146 + struct reloc *rodata_reloc; 147 + struct section *table_sec; 148 + unsigned long table_offset; 149 + 150 + annotate_reloc = find_reloc_by_table_annotate(file, insn, table_size); 151 + if (!annotate_reloc) { 152 + annotate_reloc = find_reloc_of_rodata_c_jump_table( 153 + insn->sec, insn->offset, table_size); 154 + if (!annotate_reloc) 155 + return NULL; 156 + } 157 + 158 + table_sec = annotate_reloc->sym->sec; 159 + table_offset = annotate_reloc->sym->offset + reloc_addend(annotate_reloc); 160 + 161 + /* 162 + * Each table entry has a rela associated with it. The rela 163 + * should reference text in the same function as the original 164 + * instruction. 165 + */ 166 + rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset); 167 + if (!rodata_reloc) 168 + return NULL; 169 + 170 + return rodata_reloc; 18 171 }
+14
tools/objtool/arch/powerpc/decode.c
··· 106 106 state->regs[CFI_RA].base = CFI_CFA; 107 107 state->regs[CFI_RA].offset = 0; 108 108 } 109 + 110 + unsigned int arch_reloc_size(struct reloc *reloc) 111 + { 112 + switch (reloc_type(reloc)) { 113 + case R_PPC_REL32: 114 + case R_PPC_ADDR32: 115 + case R_PPC_UADDR32: 116 + case R_PPC_PLT32: 117 + case R_PPC_PLTREL32: 118 + return 4; 119 + default: 120 + return 8; 121 + } 122 + }
+13
tools/objtool/arch/x86/decode.c
··· 852 852 return !strcmp(sym->name, "retbleed_return_thunk") || 853 853 !strcmp(sym->name, "srso_safe_ret"); 854 854 } 855 + 856 + unsigned int arch_reloc_size(struct reloc *reloc) 857 + { 858 + switch (reloc_type(reloc)) { 859 + case R_X86_64_32: 860 + case R_X86_64_32S: 861 + case R_X86_64_PC32: 862 + case R_X86_64_PLT32: 863 + return 4; 864 + default: 865 + return 8; 866 + } 867 + }
+157 -55
tools/objtool/builtin-check.c
··· 6 6 #include <subcmd/parse-options.h> 7 7 #include <string.h> 8 8 #include <stdlib.h> 9 + #include <fcntl.h> 10 + #include <unistd.h> 11 + #include <sys/stat.h> 12 + #include <sys/sendfile.h> 9 13 #include <objtool/builtin.h> 10 14 #include <objtool/objtool.h> 11 15 ··· 17 13 fprintf(stderr, \ 18 14 "error: objtool: " format "\n", \ 19 15 ##__VA_ARGS__) 16 + 17 + const char *objname; 20 18 21 19 struct opts opts; 22 20 ··· 77 71 OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"), 78 72 OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"), 79 73 OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"), 80 - OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"), 74 + OPT_BOOLEAN(0, "orc", &opts.orc, "generate ORC metadata"), 81 75 OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"), 82 76 OPT_BOOLEAN(0, "rethunk", &opts.rethunk, "validate and annotate rethunk usage"), 83 77 OPT_BOOLEAN(0, "unret", &opts.unret, "validate entry unret placement"), ··· 90 84 OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump), 91 85 92 86 OPT_GROUP("Options:"), 93 - OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"), 94 - OPT_BOOLEAN(0, "backup", &opts.backup, "create .orig files before modification"), 95 - OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"), 96 - OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"), 97 - OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"), 98 - OPT_BOOLEAN(0, "mnop", &opts.mnop, "nop out mcount call sites"), 99 - OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"), 100 - OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"), 101 - OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"), 87 + OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"), 88 + OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"), 89 + OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"), 90 + OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"), 91 + OPT_BOOLEAN(0, "mnop", &opts.mnop, "nop out mcount call sites"), 92 + OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"), 93 + OPT_STRING('o', "output", &opts.output, "file", "output file name"), 94 + OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"), 95 + OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"), 102 96 OPT_BOOLEAN('v', "verbose", &opts.verbose, "verbose warnings"), 97 + OPT_BOOLEAN(0, "Werror", &opts.werror, "return error on warnings"), 103 98 104 99 OPT_END(), 105 100 }; ··· 138 131 139 132 static bool opts_valid(void) 140 133 { 134 + if (opts.mnop && !opts.mcount) { 135 + ERROR("--mnop requires --mcount"); 136 + return false; 137 + } 138 + 139 + if (opts.noinstr && !opts.link) { 140 + ERROR("--noinstr requires --link"); 141 + return false; 142 + } 143 + 144 + if (opts.ibt && !opts.link) { 145 + ERROR("--ibt requires --link"); 146 + return false; 147 + } 148 + 149 + if (opts.unret && !opts.link) { 150 + ERROR("--unret requires --link"); 151 + return false; 152 + } 153 + 141 154 if (opts.hack_jump_label || 142 155 opts.hack_noinstr || 143 156 opts.ibt || ··· 178 151 return true; 179 152 } 180 153 181 - if (opts.unret && !opts.rethunk) { 182 - ERROR("--unret requires --rethunk"); 183 - return false; 184 - } 185 - 186 154 if (opts.dump_orc) 187 155 return true; 188 156 ··· 185 163 return false; 186 164 } 187 165 188 - static bool mnop_opts_valid(void) 166 + static int copy_file(const char *src, const char *dst) 189 167 { 190 - if (opts.mnop && !opts.mcount) { 191 - ERROR("--mnop requires --mcount"); 192 - return false; 168 + size_t to_copy, copied; 169 + int dst_fd, src_fd; 170 + struct stat stat; 171 + off_t offset = 0; 172 + 173 + src_fd = open(src, O_RDONLY); 174 + if (src_fd == -1) { 175 + ERROR("can't open '%s' for reading", src); 176 + return 1; 193 177 } 194 178 195 - return true; 179 + dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0400); 180 + if (dst_fd == -1) { 181 + ERROR("can't open '%s' for writing", dst); 182 + return 1; 183 + } 184 + 185 + if (fstat(src_fd, &stat) == -1) { 186 + perror("fstat"); 187 + return 1; 188 + } 189 + 190 + if (fchmod(dst_fd, stat.st_mode) == -1) { 191 + perror("fchmod"); 192 + return 1; 193 + } 194 + 195 + for (to_copy = stat.st_size; to_copy > 0; to_copy -= copied) { 196 + copied = sendfile(dst_fd, src_fd, &offset, to_copy); 197 + if (copied == -1) { 198 + perror("sendfile"); 199 + return 1; 200 + } 201 + } 202 + 203 + close(dst_fd); 204 + close(src_fd); 205 + return 0; 196 206 } 197 207 198 - static bool link_opts_valid(struct objtool_file *file) 208 + static char **save_argv(int argc, const char **argv) 199 209 { 200 - if (opts.link) 201 - return true; 210 + char **orig_argv; 202 211 203 - if (has_multiple_files(file->elf)) { 204 - ERROR("Linked object detected, forcing --link"); 205 - opts.link = true; 206 - return true; 212 + orig_argv = calloc(argc, sizeof(char *)); 213 + if (!orig_argv) { 214 + perror("calloc"); 215 + return NULL; 207 216 } 208 217 209 - if (opts.noinstr) { 210 - ERROR("--noinstr requires --link"); 211 - return false; 212 - } 218 + for (int i = 0; i < argc; i++) { 219 + orig_argv[i] = strdup(argv[i]); 220 + if (!orig_argv[i]) { 221 + perror("strdup"); 222 + return NULL; 223 + } 224 + }; 213 225 214 - if (opts.ibt) { 215 - ERROR("--ibt requires --link"); 216 - return false; 217 - } 218 - 219 - if (opts.unret) { 220 - ERROR("--unret requires --link"); 221 - return false; 222 - } 223 - 224 - return true; 226 + return orig_argv; 225 227 } 228 + 229 + #define ORIG_SUFFIX ".orig" 226 230 227 231 int objtool_run(int argc, const char **argv) 228 232 { 229 - const char *objname; 230 233 struct objtool_file *file; 231 - int ret; 234 + char *backup = NULL; 235 + char **orig_argv; 236 + int ret = 0; 232 237 233 - argc = cmd_parse_options(argc, argv, check_usage); 234 - objname = argv[0]; 238 + orig_argv = save_argv(argc, argv); 239 + if (!orig_argv) 240 + return 1; 241 + 242 + cmd_parse_options(argc, argv, check_usage); 235 243 236 244 if (!opts_valid()) 237 245 return 1; 238 246 247 + objname = argv[0]; 248 + 239 249 if (opts.dump_orc) 240 250 return orc_dump(objname); 241 251 252 + if (!opts.dryrun && opts.output) { 253 + /* copy original .o file to output file */ 254 + if (copy_file(objname, opts.output)) 255 + return 1; 256 + 257 + /* from here on, work directly on the output file */ 258 + objname = opts.output; 259 + } 260 + 242 261 file = objtool_open_read(objname); 243 262 if (!file) 244 - return 1; 263 + goto err; 245 264 246 - if (!mnop_opts_valid()) 247 - return 1; 248 - 249 - if (!link_opts_valid(file)) 250 - return 1; 265 + if (!opts.link && has_multiple_files(file->elf)) { 266 + ERROR("Linked object requires --link"); 267 + goto err; 268 + } 251 269 252 270 ret = check(file); 253 271 if (ret) 254 - return ret; 272 + goto err; 255 273 256 - if (file->elf->changed) 257 - return elf_write(file->elf); 274 + if (!opts.dryrun && file->elf->changed && elf_write(file->elf)) 275 + goto err; 258 276 259 277 return 0; 278 + 279 + err: 280 + if (opts.dryrun) 281 + goto err_msg; 282 + 283 + if (opts.output) { 284 + unlink(opts.output); 285 + goto err_msg; 286 + } 287 + 288 + /* 289 + * Make a backup before kbuild deletes the file so the error 290 + * can be recreated without recompiling or relinking. 291 + */ 292 + backup = malloc(strlen(objname) + strlen(ORIG_SUFFIX) + 1); 293 + if (!backup) { 294 + perror("malloc"); 295 + return 1; 296 + } 297 + 298 + strcpy(backup, objname); 299 + strcat(backup, ORIG_SUFFIX); 300 + if (copy_file(objname, backup)) 301 + return 1; 302 + 303 + err_msg: 304 + fprintf(stderr, "%s", orig_argv[0]); 305 + 306 + for (int i = 1; i < argc; i++) { 307 + char *arg = orig_argv[i]; 308 + 309 + if (backup && !strcmp(arg, objname)) 310 + fprintf(stderr, " %s -o %s", backup, objname); 311 + else 312 + fprintf(stderr, " %s", arg); 313 + } 314 + 315 + fprintf(stderr, "\n"); 316 + 317 + return 1; 260 318 }
+38 -45
tools/objtool/check.c
··· 1944 1944 return ret; 1945 1945 } 1946 1946 1947 + __weak unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table) 1948 + { 1949 + return reloc->sym->offset + reloc_addend(reloc); 1950 + } 1951 + 1947 1952 static int add_jump_table(struct objtool_file *file, struct instruction *insn, 1948 1953 struct reloc *next_table) 1949 1954 { ··· 1959 1954 unsigned int prev_offset = 0; 1960 1955 struct reloc *reloc = table; 1961 1956 struct alternative *alt; 1957 + unsigned long sym_offset; 1962 1958 1963 1959 /* 1964 1960 * Each @reloc is a switch table relocation which points to the target ··· 1974 1968 break; 1975 1969 1976 1970 /* Make sure the table entries are consecutive: */ 1977 - if (prev_offset && reloc_offset(reloc) != prev_offset + 8) 1971 + if (prev_offset && reloc_offset(reloc) != prev_offset + arch_reloc_size(reloc)) 1978 1972 break; 1979 1973 1974 + sym_offset = arch_jump_table_sym_offset(reloc, table); 1975 + 1980 1976 /* Detect function pointers from contiguous objects: */ 1981 - if (reloc->sym->sec == pfunc->sec && 1982 - reloc_addend(reloc) == pfunc->offset) 1977 + if (reloc->sym->sec == pfunc->sec && sym_offset == pfunc->offset) 1983 1978 break; 1984 1979 1985 1980 /* ··· 1988 1981 * which point to the end of the function. Ignore them. 1989 1982 */ 1990 1983 if (reloc->sym->sec == pfunc->sec && 1991 - reloc_addend(reloc) == pfunc->offset + pfunc->len) 1984 + sym_offset == pfunc->offset + pfunc->len) 1992 1985 goto next; 1993 1986 1994 - dest_insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); 1987 + dest_insn = find_insn(file, reloc->sym->sec, sym_offset); 1995 1988 if (!dest_insn) 1996 1989 break; 1997 1990 ··· 2030 2023 struct reloc *table_reloc; 2031 2024 struct instruction *dest_insn, *orig_insn = insn; 2032 2025 unsigned long table_size; 2026 + unsigned long sym_offset; 2033 2027 2034 2028 /* 2035 2029 * Backward search using the @first_jump_src links, these help avoid ··· 2054 2046 table_reloc = arch_find_switch_table(file, insn, &table_size); 2055 2047 if (!table_reloc) 2056 2048 continue; 2057 - dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc)); 2049 + 2050 + sym_offset = table_reloc->sym->offset + reloc_addend(table_reloc); 2051 + 2052 + dest_insn = find_insn(file, table_reloc->sym->sec, sym_offset); 2058 2053 if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func) 2059 2054 continue; 2060 2055 ··· 4460 4449 return warnings; 4461 4450 } 4462 4451 4463 - static bool ignore_noreturn_call(struct instruction *insn) 4464 - { 4465 - struct symbol *call_dest = insn_call_dest(insn); 4466 - 4467 - /* 4468 - * FIXME: hack, we need a real noreturn solution 4469 - * 4470 - * Problem is, exc_double_fault() may or may not return, depending on 4471 - * whether CONFIG_X86_ESPFIX64 is set. But objtool has no visibility 4472 - * to the kernel config. 4473 - * 4474 - * Other potential ways to fix it: 4475 - * 4476 - * - have compiler communicate __noreturn functions somehow 4477 - * - remove CONFIG_X86_ESPFIX64 4478 - * - read the .config file 4479 - * - add a cmdline option 4480 - * - create a generic objtool annotation format (vs a bunch of custom 4481 - * formats) and annotate it 4482 - */ 4483 - if (!strcmp(call_dest->name, "exc_double_fault")) { 4484 - /* prevent further unreachable warnings for the caller */ 4485 - insn->sym->warned = 1; 4486 - return true; 4487 - } 4488 - 4489 - return false; 4490 - } 4491 - 4492 4452 static int validate_reachable_instructions(struct objtool_file *file) 4493 4453 { 4494 4454 struct instruction *insn, *prev_insn; ··· 4476 4494 prev_insn = prev_insn_same_sec(file, insn); 4477 4495 if (prev_insn && prev_insn->dead_end) { 4478 4496 call_dest = insn_call_dest(prev_insn); 4479 - if (call_dest && !ignore_noreturn_call(prev_insn)) { 4480 - WARN_INSN(insn, "%s() is missing a __noreturn annotation", 4497 + if (call_dest) { 4498 + WARN_INSN(insn, "%s() missing __noreturn in .c/.h or NORETURN() in noreturns.h", 4481 4499 call_dest->name); 4482 4500 warnings++; 4483 4501 continue; ··· 4547 4565 char *funcs = NULL, *tmp; 4548 4566 4549 4567 for_each_sym(file, sym) { 4550 - if (sym->warned) { 4568 + if (sym->warnings) { 4551 4569 if (!funcs) { 4552 4570 funcs = malloc(strlen(sym->name) + 1); 4553 4571 strcpy(funcs, sym->name); ··· 4605 4623 init_cfi_state(&force_undefined_cfi); 4606 4624 force_undefined_cfi.force_undefined = true; 4607 4625 4608 - if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) 4626 + if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) { 4627 + ret = -1; 4609 4628 goto out; 4629 + } 4610 4630 4611 4631 cfi_hash_add(&init_cfi); 4612 4632 cfi_hash_add(&func_cfi); ··· 4625 4641 if (opts.retpoline) { 4626 4642 ret = validate_retpoline(file); 4627 4643 if (ret < 0) 4628 - return ret; 4644 + goto out; 4629 4645 warnings += ret; 4630 4646 } 4631 4647 ··· 4661 4677 */ 4662 4678 ret = validate_unrets(file); 4663 4679 if (ret < 0) 4664 - return ret; 4680 + goto out; 4665 4681 warnings += ret; 4666 4682 } 4667 4683 ··· 4724 4740 if (opts.prefix) { 4725 4741 ret = add_prefix_symbols(file); 4726 4742 if (ret < 0) 4727 - return ret; 4743 + goto out; 4728 4744 warnings += ret; 4729 4745 } 4730 4746 ··· 4756 4772 4757 4773 out: 4758 4774 /* 4759 - * For now, don't fail the kernel build on fatal warnings. These 4760 - * errors are still fairly common due to the growing matrix of 4761 - * supported toolchains and their recent pace of change. 4775 + * CONFIG_OBJTOOL_WERROR upgrades all warnings (and errors) to actual 4776 + * errors. 4777 + * 4778 + * Note that even "fatal" type errors don't actually return an error 4779 + * without CONFIG_OBJTOOL_WERROR. That probably needs improved at some 4780 + * point. 4762 4781 */ 4782 + if (opts.werror && (ret || warnings)) { 4783 + if (warnings) 4784 + WARN("%d warning(s) upgraded to errors", warnings); 4785 + return 1; 4786 + } 4787 + 4763 4788 return 0; 4764 4789 }
-3
tools/objtool/elf.c
··· 1302 1302 struct section *sec; 1303 1303 Elf_Scn *s; 1304 1304 1305 - if (opts.dryrun) 1306 - return 0; 1307 - 1308 1305 /* Update changed relocation sections and section headers: */ 1309 1306 list_for_each_entry(sec, &elf->sections, list) { 1310 1307 if (sec->truncate)
+3
tools/objtool/include/objtool/arch.h
··· 97 97 98 98 bool arch_pc_relative_reloc(struct reloc *reloc); 99 99 100 + unsigned int arch_reloc_size(struct reloc *reloc); 101 + unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table); 102 + 100 103 #endif /* _ARCH_H */
+2 -1
tools/objtool/include/objtool/builtin.h
··· 29 29 30 30 /* options: */ 31 31 bool backtrace; 32 - bool backup; 33 32 bool dryrun; 34 33 bool link; 35 34 bool mnop; 36 35 bool module; 37 36 bool no_unreachable; 37 + const char *output; 38 38 bool sec_address; 39 39 bool stats; 40 40 bool verbose; 41 + bool werror; 41 42 }; 42 43 43 44 extern struct opts opts;
+1 -1
tools/objtool/include/objtool/elf.h
··· 65 65 u8 return_thunk : 1; 66 66 u8 fentry : 1; 67 67 u8 profiling_func : 1; 68 - u8 warned : 1; 69 68 u8 embedded_insn : 1; 70 69 u8 local_label : 1; 71 70 u8 frame_pointer : 1; 71 + u8 warnings : 2; 72 72 struct list_head pv_target; 73 73 struct reloc *relocs; 74 74 };
+15 -5
tools/objtool/include/objtool/warn.h
··· 43 43 44 44 #define WARN(format, ...) \ 45 45 fprintf(stderr, \ 46 - "%s: warning: objtool: " format "\n", \ 47 - objname, ##__VA_ARGS__) 46 + "%s: %s: objtool: " format "\n", \ 47 + objname, \ 48 + opts.werror ? "error" : "warning", \ 49 + ##__VA_ARGS__) 48 50 49 51 #define WARN_FUNC(format, sec, offset, ...) \ 50 52 ({ \ ··· 55 53 free(_str); \ 56 54 }) 57 55 56 + #define WARN_LIMIT 2 57 + 58 58 #define WARN_INSN(insn, format, ...) \ 59 59 ({ \ 60 60 struct instruction *_insn = (insn); \ 61 - if (!_insn->sym || !_insn->sym->warned) \ 61 + BUILD_BUG_ON(WARN_LIMIT > 2); \ 62 + if (!_insn->sym || _insn->sym->warnings < WARN_LIMIT) { \ 62 63 WARN_FUNC(format, _insn->sec, _insn->offset, \ 63 64 ##__VA_ARGS__); \ 64 - if (_insn->sym) \ 65 - _insn->sym->warned = 1; \ 65 + if (_insn->sym) \ 66 + _insn->sym->warnings++; \ 67 + } else if (_insn->sym && _insn->sym->warnings == WARN_LIMIT) { \ 68 + WARN_FUNC("skipping duplicate warning(s)", \ 69 + _insn->sec, _insn->offset); \ 70 + _insn->sym->warnings++; \ 71 + } \ 66 72 }) 67 73 68 74 #define BT_INSN(insn, format, ...) \
+5 -73
tools/objtool/objtool.c
··· 18 18 19 19 bool help; 20 20 21 - const char *objname; 22 21 static struct objtool_file file; 23 22 24 - static bool objtool_create_backup(const char *_objname) 23 + struct objtool_file *objtool_open_read(const char *filename) 25 24 { 26 - int len = strlen(_objname); 27 - char *buf, *base, *name = malloc(len+6); 28 - int s, d, l, t; 29 - 30 - if (!name) { 31 - perror("failed backup name malloc"); 32 - return false; 25 + if (file.elf) { 26 + WARN("won't handle more than one file at a time"); 27 + return NULL; 33 28 } 34 29 35 - strcpy(name, _objname); 36 - strcpy(name + len, ".orig"); 37 - 38 - d = open(name, O_CREAT|O_WRONLY|O_TRUNC, 0644); 39 - if (d < 0) { 40 - perror("failed to create backup file"); 41 - return false; 42 - } 43 - 44 - s = open(_objname, O_RDONLY); 45 - if (s < 0) { 46 - perror("failed to open orig file"); 47 - return false; 48 - } 49 - 50 - buf = malloc(4096); 51 - if (!buf) { 52 - perror("failed backup data malloc"); 53 - return false; 54 - } 55 - 56 - while ((l = read(s, buf, 4096)) > 0) { 57 - base = buf; 58 - do { 59 - t = write(d, base, l); 60 - if (t < 0) { 61 - perror("failed backup write"); 62 - return false; 63 - } 64 - base += t; 65 - l -= t; 66 - } while (l); 67 - } 68 - 69 - if (l < 0) { 70 - perror("failed backup read"); 71 - return false; 72 - } 73 - 74 - free(name); 75 - free(buf); 76 - close(d); 77 - close(s); 78 - 79 - return true; 80 - } 81 - 82 - struct objtool_file *objtool_open_read(const char *_objname) 83 - { 84 - if (objname) { 85 - if (strcmp(objname, _objname)) { 86 - WARN("won't handle more than one file at a time"); 87 - return NULL; 88 - } 89 - return &file; 90 - } 91 - objname = _objname; 92 - 93 - file.elf = elf_open_read(objname, O_RDWR); 30 + file.elf = elf_open_read(filename, O_RDWR); 94 31 if (!file.elf) 95 32 return NULL; 96 - 97 - if (opts.backup && !objtool_create_backup(objname)) { 98 - WARN("can't create backup file"); 99 - return NULL; 100 - } 101 33 102 34 hash_init(file.insn_hash); 103 35 INIT_LIST_HEAD(&file.retpoline_call_list);
+2 -5
tools/objtool/orc_dump.c
··· 10 10 #include <objtool/warn.h> 11 11 #include <objtool/endianness.h> 12 12 13 - int orc_dump(const char *_objname) 13 + int orc_dump(const char *filename) 14 14 { 15 15 int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0; 16 16 struct orc_entry *orc = NULL; ··· 26 26 Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL; 27 27 struct elf dummy_elf = {}; 28 28 29 - 30 - objname = _objname; 31 - 32 29 elf_version(EV_CURRENT); 33 30 34 - fd = open(objname, O_RDONLY); 31 + fd = open(filename, O_RDONLY); 35 32 if (fd == -1) { 36 33 perror("open"); 37 34 return -1;