From 1e046b9640947378fd1f314d0fede9632e5fd46a Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 19 Jan 2009 15:19:40 -0800 Subject: [PATCH] Add support for dynamic library symbols to ofp-parse-leaks. In adding support for the leak checker to NOX, it became clear that we needed to support fetching symbols for dynamically loaded libraries, because most of NOX is in fact in such libraries. This adds that support. --- utilities/ofp-parse-leaks.in | 104 ++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/utilities/ofp-parse-leaks.in b/utilities/ofp-parse-leaks.in index c632a59c..059c8509 100755 --- a/utilities/ofp-parse-leaks.in +++ b/utilities/ofp-parse-leaks.in @@ -29,9 +29,14 @@ if (!@ARGV) { $binary = $ARGV[0]; } +our ($objdump) = search_path("objdump"); +print "objdump not found; dynamic library symbols will not be translated\n" + if !defined($objdump); + our %blocks; +our @segments; while () { - my $ptr = "(0x[0-9a-fA-F]+|\\(nil\\))"; + my $ptr = "((?:0x)?[0-9a-fA-F]+|\\(nil\\))"; my $callers = ":((?: $ptr)+)"; if (/^malloc\((\d+)\) -> $ptr$callers$/) { allocated($., $2, $1, $3); @@ -43,6 +48,8 @@ while () { allocated($., $3, $2, $callers); } elsif (/^free\($ptr\)$callers$/) { freed($., $1, $2); + } elsif (/^segment: $ptr-$ptr $ptr [-r][-w][-x][sp] (.*)/) { + add_segment(hex($1), hex($2), hex($3), $4); } else { print "stdin:$.: syntax error\n"; } @@ -143,10 +150,13 @@ sub lookup_pc { my ($pc) = hex($s_pc); my ($output) = "$s_pc: "; if (!exists($cache{$pc})) { - open(A2L, "$a2l -fe $binary $s_pc|"); + open(A2L, "$a2l -fe $binary --demangle $s_pc|"); chomp(my $function = ); chomp(my $line = ); close(A2L); + if ($function eq '??') { + ($function, $line) = lookup_pc_by_segment($pc); + } $line =~ s/^(\.\.\/)*//; $line = "..." . substr($line, -25) if length($line) > 28; $cache{$pc} = "$s_pc: $function ($line)"; @@ -180,6 +190,96 @@ sub search_path { return undef; } +sub add_segment { + my ($vm_start, $vm_end, $vm_pgoff, $file) = @_; + for (my $i = 0; $i <= $#segments; $i++) { + my ($s) = $segments[$i]; + next if $vm_end <= $s->{START} || $vm_start >= $s->{END}; + if ($vm_start <= $s->{START} && $vm_end >= $s->{END}) { + splice(@segments, $i, 1); + --$i; + } else { + $s->{START} = $vm_end if $vm_end > $s->{START}; + $s->{END} = $vm_start if $vm_start <= $s->{END}; + } + } + push(@segments, {START => $vm_start, + END => $vm_end, + PGOFF => $vm_pgoff, + FILE => $file}); + @segments = sort { $a->{START} <=> $b->{START} } @segments; +} + +sub binary_search { + my ($array, $value) = @_; + my $l = 0; + my $r = $#{$array}; + while ($l <= $r) { + my $m = int(($l + $r) / 2); + my $e = $array->[$m]; + if ($value < $e->{START}) { + $r = $m - 1; + } elsif ($value >= $e->{END}) { + $l = $m + 1; + } else { + return $e; + } + } + return undef; +} + +sub read_sections { + my ($file) = @_; + my (@sections); + open(OBJDUMP, "$objdump -h $file|"); + while () { + my $ptr = "([0-9a-fA-F]+)"; + my ($name, $size, $vma, $lma, $file_off) + = /^\s*\d+\s+(\S+)\s+$ptr\s+$ptr\s+$ptr\s+$ptr/ + or next; + push(@sections, {START => hex($file_off), + END => hex($file_off) + hex($size), + NAME => $name}); + } + close(OBJDUMP); + return [sort { $a->{START} <=> $b->{START} } @sections ]; +} + +our %file_to_sections; +sub segment_to_section { + my ($file, $file_offset) = @_; + if (!defined($file_to_sections{$file})) { + $file_to_sections{$file} = read_sections($file); + } + return binary_search($file_to_sections{$file}, $file_offset); +} + +sub address_to_segment { + my ($pc) = @_; + return binary_search(\@segments, $pc); +} + +sub lookup_pc_by_segment { + return ('??', 0) if !defined($objdump); + + my ($pc) = @_; + my ($segment) = address_to_segment($pc); + return ('??', 0) if !defined($segment) || $segment->{FILE} eq ''; + + my ($file_offset) = $pc - $segment->{START} + $segment->{PGOFF}; + my ($section) = segment_to_section($segment->{FILE}, $file_offset); + return ('??', 0) if !defined($section); + + my ($section_offset) = $file_offset - $section->{START}; + open(A2L, sprintf("%s -fe %s --demangle --section=$section->{NAME} 0x%x|", + $a2l, $segment->{FILE}, $section_offset)); + chomp(my $function = ); + chomp(my $line = ); + close(A2L); + + return ($function, $line); +} + # Local Variables: # mode: perl # End: -- 2.30.2