The DWARF specification knows 3 kinds of non-empty simple location descriptions: 1. Register location descriptions - describe a variable in a register - consist of only a DW_OP_reg 2. Memory location descriptions - describe the address of a variable 3. Implicit location descriptions - describe the value of a variable - end with DW_OP_stack_value & friends The existing DwarfExpression code is pretty much ignorant of these restrictions. This used to not matter because we only emitted very short expressions that we happened to get right by accident. This patch makes DwarfExpression aware of the rules defined by the DWARF standard and now chooses the right kind of location description for each expression being emitted. This would have been an NFC commit (for the existing testsuite) if not for the way that clang describes captured block variables. Based on how the previous code in LLVM emitted locations, DW_OP_deref operations that should have come at the end of the expression are put at its beginning. Fixing this means changing the semantics of DIExpression, so this patch bumps the version number of DIExpression and implements a bitcode upgrade. There are two major changes in this patch: I had to fix the semantics of dbg.declare for describing function arguments. After this patch a dbg.declare always takes the *address* of a variable as the first argument, even if the argument is not an alloca. When lowering a DBG_VALUE, the decision of whether to emit a register location description or a memory location description depends on the MachineLocation — register machine locations may get promoted to memory locations based on their DIExpression. (Future) optimization passes that want to salvage implicit debug location for variables may do so by appending a DW_OP_stack_value. For example: DBG_VALUE, [RBP-8] --> DW_OP_fbreg -8 DBG_VALUE, RAX --> DW_OP_reg0 +0 DBG_VALUE, RAX, DIExpression(DW_OP_deref) --> DW_OP_reg0 +0 All testcases that were modified were regenerated from clang. I also added source-based testcases for each of these to the debuginfo-tests repository over the last week to make sure that no synchronized bugs slip in. The debuginfo-tests compile from source and run the debugger. https://bugs.llvm.org/show_bug.cgi?id=32382 <rdar://problem/31205000> Differential Revision: https://reviews.llvm.org/D31439 llvm-svn: 300522
83 lines
4.2 KiB
LLVM
83 lines
4.2 KiB
LLVM
; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
|
|
|
|
; Test debug location for the local variables moved onto the unsafe stack.
|
|
|
|
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
|
target triple = "x86_64-unknown-linux-gnu"
|
|
|
|
%struct.S = type { [100 x i8] }
|
|
|
|
; Function Attrs: safestack uwtable
|
|
define void @f(%struct.S* byval align 8 %zzz) #0 !dbg !12 {
|
|
; CHECK: define void @f
|
|
|
|
entry:
|
|
; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
|
|
|
|
%xxx = alloca %struct.S, align 1
|
|
call void @llvm.dbg.declare(metadata %struct.S* %zzz, metadata !18, metadata !19), !dbg !20
|
|
call void @llvm.dbg.declare(metadata %struct.S* %xxx, metadata !21, metadata !19), !dbg !22
|
|
|
|
; dbg.declare for %zzz and %xxx are gone; replaced with dbg.declare based off the unsafe stack pointer
|
|
; CHECK-NOT: call void @llvm.dbg.declare
|
|
; CHECK: call void @llvm.dbg.declare(metadata i8* %[[USP]], metadata ![[VAR_ARG:.*]], metadata ![[EXPR_ARG:.*]])
|
|
; CHECK-NOT: call void @llvm.dbg.declare
|
|
; CHECK: call void @llvm.dbg.declare(metadata i8* %[[USP]], metadata ![[VAR_LOCAL:.*]], metadata ![[EXPR_LOCAL:.*]])
|
|
; CHECK-NOT: call void @llvm.dbg.declare
|
|
|
|
call void @Capture(%struct.S* %zzz), !dbg !23
|
|
call void @Capture(%struct.S* %xxx), !dbg !24
|
|
|
|
; dbg.declare appears before the first use
|
|
; CHECK: call void @Capture
|
|
; CHECK: call void @Capture
|
|
|
|
ret void, !dbg !25
|
|
}
|
|
|
|
; CHECK-DAG: ![[VAR_ARG]] = !DILocalVariable(name: "zzz"
|
|
; 100 aligned up to 8
|
|
; CHECK-DAG: ![[EXPR_ARG]] = !DIExpression(DW_OP_minus, 104)
|
|
|
|
; CHECK-DAG: ![[VAR_LOCAL]] = !DILocalVariable(name: "xxx"
|
|
; CHECK-DAG: ![[EXPR_LOCAL]] = !DIExpression(DW_OP_minus, 208)
|
|
|
|
; Function Attrs: nounwind readnone
|
|
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
|
|
|
|
declare void @Capture(%struct.S*) #2
|
|
|
|
attributes #0 = { safestack uwtable "disable-tail-calls"="false" "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" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
|
attributes #1 = { nounwind readnone }
|
|
attributes #2 = { "disable-tail-calls"="false" "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" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
|
|
|
!llvm.dbg.cu = !{!0}
|
|
!llvm.module.flags = !{!15, !16}
|
|
!llvm.ident = !{!17}
|
|
|
|
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 254019) (llvm/trunk 254036)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3)
|
|
!1 = !DIFile(filename: "../llvm/2.cc", directory: "/code/build-llvm")
|
|
!2 = !{}
|
|
!3 = !{!4}
|
|
!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !1, line: 4, size: 800, align: 8, elements: !5, identifier: "_ZTS1S")
|
|
!5 = !{!6}
|
|
!6 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !4, file: !1, line: 5, baseType: !7, size: 800, align: 8)
|
|
!7 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 800, align: 8, elements: !9)
|
|
!8 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
|
|
!9 = !{!10}
|
|
!10 = !DISubrange(count: 100)
|
|
!12 = distinct !DISubprogram(name: "f", linkageName: "_Z1f1S", scope: !1, file: !1, line: 10, type: !13, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
|
|
!13 = !DISubroutineType(types: !14)
|
|
!14 = !{null, !4}
|
|
!15 = !{i32 2, !"Dwarf Version", i32 4}
|
|
!16 = !{i32 2, !"Debug Info Version", i32 3}
|
|
!17 = !{!"clang version 3.8.0 (trunk 254019) (llvm/trunk 254036)"}
|
|
!18 = !DILocalVariable(name: "zzz", arg: 1, scope: !12, file: !1, line: 10, type: !4)
|
|
!19 = !DIExpression()
|
|
!20 = !DILocation(line: 10, column: 10, scope: !12)
|
|
!21 = !DILocalVariable(name: "xxx", scope: !12, file: !1, line: 11, type: !4)
|
|
!22 = !DILocation(line: 11, column: 5, scope: !12)
|
|
!23 = !DILocation(line: 12, column: 3, scope: !12)
|
|
!24 = !DILocation(line: 13, column: 3, scope: !12)
|
|
!25 = !DILocation(line: 14, column: 1, scope: !12)
|