Summary: This is a follow-up to D57510. This patch stops DebugHandlerBase from changing the starting label for the first non-overlapping, register-described parameter DBG_VALUEs to the beginning of the function. That code did not consider what defined the registers, which could result in the ranges for the debug values starting before their defining instructions. We currently do not emit debug values for constant values directly at the start of the function, so this code is still useful for such values, but my intention is to remove the code from DebugHandlerBase completely when we get there. One reason for removing it is that the code violates the history map's ranges, which I think can make it quite confusing when troubleshooting. In D57510, PrologEpilogInserter was amended so that parameter DBG_VALUEs now are kept at the start of the entry block, even after emission of prologue code. That was done to reduce the degradation of debug completeness from this patch. PR40638 is another example, where the lexical-scope trimming that LDV does, in combination with scheduling, results in instructions after the prologue being left without locations. There might be other cases where the DBG_VALUEs are pushed further down, for which the DebugHandlerBase code may be helpful, but as it now quite often result in incorrect locations, even after the prologue, it seems better to remove that code, and try to work our way up with accurate locations. In the long run we should maybe not aim to provide accurate locations inside the prologue. Some single location descriptions, at least those referring to stack values, generate inaccurate values inside the epilogue, so we maybe should not aim to achieve accuracy for location lists. However, it seems that we now emit line number programs that can result in GDB and LLDB stopping inside the prologue when doing line number stepping into functions. See PR40188 for more information. A summary of some of the changed test cases is available in PR40188#c2. Reviewers: aprantl, dblaikie, rnk, jmorse Reviewed By: aprantl Subscribers: jdoerfert, jholewinski, jvesely, javed.absar, llvm-commits Tags: #debug-info, #llvm Differential Revision: https://reviews.llvm.org/D57511 llvm-svn: 353928
277 lines
13 KiB
YAML
277 lines
13 KiB
YAML
# RUN: llc -o - %s -start-after=patchable-function -filetype=obj -O0 -mtriple=i386-unknown-linux-gnu -dwarf-version=4 | llvm-dwarfdump -v - | FileCheck %s
|
|
|
|
# From the code:
|
|
#
|
|
# debug-loc-offset1.cc
|
|
# int bar (int b) {
|
|
# return b+4;
|
|
# }
|
|
#
|
|
# debug-loc-offset2.cc
|
|
# struct A {
|
|
# int var;
|
|
# virtual char foo();
|
|
# };
|
|
#
|
|
# void baz(struct A a) {
|
|
# int z = 2;
|
|
# if (a.var > 2)
|
|
# z++;
|
|
# if (a.foo() == 'a')
|
|
# z++;
|
|
# }
|
|
#
|
|
# Compiled separately for i386-pc-linux-gnu and linked together.
|
|
# This ensures that we have multiple compile units and multiple location lists
|
|
# so that we can verify that
|
|
# debug_loc entries are relative to the low_pc of the CU. The loc entry for
|
|
# the byval argument in foo.cpp is in the second CU and so should have
|
|
# an offset relative to that CU rather than from the beginning of the text
|
|
# section.
|
|
#
|
|
# Checking that we have two compile units with two sets of high/lo_pc.
|
|
# CHECK: .debug_info contents
|
|
# CHECK: DW_TAG_compile_unit
|
|
# CHECK: DW_AT_low_pc {{.*}} (0x0000000000000020 ".text")
|
|
# CHECK: DW_AT_high_pc
|
|
#
|
|
# CHECK: DW_TAG_subprogram
|
|
# CHECK-NOT: DW_TAG
|
|
# CHECK: DW_AT_linkage_name [DW_FORM_strp]{{.*}}"_Z3baz1A"
|
|
# CHECK-NOT: {{DW_TAG|NULL}}
|
|
# CHECK: DW_TAG_formal_parameter
|
|
# CHECK-NOT: DW_TAG
|
|
# CHECK: DW_AT_location [DW_FORM_sec_offset] ({{.*}}
|
|
# CHECK-NEXT: [0x00000029, 0x00000037): DW_OP_breg0 EAX+0, DW_OP_deref
|
|
# CHECK-NEXT: [0x00000037, 0x00000063): DW_OP_breg5 EBP-8, DW_OP_deref, DW_OP_deref
|
|
# CHECK-NEXT: DW_AT_name [DW_FORM_strp]{{.*}}"a"
|
|
#
|
|
# CHECK: DW_TAG_variable
|
|
# CHECK: DW_AT_location [DW_FORM_exprloc]
|
|
# CHECK-NOT: DW_AT_location
|
|
#
|
|
# CHECK: DW_TAG_compile_unit
|
|
# CHECK: DW_AT_low_pc {{.*}} (0x0000000000000000 ".text")
|
|
# CHECK: DW_AT_high_pc
|
|
#
|
|
# CHECK: DW_TAG_subprogram
|
|
# CHECK-NOT: DW_TAG
|
|
# CHECK: DW_AT_linkage_name [DW_FORM_strp]{{.*}}"_Z3bari"
|
|
# CHECK-NOT: {{DW_TAG|NULL}}
|
|
# CHECK: DW_TAG_formal_parameter
|
|
# CHECK-NOT: DW_TAG
|
|
# CHECK: DW_AT_location [DW_FORM_sec_offset] ({{.*}}
|
|
# CHECK-NEXT: [0x00000000, 0x0000000a): DW_OP_consts +0, DW_OP_stack_value
|
|
# CHECK-NEXT: [0x0000000a, 0x00000017): DW_OP_consts +1, DW_OP_stack_value)
|
|
# CHECK-NEXT: DW_AT_name [DW_FORM_strp]{{.*}}"b"
|
|
#
|
|
# CHECK: .debug_loc contents:
|
|
# CHECK: 0x00000000:
|
|
# CHECK-NEXT: [0x00000000, 0x0000000a): DW_OP_consts +0, DW_OP_stack_value
|
|
# CHECK-NEXT: [0x0000000a, 0x00000017): DW_OP_consts +1, DW_OP_stack_value
|
|
# CHECK: 0x00000022:
|
|
# CHECK-NEXT: [0x00000009, 0x00000017): DW_OP_breg0 EAX+0, DW_OP_deref
|
|
# CHECK-NEXT: [0x00000017, 0x00000043): DW_OP_breg5 EBP-8, DW_OP_deref, DW_OP_deref
|
|
--- |
|
|
target triple = "i386-unknown-linux-gnu"
|
|
|
|
%struct.A = type { i32 (...)**, i32 }
|
|
|
|
; Function Attrs: nounwind
|
|
define i32 @_Z3bari(i32 %b) #0 !dbg !10 {
|
|
entry:
|
|
%b.addr = alloca i32, align 4
|
|
store i32 %b, i32* %b.addr, align 4
|
|
call void @llvm.dbg.value(metadata i32 0, metadata !14, metadata !DIExpression()), !dbg !15
|
|
%0 = load i32, i32* %b.addr, align 4, !dbg !16
|
|
call void @llvm.dbg.value(metadata i32 1, metadata !14, metadata !DIExpression()), !dbg !15
|
|
%add = add nsw i32 %0, 4, !dbg !16
|
|
ret i32 %add, !dbg !16
|
|
}
|
|
|
|
; Function Attrs: nounwind readnone speculatable
|
|
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
|
|
|
|
; Function Attrs: nounwind readnone speculatable
|
|
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
|
|
|
|
define void @_Z3baz1A(%struct.A* %a) #2 !dbg !17 {
|
|
entry:
|
|
%z = alloca i32, align 4
|
|
call void @llvm.dbg.declare(metadata %struct.A* %a, metadata !20, metadata !DIExpression(DW_OP_deref)), !dbg !21
|
|
call void @llvm.dbg.declare(metadata i32* %z, metadata !22, metadata !DIExpression()), !dbg !23
|
|
store i32 2, i32* %z, align 4, !dbg !23
|
|
%var = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 1, !dbg !24
|
|
%0 = load i32, i32* %var, align 4, !dbg !24
|
|
%cmp = icmp sgt i32 %0, 2, !dbg !24
|
|
br i1 %cmp, label %if.then, label %if.end, !dbg !24
|
|
|
|
if.then: ; preds = %entry
|
|
%1 = load i32, i32* %z, align 4, !dbg !26
|
|
%inc = add nsw i32 %1, 1, !dbg !26
|
|
store i32 %inc, i32* %z, align 4, !dbg !26
|
|
br label %if.end, !dbg !26
|
|
|
|
if.end: ; preds = %if.then, %entry
|
|
%call = call signext i8 @_ZN1A3fooEv(%struct.A* %a), !dbg !27
|
|
%conv = sext i8 %call to i32, !dbg !27
|
|
%cmp1 = icmp eq i32 %conv, 97, !dbg !27
|
|
br i1 %cmp1, label %if.then2, label %if.end4, !dbg !27
|
|
|
|
if.then2: ; preds = %if.end
|
|
%2 = load i32, i32* %z, align 4, !dbg !29
|
|
%inc3 = add nsw i32 %2, 1, !dbg !29
|
|
store i32 %inc3, i32* %z, align 4, !dbg !29
|
|
br label %if.end4, !dbg !29
|
|
|
|
if.end4: ; preds = %if.then2, %if.end
|
|
ret void, !dbg !30
|
|
}
|
|
|
|
declare signext i8 @_ZN1A3fooEv(%struct.A*) #2
|
|
|
|
; Function Attrs: nounwind
|
|
declare void @llvm.stackprotector(i8*, i8**) #3
|
|
|
|
attributes #0 = { nounwind "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 speculatable }
|
|
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, !3}
|
|
!llvm.module.flags = !{!7, !8}
|
|
!llvm.ident = !{!9, !9}
|
|
|
|
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.5.0 (210479)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
|
|
!1 = !DIFile(filename: "debug-loc-offset1.cc", directory: "/llvm_cmake_gcc")
|
|
!2 = !{}
|
|
!3 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !4, producer: "clang version 3.5.0 (210479)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !5, globals: !2, imports: !2)
|
|
!4 = !DIFile(filename: "debug-loc-offset2.cc", directory: "/llvm_cmake_gcc")
|
|
!5 = !{!6}
|
|
!6 = !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !4, line: 1, flags: DIFlagFwdDecl, identifier: "_ZTS1A")
|
|
!7 = !{i32 2, !"Dwarf Version", i32 4}
|
|
!8 = !{i32 2, !"Debug Info Version", i32 3}
|
|
!9 = !{!"clang version 3.5.0 (210479)"}
|
|
!10 = distinct !DISubprogram(name: "bar", linkageName: "_Z3bari", scope: !1, file: !1, line: 1, type: !11, isLocal: false, isDefinition: true, scopeLine: 1, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
|
|
!11 = !DISubroutineType(types: !12)
|
|
!12 = !{!13, !13}
|
|
!13 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
|
|
!14 = !DILocalVariable(name: "b", arg: 1, scope: !10, file: !1, line: 1, type: !13)
|
|
!15 = !DILocation(line: 1, scope: !10)
|
|
!16 = !DILocation(line: 2, scope: !10)
|
|
!17 = distinct !DISubprogram(name: "baz", linkageName: "_Z3baz1A", scope: !4, file: !4, line: 6, type: !18, isLocal: false, isDefinition: true, scopeLine: 6, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !3, retainedNodes: !2)
|
|
!18 = !DISubroutineType(types: !19)
|
|
!19 = !{null, !6}
|
|
!20 = !DILocalVariable(name: "a", arg: 1, scope: !17, file: !4, line: 6, type: !6)
|
|
!21 = !DILocation(line: 6, scope: !17)
|
|
!22 = !DILocalVariable(name: "z", scope: !17, file: !4, line: 7, type: !13)
|
|
!23 = !DILocation(line: 7, scope: !17)
|
|
!24 = !DILocation(line: 8, scope: !25)
|
|
!25 = distinct !DILexicalBlock(scope: !17, file: !4, line: 8)
|
|
!26 = !DILocation(line: 9, scope: !25)
|
|
!27 = !DILocation(line: 10, scope: !28)
|
|
!28 = distinct !DILexicalBlock(scope: !17, file: !4, line: 10)
|
|
!29 = !DILocation(line: 11, scope: !28)
|
|
!30 = !DILocation(line: 12, scope: !17)
|
|
|
|
...
|
|
---
|
|
name: _Z3bari
|
|
alignment: 4
|
|
tracksRegLiveness: true
|
|
frameInfo:
|
|
stackSize: 8
|
|
offsetAdjustment: -4
|
|
maxAlignment: 4
|
|
maxCallFrameSize: 0
|
|
fixedStack:
|
|
- { id: 0, type: spill-slot, offset: -8, size: 4, alignment: 8, stack-id: 0 }
|
|
- { id: 1, size: 4, alignment: 16, stack-id: 0 }
|
|
stack:
|
|
- { id: 0, type: spill-slot, offset: -12, size: 4, alignment: 4, stack-id: 0 }
|
|
body: |
|
|
bb.0.entry:
|
|
frame-setup PUSH32r killed $ebp, implicit-def $esp, implicit $esp
|
|
CFI_INSTRUCTION def_cfa_offset 8
|
|
CFI_INSTRUCTION offset $ebp, -8
|
|
$ebp = frame-setup MOV32rr $esp
|
|
CFI_INSTRUCTION def_cfa_register $ebp
|
|
frame-setup PUSH32r undef $eax, implicit-def $esp, implicit $esp
|
|
renamable $eax = MOV32rm $ebp, 1, $noreg, 8, $noreg :: (load 4 from %fixed-stack.1)
|
|
DBG_VALUE 0, 0, !14, !DIExpression(), debug-location !15
|
|
renamable $ecx = MOV32rm $ebp, 1, $noreg, 8, $noreg, debug-location !16 :: (load 4 from %ir.b.addr)
|
|
DBG_VALUE 1, 0, !14, !DIExpression(), debug-location !15
|
|
renamable $ecx = ADD32ri8 renamable $ecx, 4, implicit-def $eflags, debug-location !16
|
|
MOV32mr $ebp, 1, $noreg, -4, $noreg, killed $eax :: (store 4 into %fixed-stack.1)
|
|
$eax = MOV32rr killed $ecx, debug-location !16
|
|
$esp = frame-destroy ADD32ri8 $esp, 4, implicit-def dead $eflags, debug-location !16
|
|
$ebp = frame-destroy POP32r implicit-def $esp, implicit $esp, debug-location !16
|
|
CFI_INSTRUCTION def_cfa $esp, 4, debug-location !16
|
|
RETL implicit killed $eax, debug-location !16
|
|
|
|
...
|
|
---
|
|
name: _Z3baz1A
|
|
alignment: 4
|
|
tracksRegLiveness: true
|
|
frameInfo:
|
|
stackSize: 28
|
|
offsetAdjustment: -24
|
|
maxAlignment: 4
|
|
adjustsStack: true
|
|
hasCalls: true
|
|
maxCallFrameSize: 4
|
|
fixedStack:
|
|
- { id: 0, type: spill-slot, offset: -8, size: 4, alignment: 8, stack-id: 0 }
|
|
- { id: 1, size: 4, alignment: 16, stack-id: 0, isImmutable: true }
|
|
stack:
|
|
- { id: 0, name: z, offset: -12, size: 4, alignment: 4, stack-id: 0,
|
|
debug-info-variable: '!22', debug-info-expression: '!DIExpression()',
|
|
debug-info-location: '!23' }
|
|
- { id: 1, type: spill-slot, offset: -16, size: 4, alignment: 4, stack-id: 0 }
|
|
body: |
|
|
bb.0.entry:
|
|
frame-setup PUSH32r killed $ebp, implicit-def $esp, implicit $esp
|
|
CFI_INSTRUCTION def_cfa_offset 8
|
|
CFI_INSTRUCTION offset $ebp, -8
|
|
$ebp = frame-setup MOV32rr $esp
|
|
CFI_INSTRUCTION def_cfa_register $ebp
|
|
$esp = frame-setup SUB32ri8 $esp, 24, implicit-def dead $eflags
|
|
renamable $eax = MOV32rm $ebp, 1, $noreg, 8, $noreg :: (load 4 from %fixed-stack.1)
|
|
DBG_VALUE renamable $eax, 0, !20, !DIExpression(DW_OP_deref), debug-location !21
|
|
MOV32mi $ebp, 1, $noreg, -4, $noreg, 2, debug-location !23 :: (store 4 into %ir.z)
|
|
CMP32mi8 renamable $eax, 1, $noreg, 4, $noreg, 2, implicit-def $eflags, debug-location !24 :: (load 4 from %ir.var)
|
|
MOV32mr $ebp, 1, $noreg, -8, $noreg, killed $eax :: (store 4 into %stack.1)
|
|
DBG_VALUE $ebp, 0, !20, !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_deref, DW_OP_deref), debug-location !21
|
|
JLE_1 %bb.2, implicit $eflags, debug-location !24
|
|
|
|
bb.1.if.then:
|
|
DBG_VALUE $ebp, 0, !20, !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_deref, DW_OP_deref), debug-location !21
|
|
renamable $eax = MOV32rm $ebp, 1, $noreg, -4, $noreg, debug-location !26 :: (load 4 from %ir.z)
|
|
renamable $eax = ADD32ri8 renamable $eax, 1, implicit-def $eflags, debug-location !26
|
|
MOV32mr $ebp, 1, $noreg, -4, $noreg, killed renamable $eax, debug-location !26 :: (store 4 into %ir.z)
|
|
|
|
bb.2.if.end:
|
|
DBG_VALUE $ebp, 0, !20, !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_deref, DW_OP_deref), debug-location !21
|
|
$eax = MOV32rm $ebp, 1, $noreg, -8, $noreg :: (load 4 from %stack.1)
|
|
MOV32mr $esp, 1, $noreg, 0, $noreg, killed renamable $eax, debug-location !27 :: (store 4 into stack)
|
|
CALLpcrel32 @_ZN1A3fooEv, csr_32, implicit $esp, implicit $ssp, implicit-def $al, debug-location !27
|
|
renamable $ecx = MOVSX32rr8 killed renamable $al, debug-location !27
|
|
CMP32ri8 killed renamable $ecx, 97, implicit-def $eflags, debug-location !27
|
|
JNE_1 %bb.4, implicit $eflags, debug-location !27
|
|
|
|
bb.3.if.then2:
|
|
DBG_VALUE $ebp, 0, !20, !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_deref, DW_OP_deref), debug-location !21
|
|
renamable $eax = MOV32rm $ebp, 1, $noreg, -4, $noreg, debug-location !29 :: (load 4 from %ir.z)
|
|
renamable $eax = ADD32ri8 renamable $eax, 1, implicit-def $eflags, debug-location !29
|
|
MOV32mr $ebp, 1, $noreg, -4, $noreg, killed renamable $eax, debug-location !29 :: (store 4 into %ir.z)
|
|
|
|
bb.4.if.end4:
|
|
DBG_VALUE $ebp, 0, !20, !DIExpression(DW_OP_constu, 8, DW_OP_minus, DW_OP_deref, DW_OP_deref), debug-location !21
|
|
$esp = frame-destroy ADD32ri8 $esp, 24, implicit-def dead $eflags, debug-location !30
|
|
$ebp = frame-destroy POP32r implicit-def $esp, implicit $esp, debug-location !30
|
|
CFI_INSTRUCTION def_cfa $esp, 4, debug-location !30
|
|
RETL debug-location !30
|
|
|
|
...
|