Kernel oops reader

=?ISO-8859-1?Q?Thomas_K=F6nig?= (Thomas.Koenig@ciw.uni-karlsruhe.de)
Wed, 5 Jul 1995 15:19:54 +0200 (MET DST)


This is a small kernel oops reader, which reads /usr/src/linux/System.map
for the address of the EIP and the call traces.

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.