| Index: third_party/tcmalloc/chromium/src/pprof
|
| ===================================================================
|
| --- third_party/tcmalloc/chromium/src/pprof (revision 41940)
|
| +++ third_party/tcmalloc/chromium/src/pprof (working copy)
|
| @@ -72,7 +72,7 @@
|
| use warnings;
|
| use Getopt::Long;
|
|
|
| -my $PPROF_VERSION = "1.5";
|
| +my $PPROF_VERSION = "1.4";
|
|
|
| # These are the object tools we use which can come from a
|
| # user-specified location using --tools, from the PPROF_TOOLS
|
| @@ -92,7 +92,6 @@
|
| my $PS2PDF = "ps2pdf";
|
| # These are used for dynamic profiles
|
| my $WGET = "wget";
|
| -my $WGET_FLAGS = "--no-http-keep-alive"; # only supported by some wgets
|
| my $CURL = "curl";
|
|
|
| # These are the web pages that servers need to support for dynamic profiles
|
| @@ -118,11 +117,6 @@
|
| # A list of paths to search for shared object files
|
| my @prefix_list = ();
|
|
|
| -# Special routine name that should not have any symbols.
|
| -# Used as separator to parse "addr2line -i" output.
|
| -my $sep_symbol = '_fini';
|
| -my $sep_address = undef;
|
| -
|
| ##### Argument parsing #####
|
|
|
| sub usage_string {
|
| @@ -510,20 +504,6 @@
|
| ConfigureObjTools($main::prog)
|
| }
|
|
|
| - # Check what flags our commandline utilities support
|
| - if (open(TFILE, "$WGET $WGET_FLAGS -V 2>&1 |")) {
|
| - my @lines = <TFILE>;
|
| - if (grep(/unrecognized/, @lines) > 0) {
|
| - # grep found 'unrecognized' token from WGET, clear WGET flags
|
| - $WGET_FLAGS = "";
|
| - }
|
| - close(TFILE);
|
| - }
|
| - # TODO(csilvers): check all the other binaries and objtools to see
|
| - # if they are installed and what flags they support, and store that
|
| - # in a data structure here, rather than scattering these tests about.
|
| - # Then, ideally, rewrite code to use wget OR curl OR GET or ...
|
| -
|
| # Break the opt_list_prefix into the prefix_list array
|
| @prefix_list = split (',', $main::opt_lib_prefix);
|
|
|
| @@ -972,31 +952,22 @@
|
| print 'binary=', $prog, "\n";
|
| }
|
| while (my ($pc, $name) = each(%{$symbols})) {
|
| - my $sep = ' ';
|
| - print '0x', $pc;
|
| - # We have a list of function names, which include the inlined
|
| - # calls. They are separated (and terminated) by --, which is
|
| - # illegal in function names.
|
| - for (my $j = 2; $j <= $#{$name}; $j += 3) {
|
| - print $sep, $name->[$j];
|
| - $sep = '--';
|
| - }
|
| - print "\n";
|
| + my $fullname = $name->[2];
|
| + print '0x', $pc, ' ', $fullname, "\n";
|
| }
|
| print '---', "\n";
|
|
|
| - $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
|
| - my $profile_marker = $&;
|
| - print '--- ', $profile_marker, "\n";
|
| if (defined($main::collected_profile)) {
|
| # if used with remote fetch, simply dump the collected profile to output.
|
| open(SRC, "<$main::collected_profile");
|
| while (<SRC>) {
|
| print $_;
|
| }
|
| - close(SRC);
|
| } else {
|
| # dump a cpu-format profile to standard out
|
| + $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
|
| + my $profile_marker = $&;
|
| + print '--- ', $profile_marker, "\n";
|
| PrintProfileData($profile);
|
| }
|
| }
|
| @@ -1098,9 +1069,9 @@
|
| }
|
|
|
| # Return reference to array of tuples of the form:
|
| -# [start_address, filename, linenumber, instruction, limit_address]
|
| +# [address, filename, linenumber, instruction]
|
| # E.g.,
|
| -# ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"]
|
| +# ["0x806c43d", "/foo/bar.cc", 131, "ret"]
|
| sub Disassemble {
|
| my $prog = shift;
|
| my $offset = shift;
|
| @@ -1115,7 +1086,6 @@
|
| my @result = ();
|
| my $filename = "";
|
| my $linenumber = -1;
|
| - my $last = ["", "", "", ""];
|
| while (<OBJDUMP>) {
|
| s/\r//g; # turn windows-looking lines into unix-looking lines
|
| chop;
|
| @@ -1128,9 +1098,7 @@
|
| # Disassembly line -- zero-extend address to full length
|
| my $addr = HexExtend($1);
|
| my $k = AddressAdd($addr, $offset);
|
| - $last->[4] = $k; # Store ending address for previous instruction
|
| - $last = [$k, $filename, $linenumber, $2, $end_addr];
|
| - push(@result, $last);
|
| + push(@result, [$k, $filename, $linenumber, $2]);
|
| }
|
| }
|
| close(OBJDUMP);
|
| @@ -1306,13 +1274,8 @@
|
| my $total1 = 0; # Total flat counts
|
| my $total2 = 0; # Total cumulative counts
|
| foreach my $e (@instructions) {
|
| - # Add up counts for all address that fall inside this instruction
|
| - my $c1 = 0;
|
| - my $c2 = 0;
|
| - for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
|
| - $c1 += GetEntry($flat, $a);
|
| - $c2 += GetEntry($cumulative, $a);
|
| - }
|
| + my $c1 = GetEntry($flat, $e->[0]);
|
| + my $c2 = GetEntry($cumulative, $e->[0]);
|
| $running1 += $c1;
|
| $running2 += $c2;
|
| $total1 += $c1;
|
| @@ -1423,13 +1386,8 @@
|
| my $flat_total = 0;
|
| my $cum_total = 0;
|
| foreach my $e (@instructions) {
|
| - # Add up counts for all address that fall inside this instruction
|
| - my $c1 = 0;
|
| - my $c2 = 0;
|
| - for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
|
| - $c1 += GetEntry($flat, $a);
|
| - $c2 += GetEntry($cumulative, $a);
|
| - }
|
| + my $c1 = GetEntry($flat, $e->[0]);
|
| + my $c2 = GetEntry($cumulative, $e->[0]);
|
| push(@flat_count, $c1);
|
| push(@cum_count, $c2);
|
| $flat_total += $c1;
|
| @@ -1657,10 +1615,10 @@
|
| foreach my $k (keys(%{$raw})) {
|
| # TODO: omit low %age edges
|
| $n = $raw->{$k};
|
| - my @translated = TranslateStack($symbols, $k);
|
| - for (my $i = 1; $i <= $#translated; $i++) {
|
| - my $src = $translated[$i];
|
| - my $dst = $translated[$i-1];
|
| + my @addrs = split(/\n/, $k);
|
| + for (my $i = 1; $i <= $#addrs; $i++) {
|
| + my $src = OutputKey($symbols, $addrs[$i]);
|
| + my $dst = OutputKey($symbols, $addrs[$i-1]);
|
| #next if ($src eq $dst); # Avoid self-edges?
|
| if (exists($node{$src}) && exists($node{$dst})) {
|
| my $edge_label = "$src\001$dst";
|
| @@ -1690,18 +1648,14 @@
|
| if ($edgeweight > 100000) { $edgeweight = 100000; }
|
| $edgeweight = int($edgeweight);
|
|
|
| - my $style = sprintf("setlinewidth(%f)", $w);
|
| - if ($x[1] =~ m/\(inline\)/) {
|
| - $style .= ",dashed";
|
| - }
|
| -
|
| # Use a slightly squashed function of the edge count as the weight
|
| - printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n",
|
| + printf DOT ("N%s -> N%s [label=%s, weight=%d, " .
|
| + "style=\"setlinewidth(%f)\"];\n",
|
| $node{$x[0]},
|
| $node{$x[1]},
|
| Unparse($n),
|
| $edgeweight,
|
| - $style);
|
| + $w);
|
| }
|
| }
|
|
|
| @@ -1711,74 +1665,42 @@
|
| return 1;
|
| }
|
|
|
| -# Translate a stack of addresses into a stack of symbols
|
| -sub TranslateStack {
|
| +# Generate the key under which a given address should be counted
|
| +# based on the user-specified output granularity.
|
| +sub OutputKey {
|
| my $symbols = shift;
|
| - my $k = shift;
|
| + my $a = shift;
|
|
|
| - my @addrs = split(/\n/, $k);
|
| - my @result = ();
|
| - for (my $i = 0; $i <= $#addrs; $i++) {
|
| - my $a = $addrs[$i];
|
| + # Skip large addresses since they sometimes show up as fake entries on RH9
|
| + if (length($a) > 8) {
|
| + if ($a gt "7fffffffffffffff") { return ''; }
|
| + }
|
|
|
| - # Skip large addresses since they sometimes show up as fake entries on RH9
|
| - if (length($a) > 8 && $a gt "7fffffffffffffff") {
|
| - next;
|
| - }
|
| -
|
| - if ($main::opt_disasm || $main::opt_list) {
|
| - # We want just the address for the key
|
| - push(@result, $a);
|
| - next;
|
| - }
|
| -
|
| - my $symlist = $symbols->{$a};
|
| - if (!defined($symlist)) {
|
| - $symlist = [$a, "", $a];
|
| - }
|
| -
|
| - # We can have a sequence of symbols for a particular entry
|
| - # (more than one symbol in the case of inlining). Callers
|
| - # come before callees in symlist, so walk backwards since
|
| - # the translated stack should contain callees before callers.
|
| - for (my $j = $#{$symlist}; $j >= 2; $j -= 3) {
|
| - my $func = $symlist->[$j-2];
|
| - my $fileline = $symlist->[$j-1];
|
| - my $fullfunc = $symlist->[$j];
|
| - if ($j > 2) {
|
| - $func = "$func (inline)";
|
| - }
|
| - if ($main::opt_addresses) {
|
| - push(@result, "$a $func $fileline");
|
| - } elsif ($main::opt_lines) {
|
| - if ($func eq '??' && $fileline eq '??:0') {
|
| - push(@result, "$a");
|
| - } else {
|
| - push(@result, "$func $fileline");
|
| - }
|
| - } elsif ($main::opt_functions) {
|
| - if ($func eq '??') {
|
| - push(@result, "$a");
|
| - } else {
|
| - push(@result, $func);
|
| - }
|
| - } elsif ($main::opt_files) {
|
| - if ($fileline eq '??:0' || $fileline eq '') {
|
| - push(@result, "$a");
|
| - } else {
|
| - my $f = $fileline;
|
| - $f =~ s/:\d+$//;
|
| - push(@result, $f);
|
| - }
|
| - } else {
|
| - push(@result, $a);
|
| - last; # Do not print inlined info
|
| - }
|
| - }
|
| + # Extract symbolic info for address
|
| + my $func = $a;
|
| + my $fullfunc = $a;
|
| + my $fileline = "";
|
| + if (exists($symbols->{$a})) {
|
| + $func = $symbols->{$a}->[0];
|
| + $fullfunc = $symbols->{$a}->[2];
|
| + $fileline = $symbols->{$a}->[1];
|
| }
|
|
|
| - # print join(",", @addrs), " => ", join(",", @result), "\n";
|
| - return @result;
|
| + if ($main::opt_disasm || $main::opt_list) {
|
| + return $a; # We want just the address for the key
|
| + } elsif ($main::opt_addresses) {
|
| + return "$a $func $fileline";
|
| + } elsif ($main::opt_lines) {
|
| + return "$func $fileline";
|
| + } elsif ($main::opt_functions) {
|
| + return $func;
|
| + } elsif ($main::opt_files) {
|
| + my $f = ($fileline eq '') ? $a : $fileline;
|
| + $f =~ s/:\d+$//;
|
| + return $f;
|
| + } else {
|
| + return $a;
|
| + }
|
| }
|
|
|
| # Generate percent string for a number and a total
|
| @@ -1968,7 +1890,6 @@
|
| 'tc_newarray_nothrow',
|
| 'do_malloc',
|
| '::do_malloc', # new name -- got moved to an unnamed ns
|
| - '::do_malloc_or_cpp_alloc',
|
| 'DoSampledAllocation',
|
| 'simple_alloc::allocate',
|
| '__malloc_alloc_template::allocate',
|
| @@ -1977,12 +1898,7 @@
|
| '__builtin_vec_delete',
|
| '__builtin_vec_new',
|
| 'operator new',
|
| - 'operator new[]',
|
| - # These mark the beginning/end of our custom sections
|
| - '__start_google_malloc',
|
| - '__stop_google_malloc',
|
| - '__start_malloc_hook',
|
| - '__stop_malloc_hook') {
|
| + 'operator new[]') {
|
| $skip{$name} = 1;
|
| $skip{"_" . $name} = 1; # Mach (OS X) adds a _ prefix to everything
|
| }
|
| @@ -2062,16 +1978,17 @@
|
| my $result = {};
|
| foreach my $k (keys(%{$profile})) {
|
| my $count = $profile->{$k};
|
| - my @translated = TranslateStack($symbols, $k);
|
| + my @addrs = split(/\n/, $k);
|
| my @path = ();
|
| my %seen = ();
|
| $seen{''} = 1; # So that empty keys are skipped
|
| - foreach my $e (@translated) {
|
| + foreach my $a (@addrs) {
|
| # To avoid double-counting due to recursion, skip a stack-trace
|
| # entry if it has already been seen
|
| - if (!$seen{$e}) {
|
| - $seen{$e} = 1;
|
| - push(@path, $e);
|
| + my $key = OutputKey($symbols, $a);
|
| + if (!$seen{$key}) {
|
| + $seen{$key} = 1;
|
| + push(@path, $key);
|
| }
|
| }
|
| my $reduced_path = join("\n", @path);
|
| @@ -2080,20 +1997,6 @@
|
| return $result;
|
| }
|
|
|
| -# Does the specified symbol array match the regexp?
|
| -sub SymbolMatches {
|
| - my $sym = shift;
|
| - my $re = shift;
|
| - if (defined($sym)) {
|
| - for (my $i = 0; $i < $#{$sym}; $i += 3) {
|
| - if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) {
|
| - return 1;
|
| - }
|
| - }
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| # Focus only on paths involving specified regexps
|
| sub FocusProfile {
|
| my $symbols = shift;
|
| @@ -2105,7 +2008,10 @@
|
| my @addrs = split(/\n/, $k);
|
| foreach my $a (@addrs) {
|
| # Reply if it matches either the address/shortname/fileline
|
| - if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) {
|
| + if (($a =~ m/$focus/) ||
|
| + (exists($symbols->{$a}) &&
|
| + (($symbols->{$a}->[0] =~ m/$focus/) ||
|
| + ($symbols->{$a}->[1] =~ m/$focus/)))) {
|
| AddEntry($result, $k, $count);
|
| last;
|
| }
|
| @@ -2126,7 +2032,10 @@
|
| my $matched = 0;
|
| foreach my $a (@addrs) {
|
| # Reply if it matches either the address/shortname/fileline
|
| - if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) {
|
| + if (($a =~ m/$ignore/) ||
|
| + (exists($symbols->{$a}) &&
|
| + (($symbols->{$a}->[0] =~ m/$ignore/) ||
|
| + ($symbols->{$a}->[1] =~ m/$ignore/)))) {
|
| $matched = 1;
|
| last;
|
| }
|
| @@ -2286,7 +2195,7 @@
|
|
|
| sub CheckSymbolPage {
|
| my $url = SymbolPageURL();
|
| - open(SYMBOL, "$WGET $WGET_FLAGS -qO- '$url' |");
|
| + open(SYMBOL, "$WGET -qO- '$url' |");
|
| my $line = <SYMBOL>;
|
| $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
|
| close(SYMBOL);
|
| @@ -2331,7 +2240,7 @@
|
| sub FetchProgramName() {
|
| my ($host, $port, $path) = ParseProfileURL($main::pfile_args[0]);
|
| my $url = "http://$host:$port$PROGRAM_NAME_PAGE";
|
| - my $command_line = "$WGET $WGET_FLAGS -qO- '$url'";
|
| + my $command_line = "$WGET -qO- '$url'";
|
| open(CMDLINE, "$command_line |") or error($command_line);
|
| my $cmdline = <CMDLINE>;
|
| $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines
|
| @@ -2437,21 +2346,13 @@
|
| # /symbol, the symbols match and are retrievable from the map.
|
| my $shortpc = $pc;
|
| $shortpc =~ s/^0*//;
|
| - # Each line may have a list of names, which includes the function
|
| - # and also other functions it has inlined. They are separated
|
| - # (in PrintSymbolizedFile), by --, which is illegal in function names.
|
| - my $fullnames;
|
| if (defined($symbol_map->{$shortpc})) {
|
| - $fullnames = $symbol_map->{$shortpc};
|
| + $fullname = $symbol_map->{$shortpc};
|
| } else {
|
| - $fullnames = "0x" . $pc; # Just use addresses
|
| + $fullname = "0x" . $pc; # Just use addresses
|
| }
|
| - my $sym = [];
|
| - $symbols->{$pc} = $sym;
|
| - foreach my $fullname (split("--", $fullnames)) {
|
| - my $name = ShortFunctionName($fullname);
|
| - push(@{$sym}, $name, "?", $fullname);
|
| - }
|
| + my $name = ShortFunctionName($fullname);
|
| + $symbols->{$pc} = [$name, "?", $fullname];
|
| }
|
| return $symbols;
|
| }
|
| @@ -2491,7 +2392,7 @@
|
| my $wget_timeout;
|
| if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)) {
|
| if ($path =~ m/$PROFILE_PAGE/) {
|
| - $url = sprintf("http://$host:$port$path?seconds=%d",
|
| + $url = sprintf("http://$host:$port$PROFILE_PAGE?seconds=%d",
|
| $main::opt_seconds);
|
| } else {
|
| if ($profile_name =~ m/[?]/) {
|
| @@ -2526,7 +2427,7 @@
|
| return $real_profile;
|
| }
|
|
|
| - my $cmd = "$WGET $WGET_FLAGS $wget_timeout -q -O $tmp_profile '$url'";
|
| + my $cmd = "$WGET $wget_timeout -q -O $tmp_profile '$url'";
|
| if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)){
|
| print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n ${real_profile}\n";
|
| if ($encourage_patience) {
|
| @@ -2851,26 +2752,12 @@
|
|
|
| # Make key out of the stack entries
|
| my @k = ();
|
| - for (my $j = 0; $j < $d; $j++) {
|
| + for (my $j = $d; $j--; ) {
|
| my $pclo = $slots->get($i++);
|
| my $pchi = $slots->get($i++);
|
| if ($pclo == -1 || $pchi == -1) {
|
| error("$fname: Unexpected EOF when reading stack of depth $d\n");
|
| }
|
| -
|
| - # Subtract one from caller pc so we map back to call instr.
|
| - # However, don't do this if we're reading a symbolized profile
|
| - # file, in which case the subtract-one was done when the file
|
| - # was written.
|
| - if ($j > 0 && !$main::use_symbolized_profile) {
|
| - if ($pclo == 0) {
|
| - $pchi--;
|
| - $pclo = 0xffffffff;
|
| - } else {
|
| - $pclo--;
|
| - }
|
| - }
|
| -
|
| my $pc = sprintf("%08x%08x", $pchi, $pclo);
|
| $pcs->{$pc} = 1;
|
| push @k, $pc;
|
| @@ -3369,7 +3256,7 @@
|
| my $finish;
|
| my $offset;
|
| my $lib;
|
| - if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib|bundle)((\.\d+)+\w*)?)$/i) {
|
| + if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib)((\.\d+)+\w*)?)$/i) {
|
| # Full line from /proc/self/maps. Example:
|
| # 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so
|
| $start = HexExtend($1);
|
| @@ -3629,111 +3516,87 @@
|
| my $pclist = shift;
|
| my $symbols = shift;
|
|
|
| - my $debug = 0;
|
| -
|
| # Ignore empty binaries
|
| if ($#{$pclist} < 0) { return; }
|
|
|
| - # Figure out the addr2line command to use
|
| - my $addr2line = $obj_tool_map{"addr2line"};
|
| - my $cmd = "$addr2line -f -C -e $image";
|
| - if (exists $obj_tool_map{"addr2line_pdb"}) {
|
| - $addr2line = $obj_tool_map{"addr2line_pdb"};
|
| - $cmd = "$addr2line --demangle -f -C -e $image";
|
| + my $got_symbols = MapSymbolsWithNM($image, $offset, $pclist, $symbols);
|
| + if ($main::opt_interactive ||
|
| + $main::opt_addresses ||
|
| + $main::opt_lines ||
|
| + $main::opt_files ||
|
| + $main::opt_list ||
|
| + $main::opt_callgrind ||
|
| + !$got_symbols) {
|
| + GetLineNumbers($image, $offset, $pclist, $symbols);
|
| }
|
| +}
|
|
|
| - # If "addr2line" isn't installed on the system at all, just use
|
| - # nm to get what info we can (function names, but not line numbers).
|
| - if (system("$addr2line --help >/dev/null 2>&1") != 0) {
|
| - MapSymbolsWithNM($image, $offset, $pclist, $symbols);
|
| - return;
|
| - }
|
| +# The file $tmpfile_sym must already have been created before calling this.
|
| +sub GetLineNumbersViaAddr2Line {
|
| + my $addr2line_command = shift;
|
| + my $pclist = shift;
|
| + my $symbols = shift;
|
|
|
| - # "addr2line -i" can produce a variable number of lines per input
|
| - # address, with no separator that allows us to tell when data for
|
| - # the next address starts. So we find the address for a special
|
| - # symbol (_fini) and interleave this address between all real
|
| - # addresses passed to addr2line. The name of this special symbol
|
| - # can then be used as a separator.
|
| - $sep_address = undef; # May be filled in by MapSymbolsWithNM()
|
| - my $nm_symbols = {};
|
| - MapSymbolsWithNM($image, $offset, $pclist, $nm_symbols);
|
| - # TODO(csilvers): only add '-i' if addr2line supports it.
|
| - if (defined($sep_address)) {
|
| - # Only add " -i" to addr2line if the binary supports it.
|
| - # addr2line --help returns 0, but not if it sees an unknown flag first.
|
| - if (system("$cmd -i --help >/dev/null 2>&1") == 0) {
|
| - $cmd .= " -i";
|
| - } else {
|
| - $sep_address = undef; # no need for sep_address if we don't support -i
|
| - }
|
| - }
|
| -
|
| - # Make file with all PC values with intervening 'sep_address' so
|
| - # that we can reliably detect the end of inlined function list
|
| - open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n");
|
| - if ($debug) { print("---- $image ---\n"); }
|
| - for (my $i = 0; $i <= $#{$pclist}; $i++) {
|
| - # addr2line always reads hex addresses, and does not need '0x' prefix.
|
| - if ($debug) { printf("%s\n", $pclist->[$i]); }
|
| - printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset));
|
| - if (defined($sep_address)) {
|
| - printf ADDRESSES ("%s\n", $sep_address);
|
| - }
|
| - }
|
| - close(ADDRESSES);
|
| - if ($debug) {
|
| - print("----\n");
|
| - system("cat $main::tmpfile_sym");
|
| - print("----\n");
|
| - system("$cmd <$main::tmpfile_sym");
|
| - print("----\n");
|
| - }
|
| -
|
| - open(SYMBOLS, "$cmd <$main::tmpfile_sym |") || error("$cmd: $!\n");
|
| - my $count = 0; # Index in pclist
|
| + open(SYMBOLS, "$addr2line_command <$main::tmpfile_sym |")
|
| + || error("$addr2line_command: $!\n");
|
| + my $count = 0;
|
| while (<SYMBOLS>) {
|
| - # Read fullfunction and filelineinfo from next pair of lines
|
| s/\r?\n$//g;
|
| my $fullfunction = $_;
|
| +
|
| $_ = <SYMBOLS>;
|
| s/\r?\n$//g;
|
| my $filelinenum = $_;
|
| -
|
| - if (defined($sep_address) && $fullfunction eq $sep_symbol) {
|
| - # Terminating marker for data for this address
|
| - $count++;
|
| - next;
|
| + $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths
|
| + if (!$main::opt_list) {
|
| + $filelinenum =~ s|^.*/([^/]+:\d+)$|$1|; # Remove directory name
|
| }
|
|
|
| - $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths
|
| -
|
| my $pcstr = $pclist->[$count];
|
| - my $function = ShortFunctionName($fullfunction);
|
| - if ($fullfunction eq '??') {
|
| - # See if nm found a symbol
|
| - my $nms = $nm_symbols->{$pcstr};
|
| - if (defined($nms)) {
|
| - $function = $nms->[0];
|
| - $fullfunction = $nms->[2];
|
| + if (defined($symbols->{$pcstr})) {
|
| + # Override just the line-number portion. The function name portion
|
| + # is less buggy when computed using nm instead of addr2line. But
|
| + # don't override if addr2line is giving ??'s and nm didn't. (This
|
| + # may be seen mostly/entirely on cygwin's addr2line/nm.)
|
| + if (($filelinenum ne "??:0") || ($symbols->{$pcstr}->[1] eq "?")) {
|
| + $symbols->{$pcstr}->[1] = $filelinenum;
|
| }
|
| + } else {
|
| + my $function = ShortFunctionName($fullfunction);
|
| + $symbols->{$pcstr} = [$function, $filelinenum, $fullfunction];
|
| }
|
| + $count++;
|
| + }
|
| + close(SYMBOLS);
|
| + return $count;
|
| +}
|
|
|
| - # Prepend to accumulated symbols for pcstr
|
| - # (so that caller comes before callee)
|
| - my $sym = $symbols->{$pcstr};
|
| - if (!defined($sym)) {
|
| - $sym = [];
|
| - $symbols->{$pcstr} = $sym;
|
| +sub GetLineNumbers {
|
| + my $image = shift;
|
| + my $offset = shift;
|
| + my $pclist = shift;
|
| + my $symbols = shift;
|
| +
|
| + # Make file with all PC values
|
| + open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n");
|
| + for (my $i = 0; $i <= $#{$pclist}; $i++) {
|
| + # addr2line always reads hex addresses, and does not need '0x' prefix.
|
| + printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset));
|
| + }
|
| + close(ADDRESSES);
|
| +
|
| + # Pass to addr2line
|
| + my $addr2line = $obj_tool_map{"addr2line"};
|
| + my @addr2line_commands = ("$addr2line -f -C -e $image");
|
| + if (exists $obj_tool_map{"addr2line_pdb"}) {
|
| + my $addr2line_pdb = $obj_tool_map{"addr2line_pdb"};
|
| + push(@addr2line_commands, "$addr2line_pdb --demangle -f -C -e $image");
|
| + }
|
| + foreach my $addr2line_command (@addr2line_commands) {
|
| + if (GetLineNumbersViaAddr2Line("$addr2line_command", $pclist, $symbols)) {
|
| + last;
|
| }
|
| - unshift(@{$sym}, $function, $filelinenum, $fullfunction);
|
| - if ($debug) { printf("%s => [%s]\n", $pcstr, join(" ", @{$sym})); }
|
| - if (!defined($sep_address)) {
|
| - # Inlining is off, se this entry ends immediately
|
| - $count++;
|
| - }
|
| }
|
| - close(SYMBOLS);
|
| }
|
|
|
| # Use nm to map the list of referenced PCs to symbols. Return true iff we
|
| @@ -3783,7 +3646,7 @@
|
| }
|
| return 1;
|
| }
|
| -
|
| +
|
| sub ShortFunctionName {
|
| my $function = shift;
|
| while ($function =~ s/\([^()]*\)(\s*const)?//g) { } # Argument types
|
| @@ -3950,10 +3813,6 @@
|
| next;
|
| }
|
|
|
| - if ($this_routine eq $sep_symbol) {
|
| - $sep_address = HexExtend($start_val);
|
| - }
|
| -
|
| # Tag this routine with the starting address in case the image
|
| # has multiple occurrences of this routine. We use a syntax
|
| # that resembles template paramters that are automatically
|
|
|