Call graph generation

Call graphs are very useful in understanding how a program works. Here are two ways to generate them.

Approach 1: Cygwin profiling interface

This approach assumes you have the source files and you use GCC.

GCC supports the Cygwin profiling interface. Put it simply, first, implement two functions

void __cyg_profile_func_enter(void *this_fn, void *call_site)

void __cyg_profile_func_exit(void *this_fn, void *call_site)
Then compile everything with -finstrument-functions compiler command-line options.

As an example, see N. Devillard's etrace on how to generate call graphs.

More examples: here and here

Approach 2: GDB break points

This approach does not need the source files because it works directly on executable binaries, and it works best when the binaries are not stripped. The idea comes from here.

The only issue with this approach is many functions could have been inlined during compilation and thus their information (symbolic references) will be missing.

This approach runs a GDB script which sets a break point at each function and parses the result to generate call graphs.

The first script genCallgraph.sh (adapted from Juan M. Bello Rivas's code) takes an executable binary and generates a series of caller-callee pairs. Then one can send this output to an awk script cg2dot.awk to generate a dot file which can be plotted using Graphviz.

The second script genCallgraphLocal.sh is a small variant of the first one. It only traces function calls within your executable binaries (because you are not interested in what's going on inside the dynamic libraries) as well as all system calls.

The third script genCallgraphLDSO.sh is designed to trace what's going on inside the runtime linker ld.so. It takes a dynamic executable binary and generates a series of caller-callee pairs within ld.so.

There are several showcases. The compile and runtime environment is Linux kernel version 2.6.34 (x86_64), GDB version 7.1, GCC version 4.5.0, unstrippped Glibc version 2.11.1 (some Linux distributions, such as Ubuntu version 10, ship stripped libc.so), GNU Binutils version 2.20.1.


Also make sure your GCC does not enable PIC by default. If so, please disable it by -no-pie. See this article for more details.