Skip to content

Commit 02354ec

Browse files
committed
[DebugInfo][DWARF] Don't emit bogus DW_AT_call_target for complex calls
On X86-64, LLVM currently generates the same DWARF debug info for `call rax` and `call [rax]`; in both cases, the generated DWARF claims that the call goes to address RAX. This bug occurs because the X86 machine instructions CALL64r and CALL64m both receive register operands, but those register operands have different semantics. To fix it, change DwarfDebug::constructCallSiteEntryDIEs() to validate the callee operand's semantics (`OperandType`) and make sure it is not semantically describing a memory location. This fix will result in less DW_TAG_call_site and DW_AT_call_target entries being generated. There is an existing test in dwarf-callsite-related-attrs.ll that asserts the broken behavior; remove the broken check, and instead add a new test dwarf-callsite-related-attrs-indirect.ll that checks behavior for indirect calls. The existing test xray-custom-log.ll is validating something even more broken: It checks the debug info generated by a PATCHABLE_EVENT_CALL. `TII->getCalleeOperand()` assumes that the first argument of a call instruction is always the destination, but the first argument of PATCHABLE_EVENT_CALL is instead the event structure; and so we were emitting debug info claiming the callee was stored in a register that actually contains some kind of xray event descriptor, and the test validates that this happens. I am breaking and deleting this test. I guess the intent there might have been to validate that we emit debuginfo referencing the target of the direct call that LLVM emits (which we don't do)? But I'm not sure. WebAssembly's CALL instruction somehow has the call target in operand 1, despite the MCInstrDesc only describing a single operand; in such cases, assume that the operand is meant to be a register operand.
1 parent 74e4a86 commit 02354ec

File tree

5 files changed

+91
-38
lines changed

5 files changed

+91
-38
lines changed

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -940,14 +940,23 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
940940
// In the case of an indirect call find the register that holds
941941
// the callee.
942942
const MachineOperand &CalleeOp = TII->getCalleeOperand(MI);
943-
if (!CalleeOp.isGlobal() &&
944-
(!CalleeOp.isReg() || !CalleeOp.getReg().isPhysical()))
943+
bool PhysRegCalleeOperand =
944+
CalleeOp.isReg() && CalleeOp.getReg().isPhysical();
945+
// Hack: WebAssembly CALL instructions have MCInstrDesc that does not
946+
// describe the call target operand.
947+
if (CalleeOp.getOperandNo() < MI.getDesc().operands().size()) {
948+
const MCOperandInfo &MCOI =
949+
MI.getDesc().operands()[CalleeOp.getOperandNo()];
950+
PhysRegCalleeOperand =
951+
PhysRegCalleeOperand && MCOI.OperandType == MCOI::OPERAND_REGISTER;
952+
}
953+
if (!CalleeOp.isGlobal() && !PhysRegCalleeOperand)
945954
continue;
946955

947956
unsigned CallReg = 0;
948957
const DISubprogram *CalleeSP = nullptr;
949958
const Function *CalleeDecl = nullptr;
950-
if (CalleeOp.isReg()) {
959+
if (PhysRegCalleeOperand) {
951960
CallReg = CalleeOp.getReg();
952961
if (!CallReg)
953962
continue;

llvm/test/CodeGen/AArch64/xray-custom-log.ll

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
; RUN: llc -mtriple=aarch64 < %s | FileCheck %s
22
; RUN: llc -mtriple=arm64-apple-darwin < %s | FileCheck %s --check-prefix=MACHO
3-
; RUN: llc -filetype=obj -mtriple=aarch64 %s -o %t
4-
; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s --check-prefix=DBG
53

64
; MACHO: bl ___xray_CustomEvent
75
; MACHO: bl ___xray_CustomEvent
@@ -92,18 +90,6 @@ entry:
9290
; CHECK-NEXT: .byte 0x02
9391
; CHECK-NEXT: .zero 13
9492

95-
;; Construct call site entries for PATCHABLE_EVENT_CALL.
96-
; DBG: DW_TAG_subprogram
97-
; DBG: DW_AT_name
98-
; DBG-SAME: ("customevent")
99-
; DBG: DW_TAG_call_site
100-
; DBG-NEXT: DW_AT_call_target (DW_OP_reg0 {{.*}})
101-
; DBG-NEXT: DW_AT_call_return_pc
102-
; DBG-EMPTY:
103-
; DBG: DW_TAG_call_site
104-
; DBG-NEXT: DW_AT_call_target (DW_OP_reg2 {{.*}})
105-
; DBG-NEXT: DW_AT_call_return_pc
106-
10793
declare void @llvm.xray.customevent(ptr, i64)
10894
declare void @llvm.xray.typedevent(i64, ptr, i64)
10995

llvm/test/CodeGen/X86/xray-custom-log.ll

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
; RUN: llc -mtriple=x86_64 < %s | FileCheck %s
22
; RUN: llc -mtriple=x86_64 -relocation-model=pic < %s | FileCheck %s --check-prefix=PIC
33

4-
; RUN: llc -mtriple=x86_64 -filetype=obj %s -o %t
5-
; RUN: llvm-dwarfdump %t | FileCheck %s --check-prefix=DBG
6-
74
define i32 @customevent() nounwind "function-instrument"="xray-always" !dbg !1 {
85
%eventptr = alloca i8
96
%eventsize = alloca i64
@@ -93,17 +90,6 @@ define void @leaf_func() "function-instrument"="xray-always" "frame-pointer"="no
9390
declare void @llvm.xray.customevent(ptr, i64)
9491
declare void @llvm.xray.typedevent(i64, ptr, i64)
9592

96-
;; Construct call site entries for PATCHABLE_EVENT_CALL.
97-
; DBG: DW_TAG_subprogram
98-
; DBG: DW_TAG_call_site
99-
; DBG-NEXT: DW_AT_call_target (DW_OP_reg{{.*}})
100-
; DBG-NEXT: DW_AT_call_return_pc
101-
102-
; DBG: DW_TAG_subprogram
103-
; DBG: DW_TAG_call_site
104-
; DBG-NEXT: DW_AT_call_target (DW_OP_reg{{.*}})
105-
; DBG-NEXT: DW_AT_call_return_pc
106-
10793
!llvm.dbg.cu = !{!7}
10894
!llvm.module.flags = !{!10, !11}
10995

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
; $ clang -O2 -S -emit-llvm indir.c -gdwarf-5
2+
; __attribute__((disable_tail_calls)) void call_reg(void (*f)()) { f(); }
3+
; __attribute__((disable_tail_calls)) void call_mem(void (**f)()) { (*f)(); }
4+
5+
; RUN: llc -mtriple=x86_64 -debugger-tune=lldb < %s -filetype=obj -o %t.o
6+
; RUN: llvm-dwarfdump %t.o -o - | FileCheck %s -check-prefix=OBJ -implicit-check-not=DW_TAG_call_site -implicit-check-not=DW_AT_call_target
7+
; RUN: llvm-dwarfdump -verify %t.o 2>&1 | FileCheck %s -check-prefix=VERIFY
8+
; RUN: llvm-dwarfdump -statistics %t.o | FileCheck %s -check-prefix=STATS
9+
10+
; VERIFY: No errors.
11+
; STATS: "#call site DIEs": 1,
12+
13+
; OBJ: DW_TAG_subprogram
14+
; OBJ: DW_AT_name ("call_reg")
15+
; Function Attrs: nounwind uwtable
16+
define dso_local void @call_reg(ptr noundef readonly captures(none) %f) local_unnamed_addr #0 !dbg !10 {
17+
entry:
18+
#dbg_value(ptr %f, !17, !DIExpression(), !18)
19+
20+
; OBJ: DW_TAG_call_site
21+
; OBJ: DW_AT_call_target
22+
; OBJ: DW_AT_call_return_pc
23+
call void (...) %f() #1, !dbg !19
24+
ret void, !dbg !20
25+
}
26+
27+
; OBJ: DW_TAG_subprogram
28+
; OBJ: DW_AT_name ("call_mem")
29+
; Function Attrs: nounwind uwtable
30+
define dso_local void @call_mem(ptr noundef readonly captures(none) %f) local_unnamed_addr #0 !dbg !21 {
31+
entry:
32+
#dbg_value(ptr %f, !26, !DIExpression(), !27)
33+
%0 = load ptr, ptr %f, align 8, !dbg !28, !tbaa !29
34+
call void (...) %0() #1, !dbg !28
35+
ret void, !dbg !33
36+
}
37+
38+
attributes #0 = { nounwind uwtable "disable-tail-calls"="true" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
39+
attributes #1 = { nounwind }
40+
41+
!llvm.dbg.cu = !{!0}
42+
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
43+
!llvm.ident = !{!9}
44+
45+
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git (https://github.com/llvm/llvm-project 74e4a8645da91247dc8dc502771c2cc4d46f1f91)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
46+
!1 = !DIFile(filename: "indir.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "4a7538b13e2edbec44f43ed5154be38c")
47+
!2 = !{i32 7, !"Dwarf Version", i32 5}
48+
!3 = !{i32 2, !"Debug Info Version", i32 3}
49+
!4 = !{i32 1, !"wchar_size", i32 4}
50+
!5 = !{i32 8, !"PIC Level", i32 2}
51+
!6 = !{i32 7, !"PIE Level", i32 2}
52+
!7 = !{i32 7, !"uwtable", i32 2}
53+
!8 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
54+
!9 = !{!"clang version 22.0.0git (https://github.com/llvm/llvm-project 74e4a8645da91247dc8dc502771c2cc4d46f1f91)"}
55+
!10 = distinct !DISubprogram(name: "call_reg", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16)
56+
!11 = !DISubroutineType(types: !12)
57+
!12 = !{null, !13}
58+
!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64)
59+
!14 = !DISubroutineType(types: !15)
60+
!15 = !{null, null}
61+
!16 = !{!17}
62+
!17 = !DILocalVariable(name: "f", arg: 1, scope: !10, file: !1, line: 1, type: !13)
63+
!18 = !DILocation(line: 0, scope: !10)
64+
!19 = !DILocation(line: 1, column: 66, scope: !10)
65+
!20 = !DILocation(line: 1, column: 71, scope: !10)
66+
!21 = distinct !DISubprogram(name: "call_mem", scope: !1, file: !1, line: 2, type: !22, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !25)
67+
!22 = !DISubroutineType(types: !23)
68+
!23 = !{null, !24}
69+
!24 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64)
70+
!25 = !{!26}
71+
!26 = !DILocalVariable(name: "f", arg: 1, scope: !21, file: !1, line: 2, type: !24)
72+
!27 = !DILocation(line: 0, scope: !21)
73+
!28 = !DILocation(line: 2, column: 67, scope: !21)
74+
!29 = !{!30, !30, i64 0}
75+
!30 = !{!"any pointer", !31, i64 0}
76+
!31 = !{!"omnipotent char", !32, i64 0}
77+
!32 = !{!"Simple C/C++ TBAA"}
78+
!33 = !DILocation(line: 2, column: 75, scope: !21)

llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis -o /dev/null
2121

2222
; VERIFY: No errors.
23-
; STATS: "#call site DIEs": 6,
23+
; STATS: "#call site DIEs": 5,
2424

2525
@sink = global i32 0, align 4, !dbg !0
2626

@@ -94,16 +94,10 @@ entry:
9494
; OBJ: DW_TAG_call_site
9595
; OBJ: DW_AT_call_origin ([[foo_sp]] "_Z3foov")
9696
; OBJ: DW_AT_call_return_pc
97-
; OBJ: DW_TAG_call_site
98-
; OBJ: DW_AT_call_target
99-
; OBJ: DW_AT_call_return_pc
10097
define i32 @main() !dbg !29 {
10198
entry:
10299
call void @_Z3foov(), !dbg !32
103100

104-
%indirect_target = load ptr, ptr undef
105-
call void %indirect_target()
106-
107101
call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
108102

109103
ret i32 0, !dbg !33

0 commit comments

Comments
 (0)