fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / tools / dev / nm.pl
blobc11429a300e1d9e4e4d47b7164862edac1ee4523
1 #! perl
2 # Copyright (C) 2004-2007, Parrot Foundation.
3 # $Id$
5 =head1 NAME
7 tools/dev/nm.pl - Display symbol table information
9 =head1 SYNOPSIS
11 % perl tools/dev/nm.pl [options] file
13 To list all the symbols in Parrot:
15 % perl tools/dev/nm.pl parrot
17 =head1 DESCRIPTION
19 Portable frontend for C<nm(1)>; by default lists all the code and data
20 symbols in the object or archive files.
22 =head2 Command-Line Options
24 The following options can be used to limit the symbols:
26 =over 4
28 =item C<--code>
30 =item C<-c>
32 List the code/text symbols.
34 =item C<--data>
36 =item C<-d>
38 List the data symbols.
40 =item C<--init>
42 =item C<-i>
44 List the initialised data symbols.
46 =item C<--uninit>
48 =item C<-u>
50 List the uninitialised data symbols.
52 =item C<--const>
54 =item C<-C>
56 List the constant (read-only) data symbols.
58 Not all platforms support this, a warning will be given if not. You can
59 try GNU C<nm> if you want this feature.
61 =item C<--undef>
63 =item C<-U>
65 List the undefined symbols.
67 =item C<--def>
69 =item C<-D>
71 List the defined symbols.
73 =item C<--file>
75 =item C<-f>
77 List the file(name) symbols.
79 =back
81 If more than one of all the above options are given, they are C<AND>ed.
82 They can also be negated with a "no", for example C<--noconst>.
84 =over 4
86 =item C<--objectname>
88 =item C<-o>
90 Prepend the object name before the symbol name.
92 =item C<--t>
94 Append the short BSD-style type to the symbol name.
96 B - uninitialised data symbol
97 D - initialised data symbol
98 F - file name symbol
99 R - read-only data symbol
100 T - code/text symbol
101 U - undefined symbol
103 Uppercase indicates that the symbol is global; lowercase indicates that
104 it is local.
106 =item C<--type=bsd>
108 =item C<-B>
110 The same as C<--t>.
112 =item C<--type=long>
114 =item C<-L>
116 Append a long type (e.g. "global_const_init_data" versus "R") to the
117 symbol name.
119 =item C<--help>
121 Show the help.
123 =item C<--version>
125 Show the version number.
127 =back
129 All the options can be shortened to their unique prefixes, and one
130 leading dash ("-") can be used instead of two ("--").
132 =cut
134 use strict;
135 use warnings;
136 use Getopt::Long;
137 use File::Basename;
139 use vars qw($VERSION);
141 require 5.005;
143 $VERSION = sprintf "%d.%d", q$Revision$ =~ /(\d+)/g; # jhi@iki.fi;
145 my $ME = basename($0);
146 my $RCS_DATE = q$Date$;
148 my $nm_cmd = 'nm';
149 my $nm_opt = '';
150 my $nm_try = qx(nm -V 2>&1);
151 my $nm_gnu;
152 my $nm_ro; # can tell apart read-only (const) data sections
154 my (
155 $Code, $Data, $Init, $Uninit, $Const, $Mutable,
156 $Global, $Local, $Undef, $Def, $File, $ObjectName,
157 $Type, $BSD, $Long, $Help, $Version
160 sub show_version {
161 print "$ME: $VERSION ( $RCS_DATE)\n";
164 sub show_help {
165 print <<__EOF__;
166 $ME: Usage: $ME [options] [ foo.o ... | bar.a | other_library_format ]
167 Portable frontend for nm(1); by default lists all the code and data symbols
168 in the object or archive files. The options can be used to limit the symbols:
169 --code|-c code/text symbols (Tt)
170 --data|-d data symbols (Dd, Bb)
171 --init|-i initialised data symbols (Dd)
172 --uninit|-u uninitialised data symbols (Bb)
173 --local|-l local symbols (tdbruf)
174 --global|-g global symbols (TDBRUF)
175 --const|-C const (read-only) data symbols (Rr) [1]
176 --undef|-U undefined symbols (Uu)
177 --def|-D defined symbols (not Uu)
178 --file|-f file(name) symbols (Ff)
179 If more than one of all the above options are given, they are ANDed.
180 They can also be negated with a "no", for example --noconst.
181 [1] Not all platforms support this, a warning will be given if not.
182 You can try GNU nm if you want this feature.
183 --objectname|-o prepend the object name before the symbol name
184 --t append the short BSD-style type (in parentheses above)
185 --type=bsd|-B same as --t
186 --type=long|-L append a long type (e.g. "global_const_init_data" versus "R")
187 --help|-h show this help
188 --version|-v show version
189 All the options can be shortened to their unique prefixes,
190 and one leading dash ("-") can be used instead of two ("--").
191 __EOF__
194 if ( $^O eq 'solaris' && $nm_try =~ /Solaris/ ) {
195 $nm_opt = '-p';
197 elsif ( $^O eq 'hpux' && $nm_try =~ /linker command|HP-UX/ ) {
198 $nm_opt = '-p';
200 elsif ( $^O eq 'aix' && $nm_try =~ /illegal option/ ) {
201 $nm_opt = '-B';
203 elsif ( $^O eq 'irix' && $nm_try =~ /C Development Set/ ) {
204 $nm_opt = '-B';
205 $nm_ro = 1;
207 elsif ( $^O eq 'dec_osf' && $nm_try =~ /Alpha/ ) { # aka Tru64 aka DEC OSF/1
208 $nm_opt = '-B';
209 $nm_ro = 1;
211 elsif ( $^O eq 'darwin' && $nm_try =~ /invalid argument/ ) {
212 $nm_opt = '';
214 elsif ( $nm_try =~ /GNU nm/ ) {
215 $nm_opt = '';
216 $nm_gnu = 1;
217 $nm_ro = 1;
219 else {
221 # Hope for BSD-style nm output.
224 Getopt::Long::Configure("bundling");
226 unless (
227 GetOptions(
228 'code|c!' => \$Code,
229 'data|d!' => \$Data,
230 'init|i!' => \$Init,
231 'uninit|u!' => \$Uninit,
232 'const|C!' => \$Const,
233 'global|g!' => \$Global,
234 'local|l!' => \$Local,
235 'undef|U!' => \$Undef,
236 'def|D!' => \$Def,
237 'file|f!' => \$File,
238 'objectname|o' => \$ObjectName,
239 't' => \$Type,
240 'bsd|B' => \$BSD,
241 'long|L' => \$Long,
242 'type:s' => \$Type,
243 'help|h' => \$Help,
244 'version|v' => \$Version,
248 show_help();
249 exit(1);
252 if ( $Const && !$nm_ro ) {
253 warn "$ME: the native nm cannot tell apart const data sections\n";
256 if ($Version) {
257 show_version();
258 exit(0);
261 if ($Help) {
262 show_help();
263 exit(0);
266 unless (@ARGV) {
267 show_help();
268 exit(1);
271 sub warn_if_both {
272 my ( $a, $b, $sa, $sb ) = @_;
273 if ( defined $a && defined $b && $a == $b ) {
274 warn "$ME: both --$sa and --$sb used\n";
278 warn_if_both( $Code, $Data, 'code', 'data' );
279 warn_if_both( $Global, $Local, 'global', 'local' );
280 warn_if_both( $Init, $Uninit, 'init', 'uninit' );
281 warn_if_both( $Def, $Undef, 'def', 'undef' );
283 $Undef ||= !$Def if defined $Def && !defined $Undef;
285 my %Type;
286 @Type{qw(bsd long)} = ();
287 $Type = 'bsd'
288 if $BSD
289 || ( defined $Type && $Type eq '1' ); # So they used --t.
290 $Type = 'long' if $Long;
291 die "$ME: --type=$Type unknown\n"
292 if defined $Type && $Type ne '' && !exists $Type{$Type};
294 my $TypeLong = defined $Type && $Type eq 'long';
296 for my $f (@ARGV) {
297 unless ( -f $f ) {
298 warn "$ME: No such file: $f\n";
299 next;
301 if ( open( my $NM, '<', "$nm_cmd $nm_opt $f |" ) ) {
302 my $o = '?';
303 $o = $f if $f =~ /\.o$/;
304 my $file;
305 while (<$NM>) {
306 chomp;
307 if ( m/^(.+\.o):$/ || m/\[(.+\.o)\]:$/ || m/\((.+\.o)\):$/ ) {
308 $o = $1;
310 elsif (/ ([A-Za-z]) \.?(\w+)$/) {
312 # Especially text symbols are sometimes prefixed by a ".".
313 my ( $type, $name ) = ( $1, $2 );
315 # The following are assumed to work Everywhere.
316 my $absolute = ( $type =~ /^[Aa]$/ ) ? 1 : 0;
317 my $uninit = ( $type =~ /^[BbCc]$/ ) ? 1 : 0;
318 my $init = ( $type =~ /^[DdGg]$/ ) ? 1 : 0;
319 my $file = ( $type =~ /^[Ff]$/ ) ? 1 : 0;
320 my $small = ( $type =~ /^[Gg]$/ ) ? 1 : 0;
321 my $code = ( $type =~ /^[Tt]$/ ) ? 1 : 0;
322 my $undef = ( $type =~ /^[Uu]$/ ) ? 1 : 0;
323 my $zeroed = 0;
324 my $const = 0;
325 my $local = $type eq lc $type ? 1 : 0;
326 my $other = 0;
328 if ( ( $^O eq 'irix' || $^O eq 'dec_osf' )
329 && $type =~ /^[BbSs]$/ )
331 if ( $type =~ /^[Ss]$/ ) {
332 $small = 1;
333 $uninit = 1;
335 $zeroed = 1;
337 if ( $^O eq 'irix' && $type =~ /^[Rr]$/ ) {
338 $const = 1;
339 $init = 1;
341 if ( $^O eq 'dec_osf' ) {
342 if ( $type eq 'E' ) {
343 $small = 1;
345 elsif ( $type =~ /^[RrQq]$/ ) {
346 $const = 1;
347 $init = 1;
350 if ( $^O eq 'darwin' ) {
351 $other = 1;
353 if ($nm_gnu) {
354 if ( $type =~ /^[Rr]$/ ) {
355 $const = 1;
356 $init = 1;
358 elsif ( $type =~ /^[Ss]$/ ) {
359 $small = 1;
360 $uninit = 1;
363 if ( $type =~ /^[ABCDFGQRSTU]$/i ) {
364 unless ( $undef || $code || $other || $absolute ) {
365 if ( $init && $uninit ) {
366 warn "$.:$_: both init and uninit?\n";
368 elsif ( !$init && !$uninit ) {
369 warn "$.:$_: neither init and uninit?\n";
373 my $data = ( $uninit || $init ) && !$code;
374 my $global = !$local;
375 my $show = 1;
377 sub want_show {
378 my ( $show, $Got, $got ) = @_;
379 if ( defined $Got ) {
380 if ( $Got == $got ) {
381 $$show++;
383 else {
384 $$show = 0;
388 want_show( \$show, $Code, $code ) if $show;
389 want_show( \$show, $Data, $data ) if $show;
390 want_show( \$show, $Init, $init ) if $show;
391 want_show( \$show, $Uninit, $uninit ) if $show;
392 want_show( \$show, $Const, $const ) if $show;
393 want_show( \$show, $Global, $global ) if $show;
394 want_show( \$show, $Local, $local ) if $show;
395 want_show( \$show, $Undef, $undef ) if $show;
396 want_show( \$show, $File, $file ) if $show;
398 if ($show) {
399 $show = $ObjectName ? "$o\t$name" : $name;
400 if ( defined $Type ) {
401 $show .= "\t";
402 my $symbol;
403 if ($code) {
404 $symbol = $TypeLong ? "code" : "T";
406 elsif ($data) {
407 if ($const) {
408 $symbol = $TypeLong ? "const_init" : "R";
410 elsif ($init) {
411 $symbol = $TypeLong ? "init" : "D";
413 elsif ($uninit) {
414 $symbol = $TypeLong ? "uninit" : "B";
416 else {
417 $symbol = $TypeLong ? "unknown" : "D?";
419 $symbol .= "_data" if $TypeLong;
421 elsif ($undef) {
422 $symbol = $TypeLong ? "undef" : "U";
424 else {
425 $symbol = $TypeLong ? "unknown" : "?";
427 if ($TypeLong) {
428 $show .= $global ? "global_$symbol" : "local_$symbol";
430 else {
431 $show .= $global ? $symbol : lc $symbol;
434 print $show, "\n";
438 close($NM);
440 else {
441 warn "$ME: '$nm_cmd $nm_opt $f' failed: $!\n";
445 exit(0);
447 =head1 HISTORY
449 Author: Jarkko Hietaniemi.
451 =cut
453 # Local Variables:
454 # mode: cperl
455 # cperl-indent-level: 4
456 # fill-column: 100
457 # End:
458 # vim: expandtab shiftwidth=4: