Commit 5aea50b5c76b07f2b6bda3426dba998156eaf6d0

Authored by Arjan van de Ven
Committed by Linus Torvalds
1 parent d6624f996a

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>

Showing 1 changed file with 162 additions and 0 deletions Side-by-side Diff

scripts/markup_oops.pl
  1 +#!/usr/bin/perl -w
  2 +
  3 +# Copyright 2008, Intel Corporation
  4 +#
  5 +# This file is part of the Linux kernel
  6 +#
  7 +# This program file is free software; you can redistribute it and/or modify it
  8 +# under the terms of the GNU General Public License as published by the
  9 +# Free Software Foundation; version 2 of the License.
  10 +#
  11 +# Authors:
  12 +# Arjan van de Ven <arjan@linux.intel.com>
  13 +
  14 +
  15 +my $vmlinux_name = $ARGV[0];
  16 +
  17 +#
  18 +# Step 1: Parse the oops to find the EIP value
  19 +#
  20 +
  21 +my $target = "0";
  22 +while (<STDIN>) {
  23 + if ($_ =~ /EIP: 0060:\[\<([a-z0-9]+)\>\]/) {
  24 + $target = $1;
  25 + }
  26 +}
  27 +
  28 +if ($target =~ /^f8/) {
  29 + print "This script does not work on modules ... \n";
  30 + exit;
  31 +}
  32 +
  33 +if ($target eq "0") {
  34 + print "No oops found!\n";
  35 + print "Usage: \n";
  36 + print " dmesg | perl scripts/markup_oops.pl vmlinux\n";
  37 + exit;
  38 +}
  39 +
  40 +my $counter = 0;
  41 +my $state = 0;
  42 +my $center = 0;
  43 +my @lines;
  44 +
  45 +sub InRange {
  46 + my ($address, $target) = @_;
  47 + my $ad = "0x".$address;
  48 + my $ta = "0x".$target;
  49 + my $delta = hex($ad) - hex($ta);
  50 +
  51 + if (($delta > -4096) && ($delta < 4096)) {
  52 + return 1;
  53 + }
  54 + return 0;
  55 +}
  56 +
  57 +
  58 +
  59 +# first, parse the input into the lines array, but to keep size down,
  60 +# we only do this for 4Kb around the sweet spot
  61 +
  62 +my $filename;
  63 +
  64 +open(FILE, "objdump -dS $vmlinux_name |") || die "Cannot start objdump";
  65 +
  66 +while (<FILE>) {
  67 + my $line = $_;
  68 + chomp($line);
  69 + if ($state == 0) {
  70 + if ($line =~ /^([a-f0-9]+)\:/) {
  71 + if (InRange($1, $target)) {
  72 + $state = 1;
  73 + }
  74 + }
  75 + } else {
  76 + if ($line =~ /^([a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]+)\:/) {
  77 + my $val = $1;
  78 + if (!InRange($val, $target)) {
  79 + last;
  80 + }
  81 + if ($val eq $target) {
  82 + $center = $counter;
  83 + }
  84 + }
  85 + $lines[$counter] = $line;
  86 +
  87 + $counter = $counter + 1;
  88 + }
  89 +}
  90 +
  91 +close(FILE);
  92 +
  93 +if ($counter == 0) {
  94 + print "No matching code found \n";
  95 + exit;
  96 +}
  97 +
  98 +if ($center == 0) {
  99 + print "No matching code found \n";
  100 + exit;
  101 +}
  102 +
  103 +my $start;
  104 +my $finish;
  105 +my $codelines = 0;
  106 +my $binarylines = 0;
  107 +# now we go up and down in the array to find how much we want to print
  108 +
  109 +$start = $center;
  110 +
  111 +while ($start > 1) {
  112 + $start = $start - 1;
  113 + my $line = $lines[$start];
  114 + if ($line =~ /^([a-f0-9]+)\:/) {
  115 + $binarylines = $binarylines + 1;
  116 + } else {
  117 + $codelines = $codelines + 1;
  118 + }
  119 + if ($codelines > 10) {
  120 + last;
  121 + }
  122 + if ($binarylines > 20) {
  123 + last;
  124 + }
  125 +}
  126 +
  127 +
  128 +$finish = $center;
  129 +$codelines = 0;
  130 +$binarylines = 0;
  131 +while ($finish < $counter) {
  132 + $finish = $finish + 1;
  133 + my $line = $lines[$finish];
  134 + if ($line =~ /^([a-f0-9]+)\:/) {
  135 + $binarylines = $binarylines + 1;
  136 + } else {
  137 + $codelines = $codelines + 1;
  138 + }
  139 + if ($codelines > 10) {
  140 + last;
  141 + }
  142 + if ($binarylines > 20) {
  143 + last;
  144 + }
  145 +}
  146 +
  147 +
  148 +my $i;
  149 +
  150 +my $fulltext = "";
  151 +$i = $start;
  152 +while ($i < $finish) {
  153 + if ($i == $center) {
  154 + $fulltext = $fulltext . "*$lines[$i] <----- faulting instruction\n";
  155 + } else {
  156 + $fulltext = $fulltext . " $lines[$i]\n";
  157 + }
  158 + $i = $i +1;
  159 +}
  160 +
  161 +print $fulltext;