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

Merge tag 'objtool-urgent-2025-04-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool fixes from Ingo Molnar:
"These are objtool fixes and updates by Josh Poimboeuf, centered around
the fallout from the new CONFIG_OBJTOOL_WERROR=y feature, which,
despite its default-off nature, increased the profile/impact of
objtool warnings:

- Improve error handling and the presentation of warnings/errors

- Revert the new summary warning line that some test-bot tools
interpreted as new regressions

- Fix a number of objtool warnings in various drivers, core kernel
code and architecture code. About half of them are potential
problems related to out-of-bounds accesses or potential undefined
behavior, the other half are additional objtool annotations

- Update objtool to latest (known) compiler quirks and objtool bugs
triggered by compiler code generation

- Misc fixes"

* tag 'objtool-urgent-2025-04-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (36 commits)
objtool/loongarch: Add unwind hints in prepare_frametrace()
rcu-tasks: Always inline rcu_irq_work_resched()
context_tracking: Always inline ct_{nmi,irq}_{enter,exit}()
sched/smt: Always inline sched_smt_active()
objtool: Fix verbose disassembly if CROSS_COMPILE isn't set
objtool: Change "warning:" to "error: " for fatal errors
objtool: Always fail on fatal errors
Revert "objtool: Increase per-function WARN_FUNC() rate limit"
objtool: Append "()" to function name in "unexpected end of section" warning
objtool: Ignore end-of-section jumps for KCOV/GCOV
objtool: Silence more KCOV warnings, part 2
objtool, drm/vmwgfx: Don't ignore vmw_send_msg() for ORC
objtool: Fix STACK_FRAME_NON_STANDARD for cold subfunctions
objtool: Fix segfault in ignore_unreachable_insn()
objtool: Fix NULL printf() '%s' argument in builtin-check.c:save_argv()
objtool, lkdtm: Obfuscate the do_nothing() pointer
objtool, regulator: rk808: Remove potential undefined behavior in rk806_set_mode_dcdc()
objtool, ASoC: codecs: wcd934x: Remove potential undefined behavior in wcd934x_slim_irq_handler()
objtool, Input: cyapa - Remove undefined behavior in cyapa_update_fw_store()
objtool, panic: Disable SMAP in __stack_chk_fail()
...

+679 -650
+3
arch/loongarch/include/asm/stacktrace.h
··· 8 8 #include <asm/asm.h> 9 9 #include <asm/ptrace.h> 10 10 #include <asm/loongarch.h> 11 + #include <asm/unwind_hints.h> 11 12 #include <linux/stringify.h> 12 13 13 14 enum stack_type { ··· 44 43 static __always_inline void prepare_frametrace(struct pt_regs *regs) 45 44 { 46 45 __asm__ __volatile__( 46 + UNWIND_HINT_SAVE 47 47 /* Save $ra */ 48 48 STORE_ONE_REG(1) 49 49 /* Use $ra to save PC */ ··· 82 80 STORE_ONE_REG(29) 83 81 STORE_ONE_REG(30) 84 82 STORE_ONE_REG(31) 83 + UNWIND_HINT_RESTORE 85 84 : "=m" (regs->csr_era) 86 85 : "r" (regs->regs) 87 86 : "memory");
+9 -1
arch/loongarch/include/asm/unwind_hints.h
··· 23 23 UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_CALL 24 24 .endm 25 25 26 - #endif /* __ASSEMBLY__ */ 26 + #else /* !__ASSEMBLY__ */ 27 + 28 + #define UNWIND_HINT_SAVE \ 29 + UNWIND_HINT(UNWIND_HINT_TYPE_SAVE, 0, 0, 0) 30 + 31 + #define UNWIND_HINT_RESTORE \ 32 + UNWIND_HINT(UNWIND_HINT_TYPE_RESTORE, 0, 0, 0) 33 + 34 + #endif /* !__ASSEMBLY__ */ 27 35 28 36 #endif /* _ASM_LOONGARCH_UNWIND_HINTS_H */
+4 -2
arch/x86/include/asm/arch_hweight.h
··· 16 16 { 17 17 unsigned int res; 18 18 19 - asm_inline (ALTERNATIVE("call __sw_hweight32", 19 + asm_inline (ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE 20 + "call __sw_hweight32", 20 21 "popcntl %[val], %[cnt]", X86_FEATURE_POPCNT) 21 22 : [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT 22 23 : [val] REG_IN (w)); ··· 46 45 { 47 46 unsigned long res; 48 47 49 - asm_inline (ALTERNATIVE("call __sw_hweight64", 48 + asm_inline (ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE 49 + "call __sw_hweight64", 50 50 "popcntq %[val], %[cnt]", X86_FEATURE_POPCNT) 51 51 : [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT 52 52 : [val] REG_IN (w));
+15 -8
arch/x86/include/asm/smap.h
··· 16 16 #ifdef __ASSEMBLER__ 17 17 18 18 #define ASM_CLAC \ 19 - ALTERNATIVE "", "clac", X86_FEATURE_SMAP 19 + ALTERNATIVE __stringify(ANNOTATE_IGNORE_ALTERNATIVE), "clac", X86_FEATURE_SMAP 20 20 21 21 #define ASM_STAC \ 22 - ALTERNATIVE "", "stac", X86_FEATURE_SMAP 22 + ALTERNATIVE __stringify(ANNOTATE_IGNORE_ALTERNATIVE), "stac", X86_FEATURE_SMAP 23 23 24 24 #else /* __ASSEMBLER__ */ 25 25 26 26 static __always_inline void clac(void) 27 27 { 28 28 /* Note: a barrier is implicit in alternative() */ 29 - alternative("", "clac", X86_FEATURE_SMAP); 29 + alternative(ANNOTATE_IGNORE_ALTERNATIVE "", "clac", X86_FEATURE_SMAP); 30 30 } 31 31 32 32 static __always_inline void stac(void) 33 33 { 34 34 /* Note: a barrier is implicit in alternative() */ 35 - alternative("", "stac", X86_FEATURE_SMAP); 35 + alternative(ANNOTATE_IGNORE_ALTERNATIVE "", "stac", X86_FEATURE_SMAP); 36 36 } 37 37 38 38 static __always_inline unsigned long smap_save(void) ··· 40 40 unsigned long flags; 41 41 42 42 asm volatile ("# smap_save\n\t" 43 - ALTERNATIVE("", "pushf; pop %0; " "clac" "\n\t", 43 + ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE 44 + "", "pushf; pop %0; clac", 44 45 X86_FEATURE_SMAP) 45 46 : "=rm" (flags) : : "memory", "cc"); 46 47 ··· 51 50 static __always_inline void smap_restore(unsigned long flags) 52 51 { 53 52 asm volatile ("# smap_restore\n\t" 54 - ALTERNATIVE("", "push %0; popf\n\t", 53 + ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE 54 + "", "push %0; popf", 55 55 X86_FEATURE_SMAP) 56 56 : : "g" (flags) : "memory", "cc"); 57 57 } 58 58 59 59 /* These macros can be used in asm() statements */ 60 60 #define ASM_CLAC \ 61 - ALTERNATIVE("", "clac", X86_FEATURE_SMAP) 61 + ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "", "clac", X86_FEATURE_SMAP) 62 62 #define ASM_STAC \ 63 - ALTERNATIVE("", "stac", X86_FEATURE_SMAP) 63 + ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "", "stac", X86_FEATURE_SMAP) 64 + 65 + #define ASM_CLAC_UNSAFE \ 66 + ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "clac", X86_FEATURE_SMAP) 67 + #define ASM_STAC_UNSAFE \ 68 + ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "stac", X86_FEATURE_SMAP) 64 69 65 70 #endif /* __ASSEMBLER__ */ 66 71
+2 -4
arch/x86/include/asm/xen/hypercall.h
··· 231 231 * Suppress objtool seeing the STAC/CLAC and getting confused about it 232 232 * calling random code with AC=1. 233 233 */ 234 - asm volatile(ANNOTATE_IGNORE_ALTERNATIVE 235 - ASM_STAC ::: "memory", "flags"); 234 + asm volatile(ASM_STAC_UNSAFE ::: "memory", "flags"); 236 235 } 237 236 238 237 static __always_inline void __xen_clac(void) 239 238 { 240 - asm volatile(ANNOTATE_IGNORE_ALTERNATIVE 241 - ASM_CLAC ::: "memory", "flags"); 239 + asm volatile(ASM_CLAC_UNSAFE ::: "memory", "flags"); 242 240 } 243 241 244 242 static inline long
+1 -1
drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
··· 289 289 290 290 return -EINVAL; 291 291 } 292 - STACK_FRAME_NON_STANDARD(vmw_send_msg); 292 + STACK_FRAME_NON_STANDARD_FP(vmw_send_msg); 293 293 294 294 295 295 /**
+2 -2
drivers/input/mouse/cyapa.c
··· 1080 1080 char fw_name[NAME_MAX]; 1081 1081 int ret, error; 1082 1082 1083 - if (count >= NAME_MAX) { 1084 - dev_err(dev, "File name too long\n"); 1083 + if (!count || count >= NAME_MAX) { 1084 + dev_err(dev, "Bad file name size\n"); 1085 1085 return -EINVAL; 1086 1086 } 1087 1087
+4 -1
drivers/media/dvb-frontends/dib8000.c
··· 2701 2701 u8 ratio; 2702 2702 2703 2703 if (state->revision == 0x8090) { 2704 + u32 internal = dib8000_read32(state, 23) / 1000; 2705 + 2704 2706 ratio = 4; 2705 - unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000); 2707 + 2708 + unit_khz_dds_val = (1<<26) / (internal ?: 1); 2706 2709 if (offset_khz < 0) 2707 2710 dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val); 2708 2711 else
+11 -3
drivers/misc/lkdtm/perms.c
··· 29 29 static unsigned long ro_after_init __ro_after_init = 0x55AA5500; 30 30 31 31 /* 32 + * This is a pointer to do_nothing() which is initialized at runtime rather 33 + * than build time to avoid objtool IBT validation warnings caused by an 34 + * inlined unrolled memcpy() in execute_location(). 35 + */ 36 + static void __ro_after_init *do_nothing_ptr; 37 + 38 + /* 32 39 * This just returns to the caller. It is designed to be copied into 33 40 * non-executable memory regions. 34 41 */ ··· 72 65 { 73 66 void (*func)(void); 74 67 func_desc_t fdesc; 75 - void *do_nothing_text = dereference_function_descriptor(do_nothing); 76 68 77 - pr_info("attempting ok execution at %px\n", do_nothing_text); 69 + pr_info("attempting ok execution at %px\n", do_nothing_ptr); 78 70 do_nothing(); 79 71 80 72 if (write == CODE_WRITE) { 81 - memcpy(dst, do_nothing_text, EXEC_SIZE); 73 + memcpy(dst, do_nothing_ptr, EXEC_SIZE); 82 74 flush_icache_range((unsigned long)dst, 83 75 (unsigned long)dst + EXEC_SIZE); 84 76 } ··· 273 267 274 268 void __init lkdtm_perms_init(void) 275 269 { 270 + do_nothing_ptr = dereference_function_descriptor(do_nothing); 271 + 276 272 /* Make sure we can write to __ro_after_init values during __init */ 277 273 ro_after_init |= 0xAA; 278 274 }
+1 -1
drivers/nvme/target/debugfs.c
··· 78 78 bool sep = false; 79 79 int i; 80 80 81 - for (i = 0; i < 7; i++) { 81 + for (i = 0; i < ARRAY_SIZE(csts_state_names); i++) { 82 82 int state = BIT(i); 83 83 84 84 if (!(ctrl->csts & state))
+2 -2
drivers/regulator/rk808-regulator.c
··· 270 270 271 271 static int rk806_set_mode_dcdc(struct regulator_dev *rdev, unsigned int mode) 272 272 { 273 - int rid = rdev_get_id(rdev); 274 - int ctr_bit, reg; 273 + unsigned int rid = rdev_get_id(rdev); 274 + unsigned int ctr_bit, reg; 275 275 276 276 reg = RK806_POWER_FPWM_EN0 + rid / 8; 277 277 ctr_bit = rid % 8;
+1 -1
drivers/spi/spi-amd.c
··· 302 302 { 303 303 unsigned int i, spd7_val, alt_spd; 304 304 305 - for (i = 0; i < ARRAY_SIZE(amd_spi_freq); i++) 305 + for (i = 0; i < ARRAY_SIZE(amd_spi_freq)-1; i++) 306 306 if (speed_hz >= amd_spi_freq[i].speed_hz) 307 307 break; 308 308
+4 -4
include/linux/context_tracking_irq.h
··· 10 10 void ct_nmi_enter(void); 11 11 void ct_nmi_exit(void); 12 12 #else 13 - static inline void ct_irq_enter(void) { } 14 - static inline void ct_irq_exit(void) { } 13 + static __always_inline void ct_irq_enter(void) { } 14 + static __always_inline void ct_irq_exit(void) { } 15 15 static inline void ct_irq_enter_irqson(void) { } 16 16 static inline void ct_irq_exit_irqson(void) { } 17 - static inline void ct_nmi_enter(void) { } 18 - static inline void ct_nmi_exit(void) { } 17 + static __always_inline void ct_nmi_enter(void) { } 18 + static __always_inline void ct_nmi_exit(void) { } 19 19 #endif 20 20 21 21 #endif
-4
include/linux/linkage.h
··· 134 134 .size name, .-name 135 135 #endif 136 136 137 - /* If symbol 'name' is treated as a subroutine (gets called, and returns) 138 - * then please use ENDPROC to mark 'name' as STT_FUNC for the benefit of 139 - * static analysis tools such as stack depth analyzer. 140 - */ 141 137 #ifndef ENDPROC 142 138 /* deprecated, use SYM_FUNC_END */ 143 139 #define ENDPROC(name) \
+1 -1
include/linux/objtool.h
··· 69 69 * In asm, there are two kinds of code: normal C-type callable functions and 70 70 * the rest. The normal callable functions can be called by other code, and 71 71 * don't do anything unusual with the stack. Such normal callable functions 72 - * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this 72 + * are annotated with SYM_FUNC_{START,END}. Most asm code falls in this 73 73 * category. In this case, no special debugging annotations are needed because 74 74 * objtool can automatically generate the ORC data for the ORC unwinder to read 75 75 * at runtime.
+1 -1
include/linux/rcupdate.h
··· 132 132 #if defined(CONFIG_NO_HZ_FULL) && (!defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK)) 133 133 void rcu_irq_work_resched(void); 134 134 #else 135 - static inline void rcu_irq_work_resched(void) { } 135 + static __always_inline void rcu_irq_work_resched(void) { } 136 136 #endif 137 137 138 138 #ifdef CONFIG_RCU_NOCB_CPU
+1 -1
include/linux/sched/smt.h
··· 12 12 return static_branch_likely(&sched_smt_present); 13 13 } 14 14 #else 15 - static inline bool sched_smt_active(void) { return false; } 15 + static __always_inline bool sched_smt_active(void) { return false; } 16 16 #endif 17 17 18 18 void arch_smt_update(void);
+6
kernel/panic.c
··· 833 833 */ 834 834 __visible noinstr void __stack_chk_fail(void) 835 835 { 836 + unsigned long flags; 837 + 836 838 instrumentation_begin(); 839 + flags = user_access_save(); 840 + 837 841 panic("stack-protector: Kernel stack is corrupted in: %pB", 838 842 __builtin_return_address(0)); 843 + 844 + user_access_restore(flags); 839 845 instrumentation_end(); 840 846 } 841 847 EXPORT_SYMBOL(__stack_chk_fail);
+2 -2
scripts/Makefile.lib
··· 275 275 objtool-args-$(CONFIG_STACK_VALIDATION) += --stackval 276 276 objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE) += --static-call 277 277 objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) += --uaccess 278 - objtool-args-$(CONFIG_GCOV_KERNEL) += --no-unreachable 278 + objtool-args-$(or $(CONFIG_GCOV_KERNEL),$(CONFIG_KCOV)) += --no-unreachable 279 279 objtool-args-$(CONFIG_PREFIX_SYMBOLS) += --prefix=$(CONFIG_FUNCTION_PADDING_BYTES) 280 - objtool-args-$(CONFIG_OBJTOOL_WERROR) += --Werror --backtrace 280 + objtool-args-$(CONFIG_OBJTOOL_WERROR) += --Werror 281 281 282 282 objtool-args = $(objtool-args-y) \ 283 283 $(if $(delay-objtool), --link) \
+11 -4
scripts/Makefile.vmlinux_o
··· 30 30 # objtool for vmlinux.o 31 31 # --------------------------------------------------------------------------- 32 32 # 33 - # For LTO and IBT, objtool doesn't run on individual translation units. 34 - # Run everything on vmlinux instead. 33 + # For delay-objtool (IBT or LTO), objtool doesn't run on individual translation 34 + # units. Instead it runs on vmlinux.o. 35 + # 36 + # For !delay-objtool + CONFIG_NOINSTR_VALIDATION, it runs on both translation 37 + # units and vmlinux.o, with the latter only used for noinstr/unret validation. 35 38 36 39 objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION)) 37 40 38 - vmlinux-objtool-args-$(delay-objtool) += $(objtool-args-y) 39 - vmlinux-objtool-args-$(CONFIG_GCOV_KERNEL) += --no-unreachable 41 + ifeq ($(delay-objtool),y) 42 + vmlinux-objtool-args-y += $(objtool-args-y) 43 + else 44 + vmlinux-objtool-args-$(CONFIG_OBJTOOL_WERROR) += --Werror 45 + endif 46 + 40 47 vmlinux-objtool-args-$(CONFIG_NOINSTR_VALIDATION) += --noinstr \ 41 48 $(if $(or $(CONFIG_MITIGATION_UNRET_ENTRY),$(CONFIG_MITIGATION_SRSO)), --unret) 42 49
+1 -1
sound/soc/codecs/wcd934x.c
··· 2263 2263 { 2264 2264 struct wcd934x_codec *wcd = data; 2265 2265 unsigned long status = 0; 2266 - int i, j, port_id; 2266 + unsigned int i, j, port_id; 2267 2267 unsigned int val, int_val = 0; 2268 2268 irqreturn_t ret = IRQ_NONE; 2269 2269 bool tx;
+5 -5
tools/objtool/Documentation/objtool.txt
··· 34 34 - Return thunk annotation -- annotates all return thunk sites so kernel 35 35 can patch them inline, depending on enabled mitigations 36 36 37 - - Return thunk training valiation -- validate that all entry paths 37 + - Return thunk untraining validation -- validate that all entry paths 38 38 untrain a "safe return" before the first return (or call) 39 39 40 40 - Non-instrumentation validation -- validates non-instrumentable ··· 281 281 If the error is for an asm file, and func() is indeed a callable 282 282 function, add proper frame pointer logic using the FRAME_BEGIN and 283 283 FRAME_END macros. Otherwise, if it's not a callable function, remove 284 - its ELF function annotation by changing ENDPROC to END, and instead 285 - use the manual unwind hint macros in asm/unwind_hints.h. 284 + its ELF function annotation by using SYM_CODE_{START,END} and use the 285 + manual unwind hint macros in asm/unwind_hints.h. 286 286 287 287 If it's a GCC-compiled .c file, the error may be because the function 288 288 uses an inline asm() statement which has a "call" instruction. An ··· 352 352 This is a kernel entry/exit instruction like sysenter or iret. Such 353 353 instructions aren't allowed in a callable function, and are most 354 354 likely part of the kernel entry code. Such code should probably be 355 - placed in a SYM_FUNC_CODE block with unwind hints. 355 + placed in a SYM_CODE_{START,END} block with unwind hints. 356 356 357 357 358 358 6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame ··· 381 381 382 382 Another possibility is that the code has some asm or inline asm which 383 383 does some unusual things to the stack or the frame pointer. In such 384 - cases it's probably appropriate to use SYM_FUNC_CODE with unwind 384 + cases it's probably appropriate to use SYM_CODE_{START,END} with unwind 385 385 hints. 386 386 387 387
+9 -5
tools/objtool/arch/loongarch/decode.c
··· 63 63 if (elf->ehdr.e_machine == EM_LOONGARCH) 64 64 return true; 65 65 66 - WARN("unexpected ELF machine type %d", elf->ehdr.e_machine); 66 + ERROR("unexpected ELF machine type %d", elf->ehdr.e_machine); 67 67 return false; 68 68 } 69 69 ··· 327 327 { 328 328 static u32 nop; 329 329 330 - if (len != LOONGARCH_INSN_SIZE) 331 - WARN("invalid NOP size: %d\n", len); 330 + if (len != LOONGARCH_INSN_SIZE) { 331 + ERROR("invalid NOP size: %d\n", len); 332 + return NULL; 333 + } 332 334 333 335 nop = LOONGARCH_INSN_NOP; 334 336 ··· 341 339 { 342 340 static u32 ret; 343 341 344 - if (len != LOONGARCH_INSN_SIZE) 345 - WARN("invalid RET size: %d\n", len); 342 + if (len != LOONGARCH_INSN_SIZE) { 343 + ERROR("invalid RET size: %d\n", len); 344 + return NULL; 345 + } 346 346 347 347 emit_jirl((union loongarch_instruction *)&ret, LOONGARCH_GPR_RA, LOONGARCH_GPR_ZERO, 0); 348 348
+4 -4
tools/objtool/arch/loongarch/orc.c
··· 41 41 orc->type = ORC_TYPE_REGS_PARTIAL; 42 42 break; 43 43 default: 44 - WARN_INSN(insn, "unknown unwind hint type %d", cfi->type); 44 + ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type); 45 45 return -1; 46 46 } 47 47 ··· 55 55 orc->sp_reg = ORC_REG_FP; 56 56 break; 57 57 default: 58 - WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); 58 + ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); 59 59 return -1; 60 60 } 61 61 ··· 72 72 orc->fp_reg = ORC_REG_FP; 73 73 break; 74 74 default: 75 - WARN_INSN(insn, "unknown FP base reg %d", fp->base); 75 + ERROR_INSN(insn, "unknown FP base reg %d", fp->base); 76 76 return -1; 77 77 } 78 78 ··· 89 89 orc->ra_reg = ORC_REG_FP; 90 90 break; 91 91 default: 92 - WARN_INSN(insn, "unknown RA base reg %d", ra->base); 92 + ERROR_INSN(insn, "unknown RA base reg %d", ra->base); 93 93 return -1; 94 94 } 95 95
+7 -8
tools/objtool/arch/x86/decode.c
··· 36 36 case EM_386: 37 37 return 0; 38 38 default: 39 - WARN("unexpected ELF machine type %d", elf->ehdr.e_machine); 39 + ERROR("unexpected ELF machine type %d", elf->ehdr.e_machine); 40 40 return -1; 41 41 } 42 42 } ··· 173 173 ret = insn_decode(&ins, sec->data->d_buf + offset, maxlen, 174 174 x86_64 ? INSN_MODE_64 : INSN_MODE_32); 175 175 if (ret < 0) { 176 - WARN("can't decode instruction at %s:0x%lx", sec->name, offset); 176 + ERROR("can't decode instruction at %s:0x%lx", sec->name, offset); 177 177 return -1; 178 178 } 179 179 ··· 321 321 break; 322 322 323 323 default: 324 - /* WARN ? */ 324 + /* ERROR ? */ 325 325 break; 326 326 } 327 327 ··· 561 561 if (ins.prefixes.nbytes == 1 && 562 562 ins.prefixes.bytes[0] == 0xf2) { 563 563 /* ENQCMD cannot be used in the kernel. */ 564 - WARN("ENQCMD instruction at %s:%lx", sec->name, 565 - offset); 564 + WARN("ENQCMD instruction at %s:%lx", sec->name, offset); 566 565 } 567 566 568 567 } else if (op2 == 0xa0 || op2 == 0xa8) { ··· 645 646 if (disp->sym->type == STT_SECTION) 646 647 func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp)); 647 648 if (!func) { 648 - WARN("no func for pv_ops[]"); 649 + ERROR("no func for pv_ops[]"); 649 650 return -1; 650 651 } 651 652 ··· 775 776 }; 776 777 777 778 if (len < 1 || len > 5) { 778 - WARN("invalid NOP size: %d\n", len); 779 + ERROR("invalid NOP size: %d\n", len); 779 780 return NULL; 780 781 } 781 782 ··· 795 796 }; 796 797 797 798 if (len < 1 || len > 5) { 798 - WARN("invalid RET size: %d\n", len); 799 + ERROR("invalid RET size: %d\n", len); 799 800 return NULL; 800 801 } 801 802
+3 -3
tools/objtool/arch/x86/orc.c
··· 40 40 orc->type = ORC_TYPE_REGS_PARTIAL; 41 41 break; 42 42 default: 43 - WARN_INSN(insn, "unknown unwind hint type %d", cfi->type); 43 + ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type); 44 44 return -1; 45 45 } 46 46 ··· 72 72 orc->sp_reg = ORC_REG_DX; 73 73 break; 74 74 default: 75 - WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); 75 + ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); 76 76 return -1; 77 77 } 78 78 ··· 87 87 orc->bp_reg = ORC_REG_BP; 88 88 break; 89 89 default: 90 - WARN_INSN(insn, "unknown BP base reg %d", bp->base); 90 + ERROR_INSN(insn, "unknown BP base reg %d", bp->base); 91 91 return -1; 92 92 } 93 93
+5 -33
tools/objtool/arch/x86/special.c
··· 3 3 4 4 #include <objtool/special.h> 5 5 #include <objtool/builtin.h> 6 + #include <objtool/warn.h> 6 7 7 - #define X86_FEATURE_POPCNT (4 * 32 + 23) 8 - #define X86_FEATURE_SMAP (9 * 32 + 20) 9 - 10 - void arch_handle_alternative(unsigned short feature, struct special_alt *alt) 8 + void arch_handle_alternative(struct special_alt *alt) 11 9 { 12 10 static struct special_alt *group, *prev; 13 11 ··· 29 31 } else group = alt; 30 32 31 33 prev = alt; 32 - 33 - switch (feature) { 34 - case X86_FEATURE_SMAP: 35 - /* 36 - * If UACCESS validation is enabled; force that alternative; 37 - * otherwise force it the other way. 38 - * 39 - * What we want to avoid is having both the original and the 40 - * alternative code flow at the same time, in that case we can 41 - * find paths that see the STAC but take the NOP instead of 42 - * CLAC and the other way around. 43 - */ 44 - if (opts.uaccess) 45 - alt->skip_orig = true; 46 - else 47 - alt->skip_alt = true; 48 - break; 49 - case X86_FEATURE_POPCNT: 50 - /* 51 - * It has been requested that we don't validate the !POPCNT 52 - * feature path which is a "very very small percentage of 53 - * machines". 54 - */ 55 - alt->skip_orig = true; 56 - break; 57 - default: 58 - break; 59 - } 60 34 } 61 35 62 36 bool arch_support_alt_relocation(struct special_alt *special_alt, ··· 126 156 * indicates a rare GCC quirk/bug which can leave dead 127 157 * code behind. 128 158 */ 129 - if (reloc_type(text_reloc) == R_X86_64_PC32) 159 + if (reloc_type(text_reloc) == R_X86_64_PC32) { 160 + WARN_INSN(insn, "ignoring unreachables due to jump table quirk"); 130 161 file->ignore_unreachables = true; 162 + } 131 163 132 164 *table_size = 0; 133 165 return rodata_reloc;
+63 -69
tools/objtool/builtin-check.c
··· 8 8 #include <stdlib.h> 9 9 #include <fcntl.h> 10 10 #include <unistd.h> 11 + #include <errno.h> 11 12 #include <sys/stat.h> 12 13 #include <sys/sendfile.h> 13 14 #include <objtool/builtin.h> 14 15 #include <objtool/objtool.h> 16 + #include <objtool/warn.h> 15 17 16 - #define ERROR(format, ...) \ 17 - fprintf(stderr, \ 18 - "error: objtool: " format "\n", \ 19 - ##__VA_ARGS__) 18 + #define ORIG_SUFFIX ".orig" 20 19 20 + int orig_argc; 21 + static char **orig_argv; 21 22 const char *objname; 22 - 23 23 struct opts opts; 24 24 25 25 static const char * const check_usage[] = { ··· 194 194 195 195 src_fd = open(src, O_RDONLY); 196 196 if (src_fd == -1) { 197 - ERROR("can't open '%s' for reading", src); 197 + ERROR("can't open %s for reading: %s", src, strerror(errno)); 198 198 return 1; 199 199 } 200 200 201 201 dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0400); 202 202 if (dst_fd == -1) { 203 - ERROR("can't open '%s' for writing", dst); 203 + ERROR("can't open %s for writing: %s", dst, strerror(errno)); 204 204 return 1; 205 205 } 206 206 207 207 if (fstat(src_fd, &stat) == -1) { 208 - perror("fstat"); 208 + ERROR_GLIBC("fstat"); 209 209 return 1; 210 210 } 211 211 212 212 if (fchmod(dst_fd, stat.st_mode) == -1) { 213 - perror("fchmod"); 213 + ERROR_GLIBC("fchmod"); 214 214 return 1; 215 215 } 216 216 217 217 for (to_copy = stat.st_size; to_copy > 0; to_copy -= copied) { 218 218 copied = sendfile(dst_fd, src_fd, &offset, to_copy); 219 219 if (copied == -1) { 220 - perror("sendfile"); 220 + ERROR_GLIBC("sendfile"); 221 221 return 1; 222 222 } 223 223 } ··· 227 227 return 0; 228 228 } 229 229 230 - static char **save_argv(int argc, const char **argv) 230 + static void save_argv(int argc, const char **argv) 231 231 { 232 - char **orig_argv; 233 - 234 232 orig_argv = calloc(argc, sizeof(char *)); 235 233 if (!orig_argv) { 236 - perror("calloc"); 237 - return NULL; 234 + ERROR_GLIBC("calloc"); 235 + exit(1); 238 236 } 239 237 240 238 for (int i = 0; i < argc; i++) { 241 239 orig_argv[i] = strdup(argv[i]); 242 240 if (!orig_argv[i]) { 243 - perror("strdup"); 244 - return NULL; 241 + ERROR_GLIBC("strdup(%s)", argv[i]); 242 + exit(1); 245 243 } 246 244 }; 247 - 248 - return orig_argv; 249 245 } 250 246 251 - #define ORIG_SUFFIX ".orig" 247 + void print_args(void) 248 + { 249 + char *backup = NULL; 250 + 251 + if (opts.output || opts.dryrun) 252 + goto print; 253 + 254 + /* 255 + * Make a backup before kbuild deletes the file so the error 256 + * can be recreated without recompiling or relinking. 257 + */ 258 + backup = malloc(strlen(objname) + strlen(ORIG_SUFFIX) + 1); 259 + if (!backup) { 260 + ERROR_GLIBC("malloc"); 261 + goto print; 262 + } 263 + 264 + strcpy(backup, objname); 265 + strcat(backup, ORIG_SUFFIX); 266 + if (copy_file(objname, backup)) { 267 + backup = NULL; 268 + goto print; 269 + } 270 + 271 + print: 272 + /* 273 + * Print the cmdline args to make it easier to recreate. If '--output' 274 + * wasn't used, add it to the printed args with the backup as input. 275 + */ 276 + fprintf(stderr, "%s", orig_argv[0]); 277 + 278 + for (int i = 1; i < orig_argc; i++) { 279 + char *arg = orig_argv[i]; 280 + 281 + if (backup && !strcmp(arg, objname)) 282 + fprintf(stderr, " %s -o %s", backup, objname); 283 + else 284 + fprintf(stderr, " %s", arg); 285 + } 286 + 287 + fprintf(stderr, "\n"); 288 + } 252 289 253 290 int objtool_run(int argc, const char **argv) 254 291 { 255 292 struct objtool_file *file; 256 - char *backup = NULL; 257 - char **orig_argv; 258 293 int ret = 0; 259 294 260 - orig_argv = save_argv(argc, argv); 261 - if (!orig_argv) 262 - return 1; 295 + orig_argc = argc; 296 + save_argv(argc, argv); 263 297 264 298 cmd_parse_options(argc, argv, check_usage); 265 299 ··· 316 282 317 283 file = objtool_open_read(objname); 318 284 if (!file) 319 - goto err; 285 + return 1; 320 286 321 287 if (!opts.link && has_multiple_files(file->elf)) { 322 288 ERROR("Linked object requires --link"); 323 - goto err; 289 + return 1; 324 290 } 325 291 326 292 ret = check(file); 327 293 if (ret) 328 - goto err; 294 + return ret; 329 295 330 296 if (!opts.dryrun && file->elf->changed && elf_write(file->elf)) 331 - goto err; 297 + return 1; 332 298 333 299 return 0; 334 - 335 - err: 336 - if (opts.dryrun) 337 - goto err_msg; 338 - 339 - if (opts.output) { 340 - unlink(opts.output); 341 - goto err_msg; 342 - } 343 - 344 - /* 345 - * Make a backup before kbuild deletes the file so the error 346 - * can be recreated without recompiling or relinking. 347 - */ 348 - backup = malloc(strlen(objname) + strlen(ORIG_SUFFIX) + 1); 349 - if (!backup) { 350 - perror("malloc"); 351 - return 1; 352 - } 353 - 354 - strcpy(backup, objname); 355 - strcat(backup, ORIG_SUFFIX); 356 - if (copy_file(objname, backup)) 357 - return 1; 358 - 359 - err_msg: 360 - fprintf(stderr, "%s", orig_argv[0]); 361 - 362 - for (int i = 1; i < argc; i++) { 363 - char *arg = orig_argv[i]; 364 - 365 - if (backup && !strcmp(arg, objname)) 366 - fprintf(stderr, " %s -o %s", backup, objname); 367 - else 368 - fprintf(stderr, " %s", arg); 369 - } 370 - 371 - fprintf(stderr, "\n"); 372 - 373 - return 1; 374 300 }
+322 -325
tools/objtool/check.c
··· 25 25 struct alternative { 26 26 struct alternative *next; 27 27 struct instruction *insn; 28 - bool skip_orig; 29 28 }; 30 29 31 30 static unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache; ··· 340 341 memset(state, 0, sizeof(*state)); 341 342 init_cfi_state(&state->cfi); 342 343 343 - /* 344 - * We need the full vmlinux for noinstr validation, otherwise we can 345 - * not correctly determine insn_call_dest(insn)->sec (external symbols 346 - * do not have a section). 347 - */ 348 - if (opts.link && opts.noinstr && sec) 344 + if (opts.noinstr && sec) 349 345 state->noinstr = sec->noinstr; 350 346 } 351 347 ··· 348 354 { 349 355 struct cfi_state *cfi = calloc(1, sizeof(struct cfi_state)); 350 356 if (!cfi) { 351 - WARN("calloc failed"); 357 + ERROR_GLIBC("calloc"); 352 358 exit(1); 353 359 } 354 360 nr_cfi++; ··· 404 410 PROT_READ|PROT_WRITE, 405 411 MAP_PRIVATE|MAP_ANON, -1, 0); 406 412 if (cfi_hash == (void *)-1L) { 407 - WARN("mmap fail cfi_hash"); 413 + ERROR_GLIBC("mmap fail cfi_hash"); 408 414 cfi_hash = NULL; 409 415 } else if (opts.stats) { 410 416 printf("cfi_bits: %d\n", cfi_bits); ··· 460 466 if (!insns || idx == INSN_CHUNK_MAX) { 461 467 insns = calloc(sizeof(*insn), INSN_CHUNK_SIZE); 462 468 if (!insns) { 463 - WARN("malloc failed"); 469 + ERROR_GLIBC("calloc"); 464 470 return -1; 465 471 } 466 472 idx = 0; ··· 495 501 nr_insns++; 496 502 } 497 503 498 - // printf("%s: last chunk used: %d\n", sec->name, (int)idx); 499 - 500 504 sec_for_each_sym(sec, func) { 501 505 if (func->type != STT_NOTYPE && func->type != STT_FUNC) 502 506 continue; ··· 503 511 /* Heuristic: likely an "end" symbol */ 504 512 if (func->type == STT_NOTYPE) 505 513 continue; 506 - WARN("%s(): STT_FUNC at end of section", 507 - func->name); 514 + ERROR("%s(): STT_FUNC at end of section", func->name); 508 515 return -1; 509 516 } 510 517 ··· 511 520 continue; 512 521 513 522 if (!find_insn(file, sec, func->offset)) { 514 - WARN("%s(): can't find starting instruction", 515 - func->name); 523 + ERROR("%s(): can't find starting instruction", func->name); 516 524 return -1; 517 525 } 518 526 ··· 558 568 if (!reloc) 559 569 break; 560 570 571 + idx = (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long); 572 + 561 573 func = reloc->sym; 562 574 if (func->type == STT_SECTION) 563 575 func = find_symbol_by_offset(reloc->sym->sec, 564 576 reloc_addend(reloc)); 577 + if (!func) { 578 + ERROR_FUNC(reloc->sym->sec, reloc_addend(reloc), 579 + "can't find func at %s[%d]", symname, idx); 580 + return -1; 581 + } 565 582 566 - idx = (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long); 567 - 568 - objtool_pv_add(file, idx, func); 583 + if (objtool_pv_add(file, idx, func)) 584 + return -1; 569 585 570 586 off = reloc_offset(reloc) + 1; 571 587 if (off > end) ··· 595 599 }; 596 600 const char *pv_ops; 597 601 struct symbol *sym; 598 - int idx, nr; 602 + int idx, nr, ret; 599 603 600 604 if (!opts.noinstr) 601 605 return 0; ··· 608 612 609 613 nr = sym->len / sizeof(unsigned long); 610 614 file->pv_ops = calloc(sizeof(struct pv_state), nr); 611 - if (!file->pv_ops) 615 + if (!file->pv_ops) { 616 + ERROR_GLIBC("calloc"); 612 617 return -1; 618 + } 613 619 614 620 for (idx = 0; idx < nr; idx++) 615 621 INIT_LIST_HEAD(&file->pv_ops[idx].targets); 616 622 617 - for (idx = 0; (pv_ops = pv_ops_tables[idx]); idx++) 618 - add_pv_ops(file, pv_ops); 623 + for (idx = 0; (pv_ops = pv_ops_tables[idx]); idx++) { 624 + ret = add_pv_ops(file, pv_ops); 625 + if (ret) 626 + return ret; 627 + } 619 628 620 629 return 0; 621 630 } ··· 668 667 /* find key symbol */ 669 668 key_name = strdup(insn_call_dest(insn)->name); 670 669 if (!key_name) { 671 - perror("strdup"); 670 + ERROR_GLIBC("strdup"); 672 671 return -1; 673 672 } 674 673 if (strncmp(key_name, STATIC_CALL_TRAMP_PREFIX_STR, 675 674 STATIC_CALL_TRAMP_PREFIX_LEN)) { 676 - WARN("static_call: trampoline name malformed: %s", key_name); 677 - free(key_name); 675 + ERROR("static_call: trampoline name malformed: %s", key_name); 678 676 return -1; 679 677 } 680 678 tmp = key_name + STATIC_CALL_TRAMP_PREFIX_LEN - STATIC_CALL_KEY_PREFIX_LEN; ··· 682 682 key_sym = find_symbol_by_name(file->elf, tmp); 683 683 if (!key_sym) { 684 684 if (!opts.module) { 685 - WARN("static_call: can't find static_call_key symbol: %s", tmp); 686 - free(key_name); 685 + ERROR("static_call: can't find static_call_key symbol: %s", tmp); 687 686 return -1; 688 687 } 689 688 ··· 697 698 */ 698 699 key_sym = insn_call_dest(insn); 699 700 } 700 - free(key_name); 701 701 702 702 /* populate reloc for 'key' */ 703 703 if (!elf_init_reloc_data_sym(file->elf, sec, ··· 827 829 if (opts.module && sym && sym->type == STT_FUNC && 828 830 insn->offset == sym->offset && 829 831 (!strcmp(sym->name, "init_module") || 830 - !strcmp(sym->name, "cleanup_module"))) 831 - WARN("%s(): not an indirect call target", sym->name); 832 + !strcmp(sym->name, "cleanup_module"))) { 833 + ERROR("%s(): Magic init_module() function name is deprecated, use module_init(fn) instead", 834 + sym->name); 835 + return -1; 836 + } 832 837 833 838 if (!elf_init_reloc_text_sym(file->elf, sec, 834 839 idx * sizeof(int), idx, ··· 980 979 /* 981 980 * Warnings shouldn't be reported for ignored functions. 982 981 */ 983 - static void add_ignores(struct objtool_file *file) 982 + static int add_ignores(struct objtool_file *file) 984 983 { 985 - struct instruction *insn; 986 984 struct section *rsec; 987 985 struct symbol *func; 988 986 struct reloc *reloc; 989 987 990 988 rsec = find_section_by_name(file->elf, ".rela.discard.func_stack_frame_non_standard"); 991 989 if (!rsec) 992 - return; 990 + return 0; 993 991 994 992 for_each_reloc(rsec, reloc) { 995 993 switch (reloc->sym->type) { ··· 1003 1003 break; 1004 1004 1005 1005 default: 1006 - WARN("unexpected relocation symbol type in %s: %d", 1007 - rsec->name, reloc->sym->type); 1008 - continue; 1006 + ERROR("unexpected relocation symbol type in %s: %d", 1007 + rsec->name, reloc->sym->type); 1008 + return -1; 1009 1009 } 1010 1010 1011 - func_for_each_insn(file, func, insn) 1012 - insn->ignore = true; 1011 + func->ignore = true; 1012 + if (func->cfunc) 1013 + func->cfunc->ignore = true; 1013 1014 } 1015 + 1016 + return 0; 1014 1017 } 1015 1018 1016 1019 /* ··· 1191 1188 "__ubsan_handle_load_invalid_value", 1192 1189 /* STACKLEAK */ 1193 1190 "stackleak_track_stack", 1191 + /* TRACE_BRANCH_PROFILING */ 1192 + "ftrace_likely_update", 1193 + /* STACKPROTECTOR */ 1194 + "__stack_chk_fail", 1194 1195 /* misc */ 1195 1196 "csum_partial_copy_generic", 1196 1197 "copy_mc_fragile", 1197 1198 "copy_mc_fragile_handle_tail", 1198 1199 "copy_mc_enhanced_fast_string", 1199 - "ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */ 1200 1200 "rep_stos_alternative", 1201 1201 "rep_movs_alternative", 1202 1202 "__copy_user_nocache", ··· 1281 1275 insn->stack_ops = NULL; 1282 1276 } 1283 1277 1284 - static void annotate_call_site(struct objtool_file *file, 1278 + static int annotate_call_site(struct objtool_file *file, 1285 1279 struct instruction *insn, bool sibling) 1286 1280 { 1287 1281 struct reloc *reloc = insn_reloc(file, insn); ··· 1292 1286 1293 1287 if (sym->static_call_tramp) { 1294 1288 list_add_tail(&insn->call_node, &file->static_call_list); 1295 - return; 1289 + return 0; 1296 1290 } 1297 1291 1298 1292 if (sym->retpoline_thunk) { 1299 1293 list_add_tail(&insn->call_node, &file->retpoline_call_list); 1300 - return; 1294 + return 0; 1301 1295 } 1302 1296 1303 1297 /* ··· 1309 1303 if (reloc) 1310 1304 set_reloc_type(file->elf, reloc, R_NONE); 1311 1305 1312 - elf_write_insn(file->elf, insn->sec, 1313 - insn->offset, insn->len, 1314 - sibling ? arch_ret_insn(insn->len) 1315 - : arch_nop_insn(insn->len)); 1306 + if (elf_write_insn(file->elf, insn->sec, 1307 + insn->offset, insn->len, 1308 + sibling ? arch_ret_insn(insn->len) 1309 + : arch_nop_insn(insn->len))) { 1310 + return -1; 1311 + } 1316 1312 1317 1313 insn->type = sibling ? INSN_RETURN : INSN_NOP; 1318 1314 ··· 1328 1320 insn->retpoline_safe = true; 1329 1321 } 1330 1322 1331 - return; 1323 + return 0; 1332 1324 } 1333 1325 1334 1326 if (opts.mcount && sym->fentry) { ··· 1338 1330 if (reloc) 1339 1331 set_reloc_type(file->elf, reloc, R_NONE); 1340 1332 1341 - elf_write_insn(file->elf, insn->sec, 1342 - insn->offset, insn->len, 1343 - arch_nop_insn(insn->len)); 1333 + if (elf_write_insn(file->elf, insn->sec, 1334 + insn->offset, insn->len, 1335 + arch_nop_insn(insn->len))) { 1336 + return -1; 1337 + } 1344 1338 1345 1339 insn->type = INSN_NOP; 1346 1340 } 1347 1341 1348 1342 list_add_tail(&insn->call_node, &file->mcount_loc_list); 1349 - return; 1343 + return 0; 1350 1344 } 1351 1345 1352 1346 if (insn->type == INSN_CALL && !insn->sec->init && ··· 1357 1347 1358 1348 if (!sibling && dead_end_function(file, sym)) 1359 1349 insn->dead_end = true; 1350 + 1351 + return 0; 1360 1352 } 1361 1353 1362 - static void add_call_dest(struct objtool_file *file, struct instruction *insn, 1354 + static int add_call_dest(struct objtool_file *file, struct instruction *insn, 1363 1355 struct symbol *dest, bool sibling) 1364 1356 { 1365 1357 insn->_call_dest = dest; 1366 1358 if (!dest) 1367 - return; 1359 + return 0; 1368 1360 1369 1361 /* 1370 1362 * Whatever stack impact regular CALLs have, should be undone ··· 1377 1365 */ 1378 1366 remove_insn_ops(insn); 1379 1367 1380 - annotate_call_site(file, insn, sibling); 1368 + return annotate_call_site(file, insn, sibling); 1381 1369 } 1382 1370 1383 - static void add_retpoline_call(struct objtool_file *file, struct instruction *insn) 1371 + static int add_retpoline_call(struct objtool_file *file, struct instruction *insn) 1384 1372 { 1385 1373 /* 1386 1374 * Retpoline calls/jumps are really dynamic calls/jumps in disguise, ··· 1397 1385 insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL; 1398 1386 break; 1399 1387 default: 1400 - return; 1388 + return 0; 1401 1389 } 1402 1390 1403 1391 insn->retpoline_safe = true; ··· 1411 1399 */ 1412 1400 remove_insn_ops(insn); 1413 1401 1414 - annotate_call_site(file, insn, false); 1402 + return annotate_call_site(file, insn, false); 1415 1403 } 1416 1404 1417 1405 static void add_return_call(struct objtool_file *file, struct instruction *insn, bool add) ··· 1480 1468 struct reloc *reloc; 1481 1469 struct section *dest_sec; 1482 1470 unsigned long dest_off; 1471 + int ret; 1483 1472 1484 1473 for_each_insn(file, insn) { 1474 + struct symbol *func = insn_func(insn); 1475 + 1485 1476 if (insn->jump_dest) { 1486 1477 /* 1487 1478 * handle_group_alt() may have previously set ··· 1503 1488 dest_sec = reloc->sym->sec; 1504 1489 dest_off = arch_dest_reloc_offset(reloc_addend(reloc)); 1505 1490 } else if (reloc->sym->retpoline_thunk) { 1506 - add_retpoline_call(file, insn); 1491 + ret = add_retpoline_call(file, insn); 1492 + if (ret) 1493 + return ret; 1507 1494 continue; 1508 1495 } else if (reloc->sym->return_thunk) { 1509 1496 add_return_call(file, insn, true); 1510 1497 continue; 1511 - } else if (insn_func(insn)) { 1498 + } else if (func) { 1512 1499 /* 1513 1500 * External sibling call or internal sibling call with 1514 1501 * STT_FUNC reloc. 1515 1502 */ 1516 - add_call_dest(file, insn, reloc->sym, true); 1503 + ret = add_call_dest(file, insn, reloc->sym, true); 1504 + if (ret) 1505 + return ret; 1517 1506 continue; 1518 1507 } else if (reloc->sym->sec->idx) { 1519 1508 dest_sec = reloc->sym->sec; ··· 1545 1526 continue; 1546 1527 } 1547 1528 1548 - WARN_INSN(insn, "can't find jump dest instruction at %s+0x%lx", 1549 - dest_sec->name, dest_off); 1529 + /* 1530 + * GCOV/KCOV dead code can jump to the end of the 1531 + * function/section. 1532 + */ 1533 + if (file->ignore_unreachables && func && 1534 + dest_sec == insn->sec && 1535 + dest_off == func->offset + func->len) 1536 + continue; 1537 + 1538 + ERROR_INSN(insn, "can't find jump dest instruction at %s+0x%lx", 1539 + dest_sec->name, dest_off); 1550 1540 return -1; 1551 1541 } 1552 1542 ··· 1566 1538 */ 1567 1539 if (jump_dest->sym && jump_dest->offset == jump_dest->sym->offset) { 1568 1540 if (jump_dest->sym->retpoline_thunk) { 1569 - add_retpoline_call(file, insn); 1541 + ret = add_retpoline_call(file, insn); 1542 + if (ret) 1543 + return ret; 1570 1544 continue; 1571 1545 } 1572 1546 if (jump_dest->sym->return_thunk) { ··· 1580 1550 /* 1581 1551 * Cross-function jump. 1582 1552 */ 1583 - if (insn_func(insn) && insn_func(jump_dest) && 1584 - insn_func(insn) != insn_func(jump_dest)) { 1553 + if (func && insn_func(jump_dest) && func != insn_func(jump_dest)) { 1585 1554 1586 1555 /* 1587 1556 * For GCC 8+, create parent/child links for any cold ··· 1597 1568 * case where the parent function's only reference to a 1598 1569 * subfunction is through a jump table. 1599 1570 */ 1600 - if (!strstr(insn_func(insn)->name, ".cold") && 1571 + if (!strstr(func->name, ".cold") && 1601 1572 strstr(insn_func(jump_dest)->name, ".cold")) { 1602 - insn_func(insn)->cfunc = insn_func(jump_dest); 1603 - insn_func(jump_dest)->pfunc = insn_func(insn); 1573 + func->cfunc = insn_func(jump_dest); 1574 + insn_func(jump_dest)->pfunc = func; 1604 1575 } 1605 1576 } 1606 1577 ··· 1609 1580 * Internal sibling call without reloc or with 1610 1581 * STT_SECTION reloc. 1611 1582 */ 1612 - add_call_dest(file, insn, insn_func(jump_dest), true); 1583 + ret = add_call_dest(file, insn, insn_func(jump_dest), true); 1584 + if (ret) 1585 + return ret; 1613 1586 continue; 1614 1587 } 1615 1588 ··· 1641 1610 unsigned long dest_off; 1642 1611 struct symbol *dest; 1643 1612 struct reloc *reloc; 1613 + int ret; 1644 1614 1645 1615 for_each_insn(file, insn) { 1616 + struct symbol *func = insn_func(insn); 1646 1617 if (insn->type != INSN_CALL) 1647 1618 continue; 1648 1619 ··· 1653 1620 dest_off = arch_jump_destination(insn); 1654 1621 dest = find_call_destination(insn->sec, dest_off); 1655 1622 1656 - add_call_dest(file, insn, dest, false); 1623 + ret = add_call_dest(file, insn, dest, false); 1624 + if (ret) 1625 + return ret; 1657 1626 1658 - if (insn->ignore) 1627 + if (func && func->ignore) 1659 1628 continue; 1660 1629 1661 1630 if (!insn_call_dest(insn)) { 1662 - WARN_INSN(insn, "unannotated intra-function call"); 1631 + ERROR_INSN(insn, "unannotated intra-function call"); 1663 1632 return -1; 1664 1633 } 1665 1634 1666 - if (insn_func(insn) && insn_call_dest(insn)->type != STT_FUNC) { 1667 - WARN_INSN(insn, "unsupported call to non-function"); 1635 + if (func && insn_call_dest(insn)->type != STT_FUNC) { 1636 + ERROR_INSN(insn, "unsupported call to non-function"); 1668 1637 return -1; 1669 1638 } 1670 1639 ··· 1674 1639 dest_off = arch_dest_reloc_offset(reloc_addend(reloc)); 1675 1640 dest = find_call_destination(reloc->sym->sec, dest_off); 1676 1641 if (!dest) { 1677 - WARN_INSN(insn, "can't find call dest symbol at %s+0x%lx", 1678 - reloc->sym->sec->name, dest_off); 1642 + ERROR_INSN(insn, "can't find call dest symbol at %s+0x%lx", 1643 + reloc->sym->sec->name, dest_off); 1679 1644 return -1; 1680 1645 } 1681 1646 1682 - add_call_dest(file, insn, dest, false); 1647 + ret = add_call_dest(file, insn, dest, false); 1648 + if (ret) 1649 + return ret; 1683 1650 1684 1651 } else if (reloc->sym->retpoline_thunk) { 1685 - add_retpoline_call(file, insn); 1652 + ret = add_retpoline_call(file, insn); 1653 + if (ret) 1654 + return ret; 1686 1655 1687 - } else 1688 - add_call_dest(file, insn, reloc->sym, false); 1656 + } else { 1657 + ret = add_call_dest(file, insn, reloc->sym, false); 1658 + if (ret) 1659 + return ret; 1660 + } 1689 1661 } 1690 1662 1691 1663 return 0; ··· 1715 1673 if (!orig_alt_group) { 1716 1674 struct instruction *last_orig_insn = NULL; 1717 1675 1718 - orig_alt_group = malloc(sizeof(*orig_alt_group)); 1676 + orig_alt_group = calloc(1, sizeof(*orig_alt_group)); 1719 1677 if (!orig_alt_group) { 1720 - WARN("malloc failed"); 1678 + ERROR_GLIBC("calloc"); 1721 1679 return -1; 1722 1680 } 1723 1681 orig_alt_group->cfi = calloc(special_alt->orig_len, 1724 1682 sizeof(struct cfi_state *)); 1725 1683 if (!orig_alt_group->cfi) { 1726 - WARN("calloc failed"); 1684 + ERROR_GLIBC("calloc"); 1727 1685 return -1; 1728 1686 } 1729 1687 ··· 1739 1697 orig_alt_group->first_insn = orig_insn; 1740 1698 orig_alt_group->last_insn = last_orig_insn; 1741 1699 orig_alt_group->nop = NULL; 1700 + orig_alt_group->ignore = orig_insn->ignore_alts; 1742 1701 } else { 1743 1702 if (orig_alt_group->last_insn->offset + orig_alt_group->last_insn->len - 1744 1703 orig_alt_group->first_insn->offset != special_alt->orig_len) { 1745 - WARN_INSN(orig_insn, "weirdly overlapping alternative! %ld != %d", 1746 - orig_alt_group->last_insn->offset + 1747 - orig_alt_group->last_insn->len - 1748 - orig_alt_group->first_insn->offset, 1749 - special_alt->orig_len); 1704 + ERROR_INSN(orig_insn, "weirdly overlapping alternative! %ld != %d", 1705 + orig_alt_group->last_insn->offset + 1706 + orig_alt_group->last_insn->len - 1707 + orig_alt_group->first_insn->offset, 1708 + special_alt->orig_len); 1750 1709 return -1; 1751 1710 } 1752 1711 } 1753 1712 1754 - new_alt_group = malloc(sizeof(*new_alt_group)); 1713 + new_alt_group = calloc(1, sizeof(*new_alt_group)); 1755 1714 if (!new_alt_group) { 1756 - WARN("malloc failed"); 1715 + ERROR_GLIBC("calloc"); 1757 1716 return -1; 1758 1717 } 1759 1718 ··· 1766 1723 * instruction affects the stack, the instruction after it (the 1767 1724 * nop) will propagate the new state to the shared CFI array. 1768 1725 */ 1769 - nop = malloc(sizeof(*nop)); 1726 + nop = calloc(1, sizeof(*nop)); 1770 1727 if (!nop) { 1771 - WARN("malloc failed"); 1728 + ERROR_GLIBC("calloc"); 1772 1729 return -1; 1773 1730 } 1774 1731 memset(nop, 0, sizeof(*nop)); ··· 1779 1736 nop->type = INSN_NOP; 1780 1737 nop->sym = orig_insn->sym; 1781 1738 nop->alt_group = new_alt_group; 1782 - nop->ignore = orig_insn->ignore_alts; 1783 1739 } 1784 1740 1785 1741 if (!special_alt->new_len) { ··· 1795 1753 1796 1754 last_new_insn = insn; 1797 1755 1798 - insn->ignore = orig_insn->ignore_alts; 1799 1756 insn->sym = orig_insn->sym; 1800 1757 insn->alt_group = new_alt_group; 1801 1758 ··· 1810 1769 if (alt_reloc && arch_pc_relative_reloc(alt_reloc) && 1811 1770 !arch_support_alt_relocation(special_alt, insn, alt_reloc)) { 1812 1771 1813 - WARN_INSN(insn, "unsupported relocation in alternatives section"); 1772 + ERROR_INSN(insn, "unsupported relocation in alternatives section"); 1814 1773 return -1; 1815 1774 } 1816 1775 ··· 1824 1783 if (dest_off == special_alt->new_off + special_alt->new_len) { 1825 1784 insn->jump_dest = next_insn_same_sec(file, orig_alt_group->last_insn); 1826 1785 if (!insn->jump_dest) { 1827 - WARN_INSN(insn, "can't find alternative jump destination"); 1786 + ERROR_INSN(insn, "can't find alternative jump destination"); 1828 1787 return -1; 1829 1788 } 1830 1789 } 1831 1790 } 1832 1791 1833 1792 if (!last_new_insn) { 1834 - WARN_FUNC("can't find last new alternative instruction", 1835 - special_alt->new_sec, special_alt->new_off); 1793 + ERROR_FUNC(special_alt->new_sec, special_alt->new_off, 1794 + "can't find last new alternative instruction"); 1836 1795 return -1; 1837 1796 } 1838 1797 ··· 1841 1800 new_alt_group->first_insn = *new_insn; 1842 1801 new_alt_group->last_insn = last_new_insn; 1843 1802 new_alt_group->nop = nop; 1803 + new_alt_group->ignore = (*new_insn)->ignore_alts; 1844 1804 new_alt_group->cfi = orig_alt_group->cfi; 1845 1805 return 0; 1846 1806 } ··· 1859 1817 if (orig_insn->type != INSN_JUMP_UNCONDITIONAL && 1860 1818 orig_insn->type != INSN_NOP) { 1861 1819 1862 - WARN_INSN(orig_insn, "unsupported instruction at jump label"); 1820 + ERROR_INSN(orig_insn, "unsupported instruction at jump label"); 1863 1821 return -1; 1864 1822 } 1865 1823 ··· 1868 1826 1869 1827 if (reloc) 1870 1828 set_reloc_type(file->elf, reloc, R_NONE); 1871 - elf_write_insn(file->elf, orig_insn->sec, 1872 - orig_insn->offset, orig_insn->len, 1873 - arch_nop_insn(orig_insn->len)); 1829 + 1830 + if (elf_write_insn(file->elf, orig_insn->sec, 1831 + orig_insn->offset, orig_insn->len, 1832 + arch_nop_insn(orig_insn->len))) { 1833 + return -1; 1834 + } 1835 + 1874 1836 orig_insn->type = INSN_NOP; 1875 1837 } 1876 1838 ··· 1910 1864 struct alternative *alt; 1911 1865 int ret; 1912 1866 1913 - ret = special_get_alts(file->elf, &special_alts); 1914 - if (ret) 1915 - return ret; 1867 + if (special_get_alts(file->elf, &special_alts)) 1868 + return -1; 1916 1869 1917 1870 list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { 1918 1871 1919 1872 orig_insn = find_insn(file, special_alt->orig_sec, 1920 1873 special_alt->orig_off); 1921 1874 if (!orig_insn) { 1922 - WARN_FUNC("special: can't find orig instruction", 1923 - special_alt->orig_sec, special_alt->orig_off); 1924 - ret = -1; 1925 - goto out; 1875 + ERROR_FUNC(special_alt->orig_sec, special_alt->orig_off, 1876 + "special: can't find orig instruction"); 1877 + return -1; 1926 1878 } 1927 1879 1928 1880 new_insn = NULL; ··· 1928 1884 new_insn = find_insn(file, special_alt->new_sec, 1929 1885 special_alt->new_off); 1930 1886 if (!new_insn) { 1931 - WARN_FUNC("special: can't find new instruction", 1932 - special_alt->new_sec, 1933 - special_alt->new_off); 1934 - ret = -1; 1935 - goto out; 1887 + ERROR_FUNC(special_alt->new_sec, special_alt->new_off, 1888 + "special: can't find new instruction"); 1889 + return -1; 1936 1890 } 1937 1891 } 1938 1892 1939 1893 if (special_alt->group) { 1940 1894 if (!special_alt->orig_len) { 1941 - WARN_INSN(orig_insn, "empty alternative entry"); 1895 + ERROR_INSN(orig_insn, "empty alternative entry"); 1942 1896 continue; 1943 1897 } 1944 1898 1945 1899 ret = handle_group_alt(file, special_alt, orig_insn, 1946 1900 &new_insn); 1947 1901 if (ret) 1948 - goto out; 1902 + return ret; 1903 + 1949 1904 } else if (special_alt->jump_or_nop) { 1950 1905 ret = handle_jump_alt(file, special_alt, orig_insn, 1951 1906 &new_insn); 1952 1907 if (ret) 1953 - goto out; 1908 + return ret; 1954 1909 } 1955 1910 1956 - alt = malloc(sizeof(*alt)); 1911 + alt = calloc(1, sizeof(*alt)); 1957 1912 if (!alt) { 1958 - WARN("malloc failed"); 1959 - ret = -1; 1960 - goto out; 1913 + ERROR_GLIBC("calloc"); 1914 + return -1; 1961 1915 } 1962 1916 1963 1917 alt->insn = new_insn; 1964 - alt->skip_orig = special_alt->skip_orig; 1965 - orig_insn->ignore_alts |= special_alt->skip_alt; 1966 1918 alt->next = orig_insn->alts; 1967 1919 orig_insn->alts = alt; 1968 1920 ··· 1972 1932 printf("long:\t%ld\t%ld\n", file->jl_nop_long, file->jl_long); 1973 1933 } 1974 1934 1975 - out: 1976 - return ret; 1935 + return 0; 1977 1936 } 1978 1937 1979 1938 __weak unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table) ··· 1980 1941 return reloc->sym->offset + reloc_addend(reloc); 1981 1942 } 1982 1943 1983 - static int add_jump_table(struct objtool_file *file, struct instruction *insn, 1984 - struct reloc *next_table) 1944 + static int add_jump_table(struct objtool_file *file, struct instruction *insn) 1985 1945 { 1986 1946 unsigned long table_size = insn_jump_table_size(insn); 1987 1947 struct symbol *pfunc = insn_func(insn)->pfunc; ··· 2000 1962 /* Check for the end of the table: */ 2001 1963 if (table_size && reloc_offset(reloc) - reloc_offset(table) >= table_size) 2002 1964 break; 2003 - if (reloc != table && reloc == next_table) 1965 + if (reloc != table && is_jump_table(reloc)) 2004 1966 break; 2005 1967 2006 1968 /* Make sure the table entries are consecutive: */ ··· 2029 1991 if (!insn_func(dest_insn) || insn_func(dest_insn)->pfunc != pfunc) 2030 1992 break; 2031 1993 2032 - alt = malloc(sizeof(*alt)); 1994 + alt = calloc(1, sizeof(*alt)); 2033 1995 if (!alt) { 2034 - WARN("malloc failed"); 1996 + ERROR_GLIBC("calloc"); 2035 1997 return -1; 2036 1998 } 2037 1999 ··· 2043 2005 } 2044 2006 2045 2007 if (!prev_offset) { 2046 - WARN_INSN(insn, "can't find switch jump table"); 2008 + ERROR_INSN(insn, "can't find switch jump table"); 2047 2009 return -1; 2048 2010 } 2049 2011 ··· 2079 2041 insn->jump_dest && 2080 2042 (insn->jump_dest->offset <= insn->offset || 2081 2043 insn->jump_dest->offset > orig_insn->offset)) 2082 - break; 2044 + break; 2083 2045 2084 2046 table_reloc = arch_find_switch_table(file, insn, &table_size); 2085 2047 if (!table_reloc) ··· 2091 2053 if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func) 2092 2054 continue; 2093 2055 2056 + set_jump_table(table_reloc); 2094 2057 orig_insn->_jump_table = table_reloc; 2095 2058 orig_insn->_jump_table_size = table_size; 2059 + 2096 2060 break; 2097 2061 } 2098 2062 } ··· 2136 2096 static int add_func_jump_tables(struct objtool_file *file, 2137 2097 struct symbol *func) 2138 2098 { 2139 - struct instruction *insn, *insn_t1 = NULL, *insn_t2; 2140 - int ret = 0; 2099 + struct instruction *insn; 2100 + int ret; 2141 2101 2142 2102 func_for_each_insn(file, func, insn) { 2143 2103 if (!insn_jump_table(insn)) 2144 2104 continue; 2145 2105 2146 - if (!insn_t1) { 2147 - insn_t1 = insn; 2148 - continue; 2149 - } 2150 - 2151 - insn_t2 = insn; 2152 - 2153 - ret = add_jump_table(file, insn_t1, insn_jump_table(insn_t2)); 2106 + ret = add_jump_table(file, insn); 2154 2107 if (ret) 2155 2108 return ret; 2156 - 2157 - insn_t1 = insn_t2; 2158 2109 } 2159 2110 2160 - if (insn_t1) 2161 - ret = add_jump_table(file, insn_t1, NULL); 2162 - 2163 - return ret; 2111 + return 0; 2164 2112 } 2165 2113 2166 2114 /* ··· 2201 2173 return 0; 2202 2174 2203 2175 if (!sec->rsec) { 2204 - WARN("missing .rela.discard.unwind_hints section"); 2176 + ERROR("missing .rela.discard.unwind_hints section"); 2205 2177 return -1; 2206 2178 } 2207 2179 2208 2180 if (sec->sh.sh_size % sizeof(struct unwind_hint)) { 2209 - WARN("struct unwind_hint size mismatch"); 2181 + ERROR("struct unwind_hint size mismatch"); 2210 2182 return -1; 2211 2183 } 2212 2184 ··· 2217 2189 2218 2190 reloc = find_reloc_by_dest(file->elf, sec, i * sizeof(*hint)); 2219 2191 if (!reloc) { 2220 - WARN("can't find reloc for unwind_hints[%d]", i); 2192 + ERROR("can't find reloc for unwind_hints[%d]", i); 2221 2193 return -1; 2222 2194 } 2223 2195 ··· 2226 2198 } else if (reloc->sym->local_label) { 2227 2199 offset = reloc->sym->offset; 2228 2200 } else { 2229 - WARN("unexpected relocation symbol type in %s", sec->rsec->name); 2201 + ERROR("unexpected relocation symbol type in %s", sec->rsec->name); 2230 2202 return -1; 2231 2203 } 2232 2204 2233 2205 insn = find_insn(file, reloc->sym->sec, offset); 2234 2206 if (!insn) { 2235 - WARN("can't find insn for unwind_hints[%d]", i); 2207 + ERROR("can't find insn for unwind_hints[%d]", i); 2236 2208 return -1; 2237 2209 } 2238 2210 ··· 2259 2231 2260 2232 if (sym && sym->bind == STB_GLOBAL) { 2261 2233 if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) { 2262 - WARN_INSN(insn, "UNWIND_HINT_IRET_REGS without ENDBR"); 2234 + ERROR_INSN(insn, "UNWIND_HINT_IRET_REGS without ENDBR"); 2235 + return -1; 2263 2236 } 2264 2237 } 2265 2238 } ··· 2274 2245 cfi = *(insn->cfi); 2275 2246 2276 2247 if (arch_decode_hint_reg(hint->sp_reg, &cfi.cfa.base)) { 2277 - WARN_INSN(insn, "unsupported unwind_hint sp base reg %d", hint->sp_reg); 2248 + ERROR_INSN(insn, "unsupported unwind_hint sp base reg %d", hint->sp_reg); 2278 2249 return -1; 2279 2250 } 2280 2251 ··· 2320 2291 insn = find_insn(file, reloc->sym->sec, offset); 2321 2292 2322 2293 if (!insn) { 2323 - WARN("bad .discard.annotate_insn entry: %d of type %d", reloc_idx(reloc), type); 2294 + ERROR("bad .discard.annotate_insn entry: %d of type %d", reloc_idx(reloc), type); 2324 2295 return -1; 2325 2296 } 2326 2297 ··· 2335 2306 static int __annotate_early(struct objtool_file *file, int type, struct instruction *insn) 2336 2307 { 2337 2308 switch (type) { 2309 + 2310 + /* Must be before add_special_section_alts() */ 2338 2311 case ANNOTYPE_IGNORE_ALTS: 2339 2312 insn->ignore_alts = true; 2340 2313 break; ··· 2363 2332 return 0; 2364 2333 2365 2334 if (insn->type != INSN_CALL) { 2366 - WARN_INSN(insn, "intra_function_call not a direct call"); 2335 + ERROR_INSN(insn, "intra_function_call not a direct call"); 2367 2336 return -1; 2368 2337 } 2369 2338 ··· 2377 2346 dest_off = arch_jump_destination(insn); 2378 2347 insn->jump_dest = find_insn(file, insn->sec, dest_off); 2379 2348 if (!insn->jump_dest) { 2380 - WARN_INSN(insn, "can't find call dest at %s+0x%lx", 2381 - insn->sec->name, dest_off); 2349 + ERROR_INSN(insn, "can't find call dest at %s+0x%lx", 2350 + insn->sec->name, dest_off); 2382 2351 return -1; 2383 2352 } 2384 2353 ··· 2397 2366 insn->type != INSN_CALL_DYNAMIC && 2398 2367 insn->type != INSN_RETURN && 2399 2368 insn->type != INSN_NOP) { 2400 - WARN_INSN(insn, "retpoline_safe hint not an indirect jump/call/ret/nop"); 2369 + ERROR_INSN(insn, "retpoline_safe hint not an indirect jump/call/ret/nop"); 2401 2370 return -1; 2402 2371 } 2403 2372 ··· 2429 2398 break; 2430 2399 2431 2400 default: 2432 - WARN_INSN(insn, "Unknown annotation type: %d", type); 2433 - break; 2401 + ERROR_INSN(insn, "Unknown annotation type: %d", type); 2402 + return -1; 2434 2403 } 2435 2404 2436 2405 return 0; ··· 2543 2512 if (ret) 2544 2513 return ret; 2545 2514 2546 - add_ignores(file); 2515 + ret = add_ignores(file); 2516 + if (ret) 2517 + return ret; 2518 + 2547 2519 add_uaccess_safe(file); 2548 2520 2549 2521 ret = read_annotate(file, __annotate_early); ··· 2766 2732 if (cfa->base == CFI_UNDEFINED) { 2767 2733 if (insn_func(insn)) { 2768 2734 WARN_INSN(insn, "undefined stack state"); 2769 - return -1; 2735 + return 1; 2770 2736 } 2771 2737 return 0; 2772 2738 } ··· 3209 3175 if (cficmp(alt_cfi[group_off], insn->cfi)) { 3210 3176 struct alt_group *orig_group = insn->alt_group->orig_group ?: insn->alt_group; 3211 3177 struct instruction *orig = orig_group->first_insn; 3212 - char *where = offstr(insn->sec, insn->offset); 3213 - WARN_INSN(orig, "stack layout conflict in alternatives: %s", where); 3214 - free(where); 3178 + WARN_INSN(orig, "stack layout conflict in alternatives: %s", 3179 + offstr(insn->sec, insn->offset)); 3215 3180 return -1; 3216 3181 } 3217 3182 } ··· 3223 3190 struct insn_state *state) 3224 3191 { 3225 3192 struct stack_op *op; 3193 + int ret; 3226 3194 3227 3195 for (op = insn->stack_ops; op; op = op->next) { 3228 3196 3229 - if (update_cfi_state(insn, next_insn, &state->cfi, op)) 3230 - return 1; 3197 + ret = update_cfi_state(insn, next_insn, &state->cfi, op); 3198 + if (ret) 3199 + return ret; 3231 3200 3232 - if (!insn->alt_group) 3201 + if (!opts.uaccess || !insn->alt_group) 3233 3202 continue; 3234 3203 3235 3204 if (op->dest.type == OP_DEST_PUSHF) { ··· 3273 3238 WARN_INSN(insn, "stack state mismatch: cfa1=%d%+d cfa2=%d%+d", 3274 3239 cfi1->cfa.base, cfi1->cfa.offset, 3275 3240 cfi2->cfa.base, cfi2->cfa.offset); 3241 + return false; 3276 3242 3277 - } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) { 3243 + } 3244 + 3245 + if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) { 3278 3246 for (i = 0; i < CFI_NUM_REGS; i++) { 3279 - if (!memcmp(&cfi1->regs[i], &cfi2->regs[i], 3280 - sizeof(struct cfi_reg))) 3247 + 3248 + if (!memcmp(&cfi1->regs[i], &cfi2->regs[i], sizeof(struct cfi_reg))) 3281 3249 continue; 3282 3250 3283 3251 WARN_INSN(insn, "stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", 3284 3252 i, cfi1->regs[i].base, cfi1->regs[i].offset, 3285 3253 i, cfi2->regs[i].base, cfi2->regs[i].offset); 3286 - break; 3287 3254 } 3255 + return false; 3256 + } 3288 3257 3289 - } else if (cfi1->type != cfi2->type) { 3258 + if (cfi1->type != cfi2->type) { 3290 3259 3291 3260 WARN_INSN(insn, "stack state mismatch: type1=%d type2=%d", 3292 3261 cfi1->type, cfi2->type); 3262 + return false; 3263 + } 3293 3264 3294 - } else if (cfi1->drap != cfi2->drap || 3265 + if (cfi1->drap != cfi2->drap || 3295 3266 (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) || 3296 3267 (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) { 3297 3268 3298 3269 WARN_INSN(insn, "stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)", 3299 3270 cfi1->drap, cfi1->drap_reg, cfi1->drap_offset, 3300 3271 cfi2->drap, cfi2->drap_reg, cfi2->drap_offset); 3272 + return false; 3273 + } 3301 3274 3302 - } else 3303 - return true; 3304 - 3305 - return false; 3275 + return true; 3306 3276 } 3307 3277 3308 3278 static inline bool func_uaccess_safe(struct symbol *func) ··· 3520 3480 u8 visited; 3521 3481 int ret; 3522 3482 3483 + if (func && func->ignore) 3484 + return 0; 3485 + 3523 3486 sec = insn->sec; 3524 3487 3525 3488 while (1) { ··· 3534 3491 !strncmp(func->name, "__pfx_", 6)) 3535 3492 return 0; 3536 3493 3494 + if (file->ignore_unreachables) 3495 + return 0; 3496 + 3537 3497 WARN("%s() falls through to next function %s()", 3538 3498 func->name, insn_func(insn)->name); 3539 - return 1; 3540 - } 3499 + func->warned = 1; 3541 3500 3542 - if (func && insn->ignore) { 3543 - WARN_INSN(insn, "BUG: why am I validating an ignored function?"); 3544 3501 return 1; 3545 3502 } 3546 3503 ··· 3615 3572 if (propagate_alt_cfi(file, insn)) 3616 3573 return 1; 3617 3574 3618 - if (!insn->ignore_alts && insn->alts) { 3619 - bool skip_orig = false; 3620 - 3575 + if (insn->alts) { 3621 3576 for (alt = insn->alts; alt; alt = alt->next) { 3622 - if (alt->skip_orig) 3623 - skip_orig = true; 3624 - 3625 3577 ret = validate_branch(file, func, alt->insn, state); 3626 3578 if (ret) { 3627 3579 BT_INSN(insn, "(alt)"); 3628 3580 return ret; 3629 3581 } 3630 3582 } 3631 - 3632 - if (skip_orig) 3633 - return 0; 3634 3583 } 3584 + 3585 + if (insn->alt_group && insn->alt_group->ignore) 3586 + return 0; 3635 3587 3636 3588 if (handle_insn_ops(insn, next_insn, &state)) 3637 3589 return 1; ··· 3647 3609 WARN_INSN(insn, "call without frame pointer save/setup"); 3648 3610 return 1; 3649 3611 } 3650 - 3651 - if (insn->dead_end) 3652 - return 0; 3653 3612 3654 3613 break; 3655 3614 ··· 3695 3660 return 0; 3696 3661 3697 3662 case INSN_STAC: 3663 + if (!opts.uaccess) 3664 + break; 3665 + 3698 3666 if (state.uaccess) { 3699 3667 WARN_INSN(insn, "recursive UACCESS enable"); 3700 3668 return 1; ··· 3707 3669 break; 3708 3670 3709 3671 case INSN_CLAC: 3672 + if (!opts.uaccess) 3673 + break; 3674 + 3710 3675 if (!state.uaccess && func) { 3711 3676 WARN_INSN(insn, "redundant UACCESS disable"); 3712 3677 return 1; ··· 3751 3710 if (!next_insn) { 3752 3711 if (state.cfi.cfa.base == CFI_UNDEFINED) 3753 3712 return 0; 3754 - WARN("%s: unexpected end of section", sec->name); 3713 + if (file->ignore_unreachables) 3714 + return 0; 3715 + 3716 + WARN("%s%sunexpected end of section %s", 3717 + func ? func->name : "", func ? "(): " : "", 3718 + sec->name); 3755 3719 return 1; 3756 3720 } 3757 3721 ··· 3771 3725 struct instruction *insn, 3772 3726 struct insn_state *state) 3773 3727 { 3774 - if (insn->hint && !insn->visited && !insn->ignore) { 3728 + if (insn->hint && !insn->visited) { 3775 3729 int ret = validate_branch(file, insn_func(insn), insn, *state); 3776 3730 if (ret) 3777 3731 BT_INSN(insn, "<=== (hint)"); ··· 3822 3776 3823 3777 insn->visited |= VISITED_UNRET; 3824 3778 3825 - if (!insn->ignore_alts && insn->alts) { 3779 + if (insn->alts) { 3826 3780 struct alternative *alt; 3827 - bool skip_orig = false; 3828 - 3829 3781 for (alt = insn->alts; alt; alt = alt->next) { 3830 - if (alt->skip_orig) 3831 - skip_orig = true; 3832 - 3833 3782 ret = validate_unret(file, alt->insn); 3834 3783 if (ret) { 3835 3784 BT_INSN(insn, "(alt)"); 3836 3785 return ret; 3837 3786 } 3838 3787 } 3839 - 3840 - if (skip_orig) 3841 - return 0; 3842 3788 } 3843 3789 3844 3790 switch (insn->type) { ··· 3846 3808 if (!is_sibling_call(insn)) { 3847 3809 if (!insn->jump_dest) { 3848 3810 WARN_INSN(insn, "unresolved jump target after linking?!?"); 3849 - return -1; 3811 + return 1; 3850 3812 } 3851 3813 ret = validate_unret(file, insn->jump_dest); 3852 3814 if (ret) { ··· 3868 3830 if (!dest) { 3869 3831 WARN("Unresolved function after linking!?: %s", 3870 3832 insn_call_dest(insn)->name); 3871 - return -1; 3833 + return 1; 3872 3834 } 3873 3835 3874 3836 ret = validate_unret(file, dest); ··· 3897 3859 3898 3860 if (!next) { 3899 3861 WARN_INSN(insn, "teh end!"); 3900 - return -1; 3862 + return 1; 3901 3863 } 3902 3864 insn = next; 3903 3865 } ··· 3912 3874 static int validate_unrets(struct objtool_file *file) 3913 3875 { 3914 3876 struct instruction *insn; 3915 - int ret, warnings = 0; 3877 + int warnings = 0; 3916 3878 3917 3879 for_each_insn(file, insn) { 3918 3880 if (!insn->unret) 3919 3881 continue; 3920 3882 3921 - ret = validate_unret(file, insn); 3922 - if (ret < 0) { 3923 - WARN_INSN(insn, "Failed UNRET validation"); 3924 - return ret; 3925 - } 3926 - warnings += ret; 3883 + warnings += validate_unret(file, insn); 3927 3884 } 3928 3885 3929 3886 return warnings; ··· 3944 3911 if (insn->type == INSN_RETURN) { 3945 3912 if (opts.rethunk) { 3946 3913 WARN_INSN(insn, "'naked' return found in MITIGATION_RETHUNK build"); 3947 - } else 3948 - continue; 3949 - } else { 3950 - WARN_INSN(insn, "indirect %s found in MITIGATION_RETPOLINE build", 3951 - insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); 3914 + warnings++; 3915 + } 3916 + continue; 3952 3917 } 3953 3918 3919 + WARN_INSN(insn, "indirect %s found in MITIGATION_RETPOLINE build", 3920 + insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); 3954 3921 warnings++; 3955 3922 } 3956 3923 ··· 3972 3939 3973 3940 static bool ignore_unreachable_insn(struct objtool_file *file, struct instruction *insn) 3974 3941 { 3975 - int i; 3942 + struct symbol *func = insn_func(insn); 3976 3943 struct instruction *prev_insn; 3944 + int i; 3977 3945 3978 - if (insn->ignore || insn->type == INSN_NOP || insn->type == INSN_TRAP) 3946 + if (insn->type == INSN_NOP || insn->type == INSN_TRAP || (func && func->ignore)) 3979 3947 return true; 3980 3948 3981 3949 /* ··· 3995 3961 * In this case we'll find a piece of code (whole function) that is not 3996 3962 * covered by a !section symbol. Ignore them. 3997 3963 */ 3998 - if (opts.link && !insn_func(insn)) { 3964 + if (opts.link && !func) { 3999 3965 int size = find_symbol_hole_containing(insn->sec, insn->offset); 4000 3966 unsigned long end = insn->offset + size; 4001 3967 ··· 4021 3987 */ 4022 3988 if (insn->jump_dest && insn_func(insn->jump_dest) && 4023 3989 strstr(insn_func(insn->jump_dest)->name, ".cold")) { 4024 - struct instruction *dest = insn->jump_dest; 4025 - func_for_each_insn(file, insn_func(dest), dest) 4026 - dest->ignore = true; 3990 + insn_func(insn->jump_dest)->ignore = true; 4027 3991 } 4028 3992 } 4029 3993 4030 3994 return false; 4031 3995 } 4032 3996 4033 - if (!insn_func(insn)) 3997 + if (!func) 4034 3998 return false; 4035 3999 4036 - if (insn_func(insn)->static_call_tramp) 4000 + if (func->static_call_tramp) 4037 4001 return true; 4038 4002 4039 4003 /* ··· 4043 4011 * It may also insert a UD2 after calling a __noreturn function. 4044 4012 */ 4045 4013 prev_insn = prev_insn_same_sec(file, insn); 4046 - if (prev_insn->dead_end && 4014 + if (prev_insn && prev_insn->dead_end && 4047 4015 (insn->type == INSN_BUG || 4048 4016 (insn->type == INSN_JUMP_UNCONDITIONAL && 4049 4017 insn->jump_dest && insn->jump_dest->type == INSN_BUG))) ··· 4062 4030 4063 4031 if (insn->type == INSN_JUMP_UNCONDITIONAL) { 4064 4032 if (insn->jump_dest && 4065 - insn_func(insn->jump_dest) == insn_func(insn)) { 4033 + insn_func(insn->jump_dest) == func) { 4066 4034 insn = insn->jump_dest; 4067 4035 continue; 4068 4036 } ··· 4070 4038 break; 4071 4039 } 4072 4040 4073 - if (insn->offset + insn->len >= insn_func(insn)->offset + insn_func(insn)->len) 4041 + if (insn->offset + insn->len >= func->offset + func->len) 4074 4042 break; 4075 4043 4076 4044 insn = next_insn_same_sec(file, insn); ··· 4162 4130 return 0; 4163 4131 4164 4132 insn = find_insn(file, sec, sym->offset); 4165 - if (!insn || insn->ignore || insn->visited) 4133 + if (!insn || insn->visited) 4166 4134 return 0; 4167 4135 4168 - state->uaccess = sym->uaccess_safe; 4136 + if (opts.uaccess) 4137 + state->uaccess = sym->uaccess_safe; 4169 4138 4170 4139 ret = validate_branch(file, insn_func(insn), insn, *state); 4171 4140 if (ret) ··· 4387 4354 if (dest->noendbr) 4388 4355 return 0; 4389 4356 4390 - WARN_FUNC("data relocation to !ENDBR: %s", 4391 - reloc->sec->base, reloc_offset(reloc), 4392 - offstr(dest->sec, dest->offset)); 4357 + WARN_FUNC(reloc->sec->base, reloc_offset(reloc), 4358 + "data relocation to !ENDBR: %s", offstr(dest->sec, dest->offset)); 4393 4359 4394 4360 return 1; 4395 4361 } ··· 4516 4484 } 4517 4485 4518 4486 /* 'funcs' is a space-separated list of function names */ 4519 - static int disas_funcs(const char *funcs) 4487 + static void disas_funcs(const char *funcs) 4520 4488 { 4521 4489 const char *objdump_str, *cross_compile; 4522 4490 int size, ret; 4523 4491 char *cmd; 4524 4492 4525 4493 cross_compile = getenv("CROSS_COMPILE"); 4494 + if (!cross_compile) 4495 + cross_compile = ""; 4526 4496 4527 4497 objdump_str = "%sobjdump -wdr %s | gawk -M -v _funcs='%s' '" 4528 4498 "BEGIN { split(_funcs, funcs); }" ··· 4551 4517 size = snprintf(NULL, 0, objdump_str, cross_compile, objname, funcs) + 1; 4552 4518 if (size <= 0) { 4553 4519 WARN("objdump string size calculation failed"); 4554 - return -1; 4520 + return; 4555 4521 } 4556 4522 4557 4523 cmd = malloc(size); ··· 4561 4527 ret = system(cmd); 4562 4528 if (ret) { 4563 4529 WARN("disassembly failed: %d", ret); 4564 - return -1; 4530 + return; 4565 4531 } 4566 - 4567 - return 0; 4568 4532 } 4569 4533 4570 - static int disas_warned_funcs(struct objtool_file *file) 4534 + static void disas_warned_funcs(struct objtool_file *file) 4571 4535 { 4572 4536 struct symbol *sym; 4573 4537 char *funcs = NULL, *tmp; 4574 4538 4575 4539 for_each_sym(file, sym) { 4576 - if (sym->warnings) { 4540 + if (sym->warned) { 4577 4541 if (!funcs) { 4578 4542 funcs = malloc(strlen(sym->name) + 1); 4543 + if (!funcs) { 4544 + ERROR_GLIBC("malloc"); 4545 + return; 4546 + } 4579 4547 strcpy(funcs, sym->name); 4580 4548 } else { 4581 4549 tmp = malloc(strlen(funcs) + strlen(sym->name) + 2); 4550 + if (!tmp) { 4551 + ERROR_GLIBC("malloc"); 4552 + return; 4553 + } 4582 4554 sprintf(tmp, "%s %s", funcs, sym->name); 4583 4555 free(funcs); 4584 4556 funcs = tmp; ··· 4594 4554 4595 4555 if (funcs) 4596 4556 disas_funcs(funcs); 4597 - 4598 - return 0; 4599 4557 } 4600 4558 4601 4559 struct insn_chunk { ··· 4626 4588 4627 4589 int check(struct objtool_file *file) 4628 4590 { 4629 - int ret, warnings = 0; 4591 + int ret = 0, warnings = 0; 4630 4592 4631 4593 arch_initial_func_cfi_state(&initial_func_cfi); 4632 4594 init_cfi_state(&init_cfi); ··· 4644 4606 cfi_hash_add(&func_cfi); 4645 4607 4646 4608 ret = decode_sections(file); 4647 - if (ret < 0) 4609 + if (ret) 4648 4610 goto out; 4649 - 4650 - warnings += ret; 4651 4611 4652 4612 if (!nr_insns) 4653 4613 goto out; 4654 4614 4655 - if (opts.retpoline) { 4656 - ret = validate_retpoline(file); 4657 - if (ret < 0) 4658 - goto out; 4659 - warnings += ret; 4660 - } 4615 + if (opts.retpoline) 4616 + warnings += validate_retpoline(file); 4661 4617 4662 4618 if (opts.stackval || opts.orc || opts.uaccess) { 4663 - ret = validate_functions(file); 4664 - if (ret < 0) 4665 - goto out; 4666 - warnings += ret; 4619 + int w = 0; 4667 4620 4668 - ret = validate_unwind_hints(file, NULL); 4669 - if (ret < 0) 4670 - goto out; 4671 - warnings += ret; 4621 + w += validate_functions(file); 4622 + w += validate_unwind_hints(file, NULL); 4623 + if (!w) 4624 + w += validate_reachable_instructions(file); 4672 4625 4673 - if (!warnings) { 4674 - ret = validate_reachable_instructions(file); 4675 - if (ret < 0) 4676 - goto out; 4677 - warnings += ret; 4678 - } 4626 + warnings += w; 4679 4627 4680 4628 } else if (opts.noinstr) { 4681 - ret = validate_noinstr_sections(file); 4682 - if (ret < 0) 4683 - goto out; 4684 - warnings += ret; 4629 + warnings += validate_noinstr_sections(file); 4685 4630 } 4686 4631 4687 4632 if (opts.unret) { ··· 4672 4651 * Must be after validate_branch() and friends, it plays 4673 4652 * further games with insn->visited. 4674 4653 */ 4675 - ret = validate_unrets(file); 4676 - if (ret < 0) 4677 - goto out; 4678 - warnings += ret; 4654 + warnings += validate_unrets(file); 4679 4655 } 4680 4656 4681 - if (opts.ibt) { 4682 - ret = validate_ibt(file); 4683 - if (ret < 0) 4684 - goto out; 4685 - warnings += ret; 4686 - } 4657 + if (opts.ibt) 4658 + warnings += validate_ibt(file); 4687 4659 4688 - if (opts.sls) { 4689 - ret = validate_sls(file); 4690 - if (ret < 0) 4691 - goto out; 4692 - warnings += ret; 4693 - } 4660 + if (opts.sls) 4661 + warnings += validate_sls(file); 4694 4662 4695 4663 if (opts.static_call) { 4696 4664 ret = create_static_call_sections(file); 4697 - if (ret < 0) 4665 + if (ret) 4698 4666 goto out; 4699 - warnings += ret; 4700 4667 } 4701 4668 4702 4669 if (opts.retpoline) { 4703 4670 ret = create_retpoline_sites_sections(file); 4704 - if (ret < 0) 4671 + if (ret) 4705 4672 goto out; 4706 - warnings += ret; 4707 4673 } 4708 4674 4709 4675 if (opts.cfi) { 4710 4676 ret = create_cfi_sections(file); 4711 - if (ret < 0) 4677 + if (ret) 4712 4678 goto out; 4713 - warnings += ret; 4714 4679 } 4715 4680 4716 4681 if (opts.rethunk) { 4717 4682 ret = create_return_sites_sections(file); 4718 - if (ret < 0) 4683 + if (ret) 4719 4684 goto out; 4720 - warnings += ret; 4721 4685 4722 4686 if (opts.hack_skylake) { 4723 4687 ret = create_direct_call_sections(file); 4724 - if (ret < 0) 4688 + if (ret) 4725 4689 goto out; 4726 - warnings += ret; 4727 4690 } 4728 4691 } 4729 4692 4730 4693 if (opts.mcount) { 4731 4694 ret = create_mcount_loc_sections(file); 4732 - if (ret < 0) 4695 + if (ret) 4733 4696 goto out; 4734 - warnings += ret; 4735 4697 } 4736 4698 4737 4699 if (opts.prefix) { 4738 4700 ret = add_prefix_symbols(file); 4739 - if (ret < 0) 4701 + if (ret) 4740 4702 goto out; 4741 - warnings += ret; 4742 4703 } 4743 4704 4744 4705 if (opts.ibt) { 4745 4706 ret = create_ibt_endbr_seal_sections(file); 4746 - if (ret < 0) 4707 + if (ret) 4747 4708 goto out; 4748 - warnings += ret; 4749 4709 } 4750 4710 4751 4711 if (opts.orc && nr_insns) { 4752 4712 ret = orc_create(file); 4753 - if (ret < 0) 4713 + if (ret) 4754 4714 goto out; 4755 - warnings += ret; 4756 4715 } 4757 4716 4758 4717 free_insns(file); 4759 - 4760 - if (opts.verbose) 4761 - disas_warned_funcs(file); 4762 4718 4763 4719 if (opts.stats) { 4764 4720 printf("nr_insns_visited: %ld\n", nr_insns_visited); ··· 4745 4747 } 4746 4748 4747 4749 out: 4748 - /* 4749 - * CONFIG_OBJTOOL_WERROR upgrades all warnings (and errors) to actual 4750 - * errors. 4751 - * 4752 - * Note that even "fatal" type errors don't actually return an error 4753 - * without CONFIG_OBJTOOL_WERROR. That probably needs improved at some 4754 - * point. 4755 - */ 4756 - if (opts.werror && (ret || warnings)) { 4757 - if (warnings) 4750 + if (!ret && !warnings) 4751 + return 0; 4752 + 4753 + if (opts.werror && warnings) 4754 + ret = 1; 4755 + 4756 + if (opts.verbose) { 4757 + if (opts.werror && warnings) 4758 4758 WARN("%d warning(s) upgraded to errors", warnings); 4759 - return 1; 4759 + print_args(); 4760 + disas_warned_funcs(file); 4760 4761 } 4761 4762 4762 - return 0; 4763 + return ret; 4763 4764 }
+74 -82
tools/objtool/elf.c
··· 72 72 obj; \ 73 73 obj = elf_list_entry(obj->member.next, typeof(*(obj)), member)) 74 74 75 - #define elf_alloc_hash(name, size) \ 76 - ({ \ 77 - __elf_bits(name) = max(10, ilog2(size)); \ 75 + #define elf_alloc_hash(name, size) \ 76 + ({ \ 77 + __elf_bits(name) = max(10, ilog2(size)); \ 78 78 __elf_table(name) = mmap(NULL, sizeof(struct elf_hash_node *) << __elf_bits(name), \ 79 - PROT_READ|PROT_WRITE, \ 80 - MAP_PRIVATE|MAP_ANON, -1, 0); \ 81 - if (__elf_table(name) == (void *)-1L) { \ 82 - WARN("mmap fail " #name); \ 83 - __elf_table(name) = NULL; \ 84 - } \ 85 - __elf_table(name); \ 79 + PROT_READ|PROT_WRITE, \ 80 + MAP_PRIVATE|MAP_ANON, -1, 0); \ 81 + if (__elf_table(name) == (void *)-1L) { \ 82 + ERROR_GLIBC("mmap fail " #name); \ 83 + __elf_table(name) = NULL; \ 84 + } \ 85 + __elf_table(name); \ 86 86 }) 87 87 88 88 static inline unsigned long __sym_start(struct symbol *s) ··· 316 316 int i; 317 317 318 318 if (elf_getshdrnum(elf->elf, &sections_nr)) { 319 - WARN_ELF("elf_getshdrnum"); 319 + ERROR_ELF("elf_getshdrnum"); 320 320 return -1; 321 321 } 322 322 323 323 if (elf_getshdrstrndx(elf->elf, &shstrndx)) { 324 - WARN_ELF("elf_getshdrstrndx"); 324 + ERROR_ELF("elf_getshdrstrndx"); 325 325 return -1; 326 326 } 327 327 ··· 331 331 332 332 elf->section_data = calloc(sections_nr, sizeof(*sec)); 333 333 if (!elf->section_data) { 334 - perror("calloc"); 334 + ERROR_GLIBC("calloc"); 335 335 return -1; 336 336 } 337 337 for (i = 0; i < sections_nr; i++) { ··· 341 341 342 342 s = elf_getscn(elf->elf, i); 343 343 if (!s) { 344 - WARN_ELF("elf_getscn"); 344 + ERROR_ELF("elf_getscn"); 345 345 return -1; 346 346 } 347 347 348 348 sec->idx = elf_ndxscn(s); 349 349 350 350 if (!gelf_getshdr(s, &sec->sh)) { 351 - WARN_ELF("gelf_getshdr"); 351 + ERROR_ELF("gelf_getshdr"); 352 352 return -1; 353 353 } 354 354 355 355 sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); 356 356 if (!sec->name) { 357 - WARN_ELF("elf_strptr"); 357 + ERROR_ELF("elf_strptr"); 358 358 return -1; 359 359 } 360 360 361 361 if (sec->sh.sh_size != 0 && !is_dwarf_section(sec)) { 362 362 sec->data = elf_getdata(s, NULL); 363 363 if (!sec->data) { 364 - WARN_ELF("elf_getdata"); 364 + ERROR_ELF("elf_getdata"); 365 365 return -1; 366 366 } 367 367 if (sec->data->d_off != 0 || 368 368 sec->data->d_size != sec->sh.sh_size) { 369 - WARN("unexpected data attributes for %s", 370 - sec->name); 369 + ERROR("unexpected data attributes for %s", sec->name); 371 370 return -1; 372 371 } 373 372 } ··· 386 387 387 388 /* sanity check, one more call to elf_nextscn() should return NULL */ 388 389 if (elf_nextscn(elf->elf, s)) { 389 - WARN("section entry mismatch"); 390 + ERROR("section entry mismatch"); 390 391 return -1; 391 392 } 392 393 ··· 466 467 467 468 elf->symbol_data = calloc(symbols_nr, sizeof(*sym)); 468 469 if (!elf->symbol_data) { 469 - perror("calloc"); 470 + ERROR_GLIBC("calloc"); 470 471 return -1; 471 472 } 472 473 for (i = 0; i < symbols_nr; i++) { ··· 476 477 477 478 if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym, 478 479 &shndx)) { 479 - WARN_ELF("gelf_getsymshndx"); 480 + ERROR_ELF("gelf_getsymshndx"); 480 481 goto err; 481 482 } 482 483 483 484 sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, 484 485 sym->sym.st_name); 485 486 if (!sym->name) { 486 - WARN_ELF("elf_strptr"); 487 + ERROR_ELF("elf_strptr"); 487 488 goto err; 488 489 } 489 490 ··· 495 496 496 497 sym->sec = find_section_by_index(elf, shndx); 497 498 if (!sym->sec) { 498 - WARN("couldn't find section for symbol %s", 499 - sym->name); 499 + ERROR("couldn't find section for symbol %s", sym->name); 500 500 goto err; 501 501 } 502 502 if (GELF_ST_TYPE(sym->sym.st_info) == STT_SECTION) { ··· 534 536 pnamelen = coldstr - sym->name; 535 537 pname = strndup(sym->name, pnamelen); 536 538 if (!pname) { 537 - WARN("%s(): failed to allocate memory", 538 - sym->name); 539 + ERROR("%s(): failed to allocate memory", sym->name); 539 540 return -1; 540 541 } 541 542 ··· 542 545 free(pname); 543 546 544 547 if (!pfunc) { 545 - WARN("%s(): can't find parent function", 546 - sym->name); 548 + ERROR("%s(): can't find parent function", sym->name); 547 549 return -1; 548 550 } 549 551 ··· 579 583 { 580 584 struct reloc *reloc; 581 585 582 - for (reloc = sym->relocs; reloc; reloc = reloc->sym_next_reloc) 586 + for (reloc = sym->relocs; reloc; reloc = sym_next_reloc(reloc)) 583 587 set_reloc_sym(elf, reloc, reloc->sym->idx); 584 588 585 589 return 0; ··· 609 613 610 614 s = elf_getscn(elf->elf, symtab->idx); 611 615 if (!s) { 612 - WARN_ELF("elf_getscn"); 616 + ERROR_ELF("elf_getscn"); 613 617 return -1; 614 618 } 615 619 616 620 if (symtab_shndx) { 617 621 t = elf_getscn(elf->elf, symtab_shndx->idx); 618 622 if (!t) { 619 - WARN_ELF("elf_getscn"); 623 + ERROR_ELF("elf_getscn"); 620 624 return -1; 621 625 } 622 626 } ··· 639 643 640 644 if (idx) { 641 645 /* we don't do holes in symbol tables */ 642 - WARN("index out of range"); 646 + ERROR("index out of range"); 643 647 return -1; 644 648 } 645 649 ··· 650 654 651 655 buf = calloc(num, entsize); 652 656 if (!buf) { 653 - WARN("malloc"); 657 + ERROR_GLIBC("calloc"); 654 658 return -1; 655 659 } 656 660 ··· 665 669 if (t) { 666 670 buf = calloc(num, sizeof(Elf32_Word)); 667 671 if (!buf) { 668 - WARN("malloc"); 672 + ERROR_GLIBC("calloc"); 669 673 return -1; 670 674 } 671 675 ··· 683 687 684 688 /* empty blocks should not happen */ 685 689 if (!symtab_data->d_size) { 686 - WARN("zero size data"); 690 + ERROR("zero size data"); 687 691 return -1; 688 692 } 689 693 ··· 698 702 699 703 /* something went side-ways */ 700 704 if (idx < 0) { 701 - WARN("negative index"); 705 + ERROR("negative index"); 702 706 return -1; 703 707 } 704 708 ··· 710 714 } else { 711 715 sym->sym.st_shndx = SHN_XINDEX; 712 716 if (!shndx_data) { 713 - WARN("no .symtab_shndx"); 717 + ERROR("no .symtab_shndx"); 714 718 return -1; 715 719 } 716 720 } 717 721 718 722 if (!gelf_update_symshndx(symtab_data, shndx_data, idx, &sym->sym, shndx)) { 719 - WARN_ELF("gelf_update_symshndx"); 723 + ERROR_ELF("gelf_update_symshndx"); 720 724 return -1; 721 725 } 722 726 ··· 734 738 if (symtab) { 735 739 symtab_shndx = find_section_by_name(elf, ".symtab_shndx"); 736 740 } else { 737 - WARN("no .symtab"); 741 + ERROR("no .symtab"); 738 742 return NULL; 739 743 } 740 744 ··· 756 760 old->idx = new_idx; 757 761 758 762 if (elf_update_symbol(elf, symtab, symtab_shndx, old)) { 759 - WARN("elf_update_symbol move"); 763 + ERROR("elf_update_symbol move"); 760 764 return NULL; 761 765 } 762 766 ··· 774 778 non_local: 775 779 sym->idx = new_idx; 776 780 if (elf_update_symbol(elf, symtab, symtab_shndx, sym)) { 777 - WARN("elf_update_symbol"); 781 + ERROR("elf_update_symbol"); 778 782 return NULL; 779 783 } 780 784 ··· 795 799 struct symbol *sym = calloc(1, sizeof(*sym)); 796 800 797 801 if (!sym) { 798 - perror("malloc"); 802 + ERROR_GLIBC("malloc"); 799 803 return NULL; 800 804 } 801 805 ··· 825 829 char *name = malloc(namelen); 826 830 827 831 if (!sym || !name) { 828 - perror("malloc"); 832 + ERROR_GLIBC("malloc"); 829 833 return NULL; 830 834 } 831 835 ··· 854 858 struct reloc *reloc, empty = { 0 }; 855 859 856 860 if (reloc_idx >= sec_num_entries(rsec)) { 857 - WARN("%s: bad reloc_idx %u for %s with %d relocs", 858 - __func__, reloc_idx, rsec->name, sec_num_entries(rsec)); 861 + ERROR("%s: bad reloc_idx %u for %s with %d relocs", 862 + __func__, reloc_idx, rsec->name, sec_num_entries(rsec)); 859 863 return NULL; 860 864 } 861 865 862 866 reloc = &rsec->relocs[reloc_idx]; 863 867 864 868 if (memcmp(reloc, &empty, sizeof(empty))) { 865 - WARN("%s: %s: reloc %d already initialized!", 866 - __func__, rsec->name, reloc_idx); 869 + ERROR("%s: %s: reloc %d already initialized!", 870 + __func__, rsec->name, reloc_idx); 867 871 return NULL; 868 872 } 869 873 ··· 876 880 set_reloc_addend(elf, reloc, addend); 877 881 878 882 elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc)); 879 - reloc->sym_next_reloc = sym->relocs; 883 + set_sym_next_reloc(reloc, sym->relocs); 880 884 sym->relocs = reloc; 881 885 882 886 return reloc; ··· 892 896 int addend = insn_off; 893 897 894 898 if (!(insn_sec->sh.sh_flags & SHF_EXECINSTR)) { 895 - WARN("bad call to %s() for data symbol %s", 896 - __func__, sym->name); 899 + ERROR("bad call to %s() for data symbol %s", __func__, sym->name); 897 900 return NULL; 898 901 } 899 902 ··· 921 926 s64 addend) 922 927 { 923 928 if (sym->sec && (sec->sh.sh_flags & SHF_EXECINSTR)) { 924 - WARN("bad call to %s() for text symbol %s", 925 - __func__, sym->name); 929 + ERROR("bad call to %s() for text symbol %s", __func__, sym->name); 926 930 return NULL; 927 931 } 928 932 ··· 947 953 948 954 rsec->base = find_section_by_index(elf, rsec->sh.sh_info); 949 955 if (!rsec->base) { 950 - WARN("can't find base section for reloc section %s", 951 - rsec->name); 956 + ERROR("can't find base section for reloc section %s", rsec->name); 952 957 return -1; 953 958 } 954 959 ··· 956 963 nr_reloc = 0; 957 964 rsec->relocs = calloc(sec_num_entries(rsec), sizeof(*reloc)); 958 965 if (!rsec->relocs) { 959 - perror("calloc"); 966 + ERROR_GLIBC("calloc"); 960 967 return -1; 961 968 } 962 969 for (i = 0; i < sec_num_entries(rsec); i++) { ··· 966 973 symndx = reloc_sym(reloc); 967 974 reloc->sym = sym = find_symbol_by_index(elf, symndx); 968 975 if (!reloc->sym) { 969 - WARN("can't find reloc entry symbol %d for %s", 970 - symndx, rsec->name); 976 + ERROR("can't find reloc entry symbol %d for %s", symndx, rsec->name); 971 977 return -1; 972 978 } 973 979 974 980 elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc)); 975 - reloc->sym_next_reloc = sym->relocs; 981 + set_sym_next_reloc(reloc, sym->relocs); 976 982 sym->relocs = reloc; 977 983 978 984 nr_reloc++; ··· 997 1005 998 1006 elf = malloc(sizeof(*elf)); 999 1007 if (!elf) { 1000 - perror("malloc"); 1008 + ERROR_GLIBC("malloc"); 1001 1009 return NULL; 1002 1010 } 1003 1011 memset(elf, 0, sizeof(*elf)); ··· 1020 1028 1021 1029 elf->elf = elf_begin(elf->fd, cmd, NULL); 1022 1030 if (!elf->elf) { 1023 - WARN_ELF("elf_begin"); 1031 + ERROR_ELF("elf_begin"); 1024 1032 goto err; 1025 1033 } 1026 1034 1027 1035 if (!gelf_getehdr(elf->elf, &elf->ehdr)) { 1028 - WARN_ELF("gelf_getehdr"); 1036 + ERROR_ELF("gelf_getehdr"); 1029 1037 goto err; 1030 1038 } 1031 1039 ··· 1054 1062 if (!strtab) 1055 1063 strtab = find_section_by_name(elf, ".strtab"); 1056 1064 if (!strtab) { 1057 - WARN("can't find .strtab section"); 1065 + ERROR("can't find .strtab section"); 1058 1066 return -1; 1059 1067 } 1060 1068 1061 1069 s = elf_getscn(elf->elf, strtab->idx); 1062 1070 if (!s) { 1063 - WARN_ELF("elf_getscn"); 1071 + ERROR_ELF("elf_getscn"); 1064 1072 return -1; 1065 1073 } 1066 1074 1067 1075 data = elf_newdata(s); 1068 1076 if (!data) { 1069 - WARN_ELF("elf_newdata"); 1077 + ERROR_ELF("elf_newdata"); 1070 1078 return -1; 1071 1079 } 1072 1080 ··· 1091 1099 1092 1100 sec = malloc(sizeof(*sec)); 1093 1101 if (!sec) { 1094 - perror("malloc"); 1102 + ERROR_GLIBC("malloc"); 1095 1103 return NULL; 1096 1104 } 1097 1105 memset(sec, 0, sizeof(*sec)); ··· 1100 1108 1101 1109 s = elf_newscn(elf->elf); 1102 1110 if (!s) { 1103 - WARN_ELF("elf_newscn"); 1111 + ERROR_ELF("elf_newscn"); 1104 1112 return NULL; 1105 1113 } 1106 1114 1107 1115 sec->name = strdup(name); 1108 1116 if (!sec->name) { 1109 - perror("strdup"); 1117 + ERROR_GLIBC("strdup"); 1110 1118 return NULL; 1111 1119 } 1112 1120 ··· 1114 1122 1115 1123 sec->data = elf_newdata(s); 1116 1124 if (!sec->data) { 1117 - WARN_ELF("elf_newdata"); 1125 + ERROR_ELF("elf_newdata"); 1118 1126 return NULL; 1119 1127 } 1120 1128 ··· 1124 1132 if (size) { 1125 1133 sec->data->d_buf = malloc(size); 1126 1134 if (!sec->data->d_buf) { 1127 - perror("malloc"); 1135 + ERROR_GLIBC("malloc"); 1128 1136 return NULL; 1129 1137 } 1130 1138 memset(sec->data->d_buf, 0, size); 1131 1139 } 1132 1140 1133 1141 if (!gelf_getshdr(s, &sec->sh)) { 1134 - WARN_ELF("gelf_getshdr"); 1142 + ERROR_ELF("gelf_getshdr"); 1135 1143 return NULL; 1136 1144 } 1137 1145 ··· 1146 1154 if (!shstrtab) 1147 1155 shstrtab = find_section_by_name(elf, ".strtab"); 1148 1156 if (!shstrtab) { 1149 - WARN("can't find .shstrtab or .strtab section"); 1157 + ERROR("can't find .shstrtab or .strtab section"); 1150 1158 return NULL; 1151 1159 } 1152 1160 sec->sh.sh_name = elf_add_string(elf, shstrtab, sec->name); ··· 1171 1179 1172 1180 rsec_name = malloc(strlen(sec->name) + strlen(".rela") + 1); 1173 1181 if (!rsec_name) { 1174 - perror("malloc"); 1182 + ERROR_GLIBC("malloc"); 1175 1183 return NULL; 1176 1184 } 1177 1185 strcpy(rsec_name, ".rela"); ··· 1191 1199 1192 1200 rsec->relocs = calloc(sec_num_entries(rsec), sizeof(struct reloc)); 1193 1201 if (!rsec->relocs) { 1194 - perror("calloc"); 1202 + ERROR_GLIBC("calloc"); 1195 1203 return NULL; 1196 1204 } 1197 1205 ··· 1224 1232 Elf_Data *data = sec->data; 1225 1233 1226 1234 if (data->d_type != ELF_T_BYTE || data->d_off) { 1227 - WARN("write to unexpected data for section: %s", sec->name); 1235 + ERROR("write to unexpected data for section: %s", sec->name); 1228 1236 return -1; 1229 1237 } 1230 1238 ··· 1253 1261 1254 1262 s = elf_getscn(elf->elf, sec->idx); 1255 1263 if (!s) { 1256 - WARN_ELF("elf_getscn"); 1264 + ERROR_ELF("elf_getscn"); 1257 1265 return -1; 1258 1266 } 1259 1267 ··· 1263 1271 1264 1272 if (!data) { 1265 1273 if (size) { 1266 - WARN("end of section data but non-zero size left\n"); 1274 + ERROR("end of section data but non-zero size left\n"); 1267 1275 return -1; 1268 1276 } 1269 1277 return 0; ··· 1271 1279 1272 1280 if (truncated) { 1273 1281 /* when we remove symbols */ 1274 - WARN("truncated; but more data\n"); 1282 + ERROR("truncated; but more data\n"); 1275 1283 return -1; 1276 1284 } 1277 1285 1278 1286 if (!data->d_size) { 1279 - WARN("zero size data"); 1287 + ERROR("zero size data"); 1280 1288 return -1; 1281 1289 } 1282 1290 ··· 1302 1310 if (sec_changed(sec)) { 1303 1311 s = elf_getscn(elf->elf, sec->idx); 1304 1312 if (!s) { 1305 - WARN_ELF("elf_getscn"); 1313 + ERROR_ELF("elf_getscn"); 1306 1314 return -1; 1307 1315 } 1308 1316 1309 1317 /* Note this also flags the section dirty */ 1310 1318 if (!gelf_update_shdr(s, &sec->sh)) { 1311 - WARN_ELF("gelf_update_shdr"); 1319 + ERROR_ELF("gelf_update_shdr"); 1312 1320 return -1; 1313 1321 } 1314 1322 ··· 1321 1329 1322 1330 /* Write all changes to the file. */ 1323 1331 if (elf_update(elf->elf, ELF_C_WRITE) < 0) { 1324 - WARN_ELF("elf_update"); 1332 + ERROR_ELF("elf_update"); 1325 1333 return -1; 1326 1334 } 1327 1335
+4 -2
tools/objtool/include/objtool/builtin.h
··· 43 43 44 44 extern struct opts opts; 45 45 46 - extern int cmd_parse_options(int argc, const char **argv, const char * const usage[]); 46 + int cmd_parse_options(int argc, const char **argv, const char * const usage[]); 47 47 48 - extern int objtool_run(int argc, const char **argv); 48 + int objtool_run(int argc, const char **argv); 49 + 50 + void print_args(void); 49 51 50 52 #endif /* _BUILTIN_H */
+2 -1
tools/objtool/include/objtool/check.h
··· 34 34 * This is shared with the other alt_groups in the same alternative. 35 35 */ 36 36 struct cfi_state **cfi; 37 + 38 + bool ignore; 37 39 }; 38 40 39 41 #define INSN_CHUNK_BITS 8 ··· 56 54 57 55 u32 idx : INSN_CHUNK_BITS, 58 56 dead_end : 1, 59 - ignore : 1, 60 57 ignore_alts : 1, 61 58 hint : 1, 62 59 save : 1,
+28 -2
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; 68 69 u8 embedded_insn : 1; 69 70 u8 local_label : 1; 70 71 u8 frame_pointer : 1; 71 - u8 warnings : 2; 72 + u8 ignore : 1; 72 73 struct list_head pv_target; 73 74 struct reloc *relocs; 74 75 }; ··· 78 77 struct elf_hash_node hash; 79 78 struct section *sec; 80 79 struct symbol *sym; 81 - struct reloc *sym_next_reloc; 80 + unsigned long _sym_next_reloc; 82 81 }; 83 82 84 83 struct elf { ··· 296 295 __set_reloc_field(reloc, r_info, info); 297 296 298 297 mark_sec_changed(elf, reloc->sec, true); 298 + } 299 + 300 + #define RELOC_JUMP_TABLE_BIT 1UL 301 + 302 + /* Does reloc mark the beginning of a jump table? */ 303 + static inline bool is_jump_table(struct reloc *reloc) 304 + { 305 + return reloc->_sym_next_reloc & RELOC_JUMP_TABLE_BIT; 306 + } 307 + 308 + static inline void set_jump_table(struct reloc *reloc) 309 + { 310 + reloc->_sym_next_reloc |= RELOC_JUMP_TABLE_BIT; 311 + } 312 + 313 + static inline struct reloc *sym_next_reloc(struct reloc *reloc) 314 + { 315 + return (struct reloc *)(reloc->_sym_next_reloc & ~RELOC_JUMP_TABLE_BIT); 316 + } 317 + 318 + static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next) 319 + { 320 + unsigned long bit = reloc->_sym_next_reloc & RELOC_JUMP_TABLE_BIT; 321 + 322 + reloc->_sym_next_reloc = (unsigned long)next | bit; 299 323 } 300 324 301 325 #define for_each_sec(file, sec) \
+1 -1
tools/objtool/include/objtool/objtool.h
··· 41 41 42 42 struct objtool_file *objtool_open_read(const char *_objname); 43 43 44 - void objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func); 44 + int objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func); 45 45 46 46 int check(struct objtool_file *file); 47 47 int orc_dump(const char *objname);
+1 -3
tools/objtool/include/objtool/special.h
··· 16 16 struct list_head list; 17 17 18 18 bool group; 19 - bool skip_orig; 20 - bool skip_alt; 21 19 bool jump_or_nop; 22 20 u8 key_addend; 23 21 ··· 30 32 31 33 int special_get_alts(struct elf *elf, struct list_head *alts); 32 34 33 - void arch_handle_alternative(unsigned short feature, struct special_alt *alt); 35 + void arch_handle_alternative(struct special_alt *alt); 34 36 35 37 bool arch_support_alt_relocation(struct special_alt *special_alt, 36 38 struct instruction *insn,
+39 -23
tools/objtool/include/objtool/warn.h
··· 11 11 #include <sys/types.h> 12 12 #include <sys/stat.h> 13 13 #include <fcntl.h> 14 + #include <errno.h> 14 15 #include <objtool/builtin.h> 15 16 #include <objtool/elf.h> 16 17 ··· 42 41 return str; 43 42 } 44 43 45 - #define WARN(format, ...) \ 46 - fprintf(stderr, \ 47 - "%s: %s: objtool: " format "\n", \ 48 - objname, \ 49 - opts.werror ? "error" : "warning", \ 44 + #define ___WARN(severity, extra, format, ...) \ 45 + fprintf(stderr, \ 46 + "%s%s%s: objtool" extra ": " format "\n", \ 47 + objname ?: "", \ 48 + objname ? ": " : "", \ 49 + severity, \ 50 50 ##__VA_ARGS__) 51 51 52 - #define WARN_FUNC(format, sec, offset, ...) \ 53 - ({ \ 54 - char *_str = offstr(sec, offset); \ 55 - WARN("%s: " format, _str, ##__VA_ARGS__); \ 56 - free(_str); \ 52 + #define __WARN(severity, format, ...) \ 53 + ___WARN(severity, "", format, ##__VA_ARGS__) 54 + 55 + #define __WARN_LINE(severity, format, ...) \ 56 + ___WARN(severity, " [%s:%d]", format, __FILE__, __LINE__, ##__VA_ARGS__) 57 + 58 + #define __WARN_ELF(severity, format, ...) \ 59 + __WARN_LINE(severity, "%s: " format " failed: %s", __func__, ##__VA_ARGS__, elf_errmsg(-1)) 60 + 61 + #define __WARN_GLIBC(severity, format, ...) \ 62 + __WARN_LINE(severity, "%s: " format " failed: %s", __func__, ##__VA_ARGS__, strerror(errno)) 63 + 64 + #define __WARN_FUNC(severity, sec, offset, format, ...) \ 65 + ({ \ 66 + char *_str = offstr(sec, offset); \ 67 + __WARN(severity, "%s: " format, _str, ##__VA_ARGS__); \ 68 + free(_str); \ 57 69 }) 58 70 59 - #define WARN_LIMIT 2 71 + #define WARN_STR (opts.werror ? "error" : "warning") 72 + 73 + #define WARN(format, ...) __WARN(WARN_STR, format, ##__VA_ARGS__) 74 + #define WARN_FUNC(sec, offset, format, ...) __WARN_FUNC(WARN_STR, sec, offset, format, ##__VA_ARGS__) 60 75 61 76 #define WARN_INSN(insn, format, ...) \ 62 77 ({ \ 63 78 struct instruction *_insn = (insn); \ 64 - BUILD_BUG_ON(WARN_LIMIT > 2); \ 65 - if (!_insn->sym || _insn->sym->warnings < WARN_LIMIT) { \ 66 - WARN_FUNC(format, _insn->sec, _insn->offset, \ 79 + if (!_insn->sym || !_insn->sym->warned) \ 80 + WARN_FUNC(_insn->sec, _insn->offset, format, \ 67 81 ##__VA_ARGS__); \ 68 - if (_insn->sym) \ 69 - _insn->sym->warnings++; \ 70 - } else if (_insn->sym && _insn->sym->warnings == WARN_LIMIT) { \ 71 - WARN_FUNC("skipping duplicate warning(s)", \ 72 - _insn->sec, _insn->offset); \ 73 - _insn->sym->warnings++; \ 74 - } \ 82 + if (_insn->sym) \ 83 + _insn->sym->warned = 1; \ 75 84 }) 76 85 77 86 #define BT_INSN(insn, format, ...) \ ··· 94 83 } \ 95 84 }) 96 85 97 - #define WARN_ELF(format, ...) \ 98 - WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) 86 + #define ERROR_STR "error" 87 + 88 + #define ERROR(format, ...) __WARN(ERROR_STR, format, ##__VA_ARGS__) 89 + #define ERROR_ELF(format, ...) __WARN_ELF(ERROR_STR, format, ##__VA_ARGS__) 90 + #define ERROR_GLIBC(format, ...) __WARN_GLIBC(ERROR_STR, format, ##__VA_ARGS__) 91 + #define ERROR_FUNC(sec, offset, format, ...) __WARN_FUNC(ERROR_STR, sec, offset, format, ##__VA_ARGS__) 92 + #define ERROR_INSN(insn, format, ...) WARN_FUNC(insn->sec, insn->offset, format, ##__VA_ARGS__) 99 93 100 94 #endif /* _WARN_H */
+8 -7
tools/objtool/objtool.c
··· 23 23 struct objtool_file *objtool_open_read(const char *filename) 24 24 { 25 25 if (file.elf) { 26 - WARN("won't handle more than one file at a time"); 26 + ERROR("won't handle more than one file at a time"); 27 27 return NULL; 28 28 } 29 29 ··· 44 44 return &file; 45 45 } 46 46 47 - void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func) 47 + int objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func) 48 48 { 49 49 if (!opts.noinstr) 50 - return; 50 + return 0; 51 51 52 52 if (!f->pv_ops) { 53 - WARN("paravirt confusion"); 54 - return; 53 + ERROR("paravirt confusion"); 54 + return -1; 55 55 } 56 56 57 57 /* ··· 60 60 */ 61 61 if (!strcmp(func->name, "_paravirt_nop") || 62 62 !strcmp(func->name, "_paravirt_ident_64")) 63 - return; 63 + return 0; 64 64 65 65 /* already added this function */ 66 66 if (!list_empty(&func->pv_target)) 67 - return; 67 + return 0; 68 68 69 69 list_add(&func->pv_target, &f->pv_ops[idx].targets); 70 70 f->pv_ops[idx].clean = false; 71 + return 0; 71 72 } 72 73 73 74 int main(int argc, const char **argv)
+15 -15
tools/objtool/orc_dump.c
··· 36 36 37 37 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 38 38 if (!elf) { 39 - WARN_ELF("elf_begin"); 39 + ERROR_ELF("elf_begin"); 40 40 return -1; 41 41 } 42 42 43 43 if (!elf64_getehdr(elf)) { 44 - WARN_ELF("elf64_getehdr"); 44 + ERROR_ELF("elf64_getehdr"); 45 45 return -1; 46 46 } 47 47 memcpy(&dummy_elf.ehdr, elf64_getehdr(elf), sizeof(dummy_elf.ehdr)); 48 48 49 49 if (elf_getshdrnum(elf, &nr_sections)) { 50 - WARN_ELF("elf_getshdrnum"); 50 + ERROR_ELF("elf_getshdrnum"); 51 51 return -1; 52 52 } 53 53 54 54 if (elf_getshdrstrndx(elf, &shstrtab_idx)) { 55 - WARN_ELF("elf_getshdrstrndx"); 55 + ERROR_ELF("elf_getshdrstrndx"); 56 56 return -1; 57 57 } 58 58 59 59 for (i = 0; i < nr_sections; i++) { 60 60 scn = elf_getscn(elf, i); 61 61 if (!scn) { 62 - WARN_ELF("elf_getscn"); 62 + ERROR_ELF("elf_getscn"); 63 63 return -1; 64 64 } 65 65 66 66 if (!gelf_getshdr(scn, &sh)) { 67 - WARN_ELF("gelf_getshdr"); 67 + ERROR_ELF("gelf_getshdr"); 68 68 return -1; 69 69 } 70 70 71 71 name = elf_strptr(elf, shstrtab_idx, sh.sh_name); 72 72 if (!name) { 73 - WARN_ELF("elf_strptr"); 73 + ERROR_ELF("elf_strptr"); 74 74 return -1; 75 75 } 76 76 77 77 data = elf_getdata(scn, NULL); 78 78 if (!data) { 79 - WARN_ELF("elf_getdata"); 79 + ERROR_ELF("elf_getdata"); 80 80 return -1; 81 81 } 82 82 ··· 99 99 return 0; 100 100 101 101 if (orc_size % sizeof(*orc) != 0) { 102 - WARN("bad .orc_unwind section size"); 102 + ERROR("bad .orc_unwind section size"); 103 103 return -1; 104 104 } 105 105 ··· 107 107 for (i = 0; i < nr_entries; i++) { 108 108 if (rela_orc_ip) { 109 109 if (!gelf_getrela(rela_orc_ip, i, &rela)) { 110 - WARN_ELF("gelf_getrela"); 110 + ERROR_ELF("gelf_getrela"); 111 111 return -1; 112 112 } 113 113 114 114 if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) { 115 - WARN_ELF("gelf_getsym"); 115 + ERROR_ELF("gelf_getsym"); 116 116 return -1; 117 117 } 118 118 119 119 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) { 120 120 scn = elf_getscn(elf, sym.st_shndx); 121 121 if (!scn) { 122 - WARN_ELF("elf_getscn"); 122 + ERROR_ELF("elf_getscn"); 123 123 return -1; 124 124 } 125 125 126 126 if (!gelf_getshdr(scn, &sh)) { 127 - WARN_ELF("gelf_getshdr"); 127 + ERROR_ELF("gelf_getshdr"); 128 128 return -1; 129 129 } 130 130 131 131 name = elf_strptr(elf, shstrtab_idx, sh.sh_name); 132 132 if (!name) { 133 - WARN_ELF("elf_strptr"); 133 + ERROR_ELF("elf_strptr"); 134 134 return -1; 135 135 } 136 136 } else { 137 137 name = elf_strptr(elf, strtab_idx, sym.st_name); 138 138 if (!name) { 139 - WARN_ELF("elf_strptr"); 139 + ERROR_ELF("elf_strptr"); 140 140 return -1; 141 141 } 142 142 }
+7 -18
tools/objtool/special.c
··· 54 54 {}, 55 55 }; 56 56 57 - void __weak arch_handle_alternative(unsigned short feature, struct special_alt *alt) 57 + void __weak arch_handle_alternative(struct special_alt *alt) 58 58 { 59 59 } 60 60 ··· 86 86 87 87 orig_reloc = find_reloc_by_dest(elf, sec, offset + entry->orig); 88 88 if (!orig_reloc) { 89 - WARN_FUNC("can't find orig reloc", sec, offset + entry->orig); 89 + ERROR_FUNC(sec, offset + entry->orig, "can't find orig reloc"); 90 90 return -1; 91 91 } 92 92 93 93 reloc_to_sec_off(orig_reloc, &alt->orig_sec, &alt->orig_off); 94 94 95 - if (entry->feature) { 96 - unsigned short feature; 97 - 98 - feature = bswap_if_needed(elf, 99 - *(unsigned short *)(sec->data->d_buf + 100 - offset + 101 - entry->feature)); 102 - arch_handle_alternative(feature, alt); 103 - } 95 + arch_handle_alternative(alt); 104 96 105 97 if (!entry->group || alt->new_len) { 106 98 new_reloc = find_reloc_by_dest(elf, sec, offset + entry->new); 107 99 if (!new_reloc) { 108 - WARN_FUNC("can't find new reloc", 109 - sec, offset + entry->new); 100 + ERROR_FUNC(sec, offset + entry->new, "can't find new reloc"); 110 101 return -1; 111 102 } 112 103 ··· 113 122 114 123 key_reloc = find_reloc_by_dest(elf, sec, offset + entry->key); 115 124 if (!key_reloc) { 116 - WARN_FUNC("can't find key reloc", 117 - sec, offset + entry->key); 125 + ERROR_FUNC(sec, offset + entry->key, "can't find key reloc"); 118 126 return -1; 119 127 } 120 128 alt->key_addend = reloc_addend(key_reloc); ··· 143 153 continue; 144 154 145 155 if (sec->sh.sh_size % entry->size != 0) { 146 - WARN("%s size not a multiple of %d", 147 - sec->name, entry->size); 156 + ERROR("%s size not a multiple of %d", sec->name, entry->size); 148 157 return -1; 149 158 } 150 159 ··· 152 163 for (idx = 0; idx < nr_entries; idx++) { 153 164 alt = malloc(sizeof(*alt)); 154 165 if (!alt) { 155 - WARN("malloc failed"); 166 + ERROR_GLIBC("malloc failed"); 156 167 return -1; 157 168 } 158 169 memset(alt, 0, sizeof(*alt));