Over a million developers have joined DZone.

Print Call Sequence Of A C Program

·
Perl script to run gdb and collect information about method call
sequences. See also the blog entry.


#!/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 () {
    chop;
    last if ($_ eq "(gdb) ") 
  }    
  print Writer  "set print pretty on\n";
  while () {
    chop;
    last if ($_ eq "(gdb) ") 
  }    

  print Writer  "set print array on\n";
  while () {
    chop;
    last if ($_ eq "(gdb) ") 
  }    
  print Writer  "set print union on\n"; 
  while () {
    chop;
    last if ($_ eq "(gdb) ") 
  }    
  
  print "...\n";
  open(GREP, 'grep "f$" ./tags|') || die "Do you have ctags?\n";
  while () {
    ($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 () {
      # 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 () {
  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";
	
      }
    }
  }
}

Topics:

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}