Index: llvm/include/llvm/MC/MCObjectFileInfo.h =================================================================== --- llvm/include/llvm/MC/MCObjectFileInfo.h +++ llvm/include/llvm/MC/MCObjectFileInfo.h @@ -89,6 +89,7 @@ MCSection *DwarfARangesSection = nullptr; MCSection *DwarfRangesSection = nullptr; MCSection *DwarfMacinfoSection = nullptr; + MCSection *DwarfMacroSection = nullptr; // The pubnames section is no longer generated by default. The generation // can be enabled by a compiler flag. MCSection *DwarfPubNamesSection = nullptr; @@ -275,6 +276,7 @@ MCSection *getDwarfRnglistsSection() const { return DwarfRnglistsSection; } MCSection *getDwarfLoclistsSection() const { return DwarfLoclistsSection; } MCSection *getDwarfMacinfoSection() const { return DwarfMacinfoSection; } + MCSection *getDwarfMacroSection() const { return DwarfMacroSection; } MCSection *getDwarfDebugNamesSection() const { return DwarfDebugNamesSection; Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -528,6 +528,9 @@ void emitDebugMacinfoImpl(MCSection *Section); void emitMacro(DIMacro &M); void emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U); + void emitMacroFileImpl(DIMacroFile &F, DwarfCompileUnit &U, + unsigned StartFile, unsigned EndFile, + StringRef (*MacroFormToString)(unsigned Form)); void handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U); /// DWARF 5 Experimental Split Dwarf Emitters Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1288,18 +1288,29 @@ } auto *CUNode = cast(P.first); - // If compile Unit has macros, emit "DW_AT_macro_info" attribute. + // If compile Unit has macros, emit "DW_AT_macro_info/DW_AT_macros" + // attribute. if (CUNode->getMacros()) { - if (useSplitDwarf()) - TheCU.addSectionDelta(TheCU.getUnitDie(), dwarf::DW_AT_macro_info, + if (getDwarfVersion() >= 5) { + // FIXME: Add support for DWARFv5 DW_AT_macros attribute for split + // case. + if (!useSplitDwarf()) + U.addSectionLabel(U.getUnitDie(), dwarf::DW_AT_macros, U.getMacroLabelBegin(), - TLOF.getDwarfMacinfoDWOSection()->getBeginSymbol()); - else - U.addSectionLabel(U.getUnitDie(), dwarf::DW_AT_macro_info, - U.getMacroLabelBegin(), - TLOF.getDwarfMacinfoSection()->getBeginSymbol()); + TLOF.getDwarfMacroSection()->getBeginSymbol()); + } else { + if (useSplitDwarf()) + TheCU.addSectionDelta( + TheCU.getUnitDie(), dwarf::DW_AT_macro_info, + U.getMacroLabelBegin(), + TLOF.getDwarfMacinfoDWOSection()->getBeginSymbol()); + else + U.addSectionLabel(U.getUnitDie(), dwarf::DW_AT_macro_info, + U.getMacroLabelBegin(), + TLOF.getDwarfMacinfoSection()->getBeginSymbol()); + } + } } - } // Emit all frontend-produced Skeleton CUs, i.e., Clang modules. for (auto *CUNode : MMI->getModule()->debug_compile_units()) @@ -1355,7 +1366,7 @@ // Emit info into a debug macinfo.dwo section. emitDebugMacinfoDWO(); else - // Emit info into a debug macinfo section. + // Emit info into a debug macinfo/macro section. emitDebugMacinfo(); emitDebugStr(); @@ -2854,6 +2865,27 @@ Asm->getObjFileLowering().getDwarfRnglistsDWOSection()); } +/// Emit the header of a DWARF 5 macro section. +static void emitMacroHeader(AsmPrinter *Asm, const DwarfDebug &DD, + const DwarfCompileUnit &CU) { + 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); + // We are setting Offset and line offset flags unconditionally here, + // since we're only supporting DWARF32 and line offset should be mostly + // present. + // FIXME: Add support for DWARF64. + Flags |= MACRO_FLAG_DEBUG_LINE_OFFSET; + Asm->OutStreamer->AddComment("Flags: 32 bit, debug_line_offset present"); + Asm->emitInt8(Flags); + Asm->OutStreamer->AddComment("debug_line_offset"); + Asm->OutStreamer->emitSymbolValue(CU.getLineTableStartSym(), /*Size=*/4); +} + void DwarfDebug::handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U) { for (auto *MN : Nodes) { if (auto *M = dyn_cast(MN)) @@ -2866,26 +2898,75 @@ } void DwarfDebug::emitMacro(DIMacro &M) { - Asm->emitULEB128(M.getMacinfoType()); - Asm->emitULEB128(M.getLine()); StringRef Name = M.getName(); StringRef Value = M.getValue(); - Asm->OutStreamer->emitBytes(Name); - if (!Value.empty()) { - // There should be one space between macro name and macro value. - Asm->emitInt8(' '); - Asm->OutStreamer->emitBytes(Value); + bool UseMacro = getDwarfVersion() >= 5; + + if (UseMacro) { + unsigned Type = M.getMacinfoType() == dwarf::DW_MACINFO_define + ? dwarf::DW_MACRO_define_strp + : dwarf::DW_MACRO_undef_strp; + Asm->OutStreamer->AddComment(dwarf::MacroString(Type)); + Asm->emitULEB128(Type); + Asm->OutStreamer->AddComment("Line Number"); + Asm->emitULEB128(M.getLine()); + Asm->OutStreamer->AddComment("Macro String"); + if (!Value.empty()) + Asm->OutStreamer->emitSymbolValue( + this->InfoHolder.getStringPool() + .getEntry(*Asm, (Name + " " + Value).str()) + .getSymbol(), + 4); + else + // DW_MACRO_undef_strp doesn't have a value, so just emit the macro + // string. + Asm->OutStreamer->emitSymbolValue(this->InfoHolder.getStringPool() + .getEntry(*Asm, (Name).str()) + .getSymbol(), + 4); + } else { + Asm->OutStreamer->AddComment(dwarf::MacinfoString(M.getMacinfoType())); + Asm->emitULEB128(M.getMacinfoType()); + Asm->OutStreamer->AddComment("Line Number"); + Asm->emitULEB128(M.getLine()); + Asm->OutStreamer->AddComment("Macro String"); + Asm->OutStreamer->emitBytes(Name); + if (!Value.empty()) { + // There should be one space between macro name and macro value. + Asm->emitInt8(' '); + Asm->OutStreamer->AddComment("Macro Value="); + Asm->OutStreamer->emitBytes(Value); + } + Asm->emitInt8('\0'); } - Asm->emitInt8('\0'); } -void DwarfDebug::emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U) { - assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file); - Asm->emitULEB128(dwarf::DW_MACINFO_start_file); +void DwarfDebug::emitMacroFileImpl( + DIMacroFile &F, DwarfCompileUnit &U, unsigned StartFile, unsigned EndFile, + StringRef (*MacroFormToString)(unsigned Form)) { + + Asm->OutStreamer->AddComment(MacroFormToString(StartFile)); + Asm->emitULEB128(StartFile); + Asm->OutStreamer->AddComment("Line Number"); Asm->emitULEB128(F.getLine()); + Asm->OutStreamer->AddComment("File Number"); Asm->emitULEB128(U.getOrCreateSourceID(F.getFile())); handleMacroNodes(F.getElements(), U); - Asm->emitULEB128(dwarf::DW_MACINFO_end_file); + Asm->OutStreamer->AddComment(MacroFormToString(EndFile)); + Asm->emitULEB128(EndFile); +} + +void DwarfDebug::emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U) { + // DWARFv5 macro and DWARFv4 macinfo share some common encodings, + // so for readibility/uniformity, We are explicitly emitting those. + assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file); + bool UseMacro = getDwarfVersion() >= 5; + if (UseMacro) + emitMacroFileImpl(F, U, dwarf::DW_MACRO_start_file, + dwarf::DW_MACRO_end_file, dwarf::MacroString); + else + emitMacroFileImpl(F, U, dwarf::DW_MACINFO_start_file, + dwarf::DW_MACINFO_end_file, dwarf::MacinfoString); } void DwarfDebug::emitDebugMacinfoImpl(MCSection *Section) { @@ -2899,18 +2980,26 @@ continue; Asm->OutStreamer->SwitchSection(Section); Asm->OutStreamer->emitLabel(U.getMacroLabelBegin()); + if (getDwarfVersion() >= 5) + emitMacroHeader(Asm, *this, U); handleMacroNodes(Macros, U); Asm->OutStreamer->AddComment("End Of Macro List Mark"); Asm->emitInt8(0); } } -/// Emit macros into a debug macinfo section. +/// Emit macros into a debug macinfo/macro section. void DwarfDebug::emitDebugMacinfo() { - emitDebugMacinfoImpl(Asm->getObjFileLowering().getDwarfMacinfoSection()); + auto &ObjLower = Asm->getObjFileLowering(); + emitDebugMacinfoImpl(getDwarfVersion() >= 5 + ? ObjLower.getDwarfMacroSection() + : ObjLower.getDwarfMacinfoSection()); } void DwarfDebug::emitDebugMacinfoDWO() { + // FIXME: Add support for macro.dwo section. + if (getDwarfVersion() >= 5) + return; emitDebugMacinfoImpl(Asm->getObjFileLowering().getDwarfMacinfoDWOSection()); } Index: llvm/lib/MC/MCObjectFileInfo.cpp =================================================================== --- llvm/lib/MC/MCObjectFileInfo.cpp +++ llvm/lib/MC/MCObjectFileInfo.cpp @@ -276,6 +276,9 @@ DwarfMacinfoSection = Ctx->getMachOSection("__DWARF", "__debug_macinfo", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "debug_macinfo"); + DwarfMacroSection = + Ctx->getMachOSection("__DWARF", "__debug_macro", MachO::S_ATTR_DEBUG, + SectionKind::getMetadata(), "debug_macro"); DwarfDebugInlineSection = Ctx->getMachOSection("__DWARF", "__debug_inlined", MachO::S_ATTR_DEBUG, SectionKind::getMetadata()); @@ -427,6 +430,7 @@ Ctx->getELFSection(".debug_ranges", DebugSecType, 0); DwarfMacinfoSection = Ctx->getELFSection(".debug_macinfo", DebugSecType, 0); + DwarfMacroSection = Ctx->getELFSection(".debug_macro", DebugSecType, 0); // DWARF5 Experimental Debug Info @@ -635,6 +639,11 @@ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getMetadata(), "debug_macinfo"); + DwarfMacroSection = Ctx->getCOFFSection( + ".debug_macro", + COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata(), "debug_macro"); DwarfMacinfoDWOSection = Ctx->getCOFFSection( ".debug_macinfo.dwo", COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | @@ -771,6 +780,8 @@ Ctx->getWasmSection(".debug_ranges", SectionKind::getMetadata()); DwarfMacinfoSection = Ctx->getWasmSection(".debug_macinfo", SectionKind::getMetadata()); + DwarfMacroSection = + Ctx->getWasmSection(".debug_macro", SectionKind::getMetadata()); DwarfCUIndexSection = Ctx->getWasmSection(".debug_cu_index", SectionKind::getMetadata()); DwarfTUIndexSection = Ctx->getWasmSection(".debug_tu_index", SectionKind::getMetadata()); DwarfInfoSection = Index: llvm/test/DebugInfo/X86/debug-macro-v5.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/debug-macro-v5.ll @@ -0,0 +1,73 @@ +; This test checks emission of .debug_macro section when +; -gdwarf-5 -fdebug-macro is specified. + +; RUN: %llc_dwarf -dwarf-version=5 -O0 -filetype=obj < %s \ +; | llvm-dwarfdump -v - | FileCheck %s + +; CHECK-LABEL: .debug_info contents: +; CHECK: DW_AT_macros [DW_FORM_sec_offset] (0x00000000) + +; CHECK-LABEL: .debug_macro contents: +; CHECK-NEXT: 0x00000000: +; CHECK-NEXT: macro header: version = 0x0005, flags = 0x02, debug_line_offset = 0x0000 +; CHECK-NEXT: DW_MACRO_start_file - lineno: 0 filenum: 0 +; CHECK-NEXT: DW_MACRO_start_file - lineno: 1 filenum: 1 +; CHECK-NEXT: DW_MACRO_define_strp - lineno: 1 macro: FOO 5 +; CHECK-NEXT: DW_MACRO_end_file +; CHECK-NEXT: DW_MACRO_start_file - lineno: 2 filenum: 2 +; CHECK-NEXT: DW_MACRO_undef_strp - lineno: 14 macro: YEA +; CHECK-NEXT: DW_MACRO_end_file +; CHECK-NEXT: DW_MACRO_undef_strp - lineno: 14 macro: YEA +; CHECK-NEXT: DW_MACRO_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" +; Function Attrs: noinline nounwind optnone uwtable +define dso_local i32 @main() #0 !dbg !18 { + %1 = alloca i32, align 4 + %2 = alloca i32, align 4 + call void @llvm.dbg.declare(metadata i32* %1, metadata !22, metadata !DIExpression()), !dbg !23 + store i32 3, i32* %1, align 4, !dbg !23 + call void @llvm.dbg.declare(metadata i32* %2, metadata !24, metadata !DIExpression()), !dbg !25 + store i32 5, i32* %2, align 4, !dbg !25 + ret i32 0, !dbg !26 +} +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind optnone uwtable } +attributes #1 = { nounwind readnone speculatable willreturn } + +!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/", checksumkind: CSK_MD5, checksum: "ef6a7032e0c7ceeef614583f2c00dc80") +!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/", checksumkind: CSK_MD5, checksum: "0f0cd0e15b44f49d3944992c8dc28661") +!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/", checksumkind: CSK_MD5, checksum: "bf4b34c263eaaa1d7085c18243b8d100") +!12 = !{!13} +!13 = !DIMacro(type: DW_MACINFO_undef, line: 14, name: "YEA") +!14 = !{i32 7, !"Dwarf Version", i32 5} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{!"clang version 10.0.0"} +!18 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 9, type: !19, scopeLine: 9, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!19 = !DISubroutineType(types: !20) +!20 = !{!21} +!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!22 = !DILocalVariable(name: "a", scope: !18, file: !1, line: 10, type: !21) +!23 = !DILocation(line: 10, column: 5, scope: !18) +!24 = !DILocalVariable(name: "b", scope: !18, file: !1, line: 11, type: !21) +!25 = !DILocation(line: 11, column: 5, scope: !18) +!26 = !DILocation(line: 12, column: 1, scope: !18)