Annotation of qemu/roms/ipxe/src/util/fnrec.pl, revision 1.1.1.1

1.1       root        1: #!/usr/bin/perl -w
                      2: #
                      3: # Copyright (C) 2010 Michael Brown <[email protected]>.
                      4: #
                      5: # This program is free software; you can redistribute it and/or
                      6: # modify it under the terms of the GNU General Public License as
                      7: # published by the Free Software Foundation; either version 2 of the
                      8: # License, or any later version.
                      9: #
                     10: # This program is distributed in the hope that it will be useful, but
                     11: # WITHOUT ANY WARRANTY; without even the implied warranty of
                     12: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     13: # General Public License for more details.
                     14: #
                     15: # You should have received a copy of the GNU General Public License
                     16: # along with this program; if not, write to the Free Software
                     17: # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     18: 
                     19: =head1 NAME
                     20: 
                     21: fnrec.pl
                     22: 
                     23: =head1 SYNOPSIS
                     24: 
                     25: fnrec.pl [options] bin/image.xxx < logfile
                     26: 
                     27: Decode a function trace produced by building with FNREC=1
                     28: 
                     29: Options:
                     30: 
                     31:        -m,--max-depth=N        Set maximum displayed function depth
                     32: 
                     33: =cut
                     34: 
                     35: use IPC::Open2;
                     36: use Getopt::Long;
                     37: use Pod::Usage;
                     38: use strict;
                     39: use warnings;
                     40: 
                     41: use constant MAX_OPEN_BRACE => 10;
                     42: use constant MAX_COMMON_BRACE => 3;
                     43: use constant MAX_CLOSE_BRACE => 10;
                     44: 
                     45: # Parse command-line options
                     46: my $max_depth = 16;
                     47: Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
                     48: GetOptions (
                     49:   'help|h' => sub { pod2usage ( 1 ); },
                     50:   'max-depth|m=i' => sub { shift; $max_depth = shift; },
                     51: ) or die "Could not parse command-line options\n";
                     52: pod2usage ( 1 ) unless @ARGV == 1;
                     53: my $image = shift;
                     54: my $elf = $image.".tmp";
                     55: die "ELF file ".$elf." not found\n" unless -e $elf;
                     56: 
                     57: # Start up addr2line
                     58: my $addr2line_pid = open2 ( my $addr2line_out, my $addr2line_in,
                     59:                            "addr2line", "-f", "-e", $elf )
                     60:     or die "Could not start addr2line: $!\n";
                     61: 
                     62: # Translate address using addr2line
                     63: sub addr2line {
                     64:   my $address = shift;
                     65: 
                     66:   print $addr2line_in $address."\n";
                     67:   chomp ( my $name = <$addr2line_out> );
                     68:   chomp ( my $file_line = <$addr2line_out> );
                     69:   ( my $file, my $line ) = ( $file_line =~ /^(.*):(\d+)$/ );
                     70:   $file =~ s/^.*\/src\///;
                     71:   my $location = ( $line ? $file.":".$line." = ".$address : $address );
                     72:   return ( $name, $location );
                     73: }
                     74: 
                     75: # Parse logfile
                     76: my $depth = 0;
                     77: my $depths = [];
                     78: while ( my $line = <> ) {
                     79:   chomp $line;
                     80:   $line =~ s/\r//g;
                     81:   ( my $called_fn, my $call_site, my $entry_count, my $exit_count ) =
                     82:       ( $line =~ /^(0x[0-9a-f]+)\s+(0x[0-9a-f]+)\s+([0-9]+)\s+([0-9]+)$/ )
                     83:       or print $line."\n" and next;
                     84: 
                     85:   ( my $called_fn_name, undef ) = addr2line ( $called_fn );
                     86:   ( undef, my $call_site_location ) = addr2line ( $call_site );
                     87:   $entry_count = ( $entry_count + 0 );
                     88:   $exit_count = ( $exit_count + 0 );
                     89: 
                     90:   if ( $entry_count >= $exit_count ) {
                     91:     #
                     92:     # Function entry
                     93:     #
                     94:     my $text = "";
                     95:     $text .= $called_fn_name." (from ".$call_site_location.")";
                     96:     if ( $exit_count <= MAX_COMMON_BRACE ) {
                     97:       $text .= " { }" x $exit_count;
                     98:     } else {
                     99:       $text .= " { } x ".$exit_count;
                    100:     }
                    101:     $entry_count -= $exit_count;
                    102:     if ( $entry_count <= MAX_OPEN_BRACE ) {
                    103:       $text .= " {" x $entry_count;
                    104:     } else {
                    105:       $text .= " { x ".$entry_count;
                    106:     }
                    107:     my $indent = "  " x $depth;
                    108:     print $indent.$text."\n";
                    109:     $depth += $entry_count;
                    110:     $depth = $max_depth if ( $depth > $max_depth );
                    111:     push @$depths, ( { called_fn => $called_fn, call_site => $call_site } ) x
                    112:        ( $depth - @$depths );
                    113:   } else {
                    114:     #
                    115:     # Function exit
                    116:     #
                    117:     my $text = "";
                    118:     if ( $entry_count <= MAX_COMMON_BRACE ) {
                    119:       $text .= " { }" x $entry_count;
                    120:     } else {
                    121:       $text .= " { } x ".$entry_count;
                    122:     }
                    123:     $exit_count -= $entry_count;
                    124:     if ( $exit_count <= MAX_CLOSE_BRACE ) {
                    125:       $text .= " }" x $exit_count;
                    126:     } else {
                    127:       $text .= " } x ".$exit_count;
                    128:     }
                    129:     $depth -= $exit_count;
                    130:     $depth = 0 if ( $depth < 0 );
                    131:     if ( ( @$depths == 0 ) ||
                    132:         ( $depths->[$depth]->{called_fn} ne $called_fn ) ||
                    133:         ( $depths->[$depth]->{call_site} ne $call_site ) ) {
                    134:       $text .= " (from ".$called_fn_name." to ".$call_site_location.")";
                    135:     }
                    136:     splice ( @$depths, $depth );
                    137:     my $indent = "  " x $depth;
                    138:     print substr ( $indent.$text, 1 )."\n";
                    139:   }
                    140: }
                    141: 
                    142: # Clean up addr2line
                    143: close $addr2line_in;
                    144: close $addr2line_out;
                    145: waitpid ( $addr2line_pid, 0 );

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.