[llvm] da6424c - [DebugInfo][DWARF] Don't emit bogus DW_AT_call_target for complex calls (#151378)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 5 13:25:05 PDT 2025
Author: Jann
Date: 2025-08-05T13:25:01-07:00
New Revision: da6424c9e307cd324f37745b525d3884b5077707
URL: https://github.com/llvm/llvm-project/commit/da6424c9e307cd324f37745b525d3884b5077707
DIFF: https://github.com/llvm/llvm-project/commit/da6424c9e307cd324f37745b525d3884b5077707.diff
LOG: [DebugInfo][DWARF] Don't emit bogus DW_AT_call_target for complex calls (#151378)
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.
Added:
llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs-indirect.ll
Modified:
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
llvm/test/CodeGen/AArch64/xray-custom-log.ll
llvm/test/CodeGen/X86/xray-custom-log.ll
llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 71888332a6620..5ae2d2a3958bd 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -940,14 +940,23 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
// In the case of an indirect call find the register that holds
// the callee.
const MachineOperand &CalleeOp = TII->getCalleeOperand(MI);
- if (!CalleeOp.isGlobal() &&
- (!CalleeOp.isReg() || !CalleeOp.getReg().isPhysical()))
+ bool PhysRegCalleeOperand =
+ CalleeOp.isReg() && CalleeOp.getReg().isPhysical();
+ // Hack: WebAssembly CALL instructions have MCInstrDesc that does not
+ // describe the call target operand.
+ if (CalleeOp.getOperandNo() < MI.getDesc().operands().size()) {
+ const MCOperandInfo &MCOI =
+ MI.getDesc().operands()[CalleeOp.getOperandNo()];
+ PhysRegCalleeOperand =
+ PhysRegCalleeOperand && MCOI.OperandType == MCOI::OPERAND_REGISTER;
+ }
+ if (!CalleeOp.isGlobal() && !PhysRegCalleeOperand)
continue;
unsigned CallReg = 0;
const DISubprogram *CalleeSP = nullptr;
const Function *CalleeDecl = nullptr;
- if (CalleeOp.isReg()) {
+ if (PhysRegCalleeOperand) {
CallReg = CalleeOp.getReg();
if (!CallReg)
continue;
diff --git a/llvm/test/CodeGen/AArch64/xray-custom-log.ll b/llvm/test/CodeGen/AArch64/xray-custom-log.ll
index fd8ddf93fcbfd..2432808c7946d 100644
--- a/llvm/test/CodeGen/AArch64/xray-custom-log.ll
+++ b/llvm/test/CodeGen/AArch64/xray-custom-log.ll
@@ -1,7 +1,5 @@
; RUN: llc -mtriple=aarch64 < %s | FileCheck %s
; RUN: llc -mtriple=arm64-apple-darwin < %s | FileCheck %s --check-prefix=MACHO
-; RUN: llc -filetype=obj -mtriple=aarch64 %s -o %t
-; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s --check-prefix=DBG
; MACHO: bl ___xray_CustomEvent
; MACHO: bl ___xray_CustomEvent
@@ -92,18 +90,6 @@ entry:
; CHECK-NEXT: .byte 0x02
; CHECK-NEXT: .zero 13
-;; Construct call site entries for PATCHABLE_EVENT_CALL.
-; DBG: DW_TAG_subprogram
-; DBG: DW_AT_name
-; DBG-SAME: ("customevent")
-; DBG: DW_TAG_call_site
-; DBG-NEXT: DW_AT_call_target (DW_OP_reg0 {{.*}})
-; DBG-NEXT: DW_AT_call_return_pc
-; DBG-EMPTY:
-; DBG: DW_TAG_call_site
-; DBG-NEXT: DW_AT_call_target (DW_OP_reg2 {{.*}})
-; DBG-NEXT: DW_AT_call_return_pc
-
declare void @llvm.xray.customevent(ptr, i64)
declare void @llvm.xray.typedevent(i64, ptr, i64)
diff --git a/llvm/test/CodeGen/X86/xray-custom-log.ll b/llvm/test/CodeGen/X86/xray-custom-log.ll
index 8f23055aca97c..f4cdc23687919 100644
--- a/llvm/test/CodeGen/X86/xray-custom-log.ll
+++ b/llvm/test/CodeGen/X86/xray-custom-log.ll
@@ -1,9 +1,6 @@
; RUN: llc -mtriple=x86_64 < %s | FileCheck %s
; RUN: llc -mtriple=x86_64 -relocation-model=pic < %s | FileCheck %s --check-prefix=PIC
-; RUN: llc -mtriple=x86_64 -filetype=obj %s -o %t
-; RUN: llvm-dwarfdump %t | FileCheck %s --check-prefix=DBG
-
define i32 @customevent() nounwind "function-instrument"="xray-always" !dbg !1 {
%eventptr = alloca i8
%eventsize = alloca i64
@@ -93,17 +90,6 @@ define void @leaf_func() "function-instrument"="xray-always" "frame-pointer"="no
declare void @llvm.xray.customevent(ptr, i64)
declare void @llvm.xray.typedevent(i64, ptr, i64)
-;; Construct call site entries for PATCHABLE_EVENT_CALL.
-; DBG: DW_TAG_subprogram
-; DBG: DW_TAG_call_site
-; DBG-NEXT: DW_AT_call_target (DW_OP_reg{{.*}})
-; DBG-NEXT: DW_AT_call_return_pc
-
-; DBG: DW_TAG_subprogram
-; DBG: DW_TAG_call_site
-; DBG-NEXT: DW_AT_call_target (DW_OP_reg{{.*}})
-; DBG-NEXT: DW_AT_call_return_pc
-
!llvm.dbg.cu = !{!7}
!llvm.module.flags = !{!10, !11}
diff --git a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs-indirect.ll b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs-indirect.ll
new file mode 100644
index 0000000000000..6c81e2e72d93c
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs-indirect.ll
@@ -0,0 +1,78 @@
+; $ clang -O2 -S -emit-llvm indir.c -gdwarf-5
+; __attribute__((disable_tail_calls)) void call_reg(void (*f)()) { f(); }
+; __attribute__((disable_tail_calls)) void call_mem(void (**f)()) { (*f)(); }
+
+; RUN: llc -mtriple=x86_64 -debugger-tune=lldb < %s -filetype=obj -o %t.o
+; 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
+; RUN: llvm-dwarfdump -verify %t.o 2>&1 | FileCheck %s -check-prefix=VERIFY
+; RUN: llvm-dwarfdump -statistics %t.o | FileCheck %s -check-prefix=STATS
+
+; VERIFY: No errors.
+; STATS: "#call site DIEs": 1,
+
+; OBJ: DW_TAG_subprogram
+; OBJ: DW_AT_name ("call_reg")
+; Function Attrs: nounwind uwtable
+define dso_local void @call_reg(ptr noundef readonly captures(none) %f) local_unnamed_addr #0 !dbg !10 {
+entry:
+ #dbg_value(ptr %f, !17, !DIExpression(), !18)
+
+; OBJ: DW_TAG_call_site
+; OBJ: DW_AT_call_target
+; OBJ: DW_AT_call_return_pc
+ call void (...) %f() #1, !dbg !19
+ ret void, !dbg !20
+}
+
+; OBJ: DW_TAG_subprogram
+; OBJ: DW_AT_name ("call_mem")
+; Function Attrs: nounwind uwtable
+define dso_local void @call_mem(ptr noundef readonly captures(none) %f) local_unnamed_addr #0 !dbg !21 {
+entry:
+ #dbg_value(ptr %f, !26, !DIExpression(), !27)
+ %0 = load ptr, ptr %f, align 8, !dbg !28, !tbaa !29
+ call void (...) %0() #1, !dbg !28
+ ret void, !dbg !33
+}
+
+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" }
+attributes #1 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!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)
+!1 = !DIFile(filename: "indir.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "4a7538b13e2edbec44f43ed5154be38c")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+!9 = !{!"clang version 22.0.0git (https://github.com/llvm/llvm-project 74e4a8645da91247dc8dc502771c2cc4d46f1f91)"}
+!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)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null, !13}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64)
+!14 = !DISubroutineType(types: !15)
+!15 = !{null, null}
+!16 = !{!17}
+!17 = !DILocalVariable(name: "f", arg: 1, scope: !10, file: !1, line: 1, type: !13)
+!18 = !DILocation(line: 0, scope: !10)
+!19 = !DILocation(line: 1, column: 66, scope: !10)
+!20 = !DILocation(line: 1, column: 71, scope: !10)
+!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)
+!22 = !DISubroutineType(types: !23)
+!23 = !{null, !24}
+!24 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64)
+!25 = !{!26}
+!26 = !DILocalVariable(name: "f", arg: 1, scope: !21, file: !1, line: 2, type: !24)
+!27 = !DILocation(line: 0, scope: !21)
+!28 = !DILocation(line: 2, column: 67, scope: !21)
+!29 = !{!30, !30, i64 0}
+!30 = !{!"any pointer", !31, i64 0}
+!31 = !{!"omnipotent char", !32, i64 0}
+!32 = !{!"Simple C/C++ TBAA"}
+!33 = !DILocation(line: 2, column: 75, scope: !21)
diff --git a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll
index c927ff21e0191..8ed247d436d8d 100644
--- a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll
+++ b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll
@@ -20,7 +20,7 @@
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis -o /dev/null
; VERIFY: No errors.
-; STATS: "#call site DIEs": 6,
+; STATS: "#call site DIEs": 5,
@sink = global i32 0, align 4, !dbg !0
@@ -94,16 +94,10 @@ entry:
; OBJ: DW_TAG_call_site
; OBJ: DW_AT_call_origin ([[foo_sp]] "_Z3foov")
; OBJ: DW_AT_call_return_pc
-; OBJ: DW_TAG_call_site
-; OBJ: DW_AT_call_target
-; OBJ: DW_AT_call_return_pc
define i32 @main() !dbg !29 {
entry:
call void @_Z3foov(), !dbg !32
- %indirect_target = load ptr, ptr undef
- call void %indirect_target()
-
call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
ret i32 0, !dbg !33
More information about the llvm-commits
mailing list