Index: include/llvm/MC/MCObjectFileInfo.h =================================================================== --- include/llvm/MC/MCObjectFileInfo.h +++ include/llvm/MC/MCObjectFileInfo.h @@ -92,6 +92,7 @@ MCSection *DwarfLocSection; MCSection *DwarfARangesSection; MCSection *DwarfRangesSection; + MCSection *DwarfMacinfoSection; // The pubnames section is no longer generated by default. The generation // can be enabled by a compiler flag. MCSection *DwarfPubNamesSection; @@ -245,6 +246,7 @@ MCSection *getDwarfLocSection() const { return DwarfLocSection; } MCSection *getDwarfARangesSection() const { return DwarfARangesSection; } MCSection *getDwarfRangesSection() const { return DwarfRangesSection; } + MCSection *getDwarfMacinfoSection() const { return DwarfMacinfoSection; } // DWARF5 Experimental Debug Info Sections MCSection *getDwarfAccelNamesSection() const { Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -423,18 +423,29 @@ /// Emit visible names into a debug str section. void emitDebugStr(); - /// Emit visible names into a debug loc section. + /// Emit variable locations into a debug loc section. void emitDebugLoc(); - /// Emit visible names into a debug loc dwo section. + /// Emit variable locations into a debug loc dwo section. void emitDebugLocDWO(); - /// Emit visible names into a debug aranges section. + /// Emit address ranges into a debug aranges section. void emitDebugARanges(); - /// Emit visible names into a debug ranges section. + /// Emit address ranges into a debug ranges section. void emitDebugRanges(); + /// Emit macros into a debug macinfo section. + void emitDebugMacinfo(); + unsigned getMacroSize(DIMacro &M); + void emitMacro(DIMacro &M); + unsigned getMacroFileSize(DIMacroFile &F, DwarfCompileUnit &U); + void emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U); + // If Size is not nullptr it calculates size required for emitting macro + // nodes, otherwise it emits the nodes. + void handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U, + unsigned *Size = nullptr); + /// DWARF 5 Experimental Split Dwarf Emitters /// Initialize common features of skeleton units. Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -572,6 +572,7 @@ // Collect info for variables that were optimized out. collectDeadVariables(); + unsigned MacroOffset = 0; // Handle anything that needs to be done on a per-unit basis after // all other generation. for (const auto &P : CUMap) { @@ -624,6 +625,20 @@ U.setBaseAddress(TheCU.getRanges().front().getStart()); U.attachRangesOrLowHighPC(U.getUnitDie(), TheCU.takeRanges()); } + + auto *CUNode = cast(P.first); + if (CUNode->getMacros()) { + // Compile Unit has macros, emit "DW_AT_macro_info" attribute. + U.addUInt(U.getUnitDie(), dwarf::DW_AT_macro_info, + dwarf::DW_FORM_sec_offset, MacroOffset); + } + // Update macro section offset + for (auto *MN : CUNode->getMacros()) { + if (auto *M = dyn_cast(MN)) + MacroOffset += getMacroSize(*M); + else if (auto *F = dyn_cast(MN)) + MacroOffset += getMacroFileSize(*F, U); + } } // Compute DIE offsets and sizes. @@ -667,6 +682,9 @@ // Emit info into a debug ranges section. emitDebugRanges(); + // Emit info into a debug macinfo section. + emitDebugMacinfo(); + if (useSplitDwarf()) { emitDebugStrDWO(); emitDebugInfoDWO(); @@ -1844,6 +1862,103 @@ } } +unsigned DwarfDebug::getMacroSize(DIMacro &M) { + unsigned Size = 0; + Size += getULEB128Size(M.getMacinfoType()); + Size += getULEB128Size(M.getLine()); + StringRef Name = M.getName(); + StringRef Value = M.getValue(); + Size += Name.size(); + if (!Value.empty()) { + // There should be one space between macro name and macro value. + Size += 1; // Space + Size += Value.size(); + } + Size += 1; // null-terminator + + return Size; +} + +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); + } + Asm->EmitInt8('\0'); +} + +void DwarfDebug::handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U, + unsigned *Size) { + for (auto *MN : Nodes) { + if (auto *M = dyn_cast(MN)) { + if (Size) + *Size += getMacroSize(*M); + else + emitMacro(*M); + } else if (auto *F = dyn_cast(MN)) { + if (Size) + *Size += getMacroFileSize(*F, U); + else + emitMacroFile(*F, U); + } else + llvm_unreachable("Unexpected DI type!"); + } +} + +unsigned DwarfDebug::getMacroFileSize(DIMacroFile &F, DwarfCompileUnit &U) { + unsigned Size = 0; + assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file); + Size += getULEB128Size(dwarf::DW_MACINFO_start_file); + Size += getULEB128Size(F.getLine()); + DIFile *File = F.getFile(); + unsigned FID = + U.getOrCreateSourceID(File->getFilename(), File->getDirectory()); + Size += getULEB128Size(FID); + + handleMacroNodes(F.getElements(), U, &Size); + + Size += getULEB128Size(dwarf::DW_MACINFO_end_file); + return Size; +} + +void DwarfDebug::emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U) { + assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file); + Asm->EmitULEB128(dwarf::DW_MACINFO_start_file); + Asm->EmitULEB128(F.getLine()); + DIFile *File = F.getFile(); + unsigned FID = + U.getOrCreateSourceID(File->getFilename(), File->getDirectory()); + Asm->EmitULEB128(FID); + + handleMacroNodes(F.getElements(), U); + + Asm->EmitULEB128(dwarf::DW_MACINFO_end_file); +} + +// Emit visible names into a debug macinfo section. +void DwarfDebug::emitDebugMacinfo() { + if (MCSection *Macinfo = Asm->getObjFileLowering().getDwarfMacinfoSection()) { + // Start the dwarf macinfo section. + Asm->OutStreamer->SwitchSection(Macinfo); + } + + for (const auto &P : CUMap) { + auto &TheCU = *P.second; + auto *SkCU = TheCU.getSkeleton(); + DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; + auto *CUNode = cast(P.first); + handleMacroNodes(CUNode->getMacros(), U); + } + Asm->OutStreamer->AddComment("End Of Macro List Mark"); + Asm->EmitInt8(0); +} + // DWARF5 Experimental Separate Dwarf emitters. void DwarfDebug::initSkeletonUnit(const DwarfUnit &U, DIE &Die, Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -983,6 +983,9 @@ N.getMacinfoType() == dwarf::DW_MACINFO_undef, "invalid macinfo type", &N); Assert(!N.getName().empty(), "anonymous macro", &N); + if (!N.getValue().empty()) { + assert(N.getValue().data()[0] != ' ' && "Macro value has a space prefix"); + } } void Verifier::visitDIMacroFile(const DIMacroFile &N) { Index: lib/MC/MCObjectFileInfo.cpp =================================================================== --- lib/MC/MCObjectFileInfo.cpp +++ lib/MC/MCObjectFileInfo.cpp @@ -256,6 +256,9 @@ DwarfRangesSection = Ctx->getMachOSection("__DWARF", "__debug_ranges", MachO::S_ATTR_DEBUG, SectionKind::getMetadata(), "debug_range"); + DwarfMacinfoSection = + Ctx->getMachOSection("__DWARF", "__debug_macinfo", MachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); DwarfDebugInlineSection = Ctx->getMachOSection("__DWARF", "__debug_inlined", MachO::S_ATTR_DEBUG, SectionKind::getMetadata()); @@ -505,6 +508,8 @@ Ctx->getELFSection(".debug_aranges", ELF::SHT_PROGBITS, 0); DwarfRangesSection = Ctx->getELFSection(".debug_ranges", ELF::SHT_PROGBITS, 0, "debug_range"); + DwarfMacinfoSection = + Ctx->getELFSection(".debug_macinfo", ELF::SHT_PROGBITS, 0); // DWARF5 Experimental Debug Info @@ -685,6 +690,11 @@ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getMetadata(), "debug_range"); + DwarfMacinfoSection = Ctx->getCOFFSection( + ".debug_macinfo", + COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); DwarfInfoDWOSection = Ctx->getCOFFSection( ".debug_info.dwo", COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | Index: lib/Target/NVPTX/NVPTXISelLowering.cpp =================================================================== --- lib/Target/NVPTX/NVPTXISelLowering.cpp +++ lib/Target/NVPTX/NVPTXISelLowering.cpp @@ -4549,6 +4549,7 @@ delete static_cast(DwarfLocSection); delete static_cast(DwarfARangesSection); delete static_cast(DwarfRangesSection); + delete static_cast(DwarfMacinfoSection); } MCSection * Index: lib/Target/NVPTX/NVPTXTargetObjectFile.h =================================================================== --- lib/Target/NVPTX/NVPTXTargetObjectFile.h +++ lib/Target/NVPTX/NVPTXTargetObjectFile.h @@ -41,6 +41,7 @@ DwarfLocSection = nullptr; DwarfARangesSection = nullptr; DwarfRangesSection = nullptr; + DwarfMacinfoSection = nullptr; } virtual ~NVPTXTargetObjectFile(); @@ -81,6 +82,8 @@ new NVPTXSection(MCSection::SV_ELF, SectionKind::getMetadata()); DwarfRangesSection = new NVPTXSection(MCSection::SV_ELF, SectionKind::getMetadata()); + DwarfMacinfoSection = + new NVPTXSection(MCSection::SV_ELF, SectionKind::getMetadata()); } MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, Index: test/DebugInfo/X86/debug-macro.ll =================================================================== --- test/DebugInfo/X86/debug-macro.ll +++ test/DebugInfo/X86/debug-macro.ll @@ -0,0 +1,67 @@ +; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-dump=info - | FileCheck --check-prefix=CHECK-INFO %s +; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-dump=macro - | FileCheck --check-prefix=CHECK-MACRO %s +; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-dump=line - | FileCheck --check-prefix=CHECK-LINE %s + + +; CHECK-INFO: .debug_info contents: +; CHECK-INFO: DW_TAG_compile_unit +; CHECK-INFO-NOT: DW_TAG +; CHECK-INFO: DW_AT_name {{.*}}"debug-macro.cpp") +; CHECK-INFO: DW_AT_macro_info {{.*}}(0x00000000) +; CHECK-INFO: DW_TAG_compile_unit +; CHECK-INFO-NOT: DW_TAG +; CHECK-INFO: DW_AT_name {{.*}}"debug-macro1.cpp") +; CHECK-INFO: DW_AT_macro_info {{.*}}(0x00000044) +; CHECK-INFO: DW_TAG_compile_unit +; CHECK-INFO-NOT: DW_TAG +; CHECK-INFO: DW_AT_name {{.*}}"debug-macro2.cpp") +; CHECK-INFO-NOT: DW_AT_macro_info + +; CHECK-MACRO: .debug_macinfo contents: +; CHECK-MACRO-NEXT: DW_MACINFO_define - lineno: 0 macro: NameCMD ValueCMD +; CHECK-MACRO-NEXT: DW_MACINFO_start_file - lineno: 0 filenum: 1 +; CHECK-MACRO-NEXT: DW_MACINFO_start_file - lineno: 9 filenum: 2 +; CHECK-MACRO-NEXT: DW_MACINFO_define - lineno: 1 macro: NameDef Value +; CHECK-MACRO-NEXT: DW_MACINFO_undef - lineno: 11 macro: NameUndef +; CHECK-MACRO-NEXT: DW_MACINFO_end_file +; CHECK-MACRO-NEXT: DW_MACINFO_undef - lineno: 10 macro: NameUndef2 +; CHECK-MACRO-NEXT: DW_MACINFO_end_file +; CHECK-MACRO-NEXT: DW_MACINFO_start_file - lineno: 0 filenum: 1 +; CHECK-MACRO-NEXT: DW_MACINFO_end_file + +; CHECK-LINE: .debug_line contents: +; CHECK-LINE: Dir Mod Time File Len File Name +; CHECK-LINE: file_names[ 1] {{.*}}debug-macro.cpp +; CHECK-LINE: file_names[ 2] {{.*}}debug-macro.h +; CHECK-LINE: Dir Mod Time File Len File Name +; CHECK-LINE: file_names[ 1] {{.*}}debug-macro1.cpp + +!llvm.dbg.cu = !{!0, !16, !20} +!llvm.module.flags = !{!13, !14} +!llvm.ident = !{!15} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5.0 ", isOptimized: false, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, subprograms: !2, globals: !2, imports: !2, macros: !3) +!1 = !DIFile(filename: "debug-macro.cpp", directory: "/") +!2 = !{} +!3 = !{!4, !5} +!4 = !DIMacro(type: DW_MACINFO_define, line: 0, name: "NameCMD", value: "ValueCMD") +!5 = !DIMacroFile(line: 0, file: !1, nodes: !6) +!6 = !{!7, !12} +!7 = !DIMacroFile(line: 9, file: !8, nodes: !9) +!8 = !DIFile(filename: "debug-macro.h", directory: "/") +!9 = !{!10, !11} +!10 = !DIMacro(type: DW_MACINFO_define, line: 1, name: "NameDef", value: "Value") +!11 = !DIMacro(type: DW_MACINFO_undef, line: 11, name: "NameUndef") +!12 = !DIMacro(type: DW_MACINFO_undef, line: 10, name: "NameUndef2") + +!13 = !{i32 2, !"Dwarf Version", i32 4} +!14 = !{i32 1, !"Debug Info Version", i32 3} +!15 = !{!"clang version 3.5.0 "} + +!16 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5.0 ", isOptimized: false, emissionKind: 1, file: !17, enums: !2, retainedTypes: !2, subprograms: !2, globals: !2, imports: !2, macros: !18) +!17 = !DIFile(filename: "debug-macro1.cpp", directory: "/") +!18 = !{!19} +!19 = !DIMacroFile(line: 0, file: !17, nodes: !2) + +!20 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5.0 ", isOptimized: false, emissionKind: 1, file: !21, enums: !2, retainedTypes: !2, subprograms: !2, globals: !2, imports: !2) +!21 = !DIFile(filename: "debug-macro2.cpp", directory: "/") \ No newline at end of file