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

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

+1231 -727
+2 -2
arch/x86/crypto/aesni-intel_asm.S
··· 2758 2758 pxor INC, STATE4 2759 2759 movdqu IV, 0x30(OUTP) 2760 2760 2761 - CALL_NOSPEC %r11 2761 + CALL_NOSPEC r11 2762 2762 2763 2763 movdqu 0x00(OUTP), INC 2764 2764 pxor INC, STATE1 ··· 2803 2803 _aesni_gf128mul_x_ble() 2804 2804 movups IV, (IVP) 2805 2805 2806 - CALL_NOSPEC %r11 2806 + CALL_NOSPEC r11 2807 2807 2808 2808 movdqu 0x40(OUTP), INC 2809 2809 pxor INC, STATE1
+1 -1
arch/x86/crypto/camellia-aesni-avx-asm_64.S
··· 1228 1228 vpxor 14 * 16(%rax), %xmm15, %xmm14; 1229 1229 vpxor 15 * 16(%rax), %xmm15, %xmm15; 1230 1230 1231 - CALL_NOSPEC %r9; 1231 + CALL_NOSPEC r9; 1232 1232 1233 1233 addq $(16 * 16), %rsp; 1234 1234
+1 -1
arch/x86/crypto/camellia-aesni-avx2-asm_64.S
··· 1339 1339 vpxor 14 * 32(%rax), %ymm15, %ymm14; 1340 1340 vpxor 15 * 32(%rax), %ymm15, %ymm15; 1341 1341 1342 - CALL_NOSPEC %r9; 1342 + CALL_NOSPEC r9; 1343 1343 1344 1344 addq $(16 * 32), %rsp; 1345 1345
+13 -13
arch/x86/crypto/crc32c-pcl-intel-asm_64.S
··· 75 75 76 76 .text 77 77 SYM_FUNC_START(crc_pcl) 78 - #define bufp %rdi 78 + #define bufp rdi 79 79 #define bufp_dw %edi 80 80 #define bufp_w %di 81 81 #define bufp_b %dil ··· 105 105 ## 1) ALIGN: 106 106 ################################################################ 107 107 108 - mov bufp, bufptmp # rdi = *buf 109 - neg bufp 110 - and $7, bufp # calculate the unalignment amount of 108 + mov %bufp, bufptmp # rdi = *buf 109 + neg %bufp 110 + and $7, %bufp # calculate the unalignment amount of 111 111 # the address 112 112 je proc_block # Skip if aligned 113 113 ··· 123 123 do_align: 124 124 #### Calculate CRC of unaligned bytes of the buffer (if any) 125 125 movq (bufptmp), tmp # load a quadward from the buffer 126 - add bufp, bufptmp # align buffer pointer for quadword 126 + add %bufp, bufptmp # align buffer pointer for quadword 127 127 # processing 128 - sub bufp, len # update buffer length 128 + sub %bufp, len # update buffer length 129 129 align_loop: 130 130 crc32b %bl, crc_init_dw # compute crc32 of 1-byte 131 131 shr $8, tmp # get next byte 132 - dec bufp 132 + dec %bufp 133 133 jne align_loop 134 134 135 135 proc_block: ··· 169 169 xor crc2, crc2 170 170 171 171 ## branch into array 172 - lea jump_table(%rip), bufp 173 - movzxw (bufp, %rax, 2), len 174 - lea crc_array(%rip), bufp 175 - lea (bufp, len, 1), bufp 172 + lea jump_table(%rip), %bufp 173 + movzxw (%bufp, %rax, 2), len 174 + lea crc_array(%rip), %bufp 175 + lea (%bufp, len, 1), %bufp 176 176 JMP_NOSPEC bufp 177 177 178 178 ################################################################ ··· 218 218 ## 4) Combine three results: 219 219 ################################################################ 220 220 221 - lea (K_table-8)(%rip), bufp # first entry is for idx 1 221 + lea (K_table-8)(%rip), %bufp # first entry is for idx 1 222 222 shlq $3, %rax # rax *= 8 223 - pmovzxdq (bufp,%rax), %xmm0 # 2 consts: K1:K2 223 + pmovzxdq (%bufp,%rax), %xmm0 # 2 consts: K1:K2 224 224 leal (%eax,%eax,2), %eax # rax *= 3 (total *24) 225 225 subq %rax, tmp # tmp -= rax*24 226 226
+3 -3
arch/x86/entry/entry_32.S
··· 816 816 817 817 /* kernel thread */ 818 818 1: movl %edi, %eax 819 - CALL_NOSPEC %ebx 819 + CALL_NOSPEC ebx 820 820 /* 821 821 * A kernel thread is allowed to return here after successfully 822 822 * calling do_execve(). Exit to userspace to complete the execve() ··· 1501 1501 1502 1502 TRACE_IRQS_OFF 1503 1503 movl %esp, %eax # pt_regs pointer 1504 - CALL_NOSPEC %edi 1504 + CALL_NOSPEC edi 1505 1505 jmp ret_from_exception 1506 1506 SYM_CODE_END(common_exception_read_cr2) 1507 1507 ··· 1522 1522 1523 1523 TRACE_IRQS_OFF 1524 1524 movl %esp, %eax # pt_regs pointer 1525 - CALL_NOSPEC %edi 1525 + CALL_NOSPEC edi 1526 1526 jmp ret_from_exception 1527 1527 SYM_CODE_END(common_exception) 1528 1528
+1 -1
arch/x86/entry/entry_64.S
··· 348 348 /* kernel thread */ 349 349 UNWIND_HINT_EMPTY 350 350 movq %r12, %rdi 351 - CALL_NOSPEC %rbx 351 + CALL_NOSPEC rbx 352 352 /* 353 353 * A kernel thread is allowed to return here after successfully 354 354 * calling do_execve(). Exit to userspace to complete the execve()
+25
arch/x86/include/asm/GEN-for-each-reg.h
··· 1 + #ifdef CONFIG_64BIT 2 + GEN(rax) 3 + GEN(rbx) 4 + GEN(rcx) 5 + GEN(rdx) 6 + GEN(rsi) 7 + GEN(rdi) 8 + GEN(rbp) 9 + GEN(r8) 10 + GEN(r9) 11 + GEN(r10) 12 + GEN(r11) 13 + GEN(r12) 14 + GEN(r13) 15 + GEN(r14) 16 + GEN(r15) 17 + #else 18 + GEN(eax) 19 + GEN(ebx) 20 + GEN(ecx) 21 + GEN(edx) 22 + GEN(esi) 23 + GEN(edi) 24 + GEN(ebp) 25 + #endif
+15 -20
arch/x86/include/asm/asm-prototypes.h
··· 17 17 #endif 18 18 19 19 #ifdef CONFIG_RETPOLINE 20 - #ifdef CONFIG_X86_32 21 - #define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_e ## reg(void); 22 - #else 23 - #define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_r ## reg(void); 24 - INDIRECT_THUNK(8) 25 - INDIRECT_THUNK(9) 26 - INDIRECT_THUNK(10) 27 - INDIRECT_THUNK(11) 28 - INDIRECT_THUNK(12) 29 - INDIRECT_THUNK(13) 30 - INDIRECT_THUNK(14) 31 - INDIRECT_THUNK(15) 32 - #endif 33 - INDIRECT_THUNK(ax) 34 - INDIRECT_THUNK(bx) 35 - INDIRECT_THUNK(cx) 36 - INDIRECT_THUNK(dx) 37 - INDIRECT_THUNK(si) 38 - INDIRECT_THUNK(di) 39 - INDIRECT_THUNK(bp) 20 + 21 + #define DECL_INDIRECT_THUNK(reg) \ 22 + extern asmlinkage void __x86_indirect_thunk_ ## reg (void); 23 + 24 + #define DECL_RETPOLINE(reg) \ 25 + extern asmlinkage void __x86_retpoline_ ## reg (void); 26 + 27 + #undef GEN 28 + #define GEN(reg) DECL_INDIRECT_THUNK(reg) 29 + #include <asm/GEN-for-each-reg.h> 30 + 31 + #undef GEN 32 + #define GEN(reg) DECL_RETPOLINE(reg) 33 + #include <asm/GEN-for-each-reg.h> 34 + 40 35 #endif /* CONFIG_RETPOLINE */
+20 -56
arch/x86/include/asm/nospec-branch.h
··· 4 4 #define _ASM_X86_NOSPEC_BRANCH_H_ 5 5 6 6 #include <linux/static_key.h> 7 + #include <linux/frame.h> 7 8 8 9 #include <asm/alternative.h> 9 10 #include <asm/alternative-asm.h> 10 11 #include <asm/cpufeatures.h> 11 12 #include <asm/msr-index.h> 12 - 13 - /* 14 - * This should be used immediately before a retpoline alternative. It tells 15 - * objtool where the retpolines are so that it can make sense of the control 16 - * flow by just reading the original instruction(s) and ignoring the 17 - * alternatives. 18 - */ 19 - #define ANNOTATE_NOSPEC_ALTERNATIVE \ 20 - ANNOTATE_IGNORE_ALTERNATIVE 13 + #include <asm/unwind_hints.h> 21 14 22 15 /* 23 16 * Fill the CPU return stack buffer. ··· 39 46 #define __FILL_RETURN_BUFFER(reg, nr, sp) \ 40 47 mov $(nr/2), reg; \ 41 48 771: \ 49 + ANNOTATE_INTRA_FUNCTION_CALL; \ 42 50 call 772f; \ 43 51 773: /* speculation trap */ \ 52 + UNWIND_HINT_EMPTY; \ 44 53 pause; \ 45 54 lfence; \ 46 55 jmp 773b; \ 47 56 772: \ 57 + ANNOTATE_INTRA_FUNCTION_CALL; \ 48 58 call 774f; \ 49 59 775: /* speculation trap */ \ 60 + UNWIND_HINT_EMPTY; \ 50 61 pause; \ 51 62 lfence; \ 52 63 jmp 775b; \ 53 64 774: \ 65 + add $(BITS_PER_LONG/8) * 2, sp; \ 54 66 dec reg; \ 55 - jnz 771b; \ 56 - add $(BITS_PER_LONG/8) * nr, sp; 67 + jnz 771b; 57 68 58 69 #ifdef __ASSEMBLY__ 59 70 ··· 74 77 .endm 75 78 76 79 /* 77 - * These are the bare retpoline primitives for indirect jmp and call. 78 - * Do not use these directly; they only exist to make the ALTERNATIVE 79 - * invocation below less ugly. 80 - */ 81 - .macro RETPOLINE_JMP reg:req 82 - call .Ldo_rop_\@ 83 - .Lspec_trap_\@: 84 - pause 85 - lfence 86 - jmp .Lspec_trap_\@ 87 - .Ldo_rop_\@: 88 - mov \reg, (%_ASM_SP) 89 - ret 90 - .endm 91 - 92 - /* 93 - * This is a wrapper around RETPOLINE_JMP so the called function in reg 94 - * returns to the instruction after the macro. 95 - */ 96 - .macro RETPOLINE_CALL reg:req 97 - jmp .Ldo_call_\@ 98 - .Ldo_retpoline_jmp_\@: 99 - RETPOLINE_JMP \reg 100 - .Ldo_call_\@: 101 - call .Ldo_retpoline_jmp_\@ 102 - .endm 103 - 104 - /* 105 80 * JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple 106 81 * indirect jmp/call which may be susceptible to the Spectre variant 2 107 82 * attack. 108 83 */ 109 84 .macro JMP_NOSPEC reg:req 110 85 #ifdef CONFIG_RETPOLINE 111 - ANNOTATE_NOSPEC_ALTERNATIVE 112 - ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *\reg), \ 113 - __stringify(RETPOLINE_JMP \reg), X86_FEATURE_RETPOLINE, \ 114 - __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *\reg), X86_FEATURE_RETPOLINE_AMD 86 + ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), \ 87 + __stringify(jmp __x86_retpoline_\reg), X86_FEATURE_RETPOLINE, \ 88 + __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), X86_FEATURE_RETPOLINE_AMD 115 89 #else 116 - jmp *\reg 90 + jmp *%\reg 117 91 #endif 118 92 .endm 119 93 120 94 .macro CALL_NOSPEC reg:req 121 95 #ifdef CONFIG_RETPOLINE 122 - ANNOTATE_NOSPEC_ALTERNATIVE 123 - ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; call *\reg), \ 124 - __stringify(RETPOLINE_CALL \reg), X86_FEATURE_RETPOLINE,\ 125 - __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *\reg), X86_FEATURE_RETPOLINE_AMD 96 + ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; call *%\reg), \ 97 + __stringify(call __x86_retpoline_\reg), X86_FEATURE_RETPOLINE, \ 98 + __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *%\reg), X86_FEATURE_RETPOLINE_AMD 126 99 #else 127 - call *\reg 100 + call *%\reg 128 101 #endif 129 102 .endm 130 103 ··· 104 137 */ 105 138 .macro FILL_RETURN_BUFFER reg:req nr:req ftr:req 106 139 #ifdef CONFIG_RETPOLINE 107 - ANNOTATE_NOSPEC_ALTERNATIVE 108 - ALTERNATIVE "jmp .Lskip_rsb_\@", \ 109 - __stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)) \ 110 - \ftr 140 + ALTERNATIVE "jmp .Lskip_rsb_\@", "", \ftr 141 + __FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP) 111 142 .Lskip_rsb_\@: 112 143 #endif 113 144 .endm ··· 126 161 * which is ensured when CONFIG_RETPOLINE is defined. 127 162 */ 128 163 # define CALL_NOSPEC \ 129 - ANNOTATE_NOSPEC_ALTERNATIVE \ 130 164 ALTERNATIVE_2( \ 131 165 ANNOTATE_RETPOLINE_SAFE \ 132 166 "call *%[thunk_target]\n", \ 133 - "call __x86_indirect_thunk_%V[thunk_target]\n", \ 167 + "call __x86_retpoline_%V[thunk_target]\n", \ 134 168 X86_FEATURE_RETPOLINE, \ 135 169 "lfence;\n" \ 136 170 ANNOTATE_RETPOLINE_SAFE \ 137 171 "call *%[thunk_target]\n", \ 138 172 X86_FEATURE_RETPOLINE_AMD) 173 + 139 174 # define THUNK_TARGET(addr) [thunk_target] "r" (addr) 140 175 141 176 #else /* CONFIG_X86_32 */ ··· 145 180 * here, anyway. 146 181 */ 147 182 # define CALL_NOSPEC \ 148 - ANNOTATE_NOSPEC_ALTERNATIVE \ 149 183 ALTERNATIVE_2( \ 150 184 ANNOTATE_RETPOLINE_SAFE \ 151 185 "call *%[thunk_target]\n", \
+1 -2
arch/x86/include/asm/orc_types.h
··· 58 58 #define ORC_TYPE_CALL 0 59 59 #define ORC_TYPE_REGS 1 60 60 #define ORC_TYPE_REGS_IRET 2 61 - #define UNWIND_HINT_TYPE_SAVE 3 62 - #define UNWIND_HINT_TYPE_RESTORE 4 61 + #define UNWIND_HINT_TYPE_RET_OFFSET 3 63 62 64 63 #ifndef __ASSEMBLY__ 65 64 /*
-2
arch/x86/include/asm/processor.h
··· 728 728 unsigned int tmp; 729 729 730 730 asm volatile ( 731 - UNWIND_HINT_SAVE 732 731 "mov %%ss, %0\n\t" 733 732 "pushq %q0\n\t" 734 733 "pushq %%rsp\n\t" ··· 737 738 "pushq %q0\n\t" 738 739 "pushq $1f\n\t" 739 740 "iretq\n\t" 740 - UNWIND_HINT_RESTORE 741 741 "1:" 742 742 : "=&r" (tmp), ASM_CALL_CONSTRAINT : : "cc", "memory"); 743 743 #endif
+8 -3
arch/x86/include/asm/smap.h
··· 57 57 { 58 58 unsigned long flags; 59 59 60 - asm volatile (ALTERNATIVE("", "pushf; pop %0; " __ASM_CLAC, 61 - X86_FEATURE_SMAP) 60 + asm volatile ("# smap_save\n\t" 61 + ALTERNATIVE("jmp 1f", "", X86_FEATURE_SMAP) 62 + "pushf; pop %0; " __ASM_CLAC "\n\t" 63 + "1:" 62 64 : "=rm" (flags) : : "memory", "cc"); 63 65 64 66 return flags; ··· 68 66 69 67 static __always_inline void smap_restore(unsigned long flags) 70 68 { 71 - asm volatile (ALTERNATIVE("", "push %0; popf", X86_FEATURE_SMAP) 69 + asm volatile ("# smap_restore\n\t" 70 + ALTERNATIVE("jmp 1f", "", X86_FEATURE_SMAP) 71 + "push %0; popf\n\t" 72 + "1:" 72 73 : : "g" (flags) : "memory", "cc"); 73 74 } 74 75
+7 -24
arch/x86/include/asm/unwind_hints.h
··· 86 86 UNWIND_HINT sp_offset=\sp_offset 87 87 .endm 88 88 89 - .macro UNWIND_HINT_SAVE 90 - UNWIND_HINT type=UNWIND_HINT_TYPE_SAVE 89 + /* 90 + * RET_OFFSET: Used on instructions that terminate a function; mostly RETURN 91 + * and sibling calls. On these, sp_offset denotes the expected offset from 92 + * initial_func_cfi. 93 + */ 94 + .macro UNWIND_HINT_RET_OFFSET sp_offset=8 95 + UNWIND_HINT type=UNWIND_HINT_TYPE_RET_OFFSET sp_offset=\sp_offset 91 96 .endm 92 - 93 - .macro UNWIND_HINT_RESTORE 94 - UNWIND_HINT type=UNWIND_HINT_TYPE_RESTORE 95 - .endm 96 - 97 - #else /* !__ASSEMBLY__ */ 98 - 99 - #define UNWIND_HINT(sp_reg, sp_offset, type, end) \ 100 - "987: \n\t" \ 101 - ".pushsection .discard.unwind_hints\n\t" \ 102 - /* struct unwind_hint */ \ 103 - ".long 987b - .\n\t" \ 104 - ".short " __stringify(sp_offset) "\n\t" \ 105 - ".byte " __stringify(sp_reg) "\n\t" \ 106 - ".byte " __stringify(type) "\n\t" \ 107 - ".byte " __stringify(end) "\n\t" \ 108 - ".balign 4 \n\t" \ 109 - ".popsection\n\t" 110 - 111 - #define UNWIND_HINT_SAVE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_SAVE, 0) 112 - 113 - #define UNWIND_HINT_RESTORE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_RESTORE, 0) 114 97 115 98 #endif /* __ASSEMBLY__ */ 116 99
+11 -3
arch/x86/kernel/ftrace.c
··· 282 282 283 283 /* Defined as markers to the end of the ftrace default trampolines */ 284 284 extern void ftrace_regs_caller_end(void); 285 - extern void ftrace_epilogue(void); 285 + extern void ftrace_regs_caller_ret(void); 286 + extern void ftrace_caller_end(void); 286 287 extern void ftrace_caller_op_ptr(void); 287 288 extern void ftrace_regs_caller_op_ptr(void); 288 289 ··· 335 334 call_offset = (unsigned long)ftrace_regs_call; 336 335 } else { 337 336 start_offset = (unsigned long)ftrace_caller; 338 - end_offset = (unsigned long)ftrace_epilogue; 337 + end_offset = (unsigned long)ftrace_caller_end; 339 338 op_offset = (unsigned long)ftrace_caller_op_ptr; 340 339 call_offset = (unsigned long)ftrace_call; 341 340 } ··· 366 365 ret = probe_kernel_read(ip, (void *)retq, RET_SIZE); 367 366 if (WARN_ON(ret < 0)) 368 367 goto fail; 368 + 369 + if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) { 370 + ip = trampoline + (ftrace_regs_caller_ret - ftrace_regs_caller); 371 + ret = probe_kernel_read(ip, (void *)retq, RET_SIZE); 372 + if (WARN_ON(ret < 0)) 373 + goto fail; 374 + } 369 375 370 376 /* 371 377 * The address of the ftrace_ops that is used for this trampoline ··· 441 433 end_offset = (unsigned long)ftrace_regs_caller_end; 442 434 } else { 443 435 start_offset = (unsigned long)ftrace_caller; 444 - end_offset = (unsigned long)ftrace_epilogue; 436 + end_offset = (unsigned long)ftrace_caller_end; 445 437 } 446 438 size = end_offset - start_offset; 447 439 size = size + RET_SIZE + sizeof(void *);
+1 -1
arch/x86/kernel/ftrace_32.S
··· 189 189 movl %eax, %ecx 190 190 popl %edx 191 191 popl %eax 192 - JMP_NOSPEC %ecx 192 + JMP_NOSPEC ecx 193 193 #endif
+21 -23
arch/x86/kernel/ftrace_64.S
··· 23 23 #endif /* CONFIG_FRAME_POINTER */ 24 24 25 25 /* Size of stack used to save mcount regs in save_mcount_regs */ 26 - #define MCOUNT_REG_SIZE (SS+8 + MCOUNT_FRAME_SIZE) 26 + #define MCOUNT_REG_SIZE (FRAME_SIZE + MCOUNT_FRAME_SIZE) 27 27 28 28 /* 29 29 * gcc -pg option adds a call to 'mcount' in most functions. ··· 77 77 /* 78 78 * We add enough stack to save all regs. 79 79 */ 80 - subq $(MCOUNT_REG_SIZE - MCOUNT_FRAME_SIZE), %rsp 80 + subq $(FRAME_SIZE), %rsp 81 81 movq %rax, RAX(%rsp) 82 82 movq %rcx, RCX(%rsp) 83 83 movq %rdx, RDX(%rsp) ··· 157 157 * think twice before adding any new code or changing the 158 158 * layout here. 159 159 */ 160 - SYM_INNER_LABEL(ftrace_epilogue, SYM_L_GLOBAL) 160 + SYM_INNER_LABEL(ftrace_caller_end, SYM_L_GLOBAL) 161 161 162 + jmp ftrace_epilogue 163 + SYM_FUNC_END(ftrace_caller); 164 + 165 + SYM_FUNC_START(ftrace_epilogue) 162 166 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 163 167 SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) 164 168 jmp ftrace_stub ··· 174 170 */ 175 171 SYM_INNER_LABEL_ALIGN(ftrace_stub, SYM_L_WEAK) 176 172 retq 177 - SYM_FUNC_END(ftrace_caller) 173 + SYM_FUNC_END(ftrace_epilogue) 178 174 179 175 SYM_FUNC_START(ftrace_regs_caller) 180 176 /* Save the current flags before any operations that can change them */ 181 177 pushfq 182 - 183 - UNWIND_HINT_SAVE 184 178 185 179 /* added 8 bytes to save flags */ 186 180 save_mcount_regs 8 ··· 235 233 movq ORIG_RAX(%rsp), %rax 236 234 movq %rax, MCOUNT_REG_SIZE-8(%rsp) 237 235 238 - /* If ORIG_RAX is anything but zero, make this a call to that */ 236 + /* 237 + * If ORIG_RAX is anything but zero, make this a call to that. 238 + * See arch_ftrace_set_direct_caller(). 239 + */ 239 240 movq ORIG_RAX(%rsp), %rax 240 - cmpq $0, %rax 241 - je 1f 241 + testq %rax, %rax 242 + jz 1f 242 243 243 244 /* Swap the flags with orig_rax */ 244 245 movq MCOUNT_REG_SIZE(%rsp), %rdi ··· 249 244 movq %rax, MCOUNT_REG_SIZE(%rsp) 250 245 251 246 restore_mcount_regs 8 247 + /* Restore flags */ 248 + popfq 252 249 253 - jmp 2f 250 + SYM_INNER_LABEL(ftrace_regs_caller_ret, SYM_L_GLOBAL); 251 + UNWIND_HINT_RET_OFFSET 252 + jmp ftrace_epilogue 254 253 255 254 1: restore_mcount_regs 256 - 257 - 258 - 2: 259 - /* 260 - * The stack layout is nondetermistic here, depending on which path was 261 - * taken. This confuses objtool and ORC, rightfully so. For now, 262 - * pretend the stack always looks like the non-direct case. 263 - */ 264 - UNWIND_HINT_RESTORE 265 - 266 255 /* Restore flags */ 267 256 popfq 268 257 ··· 267 268 * to the return. 268 269 */ 269 270 SYM_INNER_LABEL(ftrace_regs_caller_end, SYM_L_GLOBAL) 270 - 271 271 jmp ftrace_epilogue 272 272 273 273 SYM_FUNC_END(ftrace_regs_caller) ··· 301 303 * function tracing is enabled. 302 304 */ 303 305 movq ftrace_trace_function, %r8 304 - CALL_NOSPEC %r8 306 + CALL_NOSPEC r8 305 307 restore_mcount_regs 306 308 307 309 jmp fgraph_trace ··· 338 340 movq 8(%rsp), %rdx 339 341 movq (%rsp), %rax 340 342 addq $24, %rsp 341 - JMP_NOSPEC %rdi 343 + JMP_NOSPEC rdi 342 344 SYM_CODE_END(return_to_handler) 343 345 #endif
+2 -2
arch/x86/lib/checksum_32.S
··· 153 153 negl %ebx 154 154 lea 45f(%ebx,%ebx,2), %ebx 155 155 testl %esi, %esi 156 - JMP_NOSPEC %ebx 156 + JMP_NOSPEC ebx 157 157 158 158 # Handle 2-byte-aligned regions 159 159 20: addw (%esi), %ax ··· 436 436 andl $-32,%edx 437 437 lea 3f(%ebx,%ebx), %ebx 438 438 testl %esi, %esi 439 - JMP_NOSPEC %ebx 439 + JMP_NOSPEC ebx 440 440 1: addl $64,%esi 441 441 addl $64,%edi 442 442 SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl)
+38 -23
arch/x86/lib/retpoline.S
··· 7 7 #include <asm/alternative-asm.h> 8 8 #include <asm/export.h> 9 9 #include <asm/nospec-branch.h> 10 + #include <asm/unwind_hints.h> 11 + #include <asm/frame.h> 10 12 11 13 .macro THUNK reg 12 14 .section .text.__x86.indirect_thunk 13 15 16 + .align 32 14 17 SYM_FUNC_START(__x86_indirect_thunk_\reg) 15 - CFI_STARTPROC 16 - JMP_NOSPEC %\reg 17 - CFI_ENDPROC 18 + JMP_NOSPEC \reg 18 19 SYM_FUNC_END(__x86_indirect_thunk_\reg) 20 + 21 + SYM_FUNC_START_NOALIGN(__x86_retpoline_\reg) 22 + ANNOTATE_INTRA_FUNCTION_CALL 23 + call .Ldo_rop_\@ 24 + .Lspec_trap_\@: 25 + UNWIND_HINT_EMPTY 26 + pause 27 + lfence 28 + jmp .Lspec_trap_\@ 29 + .Ldo_rop_\@: 30 + mov %\reg, (%_ASM_SP) 31 + UNWIND_HINT_RET_OFFSET 32 + ret 33 + SYM_FUNC_END(__x86_retpoline_\reg) 34 + 19 35 .endm 20 36 21 37 /* ··· 40 24 * only see one instance of "__x86_indirect_thunk_\reg" rather 41 25 * than one per register with the correct names. So we do it 42 26 * the simple and nasty way... 27 + * 28 + * Worse, you can only have a single EXPORT_SYMBOL per line, 29 + * and CPP can't insert newlines, so we have to repeat everything 30 + * at least twice. 43 31 */ 44 - #define __EXPORT_THUNK(sym) _ASM_NOKPROBE(sym); EXPORT_SYMBOL(sym) 45 - #define EXPORT_THUNK(reg) __EXPORT_THUNK(__x86_indirect_thunk_ ## reg) 46 - #define GENERATE_THUNK(reg) THUNK reg ; EXPORT_THUNK(reg) 47 32 48 - GENERATE_THUNK(_ASM_AX) 49 - GENERATE_THUNK(_ASM_BX) 50 - GENERATE_THUNK(_ASM_CX) 51 - GENERATE_THUNK(_ASM_DX) 52 - GENERATE_THUNK(_ASM_SI) 53 - GENERATE_THUNK(_ASM_DI) 54 - GENERATE_THUNK(_ASM_BP) 55 - #ifdef CONFIG_64BIT 56 - GENERATE_THUNK(r8) 57 - GENERATE_THUNK(r9) 58 - GENERATE_THUNK(r10) 59 - GENERATE_THUNK(r11) 60 - GENERATE_THUNK(r12) 61 - GENERATE_THUNK(r13) 62 - GENERATE_THUNK(r14) 63 - GENERATE_THUNK(r15) 64 - #endif 33 + #define __EXPORT_THUNK(sym) _ASM_NOKPROBE(sym); EXPORT_SYMBOL(sym) 34 + #define EXPORT_THUNK(reg) __EXPORT_THUNK(__x86_indirect_thunk_ ## reg) 35 + #define EXPORT_RETPOLINE(reg) __EXPORT_THUNK(__x86_retpoline_ ## reg) 36 + 37 + #undef GEN 38 + #define GEN(reg) THUNK reg 39 + #include <asm/GEN-for-each-reg.h> 40 + 41 + #undef GEN 42 + #define GEN(reg) EXPORT_THUNK(reg) 43 + #include <asm/GEN-for-each-reg.h> 44 + 45 + #undef GEN 46 + #define GEN(reg) EXPORT_RETPOLINE(reg) 47 + #include <asm/GEN-for-each-reg.h>
+1 -1
arch/x86/platform/efi/efi_stub_64.S
··· 21 21 mov %r8, %r9 22 22 mov %rcx, %r8 23 23 mov %rsi, %rcx 24 - CALL_NOSPEC %rdi 24 + CALL_NOSPEC rdi 25 25 leave 26 26 ret 27 27 SYM_FUNC_END(__efi_call)
+11
include/linux/frame.h
··· 15 15 static void __used __section(.discard.func_stack_frame_non_standard) \ 16 16 *__func_stack_frame_non_standard_##func = func 17 17 18 + /* 19 + * This macro indicates that the following intra-function call is valid. 20 + * Any non-annotated intra-function call will cause objtool to issue a warning. 21 + */ 22 + #define ANNOTATE_INTRA_FUNCTION_CALL \ 23 + 999: \ 24 + .pushsection .discard.intra_function_calls; \ 25 + .long 999b; \ 26 + .popsection; 27 + 18 28 #else /* !CONFIG_STACK_VALIDATION */ 19 29 20 30 #define STACK_FRAME_NON_STANDARD(func) 31 + #define ANNOTATE_INTRA_FUNCTION_CALL 21 32 22 33 #endif /* CONFIG_STACK_VALIDATION */ 23 34
+5
lib/Kconfig.debug
··· 369 369 For more information, see 370 370 tools/objtool/Documentation/stack-validation.txt. 371 371 372 + config VMLINUX_VALIDATION 373 + bool 374 + depends on STACK_VALIDATION && DEBUG_ENTRY && !PARAVIRT 375 + default y 376 + 372 377 config DEBUG_FORCE_WEAK_PER_CPU 373 378 bool "Force weak per-cpu definitions" 374 379 depends on DEBUG_KERNEL
+4
samples/ftrace/ftrace-direct-modify.c
··· 20 20 21 21 asm ( 22 22 " .pushsection .text, \"ax\", @progbits\n" 23 + " .type my_tramp1, @function\n" 23 24 " my_tramp1:" 24 25 " pushq %rbp\n" 25 26 " movq %rsp, %rbp\n" 26 27 " call my_direct_func1\n" 27 28 " leave\n" 29 + " .size my_tramp1, .-my_tramp1\n" 28 30 " ret\n" 31 + " .type my_tramp2, @function\n" 29 32 " my_tramp2:" 30 33 " pushq %rbp\n" 31 34 " movq %rsp, %rbp\n" 32 35 " call my_direct_func2\n" 33 36 " leave\n" 34 37 " ret\n" 38 + " .size my_tramp2, .-my_tramp2\n" 35 39 " .popsection\n" 36 40 ); 37 41
+2
samples/ftrace/ftrace-direct-too.c
··· 15 15 16 16 asm ( 17 17 " .pushsection .text, \"ax\", @progbits\n" 18 + " .type my_tramp, @function\n" 18 19 " my_tramp:" 19 20 " pushq %rbp\n" 20 21 " movq %rsp, %rbp\n" ··· 28 27 " popq %rdi\n" 29 28 " leave\n" 30 29 " ret\n" 30 + " .size my_tramp, .-my_tramp\n" 31 31 " .popsection\n" 32 32 ); 33 33
+2
samples/ftrace/ftrace-direct.c
··· 13 13 14 14 asm ( 15 15 " .pushsection .text, \"ax\", @progbits\n" 16 + " .type my_tramp, @function\n" 16 17 " my_tramp:" 17 18 " pushq %rbp\n" 18 19 " movq %rsp, %rbp\n" ··· 22 21 " popq %rdi\n" 23 22 " leave\n" 24 23 " ret\n" 24 + " .size my_tramp, .-my_tramp\n" 25 25 " .popsection\n" 26 26 ); 27 27
+1 -2
tools/arch/x86/include/asm/orc_types.h
··· 58 58 #define ORC_TYPE_CALL 0 59 59 #define ORC_TYPE_REGS 1 60 60 #define ORC_TYPE_REGS_IRET 2 61 - #define UNWIND_HINT_TYPE_SAVE 3 62 - #define UNWIND_HINT_TYPE_RESTORE 4 61 + #define UNWIND_HINT_TYPE_RET_OFFSET 3 63 62 64 63 #ifndef __ASSEMBLY__ 65 64 /*
+9 -4
tools/objtool/Build
··· 1 1 objtool-y += arch/$(SRCARCH)/ 2 + 3 + objtool-y += weak.o 4 + 5 + objtool-$(SUBCMD_CHECK) += check.o 6 + objtool-$(SUBCMD_CHECK) += special.o 7 + objtool-$(SUBCMD_ORC) += check.o 8 + objtool-$(SUBCMD_ORC) += orc_gen.o 9 + objtool-$(SUBCMD_ORC) += orc_dump.o 10 + 2 11 objtool-y += builtin-check.o 3 12 objtool-y += builtin-orc.o 4 - objtool-y += check.o 5 - objtool-y += orc_gen.o 6 - objtool-y += orc_dump.o 7 13 objtool-y += elf.o 8 - objtool-y += special.o 9 14 objtool-y += objtool.o 10 15 11 16 objtool-y += libstring.o
+41
tools/objtool/Documentation/stack-validation.txt
··· 289 289 might be corrupt due to a gcc bug. For more details, see: 290 290 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646 291 291 292 + 9. file.o: warning: objtool: funcA() call to funcB() with UACCESS enabled 293 + 294 + This means that an unexpected call to a non-whitelisted function exists 295 + outside of arch-specific guards. 296 + X86: SMAP (stac/clac): __uaccess_begin()/__uaccess_end() 297 + ARM: PAN: uaccess_enable()/uaccess_disable() 298 + 299 + These functions should be called to denote a minimal critical section around 300 + access to __user variables. See also: https://lwn.net/Articles/517475/ 301 + 302 + The intention of the warning is to prevent calls to funcB() from eventually 303 + calling schedule(), potentially leaking the AC flags state, and not 304 + restoring them correctly. 305 + 306 + It also helps verify that there are no unexpected calls to funcB() which may 307 + access user space pages with protections against doing so disabled. 308 + 309 + To fix, either: 310 + 1) remove explicit calls to funcB() from funcA(). 311 + 2) add the correct guards before and after calls to low level functions like 312 + __get_user_size()/__put_user_size(). 313 + 3) add funcB to uaccess_safe_builtin whitelist in tools/objtool/check.c, if 314 + funcB obviously does not call schedule(), and is marked notrace (since 315 + function tracing inserts additional calls, which is not obvious from the 316 + sources). 317 + 318 + 10. file.o: warning: func()+0x5c: alternative modifies stack 319 + 320 + This means that an alternative includes instructions that modify the 321 + stack. The problem is that there is only one ORC unwind table, this means 322 + that the ORC unwind entries must be valid for each of the alternatives. 323 + The easiest way to enforce this is to ensure alternatives do not contain 324 + any ORC entries, which in turn implies the above constraint. 325 + 326 + 11. file.o: warning: unannotated intra-function call 327 + 328 + This warning means that a direct call is done to a destination which 329 + is not at the beginning of a function. If this is a legit call, you 330 + can remove this warning by putting the ANNOTATE_INTRA_FUNCTION_CALL 331 + directive right before the call. 332 + 292 333 293 334 If the error doesn't seem to make sense, it could be a bug in objtool. 294 335 Feel free to ask the objtool maintainer for help.
+13 -2
tools/objtool/Makefile
··· 35 35 36 36 INCLUDES := -I$(srctree)/tools/include \ 37 37 -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \ 38 - -I$(srctree)/tools/arch/$(SRCARCH)/include 38 + -I$(srctree)/tools/arch/$(SRCARCH)/include \ 39 + -I$(srctree)/tools/objtool/arch/$(SRCARCH)/include 39 40 WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed 40 41 CFLAGS := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBELF_FLAGS) 41 42 LDFLAGS += $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS) ··· 46 45 CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) 47 46 48 47 AWK = awk 48 + 49 + SUBCMD_CHECK := n 50 + SUBCMD_ORC := n 51 + 52 + ifeq ($(SRCARCH),x86) 53 + SUBCMD_CHECK := y 54 + SUBCMD_ORC := y 55 + endif 56 + 57 + export SUBCMD_CHECK SUBCMD_ORC 49 58 export srctree OUTPUT CFLAGS SRCARCH AWK 50 59 include $(srctree)/tools/build/Makefile.include 51 60 52 61 $(OBJTOOL_IN): fixdep FORCE 62 + @$(CONFIG_SHELL) ./sync-check.sh 53 63 @$(MAKE) $(build)=objtool 54 64 55 65 $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) 56 - @$(CONFIG_SHELL) ./sync-check.sh 57 66 $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ 58 67 59 68
+14 -5
tools/objtool/arch.h
··· 8 8 9 9 #include <stdbool.h> 10 10 #include <linux/list.h> 11 - #include "elf.h" 11 + #include "objtool.h" 12 12 #include "cfi.h" 13 + 14 + #include <asm/orc_types.h> 13 15 14 16 enum insn_type { 15 17 INSN_JUMP_CONDITIONAL, ··· 22 20 INSN_CALL_DYNAMIC, 23 21 INSN_RETURN, 24 22 INSN_CONTEXT_SWITCH, 25 - INSN_STACK, 26 23 INSN_BUG, 27 24 INSN_NOP, 28 25 INSN_STAC, ··· 65 64 struct stack_op { 66 65 struct op_dest dest; 67 66 struct op_src src; 67 + struct list_head list; 68 68 }; 69 69 70 - void arch_initial_func_cfi_state(struct cfi_state *state); 70 + struct instruction; 71 71 72 - int arch_decode_instruction(struct elf *elf, struct section *sec, 72 + void arch_initial_func_cfi_state(struct cfi_init_state *state); 73 + 74 + int arch_decode_instruction(const struct elf *elf, const struct section *sec, 73 75 unsigned long offset, unsigned int maxlen, 74 76 unsigned int *len, enum insn_type *type, 75 - unsigned long *immediate, struct stack_op *op); 77 + unsigned long *immediate, 78 + struct list_head *ops_list); 76 79 77 80 bool arch_callee_saved_reg(unsigned char reg); 81 + 82 + unsigned long arch_jump_destination(struct instruction *insn); 83 + 84 + unsigned long arch_dest_rela_offset(int addend); 78 85 79 86 #endif /* _ARCH_H */
+185 -117
tools/objtool/arch/x86/decode.c
··· 11 11 #include "../../../arch/x86/lib/inat.c" 12 12 #include "../../../arch/x86/lib/insn.c" 13 13 14 + #include "../../check.h" 14 15 #include "../../elf.h" 15 16 #include "../../arch.h" 16 17 #include "../../warn.h" ··· 27 26 {CFI_DI, CFI_R15}, 28 27 }; 29 28 30 - static int is_x86_64(struct elf *elf) 29 + static int is_x86_64(const struct elf *elf) 31 30 { 32 31 switch (elf->ehdr.e_machine) { 33 32 case EM_X86_64: ··· 67 66 } 68 67 } 69 68 70 - int arch_decode_instruction(struct elf *elf, struct section *sec, 69 + unsigned long arch_dest_rela_offset(int addend) 70 + { 71 + return addend + 4; 72 + } 73 + 74 + unsigned long arch_jump_destination(struct instruction *insn) 75 + { 76 + return insn->offset + insn->len + insn->immediate; 77 + } 78 + 79 + #define ADD_OP(op) \ 80 + if (!(op = calloc(1, sizeof(*op)))) \ 81 + return -1; \ 82 + else for (list_add_tail(&op->list, ops_list); op; op = NULL) 83 + 84 + int arch_decode_instruction(const struct elf *elf, const struct section *sec, 71 85 unsigned long offset, unsigned int maxlen, 72 86 unsigned int *len, enum insn_type *type, 73 - unsigned long *immediate, struct stack_op *op) 87 + unsigned long *immediate, 88 + struct list_head *ops_list) 74 89 { 75 90 struct insn insn; 76 91 int x86_64, sign; 77 92 unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, 78 93 rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0, 79 94 modrm_reg = 0, sib = 0; 95 + struct stack_op *op = NULL; 96 + struct symbol *sym; 80 97 81 98 x86_64 = is_x86_64(elf); 82 99 if (x86_64 == -1) ··· 104 85 insn_get_length(&insn); 105 86 106 87 if (!insn_complete(&insn)) { 107 - WARN_FUNC("can't decode instruction", sec, offset); 88 + WARN("can't decode instruction at %s:0x%lx", sec->name, offset); 108 89 return -1; 109 90 } 110 91 ··· 142 123 if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { 143 124 144 125 /* add/sub reg, %rsp */ 145 - *type = INSN_STACK; 146 - op->src.type = OP_SRC_ADD; 147 - op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 148 - op->dest.type = OP_DEST_REG; 149 - op->dest.reg = CFI_SP; 126 + ADD_OP(op) { 127 + op->src.type = OP_SRC_ADD; 128 + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 129 + op->dest.type = OP_DEST_REG; 130 + op->dest.reg = CFI_SP; 131 + } 150 132 } 151 133 break; 152 134 153 135 case 0x50 ... 0x57: 154 136 155 137 /* push reg */ 156 - *type = INSN_STACK; 157 - op->src.type = OP_SRC_REG; 158 - op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; 159 - op->dest.type = OP_DEST_PUSH; 138 + ADD_OP(op) { 139 + op->src.type = OP_SRC_REG; 140 + op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; 141 + op->dest.type = OP_DEST_PUSH; 142 + } 160 143 161 144 break; 162 145 163 146 case 0x58 ... 0x5f: 164 147 165 148 /* pop reg */ 166 - *type = INSN_STACK; 167 - op->src.type = OP_SRC_POP; 168 - op->dest.type = OP_DEST_REG; 169 - op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; 149 + ADD_OP(op) { 150 + op->src.type = OP_SRC_POP; 151 + op->dest.type = OP_DEST_REG; 152 + op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; 153 + } 170 154 171 155 break; 172 156 173 157 case 0x68: 174 158 case 0x6a: 175 159 /* push immediate */ 176 - *type = INSN_STACK; 177 - op->src.type = OP_SRC_CONST; 178 - op->dest.type = OP_DEST_PUSH; 160 + ADD_OP(op) { 161 + op->src.type = OP_SRC_CONST; 162 + op->dest.type = OP_DEST_PUSH; 163 + } 179 164 break; 180 165 181 166 case 0x70 ... 0x7f: ··· 193 170 194 171 if (modrm == 0xe4) { 195 172 /* and imm, %rsp */ 196 - *type = INSN_STACK; 197 - op->src.type = OP_SRC_AND; 198 - op->src.reg = CFI_SP; 199 - op->src.offset = insn.immediate.value; 200 - op->dest.type = OP_DEST_REG; 201 - op->dest.reg = CFI_SP; 173 + ADD_OP(op) { 174 + op->src.type = OP_SRC_AND; 175 + op->src.reg = CFI_SP; 176 + op->src.offset = insn.immediate.value; 177 + op->dest.type = OP_DEST_REG; 178 + op->dest.reg = CFI_SP; 179 + } 202 180 break; 203 181 } 204 182 ··· 211 187 break; 212 188 213 189 /* add/sub imm, %rsp */ 214 - *type = INSN_STACK; 215 - op->src.type = OP_SRC_ADD; 216 - op->src.reg = CFI_SP; 217 - op->src.offset = insn.immediate.value * sign; 218 - op->dest.type = OP_DEST_REG; 219 - op->dest.reg = CFI_SP; 190 + ADD_OP(op) { 191 + op->src.type = OP_SRC_ADD; 192 + op->src.reg = CFI_SP; 193 + op->src.offset = insn.immediate.value * sign; 194 + op->dest.type = OP_DEST_REG; 195 + op->dest.reg = CFI_SP; 196 + } 220 197 break; 221 198 222 199 case 0x89: 223 200 if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) { 224 201 225 202 /* mov %rsp, reg */ 226 - *type = INSN_STACK; 227 - op->src.type = OP_SRC_REG; 228 - op->src.reg = CFI_SP; 229 - op->dest.type = OP_DEST_REG; 230 - op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; 203 + ADD_OP(op) { 204 + op->src.type = OP_SRC_REG; 205 + op->src.reg = CFI_SP; 206 + op->dest.type = OP_DEST_REG; 207 + op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; 208 + } 231 209 break; 232 210 } 233 211 234 212 if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { 235 213 236 214 /* mov reg, %rsp */ 237 - *type = INSN_STACK; 238 - op->src.type = OP_SRC_REG; 239 - op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 240 - op->dest.type = OP_DEST_REG; 241 - op->dest.reg = CFI_SP; 215 + ADD_OP(op) { 216 + op->src.type = OP_SRC_REG; 217 + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 218 + op->dest.type = OP_DEST_REG; 219 + op->dest.reg = CFI_SP; 220 + } 242 221 break; 243 222 } 244 223 ··· 251 224 (modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) { 252 225 253 226 /* mov reg, disp(%rbp) */ 254 - *type = INSN_STACK; 255 - op->src.type = OP_SRC_REG; 256 - op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 257 - op->dest.type = OP_DEST_REG_INDIRECT; 258 - op->dest.reg = CFI_BP; 259 - op->dest.offset = insn.displacement.value; 227 + ADD_OP(op) { 228 + op->src.type = OP_SRC_REG; 229 + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 230 + op->dest.type = OP_DEST_REG_INDIRECT; 231 + op->dest.reg = CFI_BP; 232 + op->dest.offset = insn.displacement.value; 233 + } 260 234 261 235 } else if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) { 262 236 263 237 /* mov reg, disp(%rsp) */ 264 - *type = INSN_STACK; 265 - op->src.type = OP_SRC_REG; 266 - op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 267 - op->dest.type = OP_DEST_REG_INDIRECT; 268 - op->dest.reg = CFI_SP; 269 - op->dest.offset = insn.displacement.value; 238 + ADD_OP(op) { 239 + op->src.type = OP_SRC_REG; 240 + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 241 + op->dest.type = OP_DEST_REG_INDIRECT; 242 + op->dest.reg = CFI_SP; 243 + op->dest.offset = insn.displacement.value; 244 + } 270 245 } 271 246 272 247 break; ··· 277 248 if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) { 278 249 279 250 /* mov disp(%rbp), reg */ 280 - *type = INSN_STACK; 281 - op->src.type = OP_SRC_REG_INDIRECT; 282 - op->src.reg = CFI_BP; 283 - op->src.offset = insn.displacement.value; 284 - op->dest.type = OP_DEST_REG; 285 - op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; 251 + ADD_OP(op) { 252 + op->src.type = OP_SRC_REG_INDIRECT; 253 + op->src.reg = CFI_BP; 254 + op->src.offset = insn.displacement.value; 255 + op->dest.type = OP_DEST_REG; 256 + op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; 257 + } 286 258 287 259 } else if (rex_w && !rex_b && sib == 0x24 && 288 260 modrm_mod != 3 && modrm_rm == 4) { 289 261 290 262 /* mov disp(%rsp), reg */ 291 - *type = INSN_STACK; 292 - op->src.type = OP_SRC_REG_INDIRECT; 293 - op->src.reg = CFI_SP; 294 - op->src.offset = insn.displacement.value; 295 - op->dest.type = OP_DEST_REG; 296 - op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; 263 + ADD_OP(op) { 264 + op->src.type = OP_SRC_REG_INDIRECT; 265 + op->src.reg = CFI_SP; 266 + op->src.offset = insn.displacement.value; 267 + op->dest.type = OP_DEST_REG; 268 + op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; 269 + } 297 270 } 298 271 299 272 break; ··· 303 272 case 0x8d: 304 273 if (sib == 0x24 && rex_w && !rex_b && !rex_x) { 305 274 306 - *type = INSN_STACK; 307 - if (!insn.displacement.value) { 308 - /* lea (%rsp), reg */ 309 - op->src.type = OP_SRC_REG; 310 - } else { 311 - /* lea disp(%rsp), reg */ 312 - op->src.type = OP_SRC_ADD; 313 - op->src.offset = insn.displacement.value; 275 + ADD_OP(op) { 276 + if (!insn.displacement.value) { 277 + /* lea (%rsp), reg */ 278 + op->src.type = OP_SRC_REG; 279 + } else { 280 + /* lea disp(%rsp), reg */ 281 + op->src.type = OP_SRC_ADD; 282 + op->src.offset = insn.displacement.value; 283 + } 284 + op->src.reg = CFI_SP; 285 + op->dest.type = OP_DEST_REG; 286 + op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; 314 287 } 315 - op->src.reg = CFI_SP; 316 - op->dest.type = OP_DEST_REG; 317 - op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; 318 288 319 289 } else if (rex == 0x48 && modrm == 0x65) { 320 290 321 291 /* lea disp(%rbp), %rsp */ 322 - *type = INSN_STACK; 323 - op->src.type = OP_SRC_ADD; 324 - op->src.reg = CFI_BP; 325 - op->src.offset = insn.displacement.value; 326 - op->dest.type = OP_DEST_REG; 327 - op->dest.reg = CFI_SP; 292 + ADD_OP(op) { 293 + op->src.type = OP_SRC_ADD; 294 + op->src.reg = CFI_BP; 295 + op->src.offset = insn.displacement.value; 296 + op->dest.type = OP_DEST_REG; 297 + op->dest.reg = CFI_SP; 298 + } 328 299 329 300 } else if (rex == 0x49 && modrm == 0x62 && 330 301 insn.displacement.value == -8) { ··· 337 304 * Restoring rsp back to its original value after a 338 305 * stack realignment. 339 306 */ 340 - *type = INSN_STACK; 341 - op->src.type = OP_SRC_ADD; 342 - op->src.reg = CFI_R10; 343 - op->src.offset = -8; 344 - op->dest.type = OP_DEST_REG; 345 - op->dest.reg = CFI_SP; 307 + ADD_OP(op) { 308 + op->src.type = OP_SRC_ADD; 309 + op->src.reg = CFI_R10; 310 + op->src.offset = -8; 311 + op->dest.type = OP_DEST_REG; 312 + op->dest.reg = CFI_SP; 313 + } 346 314 347 315 } else if (rex == 0x49 && modrm == 0x65 && 348 316 insn.displacement.value == -16) { ··· 354 320 * Restoring rsp back to its original value after a 355 321 * stack realignment. 356 322 */ 357 - *type = INSN_STACK; 358 - op->src.type = OP_SRC_ADD; 359 - op->src.reg = CFI_R13; 360 - op->src.offset = -16; 361 - op->dest.type = OP_DEST_REG; 362 - op->dest.reg = CFI_SP; 323 + ADD_OP(op) { 324 + op->src.type = OP_SRC_ADD; 325 + op->src.reg = CFI_R13; 326 + op->src.offset = -16; 327 + op->dest.type = OP_DEST_REG; 328 + op->dest.reg = CFI_SP; 329 + } 363 330 } 364 331 365 332 break; 366 333 367 334 case 0x8f: 368 335 /* pop to mem */ 369 - *type = INSN_STACK; 370 - op->src.type = OP_SRC_POP; 371 - op->dest.type = OP_DEST_MEM; 336 + ADD_OP(op) { 337 + op->src.type = OP_SRC_POP; 338 + op->dest.type = OP_DEST_MEM; 339 + } 372 340 break; 373 341 374 342 case 0x90: ··· 379 343 380 344 case 0x9c: 381 345 /* pushf */ 382 - *type = INSN_STACK; 383 - op->src.type = OP_SRC_CONST; 384 - op->dest.type = OP_DEST_PUSHF; 346 + ADD_OP(op) { 347 + op->src.type = OP_SRC_CONST; 348 + op->dest.type = OP_DEST_PUSHF; 349 + } 385 350 break; 386 351 387 352 case 0x9d: 388 353 /* popf */ 389 - *type = INSN_STACK; 390 - op->src.type = OP_SRC_POPF; 391 - op->dest.type = OP_DEST_MEM; 354 + ADD_OP(op) { 355 + op->src.type = OP_SRC_POPF; 356 + op->dest.type = OP_DEST_MEM; 357 + } 392 358 break; 393 359 394 360 case 0x0f: ··· 425 387 } else if (op2 == 0xa0 || op2 == 0xa8) { 426 388 427 389 /* push fs/gs */ 428 - *type = INSN_STACK; 429 - op->src.type = OP_SRC_CONST; 430 - op->dest.type = OP_DEST_PUSH; 390 + ADD_OP(op) { 391 + op->src.type = OP_SRC_CONST; 392 + op->dest.type = OP_DEST_PUSH; 393 + } 431 394 432 395 } else if (op2 == 0xa1 || op2 == 0xa9) { 433 396 434 397 /* pop fs/gs */ 435 - *type = INSN_STACK; 436 - op->src.type = OP_SRC_POP; 437 - op->dest.type = OP_DEST_MEM; 398 + ADD_OP(op) { 399 + op->src.type = OP_SRC_POP; 400 + op->dest.type = OP_DEST_MEM; 401 + } 438 402 } 439 403 440 404 break; ··· 449 409 * mov bp, sp 450 410 * pop bp 451 411 */ 452 - *type = INSN_STACK; 453 - op->dest.type = OP_DEST_LEAVE; 412 + ADD_OP(op) 413 + op->dest.type = OP_DEST_LEAVE; 454 414 455 415 break; 456 416 ··· 469 429 *type = INSN_RETURN; 470 430 break; 471 431 432 + case 0xcf: /* iret */ 433 + /* 434 + * Handle sync_core(), which has an IRET to self. 435 + * All other IRET are in STT_NONE entry code. 436 + */ 437 + sym = find_symbol_containing(sec, offset); 438 + if (sym && sym->type == STT_FUNC) { 439 + ADD_OP(op) { 440 + /* add $40, %rsp */ 441 + op->src.type = OP_SRC_ADD; 442 + op->src.reg = CFI_SP; 443 + op->src.offset = 5*8; 444 + op->dest.type = OP_DEST_REG; 445 + op->dest.reg = CFI_SP; 446 + } 447 + break; 448 + } 449 + 450 + /* fallthrough */ 451 + 472 452 case 0xca: /* retf */ 473 453 case 0xcb: /* retf */ 474 - case 0xcf: /* iret */ 475 454 *type = INSN_CONTEXT_SWITCH; 476 455 break; 477 456 478 457 case 0xe8: 479 458 *type = INSN_CALL; 459 + /* 460 + * For the impact on the stack, a CALL behaves like 461 + * a PUSH of an immediate value (the return address). 462 + */ 463 + ADD_OP(op) { 464 + op->src.type = OP_SRC_CONST; 465 + op->dest.type = OP_DEST_PUSH; 466 + } 480 467 break; 481 468 482 469 case 0xfc: ··· 531 464 else if (modrm_reg == 6) { 532 465 533 466 /* push from mem */ 534 - *type = INSN_STACK; 535 - op->src.type = OP_SRC_CONST; 536 - op->dest.type = OP_DEST_PUSH; 467 + ADD_OP(op) { 468 + op->src.type = OP_SRC_CONST; 469 + op->dest.type = OP_DEST_PUSH; 470 + } 537 471 } 538 472 539 473 break; ··· 548 480 return 0; 549 481 } 550 482 551 - void arch_initial_func_cfi_state(struct cfi_state *state) 483 + void arch_initial_func_cfi_state(struct cfi_init_state *state) 552 484 { 553 485 int i; 554 486
+25
tools/objtool/arch/x86/include/cfi_regs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + 3 + #ifndef _OBJTOOL_CFI_REGS_H 4 + #define _OBJTOOL_CFI_REGS_H 5 + 6 + #define CFI_AX 0 7 + #define CFI_DX 1 8 + #define CFI_CX 2 9 + #define CFI_BX 3 10 + #define CFI_SI 4 11 + #define CFI_DI 5 12 + #define CFI_BP 6 13 + #define CFI_SP 7 14 + #define CFI_R8 8 15 + #define CFI_R9 9 16 + #define CFI_R10 10 17 + #define CFI_R11 11 18 + #define CFI_R12 12 19 + #define CFI_R13 13 20 + #define CFI_R14 14 21 + #define CFI_R15 15 22 + #define CFI_RA 16 23 + #define CFI_NUM_REGS 17 24 + 25 + #endif /* _OBJTOOL_CFI_REGS_H */
+10 -3
tools/objtool/builtin-check.c
··· 14 14 */ 15 15 16 16 #include <subcmd/parse-options.h> 17 + #include <string.h> 17 18 #include "builtin.h" 18 - #include "check.h" 19 + #include "objtool.h" 19 20 20 - bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats; 21 + bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, validate_dup, vmlinux; 21 22 22 23 static const char * const check_usage[] = { 23 24 "objtool check [<options>] file.o", ··· 33 32 OPT_BOOLEAN('b', "backtrace", &backtrace, "unwind on error"), 34 33 OPT_BOOLEAN('a', "uaccess", &uaccess, "enable uaccess checking"), 35 34 OPT_BOOLEAN('s', "stats", &stats, "print statistics"), 35 + OPT_BOOLEAN('d', "duplicate", &validate_dup, "duplicate validation for vmlinux.o"), 36 + OPT_BOOLEAN('l', "vmlinux", &vmlinux, "vmlinux.o validation"), 36 37 OPT_END(), 37 38 }; 38 39 39 40 int cmd_check(int argc, const char **argv) 40 41 { 41 - const char *objname; 42 + const char *objname, *s; 42 43 43 44 argc = parse_options(argc, argv, check_options, check_usage, 0); 44 45 ··· 48 45 usage_with_options(check_usage, check_options); 49 46 50 47 objname = argv[0]; 48 + 49 + s = strstr(objname, "vmlinux.o"); 50 + if (s && !s[9]) 51 + vmlinux = true; 51 52 52 53 return check(objname, false); 53 54 }
+1 -2
tools/objtool/builtin-orc.c
··· 14 14 15 15 #include <string.h> 16 16 #include "builtin.h" 17 - #include "check.h" 18 - 17 + #include "objtool.h" 19 18 20 19 static const char *orc_usage[] = { 21 20 "objtool orc generate [<options>] file.o",
+1 -1
tools/objtool/builtin.h
··· 8 8 #include <subcmd/parse-options.h> 9 9 10 10 extern const struct option check_options[]; 11 - extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats; 11 + extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, validate_dup, vmlinux; 12 12 13 13 extern int cmd_check(int argc, const char **argv); 14 14 extern int cmd_orc(int argc, const char **argv);
+16 -21
tools/objtool/cfi.h
··· 6 6 #ifndef _OBJTOOL_CFI_H 7 7 #define _OBJTOOL_CFI_H 8 8 9 + #include "cfi_regs.h" 10 + 9 11 #define CFI_UNDEFINED -1 10 12 #define CFI_CFA -2 11 13 #define CFI_SP_INDIRECT -3 12 14 #define CFI_BP_INDIRECT -4 13 - 14 - #define CFI_AX 0 15 - #define CFI_DX 1 16 - #define CFI_CX 2 17 - #define CFI_BX 3 18 - #define CFI_SI 4 19 - #define CFI_DI 5 20 - #define CFI_BP 6 21 - #define CFI_SP 7 22 - #define CFI_R8 8 23 - #define CFI_R9 9 24 - #define CFI_R10 10 25 - #define CFI_R11 11 26 - #define CFI_R12 12 27 - #define CFI_R13 13 28 - #define CFI_R14 14 29 - #define CFI_R15 15 30 - #define CFI_RA 16 31 - #define CFI_NUM_REGS 17 32 15 33 16 struct cfi_reg { 34 17 int base; 35 18 int offset; 36 19 }; 37 20 38 - struct cfi_state { 39 - struct cfi_reg cfa; 21 + struct cfi_init_state { 40 22 struct cfi_reg regs[CFI_NUM_REGS]; 23 + struct cfi_reg cfa; 24 + }; 25 + 26 + struct cfi_state { 27 + struct cfi_reg regs[CFI_NUM_REGS]; 28 + struct cfi_reg vals[CFI_NUM_REGS]; 29 + struct cfi_reg cfa; 30 + int stack_size; 31 + int drap_reg, drap_offset; 32 + unsigned char type; 33 + bool bp_scratch; 34 + bool drap; 35 + bool end; 41 36 }; 42 37 43 38 #endif /* _OBJTOOL_CFI_H */
+519 -288
tools/objtool/check.c
··· 7 7 #include <stdlib.h> 8 8 9 9 #include "builtin.h" 10 - #include "check.h" 11 - #include "elf.h" 12 - #include "special.h" 10 + #include "cfi.h" 13 11 #include "arch.h" 12 + #include "check.h" 13 + #include "special.h" 14 14 #include "warn.h" 15 15 16 16 #include <linux/hashtable.h> ··· 27 27 }; 28 28 29 29 const char *objname; 30 - struct cfi_state initial_func_cfi; 30 + struct cfi_init_state initial_func_cfi; 31 31 32 32 struct instruction *find_insn(struct objtool_file *file, 33 33 struct section *sec, unsigned long offset) 34 34 { 35 35 struct instruction *insn; 36 36 37 - hash_for_each_possible(file->insn_hash, insn, hash, offset) 37 + hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) { 38 38 if (insn->sec == sec && insn->offset == offset) 39 39 return insn; 40 + } 40 41 41 42 return NULL; 42 43 } ··· 227 226 return __dead_end_function(file, func, 0); 228 227 } 229 228 230 - static void clear_insn_state(struct insn_state *state) 229 + static void init_cfi_state(struct cfi_state *cfi) 231 230 { 232 231 int i; 233 232 234 - memset(state, 0, sizeof(*state)); 235 - state->cfa.base = CFI_UNDEFINED; 236 233 for (i = 0; i < CFI_NUM_REGS; i++) { 237 - state->regs[i].base = CFI_UNDEFINED; 238 - state->vals[i].base = CFI_UNDEFINED; 234 + cfi->regs[i].base = CFI_UNDEFINED; 235 + cfi->vals[i].base = CFI_UNDEFINED; 239 236 } 240 - state->drap_reg = CFI_UNDEFINED; 241 - state->drap_offset = -1; 237 + cfi->cfa.base = CFI_UNDEFINED; 238 + cfi->drap_reg = CFI_UNDEFINED; 239 + cfi->drap_offset = -1; 240 + } 241 + 242 + static void init_insn_state(struct insn_state *state, struct section *sec) 243 + { 244 + memset(state, 0, sizeof(*state)); 245 + init_cfi_state(&state->cfi); 246 + 247 + /* 248 + * We need the full vmlinux for noinstr validation, otherwise we can 249 + * not correctly determine insn->call_dest->sec (external symbols do 250 + * not have a section). 251 + */ 252 + if (vmlinux && sec) 253 + state->noinstr = sec->noinstr; 242 254 } 243 255 244 256 /* ··· 277 263 strncmp(sec->name, ".discard.", 9)) 278 264 sec->text = true; 279 265 266 + if (!strcmp(sec->name, ".noinstr.text") || 267 + !strcmp(sec->name, ".entry.text")) 268 + sec->noinstr = true; 269 + 280 270 for (offset = 0; offset < sec->len; offset += insn->len) { 281 271 insn = malloc(sizeof(*insn)); 282 272 if (!insn) { ··· 289 271 } 290 272 memset(insn, 0, sizeof(*insn)); 291 273 INIT_LIST_HEAD(&insn->alts); 292 - clear_insn_state(&insn->state); 274 + INIT_LIST_HEAD(&insn->stack_ops); 275 + init_cfi_state(&insn->cfi); 293 276 294 277 insn->sec = sec; 295 278 insn->offset = offset; ··· 299 280 sec->len - offset, 300 281 &insn->len, &insn->type, 301 282 &insn->immediate, 302 - &insn->stack_op); 283 + &insn->stack_ops); 303 284 if (ret) 304 285 goto err; 305 286 306 - hash_add(file->insn_hash, &insn->hash, insn->offset); 287 + hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset)); 307 288 list_add_tail(&insn->list, &file->insn_list); 308 289 nr_insns++; 309 290 } ··· 333 314 return ret; 334 315 } 335 316 317 + static struct instruction *find_last_insn(struct objtool_file *file, 318 + struct section *sec) 319 + { 320 + struct instruction *insn = NULL; 321 + unsigned int offset; 322 + unsigned int end = (sec->len > 10) ? sec->len - 10 : 0; 323 + 324 + for (offset = sec->len - 1; offset >= end && !insn; offset--) 325 + insn = find_insn(file, sec, offset); 326 + 327 + return insn; 328 + } 329 + 336 330 /* 337 331 * Mark "ud2" instructions and manually annotated dead ends. 338 332 */ ··· 354 322 struct section *sec; 355 323 struct rela *rela; 356 324 struct instruction *insn; 357 - bool found; 358 325 359 326 /* 360 327 * By default, "ud2" is a dead end unless otherwise annotated, because ··· 379 348 if (insn) 380 349 insn = list_prev_entry(insn, list); 381 350 else if (rela->addend == rela->sym->sec->len) { 382 - found = false; 383 - list_for_each_entry_reverse(insn, &file->insn_list, list) { 384 - if (insn->sec == rela->sym->sec) { 385 - found = true; 386 - break; 387 - } 388 - } 389 - 390 - if (!found) { 351 + insn = find_last_insn(file, rela->sym->sec); 352 + if (!insn) { 391 353 WARN("can't find unreachable insn at %s+0x%x", 392 354 rela->sym->sec->name, rela->addend); 393 355 return -1; ··· 414 390 if (insn) 415 391 insn = list_prev_entry(insn, list); 416 392 else if (rela->addend == rela->sym->sec->len) { 417 - found = false; 418 - list_for_each_entry_reverse(insn, &file->insn_list, list) { 419 - if (insn->sec == rela->sym->sec) { 420 - found = true; 421 - break; 422 - } 423 - } 424 - 425 - if (!found) { 393 + insn = find_last_insn(file, rela->sym->sec); 394 + if (!insn) { 426 395 WARN("can't find reachable insn at %s+0x%x", 427 396 rela->sym->sec->name, rela->addend); 428 397 return -1; ··· 507 490 "__asan_report_store16_noabort", 508 491 /* KCOV */ 509 492 "write_comp_data", 493 + "check_kcov_mode", 510 494 "__sanitizer_cov_trace_pc", 511 495 "__sanitizer_cov_trace_const_cmp1", 512 496 "__sanitizer_cov_trace_const_cmp2", ··· 603 585 insn->offset, insn->len); 604 586 if (!rela) { 605 587 dest_sec = insn->sec; 606 - dest_off = insn->offset + insn->len + insn->immediate; 588 + dest_off = arch_jump_destination(insn); 607 589 } else if (rela->sym->type == STT_SECTION) { 608 590 dest_sec = rela->sym->sec; 609 - dest_off = rela->addend + 4; 591 + dest_off = arch_dest_rela_offset(rela->addend); 610 592 } else if (rela->sym->sec->idx) { 611 593 dest_sec = rela->sym->sec; 612 - dest_off = rela->sym->sym.st_value + rela->addend + 4; 594 + dest_off = rela->sym->sym.st_value + 595 + arch_dest_rela_offset(rela->addend); 613 596 } else if (strstr(rela->sym->name, "_indirect_thunk_")) { 614 597 /* 615 598 * Retpoline jumps are really dynamic jumps in ··· 684 665 return 0; 685 666 } 686 667 668 + static void remove_insn_ops(struct instruction *insn) 669 + { 670 + struct stack_op *op, *tmp; 671 + 672 + list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) { 673 + list_del(&op->list); 674 + free(op); 675 + } 676 + } 677 + 687 678 /* 688 679 * Find the destination instructions for all calls. 689 680 */ ··· 710 681 rela = find_rela_by_dest_range(file->elf, insn->sec, 711 682 insn->offset, insn->len); 712 683 if (!rela) { 713 - dest_off = insn->offset + insn->len + insn->immediate; 684 + dest_off = arch_jump_destination(insn); 714 685 insn->call_dest = find_func_by_offset(insn->sec, dest_off); 715 686 if (!insn->call_dest) 716 687 insn->call_dest = find_symbol_by_offset(insn->sec, dest_off); ··· 719 690 continue; 720 691 721 692 if (!insn->call_dest) { 722 - WARN_FUNC("unsupported intra-function call", 723 - insn->sec, insn->offset); 724 - if (retpoline) 725 - WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); 693 + WARN_FUNC("unannotated intra-function call", insn->sec, insn->offset); 726 694 return -1; 727 695 } 728 696 ··· 730 704 } 731 705 732 706 } else if (rela->sym->type == STT_SECTION) { 707 + dest_off = arch_dest_rela_offset(rela->addend); 733 708 insn->call_dest = find_func_by_offset(rela->sym->sec, 734 - rela->addend+4); 709 + dest_off); 735 710 if (!insn->call_dest) { 736 - WARN_FUNC("can't find call dest symbol at %s+0x%x", 711 + WARN_FUNC("can't find call dest symbol at %s+0x%lx", 737 712 insn->sec, insn->offset, 738 713 rela->sym->sec->name, 739 - rela->addend + 4); 714 + dest_off); 740 715 return -1; 741 716 } 742 717 } else 743 718 insn->call_dest = rela->sym; 719 + 720 + /* 721 + * Whatever stack impact regular CALLs have, should be undone 722 + * by the RETURN of the called function. 723 + * 724 + * Annotated intra-function calls retain the stack_ops but 725 + * are converted to JUMP, see read_intra_function_calls(). 726 + */ 727 + remove_insn_ops(insn); 744 728 } 745 729 746 730 return 0; ··· 778 742 struct instruction *orig_insn, 779 743 struct instruction **new_insn) 780 744 { 745 + static unsigned int alt_group_next_index = 1; 781 746 struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL; 747 + unsigned int alt_group = alt_group_next_index++; 782 748 unsigned long dest_off; 783 749 784 750 last_orig_insn = NULL; ··· 789 751 if (insn->offset >= special_alt->orig_off + special_alt->orig_len) 790 752 break; 791 753 792 - insn->alt_group = true; 754 + insn->alt_group = alt_group; 793 755 last_orig_insn = insn; 794 756 } 795 757 ··· 801 763 } 802 764 memset(fake_jump, 0, sizeof(*fake_jump)); 803 765 INIT_LIST_HEAD(&fake_jump->alts); 804 - clear_insn_state(&fake_jump->state); 766 + INIT_LIST_HEAD(&fake_jump->stack_ops); 767 + init_cfi_state(&fake_jump->cfi); 805 768 806 769 fake_jump->sec = special_alt->new_sec; 807 770 fake_jump->offset = FAKE_JUMP_OFFSET; ··· 823 784 } 824 785 825 786 last_new_insn = NULL; 787 + alt_group = alt_group_next_index++; 826 788 insn = *new_insn; 827 789 sec_for_each_insn_from(file, insn) { 828 790 if (insn->offset >= special_alt->new_off + special_alt->new_len) ··· 833 793 834 794 insn->ignore = orig_insn->ignore_alts; 835 795 insn->func = orig_insn->func; 796 + insn->alt_group = alt_group; 836 797 837 798 /* 838 799 * Since alternative replacement code is copy/pasted by the ··· 862 821 if (!insn->immediate) 863 822 continue; 864 823 865 - dest_off = insn->offset + insn->len + insn->immediate; 824 + dest_off = arch_jump_destination(insn); 866 825 if (dest_off == special_alt->new_off + special_alt->new_len) { 867 826 if (!fake_jump) { 868 827 WARN("%s: alternative jump to end of section", ··· 957 916 } 958 917 959 918 if (special_alt->group) { 919 + if (!special_alt->orig_len) { 920 + WARN_FUNC("empty alternative entry", 921 + orig_insn->sec, orig_insn->offset); 922 + continue; 923 + } 924 + 960 925 ret = handle_group_alt(file, special_alt, orig_insn, 961 926 &new_insn); 962 927 if (ret) ··· 1300 1253 return -1; 1301 1254 } 1302 1255 1303 - cfa = &insn->state.cfa; 1256 + cfa = &insn->cfi.cfa; 1304 1257 1305 - if (hint->type == UNWIND_HINT_TYPE_SAVE) { 1306 - insn->save = true; 1307 - continue; 1308 - 1309 - } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) { 1310 - insn->restore = true; 1311 - insn->hint = true; 1258 + if (hint->type == UNWIND_HINT_TYPE_RET_OFFSET) { 1259 + insn->ret_offset = hint->sp_offset; 1312 1260 continue; 1313 1261 } 1314 1262 ··· 1341 1299 } 1342 1300 1343 1301 cfa->offset = hint->sp_offset; 1344 - insn->state.type = hint->type; 1345 - insn->state.end = hint->end; 1302 + insn->cfi.type = hint->type; 1303 + insn->cfi.end = hint->end; 1346 1304 } 1347 1305 1348 1306 return 0; ··· 1383 1341 return 0; 1384 1342 } 1385 1343 1344 + static int read_instr_hints(struct objtool_file *file) 1345 + { 1346 + struct section *sec; 1347 + struct instruction *insn; 1348 + struct rela *rela; 1349 + 1350 + sec = find_section_by_name(file->elf, ".rela.discard.instr_end"); 1351 + if (!sec) 1352 + return 0; 1353 + 1354 + list_for_each_entry(rela, &sec->rela_list, list) { 1355 + if (rela->sym->type != STT_SECTION) { 1356 + WARN("unexpected relocation symbol type in %s", sec->name); 1357 + return -1; 1358 + } 1359 + 1360 + insn = find_insn(file, rela->sym->sec, rela->addend); 1361 + if (!insn) { 1362 + WARN("bad .discard.instr_end entry"); 1363 + return -1; 1364 + } 1365 + 1366 + insn->instr--; 1367 + } 1368 + 1369 + sec = find_section_by_name(file->elf, ".rela.discard.instr_begin"); 1370 + if (!sec) 1371 + return 0; 1372 + 1373 + list_for_each_entry(rela, &sec->rela_list, list) { 1374 + if (rela->sym->type != STT_SECTION) { 1375 + WARN("unexpected relocation symbol type in %s", sec->name); 1376 + return -1; 1377 + } 1378 + 1379 + insn = find_insn(file, rela->sym->sec, rela->addend); 1380 + if (!insn) { 1381 + WARN("bad .discard.instr_begin entry"); 1382 + return -1; 1383 + } 1384 + 1385 + insn->instr++; 1386 + } 1387 + 1388 + return 0; 1389 + } 1390 + 1391 + static int read_intra_function_calls(struct objtool_file *file) 1392 + { 1393 + struct instruction *insn; 1394 + struct section *sec; 1395 + struct rela *rela; 1396 + 1397 + sec = find_section_by_name(file->elf, ".rela.discard.intra_function_calls"); 1398 + if (!sec) 1399 + return 0; 1400 + 1401 + list_for_each_entry(rela, &sec->rela_list, list) { 1402 + unsigned long dest_off; 1403 + 1404 + if (rela->sym->type != STT_SECTION) { 1405 + WARN("unexpected relocation symbol type in %s", 1406 + sec->name); 1407 + return -1; 1408 + } 1409 + 1410 + insn = find_insn(file, rela->sym->sec, rela->addend); 1411 + if (!insn) { 1412 + WARN("bad .discard.intra_function_call entry"); 1413 + return -1; 1414 + } 1415 + 1416 + if (insn->type != INSN_CALL) { 1417 + WARN_FUNC("intra_function_call not a direct call", 1418 + insn->sec, insn->offset); 1419 + return -1; 1420 + } 1421 + 1422 + /* 1423 + * Treat intra-function CALLs as JMPs, but with a stack_op. 1424 + * See add_call_destinations(), which strips stack_ops from 1425 + * normal CALLs. 1426 + */ 1427 + insn->type = INSN_JUMP_UNCONDITIONAL; 1428 + 1429 + dest_off = insn->offset + insn->len + insn->immediate; 1430 + insn->jump_dest = find_insn(file, insn->sec, dest_off); 1431 + if (!insn->jump_dest) { 1432 + WARN_FUNC("can't find call dest at %s+0x%lx", 1433 + insn->sec, insn->offset, 1434 + insn->sec->name, dest_off); 1435 + return -1; 1436 + } 1437 + } 1438 + 1439 + return 0; 1440 + } 1441 + 1386 1442 static void mark_rodata(struct objtool_file *file) 1387 1443 { 1388 1444 struct section *sec; ··· 1497 1357 * .rodata.str1.* sections are ignored; they don't contain jump tables. 1498 1358 */ 1499 1359 for_each_sec(file, sec) { 1500 - if ((!strncmp(sec->name, ".rodata", 7) && !strstr(sec->name, ".str1.")) || 1501 - !strcmp(sec->name, C_JUMP_TABLE_SECTION)) { 1360 + if (!strncmp(sec->name, ".rodata", 7) && 1361 + !strstr(sec->name, ".str1.")) { 1502 1362 sec->rodata = true; 1503 1363 found = true; 1504 1364 } ··· 1536 1396 if (ret) 1537 1397 return ret; 1538 1398 1399 + ret = read_intra_function_calls(file); 1400 + if (ret) 1401 + return ret; 1402 + 1539 1403 ret = add_call_destinations(file); 1540 1404 if (ret) 1541 1405 return ret; ··· 1556 1412 if (ret) 1557 1413 return ret; 1558 1414 1415 + ret = read_instr_hints(file); 1416 + if (ret) 1417 + return ret; 1418 + 1559 1419 return 0; 1560 1420 } 1561 1421 1562 1422 static bool is_fentry_call(struct instruction *insn) 1563 1423 { 1564 - if (insn->type == INSN_CALL && 1424 + if (insn->type == INSN_CALL && insn->call_dest && 1565 1425 insn->call_dest->type == STT_NOTYPE && 1566 1426 !strcmp(insn->call_dest->name, "__fentry__")) 1567 1427 return true; ··· 1573 1425 return false; 1574 1426 } 1575 1427 1576 - static bool has_modified_stack_frame(struct insn_state *state) 1428 + static bool has_modified_stack_frame(struct instruction *insn, struct insn_state *state) 1577 1429 { 1430 + u8 ret_offset = insn->ret_offset; 1431 + struct cfi_state *cfi = &state->cfi; 1578 1432 int i; 1579 1433 1580 - if (state->cfa.base != initial_func_cfi.cfa.base || 1581 - state->cfa.offset != initial_func_cfi.cfa.offset || 1582 - state->stack_size != initial_func_cfi.cfa.offset || 1583 - state->drap) 1434 + if (cfi->cfa.base != initial_func_cfi.cfa.base || cfi->drap) 1584 1435 return true; 1585 1436 1586 - for (i = 0; i < CFI_NUM_REGS; i++) 1587 - if (state->regs[i].base != initial_func_cfi.regs[i].base || 1588 - state->regs[i].offset != initial_func_cfi.regs[i].offset) 1437 + if (cfi->cfa.offset != initial_func_cfi.cfa.offset + ret_offset) 1438 + return true; 1439 + 1440 + if (cfi->stack_size != initial_func_cfi.cfa.offset + ret_offset) 1441 + return true; 1442 + 1443 + /* 1444 + * If there is a ret offset hint then don't check registers 1445 + * because a callee-saved register might have been pushed on 1446 + * the stack. 1447 + */ 1448 + if (ret_offset) 1449 + return false; 1450 + 1451 + for (i = 0; i < CFI_NUM_REGS; i++) { 1452 + if (cfi->regs[i].base != initial_func_cfi.regs[i].base || 1453 + cfi->regs[i].offset != initial_func_cfi.regs[i].offset) 1589 1454 return true; 1455 + } 1590 1456 1591 1457 return false; 1592 1458 } 1593 1459 1594 1460 static bool has_valid_stack_frame(struct insn_state *state) 1595 1461 { 1596 - if (state->cfa.base == CFI_BP && state->regs[CFI_BP].base == CFI_CFA && 1597 - state->regs[CFI_BP].offset == -16) 1462 + struct cfi_state *cfi = &state->cfi; 1463 + 1464 + if (cfi->cfa.base == CFI_BP && cfi->regs[CFI_BP].base == CFI_CFA && 1465 + cfi->regs[CFI_BP].offset == -16) 1598 1466 return true; 1599 1467 1600 - if (state->drap && state->regs[CFI_BP].base == CFI_BP) 1468 + if (cfi->drap && cfi->regs[CFI_BP].base == CFI_BP) 1601 1469 return true; 1602 1470 1603 1471 return false; 1604 1472 } 1605 1473 1606 - static int update_insn_state_regs(struct instruction *insn, struct insn_state *state) 1474 + static int update_cfi_state_regs(struct instruction *insn, 1475 + struct cfi_state *cfi, 1476 + struct stack_op *op) 1607 1477 { 1608 - struct cfi_reg *cfa = &state->cfa; 1609 - struct stack_op *op = &insn->stack_op; 1478 + struct cfi_reg *cfa = &cfi->cfa; 1610 1479 1611 1480 if (cfa->base != CFI_SP && cfa->base != CFI_SP_INDIRECT) 1612 1481 return 0; ··· 1644 1479 return 0; 1645 1480 } 1646 1481 1647 - static void save_reg(struct insn_state *state, unsigned char reg, int base, 1648 - int offset) 1482 + static void save_reg(struct cfi_state *cfi, unsigned char reg, int base, int offset) 1649 1483 { 1650 1484 if (arch_callee_saved_reg(reg) && 1651 - state->regs[reg].base == CFI_UNDEFINED) { 1652 - state->regs[reg].base = base; 1653 - state->regs[reg].offset = offset; 1485 + cfi->regs[reg].base == CFI_UNDEFINED) { 1486 + cfi->regs[reg].base = base; 1487 + cfi->regs[reg].offset = offset; 1654 1488 } 1655 1489 } 1656 1490 1657 - static void restore_reg(struct insn_state *state, unsigned char reg) 1491 + static void restore_reg(struct cfi_state *cfi, unsigned char reg) 1658 1492 { 1659 - state->regs[reg].base = CFI_UNDEFINED; 1660 - state->regs[reg].offset = 0; 1493 + cfi->regs[reg].base = initial_func_cfi.regs[reg].base; 1494 + cfi->regs[reg].offset = initial_func_cfi.regs[reg].offset; 1661 1495 } 1662 1496 1663 1497 /* ··· 1712 1548 * 41 5d pop %r13 1713 1549 * c3 retq 1714 1550 */ 1715 - static int update_insn_state(struct instruction *insn, struct insn_state *state) 1551 + static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi, 1552 + struct stack_op *op) 1716 1553 { 1717 - struct stack_op *op = &insn->stack_op; 1718 - struct cfi_reg *cfa = &state->cfa; 1719 - struct cfi_reg *regs = state->regs; 1554 + struct cfi_reg *cfa = &cfi->cfa; 1555 + struct cfi_reg *regs = cfi->regs; 1720 1556 1721 1557 /* stack operations don't make sense with an undefined CFA */ 1722 1558 if (cfa->base == CFI_UNDEFINED) { ··· 1727 1563 return 0; 1728 1564 } 1729 1565 1730 - if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET) 1731 - return update_insn_state_regs(insn, state); 1566 + if (cfi->type == ORC_TYPE_REGS || cfi->type == ORC_TYPE_REGS_IRET) 1567 + return update_cfi_state_regs(insn, cfi, op); 1732 1568 1733 1569 switch (op->dest.type) { 1734 1570 ··· 1743 1579 1744 1580 /* mov %rsp, %rbp */ 1745 1581 cfa->base = op->dest.reg; 1746 - state->bp_scratch = false; 1582 + cfi->bp_scratch = false; 1747 1583 } 1748 1584 1749 1585 else if (op->src.reg == CFI_SP && 1750 - op->dest.reg == CFI_BP && state->drap) { 1586 + op->dest.reg == CFI_BP && cfi->drap) { 1751 1587 1752 1588 /* drap: mov %rsp, %rbp */ 1753 1589 regs[CFI_BP].base = CFI_BP; 1754 - regs[CFI_BP].offset = -state->stack_size; 1755 - state->bp_scratch = false; 1590 + regs[CFI_BP].offset = -cfi->stack_size; 1591 + cfi->bp_scratch = false; 1756 1592 } 1757 1593 1758 1594 else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { ··· 1767 1603 * ... 1768 1604 * mov %rax, %rsp 1769 1605 */ 1770 - state->vals[op->dest.reg].base = CFI_CFA; 1771 - state->vals[op->dest.reg].offset = -state->stack_size; 1606 + cfi->vals[op->dest.reg].base = CFI_CFA; 1607 + cfi->vals[op->dest.reg].offset = -cfi->stack_size; 1772 1608 } 1773 1609 1774 1610 else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP && ··· 1779 1615 * 1780 1616 * Restore the original stack pointer (Clang). 1781 1617 */ 1782 - state->stack_size = -state->regs[CFI_BP].offset; 1618 + cfi->stack_size = -cfi->regs[CFI_BP].offset; 1783 1619 } 1784 1620 1785 1621 else if (op->dest.reg == cfa->base) { 1786 1622 1787 1623 /* mov %reg, %rsp */ 1788 1624 if (cfa->base == CFI_SP && 1789 - state->vals[op->src.reg].base == CFI_CFA) { 1625 + cfi->vals[op->src.reg].base == CFI_CFA) { 1790 1626 1791 1627 /* 1792 1628 * This is needed for the rare case ··· 1796 1632 * ... 1797 1633 * mov %rcx, %rsp 1798 1634 */ 1799 - cfa->offset = -state->vals[op->src.reg].offset; 1800 - state->stack_size = cfa->offset; 1635 + cfa->offset = -cfi->vals[op->src.reg].offset; 1636 + cfi->stack_size = cfa->offset; 1801 1637 1802 1638 } else { 1803 1639 cfa->base = CFI_UNDEFINED; ··· 1811 1647 if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) { 1812 1648 1813 1649 /* add imm, %rsp */ 1814 - state->stack_size -= op->src.offset; 1650 + cfi->stack_size -= op->src.offset; 1815 1651 if (cfa->base == CFI_SP) 1816 1652 cfa->offset -= op->src.offset; 1817 1653 break; ··· 1820 1656 if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) { 1821 1657 1822 1658 /* lea disp(%rbp), %rsp */ 1823 - state->stack_size = -(op->src.offset + regs[CFI_BP].offset); 1659 + cfi->stack_size = -(op->src.offset + regs[CFI_BP].offset); 1824 1660 break; 1825 1661 } 1826 1662 1827 1663 if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { 1828 1664 1829 1665 /* drap: lea disp(%rsp), %drap */ 1830 - state->drap_reg = op->dest.reg; 1666 + cfi->drap_reg = op->dest.reg; 1831 1667 1832 1668 /* 1833 1669 * lea disp(%rsp), %reg ··· 1839 1675 * ... 1840 1676 * mov %rcx, %rsp 1841 1677 */ 1842 - state->vals[op->dest.reg].base = CFI_CFA; 1843 - state->vals[op->dest.reg].offset = \ 1844 - -state->stack_size + op->src.offset; 1678 + cfi->vals[op->dest.reg].base = CFI_CFA; 1679 + cfi->vals[op->dest.reg].offset = \ 1680 + -cfi->stack_size + op->src.offset; 1845 1681 1846 1682 break; 1847 1683 } 1848 1684 1849 - if (state->drap && op->dest.reg == CFI_SP && 1850 - op->src.reg == state->drap_reg) { 1685 + if (cfi->drap && op->dest.reg == CFI_SP && 1686 + op->src.reg == cfi->drap_reg) { 1851 1687 1852 1688 /* drap: lea disp(%drap), %rsp */ 1853 1689 cfa->base = CFI_SP; 1854 - cfa->offset = state->stack_size = -op->src.offset; 1855 - state->drap_reg = CFI_UNDEFINED; 1856 - state->drap = false; 1690 + cfa->offset = cfi->stack_size = -op->src.offset; 1691 + cfi->drap_reg = CFI_UNDEFINED; 1692 + cfi->drap = false; 1857 1693 break; 1858 1694 } 1859 1695 1860 - if (op->dest.reg == state->cfa.base) { 1696 + if (op->dest.reg == cfi->cfa.base) { 1861 1697 WARN_FUNC("unsupported stack register modification", 1862 1698 insn->sec, insn->offset); 1863 1699 return -1; ··· 1867 1703 1868 1704 case OP_SRC_AND: 1869 1705 if (op->dest.reg != CFI_SP || 1870 - (state->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) || 1871 - (state->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) { 1706 + (cfi->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) || 1707 + (cfi->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) { 1872 1708 WARN_FUNC("unsupported stack pointer realignment", 1873 1709 insn->sec, insn->offset); 1874 1710 return -1; 1875 1711 } 1876 1712 1877 - if (state->drap_reg != CFI_UNDEFINED) { 1713 + if (cfi->drap_reg != CFI_UNDEFINED) { 1878 1714 /* drap: and imm, %rsp */ 1879 - cfa->base = state->drap_reg; 1880 - cfa->offset = state->stack_size = 0; 1881 - state->drap = true; 1715 + cfa->base = cfi->drap_reg; 1716 + cfa->offset = cfi->stack_size = 0; 1717 + cfi->drap = true; 1882 1718 } 1883 1719 1884 1720 /* ··· 1890 1726 1891 1727 case OP_SRC_POP: 1892 1728 case OP_SRC_POPF: 1893 - if (!state->drap && op->dest.type == OP_DEST_REG && 1894 - op->dest.reg == cfa->base) { 1729 + if (!cfi->drap && op->dest.reg == cfa->base) { 1895 1730 1896 1731 /* pop %rbp */ 1897 1732 cfa->base = CFI_SP; 1898 1733 } 1899 1734 1900 - if (state->drap && cfa->base == CFI_BP_INDIRECT && 1901 - op->dest.type == OP_DEST_REG && 1902 - op->dest.reg == state->drap_reg && 1903 - state->drap_offset == -state->stack_size) { 1735 + if (cfi->drap && cfa->base == CFI_BP_INDIRECT && 1736 + op->dest.reg == cfi->drap_reg && 1737 + cfi->drap_offset == -cfi->stack_size) { 1904 1738 1905 1739 /* drap: pop %drap */ 1906 - cfa->base = state->drap_reg; 1740 + cfa->base = cfi->drap_reg; 1907 1741 cfa->offset = 0; 1908 - state->drap_offset = -1; 1742 + cfi->drap_offset = -1; 1909 1743 1910 - } else if (regs[op->dest.reg].offset == -state->stack_size) { 1744 + } else if (regs[op->dest.reg].offset == -cfi->stack_size) { 1911 1745 1912 1746 /* pop %reg */ 1913 - restore_reg(state, op->dest.reg); 1747 + restore_reg(cfi, op->dest.reg); 1914 1748 } 1915 1749 1916 - state->stack_size -= 8; 1750 + cfi->stack_size -= 8; 1917 1751 if (cfa->base == CFI_SP) 1918 1752 cfa->offset -= 8; 1919 1753 1920 1754 break; 1921 1755 1922 1756 case OP_SRC_REG_INDIRECT: 1923 - if (state->drap && op->src.reg == CFI_BP && 1924 - op->src.offset == state->drap_offset) { 1757 + if (cfi->drap && op->src.reg == CFI_BP && 1758 + op->src.offset == cfi->drap_offset) { 1925 1759 1926 1760 /* drap: mov disp(%rbp), %drap */ 1927 - cfa->base = state->drap_reg; 1761 + cfa->base = cfi->drap_reg; 1928 1762 cfa->offset = 0; 1929 - state->drap_offset = -1; 1763 + cfi->drap_offset = -1; 1930 1764 } 1931 1765 1932 - if (state->drap && op->src.reg == CFI_BP && 1766 + if (cfi->drap && op->src.reg == CFI_BP && 1933 1767 op->src.offset == regs[op->dest.reg].offset) { 1934 1768 1935 1769 /* drap: mov disp(%rbp), %reg */ 1936 - restore_reg(state, op->dest.reg); 1770 + restore_reg(cfi, op->dest.reg); 1937 1771 1938 1772 } else if (op->src.reg == cfa->base && 1939 1773 op->src.offset == regs[op->dest.reg].offset + cfa->offset) { 1940 1774 1941 1775 /* mov disp(%rbp), %reg */ 1942 1776 /* mov disp(%rsp), %reg */ 1943 - restore_reg(state, op->dest.reg); 1777 + restore_reg(cfi, op->dest.reg); 1944 1778 } 1945 1779 1946 1780 break; ··· 1953 1791 1954 1792 case OP_DEST_PUSH: 1955 1793 case OP_DEST_PUSHF: 1956 - state->stack_size += 8; 1794 + cfi->stack_size += 8; 1957 1795 if (cfa->base == CFI_SP) 1958 1796 cfa->offset += 8; 1959 1797 1960 1798 if (op->src.type != OP_SRC_REG) 1961 1799 break; 1962 1800 1963 - if (state->drap) { 1964 - if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { 1801 + if (cfi->drap) { 1802 + if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) { 1965 1803 1966 1804 /* drap: push %drap */ 1967 1805 cfa->base = CFI_BP_INDIRECT; 1968 - cfa->offset = -state->stack_size; 1806 + cfa->offset = -cfi->stack_size; 1969 1807 1970 1808 /* save drap so we know when to restore it */ 1971 - state->drap_offset = -state->stack_size; 1809 + cfi->drap_offset = -cfi->stack_size; 1972 1810 1973 - } else if (op->src.reg == CFI_BP && cfa->base == state->drap_reg) { 1811 + } else if (op->src.reg == CFI_BP && cfa->base == cfi->drap_reg) { 1974 1812 1975 1813 /* drap: push %rbp */ 1976 - state->stack_size = 0; 1814 + cfi->stack_size = 0; 1977 1815 1978 1816 } else if (regs[op->src.reg].base == CFI_UNDEFINED) { 1979 1817 1980 1818 /* drap: push %reg */ 1981 - save_reg(state, op->src.reg, CFI_BP, -state->stack_size); 1819 + save_reg(cfi, op->src.reg, CFI_BP, -cfi->stack_size); 1982 1820 } 1983 1821 1984 1822 } else { 1985 1823 1986 1824 /* push %reg */ 1987 - save_reg(state, op->src.reg, CFI_CFA, -state->stack_size); 1825 + save_reg(cfi, op->src.reg, CFI_CFA, -cfi->stack_size); 1988 1826 } 1989 1827 1990 1828 /* detect when asm code uses rbp as a scratch register */ 1991 1829 if (!no_fp && insn->func && op->src.reg == CFI_BP && 1992 1830 cfa->base != CFI_BP) 1993 - state->bp_scratch = true; 1831 + cfi->bp_scratch = true; 1994 1832 break; 1995 1833 1996 1834 case OP_DEST_REG_INDIRECT: 1997 1835 1998 - if (state->drap) { 1999 - if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { 1836 + if (cfi->drap) { 1837 + if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) { 2000 1838 2001 1839 /* drap: mov %drap, disp(%rbp) */ 2002 1840 cfa->base = CFI_BP_INDIRECT; 2003 1841 cfa->offset = op->dest.offset; 2004 1842 2005 1843 /* save drap offset so we know when to restore it */ 2006 - state->drap_offset = op->dest.offset; 1844 + cfi->drap_offset = op->dest.offset; 2007 1845 } 2008 1846 2009 1847 else if (regs[op->src.reg].base == CFI_UNDEFINED) { 2010 1848 2011 1849 /* drap: mov reg, disp(%rbp) */ 2012 - save_reg(state, op->src.reg, CFI_BP, op->dest.offset); 1850 + save_reg(cfi, op->src.reg, CFI_BP, op->dest.offset); 2013 1851 } 2014 1852 2015 1853 } else if (op->dest.reg == cfa->base) { 2016 1854 2017 1855 /* mov reg, disp(%rbp) */ 2018 1856 /* mov reg, disp(%rsp) */ 2019 - save_reg(state, op->src.reg, CFI_CFA, 2020 - op->dest.offset - state->cfa.offset); 1857 + save_reg(cfi, op->src.reg, CFI_CFA, 1858 + op->dest.offset - cfi->cfa.offset); 2021 1859 } 2022 1860 2023 1861 break; 2024 1862 2025 1863 case OP_DEST_LEAVE: 2026 - if ((!state->drap && cfa->base != CFI_BP) || 2027 - (state->drap && cfa->base != state->drap_reg)) { 1864 + if ((!cfi->drap && cfa->base != CFI_BP) || 1865 + (cfi->drap && cfa->base != cfi->drap_reg)) { 2028 1866 WARN_FUNC("leave instruction with modified stack frame", 2029 1867 insn->sec, insn->offset); 2030 1868 return -1; ··· 2032 1870 2033 1871 /* leave (mov %rbp, %rsp; pop %rbp) */ 2034 1872 2035 - state->stack_size = -state->regs[CFI_BP].offset - 8; 2036 - restore_reg(state, CFI_BP); 1873 + cfi->stack_size = -cfi->regs[CFI_BP].offset - 8; 1874 + restore_reg(cfi, CFI_BP); 2037 1875 2038 - if (!state->drap) { 1876 + if (!cfi->drap) { 2039 1877 cfa->base = CFI_SP; 2040 1878 cfa->offset -= 8; 2041 1879 } ··· 2050 1888 } 2051 1889 2052 1890 /* pop mem */ 2053 - state->stack_size -= 8; 1891 + cfi->stack_size -= 8; 2054 1892 if (cfa->base == CFI_SP) 2055 1893 cfa->offset -= 8; 2056 1894 ··· 2065 1903 return 0; 2066 1904 } 2067 1905 2068 - static bool insn_state_match(struct instruction *insn, struct insn_state *state) 1906 + static int handle_insn_ops(struct instruction *insn, struct insn_state *state) 2069 1907 { 2070 - struct insn_state *state1 = &insn->state, *state2 = state; 1908 + struct stack_op *op; 1909 + 1910 + list_for_each_entry(op, &insn->stack_ops, list) { 1911 + struct cfi_state old_cfi = state->cfi; 1912 + int res; 1913 + 1914 + res = update_cfi_state(insn, &state->cfi, op); 1915 + if (res) 1916 + return res; 1917 + 1918 + if (insn->alt_group && memcmp(&state->cfi, &old_cfi, sizeof(struct cfi_state))) { 1919 + WARN_FUNC("alternative modifies stack", insn->sec, insn->offset); 1920 + return -1; 1921 + } 1922 + 1923 + if (op->dest.type == OP_DEST_PUSHF) { 1924 + if (!state->uaccess_stack) { 1925 + state->uaccess_stack = 1; 1926 + } else if (state->uaccess_stack >> 31) { 1927 + WARN_FUNC("PUSHF stack exhausted", 1928 + insn->sec, insn->offset); 1929 + return 1; 1930 + } 1931 + state->uaccess_stack <<= 1; 1932 + state->uaccess_stack |= state->uaccess; 1933 + } 1934 + 1935 + if (op->src.type == OP_SRC_POPF) { 1936 + if (state->uaccess_stack) { 1937 + state->uaccess = state->uaccess_stack & 1; 1938 + state->uaccess_stack >>= 1; 1939 + if (state->uaccess_stack == 1) 1940 + state->uaccess_stack = 0; 1941 + } 1942 + } 1943 + } 1944 + 1945 + return 0; 1946 + } 1947 + 1948 + static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2) 1949 + { 1950 + struct cfi_state *cfi1 = &insn->cfi; 2071 1951 int i; 2072 1952 2073 - if (memcmp(&state1->cfa, &state2->cfa, sizeof(state1->cfa))) { 1953 + if (memcmp(&cfi1->cfa, &cfi2->cfa, sizeof(cfi1->cfa))) { 1954 + 2074 1955 WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d", 2075 1956 insn->sec, insn->offset, 2076 - state1->cfa.base, state1->cfa.offset, 2077 - state2->cfa.base, state2->cfa.offset); 1957 + cfi1->cfa.base, cfi1->cfa.offset, 1958 + cfi2->cfa.base, cfi2->cfa.offset); 2078 1959 2079 - } else if (memcmp(&state1->regs, &state2->regs, sizeof(state1->regs))) { 1960 + } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) { 2080 1961 for (i = 0; i < CFI_NUM_REGS; i++) { 2081 - if (!memcmp(&state1->regs[i], &state2->regs[i], 1962 + if (!memcmp(&cfi1->regs[i], &cfi2->regs[i], 2082 1963 sizeof(struct cfi_reg))) 2083 1964 continue; 2084 1965 2085 1966 WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", 2086 1967 insn->sec, insn->offset, 2087 - i, state1->regs[i].base, state1->regs[i].offset, 2088 - i, state2->regs[i].base, state2->regs[i].offset); 1968 + i, cfi1->regs[i].base, cfi1->regs[i].offset, 1969 + i, cfi2->regs[i].base, cfi2->regs[i].offset); 2089 1970 break; 2090 1971 } 2091 1972 2092 - } else if (state1->type != state2->type) { 2093 - WARN_FUNC("stack state mismatch: type1=%d type2=%d", 2094 - insn->sec, insn->offset, state1->type, state2->type); 1973 + } else if (cfi1->type != cfi2->type) { 2095 1974 2096 - } else if (state1->drap != state2->drap || 2097 - (state1->drap && state1->drap_reg != state2->drap_reg) || 2098 - (state1->drap && state1->drap_offset != state2->drap_offset)) { 1975 + WARN_FUNC("stack state mismatch: type1=%d type2=%d", 1976 + insn->sec, insn->offset, cfi1->type, cfi2->type); 1977 + 1978 + } else if (cfi1->drap != cfi2->drap || 1979 + (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) || 1980 + (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) { 1981 + 2099 1982 WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)", 2100 1983 insn->sec, insn->offset, 2101 - state1->drap, state1->drap_reg, state1->drap_offset, 2102 - state2->drap, state2->drap_reg, state2->drap_offset); 1984 + cfi1->drap, cfi1->drap_reg, cfi1->drap_offset, 1985 + cfi2->drap, cfi2->drap_reg, cfi2->drap_offset); 2103 1986 2104 1987 } else 2105 1988 return true; ··· 2170 1963 2171 1964 static int validate_call(struct instruction *insn, struct insn_state *state) 2172 1965 { 1966 + if (state->noinstr && state->instr <= 0 && 1967 + (!insn->call_dest || !insn->call_dest->sec->noinstr)) { 1968 + WARN_FUNC("call to %s() leaves .noinstr.text section", 1969 + insn->sec, insn->offset, call_dest_name(insn)); 1970 + return 1; 1971 + } 1972 + 2173 1973 if (state->uaccess && !func_uaccess_safe(insn->call_dest)) { 2174 1974 WARN_FUNC("call to %s() with UACCESS enabled", 2175 1975 insn->sec, insn->offset, call_dest_name(insn)); ··· 2194 1980 2195 1981 static int validate_sibling_call(struct instruction *insn, struct insn_state *state) 2196 1982 { 2197 - if (has_modified_stack_frame(state)) { 1983 + if (has_modified_stack_frame(insn, state)) { 2198 1984 WARN_FUNC("sibling call from callable instruction with modified stack frame", 2199 1985 insn->sec, insn->offset); 2200 1986 return 1; ··· 2205 1991 2206 1992 static int validate_return(struct symbol *func, struct instruction *insn, struct insn_state *state) 2207 1993 { 1994 + if (state->noinstr && state->instr > 0) { 1995 + WARN_FUNC("return with instrumentation enabled", 1996 + insn->sec, insn->offset); 1997 + return 1; 1998 + } 1999 + 2208 2000 if (state->uaccess && !func_uaccess_safe(func)) { 2209 2001 WARN_FUNC("return with UACCESS enabled", 2210 2002 insn->sec, insn->offset); ··· 2229 2009 return 1; 2230 2010 } 2231 2011 2232 - if (func && has_modified_stack_frame(state)) { 2012 + if (func && has_modified_stack_frame(insn, state)) { 2233 2013 WARN_FUNC("return with modified stack frame", 2234 2014 insn->sec, insn->offset); 2235 2015 return 1; 2236 2016 } 2237 2017 2238 - if (state->bp_scratch) { 2018 + if (state->cfi.bp_scratch) { 2239 2019 WARN_FUNC("BP used as a scratch register", 2240 2020 insn->sec, insn->offset); 2241 2021 return 1; ··· 2245 2025 } 2246 2026 2247 2027 /* 2028 + * Alternatives should not contain any ORC entries, this in turn means they 2029 + * should not contain any CFI ops, which implies all instructions should have 2030 + * the same same CFI state. 2031 + * 2032 + * It is possible to constuct alternatives that have unreachable holes that go 2033 + * unreported (because they're NOPs), such holes would result in CFI_UNDEFINED 2034 + * states which then results in ORC entries, which we just said we didn't want. 2035 + * 2036 + * Avoid them by copying the CFI entry of the first instruction into the whole 2037 + * alternative. 2038 + */ 2039 + static void fill_alternative_cfi(struct objtool_file *file, struct instruction *insn) 2040 + { 2041 + struct instruction *first_insn = insn; 2042 + int alt_group = insn->alt_group; 2043 + 2044 + sec_for_each_insn_continue(file, insn) { 2045 + if (insn->alt_group != alt_group) 2046 + break; 2047 + insn->cfi = first_insn->cfi; 2048 + } 2049 + } 2050 + 2051 + /* 2248 2052 * Follow the branch starting at the given instruction, and recursively follow 2249 2053 * any other branches (jumps). Meanwhile, track the frame pointer state at 2250 2054 * each instruction and validate all the rules described in 2251 2055 * tools/objtool/Documentation/stack-validation.txt. 2252 2056 */ 2253 2057 static int validate_branch(struct objtool_file *file, struct symbol *func, 2254 - struct instruction *first, struct insn_state state) 2058 + struct instruction *insn, struct insn_state state) 2255 2059 { 2256 2060 struct alternative *alt; 2257 - struct instruction *insn, *next_insn; 2061 + struct instruction *next_insn; 2258 2062 struct section *sec; 2259 2063 u8 visited; 2260 2064 int ret; 2261 2065 2262 - insn = first; 2263 2066 sec = insn->sec; 2264 - 2265 - if (insn->alt_group && list_empty(&insn->alts)) { 2266 - WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", 2267 - sec, insn->offset); 2268 - return 1; 2269 - } 2270 2067 2271 2068 while (1) { 2272 2069 next_insn = next_insn_same_sec(file, insn); ··· 2302 2065 2303 2066 visited = 1 << state.uaccess; 2304 2067 if (insn->visited) { 2305 - if (!insn->hint && !insn_state_match(insn, &state)) 2068 + if (!insn->hint && !insn_cfi_match(insn, &state.cfi)) 2306 2069 return 1; 2307 2070 2308 2071 if (insn->visited & visited) 2309 2072 return 0; 2310 2073 } 2311 2074 2312 - if (insn->hint) { 2313 - if (insn->restore) { 2314 - struct instruction *save_insn, *i; 2075 + if (state.noinstr) 2076 + state.instr += insn->instr; 2315 2077 2316 - i = insn; 2317 - save_insn = NULL; 2318 - sym_for_each_insn_continue_reverse(file, func, i) { 2319 - if (i->save) { 2320 - save_insn = i; 2321 - break; 2322 - } 2323 - } 2324 - 2325 - if (!save_insn) { 2326 - WARN_FUNC("no corresponding CFI save for CFI restore", 2327 - sec, insn->offset); 2328 - return 1; 2329 - } 2330 - 2331 - if (!save_insn->visited) { 2332 - /* 2333 - * Oops, no state to copy yet. 2334 - * Hopefully we can reach this 2335 - * instruction from another branch 2336 - * after the save insn has been 2337 - * visited. 2338 - */ 2339 - if (insn == first) 2340 - return 0; 2341 - 2342 - WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo", 2343 - sec, insn->offset); 2344 - return 1; 2345 - } 2346 - 2347 - insn->state = save_insn->state; 2348 - } 2349 - 2350 - state = insn->state; 2351 - 2352 - } else 2353 - insn->state = state; 2078 + if (insn->hint) 2079 + state.cfi = insn->cfi; 2080 + else 2081 + insn->cfi = state.cfi; 2354 2082 2355 2083 insn->visited |= visited; 2356 2084 2357 - if (!insn->ignore_alts) { 2085 + if (!insn->ignore_alts && !list_empty(&insn->alts)) { 2358 2086 bool skip_orig = false; 2359 2087 2360 2088 list_for_each_entry(alt, &insn->alts, list) { ··· 2334 2132 } 2335 2133 } 2336 2134 2135 + if (insn->alt_group) 2136 + fill_alternative_cfi(file, insn); 2137 + 2337 2138 if (skip_orig) 2338 2139 return 0; 2339 2140 } 2141 + 2142 + if (handle_insn_ops(insn, &state)) 2143 + return 1; 2340 2144 2341 2145 switch (insn->type) { 2342 2146 ··· 2410 2202 } 2411 2203 return 0; 2412 2204 2413 - case INSN_STACK: 2414 - if (update_insn_state(insn, &state)) 2415 - return 1; 2416 - 2417 - if (insn->stack_op.dest.type == OP_DEST_PUSHF) { 2418 - if (!state.uaccess_stack) { 2419 - state.uaccess_stack = 1; 2420 - } else if (state.uaccess_stack >> 31) { 2421 - WARN_FUNC("PUSHF stack exhausted", sec, insn->offset); 2422 - return 1; 2423 - } 2424 - state.uaccess_stack <<= 1; 2425 - state.uaccess_stack |= state.uaccess; 2426 - } 2427 - 2428 - if (insn->stack_op.src.type == OP_SRC_POPF) { 2429 - if (state.uaccess_stack) { 2430 - state.uaccess = state.uaccess_stack & 1; 2431 - state.uaccess_stack >>= 1; 2432 - if (state.uaccess_stack == 1) 2433 - state.uaccess_stack = 0; 2434 - } 2435 - } 2436 - 2437 - break; 2438 - 2439 2205 case INSN_STAC: 2440 2206 if (state.uaccess) { 2441 2207 WARN_FUNC("recursive UACCESS enable", sec, insn->offset); ··· 2455 2273 return 0; 2456 2274 2457 2275 if (!next_insn) { 2458 - if (state.cfa.base == CFI_UNDEFINED) 2276 + if (state.cfi.cfa.base == CFI_UNDEFINED) 2459 2277 return 0; 2460 2278 WARN("%s: unexpected end of section", sec->name); 2461 2279 return 1; ··· 2467 2285 return 0; 2468 2286 } 2469 2287 2470 - static int validate_unwind_hints(struct objtool_file *file) 2288 + static int validate_unwind_hints(struct objtool_file *file, struct section *sec) 2471 2289 { 2472 2290 struct instruction *insn; 2473 - int ret, warnings = 0; 2474 2291 struct insn_state state; 2292 + int ret, warnings = 0; 2475 2293 2476 2294 if (!file->hints) 2477 2295 return 0; 2478 2296 2479 - clear_insn_state(&state); 2297 + init_insn_state(&state, sec); 2480 2298 2481 - for_each_insn(file, insn) { 2299 + if (sec) { 2300 + insn = find_insn(file, sec, 0); 2301 + if (!insn) 2302 + return 0; 2303 + } else { 2304 + insn = list_first_entry(&file->insn_list, typeof(*insn), list); 2305 + } 2306 + 2307 + while (&insn->list != &file->insn_list && (!sec || insn->sec == sec)) { 2482 2308 if (insn->hint && !insn->visited) { 2483 2309 ret = validate_branch(file, insn->func, insn, state); 2484 2310 if (ret && backtrace) 2485 2311 BT_FUNC("<=== (hint)", insn); 2486 2312 warnings += ret; 2487 2313 } 2314 + 2315 + insn = list_next_entry(insn, list); 2488 2316 } 2489 2317 2490 2318 return warnings; ··· 2609 2417 return false; 2610 2418 } 2611 2419 2420 + static int validate_symbol(struct objtool_file *file, struct section *sec, 2421 + struct symbol *sym, struct insn_state *state) 2422 + { 2423 + struct instruction *insn; 2424 + int ret; 2425 + 2426 + if (!sym->len) { 2427 + WARN("%s() is missing an ELF size annotation", sym->name); 2428 + return 1; 2429 + } 2430 + 2431 + if (sym->pfunc != sym || sym->alias != sym) 2432 + return 0; 2433 + 2434 + insn = find_insn(file, sec, sym->offset); 2435 + if (!insn || insn->ignore || insn->visited) 2436 + return 0; 2437 + 2438 + state->uaccess = sym->uaccess_safe; 2439 + 2440 + ret = validate_branch(file, insn->func, insn, *state); 2441 + if (ret && backtrace) 2442 + BT_FUNC("<=== (sym)", insn); 2443 + return ret; 2444 + } 2445 + 2612 2446 static int validate_section(struct objtool_file *file, struct section *sec) 2613 2447 { 2614 - struct symbol *func; 2615 - struct instruction *insn; 2616 2448 struct insn_state state; 2617 - int ret, warnings = 0; 2618 - 2619 - clear_insn_state(&state); 2620 - 2621 - state.cfa = initial_func_cfi.cfa; 2622 - memcpy(&state.regs, &initial_func_cfi.regs, 2623 - CFI_NUM_REGS * sizeof(struct cfi_reg)); 2624 - state.stack_size = initial_func_cfi.cfa.offset; 2449 + struct symbol *func; 2450 + int warnings = 0; 2625 2451 2626 2452 list_for_each_entry(func, &sec->symbol_list, list) { 2627 2453 if (func->type != STT_FUNC) 2628 2454 continue; 2629 2455 2630 - if (!func->len) { 2631 - WARN("%s() is missing an ELF size annotation", 2632 - func->name); 2633 - warnings++; 2634 - } 2456 + init_insn_state(&state, sec); 2457 + state.cfi.cfa = initial_func_cfi.cfa; 2458 + memcpy(&state.cfi.regs, &initial_func_cfi.regs, 2459 + CFI_NUM_REGS * sizeof(struct cfi_reg)); 2460 + state.cfi.stack_size = initial_func_cfi.cfa.offset; 2635 2461 2636 - if (func->pfunc != func || func->alias != func) 2637 - continue; 2462 + warnings += validate_symbol(file, sec, func, &state); 2463 + } 2638 2464 2639 - insn = find_insn(file, sec, func->offset); 2640 - if (!insn || insn->ignore || insn->visited) 2641 - continue; 2465 + return warnings; 2466 + } 2642 2467 2643 - state.uaccess = func->uaccess_safe; 2468 + static int validate_vmlinux_functions(struct objtool_file *file) 2469 + { 2470 + struct section *sec; 2471 + int warnings = 0; 2644 2472 2645 - ret = validate_branch(file, func, insn, state); 2646 - if (ret && backtrace) 2647 - BT_FUNC("<=== (func)", insn); 2648 - warnings += ret; 2473 + sec = find_section_by_name(file->elf, ".noinstr.text"); 2474 + if (sec) { 2475 + warnings += validate_section(file, sec); 2476 + warnings += validate_unwind_hints(file, sec); 2477 + } 2478 + 2479 + sec = find_section_by_name(file->elf, ".entry.text"); 2480 + if (sec) { 2481 + warnings += validate_section(file, sec); 2482 + warnings += validate_unwind_hints(file, sec); 2649 2483 } 2650 2484 2651 2485 return warnings; ··· 2682 2464 struct section *sec; 2683 2465 int warnings = 0; 2684 2466 2685 - for_each_sec(file, sec) 2467 + for_each_sec(file, sec) { 2468 + if (!(sec->sh.sh_flags & SHF_EXECINSTR)) 2469 + continue; 2470 + 2686 2471 warnings += validate_section(file, sec); 2472 + } 2687 2473 2688 2474 return warnings; 2689 2475 } ··· 2718 2496 2719 2497 objname = _objname; 2720 2498 2721 - file.elf = elf_read(objname, orc ? O_RDWR : O_RDONLY); 2499 + file.elf = elf_open_read(objname, orc ? O_RDWR : O_RDONLY); 2722 2500 if (!file.elf) 2723 2501 return 1; 2724 2502 ··· 2738 2516 if (list_empty(&file.insn_list)) 2739 2517 goto out; 2740 2518 2519 + if (vmlinux && !validate_dup) { 2520 + ret = validate_vmlinux_functions(&file); 2521 + if (ret < 0) 2522 + goto out; 2523 + 2524 + warnings += ret; 2525 + goto out; 2526 + } 2527 + 2741 2528 if (retpoline) { 2742 2529 ret = validate_retpoline(&file); 2743 2530 if (ret < 0) ··· 2759 2528 goto out; 2760 2529 warnings += ret; 2761 2530 2762 - ret = validate_unwind_hints(&file); 2531 + ret = validate_unwind_hints(&file, NULL); 2763 2532 if (ret < 0) 2764 2533 goto out; 2765 2534 warnings += ret;
+12 -23
tools/objtool/check.h
··· 7 7 #define _CHECK_H 8 8 9 9 #include <stdbool.h> 10 - #include "elf.h" 11 10 #include "cfi.h" 12 11 #include "arch.h" 13 - #include "orc.h" 14 - #include <linux/hashtable.h> 15 12 16 13 struct insn_state { 17 - struct cfi_reg cfa; 18 - struct cfi_reg regs[CFI_NUM_REGS]; 19 - int stack_size; 20 - unsigned char type; 21 - bool bp_scratch; 22 - bool drap, end, uaccess, df; 14 + struct cfi_state cfi; 23 15 unsigned int uaccess_stack; 24 - int drap_reg, drap_offset; 25 - struct cfi_reg vals[CFI_NUM_REGS]; 16 + bool uaccess; 17 + bool df; 18 + bool noinstr; 19 + s8 instr; 26 20 }; 27 21 28 22 struct instruction { ··· 27 33 unsigned int len; 28 34 enum insn_type type; 29 35 unsigned long immediate; 30 - bool alt_group, dead_end, ignore, hint, save, restore, ignore_alts; 36 + bool dead_end, ignore, ignore_alts; 37 + bool hint; 31 38 bool retpoline_safe; 39 + s8 instr; 32 40 u8 visited; 41 + u8 ret_offset; 42 + int alt_group; 33 43 struct symbol *call_dest; 34 44 struct instruction *jump_dest; 35 45 struct instruction *first_jump_src; 36 46 struct rela *jump_table; 37 47 struct list_head alts; 38 48 struct symbol *func; 39 - struct stack_op stack_op; 40 - struct insn_state state; 49 + struct list_head stack_ops; 50 + struct cfi_state cfi; 41 51 struct orc_entry orc; 42 52 }; 43 - 44 - struct objtool_file { 45 - struct elf *elf; 46 - struct list_head insn_list; 47 - DECLARE_HASHTABLE(insn_hash, 20); 48 - bool ignore_unreachables, c_file, hints, rodata; 49 - }; 50 - 51 - int check(const char *objname, bool orc); 52 53 53 54 struct instruction *find_insn(struct objtool_file *file, 54 55 struct section *sec, unsigned long offset);
+68 -34
tools/objtool/elf.c
··· 27 27 return jhash(str, strlen(str), 0); 28 28 } 29 29 30 + static inline int elf_hash_bits(void) 31 + { 32 + return vmlinux ? ELF_HASH_BITS : 16; 33 + } 34 + 35 + #define elf_hash_add(hashtable, node, key) \ 36 + hlist_add_head(node, &hashtable[hash_min(key, elf_hash_bits())]) 37 + 38 + static void elf_hash_init(struct hlist_head *table) 39 + { 40 + __hash_init(table, 1U << elf_hash_bits()); 41 + } 42 + 43 + #define elf_hash_for_each_possible(name, obj, member, key) \ 44 + hlist_for_each_entry(obj, &name[hash_min(key, elf_hash_bits())], member) 45 + 30 46 static void rb_add(struct rb_root *tree, struct rb_node *node, 31 47 int (*cmp)(struct rb_node *, const struct rb_node *)) 32 48 { ··· 61 45 rb_insert_color(node, tree); 62 46 } 63 47 64 - static struct rb_node *rb_find_first(struct rb_root *tree, const void *key, 48 + static struct rb_node *rb_find_first(const struct rb_root *tree, const void *key, 65 49 int (*cmp)(const void *key, const struct rb_node *)) 66 50 { 67 51 struct rb_node *node = tree->rb_node; ··· 127 111 return 0; 128 112 } 129 113 130 - struct section *find_section_by_name(struct elf *elf, const char *name) 114 + struct section *find_section_by_name(const struct elf *elf, const char *name) 131 115 { 132 116 struct section *sec; 133 117 134 - hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name)) 118 + elf_hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name)) 135 119 if (!strcmp(sec->name, name)) 136 120 return sec; 137 121 ··· 143 127 { 144 128 struct section *sec; 145 129 146 - hash_for_each_possible(elf->section_hash, sec, hash, idx) 130 + elf_hash_for_each_possible(elf->section_hash, sec, hash, idx) 147 131 if (sec->idx == idx) 148 132 return sec; 149 133 ··· 154 138 { 155 139 struct symbol *sym; 156 140 157 - hash_for_each_possible(elf->symbol_hash, sym, hash, idx) 141 + elf_hash_for_each_possible(elf->symbol_hash, sym, hash, idx) 158 142 if (sym->idx == idx) 159 143 return sym; 160 144 ··· 189 173 return NULL; 190 174 } 191 175 192 - struct symbol *find_symbol_containing(struct section *sec, unsigned long offset) 176 + struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset) 193 177 { 194 178 struct rb_node *node; 195 179 ··· 217 201 return NULL; 218 202 } 219 203 220 - struct symbol *find_symbol_by_name(struct elf *elf, const char *name) 204 + struct symbol *find_symbol_by_name(const struct elf *elf, const char *name) 221 205 { 222 206 struct symbol *sym; 223 207 224 - hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name)) 208 + elf_hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name)) 225 209 if (!strcmp(sym->name, name)) 226 210 return sym; 227 211 228 212 return NULL; 229 213 } 230 214 231 - struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec, 215 + struct rela *find_rela_by_dest_range(const struct elf *elf, struct section *sec, 232 216 unsigned long offset, unsigned int len) 233 217 { 234 218 struct rela *rela, *r = NULL; ··· 240 224 sec = sec->rela; 241 225 242 226 for_offset_range(o, offset, offset + len) { 243 - hash_for_each_possible(elf->rela_hash, rela, hash, 227 + elf_hash_for_each_possible(elf->rela_hash, rela, hash, 244 228 sec_offset_hash(sec, o)) { 245 229 if (rela->sec != sec) 246 230 continue; ··· 257 241 return NULL; 258 242 } 259 243 260 - struct rela *find_rela_by_dest(struct elf *elf, struct section *sec, unsigned long offset) 244 + struct rela *find_rela_by_dest(const struct elf *elf, struct section *sec, unsigned long offset) 261 245 { 262 246 return find_rela_by_dest_range(elf, sec, offset, 1); 263 247 } ··· 325 309 sec->len = sec->sh.sh_size; 326 310 327 311 list_add_tail(&sec->list, &elf->sections); 328 - hash_add(elf->section_hash, &sec->hash, sec->idx); 329 - hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name)); 312 + elf_hash_add(elf->section_hash, &sec->hash, sec->idx); 313 + elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name)); 330 314 } 331 315 332 316 if (stats) ··· 343 327 344 328 static int read_symbols(struct elf *elf) 345 329 { 346 - struct section *symtab, *sec; 330 + struct section *symtab, *symtab_shndx, *sec; 347 331 struct symbol *sym, *pfunc; 348 332 struct list_head *entry; 349 333 struct rb_node *pnode; 350 334 int symbols_nr, i; 351 335 char *coldstr; 336 + Elf_Data *shndx_data = NULL; 337 + Elf32_Word shndx; 352 338 353 339 symtab = find_section_by_name(elf, ".symtab"); 354 340 if (!symtab) { 355 341 WARN("missing symbol table"); 356 342 return -1; 357 343 } 344 + 345 + symtab_shndx = find_section_by_name(elf, ".symtab_shndx"); 346 + if (symtab_shndx) 347 + shndx_data = symtab_shndx->data; 358 348 359 349 symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize; 360 350 ··· 375 353 376 354 sym->idx = i; 377 355 378 - if (!gelf_getsym(symtab->data, i, &sym->sym)) { 379 - WARN_ELF("gelf_getsym"); 356 + if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym, 357 + &shndx)) { 358 + WARN_ELF("gelf_getsymshndx"); 380 359 goto err; 381 360 } 382 361 ··· 391 368 sym->type = GELF_ST_TYPE(sym->sym.st_info); 392 369 sym->bind = GELF_ST_BIND(sym->sym.st_info); 393 370 394 - if (sym->sym.st_shndx > SHN_UNDEF && 395 - sym->sym.st_shndx < SHN_LORESERVE) { 396 - sym->sec = find_section_by_index(elf, 397 - sym->sym.st_shndx); 371 + if ((sym->sym.st_shndx > SHN_UNDEF && 372 + sym->sym.st_shndx < SHN_LORESERVE) || 373 + (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) { 374 + if (sym->sym.st_shndx != SHN_XINDEX) 375 + shndx = sym->sym.st_shndx; 376 + 377 + sym->sec = find_section_by_index(elf, shndx); 398 378 if (!sym->sec) { 399 379 WARN("couldn't find section for symbol %s", 400 380 sym->name); ··· 420 394 else 421 395 entry = &sym->sec->symbol_list; 422 396 list_add(&sym->list, entry); 423 - hash_add(elf->symbol_hash, &sym->hash, sym->idx); 424 - hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name)); 397 + elf_hash_add(elf->symbol_hash, &sym->hash, sym->idx); 398 + elf_hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name)); 425 399 } 426 400 427 401 if (stats) ··· 482 456 return -1; 483 457 } 484 458 459 + void elf_add_rela(struct elf *elf, struct rela *rela) 460 + { 461 + struct section *sec = rela->sec; 462 + 463 + list_add_tail(&rela->list, &sec->rela_list); 464 + elf_hash_add(elf->rela_hash, &rela->hash, rela_hash(rela)); 465 + } 466 + 485 467 static int read_relas(struct elf *elf) 486 468 { 487 469 struct section *sec; ··· 537 503 return -1; 538 504 } 539 505 540 - list_add_tail(&rela->list, &sec->rela_list); 541 - hash_add(elf->rela_hash, &rela->hash, rela_hash(rela)); 506 + elf_add_rela(elf, rela); 542 507 nr_rela++; 543 508 } 544 509 max_rela = max(max_rela, nr_rela); ··· 552 519 return 0; 553 520 } 554 521 555 - struct elf *elf_read(const char *name, int flags) 522 + struct elf *elf_open_read(const char *name, int flags) 556 523 { 557 524 struct elf *elf; 558 525 Elf_Cmd cmd; ··· 564 531 perror("malloc"); 565 532 return NULL; 566 533 } 567 - memset(elf, 0, sizeof(*elf)); 534 + memset(elf, 0, offsetof(struct elf, sections)); 568 535 569 - hash_init(elf->symbol_hash); 570 - hash_init(elf->symbol_name_hash); 571 - hash_init(elf->section_hash); 572 - hash_init(elf->section_name_hash); 573 - hash_init(elf->rela_hash); 574 536 INIT_LIST_HEAD(&elf->sections); 537 + 538 + elf_hash_init(elf->symbol_hash); 539 + elf_hash_init(elf->symbol_name_hash); 540 + elf_hash_init(elf->section_hash); 541 + elf_hash_init(elf->section_name_hash); 542 + elf_hash_init(elf->rela_hash); 575 543 576 544 elf->fd = open(name, flags); 577 545 if (elf->fd == -1) { ··· 710 676 shstrtab->changed = true; 711 677 712 678 list_add_tail(&sec->list, &elf->sections); 713 - hash_add(elf->section_hash, &sec->hash, sec->idx); 714 - hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name)); 679 + elf_hash_add(elf->section_hash, &sec->hash, sec->idx); 680 + elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name)); 715 681 716 682 return sec; 717 683 } ··· 779 745 return 0; 780 746 } 781 747 782 - int elf_write(struct elf *elf) 748 + int elf_write(const struct elf *elf) 783 749 { 784 750 struct section *sec; 785 751 Elf_Scn *s;
+20 -17
tools/objtool/elf.h
··· 39 39 char *name; 40 40 int idx; 41 41 unsigned int len; 42 - bool changed, text, rodata; 42 + bool changed, text, rodata, noinstr; 43 43 }; 44 44 45 45 struct symbol { ··· 70 70 bool jump_table_start; 71 71 }; 72 72 73 + #define ELF_HASH_BITS 20 74 + 73 75 struct elf { 74 76 Elf *elf; 75 77 GElf_Ehdr ehdr; 76 78 int fd; 77 79 char *name; 78 80 struct list_head sections; 79 - DECLARE_HASHTABLE(symbol_hash, 20); 80 - DECLARE_HASHTABLE(symbol_name_hash, 20); 81 - DECLARE_HASHTABLE(section_hash, 16); 82 - DECLARE_HASHTABLE(section_name_hash, 16); 83 - DECLARE_HASHTABLE(rela_hash, 20); 81 + DECLARE_HASHTABLE(symbol_hash, ELF_HASH_BITS); 82 + DECLARE_HASHTABLE(symbol_name_hash, ELF_HASH_BITS); 83 + DECLARE_HASHTABLE(section_hash, ELF_HASH_BITS); 84 + DECLARE_HASHTABLE(section_name_hash, ELF_HASH_BITS); 85 + DECLARE_HASHTABLE(rela_hash, ELF_HASH_BITS); 84 86 }; 85 87 86 88 #define OFFSET_STRIDE_BITS 4 ··· 114 112 return sec_offset_hash(rela->sec, rela->offset); 115 113 } 116 114 117 - struct elf *elf_read(const char *name, int flags); 118 - struct section *find_section_by_name(struct elf *elf, const char *name); 115 + struct elf *elf_open_read(const char *name, int flags); 116 + struct section *elf_create_section(struct elf *elf, const char *name, size_t entsize, int nr); 117 + struct section *elf_create_rela_section(struct elf *elf, struct section *base); 118 + void elf_add_rela(struct elf *elf, struct rela *rela); 119 + int elf_write(const struct elf *elf); 120 + void elf_close(struct elf *elf); 121 + 122 + struct section *find_section_by_name(const struct elf *elf, const char *name); 119 123 struct symbol *find_func_by_offset(struct section *sec, unsigned long offset); 120 124 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); 121 - struct symbol *find_symbol_by_name(struct elf *elf, const char *name); 122 - struct symbol *find_symbol_containing(struct section *sec, unsigned long offset); 123 - struct rela *find_rela_by_dest(struct elf *elf, struct section *sec, unsigned long offset); 124 - struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec, 125 + struct symbol *find_symbol_by_name(const struct elf *elf, const char *name); 126 + struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset); 127 + struct rela *find_rela_by_dest(const struct elf *elf, struct section *sec, unsigned long offset); 128 + struct rela *find_rela_by_dest_range(const struct elf *elf, struct section *sec, 125 129 unsigned long offset, unsigned int len); 126 130 struct symbol *find_func_containing(struct section *sec, unsigned long offset); 127 - struct section *elf_create_section(struct elf *elf, const char *name, size_t 128 - entsize, int nr); 129 - struct section *elf_create_rela_section(struct elf *elf, struct section *base); 130 131 int elf_rebuild_rela_section(struct section *sec); 131 - int elf_write(struct elf *elf); 132 - void elf_close(struct elf *elf); 133 132 134 133 #define for_each_sec(file, sec) \ 135 134 list_for_each_entry(sec, &file->elf->sections, list)
+3 -1
tools/objtool/objtool.c
··· 58 58 59 59 printf("\n"); 60 60 61 - exit(129); 61 + if (!help) 62 + exit(129); 63 + exit(0); 62 64 } 63 65 64 66 static void handle_options(int *argc, const char ***argv)
+27
tools/objtool/objtool.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * Copyright (C) 2020 Matt Helsley <mhelsley@vmware.com> 4 + */ 5 + 6 + #ifndef _OBJTOOL_H 7 + #define _OBJTOOL_H 8 + 9 + #include <stdbool.h> 10 + #include <linux/list.h> 11 + #include <linux/hashtable.h> 12 + 13 + #include "elf.h" 14 + 15 + struct objtool_file { 16 + struct elf *elf; 17 + struct list_head insn_list; 18 + DECLARE_HASHTABLE(insn_hash, 20); 19 + bool ignore_unreachables, c_file, hints, rodata; 20 + }; 21 + 22 + int check(const char *objname, bool orc); 23 + int orc_dump(const char *objname); 24 + int create_orc(struct objtool_file *file); 25 + int create_orc_sections(struct objtool_file *file); 26 + 27 + #endif /* _OBJTOOL_H */
-18
tools/objtool/orc.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 - /* 3 - * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> 4 - */ 5 - 6 - #ifndef _ORC_H 7 - #define _ORC_H 8 - 9 - #include <asm/orc_types.h> 10 - 11 - struct objtool_file; 12 - 13 - int create_orc(struct objtool_file *file); 14 - int create_orc_sections(struct objtool_file *file); 15 - 16 - int orc_dump(const char *objname); 17 - 18 - #endif /* _ORC_H */
+2 -1
tools/objtool/orc_dump.c
··· 4 4 */ 5 5 6 6 #include <unistd.h> 7 - #include "orc.h" 7 + #include <asm/orc_types.h> 8 + #include "objtool.h" 8 9 #include "warn.h" 9 10 10 11 static const char *reg_name(unsigned int reg)
+5 -7
tools/objtool/orc_gen.c
··· 6 6 #include <stdlib.h> 7 7 #include <string.h> 8 8 9 - #include "orc.h" 10 9 #include "check.h" 11 10 #include "warn.h" 12 11 ··· 15 16 16 17 for_each_insn(file, insn) { 17 18 struct orc_entry *orc = &insn->orc; 18 - struct cfi_reg *cfa = &insn->state.cfa; 19 - struct cfi_reg *bp = &insn->state.regs[CFI_BP]; 19 + struct cfi_reg *cfa = &insn->cfi.cfa; 20 + struct cfi_reg *bp = &insn->cfi.regs[CFI_BP]; 20 21 21 - orc->end = insn->state.end; 22 + orc->end = insn->cfi.end; 22 23 23 24 if (cfa->base == CFI_UNDEFINED) { 24 25 orc->sp_reg = ORC_REG_UNDEFINED; ··· 74 75 75 76 orc->sp_offset = cfa->offset; 76 77 orc->bp_offset = bp->offset; 77 - orc->type = insn->state.type; 78 + orc->type = insn->cfi.type; 78 79 } 79 80 80 81 return 0; ··· 129 130 rela->offset = idx * sizeof(int); 130 131 rela->sec = ip_relasec; 131 132 132 - list_add_tail(&rela->list, &ip_relasec->rela_list); 133 - hash_add(elf->rela_hash, &rela->hash, rela_hash(rela)); 133 + elf_add_rela(elf, rela); 134 134 135 135 return 0; 136 136 }
+40
tools/objtool/weak.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (C) 2020 Matt Helsley <mhelsley@vmware.com> 4 + * Weak definitions necessary to compile objtool without 5 + * some subcommands (e.g. check, orc). 6 + */ 7 + 8 + #include <stdbool.h> 9 + #include <errno.h> 10 + #include "objtool.h" 11 + 12 + #define __weak __attribute__((weak)) 13 + 14 + #define UNSUPPORTED(name) \ 15 + ({ \ 16 + fprintf(stderr, "error: objtool: " name " not implemented\n"); \ 17 + return ENOSYS; \ 18 + }) 19 + 20 + const char __weak *objname; 21 + 22 + int __weak check(const char *_objname, bool orc) 23 + { 24 + UNSUPPORTED("check subcommand"); 25 + } 26 + 27 + int __weak orc_dump(const char *_objname) 28 + { 29 + UNSUPPORTED("orc"); 30 + } 31 + 32 + int __weak create_orc(struct objtool_file *file) 33 + { 34 + UNSUPPORTED("orc"); 35 + } 36 + 37 + int __weak create_orc_sections(struct objtool_file *file) 38 + { 39 + UNSUPPORTED("orc"); 40 + }