mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-24 15:56:41 +00:00
199 lines
3.7 KiB
Plaintext
199 lines
3.7 KiB
Plaintext
|
#!/usr/bin/tclsh
|
||
|
|
||
|
#
|
||
|
# \brief Decode 'Genode::backtrace()' output and other memory addresses
|
||
|
# \author Christian Prochaska
|
||
|
# \date 2024-01-25
|
||
|
#
|
||
|
# Credits: heavily inspired by the Fiasco.OC backtrace tool
|
||
|
#
|
||
|
|
||
|
|
||
|
if {$::argc == 0} {
|
||
|
puts "Usage (in Genode debug directory):"
|
||
|
puts ""
|
||
|
puts {[KERNEL=...] backtrace [binary]}
|
||
|
puts ""
|
||
|
puts "then paste shared library info and backtrace addresses."
|
||
|
puts ""
|
||
|
puts "If the KERNEL environment variable is set, the file name "
|
||
|
puts "'ld.lib.so' will be replaced by 'ld-KERNEL.lib.so'"
|
||
|
puts ""
|
||
|
exit 1
|
||
|
}
|
||
|
|
||
|
|
||
|
set genode_tools_dir "/usr/local/genode/tool/23.05/bin"
|
||
|
|
||
|
set arch {}
|
||
|
|
||
|
array set images {}
|
||
|
array set image_bases {}
|
||
|
array set sections {}
|
||
|
array set symbols {}
|
||
|
|
||
|
set sorted_symbols_keys {}
|
||
|
|
||
|
|
||
|
proc readelf {} {
|
||
|
global genode_tools_dir
|
||
|
return "$genode_tools_dir/genode-x86-readelf"
|
||
|
}
|
||
|
|
||
|
|
||
|
proc nm {} {
|
||
|
global genode_tools_dir
|
||
|
global arch
|
||
|
return "$genode_tools_dir/genode-$arch-nm"
|
||
|
}
|
||
|
|
||
|
|
||
|
proc addr2line {} {
|
||
|
global genode_tools_dir
|
||
|
global arch
|
||
|
return "$genode_tools_dir/genode-$arch-addr2line"
|
||
|
}
|
||
|
|
||
|
|
||
|
proc scan_image {img base} {
|
||
|
|
||
|
global arch
|
||
|
global images
|
||
|
global image_bases
|
||
|
global sections
|
||
|
global symbols
|
||
|
global sorted_symbols_keys
|
||
|
|
||
|
if {$arch == ""} {
|
||
|
set readelf_output [exec [readelf] -h $img]
|
||
|
if {[regexp {AArch64} $readelf_output]} {
|
||
|
set arch "aarch64"
|
||
|
} elseif {[regexp {ARM} $readelf_output]} {
|
||
|
set arch "arm"
|
||
|
} elseif {[regexp {RISC-V} $readelf_output]} {
|
||
|
set arch "riscv"
|
||
|
} elseif {[regexp {80386} $readelf_output]} {
|
||
|
set arch "x86"
|
||
|
} elseif {[regexp {X86-64} $readelf_output]} {
|
||
|
set arch "x86"
|
||
|
} else {
|
||
|
puts "Error: could not obtain architecture from image file"
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# ignore base address of ld.lib.so
|
||
|
if {$img == "ld.lib.so"} {
|
||
|
set base 0
|
||
|
if {[info exists ::env(KERNEL)]} {
|
||
|
set img ld-$::env(KERNEL).lib.so
|
||
|
}
|
||
|
}
|
||
|
|
||
|
set nm_output ""
|
||
|
|
||
|
if {[catch { set nm_output [exec [nm] -C $img.debug] } msg]} {
|
||
|
puts "Warning: $msg"
|
||
|
return
|
||
|
}
|
||
|
|
||
|
set nm_lines [split $nm_output "\n"]
|
||
|
|
||
|
foreach nm_line $nm_lines {
|
||
|
|
||
|
if {[regexp {^([0-9a-fA-F]+)\s+(\S)\s+(.*)$} $nm_line -> addr section sym]} {
|
||
|
set key "[format "0x%x" [expr $base + 0x$addr]]"
|
||
|
set images($key) $img
|
||
|
set image_bases($key) $base
|
||
|
set sections($key) $section
|
||
|
set symbols($key) $sym
|
||
|
}
|
||
|
}
|
||
|
|
||
|
set sorted_symbols_keys [lsort -integer [array names symbols]]
|
||
|
|
||
|
puts "Scanned image $img"
|
||
|
}
|
||
|
|
||
|
|
||
|
proc print_func {addr} {
|
||
|
|
||
|
global images
|
||
|
global image_bases
|
||
|
global sections
|
||
|
global symbols
|
||
|
global sorted_symbols_keys
|
||
|
|
||
|
set addr [format "0x%x" $addr]
|
||
|
|
||
|
set symbol_start_addr 0
|
||
|
|
||
|
foreach key $sorted_symbols_keys {
|
||
|
if {[expr $key > $addr]} {
|
||
|
break }
|
||
|
set symbol_start_addr $key
|
||
|
}
|
||
|
|
||
|
if {$symbol_start_addr} {
|
||
|
set img $images($symbol_start_addr)
|
||
|
set local_addr [format "0x%x" [expr $addr - $image_bases($symbol_start_addr)]]
|
||
|
set line [exec [addr2line] -e $img $local_addr]
|
||
|
puts "$symbols($symbol_start_addr)"
|
||
|
puts ""
|
||
|
puts " * $addr: $img:$local_addr $sections($symbol_start_addr)"
|
||
|
puts " * $line"
|
||
|
} else {
|
||
|
puts "<unknown>"
|
||
|
puts " * $addr"
|
||
|
}
|
||
|
|
||
|
puts ""
|
||
|
}
|
||
|
|
||
|
|
||
|
foreach arg $::argv { scan_image $arg 0 }
|
||
|
|
||
|
while {1} {
|
||
|
|
||
|
gets stdin line
|
||
|
|
||
|
# prevent mixing of pasted input and generated output
|
||
|
after 10
|
||
|
|
||
|
puts ""
|
||
|
|
||
|
if {[regexp {^\[.*\] (0x[0-9a-f]+).*?: (.*)$} $line -> base img]} {
|
||
|
|
||
|
# shared library info
|
||
|
|
||
|
# ignore linker area
|
||
|
if {$img == "linker area"} {
|
||
|
continue }
|
||
|
|
||
|
# ignore stack area
|
||
|
if {$img == "stack area"} {
|
||
|
continue }
|
||
|
|
||
|
scan_image $img $base
|
||
|
|
||
|
} elseif {[regexp {^\[.*]\s+[0-9a-f]+\s+([0-9a-f]+)$} $line -> addr]} {
|
||
|
|
||
|
# backtrace address
|
||
|
|
||
|
print_func 0x$addr
|
||
|
|
||
|
} elseif {[regexp {^(0x[0-9a-f]+)$} $line -> addr]} {
|
||
|
|
||
|
# single hex address prefixed with 0x
|
||
|
|
||
|
print_func $addr
|
||
|
|
||
|
} elseif {[regexp {^([0-9a-f]+)$} $line -> addr]} {
|
||
|
|
||
|
# single hex address not prefixed with 0x
|
||
|
|
||
|
print_func 0x$addr
|
||
|
|
||
|
}
|
||
|
}
|