2016-01-03 67 views
5

目前我正在研究一種工具,該工具可識別任意程序上的全局變量和字段變量的加載和存儲訪問。此外,訪問的變量應該由它們的源級別名稱/標識符來標識。 爲了做到這一點,我將診斷下的程序的源代碼編譯爲帶有調試信息的LLVM IR。到目前爲止,生成的元數據節點包含所需的源級別標識符。但是,我無法連接到某些LLVM IR標識符和元數據中的信息。LLVM IR:用元數據節點識別變量

例如,考慮一類的satic成員:

class TestClass { 
    public: 
    static int Number; 
}; 

相應的LLVM IR看起來是這樣的:

@_ZN12TestClass6NumberE = external global i32, align 4 

... 
!15 = !DIDerivedType(tag: DW_TAG_member, name: "Number", scope: !"_ZTS12TestClass", file: !12, line: 5, baseType: !16, flags: DIFlagPublic | DIFlagStaticMember) 

在此控制例子中,我知道, 「@ _ZN12TestClass6NumberE」 是「號碼」的標識符。但是,一般來說,我看不出如何找出哪些IR標識符對應於哪些元數據。

有人可以幫我嗎?

回答

1

由於沒有人似乎有一個很好的解決我的問題,我會告訴我自己不方便處理這個問題。 LLVM生成的元數據節點包含有關代碼的已定義類型和變量的信息。但是,沒有關於哪些生成的IR變量與哪些源代碼變量相對應的信息。 LLVM僅將IR指令的元數據信息與對應的源位置(行和列)相鏈接。這是有道理的,因爲LLVM元數據的主要任務不是分析而是調試。

儘管如此,包含的信息並不是無用的。我對這個問題的解決方案是使用clang AST來分析源代碼。這裏我們獲得關於哪個變量訪問哪個源位置的信息。因此,爲了在LLVM IR檢測期間獲得關於源變量身份的信息,我們只需要在叮噹AST分析期間將源位置映射到源變量標識。作爲第二步,我們使用之前收集的信息執行IR儀器。當我們在IR中遇到存儲或加載指令時,我們在此指令的元數據節點中搜索其相應的源位置。由於我們已將源位置映射到源變量標識,因此我們現在可以輕鬆訪問IR指令的源變量標識。

那麼,爲什麼我不只是使用clang AST來識別商店和加載變量?因爲區分AST中的讀取和寫入不是一項簡單的任務。 AST可以很容易地告訴你一個變量被訪問,但是它取決於訪問的變量是被讀取還是被寫入的操作。所以,我將不得不考慮每一個操作/操作符來確定變量是寫/讀還是兩者。 LLVM在這方面更簡單,更低級,因此不易出錯。此外,AST中的實際插裝(演講代碼插入)與LLVM相比要困難得多。由於這兩個原因,我相信叮噹AST和LLVM IR儀器的組合是解決我的問題的最佳解決方案。