xref: /linux/tools/objtool/tests/generic/test-switch-rodata.sh (revision 5b6dca02b3e2254d2fd5706d76d7ab4610a67296)
1*317cf7bbSSong Liu#!/bin/bash
2*317cf7bbSSong Liu# SPDX-License-Identifier: GPL-2.0
3*317cf7bbSSong Liu#
4*317cf7bbSSong Liu# A Clang switch jump table travels with the function it belongs to.
5*317cf7bbSSong Liu#
6*317cf7bbSSong Liu# For a dense enough switch Clang emits the targets as a table in
7*317cf7bbSSong Liu# .rodata..Lswitch.table.<function>, named after the function but not part of
8*317cf7bbSSong Liu# it.  klp diff has to associate the two: the patched function indexes into
9*317cf7bbSSong Liu# that table, so a clone which does not bring it along jumps through whatever
10*317cf7bbSSong Liu# the kernel's copy holds -- which, when the patch changed the switch, is the
11*317cf7bbSSong Liu# wrong set of targets.
12*317cf7bbSSong Liu#
13*317cf7bbSSong Liu# That is an indirect jump to a stale address, not a missing symbol, so nothing
14*317cf7bbSSong Liu# reports it at build or load time.
15*317cf7bbSSong Liu#
16*317cf7bbSSong Liu# objtool has no switch-specific code: the table is carried by the general
17*317cf7bbSSong Liu# mechanism for data a cloned function references.  So this is a regression
18*317cf7bbSSong Liu# test on that mechanism reaching a shape it is easy to get wrong, not a guard
19*317cf7bbSSong Liu# on a particular line -- making the table uncorrelated, the nearest sabotage,
20*317cf7bbSSong Liu# does not change the outcome.
21*317cf7bbSSong Liu#
22*317cf7bbSSong Liu# Covers the same ground as corpus/x86_64-llvm-switch-rodata/
23*317cf7bbSSong Liu# clang-switch-rodata-assoc in Joe Lawrence's klp-build unit test corpus.
24*317cf7bbSSong Liu
25*317cf7bbSSong Liu. "$(dirname "$0")/../lib.sh"
26*317cf7bbSSong Liu
27*317cf7bbSSong Liuclang_only "only Clang emits switch jump tables in their own section"
28*317cf7bbSSong Liu
29*317cf7bbSSong Liusetup
30*317cf7bbSSong Liubuild_pair switch_rodata.c
31*317cf7bbSSong Liu
32*317cf7bbSSong Liu# The premise: this Clang really did build a table rather than a chain of
33*317cf7bbSSong Liu# comparisons, and the added case really did change it.
34*317cf7bbSSong Liutbl=.rodata..Lswitch.table.status_to_string
35*317cf7bbSSong Liuhas_input_section orig.o "$tbl" ||
36*317cf7bbSSong Liu	probe_skip "this clang built no jump table for the switch"
37*317cf7bbSSong Liu# readelf prefixes each line with "[nn]", which splits into one or two fields
38*317cf7bbSSong Liu# depending on the index, so strip it before counting columns.
39*317cf7bbSSong Liutbl_size()
40*317cf7bbSSong Liu{
41*317cf7bbSSong Liu	in_sections "$1" | sed 's/^ *\[[ 0-9]*\] *//' |
42*317cf7bbSSong Liu		awk -v s="$tbl" '$1 == s { print $5 }'
43*317cf7bbSSong Liu}
44*317cf7bbSSong Liu[ "$(tbl_size orig.o)" != "$(tbl_size patched.o)" ] ||
45*317cf7bbSSong Liu	fail "fixture's added case did not change the jump table"
46*317cf7bbSSong Liu
47*317cf7bbSSong Liurun_diff
48*317cf7bbSSong Liu
49*317cf7bbSSong Liuassert_patched status_to_string
50*317cf7bbSSong Liuassert_section "$tbl"
51*317cf7bbSSong Liuassert_reloc_sym .text.status_to_string "$tbl"
52*317cf7bbSSong Liu
53*317cf7bbSSong Liupass "Clang switch jump table carried with the function it belongs to"
54