Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libbpf: Verify versioned symbols

Since ABI versioning info is kept separately from the code it's easy to
forget to update it while adding a new API.

Add simple verification that all global symbols exported with LIBBPF_API
are versioned in libbpf.map version script.

The idea is to check that number of global symbols in libbpf-in.o, that
is the input to the linker, matches with number of unique versioned
symbols in libbpf.so, that is the output of the linker. If these numbers
don't match, it may mean some symbol was not versioned and make will
fail.

"Unique" means that if a symbol is present in more than one version of
ABI due to ABI changes, it'll be counted once.

Another option to calculate number of global symbols in the "input"
could be to count number of LIBBPF_ABI entries in C headers but it seems
to be fragile.

Example of output when a symbol is missing in version script:

...
LD libbpf-in.o
LINK libbpf.a
LINK libbpf.so
Warning: Num of global symbols in libbpf-in.o (115) does NOT match
with num of versioned symbols in libbpf.so (114). Please make sure all
LIBBPF_API symbols are versioned in libbpf.map.
make: *** [check_abi] Error 1

Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Andrey Ignatov and committed by
Alexei Starovoitov
306b267c 16192a77

+18 -1
+18 -1
tools/lib/bpf/Makefile
··· 147 147 LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) 148 148 VERSION_SCRIPT := libbpf.map 149 149 150 + GLOBAL_SYM_COUNT = $(shell readelf -s $(BPF_IN) | \ 151 + awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {s++} END{print s}') 152 + VERSIONED_SYM_COUNT = $(shell readelf -s $(OUTPUT)libbpf.so | \ 153 + grep -Eo '[^ ]+@LIBBPF_' | cut -d@ -f1 | sort -u | wc -l) 154 + 150 155 CMD_TARGETS = $(LIB_FILE) 151 156 152 157 CXX_TEST_TARGET = $(OUTPUT)test_libbpf ··· 164 159 165 160 all: fixdep all_cmd 166 161 167 - all_cmd: $(CMD_TARGETS) 162 + all_cmd: $(CMD_TARGETS) check 168 163 169 164 $(BPF_IN): force elfdep bpfdep 170 165 @(test -f ../../include/uapi/linux/bpf.h -a -f ../../../include/uapi/linux/bpf.h && ( \ ··· 190 185 191 186 $(OUTPUT)test_libbpf: test_libbpf.cpp $(OUTPUT)libbpf.a 192 187 $(QUIET_LINK)$(CXX) $^ -lelf -o $@ 188 + 189 + check: check_abi 190 + 191 + check_abi: $(OUTPUT)libbpf.so 192 + @if [ "$(GLOBAL_SYM_COUNT)" != "$(VERSIONED_SYM_COUNT)" ]; then \ 193 + echo "Warning: Num of global symbols in $(BPF_IN)" \ 194 + "($(GLOBAL_SYM_COUNT)) does NOT match with num of" \ 195 + "versioned symbols in $^ ($(VERSIONED_SYM_COUNT))." \ 196 + "Please make sure all LIBBPF_API symbols are" \ 197 + "versioned in $(VERSION_SCRIPT)." >&2; \ 198 + exit 1; \ 199 + fi 193 200 194 201 define do_install 195 202 if [ ! -d '$(DESTDIR_SQ)$2' ]; then \