Usage:
oopsread /var/adm/messages
(or whereever you happen to have the kernel dump information stored).
This isn't perfect (probably :-), but could come in handy for people
who are too lazy to look up these values by hand.
Have fun
#!/usr/bin/perl
$reading = 0;
$map = "/usr/src/linux/System.map";
while (<>) {
if (($start = index($_,"Oops: ")) >=0 ) {
$block = "";
$reading = 1;
$rstart = $start;
}
if ($reading) {
$block .= substr($_, $rstart);
if (/Code: /) {
$reading = 0;
}
}
}
die "No kernel Oops found, aborting\n" unless $block;
print $block,"\n";
$block =~ s/\n\s+/ /g;
foreach(split("\n",$block)) {
if (/EIP:/) {
($dummy, $dummy, $hstr) = split(':',$_);
$fcn_name = &lookup_fcn($hstr);
print "EIP = $hstr ($fcn_name)\n";
}
elsif(/Call Trace/) {
($dummy, @addr) = split(' ',$_);
foreach $calltrace(@addr) {
$fcn_name = &lookup_fcn($calltrace);
print "Call trace = $calltrace ($fcn_name)\n";
}
}
}
sub lookup_fcn
{
local($straddr) = @_;
local($_,$name,$addr,$dummy,$saddr,$upper,$lower);
$saddr = hex($straddr);
if ($#names < 0) {
open(MAP,$map) || die "Cannot open $map:\n";
while(<MAP>) {
($addr, $dummy, $name) = split(' ');
push(@addrs,hex ($addr));
push(@names,$name);
}
}
$lower = 0;
$upper = $#addrs;
if (($saddr < $addrs[$lower]) || ($saddr > $addrs[$upper])) {
return "unknown";
}
while (1) {
if ($upper - $lower <=1) {
$diff = $saddr - $addrs[$lower];
return sprintf ("%s + 0x%4.4x",$names[$lower],$diff);
}
$middle = ($upper + $lower)/2;
if ($addrs[$middle] > $saddr) {
$upper = $middle;
}
else {
$lower = $middle;
}
}
}
-- Thomas Koenig, Thomas.Koenig@ciw.uni-karlsruhe.de, ig25@dkauni2.bitnet. The joy of engineering is to find a straight line on a double logarithmic diagram.