3 # Written by Sorav Bansal <sbansal@stanford.edu>.
4 # Modified by Ben Pfaff <blp@cs.stanford.edu>.
6 our $CSCOPE = $ENV{CSCOPE} || "cscope";
7 our $invoke_cscope = 0;
9 our $checkbochs_log = "checkbochs.log";
10 our $btrace_file = "btrace";
13 use Getopt::Long qw(:config require_order bundling);
18 checkbochs-trace, to interpret logs generated using 'pintos --checkbochs'
19 Usage: checkbochs [OPTION...]
21 --log=LOG Log file to read is LOG (default: checkbochs.log)
22 --output=OUT File to write in cscope format is OUT (default: btrace)
23 --object=OBJECT Kernel object file (default: build/kernel.o or kernel.o)
24 --cscope Invoke cscope on backtraces written to OUT
25 -n, -nth=N Print a backtrace for the Nth warning (default: 1)
26 -h, --help Print this help message
31 GetOptions ("log=s" => \$checkbochs_log,
32 "output=s" => \$btrace_file,
33 "object=s" => \$kernel_o,
35 "cscope" => sub { $invoke_cscope = 1; },
36 "h|help" => sub { usage (0); }
40 open (LOG, "<", $checkbochs_log) or die "$checkbochs_log: open: $!\n";
44 if (/Warning on location (.*), backtrace:/) {
46 $loc = $1 if $count == $nth;
52 print "No potential race conditions detected\n";
54 } elsif ($nth > $count) {
55 print "Only $count potential race conditions detected\n";
58 print "$count potential race conditions detected\n";
61 my ($name) = lookup_symbol (hex ($loc));
62 print "Potential race condition $nth on data at $loc";
63 print " ($name)" if defined $name;
66 print "Writing backtraces to $btrace_file\n";
69 open (LOG, "<", $checkbochs_log) or die "$checkbochs_log: open: $!\n";
70 open (OUT, ">", $btrace_file) or die "$btrace_file: create: $!\n";
72 if (my ($op, $bt) = /^(.*) location $loc.*backtrace: (.*)$/) {
73 if ($op =~ /Thread (\S+): Warning on/) {
74 $op = "Thread $1: Potential race";
78 open (BT, "backtrace kernel.o $bt |" );
81 my ($addr, $func, $fn, $ln)
82 = /^([a-f0-9]+): (\S+) \(([^:]+):([^\)]+)\)/
85 print OUT "$fn $func $ln $op\n";
95 exec ("$CSCOPE -R -F$btrace_file") if $invoke_cscope;
101 my ($nm) = search_path ("i386-elf-nm") || search_path ("nm");
103 print "neither `i386-elf-nm' nor `nm' in PATH\n";
108 if (!defined $kernel_o) {
110 $kernel_o = 'kernel.o';
111 } elsif (-e 'build/kernel.o') {
112 $kernel_o = 'build/kernel.o';
114 print "can't find kernel.o or build/kernel.o\n";
117 } elsif (! -e $kernel_o) {
118 print "$kernel_o: stat: $!\n";
122 # Use nm to find name.
123 if (!open (NM, "$nm -S $kernel_o|")) {
124 print "nm: exec: $!\n";
128 my ($h_start, $h_length, $type, $name)
129 = /^([a-f0-9]+) ([a-f0-9]+) \S (\S+)$/ or next;
130 my ($start) = hex ($h_start);
131 my ($length) = hex ($h_length);
132 next if $address < $start || $address >= $start + $length;
134 $name .= "+" . ($address - $start) if $address != $start;
142 for my $dir (split (':', $ENV{PATH})) {
143 my ($file) = "$dir/$target";
144 return $file if -e $file;