From 9b921c23c3da810790bec422a365c6786d277d49 Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Thu, 14 Oct 2021 13:46:30 +0200 Subject: [PATCH] [DebugInfo][DWARF] Add DW_AT_alloc_type support (in LLVM ID space) LLVM currently stores heapallocsite information in CodeView debuginfo, but not in DWARF debuginfo. heapallocsite information is useful for profiling and memory analysis. The DWARF v6 working draft includes this feature as DW_AT_alloc_type; but since that is not yet an official standard, use LLVM-private ID space for now. --- llvm/include/llvm/BinaryFormat/Dwarf.def | 3 ++ .../CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 15 ++++---- .../lib/CodeGen/AsmPrinter/DwarfCompileUnit.h | 3 +- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 22 ++++++------ llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp | 1 + llvm/test/DebugInfo/X86/DW_AT_alloc_type.ll | 34 +++++++++++++++++++ 6 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 llvm/test/DebugInfo/X86/DW_AT_alloc_type.ll diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def index 48b33478d5045..b561125fe37a4 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -625,6 +625,9 @@ HANDLE_DW_AT(0x3e0a, LLVM_ptrauth_authentication_mode, 0, LLVM) HANDLE_DW_AT(0x3e0b, LLVM_num_extra_inhabitants, 0, LLVM) HANDLE_DW_AT(0x3e0c, LLVM_stmt_sequence, 0, LLVM) HANDLE_DW_AT(0x3e0d, LLVM_coro_suspend_idx, 0, LLVM) +// The DWARF v6 working draft defines DW_AT_alloc_type; use this LLVM-private ID +// until that is released as an official standard. +HANDLE_DW_AT(0x3e0e, LLVM_alloc_type, 0, LLVM) // Apple extensions. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index f9d7e763e8890..67f526fe91464 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -1292,12 +1292,10 @@ DwarfCompileUnit::getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const { } } -DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE, - const DISubprogram *CalleeSP, - bool IsTail, - const MCSymbol *PCAddr, - const MCSymbol *CallAddr, - unsigned CallReg) { +DIE &DwarfCompileUnit::constructCallSiteEntryDIE( + DIE &ScopeDIE, const DISubprogram *CalleeSP, bool IsTail, + const MCSymbol *PCAddr, const MCSymbol *CallAddr, unsigned CallReg, + DIType *AllocSiteTy) { // Insert a call site entry DIE within ScopeDIE. DIE &CallSiteDIE = createAndAddDIE(getDwarf5OrGNUTag(dwarf::DW_TAG_call_site), ScopeDIE, nullptr); @@ -1306,7 +1304,7 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE, // Indirect call. addAddress(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_target), MachineLocation(CallReg)); - } else { + } else if (CalleeSP) { DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP); assert(CalleeDIE && "Could not create DIE for call site entry origin"); if (AddLinkageNamesToDeclCallOriginsForTuning(DD) && @@ -1351,6 +1349,9 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_return_pc), PCAddr); } + if (AllocSiteTy) + addType(CallSiteDIE, AllocSiteTy, dwarf::DW_AT_LLVM_alloc_type); + return CallSiteDIE; } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 09be22ce35e36..c2f6ca0913818 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -289,7 +289,8 @@ class DwarfCompileUnit final : public DwarfUnit { /// the \p CallReg is set to 0. DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram *CalleeSP, bool IsTail, const MCSymbol *PCAddr, - const MCSymbol *CallAddr, unsigned CallReg); + const MCSymbol *CallAddr, unsigned CallReg, + DIType *AllocSiteTy); /// Construct call site parameter DIEs for the \p CallSiteDIE. The \p Params /// were collected by the \ref collectCallSiteParameters. /// Note: The order of parameters does not matter, since debuggers recognize diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 5ae2d2a3958bd..c27f100775625 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -936,6 +936,8 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, if (MI.hasDelaySlot() && !delaySlotSupported(*&MI)) return; + DIType *AllocSiteTy = dyn_cast_or_null(MI.getHeapAllocMarker()); + // If this is a direct call, find the callee's subprogram. // In the case of an indirect call find the register that holds // the callee. @@ -950,23 +952,23 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, PhysRegCalleeOperand = PhysRegCalleeOperand && MCOI.OperandType == MCOI::OPERAND_REGISTER; } - if (!CalleeOp.isGlobal() && !PhysRegCalleeOperand) - continue; unsigned CallReg = 0; const DISubprogram *CalleeSP = nullptr; const Function *CalleeDecl = nullptr; if (PhysRegCalleeOperand) { - CallReg = CalleeOp.getReg(); - if (!CallReg) - continue; - } else { + CallReg = CalleeOp.getReg(); // might be zero + } else if (CalleeOp.isGlobal()) { CalleeDecl = dyn_cast(CalleeOp.getGlobal()); - if (!CalleeDecl || !CalleeDecl->getSubprogram()) - continue; - CalleeSP = CalleeDecl->getSubprogram(); + if (CalleeDecl) + CalleeSP = CalleeDecl->getSubprogram(); // might be nullptr } + // Omit DIE if we can't tell where the call goes *and* we don't want to + // add metadata to it. + if (CalleeSP == nullptr && CallReg == 0 && AllocSiteTy == nullptr) + continue; + // TODO: Omit call site entries for runtime calls (objc_msgSend, etc). bool IsTail = TII->isTailCall(MI); @@ -1000,7 +1002,7 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, << (IsTail ? " [IsTail]" : "") << "\n"); DIE &CallSiteDIE = CU.constructCallSiteEntryDIE( - ScopeDIE, CalleeSP, IsTail, PCAddr, CallAddr, CallReg); + ScopeDIE, CalleeSP, IsTail, PCAddr, CallAddr, CallReg, AllocSiteTy); // Optionally emit call-site-param debug info. if (emitDebugEntryValues()) { diff --git a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp index 6ddb12ba04349..8052773812a2c 100644 --- a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp @@ -109,6 +109,7 @@ static bool isODRAttribute(uint16_t Attr) { case dwarf::DW_AT_specification: case dwarf::DW_AT_abstract_origin: case dwarf::DW_AT_import: + case dwarf::DW_AT_LLVM_alloc_type: return true; } llvm_unreachable("Improper attribute."); diff --git a/llvm/test/DebugInfo/X86/DW_AT_alloc_type.ll b/llvm/test/DebugInfo/X86/DW_AT_alloc_type.ll new file mode 100644 index 0000000000000..33028f2234ceb --- /dev/null +++ b/llvm/test/DebugInfo/X86/DW_AT_alloc_type.ll @@ -0,0 +1,34 @@ +; RUN: llc -O3 -o %t -filetype=obj %s +; RUN: llvm-dwarfdump %t | FileCheck %s + +; based on clang++ output for `int *alloc_int() { return new int; }` + + +target triple = "x86_64-unknown-linux-gnu" + +define dso_local ptr @alloc_int() !dbg !3 { +; CHECK: DW_TAG_subprogram +entry: + %call = call ptr @alloc(i64 noundef 4), !heapallocsite !7 +; CHECK: DW_TAG_call_site +; CHECK: DW_AT_LLVM_alloc_type ([[ALLOCSITE:.*]]) + ret ptr %call +} + +; CHECK: {{.*}}[[ALLOCSITE]]: DW_TAG_base_type +; CHECK: DW_AT_name ("int") + +declare dso_local ptr @alloc(i64 noundef) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2,!8} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, emissionKind: FullDebug) +!1 = !DIFile(filename: "a.cpp", directory: "/") +!2 = !{i32 2, !"Debug Info Version", i32 3} +!3 = distinct !DISubprogram(name: "alloc_int", scope: !1, file: !1, line: 1, type: !4, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition, unit: !0) +!4 = !DISubroutineType(types: !5) +!5 = !{!6} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{i32 2, !"Dwarf Version", i32 5}