From: Ben Pfaff Date: Wed, 17 May 2006 17:00:36 +0000 (+0000) Subject: Give backtrace program ability to take multiple binary file arguments. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1a6b8dbf4ccf3f16bd410c4fd091f842c75e6fca;p=pintos-anon Give backtrace program ability to take multiple binary file arguments. Thanks to Godmar Back for suggestion. --- diff --git a/TODO b/TODO index 88a0833..522847a 100644 --- 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. diff --git a/doc/debug.texi b/doc/debug.texi index 8a52be5..e671b74 100644 --- a/doc/debug.texi +++ b/doc/debug.texi @@ -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} diff --git a/src/utils/backtrace b/src/utils/backtrace index 6cfd3ec..4d08316 100755 --- a/src/utils/backtrace +++ b/src/utils/backtrace @@ -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 () { - my ($function, $line); - chomp ($function = $_); - chomp ($line = ); - $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; ; $i++) { + my ($function, $line); + chomp ($function = $_); + chomp ($line = ); + 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); -