diff --git a/scripts/Modules/Util.pm b/scripts/Modules/Util.pm index a109a45..712bf1a 100644 --- a/scripts/Modules/Util.pm +++ b/scripts/Modules/Util.pm @@ -181,19 +181,49 @@ sub format_number_sep { return $number; } +# Run nm once and cache the result instead of running 20x per query +my %nm_cache; + +sub nm_lines { + my ( $elffile, @nm_args ) = @_; + + my $command = join ' ', 'nm', @nm_args, shell_quote($elffile); + return @{ $nm_cache{$command} } if exists $nm_cache{$command}; + + die "ELF file does not exist: $elffile\n" unless -f $elffile; + + my @lines = qx{$command 2>&1}; + my $status = $?; + + die "nm not found in PATH\n" + if $status == -1 || ( $status >> 8 ) == 127; + die "nm failed on $elffile (exit @{[ $status >> 8 ]}): @lines" + if $status != 0; + die "nm found no symbols in $elffile\n" unless @lines; + + $nm_cache{$command} = \@lines; + return @lines; +} + sub elf_sym_addr { my ( $elffile, $sym ) = @_; - my $line = qx{nm "$elffile" 2>/dev/null | grep " $sym\$"}; - return undef unless $line =~ /^([0-9a-f]+)/i; - return hex($1); + + for my $line ( nm_lines($elffile) ) { + + # "0010eefe T aot_invoke_native" + # This is case-sensitive! + next unless $line =~ /^([0-9a-fA-F]+)\s+\S\s+\Q$sym\E$/; + return hex($1); + } + + return undef; } # Determine the address range of a function symbol sub elf_sym_range { my ( $elffile, $sym ) = @_; - my @lines = qx{nm -nS "$elffile" 2>/dev/null}; - return () unless @lines; + my @lines = nm_lines( $elffile, '-nS' ); for my $i ( 0 .. $#lines ) { my $line = $lines[$i];