17c478bd9Sstevel@tonic-gate#!/usr/perl5/bin/perl -w 27c478bd9Sstevel@tonic-gate# 37c478bd9Sstevel@tonic-gate# CDDL HEADER START 47c478bd9Sstevel@tonic-gate# 57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the 6c1c6f601Srie# Common Development and Distribution License (the "License"). 7c1c6f601Srie# You may not use this file except in compliance with the License. 87c478bd9Sstevel@tonic-gate# 97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate# and limitations under the License. 137c478bd9Sstevel@tonic-gate# 147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate# 207c478bd9Sstevel@tonic-gate# CDDL HEADER END 217c478bd9Sstevel@tonic-gate# 22c1c6f601Srie 237c478bd9Sstevel@tonic-gate# 249a411307Srie# Copyright 2007 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate# Use is subject to license terms. 267c478bd9Sstevel@tonic-gate# 277c478bd9Sstevel@tonic-gate# ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate# 297c478bd9Sstevel@tonic-gate# Link Analysis of Runtime Interfaces. 307c478bd9Sstevel@tonic-gate# 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate# Define all global variables (required for strict) 3360758829Srieuse vars qw($Prog $DestDir $ObjRef $ObjFlag $ObjSize $ObjVis $TmpDir); 3460758829Srieuse vars qw($LddArgs $SymFlag); 353906e0c2Srieuse vars qw($Glob $Intp $Dirc $Cpyr $Prot $Extn $Self $Gfte $Plta $User $Func); 36*3c4993fbSrieuse vars qw($Rejt $Sfte $Afte $Objt $Nodi $Osft $Oaft $Ssft $Saft $Msft); 373906e0c2Srieuse vars qw($Rtld $GlobWeak $MultSyms $CrtSyms $Platform $DbgSeed %opt); 383906e0c2Srie 393906e0c2Srie# Global arrays that must be cleared for multi input file use. 403906e0c2Srieuse vars qw(%Symbols %Objects %Versioned %DemSyms %ObjFltrs %SymFltes); 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gateuse strict; 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gateuse Getopt::Std; 457c478bd9Sstevel@tonic-gateuse File::Basename; 467c478bd9Sstevel@tonic-gate 473906e0c2Srie# Pattern match to skip the runtime linker. 487010c12aSrie$Rtld = qr{ 497c478bd9Sstevel@tonic-gate /lib/ld\.so\.1 | 507c478bd9Sstevel@tonic-gate /usr/lib/ld\.so\.1 | 517c478bd9Sstevel@tonic-gate /lib/sparcv9/ld\.so\.1 | 52c1c6f601Srie /usr/lib/sparcv9/ld\.so\.1 | 53c1c6f601Srie /lib/amd64/ld\.so\.1 | 54c1c6f601Srie /usr/lib/amd64/ld\.so\.1 557c478bd9Sstevel@tonic-gate}x; 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate# Pattern matching required to determine a global symbol. 587c478bd9Sstevel@tonic-gate$GlobWeak = qr{ ^(?: 597c478bd9Sstevel@tonic-gate GLOB | 607c478bd9Sstevel@tonic-gate WEAK 617c478bd9Sstevel@tonic-gate )$ 627c478bd9Sstevel@tonic-gate}x; 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate# Pattern matching to determine link-editor specific symbols and those common 657c478bd9Sstevel@tonic-gate# to the compilation environment (ie. provided by all crt's). 667c478bd9Sstevel@tonic-gate$MultSyms = qr{ ^(?: 677c478bd9Sstevel@tonic-gate _DYNAMIC | 687c478bd9Sstevel@tonic-gate _GLOBAL_OFFSET_TABLE_ | 697c478bd9Sstevel@tonic-gate _PROCEDURE_LINKAGE_TABLE_ | 707c478bd9Sstevel@tonic-gate _etext | 717c478bd9Sstevel@tonic-gate _edata | 727c478bd9Sstevel@tonic-gate _end | 737c478bd9Sstevel@tonic-gate _init | 747c478bd9Sstevel@tonic-gate _fini | 757c478bd9Sstevel@tonic-gate _lib_version | # Defined in values 767c478bd9Sstevel@tonic-gate __xpg4 | # Defined in values 777c478bd9Sstevel@tonic-gate __xpg6 # Defined in values 787c478bd9Sstevel@tonic-gate )$ 797c478bd9Sstevel@tonic-gate}x; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate$CrtSyms = qr{ ^(?: 827c478bd9Sstevel@tonic-gate ___Argv | # Defined in crt 837c478bd9Sstevel@tonic-gate __environ_lock | # Defined in crt 847c478bd9Sstevel@tonic-gate _environ | # Defined in crt 857c478bd9Sstevel@tonic-gate environ # Defined in crt 867c478bd9Sstevel@tonic-gate )$ 877c478bd9Sstevel@tonic-gate}x; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate# Symbol flags. 907c478bd9Sstevel@tonic-gate$Glob = 0x00001; # symbol is global 913906e0c2Srie$Sfte = 0x00002; # symbol is a filtee backing a standard filter 923906e0c2Srie$Afte = 0x00004; # symbol is a filtee backing a auxiliary filter 933906e0c2Srie$Gfte = 0x00008; # symbol bound as a filtee 949a411307Srie$Intp = 0x00010; # symbol originates from explicit interposer 957c478bd9Sstevel@tonic-gate$Dirc = 0x00020; # symbol bound to directly 967c478bd9Sstevel@tonic-gate$Cpyr = 0x00040; # symbol bound to copy-relocation reference 977c478bd9Sstevel@tonic-gate$Prot = 0x00080; # symbol is protected (symbolic) 987c478bd9Sstevel@tonic-gate$Extn = 0x00100; # symbol has been bound to from an external reference 997c478bd9Sstevel@tonic-gate$Self = 0x00200; # symbol has been bound to from the same object 100*3c4993fbSrie$Rejt = 0x00400; # symbol binding was (at some point) rejected 1017c478bd9Sstevel@tonic-gate$Plta = 0x00800; # symbol bound to executables plt address 1027c478bd9Sstevel@tonic-gate$User = 0x01000; # symbol binding originates from user (dlsym) request 1037c478bd9Sstevel@tonic-gate$Func = 0x02000; # symbol is of type function 1047c478bd9Sstevel@tonic-gate$Objt = 0x04000; # symbol is of type object 1057c478bd9Sstevel@tonic-gate$Nodi = 0x08000; # symbol prohibits direct binding 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate$Osft = 0x10000; # symbol is an standard object filter 1087c478bd9Sstevel@tonic-gate$Oaft = 0x20000; # symbol is an auxiliary object filter 1097c478bd9Sstevel@tonic-gate$Ssft = 0x40000; # symbol is a per-symbol standard filter 1103906e0c2Srie$Saft = 0x80000; # symbol is a per-symbol auxiliary filter 1117c478bd9Sstevel@tonic-gate$Msft = 0xf0000; # filter mask 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate# Offsets into $Symbols{$SymName}{$Obj} array. 1147c478bd9Sstevel@tonic-gate$ObjRef = 0; 1157c478bd9Sstevel@tonic-gate$ObjFlag = 1; 1167c478bd9Sstevel@tonic-gate$ObjSize = 2; 11760758829Srie$ObjVis = 3; 1187c478bd9Sstevel@tonic-gate 1193906e0c2Srie# Offset into $SymFltr{$SymName}{$Filtee} array. 1203906e0c2Srie$SymFlag = 0; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate# Establish locale 1237c478bd9Sstevel@tonic-gateuse POSIX qw(locale_h); 1247c478bd9Sstevel@tonic-gateuse Sun::Solaris::Utils qw(textdomain gettext); 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gatesetlocale(LC_ALL, ""); 1277c478bd9Sstevel@tonic-gatetextdomain("SUNW_OST_SGS"); 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate# Establish a program name for any error diagnostics. 1307c478bd9Sstevel@tonic-gate$Prog = basename($0); 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gatesub inappropriate { 1337c478bd9Sstevel@tonic-gate my ($Opt1, $Opt2, $Flag) = @_; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate if ($Flag) { 1367c478bd9Sstevel@tonic-gate printf STDERR 1377c478bd9Sstevel@tonic-gate gettext("%s: inappropriate use of %s with %s: %s ignored\n"), 1387c478bd9Sstevel@tonic-gate $Prog, $Opt1, $Opt2, $Opt1; 1397c478bd9Sstevel@tonic-gate } else { 1407c478bd9Sstevel@tonic-gate printf STDERR 1417c478bd9Sstevel@tonic-gate gettext("%s: inappropriate use of %s without %s: %s ignored\n"), 1427c478bd9Sstevel@tonic-gate $Prog, $Opt1, $Opt2, $Opt1; 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate} 1457c478bd9Sstevel@tonic-gate 1463906e0c2Srie# Cleanup any temporary files on interruption. 1477c478bd9Sstevel@tonic-gatesub Cleanup { 1487c478bd9Sstevel@tonic-gate my ($Sig) = @_; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate $SIG{$Sig} = 'IGNORE'; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate if ($DbgSeed ne "") { 1537c478bd9Sstevel@tonic-gate foreach my $File (<\Q${DbgSeed}\E.*>) { 1547c478bd9Sstevel@tonic-gate if ($File =~ /^\Q$DbgSeed\E\.\d+$/) { 1557c478bd9Sstevel@tonic-gate unlink($File); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate exit 1; 1607c478bd9Sstevel@tonic-gate} 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate# Check that we have arguments. 16360758829Srieif ((getopts('abCDd:imosVv', \%opt) == 0) || ($#ARGV < 0)) { 1647c478bd9Sstevel@tonic-gate printf STDERR gettext("usage:\n"); 1657c478bd9Sstevel@tonic-gate printf STDERR 16660758829Srie gettext(" %s [-bCDsVv] [-a | -i | -o ] file | dir ...\n"), $Prog; 1677c478bd9Sstevel@tonic-gate printf STDERR 16860758829Srie gettext(" %s [-CDosVv] [-m [-d mapdir]] file\n"), $Prog; 1697c478bd9Sstevel@tonic-gate print STDERR 1707c478bd9Sstevel@tonic-gate gettext("\t[-a] print diagnostics for all symbols\n"); 1717c478bd9Sstevel@tonic-gate print STDERR 1723906e0c2Srie gettext("\t[-b] limit diagnostics to bound symbols\n"); 1737c478bd9Sstevel@tonic-gate print STDERR 1747c478bd9Sstevel@tonic-gate gettext("\t[-C] print demangled symbol names also\n"); 1757c478bd9Sstevel@tonic-gate print STDERR 1767c478bd9Sstevel@tonic-gate gettext("\t[-D] read debugging information from \"file\"\n"); 1777c478bd9Sstevel@tonic-gate print STDERR 1787c478bd9Sstevel@tonic-gate gettext("\t[-d dir] create mapfiles in \"mapdir\"\n"); 1797c478bd9Sstevel@tonic-gate print STDERR 1807c478bd9Sstevel@tonic-gate gettext("\t[-i] print interesting information (default)\n"); 1817c478bd9Sstevel@tonic-gate print STDERR 1827c478bd9Sstevel@tonic-gate gettext("\t[-m] create mapfiles for interface requirements\n"); 1837c478bd9Sstevel@tonic-gate print STDERR 1843906e0c2Srie gettext("\t[-o] limit diagnostics to overhead information\n"); 1857c478bd9Sstevel@tonic-gate print STDERR 1867c478bd9Sstevel@tonic-gate gettext("\t[-s] save bindings information created by ldd(1)\n"); 1877c478bd9Sstevel@tonic-gate print STDERR 18860758829Srie gettext("\t[-V] append interesting symbol visibilities\n"); 18960758829Srie print STDERR 1907c478bd9Sstevel@tonic-gate gettext("\t[-v] ignore versioned objects\n"); 1917c478bd9Sstevel@tonic-gate exit 1; 1927c478bd9Sstevel@tonic-gate} else { 1937c478bd9Sstevel@tonic-gate my ($Mult, $Error); 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate # Catch any incompatible argument usage. 1967c478bd9Sstevel@tonic-gate if ($opt{m}) { 1977c478bd9Sstevel@tonic-gate if ($opt{a}) { 1987c478bd9Sstevel@tonic-gate inappropriate("-a", "-m", 1); 1997c478bd9Sstevel@tonic-gate $opt{a} = 0; 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate if ($opt{i}) { 2027c478bd9Sstevel@tonic-gate inappropriate("-i", "-m", 1); 2037c478bd9Sstevel@tonic-gate $opt{i} = 0; 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate } else { 2067c478bd9Sstevel@tonic-gate if ($opt{d}) { 2077c478bd9Sstevel@tonic-gate inappropriate("-d", "-m", 0); 2087c478bd9Sstevel@tonic-gate $opt{d} = 0; 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate if ($opt{a}) { 2127c478bd9Sstevel@tonic-gate if ($opt{o}) { 2137c478bd9Sstevel@tonic-gate inappropriate("-a", "-o", 1); 2147c478bd9Sstevel@tonic-gate $opt{o} = 0; 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate if ($opt{i}) { 2177c478bd9Sstevel@tonic-gate inappropriate("-a", "-i", 1); 2187c478bd9Sstevel@tonic-gate $opt{i} = 0; 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate } 2217010c12aSrie if ($opt{o}) { 2227010c12aSrie if ($opt{i}) { 2237c478bd9Sstevel@tonic-gate inappropriate("-o", "-i", 1); 2247c478bd9Sstevel@tonic-gate $opt{i} = 0; 2257c478bd9Sstevel@tonic-gate } 2267010c12aSrie if ($opt{b}) { 2277010c12aSrie inappropriate("-o", "-b", 1); 2287010c12aSrie $opt{b} = 0; 2297010c12aSrie } 2307010c12aSrie } 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate # If -m is used, only one input file is applicable. 2337c478bd9Sstevel@tonic-gate if ($opt{m} && ($#ARGV != 0)) { 2347c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: only one input file is allowed " . 2357c478bd9Sstevel@tonic-gate "with the -m option\n"), $Prog; 2367c478bd9Sstevel@tonic-gate exit 1; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate # Insure any specified directory exists, or apply a default. 2407c478bd9Sstevel@tonic-gate if ($opt{d}) { 2417c478bd9Sstevel@tonic-gate # User specified directory - make sure it exists. 2427c478bd9Sstevel@tonic-gate if (! -d $opt{d}) { 2437c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: %s is not a directory\n"), 2447c478bd9Sstevel@tonic-gate $Prog, $opt{d}; 2457c478bd9Sstevel@tonic-gate exit 1; 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate $DestDir = $opt{d}; 2487c478bd9Sstevel@tonic-gate } else { 2497c478bd9Sstevel@tonic-gate $DestDir = "."; 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate # Establish a temporary directory if necessary. 2537c478bd9Sstevel@tonic-gate if (!$opt{D}) { 2547c478bd9Sstevel@tonic-gate if (!($TmpDir = $ENV{TMPDIR}) || (! -d $TmpDir)) { 2557c478bd9Sstevel@tonic-gate $TmpDir = "/tmp"; 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate # Establish any initial ldd(1) argument requirements. 2607c478bd9Sstevel@tonic-gate if ($LddArgs = $ENV{LARI_LDD_ARGS}) { 2617c478bd9Sstevel@tonic-gate $LddArgs = $LddArgs . ' -r -e LD_DEBUG=bindings,files,detail'; 2627c478bd9Sstevel@tonic-gate } else { 2637c478bd9Sstevel@tonic-gate $LddArgs = '-r -e LD_DEBUG=bindings,files,detail'; 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate # If we've been asked to demangle symbols, make sure we can find the 2677c478bd9Sstevel@tonic-gate # demangler. 2687c478bd9Sstevel@tonic-gate if ($opt{C}) { 2697c478bd9Sstevel@tonic-gate my ($DemName) = `dem XXXX 2> /dev/null`; 2707c478bd9Sstevel@tonic-gate if (!$DemName) { 2717c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: can not locate demangler: " . 2727c478bd9Sstevel@tonic-gate "-C ignored\n"), $Prog; 2737c478bd9Sstevel@tonic-gate $opt{C} = 0; 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate # If -a or -o hasn't been specified, default to -i. 2787c478bd9Sstevel@tonic-gate if (!$opt{a} && !$opt{o}) { 2797c478bd9Sstevel@tonic-gate $opt{i} = 1; 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate 2827010c12aSrie # Determine whether we have multiple input files. 2837c478bd9Sstevel@tonic-gate if ($#ARGV == 0) { 2847c478bd9Sstevel@tonic-gate $Mult = 0; 2857c478bd9Sstevel@tonic-gate } else { 2867c478bd9Sstevel@tonic-gate $Mult = 1; 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate # Determine what platform we're running on - some inappropriate 2907c478bd9Sstevel@tonic-gate # platform specific dependencies are better skipped. 2917c478bd9Sstevel@tonic-gate chomp($Platform = `uname -i`); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate # Establish signal handlers 2947c478bd9Sstevel@tonic-gate $SIG{INT} = \&Cleanup; 2957c478bd9Sstevel@tonic-gate $SIG{QUIT} = \&Cleanup; 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate $DbgSeed = ""; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate # For each argument determine if we're dealing with a file or directory. 3007c478bd9Sstevel@tonic-gate $Error = 0; 3017c478bd9Sstevel@tonic-gate foreach my $Arg (@ARGV) { 3027c478bd9Sstevel@tonic-gate if (!stat($Arg)) { 3037c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: %s: unable to stat file\n"), 3047c478bd9Sstevel@tonic-gate $Prog, $Arg; 3057c478bd9Sstevel@tonic-gate $Error = 1; 3067c478bd9Sstevel@tonic-gate next; 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate # Process simple files. 3107c478bd9Sstevel@tonic-gate if (-f _) { 3117c478bd9Sstevel@tonic-gate if (!-r _) { 3127c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: %s: unable to " . 3137c478bd9Sstevel@tonic-gate "read file\n"), $Prog, $Arg; 3147c478bd9Sstevel@tonic-gate $Error = 1; 3157c478bd9Sstevel@tonic-gate next; 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate if (!$opt{D}) { 3187c478bd9Sstevel@tonic-gate if (ProcFile($Arg, $Mult, 1) == 0) { 3197c478bd9Sstevel@tonic-gate $Error = 1; 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate } else { 3227c478bd9Sstevel@tonic-gate # If the -D option is specified, read the 3237c478bd9Sstevel@tonic-gate # bindings debugging information from the 3247c478bd9Sstevel@tonic-gate # specified file. 3257c478bd9Sstevel@tonic-gate if ($Mult) { 3267c478bd9Sstevel@tonic-gate print STDOUT "$Arg:\n"; 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate ProcBindings($Arg, $Mult, $Arg); 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate next; 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate # Process directories. 3347c478bd9Sstevel@tonic-gate if (-d _) { 3357c478bd9Sstevel@tonic-gate ProcDir($Arg); 3367c478bd9Sstevel@tonic-gate next; 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: %s: is not a file or directory\n"), 3407c478bd9Sstevel@tonic-gate $Prog, $Arg; 3417c478bd9Sstevel@tonic-gate $Error = 1; 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate exit $Error; 3447c478bd9Sstevel@tonic-gate} 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gatesub ProcDir { 3477c478bd9Sstevel@tonic-gate my ($Dir) = @_; 3487c478bd9Sstevel@tonic-gate my ($File); 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate # Open the directory and read each entry, omit "." and "..". Sorting 3517c478bd9Sstevel@tonic-gate # the directory listing makes analyzing different source hierarchies 3527c478bd9Sstevel@tonic-gate # easier. 3537c478bd9Sstevel@tonic-gate if (opendir(DIR, $Dir)) { 3547c478bd9Sstevel@tonic-gate foreach my $Entry (sort(readdir(DIR))) { 3557c478bd9Sstevel@tonic-gate if (($Entry eq '.') || ($Entry eq '..')) { 3567c478bd9Sstevel@tonic-gate next; 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 3593906e0c2Srie # If we're descending into a platform directory, ignore 3607c478bd9Sstevel@tonic-gate # any inappropriate platform specific files. These 3617c478bd9Sstevel@tonic-gate # files can have dependencies that in turn bring in the 3627c478bd9Sstevel@tonic-gate # appropriate platform specific file, resulting in more 3637c478bd9Sstevel@tonic-gate # than one dependency offering the same interfaces. In 3647c478bd9Sstevel@tonic-gate # practice, the non-appropriate platform specific file 3657c478bd9Sstevel@tonic-gate # wouldn't be loaded with a process. 3667c478bd9Sstevel@tonic-gate if (($Dir =~ /\/platform$/) && 3677c478bd9Sstevel@tonic-gate ($Entry !~ /^$Platform$/)) { 3687c478bd9Sstevel@tonic-gate next; 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate $File = "$Dir/$Entry"; 3727c478bd9Sstevel@tonic-gate if (!lstat($File)) { 3737c478bd9Sstevel@tonic-gate next; 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate # Ignore symlinks. 3767c478bd9Sstevel@tonic-gate if (-l _) { 3777c478bd9Sstevel@tonic-gate next; 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate # Descend into, and process any directories. 3817c478bd9Sstevel@tonic-gate if (-d _) { 3827c478bd9Sstevel@tonic-gate ProcDir($File); 3837c478bd9Sstevel@tonic-gate next; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate # Process any standard files. 3877c478bd9Sstevel@tonic-gate if (-f _ && -r _) { 3887c478bd9Sstevel@tonic-gate ProcFile($File, 1, 0); 3897c478bd9Sstevel@tonic-gate next; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate closedir(DIR); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate} 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate# Process a file. If the file was explicitly defined on the command-line, and 3987c478bd9Sstevel@tonic-gate# an error occurs, tell the user. Otherwise, this file probably came about from 3997c478bd9Sstevel@tonic-gate# scanning a directory, in which case just skip it and move on. 4007c478bd9Sstevel@tonic-gatesub ProcFile { 4017c478bd9Sstevel@tonic-gate my ($File, $Mult, $CmdLine) = @_; 4027c478bd9Sstevel@tonic-gate my (@Ldd, $NoFound, $DbgFile, @DbgGlob, $Type); 4037c478bd9Sstevel@tonic-gate 4047010c12aSrie # If we're scanning a directory (ie. /lib) and have picked up ld.so.1, 4057010c12aSrie # ignore it. 4067010c12aSrie if (($CmdLine eq 0) && ($File =~ $Rtld)) { 4077010c12aSrie return 1; 4087010c12aSrie } 4097010c12aSrie 4107c478bd9Sstevel@tonic-gate $Type = `LC_ALL=C file '$File' 2>&1`; 4117c478bd9Sstevel@tonic-gate if (($Type !~ /dynamically linked/) || ($Type =~ /Sun demand paged/)) { 4127c478bd9Sstevel@tonic-gate if ($CmdLine) { 4137c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: %s: is an invalid file " . 4147c478bd9Sstevel@tonic-gate "type\n"), $Prog, $File; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate return 0; 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate # Create a temporary filename for capturing binding information. 4207c478bd9Sstevel@tonic-gate $DbgSeed = basename($File); 4217c478bd9Sstevel@tonic-gate $DbgSeed = "$TmpDir/lari.dbg.$$.$DbgSeed"; 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate # Exercise the file under ldd(1), capturing all the bindings. 4247c478bd9Sstevel@tonic-gate @Ldd = split(/\n/, 4257c478bd9Sstevel@tonic-gate `LC_ALL=C ldd $LddArgs -e LD_DEBUG_OUTPUT='$DbgSeed' '$File' 2>&1`); 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate # If ldd isn't -e capable we'll get a usage message. The -e option was 4287c478bd9Sstevel@tonic-gate # introduced in Solaris 9 and related patches. Also, make sure the user 4297c478bd9Sstevel@tonic-gate # sees any ldd errors. 4307c478bd9Sstevel@tonic-gate $NoFound = 0; 4317c478bd9Sstevel@tonic-gate for my $Line (@Ldd) { 4327c478bd9Sstevel@tonic-gate if ($Line =~ /^usage: ldd/) { 4337c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: ldd: does not support -e, " . 4347c478bd9Sstevel@tonic-gate "unable to capture bindings output\n"), $Prog; 4357c478bd9Sstevel@tonic-gate exit 1; 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate if ($Line =~ /not found/) { 4387c478bd9Sstevel@tonic-gate $NoFound = 1; 4397c478bd9Sstevel@tonic-gate last; 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate # The runtime linker will have appended a process id to the debug file. 4447c478bd9Sstevel@tonic-gate # As we have to intuit the name, make sure there is only one debug 4457c478bd9Sstevel@tonic-gate # file match, otherwise there must be some clutter in the output 4467c478bd9Sstevel@tonic-gate # directory that is going to mess up our analysis. 4477c478bd9Sstevel@tonic-gate foreach my $Match (<\Q${DbgSeed}\E.*>) { 4487c478bd9Sstevel@tonic-gate if ($Match =~ /^\Q$DbgSeed\E\.\d+$/) { 4497c478bd9Sstevel@tonic-gate push(@DbgGlob, $Match); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate if (@DbgGlob == 0) { 4537c478bd9Sstevel@tonic-gate # If there is no debug file, bail. This can occur if the file 4547c478bd9Sstevel@tonic-gate # being processed is secure. 4557c478bd9Sstevel@tonic-gate if ($CmdLine) { 4567c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: %s: unable to capture " . 4577c478bd9Sstevel@tonic-gate "bindings output - possible secure application?\n"), 4587c478bd9Sstevel@tonic-gate $Prog, $File; 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate return 0; 4617c478bd9Sstevel@tonic-gate } elsif (@DbgGlob > 1) { 4627c478bd9Sstevel@tonic-gate # Too many debug files found. 4637c478bd9Sstevel@tonic-gate if ($CmdLine) { 4647c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: %s: multiple bindings " . 4657c478bd9Sstevel@tonic-gate "output files exist: %s: clean up temporary " . 4667c478bd9Sstevel@tonic-gate "directory\n"), $Prog, $File, $DbgSeed; 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate return 0; 4697c478bd9Sstevel@tonic-gate } else { 4707c478bd9Sstevel@tonic-gate $DbgFile = $DbgGlob[0]; 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate # Ok, we're ready to process the bindings information. Print a header 4747c478bd9Sstevel@tonic-gate # if necessary, and if there were any ldd(1) errors push some of them 4757c478bd9Sstevel@tonic-gate # out before any bindings information. Limit the output, as it can 4767c478bd9Sstevel@tonic-gate # sometimes be excessive. If there are errors, the bindings information 4777c478bd9Sstevel@tonic-gate # is likely to be incomplete. 4787c478bd9Sstevel@tonic-gate if ($Mult) { 4797c478bd9Sstevel@tonic-gate print STDOUT "$File:\n"; 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate if ($NoFound) { 4827c478bd9Sstevel@tonic-gate my ($Cnt) = 4; 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate for my $Line (@Ldd) { 4857c478bd9Sstevel@tonic-gate if ($Line =~ /not found/) { 4867c478bd9Sstevel@tonic-gate print STDOUT "$Line\n"; 4877c478bd9Sstevel@tonic-gate $Cnt--; 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate if ($Cnt == 0) { 4907c478bd9Sstevel@tonic-gate print STDOUT gettext("\tcontinued ...\n"); 4917c478bd9Sstevel@tonic-gate last; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate # If the user wants the original debugging file left behind, rename it 4977c478bd9Sstevel@tonic-gate # so that it doesn't get re-read by another instance of lari processing 4987c478bd9Sstevel@tonic-gate # this file. 4997c478bd9Sstevel@tonic-gate if ($opt{s}) { 5007c478bd9Sstevel@tonic-gate rename($DbgFile, $DbgSeed); 5017c478bd9Sstevel@tonic-gate $DbgFile = $DbgSeed; 5027c478bd9Sstevel@tonic-gate printf STDOUT gettext("%s: %s: bindings information " . 5037c478bd9Sstevel@tonic-gate "saved as: %s\n"), $Prog, $File, $DbgFile; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate ProcBindings($File, $Mult, $DbgFile); 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate # Now that we've finished with the debugging file, nuke it if necessary. 5097c478bd9Sstevel@tonic-gate if (!$opt{s}) { 5107c478bd9Sstevel@tonic-gate unlink($DbgFile); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate $DbgSeed = ""; 5137c478bd9Sstevel@tonic-gate return 1; 5147c478bd9Sstevel@tonic-gate} 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gatesub ProcBindings { 5177c478bd9Sstevel@tonic-gate my ($File, $Mult, $DbgFile) = @_; 5187c478bd9Sstevel@tonic-gate my (%Filtees, $FileHandle); 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate # Reinitialize our arrays when we're dealing with multiple files. 5217c478bd9Sstevel@tonic-gate if ($Mult) { 5227c478bd9Sstevel@tonic-gate %Symbols = (); 5237c478bd9Sstevel@tonic-gate %Objects = (); 5247c478bd9Sstevel@tonic-gate %Versioned = (); 5253906e0c2Srie %DemSyms = (); 5263906e0c2Srie %ObjFltrs = (); 5273906e0c2Srie %SymFltes = (); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate # As debugging output can be significant, read a line at a time. 5317c478bd9Sstevel@tonic-gate open($FileHandle, "<$DbgFile"); 5327c478bd9Sstevel@tonic-gate while (defined(my $Line = <$FileHandle>)) { 5337c478bd9Sstevel@tonic-gate chomp($Line); 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate # Collect the symbols from any file analyzed. 5367c478bd9Sstevel@tonic-gate if ($Line =~ /^.*: file=(.*); analyzing .*/) { 5377c478bd9Sstevel@tonic-gate GetAllSymbols($1); 5387c478bd9Sstevel@tonic-gate next; 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate # Process any symbolic relocations that bind to a file. 5427c478bd9Sstevel@tonic-gate if ($Line =~ /: binding file=.* to file=/) { 5437c478bd9Sstevel@tonic-gate my ($RefFile, $DstFile, $SymName); 5447c478bd9Sstevel@tonic-gate my (@Syms, $Found, @Fields); 5457c478bd9Sstevel@tonic-gate my ($BndInfo) = 0; 5467c478bd9Sstevel@tonic-gate my ($Offset) = 1; 5477c478bd9Sstevel@tonic-gate my ($Dlsym) = 0; 5487c478bd9Sstevel@tonic-gate my ($Detail) = 0; 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate # For greatest flexibility, split the line into fields 5517c478bd9Sstevel@tonic-gate # and walk each field until we find what we need. 5527c478bd9Sstevel@tonic-gate @Fields = split(' ', $Line); 5537c478bd9Sstevel@tonic-gate 554*3c4993fbSrie # The referencing file, "... binding file=.* ". 5557c478bd9Sstevel@tonic-gate while ($Fields[$Offset]) { 5567c478bd9Sstevel@tonic-gate if ($Fields[$Offset] =~ /^file=(.*)/) { 5577c478bd9Sstevel@tonic-gate $RefFile = $1; 5587c478bd9Sstevel@tonic-gate $Offset++; 5597c478bd9Sstevel@tonic-gate last; 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate $Offset++; 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate # The referencing offset, typically this is the address 5647c478bd9Sstevel@tonic-gate # of the reference, "(0x1234...)", but in the case of a 5657c478bd9Sstevel@tonic-gate # user lookup it's the string "(dlsym)". If we don't 5667c478bd9Sstevel@tonic-gate # find this offset information we've been given a debug 5673906e0c2Srie # file that didn't use the "detail" token, in which case 5687c478bd9Sstevel@tonic-gate # we're not getting all the information we need. 5697c478bd9Sstevel@tonic-gate if ($Fields[$Offset] =~ /^\((.*)\)/) { 5707c478bd9Sstevel@tonic-gate if ($1 eq 'dlsym') { 5717c478bd9Sstevel@tonic-gate $Dlsym = 1; 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate $Detail = 1; 5747c478bd9Sstevel@tonic-gate $Offset++; 5757c478bd9Sstevel@tonic-gate } 576*3c4993fbSrie # The destination file, "... to file=.* ". Note, in the 577*3c4993fbSrie # case of a rejection message, the file is terminated 578*3c4993fbSrie # with a colon, "... to file=.*: ", which must be 579*3c4993fbSrie # removed 5807c478bd9Sstevel@tonic-gate while ($Fields[$Offset]) { 5817c478bd9Sstevel@tonic-gate if ($Fields[$Offset] =~ /^file=(.*)/) { 5827c478bd9Sstevel@tonic-gate $DstFile = $1; 583*3c4993fbSrie $DstFile =~ s/:$//; 5847c478bd9Sstevel@tonic-gate $Offset++; 5857c478bd9Sstevel@tonic-gate last; 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate $Offset++; 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate # The symbol being bound, "... symbol `.*' ...". 5907c478bd9Sstevel@tonic-gate while ($Fields[$Offset]) { 5917c478bd9Sstevel@tonic-gate if ($Fields[$Offset] =~ /^\`(.*)\'$/) { 5927c478bd9Sstevel@tonic-gate $SymName = $1; 5937c478bd9Sstevel@tonic-gate $Offset++; 5947c478bd9Sstevel@tonic-gate last; 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate $Offset++; 5977c478bd9Sstevel@tonic-gate } 598*3c4993fbSrie # Possible trailing binding info, "... (direct,...", or 599*3c4993fbSrie # a rejection, "... (rejected - ...". 6007c478bd9Sstevel@tonic-gate while ($Fields[$Offset]) { 601*3c4993fbSrie if ($Fields[$Offset] =~ /^\((.*)/) { 6027c478bd9Sstevel@tonic-gate $BndInfo = $1; 603*3c4993fbSrie $Detail = 1; 6047c478bd9Sstevel@tonic-gate $Offset++; 6057c478bd9Sstevel@tonic-gate last; 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate $Offset++; 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate if ($Detail == 0) { 6117c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: %s: debug file " . 6127c478bd9Sstevel@tonic-gate "does not contain `detail' information\n"), 6137c478bd9Sstevel@tonic-gate $Prog, $DbgFile; 6147c478bd9Sstevel@tonic-gate return; 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate # Collect the symbols from each object. 6187c478bd9Sstevel@tonic-gate GetAllSymbols($RefFile); 6197c478bd9Sstevel@tonic-gate GetAllSymbols($DstFile); 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate # Identify that this definition has been bound to. 6227c478bd9Sstevel@tonic-gate $Symbols{$SymName}{$DstFile}[$ObjRef]++; 6237c478bd9Sstevel@tonic-gate if ($RefFile eq $DstFile) { 6247c478bd9Sstevel@tonic-gate # If the reference binds to a definition within 6257c478bd9Sstevel@tonic-gate # the same file this symbol may be a candidate 6267c478bd9Sstevel@tonic-gate # for reducing to local. 6277c478bd9Sstevel@tonic-gate $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Self; 6287c478bd9Sstevel@tonic-gate $Objects{$DstFile}{$SymName} |= $Self; 6297c478bd9Sstevel@tonic-gate } else { 6307c478bd9Sstevel@tonic-gate # This symbol is required to satisfy an external 6317c478bd9Sstevel@tonic-gate # reference. 6327c478bd9Sstevel@tonic-gate $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Extn; 6337c478bd9Sstevel@tonic-gate $Objects{$DstFile}{$SymName} |= $Extn; 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate # Assign any other state indicated by the binding info 6377c478bd9Sstevel@tonic-gate # associated with the diagnostic output. 6387c478bd9Sstevel@tonic-gate if (!$BndInfo) { 6397c478bd9Sstevel@tonic-gate next; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate if ($BndInfo =~ /direct/) { 6437c478bd9Sstevel@tonic-gate $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Dirc; 6447c478bd9Sstevel@tonic-gate $Objects{$DstFile}{$SymName} |= $Dirc; 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate if ($BndInfo =~ /copy-ref/) { 6477c478bd9Sstevel@tonic-gate $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Cpyr; 6487c478bd9Sstevel@tonic-gate $Objects{$DstFile}{$SymName} |= $Cpyr; 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate if ($BndInfo =~ /filtee/) { 6513906e0c2Srie $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Gfte; 6523906e0c2Srie $Objects{$DstFile}{$SymName} |= $Gfte; 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate if ($BndInfo =~ /interpose/) { 6557c478bd9Sstevel@tonic-gate $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Intp; 6567c478bd9Sstevel@tonic-gate $Objects{$DstFile}{$SymName} |= $Intp; 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate if ($BndInfo =~ /plt-addr/) { 6597c478bd9Sstevel@tonic-gate $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Plta; 6607c478bd9Sstevel@tonic-gate $Objects{$DstFile}{$SymName} |= $Plta; 6617c478bd9Sstevel@tonic-gate } 662*3c4993fbSrie if ($BndInfo =~ /rejected/) { 663*3c4993fbSrie $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Rejt; 664*3c4993fbSrie $Objects{$DstFile}{$SymName} |= $Rejt; 665*3c4993fbSrie } 6667c478bd9Sstevel@tonic-gate if ($Dlsym) { 6677c478bd9Sstevel@tonic-gate $Symbols{$SymName}{$DstFile}[$ObjFlag] |= $User; 6687c478bd9Sstevel@tonic-gate $Objects{$DstFile}{$SymName} |= $User; 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate close($FileHandle); 6737c478bd9Sstevel@tonic-gate 6743906e0c2Srie # Now that we've processed all objects, traverse the set of object 6753906e0c2Srie # filters that have been captured from parsing any FILTER and AUXILIARY 6763906e0c2Srie # dynamic tags. For each filtee, determine which of the symbols it 6773906e0c2Srie # exports are also defined in the filter. If a filter is bound to, the 6787c478bd9Sstevel@tonic-gate # runtime linkers diagnostics will indicate a filtee binding. However, 6797c478bd9Sstevel@tonic-gate # some of the filtee symbols may not be bound to, so here we mark them 6807c478bd9Sstevel@tonic-gate # all so as to remove them from any interesting output. 6813906e0c2Srie for my $Filter (keys(%ObjFltrs)) { 6827c478bd9Sstevel@tonic-gate 6833906e0c2Srie # Determine the filtees that are associated with this filter. 6843906e0c2Srie for my $Filtee (keys(%{$ObjFltrs{$Filter}})) { 6853906e0c2Srie my ($FileName); 6863906e0c2Srie 6873906e0c2Srie # Reduce the filtee to a simple file name. Then, try 6883906e0c2Srie # and associate this simple file name with the objects 6893906e0c2Srie # that have been processed. These objects are typically 6903906e0c2Srie # recorded with a full path name. 6913906e0c2Srie chomp($FileName = `basename $Filtee`); 6923906e0c2Srie for my $Obj (keys(%Objects)) { 6933906e0c2Srie if ($Obj =~ /\/$FileName$/) { 6943906e0c2Srie $Filtee = $Obj; 6953906e0c2Srie last; 6963906e0c2Srie } 6973906e0c2Srie } 6983906e0c2Srie 6997c478bd9Sstevel@tonic-gate if (!exists($Objects{$Filtee})) { 7007c478bd9Sstevel@tonic-gate next; 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate 7033906e0c2Srie # Traverse the symbols of the filtee (these are 7043906e0c2Srie # typically a smaller set than the filter) and if the 7053906e0c2Srie # symbol is defined by the filter tag the symbol as a 7063906e0c2Srie # filtee. 7073906e0c2Srie for my $SymName (keys(%{$Objects{$Filtee}})) { 7083906e0c2Srie my ($OFlag, $FFlag); 7097c478bd9Sstevel@tonic-gate 7103906e0c2Srie # Ignore the usual stuff. 7113906e0c2Srie if (($SymName =~ $MultSyms) || 7123906e0c2Srie ($SymName =~ $CrtSyms)) { 7137c478bd9Sstevel@tonic-gate next; 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate if (!$Symbols{$SymName}{$Filter}) { 7177c478bd9Sstevel@tonic-gate next; 7187c478bd9Sstevel@tonic-gate } 7193906e0c2Srie 7203906e0c2Srie # Determine the type of filter. 7213906e0c2Srie $OFlag = $Symbols{$SymName}{$Filter}[$ObjFlag]; 7223906e0c2Srie 7233906e0c2Srie # Specifically identify the type of filtee we 7243906e0c2Srie # have and remove any generic filtee flag. 7253906e0c2Srie if ($OFlag & ($Osft | $Ssft)) { 7263906e0c2Srie $FFlag = $Sfte; 7273906e0c2Srie } else { 7283906e0c2Srie $FFlag = $Afte; 7293906e0c2Srie } 7303906e0c2Srie 7313906e0c2Srie $Symbols{$SymName}{$Filtee}[$ObjFlag] |= $FFlag; 7323906e0c2Srie $Symbols{$SymName}{$Filtee}[$ObjFlag] &= ~$Gfte; 7333906e0c2Srie } 7343906e0c2Srie } 7353906e0c2Srie } 7363906e0c2Srie 7373906e0c2Srie # Traverse the set of per-symbol filters making sure we've tagged any 7383906e0c2Srie # associated filtee symbols, as we did above for object filters. 7393906e0c2Srie for my $Filtee (keys(%SymFltes)) { 7403906e0c2Srie my ($FullPath) = $Filtee; 7413906e0c2Srie my ($FileName); 7423906e0c2Srie 7433906e0c2Srie # Reduce the filtee to a simple file name. Then, try and 7443906e0c2Srie # associate this simple file name with the objects that have 7453906e0c2Srie # been processed. These objects are typically recorded with a 7463906e0c2Srie # full path name. 7473906e0c2Srie chomp($FileName = `basename $Filtee`); 7483906e0c2Srie for my $Obj (keys(%Objects)) { 7493906e0c2Srie if ($Obj =~ /\/$FileName$/) { 7503906e0c2Srie $FullPath = $Obj; 7513906e0c2Srie last; 7523906e0c2Srie } 7533906e0c2Srie } 7543906e0c2Srie 7553906e0c2Srie if (!exists($Objects{$FullPath})) { 7567c478bd9Sstevel@tonic-gate next; 7577c478bd9Sstevel@tonic-gate } 7583906e0c2Srie 7593906e0c2Srie for my $SymName (keys(%{$SymFltes{$Filtee}})) { 7603906e0c2Srie my ($OFlag, $FFlag); 7613906e0c2Srie 7623906e0c2Srie # Determine the type of filter. 7633906e0c2Srie $OFlag = $SymFltes{$Filtee}{$SymName}[$SymFlag]; 7643906e0c2Srie 7653906e0c2Srie # Specifically identify the type of filtee we have and 7663906e0c2Srie # remove any generic filtee flag. 7673906e0c2Srie if ($OFlag & $Ssft) { 7683906e0c2Srie $FFlag = $Sfte; 7693906e0c2Srie } else { 7703906e0c2Srie $FFlag = $Afte; 7717c478bd9Sstevel@tonic-gate } 7723906e0c2Srie 7733906e0c2Srie $Symbols{$SymName}{$FullPath}[$ObjFlag] |= $FFlag; 7743906e0c2Srie $Symbols{$SymName}{$FullPath}[$ObjFlag] &= ~$Gfte; 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate # Process objects and their symbols as required. 7797c478bd9Sstevel@tonic-gate if ($opt{m}) { 7807c478bd9Sstevel@tonic-gate # If we're creating a mapfile, traverse each object we've 7817c478bd9Sstevel@tonic-gate # collected. 7827c478bd9Sstevel@tonic-gate foreach my $Obj (keys(%Objects)) { 7837c478bd9Sstevel@tonic-gate my ($File, $Path); 7847c478bd9Sstevel@tonic-gate 785c1c6f601Srie # Skip any objects that should be ignored. 7867c478bd9Sstevel@tonic-gate if ($Obj =~ $Rtld) { 7877c478bd9Sstevel@tonic-gate next; 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate # Skip any versioned objects if required. 7917c478bd9Sstevel@tonic-gate if ($opt{v} && $Versioned{$Obj}) { 7927c478bd9Sstevel@tonic-gate next; 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate # Open the mapfile if required. 7967c478bd9Sstevel@tonic-gate $File = basename($Obj); 7977c478bd9Sstevel@tonic-gate $Path = "$DestDir/mapfile-$File"; 7987c478bd9Sstevel@tonic-gate if (!open(MAPOUT, "> $Path")) { 7997c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: %s: open failed:" . 8007c478bd9Sstevel@tonic-gate "%s\n"), $Prog, $Path, $!; 8017c478bd9Sstevel@tonic-gate exit 1; 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate # Establish the mapfile preamble. 8057c478bd9Sstevel@tonic-gate print MAPOUT "#\n# Interface Definition mapfile for:\n"; 8067c478bd9Sstevel@tonic-gate print MAPOUT "#\tDynamic Object: $Obj\n"; 8077c478bd9Sstevel@tonic-gate print MAPOUT "#\tProcess: $File\n#\n\n"; 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate # Process each global symbol. 8107c478bd9Sstevel@tonic-gate print MAPOUT "$File {\n\tglobal:\n"; 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate foreach my $SymName (sort(keys(%{$Objects{$Obj}}))) { 8137c478bd9Sstevel@tonic-gate my ($Flag) = $Objects{$Obj}{$SymName}; 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate # For the first pass we're only interested in 8167c478bd9Sstevel@tonic-gate # symbols that have been bound to from an 8177c478bd9Sstevel@tonic-gate # external object, or must be global to enable 8187c478bd9Sstevel@tonic-gate # a binding to an interposing definition. 8193906e0c2Srie # Skip bindings to ourself, as these are 8207c478bd9Sstevel@tonic-gate # candidates for demoting to local. 8217c478bd9Sstevel@tonic-gate if (!($Flag & ($Extn | $Intp))) { 8227c478bd9Sstevel@tonic-gate next; 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate if (($Flag & ($Extn | $Self)) == $Self) { 8257c478bd9Sstevel@tonic-gate next; 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate # Add the demangled name as a comment if 8297c478bd9Sstevel@tonic-gate # required. 8307c478bd9Sstevel@tonic-gate if ($opt{C}) { 8317c478bd9Sstevel@tonic-gate my ($DemName) = Demangle($SymName); 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate if ($DemName ne "") { 8347c478bd9Sstevel@tonic-gate print MAPOUT "\t\t#$DemName\n"; 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate print MAPOUT "\t\t$SymName;\n"; 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate # Process each local demotion. 8417c478bd9Sstevel@tonic-gate print MAPOUT "\tlocal:\n"; 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate if ($opt{o}) { 8447c478bd9Sstevel@tonic-gate foreach my $SymName 8457c478bd9Sstevel@tonic-gate (sort(keys(%{$Objects{$Obj}}))) { 8467c478bd9Sstevel@tonic-gate my ($Flag) = $Objects{$Obj}{$SymName}; 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate # For this pass we're only interested 8497c478bd9Sstevel@tonic-gate # in symbol definitions that haven't 8507c478bd9Sstevel@tonic-gate # been bound to, or have only been 8517c478bd9Sstevel@tonic-gate # bound to from the same object. 8527c478bd9Sstevel@tonic-gate if ($Flag & $Extn) { 8537c478bd9Sstevel@tonic-gate next; 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate # Add the demangled name as a comment if 8577c478bd9Sstevel@tonic-gate # required. 8587c478bd9Sstevel@tonic-gate if ($opt{C}) { 8597c478bd9Sstevel@tonic-gate my ($DemName) = 8607c478bd9Sstevel@tonic-gate Demangle($SymName); 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate if ($DemName ne "") { 8637c478bd9Sstevel@tonic-gate print MAPOUT 8647c478bd9Sstevel@tonic-gate "\t\t#$DemName\n"; 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate print MAPOUT "\t\t$SymName;\n"; 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate # Capture everything else as local. 8727c478bd9Sstevel@tonic-gate print MAPOUT "\t\t\*;\n};\n"; 8737c478bd9Sstevel@tonic-gate close MAPOUT; 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate } else { 8777c478bd9Sstevel@tonic-gate # If we're gathering information regarding the symbols used by 8787c478bd9Sstevel@tonic-gate # the process, automatically sort any standard output using the 8797c478bd9Sstevel@tonic-gate # symbol name. 8807c478bd9Sstevel@tonic-gate if (!open(SORT, "| sort +1")) { 8817c478bd9Sstevel@tonic-gate printf STDERR gettext("%s: fork failed: %s\n"), 8827c478bd9Sstevel@tonic-gate $Prog, $!; 8837c478bd9Sstevel@tonic-gate exit 1; 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate foreach my $SymName (keys(%Symbols)) { 8877c478bd9Sstevel@tonic-gate my ($Cnt); 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate # If we're looking for interesting symbols, inspect 8907c478bd9Sstevel@tonic-gate # each definition of each symbol. If one is found to 8917c478bd9Sstevel@tonic-gate # be interesting, the whole family are printed. 8927c478bd9Sstevel@tonic-gate if (($Cnt = Interesting($SymName)) == 0) { 8937c478bd9Sstevel@tonic-gate next; 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate # We've found something interesting, or all symbols 8977c478bd9Sstevel@tonic-gate # should be output. List all objects that define this 8987c478bd9Sstevel@tonic-gate # symbol. 8997c478bd9Sstevel@tonic-gate foreach my $Obj (keys(%{$Symbols{$SymName}})) { 9007c478bd9Sstevel@tonic-gate my ($DemName, $Type); 9017c478bd9Sstevel@tonic-gate my ($Flag) = $Symbols{$SymName}{$Obj}[$ObjFlag]; 9027c478bd9Sstevel@tonic-gate my ($Str) = "$Cnt:"; 90360758829Srie my ($Vis); 90460758829Srie my ($DisVis) = ""; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate # Do we just want overhead symbols. Consider 907*3c4993fbSrie # copy-relocations, rejections, and plt address 908*3c4993fbSrie # binding, as overhead too. 9097c478bd9Sstevel@tonic-gate if ($opt{o} && (($Flag & 910*3c4993fbSrie ($Rejt | $Extn | $Cpyr | $Plta)) == $Extn)) { 9117c478bd9Sstevel@tonic-gate next; 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate # Do we just want all symbols that have been 9157c478bd9Sstevel@tonic-gate # bound to. 9167c478bd9Sstevel@tonic-gate if (($opt{a} || $opt{o}) && $opt{b} && 9177c478bd9Sstevel@tonic-gate (($Flag & ($Extn | $Self | $Prot)) == 0)) { 9187c478bd9Sstevel@tonic-gate next; 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate # If we haven't been asked for all symbols, only 9227c478bd9Sstevel@tonic-gate # print those reserved symbols that have been 9237c478bd9Sstevel@tonic-gate # bound to, as the number of reserved symbols 9243906e0c2Srie # can be quite excessive. Also, remove any 9253906e0c2Srie # standard filters, as nothing can bind to these 926*3c4993fbSrie # symbols anyway, provided they have not 927*3c4993fbSrie # contributed to a rejected binding. 9287c478bd9Sstevel@tonic-gate if (!$opt{a} && ((($SymName =~ $MultSyms) && 9297c478bd9Sstevel@tonic-gate (($Flag & ($Extn | $Self)) == 0)) || 9307c478bd9Sstevel@tonic-gate (($SymName =~ $CrtSyms) && (($Flag & 9313906e0c2Srie ($Extn | $Self | $Prot)) == 0)) || 932*3c4993fbSrie (($Flag & ($Ssft | $Osft)) && 933*3c4993fbSrie (($Flag & $Rejt) == 0)))) { 9347c478bd9Sstevel@tonic-gate next; 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate # Skip any versioned objects if required. 9387c478bd9Sstevel@tonic-gate if ($opt{v} && $Versioned{$Obj}) { 9397c478bd9Sstevel@tonic-gate next; 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate # Display this symbol. 9437c478bd9Sstevel@tonic-gate if ($Symbols{$SymName}{$Obj}[$ObjRef]) { 9447c478bd9Sstevel@tonic-gate $Str = $Str . 9457c478bd9Sstevel@tonic-gate $Symbols{$SymName}{$Obj}[$ObjRef]; 9467c478bd9Sstevel@tonic-gate } else { 9477c478bd9Sstevel@tonic-gate $Str = $Str . '0'; 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate # Has the symbol been bound to externally 9517c478bd9Sstevel@tonic-gate if ($Flag & $Extn) { 9527c478bd9Sstevel@tonic-gate $Str = $Str . 'E'; 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate # Has the symbol been bound to from the same 9557c478bd9Sstevel@tonic-gate # object. 9567c478bd9Sstevel@tonic-gate if ($Flag & $Self) { 9577c478bd9Sstevel@tonic-gate $Str = $Str . 'S'; 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate # Has the symbol been bound to directly. 9607c478bd9Sstevel@tonic-gate if ($Flag & $Dirc) { 9617c478bd9Sstevel@tonic-gate $Str = $Str . 'D'; 9627c478bd9Sstevel@tonic-gate } 9637c478bd9Sstevel@tonic-gate # Does this symbol originate for an explicit 9647c478bd9Sstevel@tonic-gate # interposer. 9657c478bd9Sstevel@tonic-gate if ($Flag & $Intp) { 9667c478bd9Sstevel@tonic-gate $Str = $Str . 'I'; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate # Is this symbol the reference data of a copy 9697c478bd9Sstevel@tonic-gate # relocation. 9707c478bd9Sstevel@tonic-gate if ($Flag & $Cpyr) { 9717c478bd9Sstevel@tonic-gate $Str = $Str . 'C'; 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate # Is this symbol part of filtee. 9743906e0c2Srie if ($Flag & ($Sfte | $Afte | $Gfte)) { 9757c478bd9Sstevel@tonic-gate $Str = $Str . 'F'; 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate # Is this symbol protected (in which case there 9787c478bd9Sstevel@tonic-gate # may be a symbolic binding within the same 9797c478bd9Sstevel@tonic-gate # object to this symbol). 9807c478bd9Sstevel@tonic-gate if ($Flag & $Prot) { 9817c478bd9Sstevel@tonic-gate $Str = $Str . 'P'; 9827c478bd9Sstevel@tonic-gate } 9837c478bd9Sstevel@tonic-gate # Is this symbol an executables .plt address. 9847c478bd9Sstevel@tonic-gate if ($Flag & $Plta) { 9857c478bd9Sstevel@tonic-gate $Str = $Str . 'A'; 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate # Does this binding originate from a user 9887c478bd9Sstevel@tonic-gate # (dlsym) request. 9897c478bd9Sstevel@tonic-gate if ($Flag & $User) { 9907c478bd9Sstevel@tonic-gate $Str = $Str . 'U'; 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate # Does this definition redirect the binding. 9937c478bd9Sstevel@tonic-gate if ($Flag & $Msft) { 9947c478bd9Sstevel@tonic-gate $Str = $Str . 'R'; 9957c478bd9Sstevel@tonic-gate } 9963906e0c2Srie # Does this definition explicitly define no 9977c478bd9Sstevel@tonic-gate # direct binding. 9987c478bd9Sstevel@tonic-gate if ($Flag & $Nodi) { 9997c478bd9Sstevel@tonic-gate $Str = $Str . 'N'; 10007c478bd9Sstevel@tonic-gate } 1001*3c4993fbSrie # Was a binding to this definition rejected at 1002*3c4993fbSrie # some point. 1003*3c4993fbSrie if ($Flag & $Rejt) { 1004*3c4993fbSrie $Str = $Str . 'r'; 1005*3c4993fbSrie } 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate # Determine whether this is a function or a data 10087c478bd9Sstevel@tonic-gate # object. For the latter, display the symbol 10097c478bd9Sstevel@tonic-gate # size. Otherwise, the symbol is a reserved 10107c478bd9Sstevel@tonic-gate # label, and is left untyped. 10117c478bd9Sstevel@tonic-gate if ($Flag & $Func) { 10127c478bd9Sstevel@tonic-gate $Type = '()'; 10137c478bd9Sstevel@tonic-gate } elsif ($Flag & $Objt) { 10147c478bd9Sstevel@tonic-gate $Type = '[' . 10157c478bd9Sstevel@tonic-gate $Symbols{$SymName}{$Obj}[$ObjSize] . 10167c478bd9Sstevel@tonic-gate ']'; 10177c478bd9Sstevel@tonic-gate } else { 10187c478bd9Sstevel@tonic-gate $Type = ""; 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate # Demangle the symbol name if desired. 10227c478bd9Sstevel@tonic-gate $DemName = Demangle($SymName); 10237c478bd9Sstevel@tonic-gate 102460758829Srie # If symbol visibility differences are 102560758829Srie # interesting, append the verbose representation 102660758829Srie # of any interesting visibilities. 102760758829Srie $Vis = $Symbols{$SymName}{$Obj}[$ObjVis]; 102860758829Srie if ($opt{V} && $Vis) { 102960758829Srie if ($Vis =~ 'S') { 103060758829Srie $DisVis = " (singleton)"; 103160758829Srie } elsif ($Vis =~ 'P') { 103260758829Srie $DisVis = " (protected)"; 103360758829Srie } 103460758829Srie } 10357c478bd9Sstevel@tonic-gate if ($Mult) { 10367c478bd9Sstevel@tonic-gate print SORT " [$Str]: " . 103760758829Srie "$SymName$Type$DemName: " . 103860758829Srie "$Obj$DisVis\n"; 10397c478bd9Sstevel@tonic-gate } else { 10407c478bd9Sstevel@tonic-gate print SORT "[$Str]: " . 104160758829Srie "$SymName$Type$DemName: " . 104260758829Srie "$Obj$DisVis\n"; 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate close SORT; 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate} 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate# Heuristics to determine whether a symbol binding is interesting. In most 10517c478bd9Sstevel@tonic-gate# applications there can be a large amount of symbol binding information to 10527c478bd9Sstevel@tonic-gate# wade through. The most typical binding, to a single definition, probably 10537c478bd9Sstevel@tonic-gate# isn't interesting or the cause of unexpected behavior. Here, we try and 10547c478bd9Sstevel@tonic-gate# determine those bindings that may can cause unexpected behavior. 10557c478bd9Sstevel@tonic-gate# 10567c478bd9Sstevel@tonic-gate# Note, this routine is actually called for all symbols so that their count 10577c478bd9Sstevel@tonic-gate# can be calculated in one place. 10587c478bd9Sstevel@tonic-gatesub Interesting 10597c478bd9Sstevel@tonic-gate{ 10607c478bd9Sstevel@tonic-gate my ($SymName) = @_; 10617c478bd9Sstevel@tonic-gate my ($ObjCnt, $GFlags, $BndCnt, $FltCnt, $NodiCnt, $RdirCnt, $ExRef); 1062*3c4993fbSrie my ($RejCnt, $TotCnt); 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate # Scan all definitions of this symbol, thus determining the definition 10657c478bd9Sstevel@tonic-gate # count, the number of filters, redirections, executable references 10667c478bd9Sstevel@tonic-gate # (copy-relocations, or plt addresses), no-direct bindings, and the 10677c478bd9Sstevel@tonic-gate # number of definitions that have been bound to. 10687c478bd9Sstevel@tonic-gate $ObjCnt = $GFlags = $BndCnt = $FltCnt = 1069*3c4993fbSrie $NodiCnt = $RdirCnt = $ExRef = $RejCnt = $TotCnt = 0; 10707c478bd9Sstevel@tonic-gate foreach my $Obj (keys(%{$Symbols{$SymName}})) { 10717c478bd9Sstevel@tonic-gate my ($Flag) = $Symbols{$SymName}{$Obj}[$ObjFlag]; 10727c478bd9Sstevel@tonic-gate 10733906e0c2Srie $TotCnt++; 10743906e0c2Srie 10757c478bd9Sstevel@tonic-gate # Ignore standard filters when determining the symbol count, as 10767c478bd9Sstevel@tonic-gate # a standard filter can never be bound to. 10777c478bd9Sstevel@tonic-gate if (($Flag & ($Osft | $Ssft)) == 0) { 10787c478bd9Sstevel@tonic-gate $ObjCnt++; 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate 10813906e0c2Srie # If we're only looking at interesting objects, then standard 10823906e0c2Srie # filters are ignored, so suppress any standard filtee tagging. 10833906e0c2Srie if (!$opt{a}) { 10843906e0c2Srie $Flag = $Symbols{$SymName}{$Obj}[$ObjFlag] &= ~$Sfte; 10853906e0c2Srie } 10863906e0c2Srie 10877c478bd9Sstevel@tonic-gate $GFlags |= $Flag; 10883906e0c2Srie if ($Flag & ($Sfte | $Afte | $Gfte)) { 10897c478bd9Sstevel@tonic-gate $FltCnt++; 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate if ($Flag & $Nodi) { 10927c478bd9Sstevel@tonic-gate $NodiCnt++; 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate if ($Flag & ($Cpyr | $Plta)) { 10957c478bd9Sstevel@tonic-gate $ExRef++; 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate if ($Flag & $Msft) { 10987c478bd9Sstevel@tonic-gate $RdirCnt++; 10997c478bd9Sstevel@tonic-gate } 1100*3c4993fbSrie if ($Flag & $Rejt) { 1101*3c4993fbSrie $RejCnt++; 1102*3c4993fbSrie } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate # Ignore bindings to undefined .plts, and copy-relocation 11057c478bd9Sstevel@tonic-gate # references. These are implementation details, rather than 11067c478bd9Sstevel@tonic-gate # a truly interesting multiple-binding. If a symbol is tagged 11077c478bd9Sstevel@tonic-gate # as protected, count it as having bound to itself, even though 11087c478bd9Sstevel@tonic-gate # we can't tell if it's really been used. 11097c478bd9Sstevel@tonic-gate if (($Flag & ($Self | $Extn | $Prot)) && 11107c478bd9Sstevel@tonic-gate (($Flag & ($Plta | $Cpyr)) == 0)) { 11117c478bd9Sstevel@tonic-gate $BndCnt++; 11127c478bd9Sstevel@tonic-gate } 11137c478bd9Sstevel@tonic-gate } 11147c478bd9Sstevel@tonic-gate 11157010c12aSrie # If we want all overhead symbols, return the count. 11167010c12aSrie if ($opt{o}) { 11177010c12aSrie return $ObjCnt; 11187010c12aSrie } 11197010c12aSrie 11207010c12aSrie # If we want all symbols, return the count. If we want all bound 11217010c12aSrie # symbols, return the count provided it is non-zero. 11227010c12aSrie if ($opt{a} && (!$opt{b} || ($BndCnt > 0))) { 11233906e0c2Srie return $TotCnt; 11247c478bd9Sstevel@tonic-gate } 11257c478bd9Sstevel@tonic-gate 1126*3c4993fbSrie # Any rejected symbol is interesting 1127*3c4993fbSrie if ($RejCnt) { 1128*3c4993fbSrie return $TotCnt; 1129*3c4993fbSrie } 1130*3c4993fbSrie 11317c478bd9Sstevel@tonic-gate # Single instance symbol definitions aren't very interesting. 11327c478bd9Sstevel@tonic-gate if ($ObjCnt == 1) { 11337c478bd9Sstevel@tonic-gate return 0; 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate # Traverse each symbol definition looking for the following: 11377c478bd9Sstevel@tonic-gate # 11387c478bd9Sstevel@tonic-gate # . Multiple symbols are bound to externally. 11397c478bd9Sstevel@tonic-gate # . A symbol is bound to externally, and possibly symbolically. 11407c478bd9Sstevel@tonic-gate # 11417c478bd9Sstevel@tonic-gate # Two symbol bindings are acceptable in some cases, and thus aren't 11427c478bd9Sstevel@tonic-gate # interesting: 11437c478bd9Sstevel@tonic-gate # 11447c478bd9Sstevel@tonic-gate # . Copy relocations. Here, the executable binds to a shared object 11457c478bd9Sstevel@tonic-gate # to access the data definition, which is then copied to the 11467c478bd9Sstevel@tonic-gate # executable. All other references should then bind to the copied 11477c478bd9Sstevel@tonic-gate # data. 11487c478bd9Sstevel@tonic-gate # . Non-plt relocations to functions that are referenced by the 11497c478bd9Sstevel@tonic-gate # executable will bind to the .plt in the executable. This 11507c478bd9Sstevel@tonic-gate # provides for address comparison calculations (although plainly 11517c478bd9Sstevel@tonic-gate # an overhead). 11527c478bd9Sstevel@tonic-gate # 11537c478bd9Sstevel@tonic-gate # Multiple symbol bindings are acceptable in some cases, and thus aren't 11547c478bd9Sstevel@tonic-gate # interesting: 11557c478bd9Sstevel@tonic-gate # 11567c478bd9Sstevel@tonic-gate # . Filtees. Multiple filtees may exist for one filter. 11577c478bd9Sstevel@tonic-gate # 11587c478bd9Sstevel@tonic-gate if ((($ObjCnt == 2) && ($GFlags & ($Cpyr | $Plta))) || 11597c478bd9Sstevel@tonic-gate ($ObjCnt == ($FltCnt + 1))) { 11607c478bd9Sstevel@tonic-gate return 0; 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate 11637010c12aSrie # Only display any reserved symbols if more than one binding has 11647010c12aSrie # occurred. 11657010c12aSrie if ((($SymName =~ $MultSyms) || ($SymName =~ $CrtSyms)) && 11667c478bd9Sstevel@tonic-gate ($BndCnt < 2)) { 11677c478bd9Sstevel@tonic-gate return (0); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 11707010c12aSrie # For all other symbols, determine whether a binding has occurred. 11717010c12aSrie # Note: definitions within an executable are tagged as protected ("P") 11727010c12aSrie # as they may have been bound to from within the executable - we can't 11737010c12aSrie # tell. 11747010c12aSrie if ($opt{b} && ($BndCnt == 0)) { 11757010c12aSrie return (0); 11767010c12aSrie } 11777010c12aSrie 11787c478bd9Sstevel@tonic-gate # Multiple instances of a definition, where all but one are filter 11797c478bd9Sstevel@tonic-gate # references and/or copy relocations, are also uninteresting. 11807c478bd9Sstevel@tonic-gate # Effectively, only one symbol is providing the final binding. 11817c478bd9Sstevel@tonic-gate if (($FltCnt && $RdirCnt) && 11827c478bd9Sstevel@tonic-gate (($FltCnt + $RdirCnt + $ExRef) == $ObjCnt)) { 11837c478bd9Sstevel@tonic-gate return (0); 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate # Multiple instances of explicitly defined no-direct binding symbols 11877c478bd9Sstevel@tonic-gate # are known to occur, and their no-binding definition indicates they 11887c478bd9Sstevel@tonic-gate # are expected and accounted for. Thus, these aren't interesting. 11897c478bd9Sstevel@tonic-gate if (($ExRef + $NodiCnt) == $ObjCnt) { 11907c478bd9Sstevel@tonic-gate return (0); 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate # We have an interesting symbol, returns its count. 11947c478bd9Sstevel@tonic-gate return $ObjCnt; 11957c478bd9Sstevel@tonic-gate} 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate# Obtain the global symbol definitions of an object and determine whether the 11987c478bd9Sstevel@tonic-gate# object has been versioned. 11997c478bd9Sstevel@tonic-gatesub GetAllSymbols { 12007c478bd9Sstevel@tonic-gate my ($Obj) = @_; 12013906e0c2Srie my ($Type, $FileHandle); 12027c478bd9Sstevel@tonic-gate my (%AddrToName, %NameToAddr); 12033906e0c2Srie my ($Exec) = 0; 12047c478bd9Sstevel@tonic-gate my ($Vers) = 0; 12057c478bd9Sstevel@tonic-gate my ($Symb) = 0; 12067c478bd9Sstevel@tonic-gate my ($Copy) = 0; 12077c478bd9Sstevel@tonic-gate my ($Interpose) = 0; 12087c478bd9Sstevel@tonic-gate my ($Fltr) = 0; 12093906e0c2Srie my ($Ehdr) = 0; 12103906e0c2Srie my ($Dyn) = 0; 12113906e0c2Srie my ($Rel) = 0; 12123906e0c2Srie my ($Info) = 0; 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate # Determine whether we've already retrieved this object's symbols. 12157c478bd9Sstevel@tonic-gate # Also, ignore the runtime linker, it's on a separate link-map, and 12167c478bd9Sstevel@tonic-gate # except for the filtee symbols that might be bound via libdl, is 12177010c12aSrie # uninteresting. Tag the runtime linker as versioned to simplify 12187010c12aSrie # possible -v processing. 12197010c12aSrie if ($Objects{$Obj}) { 12207010c12aSrie return; 12217010c12aSrie } 12227010c12aSrie 12237010c12aSrie if ($Obj =~ $Rtld) { 12247010c12aSrie $Versioned{$Obj} = 1; 12257c478bd9Sstevel@tonic-gate return; 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate 12283906e0c2Srie # Get as much ELF information as we can from elfdump(1). A second 12293906e0c2Srie # invocation of elfdump(1) is required to obtain the symbol table, whose 12303906e0c2Srie # processing can be affected by states determined during this pass. 12313906e0c2Srie # 12323906e0c2Srie # The information required: 12333906e0c2Srie # -e ELF header provides the file type 12343906e0c2Srie # -d dynamic information provides filter names 12353906e0c2Srie # -r relocations provide for copy relocations 12363906e0c2Srie # -y symbol information section provide pre-symbol filters 12373906e0c2Srie # and direct binding information 12383906e0c2Srie # 12393906e0c2Srie # As this information can be quite large, process the elfdump(1) output 12403906e0c2Srie # through a pipe. 12413906e0c2Srie open($FileHandle, "LC_ALL=C elfdump -edry '$Obj' 2> /dev/null |"); 12427c478bd9Sstevel@tonic-gate 12433906e0c2Srie while (defined(my $Line = <$FileHandle>)) { 12443906e0c2Srie my (@Fields); 12457c478bd9Sstevel@tonic-gate 12463906e0c2Srie chomp($Line); 12473906e0c2Srie 12483906e0c2Srie # Each collection of data is preceded with a title that 12493906e0c2Srie # starts in column 0. Items of data all have some form of 12503906e0c2Srie # indentation. 12513906e0c2Srie if ($Line =~ /^[A-Z]/) { 12523906e0c2Srie if ($Line =~ /^ELF Header/) { 12533906e0c2Srie $Ehdr = 1; 12543906e0c2Srie $Dyn = $Rel = $Info = 0; 12553906e0c2Srie } elsif ($Line =~ /^Dynamic Section:/) { 12563906e0c2Srie $Dyn = 1; 12573906e0c2Srie $Ehdr = $Rel = $Info = 0; 12583906e0c2Srie } elsif ($Line =~ /^Relocation Section:/) { 12593906e0c2Srie $Rel = 1; 12603906e0c2Srie $Ehdr = $Dyn = $Info = 0; 12613906e0c2Srie } elsif ($Line =~ /^Syminfo Section:/) { 12623906e0c2Srie $Info = 1; 12633906e0c2Srie $Ehdr = $Dyn = $Rel = 0; 12643906e0c2Srie } else { 12653906e0c2Srie $Ehdr = $Dyn = $Rel = $Info = 0; 12663906e0c2Srie } 12673906e0c2Srie next; 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate 12703906e0c2Srie # Inspect the ELF header. 12713906e0c2Srie if ($Ehdr eq 1) { 12723906e0c2Srie # Determine the ELF file type from the e_type element. 12733906e0c2Srie if ($Line =~ /e_type:/) { 12743906e0c2Srie if ($Line =~ /ET_EXEC/) { 12753906e0c2Srie $Exec = 1; 12763906e0c2Srie } 12773906e0c2Srie 12783906e0c2Srie # There's nothing of interest left in the ELF 12793906e0c2Srie # header, so skip processing other entries. 12803906e0c2Srie $Ehdr = 0; 12813906e0c2Srie next; 12823906e0c2Srie } 12833906e0c2Srie } 12843906e0c2Srie 12853906e0c2Srie # Inspect the .dynamic section. 12863906e0c2Srie if ($Dyn eq 1) { 12877c478bd9Sstevel@tonic-gate @Fields = split(' ', $Line); 12887c478bd9Sstevel@tonic-gate 12893906e0c2Srie # Determine if the FILTER or AUXILIARY tag is set. 12907c478bd9Sstevel@tonic-gate if ($#Fields == 3) { 12913906e0c2Srie my ($Flte) = 0; 12923906e0c2Srie 12933906e0c2Srie if ($Fields[1] eq 'FILTER') { 12947c478bd9Sstevel@tonic-gate $Fltr |= $Osft; 12953906e0c2Srie $Flte = 1; 12963906e0c2Srie } 12973906e0c2Srie elsif ($Fields[1] eq 'AUXILIARY') { 12983906e0c2Srie $Fltr |= $Oaft; 12993906e0c2Srie $Flte = 1; 13003906e0c2Srie } 13013906e0c2Srie if ($Flte eq 1) { 13023906e0c2Srie my (@Filtees) = split(':', $Fields[3]); 13033906e0c2Srie 13043906e0c2Srie for my $Filtee (@Filtees) { 13053906e0c2Srie if ($Filtee =~ $Rtld) { 13067c478bd9Sstevel@tonic-gate next; 13077c478bd9Sstevel@tonic-gate } 13083906e0c2Srie $ObjFltrs{$Obj}{$Filtee} = 1; 13093906e0c2Srie } 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate next; 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate # We're only interested in the FLAGS entry. 13153906e0c2Srie if (($#Fields < 4) || ($Fields[1] !~ /^FLAGS/)) { 13167c478bd9Sstevel@tonic-gate next; 13177c478bd9Sstevel@tonic-gate } 13183906e0c2Srie 13193906e0c2Srie # Determine whether we've got a symbolicly bound object. 13203906e0c2Srie # With newer link-editors, all symbols will be marked as 13213906e0c2Srie # protected ("P"), but with older link-editors this 13223906e0c2Srie # state could only be inferred from the symbolic dynamic 13233906e0c2Srie # tag. 13243906e0c2Srie if (($Fields[1] eq 'FLAGS') && 13253906e0c2Srie ($Line =~ / SYMBOLIC /)) { 13267c478bd9Sstevel@tonic-gate $Symb = 1; 13277c478bd9Sstevel@tonic-gate next; 13287c478bd9Sstevel@tonic-gate } 13293906e0c2Srie 13303906e0c2Srie # Determine whether this object is an interposer. 13313906e0c2Srie if (($Fields[1] eq 'FLAGS_1') && 13329a411307Srie ($Line =~ / OBJECT-INTERPOSE /)) { 13337c478bd9Sstevel@tonic-gate $Interpose = 1; 13347c478bd9Sstevel@tonic-gate next; 13357c478bd9Sstevel@tonic-gate } 13363906e0c2Srie next; 13373906e0c2Srie } 13383906e0c2Srie 13393906e0c2Srie # Inspect the relocation information. As we're only looking 13403906e0c2Srie # for copy relocations, this processing is only necessary for 13413906e0c2Srie # executables. 13423906e0c2Srie if ($Rel eq 1) { 13433906e0c2Srie my ($SymName); 13443906e0c2Srie 13453906e0c2Srie if ($Exec eq 0) { 13463906e0c2Srie $Rel = 0; 13473906e0c2Srie next; 13483906e0c2Srie } 13493906e0c2Srie 13503906e0c2Srie # Obtain any copy relocations. 13513906e0c2Srie if ($Line !~ / R_[A-Z0-9]+_COPY /) { 13523906e0c2Srie next; 13533906e0c2Srie } 13543906e0c2Srie 13553906e0c2Srie @Fields = split(' ', $Line); 13563906e0c2Srie 13577010c12aSrie # Intel relocation records don't contain an addend, 13587010c12aSrie # where as every other supported platform does. 13597010c12aSrie if ($Fields[0] eq 'R_386_COPY') { 13607c478bd9Sstevel@tonic-gate $SymName = $Fields[3]; 13617c478bd9Sstevel@tonic-gate } else { 13627010c12aSrie $SymName = $Fields[4]; 13637c478bd9Sstevel@tonic-gate } 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate $Symbols{$SymName}{$Obj}[$ObjFlag] |= $Cpyr; 13667c478bd9Sstevel@tonic-gate $Objects{$Obj}{$SymName} |= $Cpyr; 13677c478bd9Sstevel@tonic-gate $Copy = 1; 13687c478bd9Sstevel@tonic-gate } 13693906e0c2Srie 13703906e0c2Srie # Inspect the .SUNW_syminfo section. 13713906e0c2Srie if ($Info eq 1) { 13723906e0c2Srie my ($SymName); 13733906e0c2Srie my ($Flags) = 0; 13743906e0c2Srie 13753906e0c2Srie @Fields = split(' ', $Line); 13763906e0c2Srie 13773906e0c2Srie # Binding attributes are in the second column. 13783906e0c2Srie if ($#Fields < 1) { 13793906e0c2Srie next; 13803906e0c2Srie } 13813906e0c2Srie if ($Fields[1] =~ /N/) { 13823906e0c2Srie $Flags |= $Nodi; 13833906e0c2Srie } 13843906e0c2Srie if ($Fields[1] =~ /F/) { 13853906e0c2Srie $Flags |= $Ssft; 13863906e0c2Srie } 13873906e0c2Srie if ($Fields[1] =~ /A/) { 13883906e0c2Srie $Flags |= $Saft; 13897c478bd9Sstevel@tonic-gate } 13909a411307Srie if ($Fields[1] =~ /I/) { 13919a411307Srie $Flags |= $Intp; 13929a411307Srie } 13937c478bd9Sstevel@tonic-gate 13943906e0c2Srie # Determine the symbol name based upon the number of 13953906e0c2Srie # fields. 13963906e0c2Srie if ($Flags) { 13973906e0c2Srie $SymName = $Fields[$#Fields]; 13983906e0c2Srie $Symbols{$SymName}{$Obj}[$ObjFlag] |= $Flags; 13993906e0c2Srie $Objects{$Obj}{$SymName} |= $Flags; 14003906e0c2Srie } 14013906e0c2Srie 14023906e0c2Srie # If this is a filter, we need to tag the associated 14033906e0c2Srie # filtee symbol. However, the filtee might not have 14043906e0c2Srie # been processed yet, so save this information for later. 14059a411307Srie $Flags &= ~($Nodi | $Intp); 14063906e0c2Srie if ($Flags) { 14073906e0c2Srie my ($Filtee) = $Fields[$#Fields - 1]; 14083906e0c2Srie 14093906e0c2Srie if ($Filtee =~ $Rtld) { 14103906e0c2Srie next; 14113906e0c2Srie } 14123906e0c2Srie $SymFltes{$Filtee}{$SymName}[$SymFlag] = $Flags; 14133906e0c2Srie } 14143906e0c2Srie } 14153906e0c2Srie } 14163906e0c2Srie 14173906e0c2Srie close($FileHandle); 14183906e0c2Srie 14193906e0c2Srie # If there's no expected information, it's possible we've been given a 14203906e0c2Srie # debug output file and are processing the file from a location from 14213906e0c2Srie # which the dependencies specified in the debug file aren't accessible. 14223906e0c2Srie if ($Dyn eq 0) { 14233906e0c2Srie printf STDERR gettext("%s: %s: unable to process ELF file\n"), 14243906e0c2Srie $Prog, $Obj; 14253906e0c2Srie 14263906e0c2Srie # Add the file to our list, so that we don't create the same 14273906e0c2Srie # message again. Processing should continue so that we can 14283906e0c2Srie # flush out as many error messages as possible. 14293906e0c2Srie $Objects{$Obj}{"DoesNotExist"} = 0; 14303906e0c2Srie return; 14313906e0c2Srie } 14323906e0c2Srie 14337a5d89c4Sab196087 # Process elfdump(1) once more to obtain the .dynsym symbol table. We 14347a5d89c4Sab196087 # are only interested in global symbols, so .SUNW_ldynsym is not needed. 14357c478bd9Sstevel@tonic-gate open($FileHandle, "LC_ALL=C elfdump -sN.dynsym '$Obj' 2> /dev/null |"); 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate while (defined(my $Line = <$FileHandle>)) { 14387c478bd9Sstevel@tonic-gate chomp($Line); 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate my (@Fields) = split(' ', $Line); 14417c478bd9Sstevel@tonic-gate my ($Flags); 14427c478bd9Sstevel@tonic-gate 14433906e0c2Srie # We're only interested in defined symbol entries. Unless 14443906e0c2Srie # we've been asked for all symbols, ignore any ABS or NOTY 14453906e0c2Srie # symbols. The former are typically reserved symbols or 14463906e0c2Srie # versioning names. The latter are labels that are not bound 14473906e0c2Srie # to. Note, ABS and NOTY symbols of non-zero size have been 14483906e0c2Srie # known to occur, so capture them. 14497c478bd9Sstevel@tonic-gate if (($#Fields < 8) || ($Fields[4] !~ $GlobWeak) || 14503906e0c2Srie ($Fields[7] eq 'UNDEF') || 14513906e0c2Srie (!$opt{a} && (oct($Fields[2]) eq 0) && 14523906e0c2Srie ((($Fields[7] eq 'ABS') && ($Fields[3] eq 'OBJT')) || 14533906e0c2Srie ($Fields[3] eq 'NOTY')))) { 14547c478bd9Sstevel@tonic-gate next; 14557c478bd9Sstevel@tonic-gate } 14567c478bd9Sstevel@tonic-gate 14573906e0c2Srie # If we're found copy relocations, save the address of all OBJT 14583906e0c2Srie # definitions, together with the copy symbol. These definitions 14593906e0c2Srie # are used to determine whether the copy symbol has any aliases 14603906e0c2Srie # (ie. __iob and _iob). 14613906e0c2Srie if (($Copy eq 1) && ($Fields[3] eq 'OBJT')) { 14627c478bd9Sstevel@tonic-gate push(@{$AddrToName{$Fields[1]}}, $Fields[8]); 14633906e0c2Srie 14647c478bd9Sstevel@tonic-gate if (($Symbols{$Fields[8]}{$Obj}) && 14657c478bd9Sstevel@tonic-gate ($Symbols{$Fields[8]}{$Obj}[$ObjFlag] & $Cpyr)) { 14667c478bd9Sstevel@tonic-gate $NameToAddr{$Fields[8]} = $Fields[1]; 14677c478bd9Sstevel@tonic-gate } 14683906e0c2Srie } 14693906e0c2Srie 14703906e0c2Srie # Identify this symbol as global, and associate it with any 14713906e0c2Srie # object filtering. 14723906e0c2Srie $Flags = $Glob | $Fltr; 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate # If the symbol visibility is protected, this is an internal 14753906e0c2Srie # symbolic binding. Note, an INTERNAL visibility for a global 14767c478bd9Sstevel@tonic-gate # symbol is invalid, but for a while ld(1) was setting this 14773906e0c2Srie # attribute mistakenly for protected. If this is a dynamic 14783906e0c2Srie # executable, mark its symbols as protected. These symbols 14793906e0c2Srie # can't be interposed on any more than symbols defined as 14807c478bd9Sstevel@tonic-gate # protected within shared objects). 14817c478bd9Sstevel@tonic-gate if (($Fields[5] =~ /^[IP]$/) || $Symb || $Exec) { 14827c478bd9Sstevel@tonic-gate $Flags |= $Prot; 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate # If this object is marked as an interposer, tag each symbol. 14867c478bd9Sstevel@tonic-gate if ($Interpose) { 14877c478bd9Sstevel@tonic-gate $Flags |= $Intp; 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate # Identify the symbol as a function or data type, and for the 14913906e0c2Srie # latter, capture the symbol size. Ignore the standard symbolic 14923906e0c2Srie # labels, as we don't want to type them. 14937c478bd9Sstevel@tonic-gate if ($Fields[8] !~ $MultSyms) { 14947c478bd9Sstevel@tonic-gate if ($Fields[3] =~ /^FUNC$/) { 14957c478bd9Sstevel@tonic-gate $Flags |= $Func; 14967c478bd9Sstevel@tonic-gate } elsif ($Fields[3] =~ /^OBJT$/) { 14977c478bd9Sstevel@tonic-gate my ($Size) = $Fields[2]; 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate if (oct($Size) eq 0) { 15007c478bd9Sstevel@tonic-gate $Size = "0"; 15017c478bd9Sstevel@tonic-gate } else { 15027c478bd9Sstevel@tonic-gate $Size =~ s/0x0*/0x/; 15037c478bd9Sstevel@tonic-gate } 15047c478bd9Sstevel@tonic-gate $Flags |= $Objt; 15057c478bd9Sstevel@tonic-gate $Symbols{$Fields[8]}{$Obj}[$ObjSize] = $Size; 15067c478bd9Sstevel@tonic-gate } 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate $Symbols{$Fields[8]}{$Obj}[$ObjFlag] |= $Flags; 151060758829Srie $Symbols{$Fields[8]}{$Obj}[$ObjVis] = $Fields[5]; 15117c478bd9Sstevel@tonic-gate $Objects{$Obj}{$Fields[8]} |= $Flags; 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate # If the version field is non-null this object has already been 15147c478bd9Sstevel@tonic-gate # versioned. 15157c478bd9Sstevel@tonic-gate if (($Vers == 0) && ($Fields[6] ne '0')) { 15167c478bd9Sstevel@tonic-gate $Versioned{$Obj} = 1; 15177c478bd9Sstevel@tonic-gate $Vers = 1; 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate close($FileHandle); 15217c478bd9Sstevel@tonic-gate 15223906e0c2Srie # Process any copy relocation symbols to see if the copy symbol has any 15233906e0c2Srie # aliases, which should also be marked as copy relocations. 15247c478bd9Sstevel@tonic-gate if ($Copy) { 15257c478bd9Sstevel@tonic-gate foreach my $SymName (keys(%NameToAddr)) { 15267c478bd9Sstevel@tonic-gate my ($Addr) = $NameToAddr{$SymName}; 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate # Determine all symbols that have the same address. 15297c478bd9Sstevel@tonic-gate foreach my $AliasName (@{$AddrToName{$Addr}}) { 15307c478bd9Sstevel@tonic-gate if ($SymName eq $AliasName) { 15317c478bd9Sstevel@tonic-gate next; 15327c478bd9Sstevel@tonic-gate } 15337c478bd9Sstevel@tonic-gate $Symbols{$AliasName}{$Obj}[$ObjFlag] |= $Cpyr; 15347c478bd9Sstevel@tonic-gate $Objects{$Obj}{$AliasName} |= $Cpyr; 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate } 15377c478bd9Sstevel@tonic-gate } 15387c478bd9Sstevel@tonic-gate} 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate# Demangle a symbol name if required. 15417c478bd9Sstevel@tonic-gatesub Demangle 15427c478bd9Sstevel@tonic-gate{ 15437c478bd9Sstevel@tonic-gate my ($SymName) = @_; 15447c478bd9Sstevel@tonic-gate my ($DemName); 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate if ($opt{C}) { 15477c478bd9Sstevel@tonic-gate my (@Dem); 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate # Determine if we've already demangled this name. 15507c478bd9Sstevel@tonic-gate if (exists($DemSyms{$SymName})) { 15517c478bd9Sstevel@tonic-gate return $DemSyms{$SymName}; 15527c478bd9Sstevel@tonic-gate } 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate @Dem = split(/\n/, `dem '$SymName'`); 15557c478bd9Sstevel@tonic-gate foreach my $Line (@Dem) { 15567c478bd9Sstevel@tonic-gate my (@Fields) = split(' ', $Line); 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate if (($#Fields < 2) || ($Fields[1] ne '==') || 15597c478bd9Sstevel@tonic-gate ($Fields[0] eq $Fields[2])) { 15607c478bd9Sstevel@tonic-gate next; 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate $DemName = $Line; 15637c478bd9Sstevel@tonic-gate $DemName =~ s/.*== (.*)$/ \[$1]/; 15647c478bd9Sstevel@tonic-gate $DemSyms{$SymName} = $DemName; 15657c478bd9Sstevel@tonic-gate return($DemName); 15667c478bd9Sstevel@tonic-gate } 15677c478bd9Sstevel@tonic-gate } 15687c478bd9Sstevel@tonic-gate $DemSyms{$SymName} = ""; 15697c478bd9Sstevel@tonic-gate return(""); 15707c478bd9Sstevel@tonic-gate} 1571