Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

fnrec.pl 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #!/usr/bin/perl -w
  2. #
  3. # Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
  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. =head1 NAME
  19. fnrec.pl
  20. =head1 SYNOPSIS
  21. fnrec.pl [options] bin/image.xxx < logfile
  22. Decode a function trace produced by building with FNREC=1
  23. Options:
  24. -m,--max-depth=N Set maximum displayed function depth
  25. =cut
  26. use IPC::Open2;
  27. use Getopt::Long;
  28. use Pod::Usage;
  29. use strict;
  30. use warnings;
  31. use constant MAX_OPEN_BRACE => 10;
  32. use constant MAX_COMMON_BRACE => 3;
  33. use constant MAX_CLOSE_BRACE => 10;
  34. # Parse command-line options
  35. my $max_depth = 16;
  36. Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
  37. GetOptions (
  38. 'help|h' => sub { pod2usage ( 1 ); },
  39. 'max-depth|m=i' => sub { shift; $max_depth = shift; },
  40. ) or die "Could not parse command-line options\n";
  41. pod2usage ( 1 ) unless @ARGV == 1;
  42. my $image = shift;
  43. my $elf = $image.".tmp";
  44. die "ELF file ".$elf." not found\n" unless -e $elf;
  45. # Start up addr2line
  46. my $addr2line_pid = open2 ( my $addr2line_out, my $addr2line_in,
  47. "addr2line", "-f", "-e", $elf )
  48. or die "Could not start addr2line: $!\n";
  49. # Translate address using addr2line
  50. sub addr2line {
  51. my $address = shift;
  52. print $addr2line_in $address."\n";
  53. chomp ( my $name = <$addr2line_out> );
  54. chomp ( my $file_line = <$addr2line_out> );
  55. ( my $file, my $line ) = ( $file_line =~ /^(.*):(\d+)$/ );
  56. $file =~ s/^.*\/src\///;
  57. my $location = ( $line ? $file.":".$line." = ".$address : $address );
  58. return ( $name, $location );
  59. }
  60. # Parse logfile
  61. my $depth = 0;
  62. my $depths = [];
  63. while ( my $line = <> ) {
  64. chomp $line;
  65. $line =~ s/\r//g;
  66. ( my $called_fn, my $call_site, my $entry_count, my $exit_count ) =
  67. ( $line =~ /^(0x[0-9a-f]+)\s+(0x[0-9a-f]+)\s+([0-9]+)\s+([0-9]+)$/ )
  68. or print $line."\n" and next;
  69. ( my $called_fn_name, undef ) = addr2line ( $called_fn );
  70. ( undef, my $call_site_location ) = addr2line ( $call_site );
  71. $entry_count = ( $entry_count + 0 );
  72. $exit_count = ( $exit_count + 0 );
  73. if ( $entry_count >= $exit_count ) {
  74. #
  75. # Function entry
  76. #
  77. my $text = "";
  78. $text .= $called_fn_name." (from ".$call_site_location.")";
  79. if ( $exit_count <= MAX_COMMON_BRACE ) {
  80. $text .= " { }" x $exit_count;
  81. } else {
  82. $text .= " { } x ".$exit_count;
  83. }
  84. $entry_count -= $exit_count;
  85. if ( $entry_count <= MAX_OPEN_BRACE ) {
  86. $text .= " {" x $entry_count;
  87. } else {
  88. $text .= " { x ".$entry_count;
  89. }
  90. my $indent = " " x $depth;
  91. print $indent.$text."\n";
  92. $depth += $entry_count;
  93. $depth = $max_depth if ( $depth > $max_depth );
  94. push @$depths, ( { called_fn => $called_fn, call_site => $call_site } ) x
  95. ( $depth - @$depths );
  96. } else {
  97. #
  98. # Function exit
  99. #
  100. my $text = "";
  101. if ( $entry_count <= MAX_COMMON_BRACE ) {
  102. $text .= " { }" x $entry_count;
  103. } else {
  104. $text .= " { } x ".$entry_count;
  105. }
  106. $exit_count -= $entry_count;
  107. if ( $exit_count <= MAX_CLOSE_BRACE ) {
  108. $text .= " }" x $exit_count;
  109. } else {
  110. $text .= " } x ".$exit_count;
  111. }
  112. $depth -= $exit_count;
  113. $depth = 0 if ( $depth < 0 );
  114. if ( ( @$depths == 0 ) ||
  115. ( $depths->[$depth]->{called_fn} ne $called_fn ) ||
  116. ( $depths->[$depth]->{call_site} ne $call_site ) ) {
  117. $text .= " (from ".$called_fn_name." to ".$call_site_location.")";
  118. }
  119. splice ( @$depths, $depth );
  120. my $indent = " " x $depth;
  121. print substr ( $indent.$text, 1 )."\n";
  122. }
  123. }
  124. # Clean up addr2line
  125. close $addr2line_in;
  126. close $addr2line_out;
  127. waitpid ( $addr2line_pid, 0 );