1b8851fccSafresh1#!/usr/bin/perl -w 2b8851fccSafresh1 3b8851fccSafresh1# Try opening libperl.a with nm, and verifying it has the kind of 4b8851fccSafresh1# symbols we expect, and no symbols we should avoid. 5b8851fccSafresh1# 6b8851fccSafresh1# Fail softly, expect things only on known platforms: 7b8851fccSafresh1# - linux, x86 only (ppc linux has odd symbol tables) 8b8851fccSafresh1# - darwin (OS X), both x86 and ppc 9b8851fccSafresh1# - freebsd 10b8851fccSafresh1# and on other platforms, and if things seem odd, just give up (skip_all). 11b8851fccSafresh1# 12e0680481Safresh1# Symbol types for LTO builds don't seem to match their final section, so 13e0680481Safresh1# skip on LTO builds too. 14e0680481Safresh1# 15b8851fccSafresh1# Debugging tip: nm output (this script's input) can be faked by 16b8851fccSafresh1# giving one command line argument for this script: it should be 17b8851fccSafresh1# either the filename to read, or "-" for STDIN. You can also append 18b8851fccSafresh1# "@style" (where style is a supported nm style, like "gnu" or "darwin") 19b8851fccSafresh1# to this filename for "cross-parsing". 20b8851fccSafresh1# 21b8851fccSafresh1# Some terminology: 22b8851fccSafresh1# - "text" symbols are code 23b8851fccSafresh1# - "data" symbols are data (duh), with subdivisions: 24b8851fccSafresh1# - "bss": (Block-Started-by-Symbol: originally from IBM assembler...), 25b8851fccSafresh1# uninitialized data, which often even doesn't exist in the object 26b8851fccSafresh1# file as such, only its size does, which is then created on demand 27b8851fccSafresh1# by the loader 28b8851fccSafresh1# - "const": initialized read-only data, like string literals 29b8851fccSafresh1# - "common": uninitialized data unless initialized... 30b8851fccSafresh1# (the full story is too long for here, see "man nm") 31b8851fccSafresh1# - "data": initialized read-write data 32b8851fccSafresh1# (somewhat confusingly below: "data data", but it makes code simpler) 33b8851fccSafresh1# - "undefined": external symbol referred to by an object, 34b8851fccSafresh1# most likely a text symbol. Can be either a symbol defined by 35b8851fccSafresh1# a Perl object file but referred to by other Perl object files, 36b8851fccSafresh1# or a completely external symbol from libc, or other system libraries. 37b8851fccSafresh1 38b8851fccSafresh1BEGIN { 39b8851fccSafresh1 chdir 't' if -d 't'; 40b8851fccSafresh1 @INC = '../lib'; 41b8851fccSafresh1 require "./test.pl"; 42b8851fccSafresh1} 43b8851fccSafresh1 44b8851fccSafresh1use strict; 45b8851fccSafresh1 46b8851fccSafresh1use Config; 47b8851fccSafresh1 48*3d61058aSafresh1# maint (and tarballs of maint releases) may not have updates here to 49*3d61058aSafresh1# deal with changes to nm's output in some toolchains 50*3d61058aSafresh1$^V =~ /^v\d+\.\d*[13579]\./ 51*3d61058aSafresh1 or skip_all "on maint"; 52*3d61058aSafresh1 53b8851fccSafresh1if ($Config{cc} =~ /g\+\+/) { 54b8851fccSafresh1 # XXX Could use c++filt, maybe. 55b8851fccSafresh1 skip_all "on g++"; 56b8851fccSafresh1} 57b8851fccSafresh1 58e0680481Safresh1# ccname is gcc for both gcc and clang 59e0680481Safresh1if ($Config{ccname} eq "gcc" && $Config{ccflags} =~ /-flto\b/) { 60e0680481Safresh1 # If we compile with gcc nm marks PL_no_mem as "D" (normal data) rather than a R (read only) 61e0680481Safresh1 # but the symbol still ends up in the .rodata section of the image on linking. 62e0680481Safresh1 # If we compile with clang 14, nm marks PL_no_mem as "T" (text, aka code) rather than R 63e0680481Safresh1 # but the symbol still ends up in the .rodata section on linking. 64e0680481Safresh1 skip_all "LTO libperl.a flags don't match the final linker sections"; 65e0680481Safresh1} 66e0680481Safresh1 67b8851fccSafresh1my $libperl_a; 68b8851fccSafresh1 69b8851fccSafresh1for my $f (qw(../libperl.a libperl.a)) { 70b8851fccSafresh1 if (-f $f) { 71b8851fccSafresh1 $libperl_a = $f; 72b8851fccSafresh1 last; 73b8851fccSafresh1 } 74b8851fccSafresh1} 75b8851fccSafresh1 76b8851fccSafresh1unless (defined $libperl_a) { 77b8851fccSafresh1 skip_all "no libperl.a"; 78b8851fccSafresh1} 79b8851fccSafresh1 80b8851fccSafresh1print "# \$^O = $^O\n"; 81b8851fccSafresh1print "# \$Config{archname} = $Config{archname}\n"; 82b8851fccSafresh1print "# \$Config{cc} = $Config{cc}\n"; 83b8851fccSafresh1print "# libperl = $libperl_a\n"; 84b8851fccSafresh1 85b8851fccSafresh1my $nm; 86b8851fccSafresh1my $nm_opt = ''; 87b8851fccSafresh1my $nm_style; 88b8851fccSafresh1my $nm_fh; 89b8851fccSafresh1my $nm_err_tmp = "libperl$$"; 90b8851fccSafresh1 91b8851fccSafresh1END { 92b8851fccSafresh1 # this is still executed when we skip_all above, avoid a warning 93b8851fccSafresh1 unlink $nm_err_tmp if $nm_err_tmp; 94b8851fccSafresh1} 95b8851fccSafresh1 96b8851fccSafresh1my $fake_input; 97b8851fccSafresh1my $fake_style; 98b8851fccSafresh1 99b8851fccSafresh1if (@ARGV == 1) { 100b8851fccSafresh1 $fake_input = shift @ARGV; 101b8851fccSafresh1 print "# Faking nm output from $fake_input\n"; 102b8851fccSafresh1 if ($fake_input =~ s/\@(.+)$//) { 103b8851fccSafresh1 $fake_style = $1; 104b8851fccSafresh1 print "# Faking nm style from $fake_style\n"; 105b8851fccSafresh1 if ($fake_style eq 'gnu' || 106b8851fccSafresh1 $fake_style eq 'linux' || 107b8851fccSafresh1 $fake_style eq 'freebsd') { 108b8851fccSafresh1 $nm_style = 'gnu' 109b8851fccSafresh1 } elsif ($fake_style eq 'darwin' || $fake_style eq 'osx') { 110b8851fccSafresh1 $nm_style = 'darwin' 111b8851fccSafresh1 } else { 112b8851fccSafresh1 die "$0: Unknown explicit nm style '$fake_style'\n"; 113b8851fccSafresh1 } 114b8851fccSafresh1 } 115b8851fccSafresh1} 116b8851fccSafresh1 117b8851fccSafresh1unless (defined $nm_style) { 118b8851fccSafresh1 if ($^O eq 'linux') { 119b8851fccSafresh1 # The 'gnu' style could be equally well be called 'bsd' style, 120b8851fccSafresh1 # since the output format of the GNU binutils nm is really BSD. 121b8851fccSafresh1 $nm_style = 'gnu'; 122b8851fccSafresh1 } elsif ($^O eq 'freebsd') { 123b8851fccSafresh1 $nm_style = 'gnu'; 124b8851fccSafresh1 } elsif ($^O eq 'darwin') { 125b8851fccSafresh1 $nm_style = 'darwin'; 126b8851fccSafresh1 } 127b8851fccSafresh1} 128b8851fccSafresh1 129b8851fccSafresh1if (defined $nm_style) { 130b8851fccSafresh1 if ($nm_style eq 'gnu') { 131b8851fccSafresh1 $nm = '/usr/bin/nm'; 132b8851fccSafresh1 } elsif ($nm_style eq 'darwin') { 133b8851fccSafresh1 $nm = '/usr/bin/nm'; 134b8851fccSafresh1 # With the -m option we get better information than the BSD-like 135b8851fccSafresh1 # default: with the default, a lot of symbols get dumped into 'S' 136b8851fccSafresh1 # or 's', for example one cannot tell the difference between const 137b8851fccSafresh1 # and non-const data symbols. 138b8851fccSafresh1 $nm_opt = '-m'; 139b8851fccSafresh1 } else { 140b8851fccSafresh1 die "$0: Unexpected nm style '$nm_style'\n"; 141b8851fccSafresh1 } 142b8851fccSafresh1} 143b8851fccSafresh1 1445759b3d2Safresh1if ($^O eq 'linux' && $Config{archname} !~ /^(?:x|i6)86/) { 145b8851fccSafresh1 # For example in ppc most (but not all!) code symbols are placed 146b8851fccSafresh1 # in 'D' (data), not in ' T '. We cannot work under such conditions. 147b8851fccSafresh1 skip_all "linux but archname $Config{archname} not x86*"; 148b8851fccSafresh1} 149b8851fccSafresh1 150b8851fccSafresh1unless (defined $nm) { 151b8851fccSafresh1 skip_all "no nm"; 152b8851fccSafresh1} 153b8851fccSafresh1 154b8851fccSafresh1unless (defined $nm_style) { 155b8851fccSafresh1 skip_all "no nm style"; 156b8851fccSafresh1} 157b8851fccSafresh1 158b8851fccSafresh1print "# nm = $nm\n"; 159b8851fccSafresh1print "# nm_style = $nm_style\n"; 160b8851fccSafresh1print "# nm_opt = $nm_opt\n"; 161b8851fccSafresh1 162b8851fccSafresh1unless (-x $nm) { 163b8851fccSafresh1 skip_all "no executable nm $nm"; 164b8851fccSafresh1} 165b8851fccSafresh1 166b8851fccSafresh1if ($nm_style eq 'gnu' && !defined $fake_style) { 167b8851fccSafresh1 open(my $gnu_verify, "$nm --version|") or 168b8851fccSafresh1 skip_all "nm failed: $!"; 169b8851fccSafresh1 my $gnu_verified; 170b8851fccSafresh1 while (<$gnu_verify>) { 171b8851fccSafresh1 if (/^GNU nm/) { 172b8851fccSafresh1 $gnu_verified = 1; 173b8851fccSafresh1 last; 174b8851fccSafresh1 } 175b8851fccSafresh1 } 176b8851fccSafresh1 unless ($gnu_verified) { 177b8851fccSafresh1 skip_all "no GNU nm"; 178b8851fccSafresh1 } 179b8851fccSafresh1} 180b8851fccSafresh1 181b8851fccSafresh1if (defined $fake_input) { 182b8851fccSafresh1 if ($fake_input eq '-') { 183b8851fccSafresh1 open($nm_fh, "<&STDIN") or 184b8851fccSafresh1 skip_all "Duping STDIN failed: $!"; 185b8851fccSafresh1 } else { 186b8851fccSafresh1 open($nm_fh, "<", $fake_input) or 187b8851fccSafresh1 skip_all "Opening '$fake_input' failed: $!"; 188b8851fccSafresh1 } 189b8851fccSafresh1 undef $nm_err_tmp; # In this case there will be no nm errors. 190b8851fccSafresh1} else { 1915759b3d2Safresh1 print qq{# command: "$nm $nm_opt $libperl_a 2>$nm_err_tmp |"\n}; 192b8851fccSafresh1 open($nm_fh, "$nm $nm_opt $libperl_a 2>$nm_err_tmp |") or 193b8851fccSafresh1 skip_all "$nm $nm_opt $libperl_a failed: $!"; 194b8851fccSafresh1} 195b8851fccSafresh1 196b8851fccSafresh1sub is_perlish_symbol { 197b8851fccSafresh1 $_[0] =~ /^(?:PL_|Perl|PerlIO)/; 198b8851fccSafresh1} 199b8851fccSafresh1 200b8851fccSafresh1# XXX Implement "internal test" for this script (option -t?) 201b8851fccSafresh1# to verify that the parsing does what it's intended to. 202b8851fccSafresh1 203b8851fccSafresh1sub nm_parse_gnu { 204b8851fccSafresh1 my $symbols = shift; 205b8851fccSafresh1 my $line = $_; 206b8851fccSafresh1 if (m{^(\w+\.o):$}) { 207b8851fccSafresh1 # object file name 208b8851fccSafresh1 $symbols->{obj}{$1}++; 209b8851fccSafresh1 $symbols->{o} = $1; 210b8851fccSafresh1 return; 211b8851fccSafresh1 } else { 212b8851fccSafresh1 die "$0: undefined current object: $line" 213b8851fccSafresh1 unless defined $symbols->{o}; 214b8851fccSafresh1 # 64-bit systems have 16 hexdigits, 32-bit systems have 8. 215b8851fccSafresh1 if (s/^[0-9a-f]{8}(?:[0-9a-f]{8})? //) { 216b8851fccSafresh1 if (/^[Rr] (\w+)$/) { 217b8851fccSafresh1 # R: read only (const) 218b8851fccSafresh1 $symbols->{data}{const}{$1}{$symbols->{o}}++; 219b8851fccSafresh1 } elsif (/^r .+$/) { 220b8851fccSafresh1 # Skip local const (read only). 221b8851fccSafresh1 } elsif (/^([Tti]) (\w+)(\..+)?$/) { 222b8851fccSafresh1 $symbols->{text}{$2}{$symbols->{o}}{$1}++; 223b8851fccSafresh1 } elsif (/^C (\w+)$/) { 224b8851fccSafresh1 $symbols->{data}{common}{$1}{$symbols->{o}}++; 225b8851fccSafresh1 } elsif (/^[BbSs] (\w+)(\.\d+)?$/) { 226b8851fccSafresh1 # Bb: uninitialized data (bss) 227b8851fccSafresh1 # Ss: uninitialized data "for small objects" 228b8851fccSafresh1 $symbols->{data}{bss}{$1}{$symbols->{o}}++; 229b8851fccSafresh1 } elsif (/^D _LIB_VERSION$/) { 230b8851fccSafresh1 # Skip the _LIB_VERSION (not ours, probably libm) 231b8851fccSafresh1 } elsif (/^[DdGg] (\w+)$/) { 232b8851fccSafresh1 # Dd: initialized data 233b8851fccSafresh1 # Gg: initialized "for small objects" 234b8851fccSafresh1 $symbols->{data}{data}{$1}{$symbols->{o}}++; 235b8851fccSafresh1 } elsif (/^. \.?(\w+)$/) { 236b8851fccSafresh1 # Skip the unknown types. 237b8851fccSafresh1 print "# Unknown type: $line ($symbols->{o})\n"; 238b8851fccSafresh1 } 239b8851fccSafresh1 return; 240b8851fccSafresh1 } elsif (/^ {8}(?: {8})? U _?(\w+)$/) { 241b8851fccSafresh1 my ($symbol) = $1; 242b8851fccSafresh1 return if is_perlish_symbol($symbol); 243b8851fccSafresh1 $symbols->{undef}{$symbol}{$symbols->{o}}++; 244b8851fccSafresh1 return; 245b8851fccSafresh1 } 246b8851fccSafresh1 } 247b8851fccSafresh1 print "# Unexpected nm output '$line' ($symbols->{o})\n"; 248b8851fccSafresh1} 249b8851fccSafresh1 250b8851fccSafresh1sub nm_parse_darwin { 251b8851fccSafresh1 my $symbols = shift; 252b8851fccSafresh1 my $line = $_; 253*3d61058aSafresh1 if (m{^(?:.+)?libperl\.a\((\w+\.o)\):$} || 254*3d61058aSafresh1 m{^(\w+\.o):$}) { 255b8851fccSafresh1 # object file name 256b8851fccSafresh1 $symbols->{obj}{$1}++; 257b8851fccSafresh1 $symbols->{o} = $1; 258b8851fccSafresh1 return; 259b8851fccSafresh1 } else { 260b8851fccSafresh1 die "$0: undefined current object: $line" unless defined $symbols->{o}; 261b8851fccSafresh1 # 64-bit systems have 16 hexdigits, 32-bit systems have 8. 262b8851fccSafresh1 if (s/^[0-9a-f]{8}(?:[0-9a-f]{8})? //) { 263b8851fccSafresh1 # String literals can live in different sections 264b8851fccSafresh1 # depending on the compiler and os release, assumedly 265b8851fccSafresh1 # also linker flags. 266*3d61058aSafresh1 if (/^\(__TEXT,__(?:const|(?:asan_)?cstring|literal\d+)\) (?:non-)?external _?(\w+)(\.\w+){0,2}$/) { 267b8851fccSafresh1 my ($symbol, $suffix) = ($1, $2); 268b8851fccSafresh1 # Ignore function-local constants like 269b8851fccSafresh1 # _Perl_av_extend_guts.oom_array_extend 270b8851fccSafresh1 return if defined $suffix && /__TEXT,__const/; 271b8851fccSafresh1 # Ignore the cstring unnamed strings. 272b8851fccSafresh1 return if $symbol =~ /^L\.str\d+$/; 273b8851fccSafresh1 $symbols->{data}{const}{$symbol}{$symbols->{o}}++; 274*3d61058aSafresh1 } elsif (/^\(__TEXT,__text\) ((?:non-|private )?external) \[cold func\] _(\w+\.cold\.[1-9][0-9]*)$/) { 275*3d61058aSafresh1 # for N_COLD_FUNC symbols in MachO 276*3d61058aSafresh1 # eg. 0000000000022c60 (__TEXT,__text) non-external [cold func] _Perl_lex_next_chunk.cold.1 (toke.o) 277*3d61058aSafresh1 } elsif (/^\(__TEXT,__text\) ((?:non-|private )?external) _(\w+)$/) { 278b8851fccSafresh1 my ($exp, $sym) = ($1, $2); 279b8851fccSafresh1 $symbols->{text}{$sym}{$symbols->{o}}{$exp =~ /^non/ ? 't' : 'T'}++; 280*3d61058aSafresh1 } elsif (/^\(__DATA,__\w*?(const|data|bss|common)\w*\) (?:non-)?external _?(\w+)(\.\w+){0,3}$/) { 281b8851fccSafresh1 my ($dtype, $symbol, $suffix) = ($1, $2, $3); 282b8851fccSafresh1 # Ignore function-local constants like 283b8851fccSafresh1 # _Perl_pp_gmtime.dayname 284b8851fccSafresh1 return if defined $suffix; 285b8851fccSafresh1 $symbols->{data}{$dtype}{$symbol}{$symbols->{o}}++; 286b8851fccSafresh1 } elsif (/^\(__DATA,__const\) non-external _\.memset_pattern\d*$/) { 287b8851fccSafresh1 # Skip this, whatever it is (some inlined leakage from 288b8851fccSafresh1 # darwin libc?) 289b8851fccSafresh1 } elsif (/^\(__TEXT,__eh_frame/) { 290b8851fccSafresh1 # Skip the eh_frame (exception handling) symbols. 291b8851fccSafresh1 return; 292b8851fccSafresh1 } elsif (/^\(__\w+,__\w+\) /) { 293b8851fccSafresh1 # Skip the unknown types. 294b8851fccSafresh1 print "# Unknown type: $line ($symbols->{o})\n"; 295b8851fccSafresh1 } 296b8851fccSafresh1 return; 297b8851fccSafresh1 } elsif (/^ {8}(?: {8})? \(undefined(?: \[lazy bound\])?\) external _?(.+)/) { 298b8851fccSafresh1 # darwin/ppc marks most undefined text symbols 299b8851fccSafresh1 # as "[lazy bound]". 3005759b3d2Safresh1 my ($symbol) = $1 =~ s/\$UNIX2003\z//r; 301b8851fccSafresh1 return if is_perlish_symbol($symbol); 302b8851fccSafresh1 $symbols->{undef}{$symbol}{$symbols->{o}}++; 303b8851fccSafresh1 return; 304b8851fccSafresh1 } 305b8851fccSafresh1 } 306b8851fccSafresh1 print "# Unexpected nm output '$line' ($symbols->{o})\n"; 307b8851fccSafresh1} 308b8851fccSafresh1 309b8851fccSafresh1my $nm_parse; 310b8851fccSafresh1 311b8851fccSafresh1if ($nm_style eq 'gnu') { 312b8851fccSafresh1 $nm_parse = \&nm_parse_gnu; 313b8851fccSafresh1} elsif ($nm_style eq 'darwin') { 314b8851fccSafresh1 $nm_parse = \&nm_parse_darwin; 315b8851fccSafresh1} 316b8851fccSafresh1 317b8851fccSafresh1unless (defined $nm_parse) { 318b8851fccSafresh1 skip_all "no nm parser ($nm_style $nm_style, \$^O $^O)"; 319b8851fccSafresh1} 320b8851fccSafresh1 321b8851fccSafresh1my %symbols; 322b8851fccSafresh1 323b8851fccSafresh1while (<$nm_fh>) { 324b8851fccSafresh1 next if /^$/; 325b8851fccSafresh1 chomp; 326b8851fccSafresh1 $nm_parse->(\%symbols); 327b8851fccSafresh1} 328b8851fccSafresh1 329b8851fccSafresh1# use Data::Dumper; print Dumper(\%symbols); 330b8851fccSafresh1 331b8851fccSafresh1# Something went awfully wrong. Wrong nm? Wrong options? 332b8851fccSafresh1unless (keys %symbols) { 333b8851fccSafresh1 skip_all "no symbols\n"; 334b8851fccSafresh1} 335b8851fccSafresh1unless (exists $symbols{text}) { 336b8851fccSafresh1 skip_all "no text symbols\n"; 337b8851fccSafresh1} 338b8851fccSafresh1 339b8851fccSafresh1# These should always be true for everyone. 340b8851fccSafresh1 341e0680481Safresh1ok($symbols{obj}{'util.o'}, "has object util.o"); 342e0680481Safresh1ok($symbols{text}{'Perl_croak'}{'util.o'}, "has text Perl_croak in util.o"); 343b8851fccSafresh1ok(exists $symbols{data}{const}, "has data const symbols"); 344*3d61058aSafresh1ok($symbols{data}{const}{PL_no_modify}{'globals.o'}, "has PL_no_modify"); 345b8851fccSafresh1 346b46d8ef2Safresh1my $nocommon = $Config{ccflags} =~ /-fno-common/ ? 1 : 0; 347b8851fccSafresh1 348b46d8ef2Safresh1print "# nocommon = $nocommon\n"; 349b8851fccSafresh1 350b8851fccSafresh1my %data_symbols; 351b8851fccSafresh1 352b8851fccSafresh1for my $dtype (sort keys %{$symbols{data}}) { 353b8851fccSafresh1 for my $symbol (sort keys %{$symbols{data}{$dtype}}) { 354b8851fccSafresh1 $data_symbols{$symbol}++; 355b8851fccSafresh1 } 356b8851fccSafresh1} 357b8851fccSafresh1 358b8851fccSafresh1if ( !$symbols{data}{common} ) { 359b8851fccSafresh1 # This is likely because Perl was compiled with 360b8851fccSafresh1 # -Accflags="-fno-common" 361b8851fccSafresh1 $symbols{data}{common} = $symbols{data}{bss}; 362b8851fccSafresh1} 363b8851fccSafresh1 3649dc91179Safresh1ok($symbols{data}{common}{PL_hash_seed_w}{'globals.o'}, "has PL_hash_seed_w"); 365b8851fccSafresh1ok($symbols{data}{data}{PL_ppaddr}{'globals.o'}, "has PL_ppaddr"); 366b8851fccSafresh1 367b8851fccSafresh1# See the comments in the beginning for what "undefined symbols" 368b8851fccSafresh1# really means. We *should* have many of those, that is a good thing. 369b8851fccSafresh1ok(keys %{$symbols{undef}}, "has undefined symbols"); 370b8851fccSafresh1 371b8851fccSafresh1# There are certain symbols we expect to see. 372b8851fccSafresh1 373b8851fccSafresh1# chmod, socket, getenv, sigaction, exp, time are system/library 374b8851fccSafresh1# calls that should each see at least one use. exp can be expl 375b8851fccSafresh1# if so configured. 376b8851fccSafresh1my %expected = ( 377b8851fccSafresh1 chmod => undef, # There is no Configure symbol for chmod. 378b8851fccSafresh1 socket => 'd_socket', 379b8851fccSafresh1 getenv => undef, # There is no Configure symbol for getenv, 380b8851fccSafresh1 sigaction => 'd_sigaction', 381b8851fccSafresh1 time => 'd_time', 382b8851fccSafresh1 ); 383b8851fccSafresh1 384b8851fccSafresh1if ($Config{uselongdouble} && $Config{longdblsize} > $Config{doublesize}) { 385b8851fccSafresh1 $expected{expl} = undef; # There is no Configure symbol for expl. 386b8851fccSafresh1} elsif ($Config{usequadmath}) { 387b8851fccSafresh1 $expected{expq} = undef; # There is no Configure symbol for expq. 388b8851fccSafresh1} else { 389b8851fccSafresh1 $expected{exp} = undef; # There is no Configure symbol for exp. 390b8851fccSafresh1} 391b8851fccSafresh1 392b8851fccSafresh1# DynaLoader will use dlopen, unless we are building static, 393b8851fccSafresh1# and it is used in the platforms we are supporting in this test. 394b8851fccSafresh1if ($Config{usedl} ) { 395b8851fccSafresh1 $expected{dlopen} = 'd_dlopen'; 396b8851fccSafresh1} 397b8851fccSafresh1 398b8851fccSafresh1for my $symbol (sort keys %expected) { 399b8851fccSafresh1 if (defined $expected{$symbol} && !$Config{$expected{$symbol}}) { 400b8851fccSafresh1 SKIP: { 401b8851fccSafresh1 skip("no $symbol"); 402b8851fccSafresh1 } 403b8851fccSafresh1 next; 404b8851fccSafresh1 } 405b8851fccSafresh1 my @o = exists $symbols{undef}{$symbol} ? 406b8851fccSafresh1 sort keys %{ $symbols{undef}{$symbol} } : (); 407b8851fccSafresh1 ok(@o, "uses $symbol (@o)"); 408b8851fccSafresh1} 409b8851fccSafresh1 410b8851fccSafresh1# There are certain symbols we expect NOT to see. 411b8851fccSafresh1# 412b8851fccSafresh1# gets is horribly unsafe. 413b8851fccSafresh1# 414b8851fccSafresh1# fgets should not be used (Perl has its own API, sv_gets), 415b8851fccSafresh1# even without perlio. 416b8851fccSafresh1# 417b8851fccSafresh1# tmpfile is unsafe. 418b8851fccSafresh1# 419b8851fccSafresh1# strcat, strcpy, strncat, strncpy are unsafe. 420b8851fccSafresh1# 421b8851fccSafresh1# sprintf and vsprintf should not be used because 422b8851fccSafresh1# Perl has its own safer and more portable implementations. 423b8851fccSafresh1# (One exception: for certain floating point outputs 424b8851fccSafresh1# the native sprintf is still used in some platforms, see below.) 425b8851fccSafresh1# 426b8851fccSafresh1# atoi has unsafe and undefined failure modes, and is affected by locale. 427b8851fccSafresh1# Its cousins include atol and atoll. 428b8851fccSafresh1# 429b8851fccSafresh1# strtol and strtoul are affected by locale. 430b8851fccSafresh1# Cousins include strtoq. 431b8851fccSafresh1# 432b8851fccSafresh1# system should not be used, use pp_system or my_popen. 433b8851fccSafresh1# 434b8851fccSafresh1 435b8851fccSafresh1my %unexpected; 436b8851fccSafresh1 437b8851fccSafresh1for my $str (qw(system)) { 438b8851fccSafresh1 $unexpected{$str} = "d_$str"; 439b8851fccSafresh1} 440b8851fccSafresh1 441b8851fccSafresh1for my $stdio (qw(gets fgets tmpfile sprintf vsprintf)) { 442b8851fccSafresh1 $unexpected{$stdio} = undef; # No Configure symbol for these. 443b8851fccSafresh1} 444b8851fccSafresh1for my $str (qw(strcat strcpy strncat strncpy)) { 445b8851fccSafresh1 $unexpected{$str} = undef; # No Configure symbol for these. 446b8851fccSafresh1} 447b8851fccSafresh1 448b8851fccSafresh1$unexpected{atoi} = undef; # No Configure symbol for atoi. 449b8851fccSafresh1$unexpected{atol} = undef; # No Configure symbol for atol. 450b8851fccSafresh1 451b8851fccSafresh1for my $str (qw(atoll strtol strtoul strtoq)) { 452b8851fccSafresh1 $unexpected{$str} = "d_$str"; 453b8851fccSafresh1} 454b8851fccSafresh1 455b8851fccSafresh1for my $symbol (sort keys %unexpected) { 456b8851fccSafresh1 if (defined $unexpected{$symbol} && !$Config{$unexpected{$symbol}}) { 457b8851fccSafresh1 SKIP: { 458b8851fccSafresh1 skip("no $symbol"); 459b8851fccSafresh1 } 460b8851fccSafresh1 next; 461b8851fccSafresh1 } 462b8851fccSafresh1 my @o = exists $symbols{undef}{$symbol} ? 463b8851fccSafresh1 sort keys %{ $symbols{undef}{$symbol} } : (); 464b8851fccSafresh1 # While sprintf() is bad in the general case, 465b8851fccSafresh1 # some platforms implement Gconvert via sprintf, in sv.o. 466b8851fccSafresh1 if ($symbol eq 'sprintf' && 467b8851fccSafresh1 $Config{d_Gconvert} =~ /^sprintf/ && 468b8851fccSafresh1 @o == 1 && $o[0] eq 'sv.o') { 469b8851fccSafresh1 SKIP: { 470b8851fccSafresh1 skip("uses sprintf for Gconvert in sv.o"); 471b8851fccSafresh1 } 472b8851fccSafresh1 } else { 473b8851fccSafresh1 is(@o, 0, "uses no $symbol (@o)"); 474b8851fccSafresh1 } 475b8851fccSafresh1} 476b8851fccSafresh1 477b8851fccSafresh1# Check that any text symbols named S_ are not exported. 478b8851fccSafresh1my $export_S_prefix = 0; 479b8851fccSafresh1for my $t (sort grep { /^S_/ } keys %{$symbols{text}}) { 480b8851fccSafresh1 for my $o (sort keys %{$symbols{text}{$t}}) { 481b8851fccSafresh1 if (exists $symbols{text}{$t}{$o}{T}) { 482b8851fccSafresh1 fail($t, "$t exported from $o"); 483b8851fccSafresh1 $export_S_prefix++; 484b8851fccSafresh1 } 485b8851fccSafresh1 } 486b8851fccSafresh1} 487b8851fccSafresh1is($export_S_prefix, 0, "no S_ exports"); 488b8851fccSafresh1 489b8851fccSafresh1if (defined $nm_err_tmp) { 490b8851fccSafresh1 if (open(my $nm_err_fh, $nm_err_tmp)) { 491b8851fccSafresh1 my $error; 492b8851fccSafresh1 while (<$nm_err_fh>) { 493b8851fccSafresh1 # OS X has weird error where nm warns about 494b8851fccSafresh1 # "no name list" but then outputs fine. 495eac174f2Safresh1 # llvm-nm may also complain about 'no symbols'. In some 496eac174f2Safresh1 # versions this is exactly the string "no symbols\n" but in later 497eac174f2Safresh1 # versions becomes a string followed by ": no symbols\n". For this 498eac174f2Safresh1 # test it is typically "../libperl.a:perlapi.o: no symbols\n" 49998dafc01Safresh1 if ( $^O eq 'darwin' ) { 500eac174f2Safresh1 if (/nm: no name list/ || /^(.*: )?no symbols$/ ) { 501b8851fccSafresh1 print "# $^O ignoring $nm output: $_"; 502b8851fccSafresh1 next; 503b8851fccSafresh1 } 50498dafc01Safresh1 } 505b8851fccSafresh1 warn "$0: Unexpected $nm error: $_"; 506b8851fccSafresh1 $error++; 507b8851fccSafresh1 } 508b8851fccSafresh1 die "$0: Unexpected $nm errors\n" if $error; 509b8851fccSafresh1 } else { 510b8851fccSafresh1 warn "Failed to open '$nm_err_tmp': $!\n"; 511b8851fccSafresh1 } 512b8851fccSafresh1} 513b8851fccSafresh1 514b8851fccSafresh1done_testing(); 515