Mail Archives: cygwin/2002/12/17/09:00:59
The attached script is an improved version of a script previously
posted. This one takes hex numbers on the command line and dumps
the associated dll symbol information. It is useful in determining
what functions are present in a stack trace.
The dll information is cached. Use --update to update the cache
(dll modify times are checked) or --rebuild to rebuild the cache
completely (all dll files are reexamined).
Change $CACHEFILE and @DLLDIRS to suit.
Joe Buehler
#!/usr/bin/perl
#
# find symbol and dll given an address
#
# You need "dumpbin" for this to work.
#
# Set @DLLDIRS to the list of directories in which you are interested.
# Set $CACHEFILE to the location of the cache file.
#
# coded by Joe Buehler (joseph DOT buehler AT spirentcom DOT com)
#
# $Id: find-dll-symbol,v 1.1 2002/12/17 13:56:08 jhpb Exp $
#
$CACHEFILE = "/usr/local/lib/dll-info";
@DLLDIRS = ("/bin", "/sys");
my @SYMBOL_INFO;
update_symbol_info();
for $arg (@ARGV) {
if ($arg eq "--rebuild") {
unlink($CACHEFILE);
update_symbol_info(1);
} elsif ($arg eq "--update") {
update_symbol_info(1);
} elsif ($arg =~ /^-/o) {
print STDERR "$0: $arg: unknown option\n";
exit(1);
} else {
find_symbol($arg);
}
}
sub update_symbol_info
{
my($force_rebuild) = @_;
my %dll_info;
my $modified = 0;
my $mtime_cache = 0;
my $cache_was_read = 0;
# don't do this if we have already done it
return if (@SYMBOL_INFO && !$force_rebuild);
# read in the cache file if it exists
if (-f $CACHEFILE) {
# get modify time for cache file
my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks) = stat(_);
$mtime_cache = $mtime;
# read in cache file
open(CACHE, "<$CACHEFILE");
while (<CACHE>) {
chomp;
my($start, $dll, $name) = split(/:/, $_, 3);
push(@{$dll_info{$dll}}, [hex($start), $dll, $name]);
push(@SYMBOL_INFO, [hex($start), $dll, $name]);
}
close(CACHE);
return unless $force_rebuild;
++$cache_was_read;
}
print STDERR "rebuilding cache...\n";
# update files for which there is no data in the cache or it is out of date
for $dlldir (@DLLDIRS) {
next unless -d "$dlldir";
opendir(DLLDIR, $dlldir);
while ($dll = readdir(DLLDIR)) {
next unless $dll =~ /[.]dll$/io;
next unless -f "$dlldir/$dll";
# normalize dll file name
$dll = lc $dll;
# check dll modify time vs. cache file
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks) = stat(_);
next if ((exists $dll_info{$dll}) && ($mtime < $mtime_cache));
print STDERR "*** updating $dlldir/$dll\n";
$modified = 1;
delete $dll_info{$dll};
push(@{$dll_info{$dll}}, [0, $dll, ""]);
open(DUMPBIN, qq{ cd '$dlldir' && dumpbin /headers /exports '$dll' | });
while (<DUMPBIN>) {
# remove line endings
s/\r*\n//o;
# discard blank lines
next if /^\s*$/o;
# process stuff in which we are interested
if (/^\s*(\S+)\s+image\s+base\s*$/io) {
$image_base_address = hex $1;
} elsif (/^\s+ordinal\s+hint\s+RVA\s+name\s*$/io .. /^\S/o) {
next if /^\s+ordinal\s+hint\s+RVA\s+name\s*$/io;
next if /^\S/io;
next unless ($ordinal, $hint, $RVA, $name) =
/^\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$/o;
push(@{$dll_info{$dll}}, [$image_base_address + hex($RVA), $dll, $name]);
}
}
close(DUMPBIN);
}
closedir(DLLDIR);
}
if ($modified) {
undef @SYMBOL_INFO;
for $info (values %dll_info) {
for (@$info) {
push(@SYMBOL_INFO, [@$_]);
}
}
@SYMBOL_INFO = sort { $$a[0] <=> $$b[0] } @SYMBOL_INFO;
open(CACHEFILE, ">$CACHEFILE");
for $info (@SYMBOL_INFO) {
printf CACHEFILE ("0x%08x:%s:%s\n", $$info[0], $$info[1], $$info[2]);
}
close(CACHEFILE);
}
}
sub find_symbol
{
my($address) = @_;
my $low = 0;
my $high = $#SYMBOL_INFO;
my $middle;
$address = hex($address);
# binary search to find symbols that match provided address
while ($low <= $high) {
$middle = int(($low + $high) / 2);
if ($address >= $SYMBOL_INFO[$middle][0] && ($middle >= $#SYMBOL_INFO || $address < $SYMBOL_INFO[$middle + 1][0])) {
my @out;
for ($m = $middle - 1; $m >= 0; --$m) {
last if ($SYMBOL_INFO[$m][0] != $SYMBOL_INFO[$middle][0]);
unshift(@out, sprintf("0x%08x %s %s\n", @{$SYMBOL_INFO[$m]}));
}
push @out, sprintf("0x%08x %s %s\n", @{$SYMBOL_INFO[$middle]});
for ($m = $middle + 1; $m <= $#SYMBOL_INFO; ++$m) {
last if ($SYMBOL_INFO[$m][0] != $SYMBOL_INFO[$middle][0]);
push(@out, sprintf("0x%08x %s %s\n", @{$SYMBOL_INFO[$m]}));
}
print STDERR @out;
last;
} elsif ( $address < $SYMBOL_INFO[$middle][0] ) {
$high = $middle - 1;
} else {
$low = $middle + 1;
}
}
}
#
# $Log: find-dll-symbol,v $
# Revision 1.1 2002/12/17 13:56:08 jhpb
# Initial revision
#
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Bug reporting: http://cygwin.com/bugs.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/
- Raw text -