diff --git a/util/mksymtbl.pl b/util/mksymtbl.pl new file mode 100755 index 0000000000..b0fef5f42f --- /dev/null +++ b/util/mksymtbl.pl @@ -0,0 +1,113 @@ +#!/usr/bin/env perl + +# Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +# $Id: mksymtbl.pl,v 1.2 2009/09/01 18:50:52 jinmei Exp $ + +use strict; +use diagnostics; +$^W = 1; + +my $rev = '$Id: mksymtbl.pl,v 1.2 2009/09/01 18:50:52 jinmei Exp $'; +$rev =~ s/\$//g; +$rev =~ s/,v//g; +$rev =~ s/Id: //; + +use Getopt::Std; +my %options; +getopts('i:o:', \%options); + +my ($binname, $need_uscorefix, $outputfile, $nsyms, $ostype, $nm_prog); +my %symmap; + +$binname = $ARGV[0]; +$need_uscorefix = 0; +if ($options{'o'}) { + $outputfile = $options{'o'}; +} else { + $outputfile = "symtbl.c"; +} + +# OS-depending configuration +$nm_prog = "nm"; +$ostype = `uname -s`; +chop($ostype); +if ($ostype eq "SunOS" || $ostype eq "HP-UX") { + $nm_prog = "/usr/ccs/bin/nm -x" +} + +if ($options{'i'}) { + open(SYMBOLS, $options{'i'}) || die "failed to open $options{'i'}"; +} else { + open(SYMBOLS, "$nm_prog $binname |") || + die "failed to invoke utility to get symbols"; +} +open(TBLFILE, ">$outputfile") || die "failed to open output file: $outputfile"; + +$nsyms = 0; +while () { + my ($addr, $symbol) = (0, ""); + if ($ostype eq "SunOS") { + if (/\[\d*\]\s*\|\s*0x([0-9a-f]*)\|\s*0x[0-9a-f]*\|FUNC\s*(.*)\|([^|]+)$/) { + next if ($2 =~ /UNDEF/); # skip undefined symbols + $addr = $1; + $symbol = $3; + chop($symbol); + } + } elsif ($ostype eq "HP-UX") { + if (/(\S*)\s*\|0x([0-9a-f]*)\|([^|]*\|entry|extern\|code)/) { + $addr = $2; + $symbol = $1; + # this filter catches a massive number of awkward + # symbols such as "$START$". we are not interested in + # those and ignore them. + next if ($symbol =~ /\$/); + } + } else { + # *BSDs, Linux, etc. + if (/([0-9a-f]*)\s[tT]\s(.*)/) { + ($addr, $symbol) = ($1, $2); + # heuristics: some compilers add a "_" to all program + # defined symbols. Detect and fix it for a well known + # symbol of "main". + $need_uscorefix = 1 if ($symbol eq "_main"); + } + } + if ($symbol ne "") { + # XXX: HP-UX's nm can produce a duplicate entry for the same + # address. Ignore duplicate entries except the first one. + next if ($symmap{$addr}); + + $symmap{$addr} = $symbol; + $nsyms++; + } +} + +print TBLFILE "/*\n * Generated by $rev \n */\n"; +print TBLFILE "#include \n"; +print TBLFILE "const int isc__backtrace_nsymbols = $nsyms;\n"; +print TBLFILE "const isc_backtrace_symmap_t isc__backtrace_symtable[] = {\n"; +foreach (sort {hex($a) <=> hex($b)} keys(%symmap)) { + my ($addr, $symbol) = ($_, $symmap{$_}); + if ($need_uscorefix && $symbol =~ /^_(.*)/) { + $symbol = $1; + } + print TBLFILE "\t{ (void *)0x$addr, \"$symbol\" },\n"; +} +print TBLFILE "\t{ (void *)0x0, \"\" },\n"; +print TBLFILE "};\n"; + +close(TBLFILE); +close(SYMBOLS);