#! /usr/bin/perl use strict; use vars qw($NM_CMD %SYMBOLS %CALLS %TOTAL); $NM_CMD = "/usr/bin/nm -S"; # -------------------------------------------------------------------- my $file_sym = $ARGV[0] or die; &read_symbol($file_sym); my $file_inst = $ARGV[1] or die; my (@stack); open(F, "$file_inst") or die "$file_inst"; my $depth = 0; while () { chomp; /^([EX])0x([\da-f]+)/ or next; my ($ex) = $1; my ($addr) = hex($2); if ($ex eq 'E') { push(@stack, $addr); } elsif ($ex eq 'X') { pop(@stack); } next if $ex eq 'X'; next unless exists($SYMBOLS{$addr}); my $sym_callee = $SYMBOLS{$addr}; my $sym_caller = &find_caller(\@stack); next unless $sym_caller; # print "$sym_caller -> $sym_callee\n"; ++$CALLS{$sym_caller}{$sym_callee}; ++$TOTAL{$sym_caller}; exists($TOTAL{$sym_callee}) or $TOTAL{$sym_callee} = 0; # print ' ' x $#stack, $sym_callee, "\n"; } close(F); # -------------------------------------------------------------------- print "digraph G \{\n\n"; # vertecies foreach (keys %TOTAL) { my $caller = $_; if ($TOTAL{$caller} > 0) { print " \"$caller\" [shape=rectangle];\n"; } else { print " \"$caller\" [shape=ellipse];\n"; } } # edges foreach (keys %CALLS) { my $caller = $_; foreach (keys %{$CALLS{$caller}}) { my $callee = $_; my $count = $CALLS{$caller}{$callee}; print " \"$caller\" -> \"$callee\" [label=\"$count calls\" fontsize=\"10\"];\n"; } } print "}\n"; # -------------------------------------------------------------------- sub read_symbol { my $file = shift; open(P, "$NM_CMD $file |") or die "$NM_CMD $file"; while (

) { next unless /^([\da-f]+)\s+([\da-f]+)\s+[tTW]\s+(\w+)$/; my ($begin, $size, $symbol) = ($1, $2, $3); local($_) = $symbol; next if /^_ZNK?5boost/; next if /^_ZN?K?S/; next if /^_ZNK?9__gnu_cxx/; next if /^_Z41__static_/; next if /^_ZNK4mpl/; next if /^__tcf_/; next if /^_Z8__istypeim/; next if /^_GLOBAL__/; next if /^_Z10__maskruneim/; next if /^_Znw/; next if /^_Zdl/; next if /^__cyg_/; $SYMBOLS{hex($begin)} = $symbol; } close(P); } sub find_caller { my $stack = shift; my $depth = scalar(@$stack); local($_) = $depth - 2; for (; $_ >= 0; --$_) { my $addr = $stack->[$_]; return $SYMBOLS{$addr} if $SYMBOLS{$addr}; } }