| #! /usr/bin/perl |
| eval "exec /usr/bin/perl -S $0 $@" |
| if 0; |
| # Copyright (C) 1997-2014 Free Software Foundation, Inc. |
| # This file is part of the GNU C Library. |
| # Contributed by Ulrich Drepper <drepper@gnu.org>, 1997. |
| # Based on the mtrace.awk script. |
| |
| # The GNU C Library is free software; you can redistribute it and/or |
| # modify it under the terms of the GNU Lesser General Public |
| # License as published by the Free Software Foundation; either |
| # version 2.1 of the License, or (at your option) any later version. |
| |
| # The GNU C Library is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| # Lesser General Public License for more details. |
| |
| # You should have received a copy of the GNU Lesser General Public |
| # License along with the GNU C Library; if not, see |
| # <http://www.gnu.org/licenses/>. |
| |
| $VERSION = "2.19-2014.08-1-git"; |
| $PKGVERSION = "(EGLIBC) "; |
| $REPORT_BUGS_TO = '<http://www.eglibc.org/issues/>'; |
| $progname = $0; |
| |
| sub usage { |
| print "Usage: mtrace [OPTION]... [Binary] MtraceData\n"; |
| print " --help print this help, then exit\n"; |
| print " --version print version number, then exit\n"; |
| print "\n"; |
| print "For bug reporting instructions, please see:\n"; |
| print "$REPORT_BUGS_TO.\n"; |
| exit 0; |
| } |
| |
| # We expect two arguments: |
| # #1: the complete path to the binary |
| # #2: the mtrace data filename |
| # The usual options are also recognized. |
| |
| arglist: while (@ARGV) { |
| if ($ARGV[0] eq "--v" || $ARGV[0] eq "--ve" || $ARGV[0] eq "--ver" || |
| $ARGV[0] eq "--vers" || $ARGV[0] eq "--versi" || |
| $ARGV[0] eq "--versio" || $ARGV[0] eq "--version") { |
| print "mtrace $PKGVERSION$VERSION\n"; |
| print "Copyright (C) 2014 Free Software Foundation, Inc.\n"; |
| print "This is free software; see the source for copying conditions. There is NO\n"; |
| print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"; |
| print "Written by Ulrich Drepper <drepper\@gnu.org>\n"; |
| |
| exit 0; |
| } elsif ($ARGV[0] eq "--h" || $ARGV[0] eq "--he" || $ARGV[0] eq "--hel" || |
| $ARGV[0] eq "--help") { |
| &usage; |
| } elsif ($ARGV[0] =~ /^-/) { |
| print "$progname: unrecognized option `$ARGV[0]'\n"; |
| print "Try `$progname --help' for more information.\n"; |
| exit 1; |
| } else { |
| last arglist; |
| } |
| } |
| |
| if ($#ARGV == 0) { |
| $binary=""; |
| $data=$ARGV[0]; |
| } elsif ($#ARGV == 1) { |
| $binary=$ARGV[0]; |
| $data=$ARGV[1]; |
| |
| if ($binary =~ /^.*[\/].*$/) { |
| $prog = $binary; |
| } else { |
| $prog = "./$binary"; |
| } |
| if (open (LOCS, "env LD_TRACE_LOADED_OBJECTS=1 $prog |")) { |
| while (<LOCS>) { |
| chop; |
| if (/^.*=> (.*) .(0x[0123456789abcdef]*).$/) { |
| $locs{$1} = $2; |
| } |
| } |
| close (LOCS); |
| } |
| } else { |
| die "Wrong number of arguments, run $progname --help for help."; |
| } |
| |
| sub location { |
| my $str = pop(@_); |
| return $str if ($str eq ""); |
| if ($str =~ /.*[[](0x[^]]*)]:(.)*/) { |
| my $addr = $1; |
| my $fct = $2; |
| return $cache{$addr} if (exists $cache{$addr}); |
| if ($binary ne "" && open (ADDR, "addr2line -e $binary $addr|")) { |
| my $line = <ADDR>; |
| chomp $line; |
| close (ADDR); |
| if ($line ne '??:0') { |
| $cache{$addr} = $line; |
| return $cache{$addr}; |
| } |
| } |
| $cache{$addr} = $str = "$fct @ $addr"; |
| } elsif ($str =~ /^(.*):.*[[](0x[^]]*)]$/) { |
| my $prog = $1; |
| my $addr = $2; |
| my $searchaddr; |
| return $cache{$addr} if (exists $cache{$addr}); |
| if ($locs{$prog} ne "") { |
| $searchaddr = sprintf "%#x", $addr - $locs{$prog}; |
| } else { |
| $searchaddr = $addr; |
| $prog = $binary; |
| } |
| if ($binary ne "" && open (ADDR, "addr2line -e $prog $searchaddr|")) { |
| my $line = <ADDR>; |
| chomp $line; |
| close (ADDR); |
| if ($line ne '??:0') { |
| $cache{$addr} = $line; |
| return $cache{$addr}; |
| } |
| } |
| $cache{$addr} = $str = $addr; |
| } elsif ($str =~ /^.*[[](0x[^]]*)]$/) { |
| my $addr = $1; |
| return $cache{$addr} if (exists $cache{$addr}); |
| if ($binary ne "" && open (ADDR, "addr2line -e $binary $addr|")) { |
| my $line = <ADDR>; |
| chomp $line; |
| close (ADDR); |
| if ($line ne '??:0') { |
| $cache{$addr} = $line; |
| return $cache{$addr}; |
| } |
| } |
| $cache{$addr} = $str = $addr; |
| } |
| return $str; |
| } |
| |
| $nr=0; |
| open(DATA, "<$data") || die "Cannot open mtrace data file"; |
| while (<DATA>) { |
| my @cols = split (' '); |
| my $n, $where; |
| if ($cols[0] eq "@") { |
| # We have address and/or function name. |
| $where=$cols[1]; |
| $n=2; |
| } else { |
| $where=""; |
| $n=0; |
| } |
| |
| $allocaddr=$cols[$n + 1]; |
| $howmuch=hex($cols[$n + 2]); |
| |
| ++$nr; |
| SWITCH: { |
| if ($cols[$n] eq "+") { |
| if (defined $allocated{$allocaddr}) { |
| printf ("+ %#018x Alloc %d duplicate: %s %s\n", |
| hex($allocaddr), $nr, &location($addrwas{$allocaddr}), |
| $where); |
| } else { |
| $allocated{$allocaddr}=$howmuch; |
| $addrwas{$allocaddr}=$where; |
| } |
| last SWITCH; |
| } |
| if ($cols[$n] eq "-") { |
| if (defined $allocated{$allocaddr}) { |
| undef $allocated{$allocaddr}; |
| undef $addrwas{$allocaddr}; |
| } else { |
| printf ("- %#018x Free %d was never alloc'd %s\n", |
| hex($allocaddr), $nr, &location($where)); |
| } |
| last SWITCH; |
| } |
| if ($cols[$n] eq "<") { |
| if (defined $allocated{$allocaddr}) { |
| undef $allocated{$allocaddr}; |
| undef $addrwas{$allocaddr}; |
| } else { |
| printf ("- %#018x Realloc %d was never alloc'd %s\n", |
| hex($allocaddr), $nr, &location($where)); |
| } |
| last SWITCH; |
| } |
| if ($cols[$n] eq ">") { |
| if (defined $allocated{$allocaddr}) { |
| printf ("+ %#018x Realloc %d duplicate: %#010x %s %s\n", |
| hex($allocaddr), $nr, $allocated{$allocaddr}, |
| &location($addrwas{$allocaddr}), &location($where)); |
| } else { |
| $allocated{$allocaddr}=$howmuch; |
| $addrwas{$allocaddr}=$where; |
| } |
| last SWITCH; |
| } |
| if ($cols[$n] eq "=") { |
| # Ignore "= Start". |
| last SWITCH; |
| } |
| if ($cols[$n] eq "!") { |
| # Ignore failed realloc for now. |
| last SWITCH; |
| } |
| } |
| } |
| close (DATA); |
| |
| # Now print all remaining entries. |
| @addrs= keys %allocated; |
| $anything=0; |
| if ($#addrs >= 0) { |
| foreach $addr (sort @addrs) { |
| if (defined $allocated{$addr}) { |
| if ($anything == 0) { |
| print "\nMemory not freed:\n-----------------\n"; |
| print ' ' x (18 - 7), "Address Size Caller\n"; |
| $anything=1; |
| } |
| printf ("%#018x %#8x at %s\n", hex($addr), $allocated{$addr}, |
| &location($addrwas{$addr})); |
| } |
| } |
| } |
| print "No memory leaks.\n" if ($anything == 0); |
| |
| exit $anything != 0; |