#!/usr/bin/perl ## sym-trace -- Really, its -*-perl-*-. ## ## Copyright (c) 1997-2000 University of Utah and the Flux Group. ## All rights reserved. ## ## This file is part of the Flux OSKit. The OSKit is free software, also known ## as "open source;" you can redistribute it and/or modify it under the terms ## of the GNU General Public License (GPL), version 2, as published by the Free ## Software Foundation (FSF). To explore alternate licensing terms, contact ## the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271. ## ## The OSKit 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 GPL for more details. You should have ## received a copy of the GPL along with the OSKit; see the file COPYING. If ## not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. ## ## ## Turn a stack trace into a list of function names. ## ## Expects a list in the format that backtrace() dumps it. ## By default looks at obj/kernel/fluke. You may want ## something different and should use the "-o " option ## to specifiy a different object/executable. Or, set the ## env var FLSYM_TARGET to the name of the object file. ## ## This script is tweaked and customized for the envronment here ## at the University of Utah. It is not a supported part of ## of the OSKit release (Tech Support just won't know what you're ## talking about.) You will have to customize it somewhat for ## your environment. ## open(HOSTNAME_HACK, "hostname|") || die "Can't exec 'hostname'\n"; $hostname = ; chop $hostname; close(HOSTNAME_HACK); #default object file $objectFile = $ENV{'FLSYM_TARGET'}; $objectFile = "obj/kernel/fluke" if ( "$objectFile" eq "" ) ; ## This gets replaced by configure. $nm = @NM@; if ($hostname eq "marker.cs.utah.edu") { $nm = "/usr/local/fluke/bin/i486-linux-nm"; } elsif ($hostname eq "fast.cs.utah.edu") { $nm = "/n/fast/usr/lsrc/mach/tools/i486-linux/bin/nm"; } ## Parse the command line arguments $inputFormat = 1; # default format while (@ARGV) { ## -o to use a different object file if ($ARGV[0] eq "-o") { if ($#ARGV >= 1) { $objectFile = $ARGV[1]; shift @ARGV; } else { &usage; } ## } elsif ($ARGV[0] eq "-oneline") { $inputFormat = 1; } elsif ($ARGV[0] eq "-perline") { $inputFormat = 0; ## -h for usage } elsif ($ARGV[0] eq "-h") { &usage; ## Unknown args are fatal } else { print "Unknown option $ARGV[0]\n"; &usage; } shift @ARGV; } -x $objectFile || die "$objectFile not found.\n"; ## yes this is bad.. just stick the whole output into ## the OBLIST array. Note that we make nm output in ## decimal, sorted by address open (NMOUT, "$nm --numeric-sort --radix=d $objectFile|"); @OBLIST = ; @BACKTRACE = ; @BACKTRACE || die "No stdin provided??\n"; $ct = 0; print "Generating backtrace for object file $objectFile\n"; while (@BACKTRACE) { $traceLine = shift @BACKTRACE; chop $traceLine; next if ($traceLine eq ""); if ($inputFormat == 0) { # If old, eip-per-line format ($bs, $eipStr) = split(/=/, $traceLine, 2); $eip = oct($eipStr); # Cvt from 0xNNN notation to _decimal_ &findFunction($eip); } else { # Else, the one line of eips format @eips = split(' ', $traceLine); foreach $eip (@eips) { $eipDec = oct("0x" . "$eip");# Cvt from hex NNN notation to _decimal_ &findFunction($eipDec); } } } # # Given an EIP, find the name of the corresponding function # (EIP should be in decimal) sub findFunction { local($eip) = @_; local($more, $index, $bestAddr, $bestFunc, $addr, $type, $proc); $more = 1; $index = 0; $bestAddr = -1; $bestFunc = "NOT FOUND"; while ($more && $eip && ($index <= $#OBLIST)) { $_ = $OBLIST[$index]; chop; ($addr, $type, $proc) = split(/ /, $_, 3); # List is sorted, so if we go beyond, then prev is answer. if ($addr > $eip) { $more = 0; } else { $bestFunc = $proc . "()"; $bestAddr = $addr; $index += 1; } } # If we didn't find a useful address... if ($index > $#OBLIST) { $bestFunc = ""; $bestAddr = 0; } if ($eip) { printf "0x%07x in (0x%07x) $bestFunc\n", $eip, $bestAddr; } } sub usage { print "sym-trace [-o ] [-perline] [-oneline] [-h]\n"; exit 0; }