iBoot/tools/pctrace-decoder

194 lines
5.2 KiB
Tcl

#!/usr/bin/tclsh
#
# Takes a PC trace from simulation and annotates it with function/line number information
#
# The PC trace is assumed to have one PC per line; the first likely-looking number on each line is assumed to be the PC.
#
# usage: pctrace-decoder <PC trace file> <path to symbolicated binary in build directory>
#
package require log
package require fileutil
################################################################################
# utilities
proc fatal {msg} {
global errorInfo
::log::log error $msg
# if {$errorInfo != ""} {
# ::log::log debug $errorInfo
# }
exit 1
}
################################################################################
proc generateBatch {pctrace batchfile} {
::log::log debug "parsing trace $pctrace"
::fileutil::foreachLine inputLine $pctrace {
foreach tok $inputLine {
switch -glob $tok {
[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F] {
set addresses($tok) ""
break
}
0x[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F] {
# hex number
set addresses([string range $tok 2 end]) ""
break
}
default {
continue
}
}
}
}
if {![array exists addresses]} {
fatal "no recognisable data in '$pctrace' (maybe need a smarter parser?)"
}
set batch [open $batchfile w]
::log::log debug "generating batchfile $batchfile"
foreach address [array names addresses] {
puts $batch [format "echo &%s&" $address]
puts $batch [format "info line *0x%s" $address]
}
close $batch
}
################################################################################
proc runBatch {symfile batchfile batchresult} {
::log::log debug "generating symbol data $batchresult"
if {[catch {exec gdb -n -batch -x $batchfile $symfile > $batchresult} result]} {
fatal "gdb failed: $result"
}
}
################################################################################
proc annotateTrace {pctrace batchresult traceoutput condensed} {
::log::log debug "reading batch results"
::fileutil::foreachLine inputLine $batchresult {
if {[scan $inputLine "&%\[^&\]&Line %d of \"%\[^\"\]\" starts at address %x <%\[^>\]> and ends at %x <%\[^>\]>" key lineNumber fileName startAddr startSym endAddr endSym] == 7} {
if {[scan $startSym "%\[^+\]+%x" sym addr] == 2} {
set startSym $sym
}
if {[scan $endSym "%\[^+\]+%x" sym addr] == 2} {
set endSym $sym
}
if {$startSym == $endSym} {
set addrinfo($key) [format "%s:%s:%d" $fileName $startSym $lineNumber]
} else {
set addrinfo($key) [format "%s:%s/%s:%d" $fileName $startSym $endSym $lineNumber]
}
continue
}
if {[scan $inputLine "&%\[^&\]&No line number information available for address %x <%\[^>\]>" key address addrSym] == 3} {
if {[scan $addrSym "%\[^+\]+%x" sym addr] == 2} {
set addrSym $sym
}
set addrinfo($key) [format "%s" $addrSym]
continue
}
log::log warning "unexpected batch result '$inputLine'"
}
set out [open $traceoutput w]
set cout [open $condensed w]
::log::log debug "annotating trace"
set lastSuffix ""
::fileutil::foreachLine inputLine $pctrace {
set address ""
foreach tok $inputLine {
switch -glob $tok {
[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F] {
set address $tok
break
}
0x[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F] {
# hex number
set address [string range $tok 2 end]
break
}
default {
continue
}
}
}
if {($address != "") && ([array names addrinfo -exact $address] != "")} {
set suffix $addrinfo($address)
if {$suffix != $lastSuffix} {
puts $cout $suffix
set lastSuffix $suffix
}
} else {
set suffix ""
}
puts $out [format "%s -- %s" $inputLine $suffix]
}
close $out
close $cout
}
################################################################################
proc main {} {
global argv
# logging
::log::lvSuppress error 0
::log::lvSuppress warning 0
::log::lvSuppress notice 0
::log::lvSuppress debug 1
set pctrace [lindex $argv 0]
set symfile [lindex $argv 1]
if {![file readable $pctrace]} {
fatal "missing or unreadable PC trace file '$pctrace'"
}
if {![file readable $symfile]} {
fatal "missing or unreadable symbol file '$symfile'"
}
# generate a gdb batch file
::log::log notice "generating gdb batch from PC trace..."
set batchfile [::fileutil::tempfile ptrace_decoder_batch_]
generateBatch $pctrace $batchfile
# invoke gdb against the batch file
::log::log notice "processing batch..."
set batchresult [::fileutil::tempfile ptrace_decoder_result_]
runBatch $symfile $batchfile $batchresult
file delete $batchfile
# annotate the pctrace with results from the result file
::log::log notice "annotating trace..."
set traceoutput [format "%s.annotated" $pctrace]
set condensed [format "%s.condensed" $pctrace]
annotateTrace $pctrace $batchresult $traceoutput $condensed
file delete $batchresult
::log::log notice "Annotated output in '$traceoutput', condensed output in '$condensed'"
}
main