Print call sequence of a C program
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 (<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"; } } } }