From c11a95fb078ef1e00faab6fc61c7a77257eedb13 Mon Sep 17 00:00:00 2001 From: Wolfgang Pieb Date: Thu, 12 Jul 2018 18:18:21 +0000 Subject: [PATCH] [DWARF v5] Generate range list tables into the .debug_rnglists section. No support for split DWARF and no use of DW_FORM_rnglistx with the DW_AT_ranges attribute. Reviewer: aprantl Differential Revision: https://reviews.llvm.org/D49214 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@336927 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCObjectFileInfo.h | 9 +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 23 ++++-- lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 109 +++++++++++++++++++++++++--- lib/CodeGen/AsmPrinter/DwarfDebug.h | 3 + lib/CodeGen/AsmPrinter/DwarfFile.h | 8 ++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 9 +++ lib/CodeGen/AsmPrinter/DwarfUnit.h | 5 ++ lib/MC/MCObjectFileInfo.cpp | 6 ++ test/DebugInfo/X86/fission-ranges.ll | 21 +++++- test/DebugInfo/X86/rnglists-nobase.ll | 87 ++++++++++++++++++++++ 10 files changed, 259 insertions(+), 21 deletions(-) create mode 100644 test/DebugInfo/X86/rnglists-nobase.ll diff --git a/include/llvm/MC/MCObjectFileInfo.h b/include/llvm/MC/MCObjectFileInfo.h index 9f2241d14a9..3a27ef8c8fe 100644 --- a/include/llvm/MC/MCObjectFileInfo.h +++ b/include/llvm/MC/MCObjectFileInfo.h @@ -116,6 +116,11 @@ protected: /// The DWARF v5 string offset and address table sections. MCSection *DwarfStrOffSection; MCSection *DwarfAddrSection; + /// The DWARF v5 range list section. + MCSection *DwarfRnglistsSection; + + /// The DWARF v5 range list section for fission. + MCSection *DwarfRnglistsDWOSection; // These are for Fission DWP files. MCSection *DwarfCUIndexSection; @@ -256,6 +261,7 @@ public: MCSection *getDwarfLocSection() const { return DwarfLocSection; } MCSection *getDwarfARangesSection() const { return DwarfARangesSection; } MCSection *getDwarfRangesSection() const { return DwarfRangesSection; } + MCSection *getDwarfRnglistsSection() const { return DwarfRnglistsSection; } MCSection *getDwarfMacinfoSection() const { return DwarfMacinfoSection; } MCSection *getDwarfDebugNamesSection() const { @@ -281,6 +287,9 @@ public: MCSection *getDwarfStrOffDWOSection() const { return DwarfStrOffDWOSection; } MCSection *getDwarfStrOffSection() const { return DwarfStrOffSection; } MCSection *getDwarfAddrSection() const { return DwarfAddrSection; } + MCSection *getDwarfRnglistsDWOSection() const { + return DwarfRnglistsDWOSection; + } MCSection *getDwarfCUIndexSection() const { return DwarfCUIndexSection; } MCSection *getDwarfTUIndexSection() const { return DwarfTUIndexSection; } MCSection *getDwarfSwiftASTSection() const { return DwarfSwiftASTSection; } diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 04c206ffea2..cf941a920c5 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -399,21 +399,30 @@ void DwarfCompileUnit::addScopeRangeList(DIE &ScopeDIE, SmallVector Range) { const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); - // Emit offset in .debug_range as a relocatable label. emitDIE will handle - // emitting it appropriately. + // Emit the offset into .debug_ranges or .debug_rnglists as a relocatable + // label. emitDIE() will handle emitting it appropriately. const MCSymbol *RangeSectionSym = - TLOF.getDwarfRangesSection()->getBeginSymbol(); + DD->getDwarfVersion() >= 5 + ? TLOF.getDwarfRnglistsSection()->getBeginSymbol() + : TLOF.getDwarfRangesSection()->getBeginSymbol(); RangeSpanList List(Asm->createTempSymbol("debug_ranges"), std::move(Range)); // Under fission, ranges are specified by constant offsets relative to the // CU's DW_AT_GNU_ranges_base. - if (isDwoUnit()) - addSectionDelta(ScopeDIE, dwarf::DW_AT_ranges, List.getSym(), - RangeSectionSym); - else + // FIXME: For DWARF v5, do not generate the DW_AT_ranges attribute under + // fission until we support the forms using the .debug_addr section + // (DW_RLE_startx_endx etc.). + if (isDwoUnit()) { + if (DD->getDwarfVersion() < 5) + addSectionDelta(ScopeDIE, dwarf::DW_AT_ranges, List.getSym(), + RangeSectionSym); + } else { addSectionLabel(ScopeDIE, dwarf::DW_AT_ranges, List.getSym(), RangeSectionSym); + if (DD->getDwarfVersion() >= 5) + addRnglistsBase(); + } // Add the range list to the set of ranges to be emitted. (Skeleton ? Skeleton : this)->CURangeLists.push_back(std::move(List)); diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index c9e7a917daf..e12c866def1 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -645,6 +645,12 @@ void DwarfDebug::beginModule() { (useSplitDwarf() ? SkeletonHolder : InfoHolder) .setStringOffsetsStartSym(Asm->createTempSymbol("str_offsets_base")); + // Create the symbol that designates the start of the DWARF v5 range list + // table. It is located past the header and before the offsets table. + if (getDwarfVersion() >= 5) + (useSplitDwarf() ? SkeletonHolder : InfoHolder) + .setRnglistsTableBaseSym(Asm->createTempSymbol("rnglists_table_base")); + for (DICompileUnit *CUNode : M->debug_compile_units()) { // FIXME: Move local imported entities into a list attached to the // subprogram, then this search won't be needed and a @@ -765,7 +771,7 @@ void DwarfDebug::finalizeModuleInfo() { SkCU->addSectionLabel(SkCU->getUnitDie(), dwarf::DW_AT_GNU_addr_base, Sym, Sym); } - if (!SkCU->getRangeLists().empty()) { + if (getDwarfVersion() < 5 && !SkCU->getRangeLists().empty()) { const MCSymbol *Sym = TLOF.getDwarfRangesSection()->getBeginSymbol(); SkCU->addSectionLabel(SkCU->getUnitDie(), dwarf::DW_AT_GNU_ranges_base, Sym, Sym); @@ -1970,9 +1976,11 @@ void DwarfDebug::emitDebugARanges() { } } -/// Emit a single range list. +/// Emit a single range list. We handle both DWARF v5 and earlier. static void emitRangeList(AsmPrinter *Asm, DwarfCompileUnit *CU, const RangeSpanList &List) { + + auto DwarfVersion = CU->getDwarfVersion(); // Emit our symbol so we can find the beginning of the range. Asm->OutStreamer->EmitLabel(List.getSym()); // Gather all the ranges that apply to the same section so they can share @@ -1992,18 +2000,24 @@ static void emitRangeList(AsmPrinter *Asm, DwarfCompileUnit *CU, // usually consist of single regions from each of many sections // (-ffunction-sections, or just C++ inline functions) except under LTO // or optnone where there may be holes in a single CU's section - // contrubutions. + // contributions. auto *Base = CUBase; if (!Base && P.second.size() > 1 && UseDwarfRangesBaseAddressSpecifier) { BaseIsSet = true; // FIXME/use care: This may not be a useful base address if it's not // the lowest address/range in this object. Base = P.second.front()->getStart(); - Asm->OutStreamer->EmitIntValue(-1, Size); + if (DwarfVersion >= 5) + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_base_address, 1); + else + Asm->OutStreamer->EmitIntValue(-1, Size); Asm->OutStreamer->EmitSymbolValue(Base, Size); } else if (BaseIsSet) { BaseIsSet = false; - Asm->OutStreamer->EmitIntValue(-1, Size); + if (DwarfVersion >= 5) + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_base_address, 1); + else + Asm->OutStreamer->EmitIntValue(-1, Size); Asm->OutStreamer->EmitIntValue(0, Size); } @@ -2013,21 +2027,87 @@ static void emitRangeList(AsmPrinter *Asm, DwarfCompileUnit *CU, assert(Begin && "Range without a begin symbol?"); assert(End && "Range without an end symbol?"); if (Base) { - Asm->EmitLabelDifference(Begin, Base, Size); - Asm->EmitLabelDifference(End, Base, Size); + if (DwarfVersion >= 5) { + // Emit DW_RLE_offset_pair when we have a base. + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_offset_pair, 1); + Asm->EmitLabelDifferenceAsULEB128(Begin, Base); + Asm->EmitLabelDifferenceAsULEB128(End, Base); + } else { + Asm->EmitLabelDifference(Begin, Base, Size); + Asm->EmitLabelDifference(End, Base, Size); + } + } else if (DwarfVersion >= 5) { + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_start_length, 1); + Asm->OutStreamer->EmitSymbolValue(Begin, Size); + Asm->EmitLabelDifferenceAsULEB128(End, Begin); } else { Asm->OutStreamer->EmitSymbolValue(Begin, Size); Asm->OutStreamer->EmitSymbolValue(End, Size); } } } + if (DwarfVersion >= 5) + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_end_of_list, 1); + else { + // Terminate the list with two 0 values. + Asm->OutStreamer->EmitIntValue(0, Size); + Asm->OutStreamer->EmitIntValue(0, Size); + } +} + +void DwarfDebug::emitDebugRnglists() { - // And terminate the list with two 0 values. - Asm->OutStreamer->EmitIntValue(0, Size); - Asm->OutStreamer->EmitIntValue(0, Size); + // Don't emit a rangelist table if there are no ranges. + if (llvm::all_of(CUMap, + [](const decltype(CUMap)::const_iterator::value_type &Pair) { + DwarfCompileUnit *TheCU = Pair.second; + if (auto *Skel = TheCU->getSkeleton()) + TheCU = Skel; + return TheCU->getRangeLists().empty(); + })) + return; + + assert(getDwarfVersion() >= 5 && "Dwarf version must be 5 or greater"); + // FIXME: As long as we don't support DW_RLE_base_addrx, we cannot generate + // any tables in the .debug_rnglists.dwo section. + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfRnglistsSection()); + // The length is described by a starting label right after the length field + // and an end label. + MCSymbol *TableStart = Asm->createTempSymbol("debug_rnglist_table_start"); + MCSymbol *TableEnd = Asm->createTempSymbol("debug_rnglist_table_end"); + // Build the range table header, which starts with the length field. + Asm->EmitLabelDifference(TableEnd, TableStart, 4); + Asm->OutStreamer->EmitLabel(TableStart); + // Version number (DWARF v5 and later). + Asm->emitInt16(getDwarfVersion()); + // Address size. + Asm->emitInt8(Asm->MAI->getCodePointerSize()); + // Segment selector size. + Asm->emitInt8(0); + + MCSymbol *RnglistTableBaseSym = + (useSplitDwarf() ? SkeletonHolder : InfoHolder).getRnglistsTableBaseSym(); + + // FIXME: Generate the offsets table and use DW_FORM_rnglistx with the + // DW_AT_ranges attribute. Until then set the number of offsets to 0. + Asm->emitInt32(0); + Asm->OutStreamer->EmitLabel(RnglistTableBaseSym); + + // Emit the individual range lists. + for (const auto &I : CUMap) { + DwarfCompileUnit *TheCU = I.second; + if (auto *Skel = TheCU->getSkeleton()) + TheCU = Skel; + for (const RangeSpanList &List : TheCU->getRangeLists()) + emitRangeList(Asm, TheCU, List); + } + + Asm->OutStreamer->EmitLabel(TableEnd); } -/// Emit address ranges into a debug ranges section. +/// Emit address ranges into the .debug_ranges section or DWARF v5 rangelists +/// into the .debug_rnglists section. void DwarfDebug::emitDebugRanges() { if (CUMap.empty()) return; @@ -2042,6 +2122,11 @@ void DwarfDebug::emitDebugRanges() { return; } + if (getDwarfVersion() >= 5) { + emitDebugRnglists(); + return; + } + // Start the dwarf ranges section. Asm->OutStreamer->SwitchSection( Asm->getObjFileLowering().getDwarfRangesSection()); @@ -2134,7 +2219,7 @@ void DwarfDebug::initSkeletonUnit(const DwarfUnit &U, DIE &Die, // This DIE has the following attributes: DW_AT_comp_dir, DW_AT_stmt_list, // DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_dwo_name, DW_AT_dwo_id, -// DW_AT_addr_base, DW_AT_ranges_base. +// DW_AT_addr_base, DW_AT_ranges_base or DW_AT_rnglists_base. DwarfCompileUnit &DwarfDebug::constructSkeletonCU(const DwarfCompileUnit &CU) { auto OwnedUnit = llvm::make_unique( diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 54f0e5b6a79..528f83d2e4b 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -405,6 +405,9 @@ class DwarfDebug : public DebugHandlerBase { /// Emit address ranges into a debug ranges section. void emitDebugRanges(); + /// Emit range lists into a DWARF v5 debug rnglists section. + void emitDebugRnglists(); + /// Emit macros into a debug macinfo section. void emitDebugMacinfo(); void emitMacro(DIMacro &M); diff --git a/lib/CodeGen/AsmPrinter/DwarfFile.h b/lib/CodeGen/AsmPrinter/DwarfFile.h index 442b4fc14b5..272a26851b7 100644 --- a/lib/CodeGen/AsmPrinter/DwarfFile.h +++ b/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -48,6 +48,10 @@ class DwarfFile { /// the string offsets table. The contribution is shared by all units. MCSymbol *StringOffsetsStartSym = nullptr; + /// DWARF v5: The symbol that designates the base of the range list table. + /// The table is shared by all units. + MCSymbol *RnglistsTableBaseSym = nullptr; + /// The variables of a lexical scope. struct ScopeVars { /// We need to sort Args by ArgNo and check for duplicates. This could also @@ -114,6 +118,10 @@ public: void setStringOffsetsStartSym(MCSymbol *Sym) { StringOffsetsStartSym = Sym; } + MCSymbol *getRnglistsTableBaseSym() const { return RnglistsTableBaseSym; } + + void setRnglistsTableBaseSym(MCSymbol *Sym) { RnglistsTableBaseSym = Sym; } + /// \returns false if the variable was merged with a previous one. bool addScopeVariable(LexicalScope *LS, DbgVariable *Var); diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 77861ad45be..9af555464d4 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1757,3 +1757,12 @@ void DwarfUnit::addStringOffsetsStart() { DU->getStringOffsetsStartSym(), TLOF.getDwarfStrOffSection()->getBeginSymbol()); } + +void DwarfUnit::addRnglistsBase() { + assert(DD->getDwarfVersion() >= 5 && + "DW_AT_rnglists_base requires DWARF version 5 or later"); + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + addSectionLabel(getUnitDie(), dwarf::DW_AT_rnglists_base, + DU->getRnglistsTableBaseSym(), + TLOF.getDwarfRnglistsSection()->getBeginSymbol()); +} diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.h b/lib/CodeGen/AsmPrinter/DwarfUnit.h index c1d46173567..08c6f455d76 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -112,6 +112,8 @@ public: uint16_t getLanguage() const { return CUNode->getSourceLanguage(); } const DICompileUnit *getCUNode() const { return CUNode; } + uint16_t getDwarfVersion() const { return DD->getDwarfVersion(); } + /// Return true if this compile unit has something to write out. bool hasContent() const { return getUnitDie().hasChildren(); } @@ -293,6 +295,9 @@ public: /// Add the DW_AT_str_offsets_base attribute to the unit DIE. void addStringOffsetsStart(); + /// Add the DW_AT_rnglists_base attribute to the unit DIE. + void addRnglistsBase(); + virtual DwarfCompileUnit &getCU() = 0; void constructTypeDIE(DIE &Buffer, const DICompositeType *CTy); diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp index 56c6d89c69f..29d34a8c1e3 100644 --- a/lib/MC/MCObjectFileInfo.cpp +++ b/lib/MC/MCObjectFileInfo.cpp @@ -267,6 +267,9 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) { DwarfRangesSection = Ctx->getMachOSection("__DWARF", "__debug_ranges", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "debug_range"); + DwarfRnglistsSection = + Ctx->getMachOSection("__DWARF", "__debug_rnglists", MachO::S_ATTR_DEBUG, + SectionKind::getMetadata(), "debug_range"); DwarfMacinfoSection = Ctx->getMachOSection("__DWARF", "__debug_macinfo", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "debug_macinfo"); @@ -578,6 +581,7 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { DwarfStrOffSection = Ctx->getELFSection(".debug_str_offsets", DebugSecType, 0); DwarfAddrSection = Ctx->getELFSection(".debug_addr", DebugSecType, 0); + DwarfRnglistsSection = Ctx->getELFSection(".debug_rnglists", DebugSecType, 0); // Fission Sections DwarfInfoDWOSection = @@ -595,6 +599,8 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { Ctx->getELFSection(".debug_loc.dwo", DebugSecType, 0); DwarfStrOffDWOSection = Ctx->getELFSection(".debug_str_offsets.dwo", DebugSecType, 0); + DwarfRnglistsDWOSection = + Ctx->getELFSection(".debug_rnglists.dwo", DebugSecType, 0); // DWP Sections DwarfCUIndexSection = diff --git a/test/DebugInfo/X86/fission-ranges.ll b/test/DebugInfo/X86/fission-ranges.ll index ca5e43f1fb3..29ed97ffa55 100644 --- a/test/DebugInfo/X86/fission-ranges.ll +++ b/test/DebugInfo/X86/fission-ranges.ll @@ -2,6 +2,9 @@ ; RUN: llvm-dwarfdump -v %t | FileCheck %s ; RUN: llvm-objdump -h %t | FileCheck --check-prefix=HDR %s +; RUN: llc -dwarf-version=5 -O0 %s -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o %t +; RUN: llvm-dwarfdump -v %t | FileCheck --check-prefix=V5RNGLISTS %s + ; CHECK: .debug_info contents: ; CHECK: DW_TAG_compile_unit ; CHECK-NEXT: DW_AT_stmt_list @@ -10,7 +13,6 @@ ; CHECK-NEXT: DW_AT_GNU_dwo_id ; CHECK-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset] (0x00000000) - ; CHECK: .debug_info.dwo contents: ; CHECK: DW_AT_location [DW_FORM_sec_offset] ([[A:0x[0-9a-z]*]] ; CHECK: DW_AT_location [DW_FORM_sec_offset] ([[E:0x[0-9a-z]*]] @@ -34,7 +36,6 @@ ; CHECK: [[D]]: ; CHECK-NEXT: Addr idx 6 (w/ length 17): DW_OP_reg0 RAX - ; Make sure we don't produce any relocations in any .dwo section (though in particular, debug_info.dwo) ; HDR-NOT: .rela.{{.*}}.dwo @@ -45,6 +46,22 @@ ; HDR: .debug_addr 00000038 ; HDR-NOT: .rela.{{.*}}.dwo +; Check for the existence of a DWARF v5-style range list table in the .debug_rnglists +; section and that the compile unit has a DW_AT_rnglists_base attribute. +; The table should contain at least one rangelist with at least 2 individual ranges. + +; V5RNGLISTS: .debug_info contents: +; V5RNGLISTS: DW_TAG_compile_unit +; V5RNGLISTS-NOT: DW_TAG +; V5RNGLISTS: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c) +; V5RNGLISTS: .debug_rnglists contents: +; V5RNGLISTS-NEXT: 0x00000000: Range List Header: length = 0x00000014, version = 0x0005, +; V5RNGLISTS-SAME: addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +; V5RNGLISTS-NEXT: Ranges: +; V5RNGLISTS-NEXT: 0x0000000c: [DW_RLE_offset_pair]: +; V5RNGLISTS-NEXT: 0x0000000f: [DW_RLE_offset_pair]: +; V5RNGLISTS: 0x{{[0-9a-f]+}}: [DW_RLE_end_of_list] + ; From the code: ; extern int c; diff --git a/test/DebugInfo/X86/rnglists-nobase.ll b/test/DebugInfo/X86/rnglists-nobase.ll new file mode 100644 index 00000000000..56ac3ff81c0 --- /dev/null +++ b/test/DebugInfo/X86/rnglists-nobase.ll @@ -0,0 +1,87 @@ +; RUN: llc -O0 -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o %t < %s +; RUN: llvm-dwarfdump -v %t | FileCheck %s + +; We make sure that we generate DW_RLE_start_length range list entries when +; we do not have a base, which is the case when functions go into different +; sections. We should have 3 individual range list entries because there are +; 3 functions. +; +; From the following source: +; +; class A +; { +; public: +; A(); +; }; +; +; static A glob; +; void foo() { +; } +; +; Compile with clang -O1 -gdwarf-5 -S -emit-llvm +; +; CHECK: .debug_rnglists contents: +; CHECK-NEXT: 0x00000000: Range List Header: length = 0x00000027, version = 0x0005, +; CHECK-SAME: addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 +; CHECK-NEXT: Ranges: +; CHECK-NEXT: 0x0000000c: [DW_RLE_start_length]: +; CHECK-NEXT: 0x00000016: [DW_RLE_start_length]: +; CHECK-NEXT: 0x00000020: [DW_RLE_start_length]: +; CHECK-NEXT: 0x0000002a: [DW_RLE_end_of_list ] + +%class.A = type { i8 } + +@_ZL4glob = internal global %class.A zeroinitializer, align 1, !dbg !0 +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_xx.cpp, i8* null }] + +; Function Attrs: uwtable +define internal fastcc void @__cxx_global_var_init() unnamed_addr section ".text.startup" !dbg !16 { +entry: + tail call void @_ZN1AC1Ev(%class.A* nonnull @_ZL4glob), !dbg !19 + ret void, !dbg !19 +} + +declare dso_local void @_ZN1AC1Ev(%class.A*) unnamed_addr + +; Function Attrs: norecurse nounwind readnone uwtable +define dso_local void @_Z3foov() local_unnamed_addr !dbg !20 { +entry: + ret void, !dbg !21 +} + +; Function Attrs: uwtable +define internal void @_GLOBAL__sub_I_xx.cpp() section ".text.startup" !dbg !22 { +entry: + tail call fastcc void @__cxx_global_var_init(), !dbg !24 + ret void +} + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14} +!llvm.ident = !{!15} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "glob", linkageName: "_ZL4glob", scope: !2, file: !3, line: 7, type: !6, isLocal: true, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 (trunk 335191)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) +!3 = !DIFile(filename: "test.cpp", directory: "/home/test", checksumkind: CSK_MD5, checksum: "535784cf49522e3a6d1166f6c4e482ba") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "A", file: !3, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTS1A") +!7 = !{!8} +!8 = !DISubprogram(name: "A", scope: !6, file: !3, line: 4, type: !9, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true) +!9 = !DISubroutineType(types: !10) +!10 = !{null, !11} +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!12 = !{i32 2, !"Dwarf Version", i32 5} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{!"clang version 7.0.0 (trunk 335191)"} +!16 = distinct !DISubprogram(name: "__cxx_global_var_init", scope: !3, file: !3, line: 7, type: !17, isLocal: true, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !4) +!17 = !DISubroutineType(types: !18) +!18 = !{null} +!19 = !DILocation(line: 7, column: 10, scope: !16) +!20 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !3, file: !3, line: 9, type: !17, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !4) +!21 = !DILocation(line: 10, column: 1, scope: !20) +!22 = distinct !DISubprogram(linkageName: "_GLOBAL__sub_I_xx.cpp", scope: !3, file: !3, type: !23, isLocal: true, isDefinition: true, flags: DIFlagArtificial, isOptimized: true, unit: !2, retainedNodes: !4) +!23 = !DISubroutineType(types: !4) +!24 = !DILocation(line: 0, scope: !22) -- 2.11.0