Created
December 1, 2014 18:31
-
-
Save debedb/2b00c6c5de1a0c21da7f to your computer and use it in GitHub Desktop.
Print call sequence of a C program
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
# See http://debedb.blogspot.com/2007/02/poor-mans-tracepoints-and-call-sequence.html | |
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"; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment