javastatic-code-analysiscall-graph

Creating a visual call graph for java projects from command line


I'm looking to create a callgraph for java projects from the command line. I have explored several projects, each time falling short (either in my understanding, or the functionality) of what I am aiming for. Some simple guidelines on how to do this would be great, an additional aim is to get a text representation of this graph.

Here is what I have tried:

Call-graph: https://github.com/gousiosg/java-callgraph

This gives me the text output that I want, but I cannot find a way (after looking through the documentation for some time), to turn this into a visual (image file) graph output.

Soot: http://sable.github.io/soot/

After spending a huge amount of time looking through the SOOT documentation, which seems rather difficult to follow, I managed to get SOOT to create bytecode. However, I can't find any guides on how to create a call graph from it. I only see on the main page that it can do this, and I get several email conversations from my google searches, all which are just questions without answers. I'm using the nightly build with the command:

java -cp soot-trunk.jar soot.Main -cp . -pp HelloWorld

Where HelloWorld is the name of my java file, I get an output which is a .class file, but I can't see how to get the actual call graph. This is after following the guide here: https://github.com/Sable/soot/wiki/Running-Soot. When I follow links about visualisations, they seem to be broken links which then redirect back to the homepage. I can see some information about using the -cg flag on the command line page, but can't get anything to work - I just get an option parse error, suggesting an invalid argument: https://ssebuild.cased.de/nightly/soot/doc/soot_options.htm#phase_5

Searching stackoverflow - existing answers I have already looked at several similar questions, such as: Static analysis of Java call graph However, the answers just say "use soot", or "use call-graph", I have been trying these without any luck - although I am closest with the call graph as I do have the text output.

I see some GUI based software and eclipse plugins which claim to create call-graphs, but I am trying to get this working from the command line.

Any help is really appreciated, a guide, or set of commands with either call-graph or Soot, or another program would really help.It may be worth also committing any short tutorial back to them for their documentation as there seems to be more questions than answers when searching.

For reference, I am currently attempting with a very simple class below:

public class HelloWorld {

    public static void main(String[] args) {
        foo();
    }
    public static void foo(){
        System.out.println("Hello World");
    }
}

Solution

  • It does look like Call Graph produces quite a decent output. Let's do a quick PoC.

    I'll use a sample output provided by Call Graph developer.

    org.apache.batik.dom.AbstractParentNode:appendChild org.apache.batik.dom.AbstractParentNode:fireDOMNodeInsertedEvent 6270
    org.apache.batik.dom.AbstractParentNode:fireDOMNodeInsertedEvent org.apache.batik.dom.AbstractDocument:getEventsEnabled 6280
    org.apache.batik.dom.AbstractParentNode:checkAndRemove org.apache.batik.dom.AbstractNode:getOwnerDocument 6280
    org.apache.batik.dom.util.DoublyIndexedTable:put org.apache.batik.dom.util.DoublyIndexedTable$Entry:DoublyIndexedTable$Entry 6682
    org.apache.batik.dom.util.DoublyIndexedTable:put org.apache.batik.dom.util.DoublyIndexedTable:hashCode 6693
    org.apache.batik.dom.AbstractElement:invalidateElementsByTagName org.apache.batik.dom.AbstractElement:getNodeType 7198
    org.apache.batik.dom.AbstractElement:invalidateElementsByTagName org.apache.batik.dom.AbstractDocument:getElementsByTagName 14396
    org.apache.batik.dom.AbstractElement:invalidateElementsByTagName org.apache.batik.dom.AbstractDocument:getElementsByTagNameNS 28792
    

    There are several graph rendering engines available. The simplest possible is DOT (please check the link, there are several other good tools listed).

    In order to use DOT I'll need to transform data a bit. Let's say I would like to keep ClassName:methodName and skip package.

    It is super easy, you can use any tool to do that, but I'll use sed:

    OUT=callgraph.dot
    echo "graph test {" > $OUT
    sed -E 's/[a-z]+\.//g; s/[0-9]+\/;/; s/ / -- /; s/[\$|\:]/_/g'  callgraph.txt >> $OUT
    echo "}" >> $OUT
    dot -Tpng callgraph.dot -o callgraph.png
    

    Here is generated result:

    graph test {
    AbstractParentNode_appendChild -- AbstractParentNode_fireDOMNodeInsertedEvent ;
    AbstractParentNode_fireDOMNodeInsertedEvent -- AbstractDocument_getEventsEnabled ;
    AbstractParentNode_checkAndRemove -- AbstractNode_getOwnerDocument ;
    DoublyIndexedTable_put -- DoublyIndexedTable_Entry_DoublyIndexedTable_Entry ;
    DoublyIndexedTable_put -- DoublyIndexedTable_hashCode ;
    AbstractElement_invalidateElementsByTagName -- AbstractElement_getNodeType ;
    AbstractElement_invalidateElementsByTagName -- AbstractDocument_getElementsByTagName ;
    AbstractElement_invalidateElementsByTagName -- AbstractDocument_getElementsByTagNameNS ;
    }
    

    DOT was pretty kind to render that into the following:

    enter image description here

    All graphs were extracted from the initial data:

    enter image description here

    Please note, you can tune rendering as you want. DOT is a part of graphviz which is quite a flexible set of tools.

    There is a general idea behind my answer:

    BTW, take a look at canviz

    Canviz is a JavaScript library for drawing Graphviz graphs to a web browser canvas. More technically, Canviz is a JavaScript xdot renderer. It works in most modern browsers.

    Happy coding :)