DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Print Call Sequence Of A C Program

02.27.2007
| 6628 views |
  • submit to reddit
        Perl script to run gdb and collect information about method call
sequences. See also <A href=http://debedb.blogspot.com/2007/02/poor-mans-tracepoints-and-call-sequence.html>the blog entry</a>.

#!/usr/bin/perl 

use FileHandle;
use IPC::Open2;

if (! (-e "tags")) {
  print "Cannot find tags, will run\n";
  $tagCmd = "ctags *.h *.c";
  print "\t$tagCmd\n";
  system($tagCmd) && die ("Make sure ctags is installed\n");
}

%breakId2Func = {};
%func2Args = {};

#if ($ARGV[0] eq "prepare") {
#  exec('ctags *.h *.c');
  $exec = $ARGV[0];
  splice(@ARGV, 0, 1);
  
  $pid = open2(*Reader, *Writer, "gdb -annotate 3 --interpreter=mi $exec");

  while (<Reader>) {
    chop;
    last if ($_ eq "(gdb) ") 
  }    
  print Writer  "set print pretty on\n";
  while (<Reader>) {
    chop;
    last if ($_ eq "(gdb) ") 
  }    

  print Writer  "set print array on\n";
  while (<Reader>) {
    chop;
    last if ($_ eq "(gdb) ") 
  }    
  print Writer  "set print union on\n"; 
  while (<Reader>) {
    chop;
    last if ($_ eq "(gdb) ") 
  }    
  
  print "...\n";
  open(GREP, 'grep "f$" ./tags|') || die "Do you have ctags?\n";
  while (<GREP>) {
    ($func, $file, $regexp, $f) = split(/\t+/);
    $from = index($regexp, "(") + 1;
    $to = rindex($regexp, ")");
    $args = substr($regexp, $from, $to - $from);

    print Writer  "break $func\n";
    while (<Reader>) {
      # Store the number of the breakpoint, we will
       # need it later to determine when it's hit
      chop;
       if ($_ =~ /Breakpoint/) {
	 $breakId = substr($_, length('~"Breakpoint '));
         $breakId = substr($breakId, 0, index($breakId, " "));
         $breakId2Func{$breakId} = $func;
       } 
       last if $_ eq "(gdb) ";
     }

    ##############################################################
    # I wrote this when I didn't realize I can call "info args"
    # But maybe saving this is still useful for more information
    # like figuring out the type of variable and printing more
    # info about it, in case it's some pointer to struct to whatever
    #
    # Save argument names for evaluation when breakpoint is hit    
    # @args = split(/,/, $args );
    #
    # @$func = ();
    # foreach $arg (@args) {
    #  @typeAndVar = split(/\s+/,$arg);
    #
    #  $$func[++$#$func] = $typeAndVar[$#typeAndVar];
    # }
    #    $func2Args{$func} = \@$func;
    #    *x = $func2Args{$func};
    #    print "$func > @x\n";
    # }


print "Calling run @ARGV\n";
print Writer "run @ARGV\n";

$inBreak = 0;
while (<Reader>) {
  chop;
  if ($_ =~ /Breakpoint/) {
    #      print "$_\n";
    $breakId = substr($_, length('~"Breakpoint '));
    $breakId = substr($breakId, 0, index($breakId, ","));
    
    $func = $breakId2Func{$breakId};
    $inBreak = $breakId;
    
    # Which one is better?
    print Writer "info args\n";
    # print Writer "-stack-list-arguments 1 0 0\n";

    print Writer "cont\n";
  }
  
  if ($inBreak) {
    if ($_ =~ /~\"Continuing./) {
      $inBreak = 0;
      print "***************************\n";
    } else {
      if ($_ ne "(gdb) " &&
	  $_ ne "^done" &&
	  $_ ne '~"\n"' &&
          $_ ne '&"cont\n"' &&
	 $_ !~ /stopped/) {

	$_ =~ s/\\[nt]//g;
	$_ =~ s/\\032//g;
	$_ =~ s/^~\"//g;
	print "$_\n";
	
      }
    }
  }
}