diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 3fb47948b4d..f438dff2708 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -147,6 +147,11 @@ static cl::opt DwarfSectionsAsReferences( clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")), cl::init(Default)); +static cl::opt + UseGNUDebugMacro("use-gnu-debug-macro", cl::Hidden, + cl::desc("Emit the GNU .debug_macro format with DWARF <5"), + cl::init(false)); + enum LinkageNameOption { DefaultLinkageNames, AllLinkageNames, @@ -428,7 +433,10 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) // the debug entry values feature. It can also be enabled explicitly. EmitDebugEntryValues = Asm->TM.Options.ShouldEmitDebugEntryValues(); - UseDebugMacroSection = DwarfVersion >= 5; + // It is unclear if the GCC .debug_macro extension is well-specified + // for split DWARF. For now, do not allow LLVM to emit it. + UseDebugMacroSection = + DwarfVersion >= 5 || (UseGNUDebugMacro && !useSplitDwarf()); Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion); } @@ -1353,10 +1361,13 @@ void DwarfDebug::finalizeModuleInfo() { TheCU.addSectionDelta( TheCU.getUnitDie(), dwarf::DW_AT_macros, U.getMacroLabelBegin(), TLOF.getDwarfMacroDWOSection()->getBeginSymbol()); - else - U.addSectionLabel(U.getUnitDie(), dwarf::DW_AT_macros, - U.getMacroLabelBegin(), + else { + dwarf::Attribute MacrosAttr = getDwarfVersion() >= 5 + ? dwarf::DW_AT_macros + : dwarf::DW_AT_GNU_macros; + U.addSectionLabel(U.getUnitDie(), MacrosAttr, U.getMacroLabelBegin(), TLOF.getDwarfMacroSection()->getBeginSymbol()); + } } else { if (useSplitDwarf()) TheCU.addSectionDelta( @@ -2980,16 +2991,17 @@ void DwarfDebug::emitDebugRangesDWO() { Asm->getObjFileLowering().getDwarfRnglistsDWOSection()); } -/// Emit the header of a DWARF 5 macro section. +/// Emit the header of a DWARF 5 macro section, or the GNU extension for +/// DWARF 4. static void emitMacroHeader(AsmPrinter *Asm, const DwarfDebug &DD, - const DwarfCompileUnit &CU) { + const DwarfCompileUnit &CU, uint16_t DwarfVersion) { enum HeaderFlagMask { #define HANDLE_MACRO_FLAG(ID, NAME) MACRO_FLAG_##NAME = ID, #include "llvm/BinaryFormat/Dwarf.def" }; uint8_t Flags = 0; Asm->OutStreamer->AddComment("Macro information version"); - Asm->emitInt16(5); + Asm->emitInt16(DwarfVersion >= 5 ? DwarfVersion : 4); // We are setting Offset and line offset flags unconditionally here, // since we're only supporting DWARF32 and line offset should be mostly // present. @@ -3024,16 +3036,31 @@ void DwarfDebug::emitMacro(DIMacro &M) { std::string Str = Value.empty() ? Name.str() : (Name + " " + Value).str(); if (UseDebugMacroSection) { - unsigned Type = M.getMacinfoType() == dwarf::DW_MACINFO_define - ? dwarf::DW_MACRO_define_strx - : dwarf::DW_MACRO_undef_strx; - Asm->OutStreamer->AddComment(dwarf::MacroString(Type)); - Asm->emitULEB128(Type); - Asm->OutStreamer->AddComment("Line Number"); - Asm->emitULEB128(M.getLine()); - Asm->OutStreamer->AddComment("Macro String"); - Asm->emitULEB128( - InfoHolder.getStringPool().getIndexedEntry(*Asm, Str).getIndex()); + if (getDwarfVersion() >= 5) { + unsigned Type = M.getMacinfoType() == dwarf::DW_MACINFO_define + ? dwarf::DW_MACRO_define_strx + : dwarf::DW_MACRO_undef_strx; + Asm->OutStreamer->AddComment(dwarf::MacroString(Type)); + Asm->emitULEB128(Type); + Asm->OutStreamer->AddComment("Line Number"); + Asm->emitULEB128(M.getLine()); + Asm->OutStreamer->AddComment("Macro String"); + Asm->emitULEB128( + InfoHolder.getStringPool().getIndexedEntry(*Asm, Str).getIndex()); + } else { + unsigned Type = M.getMacinfoType() == dwarf::DW_MACINFO_define + ? dwarf::DW_MACRO_GNU_define_indirect + : dwarf::DW_MACRO_GNU_undef_indirect; + Asm->OutStreamer->AddComment(dwarf::GnuMacroString(Type)); + Asm->emitULEB128(Type); + Asm->OutStreamer->AddComment("Line Number"); + Asm->emitULEB128(M.getLine()); + Asm->OutStreamer->AddComment("Macro String"); + // FIXME: Add support for DWARF64. + Asm->OutStreamer->emitSymbolValue( + InfoHolder.getStringPool().getEntry(*Asm, Str).getSymbol(), + /*Size=*/4); + } } else { Asm->OutStreamer->AddComment(dwarf::MacinfoString(M.getMacinfoType())); Asm->emitULEB128(M.getMacinfoType()); @@ -3071,8 +3098,9 @@ void DwarfDebug::emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U) { // so for readibility/uniformity, We are explicitly emitting those. assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file); if (UseDebugMacroSection) - emitMacroFileImpl(F, U, dwarf::DW_MACRO_start_file, - dwarf::DW_MACRO_end_file, dwarf::MacroString); + emitMacroFileImpl( + F, U, dwarf::DW_MACRO_start_file, dwarf::DW_MACRO_end_file, + (getDwarfVersion() >= 5) ? dwarf::MacroString : dwarf::GnuMacroString); else emitMacroFileImpl(F, U, dwarf::DW_MACINFO_start_file, dwarf::DW_MACINFO_end_file, dwarf::MacinfoString); @@ -3090,7 +3118,7 @@ void DwarfDebug::emitDebugMacinfoImpl(MCSection *Section) { Asm->OutStreamer->SwitchSection(Section); Asm->OutStreamer->emitLabel(U.getMacroLabelBegin()); if (UseDebugMacroSection) - emitMacroHeader(Asm, *this, U); + emitMacroHeader(Asm, *this, U, getDwarfVersion()); handleMacroNodes(Macros, U); Asm->OutStreamer->AddComment("End Of Macro List Mark"); Asm->emitInt8(0); diff --git a/test/DebugInfo/X86/debug-macro-gnu-dwo.ll b/test/DebugInfo/X86/debug-macro-gnu-dwo.ll new file mode 100644 index 00000000000..b9050a681f7 --- /dev/null +++ b/test/DebugInfo/X86/debug-macro-gnu-dwo.ll @@ -0,0 +1,50 @@ +; It is unclear if the GNU .debug_macro extension is well-specified for split +; DWARF. For now, verify that a .debug_macinfo.dwo section is emitted when +; -gdwarf-4 -gsplit-dwarf -fdebug-macro is specified, regardless of the GNU +; extension being requested. + +; RUN: %llc_dwarf -dwarf-version=4 -O0 -filetype=obj -use-gnu-debug-macro \ +; RUN: -split-dwarf-file=foo.dwo < %s | llvm-dwarfdump -v - | FileCheck %s + +; CHECK: .debug_info.dwo contents: +; CHECK: DW_AT_macro_info [DW_FORM_sec_offset] (0x00000000) + +; CHECK-LABEL: .debug_macinfo.dwo contents: +; CHECK-NEXT: 0x00000000: +; CHECK-NEXT: DW_MACINFO_start_file - lineno: 0 filenum: 1 +; CHECK-NEXT: DW_MACINFO_start_file - lineno: 1 filenum: 2 +; CHECK-NEXT: DW_MACINFO_define - lineno: 1 macro: FOO 5 +; CHECK-NEXT: DW_MACINFO_end_file +; CHECK-NEXT: DW_MACINFO_start_file - lineno: 2 filenum: 3 +; CHECK-NEXT: DW_MACINFO_undef - lineno: 14 macro: YEA +; CHECK-NEXT: DW_MACINFO_end_file +; CHECK-NEXT: DW_MACINFO_undef - lineno: 14 macro: YEA +; CHECK-NEXT: DW_MACINFO_end_file + +; ModuleID = 'test.c' +source_filename = "test.c" +target datalayout = "e-m:e-p200:32:32-p201:32:32-p202:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15, !16} +!llvm.ident = !{!17} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, macros: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/home/") +!2 = !{} +!3 = !{!4} +!4 = !DIMacroFile(file: !1, nodes: !5) +!5 = !{!6, !10, !13} +!6 = !DIMacroFile(line: 1, file: !7, nodes: !8) +!7 = !DIFile(filename: "./foo.h", directory: "/home/") +!8 = !{!9} +!9 = !DIMacro(type: DW_MACINFO_define, line: 1, name: "FOO", value: "5") +!10 = !DIMacroFile(line: 2, file: !11, nodes: !12) +!11 = !DIFile(filename: "./bar.h", directory: "/home/") +!12 = !{!13} +!13 = !DIMacro(type: DW_MACINFO_undef, line: 14, name: "YEA") +!14 = !{i32 7, !"Dwarf Version", i32 4} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{!"clang version 10.0.0"} diff --git a/test/DebugInfo/X86/debug-macro-gnu.ll b/test/DebugInfo/X86/debug-macro-gnu.ll new file mode 100644 index 00000000000..24b90192c99 --- /dev/null +++ b/test/DebugInfo/X86/debug-macro-gnu.ll @@ -0,0 +1,47 @@ +; This test checks emission of the GNU extension for the .debug_macro section. + +; RUN: %llc_dwarf -dwarf-version=4 -O0 -use-gnu-debug-macro -filetype=obj < %s | llvm-dwarfdump -v - | FileCheck %s + +; CHECK-LABEL: .debug_info contents: +; CHECK: DW_AT_GNU_macros [DW_FORM_sec_offset] (0x00000000) + +; CHECK-LABEL: .debug_macro contents: +; CHECK-NEXT: 0x00000000: +; CHECK-NEXT: macro header: version = 0x0004, flags = 0x02, format = DWARF32, debug_line_offset = 0x0000 +; CHECK-NEXT: DW_MACRO_GNU_start_file - lineno: 0 filenum: 1 +; CHECK-NEXT: DW_MACRO_GNU_start_file - lineno: 1 filenum: 2 +; CHECK-NEXT: DW_MACRO_GNU_define_indirect - lineno: 1 macro: FOO 5 +; CHECK-NEXT: DW_MACRO_GNU_end_file +; CHECK-NEXT: DW_MACRO_GNU_start_file - lineno: 2 filenum: 3 +; CHECK-NEXT: DW_MACRO_GNU_undef_indirect - lineno: 14 macro: YEA +; CHECK-NEXT: DW_MACRO_GNU_end_file +; CHECK-NEXT: DW_MACRO_GNU_undef_indirect - lineno: 14 macro: YEA +; CHECK-NEXT: DW_MACRO_GNU_end_file + +; ModuleID = 'test.c' +source_filename = "test.c" +target datalayout = "e-m:e-p200:32:32-p201:32:32-p202:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15, !16} +!llvm.ident = !{!17} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, macros: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/home/") +!2 = !{} +!3 = !{!4} +!4 = !DIMacroFile(file: !1, nodes: !5) +!5 = !{!6, !10, !13} +!6 = !DIMacroFile(line: 1, file: !7, nodes: !8) +!7 = !DIFile(filename: "./foo.h", directory: "/home/") +!8 = !{!9} +!9 = !DIMacro(type: DW_MACINFO_define, line: 1, name: "FOO", value: "5") +!10 = !DIMacroFile(line: 2, file: !11, nodes: !12) +!11 = !DIFile(filename: "./bar.h", directory: "/home/") +!12 = !{!13} +!13 = !DIMacro(type: DW_MACINFO_undef, line: 14, name: "YEA") +!14 = !{i32 7, !"Dwarf Version", i32 4} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{!"clang version 10.0.0"}