mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	There are a lot of objtool changes in this cycle, all across the map:
- Speed up objtool significantly, especially when there are large number of sections
  - Improve objtool's understanding of special instructions such as IRET,
    to reduce the number of annotations required
  - Implement 'noinstr' validation
  - Do baby steps for non-x86 objtool use
  - Simplify/fix retpoline decoding
  - Add vmlinux validation
  - Improve documentation
  - Fix various bugs and apply smaller cleanups
 
 Signed-off-by: Ingo Molnar <mingo@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAl7VHvcRHG1pbmdvQGtl
 cm5lbC5vcmcACgkQEnMQ0APhK1gEfBAAhvPWljUmfQsetYq4q9BdbuC4xPSQN9ra
 e+2zu1MQaohkjAdFM1boNVhCCGKFUvlTEEw3GJR141Us6Y/ZRS8VIo70tmVSku6I
 OwuR5i8SgEKwurr1SwLxrI05rovYWRLSaDIRTHn2CViPEjgriyFGRV8QKam3AYmI
 dx47la3ELwuQR68nIdIMzDRt49oZVy+ZKW8Pjgjklzrd5KMYsPy7HPtraHUMeDg+
 GdoC7RresIt5AFiDiIJzKTT/jROI7KuHFnM6blluKHoKenWhYBFCz3sd6IvCdQWX
 JGy+KKY6H+YDMSpgc4FRP56M3GI0hX14oCd7L72epSLfOuzPr9Tmf6wfyQ8f50Je
 LGLD47tyltIcQR9H85YdR8UQspkjSW6xcql4ByCPTEqp0UzSGTsVntvsHzwsgz6A
 Csh3s+DVdv0rk5ZjMCu8STA2oErpehJm7fmugt2oLx+nsCNCBUI25lilw5JGeq5c
 +cO0IRxRxHPeRvMWvItTjbixVAHOHYlB00ilDbvsm+GnTJgu/5cMqpXdLvfXI2Rr
 nl360bSS3t3J4w5rX0mXw4x24vjQmVrA69jU+oo8RSHje2X8Y4Q7sFHNjmN0YAI3
 Re8aP6HSLQjioJxGz9aISlrxmPOXe0CMp8JE586SREVgmS/olXtidMgi7l12uZ2B
 cRdtNYcn31U=
 =dbCU
 -----END PGP SIGNATURE-----
Merge tag 'objtool-core-2020-06-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull objtool updates from Ingo Molnar:
 "There are a lot of objtool changes in this cycle, all across the map:
   - Speed up objtool significantly, especially when there are large
     number of sections
   - Improve objtool's understanding of special instructions such as
     IRET, to reduce the number of annotations required
   - Implement 'noinstr' validation
   - Do baby steps for non-x86 objtool use
   - Simplify/fix retpoline decoding
   - Add vmlinux validation
   - Improve documentation
   - Fix various bugs and apply smaller cleanups"
* tag 'objtool-core-2020-06-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (54 commits)
  objtool: Enable compilation of objtool for all architectures
  objtool: Move struct objtool_file into arch-independent header
  objtool: Exit successfully when requesting help
  objtool: Add check_kcov_mode() to the uaccess safelist
  samples/ftrace: Fix asm function ELF annotations
  objtool: optimize add_dead_ends for split sections
  objtool: use gelf_getsymshndx to handle >64k sections
  objtool: Allow no-op CFI ops in alternatives
  x86/retpoline: Fix retpoline unwind
  x86: Change {JMP,CALL}_NOSPEC argument
  x86: Simplify retpoline declaration
  x86/speculation: Change FILL_RETURN_BUFFER to work with objtool
  objtool: Add support for intra-function calls
  objtool: Move the IRET hack into the arch decoder
  objtool: Remove INSN_STACK
  objtool: Make handle_insn_ops() unconditional
  objtool: Rework allocating stack_ops on decode
  objtool: UNWIND_HINT_RET_OFFSET should not check registers
  objtool: is_fentry_call() crashes if call has no destination
  x86,smap: Fix smap_{save,restore}() alternatives
  ...
			
			
This commit is contained in:
		
						commit
						69fc06f70f
					
				
					 46 changed files with 1231 additions and 727 deletions
				
			
		| 
						 | 
					@ -2758,7 +2758,7 @@ SYM_FUNC_START(aesni_xts_crypt8)
 | 
				
			||||||
	pxor INC, STATE4
 | 
						pxor INC, STATE4
 | 
				
			||||||
	movdqu IV, 0x30(OUTP)
 | 
						movdqu IV, 0x30(OUTP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CALL_NOSPEC %r11
 | 
						CALL_NOSPEC r11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	movdqu 0x00(OUTP), INC
 | 
						movdqu 0x00(OUTP), INC
 | 
				
			||||||
	pxor INC, STATE1
 | 
						pxor INC, STATE1
 | 
				
			||||||
| 
						 | 
					@ -2803,7 +2803,7 @@ SYM_FUNC_START(aesni_xts_crypt8)
 | 
				
			||||||
	_aesni_gf128mul_x_ble()
 | 
						_aesni_gf128mul_x_ble()
 | 
				
			||||||
	movups IV, (IVP)
 | 
						movups IV, (IVP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CALL_NOSPEC %r11
 | 
						CALL_NOSPEC r11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	movdqu 0x40(OUTP), INC
 | 
						movdqu 0x40(OUTP), INC
 | 
				
			||||||
	pxor INC, STATE1
 | 
						pxor INC, STATE1
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1228,7 +1228,7 @@ SYM_FUNC_START_LOCAL(camellia_xts_crypt_16way)
 | 
				
			||||||
	vpxor 14 * 16(%rax), %xmm15, %xmm14;
 | 
						vpxor 14 * 16(%rax), %xmm15, %xmm14;
 | 
				
			||||||
	vpxor 15 * 16(%rax), %xmm15, %xmm15;
 | 
						vpxor 15 * 16(%rax), %xmm15, %xmm15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CALL_NOSPEC %r9;
 | 
						CALL_NOSPEC r9;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addq $(16 * 16), %rsp;
 | 
						addq $(16 * 16), %rsp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1339,7 +1339,7 @@ SYM_FUNC_START_LOCAL(camellia_xts_crypt_32way)
 | 
				
			||||||
	vpxor 14 * 32(%rax), %ymm15, %ymm14;
 | 
						vpxor 14 * 32(%rax), %ymm15, %ymm14;
 | 
				
			||||||
	vpxor 15 * 32(%rax), %ymm15, %ymm15;
 | 
						vpxor 15 * 32(%rax), %ymm15, %ymm15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CALL_NOSPEC %r9;
 | 
						CALL_NOSPEC r9;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addq $(16 * 32), %rsp;
 | 
						addq $(16 * 32), %rsp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,7 +75,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.text
 | 
					.text
 | 
				
			||||||
SYM_FUNC_START(crc_pcl)
 | 
					SYM_FUNC_START(crc_pcl)
 | 
				
			||||||
#define    bufp		%rdi
 | 
					#define    bufp		rdi
 | 
				
			||||||
#define    bufp_dw	%edi
 | 
					#define    bufp_dw	%edi
 | 
				
			||||||
#define    bufp_w	%di
 | 
					#define    bufp_w	%di
 | 
				
			||||||
#define    bufp_b	%dil
 | 
					#define    bufp_b	%dil
 | 
				
			||||||
| 
						 | 
					@ -105,9 +105,9 @@ SYM_FUNC_START(crc_pcl)
 | 
				
			||||||
	## 1) ALIGN:
 | 
						## 1) ALIGN:
 | 
				
			||||||
	################################################################
 | 
						################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mov     bufp, bufptmp		# rdi = *buf
 | 
						mov     %bufp, bufptmp		# rdi = *buf
 | 
				
			||||||
	neg     bufp
 | 
						neg     %bufp
 | 
				
			||||||
	and     $7, bufp		# calculate the unalignment amount of
 | 
						and     $7, %bufp		# calculate the unalignment amount of
 | 
				
			||||||
					# the address
 | 
										# the address
 | 
				
			||||||
	je      proc_block		# Skip if aligned
 | 
						je      proc_block		# Skip if aligned
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -123,13 +123,13 @@ SYM_FUNC_START(crc_pcl)
 | 
				
			||||||
do_align:
 | 
					do_align:
 | 
				
			||||||
	#### Calculate CRC of unaligned bytes of the buffer (if any)
 | 
						#### Calculate CRC of unaligned bytes of the buffer (if any)
 | 
				
			||||||
	movq    (bufptmp), tmp		# load a quadward from the buffer
 | 
						movq    (bufptmp), tmp		# load a quadward from the buffer
 | 
				
			||||||
	add     bufp, bufptmp		# align buffer pointer for quadword
 | 
						add     %bufp, bufptmp		# align buffer pointer for quadword
 | 
				
			||||||
					# processing
 | 
										# processing
 | 
				
			||||||
	sub     bufp, len		# update buffer length
 | 
						sub     %bufp, len		# update buffer length
 | 
				
			||||||
align_loop:
 | 
					align_loop:
 | 
				
			||||||
	crc32b  %bl, crc_init_dw 	# compute crc32 of 1-byte
 | 
						crc32b  %bl, crc_init_dw 	# compute crc32 of 1-byte
 | 
				
			||||||
	shr     $8, tmp			# get next byte
 | 
						shr     $8, tmp			# get next byte
 | 
				
			||||||
	dec     bufp
 | 
						dec     %bufp
 | 
				
			||||||
	jne     align_loop
 | 
						jne     align_loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proc_block:
 | 
					proc_block:
 | 
				
			||||||
| 
						 | 
					@ -169,10 +169,10 @@ continue_block:
 | 
				
			||||||
	xor     crc2, crc2
 | 
						xor     crc2, crc2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	## branch into array
 | 
						## branch into array
 | 
				
			||||||
	lea	jump_table(%rip), bufp
 | 
						lea	jump_table(%rip), %bufp
 | 
				
			||||||
	movzxw  (bufp, %rax, 2), len
 | 
						movzxw  (%bufp, %rax, 2), len
 | 
				
			||||||
	lea	crc_array(%rip), bufp
 | 
						lea	crc_array(%rip), %bufp
 | 
				
			||||||
	lea     (bufp, len, 1), bufp
 | 
						lea     (%bufp, len, 1), %bufp
 | 
				
			||||||
	JMP_NOSPEC bufp
 | 
						JMP_NOSPEC bufp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	################################################################
 | 
						################################################################
 | 
				
			||||||
| 
						 | 
					@ -218,9 +218,9 @@ LABEL crc_ %i
 | 
				
			||||||
	## 4) Combine three results:
 | 
						## 4) Combine three results:
 | 
				
			||||||
	################################################################
 | 
						################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lea	(K_table-8)(%rip), bufp		# first entry is for idx 1
 | 
						lea	(K_table-8)(%rip), %bufp		# first entry is for idx 1
 | 
				
			||||||
	shlq    $3, %rax			# rax *= 8
 | 
						shlq    $3, %rax			# rax *= 8
 | 
				
			||||||
	pmovzxdq (bufp,%rax), %xmm0		# 2 consts: K1:K2
 | 
						pmovzxdq (%bufp,%rax), %xmm0		# 2 consts: K1:K2
 | 
				
			||||||
	leal	(%eax,%eax,2), %eax		# rax *= 3 (total *24)
 | 
						leal	(%eax,%eax,2), %eax		# rax *= 3 (total *24)
 | 
				
			||||||
	subq    %rax, tmp			# tmp -= rax*24
 | 
						subq    %rax, tmp			# tmp -= rax*24
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -816,7 +816,7 @@ SYM_CODE_START(ret_from_fork)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* kernel thread */
 | 
						/* kernel thread */
 | 
				
			||||||
1:	movl	%edi, %eax
 | 
					1:	movl	%edi, %eax
 | 
				
			||||||
	CALL_NOSPEC %ebx
 | 
						CALL_NOSPEC ebx
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * A kernel thread is allowed to return here after successfully
 | 
						 * A kernel thread is allowed to return here after successfully
 | 
				
			||||||
	 * calling do_execve().  Exit to userspace to complete the execve()
 | 
						 * calling do_execve().  Exit to userspace to complete the execve()
 | 
				
			||||||
| 
						 | 
					@ -1501,7 +1501,7 @@ SYM_CODE_START_LOCAL_NOALIGN(common_exception_read_cr2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	TRACE_IRQS_OFF
 | 
						TRACE_IRQS_OFF
 | 
				
			||||||
	movl	%esp, %eax			# pt_regs pointer
 | 
						movl	%esp, %eax			# pt_regs pointer
 | 
				
			||||||
	CALL_NOSPEC %edi
 | 
						CALL_NOSPEC edi
 | 
				
			||||||
	jmp	ret_from_exception
 | 
						jmp	ret_from_exception
 | 
				
			||||||
SYM_CODE_END(common_exception_read_cr2)
 | 
					SYM_CODE_END(common_exception_read_cr2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1522,7 +1522,7 @@ SYM_CODE_START_LOCAL_NOALIGN(common_exception)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	TRACE_IRQS_OFF
 | 
						TRACE_IRQS_OFF
 | 
				
			||||||
	movl	%esp, %eax			# pt_regs pointer
 | 
						movl	%esp, %eax			# pt_regs pointer
 | 
				
			||||||
	CALL_NOSPEC %edi
 | 
						CALL_NOSPEC edi
 | 
				
			||||||
	jmp	ret_from_exception
 | 
						jmp	ret_from_exception
 | 
				
			||||||
SYM_CODE_END(common_exception)
 | 
					SYM_CODE_END(common_exception)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -348,7 +348,7 @@ SYM_CODE_START(ret_from_fork)
 | 
				
			||||||
	/* kernel thread */
 | 
						/* kernel thread */
 | 
				
			||||||
	UNWIND_HINT_EMPTY
 | 
						UNWIND_HINT_EMPTY
 | 
				
			||||||
	movq	%r12, %rdi
 | 
						movq	%r12, %rdi
 | 
				
			||||||
	CALL_NOSPEC %rbx
 | 
						CALL_NOSPEC rbx
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * A kernel thread is allowed to return here after successfully
 | 
						 * A kernel thread is allowed to return here after successfully
 | 
				
			||||||
	 * calling do_execve().  Exit to userspace to complete the execve()
 | 
						 * calling do_execve().  Exit to userspace to complete the execve()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								arch/x86/include/asm/GEN-for-each-reg.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								arch/x86/include/asm/GEN-for-each-reg.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					#ifdef CONFIG_64BIT
 | 
				
			||||||
 | 
					GEN(rax)
 | 
				
			||||||
 | 
					GEN(rbx)
 | 
				
			||||||
 | 
					GEN(rcx)
 | 
				
			||||||
 | 
					GEN(rdx)
 | 
				
			||||||
 | 
					GEN(rsi)
 | 
				
			||||||
 | 
					GEN(rdi)
 | 
				
			||||||
 | 
					GEN(rbp)
 | 
				
			||||||
 | 
					GEN(r8)
 | 
				
			||||||
 | 
					GEN(r9)
 | 
				
			||||||
 | 
					GEN(r10)
 | 
				
			||||||
 | 
					GEN(r11)
 | 
				
			||||||
 | 
					GEN(r12)
 | 
				
			||||||
 | 
					GEN(r13)
 | 
				
			||||||
 | 
					GEN(r14)
 | 
				
			||||||
 | 
					GEN(r15)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					GEN(eax)
 | 
				
			||||||
 | 
					GEN(ebx)
 | 
				
			||||||
 | 
					GEN(ecx)
 | 
				
			||||||
 | 
					GEN(edx)
 | 
				
			||||||
 | 
					GEN(esi)
 | 
				
			||||||
 | 
					GEN(edi)
 | 
				
			||||||
 | 
					GEN(ebp)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -17,24 +17,19 @@ extern void cmpxchg8b_emu(void);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_RETPOLINE
 | 
					#ifdef CONFIG_RETPOLINE
 | 
				
			||||||
#ifdef CONFIG_X86_32
 | 
					
 | 
				
			||||||
#define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_e ## reg(void);
 | 
					#define DECL_INDIRECT_THUNK(reg) \
 | 
				
			||||||
#else
 | 
						extern asmlinkage void __x86_indirect_thunk_ ## reg (void);
 | 
				
			||||||
#define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_r ## reg(void);
 | 
					
 | 
				
			||||||
INDIRECT_THUNK(8)
 | 
					#define DECL_RETPOLINE(reg) \
 | 
				
			||||||
INDIRECT_THUNK(9)
 | 
						extern asmlinkage void __x86_retpoline_ ## reg (void);
 | 
				
			||||||
INDIRECT_THUNK(10)
 | 
					
 | 
				
			||||||
INDIRECT_THUNK(11)
 | 
					#undef GEN
 | 
				
			||||||
INDIRECT_THUNK(12)
 | 
					#define GEN(reg) DECL_INDIRECT_THUNK(reg)
 | 
				
			||||||
INDIRECT_THUNK(13)
 | 
					#include <asm/GEN-for-each-reg.h>
 | 
				
			||||||
INDIRECT_THUNK(14)
 | 
					
 | 
				
			||||||
INDIRECT_THUNK(15)
 | 
					#undef GEN
 | 
				
			||||||
#endif
 | 
					#define GEN(reg) DECL_RETPOLINE(reg)
 | 
				
			||||||
INDIRECT_THUNK(ax)
 | 
					#include <asm/GEN-for-each-reg.h>
 | 
				
			||||||
INDIRECT_THUNK(bx)
 | 
					
 | 
				
			||||||
INDIRECT_THUNK(cx)
 | 
					 | 
				
			||||||
INDIRECT_THUNK(dx)
 | 
					 | 
				
			||||||
INDIRECT_THUNK(si)
 | 
					 | 
				
			||||||
INDIRECT_THUNK(di)
 | 
					 | 
				
			||||||
INDIRECT_THUNK(bp)
 | 
					 | 
				
			||||||
#endif /* CONFIG_RETPOLINE */
 | 
					#endif /* CONFIG_RETPOLINE */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,20 +4,13 @@
 | 
				
			||||||
#define _ASM_X86_NOSPEC_BRANCH_H_
 | 
					#define _ASM_X86_NOSPEC_BRANCH_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/static_key.h>
 | 
					#include <linux/static_key.h>
 | 
				
			||||||
 | 
					#include <linux/frame.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/alternative.h>
 | 
					#include <asm/alternative.h>
 | 
				
			||||||
#include <asm/alternative-asm.h>
 | 
					#include <asm/alternative-asm.h>
 | 
				
			||||||
#include <asm/cpufeatures.h>
 | 
					#include <asm/cpufeatures.h>
 | 
				
			||||||
#include <asm/msr-index.h>
 | 
					#include <asm/msr-index.h>
 | 
				
			||||||
 | 
					#include <asm/unwind_hints.h>
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * This should be used immediately before a retpoline alternative. It tells
 | 
					 | 
				
			||||||
 * objtool where the retpolines are so that it can make sense of the control
 | 
					 | 
				
			||||||
 * flow by just reading the original instruction(s) and ignoring the
 | 
					 | 
				
			||||||
 * alternatives.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define ANNOTATE_NOSPEC_ALTERNATIVE \
 | 
					 | 
				
			||||||
	ANNOTATE_IGNORE_ALTERNATIVE
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Fill the CPU return stack buffer.
 | 
					 * Fill the CPU return stack buffer.
 | 
				
			||||||
| 
						 | 
					@ -46,21 +39,25 @@
 | 
				
			||||||
#define __FILL_RETURN_BUFFER(reg, nr, sp)	\
 | 
					#define __FILL_RETURN_BUFFER(reg, nr, sp)	\
 | 
				
			||||||
	mov	$(nr/2), reg;			\
 | 
						mov	$(nr/2), reg;			\
 | 
				
			||||||
771:						\
 | 
					771:						\
 | 
				
			||||||
 | 
						ANNOTATE_INTRA_FUNCTION_CALL;		\
 | 
				
			||||||
	call	772f;				\
 | 
						call	772f;				\
 | 
				
			||||||
773:	/* speculation trap */			\
 | 
					773:	/* speculation trap */			\
 | 
				
			||||||
 | 
						UNWIND_HINT_EMPTY;			\
 | 
				
			||||||
	pause;					\
 | 
						pause;					\
 | 
				
			||||||
	lfence;					\
 | 
						lfence;					\
 | 
				
			||||||
	jmp	773b;				\
 | 
						jmp	773b;				\
 | 
				
			||||||
772:						\
 | 
					772:						\
 | 
				
			||||||
 | 
						ANNOTATE_INTRA_FUNCTION_CALL;		\
 | 
				
			||||||
	call	774f;				\
 | 
						call	774f;				\
 | 
				
			||||||
775:	/* speculation trap */			\
 | 
					775:	/* speculation trap */			\
 | 
				
			||||||
 | 
						UNWIND_HINT_EMPTY;			\
 | 
				
			||||||
	pause;					\
 | 
						pause;					\
 | 
				
			||||||
	lfence;					\
 | 
						lfence;					\
 | 
				
			||||||
	jmp	775b;				\
 | 
						jmp	775b;				\
 | 
				
			||||||
774:						\
 | 
					774:						\
 | 
				
			||||||
 | 
						add	$(BITS_PER_LONG/8) * 2, sp;	\
 | 
				
			||||||
	dec	reg;				\
 | 
						dec	reg;				\
 | 
				
			||||||
	jnz	771b;				\
 | 
						jnz	771b;
 | 
				
			||||||
	add	$(BITS_PER_LONG/8) * nr, sp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __ASSEMBLY__
 | 
					#ifdef __ASSEMBLY__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,34 +73,6 @@
 | 
				
			||||||
	.popsection
 | 
						.popsection
 | 
				
			||||||
.endm
 | 
					.endm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * These are the bare retpoline primitives for indirect jmp and call.
 | 
					 | 
				
			||||||
 * Do not use these directly; they only exist to make the ALTERNATIVE
 | 
					 | 
				
			||||||
 * invocation below less ugly.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
.macro RETPOLINE_JMP reg:req
 | 
					 | 
				
			||||||
	call	.Ldo_rop_\@
 | 
					 | 
				
			||||||
.Lspec_trap_\@:
 | 
					 | 
				
			||||||
	pause
 | 
					 | 
				
			||||||
	lfence
 | 
					 | 
				
			||||||
	jmp	.Lspec_trap_\@
 | 
					 | 
				
			||||||
.Ldo_rop_\@:
 | 
					 | 
				
			||||||
	mov	\reg, (%_ASM_SP)
 | 
					 | 
				
			||||||
	ret
 | 
					 | 
				
			||||||
.endm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * This is a wrapper around RETPOLINE_JMP so the called function in reg
 | 
					 | 
				
			||||||
 * returns to the instruction after the macro.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
.macro RETPOLINE_CALL reg:req
 | 
					 | 
				
			||||||
	jmp	.Ldo_call_\@
 | 
					 | 
				
			||||||
.Ldo_retpoline_jmp_\@:
 | 
					 | 
				
			||||||
	RETPOLINE_JMP \reg
 | 
					 | 
				
			||||||
.Ldo_call_\@:
 | 
					 | 
				
			||||||
	call	.Ldo_retpoline_jmp_\@
 | 
					 | 
				
			||||||
.endm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple
 | 
					 * JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple
 | 
				
			||||||
 * indirect jmp/call which may be susceptible to the Spectre variant 2
 | 
					 * indirect jmp/call which may be susceptible to the Spectre variant 2
 | 
				
			||||||
| 
						 | 
					@ -111,23 +80,21 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
.macro JMP_NOSPEC reg:req
 | 
					.macro JMP_NOSPEC reg:req
 | 
				
			||||||
#ifdef CONFIG_RETPOLINE
 | 
					#ifdef CONFIG_RETPOLINE
 | 
				
			||||||
	ANNOTATE_NOSPEC_ALTERNATIVE
 | 
						ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), \
 | 
				
			||||||
	ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *\reg),	\
 | 
							      __stringify(jmp __x86_retpoline_\reg), X86_FEATURE_RETPOLINE, \
 | 
				
			||||||
		__stringify(RETPOLINE_JMP \reg), X86_FEATURE_RETPOLINE,	\
 | 
							      __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), X86_FEATURE_RETPOLINE_AMD
 | 
				
			||||||
		__stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *\reg), X86_FEATURE_RETPOLINE_AMD
 | 
					 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	jmp	*\reg
 | 
						jmp	*%\reg
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
.endm
 | 
					.endm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.macro CALL_NOSPEC reg:req
 | 
					.macro CALL_NOSPEC reg:req
 | 
				
			||||||
#ifdef CONFIG_RETPOLINE
 | 
					#ifdef CONFIG_RETPOLINE
 | 
				
			||||||
	ANNOTATE_NOSPEC_ALTERNATIVE
 | 
						ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; call *%\reg), \
 | 
				
			||||||
	ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; call *\reg),	\
 | 
							      __stringify(call __x86_retpoline_\reg), X86_FEATURE_RETPOLINE, \
 | 
				
			||||||
		__stringify(RETPOLINE_CALL \reg), X86_FEATURE_RETPOLINE,\
 | 
							      __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *%\reg), X86_FEATURE_RETPOLINE_AMD
 | 
				
			||||||
		__stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *\reg), X86_FEATURE_RETPOLINE_AMD
 | 
					 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	call	*\reg
 | 
						call	*%\reg
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
.endm
 | 
					.endm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -137,10 +104,8 @@
 | 
				
			||||||
  */
 | 
					  */
 | 
				
			||||||
.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
 | 
					.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
 | 
				
			||||||
#ifdef CONFIG_RETPOLINE
 | 
					#ifdef CONFIG_RETPOLINE
 | 
				
			||||||
	ANNOTATE_NOSPEC_ALTERNATIVE
 | 
						ALTERNATIVE "jmp .Lskip_rsb_\@", "", \ftr
 | 
				
			||||||
	ALTERNATIVE "jmp .Lskip_rsb_\@",				\
 | 
						__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)
 | 
				
			||||||
		__stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP))	\
 | 
					 | 
				
			||||||
		\ftr
 | 
					 | 
				
			||||||
.Lskip_rsb_\@:
 | 
					.Lskip_rsb_\@:
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
.endm
 | 
					.endm
 | 
				
			||||||
| 
						 | 
					@ -161,16 +126,16 @@
 | 
				
			||||||
 * which is ensured when CONFIG_RETPOLINE is defined.
 | 
					 * which is ensured when CONFIG_RETPOLINE is defined.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
# define CALL_NOSPEC						\
 | 
					# define CALL_NOSPEC						\
 | 
				
			||||||
	ANNOTATE_NOSPEC_ALTERNATIVE				\
 | 
					 | 
				
			||||||
	ALTERNATIVE_2(						\
 | 
						ALTERNATIVE_2(						\
 | 
				
			||||||
	ANNOTATE_RETPOLINE_SAFE					\
 | 
						ANNOTATE_RETPOLINE_SAFE					\
 | 
				
			||||||
	"call *%[thunk_target]\n",				\
 | 
						"call *%[thunk_target]\n",				\
 | 
				
			||||||
	"call __x86_indirect_thunk_%V[thunk_target]\n",		\
 | 
						"call __x86_retpoline_%V[thunk_target]\n",		\
 | 
				
			||||||
	X86_FEATURE_RETPOLINE,					\
 | 
						X86_FEATURE_RETPOLINE,					\
 | 
				
			||||||
	"lfence;\n"						\
 | 
						"lfence;\n"						\
 | 
				
			||||||
	ANNOTATE_RETPOLINE_SAFE					\
 | 
						ANNOTATE_RETPOLINE_SAFE					\
 | 
				
			||||||
	"call *%[thunk_target]\n",				\
 | 
						"call *%[thunk_target]\n",				\
 | 
				
			||||||
	X86_FEATURE_RETPOLINE_AMD)
 | 
						X86_FEATURE_RETPOLINE_AMD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# define THUNK_TARGET(addr) [thunk_target] "r" (addr)
 | 
					# define THUNK_TARGET(addr) [thunk_target] "r" (addr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else /* CONFIG_X86_32 */
 | 
					#else /* CONFIG_X86_32 */
 | 
				
			||||||
| 
						 | 
					@ -180,7 +145,6 @@
 | 
				
			||||||
 * here, anyway.
 | 
					 * here, anyway.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
# define CALL_NOSPEC						\
 | 
					# define CALL_NOSPEC						\
 | 
				
			||||||
	ANNOTATE_NOSPEC_ALTERNATIVE				\
 | 
					 | 
				
			||||||
	ALTERNATIVE_2(						\
 | 
						ALTERNATIVE_2(						\
 | 
				
			||||||
	ANNOTATE_RETPOLINE_SAFE					\
 | 
						ANNOTATE_RETPOLINE_SAFE					\
 | 
				
			||||||
	"call *%[thunk_target]\n",				\
 | 
						"call *%[thunk_target]\n",				\
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,8 +58,7 @@
 | 
				
			||||||
#define ORC_TYPE_CALL			0
 | 
					#define ORC_TYPE_CALL			0
 | 
				
			||||||
#define ORC_TYPE_REGS			1
 | 
					#define ORC_TYPE_REGS			1
 | 
				
			||||||
#define ORC_TYPE_REGS_IRET		2
 | 
					#define ORC_TYPE_REGS_IRET		2
 | 
				
			||||||
#define UNWIND_HINT_TYPE_SAVE		3
 | 
					#define UNWIND_HINT_TYPE_RET_OFFSET	3
 | 
				
			||||||
#define UNWIND_HINT_TYPE_RESTORE	4
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef __ASSEMBLY__
 | 
					#ifndef __ASSEMBLY__
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -728,7 +728,6 @@ static inline void sync_core(void)
 | 
				
			||||||
	unsigned int tmp;
 | 
						unsigned int tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	asm volatile (
 | 
						asm volatile (
 | 
				
			||||||
		UNWIND_HINT_SAVE
 | 
					 | 
				
			||||||
		"mov %%ss, %0\n\t"
 | 
							"mov %%ss, %0\n\t"
 | 
				
			||||||
		"pushq %q0\n\t"
 | 
							"pushq %q0\n\t"
 | 
				
			||||||
		"pushq %%rsp\n\t"
 | 
							"pushq %%rsp\n\t"
 | 
				
			||||||
| 
						 | 
					@ -738,7 +737,6 @@ static inline void sync_core(void)
 | 
				
			||||||
		"pushq %q0\n\t"
 | 
							"pushq %q0\n\t"
 | 
				
			||||||
		"pushq $1f\n\t"
 | 
							"pushq $1f\n\t"
 | 
				
			||||||
		"iretq\n\t"
 | 
							"iretq\n\t"
 | 
				
			||||||
		UNWIND_HINT_RESTORE
 | 
					 | 
				
			||||||
		"1:"
 | 
							"1:"
 | 
				
			||||||
		: "=&r" (tmp), ASM_CALL_CONSTRAINT : : "cc", "memory");
 | 
							: "=&r" (tmp), ASM_CALL_CONSTRAINT : : "cc", "memory");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,8 +57,10 @@ static __always_inline unsigned long smap_save(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long flags;
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	asm volatile (ALTERNATIVE("", "pushf; pop %0; " __ASM_CLAC,
 | 
						asm volatile ("# smap_save\n\t"
 | 
				
			||||||
				  X86_FEATURE_SMAP)
 | 
							      ALTERNATIVE("jmp 1f", "", X86_FEATURE_SMAP)
 | 
				
			||||||
 | 
							      "pushf; pop %0; " __ASM_CLAC "\n\t"
 | 
				
			||||||
 | 
							      "1:"
 | 
				
			||||||
		      : "=rm" (flags) : : "memory", "cc");
 | 
							      : "=rm" (flags) : : "memory", "cc");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return flags;
 | 
						return flags;
 | 
				
			||||||
| 
						 | 
					@ -66,7 +68,10 @@ 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 (ALTERNATIVE("", "push %0; popf", X86_FEATURE_SMAP)
 | 
						asm volatile ("# smap_restore\n\t"
 | 
				
			||||||
 | 
							      ALTERNATIVE("jmp 1f", "", X86_FEATURE_SMAP)
 | 
				
			||||||
 | 
							      "push %0; popf\n\t"
 | 
				
			||||||
 | 
							      "1:"
 | 
				
			||||||
		      : : "g" (flags) : "memory", "cc");
 | 
							      : : "g" (flags) : "memory", "cc");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,32 +86,15 @@
 | 
				
			||||||
	UNWIND_HINT sp_offset=\sp_offset
 | 
						UNWIND_HINT sp_offset=\sp_offset
 | 
				
			||||||
.endm
 | 
					.endm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.macro UNWIND_HINT_SAVE
 | 
					/*
 | 
				
			||||||
	UNWIND_HINT type=UNWIND_HINT_TYPE_SAVE
 | 
					 * RET_OFFSET: Used on instructions that terminate a function; mostly RETURN
 | 
				
			||||||
 | 
					 * and sibling calls. On these, sp_offset denotes the expected offset from
 | 
				
			||||||
 | 
					 * initial_func_cfi.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					.macro UNWIND_HINT_RET_OFFSET sp_offset=8
 | 
				
			||||||
 | 
						UNWIND_HINT type=UNWIND_HINT_TYPE_RET_OFFSET sp_offset=\sp_offset
 | 
				
			||||||
.endm
 | 
					.endm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.macro UNWIND_HINT_RESTORE
 | 
					 | 
				
			||||||
	UNWIND_HINT type=UNWIND_HINT_TYPE_RESTORE
 | 
					 | 
				
			||||||
.endm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#else /* !__ASSEMBLY__ */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define UNWIND_HINT(sp_reg, sp_offset, type, end)		\
 | 
					 | 
				
			||||||
	"987: \n\t"						\
 | 
					 | 
				
			||||||
	".pushsection .discard.unwind_hints\n\t"		\
 | 
					 | 
				
			||||||
	/* struct unwind_hint */				\
 | 
					 | 
				
			||||||
	".long 987b - .\n\t"					\
 | 
					 | 
				
			||||||
	".short " __stringify(sp_offset) "\n\t"			\
 | 
					 | 
				
			||||||
	".byte " __stringify(sp_reg) "\n\t"			\
 | 
					 | 
				
			||||||
	".byte " __stringify(type) "\n\t"			\
 | 
					 | 
				
			||||||
	".byte " __stringify(end) "\n\t"			\
 | 
					 | 
				
			||||||
	".balign 4 \n\t"					\
 | 
					 | 
				
			||||||
	".popsection\n\t"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define UNWIND_HINT_SAVE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_SAVE, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define UNWIND_HINT_RESTORE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_RESTORE, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* __ASSEMBLY__ */
 | 
					#endif /* __ASSEMBLY__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ASM_X86_UNWIND_HINTS_H */
 | 
					#endif /* _ASM_X86_UNWIND_HINTS_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -282,7 +282,8 @@ static inline void tramp_free(void *tramp) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Defined as markers to the end of the ftrace default trampolines */
 | 
					/* Defined as markers to the end of the ftrace default trampolines */
 | 
				
			||||||
extern void ftrace_regs_caller_end(void);
 | 
					extern void ftrace_regs_caller_end(void);
 | 
				
			||||||
extern void ftrace_epilogue(void);
 | 
					extern void ftrace_regs_caller_ret(void);
 | 
				
			||||||
 | 
					extern void ftrace_caller_end(void);
 | 
				
			||||||
extern void ftrace_caller_op_ptr(void);
 | 
					extern void ftrace_caller_op_ptr(void);
 | 
				
			||||||
extern void ftrace_regs_caller_op_ptr(void);
 | 
					extern void ftrace_regs_caller_op_ptr(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -334,7 +335,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
 | 
				
			||||||
		call_offset = (unsigned long)ftrace_regs_call;
 | 
							call_offset = (unsigned long)ftrace_regs_call;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		start_offset = (unsigned long)ftrace_caller;
 | 
							start_offset = (unsigned long)ftrace_caller;
 | 
				
			||||||
		end_offset = (unsigned long)ftrace_epilogue;
 | 
							end_offset = (unsigned long)ftrace_caller_end;
 | 
				
			||||||
		op_offset = (unsigned long)ftrace_caller_op_ptr;
 | 
							op_offset = (unsigned long)ftrace_caller_op_ptr;
 | 
				
			||||||
		call_offset = (unsigned long)ftrace_call;
 | 
							call_offset = (unsigned long)ftrace_call;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -366,6 +367,13 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
 | 
				
			||||||
	if (WARN_ON(ret < 0))
 | 
						if (WARN_ON(ret < 0))
 | 
				
			||||||
		goto fail;
 | 
							goto fail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
 | 
				
			||||||
 | 
							ip = trampoline + (ftrace_regs_caller_ret - ftrace_regs_caller);
 | 
				
			||||||
 | 
							ret = probe_kernel_read(ip, (void *)retq, RET_SIZE);
 | 
				
			||||||
 | 
							if (WARN_ON(ret < 0))
 | 
				
			||||||
 | 
								goto fail;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The address of the ftrace_ops that is used for this trampoline
 | 
						 * The address of the ftrace_ops that is used for this trampoline
 | 
				
			||||||
	 * is stored at the end of the trampoline. This will be used to
 | 
						 * is stored at the end of the trampoline. This will be used to
 | 
				
			||||||
| 
						 | 
					@ -433,7 +441,7 @@ void set_ftrace_ops_ro(void)
 | 
				
			||||||
			end_offset = (unsigned long)ftrace_regs_caller_end;
 | 
								end_offset = (unsigned long)ftrace_regs_caller_end;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			start_offset = (unsigned long)ftrace_caller;
 | 
								start_offset = (unsigned long)ftrace_caller;
 | 
				
			||||||
			end_offset = (unsigned long)ftrace_epilogue;
 | 
								end_offset = (unsigned long)ftrace_caller_end;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		size = end_offset - start_offset;
 | 
							size = end_offset - start_offset;
 | 
				
			||||||
		size = size + RET_SIZE + sizeof(void *);
 | 
							size = size + RET_SIZE + sizeof(void *);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -189,5 +189,5 @@ return_to_handler:
 | 
				
			||||||
	movl	%eax, %ecx
 | 
						movl	%eax, %ecx
 | 
				
			||||||
	popl	%edx
 | 
						popl	%edx
 | 
				
			||||||
	popl	%eax
 | 
						popl	%eax
 | 
				
			||||||
	JMP_NOSPEC %ecx
 | 
						JMP_NOSPEC ecx
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@
 | 
				
			||||||
#endif /* CONFIG_FRAME_POINTER */
 | 
					#endif /* CONFIG_FRAME_POINTER */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Size of stack used to save mcount regs in save_mcount_regs */
 | 
					/* Size of stack used to save mcount regs in save_mcount_regs */
 | 
				
			||||||
#define MCOUNT_REG_SIZE		(SS+8 + MCOUNT_FRAME_SIZE)
 | 
					#define MCOUNT_REG_SIZE		(FRAME_SIZE + MCOUNT_FRAME_SIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * gcc -pg option adds a call to 'mcount' in most functions.
 | 
					 * gcc -pg option adds a call to 'mcount' in most functions.
 | 
				
			||||||
| 
						 | 
					@ -77,7 +77,7 @@
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * We add enough stack to save all regs.
 | 
						 * We add enough stack to save all regs.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	subq $(MCOUNT_REG_SIZE - MCOUNT_FRAME_SIZE), %rsp
 | 
						subq $(FRAME_SIZE), %rsp
 | 
				
			||||||
	movq %rax, RAX(%rsp)
 | 
						movq %rax, RAX(%rsp)
 | 
				
			||||||
	movq %rcx, RCX(%rsp)
 | 
						movq %rcx, RCX(%rsp)
 | 
				
			||||||
	movq %rdx, RDX(%rsp)
 | 
						movq %rdx, RDX(%rsp)
 | 
				
			||||||
| 
						 | 
					@ -157,8 +157,12 @@ SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
 | 
				
			||||||
	 * think twice before adding any new code or changing the
 | 
						 * think twice before adding any new code or changing the
 | 
				
			||||||
	 * layout here.
 | 
						 * layout here.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
SYM_INNER_LABEL(ftrace_epilogue, SYM_L_GLOBAL)
 | 
					SYM_INNER_LABEL(ftrace_caller_end, SYM_L_GLOBAL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						jmp ftrace_epilogue
 | 
				
			||||||
 | 
					SYM_FUNC_END(ftrace_caller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SYM_FUNC_START(ftrace_epilogue)
 | 
				
			||||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 | 
					#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 | 
				
			||||||
SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL)
 | 
					SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL)
 | 
				
			||||||
	jmp ftrace_stub
 | 
						jmp ftrace_stub
 | 
				
			||||||
| 
						 | 
					@ -170,14 +174,12 @@ SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
SYM_INNER_LABEL_ALIGN(ftrace_stub, SYM_L_WEAK)
 | 
					SYM_INNER_LABEL_ALIGN(ftrace_stub, SYM_L_WEAK)
 | 
				
			||||||
	retq
 | 
						retq
 | 
				
			||||||
SYM_FUNC_END(ftrace_caller)
 | 
					SYM_FUNC_END(ftrace_epilogue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SYM_FUNC_START(ftrace_regs_caller)
 | 
					SYM_FUNC_START(ftrace_regs_caller)
 | 
				
			||||||
	/* Save the current flags before any operations that can change them */
 | 
						/* Save the current flags before any operations that can change them */
 | 
				
			||||||
	pushfq
 | 
						pushfq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	UNWIND_HINT_SAVE
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* added 8 bytes to save flags */
 | 
						/* added 8 bytes to save flags */
 | 
				
			||||||
	save_mcount_regs 8
 | 
						save_mcount_regs 8
 | 
				
			||||||
	/* save_mcount_regs fills in first two parameters */
 | 
						/* save_mcount_regs fills in first two parameters */
 | 
				
			||||||
| 
						 | 
					@ -233,10 +235,13 @@ SYM_INNER_LABEL(ftrace_regs_call, SYM_L_GLOBAL)
 | 
				
			||||||
	movq ORIG_RAX(%rsp), %rax
 | 
						movq ORIG_RAX(%rsp), %rax
 | 
				
			||||||
	movq %rax, MCOUNT_REG_SIZE-8(%rsp)
 | 
						movq %rax, MCOUNT_REG_SIZE-8(%rsp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If ORIG_RAX is anything but zero, make this a call to that */
 | 
						/*
 | 
				
			||||||
 | 
						 * If ORIG_RAX is anything but zero, make this a call to that.
 | 
				
			||||||
 | 
						 * See arch_ftrace_set_direct_caller().
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	movq ORIG_RAX(%rsp), %rax
 | 
						movq ORIG_RAX(%rsp), %rax
 | 
				
			||||||
	cmpq	$0, %rax
 | 
						testq	%rax, %rax
 | 
				
			||||||
	je	1f
 | 
						jz	1f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Swap the flags with orig_rax */
 | 
						/* Swap the flags with orig_rax */
 | 
				
			||||||
	movq MCOUNT_REG_SIZE(%rsp), %rdi
 | 
						movq MCOUNT_REG_SIZE(%rsp), %rdi
 | 
				
			||||||
| 
						 | 
					@ -244,20 +249,14 @@ SYM_INNER_LABEL(ftrace_regs_call, SYM_L_GLOBAL)
 | 
				
			||||||
	movq %rax, MCOUNT_REG_SIZE(%rsp)
 | 
						movq %rax, MCOUNT_REG_SIZE(%rsp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	restore_mcount_regs 8
 | 
						restore_mcount_regs 8
 | 
				
			||||||
 | 
						/* Restore flags */
 | 
				
			||||||
 | 
						popfq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	jmp	2f
 | 
					SYM_INNER_LABEL(ftrace_regs_caller_ret, SYM_L_GLOBAL);
 | 
				
			||||||
 | 
						UNWIND_HINT_RET_OFFSET
 | 
				
			||||||
 | 
						jmp	ftrace_epilogue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1:	restore_mcount_regs
 | 
					1:	restore_mcount_regs
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2:
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * The stack layout is nondetermistic here, depending on which path was
 | 
					 | 
				
			||||||
	 * taken.  This confuses objtool and ORC, rightfully so.  For now,
 | 
					 | 
				
			||||||
	 * pretend the stack always looks like the non-direct case.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	UNWIND_HINT_RESTORE
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Restore flags */
 | 
						/* Restore flags */
 | 
				
			||||||
	popfq
 | 
						popfq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -268,7 +267,6 @@ SYM_INNER_LABEL(ftrace_regs_call, SYM_L_GLOBAL)
 | 
				
			||||||
	 * to the return.
 | 
						 * to the return.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
SYM_INNER_LABEL(ftrace_regs_caller_end, SYM_L_GLOBAL)
 | 
					SYM_INNER_LABEL(ftrace_regs_caller_end, SYM_L_GLOBAL)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	jmp ftrace_epilogue
 | 
						jmp ftrace_epilogue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SYM_FUNC_END(ftrace_regs_caller)
 | 
					SYM_FUNC_END(ftrace_regs_caller)
 | 
				
			||||||
| 
						 | 
					@ -303,7 +301,7 @@ trace:
 | 
				
			||||||
	 * function tracing is enabled.
 | 
						 * function tracing is enabled.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	movq ftrace_trace_function, %r8
 | 
						movq ftrace_trace_function, %r8
 | 
				
			||||||
	CALL_NOSPEC %r8
 | 
						CALL_NOSPEC r8
 | 
				
			||||||
	restore_mcount_regs
 | 
						restore_mcount_regs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	jmp fgraph_trace
 | 
						jmp fgraph_trace
 | 
				
			||||||
| 
						 | 
					@ -340,6 +338,6 @@ SYM_CODE_START(return_to_handler)
 | 
				
			||||||
	movq 8(%rsp), %rdx
 | 
						movq 8(%rsp), %rdx
 | 
				
			||||||
	movq (%rsp), %rax
 | 
						movq (%rsp), %rax
 | 
				
			||||||
	addq $24, %rsp
 | 
						addq $24, %rsp
 | 
				
			||||||
	JMP_NOSPEC %rdi
 | 
						JMP_NOSPEC rdi
 | 
				
			||||||
SYM_CODE_END(return_to_handler)
 | 
					SYM_CODE_END(return_to_handler)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -153,7 +153,7 @@ SYM_FUNC_START(csum_partial)
 | 
				
			||||||
	negl %ebx
 | 
						negl %ebx
 | 
				
			||||||
	lea 45f(%ebx,%ebx,2), %ebx
 | 
						lea 45f(%ebx,%ebx,2), %ebx
 | 
				
			||||||
	testl %esi, %esi
 | 
						testl %esi, %esi
 | 
				
			||||||
	JMP_NOSPEC %ebx
 | 
						JMP_NOSPEC ebx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# Handle 2-byte-aligned regions
 | 
						# Handle 2-byte-aligned regions
 | 
				
			||||||
20:	addw (%esi), %ax
 | 
					20:	addw (%esi), %ax
 | 
				
			||||||
| 
						 | 
					@ -436,7 +436,7 @@ SYM_FUNC_START(csum_partial_copy_generic)
 | 
				
			||||||
	andl $-32,%edx
 | 
						andl $-32,%edx
 | 
				
			||||||
	lea 3f(%ebx,%ebx), %ebx
 | 
						lea 3f(%ebx,%ebx), %ebx
 | 
				
			||||||
	testl %esi, %esi 
 | 
						testl %esi, %esi 
 | 
				
			||||||
	JMP_NOSPEC %ebx
 | 
						JMP_NOSPEC ebx
 | 
				
			||||||
1:	addl $64,%esi
 | 
					1:	addl $64,%esi
 | 
				
			||||||
	addl $64,%edi 
 | 
						addl $64,%edi 
 | 
				
			||||||
	SRC(movb -32(%edx),%bl)	; SRC(movb (%edx),%bl)
 | 
						SRC(movb -32(%edx),%bl)	; SRC(movb (%edx),%bl)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,15 +7,31 @@
 | 
				
			||||||
#include <asm/alternative-asm.h>
 | 
					#include <asm/alternative-asm.h>
 | 
				
			||||||
#include <asm/export.h>
 | 
					#include <asm/export.h>
 | 
				
			||||||
#include <asm/nospec-branch.h>
 | 
					#include <asm/nospec-branch.h>
 | 
				
			||||||
 | 
					#include <asm/unwind_hints.h>
 | 
				
			||||||
 | 
					#include <asm/frame.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.macro THUNK reg
 | 
					.macro THUNK reg
 | 
				
			||||||
	.section .text.__x86.indirect_thunk
 | 
						.section .text.__x86.indirect_thunk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.align 32
 | 
				
			||||||
SYM_FUNC_START(__x86_indirect_thunk_\reg)
 | 
					SYM_FUNC_START(__x86_indirect_thunk_\reg)
 | 
				
			||||||
	CFI_STARTPROC
 | 
						JMP_NOSPEC \reg
 | 
				
			||||||
	JMP_NOSPEC %\reg
 | 
					 | 
				
			||||||
	CFI_ENDPROC
 | 
					 | 
				
			||||||
SYM_FUNC_END(__x86_indirect_thunk_\reg)
 | 
					SYM_FUNC_END(__x86_indirect_thunk_\reg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SYM_FUNC_START_NOALIGN(__x86_retpoline_\reg)
 | 
				
			||||||
 | 
						ANNOTATE_INTRA_FUNCTION_CALL
 | 
				
			||||||
 | 
						call	.Ldo_rop_\@
 | 
				
			||||||
 | 
					.Lspec_trap_\@:
 | 
				
			||||||
 | 
						UNWIND_HINT_EMPTY
 | 
				
			||||||
 | 
						pause
 | 
				
			||||||
 | 
						lfence
 | 
				
			||||||
 | 
						jmp	.Lspec_trap_\@
 | 
				
			||||||
 | 
					.Ldo_rop_\@:
 | 
				
			||||||
 | 
						mov	%\reg, (%_ASM_SP)
 | 
				
			||||||
 | 
						UNWIND_HINT_RET_OFFSET
 | 
				
			||||||
 | 
						ret
 | 
				
			||||||
 | 
					SYM_FUNC_END(__x86_retpoline_\reg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.endm
 | 
					.endm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -24,25 +40,24 @@ SYM_FUNC_END(__x86_indirect_thunk_\reg)
 | 
				
			||||||
 * only see one instance of "__x86_indirect_thunk_\reg" rather
 | 
					 * only see one instance of "__x86_indirect_thunk_\reg" rather
 | 
				
			||||||
 * than one per register with the correct names. So we do it
 | 
					 * than one per register with the correct names. So we do it
 | 
				
			||||||
 * the simple and nasty way...
 | 
					 * the simple and nasty way...
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Worse, you can only have a single EXPORT_SYMBOL per line,
 | 
				
			||||||
 | 
					 * and CPP can't insert newlines, so we have to repeat everything
 | 
				
			||||||
 | 
					 * at least twice.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define __EXPORT_THUNK(sym)	_ASM_NOKPROBE(sym); EXPORT_SYMBOL(sym)
 | 
					#define __EXPORT_THUNK(sym)	_ASM_NOKPROBE(sym); EXPORT_SYMBOL(sym)
 | 
				
			||||||
#define EXPORT_THUNK(reg)	__EXPORT_THUNK(__x86_indirect_thunk_ ## reg)
 | 
					#define EXPORT_THUNK(reg)	__EXPORT_THUNK(__x86_indirect_thunk_ ## reg)
 | 
				
			||||||
#define GENERATE_THUNK(reg) THUNK reg ; EXPORT_THUNK(reg)
 | 
					#define EXPORT_RETPOLINE(reg)  __EXPORT_THUNK(__x86_retpoline_ ## reg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GENERATE_THUNK(_ASM_AX)
 | 
					#undef GEN
 | 
				
			||||||
GENERATE_THUNK(_ASM_BX)
 | 
					#define GEN(reg) THUNK reg
 | 
				
			||||||
GENERATE_THUNK(_ASM_CX)
 | 
					#include <asm/GEN-for-each-reg.h>
 | 
				
			||||||
GENERATE_THUNK(_ASM_DX)
 | 
					
 | 
				
			||||||
GENERATE_THUNK(_ASM_SI)
 | 
					#undef GEN
 | 
				
			||||||
GENERATE_THUNK(_ASM_DI)
 | 
					#define GEN(reg) EXPORT_THUNK(reg)
 | 
				
			||||||
GENERATE_THUNK(_ASM_BP)
 | 
					#include <asm/GEN-for-each-reg.h>
 | 
				
			||||||
#ifdef CONFIG_64BIT
 | 
					
 | 
				
			||||||
GENERATE_THUNK(r8)
 | 
					#undef GEN
 | 
				
			||||||
GENERATE_THUNK(r9)
 | 
					#define GEN(reg) EXPORT_RETPOLINE(reg)
 | 
				
			||||||
GENERATE_THUNK(r10)
 | 
					#include <asm/GEN-for-each-reg.h>
 | 
				
			||||||
GENERATE_THUNK(r11)
 | 
					 | 
				
			||||||
GENERATE_THUNK(r12)
 | 
					 | 
				
			||||||
GENERATE_THUNK(r13)
 | 
					 | 
				
			||||||
GENERATE_THUNK(r14)
 | 
					 | 
				
			||||||
GENERATE_THUNK(r15)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ SYM_FUNC_START(__efi_call)
 | 
				
			||||||
	mov %r8, %r9
 | 
						mov %r8, %r9
 | 
				
			||||||
	mov %rcx, %r8
 | 
						mov %rcx, %r8
 | 
				
			||||||
	mov %rsi, %rcx
 | 
						mov %rsi, %rcx
 | 
				
			||||||
	CALL_NOSPEC %rdi
 | 
						CALL_NOSPEC rdi
 | 
				
			||||||
	leave
 | 
						leave
 | 
				
			||||||
	ret
 | 
						ret
 | 
				
			||||||
SYM_FUNC_END(__efi_call)
 | 
					SYM_FUNC_END(__efi_call)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,9 +15,20 @@
 | 
				
			||||||
	static void __used __section(.discard.func_stack_frame_non_standard) \
 | 
						static void __used __section(.discard.func_stack_frame_non_standard) \
 | 
				
			||||||
		*__func_stack_frame_non_standard_##func = func
 | 
							*__func_stack_frame_non_standard_##func = func
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This macro indicates that the following intra-function call is valid.
 | 
				
			||||||
 | 
					 * Any non-annotated intra-function call will cause objtool to issue a warning.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define ANNOTATE_INTRA_FUNCTION_CALL				\
 | 
				
			||||||
 | 
						999:							\
 | 
				
			||||||
 | 
						.pushsection .discard.intra_function_calls;		\
 | 
				
			||||||
 | 
						.long 999b;						\
 | 
				
			||||||
 | 
						.popsection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else /* !CONFIG_STACK_VALIDATION */
 | 
					#else /* !CONFIG_STACK_VALIDATION */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STACK_FRAME_NON_STANDARD(func)
 | 
					#define STACK_FRAME_NON_STANDARD(func)
 | 
				
			||||||
 | 
					#define ANNOTATE_INTRA_FUNCTION_CALL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* CONFIG_STACK_VALIDATION */
 | 
					#endif /* CONFIG_STACK_VALIDATION */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -369,6 +369,11 @@ config STACK_VALIDATION
 | 
				
			||||||
	  For more information, see
 | 
						  For more information, see
 | 
				
			||||||
	  tools/objtool/Documentation/stack-validation.txt.
 | 
						  tools/objtool/Documentation/stack-validation.txt.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config VMLINUX_VALIDATION
 | 
				
			||||||
 | 
						bool
 | 
				
			||||||
 | 
						depends on STACK_VALIDATION && DEBUG_ENTRY && !PARAVIRT
 | 
				
			||||||
 | 
						default y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config DEBUG_FORCE_WEAK_PER_CPU
 | 
					config DEBUG_FORCE_WEAK_PER_CPU
 | 
				
			||||||
	bool "Force weak per-cpu definitions"
 | 
						bool "Force weak per-cpu definitions"
 | 
				
			||||||
	depends on DEBUG_KERNEL
 | 
						depends on DEBUG_KERNEL
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,18 +20,22 @@ static unsigned long my_ip = (unsigned long)schedule;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asm (
 | 
					asm (
 | 
				
			||||||
"	.pushsection    .text, \"ax\", @progbits\n"
 | 
					"	.pushsection    .text, \"ax\", @progbits\n"
 | 
				
			||||||
 | 
					"	.type		my_tramp1, @function\n"
 | 
				
			||||||
"   my_tramp1:"
 | 
					"   my_tramp1:"
 | 
				
			||||||
"	pushq %rbp\n"
 | 
					"	pushq %rbp\n"
 | 
				
			||||||
"	movq %rsp, %rbp\n"
 | 
					"	movq %rsp, %rbp\n"
 | 
				
			||||||
"	call my_direct_func1\n"
 | 
					"	call my_direct_func1\n"
 | 
				
			||||||
"	leave\n"
 | 
					"	leave\n"
 | 
				
			||||||
 | 
					"	.size		my_tramp1, .-my_tramp1\n"
 | 
				
			||||||
"	ret\n"
 | 
					"	ret\n"
 | 
				
			||||||
 | 
					"	.type		my_tramp2, @function\n"
 | 
				
			||||||
"   my_tramp2:"
 | 
					"   my_tramp2:"
 | 
				
			||||||
"	pushq %rbp\n"
 | 
					"	pushq %rbp\n"
 | 
				
			||||||
"	movq %rsp, %rbp\n"
 | 
					"	movq %rsp, %rbp\n"
 | 
				
			||||||
"	call my_direct_func2\n"
 | 
					"	call my_direct_func2\n"
 | 
				
			||||||
"	leave\n"
 | 
					"	leave\n"
 | 
				
			||||||
"	ret\n"
 | 
					"	ret\n"
 | 
				
			||||||
 | 
					"	.size		my_tramp2, .-my_tramp2\n"
 | 
				
			||||||
"	.popsection\n"
 | 
					"	.popsection\n"
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@ extern void my_tramp(void *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asm (
 | 
					asm (
 | 
				
			||||||
"	.pushsection    .text, \"ax\", @progbits\n"
 | 
					"	.pushsection    .text, \"ax\", @progbits\n"
 | 
				
			||||||
 | 
					"	.type		my_tramp, @function\n"
 | 
				
			||||||
"   my_tramp:"
 | 
					"   my_tramp:"
 | 
				
			||||||
"	pushq %rbp\n"
 | 
					"	pushq %rbp\n"
 | 
				
			||||||
"	movq %rsp, %rbp\n"
 | 
					"	movq %rsp, %rbp\n"
 | 
				
			||||||
| 
						 | 
					@ -27,6 +28,7 @@ asm (
 | 
				
			||||||
"	popq %rdi\n"
 | 
					"	popq %rdi\n"
 | 
				
			||||||
"	leave\n"
 | 
					"	leave\n"
 | 
				
			||||||
"	ret\n"
 | 
					"	ret\n"
 | 
				
			||||||
 | 
					"	.size		my_tramp, .-my_tramp\n"
 | 
				
			||||||
"	.popsection\n"
 | 
					"	.popsection\n"
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,7 @@ extern void my_tramp(void *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asm (
 | 
					asm (
 | 
				
			||||||
"	.pushsection    .text, \"ax\", @progbits\n"
 | 
					"	.pushsection    .text, \"ax\", @progbits\n"
 | 
				
			||||||
 | 
					"	.type		my_tramp, @function\n"
 | 
				
			||||||
"   my_tramp:"
 | 
					"   my_tramp:"
 | 
				
			||||||
"	pushq %rbp\n"
 | 
					"	pushq %rbp\n"
 | 
				
			||||||
"	movq %rsp, %rbp\n"
 | 
					"	movq %rsp, %rbp\n"
 | 
				
			||||||
| 
						 | 
					@ -21,6 +22,7 @@ asm (
 | 
				
			||||||
"	popq %rdi\n"
 | 
					"	popq %rdi\n"
 | 
				
			||||||
"	leave\n"
 | 
					"	leave\n"
 | 
				
			||||||
"	ret\n"
 | 
					"	ret\n"
 | 
				
			||||||
 | 
					"	.size		my_tramp, .-my_tramp\n"
 | 
				
			||||||
"	.popsection\n"
 | 
					"	.popsection\n"
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,6 +55,29 @@ modpost_link()
 | 
				
			||||||
	${LD} ${KBUILD_LDFLAGS} -r -o ${1} ${objects}
 | 
						${LD} ${KBUILD_LDFLAGS} -r -o ${1} ${objects}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					objtool_link()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						local objtoolopt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if [ -n "${CONFIG_VMLINUX_VALIDATION}" ]; then
 | 
				
			||||||
 | 
							objtoolopt="check"
 | 
				
			||||||
 | 
							if [ -z "${CONFIG_FRAME_POINTER}" ]; then
 | 
				
			||||||
 | 
								objtoolopt="${objtoolopt} --no-fp"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							if [ -n "${CONFIG_GCOV_KERNEL}" ]; then
 | 
				
			||||||
 | 
								objtoolopt="${objtoolopt} --no-unreachable"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							if [ -n "${CONFIG_RETPOLINE}" ]; then
 | 
				
			||||||
 | 
								objtoolopt="${objtoolopt} --retpoline"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							if [ -n "${CONFIG_X86_SMAP}" ]; then
 | 
				
			||||||
 | 
								objtoolopt="${objtoolopt} --uaccess"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							info OBJTOOL ${1}
 | 
				
			||||||
 | 
							tools/objtool/objtool ${objtoolopt} ${1}
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Link of vmlinux
 | 
					# Link of vmlinux
 | 
				
			||||||
# ${1} - output file
 | 
					# ${1} - output file
 | 
				
			||||||
# ${2}, ${3}, ... - optional extra .o files
 | 
					# ${2}, ${3}, ... - optional extra .o files
 | 
				
			||||||
| 
						 | 
					@ -251,6 +274,7 @@ ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init need-builtin=1
 | 
				
			||||||
#link vmlinux.o
 | 
					#link vmlinux.o
 | 
				
			||||||
info LD vmlinux.o
 | 
					info LD vmlinux.o
 | 
				
			||||||
modpost_link vmlinux.o
 | 
					modpost_link vmlinux.o
 | 
				
			||||||
 | 
					objtool_link vmlinux.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# modpost vmlinux.o to check for section mismatches
 | 
					# modpost vmlinux.o to check for section mismatches
 | 
				
			||||||
${MAKE} -f "${srctree}/scripts/Makefile.modpost" MODPOST_VMLINUX=1
 | 
					${MAKE} -f "${srctree}/scripts/Makefile.modpost" MODPOST_VMLINUX=1
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,8 +58,7 @@
 | 
				
			||||||
#define ORC_TYPE_CALL			0
 | 
					#define ORC_TYPE_CALL			0
 | 
				
			||||||
#define ORC_TYPE_REGS			1
 | 
					#define ORC_TYPE_REGS			1
 | 
				
			||||||
#define ORC_TYPE_REGS_IRET		2
 | 
					#define ORC_TYPE_REGS_IRET		2
 | 
				
			||||||
#define UNWIND_HINT_TYPE_SAVE		3
 | 
					#define UNWIND_HINT_TYPE_RET_OFFSET	3
 | 
				
			||||||
#define UNWIND_HINT_TYPE_RESTORE	4
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef __ASSEMBLY__
 | 
					#ifndef __ASSEMBLY__
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,16 @@
 | 
				
			||||||
objtool-y += arch/$(SRCARCH)/
 | 
					objtool-y += arch/$(SRCARCH)/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					objtool-y += weak.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					objtool-$(SUBCMD_CHECK) += check.o
 | 
				
			||||||
 | 
					objtool-$(SUBCMD_CHECK) += special.o
 | 
				
			||||||
 | 
					objtool-$(SUBCMD_ORC) += check.o
 | 
				
			||||||
 | 
					objtool-$(SUBCMD_ORC) += orc_gen.o
 | 
				
			||||||
 | 
					objtool-$(SUBCMD_ORC) += orc_dump.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
objtool-y += builtin-check.o
 | 
					objtool-y += builtin-check.o
 | 
				
			||||||
objtool-y += builtin-orc.o
 | 
					objtool-y += builtin-orc.o
 | 
				
			||||||
objtool-y += check.o
 | 
					 | 
				
			||||||
objtool-y += orc_gen.o
 | 
					 | 
				
			||||||
objtool-y += orc_dump.o
 | 
					 | 
				
			||||||
objtool-y += elf.o
 | 
					objtool-y += elf.o
 | 
				
			||||||
objtool-y += special.o
 | 
					 | 
				
			||||||
objtool-y += objtool.o
 | 
					objtool-y += objtool.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
objtool-y += libstring.o
 | 
					objtool-y += libstring.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -289,6 +289,47 @@ they mean, and suggestions for how to fix them.
 | 
				
			||||||
      might be corrupt due to a gcc bug.  For more details, see:
 | 
					      might be corrupt due to a gcc bug.  For more details, see:
 | 
				
			||||||
      https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646
 | 
					      https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					9. file.o: warning: objtool: funcA() call to funcB() with UACCESS enabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   This means that an unexpected call to a non-whitelisted function exists
 | 
				
			||||||
 | 
					   outside of arch-specific guards.
 | 
				
			||||||
 | 
					   X86: SMAP (stac/clac): __uaccess_begin()/__uaccess_end()
 | 
				
			||||||
 | 
					   ARM: PAN: uaccess_enable()/uaccess_disable()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   These functions should be called to denote a minimal critical section around
 | 
				
			||||||
 | 
					   access to __user variables. See also: https://lwn.net/Articles/517475/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   The intention of the warning is to prevent calls to funcB() from eventually
 | 
				
			||||||
 | 
					   calling schedule(), potentially leaking the AC flags state, and not
 | 
				
			||||||
 | 
					   restoring them correctly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   It also helps verify that there are no unexpected calls to funcB() which may
 | 
				
			||||||
 | 
					   access user space pages with protections against doing so disabled.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   To fix, either:
 | 
				
			||||||
 | 
					   1) remove explicit calls to funcB() from funcA().
 | 
				
			||||||
 | 
					   2) add the correct guards before and after calls to low level functions like
 | 
				
			||||||
 | 
					      __get_user_size()/__put_user_size().
 | 
				
			||||||
 | 
					   3) add funcB to uaccess_safe_builtin whitelist in tools/objtool/check.c, if
 | 
				
			||||||
 | 
					      funcB obviously does not call schedule(), and is marked notrace (since
 | 
				
			||||||
 | 
					      function tracing inserts additional calls, which is not obvious from the
 | 
				
			||||||
 | 
					      sources).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					10. file.o: warning: func()+0x5c: alternative modifies stack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This means that an alternative includes instructions that modify the
 | 
				
			||||||
 | 
					    stack. The problem is that there is only one ORC unwind table, this means
 | 
				
			||||||
 | 
					    that the ORC unwind entries must be valid for each of the alternatives.
 | 
				
			||||||
 | 
					    The easiest way to enforce this is to ensure alternatives do not contain
 | 
				
			||||||
 | 
					    any ORC entries, which in turn implies the above constraint.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					11. file.o: warning: unannotated intra-function call
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   This warning means that a direct call is done to a destination which
 | 
				
			||||||
 | 
					   is not at the beginning of a function. If this is a legit call, you
 | 
				
			||||||
 | 
					   can remove this warning by putting the ANNOTATE_INTRA_FUNCTION_CALL
 | 
				
			||||||
 | 
					   directive right before the call.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If the error doesn't seem to make sense, it could be a bug in objtool.
 | 
					If the error doesn't seem to make sense, it could be a bug in objtool.
 | 
				
			||||||
Feel free to ask the objtool maintainer for help.
 | 
					Feel free to ask the objtool maintainer for help.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,8 @@ all: $(OBJTOOL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
INCLUDES := -I$(srctree)/tools/include \
 | 
					INCLUDES := -I$(srctree)/tools/include \
 | 
				
			||||||
	    -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \
 | 
						    -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \
 | 
				
			||||||
	    -I$(srctree)/tools/arch/$(SRCARCH)/include
 | 
						    -I$(srctree)/tools/arch/$(SRCARCH)/include	\
 | 
				
			||||||
 | 
						    -I$(srctree)/tools/objtool/arch/$(SRCARCH)/include
 | 
				
			||||||
WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed
 | 
					WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed
 | 
				
			||||||
CFLAGS   := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBELF_FLAGS)
 | 
					CFLAGS   := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBELF_FLAGS)
 | 
				
			||||||
LDFLAGS  += $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS)
 | 
					LDFLAGS  += $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS)
 | 
				
			||||||
| 
						 | 
					@ -45,14 +46,24 @@ elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(CC) $(CFLAGS) -x c -E -
 | 
				
			||||||
CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED)
 | 
					CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AWK = awk
 | 
					AWK = awk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SUBCMD_CHECK := n
 | 
				
			||||||
 | 
					SUBCMD_ORC := n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifeq ($(SRCARCH),x86)
 | 
				
			||||||
 | 
						SUBCMD_CHECK := y
 | 
				
			||||||
 | 
						SUBCMD_ORC := y
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export SUBCMD_CHECK SUBCMD_ORC
 | 
				
			||||||
export srctree OUTPUT CFLAGS SRCARCH AWK
 | 
					export srctree OUTPUT CFLAGS SRCARCH AWK
 | 
				
			||||||
include $(srctree)/tools/build/Makefile.include
 | 
					include $(srctree)/tools/build/Makefile.include
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(OBJTOOL_IN): fixdep FORCE
 | 
					$(OBJTOOL_IN): fixdep FORCE
 | 
				
			||||||
 | 
						@$(CONFIG_SHELL) ./sync-check.sh
 | 
				
			||||||
	@$(MAKE) $(build)=objtool
 | 
						@$(MAKE) $(build)=objtool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN)
 | 
					$(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN)
 | 
				
			||||||
	@$(CONFIG_SHELL) ./sync-check.sh
 | 
					 | 
				
			||||||
	$(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@
 | 
						$(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,9 +8,11 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <linux/list.h>
 | 
					#include <linux/list.h>
 | 
				
			||||||
#include "elf.h"
 | 
					#include "objtool.h"
 | 
				
			||||||
#include "cfi.h"
 | 
					#include "cfi.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/orc_types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum insn_type {
 | 
					enum insn_type {
 | 
				
			||||||
	INSN_JUMP_CONDITIONAL,
 | 
						INSN_JUMP_CONDITIONAL,
 | 
				
			||||||
	INSN_JUMP_UNCONDITIONAL,
 | 
						INSN_JUMP_UNCONDITIONAL,
 | 
				
			||||||
| 
						 | 
					@ -20,7 +22,6 @@ enum insn_type {
 | 
				
			||||||
	INSN_CALL_DYNAMIC,
 | 
						INSN_CALL_DYNAMIC,
 | 
				
			||||||
	INSN_RETURN,
 | 
						INSN_RETURN,
 | 
				
			||||||
	INSN_CONTEXT_SWITCH,
 | 
						INSN_CONTEXT_SWITCH,
 | 
				
			||||||
	INSN_STACK,
 | 
					 | 
				
			||||||
	INSN_BUG,
 | 
						INSN_BUG,
 | 
				
			||||||
	INSN_NOP,
 | 
						INSN_NOP,
 | 
				
			||||||
	INSN_STAC,
 | 
						INSN_STAC,
 | 
				
			||||||
| 
						 | 
					@ -64,15 +65,23 @@ struct op_src {
 | 
				
			||||||
struct stack_op {
 | 
					struct stack_op {
 | 
				
			||||||
	struct op_dest dest;
 | 
						struct op_dest dest;
 | 
				
			||||||
	struct op_src src;
 | 
						struct op_src src;
 | 
				
			||||||
 | 
						struct list_head list;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void arch_initial_func_cfi_state(struct cfi_state *state);
 | 
					struct instruction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
					void arch_initial_func_cfi_state(struct cfi_init_state *state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int arch_decode_instruction(const struct elf *elf, const struct section *sec,
 | 
				
			||||||
			    unsigned long offset, unsigned int maxlen,
 | 
								    unsigned long offset, unsigned int maxlen,
 | 
				
			||||||
			    unsigned int *len, enum insn_type *type,
 | 
								    unsigned int *len, enum insn_type *type,
 | 
				
			||||||
			    unsigned long *immediate, struct stack_op *op);
 | 
								    unsigned long *immediate,
 | 
				
			||||||
 | 
								    struct list_head *ops_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool arch_callee_saved_reg(unsigned char reg);
 | 
					bool arch_callee_saved_reg(unsigned char reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned long arch_jump_destination(struct instruction *insn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned long arch_dest_rela_offset(int addend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ARCH_H */
 | 
					#endif /* _ARCH_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@
 | 
				
			||||||
#include "../../../arch/x86/lib/inat.c"
 | 
					#include "../../../arch/x86/lib/inat.c"
 | 
				
			||||||
#include "../../../arch/x86/lib/insn.c"
 | 
					#include "../../../arch/x86/lib/insn.c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../../check.h"
 | 
				
			||||||
#include "../../elf.h"
 | 
					#include "../../elf.h"
 | 
				
			||||||
#include "../../arch.h"
 | 
					#include "../../arch.h"
 | 
				
			||||||
#include "../../warn.h"
 | 
					#include "../../warn.h"
 | 
				
			||||||
| 
						 | 
					@ -26,7 +27,7 @@ static unsigned char op_to_cfi_reg[][2] = {
 | 
				
			||||||
	{CFI_DI, CFI_R15},
 | 
						{CFI_DI, CFI_R15},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int is_x86_64(struct elf *elf)
 | 
					static int is_x86_64(const struct elf *elf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (elf->ehdr.e_machine) {
 | 
						switch (elf->ehdr.e_machine) {
 | 
				
			||||||
	case EM_X86_64:
 | 
						case EM_X86_64:
 | 
				
			||||||
| 
						 | 
					@ -66,16 +67,34 @@ bool arch_callee_saved_reg(unsigned char reg)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
					unsigned long arch_dest_rela_offset(int addend)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return addend + 4;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned long arch_jump_destination(struct instruction *insn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return insn->offset + insn->len + insn->immediate;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ADD_OP(op) \
 | 
				
			||||||
 | 
						if (!(op = calloc(1, sizeof(*op)))) \
 | 
				
			||||||
 | 
							return -1; \
 | 
				
			||||||
 | 
						else for (list_add_tail(&op->list, ops_list); op; op = NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int arch_decode_instruction(const struct elf *elf, const struct section *sec,
 | 
				
			||||||
			    unsigned long offset, unsigned int maxlen,
 | 
								    unsigned long offset, unsigned int maxlen,
 | 
				
			||||||
			    unsigned int *len, enum insn_type *type,
 | 
								    unsigned int *len, enum insn_type *type,
 | 
				
			||||||
			    unsigned long *immediate, struct stack_op *op)
 | 
								    unsigned long *immediate,
 | 
				
			||||||
 | 
								    struct list_head *ops_list)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct insn insn;
 | 
						struct insn insn;
 | 
				
			||||||
	int x86_64, sign;
 | 
						int x86_64, sign;
 | 
				
			||||||
	unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0,
 | 
						unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0,
 | 
				
			||||||
		      rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0,
 | 
							      rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0,
 | 
				
			||||||
		      modrm_reg = 0, sib = 0;
 | 
							      modrm_reg = 0, sib = 0;
 | 
				
			||||||
 | 
						struct stack_op *op = NULL;
 | 
				
			||||||
 | 
						struct symbol *sym;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	x86_64 = is_x86_64(elf);
 | 
						x86_64 = is_x86_64(elf);
 | 
				
			||||||
	if (x86_64 == -1)
 | 
						if (x86_64 == -1)
 | 
				
			||||||
| 
						 | 
					@ -85,7 +104,7 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
	insn_get_length(&insn);
 | 
						insn_get_length(&insn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!insn_complete(&insn)) {
 | 
						if (!insn_complete(&insn)) {
 | 
				
			||||||
		WARN_FUNC("can't decode instruction", sec, offset);
 | 
							WARN("can't decode instruction at %s:0x%lx", sec->name, offset);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -123,40 +142,44 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
		if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) {
 | 
							if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* add/sub reg, %rsp */
 | 
								/* add/sub reg, %rsp */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_ADD;
 | 
									op->src.type = OP_SRC_ADD;
 | 
				
			||||||
				op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
									op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
				
			||||||
				op->dest.type = OP_DEST_REG;
 | 
									op->dest.type = OP_DEST_REG;
 | 
				
			||||||
				op->dest.reg = CFI_SP;
 | 
									op->dest.reg = CFI_SP;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0x50 ... 0x57:
 | 
						case 0x50 ... 0x57:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* push reg */
 | 
							/* push reg */
 | 
				
			||||||
		*type = INSN_STACK;
 | 
							ADD_OP(op) {
 | 
				
			||||||
			op->src.type = OP_SRC_REG;
 | 
								op->src.type = OP_SRC_REG;
 | 
				
			||||||
			op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b];
 | 
								op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b];
 | 
				
			||||||
			op->dest.type = OP_DEST_PUSH;
 | 
								op->dest.type = OP_DEST_PUSH;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0x58 ... 0x5f:
 | 
						case 0x58 ... 0x5f:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* pop reg */
 | 
							/* pop reg */
 | 
				
			||||||
		*type = INSN_STACK;
 | 
							ADD_OP(op) {
 | 
				
			||||||
			op->src.type = OP_SRC_POP;
 | 
								op->src.type = OP_SRC_POP;
 | 
				
			||||||
			op->dest.type = OP_DEST_REG;
 | 
								op->dest.type = OP_DEST_REG;
 | 
				
			||||||
			op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b];
 | 
								op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0x68:
 | 
						case 0x68:
 | 
				
			||||||
	case 0x6a:
 | 
						case 0x6a:
 | 
				
			||||||
		/* push immediate */
 | 
							/* push immediate */
 | 
				
			||||||
		*type = INSN_STACK;
 | 
							ADD_OP(op) {
 | 
				
			||||||
			op->src.type = OP_SRC_CONST;
 | 
								op->src.type = OP_SRC_CONST;
 | 
				
			||||||
			op->dest.type = OP_DEST_PUSH;
 | 
								op->dest.type = OP_DEST_PUSH;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0x70 ... 0x7f:
 | 
						case 0x70 ... 0x7f:
 | 
				
			||||||
| 
						 | 
					@ -170,12 +193,13 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (modrm == 0xe4) {
 | 
							if (modrm == 0xe4) {
 | 
				
			||||||
			/* and imm, %rsp */
 | 
								/* and imm, %rsp */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_AND;
 | 
									op->src.type = OP_SRC_AND;
 | 
				
			||||||
				op->src.reg = CFI_SP;
 | 
									op->src.reg = CFI_SP;
 | 
				
			||||||
				op->src.offset = insn.immediate.value;
 | 
									op->src.offset = insn.immediate.value;
 | 
				
			||||||
				op->dest.type = OP_DEST_REG;
 | 
									op->dest.type = OP_DEST_REG;
 | 
				
			||||||
				op->dest.reg = CFI_SP;
 | 
									op->dest.reg = CFI_SP;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -187,34 +211,37 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* add/sub imm, %rsp */
 | 
							/* add/sub imm, %rsp */
 | 
				
			||||||
		*type = INSN_STACK;
 | 
							ADD_OP(op) {
 | 
				
			||||||
			op->src.type = OP_SRC_ADD;
 | 
								op->src.type = OP_SRC_ADD;
 | 
				
			||||||
			op->src.reg = CFI_SP;
 | 
								op->src.reg = CFI_SP;
 | 
				
			||||||
			op->src.offset = insn.immediate.value * sign;
 | 
								op->src.offset = insn.immediate.value * sign;
 | 
				
			||||||
			op->dest.type = OP_DEST_REG;
 | 
								op->dest.type = OP_DEST_REG;
 | 
				
			||||||
			op->dest.reg = CFI_SP;
 | 
								op->dest.reg = CFI_SP;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0x89:
 | 
						case 0x89:
 | 
				
			||||||
		if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) {
 | 
							if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* mov %rsp, reg */
 | 
								/* mov %rsp, reg */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_REG;
 | 
									op->src.type = OP_SRC_REG;
 | 
				
			||||||
				op->src.reg = CFI_SP;
 | 
									op->src.reg = CFI_SP;
 | 
				
			||||||
				op->dest.type = OP_DEST_REG;
 | 
									op->dest.type = OP_DEST_REG;
 | 
				
			||||||
				op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b];
 | 
									op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) {
 | 
							if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* mov reg, %rsp */
 | 
								/* mov reg, %rsp */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_REG;
 | 
									op->src.type = OP_SRC_REG;
 | 
				
			||||||
				op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
									op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
				
			||||||
				op->dest.type = OP_DEST_REG;
 | 
									op->dest.type = OP_DEST_REG;
 | 
				
			||||||
				op->dest.reg = CFI_SP;
 | 
									op->dest.reg = CFI_SP;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -224,23 +251,25 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
		    (modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) {
 | 
							    (modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* mov reg, disp(%rbp) */
 | 
								/* mov reg, disp(%rbp) */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_REG;
 | 
									op->src.type = OP_SRC_REG;
 | 
				
			||||||
				op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
									op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
				
			||||||
				op->dest.type = OP_DEST_REG_INDIRECT;
 | 
									op->dest.type = OP_DEST_REG_INDIRECT;
 | 
				
			||||||
				op->dest.reg = CFI_BP;
 | 
									op->dest.reg = CFI_BP;
 | 
				
			||||||
				op->dest.offset = insn.displacement.value;
 | 
									op->dest.offset = insn.displacement.value;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) {
 | 
							} else if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* mov reg, disp(%rsp) */
 | 
								/* mov reg, disp(%rsp) */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_REG;
 | 
									op->src.type = OP_SRC_REG;
 | 
				
			||||||
				op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
									op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
				
			||||||
				op->dest.type = OP_DEST_REG_INDIRECT;
 | 
									op->dest.type = OP_DEST_REG_INDIRECT;
 | 
				
			||||||
				op->dest.reg = CFI_SP;
 | 
									op->dest.reg = CFI_SP;
 | 
				
			||||||
				op->dest.offset = insn.displacement.value;
 | 
									op->dest.offset = insn.displacement.value;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -248,31 +277,33 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
		if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) {
 | 
							if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* mov disp(%rbp), reg */
 | 
								/* mov disp(%rbp), reg */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_REG_INDIRECT;
 | 
									op->src.type = OP_SRC_REG_INDIRECT;
 | 
				
			||||||
				op->src.reg = CFI_BP;
 | 
									op->src.reg = CFI_BP;
 | 
				
			||||||
				op->src.offset = insn.displacement.value;
 | 
									op->src.offset = insn.displacement.value;
 | 
				
			||||||
				op->dest.type = OP_DEST_REG;
 | 
									op->dest.type = OP_DEST_REG;
 | 
				
			||||||
				op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
									op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else if (rex_w && !rex_b && sib == 0x24 &&
 | 
							} else if (rex_w && !rex_b && sib == 0x24 &&
 | 
				
			||||||
			   modrm_mod != 3 && modrm_rm == 4) {
 | 
								   modrm_mod != 3 && modrm_rm == 4) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* mov disp(%rsp), reg */
 | 
								/* mov disp(%rsp), reg */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_REG_INDIRECT;
 | 
									op->src.type = OP_SRC_REG_INDIRECT;
 | 
				
			||||||
				op->src.reg = CFI_SP;
 | 
									op->src.reg = CFI_SP;
 | 
				
			||||||
				op->src.offset = insn.displacement.value;
 | 
									op->src.offset = insn.displacement.value;
 | 
				
			||||||
				op->dest.type = OP_DEST_REG;
 | 
									op->dest.type = OP_DEST_REG;
 | 
				
			||||||
				op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
									op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0x8d:
 | 
						case 0x8d:
 | 
				
			||||||
		if (sib == 0x24 && rex_w && !rex_b && !rex_x) {
 | 
							if (sib == 0x24 && rex_w && !rex_b && !rex_x) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				if (!insn.displacement.value) {
 | 
									if (!insn.displacement.value) {
 | 
				
			||||||
					/* lea (%rsp), reg */
 | 
										/* lea (%rsp), reg */
 | 
				
			||||||
					op->src.type = OP_SRC_REG;
 | 
										op->src.type = OP_SRC_REG;
 | 
				
			||||||
| 
						 | 
					@ -284,16 +315,18 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
				op->src.reg = CFI_SP;
 | 
									op->src.reg = CFI_SP;
 | 
				
			||||||
				op->dest.type = OP_DEST_REG;
 | 
									op->dest.type = OP_DEST_REG;
 | 
				
			||||||
				op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
									op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else if (rex == 0x48 && modrm == 0x65) {
 | 
							} else if (rex == 0x48 && modrm == 0x65) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* lea disp(%rbp), %rsp */
 | 
								/* lea disp(%rbp), %rsp */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_ADD;
 | 
									op->src.type = OP_SRC_ADD;
 | 
				
			||||||
				op->src.reg = CFI_BP;
 | 
									op->src.reg = CFI_BP;
 | 
				
			||||||
				op->src.offset = insn.displacement.value;
 | 
									op->src.offset = insn.displacement.value;
 | 
				
			||||||
				op->dest.type = OP_DEST_REG;
 | 
									op->dest.type = OP_DEST_REG;
 | 
				
			||||||
				op->dest.reg = CFI_SP;
 | 
									op->dest.reg = CFI_SP;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else if (rex == 0x49 && modrm == 0x62 &&
 | 
							} else if (rex == 0x49 && modrm == 0x62 &&
 | 
				
			||||||
			   insn.displacement.value == -8) {
 | 
								   insn.displacement.value == -8) {
 | 
				
			||||||
| 
						 | 
					@ -304,12 +337,13 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
			 * Restoring rsp back to its original value after a
 | 
								 * Restoring rsp back to its original value after a
 | 
				
			||||||
			 * stack realignment.
 | 
								 * stack realignment.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_ADD;
 | 
									op->src.type = OP_SRC_ADD;
 | 
				
			||||||
				op->src.reg = CFI_R10;
 | 
									op->src.reg = CFI_R10;
 | 
				
			||||||
				op->src.offset = -8;
 | 
									op->src.offset = -8;
 | 
				
			||||||
				op->dest.type = OP_DEST_REG;
 | 
									op->dest.type = OP_DEST_REG;
 | 
				
			||||||
				op->dest.reg = CFI_SP;
 | 
									op->dest.reg = CFI_SP;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else if (rex == 0x49 && modrm == 0x65 &&
 | 
							} else if (rex == 0x49 && modrm == 0x65 &&
 | 
				
			||||||
			   insn.displacement.value == -16) {
 | 
								   insn.displacement.value == -16) {
 | 
				
			||||||
| 
						 | 
					@ -320,21 +354,23 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
			 * Restoring rsp back to its original value after a
 | 
								 * Restoring rsp back to its original value after a
 | 
				
			||||||
			 * stack realignment.
 | 
								 * stack realignment.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_ADD;
 | 
									op->src.type = OP_SRC_ADD;
 | 
				
			||||||
				op->src.reg = CFI_R13;
 | 
									op->src.reg = CFI_R13;
 | 
				
			||||||
				op->src.offset = -16;
 | 
									op->src.offset = -16;
 | 
				
			||||||
				op->dest.type = OP_DEST_REG;
 | 
									op->dest.type = OP_DEST_REG;
 | 
				
			||||||
				op->dest.reg = CFI_SP;
 | 
									op->dest.reg = CFI_SP;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0x8f:
 | 
						case 0x8f:
 | 
				
			||||||
		/* pop to mem */
 | 
							/* pop to mem */
 | 
				
			||||||
		*type = INSN_STACK;
 | 
							ADD_OP(op) {
 | 
				
			||||||
			op->src.type = OP_SRC_POP;
 | 
								op->src.type = OP_SRC_POP;
 | 
				
			||||||
			op->dest.type = OP_DEST_MEM;
 | 
								op->dest.type = OP_DEST_MEM;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0x90:
 | 
						case 0x90:
 | 
				
			||||||
| 
						 | 
					@ -343,16 +379,18 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0x9c:
 | 
						case 0x9c:
 | 
				
			||||||
		/* pushf */
 | 
							/* pushf */
 | 
				
			||||||
		*type = INSN_STACK;
 | 
							ADD_OP(op) {
 | 
				
			||||||
			op->src.type = OP_SRC_CONST;
 | 
								op->src.type = OP_SRC_CONST;
 | 
				
			||||||
			op->dest.type = OP_DEST_PUSHF;
 | 
								op->dest.type = OP_DEST_PUSHF;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0x9d:
 | 
						case 0x9d:
 | 
				
			||||||
		/* popf */
 | 
							/* popf */
 | 
				
			||||||
		*type = INSN_STACK;
 | 
							ADD_OP(op) {
 | 
				
			||||||
			op->src.type = OP_SRC_POPF;
 | 
								op->src.type = OP_SRC_POPF;
 | 
				
			||||||
			op->dest.type = OP_DEST_MEM;
 | 
								op->dest.type = OP_DEST_MEM;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0x0f:
 | 
						case 0x0f:
 | 
				
			||||||
| 
						 | 
					@ -387,17 +425,19 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
		} else if (op2 == 0xa0 || op2 == 0xa8) {
 | 
							} else if (op2 == 0xa0 || op2 == 0xa8) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* push fs/gs */
 | 
								/* push fs/gs */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_CONST;
 | 
									op->src.type = OP_SRC_CONST;
 | 
				
			||||||
				op->dest.type = OP_DEST_PUSH;
 | 
									op->dest.type = OP_DEST_PUSH;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else if (op2 == 0xa1 || op2 == 0xa9) {
 | 
							} else if (op2 == 0xa1 || op2 == 0xa9) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* pop fs/gs */
 | 
								/* pop fs/gs */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_POP;
 | 
									op->src.type = OP_SRC_POP;
 | 
				
			||||||
				op->dest.type = OP_DEST_MEM;
 | 
									op->dest.type = OP_DEST_MEM;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -409,7 +449,7 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
		 * mov bp, sp
 | 
							 * mov bp, sp
 | 
				
			||||||
		 * pop bp
 | 
							 * pop bp
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		*type = INSN_STACK;
 | 
							ADD_OP(op)
 | 
				
			||||||
			op->dest.type = OP_DEST_LEAVE;
 | 
								op->dest.type = OP_DEST_LEAVE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -429,14 +469,41 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
		*type = INSN_RETURN;
 | 
							*type = INSN_RETURN;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case 0xcf: /* iret */
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Handle sync_core(), which has an IRET to self.
 | 
				
			||||||
 | 
							 * All other IRET are in STT_NONE entry code.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							sym = find_symbol_containing(sec, offset);
 | 
				
			||||||
 | 
							if (sym && sym->type == STT_FUNC) {
 | 
				
			||||||
 | 
								ADD_OP(op) {
 | 
				
			||||||
 | 
									/* add $40, %rsp */
 | 
				
			||||||
 | 
									op->src.type = OP_SRC_ADD;
 | 
				
			||||||
 | 
									op->src.reg = CFI_SP;
 | 
				
			||||||
 | 
									op->src.offset = 5*8;
 | 
				
			||||||
 | 
									op->dest.type = OP_DEST_REG;
 | 
				
			||||||
 | 
									op->dest.reg = CFI_SP;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* fallthrough */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0xca: /* retf */
 | 
						case 0xca: /* retf */
 | 
				
			||||||
	case 0xcb: /* retf */
 | 
						case 0xcb: /* retf */
 | 
				
			||||||
	case 0xcf: /* iret */
 | 
					 | 
				
			||||||
		*type = INSN_CONTEXT_SWITCH;
 | 
							*type = INSN_CONTEXT_SWITCH;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0xe8:
 | 
						case 0xe8:
 | 
				
			||||||
		*type = INSN_CALL;
 | 
							*type = INSN_CALL;
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * For the impact on the stack, a CALL behaves like
 | 
				
			||||||
 | 
							 * a PUSH of an immediate value (the return address).
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							ADD_OP(op) {
 | 
				
			||||||
 | 
								op->src.type = OP_SRC_CONST;
 | 
				
			||||||
 | 
								op->dest.type = OP_DEST_PUSH;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 0xfc:
 | 
						case 0xfc:
 | 
				
			||||||
| 
						 | 
					@ -464,10 +531,11 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
		else if (modrm_reg == 6) {
 | 
							else if (modrm_reg == 6) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* push from mem */
 | 
								/* push from mem */
 | 
				
			||||||
			*type = INSN_STACK;
 | 
								ADD_OP(op) {
 | 
				
			||||||
				op->src.type = OP_SRC_CONST;
 | 
									op->src.type = OP_SRC_CONST;
 | 
				
			||||||
				op->dest.type = OP_DEST_PUSH;
 | 
									op->dest.type = OP_DEST_PUSH;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -480,7 +548,7 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void arch_initial_func_cfi_state(struct cfi_state *state)
 | 
					void arch_initial_func_cfi_state(struct cfi_init_state *state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								tools/objtool/arch/x86/include/cfi_regs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tools/objtool/arch/x86/include/cfi_regs.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					/* SPDX-License-Identifier: GPL-2.0-or-later */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _OBJTOOL_CFI_REGS_H
 | 
				
			||||||
 | 
					#define _OBJTOOL_CFI_REGS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CFI_AX			0
 | 
				
			||||||
 | 
					#define CFI_DX			1
 | 
				
			||||||
 | 
					#define CFI_CX			2
 | 
				
			||||||
 | 
					#define CFI_BX			3
 | 
				
			||||||
 | 
					#define CFI_SI			4
 | 
				
			||||||
 | 
					#define CFI_DI			5
 | 
				
			||||||
 | 
					#define CFI_BP			6
 | 
				
			||||||
 | 
					#define CFI_SP			7
 | 
				
			||||||
 | 
					#define CFI_R8			8
 | 
				
			||||||
 | 
					#define CFI_R9			9
 | 
				
			||||||
 | 
					#define CFI_R10			10
 | 
				
			||||||
 | 
					#define CFI_R11			11
 | 
				
			||||||
 | 
					#define CFI_R12			12
 | 
				
			||||||
 | 
					#define CFI_R13			13
 | 
				
			||||||
 | 
					#define CFI_R14			14
 | 
				
			||||||
 | 
					#define CFI_R15			15
 | 
				
			||||||
 | 
					#define CFI_RA			16
 | 
				
			||||||
 | 
					#define CFI_NUM_REGS		17
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _OBJTOOL_CFI_REGS_H */
 | 
				
			||||||
| 
						 | 
					@ -14,10 +14,11 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <subcmd/parse-options.h>
 | 
					#include <subcmd/parse-options.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
#include "builtin.h"
 | 
					#include "builtin.h"
 | 
				
			||||||
#include "check.h"
 | 
					#include "objtool.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats;
 | 
					bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, validate_dup, vmlinux;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char * const check_usage[] = {
 | 
					static const char * const check_usage[] = {
 | 
				
			||||||
	"objtool check [<options>] file.o",
 | 
						"objtool check [<options>] file.o",
 | 
				
			||||||
| 
						 | 
					@ -32,12 +33,14 @@ const struct option check_options[] = {
 | 
				
			||||||
	OPT_BOOLEAN('b', "backtrace", &backtrace, "unwind on error"),
 | 
						OPT_BOOLEAN('b', "backtrace", &backtrace, "unwind on error"),
 | 
				
			||||||
	OPT_BOOLEAN('a', "uaccess", &uaccess, "enable uaccess checking"),
 | 
						OPT_BOOLEAN('a', "uaccess", &uaccess, "enable uaccess checking"),
 | 
				
			||||||
	OPT_BOOLEAN('s', "stats", &stats, "print statistics"),
 | 
						OPT_BOOLEAN('s', "stats", &stats, "print statistics"),
 | 
				
			||||||
 | 
						OPT_BOOLEAN('d', "duplicate", &validate_dup, "duplicate validation for vmlinux.o"),
 | 
				
			||||||
 | 
						OPT_BOOLEAN('l', "vmlinux", &vmlinux, "vmlinux.o validation"),
 | 
				
			||||||
	OPT_END(),
 | 
						OPT_END(),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int cmd_check(int argc, const char **argv)
 | 
					int cmd_check(int argc, const char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *objname;
 | 
						const char *objname, *s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	argc = parse_options(argc, argv, check_options, check_usage, 0);
 | 
						argc = parse_options(argc, argv, check_options, check_usage, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,5 +49,9 @@ int cmd_check(int argc, const char **argv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	objname = argv[0];
 | 
						objname = argv[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						s = strstr(objname, "vmlinux.o");
 | 
				
			||||||
 | 
						if (s && !s[9])
 | 
				
			||||||
 | 
							vmlinux = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return check(objname, false);
 | 
						return check(objname, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,8 +14,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include "builtin.h"
 | 
					#include "builtin.h"
 | 
				
			||||||
#include "check.h"
 | 
					#include "objtool.h"
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *orc_usage[] = {
 | 
					static const char *orc_usage[] = {
 | 
				
			||||||
	"objtool orc generate [<options>] file.o",
 | 
						"objtool orc generate [<options>] file.o",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@
 | 
				
			||||||
#include <subcmd/parse-options.h>
 | 
					#include <subcmd/parse-options.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const struct option check_options[];
 | 
					extern const struct option check_options[];
 | 
				
			||||||
extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats;
 | 
					extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, validate_dup, vmlinux;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int cmd_check(int argc, const char **argv);
 | 
					extern int cmd_check(int argc, const char **argv);
 | 
				
			||||||
extern int cmd_orc(int argc, const char **argv);
 | 
					extern int cmd_orc(int argc, const char **argv);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,38 +6,33 @@
 | 
				
			||||||
#ifndef _OBJTOOL_CFI_H
 | 
					#ifndef _OBJTOOL_CFI_H
 | 
				
			||||||
#define _OBJTOOL_CFI_H
 | 
					#define _OBJTOOL_CFI_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "cfi_regs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CFI_UNDEFINED		-1
 | 
					#define CFI_UNDEFINED		-1
 | 
				
			||||||
#define CFI_CFA			-2
 | 
					#define CFI_CFA			-2
 | 
				
			||||||
#define CFI_SP_INDIRECT		-3
 | 
					#define CFI_SP_INDIRECT		-3
 | 
				
			||||||
#define CFI_BP_INDIRECT		-4
 | 
					#define CFI_BP_INDIRECT		-4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CFI_AX			0
 | 
					 | 
				
			||||||
#define CFI_DX			1
 | 
					 | 
				
			||||||
#define CFI_CX			2
 | 
					 | 
				
			||||||
#define CFI_BX			3
 | 
					 | 
				
			||||||
#define CFI_SI			4
 | 
					 | 
				
			||||||
#define CFI_DI			5
 | 
					 | 
				
			||||||
#define CFI_BP			6
 | 
					 | 
				
			||||||
#define CFI_SP			7
 | 
					 | 
				
			||||||
#define CFI_R8			8
 | 
					 | 
				
			||||||
#define CFI_R9			9
 | 
					 | 
				
			||||||
#define CFI_R10			10
 | 
					 | 
				
			||||||
#define CFI_R11			11
 | 
					 | 
				
			||||||
#define CFI_R12			12
 | 
					 | 
				
			||||||
#define CFI_R13			13
 | 
					 | 
				
			||||||
#define CFI_R14			14
 | 
					 | 
				
			||||||
#define CFI_R15			15
 | 
					 | 
				
			||||||
#define CFI_RA			16
 | 
					 | 
				
			||||||
#define CFI_NUM_REGS		17
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct cfi_reg {
 | 
					struct cfi_reg {
 | 
				
			||||||
	int base;
 | 
						int base;
 | 
				
			||||||
	int offset;
 | 
						int offset;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cfi_state {
 | 
					struct cfi_init_state {
 | 
				
			||||||
	struct cfi_reg cfa;
 | 
					 | 
				
			||||||
	struct cfi_reg regs[CFI_NUM_REGS];
 | 
						struct cfi_reg regs[CFI_NUM_REGS];
 | 
				
			||||||
 | 
						struct cfi_reg cfa;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cfi_state {
 | 
				
			||||||
 | 
						struct cfi_reg regs[CFI_NUM_REGS];
 | 
				
			||||||
 | 
						struct cfi_reg vals[CFI_NUM_REGS];
 | 
				
			||||||
 | 
						struct cfi_reg cfa;
 | 
				
			||||||
 | 
						int stack_size;
 | 
				
			||||||
 | 
						int drap_reg, drap_offset;
 | 
				
			||||||
 | 
						unsigned char type;
 | 
				
			||||||
 | 
						bool bp_scratch;
 | 
				
			||||||
 | 
						bool drap;
 | 
				
			||||||
 | 
						bool end;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _OBJTOOL_CFI_H */
 | 
					#endif /* _OBJTOOL_CFI_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -7,22 +7,16 @@
 | 
				
			||||||
#define _CHECK_H
 | 
					#define _CHECK_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include "elf.h"
 | 
					 | 
				
			||||||
#include "cfi.h"
 | 
					#include "cfi.h"
 | 
				
			||||||
#include "arch.h"
 | 
					#include "arch.h"
 | 
				
			||||||
#include "orc.h"
 | 
					 | 
				
			||||||
#include <linux/hashtable.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct insn_state {
 | 
					struct insn_state {
 | 
				
			||||||
	struct cfi_reg cfa;
 | 
						struct cfi_state cfi;
 | 
				
			||||||
	struct cfi_reg regs[CFI_NUM_REGS];
 | 
					 | 
				
			||||||
	int stack_size;
 | 
					 | 
				
			||||||
	unsigned char type;
 | 
					 | 
				
			||||||
	bool bp_scratch;
 | 
					 | 
				
			||||||
	bool drap, end, uaccess, df;
 | 
					 | 
				
			||||||
	unsigned int uaccess_stack;
 | 
						unsigned int uaccess_stack;
 | 
				
			||||||
	int drap_reg, drap_offset;
 | 
						bool uaccess;
 | 
				
			||||||
	struct cfi_reg vals[CFI_NUM_REGS];
 | 
						bool df;
 | 
				
			||||||
 | 
						bool noinstr;
 | 
				
			||||||
 | 
						s8 instr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct instruction {
 | 
					struct instruction {
 | 
				
			||||||
| 
						 | 
					@ -33,29 +27,24 @@ struct instruction {
 | 
				
			||||||
	unsigned int len;
 | 
						unsigned int len;
 | 
				
			||||||
	enum insn_type type;
 | 
						enum insn_type type;
 | 
				
			||||||
	unsigned long immediate;
 | 
						unsigned long immediate;
 | 
				
			||||||
	bool alt_group, dead_end, ignore, hint, save, restore, ignore_alts;
 | 
						bool dead_end, ignore, ignore_alts;
 | 
				
			||||||
 | 
						bool hint;
 | 
				
			||||||
	bool retpoline_safe;
 | 
						bool retpoline_safe;
 | 
				
			||||||
 | 
						s8 instr;
 | 
				
			||||||
	u8 visited;
 | 
						u8 visited;
 | 
				
			||||||
 | 
						u8 ret_offset;
 | 
				
			||||||
 | 
						int alt_group;
 | 
				
			||||||
	struct symbol *call_dest;
 | 
						struct symbol *call_dest;
 | 
				
			||||||
	struct instruction *jump_dest;
 | 
						struct instruction *jump_dest;
 | 
				
			||||||
	struct instruction *first_jump_src;
 | 
						struct instruction *first_jump_src;
 | 
				
			||||||
	struct rela *jump_table;
 | 
						struct rela *jump_table;
 | 
				
			||||||
	struct list_head alts;
 | 
						struct list_head alts;
 | 
				
			||||||
	struct symbol *func;
 | 
						struct symbol *func;
 | 
				
			||||||
	struct stack_op stack_op;
 | 
						struct list_head stack_ops;
 | 
				
			||||||
	struct insn_state state;
 | 
						struct cfi_state cfi;
 | 
				
			||||||
	struct orc_entry orc;
 | 
						struct orc_entry orc;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct objtool_file {
 | 
					 | 
				
			||||||
	struct elf *elf;
 | 
					 | 
				
			||||||
	struct list_head insn_list;
 | 
					 | 
				
			||||||
	DECLARE_HASHTABLE(insn_hash, 20);
 | 
					 | 
				
			||||||
	bool ignore_unreachables, c_file, hints, rodata;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int check(const char *objname, bool orc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct instruction *find_insn(struct objtool_file *file,
 | 
					struct instruction *find_insn(struct objtool_file *file,
 | 
				
			||||||
			      struct section *sec, unsigned long offset);
 | 
								      struct section *sec, unsigned long offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,22 @@ static inline u32 str_hash(const char *str)
 | 
				
			||||||
	return jhash(str, strlen(str), 0);
 | 
						return jhash(str, strlen(str), 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int elf_hash_bits(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return vmlinux ? ELF_HASH_BITS : 16;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define elf_hash_add(hashtable, node, key) \
 | 
				
			||||||
 | 
						hlist_add_head(node, &hashtable[hash_min(key, elf_hash_bits())])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void elf_hash_init(struct hlist_head *table)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						__hash_init(table, 1U << elf_hash_bits());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define elf_hash_for_each_possible(name, obj, member, key)			\
 | 
				
			||||||
 | 
						hlist_for_each_entry(obj, &name[hash_min(key, elf_hash_bits())], member)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void rb_add(struct rb_root *tree, struct rb_node *node,
 | 
					static void rb_add(struct rb_root *tree, struct rb_node *node,
 | 
				
			||||||
		   int (*cmp)(struct rb_node *, const struct rb_node *))
 | 
							   int (*cmp)(struct rb_node *, const struct rb_node *))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -45,7 +61,7 @@ static void rb_add(struct rb_root *tree, struct rb_node *node,
 | 
				
			||||||
	rb_insert_color(node, tree);
 | 
						rb_insert_color(node, tree);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rb_node *rb_find_first(struct rb_root *tree, const void *key,
 | 
					static struct rb_node *rb_find_first(const struct rb_root *tree, const void *key,
 | 
				
			||||||
			       int (*cmp)(const void *key, const struct rb_node *))
 | 
								       int (*cmp)(const void *key, const struct rb_node *))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rb_node *node = tree->rb_node;
 | 
						struct rb_node *node = tree->rb_node;
 | 
				
			||||||
| 
						 | 
					@ -111,11 +127,11 @@ static int symbol_by_offset(const void *key, const struct rb_node *node)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct section *find_section_by_name(struct elf *elf, const char *name)
 | 
					struct section *find_section_by_name(const struct elf *elf, const char *name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct section *sec;
 | 
						struct section *sec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name))
 | 
						elf_hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name))
 | 
				
			||||||
		if (!strcmp(sec->name, name))
 | 
							if (!strcmp(sec->name, name))
 | 
				
			||||||
			return sec;
 | 
								return sec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,7 +143,7 @@ static struct section *find_section_by_index(struct elf *elf,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct section *sec;
 | 
						struct section *sec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hash_for_each_possible(elf->section_hash, sec, hash, idx)
 | 
						elf_hash_for_each_possible(elf->section_hash, sec, hash, idx)
 | 
				
			||||||
		if (sec->idx == idx)
 | 
							if (sec->idx == idx)
 | 
				
			||||||
			return sec;
 | 
								return sec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,7 +154,7 @@ static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct symbol *sym;
 | 
						struct symbol *sym;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hash_for_each_possible(elf->symbol_hash, sym, hash, idx)
 | 
						elf_hash_for_each_possible(elf->symbol_hash, sym, hash, idx)
 | 
				
			||||||
		if (sym->idx == idx)
 | 
							if (sym->idx == idx)
 | 
				
			||||||
			return sym;
 | 
								return sym;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -173,7 +189,7 @@ struct symbol *find_func_by_offset(struct section *sec, unsigned long offset)
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct symbol *find_symbol_containing(struct section *sec, unsigned long offset)
 | 
					struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rb_node *node;
 | 
						struct rb_node *node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -201,18 +217,18 @@ struct symbol *find_func_containing(struct section *sec, unsigned long offset)
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct symbol *find_symbol_by_name(struct elf *elf, const char *name)
 | 
					struct symbol *find_symbol_by_name(const struct elf *elf, const char *name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct symbol *sym;
 | 
						struct symbol *sym;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name))
 | 
						elf_hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name))
 | 
				
			||||||
		if (!strcmp(sym->name, name))
 | 
							if (!strcmp(sym->name, name))
 | 
				
			||||||
			return sym;
 | 
								return sym;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec,
 | 
					struct rela *find_rela_by_dest_range(const struct elf *elf, struct section *sec,
 | 
				
			||||||
				     unsigned long offset, unsigned int len)
 | 
									     unsigned long offset, unsigned int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rela *rela, *r = NULL;
 | 
						struct rela *rela, *r = NULL;
 | 
				
			||||||
| 
						 | 
					@ -224,7 +240,7 @@ struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec,
 | 
				
			||||||
	sec = sec->rela;
 | 
						sec = sec->rela;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_offset_range(o, offset, offset + len) {
 | 
						for_offset_range(o, offset, offset + len) {
 | 
				
			||||||
		hash_for_each_possible(elf->rela_hash, rela, hash,
 | 
							elf_hash_for_each_possible(elf->rela_hash, rela, hash,
 | 
				
			||||||
				       sec_offset_hash(sec, o)) {
 | 
									       sec_offset_hash(sec, o)) {
 | 
				
			||||||
			if (rela->sec != sec)
 | 
								if (rela->sec != sec)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
| 
						 | 
					@ -241,7 +257,7 @@ struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec,
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rela *find_rela_by_dest(struct elf *elf, struct section *sec, unsigned long offset)
 | 
					struct rela *find_rela_by_dest(const struct elf *elf, struct section *sec, unsigned long offset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return find_rela_by_dest_range(elf, sec, offset, 1);
 | 
						return find_rela_by_dest_range(elf, sec, offset, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -309,8 +325,8 @@ static int read_sections(struct elf *elf)
 | 
				
			||||||
		sec->len = sec->sh.sh_size;
 | 
							sec->len = sec->sh.sh_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		list_add_tail(&sec->list, &elf->sections);
 | 
							list_add_tail(&sec->list, &elf->sections);
 | 
				
			||||||
		hash_add(elf->section_hash, &sec->hash, sec->idx);
 | 
							elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
 | 
				
			||||||
		hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
 | 
							elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (stats)
 | 
						if (stats)
 | 
				
			||||||
| 
						 | 
					@ -327,12 +343,14 @@ static int read_sections(struct elf *elf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int read_symbols(struct elf *elf)
 | 
					static int read_symbols(struct elf *elf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct section *symtab, *sec;
 | 
						struct section *symtab, *symtab_shndx, *sec;
 | 
				
			||||||
	struct symbol *sym, *pfunc;
 | 
						struct symbol *sym, *pfunc;
 | 
				
			||||||
	struct list_head *entry;
 | 
						struct list_head *entry;
 | 
				
			||||||
	struct rb_node *pnode;
 | 
						struct rb_node *pnode;
 | 
				
			||||||
	int symbols_nr, i;
 | 
						int symbols_nr, i;
 | 
				
			||||||
	char *coldstr;
 | 
						char *coldstr;
 | 
				
			||||||
 | 
						Elf_Data *shndx_data = NULL;
 | 
				
			||||||
 | 
						Elf32_Word shndx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	symtab = find_section_by_name(elf, ".symtab");
 | 
						symtab = find_section_by_name(elf, ".symtab");
 | 
				
			||||||
	if (!symtab) {
 | 
						if (!symtab) {
 | 
				
			||||||
| 
						 | 
					@ -340,6 +358,10 @@ static int read_symbols(struct elf *elf)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
 | 
				
			||||||
 | 
						if (symtab_shndx)
 | 
				
			||||||
 | 
							shndx_data = symtab_shndx->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
 | 
						symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < symbols_nr; i++) {
 | 
						for (i = 0; i < symbols_nr; i++) {
 | 
				
			||||||
| 
						 | 
					@ -353,8 +375,9 @@ static int read_symbols(struct elf *elf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sym->idx = i;
 | 
							sym->idx = i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!gelf_getsym(symtab->data, i, &sym->sym)) {
 | 
							if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
 | 
				
			||||||
			WARN_ELF("gelf_getsym");
 | 
									      &shndx)) {
 | 
				
			||||||
 | 
								WARN_ELF("gelf_getsymshndx");
 | 
				
			||||||
			goto err;
 | 
								goto err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -368,10 +391,13 @@ static int read_symbols(struct elf *elf)
 | 
				
			||||||
		sym->type = GELF_ST_TYPE(sym->sym.st_info);
 | 
							sym->type = GELF_ST_TYPE(sym->sym.st_info);
 | 
				
			||||||
		sym->bind = GELF_ST_BIND(sym->sym.st_info);
 | 
							sym->bind = GELF_ST_BIND(sym->sym.st_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (sym->sym.st_shndx > SHN_UNDEF &&
 | 
							if ((sym->sym.st_shndx > SHN_UNDEF &&
 | 
				
			||||||
		    sym->sym.st_shndx < SHN_LORESERVE) {
 | 
							     sym->sym.st_shndx < SHN_LORESERVE) ||
 | 
				
			||||||
			sym->sec = find_section_by_index(elf,
 | 
							    (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) {
 | 
				
			||||||
							 sym->sym.st_shndx);
 | 
								if (sym->sym.st_shndx != SHN_XINDEX)
 | 
				
			||||||
 | 
									shndx = sym->sym.st_shndx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								sym->sec = find_section_by_index(elf, shndx);
 | 
				
			||||||
			if (!sym->sec) {
 | 
								if (!sym->sec) {
 | 
				
			||||||
				WARN("couldn't find section for symbol %s",
 | 
									WARN("couldn't find section for symbol %s",
 | 
				
			||||||
				     sym->name);
 | 
									     sym->name);
 | 
				
			||||||
| 
						 | 
					@ -394,8 +420,8 @@ static int read_symbols(struct elf *elf)
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			entry = &sym->sec->symbol_list;
 | 
								entry = &sym->sec->symbol_list;
 | 
				
			||||||
		list_add(&sym->list, entry);
 | 
							list_add(&sym->list, entry);
 | 
				
			||||||
		hash_add(elf->symbol_hash, &sym->hash, sym->idx);
 | 
							elf_hash_add(elf->symbol_hash, &sym->hash, sym->idx);
 | 
				
			||||||
		hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name));
 | 
							elf_hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (stats)
 | 
						if (stats)
 | 
				
			||||||
| 
						 | 
					@ -456,6 +482,14 @@ static int read_symbols(struct elf *elf)
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void elf_add_rela(struct elf *elf, struct rela *rela)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct section *sec = rela->sec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_add_tail(&rela->list, &sec->rela_list);
 | 
				
			||||||
 | 
						elf_hash_add(elf->rela_hash, &rela->hash, rela_hash(rela));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int read_relas(struct elf *elf)
 | 
					static int read_relas(struct elf *elf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct section *sec;
 | 
						struct section *sec;
 | 
				
			||||||
| 
						 | 
					@ -503,8 +537,7 @@ static int read_relas(struct elf *elf)
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			list_add_tail(&rela->list, &sec->rela_list);
 | 
								elf_add_rela(elf, rela);
 | 
				
			||||||
			hash_add(elf->rela_hash, &rela->hash, rela_hash(rela));
 | 
					 | 
				
			||||||
			nr_rela++;
 | 
								nr_rela++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		max_rela = max(max_rela, nr_rela);
 | 
							max_rela = max(max_rela, nr_rela);
 | 
				
			||||||
| 
						 | 
					@ -519,7 +552,7 @@ static int read_relas(struct elf *elf)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct elf *elf_read(const char *name, int flags)
 | 
					struct elf *elf_open_read(const char *name, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct elf *elf;
 | 
						struct elf *elf;
 | 
				
			||||||
	Elf_Cmd cmd;
 | 
						Elf_Cmd cmd;
 | 
				
			||||||
| 
						 | 
					@ -531,15 +564,16 @@ struct elf *elf_read(const char *name, int flags)
 | 
				
			||||||
		perror("malloc");
 | 
							perror("malloc");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	memset(elf, 0, sizeof(*elf));
 | 
						memset(elf, 0, offsetof(struct elf, sections));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hash_init(elf->symbol_hash);
 | 
					 | 
				
			||||||
	hash_init(elf->symbol_name_hash);
 | 
					 | 
				
			||||||
	hash_init(elf->section_hash);
 | 
					 | 
				
			||||||
	hash_init(elf->section_name_hash);
 | 
					 | 
				
			||||||
	hash_init(elf->rela_hash);
 | 
					 | 
				
			||||||
	INIT_LIST_HEAD(&elf->sections);
 | 
						INIT_LIST_HEAD(&elf->sections);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						elf_hash_init(elf->symbol_hash);
 | 
				
			||||||
 | 
						elf_hash_init(elf->symbol_name_hash);
 | 
				
			||||||
 | 
						elf_hash_init(elf->section_hash);
 | 
				
			||||||
 | 
						elf_hash_init(elf->section_name_hash);
 | 
				
			||||||
 | 
						elf_hash_init(elf->rela_hash);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elf->fd = open(name, flags);
 | 
						elf->fd = open(name, flags);
 | 
				
			||||||
	if (elf->fd == -1) {
 | 
						if (elf->fd == -1) {
 | 
				
			||||||
		fprintf(stderr, "objtool: Can't open '%s': %s\n",
 | 
							fprintf(stderr, "objtool: Can't open '%s': %s\n",
 | 
				
			||||||
| 
						 | 
					@ -676,8 +710,8 @@ struct section *elf_create_section(struct elf *elf, const char *name,
 | 
				
			||||||
	shstrtab->changed = true;
 | 
						shstrtab->changed = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_add_tail(&sec->list, &elf->sections);
 | 
						list_add_tail(&sec->list, &elf->sections);
 | 
				
			||||||
	hash_add(elf->section_hash, &sec->hash, sec->idx);
 | 
						elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
 | 
				
			||||||
	hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
 | 
						elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sec;
 | 
						return sec;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -745,7 +779,7 @@ int elf_rebuild_rela_section(struct section *sec)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int elf_write(struct elf *elf)
 | 
					int elf_write(const struct elf *elf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct section *sec;
 | 
						struct section *sec;
 | 
				
			||||||
	Elf_Scn *s;
 | 
						Elf_Scn *s;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@ struct section {
 | 
				
			||||||
	char *name;
 | 
						char *name;
 | 
				
			||||||
	int idx;
 | 
						int idx;
 | 
				
			||||||
	unsigned int len;
 | 
						unsigned int len;
 | 
				
			||||||
	bool changed, text, rodata;
 | 
						bool changed, text, rodata, noinstr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct symbol {
 | 
					struct symbol {
 | 
				
			||||||
| 
						 | 
					@ -70,17 +70,19 @@ struct rela {
 | 
				
			||||||
	bool jump_table_start;
 | 
						bool jump_table_start;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ELF_HASH_BITS	20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct elf {
 | 
					struct elf {
 | 
				
			||||||
	Elf *elf;
 | 
						Elf *elf;
 | 
				
			||||||
	GElf_Ehdr ehdr;
 | 
						GElf_Ehdr ehdr;
 | 
				
			||||||
	int fd;
 | 
						int fd;
 | 
				
			||||||
	char *name;
 | 
						char *name;
 | 
				
			||||||
	struct list_head sections;
 | 
						struct list_head sections;
 | 
				
			||||||
	DECLARE_HASHTABLE(symbol_hash, 20);
 | 
						DECLARE_HASHTABLE(symbol_hash, ELF_HASH_BITS);
 | 
				
			||||||
	DECLARE_HASHTABLE(symbol_name_hash, 20);
 | 
						DECLARE_HASHTABLE(symbol_name_hash, ELF_HASH_BITS);
 | 
				
			||||||
	DECLARE_HASHTABLE(section_hash, 16);
 | 
						DECLARE_HASHTABLE(section_hash, ELF_HASH_BITS);
 | 
				
			||||||
	DECLARE_HASHTABLE(section_name_hash, 16);
 | 
						DECLARE_HASHTABLE(section_name_hash, ELF_HASH_BITS);
 | 
				
			||||||
	DECLARE_HASHTABLE(rela_hash, 20);
 | 
						DECLARE_HASHTABLE(rela_hash, ELF_HASH_BITS);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define OFFSET_STRIDE_BITS	4
 | 
					#define OFFSET_STRIDE_BITS	4
 | 
				
			||||||
| 
						 | 
					@ -112,22 +114,23 @@ static inline u32 rela_hash(struct rela *rela)
 | 
				
			||||||
	return sec_offset_hash(rela->sec, rela->offset);
 | 
						return sec_offset_hash(rela->sec, rela->offset);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct elf *elf_read(const char *name, int flags);
 | 
					struct elf *elf_open_read(const char *name, int flags);
 | 
				
			||||||
struct section *find_section_by_name(struct elf *elf, const char *name);
 | 
					struct section *elf_create_section(struct elf *elf, const char *name, size_t entsize, int nr);
 | 
				
			||||||
 | 
					struct section *elf_create_rela_section(struct elf *elf, struct section *base);
 | 
				
			||||||
 | 
					void elf_add_rela(struct elf *elf, struct rela *rela);
 | 
				
			||||||
 | 
					int elf_write(const struct elf *elf);
 | 
				
			||||||
 | 
					void elf_close(struct elf *elf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct section *find_section_by_name(const struct elf *elf, const char *name);
 | 
				
			||||||
struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
 | 
					struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
 | 
				
			||||||
struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
 | 
					struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
 | 
				
			||||||
struct symbol *find_symbol_by_name(struct elf *elf, const char *name);
 | 
					struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
 | 
				
			||||||
struct symbol *find_symbol_containing(struct section *sec, unsigned long offset);
 | 
					struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
 | 
				
			||||||
struct rela *find_rela_by_dest(struct elf *elf, struct section *sec, unsigned long offset);
 | 
					struct rela *find_rela_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
 | 
				
			||||||
struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec,
 | 
					struct rela *find_rela_by_dest_range(const struct elf *elf, struct section *sec,
 | 
				
			||||||
				     unsigned long offset, unsigned int len);
 | 
									     unsigned long offset, unsigned int len);
 | 
				
			||||||
struct symbol *find_func_containing(struct section *sec, unsigned long offset);
 | 
					struct symbol *find_func_containing(struct section *sec, unsigned long offset);
 | 
				
			||||||
struct section *elf_create_section(struct elf *elf, const char *name, size_t
 | 
					 | 
				
			||||||
				   entsize, int nr);
 | 
					 | 
				
			||||||
struct section *elf_create_rela_section(struct elf *elf, struct section *base);
 | 
					 | 
				
			||||||
int elf_rebuild_rela_section(struct section *sec);
 | 
					int elf_rebuild_rela_section(struct section *sec);
 | 
				
			||||||
int elf_write(struct elf *elf);
 | 
					 | 
				
			||||||
void elf_close(struct elf *elf);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,7 +58,9 @@ static void cmd_usage(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("\n");
 | 
						printf("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!help)
 | 
				
			||||||
		exit(129);
 | 
							exit(129);
 | 
				
			||||||
 | 
						exit(0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_options(int *argc, const char ***argv)
 | 
					static void handle_options(int *argc, const char ***argv)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										27
									
								
								tools/objtool/objtool.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								tools/objtool/objtool.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					/* SPDX-License-Identifier: GPL-2.0-or-later */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2020 Matt Helsley <mhelsley@vmware.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _OBJTOOL_H
 | 
				
			||||||
 | 
					#define _OBJTOOL_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					#include <linux/hashtable.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "elf.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct objtool_file {
 | 
				
			||||||
 | 
						struct elf *elf;
 | 
				
			||||||
 | 
						struct list_head insn_list;
 | 
				
			||||||
 | 
						DECLARE_HASHTABLE(insn_hash, 20);
 | 
				
			||||||
 | 
						bool ignore_unreachables, c_file, hints, rodata;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int check(const char *objname, bool orc);
 | 
				
			||||||
 | 
					int orc_dump(const char *objname);
 | 
				
			||||||
 | 
					int create_orc(struct objtool_file *file);
 | 
				
			||||||
 | 
					int create_orc_sections(struct objtool_file *file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _OBJTOOL_H */
 | 
				
			||||||
| 
						 | 
					@ -1,18 +0,0 @@
 | 
				
			||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _ORC_H
 | 
					 | 
				
			||||||
#define _ORC_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <asm/orc_types.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct objtool_file;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int create_orc(struct objtool_file *file);
 | 
					 | 
				
			||||||
int create_orc_sections(struct objtool_file *file);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int orc_dump(const char *objname);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* _ORC_H */
 | 
					 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,8 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include "orc.h"
 | 
					#include <asm/orc_types.h>
 | 
				
			||||||
 | 
					#include "objtool.h"
 | 
				
			||||||
#include "warn.h"
 | 
					#include "warn.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *reg_name(unsigned int reg)
 | 
					static const char *reg_name(unsigned int reg)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,6 @@
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "orc.h"
 | 
					 | 
				
			||||||
#include "check.h"
 | 
					#include "check.h"
 | 
				
			||||||
#include "warn.h"
 | 
					#include "warn.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,10 +15,10 @@ int create_orc(struct objtool_file *file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_insn(file, insn) {
 | 
						for_each_insn(file, insn) {
 | 
				
			||||||
		struct orc_entry *orc = &insn->orc;
 | 
							struct orc_entry *orc = &insn->orc;
 | 
				
			||||||
		struct cfi_reg *cfa = &insn->state.cfa;
 | 
							struct cfi_reg *cfa = &insn->cfi.cfa;
 | 
				
			||||||
		struct cfi_reg *bp = &insn->state.regs[CFI_BP];
 | 
							struct cfi_reg *bp = &insn->cfi.regs[CFI_BP];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		orc->end = insn->state.end;
 | 
							orc->end = insn->cfi.end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (cfa->base == CFI_UNDEFINED) {
 | 
							if (cfa->base == CFI_UNDEFINED) {
 | 
				
			||||||
			orc->sp_reg = ORC_REG_UNDEFINED;
 | 
								orc->sp_reg = ORC_REG_UNDEFINED;
 | 
				
			||||||
| 
						 | 
					@ -75,7 +74,7 @@ int create_orc(struct objtool_file *file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		orc->sp_offset = cfa->offset;
 | 
							orc->sp_offset = cfa->offset;
 | 
				
			||||||
		orc->bp_offset = bp->offset;
 | 
							orc->bp_offset = bp->offset;
 | 
				
			||||||
		orc->type = insn->state.type;
 | 
							orc->type = insn->cfi.type;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -130,8 +129,7 @@ static int create_orc_entry(struct elf *elf, struct section *u_sec, struct secti
 | 
				
			||||||
	rela->offset = idx * sizeof(int);
 | 
						rela->offset = idx * sizeof(int);
 | 
				
			||||||
	rela->sec = ip_relasec;
 | 
						rela->sec = ip_relasec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_add_tail(&rela->list, &ip_relasec->rela_list);
 | 
						elf_add_rela(elf, rela);
 | 
				
			||||||
	hash_add(elf->rela_hash, &rela->hash, rela_hash(rela));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										40
									
								
								tools/objtool/weak.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								tools/objtool/weak.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,40 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0-or-later
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2020 Matt Helsley <mhelsley@vmware.com>
 | 
				
			||||||
 | 
					 * Weak definitions necessary to compile objtool without
 | 
				
			||||||
 | 
					 * some subcommands (e.g. check, orc).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include "objtool.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __weak __attribute__((weak))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define UNSUPPORTED(name)						\
 | 
				
			||||||
 | 
					({									\
 | 
				
			||||||
 | 
						fprintf(stderr, "error: objtool: " name " not implemented\n");	\
 | 
				
			||||||
 | 
						return ENOSYS;							\
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char __weak *objname;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __weak check(const char *_objname, bool orc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						UNSUPPORTED("check subcommand");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __weak orc_dump(const char *_objname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						UNSUPPORTED("orc");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __weak create_orc(struct objtool_file *file)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						UNSUPPORTED("orc");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __weak create_orc_sections(struct objtool_file *file)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						UNSUPPORTED("orc");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in a new issue