我想知道从C源文件解析和获取数据结构的最佳解决方案是什么。假设我有:
typedef int M_Int;
typedef float* P_Float;
typedef struct Foo {
M_Int a;
P_Float p_f;
} Foo;
展开数据结构以获取struct a
的变量p_f
和Foo
的基元的最佳方法是什么?
对于非常简单的示例,解析AST可能是最好的方法,但是当代码变得更复杂时,使用IR代码以更低级别的方式工作可能更好吗?
答案 0 :(得分:0)
您可以使用llvm调试信息来获取所需的信息。如果使用-g
选项编译C代码,它将生成包含所有信息的调试信息。理解llvm debuginfo很棘手,主要是因为没有太多关于它们的结构以及如何访问它们的文档。以下是一些链接:
1)http://llvm.org/docs/SourceLevelDebugging.html
2)这是我正在使用调试信息的项目的链接。这可能不太有用,因为没有太多文档但是查看debuginfo类的用法可能会有用。我们试图获得C函数的所有指针参数(包括结构参数的字段名称)的字段名称。与debuginfo访问相关的所有代码都在此文件中:https://github.com/jiten-thakkar/DataStructureAnalysis/blob/dsa_llvm3.8/lib/dsaGenerator/DSAGenerator.cpp
答案 1 :(得分:0)
要查找基础类型,AST是一个很好的工作级别。 Clang可以使用AST Matchers和Callbacks自动化和扩展这个过程,与libtooling一起使用。例如,AST匹配器组合
bind()
将匹配使用typedef而不是内置类型声明的C结构中的字段。 run()
调用使AST节点可以被回调访问。这是一个回调,其virtual void run(clang::ast_matchers::MatchFinder::MatchResult const & result) override
{
using namespace clang;
FieldDecl * f_decl =
const_cast<FieldDecl *>(result.Nodes.getNodeAs<FieldDecl>("field"));
TypedefType * tt = const_cast<TypedefType *>(
result.Nodes.getNodeAs<TypedefType>("typedef"));
if(f_decl && tt) {
QualType ut = tt->getDecl()->getUnderlyingType();
TypedefNameDecl * tnd = tt->getDecl();
std::string struct_name = f_decl->getParent()->getNameAsString();
std::string fld_name = f_decl->getNameAsString();
std::string ut_name = ut.getAsString();
std::string tnd_name = tnd->getNameAsString();
std::cout << "Struct '" << struct_name << "' declares field '"
<< fld_name << " with typedef name = '" << tnd_name << "'"
<< ", underlying type = '" << ut_name << "'" << std::endl;
}
else {
// error handling
}
return;
} // run
方法获取字段声明的基础类型:
typedef-report Foo.h -- # Note two dashes
将其放入Clang工具并构建,运行
Struct 'Foo' declares field 'a' with typedef name = 'M_Int', underlying type = 'int'
Struct 'Foo' declares field 'p_f' with typedef name = 'P_Float', underlying type = 'float *'
产生
groupBy
我在Code Analysis and Refactoring Examples with Clang Tools project中设置了一个完整的工作示例应用(请参阅apps / TypedefFinder.cc)。