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?
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);
}
}
}