mirror of
https://github.com/openssh/libopenssh
synced 2026-04-16 09:45:53 +00:00
objdump -rd *.o | objdump2.pl -b asn1_d2i_read_bio | dot -Tpdf > asn1_d2i_read_bio.pdf
This commit is contained in:
97
leakmalloc/objdump2dot.pl
Executable file
97
leakmalloc/objdump2dot.pl
Executable file
@@ -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 <ASN1_d2i_fp>:
|
||||
## 9: e8 00 00 00 00 call e <ASN1_d2i_fp+0xe> NOT
|
||||
## 16: R_386_PLT32 BIO_s_file YES
|
||||
## 1e: R_386_PLT32 BIO_new YES
|
||||
## 106: e8 c5 00 00 00 call 1d0 <asn1_d2i_read_bio> 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";
|
||||
Reference in New Issue
Block a user