126 lines
2.3 KiB
Bash
126 lines
2.3 KiB
Bash
#! /usr/bin/env bash
|
|
# Reserved for future comments ...
|
|
#
|
|
#
|
|
#
|
|
# --------------------------------
|
|
|
|
prog_name="callygraphs"
|
|
|
|
if [ $# -lt 1 ]; then
|
|
echo "Usage: $prog_name EXECUTABLE [ARGS...]"
|
|
echo
|
|
echo "Example: $prog_name ~/bin/test-program foo 23"
|
|
exit 1
|
|
fi
|
|
|
|
# Sanity checks.
|
|
FILE=$1
|
|
|
|
if [ ! -x $FILE ]; then
|
|
echo "$prog_name: Unable to find executable '$FILE'"
|
|
exit 1
|
|
fi
|
|
|
|
LANG="" gdb --eval-command=quit $FILE 2>&1 \
|
|
| grep -E '(no\ debugging\ symbols\ found|not\ in\ executable\ format)' 2>&1 > /dev/null
|
|
if [ $? -eq 0 ]; then
|
|
echo -n "$prog_name: Can't print call graph for '$FILE' because it's not a "
|
|
echo "binary executable compiled with debugging symbols."
|
|
exit 1;
|
|
fi
|
|
|
|
shift
|
|
|
|
# Set up temporary files.
|
|
TRACE="`mktemp -t $prog_name.XXXXXXXXXX`" || exit
|
|
GETFUNCS="`mktemp -t $prog_name.XXXXXXXXXX`" || exit
|
|
trap 'rm -f -- "$TRACE" "$GETFUNCS"' EXIT
|
|
trap 'trap - EXIT; rm -f -- "$TRACE" "$GETFUNCS"; exit 1' HUP INT QUIT TERM
|
|
|
|
# Take control of GDB and print call graph.
|
|
cat > $GETFUNCS <<EOF
|
|
set height 0
|
|
info functions
|
|
EOF
|
|
|
|
gdb --batch --command=$GETFUNCS $FILE 2>/dev/null | awk '
|
|
function get_func_name(str)
|
|
{
|
|
split(str, part, "(");
|
|
len = split(part[1], part, " ");
|
|
len = split(part[len], part, "*");
|
|
|
|
return part[len];
|
|
}
|
|
|
|
BEGIN {
|
|
total = 0;
|
|
print "set width 0";
|
|
print "set height 0";
|
|
print "set verbose off";
|
|
}
|
|
|
|
/[a-zA-Z_][a-zA-Z0-9_]*\(/ {
|
|
fn = get_func_name($0);
|
|
printf("break %s\n", fn);
|
|
++total;
|
|
}
|
|
|
|
END {
|
|
for (i = 1; i <= total; i++) {
|
|
print "commands", i;
|
|
/* print "info args"; */
|
|
print "backtrace 2";
|
|
print "continue";
|
|
print "end";
|
|
}
|
|
|
|
print "run"
|
|
}
|
|
' > $TRACE
|
|
|
|
gdb --batch --command=$TRACE --tty=/dev/null --args $FILE $@ 2>/dev/null | awk '
|
|
function get_callee(s)
|
|
{
|
|
split(s, info, ",");
|
|
split(info[2], fn, " ");
|
|
callee = fn[1];
|
|
|
|
return callee;
|
|
}
|
|
|
|
function get_params(s, n)
|
|
{
|
|
split(s, par, n);
|
|
split(par[2], par, " at ");
|
|
sub(/ \(/, "(", par[1]);
|
|
|
|
return par[1];
|
|
}
|
|
|
|
BEGIN {
|
|
isrecord = 0;
|
|
callee = "";
|
|
caller = "*INITIAL*";
|
|
params = "";
|
|
}
|
|
|
|
/^Breakpoint [0-9]+,/ {
|
|
isrecord = 1;
|
|
|
|
callee = get_callee($0);
|
|
params = get_params($0, callee);
|
|
}
|
|
|
|
/^#1[ \t]+/ {
|
|
if (isrecord)
|
|
caller = $4;
|
|
}
|
|
|
|
/^$/ {
|
|
if (isrecord && (caller != "*INITIAL*")) {
|
|
printf("%s %s %s\n", caller, callee, params);
|
|
callee = caller = params = "";
|
|
}
|
|
}
|