xref: /linux/tools/objtool/tests/lib.sh (revision 48dafeead17e96ee5a63816580a0b92732ea32f6)
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() { echo "ok - $test_name${1:+: $1}"; exit 0; }
167fail() { echo "not ok - $test_name: $1"; 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() { echo "ok - $test_name # SKIP (declared) $*"; exit 0; }
181probe_skip()    { echo "ok - $test_name # SKIP (probe) $*"; exit 0; }
182skip()          { echo "ok - $test_name # SKIP $*"; exit 0; }
183
184# TAP directives.  A test which is known to fail reports it rather than being
185# commented out and forgotten, and one which starts passing again says so
186# instead of quietly going green: the expectation has to be removed by hand,
187# which is the point.
188xfail()
189{
190	echo "not ok - $test_name${1:+: $1} # TODO known failure"
191	exit 0
192}
193
194xpass()
195{
196	echo "ok - $test_name${1:+: $1} # TODO expected failure, but passed"
197	exit 1
198}
199
200cleanup()
201{
202	[ -n "$workdir" ] || return 0
203
204	if [ -n "${KLP_TEST_KEEP:-}" ]; then
205		[ -n "${KLP_TEST_WORKDIR:-}" ] || echo "# kept $workdir"
206		return 0
207	fi
208
209	rm -rf "$workdir"
210}
211
212# setup [exported symbol...]
213setup()
214{
215	if [ -n "${KLP_TEST_WORKDIR:-}" ]; then
216		workdir="$KLP_TEST_WORKDIR"
217		mkdir -p "$workdir" || fail "cannot create $workdir"
218	else
219		workdir="$(mktemp -d)" || fail "mktemp failed"
220	fi
221	trap cleanup EXIT
222
223	export_syms "$@"
224}
225
226# export_syms [symbol...]
227#
228# Rewrite Module.symvers so exactly these symbols are exported by vmlinux.
229# Whether a symbol is listed decides between an ordinary relocation and a klp
230# relocation, so tests flip it to cover both.
231export_syms()
232{
233	: > "$workdir/Module.symvers"
234	add_exports vmlinux "$@"
235}
236
237# add_exports <object> [symbol...]
238#
239# Append exports owned by one object, without clearing what is already there,
240# so a test can describe a kernel where several objects export things.
241#
242# Which object owns a symbol is not cosmetic: a reference to a vmlinux symbol
243# is applied when the patch module loads, and a reference to a module's symbol
244# when that patched module loads, so klp diff files them in different sections.
245add_exports()
246{
247	local owner="$1"; shift
248
249	add_exports_ns "$owner" "" "$@"
250}
251
252# add_exports_ns <object> <namespace> [symbol...]
253#
254# Exports in a symbol namespace, the last field of a Module.symvers line.
255#
256# A "module:<names>" namespace is EXPORT_SYMBOL_FOR_MODULES(), where the module
257# loader grants access by matching the importing module's name against the
258# list.  A livepatch module is never on that list, so such a symbol has to be
259# referenced the way an unexported one is.  Ordinary namespaces are not
260# special here.
261add_exports_ns()
262{
263	local owner="$1" ns="$2"; shift 2
264
265	local sym
266
267	for sym in "$@"; do
268		printf '0x00000000\t%s\t%s\tEXPORT_SYMBOL\t%s\n' \
269			"$sym" "$owner" "$ns" >> "$workdir/Module.symvers"
270	done
271}
272
273# gcc_only / clang_only <reason>
274gcc_only()
275{
276	case "$($CC --version 2>/dev/null | head -1)" in
277	*[Gg][Cc][Cc]*)	return 0 ;;
278	esac
279	declared_skip "gcc only${1:+: $1}"
280}
281
282clang_only()
283{
284	case "$($CC --version 2>/dev/null | head -1)" in
285	*clang*)	return 0 ;;
286	esac
287	declared_skip "clang only${1:+: $1}"
288}
289
290# build_one <fixture.c> <output object> [cflags...]
291build_one()
292{
293	local fixture out
294	fixture="$FIXTURES_DIR/$1"
295	out="$workdir/$2"
296	shift 2
297
298	[ -f "$fixture" ] || fail "missing fixture $fixture"
299
300	# run_checksum only runs once per workdir.  A fresh object has no
301	# checksums in it, so anything built now needs that to happen again.
302	rm -f "$workdir/.checksummed"
303
304	$CC -c $FIXTURE_CFLAGS "$@" -o "$out" "$fixture" 2>"$workdir/cc.log" ||
305		fail "$(basename "$fixture") does not build: $(tail -1 "$workdir/cc.log")"
306}
307
308# build_pair <fixture.c> [cflags...]
309build_pair()
310{
311	local fixture="$1"; shift
312
313	# Name what this builds.  A test may run several segments, and
314	# make_vmlinux_pair() repoints orig_obj at the image it links, so
315	# without this the next run_diff() would still be reading that.
316	orig_obj=orig.o
317	patched_obj=patched.o
318
319	build_one "$fixture" orig.o "$@"
320	build_one "$fixture" patched.o "$@" -DPATCHED
321}
322
323# run_objtool_check <objtool arguments...>
324#
325# Run objtool's ordinary check pass over the pair, as the kernel build does.
326#
327# Some of what klp diff consumes is produced by this pass rather than by the
328# compiler: .static_call_sites, .mcount_loc, .ibt_endbr_seal, ORC.
329#
330# Only module objects see it before klp-build -- with CONFIG_KLP_BUILD the
331# per-object pass is deferred, so built-in objects reach klp diff exactly as
332# the compiler left them.
333run_objtool_check()
334{
335	local obj
336
337	# This rewrites both objects, so checksums taken before it describe
338	# something that no longer exists.  As in build_one(), drop the marker
339	# so run_checksum() takes them again.
340	rm -f "$workdir/.checksummed"
341
342	for obj in "$orig_obj" "$patched_obj"; do
343		"$OBJTOOL" "$@" "$workdir/$obj" ||
344			fail "objtool $* failed on $obj"
345	done
346}
347
348run_checksum()
349{
350	# Checksums live in the objects, and a test may ask for them more than
351	# once -- diffing the same pair again with a different Module.symvers,
352	# say.  objtool does the right thing when asked twice, leaving the
353	# object alone, but it says so, and that warning would be most of what
354	# a passing run prints.  Remember instead, and keep quiet.
355	[ -e "$workdir/.checksummed" ] && return 0
356
357	"$OBJTOOL" klp checksum "$workdir/$orig_obj" ||
358		fail "klp checksum $orig_obj failed"
359	"$OBJTOOL" klp checksum "$workdir/$patched_obj" ||
360		fail "klp checksum $patched_obj failed"
361	touch "$workdir/.checksummed"
362}
363
364# run_diff [expected exit status]
365run_diff()
366{
367	local expect="${1:-0}" rc=0
368
369	run_checksum
370
371	# klp diff looks for Module.symvers relative to the working directory.
372	( cd "$workdir" && "$OBJTOOL" klp diff "$orig_obj" "$patched_obj" out.o ) \
373		> "$workdir/diff.log" 2>&1 || rc=$?
374
375	[ "$rc" = "$expect" ] ||
376		fail "klp diff exited $rc, expected $expect: $(tail -2 "$workdir/diff.log")"
377}
378
379cc_supports()
380{
381	echo 'int f(void) { return 0; }' > "$workdir/flagtest.c"
382	$CC $1 -c "$workdir/flagtest.c" -o "$workdir/flagtest.o" 2>/dev/null
383}
384
385# partial_link <output> <object...>
386#
387# "ld -r" through the compiler driver so the link targets the same
388# architecture as the objects.
389partial_link()
390{
391	local out="$1"; shift
392
393	rm -f "$workdir/.checksummed"
394
395	$CC -r -nostdlib -o "$out" "$@" 2>/dev/null ||
396		$CC -r -nostdlib -fuse-ld=lld -o "$out" "$@" 2>/dev/null
397}
398
399# link_vmlinux <output> <object...>
400#
401# Link objects into an executable, the way the kernel's final link produces
402# vmlinux from vmlinux.o.  Entry point 0 and no libc: nothing runs it, it only
403# has to be a linked image with resolved addresses.
404#
405# The sub-sections have to come out in name order rather than object order,
406# the way the kernel's linker script gathers .text.unlikely and .data.. apart
407# from the rest.  That reordering is the entire reason .klp.symid exists: a
408# link which preserves order cannot tell a correct sympos from one that merely
409# counted, and the caller checks the two orders really did diverge.
410#
411# A linker script rather than --sort-section=name, because lld accepts that
412# option and ignores it -- so on a host where only lld can link the target, the
413# test would quietly stop testing the thing it is named for.
414#
415# Three attempts because a cross run has neither $LD nor the compiler's default
416# linker able to touch the target: on an arm64 host linking x86 objects, only
417# lld will do it.
418link_vmlinux()
419{
420	local out="$1" lds="$workdir/sort.lds"; shift
421
422	echo 'SECTIONS { .data : { *(SORT_BY_NAME(.data.*)) } }' > "$lds"
423
424	$LD -e 0 -T "$lds" -o "$out" "$@" 2>/dev/null ||
425		$CC -nostdlib -Wl,-e,0 -Wl,-T,"$lds" \
426			-o "$out" "$@" 2>/dev/null ||
427		$CC -nostdlib -fuse-ld=lld -Wl,-e,0 -Wl,-T,"$lds" \
428			-o "$out" "$@" 2>/dev/null
429}
430
431# make_vmlinux_pair <orig object...> -- <patched object...>
432#
433# Build the vmlinux.o / vmlinux pair klp diff needs to resolve sympos the way
434# it does for built-in code, and point the diff at it.
435#
436# For a module, sympos is a count in symbol table order, which klp diff can do
437# from the object alone.  vmlinux is different: the final link reorders
438# sub-sections, so the position comes from the linked image, bridged by
439# .klp.symid.  klp diff only looks for that when the object it was handed is
440# called vmlinux.o and a vmlinux sits beside it -- so both the name and the
441# linked image matter.
442make_vmlinux_pair()
443{
444	local orig=() patched=() seen= arg
445
446	for arg in "$@"; do
447		if [ "$arg" = -- ]; then seen=y; continue; fi
448		if [ -n "$seen" ]; then patched+=( "$arg" ); else orig+=( "$arg" ); fi
449	done
450
451	# Both sides have to have been named.  Without this, forgetting the --
452	# leaves one list empty, the link of nothing fails, and the test skips
453	# saying the toolchain cannot link -- which is a test bug wearing the
454	# costume of an environment one.
455	[ "${#orig[@]}" -gt 0 ] && [ "${#patched[@]}" -gt 0 ] ||
456		fail "make_vmlinux_pair needs objects either side of --"
457
458	partial_link "$workdir/vmlinux.o" "${orig[@]}" ||
459		probe_skip "partial link unavailable"
460	partial_link "$workdir/patched.o" "${patched[@]}" ||
461		probe_skip "partial link unavailable"
462
463	"$OBJTOOL" --klp-symids --link "$workdir/vmlinux.o" ||
464		fail "objtool --klp-symids failed"
465
466	link_vmlinux "$workdir/vmlinux" "$workdir/vmlinux.o" ||
467		probe_skip "cannot link a vmlinux here"
468
469	orig_obj=vmlinux.o
470}
471
472# build_module_pair <fixture.c> <module name> [cflags...]
473#
474# Build the pair as objects belonging to a module rather than to vmlinux.  klp
475# diff reads the object's module name from .modinfo, and that decides which
476# object a relocation is attributed to and whether a reference counts as
477# cross-module, so a good deal of the code has a module path the vmlinux
478# fixtures never reach.
479#
480# The fixture defines its .modinfo name from MODNAME.  Passing that through
481# -D needs two levels of quoting, which is easy to get wrong at the call site.
482build_module_pair()
483{
484	local fixture="$1" modname="$2"; shift 2
485
486	build_pair "$fixture" -DMODNAME="\"$modname\"" "$@"
487}
488
489# find_thinlto_toolchain
490#
491# Set $THIN_LD to an lld from the same LLVM release as $CC (or THIN_CC).  A
492# mismatched pair fails with "Invalid summary version", which reads like a
493# broken test rather than a broken environment.
494#
495# ThinLTO is clang-only; callers must use clang_only before calling this.
496# Only $CC (or an explicit THIN_CC override) is consulted -- the harness does
497# not search for a second compiler beside a gcc $CC.
498find_thinlto_toolchain()
499{
500	local cc ver ld
501
502	for cc in "${THIN_CC:-}" "$CC"; do
503		[ -n "$cc" ] || continue
504		command -v "${cc%% *}" >/dev/null 2>&1 || return 1
505
506		ver=$($cc -dumpversion 2>/dev/null | cut -d. -f1)
507
508		for ld in "${THIN_LD:-}" "ld.lld-$ver" ld.lld; do
509			[ -n "$ld" ] || continue
510			command -v "$ld" >/dev/null 2>&1 || continue
511
512			echo 'int probe(void) { return 0; }' > "$workdir/probe.c"
513			$cc -flto=thin -O2 -c "$workdir/probe.c" \
514				-o "$workdir/probe.o" 2>/dev/null || continue
515			"$ld" -r "$workdir/probe.o" -o "$workdir/probe.elf" \
516				2>/dev/null || continue
517
518			THIN_CC="$cc"
519			THIN_LD="$ld"
520			return 0
521		done
522	done
523
524	return 1
525}
526
527out_sections() { $READELF -S -W "$workdir/out.o" 2>/dev/null; }
528out_relocs()   { $READELF -r -W "$workdir/out.o" 2>/dev/null; }
529out_symbols()  { $READELF -s -W "$workdir/out.o" 2>/dev/null; }
530diff_log()     { cat "$workdir/diff.log"; }
531
532# out_strings <section>
533#
534# The strings in one section of the output, for the names livepatch matches on.
535out_strings() { $READELF -p "$1" "$workdir/out.o" 2>/dev/null; }
536
537# Checks on the input objects, to run before klp diff.  The two forms differ in
538# what an absent construct means:
539#
540#   require_*  the compiler cannot produce it here	-> skip
541#   assert_*   the fixture is supposed to produce it	-> fail
542
543in_sections() { $READELF -S -W "$workdir/$1" 2>/dev/null; }
544in_symbols()  { $READELF -s -W "$workdir/$1" 2>/dev/null; }
545in_relocs()   { $READELF -r -W "$workdir/$1" 2>/dev/null; }
546
547# count_input_symbols <object> <name>
548#
549# How many object symbols of exactly that name the input has.  Deliberately not
550# a grep: readelf lists section symbols too, and a newer binutils prints their
551# name -- ".data.<name>" -- where an older one leaves the column blank.  A dot
552# is not a word character, so "grep -w <name>" counts that line as well, and
553# the same object gives a different answer depending on which readelf reads it.
554count_input_symbols()
555{
556	in_symbols "$1" | awk -v n="$2" '$4 == "OBJECT" && $8 == n' | wc -l
557}
558
559# re_quote <string>
560#
561# A string as a literal basic regular expression.  Nearly every name these
562# assertions match on contains a dot -- .text.target, .klp.rela.vmlinux -- and
563# an unescaped dot matches any character, so an assertion for one section can be
564# satisfied by a different one whose name merely lines up.
565re_quote() { printf '%s' "$1" | sed 's|[].[^$*\\/]|\\&|g'; }
566
567has_input_section() { in_sections "$1" | grep -q "[[:space:]]$(re_quote "$2")[[:space:]]"; }
568has_input_symbol()  { in_symbols "$1" | awk -v n="$2" '$NF == n' | grep -q .; }
569
570assert_input_section()
571{
572	local obj
573
574	for obj in "$orig_obj" "$patched_obj"; do
575		has_input_section "$obj" "$1" ||
576			fail "fixture produced no section '$1' in $obj"
577	done
578}
579
580assert_input_symbol()
581{
582	local obj
583
584	for obj in "$orig_obj" "$patched_obj"; do
585		has_input_symbol "$obj" "$1" ||
586			fail "fixture produced no symbol '$1' in $obj"
587	done
588}
589
590require_input_section()
591{
592	local obj
593
594	for obj in "$orig_obj" "$patched_obj"; do
595		has_input_section "$obj" "$1" ||
596			probe_skip "compiler produced no section '$1' here"
597	done
598}
599
600assert_section()
601{
602	out_sections | grep -q "[[:space:]]$(re_quote "$1")[[:space:]]" ||
603		fail "expected section '$1' in output"
604}
605
606assert_no_section()
607{
608	out_sections | grep -q "[[:space:]]$(re_quote "$1")[[:space:]]" &&
609		fail "unexpected section '$1' in output"
610	return 0
611}
612
613assert_patched()
614{
615	assert_section ".text.$1"
616}
617
618assert_not_patched()
619{
620	out_sections | grep -q "[[:space:]]$(re_quote ".text.$1")[[:space:]]" &&
621		fail "function '$1' should not have been cloned"
622	return 0
623}
624
625# section_relocs <section>
626#
627# The relocations against one section.  readelf prints every relocation section
628# in turn, so a test asking about ".smp_locks" has to cut its block out of the
629# listing first.
630section_relocs()
631{
632	local sec="${1//./\\.}"
633
634	out_relocs | awk "/rela$sec'/,/^\$/"
635}
636
637assert_reloc_sym()
638{
639	section_relocs "$1" | awk -v n="$2" '$5 == n' | grep -q . ||
640		fail "expected a relocation to '$2' in '$1'"
641}
642
643assert_no_reloc_sym()
644{
645	section_relocs "$1" | awk -v n="$2" '$5 == n' | grep -q . &&
646		fail "unexpected relocation to '$2' in '$1'"
647	return 0
648}
649
650# assert_reloc_count <section> <count>
651#
652# Counts relocation entries, not header or blank lines: whether a special
653# section entry was extracted once, twice or not at all is usually the whole
654# question.
655#
656# A count of zero is ambiguous on its own -- a section with no relocations and
657# no section at all both read as zero -- so require the section to exist.  A
658# test expecting nothing there wants assert_no_section.
659assert_reloc_count()
660{
661	local n
662
663	assert_section "$1"
664
665	n="$(section_relocs "$1" | grep -cE '^[0-9a-f]{8,}')"
666	[ "$n" = "$2" ] ||
667		fail "expected $2 relocations in '$1', found $n"
668}
669
670# assert_klp_sym <symbol> [object]
671#
672# A klp symbol is named .klp.sym.<object>.<symbol>,<sympos>.  The object
673# defaults to any, since most tests care that the reference was converted at
674# all rather than which object it resolved against.
675assert_klp_sym()
676{
677	out_symbols | grep -q "\.klp\.sym\.${2:-[^.]*}\.$(re_quote "$1")," ||
678		fail "expected klp symbol for '$1'"
679}
680
681# assert_klp_sympos <symbol> <sympos>
682#
683# The number after the comma in .klp.sym.<object>.<symbol>,<sympos> says which
684# of several same-named symbols livepatch should resolve to, counting from 1;
685# 0 means the name is unique and no disambiguation is needed.  Resolving to the
686# wrong one is not a load failure, it is a patch quietly wired to the wrong
687# object.
688assert_klp_sympos()
689{
690	out_symbols | grep -qE "\.klp\.sym\.[^.]+\.$(re_quote "$1"),$2([[:space:]]|\$)" ||
691		fail "expected klp symbol for '$1' with sympos $2, found:$(
692			out_symbols | grep -o "\.klp\.sym\.[^.]*\.$(re_quote "$1"),[0-9]*" |
693			sort -u | tr '\n' ' ')"
694}
695
696assert_no_klp_sym()
697{
698	out_symbols | grep -q "\.klp\.sym\.${2:-[^.]*}\.$(re_quote "$1")," &&
699		fail "unexpected klp symbol for '$1'"
700	return 0
701}
702
703assert_tombstone()
704{
705	out_symbols | grep -qE "\.klp\.tombstone\.$(re_quote "$1")([[:space:]]|\$)" ||
706		fail "expected a tombstone for '$1'"
707}
708
709assert_symbol()
710{
711	out_symbols | awk -v n="$1" '$NF == n' | grep -q . ||
712		fail "expected symbol '$1' in output"
713}
714
715assert_no_symbol()
716{
717	out_symbols | awk -v n="$1" '$NF == n' | grep -q . &&
718		fail "unexpected symbol '$1' in output"
719	return 0
720}
721
722# assert_diff_log <regex>
723#
724# klp diff's combined output, for tests asserting on a diagnostic.  Error
725# messages are part of the interface when the whole point is that a construct
726# gets rejected, and a rejection for the wrong reason is not a pass.
727assert_diff_log()
728{
729	diff_log | grep -qE -- "$1" ||
730		fail "expected '$1' in klp diff output: $(tail -2 "$workdir/diff.log")"
731}
732
733# checksum_of <object> <symbol>
734#
735# The checksum "klp checksum" recorded for one symbol, as a hex string.
736#
737# .discard.sym_checksum is an array of { u64 addr; u64 checksum; }, where addr
738# is the target of a relocation naming the symbol.  Nothing in the section
739# itself says which symbol an entry belongs to, so the relocation is what
740# locates the entry; the checksum is the eight bytes after it.
741# Callers use this in a command substitution, where fail() would only exit the
742# subshell and the test would carry on with an empty checksum.  So this returns
743# non-zero and prints nothing, and the assertions below check for that.  For
744# the same reason it does not run run_checksum() itself: that one does call
745# fail(), and from in here the message would be captured as the checksum
746# rather than ending the test.  The caller runs it first.
747checksum_of()
748{
749	local obj="$workdir/$1" sym="$2" off
750
751	off="$($READELF -rW "$obj" 2>/dev/null |
752	       awk -v s="$sym" '/rela\.discard\.sym_checksum/,/^$/ {
753			if ($5 == s) { print $1; exit }
754	       }')"
755
756	[ -n "$off" ] || return 1
757
758	$OBJCOPY -O binary --only-section=.discard.sym_checksum \
759		"$obj" "$workdir/checksums.bin" 2>/dev/null || return 1
760
761	dd if="$workdir/checksums.bin" bs=1 skip=$((16#$off + 8)) count=8 \
762		status=none | od -An -tx1 | tr -d ' \n'
763}
764
765# assert_checksum_differs <symbol> / assert_checksum_matches <symbol>
766#
767# Compare what klp checksum recorded for a symbol in the original against the
768# patched object.  This is what decides whether klp diff treats a function as
769# changed, so a test asserting only that the right functions were cloned cannot
770# tell a correct checksum from one which happens to differ.
771checksum_pair()
772{
773	run_checksum
774
775	orig_checksum="$(checksum_of "$orig_obj" "$1")"
776	patched_checksum="$(checksum_of "$patched_obj" "$1")"
777
778	[ -n "$orig_checksum" ] ||
779		fail "no checksum recorded for '$1' in $orig_obj"
780	[ -n "$patched_checksum" ] ||
781		fail "no checksum recorded for '$1' in $patched_obj"
782}
783
784assert_checksum_differs()
785{
786	checksum_pair "$1"
787
788	[ "$orig_checksum" != "$patched_checksum" ] ||
789		fail "checksum for '$1' unchanged at $orig_checksum, expected it to differ"
790}
791
792assert_checksum_matches()
793{
794	checksum_pair "$1"
795
796	[ "$orig_checksum" = "$patched_checksum" ] ||
797		fail "checksum for '$1' changed from $orig_checksum to" \
798		     "$patched_checksum, expected no change"
799}
800
801# run_post_link [expected exit status]
802#
803# klp post-link runs last in a livepatch build, converting the intermediate
804# __klp_relocs.* sections into the .klp.rela.* form the kernel consumes.  It
805# needs nothing but an object containing those sections, which is what klp diff
806# produces, so it runs on out.o here rather than on a built module.  Rewrites
807# out.o in place, so the out_* helpers show the result afterwards.
808run_post_link()
809{
810	local expect="${1:-0}" rc=0
811
812	"$OBJTOOL" klp post-link "$workdir/out.o" \
813		> "$workdir/post-link.log" 2>&1 || rc=$?
814
815	[ "$rc" = "$expect" ] ||
816		fail "klp post-link exited $rc, expected $expect:" \
817		     "$(tail -2 "$workdir/post-link.log")"
818}
819
820# The flags readelf prints for a section, or nothing when it has none.  The
821# leading "[nn]" index is stripped first so the columns can be counted.
822section_flags()
823{
824	out_sections | sed 's/^ *\[[ 0-9]*\] *//' |
825		awk -v s="$1" '$1 == s && $7 ~ /^[A-Za-z]+$/ { print $7 }'
826}
827
828# assert_section_flag <section> <letter>
829#
830# SHF_RELA_LIVEPATCH is OS-specific, so readelf renders it as "o".  A klp rela
831# section which lost it is an ordinary rela section, which the linker may apply
832# and the livepatch code will not.
833assert_section_flag()
834{
835	local flags; flags="$(section_flags "$1")"
836
837	[ -n "$flags" ] ||
838		fail "section '$1' has no flags, expected '$2'"
839	case "$flags" in
840	*"$2"*)	;;
841	*)	fail "section '$1' has flags '$flags', expected '$2'" ;;
842	esac
843}
844
845# assert_klp_rela <object> <section>
846#
847# post-link names the converted sections .klp.rela.<object>.<section>, one per
848# base section.  Also checks SHF_RELA_LIVEPATCH, since the name alone is not
849# what makes the kernel process it.
850assert_klp_rela()
851{
852	local name=".klp.rela.$1.$2"
853
854	out_sections | grep -q "[[:space:]]$(re_quote "$name")[[:space:]]" ||
855		fail "expected section '$name' in output"
856
857	assert_section_flag "$name" o
858}
859
860# assert_livepatch_sym <symbol>
861#
862# Symbols a klp relocation resolves against live in SHN_LIVEPATCH, which
863# readelf prints as "OS [0xff20]" -- llvm-readelf without the space, so match
864# either.  The kernel resolves these itself at patch load; anything else is a
865# symbol the module loader will try, and fail, to resolve normally.
866assert_livepatch_sym()
867{
868	out_symbols | grep -E 'OS ?\[0xff20\]' |
869		grep -qE "\.klp\.sym\.[^.]+\.$(re_quote "$1")," ||
870		fail "expected a klp symbol for '$1' in SHN_LIVEPATCH"
871}
872