我有以下代码:
int main(int argc, char *argv[])
{
int a = 2;
int b = 5;
int soma = a + b;
//...}
产生的llvm bitcode是:
define i32 @main(i32 %argc, i8** %argv) #0 {
entry:
...
%a = alloca i32, align 4
%b = alloca i32, align 4
%soma = alloca i32, align 4
...
call void @llvm.dbg.declare(metadata !{i32* %a}, metadata !15), !dbg !16
store i32 2, i32* %a, align 4, !dbg !16
call void @llvm.dbg.declare(metadata !{i32* %b}, metadata !17), !dbg !18
store i32 5, i32* %b, align 4, !dbg !18
call void @llvm.dbg.declare(metadata !{i32* %soma}, metadata !19), !dbg !20
%0 = load i32* %a, align 4, !dbg !20
%1 = load i32* %b, align 4, !dbg !20
%add = add nsw i32 %0, %1, !dbg !20
store i32 %add, i32* %soma, align 4, !dbg !20
...
!1 = metadata !{i32 0}
!2 = metadata !{metadata !3}
...
!15 = metadata !{i32 786688, metadata !3, metadata !"a", metadata !4, i32 6, metadata !7, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [a] [line 6]
!16 = metadata !{i32 6, i32 0, metadata !3, null}
!17 = metadata !{i32 786688, metadata !3, metadata !"b", metadata !4, i32 7, metadata !7, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [b] [line 7]
!18 = metadata !{i32 7, i32 0, metadata !3, null}
!19 = metadata !{i32 786688, metadata !3, metadata !"soma", metadata !4, i32 8, metadata !7, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [soma] [line 8]
!20 = metadata !{i32 8, i32 0, metadata !3, null}
从bitcode我需要得到以下文字:
a = 2
b = 5
soma = a + b
我怀疑如何从元数据中提取我需要的信息(dgb)?
现在我只有I-> getName ()
指令的名称和valueOp Value * = I-> getOperand (i); valueOp-> getName (). Str ();
操作数的名称
元数据非常广泛。如何从元数据中获取此信息?
答案 0 :(得分:2)
依靠I->getName()
查找变量名称不是一个好主意 - 您有调试信息。找出所有C / C ++局部变量名称的正确方法是遍历IR并查找对@llvm.dbg.declare
的所有调用,然后转到第二个操作数(调试元数据),并检索变量名称从那里。
使用source-level debugging guide了解调试元数据的布局方式。特别是for local variables, the 3rd argument will be a metadata string with the variable name in the C/C++ source。
剩下的就是找出变量初始化的内容。为此,按照@llvm.dbg.declare
的第一个参数获取实际使用的LLVM值,然后找到第一个store
指令,并检查那里使用的数据。
如果它是常量,那么现在您拥有输出a = 5
- 样式信息所需的一切。如果它是另一条指令,你必须自己跟踪它并“解码”它 - 例如,如果它是一个“添加”,那么你需要打印它的两个操作数,中间有一个“+”等等。当然还有打印必须是递归的...不简单。但它会为您提供准确的初始化值。
如果您正在寻找更粗略的东西并且您可以访问原始源,您可以获取声明变量的行号(调试元数据中的第5个操作数,假设标记(第1个)确实是DW_TAG_auto_variable
而不是DW_TAG_arg_variable
,它表示一个参数)。然后从原始来源打印出该行。但是这不会打印所有相关信息(如果初始化值是由多行构成的),并且可以打印不相关的信息(例如,如果该行中有多个语句)。
最后,记住优化可以严重搞砸调试信息。如果获取这些打印输出非常重要,请谨慎使用-O
选项,也可以坚持使用-O0
。