Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com X-Injected-Via-Gmane: http://gmane.org/ To: cygwin AT cygwin DOT com Path: not-for-mail From: Joe Buehler Subject: [SCRIPT] find-dll-symbol Date: Tue, 17 Dec 2002 09:00:08 -0500 Lines: 187 Message-ID: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit X-Complaints-To: usenet AT main DOT gmane DOT org User-Agent: Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.2) Gecko/20021126 X-Accept-Language: en-us, en 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 () { 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 () { # 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/