mirror of
https://github.com/torvalds/linux.git
synced 2024-12-06 11:01:43 +00:00
22922deae1
- Comprehensive interface overhaul: ================================= Objtool's interface has some issues: - Several features are done unconditionally, without any way to turn them off. Some of them might be surprising. This makes objtool tricky to use, and prevents porting individual features to other arches. - The config dependencies are too coarse-grained. Objtool enablement is tied to CONFIG_STACK_VALIDATION, but it has several other features independent of that. - The objtool subcmds ("check" and "orc") are clumsy: "check" is really a subset of "orc", so it has all the same options. The subcmd model has never really worked for objtool, as it only has a single purpose: "do some combination of things on an object file". - The '--lto' and '--vmlinux' options are nonsensical and have surprising behavior. Overhaul the interface: - get rid of subcmds - make all features individually selectable - remove and/or clarify confusing/obsolete options - update the documentation - fix some bugs found along the way - Fix x32 regression - Fix Kbuild cleanup bugs - Add scripts/objdump-func helper script to disassemble a single function from an object file. - Rewrite scripts/faddr2line to be section-aware, by basing it on 'readelf', moving it away from 'nm', which doesn't handle multiple sections well, which can result in decoding failure. - Rewrite & fix symbol handling - which had a number of bugs wrt. object files that don't have global symbols - which is rare but possible. Also fix a bunch of symbol handling bugs found along the way. Signed-off-by: Ingo Molnar <mingo@kernel.org> -----BEGIN PGP SIGNATURE----- iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmKLtcURHG1pbmdvQGtl cm5lbC5vcmcACgkQEnMQ0APhK1jVQg//QM8nCNadJAVS9exVGX1DZI9pnf3OJaA9 gOFML7Lv3MC+Lwdxt6Iv020rFVaeAnOcjPsis3dppFz62FZzzMWoemn5irg2BFiJ dp++UtJWTfKxgU2BHydU9uXD0kcJkD4AjBCIaFsgmTjAz8QvMGa9j0smuUm3cDSL 0Bdid+LhkQqW3P2FiLWsSAzh4vqZmdwpXgERZRql8qD3NYk5hV4QDKs3gMguktat 9gos4kGt0uwKfiEvmeNEXkoAwUsTvE/vqaOy9cVxxCqcWrrC+yQeBpwSoqhHK526 dyHlwlYvBaPFqZnmquVUv21iv1MU6dUBJPhNIChke0NDTwVzSXdI75207FARyk5J 3igSFEfJcU9zMvhAAsAjzD/uQP2ATowg5qa/V2xyWwtyaRgBleRffYiDsbhgDoNc R4/vI+vn/fQXouMhmmjPNYzu9uHQ+k89wQCJIY8Bswf7oNu6nKL3jJb/a/a7xhsH ZNqv+M0KEENTZcjBU2UHGyImApmkTlsp2mxUiiHs7QoV1hTfz+TcTXKPM1mIuJB8 /HrVpv64CZ3S7p4JyGBUTNpci4mBjgBmwwAf16+dtaxyxxfoqReVWh3+bzsZbH+B kRjezWHh7/yCsoyDm7/LPgyPKEbozLLzMsTsjVJeWgeTgZ+xuqku3PTVctyzAI21 DVL5oZe3iK4= =ARdm -----END PGP SIGNATURE----- Merge tag 'objtool-core-2022-05-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull objtool updates from Ingo Molnar: - Comprehensive interface overhaul: ================================= Objtool's interface has some issues: - Several features are done unconditionally, without any way to turn them off. Some of them might be surprising. This makes objtool tricky to use, and prevents porting individual features to other arches. - The config dependencies are too coarse-grained. Objtool enablement is tied to CONFIG_STACK_VALIDATION, but it has several other features independent of that. - The objtool subcmds ("check" and "orc") are clumsy: "check" is really a subset of "orc", so it has all the same options. The subcmd model has never really worked for objtool, as it only has a single purpose: "do some combination of things on an object file". - The '--lto' and '--vmlinux' options are nonsensical and have surprising behavior. Overhaul the interface: - get rid of subcmds - make all features individually selectable - remove and/or clarify confusing/obsolete options - update the documentation - fix some bugs found along the way - Fix x32 regression - Fix Kbuild cleanup bugs - Add scripts/objdump-func helper script to disassemble a single function from an object file. - Rewrite scripts/faddr2line to be section-aware, by basing it on 'readelf', moving it away from 'nm', which doesn't handle multiple sections well, which can result in decoding failure. - Rewrite & fix symbol handling - which had a number of bugs wrt. object files that don't have global symbols - which is rare but possible. Also fix a bunch of symbol handling bugs found along the way. * tag 'objtool-core-2022-05-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (23 commits) objtool: Fix objtool regression on x32 systems objtool: Fix symbol creation scripts/faddr2line: Fix overlapping text section failures scripts: Create objdump-func helper script objtool: Remove libsubcmd.a when make clean objtool: Remove inat-tables.c when make clean objtool: Update documentation objtool: Remove --lto and --vmlinux in favor of --link objtool: Add HAVE_NOINSTR_VALIDATION objtool: Rename "VMLINUX_VALIDATION" -> "NOINSTR_VALIDATION" objtool: Make noinstr hacks optional objtool: Make jump label hack optional objtool: Make static call annotation optional objtool: Make stack validation frame-pointer-specific objtool: Add CONFIG_OBJTOOL objtool: Extricate sls from stack validation objtool: Rework ibt and extricate from stack validation objtool: Make stack validation optional objtool: Add option to print section addresses objtool: Don't print parentheses in function addresses ...
453 lines
11 KiB
Bash
Executable File
453 lines
11 KiB
Bash
Executable File
#!/bin/sh
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
#
|
|
# link vmlinux
|
|
#
|
|
# vmlinux is linked from the objects selected by $(KBUILD_VMLINUX_OBJS) and
|
|
# $(KBUILD_VMLINUX_LIBS). Most are built-in.a files from top-level directories
|
|
# in the kernel tree, others are specified in arch/$(ARCH)/Makefile.
|
|
# $(KBUILD_VMLINUX_LIBS) are archives which are linked conditionally
|
|
# (not within --whole-archive), and do not require symbol indexes added.
|
|
#
|
|
# vmlinux
|
|
# ^
|
|
# |
|
|
# +--< $(KBUILD_VMLINUX_OBJS)
|
|
# | +--< init/built-in.a drivers/built-in.a mm/built-in.a + more
|
|
# |
|
|
# +--< $(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"
|
|
|
|
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}"
|
|
}
|
|
|
|
# Generate a linker script to ensure correct ordering of initcalls.
|
|
gen_initcalls()
|
|
{
|
|
info GEN .tmp_initcalls.lds
|
|
|
|
${PYTHON3} ${srctree}/scripts/jobserver-exec \
|
|
${PERL} ${srctree}/scripts/generate_initcall_order.pl \
|
|
${KBUILD_VMLINUX_OBJS} ${KBUILD_VMLINUX_LIBS} \
|
|
> .tmp_initcalls.lds
|
|
}
|
|
|
|
# If CONFIG_LTO_CLANG is selected, collect generated symbol versions into
|
|
# .tmp_symversions.lds
|
|
gen_symversions()
|
|
{
|
|
info GEN .tmp_symversions.lds
|
|
rm -f .tmp_symversions.lds
|
|
|
|
for o in ${KBUILD_VMLINUX_OBJS} ${KBUILD_VMLINUX_LIBS}; do
|
|
if [ -f ${o}.symversions ]; then
|
|
cat ${o}.symversions >> .tmp_symversions.lds
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Link of vmlinux.o used for section mismatch analysis
|
|
# ${1} output file
|
|
modpost_link()
|
|
{
|
|
local objects
|
|
local lds=""
|
|
|
|
objects="--whole-archive \
|
|
${KBUILD_VMLINUX_OBJS} \
|
|
--no-whole-archive \
|
|
--start-group \
|
|
${KBUILD_VMLINUX_LIBS} \
|
|
--end-group"
|
|
|
|
if is_enabled CONFIG_LTO_CLANG; then
|
|
gen_initcalls
|
|
lds="-T .tmp_initcalls.lds"
|
|
|
|
if is_enabled CONFIG_MODVERSIONS; then
|
|
gen_symversions
|
|
lds="${lds} -T .tmp_symversions.lds"
|
|
fi
|
|
|
|
# This might take a while, so indicate that we're doing
|
|
# an LTO link
|
|
info LTO ${1}
|
|
else
|
|
info LD ${1}
|
|
fi
|
|
|
|
${LD} ${KBUILD_LDFLAGS} -r -o ${1} ${lds} ${objects}
|
|
}
|
|
|
|
objtool_link()
|
|
{
|
|
local objtoolcmd;
|
|
local objtoolopt;
|
|
|
|
if ! is_enabled CONFIG_OBJTOOL; then
|
|
return;
|
|
fi
|
|
|
|
if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then
|
|
|
|
# For LTO and IBT, objtool doesn't run on individual
|
|
# translation units. Run everything on vmlinux instead.
|
|
|
|
if is_enabled CONFIG_HAVE_JUMP_LABEL_HACK; then
|
|
objtoolopt="${objtoolopt} --hacks=jump_label"
|
|
fi
|
|
|
|
if is_enabled CONFIG_HAVE_NOINSTR_HACK; then
|
|
objtoolopt="${objtoolopt} --hacks=noinstr"
|
|
fi
|
|
|
|
if is_enabled CONFIG_X86_KERNEL_IBT; then
|
|
objtoolopt="${objtoolopt} --ibt"
|
|
fi
|
|
|
|
if is_enabled CONFIG_FTRACE_MCOUNT_USE_OBJTOOL; then
|
|
objtoolopt="${objtoolopt} --mcount"
|
|
fi
|
|
|
|
if is_enabled CONFIG_UNWINDER_ORC; then
|
|
objtoolopt="${objtoolopt} --orc"
|
|
fi
|
|
|
|
if is_enabled CONFIG_RETPOLINE; then
|
|
objtoolopt="${objtoolopt} --retpoline"
|
|
fi
|
|
|
|
if is_enabled CONFIG_SLS; then
|
|
objtoolopt="${objtoolopt} --sls"
|
|
fi
|
|
|
|
if is_enabled CONFIG_STACK_VALIDATION; then
|
|
objtoolopt="${objtoolopt} --stackval"
|
|
fi
|
|
|
|
if is_enabled CONFIG_HAVE_STATIC_CALL_INLINE; then
|
|
objtoolopt="${objtoolopt} --static-call"
|
|
fi
|
|
|
|
objtoolopt="${objtoolopt} --uaccess"
|
|
fi
|
|
|
|
if is_enabled CONFIG_NOINSTR_VALIDATION; then
|
|
objtoolopt="${objtoolopt} --noinstr"
|
|
fi
|
|
|
|
if [ -n "${objtoolopt}" ]; then
|
|
|
|
if is_enabled CONFIG_GCOV_KERNEL; then
|
|
objtoolopt="${objtoolopt} --no-unreachable"
|
|
fi
|
|
|
|
objtoolopt="${objtoolopt} --link"
|
|
|
|
info OBJTOOL ${1}
|
|
tools/objtool/objtool ${objtoolopt} ${1}
|
|
fi
|
|
}
|
|
|
|
# Link of vmlinux
|
|
# ${1} - output file
|
|
# ${2}, ${3}, ... - optional extra .o files
|
|
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="${KBUILD_VMLINUX_OBJS}"
|
|
libs="${KBUILD_VMLINUX_LIBS}"
|
|
fi
|
|
|
|
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 [ "$output" != "${output#.tmp_vmlinux.kallsyms}" ] ; then
|
|
ldflags="${ldflags} ${wl}--strip-debug"
|
|
fi
|
|
|
|
if is_enabled CONFIG_VMLINUX_MAP; then
|
|
ldflags="${ldflags} ${wl}-Map=${output}.map"
|
|
fi
|
|
|
|
${ld} ${ldflags} -o ${output} \
|
|
${wl}--whole-archive ${objs} ${wl}--no-whole-archive \
|
|
${wl}--start-group ${libs} ${wl}--end-group \
|
|
$@ ${ldlibs}
|
|
}
|
|
|
|
# generate .BTF typeinfo from DWARF debuginfo
|
|
# ${1} - vmlinux image
|
|
# ${2} - file to dump raw BTF data into
|
|
gen_btf()
|
|
{
|
|
local pahole_ver
|
|
|
|
if ! [ -x "$(command -v ${PAHOLE})" ]; then
|
|
echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available"
|
|
return 1
|
|
fi
|
|
|
|
pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/')
|
|
if [ "${pahole_ver}" -lt "116" ]; then
|
|
echo >&2 "BTF: ${1}: pahole version $(${PAHOLE} --version) is too old, need at least v1.16"
|
|
return 1
|
|
fi
|
|
|
|
vmlinux_link ${1}
|
|
|
|
info "BTF" ${2}
|
|
LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1}
|
|
|
|
# Create ${2} 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} ${2} 2>/dev/null
|
|
# Change e_type to ET_REL so that it can be used to link final vmlinux.
|
|
# Unlike GNU ld, lld does not allow an ET_EXEC input.
|
|
printf '\1' | dd of=${2} conv=notrunc bs=1 seek=16 status=none
|
|
}
|
|
|
|
# Create ${2} .S file with all symbols from the ${1} object file
|
|
kallsyms()
|
|
{
|
|
local kallsymopt;
|
|
|
|
if is_enabled CONFIG_KALLSYMS_ALL; then
|
|
kallsymopt="${kallsymopt} --all-symbols"
|
|
fi
|
|
|
|
if is_enabled CONFIG_KALLSYMS_ABSOLUTE_PERCPU; then
|
|
kallsymopt="${kallsymopt} --absolute-percpu"
|
|
fi
|
|
|
|
if is_enabled CONFIG_KALLSYMS_BASE_RELATIVE; then
|
|
kallsymopt="${kallsymopt} --base-relative"
|
|
fi
|
|
|
|
info KSYMS ${2}
|
|
${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${2}
|
|
}
|
|
|
|
# Perform one step in kallsyms generation, including temporary linking of
|
|
# vmlinux.
|
|
kallsyms_step()
|
|
{
|
|
kallsymso_prev=${kallsymso}
|
|
kallsyms_vmlinux=.tmp_vmlinux.kallsyms${1}
|
|
kallsymso=${kallsyms_vmlinux}.o
|
|
kallsyms_S=${kallsyms_vmlinux}.S
|
|
|
|
vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o}
|
|
kallsyms ${kallsyms_vmlinux} ${kallsyms_S}
|
|
|
|
info AS ${kallsyms_S}
|
|
${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} \
|
|
${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
|
|
-c -o ${kallsymso} ${kallsyms_S}
|
|
}
|
|
|
|
# Create map file with all symbols from ${1}
|
|
# See mksymap for additional details
|
|
mksysmap()
|
|
{
|
|
${CONFIG_SHELL} "${srctree}/scripts/mksysmap" ${1} ${2}
|
|
}
|
|
|
|
sorttable()
|
|
{
|
|
${objtree}/scripts/sorttable ${1}
|
|
}
|
|
|
|
# Delete output files in case of error
|
|
cleanup()
|
|
{
|
|
rm -f .btf.*
|
|
rm -f .tmp_System.map
|
|
rm -f .tmp_initcalls.lds
|
|
rm -f .tmp_symversions.lds
|
|
rm -f .tmp_vmlinux*
|
|
rm -f System.map
|
|
rm -f vmlinux
|
|
rm -f vmlinux.map
|
|
rm -f vmlinux.o
|
|
rm -f .vmlinux.d
|
|
}
|
|
|
|
# Use "make V=1" to debug this script
|
|
case "${KBUILD_VERBOSE}" in
|
|
*1*)
|
|
set -x
|
|
;;
|
|
esac
|
|
|
|
if [ "$1" = "clean" ]; then
|
|
cleanup
|
|
exit 0
|
|
fi
|
|
|
|
# Update version
|
|
info GEN .version
|
|
if [ -r .version ]; then
|
|
VERSION=$(expr 0$(cat .version) + 1)
|
|
echo $VERSION > .version
|
|
else
|
|
rm -f .version
|
|
echo 1 > .version
|
|
fi;
|
|
|
|
# final build of init/
|
|
${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init need-builtin=1
|
|
|
|
#link vmlinux.o
|
|
modpost_link vmlinux.o
|
|
objtool_link vmlinux.o
|
|
|
|
# modpost vmlinux.o to check for section mismatches
|
|
${MAKE} -f "${srctree}/scripts/Makefile.modpost" MODPOST_VMLINUX=1
|
|
|
|
info MODINFO modules.builtin.modinfo
|
|
${OBJCOPY} -j .modinfo -O binary vmlinux.o modules.builtin.modinfo
|
|
info GEN modules.builtin
|
|
# The second line aids cases where multiple modules share the same object.
|
|
tr '\0' '\n' < modules.builtin.modinfo | sed -n 's/^[[:alnum:]:_]*\.file=//p' |
|
|
tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$/.ko/' > modules.builtin
|
|
|
|
btf_vmlinux_bin_o=""
|
|
if is_enabled CONFIG_DEBUG_INFO_BTF; then
|
|
btf_vmlinux_bin_o=.btf.vmlinux.bin.o
|
|
if ! gen_btf .tmp_vmlinux.btf $btf_vmlinux_bin_o ; then
|
|
echo >&2 "Failed to generate BTF for vmlinux"
|
|
echo >&2 "Try to disable CONFIG_DEBUG_INFO_BTF"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
kallsymso=""
|
|
kallsymso_prev=""
|
|
kallsyms_vmlinux=""
|
|
if is_enabled CONFIG_KALLSYMS; then
|
|
|
|
# kallsyms support
|
|
# Generate section listing all symbols and add it into vmlinux
|
|
# It's a three step process:
|
|
# 1) Link .tmp_vmlinux.kallsyms1 so it has all symbols and sections,
|
|
# but __kallsyms is empty.
|
|
# Running kallsyms on that gives us .tmp_kallsyms1.o with
|
|
# the right size
|
|
# 2) Link .tmp_vmlinux.kallsyms2 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_vmlinux.kallsyms2.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}.
|
|
|
|
kallsyms_step 1
|
|
kallsyms_step 2
|
|
|
|
# step 3
|
|
size1=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso_prev})
|
|
size2=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" ${kallsymso})
|
|
|
|
if [ $size1 -ne $size2 ] || [ -n "${KALLSYMS_EXTRA_PASS}" ]; then
|
|
kallsyms_step 3
|
|
fi
|
|
fi
|
|
|
|
vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o}
|
|
|
|
# fill in BTF IDs
|
|
if is_enabled CONFIG_DEBUG_INFO_BTF && is_enabled CONFIG_BPF; then
|
|
info BTFIDS vmlinux
|
|
${RESOLVE_BTFIDS} vmlinux
|
|
fi
|
|
|
|
info SYSMAP System.map
|
|
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
|
|
mksysmap ${kallsyms_vmlinux} .tmp_System.map
|
|
|
|
if ! cmp -s System.map .tmp_System.map; 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
|