mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 06:24:43 +01:00
If a tracepoint is defined via DECLARE_TRACE() or TRACE_EVENT() but never called (via the trace_<tracepoint>() function), its metadata is still around in memory and not discarded. When created via TRACE_EVENT() the situation is worse because the TRACE_EVENT() creates metadata that can be around 5k per trace event. Having unused trace events causes several thousand of wasted bytes. Add a verifier that injects a string of the name of the tracepoint it calls that is added to the discarded section "__tracepoint_check". For every builtin tracepoint, its name (which is saved in the in-memory section "__tracepoint_strings") will have its name also in the "__tracepoint_check" section if it is used. Add a new program that is run on build called tracepoint-update. This is executed on the vmlinux.o before the __tracepoint_check section is discarded (the section is discarded before vmlinux is created). This program will create an array of each string in the __tracepoint_check section and then sort it. Then it will walk the strings in the __tracepoint_strings section and do a binary search to check if its name is in the __tracepoint_check section. If it is not, then it is unused and a warning is printed. Note, this currently only handles tracepoints that are builtin and not in modules. Enabling this currently with a given config produces: warning: tracepoint 'sched_move_numa' is unused. warning: tracepoint 'sched_stick_numa' is unused. warning: tracepoint 'sched_swap_numa' is unused. warning: tracepoint 'pelt_hw_tp' is unused. warning: tracepoint 'pelt_irq_tp' is unused. warning: tracepoint 'rcu_preempt_task' is unused. warning: tracepoint 'rcu_unlock_preempted_task' is unused. warning: tracepoint 'xdp_bulk_tx' is unused. warning: tracepoint 'xdp_redirect_map' is unused. warning: tracepoint 'xdp_redirect_map_err' is unused. warning: tracepoint 'vma_mas_szero' is unused. warning: tracepoint 'vma_store' is unused. warning: tracepoint 'hugepage_set_pmd' is unused. warning: tracepoint 'hugepage_set_pud' is unused. warning: tracepoint 'hugepage_update_pmd' is unused. warning: tracepoint 'hugepage_update_pud' is unused. warning: tracepoint 'block_rq_remap' is unused. warning: tracepoint 'xhci_dbc_handle_event' is unused. warning: tracepoint 'xhci_dbc_handle_transfer' is unused. warning: tracepoint 'xhci_dbc_gadget_ep_queue' is unused. warning: tracepoint 'xhci_dbc_alloc_request' is unused. warning: tracepoint 'xhci_dbc_free_request' is unused. warning: tracepoint 'xhci_dbc_queue_request' is unused. warning: tracepoint 'xhci_dbc_giveback_request' is unused. warning: tracepoint 'tcp_ao_wrong_maclen' is unused. warning: tracepoint 'tcp_ao_mismatch' is unused. warning: tracepoint 'tcp_ao_key_not_found' is unused. warning: tracepoint 'tcp_ao_rnext_request' is unused. warning: tracepoint 'tcp_ao_synack_no_key' is unused. warning: tracepoint 'tcp_ao_snd_sne_update' is unused. warning: tracepoint 'tcp_ao_rcv_sne_update' is unused. Some of the above is totally unused but others are not used due to their "trace_" functions being inside configs, in which case, the defined tracepoints should also be inside those same configs. Others are architecture specific but defined in generic code, where they should either be moved to the architecture or be surrounded by #ifdef for the architectures they are for. This tool could be updated to process modules in the future. I'd like to thank Mathieu Desnoyers for suggesting using strings instead of pointers, as using pointers in vmlinux.o required handling relocations and it required implementing almost a full feature linker to do so. To enable this check, run the build with: make UT=1 Note, when all the existing unused tracepoints are removed from the build, the "UT=1" will be removed and this will always be enabled when tracepoints are configured to warn on any new tracepoints. The reason this isn't always enabled now is because it will introduce a lot of warnings for the current unused tracepoints, and all bisects would end at this commit for those warnings. Link: https://lore.kernel.org/all/20250528114549.4d8a5e03@gandalf.local.home/ Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Masahiro Yamada <masahiroy@kernel.org> Cc: Nathan Chancellor <nathan@kernel.org> Cc: Nicolas Schier <nicolas.schier@linux.dev> Cc: Nick Desaulniers <nick.desaulniers+lkml@gmail.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Link: https://lore.kernel.org/20251022004452.920728129@kernel.org Suggested-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> # for using strings instead of pointers Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
321 lines
7.8 KiB
Bash
Executable file
321 lines
7.8 KiB
Bash
Executable file
#!/bin/sh
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
#
|
|
# link vmlinux
|
|
#
|
|
# vmlinux is linked from the objects in vmlinux.a and $(KBUILD_VMLINUX_LIBS).
|
|
# vmlinux.a contains objects that are linked unconditionally.
|
|
# $(KBUILD_VMLINUX_LIBS) are archives which are linked conditionally
|
|
# (not within --whole-archive), and do not require symbol indexes added.
|
|
#
|
|
# vmlinux
|
|
# ^
|
|
# |
|
|
# +--< vmlinux.a
|
|
# |
|
|
# +--< $(KBUILD_VMLINUX_LIBS)
|
|
# | +--< lib/lib.a + more
|
|
# |
|
|
# +-< ${kallsymso} (see description in KALLSYMS section)
|
|
#
|
|
# vmlinux version (uname -v) cannot be updated during normal
|
|
# descending-into-subdirs phase since we do not yet know if we need to
|
|
# update vmlinux.
|
|
# Therefore this step is delayed until just before final link of vmlinux.
|
|
#
|
|
# System.map is generated to document addresses of all kernel symbols
|
|
|
|
# Error out on error
|
|
set -e
|
|
|
|
LD="$1"
|
|
KBUILD_LDFLAGS="$2"
|
|
LDFLAGS_vmlinux="$3"
|
|
VMLINUX="$4"
|
|
|
|
is_enabled() {
|
|
grep -q "^$1=y" include/config/auto.conf
|
|
}
|
|
|
|
# Nice output in kbuild format
|
|
# Will be supressed by "make -s"
|
|
info()
|
|
{
|
|
printf " %-7s %s\n" "${1}" "${2}"
|
|
}
|
|
|
|
# Link of vmlinux
|
|
# ${1} - output file
|
|
vmlinux_link()
|
|
{
|
|
local output=${1}
|
|
local objs
|
|
local libs
|
|
local ld
|
|
local ldflags
|
|
local ldlibs
|
|
|
|
info LD ${output}
|
|
|
|
# skip output file argument
|
|
shift
|
|
|
|
if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then
|
|
# Use vmlinux.o instead of performing the slow LTO link again.
|
|
objs=vmlinux.o
|
|
libs=
|
|
else
|
|
objs=vmlinux.a
|
|
libs="${KBUILD_VMLINUX_LIBS}"
|
|
fi
|
|
|
|
if is_enabled CONFIG_GENERIC_BUILTIN_DTB; then
|
|
objs="${objs} .builtin-dtbs.o"
|
|
fi
|
|
|
|
objs="${objs} .vmlinux.export.o"
|
|
objs="${objs} init/version-timestamp.o"
|
|
|
|
if [ "${SRCARCH}" = "um" ]; then
|
|
wl=-Wl,
|
|
ld="${CC}"
|
|
ldflags="${CFLAGS_vmlinux}"
|
|
ldlibs="-lutil -lrt -lpthread"
|
|
else
|
|
wl=
|
|
ld="${LD}"
|
|
ldflags="${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux}"
|
|
ldlibs=
|
|
fi
|
|
|
|
ldflags="${ldflags} ${wl}--script=${objtree}/${KBUILD_LDS}"
|
|
|
|
# The kallsyms linking does not need debug symbols included.
|
|
if [ -n "${strip_debug}" ] ; then
|
|
ldflags="${ldflags} ${wl}--strip-debug"
|
|
fi
|
|
|
|
if [ -n "${generate_map}" ]; then
|
|
ldflags="${ldflags} ${wl}-Map=vmlinux.map"
|
|
fi
|
|
|
|
${ld} ${ldflags} -o ${output} \
|
|
${wl}--whole-archive ${objs} ${wl}--no-whole-archive \
|
|
${wl}--start-group ${libs} ${wl}--end-group \
|
|
${kallsymso} ${btf_vmlinux_bin_o} ${arch_vmlinux_o} ${ldlibs}
|
|
}
|
|
|
|
# generate .BTF typeinfo from DWARF debuginfo
|
|
# ${1} - vmlinux image
|
|
gen_btf()
|
|
{
|
|
local btf_data=${1}.btf.o
|
|
|
|
info BTF "${btf_data}"
|
|
LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1}
|
|
|
|
# Create ${btf_data} which contains just .BTF section but no symbols. Add
|
|
# SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all
|
|
# deletes all symbols including __start_BTF and __stop_BTF, which will
|
|
# be redefined in the linker script. Add 2>/dev/null to suppress GNU
|
|
# objcopy warnings: "empty loadable segment detected at ..."
|
|
${OBJCOPY} --only-section=.BTF --set-section-flags .BTF=alloc,readonly \
|
|
--strip-all ${1} "${btf_data}" 2>/dev/null
|
|
# Change e_type to ET_REL so that it can be used to link final vmlinux.
|
|
# GNU ld 2.35+ and lld do not allow an ET_EXEC input.
|
|
if is_enabled CONFIG_CPU_BIG_ENDIAN; then
|
|
et_rel='\0\1'
|
|
else
|
|
et_rel='\1\0'
|
|
fi
|
|
printf "${et_rel}" | dd of="${btf_data}" conv=notrunc bs=1 seek=16 status=none
|
|
|
|
btf_vmlinux_bin_o=${btf_data}
|
|
}
|
|
|
|
# Create ${2}.o file with all symbols from the ${1} object file
|
|
kallsyms()
|
|
{
|
|
local kallsymopt;
|
|
|
|
if is_enabled CONFIG_KALLSYMS_ALL; then
|
|
kallsymopt="${kallsymopt} --all-symbols"
|
|
fi
|
|
|
|
info KSYMS "${2}.S"
|
|
scripts/kallsyms ${kallsymopt} "${1}" > "${2}.S"
|
|
|
|
info AS "${2}.o"
|
|
${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} \
|
|
${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} -c -o "${2}.o" "${2}.S"
|
|
|
|
kallsymso=${2}.o
|
|
}
|
|
|
|
# Perform kallsyms for the given temporary vmlinux.
|
|
sysmap_and_kallsyms()
|
|
{
|
|
mksysmap "${1}" "${1}.syms"
|
|
kallsyms "${1}.syms" "${1}.kallsyms"
|
|
|
|
kallsyms_sysmap=${1}.syms
|
|
}
|
|
|
|
# Create map file with all symbols from ${1}
|
|
# See mksymap for additional details
|
|
mksysmap()
|
|
{
|
|
info NM ${2}
|
|
${NM} -n "${1}" | sed -f "${srctree}/scripts/mksysmap" > "${2}"
|
|
}
|
|
|
|
sorttable()
|
|
{
|
|
${NM} -S ${1} > .tmp_vmlinux.nm-sort
|
|
${objtree}/scripts/sorttable -s .tmp_vmlinux.nm-sort ${1}
|
|
}
|
|
|
|
cleanup()
|
|
{
|
|
rm -f .btf.*
|
|
rm -f .tmp_vmlinux.nm-sort
|
|
rm -f System.map
|
|
rm -f vmlinux
|
|
rm -f vmlinux.map
|
|
}
|
|
|
|
# Use "make V=1" to debug this script
|
|
case "${KBUILD_VERBOSE}" in
|
|
*1*)
|
|
set -x
|
|
;;
|
|
esac
|
|
|
|
if [ "$1" = "clean" ]; then
|
|
cleanup
|
|
exit 0
|
|
fi
|
|
|
|
${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init init/version-timestamp.o
|
|
|
|
arch_vmlinux_o=
|
|
if is_enabled CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX; then
|
|
arch_vmlinux_o=arch/${SRCARCH}/tools/vmlinux.arch.o
|
|
fi
|
|
|
|
btf_vmlinux_bin_o=
|
|
kallsymso=
|
|
strip_debug=
|
|
generate_map=
|
|
|
|
# Use "make UT=1" to trigger warnings on unused tracepoints
|
|
case "${WARN_ON_UNUSED_TRACEPOINTS}" in
|
|
*1*)
|
|
${objtree}/scripts/tracepoint-update vmlinux.o
|
|
;;
|
|
esac
|
|
|
|
if is_enabled CONFIG_KALLSYMS; then
|
|
true > .tmp_vmlinux0.syms
|
|
kallsyms .tmp_vmlinux0.syms .tmp_vmlinux0.kallsyms
|
|
fi
|
|
|
|
if is_enabled CONFIG_KALLSYMS || is_enabled CONFIG_DEBUG_INFO_BTF; then
|
|
|
|
# The kallsyms linking does not need debug symbols, but the BTF does.
|
|
if ! is_enabled CONFIG_DEBUG_INFO_BTF; then
|
|
strip_debug=1
|
|
fi
|
|
|
|
vmlinux_link .tmp_vmlinux1
|
|
fi
|
|
|
|
if is_enabled CONFIG_DEBUG_INFO_BTF; then
|
|
if ! gen_btf .tmp_vmlinux1; then
|
|
echo >&2 "Failed to generate BTF for vmlinux"
|
|
echo >&2 "Try to disable CONFIG_DEBUG_INFO_BTF"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if is_enabled CONFIG_KALLSYMS; then
|
|
|
|
# kallsyms support
|
|
# Generate section listing all symbols and add it into vmlinux
|
|
# It's a four step process:
|
|
# 0) Generate a dummy __kallsyms with empty symbol list.
|
|
# 1) Link .tmp_vmlinux1.kallsyms so it has all symbols and sections,
|
|
# with a dummy __kallsyms.
|
|
# Running kallsyms on that gives us .tmp_vmlinux1.kallsyms.o with
|
|
# the right size
|
|
# 2) Link .tmp_vmlinux2.kallsyms so it now has a __kallsyms section of
|
|
# the right size, but due to the added section, some
|
|
# addresses have shifted.
|
|
# From here, we generate a correct .tmp_vmlinux2.kallsyms.o
|
|
# 3) That link may have expanded the kernel image enough that
|
|
# more linker branch stubs / trampolines had to be added, which
|
|
# introduces new names, which further expands kallsyms. Do another
|
|
# pass if that is the case. In theory it's possible this results
|
|
# in even more stubs, but unlikely.
|
|
# KALLSYMS_EXTRA_PASS=1 may also used to debug or work around
|
|
# other bugs.
|
|
# 4) The correct ${kallsymso} is linked into the final vmlinux.
|
|
#
|
|
# a) Verify that the System.map from vmlinux matches the map from
|
|
# ${kallsymso}.
|
|
|
|
# The kallsyms linking does not need debug symbols included.
|
|
strip_debug=1
|
|
|
|
sysmap_and_kallsyms .tmp_vmlinux1
|
|
size1=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso})
|
|
|
|
vmlinux_link .tmp_vmlinux2
|
|
sysmap_and_kallsyms .tmp_vmlinux2
|
|
size2=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso})
|
|
|
|
if [ $size1 -ne $size2 ] || [ -n "${KALLSYMS_EXTRA_PASS}" ]; then
|
|
vmlinux_link .tmp_vmlinux3
|
|
sysmap_and_kallsyms .tmp_vmlinux3
|
|
fi
|
|
fi
|
|
|
|
strip_debug=
|
|
|
|
if is_enabled CONFIG_VMLINUX_MAP; then
|
|
generate_map=1
|
|
fi
|
|
|
|
vmlinux_link "${VMLINUX}"
|
|
|
|
# fill in BTF IDs
|
|
if is_enabled CONFIG_DEBUG_INFO_BTF; then
|
|
info BTFIDS "${VMLINUX}"
|
|
RESOLVE_BTFIDS_ARGS=""
|
|
if is_enabled CONFIG_WERROR; then
|
|
RESOLVE_BTFIDS_ARGS=" --fatal_warnings "
|
|
fi
|
|
${RESOLVE_BTFIDS} ${RESOLVE_BTFIDS_ARGS} "${VMLINUX}"
|
|
fi
|
|
|
|
mksysmap "${VMLINUX}" System.map
|
|
|
|
if is_enabled CONFIG_BUILDTIME_TABLE_SORT; then
|
|
info SORTTAB "${VMLINUX}"
|
|
if ! sorttable "${VMLINUX}"; then
|
|
echo >&2 Failed to sort kernel tables
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# step a (see comment above)
|
|
if is_enabled CONFIG_KALLSYMS; then
|
|
if ! cmp -s System.map "${kallsyms_sysmap}"; then
|
|
echo >&2 Inconsistent kallsyms data
|
|
echo >&2 'Try "make KALLSYMS_EXTRA_PASS=1" as a workaround'
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# For fixdep
|
|
echo "${VMLINUX}: $0" > ".${VMLINUX}.d"
|