#!/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.4 2009-10-05 22:39:09 jinmei Exp $ use strict; use diagnostics; $^W = 1; my $rev = '$Id: mksymtbl.pl,v 1.4 2009-10-05 22:39:09 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);