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