8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / sgs / lari / lari.pl
blob7a1683bac96e341420185f00983781ce661da9f5
1 #!/usr/perl5/bin/perl -w
3 # CDDL HEADER START
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
20 # CDDL HEADER END
24 # Copyright 2010 Sun Microsystems, Inc. All rights reserved.
25 # Use is subject to license terms.
27 # Link Analysis of Runtime Interfaces.
30 # Define all global variables (required for strict)
31 use vars qw($Prog $DestDir $ObjRef $ObjFlag $ObjSize $ObjVis $TmpDir);
32 use vars qw($LddArgs $SymFlag);
33 use vars qw($Glob $Intp $Dirc $Cpyr $Prot $Extn $Self $Gfte $Plta $User $Func);
34 use vars qw($Rejt $Sfte $Afte $Objt $Nodi $Osft $Oaft $Ssft $Saft $Msft);
35 use vars qw($Rtld $GlobWeak $MultSyms $CrtSyms $Platform $DbgSeed %opt);
37 # Global arrays that must be cleared for multi input file use.
38 use vars qw(%Symbols %Objects %Versioned %DemSyms %ObjFltrs %SymFltes);
40 use strict;
42 use Getopt::Std;
43 use File::Basename;
45 # Pattern match to skip the runtime linker.
46 $Rtld = qr{
47 /lib/ld\.so\.1 |
48 /usr/lib/ld\.so\.1 |
49 /lib/sparcv9/ld\.so\.1 |
50 /usr/lib/sparcv9/ld\.so\.1 |
51 /lib/amd64/ld\.so\.1 |
52 /usr/lib/amd64/ld\.so\.1
53 }x;
55 # Pattern matching required to determine a global symbol.
56 $GlobWeak = qr{ ^(?:
57 GLOB |
58 WEAK
60 }x;
62 # Pattern matching to determine link-editor specific symbols and those common
63 # to the compilation environment (ie. provided by all crt's).
64 $MultSyms = qr{ ^(?:
65 _DYNAMIC |
66 _GLOBAL_OFFSET_TABLE_ |
67 _PROCEDURE_LINKAGE_TABLE_ |
68 _etext |
69 _edata |
70 _end |
71 _init |
72 _fini |
73 _lib_version | # Defined in values
74 __xpg4 | # Defined in values
75 __xpg6 # Defined in values
77 }x;
79 $CrtSyms = qr{ ^(?:
80 ___Argv | # Defined in crt
81 __environ_lock | # Defined in crt
82 _environ | # Defined in crt
83 environ # Defined in crt
85 }x;
87 # Symbol flags.
88 $Glob = 0x00001; # symbol is global
89 $Sfte = 0x00002; # symbol is a filtee backing a standard filter
90 $Afte = 0x00004; # symbol is a filtee backing a auxiliary filter
91 $Gfte = 0x00008; # symbol bound as a filtee
92 $Intp = 0x00010; # symbol originates from explicit interposer
93 $Dirc = 0x00020; # symbol bound to directly
94 $Cpyr = 0x00040; # symbol bound to copy-relocation reference
95 $Prot = 0x00080; # symbol is protected (symbolic)
96 $Extn = 0x00100; # symbol has been bound to from an external reference
97 $Self = 0x00200; # symbol has been bound to from the same object
98 $Rejt = 0x00400; # symbol binding was (at some point) rejected
99 $Plta = 0x00800; # symbol bound to executables plt address
100 $User = 0x01000; # symbol binding originates from user (dlsym) request
101 $Func = 0x02000; # symbol is of type function
102 $Objt = 0x04000; # symbol is of type object
103 $Nodi = 0x08000; # symbol prohibits direct binding
105 $Osft = 0x10000; # symbol is an standard object filter
106 $Oaft = 0x20000; # symbol is an auxiliary object filter
107 $Ssft = 0x40000; # symbol is a per-symbol standard filter
108 $Saft = 0x80000; # symbol is a per-symbol auxiliary filter
109 $Msft = 0xf0000; # filter mask
111 # Offsets into $Symbols{$SymName}{$Obj} array.
112 $ObjRef = 0;
113 $ObjFlag = 1;
114 $ObjSize = 2;
115 $ObjVis = 3;
117 # Offset into $SymFltr{$SymName}{$Filtee} array.
118 $SymFlag = 0;
120 # Establish locale
121 use POSIX qw(locale_h);
122 use Sun::Solaris::Utils qw(textdomain gettext);
124 setlocale(LC_ALL, "");
125 textdomain("SUNW_OST_SGS");
127 # Establish a program name for any error diagnostics.
128 $Prog = basename($0);
130 sub inappropriate {
131 my ($Opt1, $Opt2, $Flag) = @_;
133 if ($Flag) {
134 printf STDERR
135 gettext("%s: inappropriate use of %s with %s: %s ignored\n"),
136 $Prog, $Opt1, $Opt2, $Opt1;
137 } else {
138 printf STDERR
139 gettext("%s: inappropriate use of %s without %s: %s ignored\n"),
140 $Prog, $Opt1, $Opt2, $Opt1;
144 # Cleanup any temporary files on interruption.
145 sub Cleanup {
146 my ($Sig) = @_;
148 $SIG{$Sig} = 'IGNORE';
150 if ($DbgSeed ne "") {
151 foreach my $File (<\Q${DbgSeed}\E.*>) {
152 if ($File =~ /^\Q$DbgSeed\E\.\d+$/) {
153 unlink($File);
157 exit 1;
160 # Check that we have arguments.
161 if ((getopts('abCDd:imosVv', \%opt) == 0) || ($#ARGV < 0)) {
162 printf STDERR gettext("usage:\n");
163 printf STDERR
164 gettext(" %s [-bCDsVv] [-a | -i | -o ] file | dir ...\n"), $Prog;
165 printf STDERR
166 gettext(" %s [-CDosVv] [-m [-d mapdir]] file\n"), $Prog;
167 print STDERR
168 gettext("\t[-a] print diagnostics for all symbols\n");
169 print STDERR
170 gettext("\t[-b] limit diagnostics to bound symbols\n");
171 print STDERR
172 gettext("\t[-C] print demangled symbol names also\n");
173 print STDERR
174 gettext("\t[-D] read debugging information from \"file\"\n");
175 print STDERR
176 gettext("\t[-d dir] create mapfiles in \"mapdir\"\n");
177 print STDERR
178 gettext("\t[-i] print interesting information (default)\n");
179 print STDERR
180 gettext("\t[-m] create mapfiles for interface requirements\n");
181 print STDERR
182 gettext("\t[-o] limit diagnostics to overhead information\n");
183 print STDERR
184 gettext("\t[-s] save bindings information created by ldd(1)\n");
185 print STDERR
186 gettext("\t[-V] append interesting symbol visibilities\n");
187 print STDERR
188 gettext("\t[-v] ignore versioned objects\n");
189 exit 1;
190 } else {
191 my ($Mult, $Error);
193 # Catch any incompatible argument usage.
194 if ($opt{m}) {
195 if ($opt{a}) {
196 inappropriate("-a", "-m", 1);
197 $opt{a} = 0;
199 if ($opt{i}) {
200 inappropriate("-i", "-m", 1);
201 $opt{i} = 0;
203 } else {
204 if ($opt{d}) {
205 inappropriate("-d", "-m", 0);
206 $opt{d} = 0;
209 if ($opt{a}) {
210 if ($opt{o}) {
211 inappropriate("-a", "-o", 1);
212 $opt{o} = 0;
214 if ($opt{i}) {
215 inappropriate("-a", "-i", 1);
216 $opt{i} = 0;
219 if ($opt{o}) {
220 if ($opt{i}) {
221 inappropriate("-o", "-i", 1);
222 $opt{i} = 0;
224 if ($opt{b}) {
225 inappropriate("-o", "-b", 1);
226 $opt{b} = 0;
230 # If -m is used, only one input file is applicable.
231 if ($opt{m} && ($#ARGV != 0)) {
232 printf STDERR gettext("%s: only one input file is allowed " .
233 "with the -m option\n"), $Prog;
234 exit 1;
237 # Insure any specified directory exists, or apply a default.
238 if ($opt{d}) {
239 # User specified directory - make sure it exists.
240 if (! -d $opt{d}) {
241 printf STDERR gettext("%s: %s is not a directory\n"),
242 $Prog, $opt{d};
243 exit 1;
245 $DestDir = $opt{d};
246 } else {
247 $DestDir = ".";
250 # Establish a temporary directory if necessary.
251 if (!$opt{D}) {
252 if (!($TmpDir = $ENV{TMPDIR}) || (! -d $TmpDir)) {
253 $TmpDir = "/tmp";
257 # Establish any initial ldd(1) argument requirements.
258 if ($LddArgs = $ENV{LARI_LDD_ARGS}) {
259 $LddArgs = $LddArgs . ' -r -e LD_DEBUG=bindings,files,detail';
260 } else {
261 $LddArgs = '-r -e LD_DEBUG=bindings,files,detail';
264 # If we've been asked to demangle symbols, make sure we can find the
265 # demangler.
266 if ($opt{C}) {
267 my ($DemName) = `dem XXXX 2> /dev/null`;
268 if (!$DemName) {
269 printf STDERR gettext("%s: can not locate demangler: " .
270 "-C ignored\n"), $Prog;
271 $opt{C} = 0;
275 # If -a or -o hasn't been specified, default to -i.
276 if (!$opt{a} && !$opt{o}) {
277 $opt{i} = 1;
280 # Determine whether we have multiple input files.
281 if ($#ARGV == 0) {
282 $Mult = 0;
283 } else {
284 $Mult = 1;
287 # Determine what platform we're running on - some inappropriate
288 # platform specific dependencies are better skipped.
289 chomp($Platform = `uname -i`);
291 # Establish signal handlers
292 $SIG{INT} = \&Cleanup;
293 $SIG{QUIT} = \&Cleanup;
295 $DbgSeed = "";
297 # For each argument determine if we're dealing with a file or directory.
298 $Error = 0;
299 foreach my $Arg (@ARGV) {
300 if (!stat($Arg)) {
301 printf STDERR gettext("%s: %s: unable to stat file\n"),
302 $Prog, $Arg;
303 $Error = 1;
304 next;
307 # Process simple files.
308 if (-f _) {
309 if (!-r _) {
310 printf STDERR gettext("%s: %s: unable to " .
311 "read file\n"), $Prog, $Arg;
312 $Error = 1;
313 next;
315 if (!$opt{D}) {
316 if (ProcFile($Arg, $Mult, 1) == 0) {
317 $Error = 1;
319 } else {
320 # If the -D option is specified, read the
321 # bindings debugging information from the
322 # specified file.
323 if ($Mult) {
324 print STDOUT "$Arg:\n";
326 ProcBindings($Arg, $Mult, $Arg);
328 next;
331 # Process directories.
332 if (-d _) {
333 ProcDir($Arg);
334 next;
337 printf STDERR gettext("%s: %s: is not a file or directory\n"),
338 $Prog, $Arg;
339 $Error = 1;
341 exit $Error;
344 sub ProcDir {
345 my ($Dir) = @_;
346 my ($File);
348 # Open the directory and read each entry, omit "." and "..". Sorting
349 # the directory listing makes analyzing different source hierarchies
350 # easier.
351 if (opendir(DIR, $Dir)) {
352 foreach my $Entry (sort(readdir(DIR))) {
353 if (($Entry eq '.') || ($Entry eq '..')) {
354 next;
357 # If we're descending into a platform directory, ignore
358 # any inappropriate platform specific files. These
359 # files can have dependencies that in turn bring in the
360 # appropriate platform specific file, resulting in more
361 # than one dependency offering the same interfaces. In
362 # practice, the non-appropriate platform specific file
363 # wouldn't be loaded with a process.
364 if (($Dir =~ /\/platform$/) &&
365 ($Entry !~ /^$Platform$/)) {
366 next;
369 $File = "$Dir/$Entry";
370 if (!lstat($File)) {
371 next;
373 # Ignore symlinks.
374 if (-l _) {
375 next;
378 # Descend into, and process any directories.
379 if (-d _) {
380 ProcDir($File);
381 next;
384 # Process any standard files.
385 if (-f _ && -r _) {
386 ProcFile($File, 1, 0);
387 next;
391 closedir(DIR);
395 # Process a file. If the file was explicitly defined on the command-line, and
396 # an error occurs, tell the user. Otherwise, this file probably came about from
397 # scanning a directory, in which case just skip it and move on.
398 sub ProcFile {
399 my ($File, $Mult, $CmdLine) = @_;
400 my (@Ldd, $NoFound, $DbgFile, @DbgGlob, $Type);
402 # If we're scanning a directory (ie. /lib) and have picked up ld.so.1,
403 # ignore it.
404 if (($CmdLine eq 0) && ($File =~ $Rtld)) {
405 return 1;
408 $Type = `LC_ALL=C file '$File' 2>&1`;
409 if (($Type !~ /dynamically linked/) || ($Type =~ /Sun demand paged/)) {
410 if ($CmdLine) {
411 printf STDERR gettext("%s: %s: is an invalid file " .
412 "type\n"), $Prog, $File;
414 return 0;
417 # Create a temporary filename for capturing binding information.
418 $DbgSeed = basename($File);
419 $DbgSeed = "$TmpDir/lari.dbg.$$.$DbgSeed";
421 # Exercise the file under ldd(1), capturing all the bindings.
422 @Ldd = split(/\n/,
423 `LC_ALL=C ldd $LddArgs -e LD_DEBUG_OUTPUT='$DbgSeed' '$File' 2>&1`);
425 # If ldd isn't -e capable we'll get a usage message. The -e option was
426 # introduced in Solaris 9 and related patches. Also, make sure the user
427 # sees any ldd errors.
428 $NoFound = 0;
429 for my $Line (@Ldd) {
430 if ($Line =~ /^usage: ldd/) {
431 printf STDERR gettext("%s: ldd: does not support -e, " .
432 "unable to capture bindings output\n"), $Prog;
433 exit 1;
435 if ($Line =~ /not found/) {
436 $NoFound = 1;
437 last;
441 # The runtime linker will have appended a process id to the debug file.
442 # As we have to intuit the name, make sure there is only one debug
443 # file match, otherwise there must be some clutter in the output
444 # directory that is going to mess up our analysis.
445 foreach my $Match (<\Q${DbgSeed}\E.*>) {
446 if ($Match =~ /^\Q$DbgSeed\E\.\d+$/) {
447 push(@DbgGlob, $Match);
450 if (@DbgGlob == 0) {
451 # If there is no debug file, bail. This can occur if the file
452 # being processed is secure.
453 if ($CmdLine) {
454 printf STDERR gettext("%s: %s: unable to capture " .
455 "bindings output - possible secure application?\n"),
456 $Prog, $File;
458 return 0;
459 } elsif (@DbgGlob > 1) {
460 # Too many debug files found.
461 if ($CmdLine) {
462 printf STDERR gettext("%s: %s: multiple bindings " .
463 "output files exist: %s: clean up temporary " .
464 "directory\n"), $Prog, $File, $DbgSeed;
466 return 0;
467 } else {
468 $DbgFile = $DbgGlob[0];
471 # Ok, we're ready to process the bindings information. Print a header
472 # if necessary, and if there were any ldd(1) errors push some of them
473 # out before any bindings information. Limit the output, as it can
474 # sometimes be excessive. If there are errors, the bindings information
475 # is likely to be incomplete.
476 if ($Mult) {
477 print STDOUT "$File:\n";
479 if ($NoFound) {
480 my ($Cnt) = 4;
482 for my $Line (@Ldd) {
483 if ($Line =~ /not found/) {
484 print STDOUT "$Line\n";
485 $Cnt--;
487 if ($Cnt == 0) {
488 print STDOUT gettext("\tcontinued ...\n");
489 last;
494 # If the user wants the original debugging file left behind, rename it
495 # so that it doesn't get re-read by another instance of lari processing
496 # this file.
497 if ($opt{s}) {
498 rename($DbgFile, $DbgSeed);
499 $DbgFile = $DbgSeed;
500 printf STDOUT gettext("%s: %s: bindings information " .
501 "saved as: %s\n"), $Prog, $File, $DbgFile;
504 ProcBindings($File, $Mult, $DbgFile);
506 # Now that we've finished with the debugging file, nuke it if necessary.
507 if (!$opt{s}) {
508 unlink($DbgFile);
510 $DbgSeed = "";
511 return 1;
514 sub ProcBindings {
515 my ($File, $Mult, $DbgFile) = @_;
516 my (%Filtees, $FileHandle);
518 # Reinitialize our arrays when we're dealing with multiple files.
519 if ($Mult) {
520 %Symbols = ();
521 %Objects = ();
522 %Versioned = ();
523 %DemSyms = ();
524 %ObjFltrs = ();
525 %SymFltes = ();
528 # As debugging output can be significant, read a line at a time.
529 open($FileHandle, "<$DbgFile");
530 while (defined(my $Line = <$FileHandle>)) {
531 chomp($Line);
533 # Collect the symbols from any file analyzed.
534 if ($Line =~ /^.*: file=(.*); analyzing .*/) {
535 GetAllSymbols($1);
536 next;
539 # Process any symbolic relocations that bind to a file.
540 if ($Line =~ /: binding file=.* to file=/) {
541 my ($RefFile, $DstFile, $SymName);
542 my (@Syms, $Found, @Fields);
543 my ($BndInfo) = 0;
544 my ($Offset) = 1;
545 my ($Dlsym) = 0;
546 my ($Detail) = 0;
548 # For greatest flexibility, split the line into fields
549 # and walk each field until we find what we need.
550 @Fields = split(' ', $Line);
552 # The referencing file, "... binding file=.* ".
553 while ($Fields[$Offset]) {
554 if ($Fields[$Offset] =~ /^file=(.*)/) {
555 $RefFile = $1;
556 $Offset++;
557 last;
559 $Offset++;
561 # The referencing offset, typically this is the address
562 # of the reference, "(0x1234...)", but in the case of a
563 # user lookup it's the string "(dlsym)". If we don't
564 # find this offset information we've been given a debug
565 # file that didn't use the "detail" token, in which case
566 # we're not getting all the information we need.
567 if ($Fields[$Offset] =~ /^\((.*)\)/) {
568 if ($1 eq 'dlsym') {
569 $Dlsym = 1;
571 $Detail = 1;
572 $Offset++;
574 # The destination file, "... to file=.* ". Note, in the
575 # case of a rejection message, the file is terminated
576 # with a colon, "... to file=.*: ", which must be
577 # removed
578 while ($Fields[$Offset]) {
579 if ($Fields[$Offset] =~ /^file=(.*)/) {
580 $DstFile = $1;
581 $DstFile =~ s/:$//;
582 $Offset++;
583 last;
585 $Offset++;
587 # The symbol being bound. Over the years, we have used
588 # a ` quoting style, and more recently a ' style.
589 # Match either of:
590 # "... symbol `.*' ...".
591 # "... symbol '.*' ...".
592 while ($Fields[$Offset]) {
593 if ($Fields[$Offset] =~ /^(\`|\')(.*)\'$/) {
594 $SymName = $2;
595 $Offset++;
596 last;
598 $Offset++;
600 # Possible trailing binding info, "... (direct,...", or
601 # a rejection, "... (rejected - ...".
602 while ($Fields[$Offset]) {
603 if ($Fields[$Offset] =~ /^\((.*)/) {
604 $BndInfo = $1;
605 $Detail = 1;
606 $Offset++;
607 last;
609 $Offset++;
612 if ($Detail == 0) {
613 printf STDERR gettext("%s: %s: debug file " .
614 "does not contain `detail' information\n"),
615 $Prog, $DbgFile;
616 return;
619 # Collect the symbols from each object.
620 GetAllSymbols($RefFile);
621 GetAllSymbols($DstFile);
623 # Identify that this definition has been bound to.
624 $Symbols{$SymName}{$DstFile}[$ObjRef]++;
625 if ($RefFile eq $DstFile) {
626 # If the reference binds to a definition within
627 # the same file this symbol may be a candidate
628 # for reducing to local.
629 $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Self;
630 $Objects{$DstFile}{$SymName} |= $Self;
631 } else {
632 # This symbol is required to satisfy an external
633 # reference.
634 $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Extn;
635 $Objects{$DstFile}{$SymName} |= $Extn;
638 # Assign any other state indicated by the binding info
639 # associated with the diagnostic output.
640 if (!$BndInfo) {
641 next;
644 if ($BndInfo =~ /direct/) {
645 $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Dirc;
646 $Objects{$DstFile}{$SymName} |= $Dirc;
648 if ($BndInfo =~ /copy-ref/) {
649 $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Cpyr;
650 $Objects{$DstFile}{$SymName} |= $Cpyr;
652 if ($BndInfo =~ /filtee/) {
653 $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Gfte;
654 $Objects{$DstFile}{$SymName} |= $Gfte;
656 if ($BndInfo =~ /interpose/) {
657 $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Intp;
658 $Objects{$DstFile}{$SymName} |= $Intp;
660 if ($BndInfo =~ /plt-addr/) {
661 $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Plta;
662 $Objects{$DstFile}{$SymName} |= $Plta;
664 if ($BndInfo =~ /rejected/) {
665 $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Rejt;
666 $Objects{$DstFile}{$SymName} |= $Rejt;
668 if ($Dlsym) {
669 $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $User;
670 $Objects{$DstFile}{$SymName} |= $User;
674 close($FileHandle);
676 # Now that we've processed all objects, traverse the set of object
677 # filters that have been captured from parsing any FILTER and AUXILIARY
678 # dynamic tags. For each filtee, determine which of the symbols it
679 # exports are also defined in the filter. If a filter is bound to, the
680 # runtime linkers diagnostics will indicate a filtee binding. However,
681 # some of the filtee symbols may not be bound to, so here we mark them
682 # all so as to remove them from any interesting output.
683 for my $Filter (keys(%ObjFltrs)) {
685 # Determine the filtees that are associated with this filter.
686 for my $Filtee (keys(%{$ObjFltrs{$Filter}})) {
687 my ($FileName);
689 # Reduce the filtee to a simple file name. Then, try
690 # and associate this simple file name with the objects
691 # that have been processed. These objects are typically
692 # recorded with a full path name.
693 chomp($FileName = `basename $Filtee`);
694 for my $Obj (keys(%Objects)) {
695 if ($Obj =~ /\/$FileName$/) {
696 $Filtee = $Obj;
697 last;
701 if (!exists($Objects{$Filtee})) {
702 next;
705 # Traverse the symbols of the filtee (these are
706 # typically a smaller set than the filter) and if the
707 # symbol is defined by the filter tag the symbol as a
708 # filtee.
709 for my $SymName (keys(%{$Objects{$Filtee}})) {
710 my ($OFlag, $FFlag);
712 # Ignore the usual stuff.
713 if (($SymName =~ $MultSyms) ||
714 ($SymName =~ $CrtSyms)) {
715 next;
718 if (!$Symbols{$SymName}{$Filter}) {
719 next;
722 # Determine the type of filter.
723 $OFlag = $Symbols{$SymName}{$Filter}[$ObjFlag];
725 # Specifically identify the type of filtee we
726 # have and remove any generic filtee flag.
727 if ($OFlag & ($Osft | $Ssft)) {
728 $FFlag = $Sfte;
729 } else {
730 $FFlag = $Afte;
733 $Symbols{$SymName}{$Filtee}[$ObjFlag] |= $FFlag;
734 $Symbols{$SymName}{$Filtee}[$ObjFlag] &= ~$Gfte;
739 # Traverse the set of per-symbol filters making sure we've tagged any
740 # associated filtee symbols, as we did above for object filters.
741 for my $Filtee (keys(%SymFltes)) {
742 my ($FullPath) = $Filtee;
743 my ($FileName);
745 # Reduce the filtee to a simple file name. Then, try and
746 # associate this simple file name with the objects that have
747 # been processed. These objects are typically recorded with a
748 # full path name.
749 chomp($FileName = `basename $Filtee`);
750 for my $Obj (keys(%Objects)) {
751 if ($Obj =~ /\/$FileName$/) {
752 $FullPath = $Obj;
753 last;
757 if (!exists($Objects{$FullPath})) {
758 next;
761 for my $SymName (keys(%{$SymFltes{$Filtee}})) {
762 my ($OFlag, $FFlag);
764 # Determine the type of filter.
765 $OFlag = $SymFltes{$Filtee}{$SymName}[$SymFlag];
767 # Specifically identify the type of filtee we have and
768 # remove any generic filtee flag.
769 if ($OFlag & $Ssft) {
770 $FFlag = $Sfte;
771 } else {
772 $FFlag = $Afte;
775 $Symbols{$SymName}{$FullPath}[$ObjFlag] |= $FFlag;
776 $Symbols{$SymName}{$FullPath}[$ObjFlag] &= ~$Gfte;
780 # Process objects and their symbols as required.
781 if ($opt{m}) {
782 # If we're creating a mapfile, traverse each object we've
783 # collected.
784 foreach my $Obj (keys(%Objects)) {
785 my ($File, $Path);
787 # Skip any objects that should be ignored.
788 if ($Obj =~ $Rtld) {
789 next;
792 # Skip any versioned objects if required.
793 if ($opt{v} && $Versioned{$Obj}) {
794 next;
797 # Open the mapfile if required.
798 $File = basename($Obj);
799 $Path = "$DestDir/mapfile-$File";
800 if (!open(MAPOUT, "> $Path")) {
801 printf STDERR gettext("%s: %s: open failed:" .
802 "%s\n"), $Prog, $Path, $!;
803 exit 1;
806 # Establish the mapfile preamble.
807 print MAPOUT "#\n# Interface Definition mapfile for:\n";
808 print MAPOUT "#\tDynamic Object: $Obj\n";
809 print MAPOUT "#\tProcess: $File\n#\n\n";
811 # Process each global symbol.
812 print MAPOUT "$File {\n\tglobal:\n";
814 foreach my $SymName (sort(keys(%{$Objects{$Obj}}))) {
815 my ($Flag) = $Objects{$Obj}{$SymName};
817 # For the first pass we're only interested in
818 # symbols that have been bound to from an
819 # external object, or must be global to enable
820 # a binding to an interposing definition.
821 # Skip bindings to ourself, as these are
822 # candidates for demoting to local.
823 if (!($Flag & ($Extn | $Intp))) {
824 next;
826 if (($Flag & ($Extn | $Self)) == $Self) {
827 next;
830 # Add the demangled name as a comment if
831 # required.
832 if ($opt{C}) {
833 my ($DemName) = Demangle($SymName);
835 if ($DemName ne "") {
836 print MAPOUT "\t\t#$DemName\n";
839 print MAPOUT "\t\t$SymName;\n";
842 # Process each local demotion.
843 print MAPOUT "\tlocal:\n";
845 if ($opt{o}) {
846 foreach my $SymName
847 (sort(keys(%{$Objects{$Obj}}))) {
848 my ($Flag) = $Objects{$Obj}{$SymName};
850 # For this pass we're only interested
851 # in symbol definitions that haven't
852 # been bound to, or have only been
853 # bound to from the same object.
854 if ($Flag & $Extn) {
855 next;
858 # Add the demangled name as a comment if
859 # required.
860 if ($opt{C}) {
861 my ($DemName) =
862 Demangle($SymName);
864 if ($DemName ne "") {
865 print MAPOUT
866 "\t\t#$DemName\n";
869 print MAPOUT "\t\t$SymName;\n";
873 # Capture everything else as local.
874 print MAPOUT "\t\t\*;\n};\n";
875 close MAPOUT;
878 } else {
879 # If we're gathering information regarding the symbols used by
880 # the process, automatically sort any standard output using the
881 # symbol name.
882 if (!open(SORT, "| sort +1")) {
883 printf STDERR gettext("%s: fork failed: %s\n"),
884 $Prog, $!;
885 exit 1;
888 foreach my $SymName (keys(%Symbols)) {
889 my ($Cnt);
891 # If we're looking for interesting symbols, inspect
892 # each definition of each symbol. If one is found to
893 # be interesting, the whole family are printed.
894 if (($Cnt = Interesting($SymName)) == 0) {
895 next;
898 # We've found something interesting, or all symbols
899 # should be output. List all objects that define this
900 # symbol.
901 foreach my $Obj (keys(%{$Symbols{$SymName}})) {
902 my ($DemName, $Type);
903 my ($Flag) = $Symbols{$SymName}{$Obj}[$ObjFlag];
904 my ($Str) = "$Cnt:";
905 my ($Vis);
906 my ($DisVis) = "";
908 # Do we just want overhead symbols. Consider
909 # copy-relocations, rejections, and plt address
910 # binding, as overhead too.
911 if ($opt{o} && (($Flag &
912 ($Rejt | $Extn | $Cpyr | $Plta)) == $Extn)) {
913 next;
916 # Do we just want all symbols that have been
917 # bound to.
918 if (($opt{a} || $opt{o}) && $opt{b} &&
919 (($Flag & ($Extn | $Self | $Prot)) == 0)) {
920 next;
923 # If we haven't been asked for all symbols, only
924 # print those reserved symbols that have been
925 # bound to, as the number of reserved symbols
926 # can be quite excessive. Also, remove any
927 # standard filters, as nothing can bind to these
928 # symbols anyway, provided they have not
929 # contributed to a rejected binding.
930 if (!$opt{a} && ((($SymName =~ $MultSyms) &&
931 (($Flag & ($Extn | $Self)) == 0)) ||
932 (($SymName =~ $CrtSyms) && (($Flag &
933 ($Extn | $Self | $Prot)) == 0)) ||
934 (($Flag & ($Ssft | $Osft)) &&
935 (($Flag & $Rejt) == 0)))) {
936 next;
939 # Skip any versioned objects if required.
940 if ($opt{v} && $Versioned{$Obj}) {
941 next;
944 # Display this symbol.
945 if ($Symbols{$SymName}{$Obj}[$ObjRef]) {
946 $Str = $Str .
947 $Symbols{$SymName}{$Obj}[$ObjRef];
948 } else {
949 $Str = $Str . '0';
952 # Has the symbol been bound to externally
953 if ($Flag & $Extn) {
954 $Str = $Str . 'E';
956 # Has the symbol been bound to from the same
957 # object.
958 if ($Flag & $Self) {
959 $Str = $Str . 'S';
961 # Has the symbol been bound to directly.
962 if ($Flag & $Dirc) {
963 $Str = $Str . 'D';
965 # Does this symbol originate for an explicit
966 # interposer.
967 if ($Flag & $Intp) {
968 $Str = $Str . 'I';
970 # Is this symbol the reference data of a copy
971 # relocation.
972 if ($Flag & $Cpyr) {
973 $Str = $Str . 'C';
975 # Is this symbol part of filtee.
976 if ($Flag & ($Sfte | $Afte | $Gfte)) {
977 $Str = $Str . 'F';
979 # Is this symbol protected (in which case there
980 # may be a symbolic binding within the same
981 # object to this symbol).
982 if ($Flag & $Prot) {
983 $Str = $Str . 'P';
985 # Is this symbol an executables .plt address.
986 if ($Flag & $Plta) {
987 $Str = $Str . 'A';
989 # Does this binding originate from a user
990 # (dlsym) request.
991 if ($Flag & $User) {
992 $Str = $Str . 'U';
994 # Does this definition redirect the binding.
995 if ($Flag & $Msft) {
996 $Str = $Str . 'R';
998 # Does this definition explicitly define no
999 # direct binding.
1000 if ($Flag & $Nodi) {
1001 $Str = $Str . 'N';
1003 # Was a binding to this definition rejected at
1004 # some point.
1005 if ($Flag & $Rejt) {
1006 $Str = $Str . 'r';
1009 # Determine whether this is a function or a data
1010 # object. For the latter, display the symbol
1011 # size. Otherwise, the symbol is a reserved
1012 # label, and is left untyped.
1013 if ($Flag & $Func) {
1014 $Type = '()';
1015 } elsif ($Flag & $Objt) {
1016 $Type = '[' .
1017 $Symbols{$SymName}{$Obj}[$ObjSize] .
1018 ']';
1019 } else {
1020 $Type = "";
1023 # Demangle the symbol name if desired.
1024 $DemName = Demangle($SymName);
1026 # If symbol visibility differences are
1027 # interesting, append the verbose representation
1028 # of any interesting visibilities.
1029 $Vis = $Symbols{$SymName}{$Obj}[$ObjVis];
1030 if ($opt{V} && $Vis) {
1031 if ($Vis =~ 'S') {
1032 $DisVis = " (singleton)";
1033 } elsif ($Vis =~ 'P') {
1034 $DisVis = " (protected)";
1037 if ($Mult) {
1038 print SORT " [$Str]: " .
1039 "$SymName$Type$DemName: " .
1040 "$Obj$DisVis\n";
1041 } else {
1042 print SORT "[$Str]: " .
1043 "$SymName$Type$DemName: " .
1044 "$Obj$DisVis\n";
1048 close SORT;
1052 # Heuristics to determine whether a symbol binding is interesting. In most
1053 # applications there can be a large amount of symbol binding information to
1054 # wade through. The most typical binding, to a single definition, probably
1055 # isn't interesting or the cause of unexpected behavior. Here, we try and
1056 # determine those bindings that may can cause unexpected behavior.
1058 # Note, this routine is actually called for all symbols so that their count
1059 # can be calculated in one place.
1060 sub Interesting
1062 my ($SymName) = @_;
1063 my ($ObjCnt, $GFlags, $BndCnt, $FltCnt, $NodiCnt, $RdirCnt, $ExRef);
1064 my ($RejCnt, $TotCnt);
1066 # Scan all definitions of this symbol, thus determining the definition
1067 # count, the number of filters, redirections, executable references
1068 # (copy-relocations, or plt addresses), no-direct bindings, and the
1069 # number of definitions that have been bound to.
1070 $ObjCnt = $GFlags = $BndCnt = $FltCnt =
1071 $NodiCnt = $RdirCnt = $ExRef = $RejCnt = $TotCnt = 0;
1072 foreach my $Obj (keys(%{$Symbols{$SymName}})) {
1073 my ($Flag) = $Symbols{$SymName}{$Obj}[$ObjFlag];
1075 $TotCnt++;
1077 # Ignore standard filters when determining the symbol count, as
1078 # a standard filter can never be bound to.
1079 if (($Flag & ($Osft | $Ssft)) == 0) {
1080 $ObjCnt++;
1083 # If we're only looking at interesting objects, then standard
1084 # filters are ignored, so suppress any standard filtee tagging.
1085 if (!$opt{a}) {
1086 $Flag = $Symbols{$SymName}{$Obj}[$ObjFlag] &= ~$Sfte;
1089 $GFlags |= $Flag;
1090 if ($Flag & ($Sfte | $Afte | $Gfte)) {
1091 $FltCnt++;
1093 if ($Flag & $Nodi) {
1094 $NodiCnt++;
1096 if ($Flag & ($Cpyr | $Plta)) {
1097 $ExRef++;
1099 if ($Flag & $Msft) {
1100 $RdirCnt++;
1102 if ($Flag & $Rejt) {
1103 $RejCnt++;
1106 # Ignore bindings to undefined .plts, and copy-relocation
1107 # references. These are implementation details, rather than
1108 # a truly interesting multiple-binding. If a symbol is tagged
1109 # as protected, count it as having bound to itself, even though
1110 # we can't tell if it's really been used.
1111 if (($Flag & ($Self | $Extn | $Prot)) &&
1112 (($Flag & ($Plta | $Cpyr)) == 0)) {
1113 $BndCnt++;
1117 # If we want all overhead symbols, return the count.
1118 if ($opt{o}) {
1119 return $ObjCnt;
1122 # If we want all symbols, return the count. If we want all bound
1123 # symbols, return the count provided it is non-zero.
1124 if ($opt{a} && (!$opt{b} || ($BndCnt > 0))) {
1125 return $TotCnt;
1128 # Any rejected symbol is interesting
1129 if ($RejCnt) {
1130 return $TotCnt;
1133 # Single instance symbol definitions aren't very interesting.
1134 if ($ObjCnt == 1) {
1135 return 0;
1138 # Traverse each symbol definition looking for the following:
1140 # . Multiple symbols are bound to externally.
1141 # . A symbol is bound to externally, and possibly symbolically.
1143 # Two symbol bindings are acceptable in some cases, and thus aren't
1144 # interesting:
1146 # . Copy relocations. Here, the executable binds to a shared object
1147 # to access the data definition, which is then copied to the
1148 # executable. All other references should then bind to the copied
1149 # data.
1150 # . Non-plt relocations to functions that are referenced by the
1151 # executable will bind to the .plt in the executable. This
1152 # provides for address comparison calculations (although plainly
1153 # an overhead).
1155 # Multiple symbol bindings are acceptable in some cases, and thus aren't
1156 # interesting:
1158 # . Filtees. Multiple filtees may exist for one filter.
1160 if ((($ObjCnt == 2) && ($GFlags & ($Cpyr | $Plta))) ||
1161 ($ObjCnt == ($FltCnt + 1))) {
1162 return 0;
1165 # Only display any reserved symbols if more than one binding has
1166 # occurred.
1167 if ((($SymName =~ $MultSyms) || ($SymName =~ $CrtSyms)) &&
1168 ($BndCnt < 2)) {
1169 return (0);
1172 # For all other symbols, determine whether a binding has occurred.
1173 # Note: definitions within an executable are tagged as protected ("P")
1174 # as they may have been bound to from within the executable - we can't
1175 # tell.
1176 if ($opt{b} && ($BndCnt == 0)) {
1177 return (0);
1180 # Multiple instances of a definition, where all but one are filter
1181 # references and/or copy relocations, are also uninteresting.
1182 # Effectively, only one symbol is providing the final binding.
1183 if (($FltCnt && $RdirCnt) &&
1184 (($FltCnt + $RdirCnt + $ExRef) == $ObjCnt)) {
1185 return (0);
1188 # Multiple instances of explicitly defined no-direct binding symbols
1189 # are known to occur, and their no-binding definition indicates they
1190 # are expected and accounted for. Thus, these aren't interesting.
1191 if (($ExRef + $NodiCnt) == $ObjCnt) {
1192 return (0);
1195 # We have an interesting symbol, returns its count.
1196 return $ObjCnt;
1199 # Obtain the global symbol definitions of an object and determine whether the
1200 # object has been versioned.
1201 sub GetAllSymbols {
1202 my ($Obj) = @_;
1203 my ($Type, $FileHandle);
1204 my (%AddrToName, %NameToAddr);
1205 my ($Exec) = 0;
1206 my ($Symb) = 0;
1207 my ($Copy) = 0;
1208 my ($Interpose) = 0;
1209 my ($Fltr) = 0;
1210 my ($Ehdr) = 0;
1211 my ($Dyn) = 0;
1212 my ($Rel) = 0;
1213 my ($Info) = 0;
1215 # Determine whether we've already retrieved this object's symbols.
1216 # Also, ignore the runtime linker, it's on a separate link-map, and
1217 # except for the filtee symbols that might be bound via libdl, is
1218 # uninteresting. Tag the runtime linker as versioned to simplify
1219 # possible -v processing.
1220 if ($Objects{$Obj}) {
1221 return;
1224 if ($Obj =~ $Rtld) {
1225 $Versioned{$Obj} = 1;
1226 return;
1229 # Get as much ELF information as we can from elfdump(1). A second
1230 # invocation of elfdump(1) is required to obtain the symbol table, whose
1231 # processing can be affected by states determined during this pass.
1233 # The information required:
1234 # -e ELF header provides the file type
1235 # -d dynamic information provides filter names
1236 # -r relocations provide for copy relocations
1237 # -v object versioning
1238 # -y symbol information section provide pre-symbol filters
1239 # and direct binding information
1241 # As this information can be quite large, process the elfdump(1) output
1242 # through a pipe.
1243 open($FileHandle, "LC_ALL=C elfdump -edrvy '$Obj' 2> /dev/null |");
1245 while (defined(my $Line = <$FileHandle>)) {
1246 my (@Fields);
1248 chomp($Line);
1250 # Each collection of data is preceded with a title that
1251 # starts in column 0. Items of data all have some form of
1252 # indentation.
1253 if ($Line =~ /^[A-Z]/) {
1254 if ($Line =~ /^ELF Header/) {
1255 $Ehdr = 1;
1256 $Dyn = $Rel = $Info = 0;
1257 } elsif ($Line =~ /^Dynamic Section:/) {
1258 $Dyn = 1;
1259 $Ehdr = $Rel = $Info = 0;
1260 } elsif ($Line =~ /^Relocation Section:/) {
1261 $Rel = 1;
1262 $Ehdr = $Dyn = $Info = 0;
1263 } elsif ($Line =~ /^Syminfo Section:/) {
1264 $Info = 1;
1265 $Ehdr = $Dyn = $Rel = 0;
1266 } elsif ($Line =~ /^Version Definition Section:/) {
1267 # The existance of a VERDEF section is all we
1268 # are looking for. There is no need to parse
1269 # the specific version definitions.
1270 $Versioned{$Obj} = 1;
1271 $Ehdr = $Dyn = $Rel = $Info = 0;
1272 } else {
1273 $Ehdr = $Dyn = $Rel = $Info = 0;
1275 next;
1278 # Inspect the ELF header.
1279 if ($Ehdr eq 1) {
1280 # Determine the ELF file type from the e_type element.
1281 if ($Line =~ /e_type:/) {
1282 if ($Line =~ /ET_EXEC/) {
1283 $Exec = 1;
1286 # There's nothing of interest left in the ELF
1287 # header, so skip processing other entries.
1288 $Ehdr = 0;
1289 next;
1293 # Inspect the .dynamic section.
1294 if ($Dyn eq 1) {
1295 @Fields = split(' ', $Line);
1297 # Determine if the FILTER or AUXILIARY tag is set.
1298 if ($#Fields == 3) {
1299 my ($Flte) = 0;
1301 if ($Fields[1] eq 'FILTER') {
1302 $Fltr |= $Osft;
1303 $Flte = 1;
1305 elsif ($Fields[1] eq 'AUXILIARY') {
1306 $Fltr |= $Oaft;
1307 $Flte = 1;
1309 if ($Flte eq 1) {
1310 my (@Filtees) = split(':', $Fields[3]);
1312 for my $Filtee (@Filtees) {
1313 if ($Filtee =~ $Rtld) {
1314 next;
1316 $ObjFltrs{$Obj}{$Filtee} = 1;
1319 next;
1322 # We're only interested in the FLAGS entry.
1323 if (($#Fields < 4) || ($Fields[1] !~ /^FLAGS/)) {
1324 next;
1327 # Determine whether we've got a symbolicly bound object.
1328 # With newer link-editors, all symbols will be marked as
1329 # protected ("P"), but with older link-editors this
1330 # state could only be inferred from the symbolic dynamic
1331 # tag.
1332 if (($Fields[1] eq 'FLAGS') &&
1333 ($Line =~ / SYMBOLIC /)) {
1334 $Symb = 1;
1335 next;
1338 # Determine whether this object is an interposer.
1339 if (($Fields[1] eq 'FLAGS_1') &&
1340 ($Line =~ / OBJECT-INTERPOSE /)) {
1341 $Interpose = 1;
1342 next;
1344 next;
1347 # Inspect the relocation information. As we're only looking
1348 # for copy relocations, this processing is only necessary for
1349 # executables.
1350 if ($Rel eq 1) {
1351 my ($SymName);
1353 if ($Exec eq 0) {
1354 $Rel = 0;
1355 next;
1358 # Obtain any copy relocations.
1359 if ($Line !~ / R_[A-Z0-9]+_COPY /) {
1360 next;
1363 @Fields = split(' ', $Line);
1365 # Intel relocation records don't contain an addend,
1366 # where as every other supported platform does.
1367 if ($Fields[0] eq 'R_386_COPY') {
1368 $SymName = $Fields[3];
1369 } else {
1370 $SymName = $Fields[4];
1373 $Symbols{$SymName}{$Obj}[$ObjFlag] |= $Cpyr;
1374 $Objects{$Obj}{$SymName} |= $Cpyr;
1375 $Copy = 1;
1378 # Inspect the .SUNW_syminfo section.
1379 if ($Info eq 1) {
1380 my ($SymName);
1381 my ($Flags) = 0;
1383 @Fields = split(' ', $Line);
1385 # Binding attributes are in the second column.
1386 if ($#Fields < 1) {
1387 next;
1389 if ($Fields[1] =~ /N/) {
1390 $Flags |= $Nodi;
1392 if ($Fields[1] =~ /F/) {
1393 $Flags |= $Ssft;
1395 if ($Fields[1] =~ /A/) {
1396 $Flags |= $Saft;
1398 if ($Fields[1] =~ /I/) {
1399 $Flags |= $Intp;
1402 # Determine the symbol name based upon the number of
1403 # fields.
1404 if ($Flags) {
1405 $SymName = $Fields[$#Fields];
1406 $Symbols{$SymName}{$Obj}[$ObjFlag] |= $Flags;
1407 $Objects{$Obj}{$SymName} |= $Flags;
1410 # If this is a filter, we need to tag the associated
1411 # filtee symbol. However, the filtee might not have
1412 # been processed yet, so save this information for later.
1413 $Flags &= ~($Nodi | $Intp);
1414 if ($Flags) {
1415 my ($Filtee) = $Fields[$#Fields - 1];
1417 if ($Filtee =~ $Rtld) {
1418 next;
1420 $SymFltes{$Filtee}{$SymName}[$SymFlag] = $Flags;
1425 close($FileHandle);
1427 # If there's no expected information, it's possible we've been given a
1428 # debug output file and are processing the file from a location from
1429 # which the dependencies specified in the debug file aren't accessible.
1430 if ($Dyn eq 0) {
1431 printf STDERR gettext("%s: %s: unable to process ELF file\n"),
1432 $Prog, $Obj;
1434 # Add the file to our list, so that we don't create the same
1435 # message again. Processing should continue so that we can
1436 # flush out as many error messages as possible.
1437 $Objects{$Obj}{"DoesNotExist"} = 0;
1438 return;
1441 # Process elfdump(1) once more to obtain the .dynsym symbol table. We
1442 # are only interested in global symbols, so .SUNW_ldynsym is not needed.
1443 open($FileHandle, "LC_ALL=C elfdump -sN.dynsym '$Obj' 2> /dev/null |");
1445 while (defined(my $Line = <$FileHandle>)) {
1446 chomp($Line);
1448 my (@Fields) = split(' ', $Line);
1449 my ($Flags);
1451 # We're only interested in defined symbol entries. Unless
1452 # we've been asked for all symbols, ignore any ABS or NOTY
1453 # symbols. The former are typically reserved symbols or
1454 # versioning names. The latter are labels that are not bound
1455 # to. Note, ABS and NOTY symbols of non-zero size have been
1456 # known to occur, so capture them.
1457 if (($#Fields < 8) || ($Fields[4] !~ $GlobWeak) ||
1458 ($Fields[7] eq 'UNDEF') ||
1459 (!$opt{a} && (oct($Fields[2]) eq 0) &&
1460 ((($Fields[7] eq 'ABS') && ($Fields[3] eq 'OBJT')) ||
1461 ($Fields[3] eq 'NOTY')))) {
1462 next;
1465 # If we're found copy relocations, save the address of all OBJT
1466 # definitions, together with the copy symbol. These definitions
1467 # are used to determine whether the copy symbol has any aliases
1468 # (ie. __iob and _iob).
1469 if (($Copy eq 1) && ($Fields[3] eq 'OBJT')) {
1470 push(@{$AddrToName{$Fields[1]}}, $Fields[8]);
1472 if (($Symbols{$Fields[8]}{$Obj}) &&
1473 ($Symbols{$Fields[8]}{$Obj}[$ObjFlag] & $Cpyr)) {
1474 $NameToAddr{$Fields[8]} = $Fields[1];
1478 # Identify this symbol as global, and associate it with any
1479 # object filtering.
1480 $Flags = $Glob | $Fltr;
1482 # If the symbol visibility is protected, this is an internal
1483 # symbolic binding. Note, an INTERNAL visibility for a global
1484 # symbol is invalid, but for a while ld(1) was setting this
1485 # attribute mistakenly for protected. If this is a dynamic
1486 # executable, mark its symbols as protected. These symbols
1487 # can't be interposed on any more than symbols defined as
1488 # protected within shared objects).
1489 if (($Fields[5] =~ /^[IP]$/) || $Symb || $Exec) {
1490 $Flags |= $Prot;
1493 # If this object is marked as an interposer, tag each symbol.
1494 if ($Interpose) {
1495 $Flags |= $Intp;
1498 # Identify the symbol as a function or data type, and for the
1499 # latter, capture the symbol size. Ignore the standard symbolic
1500 # labels, as we don't want to type them.
1501 if ($Fields[8] !~ $MultSyms) {
1502 if ($Fields[3] =~ /^FUNC$/) {
1503 $Flags |= $Func;
1504 } elsif ($Fields[3] =~ /^OBJT$/) {
1505 my ($Size) = $Fields[2];
1507 if (oct($Size) eq 0) {
1508 $Size = "0";
1509 } else {
1510 $Size =~ s/0x0*/0x/;
1512 $Flags |= $Objt;
1513 $Symbols{$Fields[8]}{$Obj}[$ObjSize] = $Size;
1517 $Symbols{$Fields[8]}{$Obj}[$ObjFlag] |= $Flags;
1518 $Symbols{$Fields[8]}{$Obj}[$ObjVis] = $Fields[5];
1519 $Objects{$Obj}{$Fields[8]} |= $Flags;
1521 close($FileHandle);
1523 # Process any copy relocation symbols to see if the copy symbol has any
1524 # aliases, which should also be marked as copy relocations.
1525 if ($Copy) {
1526 foreach my $SymName (keys(%NameToAddr)) {
1527 my ($Addr) = $NameToAddr{$SymName};
1529 # Determine all symbols that have the same address.
1530 foreach my $AliasName (@{$AddrToName{$Addr}}) {
1531 if ($SymName eq $AliasName) {
1532 next;
1534 $Symbols{$AliasName}{$Obj}[$ObjFlag] |= $Cpyr;
1535 $Objects{$Obj}{$AliasName} |= $Cpyr;
1541 # Demangle a symbol name if required.
1542 sub Demangle
1544 my ($SymName) = @_;
1545 my ($DemName);
1547 if ($opt{C}) {
1548 my (@Dem);
1550 # Determine if we've already demangled this name.
1551 if (exists($DemSyms{$SymName})) {
1552 return $DemSyms{$SymName};
1555 @Dem = split(/\n/, `dem '$SymName'`);
1556 foreach my $Line (@Dem) {
1557 my (@Fields) = split(' ', $Line);
1559 if (($#Fields < 2) || ($Fields[1] ne '==') ||
1560 ($Fields[0] eq $Fields[2])) {
1561 next;
1563 $DemName = $Line;
1564 $DemName =~ s/.*== (.*)$/ \[$1]/;
1565 $DemSyms{$SymName} = $DemName;
1566 return($DemName);
1569 $DemSyms{$SymName} = "";
1570 return("");