1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# 4# Symbols which must not get a checksum entry of their own. 5# 6# .discard.sym_checksum is an array of { address, checksum } looked up by the 7# address a relocation points at, so the invariant is one entry per address. 8# calculate_checksums() skips three kinds of symbol to keep it: 9# 10# zero-length nothing to hash, and its address belongs to whatever really 11# lives there 12# alias a second name for an address already covered 13# cold part hashed into its parent, which func_for_each_insn() walks 14# into, so its own entry would double-count 15# 16# A duplicate entry is not a build failure. It makes the lookup ambiguous, and 17# whichever checksum loses is simply never consulted again -- so a function 18# whose code changed can be read as unchanged and dropped from the patch. 19# 20# Of the three, only the alias skip is isolated here: removing it makes this 21# test fail. A zero-length symbol is excluded by more than one of the guards 22# at once -- its section has no data either -- so no single change makes that 23# assertion fail, and it stands as a check on the behaviour rather than on the 24# line which produces it. Nothing here reaches the cold-part skip, which 25# wants a compiler that splits functions; test-cold-function covers that 26# symbol surviving into the patch, not its checksum. 27# 28# Covers the same ground as corpus/x86_64/checksum-zero-len-sym, 29# checksum-alias-skip and checksum-cold-skip in Joe Lawrence's klp-build unit 30# test corpus. 31 32. "$(dirname "$0")/../lib.sh" 33 34setup 35build_pair checksum_skip.c 36 37assert_input_symbol empty_marker 38assert_input_symbol alias_function 39run_checksum 40 41# entries_for <object> [-t] 42# 43# The symbol names .discard.sym_checksum has an entry for, one per line. With 44# -t, what each entry points at instead: the name and its addend, which is the 45# address the kernel looks the entry up by. A name alone is not that address, 46# since a relocation against a section symbol names the section and puts the 47# offset in the addend, and several entries can then share a name honestly. 48entries_for() 49{ 50 in_relocs "$1" | awk -v target="${2:-}" '/rela\.discard\.sym_checksum/,/^$/ { 51 if ($1 !~ /^[0-9a-f]{8,}/) 52 next 53 if (target == "-t") 54 print $5, $6, $7 55 else 56 print $5 57 }' 58} 59 60entries="$(entries_for orig.o)" 61 62# The control: something real did get an entry, so an empty listing cannot 63# make the rest of this pass by default. 64echo "$entries" | grep -qx target || 65 fail "no checksum entry for target" 66 67echo "$entries" | grep -qx empty_marker && 68 fail "zero-length symbol got a checksum entry" 69 70# One of the two names for that address is kept and the other skipped; which 71# one falls out of symbol table order and is not the point. Two would be. 72n="$(echo "$entries" | grep -cxE 'real_function|alias_function')" 73[ "$n" = 1 ] || 74 fail "expected 1 checksum entry across real_function and its alias, found $n" 75 76# One entry per address, which is what the skipping is for. 77dupes="$(entries_for orig.o -t | sort | uniq -d)" 78[ -z "$dupes" ] || 79 fail "two checksum entries for one address: $dupes" 80 81pass "zero-length symbols and aliases get no checksum entry of their own" 82