1*2bbf68f4SSong Liu#!/bin/bash 2*2bbf68f4SSong Liu# SPDX-License-Identifier: GPL-2.0 3*2bbf68f4SSong Liu# 4*2bbf68f4SSong Liu# A patch can change a symbol's linkage without renaming it: dropping "static" 5*2bbf68f4SSong Liu# from a helper so something else can call it, or adding it to one that is no 6*2bbf68f4SSong Liu# longer shared. Correlation keys off more than the name, so a symbol whose 7*2bbf68f4SSong Liu# binding moved can fail to pair with itself. 8*2bbf68f4SSong Liu# 9*2bbf68f4SSong Liu# Failing to correlate is not a build failure. The symbol looks new, and a 10*2bbf68f4SSong Liu# "new" data symbol is either rejected or cloned as a second copy -- at which 11*2bbf68f4SSong Liu# point the patched code updates its own private variable and the rest of the 12*2bbf68f4SSong Liu# kernel keeps reading the original. 13*2bbf68f4SSong Liu 14*2bbf68f4SSong Liu. "$(dirname "$0")/../lib.sh" 15*2bbf68f4SSong Liu 16*2bbf68f4SSong Liusetup 17*2bbf68f4SSong Liubuild_pair local_to_global.c 18*2bbf68f4SSong Liu 19*2bbf68f4SSong Liu# Confirm the fixture really moved the bindings, in both directions. 20*2bbf68f4SSong Liu# 21*2bbf68f4SSong Liu# Match the binding and the name as fields, not as substrings of the line. 22*2bbf68f4SSong Liu# -ffunction-sections and -fdata-sections give these symbols sections of their 23*2bbf68f4SSong Liu# own, and the section symbols -- .text.flipped_up, .data.flipped_down -- are 24*2bbf68f4SSong Liu# always LOCAL, so "does a LOCAL line mention flipped_up" is answered by the 25*2bbf68f4SSong Liu# wrong symbol. GNU readelf 2.35 happens to leave section symbol names blank, 26*2bbf68f4SSong Liu# but llvm-readelf prints them, and a premise that holds on one readelf and 27*2bbf68f4SSong Liu# not the other is no premise at all. 28*2bbf68f4SSong Liuhas_binding() # $1 object, $2 binding, $3 symbol 29*2bbf68f4SSong Liu{ 30*2bbf68f4SSong Liu in_symbols "$1" | awk -v b="$2" -v n="$3" '$5 == b && $NF == n' | grep -q . 31*2bbf68f4SSong Liu} 32*2bbf68f4SSong Liu 33*2bbf68f4SSong Liuhas_binding orig.o LOCAL flipped_up || 34*2bbf68f4SSong Liu fail "flipped_up is not local in the original" 35*2bbf68f4SSong Liuhas_binding patched.o GLOBAL flipped_up || 36*2bbf68f4SSong Liu fail "flipped_up is not global in the patched object" 37*2bbf68f4SSong Liuhas_binding orig.o GLOBAL flipped_down || 38*2bbf68f4SSong Liu fail "flipped_down is not global in the original" 39*2bbf68f4SSong Liuhas_binding patched.o LOCAL flipped_down || 40*2bbf68f4SSong Liu fail "flipped_down is not local in the patched object" 41*2bbf68f4SSong Liu 42*2bbf68f4SSong Liurun_diff 43*2bbf68f4SSong Liu 44*2bbf68f4SSong Liuassert_diff_log 'changed function: caller' 45*2bbf68f4SSong Liu 46*2bbf68f4SSong Liu# Correlated means each pairs with its own counterpart in the original, so the 47*2bbf68f4SSong Liu# patch refers back to the kernel's copy ... 48*2bbf68f4SSong Liuassert_klp_sym flipped_up vmlinux 49*2bbf68f4SSong Liuassert_klp_sym flipped_down vmlinux 50*2bbf68f4SSong Liu 51*2bbf68f4SSong Liu# ... rather than carrying its own. A second copy of flipped_down is the bad 52*2bbf68f4SSong Liu# outcome: patched code would update its private one while the rest of the 53*2bbf68f4SSong Liu# kernel keeps reading the original. 54*2bbf68f4SSong Liuassert_not_patched flipped_up 55*2bbf68f4SSong Liuassert_no_section .data.flipped_down 56*2bbf68f4SSong Liuassert_no_section .bss.flipped_down 57*2bbf68f4SSong Liu 58*2bbf68f4SSong Liudiff_log | grep -q 'no correlation' && 59*2bbf68f4SSong Liu fail "linkage change reported as an uncorrelated symbol" 60*2bbf68f4SSong Liudiff_log | grep -q 'changed data' && 61*2bbf68f4SSong Liu fail "linkage change reported as changed data" 62*2bbf68f4SSong Liu 63*2bbf68f4SSong Liupass "symbols correlated across a change of linkage" 64