Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -420,8 +420,6 @@ } 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. Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -420,8 +420,13 @@ void initSkeletonUnit(const DwarfUnit &U, DIE &Die, std::unique_ptr NewU); - /// Construct the split debug info compile unit for the debug info - /// section. + /// Construct the split debug info compile unit for the debug info section. + /// In DWARF v5, the skeleton unit DIE may have the following attributes: + /// DW_AT_addr_base, DW_AT_comp_dir, DW_AT_dwo_name, DW_AT_high_pc, + /// DW_AT_low_pc, DW_AT_ranges, DW_AT_stmt_list, and DW_AT_str_offsets_base. + /// Prior to DWARF v5 it may also have DW_AT_GNU_dwo_id. DW_AT_GNU_dwo_name + /// is used instead of DW_AT_dwo_name, Dw_AT_GNU_addr_base instead of + /// DW_AT_addr_base, and DW_AT_GNU_ranges_base instead of DW_AT_rnglists_base. DwarfCompileUnit &constructSkeletonCU(const DwarfCompileUnit &CU); /// Emit the debug info dwo section. Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -786,6 +786,8 @@ // ranges for all subprogram DIEs for mach-o. DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; if (unsigned NumRanges = TheCU.getRanges().size()) { + if (getDwarfVersion() >= 5) + U.addRnglistsBase(); if (NumRanges > 1 && useRangesSection()) // A DW_AT_low_pc attribute may also be specified in combination with // DW_AT_ranges to specify the default base address for use in @@ -2063,81 +2065,61 @@ } } -void DwarfDebug::emitDebugRnglists() { - - // 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()); +static void emitRnglistsTableHeader(AsmPrinter *Asm, DwarfFile &Holder, + MCSymbol *&TableEnd) { // 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"); + 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()); + Asm->emitInt16(Asm->OutStreamer->getContext().getDwarfVersion()); // Address size. Asm->emitInt8(Asm->MAI->getCodePointerSize()); // Segment selector size. Asm->emitInt8(0); - MCSymbol *RnglistTableBaseSym = - (useSplitDwarf() ? SkeletonHolder : InfoHolder).getRnglistsTableBaseSym(); + MCSymbol *RnglistTableBaseSym = Holder.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 the .debug_ranges section or DWARF v5 rangelists -/// into the .debug_rnglists section. +/// Emit address ranges into the .debug_ranges section or into the DWARF v5 +/// .debug_rnglists section. void DwarfDebug::emitDebugRanges() { if (CUMap.empty()) return; + auto NoRangesPresent = [this]() { + return (llvm::all_of( + CUMap, [](const decltype(CUMap)::const_iterator::value_type &Pair) { + return Pair.second->getRangeLists().empty(); + })); + }; + if (!useRangesSection()) { - assert(llvm::all_of( - CUMap, - [](const decltype(CUMap)::const_iterator::value_type &Pair) { - return Pair.second->getRangeLists().empty(); - }) && - "No debug ranges expected."); + assert(NoRangesPresent() && "No debug ranges expected."); return; } - if (getDwarfVersion() >= 5) { - emitDebugRnglists(); + if (NoRangesPresent()) return; - } // Start the dwarf ranges section. - Asm->OutStreamer->SwitchSection( - Asm->getObjFileLowering().getDwarfRangesSection()); + MCSymbol *TableEnd = nullptr; + if (getDwarfVersion() >= 5) { + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfRnglistsSection()); + emitRnglistsTableHeader(Asm, useSplitDwarf() ? SkeletonHolder : InfoHolder, + TableEnd); + } else + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfRangesSection()); // Grab the specific ranges for the compile units in the module. for (const auto &I : CUMap) { @@ -2150,6 +2132,11 @@ for (const RangeSpanList &List : TheCU->getRangeLists()) emitRangeList(Asm, TheCU, List); } + + if (getDwarfVersion() >= 5) { + assert(TableEnd && "End label for rnglists table not created"); + Asm->OutStreamer->EmitLabel(TableEnd); + } } void DwarfDebug::handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U) { @@ -2225,9 +2212,6 @@ SkeletonHolder.addUnit(std::move(NewU)); } -// 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 or DW_AT_rnglists_base. DwarfCompileUnit &DwarfDebug::constructSkeletonCU(const DwarfCompileUnit &CU) { auto OwnedUnit = llvm::make_unique( Index: test/DebugInfo/X86/rnglists_base_attr.ll =================================================================== --- test/DebugInfo/X86/rnglists_base_attr.ll +++ test/DebugInfo/X86/rnglists_base_attr.ll @@ -0,0 +1,83 @@ +; RUN: llc -dwarf-version=5 -O0 %s -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o %t +; RUN: llvm-dwarfdump -v %t | FileCheck %s + +; Make sure we don't generate a duplicate DW_AT_rnglists_base attribue in the CU die. +; From the source: +; +; bool x; +; void f1() { +; if (bool b = x) {} +; } +; __attribute__((section(".text.foo"))) void f2() { } + +; Compile with clang -gwarf5 -S -emit-llvm + +; CHECK: .debug_info contents: +; CHECK: DW_TAG_compile_unit +; CHECK: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c) +; CHECK-NOT: DW_AT_rnglists_base + +@x = dso_local global i8 0, align 1, !dbg !0 + +; Function Attrs: noinline optnone uwtable +define dso_local void @_Z2f1v() !dbg !11 { +entry: + %b = alloca i8, align 1 + call void @llvm.dbg.declare(metadata i8* %b, metadata !15, metadata !DIExpression()), !dbg !17 + %0 = load i8, i8* @x, align 1, !dbg !18 + %tobool = trunc i8 %0 to i1, !dbg !18 + %frombool = zext i1 %tobool to i8, !dbg !17 + store i8 %frombool, i8* %b, align 1, !dbg !17 + %1 = load i8, i8* %b, align 1, !dbg !17 + %tobool1 = trunc i8 %1 to i1, !dbg !17 + br i1 %tobool1, label %if.then, label %if.end, !dbg !19 + +if.then: ; preds = %entry + br label %if.end, !dbg !23 + +if.end: ; preds = %if.then, %entry + ret void, !dbg !24 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @_Z2f2v() section ".text.foo" !dbg !25 { +entry: + ret void, !dbg !26 +} + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 (trunk 336915)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) +!3 = !DIFile(filename: "t2.cpp", directory: "/home/test/rangelists", checksumkind: CSK_MD5, checksum: "75e536c9febd243d11501b861628eed1") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) +!7 = !{i32 2, !"Dwarf Version", i32 5} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 7.0.0 (trunk 336915)"} +!11 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !3, file: !3, line: 2, type: !12, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !2, retainedNodes: !4) +!12 = !DISubroutineType(types: !13) +!13 = !{null} +!14 = !DILocation(line: 3, column: 3, scope: !11) +!15 = !DILocalVariable(name: "b", scope: !16, file: !3, line: 4, type: !6) +!16 = distinct !DILexicalBlock(scope: !11, file: !3, line: 4, column: 12) +!17 = !DILocation(line: 4, column: 12, scope: !16) +!18 = !DILocation(line: 4, column: 16, scope: !16) +!19 = !DILocation(line: 4, column: 12, scope: !11) +!20 = !DILocation(line: 5, column: 5, scope: !21) +!21 = distinct !DILexicalBlock(scope: !16, file: !3, line: 4, column: 19) +!22 = !DILocation(line: 6, column: 5, scope: !21) +!23 = !DILocation(line: 7, column: 3, scope: !21) +!24 = !DILocation(line: 8, column: 1, scope: !11) +!25 = distinct !DISubprogram(name: "f2", linkageName: "_Z2f2v", scope: !3, file: !3, line: 9, type: !12, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !2, retainedNodes: !4) +!26 = !DILocation(line: 9, column: 51, scope: !25) +!27 = distinct !DISubprogram(name: "f3", linkageName: "_Z2f3v", scope: !3, file: !3, line: 10, type: !12, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, unit: !2, retainedNodes: !4) +!28 = !DILocation(line: 10, column: 13, scope: !27)