######################################################## # 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 \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 = ) { # 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; } }