Correctly handle complex locations expressions in replaceDbgDeclareForAlloca()
authorFrederic Riss <friss@apple.com>
Tue, 9 Dec 2014 17:55:48 +0000 (17:55 +0000)
committerFrederic Riss <friss@apple.com>
Tue, 9 Dec 2014 17:55:48 +0000 (17:55 +0000)
replaceDbgDeclareForAlloca() replaces an alloca by a value storing the
address of what was the alloca. If there is a dbg.declare corresponding
to that alloca, we need to lower it to a dbg.value describing the additional
dereference operation to be performed to get to the underlying variable.
 This is done by adding a DW_OP_deref to the complex location part of the
location description. This deref was added to the end of the operation list,
which is wrong. The expression applies to what is described by the
dbg.{declare,value}, and as we are changing this, we need to apply the
DW_OP_deref as the first operation in the list.

Part of the fix for rdar://19162268.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@223799 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Utils/Local.cpp
test/DebugInfo/block-asan.ll [new file with mode: 0644]

index c963c51ec63847a360d1c9e469a919133ca58afc..f8f62a9273d533411e6365afbbcc50056001332f 100644 (file)
@@ -1111,7 +1111,7 @@ bool llvm::replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress,
   if (!DIVar)
     return false;
 
-  // Create a copy of the original DIDescriptor for user variable, appending
+  // Create a copy of the original DIDescriptor for user variable, prepending
   // "deref" operation to a list of address elements, as new llvm.dbg.declare
   // will take a value storing address of the memory for variable, not
   // alloca itself.
@@ -1121,7 +1121,7 @@ bool llvm::replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress,
       NewDIExpr.push_back(DIExpr.getElement(i));
     }
   }
-  NewDIExpr.push_back(dwarf::DW_OP_deref);
+  NewDIExpr.insert(NewDIExpr.begin(), dwarf::DW_OP_deref);
 
   // Insert llvm.dbg.declare in the same basic block as the original alloca,
   // and remove old llvm.dbg.declare.
diff --git a/test/DebugInfo/block-asan.ll b/test/DebugInfo/block-asan.ll
new file mode 100644 (file)
index 0000000..43f9e7f
--- /dev/null
@@ -0,0 +1,87 @@
+; RUN: opt -S -asan %s | FileCheck %s
+
+; The IR of this testcase is generated from the following C code:
+; void bar (int);
+;
+; void foo() {
+;   __block int x;
+;   bar(x);
+; }
+; by compiling it with 'clang -emit-llvm -g -S' and then by manually
+; adding the sanitize_address attribute to the @foo() function (so
+; that ASAN accepts to instrument the function in the above opt run).
+
+; Check that the location of the ASAN instrumented __block variable is
+; correct.
+; CHECK: [ DW_TAG_expression ] [DW_OP_deref] [DW_OP_plus 8] [DW_OP_deref] [DW_OP_plus 24]
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.__block_byref_x = type { i8*, %struct.__block_byref_x*, i32, i32, i32 }
+
+; Function Attrs: nounwind ssp uwtable
+define void @foo() #0 {
+entry:
+  %x = alloca %struct.__block_byref_x, align 8
+  call void @llvm.dbg.declare(metadata !{%struct.__block_byref_x* %x}, metadata !12, metadata !22), !dbg !23
+  %byref.isa = getelementptr inbounds %struct.__block_byref_x* %x, i32 0, i32 0, !dbg !24
+  store i8* null, i8** %byref.isa, !dbg !24
+  %byref.forwarding = getelementptr inbounds %struct.__block_byref_x* %x, i32 0, i32 1, !dbg !24
+  store %struct.__block_byref_x* %x, %struct.__block_byref_x** %byref.forwarding, !dbg !24
+  %byref.flags = getelementptr inbounds %struct.__block_byref_x* %x, i32 0, i32 2, !dbg !24
+  store i32 0, i32* %byref.flags, !dbg !24
+  %byref.size = getelementptr inbounds %struct.__block_byref_x* %x, i32 0, i32 3, !dbg !24
+  store i32 32, i32* %byref.size, !dbg !24
+  %forwarding = getelementptr inbounds %struct.__block_byref_x* %x, i32 0, i32 1, !dbg !25
+  %0 = load %struct.__block_byref_x** %forwarding, !dbg !25
+  %x1 = getelementptr inbounds %struct.__block_byref_x* %0, i32 0, i32 4, !dbg !25
+  %1 = load i32* %x1, align 4, !dbg !25
+  call void @bar(i32 %1), !dbg !25
+  %2 = bitcast %struct.__block_byref_x* %x to i8*, !dbg !26
+  call void @_Block_object_dispose(i8* %2, i32 8) #3, !dbg !26
+  ret void, !dbg !26
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+declare void @bar(i32) #2
+
+declare void @_Block_object_dispose(i8*, i32)
+
+attributes #0 = { nounwind ssp uwtable sanitize_address "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!8, !9, !10}
+!llvm.ident = !{!11}
+
+!0 = metadata !{metadata !"0x11\0012\00clang version 3.6.0 (trunk 223120) (llvm/trunk 223119)\000\00\000\00\001", metadata !1, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2} ; [ DW_TAG_compile_unit ] [/tmp/block.c] [DW_LANG_C99]
+!1 = metadata !{metadata !"block.c", metadata !"/tmp"}
+!2 = metadata !{}
+!3 = metadata !{metadata !4}
+!4 = metadata !{metadata !"0x2e\00foo\00foo\00\003\000\001\000\000\000\000\003", metadata !1, metadata !5, metadata !6, null, void ()* @foo, null, null, metadata !2} ; [ DW_TAG_subprogram ] [line 3] [def] [foo]
+!5 = metadata !{metadata !"0x29", metadata !1}    ; [ DW_TAG_file_type ] [/tmp/block.c]
+!6 = metadata !{metadata !"0x15\00\000\000\000\000\000\000", null, null, null, metadata !7, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!7 = metadata !{null}
+!8 = metadata !{i32 2, metadata !"Dwarf Version", i32 2}
+!9 = metadata !{i32 2, metadata !"Debug Info Version", i32 2}
+!10 = metadata !{i32 1, metadata !"PIC Level", i32 2}
+!11 = metadata !{metadata !"clang version 3.6.0 (trunk 223120) (llvm/trunk 223119)"}
+!12 = metadata !{metadata !"0x100\00x\004\000", metadata !4, metadata !5, metadata !13} ; [ DW_TAG_auto_variable ] [x] [line 4]
+!13 = metadata !{metadata !"0x13\00\000\00224\000\000\0016\000", metadata !1, metadata !5, null, metadata !14, null, null, null} ; [ DW_TAG_structure_type ] [line 0, size 224, align 0, offset 0] [def] [from ]
+!14 = metadata !{metadata !15, metadata !17, metadata !18, metadata !20, metadata !21}
+!15 = metadata !{metadata !"0xd\00__isa\000\0064\0064\000\000", metadata !1, metadata !5, metadata !16} ; [ DW_TAG_member ] [__isa] [line 0, size 64, align 64, offset 0] [from ]
+!16 = metadata !{metadata !"0xf\00\000\0064\0064\000\000", null, null, null} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ]
+!17 = metadata !{metadata !"0xd\00__forwarding\000\0064\0064\0064\000", metadata !1, metadata !5, metadata !16} ; [ DW_TAG_member ] [__forwarding] [line 0, size 64, align 64, offset 64] [from ]
+!18 = metadata !{metadata !"0xd\00__flags\000\0032\0032\00128\000", metadata !1, metadata !5, metadata !19} ; [ DW_TAG_member ] [__flags] [line 0, size 32, align 32, offset 128] [from int]
+!19 = metadata !{metadata !"0x24\00int\000\0032\0032\000\000\005", null, null} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
+!20 = metadata !{metadata !"0xd\00__size\000\0032\0032\00160\000", metadata !1, metadata !5, metadata !19} ; [ DW_TAG_member ] [__size] [line 0, size 32, align 32, offset 160] [from int]
+!21 = metadata !{metadata !"0xd\00x\000\0032\0032\00192\000", metadata !1, metadata !5, metadata !19} ; [ DW_TAG_member ] [x] [line 0, size 32, align 32, offset 192] [from int]
+!22 = metadata !{metadata !"0x102\0034\008\006\0034\0024"} ; [ DW_TAG_expression ] [DW_OP_plus 8] [DW_OP_deref] [DW_OP_plus 24]
+!23 = metadata !{i32 4, i32 15, metadata !4, null}
+!24 = metadata !{i32 4, i32 3, metadata !4, null}
+!25 = metadata !{i32 5, i32 3, metadata !4, null}
+!26 = metadata !{i32 6, i32 1, metadata !4, null}