pjs/cmd/xfe/listsymb.pl

224 строки
6.2 KiB
Perl

########################################################
# listsymb.pl
# Generates a list of all global C function names
# defined in Communicator except those with
# unwanted prefix specified below.
#
########################################################
# Functions with the following prefixes will not be listed.
# DISPT_GetDispatchTable & DISPT_NumDispatchPoints are exported
# using linker facilities and should always be filtered.
@unwanted_prefixes = ("__","Java_","java_","awt_","sun_","PR_", "PL_", "LL_",
"DISPT_GetDispatchTable", "DISPT_NumDispatchPoints");
@objfiles = ();
@symbols = ();
$debug = 0;
#Step 1: Get command line options
$input_file = $ARGV[0];
$output_file = $ARGV[1];
UsageAndExit() if (scalar(@ARGV) != 2);
# Step 2: Open output file for output
open (SYMB_LIST, ">$output_file") or die("Can't open \"$output_file\" for writing.\n");
# Step 3: Read input file to determine list of all obj / lib files
# needed to link the executable
GetObjFileList($input_file, \@objfiles);
# Step 4: Run NM on every single obj / lib file
# to get the complelete list of global functions
CallNM(\@objfiles, \@symbols);
# Step 5: Put all the symbols in output file
foreach (@symbols) {
print SYMB_LIST ("$_\n");
}
# --------------- Sub-Routines -----------------
#
sub UsageAndExit {
print ("Usage: perl gendisp.pl <list of obj files> <symbol list>\n");
exit(-1);
}
# CallNM calls nm on each file in objfiles
# and finds out all symbols defined in them.
# The list of symbols is returned.
sub CallNM {
my($objfiles) = $_[0];
my($symbols) = $_[1];
my(%unique) = ();
foreach (@{$objfiles}) {
my($file) = $_;
my(@results) = ();
# if such file exists, call nm
# otherwise, print a warning
if (-f $file) {
# nm -g prints only global symbols
# nm --demangle demangles C++ names
@results = `nm --demangle -g $file`;
foreach (@results) {
my($symbol) = ExtractFunctionSymbol($_);
if ($symbol ne "") {
$unique{$symbol} = "exists";
}
}
}
}
foreach (sort(keys(%unique))) {
$symbol = FilterUnwantedPrefix($_);
push(@{$symbols}, ($symbol)) if $symbol ne "";
}
}
sub IsObjFile {
# if 1st argument ends with .o .a or .so
if ($_[0] =~ m/\.(o)|\.(a)|\.(so)\s*$/) {
$firstchar = substr($_[0], 0, 1);
return $_[0] if $firstchar ne '/';
}
return "";
}
sub IsLibFile {
($_[0] =~ m/^\s*-l\s*(.+)\s*$/);
return $1;
}
sub IsLibPath {
# if begins with -L, it's a path
if ($_[0] =~ m/^\s*-L\s*(.+)\s*$/) {
# Igore absolute path, because they
# tend to be system libraries
$firstchar = substr($1, 0, 1);
return "" if ($firstchar eq '/');
# Make sure it ends with a '/'
# so that appending it to filename will work
$lastchar = substr($1, length($1)-1, 1);
return (($lastchar eq '/')? $1 : $1.'/');
} else {
return "";
}
}
# FilterUnwantedPrefix() returns 1st argument
# if
# its prefix doesn't match any of those
# defined in @unwanted_prefixes
# and
# it contains at least at least 1 upper-case letter or
# an underscore.
sub FilterUnwantedPrefix {
if ($_[0] !~ m/[A-Z_]/) {
print ("Warning: $_[0] is probably a system symbol, and so filtered.\n") if $debug > 1;
return "";
}
foreach $prefix (@unwanted_prefixes) {
if ($_[0] =~ m/^$prefix/) {
return "";
}
}
return $_[0];
}
# Returns a non-empty string if the line contains a function symbol
# Returns an empty string otherwise
# Note: a line containing a function symbol looks like this:
# 048 00000000 SECTA notype () External | _lm_DefinePkcs11
# This function searches for entries that contains SECT,(),External
sub ExtractFunctionSymbol {
if ($_[0] =~ m/ T (\w+)\s*$/) {
print ("Matched :$_[0]\n") if $debug > 1;
return $1;
} else {
print ("Not Matched:$_[0]\n") if $debug > 1;
return "";
}
}
# GetObjFileLIst reads in a file containing LINK options
# and returns the list of .obj & .lib files in 1st argu
sub GetObjFileList {
my($objfiles) = $_[1]; # path to .o's, .a's, and .so's
my @libpath = (); # -Lstuff
my @libfiles = ();# -lstuff
my @junkoptions = (); # any other options
# 1. Separate different kinds of options
open (OBJS_LIST, $_[0]) or die ("Can't open $_[0] for reading.\n");
while ($line = <OBJS_LIST>) {
# For each line, break up into words
$line =~ s/^\s+//; # eat white spaces at beginning of line
@words = split(/\s+/, $line);
foreach (@words) {
if (IsObjFile($_) ne "") {
# If the option ends with .so, .a , or .o,
# assume it is an object file to be linked in.
print ("SEPARATE: $_ is obj file.\n") if $debug;
push(@{$objfiles}, ($_));
} elsif (($temp = IsLibPath($_)) ne "") {
# If begins with -L
print ("SEPARATE: $_ is -L$temp.\n") if $debug;
push(@libpath, $temp);
} elsif (($temp = IsLibFile($_)) ne "") {
# If begins with -l
print ("SEPARATE: $_ is -l$temp.\n") if $debug;
push(@libfiles, $temp);
} else {
# Unrecognized Options
print ("SEPARATE: $_ option ignored.\n") if $debug;
push(@junkoptions, $_);
}
}
}
# 2. check to see if .a or .so exists under the specified path
foreach (@libfiles) {
if (-f $_) { #file exists?
push (@{$objfiles}, $_);
} else {
#file doesn't exist, try prepending libpath prefix
$file = $_;
$found = 0;
foreach (@libpath) {
if (-f $_."lib".$file.".a") {
print ("SEARCH: $_+lib+$file+.a found.\n") if $debug;
push (@{$objfiles}, $_."lib".$file.".a");
$found = 1;
last;
} elsif (-f $_."lib".$file.".so") {
print ("SEARCH: $_+lib+$file+.so found.\n") if $debug;
push (@{$objfiles}, $_."lib".$file.".so");
$found = 1;
last;
}
}
if ($found == 0) {
print ("SEARCH: $file not found.\n") if $debug;
}
}
}
# 3. Returns the list of all object, .a, .so files
foreach (@{$objfiles}) {
print ("OBJ: $_\n") if $debug;
}
}