@@ -85,15 +85,17 @@ command -v ${ADDR2LINE} >/dev/null 2>&1 || die "${ADDR2LINE} isn't installed"
85
85
# init/main.c! This only works for vmlinux. Otherwise it falls back to
86
86
# printing the absolute path.
87
87
find_dir_prefix () {
88
- local objfile=$1
89
-
90
- local start_kernel_addr=$( ${READELF} --symbols --wide $objfile | sed ' s/\[.*\]//' |
88
+ local start_kernel_addr=$( echo " ${ELF_SYMS} " | sed ' s/\[.*\]//' |
91
89
${AWK} ' $8 == "start_kernel" {printf "0x%s", $2}' )
92
90
[[ -z $start_kernel_addr ]] && return
93
91
94
- local file_line= $( ${ADDR2LINE} -e $objfile $start_kernel_addr )
95
- [[ -z $file_line ]] && return
92
+ run_addr2line ${start_kernel_addr} " "
93
+ [[ -z $ADDR2LINE_OUT ]] && return
96
94
95
+ local file_line=${ADDR2LINE_OUT#* at }
96
+ if [[ -z $file_line ]] || [[ $file_line = $ADDR2LINE_OUT ]]; then
97
+ return
98
+ fi
97
99
local prefix=${file_line% init/ main.c:* }
98
100
if [[ -z $prefix ]] || [[ $prefix = $file_line ]]; then
99
101
return
@@ -103,6 +105,71 @@ find_dir_prefix() {
103
105
return 0
104
106
}
105
107
108
+ run_readelf () {
109
+ local objfile=$1
110
+ local out=$( ${READELF} --file-header --section-headers --symbols --wide $objfile )
111
+
112
+ # This assumes that readelf first prints the file header, then the section headers, then the symbols.
113
+ # Note: It seems that GNU readelf does not prefix section headers with the "There are X section headers"
114
+ # line when multiple options are given, so let's also match with the "Section Headers:" line.
115
+ ELF_FILEHEADER=$( echo " ${out} " | sed -n ' /There are [0-9]* section headers, starting at offset\|Section Headers:/q;p' )
116
+ ELF_SECHEADERS=$( echo " ${out} " | sed -n ' /There are [0-9]* section headers, starting at offset\|Section Headers:/,$p' | sed -n ' /Symbol table .* contains [0-9]* entries:/q;p' )
117
+ ELF_SYMS=$( echo " ${out} " | sed -n ' /Symbol table .* contains [0-9]* entries:/,$p' )
118
+ }
119
+
120
+ check_vmlinux () {
121
+ # vmlinux uses absolute addresses in the section table rather than
122
+ # section offsets.
123
+ IS_VMLINUX=0
124
+ local file_type=$( echo " ${ELF_FILEHEADER} " |
125
+ ${AWK} ' $1 == "Type:" { print $2; exit }' )
126
+ if [[ $file_type = " EXEC" ]] || [[ $file_type == " DYN" ]]; then
127
+ IS_VMLINUX=1
128
+ fi
129
+ }
130
+
131
+ init_addr2line () {
132
+ local objfile=$1
133
+
134
+ check_vmlinux
135
+
136
+ ADDR2LINE_ARGS=" --functions --pretty-print --inlines --addresses --exe=$objfile "
137
+ if [[ $IS_VMLINUX = 1 ]]; then
138
+ # If the executable file is vmlinux, we don't pass section names to
139
+ # addr2line, so we can launch it now as a single long-running process.
140
+ coproc ADDR2LINE_PROC (${ADDR2LINE} ${ADDR2LINE_ARGS} )
141
+ fi
142
+ }
143
+
144
+ run_addr2line () {
145
+ local addr=$1
146
+ local sec_name=$2
147
+
148
+ if [[ $IS_VMLINUX = 1 ]]; then
149
+ # We send to the addr2line process: (1) the address, then (2) a sentinel
150
+ # value, i.e., something that can't be interpreted as a valid address
151
+ # (i.e., ","). This causes addr2line to write out: (1) the answer for
152
+ # our address, then (2) either "?? ??:0" or "0x0...0: ..." (if
153
+ # using binutils' addr2line), or "," (if using LLVM's addr2line).
154
+ echo ${addr} >& " ${ADDR2LINE_PROC[1]} "
155
+ echo " ," >& " ${ADDR2LINE_PROC[1]} "
156
+ local first_line
157
+ read -r first_line < & " ${ADDR2LINE_PROC[0]} "
158
+ ADDR2LINE_OUT=$( echo " ${first_line} " | sed ' s/^0x[0-9a-fA-F]*: //' )
159
+ while read -r line < & " ${ADDR2LINE_PROC[0]} " ; do
160
+ if [[ " $line " == " ?? ??:0" ]] || [[ " $line " == " ," ]] || [[ $( echo " $line " | ${GREP} " ^0x00*: " ) ]]; then
161
+ break
162
+ fi
163
+ ADDR2LINE_OUT+=$' \n ' $( echo " $line " | sed ' s/^0x[0-9a-fA-F]*: //' )
164
+ done
165
+ else
166
+ # Run addr2line as a single invocation.
167
+ local sec_arg
168
+ [[ -z $sec_name ]] && sec_arg=" " || sec_arg=" --section=${sec_name} "
169
+ ADDR2LINE_OUT=$( ${ADDR2LINE} ${ADDR2LINE_ARGS} ${sec_arg} ${addr} | sed ' s/^0x[0-9a-fA-F]*: //' )
170
+ fi
171
+ }
172
+
106
173
__faddr2line () {
107
174
local objfile=$1
108
175
local func_addr=$2
@@ -113,8 +180,6 @@ __faddr2line() {
113
180
local func_offset=${func_addr#* +}
114
181
func_offset=${func_offset%/* }
115
182
local user_size=
116
- local file_type
117
- local is_vmlinux=0
118
183
[[ $func_addr =~ " /" ]] && user_size=${func_addr#*/ }
119
184
120
185
if [[ -z $sym_name ]] || [[ -z $func_offset ]] || [[ $sym_name = $func_addr ]]; then
@@ -123,14 +188,6 @@ __faddr2line() {
123
188
return
124
189
fi
125
190
126
- # vmlinux uses absolute addresses in the section table rather than
127
- # section offsets.
128
- local file_type=$( ${READELF} --file-header $objfile |
129
- ${AWK} ' $1 == "Type:" { print $2; exit }' )
130
- if [[ $file_type = " EXEC" ]] || [[ $file_type == " DYN" ]]; then
131
- is_vmlinux=1
132
- fi
133
-
134
191
# Go through each of the object's symbols which match the func name.
135
192
# In rare cases there might be duplicates, in which case we print all
136
193
# matches.
@@ -143,8 +200,7 @@ __faddr2line() {
143
200
local sec_name
144
201
145
202
# Get the section size:
146
- sec_size=$( ${READELF} --section-headers --wide $objfile |
147
- sed ' s/\[ /\[/' |
203
+ sec_size=$( echo " ${ELF_SECHEADERS} " | sed ' s/\[ /\[/' |
148
204
${AWK} -v sec=$sym_sec ' $1 == "[" sec "]" { print "0x" $6; exit }' )
149
205
150
206
if [[ -z $sec_size ]]; then
@@ -154,8 +210,7 @@ __faddr2line() {
154
210
fi
155
211
156
212
# Get the section name:
157
- sec_name=$( ${READELF} --section-headers --wide $objfile |
158
- sed ' s/\[ /\[/' |
213
+ sec_name=$( echo " ${ELF_SECHEADERS} " | sed ' s/\[ /\[/' |
159
214
${AWK} -v sec=$sym_sec ' $1 == "[" sec "]" { print $2; exit }' )
160
215
161
216
if [[ -z $sec_name ]]; then
@@ -197,7 +252,7 @@ __faddr2line() {
197
252
found=2
198
253
break
199
254
fi
200
- done < <( ${READELF} --symbols --wide $objfile | sed ' s/\[.*\]//' | ${AWK} -v sec=$sym_sec ' $7 == sec' | sort --key=2)
255
+ done < <( echo " ${ELF_SYMS} " | sed ' s/\[.*\]//' | ${AWK} -v sec=$sym_sec ' $7 == sec' | sort --key=2 | ${GREP} -A1 --no-group-separator " ${sym_name} $ " )
201
256
202
257
if [[ $found = 0 ]]; then
203
258
warn " can't find symbol: sym_name: $sym_name sym_sec: $sym_sec sym_addr: $sym_addr sym_elf_size: $sym_elf_size "
@@ -249,9 +304,8 @@ __faddr2line() {
249
304
250
305
# Pass section address to addr2line and strip absolute paths
251
306
# from the output:
252
- local args=" --functions --pretty-print --inlines --exe=$objfile "
253
- [[ $is_vmlinux = 0 ]] && args=" $args --section=$sec_name "
254
- local output=$( ${ADDR2LINE} $args $addr | sed " s; $dir_prefix \(\./\)*; ;" )
307
+ run_addr2line $addr $sec_name
308
+ local output=$( echo " ${ADDR2LINE_OUT} " | sed " s; $dir_prefix \(\./\)*; ;" )
255
309
[[ -z $output ]] && continue
256
310
257
311
# Default output (non --list):
@@ -278,7 +332,7 @@ __faddr2line() {
278
332
279
333
DONE=1
280
334
281
- done < <( ${READELF} --symbols --wide $objfile | sed ' s/\[.*\]//' | ${AWK} -v fn=$sym_name ' $8 == fn' )
335
+ done < <( echo " ${ELF_SYMS} " | sed ' s/\[.*\]//' | ${AWK} -v fn=$sym_name ' $8 == fn' )
282
336
}
283
337
284
338
[[ $# -lt 2 ]] && usage
@@ -291,10 +345,14 @@ LIST=0
291
345
[[ ! -f $objfile ]] && die " can't find objfile $objfile "
292
346
shift
293
347
294
- ${READELF} --section-headers --wide $objfile | ${GREP} -q ' \.debug_info' || die " CONFIG_DEBUG_INFO not enabled"
348
+ run_readelf $objfile
349
+
350
+ echo " ${ELF_SECHEADERS} " | ${GREP} -q ' \.debug_info' || die " CONFIG_DEBUG_INFO not enabled"
351
+
352
+ init_addr2line $objfile
295
353
296
354
DIR_PREFIX=supercalifragilisticexpialidocious
297
- find_dir_prefix $objfile
355
+ find_dir_prefix
298
356
299
357
FIRST=1
300
358
while [[ $# -gt 0 ]]; do
0 commit comments