- die "First line of output is not `($proc_name) begin' message.\n"
- if $output[0] ne "($proc_name) begin";
- die "Output contains `FAIL' message.\n"
- if grep (/FAIL/, @output);
- die "Output contains spurious ($proc_name) message.\n"
- if grep (/\($proc_name\)/, @output) > 1;
-}
-
-sub grade_pt_bad_addr {
- grade_process_death ('pt-bad-addr', @_);
-}
-
-sub grade_pt_write_code {
- grade_process_death ('pt-write-code', @_);
-}
-
-sub grade_mmap_unmap {
- grade_process_death ('mmap-unmap', @_);
-}
-\f
-sub verify_common {
- my (@output) = @_;
-
- my (@assertion) = grep (/PANIC/, @output);
- if (@assertion != 0) {
- my ($details) = "Kernel panic:\n $assertion[0]\n";
-
- my (@stack_line) = grep (/Call stack:/, @output);
- if (@stack_line != 0) {
- $details .= " $stack_line[0]\n\n";
- $details .= "Translation of backtrace:\n";
- my (@addrs) = $stack_line[0] =~ /Call stack:((?: 0x[0-9a-f]+)+)/;
-
- my ($A2L);
- if (`uname -m`
- =~ /i.86|pentium.*|[pk][56]|nexgen|viac3|6x86|athlon.*/) {
- $A2L = "addr2line";
- } else {
- $A2L = "i386-elf-addr2line";
- }
- open (A2L, "$A2L -fe pintos/src/filesys/build/kernel.o @addrs|");
- for (;;) {
- my ($function, $line);
- last unless defined ($function = <A2L>);
- $line = <A2L>;
- chomp $function;
- chomp $line;
- $details .= " $function ($line)\n";
- }
- }
-
- if ($assertion[0] =~ /sec_no < d->capacity/) {
- $details .= <<EOF;
-\nThis assertion commonly fails when accessing a file via
-an inode that has been closed and freed. Freeing an inode
-clears all its sector indexes to 0xcccccccc, which is not
-a valid sector number for disks smaller than about 1.6 TB.
-EOF
- }
-
- $extra{$test} = $details;
- die "Kernel panic. Details at end of file.\n"
- }
-
- my (@failure) = grep (/FAIL/, @output);
- if (@failure != 0) {
- eval {
- my (@core) = get_core_output (@output);
- $details{$test} = "Program output:\n\n" . join ('', map ("$_\n", @core));
- };
- my ($failure) = $failure[0];
- $failure =~ s/^\([^)]+\)\s+//;
- die "Failed with message \"$failure\"\n";
- }
-
- if (grep (/Pintos booting/, @output) > 1) {
- my ($details);
-
- $details = "Pintos spontaneously rebooted during this test.\n";
- $details .= "This is most often due to unhandled page faults.\n";
- $details .= "Here's the output from the initial boot through the\n";
- $details .= "first reboot:\n\n";
-
- my ($i) = 0;
- local ($_);
- for (@output) {
- $details .= " $_\n";
- last if /Pintos booting/ && ++$i > 1;
- }
- $details{$test} = $details;
- die "Triple-fault caused spontaneous reboot(s). "
- . "Details at end of file.\n";
- }
-
- die "No output at all\n" if @output == 0;
- die "Didn't start up properly: no \"Pintos booting\" startup message\n"
- if !grep (/Pintos booting with.*kB RAM\.\.\./, @output);
- die "Didn't start up properly: no \"Boot complete\" startup message\n"
- if !grep (/Boot complete/, @output);
- die "Didn't shut down properly: no \"Timer: # ticks\" shutdown message\n"
- if !grep (/Timer: \d+ ticks/, @output);
- die "Didn't shut down properly: no \"Powering off\" shutdown message\n"
- if !grep (/Powering off/, @output);
-}
-
-# Get @output without header or trailer.
-sub get_core_output {
- my (@output) = @_;
-
- my ($first);
- for ($first = 0; $first <= $#output; $first++) {
- $first++, last if $output[$first] =~ /^Executing '$test.*':$/;
- }
-
- my ($last);
- for ($last = $#output; $last >= 0; $last--) {
- $last--, last if $output[$last] =~ /^Timer: \d+ ticks$/;
- }
-
- if ($last < $first) {
- my ($no_first) = $first > $#output;
- my ($no_last) = $last < $#output;
- die "Couldn't locate output.\n";
- }
-
- return @output[$first ... $last];
-}
-
-sub fix_exit_codes {
- my (@output) = @_;
-
- # Remove lines that look like exit codes.
- # Exit codes are supposed to be printed in the form "process: exit(code)"
- # but people get unfortunately creative with it.
- for (my ($i) = 0; $i <= $#output; $i++) {
- local ($_) = $output[$i];
-
- my ($process, $code);
- if ((($process, $code) = /^([-a-z0-9 ]+):.*[ \(](-?\d+)\b\)?$/)
- || (($process, $code) = /^([-a-z0-9 ]+) exit\((-?\d+)\)$/)
- || (($process, $code)
- = /^([-a-z0-9 ]+) \(.*\): exit\((-?\d+)\)$/)
- || (($process, $code) = /^([-a-z0-9 ]+):\( (-?\d+) \) $/)
- || (($code, $process) = /^shell: exit\((-?\d+)\) \| ([-a-z0-9]+)/)
- ) {
- splice (@output, $i, 1);
- $i--;
- }
- }
-
- return @output;
-}
-
-sub compare_output {
- my ($exp, @actual) = @_;
- @actual = fix_exit_codes (get_core_output (map ("$_\n", @actual)));
- die "Program produced no output.\n" if !@actual;
-
- my ($details) = "";
- $details .= "$test actual output:\n";
- $details .= join ('', map (" $_", @actual));
-
- my (@exp) = map ("$_\n", snarf ($exp));
-
- my ($fuzzy_match) = 0;
- while (@exp != 0) {
- my (@expected);
- while (@exp != 0) {
- my ($s) = shift (@exp);
- last if $s eq "--OR--\n";
- push (@expected, $s);
- }