diff --git a/leakmalloc/objdump2dot.pl b/leakmalloc/objdump2dot.pl new file mode 100755 index 0000000..6808b6a --- /dev/null +++ b/leakmalloc/objdump2dot.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl + +use Data::Dumper; +use Getopt::Std; +use strict; +use warnings; + +sub usage () { + my $argv0 = $0; + $argv0 =~ s|.*/||; + printf "usage: objdump -rd *.o | $argv0 [-rb] f1 [f2...] | dot -Tpdf > out.pdf\n"; + exit 1; +} + +my %opts; +getopts('brd', \%opts) or usage(); +$#ARGV >= 0 or usage(); +my $reverse = $opts{r} || 0; # print callers, otherwise callee-s +my $both = $opts{b} || 0; +my $debug = $opts{d} || 0; +my @functions = @ARGV; +@ARGV=(); + +## parse Relocated-Disassemble output from 'objdump -rd' +##00000000 : +## 9: e8 00 00 00 00 call e NOT +## 16: R_386_PLT32 BIO_s_file YES +## 1e: R_386_PLT32 BIO_new YES +## 106: e8 c5 00 00 00 call 1d0 YES + +my $graph = {}; +my $inverse = {}; + +# check for function calls and build call-graph +my $caller = ''; +while(<>) { + chomp; + if (/^\S+ <(\S+)>:/) { + $caller=$1; + $caller='' if $caller =~ /^\./; + print "# FOUND FUNC $1\n" if $caller && $debug; + } + next unless $caller; + if (/(R_386_PC32|R_386_PLT32)\s+(\S+)/) { + my $f=$2; + print "# $caller => $f\n" if $debug; + $graph->{$caller}->{$f} = 1; + } + if (/call\s.+<(\S+)>/) { + my $f=$1; + next if ($f =~ /\+0x/); + print "# $caller -> $f\n" if $debug; + $graph->{$caller}->{$f} = 1; + } +} +print Dumper($graph) if $debug; + +if ($reverse || $both) { + # build the inverse call graph (callee->caller) + while (my ($caller, $calls) = each %$graph) { + foreach my $f (sort keys %$calls) { + $inverse->{$f}->{$caller} = 1; + } + } + print Dumper($inverse) if $debug; +} + +# recurse over the call-graph ($map) until no callers +# are found, skip if already seen (by deleting them) +sub show { + my $func = shift; + my $map = shift; + my $entry = delete $map->{$func}; + if (defined($entry)) { + foreach my $f (sort keys %{$entry}) { + if ($map == $inverse) { + printf "$f -> $func\n"; + } else { + printf "$func -> $f\n"; + } + show($f, $map); + } + } +} + +print "digraph callgraph {\n"; +print "rankdir=LR\n"; # left-to-right +foreach my $f (@functions) { + if ($reverse || $both) { + show($f, $inverse); + } + if (!$reverse || $both) { + show($f, $graph); + } + print "$f [color=red]\n"; +} +print "}\n";