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

Merge tag 'objtool-core-2021-04-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool updates from Ingo Molnar:

- Standardize the crypto asm code so that it looks like compiler-
generated code to objtool - so that it can understand it. This
enables unwinding from crypto asm code - and also fixes the last
known remaining objtool warnings for LTO and more.

- x86 decoder fixes: clean up and fix the decoder, and also extend it a
bit

- Misc fixes and cleanups

* tag 'objtool-core-2021-04-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits)
x86/crypto: Enable objtool in crypto code
x86/crypto/sha512-ssse3: Standardize stack alignment prologue
x86/crypto/sha512-avx2: Standardize stack alignment prologue
x86/crypto/sha512-avx: Standardize stack alignment prologue
x86/crypto/sha256-avx2: Standardize stack alignment prologue
x86/crypto/sha1_avx2: Standardize stack alignment prologue
x86/crypto/sha_ni: Standardize stack alignment prologue
x86/crypto/crc32c-pcl-intel: Standardize jump table
x86/crypto/camellia-aesni-avx2: Unconditionally allocate stack buffer
x86/crypto/aesni-intel_avx: Standardize stack alignment prologue
x86/crypto/aesni-intel_avx: Fix register usage comments
x86/crypto/aesni-intel_avx: Remove unused macros
objtool: Support asm jump tables
objtool: Parse options from OBJTOOL_ARGS
objtool: Collate parse_options() users
objtool: Add --backup
objtool,x86: More ModRM sugar
objtool,x86: Rewrite ADD/SUB/AND
objtool,x86: Support %riz encodings
objtool,x86: Simplify register decode
...

+389 -281
-2
arch/x86/crypto/Makefile
··· 2 2 # 3 3 # x86 crypto algorithms 4 4 5 - OBJECT_FILES_NON_STANDARD := y 6 - 7 5 obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o 8 6 twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o 9 7 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
+9 -19
arch/x86/crypto/aesni-intel_avx-x86_64.S
··· 212 212 #define arg4 %rcx 213 213 #define arg5 %r8 214 214 #define arg6 %r9 215 - #define arg7 STACK_OFFSET+8*1(%r14) 216 - #define arg8 STACK_OFFSET+8*2(%r14) 217 - #define arg9 STACK_OFFSET+8*3(%r14) 218 - #define arg10 STACK_OFFSET+8*4(%r14) 219 215 #define keysize 2*15*16(arg1) 220 216 221 217 i = 0 ··· 233 237 .noaltmacro 234 238 .endm 235 239 236 - # need to push 4 registers into stack to maintain 237 - STACK_OFFSET = 8*4 238 - 239 240 TMP1 = 16*0 # Temporary storage for AAD 240 241 TMP2 = 16*1 # Temporary storage for AES State 2 (State 1 is stored in an XMM register) 241 242 TMP3 = 16*2 # Temporary storage for AES State 3 ··· 249 256 ################################ 250 257 251 258 .macro FUNC_SAVE 252 - #the number of pushes must equal STACK_OFFSET 253 259 push %r12 254 260 push %r13 255 - push %r14 256 261 push %r15 257 262 258 - mov %rsp, %r14 259 - 260 - 263 + push %rbp 264 + mov %rsp, %rbp 261 265 262 266 sub $VARIABLE_OFFSET, %rsp 263 267 and $~63, %rsp # align rsp to 64 bytes 264 268 .endm 265 269 266 270 .macro FUNC_RESTORE 267 - mov %r14, %rsp 271 + mov %rbp, %rsp 272 + pop %rbp 268 273 269 274 pop %r15 270 - pop %r14 271 275 pop %r13 272 276 pop %r12 273 277 .endm ··· 284 294 285 295 # combined for GCM encrypt and decrypt functions 286 296 # clobbering all xmm registers 287 - # clobbering r10, r11, r12, r13, r14, r15 297 + # clobbering r10, r11, r12, r13, r15, rax 288 298 .macro GCM_ENC_DEC INITIAL_BLOCKS GHASH_8_ENCRYPT_8_PARALLEL GHASH_LAST_8 GHASH_MUL ENC_DEC REP 289 299 vmovdqu AadHash(arg2), %xmm8 290 300 vmovdqu HashKey(arg2), %xmm13 # xmm13 = HashKey ··· 986 996 ## num_initial_blocks = b mod 4# 987 997 ## encrypt the initial num_initial_blocks blocks and apply ghash on the ciphertext 988 998 ## r10, r11, r12, rax are clobbered 989 - ## arg1, arg3, arg4, r14 are used as a pointer only, not modified 999 + ## arg1, arg2, arg3, arg4 are used as pointers only, not modified 990 1000 991 1001 .macro INITIAL_BLOCKS_AVX REP num_initial_blocks T1 T2 T3 T4 T5 CTR XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 T6 T_key ENC_DEC 992 1002 i = (8-\num_initial_blocks) ··· 1221 1231 1222 1232 # encrypt 8 blocks at a time 1223 1233 # ghash the 8 previously encrypted ciphertext blocks 1224 - # arg1, arg3, arg4 are used as pointers only, not modified 1234 + # arg1, arg2, arg3, arg4 are used as pointers only, not modified 1225 1235 # r11 is the data offset value 1226 1236 .macro GHASH_8_ENCRYPT_8_PARALLEL_AVX REP T1 T2 T3 T4 T5 T6 CTR XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 T7 loop_idx ENC_DEC 1227 1237 ··· 1934 1944 ## num_initial_blocks = b mod 4# 1935 1945 ## encrypt the initial num_initial_blocks blocks and apply ghash on the ciphertext 1936 1946 ## r10, r11, r12, rax are clobbered 1937 - ## arg1, arg3, arg4, r14 are used as a pointer only, not modified 1947 + ## arg1, arg2, arg3, arg4 are used as pointers only, not modified 1938 1948 1939 1949 .macro INITIAL_BLOCKS_AVX2 REP num_initial_blocks T1 T2 T3 T4 T5 CTR XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 T6 T_key ENC_DEC VER 1940 1950 i = (8-\num_initial_blocks) ··· 2176 2186 2177 2187 # encrypt 8 blocks at a time 2178 2188 # ghash the 8 previously encrypted ciphertext blocks 2179 - # arg1, arg3, arg4 are used as pointers only, not modified 2189 + # arg1, arg2, arg3, arg4 are used as pointers only, not modified 2180 2190 # r11 is the data offset value 2181 2191 .macro GHASH_8_ENCRYPT_8_PARALLEL_AVX2 REP T1 T2 T3 T4 T5 T6 CTR XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 T7 loop_idx ENC_DEC 2182 2192
+2 -3
arch/x86/crypto/camellia-aesni-avx2-asm_64.S
··· 990 990 * %rdx: src (32 blocks) 991 991 */ 992 992 FRAME_BEGIN 993 + subq $(16 * 32), %rsp; 993 994 994 995 vzeroupper; 995 996 ··· 1003 1002 %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, 1004 1003 %ymm15, %rdx, (key_table)(CTX, %r8, 8)); 1005 1004 1006 - movq %rsp, %r10; 1007 1005 cmpq %rsi, %rdx; 1008 1006 je .Lcbc_dec_use_stack; 1009 1007 ··· 1015 1015 * dst still in-use (because dst == src), so use stack for temporary 1016 1016 * storage. 1017 1017 */ 1018 - subq $(16 * 32), %rsp; 1019 1018 movq %rsp, %rax; 1020 1019 1021 1020 .Lcbc_dec_continue: ··· 1024 1025 vpxor %ymm7, %ymm7, %ymm7; 1025 1026 vinserti128 $1, (%rdx), %ymm7, %ymm7; 1026 1027 vpxor (%rax), %ymm7, %ymm7; 1027 - movq %r10, %rsp; 1028 1028 vpxor (0 * 32 + 16)(%rdx), %ymm6, %ymm6; 1029 1029 vpxor (1 * 32 + 16)(%rdx), %ymm5, %ymm5; 1030 1030 vpxor (2 * 32 + 16)(%rdx), %ymm4, %ymm4; ··· 1045 1047 1046 1048 vzeroupper; 1047 1049 1050 + addq $(16 * 32), %rsp; 1048 1051 FRAME_END 1049 1052 ret; 1050 1053 SYM_FUNC_END(camellia_cbc_dec_32way)
+2 -5
arch/x86/crypto/crc32c-pcl-intel-asm_64.S
··· 53 53 .endm 54 54 55 55 .macro JMPTBL_ENTRY i 56 - .word crc_\i - crc_array 56 + .quad crc_\i 57 57 .endm 58 58 59 59 .macro JNC_LESS_THAN j ··· 168 168 xor crc2, crc2 169 169 170 170 ## branch into array 171 - lea jump_table(%rip), %bufp 172 - movzwq (%bufp, %rax, 2), len 173 - lea crc_array(%rip), %bufp 174 - lea (%bufp, len, 1), %bufp 171 + mov jump_table(,%rax,8), %bufp 175 172 JMP_NOSPEC bufp 176 173 177 174 ################################################################
+4 -4
arch/x86/crypto/sha1_avx2_x86_64_asm.S
··· 645 645 RESERVE_STACK = (W_SIZE*4 + 8+24) 646 646 647 647 /* Align stack */ 648 - mov %rsp, %rbx 648 + push %rbp 649 + mov %rsp, %rbp 649 650 and $~(0x20-1), %rsp 650 - push %rbx 651 651 sub $RESERVE_STACK, %rsp 652 652 653 653 avx2_zeroupper ··· 665 665 666 666 avx2_zeroupper 667 667 668 - add $RESERVE_STACK, %rsp 669 - pop %rsp 668 + mov %rbp, %rsp 669 + pop %rbp 670 670 671 671 pop %r15 672 672 pop %r14
+4 -4
arch/x86/crypto/sha1_ni_asm.S
··· 59 59 #define DATA_PTR %rsi /* 2nd arg */ 60 60 #define NUM_BLKS %rdx /* 3rd arg */ 61 61 62 - #define RSPSAVE %rax 63 - 64 62 /* gcc conversion */ 65 63 #define FRAME_SIZE 32 /* space for 2x16 bytes */ 66 64 ··· 94 96 .text 95 97 .align 32 96 98 SYM_FUNC_START(sha1_ni_transform) 97 - mov %rsp, RSPSAVE 99 + push %rbp 100 + mov %rsp, %rbp 98 101 sub $FRAME_SIZE, %rsp 99 102 and $~0xF, %rsp 100 103 ··· 287 288 pextrd $3, E0, 1*16(DIGEST_PTR) 288 289 289 290 .Ldone_hash: 290 - mov RSPSAVE, %rsp 291 + mov %rbp, %rsp 292 + pop %rbp 291 293 292 294 ret 293 295 SYM_FUNC_END(sha1_ni_transform)
+6 -7
arch/x86/crypto/sha256-avx2-asm.S
··· 117 117 _INP_END_SIZE = 8 118 118 _INP_SIZE = 8 119 119 _CTX_SIZE = 8 120 - _RSP_SIZE = 8 121 120 122 121 _XFER = 0 123 122 _XMM_SAVE = _XFER + _XFER_SIZE 124 123 _INP_END = _XMM_SAVE + _XMM_SAVE_SIZE 125 124 _INP = _INP_END + _INP_END_SIZE 126 125 _CTX = _INP + _INP_SIZE 127 - _RSP = _CTX + _CTX_SIZE 128 - STACK_SIZE = _RSP + _RSP_SIZE 126 + STACK_SIZE = _CTX + _CTX_SIZE 129 127 130 128 # rotate_Xs 131 129 # Rotate values of symbols X0...X3 ··· 531 533 pushq %r14 532 534 pushq %r15 533 535 534 - mov %rsp, %rax 536 + push %rbp 537 + mov %rsp, %rbp 538 + 535 539 subq $STACK_SIZE, %rsp 536 540 and $-32, %rsp # align rsp to 32 byte boundary 537 - mov %rax, _RSP(%rsp) 538 - 539 541 540 542 shl $6, NUM_BLKS # convert to bytes 541 543 jz done_hash ··· 702 704 703 705 done_hash: 704 706 705 - mov _RSP(%rsp), %rsp 707 + mov %rbp, %rsp 708 + pop %rbp 706 709 707 710 popq %r15 708 711 popq %r14
+19 -22
arch/x86/crypto/sha512-avx-asm.S
··· 76 76 W_SIZE = 80*8 77 77 # W[t] + K[t] | W[t+1] + K[t+1] 78 78 WK_SIZE = 2*8 79 - RSPSAVE_SIZE = 1*8 80 - GPRSAVE_SIZE = 5*8 81 79 82 80 frame_W = 0 83 81 frame_WK = frame_W + W_SIZE 84 - frame_RSPSAVE = frame_WK + WK_SIZE 85 - frame_GPRSAVE = frame_RSPSAVE + RSPSAVE_SIZE 86 - frame_size = frame_GPRSAVE + GPRSAVE_SIZE 82 + frame_size = frame_WK + WK_SIZE 87 83 88 84 # Useful QWORD "arrays" for simpler memory references 89 85 # MSG, DIGEST, K_t, W_t are arrays ··· 277 281 test msglen, msglen 278 282 je nowork 279 283 284 + # Save GPRs 285 + push %rbx 286 + push %r12 287 + push %r13 288 + push %r14 289 + push %r15 290 + 280 291 # Allocate Stack Space 281 - mov %rsp, %rax 292 + push %rbp 293 + mov %rsp, %rbp 282 294 sub $frame_size, %rsp 283 295 and $~(0x20 - 1), %rsp 284 - mov %rax, frame_RSPSAVE(%rsp) 285 - 286 - # Save GPRs 287 - mov %rbx, frame_GPRSAVE(%rsp) 288 - mov %r12, frame_GPRSAVE +8*1(%rsp) 289 - mov %r13, frame_GPRSAVE +8*2(%rsp) 290 - mov %r14, frame_GPRSAVE +8*3(%rsp) 291 - mov %r15, frame_GPRSAVE +8*4(%rsp) 292 296 293 297 updateblock: 294 298 ··· 349 353 dec msglen 350 354 jnz updateblock 351 355 352 - # Restore GPRs 353 - mov frame_GPRSAVE(%rsp), %rbx 354 - mov frame_GPRSAVE +8*1(%rsp), %r12 355 - mov frame_GPRSAVE +8*2(%rsp), %r13 356 - mov frame_GPRSAVE +8*3(%rsp), %r14 357 - mov frame_GPRSAVE +8*4(%rsp), %r15 358 - 359 356 # Restore Stack Pointer 360 - mov frame_RSPSAVE(%rsp), %rsp 357 + mov %rbp, %rsp 358 + pop %rbp 359 + 360 + # Restore GPRs 361 + pop %r15 362 + pop %r14 363 + pop %r13 364 + pop %r12 365 + pop %rbx 361 366 362 367 nowork: 363 368 ret
+20 -22
arch/x86/crypto/sha512-avx2-asm.S
··· 102 102 INP_SIZE = 1*8 103 103 INPEND_SIZE = 1*8 104 104 CTX_SIZE = 1*8 105 - RSPSAVE_SIZE = 1*8 106 - GPRSAVE_SIZE = 5*8 107 105 108 106 frame_XFER = 0 109 107 frame_SRND = frame_XFER + XFER_SIZE 110 108 frame_INP = frame_SRND + SRND_SIZE 111 109 frame_INPEND = frame_INP + INP_SIZE 112 110 frame_CTX = frame_INPEND + INPEND_SIZE 113 - frame_RSPSAVE = frame_CTX + CTX_SIZE 114 - frame_GPRSAVE = frame_RSPSAVE + RSPSAVE_SIZE 115 - frame_size = frame_GPRSAVE + GPRSAVE_SIZE 111 + frame_size = frame_CTX + CTX_SIZE 116 112 117 113 ## assume buffers not aligned 118 114 #define VMOVDQ vmovdqu ··· 566 570 # "blocks" is the message length in SHA512 blocks 567 571 ######################################################################## 568 572 SYM_FUNC_START(sha512_transform_rorx) 573 + # Save GPRs 574 + push %rbx 575 + push %r12 576 + push %r13 577 + push %r14 578 + push %r15 579 + 569 580 # Allocate Stack Space 570 - mov %rsp, %rax 581 + push %rbp 582 + mov %rsp, %rbp 571 583 sub $frame_size, %rsp 572 584 and $~(0x20 - 1), %rsp 573 - mov %rax, frame_RSPSAVE(%rsp) 574 - 575 - # Save GPRs 576 - mov %rbx, 8*0+frame_GPRSAVE(%rsp) 577 - mov %r12, 8*1+frame_GPRSAVE(%rsp) 578 - mov %r13, 8*2+frame_GPRSAVE(%rsp) 579 - mov %r14, 8*3+frame_GPRSAVE(%rsp) 580 - mov %r15, 8*4+frame_GPRSAVE(%rsp) 581 585 582 586 shl $7, NUM_BLKS # convert to bytes 583 587 jz done_hash ··· 668 672 669 673 done_hash: 670 674 671 - # Restore GPRs 672 - mov 8*0+frame_GPRSAVE(%rsp), %rbx 673 - mov 8*1+frame_GPRSAVE(%rsp), %r12 674 - mov 8*2+frame_GPRSAVE(%rsp), %r13 675 - mov 8*3+frame_GPRSAVE(%rsp), %r14 676 - mov 8*4+frame_GPRSAVE(%rsp), %r15 677 - 678 675 # Restore Stack Pointer 679 - mov frame_RSPSAVE(%rsp), %rsp 676 + mov %rbp, %rsp 677 + pop %rbp 678 + 679 + # Restore GPRs 680 + pop %r15 681 + pop %r14 682 + pop %r13 683 + pop %r12 684 + pop %rbx 685 + 680 686 ret 681 687 SYM_FUNC_END(sha512_transform_rorx) 682 688
+19 -22
arch/x86/crypto/sha512-ssse3-asm.S
··· 74 74 75 75 W_SIZE = 80*8 76 76 WK_SIZE = 2*8 77 - RSPSAVE_SIZE = 1*8 78 - GPRSAVE_SIZE = 5*8 79 77 80 78 frame_W = 0 81 79 frame_WK = frame_W + W_SIZE 82 - frame_RSPSAVE = frame_WK + WK_SIZE 83 - frame_GPRSAVE = frame_RSPSAVE + RSPSAVE_SIZE 84 - frame_size = frame_GPRSAVE + GPRSAVE_SIZE 80 + frame_size = frame_WK + WK_SIZE 85 81 86 82 # Useful QWORD "arrays" for simpler memory references 87 83 # MSG, DIGEST, K_t, W_t are arrays ··· 279 283 test msglen, msglen 280 284 je nowork 281 285 286 + # Save GPRs 287 + push %rbx 288 + push %r12 289 + push %r13 290 + push %r14 291 + push %r15 292 + 282 293 # Allocate Stack Space 283 - mov %rsp, %rax 294 + push %rbp 295 + mov %rsp, %rbp 284 296 sub $frame_size, %rsp 285 297 and $~(0x20 - 1), %rsp 286 - mov %rax, frame_RSPSAVE(%rsp) 287 - 288 - # Save GPRs 289 - mov %rbx, frame_GPRSAVE(%rsp) 290 - mov %r12, frame_GPRSAVE +8*1(%rsp) 291 - mov %r13, frame_GPRSAVE +8*2(%rsp) 292 - mov %r14, frame_GPRSAVE +8*3(%rsp) 293 - mov %r15, frame_GPRSAVE +8*4(%rsp) 294 298 295 299 updateblock: 296 300 ··· 351 355 dec msglen 352 356 jnz updateblock 353 357 354 - # Restore GPRs 355 - mov frame_GPRSAVE(%rsp), %rbx 356 - mov frame_GPRSAVE +8*1(%rsp), %r12 357 - mov frame_GPRSAVE +8*2(%rsp), %r13 358 - mov frame_GPRSAVE +8*3(%rsp), %r14 359 - mov frame_GPRSAVE +8*4(%rsp), %r15 360 - 361 358 # Restore Stack Pointer 362 - mov frame_RSPSAVE(%rsp), %rsp 359 + mov %rbp, %rsp 360 + pop %rbp 361 + 362 + # Restore GPRs 363 + pop %r15 364 + pop %r14 365 + pop %r13 366 + pop %r12 367 + pop %rbx 363 368 364 369 nowork: 365 370 ret
+168 -124
tools/objtool/arch/x86/decode.c
··· 21 21 #include <objtool/warn.h> 22 22 #include <arch/elf.h> 23 23 24 - static unsigned char op_to_cfi_reg[][2] = { 25 - {CFI_AX, CFI_R8}, 26 - {CFI_CX, CFI_R9}, 27 - {CFI_DX, CFI_R10}, 28 - {CFI_BX, CFI_R11}, 29 - {CFI_SP, CFI_R12}, 30 - {CFI_BP, CFI_R13}, 31 - {CFI_SI, CFI_R14}, 32 - {CFI_DI, CFI_R15}, 33 - }; 34 - 35 24 static int is_x86_64(const struct elf *elf) 36 25 { 37 26 switch (elf->ehdr.e_machine) { ··· 76 87 return -1; \ 77 88 else for (list_add_tail(&op->list, ops_list); op; op = NULL) 78 89 90 + /* 91 + * Helpers to decode ModRM/SIB: 92 + * 93 + * r/m| AX CX DX BX | SP | BP | SI DI | 94 + * | R8 R9 R10 R11 | R12 | R13 | R14 R15 | 95 + * Mod+----------------+-----+-----+---------+ 96 + * 00 | [r/m] |[SIB]|[IP+]| [r/m] | 97 + * 01 | [r/m + d8] |[S+d]| [r/m + d8] | 98 + * 10 | [r/m + d32] |[S+D]| [r/m + d32] | 99 + * 11 | r/ m | 100 + */ 101 + 102 + #define mod_is_mem() (modrm_mod != 3) 103 + #define mod_is_reg() (modrm_mod == 3) 104 + 105 + #define is_RIP() ((modrm_rm & 7) == CFI_BP && modrm_mod == 0) 106 + #define have_SIB() ((modrm_rm & 7) == CFI_SP && mod_is_mem()) 107 + 108 + #define rm_is(reg) (have_SIB() ? \ 109 + sib_base == (reg) && sib_index == CFI_SP : \ 110 + modrm_rm == (reg)) 111 + 112 + #define rm_is_mem(reg) (mod_is_mem() && !is_RIP() && rm_is(reg)) 113 + #define rm_is_reg(reg) (mod_is_reg() && modrm_rm == (reg)) 114 + 79 115 int arch_decode_instruction(const struct elf *elf, const struct section *sec, 80 116 unsigned long offset, unsigned int maxlen, 81 117 unsigned int *len, enum insn_type *type, ··· 108 94 struct list_head *ops_list) 109 95 { 110 96 struct insn insn; 111 - int x86_64, sign, ret; 112 - unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, 113 - rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0, 114 - modrm_reg = 0, sib = 0; 97 + int x86_64, ret; 98 + unsigned char op1, op2, 99 + rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, rex_x = 0, 100 + modrm = 0, modrm_mod = 0, modrm_rm = 0, modrm_reg = 0, 101 + sib = 0, /* sib_scale = 0, */ sib_index = 0, sib_base = 0; 115 102 struct stack_op *op = NULL; 116 103 struct symbol *sym; 104 + u64 imm; 117 105 118 106 x86_64 = is_x86_64(elf); 119 107 if (x86_64 == -1) ··· 148 132 if (insn.modrm.nbytes) { 149 133 modrm = insn.modrm.bytes[0]; 150 134 modrm_mod = X86_MODRM_MOD(modrm); 151 - modrm_reg = X86_MODRM_REG(modrm); 152 - modrm_rm = X86_MODRM_RM(modrm); 135 + modrm_reg = X86_MODRM_REG(modrm) + 8*rex_r; 136 + modrm_rm = X86_MODRM_RM(modrm) + 8*rex_b; 153 137 } 154 138 155 - if (insn.sib.nbytes) 139 + if (insn.sib.nbytes) { 156 140 sib = insn.sib.bytes[0]; 141 + /* sib_scale = X86_SIB_SCALE(sib); */ 142 + sib_index = X86_SIB_INDEX(sib) + 8*rex_x; 143 + sib_base = X86_SIB_BASE(sib) + 8*rex_b; 144 + } 157 145 158 146 switch (op1) { 159 147 160 148 case 0x1: 161 149 case 0x29: 162 - if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { 150 + if (rex_w && rm_is_reg(CFI_SP)) { 163 151 164 152 /* add/sub reg, %rsp */ 165 153 ADD_OP(op) { 166 154 op->src.type = OP_SRC_ADD; 167 - op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 155 + op->src.reg = modrm_reg; 168 156 op->dest.type = OP_DEST_REG; 169 157 op->dest.reg = CFI_SP; 170 158 } ··· 180 160 /* push reg */ 181 161 ADD_OP(op) { 182 162 op->src.type = OP_SRC_REG; 183 - op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; 163 + op->src.reg = (op1 & 0x7) + 8*rex_b; 184 164 op->dest.type = OP_DEST_PUSH; 185 165 } 186 166 ··· 192 172 ADD_OP(op) { 193 173 op->src.type = OP_SRC_POP; 194 174 op->dest.type = OP_DEST_REG; 195 - op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; 175 + op->dest.reg = (op1 & 0x7) + 8*rex_b; 196 176 } 197 177 198 178 break; ··· 210 190 *type = INSN_JUMP_CONDITIONAL; 211 191 break; 212 192 213 - case 0x81: 214 - case 0x83: 215 - if (rex != 0x48) 193 + case 0x80 ... 0x83: 194 + /* 195 + * 1000 00sw : mod OP r/m : immediate 196 + * 197 + * s - sign extend immediate 198 + * w - imm8 / imm32 199 + * 200 + * OP: 000 ADD 100 AND 201 + * 001 OR 101 SUB 202 + * 010 ADC 110 XOR 203 + * 011 SBB 111 CMP 204 + */ 205 + 206 + /* 64bit only */ 207 + if (!rex_w) 216 208 break; 217 209 218 - if (modrm == 0xe4) { 210 + /* %rsp target only */ 211 + if (!rm_is_reg(CFI_SP)) 212 + break; 213 + 214 + imm = insn.immediate.value; 215 + if (op1 & 2) { /* sign extend */ 216 + if (op1 & 1) { /* imm32 */ 217 + imm <<= 32; 218 + imm = (s64)imm >> 32; 219 + } else { /* imm8 */ 220 + imm <<= 56; 221 + imm = (s64)imm >> 56; 222 + } 223 + } 224 + 225 + switch (modrm_reg & 7) { 226 + case 5: 227 + imm = -imm; 228 + /* fallthrough */ 229 + case 0: 230 + /* add/sub imm, %rsp */ 231 + ADD_OP(op) { 232 + op->src.type = OP_SRC_ADD; 233 + op->src.reg = CFI_SP; 234 + op->src.offset = imm; 235 + op->dest.type = OP_DEST_REG; 236 + op->dest.reg = CFI_SP; 237 + } 238 + break; 239 + 240 + case 4: 219 241 /* and imm, %rsp */ 220 242 ADD_OP(op) { 221 243 op->src.type = OP_SRC_AND; ··· 267 205 op->dest.reg = CFI_SP; 268 206 } 269 207 break; 270 - } 271 208 272 - if (modrm == 0xc4) 273 - sign = 1; 274 - else if (modrm == 0xec) 275 - sign = -1; 276 - else 209 + default: 210 + /* WARN ? */ 277 211 break; 278 - 279 - /* add/sub imm, %rsp */ 280 - ADD_OP(op) { 281 - op->src.type = OP_SRC_ADD; 282 - op->src.reg = CFI_SP; 283 - op->src.offset = insn.immediate.value * sign; 284 - op->dest.type = OP_DEST_REG; 285 - op->dest.reg = CFI_SP; 286 212 } 213 + 287 214 break; 288 215 289 216 case 0x89: 290 - if (rex_w && !rex_r && modrm_reg == 4) { 217 + if (!rex_w) 218 + break; 291 219 292 - if (modrm_mod == 3) { 220 + if (modrm_reg == CFI_SP) { 221 + 222 + if (mod_is_reg()) { 293 223 /* mov %rsp, reg */ 294 224 ADD_OP(op) { 295 225 op->src.type = OP_SRC_REG; 296 226 op->src.reg = CFI_SP; 297 227 op->dest.type = OP_DEST_REG; 298 - op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; 228 + op->dest.reg = modrm_rm; 299 229 } 300 230 break; 301 231 302 232 } else { 303 - /* skip nontrivial SIB */ 304 - if (modrm_rm == 4 && !(sib == 0x24 && rex_b == rex_x)) 233 + /* skip RIP relative displacement */ 234 + if (is_RIP()) 305 235 break; 306 236 307 - /* skip RIP relative displacement */ 308 - if (modrm_rm == 5 && modrm_mod == 0) 309 - break; 237 + /* skip nontrivial SIB */ 238 + if (have_SIB()) { 239 + modrm_rm = sib_base; 240 + if (sib_index != CFI_SP) 241 + break; 242 + } 310 243 311 244 /* mov %rsp, disp(%reg) */ 312 245 ADD_OP(op) { 313 246 op->src.type = OP_SRC_REG; 314 247 op->src.reg = CFI_SP; 315 248 op->dest.type = OP_DEST_REG_INDIRECT; 316 - op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; 249 + op->dest.reg = modrm_rm; 317 250 op->dest.offset = insn.displacement.value; 318 251 } 319 252 break; ··· 317 260 break; 318 261 } 319 262 320 - if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { 263 + if (rm_is_reg(CFI_SP)) { 321 264 322 265 /* mov reg, %rsp */ 323 266 ADD_OP(op) { 324 267 op->src.type = OP_SRC_REG; 325 - op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 268 + op->src.reg = modrm_reg; 326 269 op->dest.type = OP_DEST_REG; 327 270 op->dest.reg = CFI_SP; 328 271 } ··· 331 274 332 275 /* fallthrough */ 333 276 case 0x88: 334 - if (!rex_b && 335 - (modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) { 277 + if (!rex_w) 278 + break; 279 + 280 + if (rm_is_mem(CFI_BP)) { 336 281 337 282 /* mov reg, disp(%rbp) */ 338 283 ADD_OP(op) { 339 284 op->src.type = OP_SRC_REG; 340 - op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 285 + op->src.reg = modrm_reg; 341 286 op->dest.type = OP_DEST_REG_INDIRECT; 342 287 op->dest.reg = CFI_BP; 343 288 op->dest.offset = insn.displacement.value; ··· 347 288 break; 348 289 } 349 290 350 - if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) { 291 + if (rm_is_mem(CFI_SP)) { 351 292 352 293 /* mov reg, disp(%rsp) */ 353 294 ADD_OP(op) { 354 295 op->src.type = OP_SRC_REG; 355 - op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; 296 + op->src.reg = modrm_reg; 356 297 op->dest.type = OP_DEST_REG_INDIRECT; 357 298 op->dest.reg = CFI_SP; 358 299 op->dest.offset = insn.displacement.value; ··· 363 304 break; 364 305 365 306 case 0x8b: 366 - if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) { 307 + if (!rex_w) 308 + break; 309 + 310 + if (rm_is_mem(CFI_BP)) { 367 311 368 312 /* mov disp(%rbp), reg */ 369 313 ADD_OP(op) { ··· 374 312 op->src.reg = CFI_BP; 375 313 op->src.offset = insn.displacement.value; 376 314 op->dest.type = OP_DEST_REG; 377 - op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; 315 + op->dest.reg = modrm_reg; 378 316 } 317 + break; 318 + } 379 319 380 - } else if (rex_w && !rex_b && sib == 0x24 && 381 - modrm_mod != 3 && modrm_rm == 4) { 320 + if (rm_is_mem(CFI_SP)) { 382 321 383 322 /* mov disp(%rsp), reg */ 384 323 ADD_OP(op) { ··· 387 324 op->src.reg = CFI_SP; 388 325 op->src.offset = insn.displacement.value; 389 326 op->dest.type = OP_DEST_REG; 390 - op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; 327 + op->dest.reg = modrm_reg; 391 328 } 329 + break; 392 330 } 393 331 394 332 break; 395 333 396 334 case 0x8d: 397 - if (sib == 0x24 && rex_w && !rex_b && !rex_x) { 398 - 399 - ADD_OP(op) { 400 - if (!insn.displacement.value) { 401 - /* lea (%rsp), reg */ 402 - op->src.type = OP_SRC_REG; 403 - } else { 404 - /* lea disp(%rsp), reg */ 405 - op->src.type = OP_SRC_ADD; 406 - op->src.offset = insn.displacement.value; 407 - } 408 - op->src.reg = CFI_SP; 409 - op->dest.type = OP_DEST_REG; 410 - op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; 411 - } 412 - 413 - } else if (rex == 0x48 && modrm == 0x65) { 414 - 415 - /* lea disp(%rbp), %rsp */ 416 - ADD_OP(op) { 417 - op->src.type = OP_SRC_ADD; 418 - op->src.reg = CFI_BP; 419 - op->src.offset = insn.displacement.value; 420 - op->dest.type = OP_DEST_REG; 421 - op->dest.reg = CFI_SP; 422 - } 423 - 424 - } else if (rex == 0x49 && modrm == 0x62 && 425 - insn.displacement.value == -8) { 426 - 427 - /* 428 - * lea -0x8(%r10), %rsp 429 - * 430 - * Restoring rsp back to its original value after a 431 - * stack realignment. 432 - */ 433 - ADD_OP(op) { 434 - op->src.type = OP_SRC_ADD; 435 - op->src.reg = CFI_R10; 436 - op->src.offset = -8; 437 - op->dest.type = OP_DEST_REG; 438 - op->dest.reg = CFI_SP; 439 - } 440 - 441 - } else if (rex == 0x49 && modrm == 0x65 && 442 - insn.displacement.value == -16) { 443 - 444 - /* 445 - * lea -0x10(%r13), %rsp 446 - * 447 - * Restoring rsp back to its original value after a 448 - * stack realignment. 449 - */ 450 - ADD_OP(op) { 451 - op->src.type = OP_SRC_ADD; 452 - op->src.reg = CFI_R13; 453 - op->src.offset = -16; 454 - op->dest.type = OP_DEST_REG; 455 - op->dest.reg = CFI_SP; 456 - } 335 + if (mod_is_reg()) { 336 + WARN("invalid LEA encoding at %s:0x%lx", sec->name, offset); 337 + break; 457 338 } 458 339 340 + /* skip non 64bit ops */ 341 + if (!rex_w) 342 + break; 343 + 344 + /* skip RIP relative displacement */ 345 + if (is_RIP()) 346 + break; 347 + 348 + /* skip nontrivial SIB */ 349 + if (have_SIB()) { 350 + modrm_rm = sib_base; 351 + if (sib_index != CFI_SP) 352 + break; 353 + } 354 + 355 + /* lea disp(%src), %dst */ 356 + ADD_OP(op) { 357 + op->src.offset = insn.displacement.value; 358 + if (!op->src.offset) { 359 + /* lea (%src), %dst */ 360 + op->src.type = OP_SRC_REG; 361 + } else { 362 + /* lea disp(%src), %dst */ 363 + op->src.type = OP_SRC_ADD; 364 + } 365 + op->src.reg = modrm_rm; 366 + op->dest.type = OP_DEST_REG; 367 + op->dest.reg = modrm_reg; 368 + } 459 369 break; 460 370 461 371 case 0x8f: ··· 515 479 * mov bp, sp 516 480 * pop bp 517 481 */ 518 - ADD_OP(op) 519 - op->dest.type = OP_DEST_LEAVE; 520 - 482 + ADD_OP(op) { 483 + op->src.type = OP_SRC_REG; 484 + op->src.reg = CFI_BP; 485 + op->dest.type = OP_DEST_REG; 486 + op->dest.reg = CFI_SP; 487 + } 488 + ADD_OP(op) { 489 + op->src.type = OP_SRC_POP; 490 + op->dest.type = OP_DEST_REG; 491 + op->dest.reg = CFI_BP; 492 + } 521 493 break; 522 494 523 495 case 0xe3:
+6 -6
tools/objtool/arch/x86/include/arch/cfi_regs.h
··· 4 4 #define _OBJTOOL_CFI_REGS_H 5 5 6 6 #define CFI_AX 0 7 - #define CFI_DX 1 8 - #define CFI_CX 2 7 + #define CFI_CX 1 8 + #define CFI_DX 2 9 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 10 + #define CFI_SP 4 11 + #define CFI_BP 5 12 + #define CFI_SI 6 13 + #define CFI_DI 7 14 14 #define CFI_R8 8 15 15 #define CFI_R9 9 16 16 #define CFI_R10 10
+37 -6
tools/objtool/builtin-check.c
··· 15 15 16 16 #include <subcmd/parse-options.h> 17 17 #include <string.h> 18 + #include <stdlib.h> 18 19 #include <objtool/builtin.h> 19 20 #include <objtool/objtool.h> 20 21 21 - bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, validate_dup, vmlinux, mcount, noinstr; 22 + bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, 23 + validate_dup, vmlinux, mcount, noinstr, backup; 22 24 23 25 static const char * const check_usage[] = { 24 26 "objtool check [<options>] file.o", 27 + NULL, 28 + }; 29 + 30 + static const char * const env_usage[] = { 31 + "OBJTOOL_ARGS=\"<options>\"", 25 32 NULL, 26 33 }; 27 34 ··· 44 37 OPT_BOOLEAN('n', "noinstr", &noinstr, "noinstr validation for vmlinux.o"), 45 38 OPT_BOOLEAN('l', "vmlinux", &vmlinux, "vmlinux.o validation"), 46 39 OPT_BOOLEAN('M', "mcount", &mcount, "generate __mcount_loc"), 40 + OPT_BOOLEAN('B', "backup", &backup, "create .orig files before modification"), 47 41 OPT_END(), 48 42 }; 43 + 44 + int cmd_parse_options(int argc, const char **argv, const char * const usage[]) 45 + { 46 + const char *envv[16] = { }; 47 + char *env; 48 + int envc; 49 + 50 + env = getenv("OBJTOOL_ARGS"); 51 + if (env) { 52 + envv[0] = "OBJTOOL_ARGS"; 53 + for (envc = 1; envc < ARRAY_SIZE(envv); ) { 54 + envv[envc++] = env; 55 + env = strchr(env, ' '); 56 + if (!env) 57 + break; 58 + *env = '\0'; 59 + env++; 60 + } 61 + 62 + parse_options(envc, envv, check_options, env_usage, 0); 63 + } 64 + 65 + argc = parse_options(argc, argv, check_options, usage, 0); 66 + if (argc != 1) 67 + usage_with_options(usage, check_options); 68 + return argc; 69 + } 49 70 50 71 int cmd_check(int argc, const char **argv) 51 72 { ··· 81 46 struct objtool_file *file; 82 47 int ret; 83 48 84 - argc = parse_options(argc, argv, check_options, check_usage, 0); 85 - 86 - if (argc != 1) 87 - usage_with_options(check_usage, check_options); 88 - 49 + argc = cmd_parse_options(argc, argv, check_usage); 89 50 objname = argv[0]; 90 51 91 52 file = objtool_open_read(objname);
+1 -4
tools/objtool/builtin-orc.c
··· 34 34 struct objtool_file *file; 35 35 int ret; 36 36 37 - argc = parse_options(argc, argv, check_options, orc_usage, 0); 38 - if (argc != 1) 39 - usage_with_options(orc_usage, check_options); 40 - 37 + argc = cmd_parse_options(argc, argv, orc_usage); 41 38 objname = argv[0]; 42 39 43 40 file = objtool_open_read(objname);
+24 -29
tools/objtool/check.c
··· 108 108 for (insn = next_insn_same_sec(file, insn); insn; \ 109 109 insn = next_insn_same_sec(file, insn)) 110 110 111 + static bool is_jump_table_jump(struct instruction *insn) 112 + { 113 + struct alt_group *alt_group = insn->alt_group; 114 + 115 + if (insn->jump_table) 116 + return true; 117 + 118 + /* Retpoline alternative for a jump table? */ 119 + return alt_group && alt_group->orig_group && 120 + alt_group->orig_group->first_insn->jump_table; 121 + } 122 + 111 123 static bool is_sibling_call(struct instruction *insn) 112 124 { 113 125 /* ··· 132 120 133 121 /* An indirect jump is either a sibling call or a jump to a table. */ 134 122 if (insn->type == INSN_JUMP_DYNAMIC) 135 - return list_empty(&insn->alts); 123 + return !is_jump_table_jump(insn); 136 124 137 125 /* add_jump_destinations() sets insn->call_dest for sibling calls. */ 138 126 return (is_static_jump(insn) && insn->call_dest); ··· 1981 1969 * 41 5d pop %r13 1982 1970 * c3 retq 1983 1971 */ 1984 - static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi, 1985 - struct stack_op *op) 1972 + static int update_cfi_state(struct instruction *insn, 1973 + struct instruction *next_insn, 1974 + struct cfi_state *cfi, struct stack_op *op) 1986 1975 { 1987 1976 struct cfi_reg *cfa = &cfi->cfa; 1988 1977 struct cfi_reg *regs = cfi->regs; ··· 2042 2029 } 2043 2030 2044 2031 else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP && 2045 - cfa->base == CFI_BP) { 2032 + (cfa->base == CFI_BP || cfa->base == cfi->drap_reg)) { 2046 2033 2047 2034 /* 2048 2035 * mov %rbp, %rsp ··· 2184 2171 break; 2185 2172 } 2186 2173 2187 - if (op->dest.reg == cfi->cfa.base) { 2174 + if (op->dest.reg == cfi->cfa.base && !(next_insn && next_insn->hint)) { 2188 2175 WARN_FUNC("unsupported stack register modification", 2189 2176 insn->sec, insn->offset); 2190 2177 return -1; ··· 2239 2226 cfa->offset = 0; 2240 2227 cfi->drap_offset = -1; 2241 2228 2242 - } else if (regs[op->dest.reg].offset == -cfi->stack_size) { 2229 + } else if (cfi->stack_size == -regs[op->dest.reg].offset) { 2243 2230 2244 2231 /* pop %reg */ 2245 2232 restore_reg(cfi, op->dest.reg); ··· 2380 2367 2381 2368 break; 2382 2369 2383 - case OP_DEST_LEAVE: 2384 - if ((!cfi->drap && cfa->base != CFI_BP) || 2385 - (cfi->drap && cfa->base != cfi->drap_reg)) { 2386 - WARN_FUNC("leave instruction with modified stack frame", 2387 - insn->sec, insn->offset); 2388 - return -1; 2389 - } 2390 - 2391 - /* leave (mov %rbp, %rsp; pop %rbp) */ 2392 - 2393 - cfi->stack_size = -cfi->regs[CFI_BP].offset - 8; 2394 - restore_reg(cfi, CFI_BP); 2395 - 2396 - if (!cfi->drap) { 2397 - cfa->base = CFI_SP; 2398 - cfa->offset -= 8; 2399 - } 2400 - 2401 - break; 2402 - 2403 2370 case OP_DEST_MEM: 2404 2371 if (op->src.type != OP_SRC_POP && op->src.type != OP_SRC_POPF) { 2405 2372 WARN_FUNC("unknown stack-related memory operation", ··· 2436 2443 return 0; 2437 2444 } 2438 2445 2439 - static int handle_insn_ops(struct instruction *insn, struct insn_state *state) 2446 + static int handle_insn_ops(struct instruction *insn, 2447 + struct instruction *next_insn, 2448 + struct insn_state *state) 2440 2449 { 2441 2450 struct stack_op *op; 2442 2451 2443 2452 list_for_each_entry(op, &insn->stack_ops, list) { 2444 2453 2445 - if (update_cfi_state(insn, &state->cfi, op)) 2454 + if (update_cfi_state(insn, next_insn, &state->cfi, op)) 2446 2455 return 1; 2447 2456 2448 2457 if (!insn->alt_group) ··· 2727 2732 return 0; 2728 2733 } 2729 2734 2730 - if (handle_insn_ops(insn, &state)) 2735 + if (handle_insn_ops(insn, next_insn, &state)) 2731 2736 return 1; 2732 2737 2733 2738 switch (insn->type) {
-1
tools/objtool/include/objtool/arch.h
··· 35 35 OP_DEST_MEM, 36 36 OP_DEST_PUSH, 37 37 OP_DEST_PUSHF, 38 - OP_DEST_LEAVE, 39 38 }; 40 39 41 40 struct op_dest {
+4 -1
tools/objtool/include/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, validate_dup, vmlinux, mcount, noinstr; 11 + extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats, 12 + validate_dup, vmlinux, mcount, noinstr, backup; 13 + 14 + extern int cmd_parse_options(int argc, const char **argv, const char * const usage[]); 12 15 13 16 extern int cmd_check(int argc, const char **argv); 14 17 extern int cmd_orc(int argc, const char **argv);
+64
tools/objtool/objtool.c
··· 17 17 #include <stdbool.h> 18 18 #include <string.h> 19 19 #include <stdlib.h> 20 + #include <unistd.h> 20 21 #include <subcmd/exec-cmd.h> 21 22 #include <subcmd/pager.h> 22 23 #include <linux/kernel.h> ··· 45 44 const char *objname; 46 45 static struct objtool_file file; 47 46 47 + static bool objtool_create_backup(const char *_objname) 48 + { 49 + int len = strlen(_objname); 50 + char *buf, *base, *name = malloc(len+6); 51 + int s, d, l, t; 52 + 53 + if (!name) { 54 + perror("failed backup name malloc"); 55 + return false; 56 + } 57 + 58 + strcpy(name, _objname); 59 + strcpy(name + len, ".orig"); 60 + 61 + d = open(name, O_CREAT|O_WRONLY|O_TRUNC, 0644); 62 + if (d < 0) { 63 + perror("failed to create backup file"); 64 + return false; 65 + } 66 + 67 + s = open(_objname, O_RDONLY); 68 + if (s < 0) { 69 + perror("failed to open orig file"); 70 + return false; 71 + } 72 + 73 + buf = malloc(4096); 74 + if (!buf) { 75 + perror("failed backup data malloc"); 76 + return false; 77 + } 78 + 79 + while ((l = read(s, buf, 4096)) > 0) { 80 + base = buf; 81 + do { 82 + t = write(d, base, l); 83 + if (t < 0) { 84 + perror("failed backup write"); 85 + return false; 86 + } 87 + base += t; 88 + l -= t; 89 + } while (l); 90 + } 91 + 92 + if (l < 0) { 93 + perror("failed backup read"); 94 + return false; 95 + } 96 + 97 + free(name); 98 + free(buf); 99 + close(d); 100 + close(s); 101 + 102 + return true; 103 + } 104 + 48 105 struct objtool_file *objtool_open_read(const char *_objname) 49 106 { 50 107 if (objname) { ··· 117 58 file.elf = elf_open_read(objname, O_RDWR); 118 59 if (!file.elf) 119 60 return NULL; 61 + 62 + if (backup && !objtool_create_backup(objname)) { 63 + WARN("can't create backup file"); 64 + return NULL; 65 + } 120 66 121 67 INIT_LIST_HEAD(&file.insn_list); 122 68 hash_init(file.insn_hash);