#!/usr/bin/perl # Makes a function hierarchy from output from the Examiner use strict; use vars qw(%functions $COMMENT $depth $VERSION @parents $verbose); use Getopt::Std; my $VERSION="0.1"; # Version info my $COMMENT="#"; # Default comment char my $depth=8; # Max DEPTH Default my $file; # Target file my $line; # Generic var my $args; # Arguments passed to functions my $level; # Current depth level my $current; # Current function my $start_funct; # Starting function my $call; # Function call my $verbose; # Verbosity level my %options; # Command line options getopts("vc:d:f:",\%options) || usage(); if ($options{"c"}) { $COMMENT=$options{"c"}; } if ($options{"d"}) { $depth=$options{"d"}; } if ($options{"f"}) { $file=$options{"f"}; } if ($options{"v"}) { $verbose++; } usage() if !$file; open OBJFILE, $file || die " Couldn't open $file:$!\n"; print "$COMMENT$COMMENT\n"; print "$COMMENT$COMMENT Hierarchy of $file\n"; print "$COMMENT$COMMENT\n"; while(<OBJFILE>) { $line=$_; if ($line=~/Disassembly of section \.text/) { $current=".TEXT_FUNCT"; $start_funct="1"; } if($line=~/$COMMENT \[(.*)\]/) { $current=$1; $start_funct=$current if $start_funct eq "1"; } elsif($line=~/$COMMENT CALL (.*)/) { next if !$current; $start_funct = $current if !$start_funct; $call=$1; if($call=~/(\S*)\((.*)\)/) { $call=$1; $args=$2; } $args="($args)"; # Pushes both the CALLS and ARGS to the hashref push @{ $functions{$current} }, $call, $args; # Speical rules for LIBC_START_MAIN if($call eq "__LIBC_START_MAIN_FUNCT") { push @{ $functions{$current} }, "_START_MAIN_FUNCT", "()"; } } } close OBJFILE; $level=0; print "$start_funct\n"; print_funct($level, $start_funct); exit(0); #### SUBS ### # Recursive function to print out funcion calls sub print_funct { my $level=shift; my $funct=shift; my $call; my $args; my $total_calls= $#{ $functions{$funct} }; my $count; return if !$functions{$funct}; push @parents, $funct; for($count=0; $count <= $total_calls; $count+=2) { $call=@{ $functions{$funct} }[$count]; $args=@{ $functions{$funct} }[$count+1]; print "|" x $level; print "+ "; if (is_parent($call, @parents)) { print "$call"; print "$args" if $verbose; print "<- Recursive call\n"; } elsif ($level > $depth) { print "$call"; print "$args" if $verbose; print "...\n"; } else { print "$call"; print "$args" if $verbose; print "\n"; print_funct($level+1, $call); } } pop @parents; } # Check array for a value sub is_parent { my $call=shift; my @parents = @_; my $parent; foreach $parent (@parents) { return 1 if $parent eq $call; } return 0; } # Usage: statement sub usage { print "$0 v$VERSION\n"; print "$0 [Options] -f commented_file\n"; print "Prints function hierarchy of commented files generated by the Examiner\n"; print "\n"; print "\tOptions\tDescription\n"; print "\t-v\tIncrease verbosity (enables arguement printing)\n"; print "\t-d #\tDepth to traverse functions (Default: $depth)\n"; print "\t-c char\tComment char (Default: '$COMMENT')\n"; print "\t-f file\tCommented file to parse\n"; exit(1); }