Give backtrace program ability to take multiple binary file arguments.
authorBen Pfaff <blp@cs.stanford.edu>
Wed, 17 May 2006 17:00:36 +0000 (17:00 +0000)
committerBen Pfaff <blp@cs.stanford.edu>
Wed, 17 May 2006 17:00:36 +0000 (17:00 +0000)
Thanks to Godmar Back for suggestion.

TODO
doc/debug.texi
src/utils/backtrace

diff --git a/TODO b/TODO
index 88a08331a6224dd9a0c56163c0bc79a8f6b71f1a..522847aa1dc88f2a95d36d3a0f193c13ec8353c8 100644 (file)
--- a/TODO
+++ b/TODO
@@ -207,9 +207,6 @@ via Godmar Back:
 
 * Get rid of mmap syscall, add sbrk.
 
-* Make backtrace program accept multiple object file arguments,
-  e.g. add -u option to allow backtracing user program also.
-
 * page-linear, page-shuffle VM tests do not use enough memory to force
   eviction.  Should increase memory consumption.
 
index 8a52be5efaceccd98cc16e4d95f4d0400ac9c615..e671b7495b2cc9a6e403abe6b252e1fa0ab24d35 100644 (file)
@@ -159,15 +159,15 @@ backtrace kernel.o 0xc0106eff 0xc01102fb 0xc010dc22 0xc010cf67
 The backtrace output would then look something like this:
 
 @example
-0xc0106eff: debug_panic (../../lib/debug.c:86)
-0xc01102fb: file_seek (../../filesys/file.c:405)
-0xc010dc22: seek (../../userprog/syscall.c:744)
-0xc010cf67: syscall_handler (../../userprog/syscall.c:444)
-0xc0102319: intr_handler (../../threads/interrupt.c:334)
-0xc010325a: ?? (threads/intr-stubs.S:1554)
-0x804812c: ?? (??:0)
-0x8048a96: ?? (??:0)
-0x8048ac8: ?? (??:0)
+0xc0106eff: debug_panic (lib/debug.c:86)
+0xc01102fb: file_seek (filesys/file.c:405)
+0xc010dc22: seek (userprog/syscall.c:744)
+0xc010cf67: syscall_handler (userprog/syscall.c:444)
+0xc0102319: intr_handler (threads/interrupt.c:334)
+0xc010325a: intr_entry (threads/intr-stubs.S:38)
+0x0804812c: (unknown)
+0x08048a96: (unknown)
+0x08048ac8: (unknown)
 @end example
 
 (You will probably not see exactly the same addresses if you run the
@@ -209,22 +209,48 @@ panicked, you can re-run @command{backtrace} on the user program, like
 so: (typing the command on a single line, of course):
 
 @example
-backtrace grow-too-big 0xc0106eff 0xc01102fb 0xc010dc22 0xc010cf67
-0xc0102319 0xc010325a 0x804812c 0x8048a96 0x8048ac8
+backtrace tests/filesys/extended/grow-too-big 0xc0106eff 0xc01102fb
+0xc010dc22 0xc010cf67 0xc0102319 0xc010325a 0x804812c 0x8048a96
+0x8048ac8
 @end example
 
 The results look like this:
 
 @example
-0xc0106eff: ?? (??:0)
-0xc01102fb: ?? (??:0)
-0xc010dc22: ?? (??:0)
-0xc010cf67: ?? (??:0)
-0xc0102319: ?? (??:0)
-0xc010325a: ?? (??:0)
-0x804812c: test_main (../../tests/filesys/extended/grow-too-big.c:20)
-0x8048a96: main (../../tests/main.c:10)
-0x8048ac8: _start (../../lib/user/entry.c:9)
+0xc0106eff: (unknown)
+0xc01102fb: (unknown)
+0xc010dc22: (unknown)
+0xc010cf67: (unknown)
+0xc0102319: (unknown)
+0xc010325a: (unknown)
+0x0804812c: test_main (...xtended/grow-too-big.c:20)
+0x08048a96: main (tests/main.c:10)
+0x08048ac8: _start (lib/user/entry.c:9)
+@end example
+
+You can even specify both the kernel and the user program names on
+the command line, like so:
+
+@example
+backtrace kernel.o tests/filesys/extended/grow-too-big 0xc0106eff
+0xc01102fb 0xc010dc22 0xc010cf67 0xc0102319 0xc010325a 0x804812c
+0x8048a96 0x8048ac8
+@end example
+
+The result is a combined backtrace:
+
+@example
+In kernel.o:
+0xc0106eff: debug_panic (lib/debug.c:86)
+0xc01102fb: file_seek (filesys/file.c:405)
+0xc010dc22: seek (userprog/syscall.c:744)
+0xc010cf67: syscall_handler (userprog/syscall.c:444)
+0xc0102319: intr_handler (threads/interrupt.c:334)
+0xc010325a: intr_entry (threads/intr-stubs.S:38)
+In tests/filesys/extended/grow-too-big:
+0x0804812c: test_main (...xtended/grow-too-big.c:20)
+0x08048a96: main (tests/main.c:10)
+0x08048ac8: _start (lib/user/entry.c:9)
 @end example
 
 Here's an extra tip for anyone who read this far: @command{backtrace}
index 6cfd3ec5569a1e00d412c5629e4af17b6a3b62ad..4d083169f5a1df03162bf94da9189cae7b8671f9 100755 (executable)
@@ -6,12 +6,13 @@ use strict;
 if (grep ($_ eq '-h' || $_ eq '--help', @ARGV)) {
     print <<'EOF';
 backtrace, for converting raw addresses into symbolic backtraces
-usage: backtrace [BINARY] ADDRESS...
-where BINARY is the binary file from which to obtain symbols
+usage: backtrace [BINARY]... ADDRESS...
+where BINARY is the binary file or files from which to obtain symbols
  and ADDRESS is a raw address to convert to a symbol name.
 
-If BINARY is unspecified, the default is the first of kernel.o or
-build/kernel.o that exists.
+If no BINARY is unspecified, the default is the first of kernel.o or
+build/kernel.o that exists.  If multiple binaries are specified, each
+symbol printed is from the first binary that contains a match.
 
 The ADDRESS list should be taken from the "Call stack:" printed by the
 kernel.  Read "Backtraces" in the "Debugging Tools" chapter of the
@@ -22,22 +23,27 @@ EOF
 die "backtrace: at least one argument required (use --help for help)\n"
     if @ARGV == 0;
 
-# Drop leading and trailing garbage inserted by kernel.
-shift while grep (/^(call|stack:?)$/i, $ARGV[0]);
+# Drop garbage inserted by kernel.
+@ARGV = grep (!/^(call|stack:?|[-+])$/i, @ARGV);
 s/\.$// foreach @ARGV;
 
-# Find binary file.
-my ($bin) = $ARGV[0];
-if (-e $bin) {
-    shift @ARGV;
-} elsif ($bin !~ /^0/) {
-    die "backtrace: $bin: not found (use --help for help)\n";
-} elsif (-e 'kernel.o') {
-    $bin = 'kernel.o';
-} elsif (-e 'build/kernel.o') {
-    $bin = 'build/kernel.o';
-} else {
-    die "backtrace: can't find binary for backtrace (use --help for help)\n";
+# Find binaries.
+my (@binaries);
+while ($ARGV[0] !~ /^0x/) {
+    my ($bin) = shift @ARGV;
+    die "backtrace: $bin: not found (use --help for help)\n" if ! -e $bin;
+    push (@binaries, $bin);
+}
+if (!@binaries) {
+    my ($bin);
+    if (-e 'kernel.o') {
+       $bin = 'kernel.o';
+    } elsif (-e 'build/kernel.o') {
+       $bin = 'build/kernel.o';
+    } else {
+       die "backtrace: no binary specified and neither \"kernel.o\" nor \"build/kernel.o\" exists (use --help for help)\n";
+    }
+    push (@binaries, $bin);
 }
 
 # Find addr2line.
@@ -54,14 +60,47 @@ sub search_path {
     return undef;
 }
 
-# Do backtrace.
-open (A2L, "$a2l -fe $bin " . join (' ', @ARGV) . "|");
-while (<A2L>) {
-    my ($function, $line);
-    chomp ($function = $_);
-    chomp ($line = <A2L>);
-    $line = "..." . substr ($line, -25) if length ($line) > 28;
-    print shift (@ARGV), ": $function ($line)\n";
+# Figure out backtrace.
+my (@locs) = map ({ADDR => $_}, @ARGV);
+for my $bin (@binaries) {
+    open (A2L, "$a2l -fe $bin " . join (' ', map ($_->{ADDR}, @locs)) . "|");
+    for (my ($i) = 0; <A2L>; $i++) {
+       my ($function, $line);
+       chomp ($function = $_);
+       chomp ($line = <A2L>);
+       next if defined $locs[$i]{BINARY};
+
+       if ($function ne '??' || $line ne '??:0') {
+           $locs[$i]{FUNCTION} = $function;
+           $locs[$i]{LINE} = $line;
+           $locs[$i]{BINARY} = $bin;
+       }
+    }
+    close (A2L);
+}
+
+# Print backtrace.
+my ($cur_binary);
+for my $loc (@locs) {
+    if (defined ($loc->{BINARY})
+       && @binaries > 0
+       && (!defined ($cur_binary) || $loc->{BINARY} ne $cur_binary)) {
+       $cur_binary = $loc->{BINARY};
+       print "In $cur_binary:\n";
+    }
+
+    my ($addr) = $loc->{ADDR};
+    $addr = sprintf ("0x%08x", hex ($addr)) if $addr =~ /^0x[0-9a-f]+$/i;
+
+    print $addr, ": ";
+    if (defined ($loc->{BINARY})) {
+       my ($function) = $loc->{FUNCTION};
+       my ($line) = $loc->{LINE};
+       $line =~ s/^(\.\.\/)*//;
+       $line = "..." . substr ($line, -25) if length ($line) > 28;
+       print "$function ($line)";
+    } else {
+       print "(unknown)";
+    }
+    print "\n";
 }
-close (A2L);
-