summaryrefslogtreecommitdiffstats
path: root/pintos-progos/utils/backtrace
diff options
context:
space:
mode:
Diffstat (limited to 'pintos-progos/utils/backtrace')
-rwxr-xr-xpintos-progos/utils/backtrace106
1 files changed, 106 insertions, 0 deletions
diff --git a/pintos-progos/utils/backtrace b/pintos-progos/utils/backtrace
new file mode 100755
index 0000000..95e422f
--- /dev/null
+++ b/pintos-progos/utils/backtrace
@@ -0,0 +1,106 @@
1#! /usr/bin/perl -w
2
3use strict;
4
5# Check command line.
6if (grep ($_ eq '-h' || $_ eq '--help', @ARGV)) {
7 print <<'EOF';
8backtrace, for converting raw addresses into symbolic backtraces
9usage: backtrace [BINARY]... ADDRESS...
10where BINARY is the binary file or files from which to obtain symbols
11 and ADDRESS is a raw address to convert to a symbol name.
12
13If no BINARY is unspecified, the default is the first of kernel.o or
14build/kernel.o that exists. If multiple binaries are specified, each
15symbol printed is from the first binary that contains a match.
16
17The ADDRESS list should be taken from the "Call stack:" printed by the
18kernel. Read "Backtraces" in the "Debugging Tools" chapter of the
19Pintos documentation for more information.
20EOF
21 exit 0;
22}
23die "backtrace: at least one argument required (use --help for help)\n"
24 if @ARGV == 0;
25
26# Drop garbage inserted by kernel.
27@ARGV = grep (!/^(call|stack:?|[-+])$/i, @ARGV);
28s/\.$// foreach @ARGV;
29
30# Find binaries.
31my (@binaries);
32while ($ARGV[0] !~ /^0x/) {
33 my ($bin) = shift @ARGV;
34 die "backtrace: $bin: not found (use --help for help)\n" if ! -e $bin;
35 push (@binaries, $bin);
36}
37if (!@binaries) {
38 my ($bin);
39 if (-e 'kernel.o') {
40 $bin = 'kernel.o';
41 } elsif (-e 'build/kernel.o') {
42 $bin = 'build/kernel.o';
43 } else {
44 die "backtrace: no binary specified and neither \"kernel.o\" nor \"build/kernel.o\" exists (use --help for help)\n";
45 }
46 push (@binaries, $bin);
47}
48
49# Find addr2line.
50my ($a2l) = search_path ("i386-elf-addr2line") || search_path ("addr2line");
51if (!$a2l) {
52 die "backtrace: neither `i386-elf-addr2line' nor `addr2line' in PATH\n";
53}
54sub search_path {
55 my ($target) = @_;
56 for my $dir (split (':', $ENV{PATH})) {
57 my ($file) = "$dir/$target";
58 return $file if -e $file;
59 }
60 return undef;
61}
62
63# Figure out backtrace.
64my (@locs) = map ({ADDR => $_}, @ARGV);
65for my $bin (@binaries) {
66 open (A2L, "$a2l -fe $bin " . join (' ', map ($_->{ADDR}, @locs)) . "|");
67 for (my ($i) = 0; <A2L>; $i++) {
68 my ($function, $line);
69 chomp ($function = $_);
70 chomp ($line = <A2L>);
71 next if defined $locs[$i]{BINARY};
72
73 if ($function ne '??' || $line ne '??:0') {
74 $locs[$i]{FUNCTION} = $function;
75 $locs[$i]{LINE} = $line;
76 $locs[$i]{BINARY} = $bin;
77 }
78 }
79 close (A2L);
80}
81
82# Print backtrace.
83my ($cur_binary);
84for my $loc (@locs) {
85 if (defined ($loc->{BINARY})
86 && @binaries > 1
87 && (!defined ($cur_binary) || $loc->{BINARY} ne $cur_binary)) {
88 $cur_binary = $loc->{BINARY};
89 print "In $cur_binary:\n";
90 }
91
92 my ($addr) = $loc->{ADDR};
93 $addr = sprintf ("0x%08x", hex ($addr)) if $addr =~ /^0x[0-9a-f]+$/i;
94
95 print $addr, ": ";
96 if (defined ($loc->{BINARY})) {
97 my ($function) = $loc->{FUNCTION};
98 my ($line) = $loc->{LINE};
99 $line =~ s/^(\.\.\/)*//;
100 $line = "..." . substr ($line, -25) if length ($line) > 28;
101 print "$function ($line)";
102 } else {
103 print "(unknown)";
104 }
105 print "\n";
106}