diff options
author | Arjan van de Ven <arjan@infradead.org> | 2009-01-06 14:40:57 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-06 15:59:12 -0800 |
commit | 5aea50b5c76b07f2b6bda3426dba998156eaf6d0 (patch) | |
tree | 20e522f88586e8c0835893e9236dded9fc6d87f2 /scripts/markup_oops.pl | |
parent | d6624f996ae539344e8d748cce1117ae7af06fbf (diff) | |
download | lwn-5aea50b5c76b07f2b6bda3426dba998156eaf6d0.tar.gz lwn-5aea50b5c76b07f2b6bda3426dba998156eaf6d0.zip |
scripts: script from kerneloops.org to pretty print oops dumps
We're struggling all the time to figure out where the code came from that
oopsed.. The script below (a adaption from a script used by
kerneloops.org) can help developers quite a bit, at least for non-module
cases.
It works and looks like this:
[/home/arjan/linux]$ dmesg | perl scripts/markup_oops.pl vmlinux
{
struct agp_memory *memory;
memory = agp_allocate_memory(agp_bridge, pg_count, type);
c055c10f: 89 c2 mov %eax,%edx
if (memory == NULL)
c055c111: 74 19 je c055c12c <agp_allocate_memory_wrap+0x30>
/* This function must only be called when current_controller != NULL */
static void agp_insert_into_pool(struct agp_memory * temp)
{
struct agp_memory *prev;
prev = agp_fe.current_controller->pool;
c055c113: a1 ec dc 8f c0 mov 0xc08fdcec,%eax
*c055c118: 8b 40 10 mov 0x10(%eax),%eax <----- faulting instruction
if (prev != NULL) {
c055c11b: 85 c0 test %eax,%eax
c055c11d: 74 05 je c055c124 <agp_allocate_memory_wrap+0x28>
prev->prev = temp;
c055c11f: 89 50 04 mov %edx,0x4(%eax)
temp->next = prev;
c055c122: 89 02 mov %eax,(%edx)
}
agp_fe.current_controller->pool = temp;
c055c124: a1 ec dc 8f c0 mov 0xc08fdcec,%eax
c055c129: 89 50 10 mov %edx,0x10(%eax)
if (memory == NULL)
return NULL;
agp_insert_into_pool(memory);
so in this case, we faulted while dereferencing agp_fe.current_controller
pointer, and we get to see exactly which function and line it affects...
Personally I find this very useful, and I can see value for having this
script in the kernel for more-than-just-me to use.
Caveats:
* It only works for oopses not-in-modules
* It only works nicely for kernels compiled with CONFIG_DEBUG_INFO
* It's not very fast.
* It only works on x86
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'scripts/markup_oops.pl')
-rw-r--r-- | scripts/markup_oops.pl | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/scripts/markup_oops.pl b/scripts/markup_oops.pl new file mode 100644 index 000000000000..700a7a654a3f --- /dev/null +++ b/scripts/markup_oops.pl @@ -0,0 +1,162 @@ +#!/usr/bin/perl -w + +# Copyright 2008, Intel Corporation +# +# This file is part of the Linux kernel +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# Authors: +# Arjan van de Ven <arjan@linux.intel.com> + + +my $vmlinux_name = $ARGV[0]; + +# +# Step 1: Parse the oops to find the EIP value +# + +my $target = "0"; +while (<STDIN>) { + if ($_ =~ /EIP: 0060:\[\<([a-z0-9]+)\>\]/) { + $target = $1; + } +} + +if ($target =~ /^f8/) { + print "This script does not work on modules ... \n"; + exit; +} + +if ($target eq "0") { + print "No oops found!\n"; + print "Usage: \n"; + print " dmesg | perl scripts/markup_oops.pl vmlinux\n"; + exit; +} + +my $counter = 0; +my $state = 0; +my $center = 0; +my @lines; + +sub InRange { + my ($address, $target) = @_; + my $ad = "0x".$address; + my $ta = "0x".$target; + my $delta = hex($ad) - hex($ta); + + if (($delta > -4096) && ($delta < 4096)) { + return 1; + } + return 0; +} + + + +# first, parse the input into the lines array, but to keep size down, +# we only do this for 4Kb around the sweet spot + +my $filename; + +open(FILE, "objdump -dS $vmlinux_name |") || die "Cannot start objdump"; + +while (<FILE>) { + my $line = $_; + chomp($line); + if ($state == 0) { + if ($line =~ /^([a-f0-9]+)\:/) { + if (InRange($1, $target)) { + $state = 1; + } + } + } else { + if ($line =~ /^([a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]+)\:/) { + my $val = $1; + if (!InRange($val, $target)) { + last; + } + if ($val eq $target) { + $center = $counter; + } + } + $lines[$counter] = $line; + + $counter = $counter + 1; + } +} + +close(FILE); + +if ($counter == 0) { + print "No matching code found \n"; + exit; +} + +if ($center == 0) { + print "No matching code found \n"; + exit; +} + +my $start; +my $finish; +my $codelines = 0; +my $binarylines = 0; +# now we go up and down in the array to find how much we want to print + +$start = $center; + +while ($start > 1) { + $start = $start - 1; + my $line = $lines[$start]; + if ($line =~ /^([a-f0-9]+)\:/) { + $binarylines = $binarylines + 1; + } else { + $codelines = $codelines + 1; + } + if ($codelines > 10) { + last; + } + if ($binarylines > 20) { + last; + } +} + + +$finish = $center; +$codelines = 0; +$binarylines = 0; +while ($finish < $counter) { + $finish = $finish + 1; + my $line = $lines[$finish]; + if ($line =~ /^([a-f0-9]+)\:/) { + $binarylines = $binarylines + 1; + } else { + $codelines = $codelines + 1; + } + if ($codelines > 10) { + last; + } + if ($binarylines > 20) { + last; + } +} + + +my $i; + +my $fulltext = ""; +$i = $start; +while ($i < $finish) { + if ($i == $center) { + $fulltext = $fulltext . "*$lines[$i] <----- faulting instruction\n"; + } else { + $fulltext = $fulltext . " $lines[$i]\n"; + } + $i = $i +1; +} + +print $fulltext; + |