2017-02-10 61 views
1

我想知道什麼是解析和從C源文件中獲取數據結構的最佳解決方案。假設我有:解析數據結構clang/LLVM

typedef int M_Int; 
typedef float* P_Float; 

typedef struct Foo { 
    M_Int a; 
    P_Float p_f; 
} Foo; 

什麼是展開爲了得到這兩個變量a和struct Foop_f的元數據結構的最佳方式是什麼?

對於非常簡單的例子,解析AST可能是最好的方法,但是當代碼變得更復雜時,或許用IR代碼以更低級的方式工作會更好?

回答

0

您可以使用llvm調試信息來獲取所需的信息。如果使用-g選項編譯C代碼,它將生成包含所有信息的調試信息。理解llvm調試信息很棘手,主要是因爲沒有太多關於它們結構的文檔以及如何訪問它們。這裏有一些鏈接:

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

0

要查找基礎類型,AST是一個很好的工作級別。 Clang可以使用AST Matchers和Callbacks自動執行和擴展此過程,並與libtooling結合使用。例如,AST匹配組合

fieldDecl(hasType(tyoedefType().bind("typedef"))).bind("field") 

將匹配被聲明與一個typedef代替C結構域內置型。調用bind()使AST節點可以訪問回調。這裏有一個回調,其run()方法獲取基礎類型的字段聲明:

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 

一旦被放入Clang的工具和內置,運行

typedef-report Foo.h -- # Note two dashes 

產生

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 *' 

我在Code Analysis and Refactoring Examples with Clang Tools project中放置了一個完整的工作示例應用程序(請參閱apps/TypedefFinder.cc)。