History

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 ...

Linus Torvalds committed 4 years ago

Commit 22922de2 parents 2319be1 22682a034 files · +955 −683Browse files

Showing the changes to scripts (5 of 34 files). Show all

Unified · Split

5 files
  1. scripts/Makefile.build +14 −9
  2. scripts/faddr2line +97 −53
  3. scripts/link-vmlinux.sh +39 −23
  4. scripts/objdump-func +29 −0
  5. scripts/package/builddeb +1 −1
scripts/Makefile.build+14−9
@@ -222,25 +222,29 @@ cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)), · 221 unmodified lines
222222 $(sub_cmd_record_mcount))
223223 endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT
224224
225−ifdef CONFIG_STACK_VALIDATION
225+ifdef CONFIG_OBJTOOL
226226
227227 objtool := $(objtree)/tools/objtool/objtool
228228
229229 objtool_args = \
230− $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \
231− $(if $(part-of-module), --module) \
232− $(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \
233− $(if $(CONFIG_FRAME_POINTER),, --no-fp) \
234− $(if $(CONFIG_GCOV_KERNEL), --no-unreachable) \
230+ $(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label) \
231+ $(if $(CONFIG_HAVE_NOINSTR_HACK), --hacks=noinstr) \
232+ $(if $(CONFIG_X86_KERNEL_IBT), --ibt) \
233+ $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
234+ $(if $(CONFIG_UNWINDER_ORC), --orc) \
235235 $(if $(CONFIG_RETPOLINE), --retpoline) \
236+ $(if $(CONFIG_SLS), --sls) \
237+ $(if $(CONFIG_STACK_VALIDATION), --stackval) \
238+ $(if $(CONFIG_HAVE_STATIC_CALL_INLINE), --static-call) \
236239 --uaccess \
237− $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
238− $(if $(CONFIG_SLS), --sls)
240+ $(if $(linked-object), --link) \
241+ $(if $(part-of-module), --module) \
242+ $(if $(CONFIG_GCOV_KERNEL), --no-unreachable)
239243
240244 cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@)
241245 cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd)
242246
243−endif # CONFIG_STACK_VALIDATION
247+endif # CONFIG_OBJTOOL
244248
245249 ifneq ($(CONFIG_LTO_CLANG)$(CONFIG_X86_KERNEL_IBT),)
246250
@@ -303,6 +307,7 @@ quiet_cmd_cc_prelink_modules = LD [M] $@ · 56 unmodified lines
303307 # modules into native code
304308 $(obj)/%.prelink.o: objtool-enabled = y
305309 $(obj)/%.prelink.o: part-of-module := y
310+$(obj)/%.prelink.o: linked-object := y
306311
307312 $(obj)/%.prelink.o: $(obj)/%.o FORCE
308313 $(call if_changed,cc_prelink_modules)
scripts/faddr2line+97−53
@@ -44,17 +44,6 @@ · 43 unmodified lines
4444 set -o errexit
4545 set -o nounset
4646
47−READELF="${CROSS_COMPILE:-}readelf"
48−ADDR2LINE="${CROSS_COMPILE:-}addr2line"
49−SIZE="${CROSS_COMPILE:-}size"
50−NM="${CROSS_COMPILE:-}nm"
51−
52−command -v awk >/dev/null 2>&1 || die "awk isn't installed"
53−command -v ${READELF} >/dev/null 2>&1 || die "readelf isn't installed"
54−command -v ${ADDR2LINE} >/dev/null 2>&1 || die "addr2line isn't installed"
55−command -v ${SIZE} >/dev/null 2>&1 || die "size isn't installed"
56−command -v ${NM} >/dev/null 2>&1 || die "nm isn't installed"
57−
5847 usage() {
5948 echo "usage: faddr2line [--list] <object file> <func+offset> <func+offset>..." >&2
6049 exit 1
@@ -69,6 +58,14 @@ die() { · 8 unmodified lines
6958 exit 1
7059 }
7160
61+READELF="${CROSS_COMPILE:-}readelf"
62+ADDR2LINE="${CROSS_COMPILE:-}addr2line"
63+AWK="awk"
64+
65+command -v ${AWK} >/dev/null 2>&1 || die "${AWK} isn't installed"
66+command -v ${READELF} >/dev/null 2>&1 || die "${READELF} isn't installed"
67+command -v ${ADDR2LINE} >/dev/null 2>&1 || die "${ADDR2LINE} isn't installed"
68+
7269 # Try to figure out the source directory prefix so we can remove it from the
7370 # addr2line output. HACK ALERT: This assumes that start_kernel() is in
7471 # init/main.c! This only works for vmlinux. Otherwise it falls back to
@@ -76,7 +73,7 @@ die() { · 1 unmodified line
7673 find_dir_prefix() {
7774 local objfile=$1
7875
79− local start_kernel_addr=$(${READELF} -sW $objfile | awk '$8 == "start_kernel" {printf "0x%s", $2}')
76+ local start_kernel_addr=$(${READELF} --symbols --wide $objfile | ${AWK} '$8 == "start_kernel" {printf "0x%s", $2}')
8077 [[ -z $start_kernel_addr ]] && return
8178
8279 local file_line=$(${ADDR2LINE} -e $objfile $start_kernel_addr)
@@ -97,86 +94,133 @@ __faddr2line() { · 14 unmodified lines
9794 local dir_prefix=$3
9895 local print_warnings=$4
9996
100− local func=${func_addr%+*}
97+ local sym_name=${func_addr%+*}
10198 local offset=${func_addr#*+}
10299 offset=${offset%/*}
103− local size=
104− [[ $func_addr =~ "/" ]] && size=${func_addr#*/}
100+ local user_size=
101+ [[ $func_addr =~ "/" ]] && user_size=${func_addr#*/}
105102
106− if [[ -z $func ]] || [[ -z $offset ]] || [[ $func = $func_addr ]]; then
103+ if [[ -z $sym_name ]] || [[ -z $offset ]] || [[ $sym_name = $func_addr ]]; then
107104 warn "bad func+offset $func_addr"
108105 DONE=1
109106 return
110107 fi
111108
112109 # Go through each of the object's symbols which match the func name.
113− # In rare cases there might be duplicates.
114− file_end=$(${SIZE} -Ax $objfile | awk '$1 == ".text" {print $2}')
115− while read symbol; do
116− local fields=($symbol)
117− local sym_base=0x${fields[0]}
118− local sym_type=${fields[1]}
119− local sym_end=${fields[3]}
120−
121− # calculate the size
122− local sym_size=$(($sym_end - $sym_base))
110+ # In rare cases there might be duplicates, in which case we print all
111+ # matches.
112+ while read line; do
113+ local fields=($line)
114+ local sym_addr=0x${fields[1]}
115+ local sym_elf_size=${fields[2]}
116+ local sym_sec=${fields[6]}
117+
118+ # Get the section size:
119+ local sec_size=$(${READELF} --section-headers --wide $objfile |
120+ sed 's/\[ /\[/' |
121+ ${AWK} -v sec=$sym_sec '$1 == "[" sec "]" { print "0x" $6; exit }')
122+
123+ if [[ -z $sec_size ]]; then
124+ warn "bad section size: section: $sym_sec"
125+ DONE=1
126+ return
127+ fi
128+
129+ # Calculate the symbol size.
130+ #
131+ # Unfortunately we can't use the ELF size, because kallsyms
132+ # also includes the padding bytes in its size calculation. For
133+ # kallsyms, the size calculation is the distance between the
134+ # symbol and the next symbol in a sorted list.
135+ local sym_size
136+ local cur_sym_addr
137+ local found=0
138+ while read line; do
139+ local fields=($line)
140+ cur_sym_addr=0x${fields[1]}
141+ local cur_sym_elf_size=${fields[2]}
142+ local cur_sym_name=${fields[7]:-}
143+
144+ if [[ $cur_sym_addr = $sym_addr ]] &&
145+ [[ $cur_sym_elf_size = $sym_elf_size ]] &&
146+ [[ $cur_sym_name = $sym_name ]]; then
147+ found=1
148+ continue
149+ fi
150+
151+ if [[ $found = 1 ]]; then
152+ sym_size=$(($cur_sym_addr - $sym_addr))
153+ [[ $sym_size -lt $sym_elf_size ]] && continue;
154+ found=2
155+ break
156+ fi
157+ done < <(${READELF} --symbols --wide $objfile | ${AWK} -v sec=$sym_sec '$7 == sec' | sort --key=2)
158+
159+ if [[ $found = 0 ]]; then
160+ warn "can't find symbol: sym_name: $sym_name sym_sec: $sym_sec sym_addr: $sym_addr sym_elf_size: $sym_elf_size"
161+ DONE=1
162+ return
163+ fi
164+
165+ # If nothing was found after the symbol, assume it's the last
166+ # symbol in the section.
167+ [[ $found = 1 ]] && sym_size=$(($sec_size - $sym_addr))
168+
123169 if [[ -z $sym_size ]] || [[ $sym_size -le 0 ]]; then
124− warn "bad symbol size: base: $sym_base end: $sym_end"
170+ warn "bad symbol size: sym_addr: $sym_addr cur_sym_addr: $cur_sym_addr"
125171 DONE=1
126172 return
127173 fi
174+
128175 sym_size=0x$(printf %x $sym_size)
129176
130− # calculate the address
131− local addr=$(($sym_base + $offset))
177+ # Calculate the section address from user-supplied offset:
178+ local addr=$(($sym_addr + $offset))
132179 if [[ -z $addr ]] || [[ $addr = 0 ]]; then
133− warn "bad address: $sym_base + $offset"
180+ warn "bad address: $sym_addr + $offset"
134181 DONE=1
135182 return
136183 fi
137184 addr=0x$(printf %x $addr)
138185
139− # weed out non-function symbols
140− if [[ $sym_type != t ]] && [[ $sym_type != T ]]; then
141− [[ $print_warnings = 1 ]] &&
142− echo "skipping $func address at $addr due to non-function symbol of type '$sym_type'"
143− continue
144− fi
145−
146− # if the user provided a size, make sure it matches the symbol's size
147− if [[ -n $size ]] && [[ $size -ne $sym_size ]]; then
186+ # If the user provided a size, make sure it matches the symbol's size:
187+ if [[ -n $user_size ]] && [[ $user_size -ne $sym_size ]]; then
148188 [[ $print_warnings = 1 ]] &&
149− echo "skipping $func address at $addr due to size mismatch ($size != $sym_size)"
189+ echo "skipping $sym_name address at $addr due to size mismatch ($user_size != $sym_size)"
150190 continue;
151191 fi
152192
153− # make sure the provided offset is within the symbol's range
193+ # Make sure the provided offset is within the symbol's range:
154194 if [[ $offset -gt $sym_size ]]; then
155195 [[ $print_warnings = 1 ]] &&
156− echo "skipping $func address at $addr due to size mismatch ($offset > $sym_size)"
196+ echo "skipping $sym_name address at $addr due to size mismatch ($offset > $sym_size)"
157197 continue
158198 fi
159199
160− # separate multiple entries with a blank line
200+ # In case of duplicates or multiple addresses specified on the
201+ # cmdline, separate multiple entries with a blank line:
161202 [[ $FIRST = 0 ]] && echo
162203 FIRST=0
163204
164− # pass real address to addr2line
165− echo "$func+$offset/$sym_size:"
166− local file_lines=$(${ADDR2LINE} -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;")
167− [[ -z $file_lines ]] && return
205+ echo "$sym_name+$offset/$sym_size:"
168206
207+ # Pass section address to addr2line and strip absolute paths
208+ # from the output:
209+ local output=$(${ADDR2LINE} -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;")
210+ [[ -z $output ]] && continue
211+
212+ # Default output (non --list):
169213 if [[ $LIST = 0 ]]; then
170− echo "$file_lines" | while read -r line
214+ echo "$output" | while read -r line
171215 do
172216 echo $line
173217 done
174218 DONE=1;
175− return
219+ continue
176220 fi
177221
178− # show each line with context
179− echo "$file_lines" | while read -r line
222+ # For --list, show each line with its corresponding source code:
223+ echo "$output" | while read -r line
180224 do
181225 echo
182226 echo $line
@@ -184,12 +228,12 @@ __faddr2line() { · 1 unmodified line
184228 n1=$[$n-5]
185229 n2=$[$n+5]
186230 f=$(echo $line | sed 's/.*at \(.\+\):.*/\1/g')
187− awk 'NR>=strtonum("'$n1'") && NR<=strtonum("'$n2'") { if (NR=='$n') printf(">%d<", NR); else printf(" %d ", NR); printf("\t%s\n", $0)}' $f
231+ ${AWK} 'NR>=strtonum("'$n1'") && NR<=strtonum("'$n2'") { if (NR=='$n') printf(">%d<", NR); else printf(" %d ", NR); printf("\t%s\n", $0)}' $f
188232 done
189233
190234 DONE=1
191235
192− done < <(${NM} -n $objfile | awk -v fn=$func -v end=$file_end '$3 == fn { found=1; line=$0; start=$1; next } found == 1 { found=0; print line, "0x"$1 } END {if (found == 1) print line, end; }')
236+ done < <(${READELF} --symbols --wide $objfile | ${AWK} -v fn=$sym_name '$4 == "FUNC" && $8 == fn')
193237 }
194238
195239 [[ $# -lt 2 ]] && usage
scripts/link-vmlinux.sh+39−23
@@ -108,16 +108,22 @@ objtool_link() · 107 unmodified lines
108108 local objtoolcmd;
109109 local objtoolopt;
110110
111− if is_enabled CONFIG_STACK_VALIDATION && \
112− ( is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT ); then
111+ if ! is_enabled CONFIG_OBJTOOL; then
112+ return;
113+ fi
113114
114− # Don't perform vmlinux validation unless explicitly requested,
115− # but run objtool on vmlinux.o now that we have an object file.
116− if is_enabled CONFIG_UNWINDER_ORC; then
117− objtoolcmd="orc generate"
115+ if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then
116+
117+ # For LTO and IBT, objtool doesn't run on individual
118+ # translation units. Run everything on vmlinux instead.
119+
120+ if is_enabled CONFIG_HAVE_JUMP_LABEL_HACK; then
121+ objtoolopt="${objtoolopt} --hacks=jump_label"
118122 fi
119123
120− objtoolopt="${objtoolopt} --lto"
124+ if is_enabled CONFIG_HAVE_NOINSTR_HACK; then
125+ objtoolopt="${objtoolopt} --hacks=noinstr"
126+ fi
121127
122128 if is_enabled CONFIG_X86_KERNEL_IBT; then
123129 objtoolopt="${objtoolopt} --ibt"
@@ -126,34 +132,44 @@ objtool_link() · 2 unmodified lines
126132 if is_enabled CONFIG_FTRACE_MCOUNT_USE_OBJTOOL; then
127133 objtoolopt="${objtoolopt} --mcount"
128134 fi
135+
136+ if is_enabled CONFIG_UNWINDER_ORC; then
137+ objtoolopt="${objtoolopt} --orc"
138+ fi
139+
140+ if is_enabled CONFIG_RETPOLINE; then
141+ objtoolopt="${objtoolopt} --retpoline"
142+ fi
143+
144+ if is_enabled CONFIG_SLS; then
145+ objtoolopt="${objtoolopt} --sls"
146+ fi
147+
148+ if is_enabled CONFIG_STACK_VALIDATION; then
149+ objtoolopt="${objtoolopt} --stackval"
150+ fi
151+
152+ if is_enabled CONFIG_HAVE_STATIC_CALL_INLINE; then
153+ objtoolopt="${objtoolopt} --static-call"
154+ fi
155+
156+ objtoolopt="${objtoolopt} --uaccess"
129157 fi
130158
131− if is_enabled CONFIG_VMLINUX_VALIDATION; then
159+ if is_enabled CONFIG_NOINSTR_VALIDATION; then
132160 objtoolopt="${objtoolopt} --noinstr"
133161 fi
134162
135163 if [ -n "${objtoolopt}" ]; then
136− if [ -z "${objtoolcmd}" ]; then
137− objtoolcmd="check"
138− fi
139− objtoolopt="${objtoolopt} --vmlinux"
140− if ! is_enabled CONFIG_FRAME_POINTER; then
141− objtoolopt="${objtoolopt} --no-fp"
142− fi
164+
143165 if is_enabled CONFIG_GCOV_KERNEL; then
144166 objtoolopt="${objtoolopt} --no-unreachable"
145167 fi
146− if is_enabled CONFIG_RETPOLINE; then
147− objtoolopt="${objtoolopt} --retpoline"
148− fi
149168
150− objtoolopt="${objtoolopt} --uaccess"
169+ objtoolopt="${objtoolopt} --link"
151170
152− if is_enabled CONFIG_SLS; then
153− objtoolopt="${objtoolopt} --sls"
154− fi
155171 info OBJTOOL ${1}
156− tools/objtool/objtool ${objtoolcmd} ${objtoolopt} ${1}
172+ tools/objtool/objtool ${objtoolopt} ${1}
157173 fi
158174 }
159175
scripts/objdump-func+29−0
@@ -0,0 +1,29 @@
1+#!/bin/bash
2+# SPDX-License-Identifier: GPL-2.0
3+#
4+# Disassemble a single function.
5+#
6+# usage: objdump-func <file> <func>
7+
8+set -o errexit
9+set -o nounset
10+
11+OBJDUMP="${CROSS_COMPILE:-}objdump"
12+
13+command -v gawk >/dev/null 2>&1 || die "gawk isn't installed"
14+
15+usage() {
16+ echo "usage: objdump-func <file> <func>" >&2
17+ exit 1
18+}
19+
20+[[ $# -lt 2 ]] && usage
21+
22+OBJ=$1; shift
23+FUNC=$1; shift
24+
25+# Secret feature to allow adding extra objdump args at the end
26+EXTRA_ARGS=$@
27+
28+# Note this also matches compiler-added suffixes like ".cold", etc
29+${OBJDUMP} -wdr $EXTRA_ARGS $OBJ | gawk -M -v f=$FUNC '/^$/ { P=0; } $0 ~ "<" f "(\\..*)?>:" { P=1; O=strtonum("0x" $1); } { if (P) { o=strtonum("0x" $1); printf("%04x ", o-O); print $0; } }'
scripts/package/builddeb+1−1
@@ -67,7 +67,7 @@ deploy_kernel_headers () { · 66 unmodified lines
6767 ) > debian/hdrsrcfiles
6868
6969 {
70− if is_enabled CONFIG_STACK_VALIDATION; then
70+ if is_enabled CONFIG_OBJTOOL; then
7171 echo tools/objtool/objtool
7272 fi
7373