mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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>
		
	
			
		
			
				
	
	
		
			162 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
#!/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;
 | 
						|
 |