#!/usr/bin/perl # call2sym - convert linux kernel oops call trace listings to System.map # symbolic names. # # Written by Phil Hollenback # Copyright (C) 2000 Phil Hollenback # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. # All other rights reserved. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # See the perlpod documentation at the end of this file for # instructions. # # $Id: call2sym,v 1.2 2000/09/28 20:15:59 phil Exp $ # # Configuration Options # # This will be viewable thru the "-v" switch at a later date. $version = "0.0.1"; # # End Configuration Options # # Check that we got passed a System.map file on the command line. (scalar(@ARGV) == 1) or $mapfile = "System.map"; (scalar(@ARGV) == 1) and $mapfile = $ARGV[0]; ( -r $mapfile ) or die "Can't read file $mapfile\n"; print "Ready for call trace list. on a blank line when done.\n\n"; while () { # remove newlines in case this was a cut-n-paste. chop; $trace_line .= $_; } print "\nProcessing...\n"; # Now munge call trace entries into an array. @trace_addrs = (); # Split into an array of addresses, on whitespace. @trace_addrs = split / /,$trace_line; # I think I'm clever, so use a map to remove cruft from each array # entry. @trace_addrs = map { m|\[<(.*)>\]| } @trace_addrs; # I now have an in-order array of the call trace addresses. # Suck the whole mapfile into a hash keyed on address. Convert keys to # decimal for easier compares later on. open MAPFILE, $mapfile or die "Can't open mapfile $mapfile\n"; while () { # $_ =~ s#^ffffffff##; # if ( /^00000000(.*) . (.*)/ ) if ( /^ffffffff(.*) . (.*)/ ) { # convert to decimal and pad to 10 digits. # that way everything lines up and conversions should be easy. $decaddr = sprintf "%010lu", hex($1); $funcs{$decaddr} = $2; } } # print a header print "\nAddress\t\tFunction\n\n"; # We've got all the addresses in the hash as string versions of # decimal numbers. Should now be able to iterate thru the # list until we find the one closest to each $addr. foreach $addr (@trace_addrs) { # convert addr to decimal. $decaddr = hex($addr); # loop through keys until we find the one just 1 greater. foreach $func (sort keys %funcs) { # now print out the one just 1 less. if ($func > $decaddr ) { print "$addr\t$funcs{$lastfunc}\n"; last; } $lastfunc = $func; } }