Domanda

I have a large C/C++ project where I would like to analyse the call graph for a subset of functions.

Ex for something like:

void A_Func1(){}
void A_Func2(){}

void IntermediateFunc()
{
  A_Func1();
  A_Func2();
}

void StartFunc()
{
  IntermediateFunc();
}

I would like to get the list of functions that starts with "A_" called directly or indirectly from StartFunc.

My first thought was using clang which has the CallGraph action, but the documentation is sparse and I am slowly getting to the conclusion that I cannot use it how I want.

So the question: How do I use clangs tooling libraries to perform generate such a list?

È stato utile?

Soluzione 2

I find the answer from polkovnikov.ph to be the cleaner method of doing this. I wasn't aware that the .dot is so simple, and I will definitely use that way for similar problems.

Unfortunately I also have to analyse software components where the interface to other components are C functions - which are used through the extern keyword. They do not show up in the clang call graph because of an internal filter (includeInGraph (const Decl *D)) in clang::CallGraph.

So I had to copy clang::CallGraph, remove the limitation and use it in an clang::ASTConsumer like:

virtual void HandleTranslationUnit(clang::ASTContext &Context) {
    _visitor.TraverseDecl(Context.getTranslationUnitDecl());
    for (auto root : _visitor)
    {
        if (const clang::NamedDecl* namedDecl = llvm::dyn_cast_or_null<clang::NamedDecl>(root.first))
            if(namedDecl->getIdentifier() != nullptr && namedDecl->getIdentifier()->getName().startswith("Start"))
            {
                llvm::outs() << "StartFunc: " << namedDecl->getName() << "\n";
                printAFunctions(root.second);
            }
    }
}
void printAFunctions(const clang::CallGraphNode* node)
{
    if (node != nullptr)
    {
        if (const clang::NamedDecl* namedDecl = llvm::dyn_cast_or_null<clang::NamedDecl>(node->getDecl()))
        {
            if (namedDecl->getName().startswith("A_"))
            {
                llvm::outs() << "A_ call: " << namedDecl->getName() << "\n";
            }
        }
        for (auto subNode : *node)
        {
            printAFunctions(subNode);
        }
    }
}

Altri suggerimenti

Clang outputs .dot file for it's callgraph. It's quite a simple format that can be easily parsed with a tool like PEG.js. When you get the call DAG, you can run a simple DFS, that marks all the nodes with A_ prefix on it.

The other solution is to use Clang's codebase to do it yourself. As you could already find out, it's quite an involved approach.

Also, you should be aware that clang generates an optimistic call graph, i.e. "what functions could be called". For example, void f() { if (g()) h(); } "calls" both g and h, even if bool g() { return false; }.

Possibly, you're looking for "all functions that are really called from there". Then you need to run some profiler to gather the call stacks.

The best solution would be to make a debugger script for some IDE, but I'm not aware of any IDE for C++ that have such option.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top