FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
linux/scripts/decode_stacktrace.sh at master · OneCodeMonkey/linux · GitHub
OneCodeMonkey
/
linux
Public
forked from
torvalds/linux
Notifications
You must be signed in to change notification settings
Fork
2
Star
1
Code
Pull requests
0
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
linux
/
scripts
/
decode_stacktrace.sh
Copy path
More file actions
More file actions
Latest commit
History
History
History
executable file
·
331 lines (282 loc) · 7.77 KB
Breadcrumbs
linux
/
scripts
/
decode_stacktrace.sh
Copy path
File metadata and controls
executable file
·
331 lines (282 loc) · 7.77 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#!
/bin/bash
#
SPDX-License-Identifier: GPL-2.0
#
(c) 2014, Sasha Levin <sasha.levin@oracle.com>
#
set -x
usage
() {
echo
"
Usage:
"
echo
"
$0
-r <release> | <vmlinux> [<base path>|auto] [<modules path>]
"
}
#
Try to find a Rust demangler
if
type
llvm-cxxfilt
>
/dev/null
2>&1
;
then
cppfilt=llvm-cxxfilt
elif
type
c++filt
>
/dev/null
2>&1
;
then
cppfilt=c++filt
cppfilt_opts=-i
fi
UTIL_SUFFIX=
if
[[
-z
${LLVM
:-
}
]]
;
then
UTIL_PREFIX=
${CROSS_COMPILE
:-
}
else
UTIL_PREFIX=llvm-
if
[[
${LLVM}
==
*
/ ]]
;
then
UTIL_PREFIX=
${LLVM}${UTIL_PREFIX}
elif
[[
${LLVM}
==
-
*
]]
;
then
UTIL_SUFFIX=
${LLVM}
fi
fi
READELF=
${UTIL_PREFIX}
readelf
${UTIL_SUFFIX}
ADDR2LINE=
${UTIL_PREFIX}
addr2line
${UTIL_SUFFIX}
NM=
${UTIL_PREFIX}
nm
${UTIL_SUFFIX}
if
[[
$1
==
"
-r
"
]]
;
then
vmlinux=
"
"
basepath=
"
auto
"
modpath=
"
"
release=
$2
for
fn
in
{,/usr/lib/debug}/boot/vmlinux-
$release
{,.debug} /lib/modules/
$release
{,/build}/vmlinux
;
do
if
[
-e
"
$fn
"
]
;
then
vmlinux=
$fn
break
fi
done
if
[[
$vmlinux
==
"
"
]]
;
then
echo
"
ERROR! vmlinux image for release
$release
is not found
"
>&2
usage
exit
2
fi
else
vmlinux=
$1
basepath=
${2-auto}
modpath=
$3
release=
"
"
debuginfod=
#
Can we use debuginfod-find?
if
type
debuginfod-find
>
/dev/null
2>&1
;
then
debuginfod=
${1-only}
fi
if
[[
$vmlinux
==
"
"
&&
-z
$debuginfod
]]
;
then
echo
"
ERROR! vmlinux image must be specified
"
>&2
usage
exit
1
fi
fi
declare
aarray_support=true
declare
-A cache
2>
/dev/null
if
[[
$?
!=
0 ]]
;
then
aarray_support=false
else
declare
-A modcache
fi
find_module
() {
if
[[
-n
$debuginfod
]]
;
then
if
[[
-n
$modbuildid
]]
;
then
debuginfod-find debuginfo
$modbuildid
&&
return
fi
#
Only using debuginfod so don't try to find vmlinux module path
if
[[
$debuginfod
==
"
only
"
]]
;
then
return
fi
fi
if
[[
"
$modpath
"
!=
"
"
]]
;
then
for
fn
in
$(
find
"
$modpath
"
-name
"
${module
//
_
/
[-_]}
.ko*
"
)
;
do
if
${READELF}
-WS
"
$fn
"
|
grep -qwF .debug_line
;
then
echo
$fn
return
fi
done
return
1
fi
modpath=
$(
dirname
"
$vmlinux
"
)
find_module
&&
return
if
[[
$release
==
"
"
]]
;
then
release=
$(
gdb -ex
'
print init_uts_ns.name.release
'
-ex
'
quit
'
-quiet -batch
"
$vmlinux
"
2>
/dev/null
|
sed -n
'
s/\$1 = "\(.*\)".*/\1/p
'
)
fi
for
dn
in
{/usr/lib/debug,}/lib/modules/
$release
;
do
if
[
-e
"
$dn
"
]
;
then
modpath=
"
$dn
"
find_module
&&
return
fi
done
modpath=
"
"
return
1
}
parse_symbol
() {
#
The structure of symbol at this point is:
#
([name]+[offset]/[total length])
#
#
For example:
#
do_basic_setup+0x9c/0xbf
if
[[
$module
==
"
"
]]
;
then
local
objfile=
$vmlinux
elif
[[
$aarray_support
==
true
&&
"
${modcache[$module]+isset}
"
==
"
isset
"
]]
;
then
local
objfile=
${modcache[$module]}
else
local
objfile=
$(
find_module
)
if
[[
$objfile
==
"
"
]]
;
then
echo
"
WARNING! Modules path isn't set, but is needed to parse this symbol
"
>&2
return
fi
if
[[
$aarray_support
==
true
]]
;
then
modcache[
$module
]=
$objfile
fi
fi
#
Remove the englobing parenthesis
symbol=
${symbol
#
\(
}
symbol=
${symbol
%
\)
}
#
Strip segment
local
segment
if
[[
$symbol
==
*
:
*
]]
;
then
segment=
${symbol
%%:*
}
:
symbol=
${symbol
#*:
}
fi
#
Strip the symbol name so that we could look it up
local
name=
${symbol
%
+
*
}
#
Use 'nm vmlinux' to figure out the base address of said symbol.
#
It's actually faster to call it every time than to load it
#
all into bash.
if
[[
$aarray_support
==
true
&&
"
${cache[$module,$name]+isset}
"
==
"
isset
"
]]
;
then
local
base_addr=
${cache[$module,$name]}
else
local
base_addr=
$(
${NM}
"
$objfile
"
2>
/dev/null
|
awk
'
$3 == "
'
$name
'
" && ($2 == "t" || $2 == "T") {print $1; exit}
'
)
if
[[
$base_addr
==
"
"
]]
;
then
#
address not found
return
fi
if
[[
$aarray_support
==
true
]]
;
then
cache[
$module
,
$name
]=
"
$base_addr
"
fi
fi
#
Let's start doing the math to get the exact address into the
#
symbol. First, strip out the symbol total length.
local
expr=
${symbol
%/*
}
#
Now, replace the symbol name with the base address we found
#
before.
expr=
${expr
/
$name
/
0x
$base_addr
}
#
Evaluate it to find the actual address
expr=
$((
expr
))
local
address=
$(
printf
"
%x\n
"
"
$expr
"
)
#
Pass it to addr2line to get filename and line number
#
Could get more than one result
if
[[
$aarray_support
==
true
&&
"
${cache[$module,$address]+isset}
"
==
"
isset
"
]]
;
then
local
code=
${cache[$module,$address]}
else
local
code=
$(
${ADDR2LINE}
-i -e
"
$objfile
"
"
$address
"
2>
/dev/null
)
if
[[
$aarray_support
==
true
]]
;
then
cache[
$module
,
$address
]=
$code
fi
fi
#
addr2line doesn't return a proper error code if it fails, so
#
we detect it using the value it prints so that we could preserve
#
the offset/size into the function and bail out
if
[[
$code
==
"
??:0
"
]]
;
then
return
fi
#
Strip out the base of the path on each line
code=
$(
while
read
-r line
;
do
echo
"
${line
#
$basepath
/
}
"
;
done
<<<
"
$code
"
)
#
In the case of inlines, move everything to same line
code=
${code
//
$'
\n
'
/
'
'
}
#
Demangle if the name looks like a Rust symbol and if
#
we got a Rust demangler
if
[[
$name
=~
^_R
&&
$cppfilt
!=
"
"
]]
;
then
name=
$(
"
$cppfilt
"
"
$cppfilt_opts
"
"
$name
"
)
fi
#
Replace old address with pretty line numbers
symbol=
"
$segment$name
(
$code
)
"
}
debuginfod_get_vmlinux
() {
local
vmlinux_buildid=
${1
##*
}
if
[[
$vmlinux
!=
"
"
]]
;
then
return
fi
if
[[
$vmlinux_buildid
=~
^[0-9a-f]+ ]]
;
then
vmlinux=
$(
debuginfod-find debuginfo
$vmlinux_buildid
)
if
[[
$?
-ne
0 ]]
;
then
echo
"
ERROR! vmlinux image not found via debuginfod-find
"
>&2
usage
exit
2
fi
return
fi
echo
"
ERROR! Build ID for vmlinux not found. Try passing -r or specifying vmlinux
"
>&2
usage
exit
2
}
decode_code
() {
local
scripts=
`
dirname
"
${BASH_SOURCE[0]}
"
`
echo
"
$1
"
|
$scripts
/decodecode
}
handle_line
() {
if
[[
$basepath
==
"
auto
"
&&
$vmlinux
!=
"
"
]]
;
then
module=
"
"
symbol=
"
kernel_init+0x0/0x0
"
parse_symbol
basepath=
${symbol
#
kernel_init (}
basepath=
${basepath
%/
init
/
main.c
:*
)}
fi
local
words
#
Tokenize
read
-a words
<<<
"
$1
"
#
Remove hex numbers. Do it ourselves until it happens in the
#
kernel
#
We need to know the index of the last element before we
#
remove elements because arrays are sparse
local
last=
$((
${
#
words[@]}
-
1
))
for
i
in
"
${
!
words[@]}
"
;
do
#
Remove the address
if
[[
${words[$i]}
=~
\[\<
([^]]+)
\>\]
]]
;
then
unset
words[
$i
]
fi
#
Format timestamps with tabs
if
[[
${words[$i]}
==
\[
&&
${words[$i+1]}
==
*
\]
]]
;
then
unset
words[
$i
]
words[
$i
+1]=
$(
printf
"
[%13s\n
"
"
${words[$i+1]}
"
)
fi
done
if
[[
${words[$last]}
=~
^[0-9a-f]+
\]
]]
;
then
words[
$last
-1]=
"
${words[$last-1]}
${words[$last]}
"
unset
words[
$last
]
last=
$((
$last
-
1
))
fi
if
[[
${words[$last]}
=~
\[
([^]]+)
\]
]]
;
then
module=
${words[$last]}
#
some traces format is "(%pS)", which like "(foo+0x0/0x1 [bar])"
#
so $module may like "[bar])". Strip the right parenthesis firstly
module=
${module
%
\)
}
module=
${module
#
\[
}
module=
${module
%
\]
}
modbuildid=
${module
#*
}
module=
${module
%
*
}
if
[[
$modbuildid
==
$module
]]
;
then
modbuildid=
fi
symbol=
${words[$last-1]}
unset
words[
$last
-1]
else
#
The symbol is the last element, process it
symbol=
${words[$last]}
module=
modbuildid=
fi
unset
words[
$last
]
parse_symbol
#
modifies $symbol
#
Add up the line number to the symbol
echo
"
${words[@]}
"
"
$symbol
$module
"
}
while
read
line
;
do
#
Strip unexpected carriage return at end of line
line=
${line
%
$'
\r
'
}
#
Let's see if we have an address in the line
if
[[
$line
=~
\[\<
([^]]+)
\>\]
]]
||
[[
$line
=~
[^+
\
]+
\+
0x[0-9a-f]+/0x[0-9a-f]+ ]]
;
then
#
Translate address to line numbers
handle_line
"
$line
"
#
Is it a code line?
elif
[[
$line
==
*
Code:
*
]]
;
then
decode_code
"
$line
"
#
Is it a version line?
elif
[[
-n
$debuginfod
&&
$line
=~
PID:
\
[0-9]+
\
Comm: ]]
;
then
debuginfod_get_vmlinux
"
$line
"
else
#
Nothing special in this line, show it as is
echo
"
$line
"
fi
done
Back
|
FazBrowse Home
|
New Git URL