mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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
 
 Signed-off-by: Ingo Molnar <mingo@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmfsRJMRHG1pbmdvQGtl
 cm5lbC5vcmcACgkQEnMQ0APhK1g0YRAApiCylIv+0ucdKiDVAiI+cU7dqAggFp9h
 ULcTuuCtVkfjYzIBw6y1Iw9JeYsyngYaI0VEMmLasJPt8o93K0vwBXGArXJKoMeu
 UPcVS8N6+LqrHsWBXk919t1wgBZ7csgUxsCa1K47NKa3eCijrqI0N8PtcoYqKd+M
 tOuyEcTCTfS0E2STv6Gpdp6VfDKms3Cn4MffLbcNWJXAsd1dwzDIG8IvAHUW9yG3
 /ezVjm46thneNrRd9j/qU3mqNmhsec9NemHG7URaTznRKleWULhpmhGmcPYCh4Rj
 AqGjmPtqprPELtgezeV+LIcmIm5UWF/f+0tzzBrsRy1MiY8ED2w+J51DHsLoHg8t
 IfIkPyYX/zu9StXoRIwx/7C5NQqBlUfXGp6TuOOwzgbKOt+uRJOU6SnSQ06ZDwsa
 l2brQ+NDfvF7EvGnvi18wIM+iqMc2jSuWl0AT94ATDuAZGCyzlmwluIYmDuLfyZM
 JuYOogojt5vgHXDN6Ro3rDfK+tYckwez+Txx4oByGB3IJy75osBihtvHiYno7FgW
 KXDbiAfLZ4SlfPzqxI6PPzaj3py6hG9LICEiL0U8VecC7bZ/22BZQCpdKko+/E/Y
 PwlqCatqz/25U7GlsnfBISJO2VAyyUcbymvjnVXzZCi+IPAfeih6WcsTPJ96jxsa
 LULLCnuvmoY=
 =KkiI
 -----END PGP SIGNATURE-----
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()
  ...
			
			
This commit is contained in:
		
						commit
						92b71befc3
					
				
					 39 changed files with 679 additions and 650 deletions
				
			
		| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
#include <asm/asm.h>
 | 
					#include <asm/asm.h>
 | 
				
			||||||
#include <asm/ptrace.h>
 | 
					#include <asm/ptrace.h>
 | 
				
			||||||
#include <asm/loongarch.h>
 | 
					#include <asm/loongarch.h>
 | 
				
			||||||
 | 
					#include <asm/unwind_hints.h>
 | 
				
			||||||
#include <linux/stringify.h>
 | 
					#include <linux/stringify.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum stack_type {
 | 
					enum stack_type {
 | 
				
			||||||
| 
						 | 
					@ -43,6 +44,7 @@ int get_stack_info(unsigned long stack, struct task_struct *task, struct stack_i
 | 
				
			||||||
static __always_inline void prepare_frametrace(struct pt_regs *regs)
 | 
					static __always_inline void prepare_frametrace(struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__asm__ __volatile__(
 | 
						__asm__ __volatile__(
 | 
				
			||||||
 | 
							UNWIND_HINT_SAVE
 | 
				
			||||||
		/* Save $ra */
 | 
							/* Save $ra */
 | 
				
			||||||
		STORE_ONE_REG(1)
 | 
							STORE_ONE_REG(1)
 | 
				
			||||||
		/* Use $ra to save PC */
 | 
							/* Use $ra to save PC */
 | 
				
			||||||
| 
						 | 
					@ -80,6 +82,7 @@ static __always_inline void prepare_frametrace(struct pt_regs *regs)
 | 
				
			||||||
		STORE_ONE_REG(29)
 | 
							STORE_ONE_REG(29)
 | 
				
			||||||
		STORE_ONE_REG(30)
 | 
							STORE_ONE_REG(30)
 | 
				
			||||||
		STORE_ONE_REG(31)
 | 
							STORE_ONE_REG(31)
 | 
				
			||||||
 | 
							UNWIND_HINT_RESTORE
 | 
				
			||||||
		: "=m" (regs->csr_era)
 | 
							: "=m" (regs->csr_era)
 | 
				
			||||||
		: "r" (regs->regs)
 | 
							: "r" (regs->regs)
 | 
				
			||||||
		: "memory");
 | 
							: "memory");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,14 @@
 | 
				
			||||||
	UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_CALL
 | 
						UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_CALL
 | 
				
			||||||
.endm
 | 
					.endm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __ASSEMBLY__ */
 | 
					#else /* !__ASSEMBLY__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define UNWIND_HINT_SAVE \
 | 
				
			||||||
 | 
						UNWIND_HINT(UNWIND_HINT_TYPE_SAVE, 0, 0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define UNWIND_HINT_RESTORE \
 | 
				
			||||||
 | 
						UNWIND_HINT(UNWIND_HINT_TYPE_RESTORE, 0, 0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__ASSEMBLY__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ASM_LOONGARCH_UNWIND_HINTS_H */
 | 
					#endif /* _ASM_LOONGARCH_UNWIND_HINTS_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,7 +16,8 @@ static __always_inline unsigned int __arch_hweight32(unsigned int w)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int res;
 | 
						unsigned int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	asm_inline (ALTERNATIVE("call __sw_hweight32",
 | 
						asm_inline (ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE
 | 
				
			||||||
 | 
									"call __sw_hweight32",
 | 
				
			||||||
				"popcntl %[val], %[cnt]", X86_FEATURE_POPCNT)
 | 
									"popcntl %[val], %[cnt]", X86_FEATURE_POPCNT)
 | 
				
			||||||
			 : [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT
 | 
								 : [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT
 | 
				
			||||||
			 : [val] REG_IN (w));
 | 
								 : [val] REG_IN (w));
 | 
				
			||||||
| 
						 | 
					@ -45,7 +46,8 @@ static __always_inline unsigned long __arch_hweight64(__u64 w)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long res;
 | 
						unsigned long res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	asm_inline (ALTERNATIVE("call __sw_hweight64",
 | 
						asm_inline (ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE
 | 
				
			||||||
 | 
									"call __sw_hweight64",
 | 
				
			||||||
				"popcntq %[val], %[cnt]", X86_FEATURE_POPCNT)
 | 
									"popcntq %[val], %[cnt]", X86_FEATURE_POPCNT)
 | 
				
			||||||
			 : [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT
 | 
								 : [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT
 | 
				
			||||||
			 : [val] REG_IN (w));
 | 
								 : [val] REG_IN (w));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,23 +16,23 @@
 | 
				
			||||||
#ifdef __ASSEMBLER__
 | 
					#ifdef __ASSEMBLER__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ASM_CLAC \
 | 
					#define ASM_CLAC \
 | 
				
			||||||
	ALTERNATIVE "", "clac", X86_FEATURE_SMAP
 | 
						ALTERNATIVE __stringify(ANNOTATE_IGNORE_ALTERNATIVE), "clac", X86_FEATURE_SMAP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ASM_STAC \
 | 
					#define ASM_STAC \
 | 
				
			||||||
	ALTERNATIVE "", "stac", X86_FEATURE_SMAP
 | 
						ALTERNATIVE __stringify(ANNOTATE_IGNORE_ALTERNATIVE), "stac", X86_FEATURE_SMAP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else /* __ASSEMBLER__ */
 | 
					#else /* __ASSEMBLER__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __always_inline void clac(void)
 | 
					static __always_inline void clac(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Note: a barrier is implicit in alternative() */
 | 
						/* Note: a barrier is implicit in alternative() */
 | 
				
			||||||
	alternative("", "clac", X86_FEATURE_SMAP);
 | 
						alternative(ANNOTATE_IGNORE_ALTERNATIVE "", "clac", X86_FEATURE_SMAP);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __always_inline void stac(void)
 | 
					static __always_inline void stac(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Note: a barrier is implicit in alternative() */
 | 
						/* Note: a barrier is implicit in alternative() */
 | 
				
			||||||
	alternative("", "stac", X86_FEATURE_SMAP);
 | 
						alternative(ANNOTATE_IGNORE_ALTERNATIVE "", "stac", X86_FEATURE_SMAP);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __always_inline unsigned long smap_save(void)
 | 
					static __always_inline unsigned long smap_save(void)
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,8 @@ static __always_inline unsigned long smap_save(void)
 | 
				
			||||||
	unsigned long flags;
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	asm volatile ("# smap_save\n\t"
 | 
						asm volatile ("# smap_save\n\t"
 | 
				
			||||||
		      ALTERNATIVE("", "pushf; pop %0; " "clac" "\n\t",
 | 
							      ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE
 | 
				
			||||||
 | 
									  "", "pushf; pop %0; clac",
 | 
				
			||||||
				  X86_FEATURE_SMAP)
 | 
									  X86_FEATURE_SMAP)
 | 
				
			||||||
		      : "=rm" (flags) : : "memory", "cc");
 | 
							      : "=rm" (flags) : : "memory", "cc");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,16 +51,22 @@ static __always_inline unsigned long smap_save(void)
 | 
				
			||||||
static __always_inline void smap_restore(unsigned long flags)
 | 
					static __always_inline void smap_restore(unsigned long flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	asm volatile ("# smap_restore\n\t"
 | 
						asm volatile ("# smap_restore\n\t"
 | 
				
			||||||
		      ALTERNATIVE("", "push %0; popf\n\t",
 | 
							      ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE
 | 
				
			||||||
 | 
									  "", "push %0; popf",
 | 
				
			||||||
				  X86_FEATURE_SMAP)
 | 
									  X86_FEATURE_SMAP)
 | 
				
			||||||
		      : : "g" (flags) : "memory", "cc");
 | 
							      : : "g" (flags) : "memory", "cc");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* These macros can be used in asm() statements */
 | 
					/* These macros can be used in asm() statements */
 | 
				
			||||||
#define ASM_CLAC \
 | 
					#define ASM_CLAC \
 | 
				
			||||||
	ALTERNATIVE("", "clac", X86_FEATURE_SMAP)
 | 
						ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "", "clac", X86_FEATURE_SMAP)
 | 
				
			||||||
#define ASM_STAC \
 | 
					#define ASM_STAC \
 | 
				
			||||||
	ALTERNATIVE("", "stac", X86_FEATURE_SMAP)
 | 
						ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "", "stac", X86_FEATURE_SMAP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ASM_CLAC_UNSAFE \
 | 
				
			||||||
 | 
						ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "clac", X86_FEATURE_SMAP)
 | 
				
			||||||
 | 
					#define ASM_STAC_UNSAFE \
 | 
				
			||||||
 | 
						ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "stac", X86_FEATURE_SMAP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __ASSEMBLER__ */
 | 
					#endif /* __ASSEMBLER__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -231,14 +231,12 @@ static __always_inline void __xen_stac(void)
 | 
				
			||||||
	 * Suppress objtool seeing the STAC/CLAC and getting confused about it
 | 
						 * Suppress objtool seeing the STAC/CLAC and getting confused about it
 | 
				
			||||||
	 * calling random code with AC=1.
 | 
						 * calling random code with AC=1.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	asm volatile(ANNOTATE_IGNORE_ALTERNATIVE
 | 
						asm volatile(ASM_STAC_UNSAFE ::: "memory", "flags");
 | 
				
			||||||
		     ASM_STAC ::: "memory", "flags");
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __always_inline void __xen_clac(void)
 | 
					static __always_inline void __xen_clac(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	asm volatile(ANNOTATE_IGNORE_ALTERNATIVE
 | 
						asm volatile(ASM_CLAC_UNSAFE ::: "memory", "flags");
 | 
				
			||||||
		     ASM_CLAC ::: "memory", "flags");
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline long
 | 
					static inline long
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -289,7 +289,7 @@ static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
STACK_FRAME_NON_STANDARD(vmw_send_msg);
 | 
					STACK_FRAME_NON_STANDARD_FP(vmw_send_msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1080,8 +1080,8 @@ static ssize_t cyapa_update_fw_store(struct device *dev,
 | 
				
			||||||
	char fw_name[NAME_MAX];
 | 
						char fw_name[NAME_MAX];
 | 
				
			||||||
	int ret, error;
 | 
						int ret, error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (count >= NAME_MAX) {
 | 
						if (!count || count >= NAME_MAX) {
 | 
				
			||||||
		dev_err(dev, "File name too long\n");
 | 
							dev_err(dev, "Bad file name size\n");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2701,8 +2701,11 @@ static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
 | 
				
			||||||
	u8 ratio;
 | 
						u8 ratio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (state->revision == 0x8090) {
 | 
						if (state->revision == 0x8090) {
 | 
				
			||||||
 | 
							u32 internal = dib8000_read32(state, 23) / 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ratio = 4;
 | 
							ratio = 4;
 | 
				
			||||||
		unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
 | 
					
 | 
				
			||||||
 | 
							unit_khz_dds_val = (1<<26) / (internal ?: 1);
 | 
				
			||||||
		if (offset_khz < 0)
 | 
							if (offset_khz < 0)
 | 
				
			||||||
			dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
 | 
								dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,13 @@ static const unsigned long rodata = 0xAA55AA55;
 | 
				
			||||||
/* This is marked __ro_after_init, so it should ultimately be .rodata. */
 | 
					/* This is marked __ro_after_init, so it should ultimately be .rodata. */
 | 
				
			||||||
static unsigned long ro_after_init __ro_after_init = 0x55AA5500;
 | 
					static unsigned long ro_after_init __ro_after_init = 0x55AA5500;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is a pointer to do_nothing() which is initialized at runtime rather
 | 
				
			||||||
 | 
					 * than build time to avoid objtool IBT validation warnings caused by an
 | 
				
			||||||
 | 
					 * inlined unrolled memcpy() in execute_location().
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void __ro_after_init *do_nothing_ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This just returns to the caller. It is designed to be copied into
 | 
					 * This just returns to the caller. It is designed to be copied into
 | 
				
			||||||
 * non-executable memory regions.
 | 
					 * non-executable memory regions.
 | 
				
			||||||
| 
						 | 
					@ -65,13 +72,12 @@ static noinline __nocfi void execute_location(void *dst, bool write)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void (*func)(void);
 | 
						void (*func)(void);
 | 
				
			||||||
	func_desc_t fdesc;
 | 
						func_desc_t fdesc;
 | 
				
			||||||
	void *do_nothing_text = dereference_function_descriptor(do_nothing);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr_info("attempting ok execution at %px\n", do_nothing_text);
 | 
						pr_info("attempting ok execution at %px\n", do_nothing_ptr);
 | 
				
			||||||
	do_nothing();
 | 
						do_nothing();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (write == CODE_WRITE) {
 | 
						if (write == CODE_WRITE) {
 | 
				
			||||||
		memcpy(dst, do_nothing_text, EXEC_SIZE);
 | 
							memcpy(dst, do_nothing_ptr, EXEC_SIZE);
 | 
				
			||||||
		flush_icache_range((unsigned long)dst,
 | 
							flush_icache_range((unsigned long)dst,
 | 
				
			||||||
				   (unsigned long)dst + EXEC_SIZE);
 | 
									   (unsigned long)dst + EXEC_SIZE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -267,6 +273,8 @@ static void lkdtm_ACCESS_NULL(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void __init lkdtm_perms_init(void)
 | 
					void __init lkdtm_perms_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						do_nothing_ptr = dereference_function_descriptor(do_nothing);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make sure we can write to __ro_after_init values during __init */
 | 
						/* Make sure we can write to __ro_after_init values during __init */
 | 
				
			||||||
	ro_after_init |= 0xAA;
 | 
						ro_after_init |= 0xAA;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,7 @@ static int nvmet_ctrl_state_show(struct seq_file *m, void *p)
 | 
				
			||||||
	bool sep = false;
 | 
						bool sep = false;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < 7; i++) {
 | 
						for (i = 0; i < ARRAY_SIZE(csts_state_names); i++) {
 | 
				
			||||||
		int state = BIT(i);
 | 
							int state = BIT(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!(ctrl->csts & state))
 | 
							if (!(ctrl->csts & state))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -270,8 +270,8 @@ static const unsigned int rk817_buck1_4_ramp_table[] = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rk806_set_mode_dcdc(struct regulator_dev *rdev, unsigned int mode)
 | 
					static int rk806_set_mode_dcdc(struct regulator_dev *rdev, unsigned int mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rid = rdev_get_id(rdev);
 | 
						unsigned int rid = rdev_get_id(rdev);
 | 
				
			||||||
	int ctr_bit, reg;
 | 
						unsigned int ctr_bit, reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reg = RK806_POWER_FPWM_EN0 + rid / 8;
 | 
						reg = RK806_POWER_FPWM_EN0 + rid / 8;
 | 
				
			||||||
	ctr_bit = rid % 8;
 | 
						ctr_bit = rid % 8;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -302,7 +302,7 @@ static void amd_set_spi_freq(struct amd_spi *amd_spi, u32 speed_hz)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i, spd7_val, alt_spd;
 | 
						unsigned int i, spd7_val, alt_spd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(amd_spi_freq); i++)
 | 
						for (i = 0; i < ARRAY_SIZE(amd_spi_freq)-1; i++)
 | 
				
			||||||
		if (speed_hz >= amd_spi_freq[i].speed_hz)
 | 
							if (speed_hz >= amd_spi_freq[i].speed_hz)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,12 +10,12 @@ void ct_irq_exit_irqson(void);
 | 
				
			||||||
void ct_nmi_enter(void);
 | 
					void ct_nmi_enter(void);
 | 
				
			||||||
void ct_nmi_exit(void);
 | 
					void ct_nmi_exit(void);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
static inline void ct_irq_enter(void) { }
 | 
					static __always_inline void ct_irq_enter(void) { }
 | 
				
			||||||
static inline void ct_irq_exit(void) { }
 | 
					static __always_inline void ct_irq_exit(void) { }
 | 
				
			||||||
static inline void ct_irq_enter_irqson(void) { }
 | 
					static inline void ct_irq_enter_irqson(void) { }
 | 
				
			||||||
static inline void ct_irq_exit_irqson(void) { }
 | 
					static inline void ct_irq_exit_irqson(void) { }
 | 
				
			||||||
static inline void ct_nmi_enter(void) { }
 | 
					static __always_inline void ct_nmi_enter(void) { }
 | 
				
			||||||
static inline void ct_nmi_exit(void) { }
 | 
					static __always_inline void ct_nmi_exit(void) { }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -134,10 +134,6 @@
 | 
				
			||||||
	.size name, .-name
 | 
						.size name, .-name
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* If symbol 'name' is treated as a subroutine (gets called, and returns)
 | 
					 | 
				
			||||||
 * then please use ENDPROC to mark 'name' as STT_FUNC for the benefit of
 | 
					 | 
				
			||||||
 * static analysis tools such as stack depth analyzer.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#ifndef ENDPROC
 | 
					#ifndef ENDPROC
 | 
				
			||||||
/* deprecated, use SYM_FUNC_END */
 | 
					/* deprecated, use SYM_FUNC_END */
 | 
				
			||||||
#define ENDPROC(name) \
 | 
					#define ENDPROC(name) \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,7 +69,7 @@
 | 
				
			||||||
 * In asm, there are two kinds of code: normal C-type callable functions and
 | 
					 * In asm, there are two kinds of code: normal C-type callable functions and
 | 
				
			||||||
 * the rest.  The normal callable functions can be called by other code, and
 | 
					 * the rest.  The normal callable functions can be called by other code, and
 | 
				
			||||||
 * don't do anything unusual with the stack.  Such normal callable functions
 | 
					 * don't do anything unusual with the stack.  Such normal callable functions
 | 
				
			||||||
 * are annotated with the ENTRY/ENDPROC macros.  Most asm code falls in this
 | 
					 * are annotated with SYM_FUNC_{START,END}.  Most asm code falls in this
 | 
				
			||||||
 * category.  In this case, no special debugging annotations are needed because
 | 
					 * category.  In this case, no special debugging annotations are needed because
 | 
				
			||||||
 * objtool can automatically generate the ORC data for the ORC unwinder to read
 | 
					 * objtool can automatically generate the ORC data for the ORC unwinder to read
 | 
				
			||||||
 * at runtime.
 | 
					 * at runtime.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -132,7 +132,7 @@ static inline void rcu_sysrq_end(void) { }
 | 
				
			||||||
#if defined(CONFIG_NO_HZ_FULL) && (!defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK))
 | 
					#if defined(CONFIG_NO_HZ_FULL) && (!defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK))
 | 
				
			||||||
void rcu_irq_work_resched(void);
 | 
					void rcu_irq_work_resched(void);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
static inline void rcu_irq_work_resched(void) { }
 | 
					static __always_inline void rcu_irq_work_resched(void) { }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_RCU_NOCB_CPU
 | 
					#ifdef CONFIG_RCU_NOCB_CPU
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@ static __always_inline bool sched_smt_active(void)
 | 
				
			||||||
	return static_branch_likely(&sched_smt_present);
 | 
						return static_branch_likely(&sched_smt_present);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
static inline bool sched_smt_active(void) { return false; }
 | 
					static __always_inline bool sched_smt_active(void) { return false; }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void arch_smt_update(void);
 | 
					void arch_smt_update(void);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -833,9 +833,15 @@ device_initcall(register_warn_debugfs);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
__visible noinstr void __stack_chk_fail(void)
 | 
					__visible noinstr void __stack_chk_fail(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	instrumentation_begin();
 | 
						instrumentation_begin();
 | 
				
			||||||
 | 
						flags = user_access_save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	panic("stack-protector: Kernel stack is corrupted in: %pB",
 | 
						panic("stack-protector: Kernel stack is corrupted in: %pB",
 | 
				
			||||||
		__builtin_return_address(0));
 | 
							__builtin_return_address(0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user_access_restore(flags);
 | 
				
			||||||
	instrumentation_end();
 | 
						instrumentation_end();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(__stack_chk_fail);
 | 
					EXPORT_SYMBOL(__stack_chk_fail);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -275,9 +275,9 @@ objtool-args-$(CONFIG_MITIGATION_SLS)			+= --sls
 | 
				
			||||||
objtool-args-$(CONFIG_STACK_VALIDATION)			+= --stackval
 | 
					objtool-args-$(CONFIG_STACK_VALIDATION)			+= --stackval
 | 
				
			||||||
objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE)		+= --static-call
 | 
					objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE)		+= --static-call
 | 
				
			||||||
objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION)		+= --uaccess
 | 
					objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION)		+= --uaccess
 | 
				
			||||||
objtool-args-$(CONFIG_GCOV_KERNEL)			+= --no-unreachable
 | 
					objtool-args-$(or $(CONFIG_GCOV_KERNEL),$(CONFIG_KCOV))	+= --no-unreachable
 | 
				
			||||||
objtool-args-$(CONFIG_PREFIX_SYMBOLS)			+= --prefix=$(CONFIG_FUNCTION_PADDING_BYTES)
 | 
					objtool-args-$(CONFIG_PREFIX_SYMBOLS)			+= --prefix=$(CONFIG_FUNCTION_PADDING_BYTES)
 | 
				
			||||||
objtool-args-$(CONFIG_OBJTOOL_WERROR)			+= --Werror --backtrace
 | 
					objtool-args-$(CONFIG_OBJTOOL_WERROR)			+= --Werror
 | 
				
			||||||
 | 
					
 | 
				
			||||||
objtool-args = $(objtool-args-y)					\
 | 
					objtool-args = $(objtool-args-y)					\
 | 
				
			||||||
	$(if $(delay-objtool), --link)					\
 | 
						$(if $(delay-objtool), --link)					\
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,13 +30,20 @@ endif
 | 
				
			||||||
# objtool for vmlinux.o
 | 
					# objtool for vmlinux.o
 | 
				
			||||||
# ---------------------------------------------------------------------------
 | 
					# ---------------------------------------------------------------------------
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# For LTO and IBT, objtool doesn't run on individual translation units.
 | 
					# For delay-objtool (IBT or LTO), objtool doesn't run on individual translation
 | 
				
			||||||
# Run everything on vmlinux instead.
 | 
					# units.  Instead it runs on vmlinux.o.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# For !delay-objtool + CONFIG_NOINSTR_VALIDATION, it runs on both translation
 | 
				
			||||||
 | 
					# units and vmlinux.o, with the latter only used for noinstr/unret validation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION))
 | 
					objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vmlinux-objtool-args-$(delay-objtool)			+= $(objtool-args-y)
 | 
					ifeq ($(delay-objtool),y)
 | 
				
			||||||
vmlinux-objtool-args-$(CONFIG_GCOV_KERNEL)		+= --no-unreachable
 | 
					vmlinux-objtool-args-y					+= $(objtool-args-y)
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					vmlinux-objtool-args-$(CONFIG_OBJTOOL_WERROR)		+= --Werror
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vmlinux-objtool-args-$(CONFIG_NOINSTR_VALIDATION)	+= --noinstr \
 | 
					vmlinux-objtool-args-$(CONFIG_NOINSTR_VALIDATION)	+= --noinstr \
 | 
				
			||||||
							   $(if $(or $(CONFIG_MITIGATION_UNRET_ENTRY),$(CONFIG_MITIGATION_SRSO)), --unret)
 | 
												   $(if $(or $(CONFIG_MITIGATION_UNRET_ENTRY),$(CONFIG_MITIGATION_SRSO)), --unret)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2263,7 +2263,7 @@ static irqreturn_t wcd934x_slim_irq_handler(int irq, void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct wcd934x_codec *wcd = data;
 | 
						struct wcd934x_codec *wcd = data;
 | 
				
			||||||
	unsigned long status = 0;
 | 
						unsigned long status = 0;
 | 
				
			||||||
	int i, j, port_id;
 | 
						unsigned int i, j, port_id;
 | 
				
			||||||
	unsigned int val, int_val = 0;
 | 
						unsigned int val, int_val = 0;
 | 
				
			||||||
	irqreturn_t ret = IRQ_NONE;
 | 
						irqreturn_t ret = IRQ_NONE;
 | 
				
			||||||
	bool tx;
 | 
						bool tx;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,7 @@ Objtool has the following features:
 | 
				
			||||||
- Return thunk annotation -- annotates all return thunk sites so kernel
 | 
					- Return thunk annotation -- annotates all return thunk sites so kernel
 | 
				
			||||||
  can patch them inline, depending on enabled mitigations
 | 
					  can patch them inline, depending on enabled mitigations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Return thunk training valiation -- validate that all entry paths
 | 
					- Return thunk untraining validation -- validate that all entry paths
 | 
				
			||||||
  untrain a "safe return" before the first return (or call)
 | 
					  untrain a "safe return" before the first return (or call)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Non-instrumentation validation -- validates non-instrumentable
 | 
					- Non-instrumentation validation -- validates non-instrumentable
 | 
				
			||||||
| 
						 | 
					@ -281,8 +281,8 @@ the objtool maintainers.
 | 
				
			||||||
   If the error is for an asm file, and func() is indeed a callable
 | 
					   If the error is for an asm file, and func() is indeed a callable
 | 
				
			||||||
   function, add proper frame pointer logic using the FRAME_BEGIN and
 | 
					   function, add proper frame pointer logic using the FRAME_BEGIN and
 | 
				
			||||||
   FRAME_END macros.  Otherwise, if it's not a callable function, remove
 | 
					   FRAME_END macros.  Otherwise, if it's not a callable function, remove
 | 
				
			||||||
   its ELF function annotation by changing ENDPROC to END, and instead
 | 
					   its ELF function annotation by using SYM_CODE_{START,END} and use the
 | 
				
			||||||
   use the manual unwind hint macros in asm/unwind_hints.h.
 | 
					   manual unwind hint macros in asm/unwind_hints.h.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   If it's a GCC-compiled .c file, the error may be because the function
 | 
					   If it's a GCC-compiled .c file, the error may be because the function
 | 
				
			||||||
   uses an inline asm() statement which has a "call" instruction.  An
 | 
					   uses an inline asm() statement which has a "call" instruction.  An
 | 
				
			||||||
| 
						 | 
					@ -352,7 +352,7 @@ the objtool maintainers.
 | 
				
			||||||
   This is a kernel entry/exit instruction like sysenter or iret.  Such
 | 
					   This is a kernel entry/exit instruction like sysenter or iret.  Such
 | 
				
			||||||
   instructions aren't allowed in a callable function, and are most
 | 
					   instructions aren't allowed in a callable function, and are most
 | 
				
			||||||
   likely part of the kernel entry code.  Such code should probably be
 | 
					   likely part of the kernel entry code.  Such code should probably be
 | 
				
			||||||
   placed in a SYM_FUNC_CODE block with unwind hints.
 | 
					   placed in a SYM_CODE_{START,END} block with unwind hints.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame
 | 
					6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame
 | 
				
			||||||
| 
						 | 
					@ -381,7 +381,7 @@ the objtool maintainers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   Another possibility is that the code has some asm or inline asm which
 | 
					   Another possibility is that the code has some asm or inline asm which
 | 
				
			||||||
   does some unusual things to the stack or the frame pointer.  In such
 | 
					   does some unusual things to the stack or the frame pointer.  In such
 | 
				
			||||||
   cases it's probably appropriate to use SYM_FUNC_CODE with unwind
 | 
					   cases it's probably appropriate to use SYM_CODE_{START,END} with unwind
 | 
				
			||||||
   hints.
 | 
					   hints.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,7 +63,7 @@ static bool is_loongarch(const struct elf *elf)
 | 
				
			||||||
	if (elf->ehdr.e_machine == EM_LOONGARCH)
 | 
						if (elf->ehdr.e_machine == EM_LOONGARCH)
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	WARN("unexpected ELF machine type %d", elf->ehdr.e_machine);
 | 
						ERROR("unexpected ELF machine type %d", elf->ehdr.e_machine);
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -327,8 +327,10 @@ const char *arch_nop_insn(int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static u32 nop;
 | 
						static u32 nop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len != LOONGARCH_INSN_SIZE)
 | 
						if (len != LOONGARCH_INSN_SIZE) {
 | 
				
			||||||
		WARN("invalid NOP size: %d\n", len);
 | 
							ERROR("invalid NOP size: %d\n", len);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nop = LOONGARCH_INSN_NOP;
 | 
						nop = LOONGARCH_INSN_NOP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -339,8 +341,10 @@ const char *arch_ret_insn(int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static u32 ret;
 | 
						static u32 ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len != LOONGARCH_INSN_SIZE)
 | 
						if (len != LOONGARCH_INSN_SIZE) {
 | 
				
			||||||
		WARN("invalid RET size: %d\n", len);
 | 
							ERROR("invalid RET size: %d\n", len);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	emit_jirl((union loongarch_instruction *)&ret, LOONGARCH_GPR_RA, LOONGARCH_GPR_ZERO, 0);
 | 
						emit_jirl((union loongarch_instruction *)&ret, LOONGARCH_GPR_RA, LOONGARCH_GPR_ZERO, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 | 
				
			||||||
		orc->type = ORC_TYPE_REGS_PARTIAL;
 | 
							orc->type = ORC_TYPE_REGS_PARTIAL;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		WARN_INSN(insn, "unknown unwind hint type %d", cfi->type);
 | 
							ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,7 +55,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 | 
				
			||||||
		orc->sp_reg = ORC_REG_FP;
 | 
							orc->sp_reg = ORC_REG_FP;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
 | 
							ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,7 +72,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 | 
				
			||||||
		orc->fp_reg = ORC_REG_FP;
 | 
							orc->fp_reg = ORC_REG_FP;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		WARN_INSN(insn, "unknown FP base reg %d", fp->base);
 | 
							ERROR_INSN(insn, "unknown FP base reg %d", fp->base);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,7 +89,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 | 
				
			||||||
		orc->ra_reg = ORC_REG_FP;
 | 
							orc->ra_reg = ORC_REG_FP;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		WARN_INSN(insn, "unknown RA base reg %d", ra->base);
 | 
							ERROR_INSN(insn, "unknown RA base reg %d", ra->base);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,7 @@ static int is_x86_64(const struct elf *elf)
 | 
				
			||||||
	case EM_386:
 | 
						case EM_386:
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		WARN("unexpected ELF machine type %d", elf->ehdr.e_machine);
 | 
							ERROR("unexpected ELF machine type %d", elf->ehdr.e_machine);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -173,7 +173,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 | 
				
			||||||
	ret = insn_decode(&ins, sec->data->d_buf + offset, maxlen,
 | 
						ret = insn_decode(&ins, sec->data->d_buf + offset, maxlen,
 | 
				
			||||||
			  x86_64 ? INSN_MODE_64 : INSN_MODE_32);
 | 
								  x86_64 ? INSN_MODE_64 : INSN_MODE_32);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		WARN("can't decode instruction at %s:0x%lx", sec->name, offset);
 | 
							ERROR("can't decode instruction at %s:0x%lx", sec->name, offset);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -321,7 +321,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			/* WARN ? */
 | 
								/* ERROR ? */
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -561,8 +561,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 | 
				
			||||||
			if (ins.prefixes.nbytes == 1 &&
 | 
								if (ins.prefixes.nbytes == 1 &&
 | 
				
			||||||
			    ins.prefixes.bytes[0] == 0xf2) {
 | 
								    ins.prefixes.bytes[0] == 0xf2) {
 | 
				
			||||||
				/* ENQCMD cannot be used in the kernel. */
 | 
									/* ENQCMD cannot be used in the kernel. */
 | 
				
			||||||
				WARN("ENQCMD instruction at %s:%lx", sec->name,
 | 
									WARN("ENQCMD instruction at %s:%lx", sec->name, offset);
 | 
				
			||||||
				     offset);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else if (op2 == 0xa0 || op2 == 0xa8) {
 | 
							} else if (op2 == 0xa0 || op2 == 0xa8) {
 | 
				
			||||||
| 
						 | 
					@ -646,7 +645,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 | 
				
			||||||
			if (disp->sym->type == STT_SECTION)
 | 
								if (disp->sym->type == STT_SECTION)
 | 
				
			||||||
				func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp));
 | 
									func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp));
 | 
				
			||||||
			if (!func) {
 | 
								if (!func) {
 | 
				
			||||||
				WARN("no func for pv_ops[]");
 | 
									ERROR("no func for pv_ops[]");
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -776,7 +775,7 @@ const char *arch_nop_insn(int len)
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len < 1 || len > 5) {
 | 
						if (len < 1 || len > 5) {
 | 
				
			||||||
		WARN("invalid NOP size: %d\n", len);
 | 
							ERROR("invalid NOP size: %d\n", len);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -796,7 +795,7 @@ const char *arch_ret_insn(int len)
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len < 1 || len > 5) {
 | 
						if (len < 1 || len > 5) {
 | 
				
			||||||
		WARN("invalid RET size: %d\n", len);
 | 
							ERROR("invalid RET size: %d\n", len);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 | 
				
			||||||
		orc->type = ORC_TYPE_REGS_PARTIAL;
 | 
							orc->type = ORC_TYPE_REGS_PARTIAL;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		WARN_INSN(insn, "unknown unwind hint type %d", cfi->type);
 | 
							ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,7 +72,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 | 
				
			||||||
		orc->sp_reg = ORC_REG_DX;
 | 
							orc->sp_reg = ORC_REG_DX;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
 | 
							ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,7 +87,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 | 
				
			||||||
		orc->bp_reg = ORC_REG_BP;
 | 
							orc->bp_reg = ORC_REG_BP;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		WARN_INSN(insn, "unknown BP base reg %d", bp->base);
 | 
							ERROR_INSN(insn, "unknown BP base reg %d", bp->base);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,11 +3,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <objtool/special.h>
 | 
					#include <objtool/special.h>
 | 
				
			||||||
#include <objtool/builtin.h>
 | 
					#include <objtool/builtin.h>
 | 
				
			||||||
 | 
					#include <objtool/warn.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define X86_FEATURE_POPCNT (4 * 32 + 23)
 | 
					void arch_handle_alternative(struct special_alt *alt)
 | 
				
			||||||
#define X86_FEATURE_SMAP   (9 * 32 + 20)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void arch_handle_alternative(unsigned short feature, struct special_alt *alt)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static struct special_alt *group, *prev;
 | 
						static struct special_alt *group, *prev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,34 +29,6 @@ void arch_handle_alternative(unsigned short feature, struct special_alt *alt)
 | 
				
			||||||
	} else group = alt;
 | 
						} else group = alt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	prev = alt;
 | 
						prev = alt;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (feature) {
 | 
					 | 
				
			||||||
	case X86_FEATURE_SMAP:
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * If UACCESS validation is enabled; force that alternative;
 | 
					 | 
				
			||||||
		 * otherwise force it the other way.
 | 
					 | 
				
			||||||
		 *
 | 
					 | 
				
			||||||
		 * What we want to avoid is having both the original and the
 | 
					 | 
				
			||||||
		 * alternative code flow at the same time, in that case we can
 | 
					 | 
				
			||||||
		 * find paths that see the STAC but take the NOP instead of
 | 
					 | 
				
			||||||
		 * CLAC and the other way around.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (opts.uaccess)
 | 
					 | 
				
			||||||
			alt->skip_orig = true;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			alt->skip_alt = true;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case X86_FEATURE_POPCNT:
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * It has been requested that we don't validate the !POPCNT
 | 
					 | 
				
			||||||
		 * feature path which is a "very very small percentage of
 | 
					 | 
				
			||||||
		 * machines".
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		alt->skip_orig = true;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool arch_support_alt_relocation(struct special_alt *special_alt,
 | 
					bool arch_support_alt_relocation(struct special_alt *special_alt,
 | 
				
			||||||
| 
						 | 
					@ -156,8 +126,10 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,
 | 
				
			||||||
	 * indicates a rare GCC quirk/bug which can leave dead
 | 
						 * indicates a rare GCC quirk/bug which can leave dead
 | 
				
			||||||
	 * code behind.
 | 
						 * code behind.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (reloc_type(text_reloc) == R_X86_64_PC32)
 | 
						if (reloc_type(text_reloc) == R_X86_64_PC32) {
 | 
				
			||||||
 | 
							WARN_INSN(insn, "ignoring unreachables due to jump table quirk");
 | 
				
			||||||
		file->ignore_unreachables = true;
 | 
							file->ignore_unreachables = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*table_size = 0;
 | 
						*table_size = 0;
 | 
				
			||||||
	return rodata_reloc;
 | 
						return rodata_reloc;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,18 +8,18 @@
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
#include <sys/stat.h>
 | 
					#include <sys/stat.h>
 | 
				
			||||||
#include <sys/sendfile.h>
 | 
					#include <sys/sendfile.h>
 | 
				
			||||||
#include <objtool/builtin.h>
 | 
					#include <objtool/builtin.h>
 | 
				
			||||||
#include <objtool/objtool.h>
 | 
					#include <objtool/objtool.h>
 | 
				
			||||||
 | 
					#include <objtool/warn.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ERROR(format, ...)				\
 | 
					#define ORIG_SUFFIX ".orig"
 | 
				
			||||||
	fprintf(stderr,					\
 | 
					 | 
				
			||||||
		"error: objtool: " format "\n",		\
 | 
					 | 
				
			||||||
		##__VA_ARGS__)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int orig_argc;
 | 
				
			||||||
 | 
					static char **orig_argv;
 | 
				
			||||||
const char *objname;
 | 
					const char *objname;
 | 
				
			||||||
 | 
					 | 
				
			||||||
struct opts opts;
 | 
					struct opts opts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char * const check_usage[] = {
 | 
					static const char * const check_usage[] = {
 | 
				
			||||||
| 
						 | 
					@ -194,30 +194,30 @@ static int copy_file(const char *src, const char *dst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	src_fd = open(src, O_RDONLY);
 | 
						src_fd = open(src, O_RDONLY);
 | 
				
			||||||
	if (src_fd == -1) {
 | 
						if (src_fd == -1) {
 | 
				
			||||||
		ERROR("can't open '%s' for reading", src);
 | 
							ERROR("can't open %s for reading: %s", src, strerror(errno));
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0400);
 | 
						dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0400);
 | 
				
			||||||
	if (dst_fd == -1) {
 | 
						if (dst_fd == -1) {
 | 
				
			||||||
		ERROR("can't open '%s' for writing", dst);
 | 
							ERROR("can't open %s for writing: %s", dst, strerror(errno));
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fstat(src_fd, &stat) == -1) {
 | 
						if (fstat(src_fd, &stat) == -1) {
 | 
				
			||||||
		perror("fstat");
 | 
							ERROR_GLIBC("fstat");
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fchmod(dst_fd, stat.st_mode) == -1) {
 | 
						if (fchmod(dst_fd, stat.st_mode) == -1) {
 | 
				
			||||||
		perror("fchmod");
 | 
							ERROR_GLIBC("fchmod");
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (to_copy = stat.st_size; to_copy > 0; to_copy -= copied) {
 | 
						for (to_copy = stat.st_size; to_copy > 0; to_copy -= copied) {
 | 
				
			||||||
		copied = sendfile(dst_fd, src_fd, &offset, to_copy);
 | 
							copied = sendfile(dst_fd, src_fd, &offset, to_copy);
 | 
				
			||||||
		if (copied == -1) {
 | 
							if (copied == -1) {
 | 
				
			||||||
			perror("sendfile");
 | 
								ERROR_GLIBC("sendfile");
 | 
				
			||||||
			return 1;
 | 
								return 1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -227,39 +227,73 @@ static int copy_file(const char *src, const char *dst)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char **save_argv(int argc, const char **argv)
 | 
					static void save_argv(int argc, const char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char **orig_argv;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	orig_argv = calloc(argc, sizeof(char *));
 | 
						orig_argv = calloc(argc, sizeof(char *));
 | 
				
			||||||
	if (!orig_argv) {
 | 
						if (!orig_argv) {
 | 
				
			||||||
		perror("calloc");
 | 
							ERROR_GLIBC("calloc");
 | 
				
			||||||
		return NULL;
 | 
							exit(1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = 0; i < argc; i++) {
 | 
						for (int i = 0; i < argc; i++) {
 | 
				
			||||||
		orig_argv[i] = strdup(argv[i]);
 | 
							orig_argv[i] = strdup(argv[i]);
 | 
				
			||||||
		if (!orig_argv[i]) {
 | 
							if (!orig_argv[i]) {
 | 
				
			||||||
			perror("strdup");
 | 
								ERROR_GLIBC("strdup(%s)", argv[i]);
 | 
				
			||||||
			return NULL;
 | 
								exit(1);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return orig_argv;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ORIG_SUFFIX ".orig"
 | 
					void print_args(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *backup = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (opts.output || opts.dryrun)
 | 
				
			||||||
 | 
							goto print;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Make a backup before kbuild deletes the file so the error
 | 
				
			||||||
 | 
						 * can be recreated without recompiling or relinking.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						backup = malloc(strlen(objname) + strlen(ORIG_SUFFIX) + 1);
 | 
				
			||||||
 | 
						if (!backup) {
 | 
				
			||||||
 | 
							ERROR_GLIBC("malloc");
 | 
				
			||||||
 | 
							goto print;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strcpy(backup, objname);
 | 
				
			||||||
 | 
						strcat(backup, ORIG_SUFFIX);
 | 
				
			||||||
 | 
						if (copy_file(objname, backup)) {
 | 
				
			||||||
 | 
							backup = NULL;
 | 
				
			||||||
 | 
							goto print;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					print:
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Print the cmdline args to make it easier to recreate.  If '--output'
 | 
				
			||||||
 | 
						 * wasn't used, add it to the printed args with the backup as input.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						fprintf(stderr, "%s", orig_argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 1; i < orig_argc; i++) {
 | 
				
			||||||
 | 
							char *arg = orig_argv[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (backup && !strcmp(arg, objname))
 | 
				
			||||||
 | 
								fprintf(stderr, " %s -o %s", backup, objname);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								fprintf(stderr, " %s", arg);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fprintf(stderr, "\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int objtool_run(int argc, const char **argv)
 | 
					int objtool_run(int argc, const char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct objtool_file *file;
 | 
						struct objtool_file *file;
 | 
				
			||||||
	char *backup = NULL;
 | 
					 | 
				
			||||||
	char **orig_argv;
 | 
					 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	orig_argv = save_argv(argc, argv);
 | 
						orig_argc = argc;
 | 
				
			||||||
	if (!orig_argv)
 | 
						save_argv(argc, argv);
 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd_parse_options(argc, argv, check_usage);
 | 
						cmd_parse_options(argc, argv, check_usage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -282,59 +316,19 @@ int objtool_run(int argc, const char **argv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	file = objtool_open_read(objname);
 | 
						file = objtool_open_read(objname);
 | 
				
			||||||
	if (!file)
 | 
						if (!file)
 | 
				
			||||||
		goto err;
 | 
							return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!opts.link && has_multiple_files(file->elf)) {
 | 
						if (!opts.link && has_multiple_files(file->elf)) {
 | 
				
			||||||
		ERROR("Linked object requires --link");
 | 
							ERROR("Linked object requires --link");
 | 
				
			||||||
		goto err;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = check(file);
 | 
						ret = check(file);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto err;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!opts.dryrun && file->elf->changed && elf_write(file->elf))
 | 
						if (!opts.dryrun && file->elf->changed && elf_write(file->elf))
 | 
				
			||||||
		goto err;
 | 
							return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
err:
 | 
					 | 
				
			||||||
	if (opts.dryrun)
 | 
					 | 
				
			||||||
		goto err_msg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (opts.output) {
 | 
					 | 
				
			||||||
		unlink(opts.output);
 | 
					 | 
				
			||||||
		goto err_msg;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Make a backup before kbuild deletes the file so the error
 | 
					 | 
				
			||||||
	 * can be recreated without recompiling or relinking.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	backup = malloc(strlen(objname) + strlen(ORIG_SUFFIX) + 1);
 | 
					 | 
				
			||||||
	if (!backup) {
 | 
					 | 
				
			||||||
		perror("malloc");
 | 
					 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	strcpy(backup, objname);
 | 
					 | 
				
			||||||
	strcat(backup, ORIG_SUFFIX);
 | 
					 | 
				
			||||||
	if (copy_file(objname, backup))
 | 
					 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
err_msg:
 | 
					 | 
				
			||||||
	fprintf(stderr, "%s", orig_argv[0]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (int i = 1; i < argc; i++) {
 | 
					 | 
				
			||||||
		char *arg = orig_argv[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (backup && !strcmp(arg, objname))
 | 
					 | 
				
			||||||
			fprintf(stderr, " %s -o %s", backup, objname);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			fprintf(stderr, " %s", arg);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fprintf(stderr, "\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -79,7 +79,7 @@ static inline void __elf_hash_del(struct elf_hash_node *node,
 | 
				
			||||||
				 PROT_READ|PROT_WRITE,			\
 | 
									 PROT_READ|PROT_WRITE,			\
 | 
				
			||||||
				 MAP_PRIVATE|MAP_ANON, -1, 0);		\
 | 
									 MAP_PRIVATE|MAP_ANON, -1, 0);		\
 | 
				
			||||||
	if (__elf_table(name) == (void *)-1L) {				\
 | 
						if (__elf_table(name) == (void *)-1L) {				\
 | 
				
			||||||
		WARN("mmap fail " #name); \
 | 
							ERROR_GLIBC("mmap fail " #name);			\
 | 
				
			||||||
		__elf_table(name) = NULL;				\
 | 
							__elf_table(name) = NULL;				\
 | 
				
			||||||
	}								\
 | 
						}								\
 | 
				
			||||||
	__elf_table(name);						\
 | 
						__elf_table(name);						\
 | 
				
			||||||
| 
						 | 
					@ -316,12 +316,12 @@ static int read_sections(struct elf *elf)
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (elf_getshdrnum(elf->elf, §ions_nr)) {
 | 
						if (elf_getshdrnum(elf->elf, §ions_nr)) {
 | 
				
			||||||
		WARN_ELF("elf_getshdrnum");
 | 
							ERROR_ELF("elf_getshdrnum");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (elf_getshdrstrndx(elf->elf, &shstrndx)) {
 | 
						if (elf_getshdrstrndx(elf->elf, &shstrndx)) {
 | 
				
			||||||
		WARN_ELF("elf_getshdrstrndx");
 | 
							ERROR_ELF("elf_getshdrstrndx");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -331,7 +331,7 @@ static int read_sections(struct elf *elf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elf->section_data = calloc(sections_nr, sizeof(*sec));
 | 
						elf->section_data = calloc(sections_nr, sizeof(*sec));
 | 
				
			||||||
	if (!elf->section_data) {
 | 
						if (!elf->section_data) {
 | 
				
			||||||
		perror("calloc");
 | 
							ERROR_GLIBC("calloc");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (i = 0; i < sections_nr; i++) {
 | 
						for (i = 0; i < sections_nr; i++) {
 | 
				
			||||||
| 
						 | 
					@ -341,33 +341,32 @@ static int read_sections(struct elf *elf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		s = elf_getscn(elf->elf, i);
 | 
							s = elf_getscn(elf->elf, i);
 | 
				
			||||||
		if (!s) {
 | 
							if (!s) {
 | 
				
			||||||
			WARN_ELF("elf_getscn");
 | 
								ERROR_ELF("elf_getscn");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sec->idx = elf_ndxscn(s);
 | 
							sec->idx = elf_ndxscn(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!gelf_getshdr(s, &sec->sh)) {
 | 
							if (!gelf_getshdr(s, &sec->sh)) {
 | 
				
			||||||
			WARN_ELF("gelf_getshdr");
 | 
								ERROR_ELF("gelf_getshdr");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name);
 | 
							sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name);
 | 
				
			||||||
		if (!sec->name) {
 | 
							if (!sec->name) {
 | 
				
			||||||
			WARN_ELF("elf_strptr");
 | 
								ERROR_ELF("elf_strptr");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (sec->sh.sh_size != 0 && !is_dwarf_section(sec)) {
 | 
							if (sec->sh.sh_size != 0 && !is_dwarf_section(sec)) {
 | 
				
			||||||
			sec->data = elf_getdata(s, NULL);
 | 
								sec->data = elf_getdata(s, NULL);
 | 
				
			||||||
			if (!sec->data) {
 | 
								if (!sec->data) {
 | 
				
			||||||
				WARN_ELF("elf_getdata");
 | 
									ERROR_ELF("elf_getdata");
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (sec->data->d_off != 0 ||
 | 
								if (sec->data->d_off != 0 ||
 | 
				
			||||||
			    sec->data->d_size != sec->sh.sh_size) {
 | 
								    sec->data->d_size != sec->sh.sh_size) {
 | 
				
			||||||
				WARN("unexpected data attributes for %s",
 | 
									ERROR("unexpected data attributes for %s", sec->name);
 | 
				
			||||||
				     sec->name);
 | 
					 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -387,7 +386,7 @@ static int read_sections(struct elf *elf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* sanity check, one more call to elf_nextscn() should return NULL */
 | 
						/* sanity check, one more call to elf_nextscn() should return NULL */
 | 
				
			||||||
	if (elf_nextscn(elf->elf, s)) {
 | 
						if (elf_nextscn(elf->elf, s)) {
 | 
				
			||||||
		WARN("section entry mismatch");
 | 
							ERROR("section entry mismatch");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -467,7 +466,7 @@ static int read_symbols(struct elf *elf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elf->symbol_data = calloc(symbols_nr, sizeof(*sym));
 | 
						elf->symbol_data = calloc(symbols_nr, sizeof(*sym));
 | 
				
			||||||
	if (!elf->symbol_data) {
 | 
						if (!elf->symbol_data) {
 | 
				
			||||||
		perror("calloc");
 | 
							ERROR_GLIBC("calloc");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (i = 0; i < symbols_nr; i++) {
 | 
						for (i = 0; i < symbols_nr; i++) {
 | 
				
			||||||
| 
						 | 
					@ -477,14 +476,14 @@ static int read_symbols(struct elf *elf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
 | 
							if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
 | 
				
			||||||
				      &shndx)) {
 | 
									      &shndx)) {
 | 
				
			||||||
			WARN_ELF("gelf_getsymshndx");
 | 
								ERROR_ELF("gelf_getsymshndx");
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sym->name = elf_strptr(elf->elf, symtab->sh.sh_link,
 | 
							sym->name = elf_strptr(elf->elf, symtab->sh.sh_link,
 | 
				
			||||||
				       sym->sym.st_name);
 | 
									       sym->sym.st_name);
 | 
				
			||||||
		if (!sym->name) {
 | 
							if (!sym->name) {
 | 
				
			||||||
			WARN_ELF("elf_strptr");
 | 
								ERROR_ELF("elf_strptr");
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -496,8 +495,7 @@ static int read_symbols(struct elf *elf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			sym->sec = find_section_by_index(elf, shndx);
 | 
								sym->sec = find_section_by_index(elf, shndx);
 | 
				
			||||||
			if (!sym->sec) {
 | 
								if (!sym->sec) {
 | 
				
			||||||
				WARN("couldn't find section for symbol %s",
 | 
									ERROR("couldn't find section for symbol %s", sym->name);
 | 
				
			||||||
				     sym->name);
 | 
					 | 
				
			||||||
				goto err;
 | 
									goto err;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (GELF_ST_TYPE(sym->sym.st_info) == STT_SECTION) {
 | 
								if (GELF_ST_TYPE(sym->sym.st_info) == STT_SECTION) {
 | 
				
			||||||
| 
						 | 
					@ -536,8 +534,7 @@ static int read_symbols(struct elf *elf)
 | 
				
			||||||
			pnamelen = coldstr - sym->name;
 | 
								pnamelen = coldstr - sym->name;
 | 
				
			||||||
			pname = strndup(sym->name, pnamelen);
 | 
								pname = strndup(sym->name, pnamelen);
 | 
				
			||||||
			if (!pname) {
 | 
								if (!pname) {
 | 
				
			||||||
				WARN("%s(): failed to allocate memory",
 | 
									ERROR("%s(): failed to allocate memory", sym->name);
 | 
				
			||||||
				     sym->name);
 | 
					 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -545,8 +542,7 @@ static int read_symbols(struct elf *elf)
 | 
				
			||||||
			free(pname);
 | 
								free(pname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!pfunc) {
 | 
								if (!pfunc) {
 | 
				
			||||||
				WARN("%s(): can't find parent function",
 | 
									ERROR("%s(): can't find parent function", sym->name);
 | 
				
			||||||
				     sym->name);
 | 
					 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -583,7 +579,7 @@ static int elf_update_sym_relocs(struct elf *elf, struct symbol *sym)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct reloc *reloc;
 | 
						struct reloc *reloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (reloc = sym->relocs; reloc; reloc = reloc->sym_next_reloc)
 | 
						for (reloc = sym->relocs; reloc; reloc = sym_next_reloc(reloc))
 | 
				
			||||||
		set_reloc_sym(elf, reloc, reloc->sym->idx);
 | 
							set_reloc_sym(elf, reloc, reloc->sym->idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -613,14 +609,14 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s = elf_getscn(elf->elf, symtab->idx);
 | 
						s = elf_getscn(elf->elf, symtab->idx);
 | 
				
			||||||
	if (!s) {
 | 
						if (!s) {
 | 
				
			||||||
		WARN_ELF("elf_getscn");
 | 
							ERROR_ELF("elf_getscn");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (symtab_shndx) {
 | 
						if (symtab_shndx) {
 | 
				
			||||||
		t = elf_getscn(elf->elf, symtab_shndx->idx);
 | 
							t = elf_getscn(elf->elf, symtab_shndx->idx);
 | 
				
			||||||
		if (!t) {
 | 
							if (!t) {
 | 
				
			||||||
			WARN_ELF("elf_getscn");
 | 
								ERROR_ELF("elf_getscn");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -643,7 +639,7 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (idx) {
 | 
								if (idx) {
 | 
				
			||||||
				/* we don't do holes in symbol tables */
 | 
									/* we don't do holes in symbol tables */
 | 
				
			||||||
				WARN("index out of range");
 | 
									ERROR("index out of range");
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -654,7 +650,7 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			buf = calloc(num, entsize);
 | 
								buf = calloc(num, entsize);
 | 
				
			||||||
			if (!buf) {
 | 
								if (!buf) {
 | 
				
			||||||
				WARN("malloc");
 | 
									ERROR_GLIBC("calloc");
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -669,7 +665,7 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,
 | 
				
			||||||
			if (t) {
 | 
								if (t) {
 | 
				
			||||||
				buf = calloc(num, sizeof(Elf32_Word));
 | 
									buf = calloc(num, sizeof(Elf32_Word));
 | 
				
			||||||
				if (!buf) {
 | 
									if (!buf) {
 | 
				
			||||||
					WARN("malloc");
 | 
										ERROR_GLIBC("calloc");
 | 
				
			||||||
					return -1;
 | 
										return -1;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -687,7 +683,7 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* empty blocks should not happen */
 | 
							/* empty blocks should not happen */
 | 
				
			||||||
		if (!symtab_data->d_size) {
 | 
							if (!symtab_data->d_size) {
 | 
				
			||||||
			WARN("zero size data");
 | 
								ERROR("zero size data");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -702,7 +698,7 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* something went side-ways */
 | 
						/* something went side-ways */
 | 
				
			||||||
	if (idx < 0) {
 | 
						if (idx < 0) {
 | 
				
			||||||
		WARN("negative index");
 | 
							ERROR("negative index");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -714,13 +710,13 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		sym->sym.st_shndx = SHN_XINDEX;
 | 
							sym->sym.st_shndx = SHN_XINDEX;
 | 
				
			||||||
		if (!shndx_data) {
 | 
							if (!shndx_data) {
 | 
				
			||||||
			WARN("no .symtab_shndx");
 | 
								ERROR("no .symtab_shndx");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!gelf_update_symshndx(symtab_data, shndx_data, idx, &sym->sym, shndx)) {
 | 
						if (!gelf_update_symshndx(symtab_data, shndx_data, idx, &sym->sym, shndx)) {
 | 
				
			||||||
		WARN_ELF("gelf_update_symshndx");
 | 
							ERROR_ELF("gelf_update_symshndx");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -738,7 +734,7 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym)
 | 
				
			||||||
	if (symtab) {
 | 
						if (symtab) {
 | 
				
			||||||
		symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
 | 
							symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		WARN("no .symtab");
 | 
							ERROR("no .symtab");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -760,7 +756,7 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym)
 | 
				
			||||||
		old->idx = new_idx;
 | 
							old->idx = new_idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (elf_update_symbol(elf, symtab, symtab_shndx, old)) {
 | 
							if (elf_update_symbol(elf, symtab, symtab_shndx, old)) {
 | 
				
			||||||
			WARN("elf_update_symbol move");
 | 
								ERROR("elf_update_symbol move");
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -778,7 +774,7 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym)
 | 
				
			||||||
non_local:
 | 
					non_local:
 | 
				
			||||||
	sym->idx = new_idx;
 | 
						sym->idx = new_idx;
 | 
				
			||||||
	if (elf_update_symbol(elf, symtab, symtab_shndx, sym)) {
 | 
						if (elf_update_symbol(elf, symtab, symtab_shndx, sym)) {
 | 
				
			||||||
		WARN("elf_update_symbol");
 | 
							ERROR("elf_update_symbol");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -799,7 +795,7 @@ elf_create_section_symbol(struct elf *elf, struct section *sec)
 | 
				
			||||||
	struct symbol *sym = calloc(1, sizeof(*sym));
 | 
						struct symbol *sym = calloc(1, sizeof(*sym));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!sym) {
 | 
						if (!sym) {
 | 
				
			||||||
		perror("malloc");
 | 
							ERROR_GLIBC("malloc");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -829,7 +825,7 @@ elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size)
 | 
				
			||||||
	char *name = malloc(namelen);
 | 
						char *name = malloc(namelen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!sym || !name) {
 | 
						if (!sym || !name) {
 | 
				
			||||||
		perror("malloc");
 | 
							ERROR_GLIBC("malloc");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -858,7 +854,7 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
 | 
				
			||||||
	struct reloc *reloc, empty = { 0 };
 | 
						struct reloc *reloc, empty = { 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (reloc_idx >= sec_num_entries(rsec)) {
 | 
						if (reloc_idx >= sec_num_entries(rsec)) {
 | 
				
			||||||
		WARN("%s: bad reloc_idx %u for %s with %d relocs",
 | 
							ERROR("%s: bad reloc_idx %u for %s with %d relocs",
 | 
				
			||||||
		      __func__, reloc_idx, rsec->name, sec_num_entries(rsec));
 | 
							      __func__, reloc_idx, rsec->name, sec_num_entries(rsec));
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -866,7 +862,7 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
 | 
				
			||||||
	reloc = &rsec->relocs[reloc_idx];
 | 
						reloc = &rsec->relocs[reloc_idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (memcmp(reloc, &empty, sizeof(empty))) {
 | 
						if (memcmp(reloc, &empty, sizeof(empty))) {
 | 
				
			||||||
		WARN("%s: %s: reloc %d already initialized!",
 | 
							ERROR("%s: %s: reloc %d already initialized!",
 | 
				
			||||||
		      __func__, rsec->name, reloc_idx);
 | 
							      __func__, rsec->name, reloc_idx);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -880,7 +876,7 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
 | 
				
			||||||
	set_reloc_addend(elf, reloc, addend);
 | 
						set_reloc_addend(elf, reloc, addend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
 | 
						elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
 | 
				
			||||||
	reloc->sym_next_reloc = sym->relocs;
 | 
						set_sym_next_reloc(reloc, sym->relocs);
 | 
				
			||||||
	sym->relocs = reloc;
 | 
						sym->relocs = reloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return reloc;
 | 
						return reloc;
 | 
				
			||||||
| 
						 | 
					@ -896,8 +892,7 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
 | 
				
			||||||
	int addend = insn_off;
 | 
						int addend = insn_off;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(insn_sec->sh.sh_flags & SHF_EXECINSTR)) {
 | 
						if (!(insn_sec->sh.sh_flags & SHF_EXECINSTR)) {
 | 
				
			||||||
		WARN("bad call to %s() for data symbol %s",
 | 
							ERROR("bad call to %s() for data symbol %s", __func__, sym->name);
 | 
				
			||||||
		     __func__, sym->name);
 | 
					 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -926,8 +921,7 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
 | 
				
			||||||
				      s64 addend)
 | 
									      s64 addend)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (sym->sec && (sec->sh.sh_flags & SHF_EXECINSTR)) {
 | 
						if (sym->sec && (sec->sh.sh_flags & SHF_EXECINSTR)) {
 | 
				
			||||||
		WARN("bad call to %s() for text symbol %s",
 | 
							ERROR("bad call to %s() for text symbol %s", __func__, sym->name);
 | 
				
			||||||
		     __func__, sym->name);
 | 
					 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -953,8 +947,7 @@ static int read_relocs(struct elf *elf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rsec->base = find_section_by_index(elf, rsec->sh.sh_info);
 | 
							rsec->base = find_section_by_index(elf, rsec->sh.sh_info);
 | 
				
			||||||
		if (!rsec->base) {
 | 
							if (!rsec->base) {
 | 
				
			||||||
			WARN("can't find base section for reloc section %s",
 | 
								ERROR("can't find base section for reloc section %s", rsec->name);
 | 
				
			||||||
			     rsec->name);
 | 
					 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -963,7 +956,7 @@ static int read_relocs(struct elf *elf)
 | 
				
			||||||
		nr_reloc = 0;
 | 
							nr_reloc = 0;
 | 
				
			||||||
		rsec->relocs = calloc(sec_num_entries(rsec), sizeof(*reloc));
 | 
							rsec->relocs = calloc(sec_num_entries(rsec), sizeof(*reloc));
 | 
				
			||||||
		if (!rsec->relocs) {
 | 
							if (!rsec->relocs) {
 | 
				
			||||||
			perror("calloc");
 | 
								ERROR_GLIBC("calloc");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for (i = 0; i < sec_num_entries(rsec); i++) {
 | 
							for (i = 0; i < sec_num_entries(rsec); i++) {
 | 
				
			||||||
| 
						 | 
					@ -973,13 +966,12 @@ static int read_relocs(struct elf *elf)
 | 
				
			||||||
			symndx = reloc_sym(reloc);
 | 
								symndx = reloc_sym(reloc);
 | 
				
			||||||
			reloc->sym = sym = find_symbol_by_index(elf, symndx);
 | 
								reloc->sym = sym = find_symbol_by_index(elf, symndx);
 | 
				
			||||||
			if (!reloc->sym) {
 | 
								if (!reloc->sym) {
 | 
				
			||||||
				WARN("can't find reloc entry symbol %d for %s",
 | 
									ERROR("can't find reloc entry symbol %d for %s", symndx, rsec->name);
 | 
				
			||||||
				     symndx, rsec->name);
 | 
					 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
 | 
								elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
 | 
				
			||||||
			reloc->sym_next_reloc = sym->relocs;
 | 
								set_sym_next_reloc(reloc, sym->relocs);
 | 
				
			||||||
			sym->relocs = reloc;
 | 
								sym->relocs = reloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			nr_reloc++;
 | 
								nr_reloc++;
 | 
				
			||||||
| 
						 | 
					@ -1005,7 +997,7 @@ struct elf *elf_open_read(const char *name, int flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elf = malloc(sizeof(*elf));
 | 
						elf = malloc(sizeof(*elf));
 | 
				
			||||||
	if (!elf) {
 | 
						if (!elf) {
 | 
				
			||||||
		perror("malloc");
 | 
							ERROR_GLIBC("malloc");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	memset(elf, 0, sizeof(*elf));
 | 
						memset(elf, 0, sizeof(*elf));
 | 
				
			||||||
| 
						 | 
					@ -1028,12 +1020,12 @@ struct elf *elf_open_read(const char *name, int flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elf->elf = elf_begin(elf->fd, cmd, NULL);
 | 
						elf->elf = elf_begin(elf->fd, cmd, NULL);
 | 
				
			||||||
	if (!elf->elf) {
 | 
						if (!elf->elf) {
 | 
				
			||||||
		WARN_ELF("elf_begin");
 | 
							ERROR_ELF("elf_begin");
 | 
				
			||||||
		goto err;
 | 
							goto err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!gelf_getehdr(elf->elf, &elf->ehdr)) {
 | 
						if (!gelf_getehdr(elf->elf, &elf->ehdr)) {
 | 
				
			||||||
		WARN_ELF("gelf_getehdr");
 | 
							ERROR_ELF("gelf_getehdr");
 | 
				
			||||||
		goto err;
 | 
							goto err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1062,19 +1054,19 @@ static int elf_add_string(struct elf *elf, struct section *strtab, char *str)
 | 
				
			||||||
	if (!strtab)
 | 
						if (!strtab)
 | 
				
			||||||
		strtab = find_section_by_name(elf, ".strtab");
 | 
							strtab = find_section_by_name(elf, ".strtab");
 | 
				
			||||||
	if (!strtab) {
 | 
						if (!strtab) {
 | 
				
			||||||
		WARN("can't find .strtab section");
 | 
							ERROR("can't find .strtab section");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s = elf_getscn(elf->elf, strtab->idx);
 | 
						s = elf_getscn(elf->elf, strtab->idx);
 | 
				
			||||||
	if (!s) {
 | 
						if (!s) {
 | 
				
			||||||
		WARN_ELF("elf_getscn");
 | 
							ERROR_ELF("elf_getscn");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data = elf_newdata(s);
 | 
						data = elf_newdata(s);
 | 
				
			||||||
	if (!data) {
 | 
						if (!data) {
 | 
				
			||||||
		WARN_ELF("elf_newdata");
 | 
							ERROR_ELF("elf_newdata");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1099,7 +1091,7 @@ struct section *elf_create_section(struct elf *elf, const char *name,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec = malloc(sizeof(*sec));
 | 
						sec = malloc(sizeof(*sec));
 | 
				
			||||||
	if (!sec) {
 | 
						if (!sec) {
 | 
				
			||||||
		perror("malloc");
 | 
							ERROR_GLIBC("malloc");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	memset(sec, 0, sizeof(*sec));
 | 
						memset(sec, 0, sizeof(*sec));
 | 
				
			||||||
| 
						 | 
					@ -1108,13 +1100,13 @@ struct section *elf_create_section(struct elf *elf, const char *name,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s = elf_newscn(elf->elf);
 | 
						s = elf_newscn(elf->elf);
 | 
				
			||||||
	if (!s) {
 | 
						if (!s) {
 | 
				
			||||||
		WARN_ELF("elf_newscn");
 | 
							ERROR_ELF("elf_newscn");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec->name = strdup(name);
 | 
						sec->name = strdup(name);
 | 
				
			||||||
	if (!sec->name) {
 | 
						if (!sec->name) {
 | 
				
			||||||
		perror("strdup");
 | 
							ERROR_GLIBC("strdup");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1122,7 +1114,7 @@ struct section *elf_create_section(struct elf *elf, const char *name,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec->data = elf_newdata(s);
 | 
						sec->data = elf_newdata(s);
 | 
				
			||||||
	if (!sec->data) {
 | 
						if (!sec->data) {
 | 
				
			||||||
		WARN_ELF("elf_newdata");
 | 
							ERROR_ELF("elf_newdata");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1132,14 +1124,14 @@ struct section *elf_create_section(struct elf *elf, const char *name,
 | 
				
			||||||
	if (size) {
 | 
						if (size) {
 | 
				
			||||||
		sec->data->d_buf = malloc(size);
 | 
							sec->data->d_buf = malloc(size);
 | 
				
			||||||
		if (!sec->data->d_buf) {
 | 
							if (!sec->data->d_buf) {
 | 
				
			||||||
			perror("malloc");
 | 
								ERROR_GLIBC("malloc");
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		memset(sec->data->d_buf, 0, size);
 | 
							memset(sec->data->d_buf, 0, size);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!gelf_getshdr(s, &sec->sh)) {
 | 
						if (!gelf_getshdr(s, &sec->sh)) {
 | 
				
			||||||
		WARN_ELF("gelf_getshdr");
 | 
							ERROR_ELF("gelf_getshdr");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1154,7 +1146,7 @@ struct section *elf_create_section(struct elf *elf, const char *name,
 | 
				
			||||||
	if (!shstrtab)
 | 
						if (!shstrtab)
 | 
				
			||||||
		shstrtab = find_section_by_name(elf, ".strtab");
 | 
							shstrtab = find_section_by_name(elf, ".strtab");
 | 
				
			||||||
	if (!shstrtab) {
 | 
						if (!shstrtab) {
 | 
				
			||||||
		WARN("can't find .shstrtab or .strtab section");
 | 
							ERROR("can't find .shstrtab or .strtab section");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sec->sh.sh_name = elf_add_string(elf, shstrtab, sec->name);
 | 
						sec->sh.sh_name = elf_add_string(elf, shstrtab, sec->name);
 | 
				
			||||||
| 
						 | 
					@ -1179,7 +1171,7 @@ static struct section *elf_create_rela_section(struct elf *elf,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rsec_name = malloc(strlen(sec->name) + strlen(".rela") + 1);
 | 
						rsec_name = malloc(strlen(sec->name) + strlen(".rela") + 1);
 | 
				
			||||||
	if (!rsec_name) {
 | 
						if (!rsec_name) {
 | 
				
			||||||
		perror("malloc");
 | 
							ERROR_GLIBC("malloc");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	strcpy(rsec_name, ".rela");
 | 
						strcpy(rsec_name, ".rela");
 | 
				
			||||||
| 
						 | 
					@ -1199,7 +1191,7 @@ static struct section *elf_create_rela_section(struct elf *elf,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rsec->relocs = calloc(sec_num_entries(rsec), sizeof(struct reloc));
 | 
						rsec->relocs = calloc(sec_num_entries(rsec), sizeof(struct reloc));
 | 
				
			||||||
	if (!rsec->relocs) {
 | 
						if (!rsec->relocs) {
 | 
				
			||||||
		perror("calloc");
 | 
							ERROR_GLIBC("calloc");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1232,7 +1224,7 @@ int elf_write_insn(struct elf *elf, struct section *sec,
 | 
				
			||||||
	Elf_Data *data = sec->data;
 | 
						Elf_Data *data = sec->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data->d_type != ELF_T_BYTE || data->d_off) {
 | 
						if (data->d_type != ELF_T_BYTE || data->d_off) {
 | 
				
			||||||
		WARN("write to unexpected data for section: %s", sec->name);
 | 
							ERROR("write to unexpected data for section: %s", sec->name);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1261,7 +1253,7 @@ static int elf_truncate_section(struct elf *elf, struct section *sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s = elf_getscn(elf->elf, sec->idx);
 | 
						s = elf_getscn(elf->elf, sec->idx);
 | 
				
			||||||
	if (!s) {
 | 
						if (!s) {
 | 
				
			||||||
		WARN_ELF("elf_getscn");
 | 
							ERROR_ELF("elf_getscn");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1271,7 +1263,7 @@ static int elf_truncate_section(struct elf *elf, struct section *sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!data) {
 | 
							if (!data) {
 | 
				
			||||||
			if (size) {
 | 
								if (size) {
 | 
				
			||||||
				WARN("end of section data but non-zero size left\n");
 | 
									ERROR("end of section data but non-zero size left\n");
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
| 
						 | 
					@ -1279,12 +1271,12 @@ static int elf_truncate_section(struct elf *elf, struct section *sec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (truncated) {
 | 
							if (truncated) {
 | 
				
			||||||
			/* when we remove symbols */
 | 
								/* when we remove symbols */
 | 
				
			||||||
			WARN("truncated; but more data\n");
 | 
								ERROR("truncated; but more data\n");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!data->d_size) {
 | 
							if (!data->d_size) {
 | 
				
			||||||
			WARN("zero size data");
 | 
								ERROR("zero size data");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1310,13 +1302,13 @@ int elf_write(struct elf *elf)
 | 
				
			||||||
		if (sec_changed(sec)) {
 | 
							if (sec_changed(sec)) {
 | 
				
			||||||
			s = elf_getscn(elf->elf, sec->idx);
 | 
								s = elf_getscn(elf->elf, sec->idx);
 | 
				
			||||||
			if (!s) {
 | 
								if (!s) {
 | 
				
			||||||
				WARN_ELF("elf_getscn");
 | 
									ERROR_ELF("elf_getscn");
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Note this also flags the section dirty */
 | 
								/* Note this also flags the section dirty */
 | 
				
			||||||
			if (!gelf_update_shdr(s, &sec->sh)) {
 | 
								if (!gelf_update_shdr(s, &sec->sh)) {
 | 
				
			||||||
				WARN_ELF("gelf_update_shdr");
 | 
									ERROR_ELF("gelf_update_shdr");
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1329,7 +1321,7 @@ int elf_write(struct elf *elf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Write all changes to the file. */
 | 
						/* Write all changes to the file. */
 | 
				
			||||||
	if (elf_update(elf->elf, ELF_C_WRITE) < 0) {
 | 
						if (elf_update(elf->elf, ELF_C_WRITE) < 0) {
 | 
				
			||||||
		WARN_ELF("elf_update");
 | 
							ERROR_ELF("elf_update");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,8 +43,10 @@ struct opts {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct opts opts;
 | 
					extern struct opts opts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int cmd_parse_options(int argc, const char **argv, const char * const usage[]);
 | 
					int cmd_parse_options(int argc, const char **argv, const char * const usage[]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int objtool_run(int argc, const char **argv);
 | 
					int objtool_run(int argc, const char **argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void print_args(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _BUILTIN_H */
 | 
					#endif /* _BUILTIN_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,8 @@ struct alt_group {
 | 
				
			||||||
	 * This is shared with the other alt_groups in the same alternative.
 | 
						 * This is shared with the other alt_groups in the same alternative.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct cfi_state **cfi;
 | 
						struct cfi_state **cfi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool ignore;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define INSN_CHUNK_BITS		8
 | 
					#define INSN_CHUNK_BITS		8
 | 
				
			||||||
| 
						 | 
					@ -54,7 +56,6 @@ struct instruction {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u32 idx			: INSN_CHUNK_BITS,
 | 
						u32 idx			: INSN_CHUNK_BITS,
 | 
				
			||||||
	    dead_end		: 1,
 | 
						    dead_end		: 1,
 | 
				
			||||||
	    ignore		: 1,
 | 
					 | 
				
			||||||
	    ignore_alts		: 1,
 | 
						    ignore_alts		: 1,
 | 
				
			||||||
	    hint		: 1,
 | 
						    hint		: 1,
 | 
				
			||||||
	    save		: 1,
 | 
						    save		: 1,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,10 +65,11 @@ struct symbol {
 | 
				
			||||||
	u8 return_thunk      : 1;
 | 
						u8 return_thunk      : 1;
 | 
				
			||||||
	u8 fentry            : 1;
 | 
						u8 fentry            : 1;
 | 
				
			||||||
	u8 profiling_func    : 1;
 | 
						u8 profiling_func    : 1;
 | 
				
			||||||
 | 
						u8 warned	     : 1;
 | 
				
			||||||
	u8 embedded_insn     : 1;
 | 
						u8 embedded_insn     : 1;
 | 
				
			||||||
	u8 local_label       : 1;
 | 
						u8 local_label       : 1;
 | 
				
			||||||
	u8 frame_pointer     : 1;
 | 
						u8 frame_pointer     : 1;
 | 
				
			||||||
	u8 warnings	     : 2;
 | 
						u8 ignore	     : 1;
 | 
				
			||||||
	struct list_head pv_target;
 | 
						struct list_head pv_target;
 | 
				
			||||||
	struct reloc *relocs;
 | 
						struct reloc *relocs;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -77,7 +78,7 @@ struct reloc {
 | 
				
			||||||
	struct elf_hash_node hash;
 | 
						struct elf_hash_node hash;
 | 
				
			||||||
	struct section *sec;
 | 
						struct section *sec;
 | 
				
			||||||
	struct symbol *sym;
 | 
						struct symbol *sym;
 | 
				
			||||||
	struct reloc *sym_next_reloc;
 | 
						unsigned long _sym_next_reloc;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct elf {
 | 
					struct elf {
 | 
				
			||||||
| 
						 | 
					@ -297,6 +298,31 @@ static inline void set_reloc_type(struct elf *elf, struct reloc *reloc, unsigned
 | 
				
			||||||
	mark_sec_changed(elf, reloc->sec, true);
 | 
						mark_sec_changed(elf, reloc->sec, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RELOC_JUMP_TABLE_BIT 1UL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Does reloc mark the beginning of a jump table? */
 | 
				
			||||||
 | 
					static inline bool is_jump_table(struct reloc *reloc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return reloc->_sym_next_reloc & RELOC_JUMP_TABLE_BIT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void set_jump_table(struct reloc *reloc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						reloc->_sym_next_reloc |= RELOC_JUMP_TABLE_BIT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct reloc *sym_next_reloc(struct reloc *reloc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (struct reloc *)(reloc->_sym_next_reloc & ~RELOC_JUMP_TABLE_BIT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long bit = reloc->_sym_next_reloc & RELOC_JUMP_TABLE_BIT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reloc->_sym_next_reloc = (unsigned long)next | bit;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define for_each_sec(file, sec)						\
 | 
					#define for_each_sec(file, sec)						\
 | 
				
			||||||
	list_for_each_entry(sec, &file->elf->sections, list)
 | 
						list_for_each_entry(sec, &file->elf->sections, list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@ struct objtool_file {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct objtool_file *objtool_open_read(const char *_objname);
 | 
					struct objtool_file *objtool_open_read(const char *_objname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func);
 | 
					int objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int check(struct objtool_file *file);
 | 
					int check(struct objtool_file *file);
 | 
				
			||||||
int orc_dump(const char *objname);
 | 
					int orc_dump(const char *objname);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,8 +16,6 @@ struct special_alt {
 | 
				
			||||||
	struct list_head list;
 | 
						struct list_head list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool group;
 | 
						bool group;
 | 
				
			||||||
	bool skip_orig;
 | 
					 | 
				
			||||||
	bool skip_alt;
 | 
					 | 
				
			||||||
	bool jump_or_nop;
 | 
						bool jump_or_nop;
 | 
				
			||||||
	u8 key_addend;
 | 
						u8 key_addend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,7 +30,7 @@ struct special_alt {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int special_get_alts(struct elf *elf, struct list_head *alts);
 | 
					int special_get_alts(struct elf *elf, struct list_head *alts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void arch_handle_alternative(unsigned short feature, struct special_alt *alt);
 | 
					void arch_handle_alternative(struct special_alt *alt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool arch_support_alt_relocation(struct special_alt *special_alt,
 | 
					bool arch_support_alt_relocation(struct special_alt *special_alt,
 | 
				
			||||||
				 struct instruction *insn,
 | 
									 struct instruction *insn,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include <sys/stat.h>
 | 
					#include <sys/stat.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
#include <objtool/builtin.h>
 | 
					#include <objtool/builtin.h>
 | 
				
			||||||
#include <objtool/elf.h>
 | 
					#include <objtool/elf.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,36 +42,46 @@ static inline char *offstr(struct section *sec, unsigned long offset)
 | 
				
			||||||
	return str;
 | 
						return str;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define WARN(format, ...)				\
 | 
					#define ___WARN(severity, extra, format, ...)				\
 | 
				
			||||||
	fprintf(stderr,							\
 | 
						fprintf(stderr,							\
 | 
				
			||||||
		"%s: %s: objtool: " format "\n",	\
 | 
							"%s%s%s: objtool" extra ": " format "\n",		\
 | 
				
			||||||
		objname,				\
 | 
							objname ?: "",						\
 | 
				
			||||||
		opts.werror ? "error" : "warning",	\
 | 
							objname ? ": " : "",					\
 | 
				
			||||||
 | 
							severity,						\
 | 
				
			||||||
		##__VA_ARGS__)
 | 
							##__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define WARN_FUNC(format, sec, offset, ...)		\
 | 
					#define __WARN(severity, format, ...)					\
 | 
				
			||||||
 | 
						___WARN(severity, "", format, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __WARN_LINE(severity, format, ...)				\
 | 
				
			||||||
 | 
						___WARN(severity, " [%s:%d]", format, __FILE__, __LINE__, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __WARN_ELF(severity, format, ...)				\
 | 
				
			||||||
 | 
						__WARN_LINE(severity, "%s: " format " failed: %s", __func__, ##__VA_ARGS__, elf_errmsg(-1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __WARN_GLIBC(severity, format, ...)				\
 | 
				
			||||||
 | 
						__WARN_LINE(severity, "%s: " format " failed: %s", __func__, ##__VA_ARGS__, strerror(errno))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __WARN_FUNC(severity, sec, offset, format, ...)			\
 | 
				
			||||||
({									\
 | 
					({									\
 | 
				
			||||||
	char *_str = offstr(sec, offset);				\
 | 
						char *_str = offstr(sec, offset);				\
 | 
				
			||||||
	WARN("%s: " format, _str, ##__VA_ARGS__);	\
 | 
						__WARN(severity, "%s: " format, _str, ##__VA_ARGS__);		\
 | 
				
			||||||
	free(_str);							\
 | 
						free(_str);							\
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define WARN_LIMIT 2
 | 
					#define WARN_STR (opts.werror ? "error" : "warning")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define WARN(format, ...) __WARN(WARN_STR, format, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define WARN_FUNC(sec, offset, format, ...) __WARN_FUNC(WARN_STR, sec, offset, format, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define WARN_INSN(insn, format, ...)					\
 | 
					#define WARN_INSN(insn, format, ...)					\
 | 
				
			||||||
({									\
 | 
					({									\
 | 
				
			||||||
	struct instruction *_insn = (insn);				\
 | 
						struct instruction *_insn = (insn);				\
 | 
				
			||||||
	BUILD_BUG_ON(WARN_LIMIT > 2);					\
 | 
						if (!_insn->sym || !_insn->sym->warned)				\
 | 
				
			||||||
	if (!_insn->sym || _insn->sym->warnings < WARN_LIMIT) {		\
 | 
							WARN_FUNC(_insn->sec, _insn->offset, format,		\
 | 
				
			||||||
		WARN_FUNC(format, _insn->sec, _insn->offset,		\
 | 
					 | 
				
			||||||
			  ##__VA_ARGS__);				\
 | 
								  ##__VA_ARGS__);				\
 | 
				
			||||||
	if (_insn->sym)							\
 | 
						if (_insn->sym)							\
 | 
				
			||||||
			_insn->sym->warnings++;				\
 | 
							_insn->sym->warned = 1;					\
 | 
				
			||||||
	} else if (_insn->sym && _insn->sym->warnings == WARN_LIMIT) {	\
 | 
					 | 
				
			||||||
		WARN_FUNC("skipping duplicate warning(s)",		\
 | 
					 | 
				
			||||||
			  _insn->sec, _insn->offset);			\
 | 
					 | 
				
			||||||
		_insn->sym->warnings++;					\
 | 
					 | 
				
			||||||
	}								\
 | 
					 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BT_INSN(insn, format, ...)				\
 | 
					#define BT_INSN(insn, format, ...)				\
 | 
				
			||||||
| 
						 | 
					@ -83,7 +94,12 @@ static inline char *offstr(struct section *sec, unsigned long offset)
 | 
				
			||||||
	}							\
 | 
						}							\
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define WARN_ELF(format, ...)				\
 | 
					#define ERROR_STR "error"
 | 
				
			||||||
	WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1))
 | 
					
 | 
				
			||||||
 | 
					#define ERROR(format, ...) __WARN(ERROR_STR, format, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define ERROR_ELF(format, ...) __WARN_ELF(ERROR_STR, format, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define ERROR_GLIBC(format, ...) __WARN_GLIBC(ERROR_STR, format, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define ERROR_FUNC(sec, offset, format, ...) __WARN_FUNC(ERROR_STR, sec, offset, format, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define ERROR_INSN(insn, format, ...) WARN_FUNC(insn->sec, insn->offset, format, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _WARN_H */
 | 
					#endif /* _WARN_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@ static struct objtool_file file;
 | 
				
			||||||
struct objtool_file *objtool_open_read(const char *filename)
 | 
					struct objtool_file *objtool_open_read(const char *filename)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (file.elf) {
 | 
						if (file.elf) {
 | 
				
			||||||
		WARN("won't handle more than one file at a time");
 | 
							ERROR("won't handle more than one file at a time");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,14 +44,14 @@ struct objtool_file *objtool_open_read(const char *filename)
 | 
				
			||||||
	return &file;
 | 
						return &file;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
 | 
					int objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!opts.noinstr)
 | 
						if (!opts.noinstr)
 | 
				
			||||||
		return;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!f->pv_ops) {
 | 
						if (!f->pv_ops) {
 | 
				
			||||||
		WARN("paravirt confusion");
 | 
							ERROR("paravirt confusion");
 | 
				
			||||||
		return;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -60,14 +60,15 @@ void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (!strcmp(func->name, "_paravirt_nop") ||
 | 
						if (!strcmp(func->name, "_paravirt_nop") ||
 | 
				
			||||||
	    !strcmp(func->name, "_paravirt_ident_64"))
 | 
						    !strcmp(func->name, "_paravirt_ident_64"))
 | 
				
			||||||
		return;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* already added this function */
 | 
						/* already added this function */
 | 
				
			||||||
	if (!list_empty(&func->pv_target))
 | 
						if (!list_empty(&func->pv_target))
 | 
				
			||||||
		return;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_add(&func->pv_target, &f->pv_ops[idx].targets);
 | 
						list_add(&func->pv_target, &f->pv_ops[idx].targets);
 | 
				
			||||||
	f->pv_ops[idx].clean = false;
 | 
						f->pv_ops[idx].clean = false;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, const char **argv)
 | 
					int main(int argc, const char **argv)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,47 +36,47 @@ int orc_dump(const char *filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
 | 
						elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
 | 
				
			||||||
	if (!elf) {
 | 
						if (!elf) {
 | 
				
			||||||
		WARN_ELF("elf_begin");
 | 
							ERROR_ELF("elf_begin");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!elf64_getehdr(elf)) {
 | 
						if (!elf64_getehdr(elf)) {
 | 
				
			||||||
		WARN_ELF("elf64_getehdr");
 | 
							ERROR_ELF("elf64_getehdr");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	memcpy(&dummy_elf.ehdr, elf64_getehdr(elf), sizeof(dummy_elf.ehdr));
 | 
						memcpy(&dummy_elf.ehdr, elf64_getehdr(elf), sizeof(dummy_elf.ehdr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (elf_getshdrnum(elf, &nr_sections)) {
 | 
						if (elf_getshdrnum(elf, &nr_sections)) {
 | 
				
			||||||
		WARN_ELF("elf_getshdrnum");
 | 
							ERROR_ELF("elf_getshdrnum");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (elf_getshdrstrndx(elf, &shstrtab_idx)) {
 | 
						if (elf_getshdrstrndx(elf, &shstrtab_idx)) {
 | 
				
			||||||
		WARN_ELF("elf_getshdrstrndx");
 | 
							ERROR_ELF("elf_getshdrstrndx");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < nr_sections; i++) {
 | 
						for (i = 0; i < nr_sections; i++) {
 | 
				
			||||||
		scn = elf_getscn(elf, i);
 | 
							scn = elf_getscn(elf, i);
 | 
				
			||||||
		if (!scn) {
 | 
							if (!scn) {
 | 
				
			||||||
			WARN_ELF("elf_getscn");
 | 
								ERROR_ELF("elf_getscn");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!gelf_getshdr(scn, &sh)) {
 | 
							if (!gelf_getshdr(scn, &sh)) {
 | 
				
			||||||
			WARN_ELF("gelf_getshdr");
 | 
								ERROR_ELF("gelf_getshdr");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
 | 
							name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
 | 
				
			||||||
		if (!name) {
 | 
							if (!name) {
 | 
				
			||||||
			WARN_ELF("elf_strptr");
 | 
								ERROR_ELF("elf_strptr");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		data = elf_getdata(scn, NULL);
 | 
							data = elf_getdata(scn, NULL);
 | 
				
			||||||
		if (!data) {
 | 
							if (!data) {
 | 
				
			||||||
			WARN_ELF("elf_getdata");
 | 
								ERROR_ELF("elf_getdata");
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -99,7 +99,7 @@ int orc_dump(const char *filename)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (orc_size % sizeof(*orc) != 0) {
 | 
						if (orc_size % sizeof(*orc) != 0) {
 | 
				
			||||||
		WARN("bad .orc_unwind section size");
 | 
							ERROR("bad .orc_unwind section size");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,36 +107,36 @@ int orc_dump(const char *filename)
 | 
				
			||||||
	for (i = 0; i < nr_entries; i++) {
 | 
						for (i = 0; i < nr_entries; i++) {
 | 
				
			||||||
		if (rela_orc_ip) {
 | 
							if (rela_orc_ip) {
 | 
				
			||||||
			if (!gelf_getrela(rela_orc_ip, i, &rela)) {
 | 
								if (!gelf_getrela(rela_orc_ip, i, &rela)) {
 | 
				
			||||||
				WARN_ELF("gelf_getrela");
 | 
									ERROR_ELF("gelf_getrela");
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) {
 | 
								if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) {
 | 
				
			||||||
				WARN_ELF("gelf_getsym");
 | 
									ERROR_ELF("gelf_getsym");
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {
 | 
								if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {
 | 
				
			||||||
				scn = elf_getscn(elf, sym.st_shndx);
 | 
									scn = elf_getscn(elf, sym.st_shndx);
 | 
				
			||||||
				if (!scn) {
 | 
									if (!scn) {
 | 
				
			||||||
					WARN_ELF("elf_getscn");
 | 
										ERROR_ELF("elf_getscn");
 | 
				
			||||||
					return -1;
 | 
										return -1;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (!gelf_getshdr(scn, &sh)) {
 | 
									if (!gelf_getshdr(scn, &sh)) {
 | 
				
			||||||
					WARN_ELF("gelf_getshdr");
 | 
										ERROR_ELF("gelf_getshdr");
 | 
				
			||||||
					return -1;
 | 
										return -1;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
 | 
									name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
 | 
				
			||||||
				if (!name) {
 | 
									if (!name) {
 | 
				
			||||||
					WARN_ELF("elf_strptr");
 | 
										ERROR_ELF("elf_strptr");
 | 
				
			||||||
					return -1;
 | 
										return -1;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				name = elf_strptr(elf, strtab_idx, sym.st_name);
 | 
									name = elf_strptr(elf, strtab_idx, sym.st_name);
 | 
				
			||||||
				if (!name) {
 | 
									if (!name) {
 | 
				
			||||||
					WARN_ELF("elf_strptr");
 | 
										ERROR_ELF("elf_strptr");
 | 
				
			||||||
					return -1;
 | 
										return -1;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,7 +54,7 @@ static const struct special_entry entries[] = {
 | 
				
			||||||
	{},
 | 
						{},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void __weak arch_handle_alternative(unsigned short feature, struct special_alt *alt)
 | 
					void __weak arch_handle_alternative(struct special_alt *alt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,27 +86,18 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	orig_reloc = find_reloc_by_dest(elf, sec, offset + entry->orig);
 | 
						orig_reloc = find_reloc_by_dest(elf, sec, offset + entry->orig);
 | 
				
			||||||
	if (!orig_reloc) {
 | 
						if (!orig_reloc) {
 | 
				
			||||||
		WARN_FUNC("can't find orig reloc", sec, offset + entry->orig);
 | 
							ERROR_FUNC(sec, offset + entry->orig, "can't find orig reloc");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reloc_to_sec_off(orig_reloc, &alt->orig_sec, &alt->orig_off);
 | 
						reloc_to_sec_off(orig_reloc, &alt->orig_sec, &alt->orig_off);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (entry->feature) {
 | 
						arch_handle_alternative(alt);
 | 
				
			||||||
		unsigned short feature;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		feature = bswap_if_needed(elf,
 | 
					 | 
				
			||||||
					  *(unsigned short *)(sec->data->d_buf +
 | 
					 | 
				
			||||||
							      offset +
 | 
					 | 
				
			||||||
							      entry->feature));
 | 
					 | 
				
			||||||
		arch_handle_alternative(feature, alt);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!entry->group || alt->new_len) {
 | 
						if (!entry->group || alt->new_len) {
 | 
				
			||||||
		new_reloc = find_reloc_by_dest(elf, sec, offset + entry->new);
 | 
							new_reloc = find_reloc_by_dest(elf, sec, offset + entry->new);
 | 
				
			||||||
		if (!new_reloc) {
 | 
							if (!new_reloc) {
 | 
				
			||||||
			WARN_FUNC("can't find new reloc",
 | 
								ERROR_FUNC(sec, offset + entry->new, "can't find new reloc");
 | 
				
			||||||
				  sec, offset + entry->new);
 | 
					 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -122,8 +113,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		key_reloc = find_reloc_by_dest(elf, sec, offset + entry->key);
 | 
							key_reloc = find_reloc_by_dest(elf, sec, offset + entry->key);
 | 
				
			||||||
		if (!key_reloc) {
 | 
							if (!key_reloc) {
 | 
				
			||||||
			WARN_FUNC("can't find key reloc",
 | 
								ERROR_FUNC(sec, offset + entry->key, "can't find key reloc");
 | 
				
			||||||
				  sec, offset + entry->key);
 | 
					 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		alt->key_addend = reloc_addend(key_reloc);
 | 
							alt->key_addend = reloc_addend(key_reloc);
 | 
				
			||||||
| 
						 | 
					@ -153,8 +143,7 @@ int special_get_alts(struct elf *elf, struct list_head *alts)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (sec->sh.sh_size % entry->size != 0) {
 | 
							if (sec->sh.sh_size % entry->size != 0) {
 | 
				
			||||||
			WARN("%s size not a multiple of %d",
 | 
								ERROR("%s size not a multiple of %d", sec->name, entry->size);
 | 
				
			||||||
			     sec->name, entry->size);
 | 
					 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,7 +152,7 @@ int special_get_alts(struct elf *elf, struct list_head *alts)
 | 
				
			||||||
		for (idx = 0; idx < nr_entries; idx++) {
 | 
							for (idx = 0; idx < nr_entries; idx++) {
 | 
				
			||||||
			alt = malloc(sizeof(*alt));
 | 
								alt = malloc(sizeof(*alt));
 | 
				
			||||||
			if (!alt) {
 | 
								if (!alt) {
 | 
				
			||||||
				WARN("malloc failed");
 | 
									ERROR_GLIBC("malloc failed");
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			memset(alt, 0, sizeof(*alt));
 | 
								memset(alt, 0, sizeof(*alt));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue