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