Live Patching
 help / color / mirror / Atom feed
From: Song Liu <song@kernel.org>
To: live-patching@vger.kernel.org
Cc: jpoimboe@kernel.org, peterz@infradead.org, jikos@kernel.org,
	mbenes@suse.cz, pmladek@suse.com, joe.lawrence@redhat.com,
	puranjay@kernel.org, kernel-team@meta.com,
	Song Liu <song@kernel.org>
Subject: [PATCH 05/58] objtool/klp: Build klp test fixtures through the harness
Date: Fri, 11 Sep 2026 11:42:12 -0700	[thread overview]
Message-ID: <20260911184305.1457308-6-song@kernel.org> (raw)
In-Reply-To: <20260911184305.1457308-1-song@kernel.org>

Compiling a fixture is the one thing every test does, and it has more
invariants than it looks.

  - The flags describe the kernel a fixture stands in for, and each is
    written down with its reason.  That substitution is the whole mechanism
    by which these tests cover configurations without building a kernel --
    objtool reads no .config, so a configuration reaches it only as
    compiler flags and the bytes they produce -- and a flag with no stated
    motive is indistinguishable from a mistake.

  - -c is not one of them.  Producing an object rather than a program is
    the helper's contract, not something a test may reconsider, so it lives
    at the compile and an override cannot drop it.

  - A fixture which will not compile is a failure, not a skip.  It is far
    more often a mistake in the fixture than a compiler which cannot
    express the construct, and the two are indistinguishable once reported
    as a skip.

  - A newly produced object has no checksums in it, so producing one
    invalidates the record that checksumming has already been done.  Left
    to itself that invariant ends up in each test which rebuilds.

build_one handles a single object for the tests which need more than two or
different names; build_pair and build_module_pair are expressed in terms of
it, so none of the above can be lost by going around them.

run_checksum comes out of run_diff for the same reason: a test which wants
checksums without a diff should not have to run one.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
---
 tools/objtool/tests/lib.sh | 175 +++++++++++++++++++++++++++++++++----
 1 file changed, 156 insertions(+), 19 deletions(-)

diff --git a/tools/objtool/tests/lib.sh b/tools/objtool/tests/lib.sh
index 7185198253bb..0a9da178f4dc 100644
--- a/tools/objtool/tests/lib.sh
+++ b/tools/objtool/tests/lib.sh
@@ -125,13 +125,26 @@ EOF
 
 [ -n "${KLP_TEST_PREFLIGHT:-}" ] || klp_preflight
 
-# klp-build compiles the kernel this way; klp diff needs per-symbol sections to
-# extract individual functions.
-FIXTURE_CFLAGS="-c -O2 -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables"
+# What every fixture is built with.  These describe the kernel a fixture stands
+# in for; -c is build_one's contract rather than a property of that kernel, so
+# it lives at the compile where an override cannot drop it.
+#
+#   -O2					the kernel's default
+#   -ffunction-sections -fdata-sections	klp-build passes these itself, through
+#					KCFLAGS, whatever the configuration
+#   -fno-asynchronous-unwind-tables	arch/x86/Makefile sets this always, so
+#					kernel objects carry no .eh_frame
+#
+# A test overrides it; see tools/objtool/Documentation/klp-write-tests.txt.
+FIXTURE_CFLAGS="-O2 -ffunction-sections -fdata-sections \
+		-fno-asynchronous-unwind-tables"
 
 test_name="$(basename "$0" .sh)"
 workdir=
 
+orig_obj=orig.o
+patched_obj=patched.o
+
 pass() { echo "ok - $test_name${1:+: $1}"; exit 0; }
 fail() { echo "not ok - $test_name: $1"; exit 1; }
 
@@ -211,17 +224,64 @@ clang_only()
 	declared_skip "clang only${1:+: $1}"
 }
 
+# build_one <fixture.c> <output object> [cflags...]
+build_one()
+{
+	local fixture out
+	fixture="$FIXTURES_DIR/$1"
+	out="$workdir/$2"
+	shift 2
+
+	[ -f "$fixture" ] || fail "missing fixture $fixture"
+
+	# run_checksum only runs once per workdir.  A fresh object has no
+	# checksums in it, so anything built now needs that to happen again.
+	rm -f "$workdir/.checksummed"
+
+	$CC -c $FIXTURE_CFLAGS "$@" -o "$out" "$fixture" 2>"$workdir/cc.log" ||
+		fail "$(basename "$fixture") does not build: $(tail -1 "$workdir/cc.log")"
+}
+
 # build_pair <fixture.c> [cflags...]
 build_pair()
 {
-	local fixture="$FIXTURES_DIR/$1"; shift
+	local fixture="$1"; shift
 
-	[ -f "$fixture" ] || fail "missing fixture $fixture"
+	build_one "$fixture" orig.o "$@"
+	build_one "$fixture" patched.o "$@" -DPATCHED
+}
 
-	$CC $FIXTURE_CFLAGS "$@" -o "$workdir/orig.o" "$fixture" 2>"$workdir/cc.log" ||
-		probe_skip "fixture does not build here: $(tail -1 "$workdir/cc.log")"
-	$CC $FIXTURE_CFLAGS "$@" -DPATCHED -o "$workdir/patched.o" "$fixture" 2>"$workdir/cc.log" ||
-		probe_skip "fixture does not build here: $(tail -1 "$workdir/cc.log")"
+# run_objtool_check <objtool arguments...>
+#
+# Run objtool's ordinary check pass over the pair, as the kernel build does.
+#
+# Some of what klp diff consumes is produced by this pass rather than by the
+# compiler: .static_call_sites, .mcount_loc, .ibt_endbr_seal, ORC.
+#
+# Only module objects see it before klp-build -- with CONFIG_KLP_BUILD the
+# per-object pass is deferred, so built-in objects reach klp diff exactly as
+# the compiler left them.
+run_objtool_check()
+{
+	local obj
+
+	for obj in "$orig_obj" "$patched_obj"; do
+		"$OBJTOOL" "$@" "$workdir/$obj" ||
+			fail "objtool $* failed on $obj"
+	done
+}
+
+run_checksum()
+{
+	# Checksums live in the objects, so only generate them once even when a
+	# test diffs the same pair again with a different Module.symvers.
+	[ -e "$workdir/.checksummed" ] && return 0
+
+	"$OBJTOOL" klp checksum "$workdir/$orig_obj" ||
+		fail "klp checksum $orig_obj failed"
+	"$OBJTOOL" klp checksum "$workdir/$patched_obj" ||
+		fail "klp checksum $patched_obj failed"
+	touch "$workdir/.checksummed"
 }
 
 # run_diff [expected exit status]
@@ -229,18 +289,10 @@ run_diff()
 {
 	local expect="${1:-0}" rc=0
 
-	# Checksums live in the objects, so only generate them once even when a
-	# test diffs the same pair again with a different Module.symvers.
-	if [ ! -e "$workdir/.checksummed" ]; then
-		"$OBJTOOL" klp checksum "$workdir/orig.o" ||
-			fail "klp checksum orig.o failed"
-		"$OBJTOOL" klp checksum "$workdir/patched.o" ||
-			fail "klp checksum patched.o failed"
-		touch "$workdir/.checksummed"
-	fi
+	run_checksum
 
 	# klp diff looks for Module.symvers relative to the working directory.
-	( cd "$workdir" && "$OBJTOOL" klp diff orig.o patched.o out.o ) \
+	( cd "$workdir" && "$OBJTOOL" klp diff "$orig_obj" "$patched_obj" out.o ) \
 		> "$workdir/diff.log" 2>&1 || rc=$?
 
 	[ "$rc" = "$expect" ] ||
@@ -261,10 +313,95 @@ partial_link()
 {
 	local out="$1"; shift
 
+	rm -f "$workdir/.checksummed"
+
 	$CC -r -nostdlib -o "$out" "$@" 2>/dev/null ||
 		$CC -r -nostdlib -fuse-ld=lld -o "$out" "$@" 2>/dev/null
 }
 
+# link_vmlinux <output> <object...>
+#
+# Link objects into an executable, the way the kernel's final link produces
+# vmlinux from vmlinux.o.  Entry point 0 and no libc: nothing runs it, it only
+# has to be a linked image with resolved addresses.
+#
+# The sub-sections have to come out in name order rather than object order,
+# the way the kernel's linker script gathers .text.unlikely and .data.. apart
+# from the rest.  That reordering is the entire reason .klp.symid exists: a
+# link which preserves order cannot tell a correct sympos from one that merely
+# counted, and the caller checks the two orders really did diverge.
+#
+# A linker script rather than --sort-section=name, because lld accepts that
+# option and ignores it -- so on a host where only lld can link the target, the
+# test would quietly stop testing the thing it is named for.
+#
+# Three attempts because a cross run has neither $LD nor the compiler's default
+# linker able to touch the target: on an arm64 host linking x86 objects, only
+# lld will do it.
+link_vmlinux()
+{
+	local out="$1" lds="$workdir/sort.lds"; shift
+
+	echo 'SECTIONS { .data : { *(SORT_BY_NAME(.data.*)) } }' > "$lds"
+
+	$LD -e 0 -T "$lds" -o "$out" "$@" 2>/dev/null ||
+		$CC -nostdlib -Wl,-e,0 -Wl,-T,"$lds" \
+			-o "$out" "$@" 2>/dev/null ||
+		$CC -nostdlib -fuse-ld=lld -Wl,-e,0 -Wl,-T,"$lds" \
+			-o "$out" "$@" 2>/dev/null
+}
+
+# make_vmlinux_pair <orig object...> -- <patched object...>
+#
+# Build the vmlinux.o / vmlinux pair klp diff needs to resolve sympos the way
+# it does for built-in code, and point the diff at it.
+#
+# For a module, sympos is a count in symbol table order, which klp diff can do
+# from the object alone.  vmlinux is different: the final link reorders
+# sub-sections, so the position comes from the linked image, bridged by
+# .klp.symid.  klp diff only looks for that when the object it was handed is
+# called vmlinux.o and a vmlinux sits beside it -- so both the name and the
+# linked image matter.
+make_vmlinux_pair()
+{
+	local orig=() patched=() seen= arg
+
+	for arg in "$@"; do
+		if [ "$arg" = -- ]; then seen=y; continue; fi
+		if [ -n "$seen" ]; then patched+=( "$arg" ); else orig+=( "$arg" ); fi
+	done
+
+	partial_link "$workdir/vmlinux.o" "${orig[@]}" ||
+		probe_skip "partial link unavailable"
+	partial_link "$workdir/patched.o" "${patched[@]}" ||
+		probe_skip "partial link unavailable"
+
+	"$OBJTOOL" --klp-symids --link "$workdir/vmlinux.o" ||
+		fail "objtool --klp-symids failed"
+
+	link_vmlinux "$workdir/vmlinux" "$workdir/vmlinux.o" ||
+		probe_skip "cannot link a vmlinux here"
+
+	orig_obj=vmlinux.o
+}
+
+# build_module_pair <fixture.c> <module name> [cflags...]
+#
+# Build the pair as objects belonging to a module rather than to vmlinux.  klp
+# diff reads the object's module name from .modinfo, and that decides which
+# object a relocation is attributed to and whether a reference counts as
+# cross-module, so a good deal of the code has a module path the vmlinux
+# fixtures never reach.
+#
+# The fixture defines its .modinfo name from MODNAME.  Passing that through
+# -D needs two levels of quoting, which is easy to get wrong at the call site.
+build_module_pair()
+{
+	local fixture="$1" modname="$2"; shift 2
+
+	build_pair "$fixture" -DMODNAME="\"$modname\"" "$@"
+}
+
 # find_thinlto_toolchain
 #
 # Set $THIN_LD to an lld from the same LLVM release as $CC (or THIN_CC).  A
-- 
2.53.0-Meta


  parent reply	other threads:[~2026-09-11 18:44 UTC|newest]

Thread overview: 77+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-11 18:42 [PATCH 00/58] Unit test framework for klp-build toolchain Song Liu
2026-09-11 18:42 ` [PATCH 01/58] objtool: Add test harness for the klp subcommands Song Liu
2026-09-11 18:42 ` [PATCH 02/58] objtool/klp: Check the klp test environment once, before any test Song Liu
2026-09-11 19:02   ` sashiko-bot
2026-09-11 18:42 ` [PATCH 03/58] objtool/klp: Group the klp tests by architecture Song Liu
2026-09-11 18:42 ` [PATCH 04/58] objtool/klp: Classify klp test outcomes Song Liu
2026-09-11 18:42 ` Song Liu [this message]
2026-09-11 18:42 ` [PATCH 06/58] objtool/klp: Grow the klp test harness vocabulary Song Liu
2026-09-11 19:03   ` sashiko-bot
2026-09-11 18:42 ` [PATCH 07/58] objtool/klp: Give each run one working directory, one per test inside it Song Liu
2026-09-11 18:42 ` [PATCH 08/58] objtool/klp: Run the klp tests under set -u Song Liu
2026-09-11 18:42 ` [PATCH 09/58] objtool/klp: Document the klp test harness Song Liu
2026-09-11 19:00   ` sashiko-bot
2026-09-11 18:42 ` [PATCH 10/58] objtool: Keep failing test workdirs by default Song Liu
2026-09-11 19:07   ` sashiko-bot
2026-09-11 18:42 ` [PATCH 11/58] objtool: Forward toolchain variables to the klp test runner Song Liu
2026-09-11 18:42 ` [PATCH 12/58] objtool/klp: Add test for rejecting changed data Song Liu
2026-09-11 18:42 ` [PATCH 13/58] objtool/klp: Add test for newly introduced data Song Liu
2026-09-11 19:07   ` sashiko-bot
2026-09-11 18:42 ` [PATCH 14/58] objtool/klp: Add test for newly introduced functions Song Liu
2026-09-11 18:42 ` [PATCH 15/58] objtool/klp: Add test for static local correlation Song Liu
2026-09-11 18:42 ` [PATCH 16/58] objtool/klp: Add test for cold function halves Song Liu
2026-09-11 19:07   ` sashiko-bot
2026-09-11 18:42 ` [PATCH 17/58] objtool/klp: Add test for special section extraction Song Liu
2026-09-11 18:42 ` [PATCH 18/58] objtool/klp: Add test for selective " Song Liu
2026-09-11 18:42 ` [PATCH 19/58] objtool/klp: Add test for jump table key relocations Song Liu
2026-09-11 18:42 ` [PATCH 20/58] objtool/klp: Add test for rejecting module-owned static branch keys Song Liu
2026-09-11 18:42 ` [PATCH 21/58] objtool/klp: Add test for rejecting module-owned static call keys Song Liu
2026-09-11 18:42 ` [PATCH 22/58] objtool/klp: Add test for symids in discarded sections Song Liu
2026-09-11 18:42 ` [PATCH 23/58] objtool/klp: Add test for rejecting references to init code/data Song Liu
2026-09-11 19:18   ` sashiko-bot
2026-09-11 18:42 ` [PATCH 24/58] objtool/klp: Add test for correlation across ThinLTO name mangling Song Liu
2026-09-11 18:42 ` [PATCH 25/58] objtool/klp: Add test for objects without .modinfo Song Liu
2026-09-11 18:49 ` [PATCH 26/58] objtool/klp: Add test for unchecksummed input Song Liu
2026-09-11 18:50   ` [PATCH 27/58] objtool/klp: Add klp diff and post-link regression tests Song Liu
2026-09-11 18:50   ` [PATCH 28/58] objtool/klp: Add test for klp reloc section naming in module objects Song Liu
2026-09-11 18:50   ` [PATCH 29/58] objtool/klp: Add test for vmlinux relocs in a patched module Song Liu
2026-09-11 18:50   ` [PATCH 30/58] objtool/klp: Add test for Module.symvers path normalization Song Liu
2026-09-11 18:50   ` [PATCH 31/58] objtool/klp: Add test for the contents of the klp_funcs list Song Liu
2026-09-11 18:50   ` [PATCH 32/58] objtool/klp: Add test for EXPORT_SYMBOL_FOR_MODULES references Song Liu
2026-09-11 18:50   ` [PATCH 33/58] objtool/klp: Add test for new references to exported symbols Song Liu
2026-09-11 18:50   ` [PATCH 34/58] objtool/klp: Add test for empty x86 alternative replacements Song Liu
2026-09-11 18:50   ` [PATCH 35/58] objtool/klp: Add test for recorded checksum values Song Liu
2026-09-11 18:50   ` [PATCH 36/58] objtool/klp: Add test for position-independent checksums Song Liu
2026-09-11 19:16     ` sashiko-bot
2026-09-11 18:50   ` [PATCH 37/58] objtool/klp: Add test for sympos in module objects Song Liu
2026-09-11 19:21     ` sashiko-bot
2026-09-11 18:50   ` [PATCH 38/58] objtool/klp: Add test for sympos resolved against a linked vmlinux Song Liu
2026-09-11 18:50   ` [PATCH 39/58] objtool/klp: Add test for static locals which must not be correlated Song Liu
2026-09-11 18:50   ` [PATCH 40/58] objtool/klp: Add test for __bug_table, __ex_table and __mcount_loc extraction Song Liu
2026-09-11 19:20     ` sashiko-bot
2026-09-11 18:50   ` [PATCH 41/58] objtool/klp: Add test for kCFI prefix symbols and traps Song Liu
2026-09-11 19:21     ` sashiko-bot
2026-09-11 18:50   ` [PATCH 42/58] objtool/klp: Add test for symbols whose linkage the patch changes Song Liu
2026-09-11 18:50   ` [PATCH 43/58] objtool/klp: Test rejection of a file-local static branch key Song Liu
2026-09-11 18:50   ` [PATCH 44/58] objtool/klp: Test a hand-built livepatch module's static call keys Song Liu
2026-09-11 18:50   ` [PATCH 45/58] objtool/klp: Test text annotations on alternative replacements Song Liu
2026-09-11 18:50   ` [PATCH 46/58] objtool/klp: Add test for data object checksums Song Liu
2026-09-11 18:50   ` [PATCH 47/58] objtool/klp: Add test for symbols with no checksum entry of their own Song Liu
2026-09-11 19:23     ` sashiko-bot
2026-09-11 18:50   ` [PATCH 48/58] objtool/klp: Add test for a static branch introduced by the patch Song Liu
2026-09-11 18:50   ` [PATCH 49/58] objtool/klp: Add test for tracepoint and pr_debug static branch keys Song Liu
2026-09-11 18:50   ` [PATCH 50/58] objtool/klp: Add test for a static call introduced by the patch Song Liu
2026-09-11 19:25     ` sashiko-bot
2026-09-11 18:50   ` [PATCH 51/58] objtool/klp: Add test for instruction operand checksums Song Liu
2026-09-11 18:50   ` [PATCH 52/58] objtool/klp: Add test for alternative replacement code in checksums Song Liu
2026-09-11 19:30     ` sashiko-bot
2026-09-11 18:50   ` [PATCH 53/58] objtool/klp: Add test for the alignment of cloned data sections Song Liu
2026-09-11 18:50   ` [PATCH 54/58] objtool/klp: Add test for a patch which strips a data annotation Song Liu
2026-09-11 19:24     ` sashiko-bot
2026-09-11 18:50   ` [PATCH 55/58] objtool/klp: Add test for absolute and __ADDRESSABLE symbols Song Liu
2026-09-11 18:50   ` [PATCH 56/58] objtool/klp: Add test for UBSAN metadata in an unchanged function Song Liu
2026-09-11 18:50   ` [PATCH 57/58] objtool/klp: Add test for Clang switch jump tables Song Liu
2026-09-11 19:27     ` sashiko-bot
2026-09-11 18:50   ` [PATCH 58/58] objtool/klp: Add test for ThinLTO symbols sharing a demangled name Song Liu
2026-09-11 19:28     ` sashiko-bot
2026-09-13  1:53 ` [PATCH 00/58] Unit test framework for klp-build toolchain Josh Poimboeuf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260911184305.1457308-6-song@kernel.org \
    --to=song@kernel.org \
    --cc=jikos@kernel.org \
    --cc=joe.lawrence@redhat.com \
    --cc=jpoimboe@kernel.org \
    --cc=kernel-team@meta.com \
    --cc=live-patching@vger.kernel.org \
    --cc=mbenes@suse.cz \
    --cc=peterz@infradead.org \
    --cc=pmladek@suse.com \
    --cc=puranjay@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox