#! /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 </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 = ""; } }