I was looking for a way to see how functions flow in a program.
After some search I found this nice post:
m0agx.eu/2016/12/15/making-call-graphs-with-gcc-egypt-and-cflow/
Then I downloaded egypt-1.10.tar.gz, decompressed it and run:
$ perl Makefile.PL
$ make
$ sudo make install
Then I added this flag: -fdump-rtl-expand to gcc compilation. It created many files.expand at Debug/ directory. The final command was:
$ egypt ./Debug/sources/*.expand ./Debug/sources/ext_monitor_system/*.expand ./Debug/sources/cJSON/*.expand ./Debug/sources/notification/*.expand ./Debug/sources/accessctl_perm_check/*.expand ./Debug/sources/coap_dev_resource/*.expand | dot -Gsize=15000,15000 -Grankdir=LR -Tpng -o /tmp/callgraph.png
Interesting – but SO complex it hurts my brain.
It is not so complex, just download and build the “egypt” and compile your source code passing the parameter “-fdump-rtl-expand”. It will create a .expand for each file. Then just run egypt passing these .expand files.
I wrote a call graph generator in 2008 because I had a need to analytically determine the worst case stack usage for an embedded program. I used cflow to generate the call graph as a text file, then I parsed it and generated a graphvix dot intput file from that by a bash script. Once the graph was available as a directed acyclic graph in the dot input language, I wrote a bash script to annotate each function node in the graph with the size of the stack frame that function pushed on the stack. I later added a perl script to run a search for cycles in the graph, which meant recursion was present. If there is recursion, there is no analytic way to determine the maximum cumulative stack size unless you have a way to know the maximum depth of recursion. If there is recursion, I hilite the nodes in any recursive cycles so they stand out in the graph. If there is no recursion, I make a pass thru the graph adding up the stack frame sizes along each call path. I then find the maximunm depth call path, and that shows me the max size the stack can use. This program, as an ugly bash script hack, is available at:
http://www.elilabs.com/~rj/code_graphs/index.html
I later discovered the egypt program because I wanted a way to upgrade my program to work with C++, but I have since determined that with virtual functions and class inheritance, it is very dificfult to determine a call graph staticly in an object oriented program, as classes can be multiply instantiated, are usually referenced thru a pointer or reference, and class member function calls are just too dynamic to analyze with static analysis techniques. A better way to see how a C++ program actually behaves is to run it with some kind of function call tracing enables. gcc makes this easy, and most other compilers will have profiling and code coverage tools that will do this also. Once you have such a trace, it can be parsed and fed into my shell scripts to generate dynamic call graphs instead of static ones.
My shell scripts currently generate pdf files for viewing in a browser. The also generate subgraphs that show who calls a function, and who all a function calls. It is on my To-Do list to generate SVG (Scalable Vector Graphics) files instead of PDG files, but I haven’t had time to work on it yet.
Hi Rj Brown,
thank you for sharing these thoughts and for sharing your scripts. In fact I think such tool should be available together with toolchain, because it is very useful.