#!/usr/bin/perl -w use DB_File; use Fcntl ':flock'; if (!defined($ARGV[0])) { print "usage: requires .class dump as parameter!\n"; exit; } sub bailout { untie %bcheckdb if(defined(%bcheckdb)); if(defined(MYLOCK)) { flock MYLOCK, LOCK_UN; close(MYLOCK); } print @_; exit 5; } sub ask_user { my ($dbkey, $dbchunk) = @_; if (defined($ENV{"BCHECK_UPDATE"})) { $bcheckdb{$dbkey} = $dbchunk; return; } &bailout("BC problem detected") if (! -t STDIN); print "(I)gnore / (Q)uit / (U)pdate: "; my $key; while(defined(read STDIN, $key, 1)) { $key = lc($key); print "got: >$key<\n"; return if ($key eq 'i'); &bailout("BC problem. aborted") if ($key eq 'q'); if ($key eq 'u') { $bcheckdb{$dbkey} = $dbchunk; return; } print "\n(I)gnore / (Q)uit / (U)pdate: "; } } sub diff_chunk($$) { my ($oldl, $newl) = @_; my @old = split /^/m, $oldl; my @new = split /^/m, $newl; my $haschanges = 0; my $max = $#old > $#new ? $#old : $#new; die "whoops. key different" if ($old[0] ne $new[0]); if ($#old != $#new) { warn ("Structural difference.\n"); print @old; print "-----------------------------------------------\n"; print @new; $haschanges = 1; return $haschanges; } print $old[0]; my ($class) = ($old[0] =~ /^(?:Class |Vtable for )(\S+)/); my $c = 1; while ($c < $max) { my ($o, $n) = ($old[$c], $new[$c]); chomp $o; chomp $n; $c++; next if ($o eq $n); if(defined($class) and $n =~ /^(\d+\s+)\w+(::\S+\s*.*)$/) { next if ($n eq "$1$class$2"); } $haschanges = 1; print "-$o\n+$n\n\n"; } return $haschanges; } local $dblock = $ENV{"HOME"} . "/bcheck.lock"; my $dbfile = $ENV{"HOME"} . "/bcheck.db"; my $cdump = $ARGV[0]; die "file $cdump is not readable: $!" if (! -f $cdump); # make sure the advisory lock exists open(MYLOCK, ">$dblock"); print MYLOCK ""; flock MYLOCK, LOCK_EX; tie %bcheckdb, 'DB_File', $dbfile; my $chunk = ""; open (IN, "<$cdump") or die "cannot open $cdump: $!"; while (<IN>) { chop; s/0x[0-9a-fA-F]+/0x......../g; s/base size=/size=/g; s/base align=/align=/g; $chunk .= $_ . "\n"; if(/^\s*$/) { my @lines = split /^/m, $chunk; my $key = $lines[0]; chomp $key; if($key !~ /<anonymous struct>/ && $key !~ /<anonymous union>/) { if(defined($bcheckdb{$key})) { my $dbversion = $bcheckdb{$key}; if($dbversion ne $chunk) { &ask_user($key, $chunk) if(&diff_chunk($dbversion, $chunk)); } } else { $bcheckdb{$key} = $chunk; print "NEW: $key\n"; } } $chunk = ""; next; } } close(IN); untie %bcheckdb; flock MYLOCK, LOCK_UN; close(MYLOCK); exit 0;