Search C++ call graph recursively for specific functions [closed]
-
21-12-2019 - |
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?
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.