xref: /linux/scripts/markup_oops.pl (revision b233b28eac0cc37d07c2d007ea08c86c778c5af4)
1#!/usr/bin/perl -w
2
3use File::Basename;
4
5# Copyright 2008, Intel Corporation
6#
7# This file is part of the Linux kernel
8#
9# This program file is free software; you can redistribute it and/or modify it
10# under the terms of the GNU General Public License as published by the
11# Free Software Foundation; version 2 of the License.
12#
13# Authors:
14# 	Arjan van de Ven <arjan@linux.intel.com>
15
16
17my $vmlinux_name = $ARGV[0];
18if (!defined($vmlinux_name)) {
19	my $kerver = `uname -r`;
20	chomp($kerver);
21	$vmlinux_name = "/lib/modules/$kerver/build/vmlinux";
22	print "No vmlinux specified, assuming $vmlinux_name\n";
23}
24my $filename = $vmlinux_name;
25#
26# Step 1: Parse the oops to find the EIP value
27#
28
29my $target = "0";
30my $function;
31my $module = "";
32my $func_offset;
33my $vmaoffset = 0;
34
35while (<STDIN>) {
36	my $line = $_;
37	if ($line =~ /EIP: 0060:\[\<([a-z0-9]+)\>\]/) {
38		$target = $1;
39	}
40	if ($line =~ /EIP is at ([a-zA-Z0-9\_]+)\+(0x[0-9a-f]+)\/0x[a-f0-9]/) {
41		$function = $1;
42		$func_offset = $2;
43	}
44
45	# check if it's a module
46	if ($line =~ /EIP is at ([a-zA-Z0-9\_]+)\+(0x[0-9a-f]+)\/0x[a-f0-9]+\W\[([a-zA-Z0-9\_\-]+)\]/) {
47		$module = $3;
48	}
49}
50
51my $decodestart = hex($target) - hex($func_offset);
52my $decodestop = $decodestart + 8192;
53if ($target eq "0") {
54	print "No oops found!\n";
55	print "Usage: \n";
56	print "    dmesg | perl scripts/markup_oops.pl vmlinux\n";
57	exit;
58}
59
60# if it's a module, we need to find the .ko file and calculate a load offset
61if ($module ne "") {
62	my $dir = dirname($filename);
63	$dir = $dir . "/";
64	my $mod = $module . ".ko";
65	my $modulefile = `find $dir -name $mod | head -1`;
66	chomp($modulefile);
67	$filename = $modulefile;
68	if ($filename eq "") {
69		print "Module .ko file for $module not found. Aborting\n";
70		exit;
71	}
72	# ok so we found the module, now we need to calculate the vma offset
73	open(FILE, "objdump -dS $filename |") || die "Cannot start objdump";
74	while (<FILE>) {
75		if ($_ =~ /^([0-9a-f]+) \<$function\>\:/) {
76			my $fu = $1;
77			$vmaoffset = hex($target) - hex($fu) - hex($func_offset);
78		}
79	}
80	close(FILE);
81}
82
83my $counter = 0;
84my $state   = 0;
85my $center  = 0;
86my @lines;
87
88sub InRange {
89	my ($address, $target) = @_;
90	my $ad = "0x".$address;
91	my $ta = "0x".$target;
92	my $delta = hex($ad) - hex($ta);
93
94	if (($delta > -4096) && ($delta < 4096)) {
95		return 1;
96	}
97	return 0;
98}
99
100
101
102# first, parse the input into the lines array, but to keep size down,
103# we only do this for 4Kb around the sweet spot
104
105open(FILE, "objdump -dS --adjust-vma=$vmaoffset --start-address=$decodestart --stop-address=$decodestop $filename |") || die "Cannot start objdump";
106
107while (<FILE>) {
108	my $line = $_;
109	chomp($line);
110	if ($state == 0) {
111		if ($line =~ /^([a-f0-9]+)\:/) {
112			if (InRange($1, $target)) {
113				$state = 1;
114			}
115		}
116	} else {
117		if ($line =~ /^([a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]+)\:/) {
118			my $val = $1;
119			if (!InRange($val, $target)) {
120				last;
121			}
122			if ($val eq $target) {
123				$center = $counter;
124			}
125		}
126		$lines[$counter] = $line;
127
128		$counter = $counter + 1;
129	}
130}
131
132close(FILE);
133
134if ($counter == 0) {
135	print "No matching code found \n";
136	exit;
137}
138
139if ($center == 0) {
140	print "No matching code found \n";
141	exit;
142}
143
144my $start;
145my $finish;
146my $codelines = 0;
147my $binarylines = 0;
148# now we go up and down in the array to find how much we want to print
149
150$start = $center;
151
152while ($start > 1) {
153	$start = $start - 1;
154	my $line = $lines[$start];
155	if ($line =~ /^([a-f0-9]+)\:/) {
156		$binarylines = $binarylines + 1;
157	} else {
158		$codelines = $codelines + 1;
159	}
160	if ($codelines > 10) {
161		last;
162	}
163	if ($binarylines > 20) {
164		last;
165	}
166}
167
168
169$finish = $center;
170$codelines = 0;
171$binarylines = 0;
172while ($finish < $counter) {
173	$finish = $finish + 1;
174	my $line = $lines[$finish];
175	if ($line =~ /^([a-f0-9]+)\:/) {
176		$binarylines = $binarylines + 1;
177	} else {
178		$codelines = $codelines + 1;
179	}
180	if ($codelines > 10) {
181		last;
182	}
183	if ($binarylines > 20) {
184		last;
185	}
186}
187
188
189my $i;
190
191my $fulltext = "";
192$i = $start;
193while ($i < $finish) {
194	if ($i == $center) {
195		$fulltext = $fulltext . "*$lines[$i]     <----- faulting instruction\n";
196	} else {
197		$fulltext = $fulltext .  " $lines[$i]\n";
198	}
199	$i = $i +1;
200}
201
202print $fulltext;
203
204