1# SPDX-License-Identifier: GPL-2.0 2# 3# Helpers for the objtool klp tests. A test builds a fixture twice, as the 4# original and (with -DPATCHED) the patched object, runs both through 5# "klp checksum" and diffs them, then asserts on the result. 6# 7# Assertions check properties rather than compare against recorded output: 8# codegen varies between compilers and golden files would report churn instead 9# of regressions. 10 11set -u 12 13TESTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 14 15# Tests live in generic/ or in an architecture directory beside it, and each 16# carries its own fixtures. 17FIXTURES_DIR="$(cd "$(dirname "$0")/fixtures" 2>/dev/null && pwd)" 18 19# The kernel's convention: CROSS_COMPILE is the one knob, with per-tool 20# overrides for what it does not cover. objtool itself is always a host binary 21# -- it is built with HOSTCC and only reads ELF -- so an arm64 machine can run 22# the x86 tests against x86 objects given a compiler that emits them. 23# 24# readelf reads any target, so it rarely needs overriding, and either GNU 25# readelf or llvm-readelf will do: the assertions match on fields rather than 26# on columns, and where the two spell something differently -- "OS [0xff20]" 27# against "OS[0xff20]" for SHN_LIVEPATCH -- they accept both. BFD's objcopy is 28# usually built for the host's target alone, and llvm-objcopy is the 29# target-agnostic replacement. 30CROSS_COMPILE="${CROSS_COMPILE:-}" 31CC="${CC:-${CROSS_COMPILE}gcc}" 32LD="${LD:-${CROSS_COMPILE}ld}" 33READELF="${READELF:-${CROSS_COMPILE}readelf}" 34OBJCOPY="${OBJCOPY:-${CROSS_COMPILE}objcopy}" 35 36OBJTOOL="${OBJTOOL:-$TESTS_DIR/../objtool}" 37 38# klp_preflight 39# 40# Check the environment once, before any test runs, and report what was found. 41# 42klp_preflight() 43{ 44 local tmp tool cc_version arch host cc_arch 45 46 bail() { echo "Bail out! $*" >&2; exit 1; } 47 48 # A relative $OBJTOOL is relative to the objtool directory, not tests/. 49 [ -x "$OBJTOOL" ] || [ ! -x "$TESTS_DIR/../$OBJTOOL" ] || 50 OBJTOOL="$TESTS_DIR/../$OBJTOOL" 51 52 [ -x "$OBJTOOL" ] || 53 bail "objtool not found at '$OBJTOOL' -- build it first" 54 55 # run_diff() runs objtool from inside the test's working directory, so 56 # a relative path would resolve against that instead. 57 OBJTOOL="$(realpath "$OBJTOOL")" 58 59 "$OBJTOOL" klp 2>&1 | grep -q checksum || 60 bail "objtool was built without klp support; install libxxhash (>= 0.8) and rebuild" 61 62 command -v "${CC%% *}" >/dev/null || bail "compiler not found: $CC" 63 64 for tool in "$READELF" "$OBJCOPY" "$LD"; do 65 command -v "${tool%% *}" >/dev/null || bail "$tool not found" 66 done 67 68 tmp="$(mktemp -d)" || bail "mktemp failed" 69 echo 'int probe(void) { return 0; }' > "$tmp/probe.c" 70 $CC -c -o "$tmp/probe.o" "$tmp/probe.c" 2>/dev/null || 71 { rm -rf "$tmp"; bail "$CC cannot compile a trivial object"; } 72 73 # $CC, $ARCH and objtool have to agree about the target, and cross runs 74 # are where they stop agreeing: plain "CC=clang ARCH=x86_64" on an arm64 75 # box selects the x86 tests and then builds arm64 objects, because clang 76 # needs --target= to emit anything but the host's. 77 # 78 # Ask objtool rather than comparing machine names. It rejects an object 79 # it was not built for -- "unexpected ELF machine type" -- so one check 80 # covers every way the three can disagree, and says so once instead of 81 # failing every test for the same reason. 82 "$OBJTOOL" klp checksum "$tmp/probe.o" >/dev/null 2>&1 || 83 { rm -rf "$tmp" 84 bail "objtool rejects an object built by '$CC'; they target" \ 85 "different architectures (set CROSS_COMPILE, or" \ 86 "--target= for clang)"; } 87 88 # BFD objcopy is usually built for the host's target alone, and 89 # checksum_of() needs it to read the object under test. 90 $OBJCOPY -O binary --only-section=.text "$tmp/probe.o" "$tmp/probe.bin" 2>/dev/null || 91 { rm -rf "$tmp" 92 bail "$OBJCOPY cannot read objects built by '$CC'; install" \ 93 "binutils-multiarch or set OBJCOPY=llvm-objcopy"; } 94 # $ARCH only chooses which directory of tests runs, so it can disagree 95 # with what $CC builds without objtool noticing -- and the result is the 96 # wrong set of tests, quietly. 97 case "$($READELF -hW "$tmp/probe.o" | sed -n 's/.*Machine: *//p')" in 98 *X86-64*|*Intel*80386*) cc_arch=x86 ;; 99 *AArch64*) cc_arch=arm64 ;; 100 *) cc_arch= ;; 101 esac 102 rm -rf "$tmp" 103 104 # Normalize to the kernel's SRCARCH. 105 case "${ARCH:-$(uname -m)}" in 106 x86_64|i?86) arch=x86 ;; 107 aarch64*) arch=arm64 ;; 108 *) arch="${ARCH:-$(uname -m)}" ;; 109 esac 110 111 case "$(uname -m)" in 112 x86_64|i?86) host=x86 ;; 113 aarch64*) host=arm64 ;; 114 *) host="$(uname -m)" ;; 115 esac 116 117 [ -z "$cc_arch" ] || [ "$cc_arch" = "$arch" ] || 118 bail "ARCH says $arch but '$CC' builds $cc_arch objects;" \ 119 "the $arch tests would run against the wrong architecture" 120 121 KLP_TEST_ARCH="$arch" 122 KLP_TEST_PREFLIGHT=done 123 export OBJTOOL CC KLP_TEST_ARCH KLP_TEST_PREFLIGHT 124 125 cc_version="$($CC --version 2>/dev/null | head -1)" 126 cat <<EOF 127# preflight 128# objtool $OBJTOOL (klp: yes) 129# compiler $cc_version 130# arch $KLP_TEST_ARCH$([ "$arch" = "$host" ] || echo " (host $host, cross)") 131# tmpdir ${TMPDIR:-/tmp} (each test builds in a fresh directory here) 132EOF 133} 134 135[ -n "${KLP_TEST_PREFLIGHT:-}" ] || klp_preflight 136 137# What every fixture is built with. These describe the kernel a fixture stands 138# in for; -c is build_one's contract rather than a property of that kernel, so 139# it lives at the compile where an override cannot drop it. 140# 141# -O2 the kernel's default 142# -ffunction-sections -fdata-sections klp-build passes these itself, through 143# KCFLAGS, whatever the configuration 144# -fno-asynchronous-unwind-tables arch/x86/Makefile sets this always, so 145# kernel objects carry no .eh_frame 146# -fno-common the kernel's Makefile sets it, so an 147# uninitialised global there lands in 148# .bss rather than being SHN_COMMON, 149# which has no section and so no 150# checksum 151# 152# A test overrides it; see tools/objtool/Documentation/klp-write-tests.txt. 153FIXTURE_CFLAGS="-O2 -ffunction-sections -fdata-sections -fno-common \ 154 -fno-asynchronous-unwind-tables" 155 156test_name="$(basename "$0" .sh)" 157workdir= 158 159# The pair run_diff() and the checksum helpers work on. build_pair() names 160# them again and make_vmlinux_pair() repoints orig_obj at the image it links, 161# but a test which builds its objects itself with build_one() sets neither, so 162# the default belongs here. 163orig_obj=orig.o 164patched_obj=patched.o 165 166pass() { KLP_TEST_REPORTED=1; echo "ok - $test_name${1:+: $1}"; exit 0; } 167fail() { KLP_TEST_FAILED=1; echo "not ok - $test_name: $*"; exit 1; } 168 169# Two kinds of skip, and the runner tells them apart. 170# 171# declared_skip the test said in advance it does not apply here, e.g. 172# gcc_only on a clang run. Expected indefinitely. 173# probe_skip the construct did not turn up in the built object this 174# time. Weaker: it may appear on another compiler version, 175# and one which becomes permanent is a fixture that quietly 176# stopped testing anything. 177# 178# A bare skip() is neither, and the runner counts it as a failure: a test which 179# gives up for a reason it never declared is a hole, not an outcome. 180declared_skip() 181{ 182 KLP_TEST_REPORTED=1 183 echo "ok - $test_name # SKIP (declared) $*" 184 exit 0 185} 186 187probe_skip() 188{ 189 KLP_TEST_REPORTED=1 190 echo "ok - $test_name # SKIP (probe) $*" 191 exit 0 192} 193skip() { echo "ok - $test_name # SKIP $*"; exit 0; } 194 195# TAP directives. A test which is known to fail reports it rather than being 196# commented out and forgotten, and one which starts passing again says so 197# instead of quietly going green: the expectation has to be removed by hand, 198# which is the point. 199xfail() 200{ 201 KLP_TEST_REPORTED=1 202 echo "not ok - $test_name${1:+: $1} # TODO known failure" 203 exit 0 204} 205 206xpass() 207{ 208 KLP_TEST_FAILED=1 209 echo "ok - $test_name${1:+: $1} # TODO expected failure, but passed" 210 exit 1 211} 212 213# cleanup [exit] 214# 215# Called with "exit" from the trap, when the test is over and what it built may 216# be worth keeping. Called bare by a test which has finished with one segment 217# and is about to setup() another: that one is done with, whatever the outcome 218# of the segments still to come, so it goes. 219cleanup() 220{ 221 [ -n "$workdir" ] || return 0 222 223 # run-tests.sh exports KLP_TEST_KEEP, having validated it; a test run on 224 # its own reads KEEP itself, so the same setting means the same thing 225 # either way. 226 case "${KLP_TEST_KEEP:-${KEEP:-failed}}" in 227 all) return 0 ;; 228 none) rm -rf "$workdir" ;; 229 failed|*) 230 [ "${1:-}" = exit ] || { 231 rm -rf "$workdir" 232 return 0 233 } 234 # Keep what the runner is going to point at. It counts as a 235 # failure anything which did not report an expected outcome -- 236 # including a test which died before printing one, and an 237 # undeclared skip -- and none of those set KLP_TEST_FAILED, so 238 # the question to ask is whether a result was reported at all. 239 # An exit status cannot answer it: a test killed by a signal 240 # runs this trap with the status of whatever ran last. 241 [ -n "${KLP_TEST_REPORTED:-}" ] && [ -z "${KLP_TEST_FAILED:-}" ] && { 242 rm -rf "$workdir" 243 return 0 244 } 245 # run on its own there is no runner to say where it was kept 246 [ -n "${KLP_TEST_WORKDIR:-}" ] || 247 echo "# kept $workdir" 248 ;; 249 esac 250} 251 252# setup [exported symbol...] 253setup() 254{ 255 if [ -n "${KLP_TEST_WORKDIR:-}" ]; then 256 workdir="$KLP_TEST_WORKDIR" 257 mkdir -p "$workdir" || fail "cannot create $workdir" 258 else 259 workdir="$(mktemp -d)" || fail "mktemp failed" 260 fi 261 trap 'cleanup exit' EXIT 262 263 export_syms "$@" 264} 265 266# export_syms [symbol...] 267# 268# Rewrite Module.symvers so exactly these symbols are exported by vmlinux. 269# Whether a symbol is listed decides between an ordinary relocation and a klp 270# relocation, so tests flip it to cover both. 271export_syms() 272{ 273 : > "$workdir/Module.symvers" 274 add_exports vmlinux "$@" 275} 276 277# add_exports <object> [symbol...] 278# 279# Append exports owned by one object, without clearing what is already there, 280# so a test can describe a kernel where several objects export things. 281# 282# Which object owns a symbol is not cosmetic: a reference to a vmlinux symbol 283# is applied when the patch module loads, and a reference to a module's symbol 284# when that patched module loads, so klp diff files them in different sections. 285add_exports() 286{ 287 local owner="$1"; shift 288 289 add_exports_ns "$owner" "" "$@" 290} 291 292# add_exports_ns <object> <namespace> [symbol...] 293# 294# Exports in a symbol namespace, the last field of a Module.symvers line. 295# 296# A "module:<names>" namespace is EXPORT_SYMBOL_FOR_MODULES(), where the module 297# loader grants access by matching the importing module's name against the 298# list. A livepatch module is never on that list, so such a symbol has to be 299# referenced the way an unexported one is. Ordinary namespaces are not 300# special here. 301add_exports_ns() 302{ 303 local owner="$1" ns="$2"; shift 2 304 305 local sym 306 307 for sym in "$@"; do 308 printf '0x00000000\t%s\t%s\tEXPORT_SYMBOL\t%s\n' \ 309 "$sym" "$owner" "$ns" >> "$workdir/Module.symvers" 310 done 311} 312 313# gcc_only / clang_only <reason> 314gcc_only() 315{ 316 case "$($CC --version 2>/dev/null | head -1)" in 317 *[Gg][Cc][Cc]*) return 0 ;; 318 esac 319 declared_skip "gcc only${1:+: $1}" 320} 321 322clang_only() 323{ 324 case "$($CC --version 2>/dev/null | head -1)" in 325 *clang*) return 0 ;; 326 esac 327 declared_skip "clang only${1:+: $1}" 328} 329 330# build_one <fixture.c> <output object> [cflags...] 331build_one() 332{ 333 local fixture out 334 fixture="$FIXTURES_DIR/$1" 335 out="$workdir/$2" 336 shift 2 337 338 [ -f "$fixture" ] || fail "missing fixture $fixture" 339 340 # run_checksum only runs once per workdir. A fresh object has no 341 # checksums in it, so anything built now needs that to happen again. 342 rm -f "$workdir/.checksummed" 343 344 $CC -c $FIXTURE_CFLAGS "$@" -o "$out" "$fixture" 2>"$workdir/cc.log" || 345 fail "$(basename "$fixture") does not build: $(tail -1 "$workdir/cc.log")" 346} 347 348# build_pair <fixture.c> [cflags...] 349build_pair() 350{ 351 local fixture="$1"; shift 352 353 # Name what this builds. A test may run several segments, and 354 # make_vmlinux_pair() repoints orig_obj at the image it links, so 355 # without this the next run_diff() would still be reading that. 356 orig_obj=orig.o 357 patched_obj=patched.o 358 359 build_one "$fixture" orig.o "$@" 360 build_one "$fixture" patched.o "$@" -DPATCHED 361} 362 363# run_objtool_check <objtool arguments...> 364# 365# Run objtool's ordinary check pass over the pair, as the kernel build does. 366# 367# Some of what klp diff consumes is produced by this pass rather than by the 368# compiler: .static_call_sites, .mcount_loc, .ibt_endbr_seal, ORC. 369# 370# Only module objects see it before klp-build -- with CONFIG_KLP_BUILD the 371# per-object pass is deferred, so built-in objects reach klp diff exactly as 372# the compiler left them. 373run_objtool_check() 374{ 375 local obj 376 377 # This rewrites both objects, so checksums taken before it describe 378 # something that no longer exists. As in build_one(), drop the marker 379 # so run_checksum() takes them again. 380 rm -f "$workdir/.checksummed" 381 382 for obj in "$orig_obj" "$patched_obj"; do 383 "$OBJTOOL" "$@" "$workdir/$obj" || 384 fail "objtool $* failed on $obj" 385 done 386} 387 388run_checksum() 389{ 390 # Checksums live in the objects, and a test may ask for them more than 391 # once -- diffing the same pair again with a different Module.symvers, 392 # say. objtool does the right thing when asked twice, leaving the 393 # object alone, but it says so, and that warning would be most of what 394 # a passing run prints. Remember instead, and keep quiet. 395 [ -e "$workdir/.checksummed" ] && return 0 396 397 "$OBJTOOL" klp checksum "$workdir/$orig_obj" || 398 fail "klp checksum $orig_obj failed" 399 "$OBJTOOL" klp checksum "$workdir/$patched_obj" || 400 fail "klp checksum $patched_obj failed" 401 touch "$workdir/.checksummed" 402} 403 404# run_diff [expected exit status] 405run_diff() 406{ 407 local expect="${1:-0}" rc=0 408 409 run_checksum 410 411 # klp diff looks for Module.symvers relative to the working directory. 412 ( cd "$workdir" && "$OBJTOOL" klp diff "$orig_obj" "$patched_obj" out.o ) \ 413 > "$workdir/diff.log" 2>&1 || rc=$? 414 415 [ "$rc" = "$expect" ] || 416 fail "klp diff exited $rc, expected $expect: $(tail -2 "$workdir/diff.log")" 417} 418 419cc_supports() 420{ 421 echo 'int f(void) { return 0; }' > "$workdir/flagtest.c" 422 $CC $1 -c "$workdir/flagtest.c" -o "$workdir/flagtest.o" 2>/dev/null 423} 424 425# partial_link <output> <object...> 426# 427# "ld -r" through the compiler driver so the link targets the same 428# architecture as the objects. 429partial_link() 430{ 431 local out="$1"; shift 432 433 rm -f "$workdir/.checksummed" 434 435 $CC -r -nostdlib -o "$out" "$@" 2>/dev/null || 436 $CC -r -nostdlib -fuse-ld=lld -o "$out" "$@" 2>/dev/null 437} 438 439# link_vmlinux <output> <object...> 440# 441# Link objects into an executable, the way the kernel's final link produces 442# vmlinux from vmlinux.o. Entry point 0 and no libc: nothing runs it, it only 443# has to be a linked image with resolved addresses. 444# 445# The sub-sections have to come out in name order rather than object order, 446# the way the kernel's linker script gathers .text.unlikely and .data.. apart 447# from the rest. That reordering is the entire reason .klp.symid exists: a 448# link which preserves order cannot tell a correct sympos from one that merely 449# counted, and the caller checks the two orders really did diverge. 450# 451# A linker script rather than --sort-section=name, because lld accepts that 452# option and ignores it -- so on a host where only lld can link the target, the 453# test would quietly stop testing the thing it is named for. 454# 455# Three attempts because a cross run has neither $LD nor the compiler's default 456# linker able to touch the target: on an arm64 host linking x86 objects, only 457# lld will do it. 458link_vmlinux() 459{ 460 local out="$1" lds="$workdir/sort.lds"; shift 461 462 echo 'SECTIONS { .data : { *(SORT_BY_NAME(.data.*)) } }' > "$lds" 463 464 $LD -e 0 -T "$lds" -o "$out" "$@" 2>/dev/null || 465 $CC -nostdlib -Wl,-e,0 -Wl,-T,"$lds" \ 466 -o "$out" "$@" 2>/dev/null || 467 $CC -nostdlib -fuse-ld=lld -Wl,-e,0 -Wl,-T,"$lds" \ 468 -o "$out" "$@" 2>/dev/null 469} 470 471# make_vmlinux_pair <orig object...> -- <patched object...> 472# 473# Build the vmlinux.o / vmlinux pair klp diff needs to resolve sympos the way 474# it does for built-in code, and point the diff at it. 475# 476# For a module, sympos is a count in symbol table order, which klp diff can do 477# from the object alone. vmlinux is different: the final link reorders 478# sub-sections, so the position comes from the linked image, bridged by 479# .klp.symid. klp diff only looks for that when the object it was handed is 480# called vmlinux.o and a vmlinux sits beside it -- so both the name and the 481# linked image matter. 482make_vmlinux_pair() 483{ 484 local orig=() patched=() seen= arg 485 486 for arg in "$@"; do 487 if [ "$arg" = -- ]; then seen=y; continue; fi 488 if [ -n "$seen" ]; then patched+=( "$arg" ); else orig+=( "$arg" ); fi 489 done 490 491 # Both sides have to have been named. Without this, forgetting the -- 492 # leaves one list empty, the link of nothing fails, and the test skips 493 # saying the toolchain cannot link -- which is a test bug wearing the 494 # costume of an environment one. 495 [ "${#orig[@]}" -gt 0 ] && [ "${#patched[@]}" -gt 0 ] || 496 fail "make_vmlinux_pair needs objects either side of --" 497 498 partial_link "$workdir/vmlinux.o" "${orig[@]}" || 499 probe_skip "partial link unavailable" 500 partial_link "$workdir/patched.o" "${patched[@]}" || 501 probe_skip "partial link unavailable" 502 503 "$OBJTOOL" --klp-symids --link "$workdir/vmlinux.o" || 504 fail "objtool --klp-symids failed" 505 506 link_vmlinux "$workdir/vmlinux" "$workdir/vmlinux.o" || 507 probe_skip "cannot link a vmlinux here" 508 509 orig_obj=vmlinux.o 510} 511 512# build_module_pair <fixture.c> <module name> [cflags...] 513# 514# Build the pair as objects belonging to a module rather than to vmlinux. klp 515# diff reads the object's module name from .modinfo, and that decides which 516# object a relocation is attributed to and whether a reference counts as 517# cross-module, so a good deal of the code has a module path the vmlinux 518# fixtures never reach. 519# 520# The fixture defines its .modinfo name from MODNAME. Passing that through 521# -D needs two levels of quoting, which is easy to get wrong at the call site. 522build_module_pair() 523{ 524 local fixture="$1" modname="$2"; shift 2 525 526 build_pair "$fixture" -DMODNAME="\"$modname\"" "$@" 527} 528 529# find_thinlto_toolchain 530# 531# Set $THIN_LD to an lld from the same LLVM release as $CC (or THIN_CC). A 532# mismatched pair fails with "Invalid summary version", which reads like a 533# broken test rather than a broken environment. 534# 535# ThinLTO is clang-only; callers must use clang_only before calling this. 536# Only $CC (or an explicit THIN_CC override) is consulted -- the harness does 537# not search for a second compiler beside a gcc $CC. 538find_thinlto_toolchain() 539{ 540 local cc ver ld 541 542 for cc in "${THIN_CC:-}" "$CC"; do 543 [ -n "$cc" ] || continue 544 command -v "${cc%% *}" >/dev/null 2>&1 || return 1 545 546 ver=$($cc -dumpversion 2>/dev/null | cut -d. -f1) 547 548 for ld in "${THIN_LD:-}" "ld.lld-$ver" ld.lld; do 549 [ -n "$ld" ] || continue 550 command -v "$ld" >/dev/null 2>&1 || continue 551 552 echo 'int probe(void) { return 0; }' > "$workdir/probe.c" 553 $cc -flto=thin -O2 -c "$workdir/probe.c" \ 554 -o "$workdir/probe.o" 2>/dev/null || continue 555 "$ld" -r "$workdir/probe.o" -o "$workdir/probe.elf" \ 556 2>/dev/null || continue 557 558 THIN_CC="$cc" 559 THIN_LD="$ld" 560 return 0 561 done 562 done 563 564 return 1 565} 566 567out_sections() { $READELF -S -W "$workdir/out.o" 2>/dev/null; } 568out_relocs() { $READELF -r -W "$workdir/out.o" 2>/dev/null; } 569out_symbols() { $READELF -s -W "$workdir/out.o" 2>/dev/null; } 570diff_log() { cat "$workdir/diff.log"; } 571 572# out_strings <section> 573# 574# The strings in one section of the output, for the names livepatch matches on. 575out_strings() { $READELF -p "$1" "$workdir/out.o" 2>/dev/null; } 576 577# Checks on the input objects, to run before klp diff. The two forms differ in 578# what an absent construct means: 579# 580# require_* the compiler cannot produce it here -> skip 581# assert_* the fixture is supposed to produce it -> fail 582 583in_sections() { $READELF -S -W "$workdir/$1" 2>/dev/null; } 584in_symbols() { $READELF -s -W "$workdir/$1" 2>/dev/null; } 585in_relocs() { $READELF -r -W "$workdir/$1" 2>/dev/null; } 586 587# count_input_symbols <object> <name> 588# 589# How many object symbols of exactly that name the input has. Deliberately not 590# a grep: readelf lists section symbols too, and a newer binutils prints their 591# name -- ".data.<name>" -- where an older one leaves the column blank. A dot 592# is not a word character, so "grep -w <name>" counts that line as well, and 593# the same object gives a different answer depending on which readelf reads it. 594count_input_symbols() 595{ 596 in_symbols "$1" | awk -v n="$2" '$4 == "OBJECT" && $8 == n' | wc -l 597} 598 599# re_quote <string> 600# 601# A string as a literal basic regular expression. Nearly every name these 602# assertions match on contains a dot -- .text.target, .klp.rela.vmlinux -- and 603# an unescaped dot matches any character, so an assertion for one section can be 604# satisfied by a different one whose name merely lines up. 605re_quote() { printf '%s' "$1" | sed 's|[].[^$*\\/]|\\&|g'; } 606 607has_input_section() { in_sections "$1" | grep -q "[[:space:]]$(re_quote "$2")[[:space:]]"; } 608has_input_symbol() { in_symbols "$1" | awk -v n="$2" '$NF == n' | grep -q .; } 609 610assert_input_section() 611{ 612 local obj 613 614 for obj in "$orig_obj" "$patched_obj"; do 615 has_input_section "$obj" "$1" || 616 fail "fixture produced no section '$1' in $obj" 617 done 618} 619 620assert_input_symbol() 621{ 622 local obj 623 624 for obj in "$orig_obj" "$patched_obj"; do 625 has_input_symbol "$obj" "$1" || 626 fail "fixture produced no symbol '$1' in $obj" 627 done 628} 629 630require_input_section() 631{ 632 local obj 633 634 for obj in "$orig_obj" "$patched_obj"; do 635 has_input_section "$obj" "$1" || 636 probe_skip "compiler produced no section '$1' here" 637 done 638} 639 640assert_section() 641{ 642 out_sections | grep -q "[[:space:]]$(re_quote "$1")[[:space:]]" || 643 fail "expected section '$1' in output" 644} 645 646assert_no_section() 647{ 648 out_sections | grep -q "[[:space:]]$(re_quote "$1")[[:space:]]" && 649 fail "unexpected section '$1' in output" 650 return 0 651} 652 653assert_patched() 654{ 655 assert_section ".text.$1" 656} 657 658assert_not_patched() 659{ 660 out_sections | grep -q "[[:space:]]$(re_quote ".text.$1")[[:space:]]" && 661 fail "function '$1' should not have been cloned" 662 return 0 663} 664 665# section_relocs <section> 666# 667# The relocations against one section. readelf prints every relocation section 668# in turn, so a test asking about ".smp_locks" has to cut its block out of the 669# listing first. 670section_relocs() 671{ 672 local sec="${1//./\\.}" 673 674 out_relocs | awk "/rela$sec'/,/^\$/" 675} 676 677assert_reloc_sym() 678{ 679 section_relocs "$1" | awk -v n="$2" '$5 == n' | grep -q . || 680 fail "expected a relocation to '$2' in '$1'" 681} 682 683assert_no_reloc_sym() 684{ 685 section_relocs "$1" | awk -v n="$2" '$5 == n' | grep -q . && 686 fail "unexpected relocation to '$2' in '$1'" 687 return 0 688} 689 690# assert_reloc_count <section> <count> 691# 692# Counts relocation entries, not header or blank lines: whether a special 693# section entry was extracted once, twice or not at all is usually the whole 694# question. 695# 696# A count of zero is ambiguous on its own -- a section with no relocations and 697# no section at all both read as zero -- so require the section to exist. A 698# test expecting nothing there wants assert_no_section. 699assert_reloc_count() 700{ 701 local n 702 703 assert_section "$1" 704 705 n="$(section_relocs "$1" | grep -cE '^[0-9a-f]{8,}')" 706 [ "$n" = "$2" ] || 707 fail "expected $2 relocations in '$1', found $n" 708} 709 710# assert_klp_sym <symbol> [object] 711# 712# A klp symbol is named .klp.sym.<object>.<symbol>,<sympos>. The object 713# defaults to any, since most tests care that the reference was converted at 714# all rather than which object it resolved against. 715assert_klp_sym() 716{ 717 out_symbols | grep -q "\.klp\.sym\.${2:-[^.]*}\.$(re_quote "$1")," || 718 fail "expected klp symbol for '$1'" 719} 720 721# assert_klp_sympos <symbol> <sympos> 722# 723# The number after the comma in .klp.sym.<object>.<symbol>,<sympos> says which 724# of several same-named symbols livepatch should resolve to, counting from 1; 725# 0 means the name is unique and no disambiguation is needed. Resolving to the 726# wrong one is not a load failure, it is a patch quietly wired to the wrong 727# object. 728assert_klp_sympos() 729{ 730 out_symbols | grep -qE "\.klp\.sym\.[^.]+\.$(re_quote "$1"),$2([[:space:]]|\$)" || 731 fail "expected klp symbol for '$1' with sympos $2, found:$( 732 out_symbols | grep -o "\.klp\.sym\.[^.]*\.$(re_quote "$1"),[0-9]*" | 733 sort -u | tr '\n' ' ')" 734} 735 736assert_no_klp_sym() 737{ 738 out_symbols | grep -q "\.klp\.sym\.${2:-[^.]*}\.$(re_quote "$1")," && 739 fail "unexpected klp symbol for '$1'" 740 return 0 741} 742 743assert_tombstone() 744{ 745 out_symbols | grep -qE "\.klp\.tombstone\.$(re_quote "$1")([[:space:]]|\$)" || 746 fail "expected a tombstone for '$1'" 747} 748 749assert_symbol() 750{ 751 out_symbols | awk -v n="$1" '$NF == n' | grep -q . || 752 fail "expected symbol '$1' in output" 753} 754 755assert_no_symbol() 756{ 757 out_symbols | awk -v n="$1" '$NF == n' | grep -q . && 758 fail "unexpected symbol '$1' in output" 759 return 0 760} 761 762# assert_diff_log <regex> 763# 764# klp diff's combined output, for tests asserting on a diagnostic. Error 765# messages are part of the interface when the whole point is that a construct 766# gets rejected, and a rejection for the wrong reason is not a pass. 767assert_diff_log() 768{ 769 diff_log | grep -qE -- "$1" || 770 fail "expected '$1' in klp diff output: $(tail -2 "$workdir/diff.log")" 771} 772 773# checksum_of <object> <symbol> 774# 775# The checksum "klp checksum" recorded for one symbol, as a hex string. 776# 777# .discard.sym_checksum is an array of { u64 addr; u64 checksum; }, where addr 778# is the target of a relocation naming the symbol. Nothing in the section 779# itself says which symbol an entry belongs to, so the relocation is what 780# locates the entry; the checksum is the eight bytes after it. 781# Callers use this in a command substitution, where fail() would only exit the 782# subshell and the test would carry on with an empty checksum. So this returns 783# non-zero and prints nothing, and the assertions below check for that. For 784# the same reason it does not run run_checksum() itself: that one does call 785# fail(), and from in here the message would be captured as the checksum 786# rather than ending the test. The caller runs it first. 787checksum_of() 788{ 789 local obj="$workdir/$1" sym="$2" off 790 791 off="$($READELF -rW "$obj" 2>/dev/null | 792 awk -v s="$sym" '/rela\.discard\.sym_checksum/,/^$/ { 793 if ($5 == s) { print $1; exit } 794 }')" 795 796 [ -n "$off" ] || return 1 797 798 $OBJCOPY -O binary --only-section=.discard.sym_checksum \ 799 "$obj" "$workdir/checksums.bin" 2>/dev/null || return 1 800 801 dd if="$workdir/checksums.bin" bs=1 skip=$((16#$off + 8)) count=8 \ 802 status=none | od -An -tx1 | tr -d ' \n' 803} 804 805# assert_checksum_differs <symbol> / assert_checksum_matches <symbol> 806# 807# Compare what klp checksum recorded for a symbol in the original against the 808# patched object. This is what decides whether klp diff treats a function as 809# changed, so a test asserting only that the right functions were cloned cannot 810# tell a correct checksum from one which happens to differ. 811checksum_pair() 812{ 813 run_checksum 814 815 orig_checksum="$(checksum_of "$orig_obj" "$1")" 816 patched_checksum="$(checksum_of "$patched_obj" "$1")" 817 818 [ -n "$orig_checksum" ] || 819 fail "no checksum recorded for '$1' in $orig_obj" 820 [ -n "$patched_checksum" ] || 821 fail "no checksum recorded for '$1' in $patched_obj" 822} 823 824assert_checksum_differs() 825{ 826 checksum_pair "$1" 827 828 [ "$orig_checksum" != "$patched_checksum" ] || 829 fail "checksum for '$1' unchanged at $orig_checksum, expected it to differ" 830} 831 832assert_checksum_matches() 833{ 834 checksum_pair "$1" 835 836 [ "$orig_checksum" = "$patched_checksum" ] || 837 fail "checksum for '$1' changed from $orig_checksum to" \ 838 "$patched_checksum, expected no change" 839} 840 841# run_post_link [expected exit status] 842# 843# klp post-link runs last in a livepatch build, converting the intermediate 844# __klp_relocs.* sections into the .klp.rela.* form the kernel consumes. It 845# needs nothing but an object containing those sections, which is what klp diff 846# produces, so it runs on out.o here rather than on a built module. Rewrites 847# out.o in place, so the out_* helpers show the result afterwards. 848run_post_link() 849{ 850 local expect="${1:-0}" rc=0 851 852 "$OBJTOOL" klp post-link "$workdir/out.o" \ 853 > "$workdir/post-link.log" 2>&1 || rc=$? 854 855 [ "$rc" = "$expect" ] || 856 fail "klp post-link exited $rc, expected $expect:" \ 857 "$(tail -2 "$workdir/post-link.log")" 858} 859 860# The flags readelf prints for a section, or nothing when it has none. The 861# leading "[nn]" index is stripped first so the columns can be counted. 862section_flags() 863{ 864 out_sections | sed 's/^ *\[[ 0-9]*\] *//' | 865 awk -v s="$1" '$1 == s && $7 ~ /^[A-Za-z]+$/ { print $7 }' 866} 867 868# assert_section_flag <section> <letter> 869# 870# SHF_RELA_LIVEPATCH is OS-specific, so readelf renders it as "o". A klp rela 871# section which lost it is an ordinary rela section, which the linker may apply 872# and the livepatch code will not. 873assert_section_flag() 874{ 875 local flags; flags="$(section_flags "$1")" 876 877 [ -n "$flags" ] || 878 fail "section '$1' has no flags, expected '$2'" 879 case "$flags" in 880 *"$2"*) ;; 881 *) fail "section '$1' has flags '$flags', expected '$2'" ;; 882 esac 883} 884 885# assert_klp_rela <object> <section> 886# 887# post-link names the converted sections .klp.rela.<object>.<section>, one per 888# base section. Also checks SHF_RELA_LIVEPATCH, since the name alone is not 889# what makes the kernel process it. 890assert_klp_rela() 891{ 892 local name=".klp.rela.$1.$2" 893 894 out_sections | grep -q "[[:space:]]$(re_quote "$name")[[:space:]]" || 895 fail "expected section '$name' in output" 896 897 assert_section_flag "$name" o 898} 899 900# assert_livepatch_sym <symbol> 901# 902# Symbols a klp relocation resolves against live in SHN_LIVEPATCH, which 903# readelf prints as "OS [0xff20]" -- llvm-readelf without the space, so match 904# either. The kernel resolves these itself at patch load; anything else is a 905# symbol the module loader will try, and fail, to resolve normally. 906assert_livepatch_sym() 907{ 908 out_symbols | grep -E 'OS ?\[0xff20\]' | 909 grep -qE "\.klp\.sym\.[^.]+\.$(re_quote "$1")," || 910 fail "expected a klp symbol for '$1' in SHN_LIVEPATCH" 911} 912