blob: d40449cafa84a44dac9f21c54364913c777ffc6d [file] [log] [blame]
Arjan van de Ven5aea50b2009-01-06 14:40:57 -08001#!/usr/bin/perl -w
2
Arjan van de Vend32ad102009-01-11 15:03:23 +00003use File::Basename;
4
Arjan van de Ven5aea50b2009-01-06 14:40:57 -08005# 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];
Arjan van de Vend32ad102009-01-11 15:03:23 +000018if (!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;
Arjan van de Ven5aea50b2009-01-06 14:40:57 -080025#
26# Step 1: Parse the oops to find the EIP value
27#
28
29my $target = "0";
Arjan van de Vend32ad102009-01-11 15:03:23 +000030my $function;
31my $module = "";
32my $func_offset;
33my $vmaoffset = 0;
34
Arjan van de Ven5aea50b2009-01-06 14:40:57 -080035while (<STDIN>) {
Arjan van de Vend32ad102009-01-11 15:03:23 +000036 my $line = $_;
37 if ($line =~ /EIP: 0060:\[\<([a-z0-9]+)\>\]/) {
Arjan van de Ven5aea50b2009-01-06 14:40:57 -080038 $target = $1;
39 }
Arjan van de Vend32ad102009-01-11 15:03:23 +000040 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 }
Arjan van de Ven5aea50b2009-01-06 14:40:57 -080049}
50
Arjan van de Vend32ad102009-01-11 15:03:23 +000051my $decodestart = hex($target) - hex($func_offset);
52my $decodestop = $decodestart + 8192;
Arjan van de Ven5aea50b2009-01-06 14:40:57 -080053if ($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
Arjan van de Vend32ad102009-01-11 15:03:23 +000060# 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
Arjan van de Ven5aea50b2009-01-06 14:40:57 -080083my $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
Arjan van de Vend32ad102009-01-11 15:03:23 +0000105open(FILE, "objdump -dS --adjust-vma=$vmaoffset --start-address=$decodestart --stop-address=$decodestop $filename |") || die "Cannot start objdump";
Arjan van de Ven5aea50b2009-01-06 14:40:57 -0800106
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