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

Configure Feed

Select the types of activity you want to include in your feed.

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

Pull objtool updates from Ingo Molnar:

- KLP support updates and fixes (Song Liu)

- KLP-build script updates and fixes (Joe Lawrence)

- Support Clang RAX DRAP sequence, to address clang false positive
(Josh Poimboeuf)

- Reorder ORC register numbering to match regular x86 register
numbering (Josh Poimboeuf)

- Misc cleanups (Wentong Tian, Song Liu)

* tag 'objtool-core-2026-04-13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
objtool/x86: Reorder ORC register numbering
objtool: Support Clang RAX DRAP sequence
livepatch/klp-build: report patch validation fuzz
livepatch/klp-build: add terminal color output
livepatch/klp-build: provide friendlier error messages
livepatch/klp-build: improve short-circuit validation
livepatch/klp-build: fix shellcheck complaints
livepatch/klp-build: add Makefile with check target
livepatch/klp-build: add grep-override function
livepatch/klp-build: switch to GNU patch and recountdiff
livepatch/klp-build: support patches that add/remove files
objtool/klp: Correlate locals to globals
objtool/klp: Match symbols based on demangled_name for global variables
objtool/klp: Remove .llvm suffix in demangle_name()
objtool/klp: Also demangle global objects
objtool/klp: Use sym->demangled_name for symbol_name hash
objtool/klp: Remove trailing '_' in demangle_name()
objtool/klp: Remove redundant strcmp() in correlate_symbols()
objtool: Use section/symbol type helpers

+337 -126
+5 -4
arch/x86/include/asm/orc_types.h
··· 28 28 * and GCC realigned stacks. 29 29 */ 30 30 #define ORC_REG_UNDEFINED 0 31 - #define ORC_REG_PREV_SP 1 31 + #define ORC_REG_AX 1 32 32 #define ORC_REG_DX 2 33 - #define ORC_REG_DI 3 33 + #define ORC_REG_SP 3 34 34 #define ORC_REG_BP 4 35 - #define ORC_REG_SP 5 35 + #define ORC_REG_DI 5 36 36 #define ORC_REG_R10 6 37 37 #define ORC_REG_R13 7 38 - #define ORC_REG_BP_INDIRECT 8 38 + #define ORC_REG_PREV_SP 8 39 39 #define ORC_REG_SP_INDIRECT 9 40 + #define ORC_REG_BP_INDIRECT 10 40 41 #define ORC_REG_MAX 15 41 42 42 43 #define ORC_TYPE_UNDEFINED 0
+23 -9
arch/x86/kernel/unwind_orc.c
··· 546 546 indirect = true; 547 547 break; 548 548 549 - case ORC_REG_R10: 550 - if (!get_reg(state, offsetof(struct pt_regs, r10), &sp)) { 551 - orc_warn_current("missing R10 value at %pB\n", 549 + /* 550 + * Any of the below registers may temporarily hold the stack pointer, 551 + * typically during a DRAP stack realignment sequence or some other 552 + * stack swizzle. 553 + */ 554 + 555 + case ORC_REG_AX: 556 + if (!get_reg(state, offsetof(struct pt_regs, ax), &sp)) { 557 + orc_warn_current("missing AX value at %pB\n", 552 558 (void *)state->ip); 553 559 goto err; 554 560 } 555 561 break; 556 562 557 - case ORC_REG_R13: 558 - if (!get_reg(state, offsetof(struct pt_regs, r13), &sp)) { 559 - orc_warn_current("missing R13 value at %pB\n", 563 + case ORC_REG_DX: 564 + if (!get_reg(state, offsetof(struct pt_regs, dx), &sp)) { 565 + orc_warn_current("missing DX value at %pB\n", 560 566 (void *)state->ip); 561 567 goto err; 562 568 } ··· 576 570 } 577 571 break; 578 572 579 - case ORC_REG_DX: 580 - if (!get_reg(state, offsetof(struct pt_regs, dx), &sp)) { 581 - orc_warn_current("missing DX value at %pB\n", 573 + case ORC_REG_R10: 574 + if (!get_reg(state, offsetof(struct pt_regs, r10), &sp)) { 575 + orc_warn_current("missing R10 value at %pB\n", 576 + (void *)state->ip); 577 + goto err; 578 + } 579 + break; 580 + 581 + case ORC_REG_R13: 582 + if (!get_reg(state, offsetof(struct pt_regs, r13), &sp)) { 583 + orc_warn_current("missing R13 value at %pB\n", 582 584 (void *)state->ip); 583 585 goto err; 584 586 }
+20
scripts/livepatch/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # Standalone Makefile for developer tooling (not part of kbuild). 3 + 4 + SHELLCHECK := $(shell which shellcheck 2> /dev/null) 5 + 6 + SRCS := \ 7 + klp-build 8 + 9 + .DEFAULT_GOAL := help 10 + .PHONY: help 11 + help: 12 + @echo " check - Run shellcheck on $(SRCS)" 13 + @echo " help - Show this help message" 14 + 15 + .PHONY: check 16 + check: 17 + ifndef SHELLCHECK 18 + $(error shellcheck is not installed. Please install it to run checks) 19 + endif 20 + @$(SHELLCHECK) $(SHELLCHECK_OPTIONS) $(SRCS)
+76 -55
scripts/livepatch/klp-build
··· 52 52 53 53 KLP_DIFF_LOG="$DIFF_DIR/diff.log" 54 54 55 + # Terminal output colors 56 + read -r COLOR_RESET COLOR_BOLD COLOR_ERROR COLOR_WARN <<< "" 57 + if [[ -t 1 && -t 2 ]]; then 58 + COLOR_RESET="\033[0m" 59 + COLOR_BOLD="\033[1m" 60 + COLOR_ERROR="\033[0;31m" 61 + COLOR_WARN="\033[0;33m" 62 + fi 63 + 55 64 grep0() { 65 + # shellcheck disable=SC2317 56 66 command grep "$@" || true 57 67 } 58 68 69 + # Because pipefail is enabled, the grep0 helper should be used instead of 70 + # grep, otherwise a failed match can propagate to an error. 71 + grep() { 72 + echo "error: $SCRIPT: use grep0 or 'command grep' instead of bare grep" >&2 73 + exit 1 74 + } 75 + 59 76 status() { 60 - echo "$*" 77 + echo -e "${COLOR_BOLD}$*${COLOR_RESET}" 61 78 } 62 79 63 80 warn() { 64 - echo "error: $SCRIPT: $*" >&2 81 + echo -e "${COLOR_WARN}warning${COLOR_RESET}: $SCRIPT: $*" >&2 65 82 } 66 83 67 84 die() { 68 - warn "$@" 85 + echo -e "${COLOR_ERROR}error${COLOR_RESET}: $SCRIPT: $*" >&2 69 86 exit 1 70 87 } 71 88 ··· 112 95 113 96 cleanup() { 114 97 set +o nounset 115 - revert_patches "--recount" 98 + revert_patches 116 99 restore_files 117 100 [[ "$KEEP_TMP" -eq 0 ]] && rm -rf "$TMP_DIR" 118 101 return 0 119 102 } 120 103 121 104 trap_err() { 122 - warn "line ${BASH_LINENO[0]}: '$BASH_COMMAND'" 105 + die "line ${BASH_LINENO[0]}: '$BASH_COMMAND'" 123 106 } 124 107 125 108 trap cleanup EXIT INT TERM HUP ··· 229 212 esac 230 213 done 231 214 232 - if [[ $# -eq 0 ]]; then 215 + if [[ $# -eq 0 ]] && (( SHORT_CIRCUIT <= 2 )); then 233 216 usage 234 217 exit 1 235 218 fi ··· 299 282 } 300 283 301 284 # Hardcode the value printed by the localversion script to prevent patch 302 - # application from appending it with '+' due to a dirty git working tree. 285 + # application from appending it with '+' due to a dirty working tree. 303 286 set_kernelversion() { 304 287 local file="$SRC/scripts/setlocalversion" 305 288 local kernelrelease ··· 312 295 sed -i "2i echo $kernelrelease; exit 0" scripts/setlocalversion 313 296 } 314 297 315 - get_patch_files() { 298 + get_patch_input_files() { 316 299 local patch="$1" 317 300 318 - grep0 -E '^(--- |\+\+\+ )' "$patch" \ 301 + grep0 -E '^--- ' "$patch" \ 302 + | grep0 -v -e '/dev/null' -e '1969-12-31' -e '1970-01-01' \ 319 303 | gawk '{print $2}' \ 320 304 | sed 's|^[^/]*/||' \ 321 305 | sort -u 322 306 } 323 307 324 - # Make sure git re-stats the changed files 325 - git_refresh() { 308 + get_patch_output_files() { 326 309 local patch="$1" 327 - local files=() 328 310 329 - [[ ! -e "$SRC/.git" ]] && return 311 + grep0 -E '^\+\+\+ ' "$patch" \ 312 + | grep0 -v -e '/dev/null' -e '1969-12-31' -e '1970-01-01' \ 313 + | gawk '{print $2}' \ 314 + | sed 's|^[^/]*/||' \ 315 + | sort -u 316 + } 330 317 331 - get_patch_files "$patch" | mapfile -t files 318 + get_patch_files() { 319 + local patch="$1" 332 320 333 - ( 334 - cd "$SRC" 335 - git update-index -q --refresh -- "${files[@]}" 336 - ) 321 + { get_patch_input_files "$patch"; get_patch_output_files "$patch"; } \ 322 + | sort -u 337 323 } 338 324 339 325 check_unsupported_patches() { ··· 350 330 for file in "${files[@]}"; do 351 331 case "$file" in 352 332 lib/*|*.S) 353 - die "unsupported patch to $file" 333 + die "${patch}: unsupported patch to $file" 354 334 ;; 355 335 esac 356 336 done ··· 361 341 local patch="$1" 362 342 shift 363 343 local extra_args=("$@") 344 + local drift_regex="with fuzz|offset [0-9]+ line" 345 + local output 346 + local status 364 347 365 348 [[ ! -f "$patch" ]] && die "$patch doesn't exist" 349 + status=0 350 + output=$(patch -d "$SRC" -p1 --dry-run --no-backup-if-mismatch -r /dev/null "${extra_args[@]}" < "$patch" 2>&1) || status=$? 351 + if [[ "$status" -ne 0 ]]; then 352 + echo "$output" >&2 353 + die "$patch did not apply" 354 + elif [[ "$output" =~ $drift_regex ]]; then 355 + echo "$output" >&2 356 + warn "${patch} applied with fuzz" 357 + fi 366 358 367 - ( 368 - cd "$SRC" 369 - 370 - # The sed strips the version signature from 'git format-patch', 371 - # otherwise 'git apply --recount' warns. 372 - sed -n '/^-- /q;p' "$patch" | 373 - git apply "${extra_args[@]}" 374 - ) 375 - 359 + patch -d "$SRC" -p1 --no-backup-if-mismatch -r /dev/null "${extra_args[@]}" --silent < "$patch" 376 360 APPLIED_PATCHES+=("$patch") 377 361 } 378 362 379 363 revert_patch() { 380 364 local patch="$1" 381 - shift 382 - local extra_args=("$@") 383 365 local tmp=() 384 366 385 - ( 386 - cd "$SRC" 387 - 388 - sed -n '/^-- /q;p' "$patch" | 389 - git apply --reverse "${extra_args[@]}" 390 - ) 391 - git_refresh "$patch" 367 + patch -d "$SRC" -p1 -R --silent --no-backup-if-mismatch -r /dev/null < "$patch" 392 368 393 369 for p in "${APPLIED_PATCHES[@]}"; do 394 370 [[ "$p" == "$patch" ]] && continue ··· 395 379 } 396 380 397 381 apply_patches() { 382 + local extra_args=("$@") 398 383 local patch 399 384 400 385 for patch in "${PATCHES[@]}"; do 401 - apply_patch "$patch" 386 + apply_patch "$patch" "${extra_args[@]}" 402 387 done 403 388 } 404 389 405 390 revert_patches() { 406 - local extra_args=("$@") 407 391 local patches=("${APPLIED_PATCHES[@]}") 408 392 409 393 for (( i=${#patches[@]}-1 ; i>=0 ; i-- )) ; do 410 - revert_patch "${patches[$i]}" "${extra_args[@]}" 394 + revert_patch "${patches[$i]}" 411 395 done 412 396 413 397 APPLIED_PATCHES=() ··· 431 415 APPLIED_PATCHES=() 432 416 433 417 [[ -x "$FIX_PATCH_LINES" ]] || die "can't find fix-patch-lines" 418 + command -v recountdiff &>/dev/null || die "recountdiff not found (install patchutils)" 434 419 435 420 validate_config 436 421 set_module_name ··· 442 425 refresh_patch() { 443 426 local patch="$1" 444 427 local tmpdir="$PATCH_TMP_DIR" 445 - local files=() 428 + local input_files=() 429 + local output_files=() 446 430 447 431 rm -rf "$tmpdir" 448 432 mkdir -p "$tmpdir/a" 449 433 mkdir -p "$tmpdir/b" 450 434 451 435 # Get all source files affected by the patch 452 - get_patch_files "$patch" | mapfile -t files 436 + get_patch_input_files "$patch" | mapfile -t input_files 437 + get_patch_output_files "$patch" | mapfile -t output_files 453 438 454 439 # Copy orig source files to 'a' 455 - ( cd "$SRC" && echo "${files[@]}" | xargs cp --parents --target-directory="$tmpdir/a" ) 440 + ( cd "$SRC" && echo "${input_files[@]}" | xargs cp --parents --target-directory="$tmpdir/a" ) 456 441 457 442 # Copy patched source files to 'b' 458 - apply_patch "$patch" --recount 459 - ( cd "$SRC" && echo "${files[@]}" | xargs cp --parents --target-directory="$tmpdir/b" ) 460 - revert_patch "$patch" --recount 443 + apply_patch "$patch" "--silent" 444 + ( cd "$SRC" && echo "${output_files[@]}" | xargs cp --parents --target-directory="$tmpdir/b" ) 445 + revert_patch "$patch" 461 446 462 447 # Diff 'a' and 'b' to make a clean patch 463 - ( cd "$tmpdir" && git diff --no-index --no-prefix a b > "$patch" ) || true 448 + ( cd "$tmpdir" && diff -Nupr a b > "$patch" ) || true 464 449 } 465 450 466 451 # Copy the patches to a temporary directory, fix their lines so as not to ··· 485 466 486 467 cp -f "$old_patch" "$tmp_patch" 487 468 refresh_patch "$tmp_patch" 488 - "$FIX_PATCH_LINES" "$tmp_patch" > "$new_patch" 489 - refresh_patch "$new_patch" 469 + "$FIX_PATCH_LINES" "$tmp_patch" | recountdiff > "$new_patch" 490 470 491 471 PATCHES[i]="$new_patch" 492 472 ··· 509 491 } 510 492 511 493 build_kernel() { 494 + local build="$1" 512 495 local log="$TMP_DIR/build.log" 513 496 local objtool_args=() 514 497 local cmd=() ··· 547 528 "${cmd[@]}" \ 548 529 1> >(tee -a "$log") \ 549 530 2> >(tee -a "$log" | grep0 -v "modpost.*undefined!" >&2) 550 - ) 531 + ) || die "$build kernel build failed" 551 532 } 552 533 553 534 find_objects() { ··· 574 555 for _file in "${files[@]}"; do 575 556 local rel_file="${_file/.ko/.o}" 576 557 local file="$OBJ/$rel_file" 577 - local file_dir="$(dirname "$file")" 578 558 local orig_file="$ORIG_DIR/$rel_file" 579 559 local orig_dir="$(dirname "$orig_file")" 580 560 ··· 814 796 process_args "$@" 815 797 do_init 816 798 817 - if (( SHORT_CIRCUIT <= 1 )); then 799 + if (( SHORT_CIRCUIT <= 2 )); then 818 800 status "Validating patch(es)" 819 801 validate_patches 802 + fi 803 + 804 + if (( SHORT_CIRCUIT <= 1 )); then 820 805 status "Building original kernel" 821 806 clean_kernel 822 - build_kernel 807 + build_kernel "original" 823 808 status "Copying original object files" 824 809 copy_orig_objects 825 810 fi ··· 830 809 if (( SHORT_CIRCUIT <= 2 )); then 831 810 status "Fixing patch(es)" 832 811 fix_patches 833 - apply_patches 812 + apply_patches "--silent" 834 813 status "Building patched kernel" 835 - build_kernel 814 + build_kernel "patched" 836 815 revert_patches 837 816 status "Copying patched object files" 838 817 copy_patched_objects
+5 -4
tools/arch/x86/include/asm/orc_types.h
··· 28 28 * and GCC realigned stacks. 29 29 */ 30 30 #define ORC_REG_UNDEFINED 0 31 - #define ORC_REG_PREV_SP 1 31 + #define ORC_REG_AX 1 32 32 #define ORC_REG_DX 2 33 - #define ORC_REG_DI 3 33 + #define ORC_REG_SP 3 34 34 #define ORC_REG_BP 4 35 - #define ORC_REG_SP 5 35 + #define ORC_REG_DI 5 36 36 #define ORC_REG_R10 6 37 37 #define ORC_REG_R13 7 38 - #define ORC_REG_BP_INDIRECT 8 38 + #define ORC_REG_PREV_SP 8 39 39 #define ORC_REG_SP_INDIRECT 9 40 + #define ORC_REG_BP_INDIRECT 10 40 41 #define ORC_REG_MAX 15 41 42 42 43 #define ORC_TYPE_UNDEFINED 0
+12 -6
tools/objtool/arch/x86/decode.c
··· 875 875 case ORC_REG_UNDEFINED: 876 876 *base = CFI_UNDEFINED; 877 877 break; 878 + case ORC_REG_AX: 879 + *base = CFI_AX; 880 + break; 881 + case ORC_REG_DX: 882 + *base = CFI_DX; 883 + break; 878 884 case ORC_REG_SP: 879 885 *base = CFI_SP; 880 886 break; 881 887 case ORC_REG_BP: 882 888 *base = CFI_BP; 883 889 break; 884 - case ORC_REG_SP_INDIRECT: 885 - *base = CFI_SP_INDIRECT; 890 + case ORC_REG_DI: 891 + *base = CFI_DI; 886 892 break; 887 893 case ORC_REG_R10: 888 894 *base = CFI_R10; ··· 896 890 case ORC_REG_R13: 897 891 *base = CFI_R13; 898 892 break; 899 - case ORC_REG_DI: 900 - *base = CFI_DI; 893 + case ORC_REG_SP_INDIRECT: 894 + *base = CFI_SP_INDIRECT; 901 895 break; 902 - case ORC_REG_DX: 903 - *base = CFI_DX; 896 + case ORC_REG_BP_INDIRECT: 897 + *base = CFI_BP_INDIRECT; 904 898 break; 905 899 default: 906 900 return -1;
+18 -13
tools/objtool/arch/x86/orc.c
··· 46 46 orc->signal = cfi->signal; 47 47 48 48 switch (cfi->cfa.base) { 49 + case CFI_AX: 50 + orc->sp_reg = ORC_REG_AX; 51 + break; 52 + case CFI_DX: 53 + orc->sp_reg = ORC_REG_DX; 54 + break; 49 55 case CFI_SP: 50 56 orc->sp_reg = ORC_REG_SP; 51 - break; 52 - case CFI_SP_INDIRECT: 53 - orc->sp_reg = ORC_REG_SP_INDIRECT; 54 57 break; 55 58 case CFI_BP: 56 59 orc->sp_reg = ORC_REG_BP; 57 60 break; 58 - case CFI_BP_INDIRECT: 59 - orc->sp_reg = ORC_REG_BP_INDIRECT; 61 + case CFI_DI: 62 + orc->sp_reg = ORC_REG_DI; 60 63 break; 61 64 case CFI_R10: 62 65 orc->sp_reg = ORC_REG_R10; ··· 67 64 case CFI_R13: 68 65 orc->sp_reg = ORC_REG_R13; 69 66 break; 70 - case CFI_DI: 71 - orc->sp_reg = ORC_REG_DI; 67 + case CFI_SP_INDIRECT: 68 + orc->sp_reg = ORC_REG_SP_INDIRECT; 72 69 break; 73 - case CFI_DX: 74 - orc->sp_reg = ORC_REG_DX; 70 + case CFI_BP_INDIRECT: 71 + orc->sp_reg = ORC_REG_BP_INDIRECT; 75 72 break; 76 73 default: 77 74 ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); ··· 125 122 switch (reg) { 126 123 case ORC_REG_PREV_SP: 127 124 return "prevsp"; 125 + case ORC_REG_AX: 126 + return "ax"; 128 127 case ORC_REG_DX: 129 128 return "dx"; 130 - case ORC_REG_DI: 131 - return "di"; 132 129 case ORC_REG_BP: 133 130 return "bp"; 134 131 case ORC_REG_SP: 135 132 return "sp"; 133 + case ORC_REG_DI: 134 + return "di"; 136 135 case ORC_REG_R10: 137 136 return "r10"; 138 137 case ORC_REG_R13: 139 138 return "r13"; 140 - case ORC_REG_BP_INDIRECT: 141 - return "bp(ind)"; 142 139 case ORC_REG_SP_INDIRECT: 143 140 return "sp(ind)"; 141 + case ORC_REG_BP_INDIRECT: 142 + return "bp(ind)"; 144 143 default: 145 144 return "?"; 146 145 }
+2 -2
tools/objtool/check.c
··· 4306 4306 list_for_each_entry(insn, &file->retpoline_call_list, call_node) { 4307 4307 struct symbol *sym = insn->sym; 4308 4308 4309 - if (sym && (sym->type == STT_NOTYPE || 4310 - sym->type == STT_FUNC) && !sym->nocfi) { 4309 + if (sym && (is_notype_sym(sym) || 4310 + is_func_sym(sym)) && !sym->nocfi) { 4311 4311 struct instruction *prev = 4312 4312 prev_insn_same_sym(file, insn); 4313 4313
+3 -3
tools/objtool/disas.c
··· 264 264 * If the relocation symbol is a section name (for example ".bss") 265 265 * then we try to further resolve the name. 266 266 */ 267 - if (reloc->sym->type == STT_SECTION) { 267 + if (is_sec_sym(reloc->sym)) { 268 268 str = offstr(reloc->sym->sec, reloc->sym->offset + offset); 269 269 DINFO_FPRINTF(dinfo, bfd_vma_fmt, addr, str); 270 270 free(str); ··· 580 580 */ 581 581 dinfo->buffer = insn->sec->data->d_buf; 582 582 dinfo->buffer_vma = 0; 583 - dinfo->buffer_length = insn->sec->sh.sh_size; 583 + dinfo->buffer_length = sec_size(insn->sec); 584 584 585 585 return disasm(insn->offset, &dctx->info); 586 586 } ··· 1231 1231 1232 1232 for_each_sec(dctx->file->elf, sec) { 1233 1233 1234 - if (!(sec->sh.sh_flags & SHF_EXECINSTR)) 1234 + if (!is_text_sec(sec)) 1235 1235 continue; 1236 1236 1237 1237 sec_for_each_sym(sec, sym) {
+77 -24
tools/objtool/elf.c
··· 25 25 #include <objtool/elf.h> 26 26 #include <objtool/warn.h> 27 27 28 + static ssize_t demangled_name_len(const char *name); 29 + 28 30 static inline u32 str_hash(const char *str) 29 31 { 30 32 return jhash(str, strlen(str), 0); 33 + } 34 + 35 + static inline u32 str_hash_demangled(const char *str) 36 + { 37 + return jhash(str, demangled_name_len(str), 0); 31 38 } 32 39 33 40 #define __elf_table(name) (elf->name##_hash) ··· 300 293 { 301 294 struct symbol *sym; 302 295 303 - elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash(name)) { 296 + elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash_demangled(name)) { 304 297 if (sym->bind == STB_LOCAL && sym->file == file && 305 298 !strcmp(sym->name, name)) { 306 299 return sym; ··· 314 307 { 315 308 struct symbol *sym; 316 309 317 - elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash(name)) { 310 + elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash_demangled(name)) { 318 311 if (!strcmp(sym->name, name) && !is_local_sym(sym)) 319 312 return sym; 320 313 } 321 314 322 315 return NULL; 316 + } 317 + 318 + void iterate_global_symbol_by_demangled_name(const struct elf *elf, 319 + const char *demangled_name, 320 + void (*process)(struct symbol *sym, void *data), 321 + void *data) 322 + { 323 + struct symbol *sym; 324 + 325 + elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash(demangled_name)) { 326 + if (!strcmp(sym->demangled_name, demangled_name) && !is_local_sym(sym)) 327 + process(sym, data); 328 + } 323 329 } 324 330 325 331 struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec, ··· 460 440 return 0; 461 441 } 462 442 443 + /* 444 + * Returns desired length of the demangled name. 445 + * If name doesn't need demangling, return strlen(name). 446 + */ 447 + static ssize_t demangled_name_len(const char *name) 448 + { 449 + ssize_t idx; 450 + const char *p; 451 + 452 + p = strstr(name, ".llvm."); 453 + if (p) 454 + return p - name; 455 + 456 + if (!strstarts(name, "__UNIQUE_ID_") && !strchr(name, '.')) 457 + return strlen(name); 458 + 459 + for (idx = strlen(name) - 1; idx >= 0; idx--) { 460 + char c = name[idx]; 461 + 462 + if (!isdigit(c) && c != '.' && c != '_') 463 + break; 464 + } 465 + if (idx <= 0) 466 + return strlen(name); 467 + return idx + 1; 468 + } 469 + 470 + /* 471 + * Remove number suffix of a symbol. 472 + * 473 + * Specifically, remove trailing numbers for "__UNIQUE_ID_" symbols and 474 + * symbols with '.'. 475 + * 476 + * With CONFIG_LTO_CLANG_THIN, it is possible to have nested __UNIQUE_ID_, 477 + * such as 478 + * 479 + * __UNIQUE_ID_addressable___UNIQUE_ID_pci_invalid_bar_694_695 480 + * 481 + * to remove both trailing numbers, also remove trailing '_'. 482 + * 483 + * For symbols with llvm suffix, i.e., foo.llvm.<hash>, remove the 484 + * .llvm.<hash> part. 485 + */ 463 486 static const char *demangle_name(struct symbol *sym) 464 487 { 465 488 char *str; 466 - 467 - if (!is_local_sym(sym)) 468 - return sym->name; 489 + ssize_t len; 469 490 470 491 if (!is_func_sym(sym) && !is_object_sym(sym)) 471 492 return sym->name; 472 493 473 - if (!strstarts(sym->name, "__UNIQUE_ID_") && !strchr(sym->name, '.')) 494 + len = demangled_name_len(sym->name); 495 + if (len == strlen(sym->name)) 474 496 return sym->name; 475 497 476 - str = strdup(sym->name); 498 + str = strndup(sym->name, len); 477 499 if (!str) { 478 500 ERROR_GLIBC("strdup"); 479 501 return NULL; 480 - } 481 - 482 - for (int i = strlen(str) - 1; i >= 0; i--) { 483 - char c = str[i]; 484 - 485 - if (!isdigit(c) && c != '.') { 486 - str[i + 1] = '\0'; 487 - break; 488 - } 489 502 } 490 503 491 504 return str; ··· 556 503 entry = &sym->sec->symbol_list; 557 504 list_add(&sym->list, entry); 558 505 506 + sym->demangled_name = demangle_name(sym); 507 + if (!sym->demangled_name) 508 + return -1; 509 + 559 510 list_add_tail(&sym->global_list, &elf->symbols); 560 511 elf_hash_add(symbol, &sym->hash, sym->idx); 561 - elf_hash_add(symbol_name, &sym->name_hash, str_hash(sym->name)); 512 + elf_hash_add(symbol_name, &sym->name_hash, str_hash(sym->demangled_name)); 562 513 563 514 if (is_func_sym(sym) && 564 515 (strstarts(sym->name, "__pfx_") || ··· 585 528 } 586 529 587 530 sym->pfunc = sym->cfunc = sym; 588 - 589 - sym->demangled_name = demangle_name(sym); 590 - if (!sym->demangled_name) 591 - return -1; 592 531 593 532 return 0; 594 533 } ··· 666 613 if (elf_add_symbol(elf, sym)) 667 614 return -1; 668 615 669 - if (sym->type == STT_FILE) 616 + if (is_file_sym(sym)) 670 617 file = sym; 671 618 else if (sym->bind == STB_LOCAL) 672 619 sym->file = file; ··· 1371 1318 return -1; 1372 1319 } 1373 1320 1374 - offset = ALIGN(strtab->sh.sh_size, strtab->sh.sh_addralign); 1321 + offset = ALIGN(sec_size(strtab), strtab->sh.sh_addralign); 1375 1322 1376 1323 if (!elf_add_data(elf, strtab, str, strlen(str) + 1)) 1377 1324 return -1; ··· 1413 1360 sec->data->d_size = size; 1414 1361 sec->data->d_align = sec->sh.sh_addralign; 1415 1362 1416 - offset = ALIGN(sec->sh.sh_size, sec->sh.sh_addralign); 1363 + offset = ALIGN(sec_size(sec), sec->sh.sh_addralign); 1417 1364 sec->sh.sh_size = offset + size; 1418 1365 1419 1366 mark_sec_changed(elf, sec, true);
+3
tools/objtool/include/objtool/elf.h
··· 186 186 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); 187 187 struct symbol *find_symbol_by_name(const struct elf *elf, const char *name); 188 188 struct symbol *find_global_symbol_by_name(const struct elf *elf, const char *name); 189 + void iterate_global_symbol_by_demangled_name(const struct elf *elf, const char *demangled_name, 190 + void (*process)(struct symbol *sym, void *data), 191 + void *data); 189 192 struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset); 190 193 int find_symbol_hole_containing(const struct section *sec, unsigned long offset); 191 194 struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
+93 -6
tools/objtool/klp-diff.c
··· 272 272 */ 273 273 static bool is_clang_tmp_label(struct symbol *sym) 274 274 { 275 - return sym->type == STT_NOTYPE && 275 + return is_notype_sym(sym) && 276 276 is_text_sec(sym->sec) && 277 277 strstarts(sym->name, ".Ltmp") && 278 278 isdigit(sym->name[5]); ··· 354 354 is_special_section(sym->sec) || 355 355 is_special_section_aux(sym->sec) || 356 356 strstarts(sym->name, "__initcall__"); 357 + } 358 + 359 + struct process_demangled_name_data { 360 + struct symbol *ret; 361 + int count; 362 + }; 363 + 364 + static void process_demangled_name(struct symbol *sym, void *d) 365 + { 366 + struct process_demangled_name_data *data = d; 367 + 368 + if (sym->twin) 369 + return; 370 + 371 + data->count++; 372 + data->ret = sym; 373 + } 374 + 375 + /* 376 + * When there is no full name match, try match demangled_name. This would 377 + * match original foo.llvm.123 to patched foo.llvm.456. 378 + * 379 + * Note that, in very rare cases, it is possible to have multiple 380 + * foo.llvm.<hash> in the same kernel. When this happens, report error and 381 + * fail the diff. 382 + */ 383 + static int find_global_symbol_by_demangled_name(struct elf *elf, struct symbol *sym, 384 + struct symbol **out_sym) 385 + { 386 + struct process_demangled_name_data data = {}; 387 + 388 + iterate_global_symbol_by_demangled_name(elf, sym->demangled_name, 389 + process_demangled_name, 390 + &data); 391 + if (data.count > 1) { 392 + ERROR("Multiple (%d) correlation candidates for %s", data.count, sym->name); 393 + return -1; 394 + } 395 + *out_sym = data.ret; 396 + return 0; 357 397 } 358 398 359 399 /* ··· 494 454 continue; 495 455 496 456 sym2 = find_global_symbol_by_name(e->patched, sym1->name); 497 - 498 - if (sym2 && !sym2->twin && !strcmp(sym1->name, sym2->name)) { 457 + if (sym2 && !sym2->twin) { 499 458 sym1->twin = sym2; 500 459 sym2->twin = sym1; 460 + } 461 + } 462 + 463 + /* 464 + * Correlate globals with demangled_name. 465 + * A separate loop is needed because we want to finish all the 466 + * full name correlations first. 467 + */ 468 + for_each_sym(e->orig, sym1) { 469 + if (sym1->bind == STB_LOCAL || sym1->twin) 470 + continue; 471 + 472 + if (find_global_symbol_by_demangled_name(e->patched, sym1, &sym2)) 473 + return -1; 474 + 475 + if (sym2 && !sym2->twin) { 476 + sym1->twin = sym2; 477 + sym2->twin = sym1; 478 + } 479 + } 480 + 481 + /* Correlate original locals with patched globals */ 482 + for_each_sym(e->orig, sym1) { 483 + if (sym1->twin || dont_correlate(sym1) || !is_local_sym(sym1)) 484 + continue; 485 + 486 + sym2 = find_global_symbol_by_name(e->patched, sym1->name); 487 + if (!sym2 && find_global_symbol_by_demangled_name(e->patched, sym1, &sym2)) 488 + return -1; 489 + 490 + if (sym2 && !sym2->twin) { 491 + sym1->twin = sym2; 492 + sym2->twin = sym1; 493 + } 494 + } 495 + 496 + /* Correlate original globals with patched locals */ 497 + for_each_sym(e->patched, sym2) { 498 + if (sym2->twin || dont_correlate(sym2) || !is_local_sym(sym2)) 499 + continue; 500 + 501 + sym1 = find_global_symbol_by_name(e->orig, sym2->name); 502 + if (!sym1 && find_global_symbol_by_demangled_name(e->orig, sym2, &sym1)) 503 + return -1; 504 + 505 + if (sym1 && !sym1->twin) { 506 + sym2->twin = sym1; 507 + sym1->twin = sym2; 501 508 } 502 509 } 503 510 ··· 568 481 if (sym->bind != STB_LOCAL) 569 482 return 0; 570 483 571 - if (vmlinux && sym->type == STT_FUNC) { 484 + if (vmlinux && is_func_sym(sym)) { 572 485 /* 573 486 * HACK: Unfortunately, symbol ordering can differ between 574 487 * vmlinux.o and vmlinux due to the linker script emitting ··· 1134 1047 sec->name, offset, patched_sym->name, \ 1135 1048 addend >= 0 ? "+" : "-", labs(addend), \ 1136 1049 sym_type(patched_sym), \ 1137 - patched_sym->type == STT_SECTION ? "" : " ", \ 1138 - patched_sym->type == STT_SECTION ? "" : sym_bind(patched_sym), \ 1050 + is_sec_sym(patched_sym) ? "" : " ", \ 1051 + is_sec_sym(patched_sym) ? "" : sym_bind(patched_sym), \ 1139 1052 is_undef_sym(patched_sym) ? " UNDEF" : "", \ 1140 1053 export ? " EXPORTED" : "", \ 1141 1054 klp ? " KLP" : "")