From: Amjad Aboud Date: Thu, 7 Jan 2016 14:28:20 +0000 (+0000) Subject: Added support for macro emission in dwarf (supporting DWARF version 4). X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=c8ac066f3572bdade1a2ba73fc4ffc5c755f37c9 Added support for macro emission in dwarf (supporting DWARF version 4). Differential Revision: http://reviews.llvm.org/D15495 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257060 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/DIE.h b/include/llvm/CodeGen/DIE.h index fa612d981de..72b3adc7de9 100644 --- a/include/llvm/CodeGen/DIE.h +++ b/include/llvm/CodeGen/DIE.h @@ -29,6 +29,48 @@ class MCSymbol; class raw_ostream; class DwarfTypeUnit; +// AsmStreamerBase - A base abstract interface class defines methods that +// can be implemented to stream objects or can be implemented to +// calculate the size of the streamed objects. +// The derived classes will use an AsmPrinter to implement the methods. +// +// TODO: complete this interface and use it to merge EmitValue and SizeOf +// methods in the DIE classes below. +class AsmStreamerBase { +protected: + const AsmPrinter *AP; + AsmStreamerBase(const AsmPrinter *AP) : AP(AP) {} + +public: + virtual ~AsmStreamerBase() {} + virtual unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr, + unsigned PadTo = 0) = 0; + virtual unsigned emitInt8(unsigned char Value) = 0; + virtual unsigned emitBytes(StringRef Data) = 0; +}; + +/// EmittingAsmStreamer - Implements AbstractAsmStreamer to stream objects. +/// Notice that the return value is not the actual size of the streamed object. +/// For size calculation use SizeReporterAsmStreamer. +class EmittingAsmStreamer : public AsmStreamerBase { +public: + EmittingAsmStreamer(const AsmPrinter *AP) : AsmStreamerBase(AP) {} + unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr, + unsigned PadTo = 0) override; + unsigned emitInt8(unsigned char Value) override; + unsigned emitBytes(StringRef Data) override; +}; + +/// SizeReporterAsmStreamer - Only reports the size of the streamed objects. +class SizeReporterAsmStreamer : public AsmStreamerBase { +public: + SizeReporterAsmStreamer(const AsmPrinter *AP) : AsmStreamerBase(AP) {} + unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr, + unsigned PadTo = 0) override; + unsigned emitInt8(unsigned char Value) override; + unsigned emitBytes(StringRef Data) override; +}; + //===--------------------------------------------------------------------===// /// DIEAbbrevData - Dwarf abbreviation data, describes one attribute of a /// Dwarf abbreviation. diff --git a/include/llvm/MC/MCObjectFileInfo.h b/include/llvm/MC/MCObjectFileInfo.h index cf2c3f12bb6..8a3a6af3bf7 100644 --- a/include/llvm/MC/MCObjectFileInfo.h +++ b/include/llvm/MC/MCObjectFileInfo.h @@ -92,6 +92,7 @@ protected: 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 @@ public: 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 { diff --git a/lib/CodeGen/AsmPrinter/DIE.cpp b/lib/CodeGen/AsmPrinter/DIE.cpp index bf794f7f70f..7b0cdbde379 100644 --- a/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/lib/CodeGen/AsmPrinter/DIE.cpp @@ -31,6 +31,39 @@ #include "llvm/Support/raw_ostream.h" using namespace llvm; +//===----------------------------------------------------------------------===// +// EmittingAsmStreamer Implementation +//===----------------------------------------------------------------------===// +unsigned EmittingAsmStreamer::emitULEB128(uint64_t Value, const char *Desc, + unsigned PadTo) { + AP->EmitULEB128(Value, Desc, PadTo); + return 0; +} + +unsigned EmittingAsmStreamer::emitInt8(unsigned char Value) { + AP->EmitInt8(Value); + return 0; +} + +unsigned EmittingAsmStreamer::emitBytes(StringRef Data) { + AP->OutStreamer->EmitBytes(Data); + return 0; +} + +//===----------------------------------------------------------------------===// +// SizeReporterAsmStreamer Implementation +//===----------------------------------------------------------------------===// +unsigned SizeReporterAsmStreamer::emitULEB128(uint64_t Value, const char *Desc, + unsigned PadTo) { + return getULEB128Size(Value); +} + +unsigned SizeReporterAsmStreamer::emitInt8(unsigned char Value) { return 1; } + +unsigned SizeReporterAsmStreamer::emitBytes(StringRef Data) { + return Data.size(); +} + //===----------------------------------------------------------------------===// // DIEAbbrevData Implementation //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 3466f3469f1..b8fec2bb704 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -561,6 +561,8 @@ void DwarfDebug::finalizeModuleInfo() { // Collect info for variables that were optimized out. collectDeadVariables(); + unsigned MacroOffset = 0; + std::unique_ptr AS(new SizeReporterAsmStreamer(Asm)); // Handle anything that needs to be done on a per-unit basis after // all other generation. for (const auto &P : CUMap) { @@ -613,6 +615,15 @@ void DwarfDebug::finalizeModuleInfo() { 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 + MacroOffset += handleMacroNodes(AS.get(), CUNode->getMacros(), U); + } } // Compute DIE offsets and sizes. @@ -656,6 +667,9 @@ void DwarfDebug::endModule() { // Emit info into a debug ranges section. emitDebugRanges(); + // Emit info into a debug macinfo section. + emitDebugMacinfo(); + if (useSplitDwarf()) { emitDebugStrDWO(); emitDebugInfoDWO(); @@ -1833,6 +1847,70 @@ void DwarfDebug::emitDebugRanges() { } } +unsigned DwarfDebug::handleMacroNodes(AsmStreamerBase *AS, + DIMacroNodeArray Nodes, + DwarfCompileUnit &U) { + unsigned Size = 0; + for (auto *MN : Nodes) { + if (auto *M = dyn_cast(MN)) + Size += emitMacro(AS, *M); + else if (auto *F = dyn_cast(MN)) + Size += emitMacroFile(AS, *F, U); + else + llvm_unreachable("Unexpected DI type!"); + } + return Size; +} + +unsigned DwarfDebug::emitMacro(AsmStreamerBase *AS, DIMacro &M) { + int Size = 0; + Size += AS->emitULEB128(M.getMacinfoType()); + Size += AS->emitULEB128(M.getLine()); + StringRef Name = M.getName(); + StringRef Value = M.getValue(); + Size += AS->emitBytes(Name); + if (!Value.empty()) { + // There should be one space between macro name and macro value. + Size += AS->emitInt8(' '); + Size += AS->emitBytes(Value); + } + Size += AS->emitInt8('\0'); + return Size; +} + +unsigned DwarfDebug::emitMacroFile(AsmStreamerBase *AS, DIMacroFile &F, + DwarfCompileUnit &U) { + int Size = 0; + assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file); + Size += AS->emitULEB128(dwarf::DW_MACINFO_start_file); + Size += AS->emitULEB128(F.getLine()); + DIFile *File = F.getFile(); + unsigned FID = + U.getOrCreateSourceID(File->getFilename(), File->getDirectory()); + Size += AS->emitULEB128(FID); + Size += handleMacroNodes(AS, F.getElements(), U); + Size += AS->emitULEB128(dwarf::DW_MACINFO_end_file); + return Size; +} + +// 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); + } + std::unique_ptr AS(new EmittingAsmStreamer(Asm)); + for (const auto &P : CUMap) { + auto &TheCU = *P.second; + auto *SkCU = TheCU.getSkeleton(); + DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; + auto *CUNode = cast(P.first); + handleMacroNodes(AS.get(), 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, diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 4c613a90545..460c186683f 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -400,18 +400,26 @@ class DwarfDebug : public AsmPrinterHandler { /// 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 emitMacro(AsmStreamerBase *AS, DIMacro &M); + unsigned emitMacroFile(AsmStreamerBase *AS, DIMacroFile &F, + DwarfCompileUnit &U); + unsigned handleMacroNodes(AsmStreamerBase *AS, DIMacroNodeArray Nodes, + DwarfCompileUnit &U); + /// DWARF 5 Experimental Split Dwarf Emitters /// Initialize common features of skeleton units. diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index fb42ea16c99..64d7575b8a1 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -984,6 +984,9 @@ void Verifier::visitDIMacro(const DIMacro &N) { 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) { diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp index 34f49cac162..f86f7e40acb 100644 --- a/lib/MC/MCObjectFileInfo.cpp +++ b/lib/MC/MCObjectFileInfo.cpp @@ -256,6 +256,9 @@ void MCObjectFileInfo::initMachOMCObjectFileInfo(Triple T) { 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 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(Triple T) { 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 @@ -684,6 +689,11 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(Triple T) { 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 | diff --git a/lib/Target/NVPTX/NVPTXISelLowering.cpp b/lib/Target/NVPTX/NVPTXISelLowering.cpp index 766369631e1..be735f6c1bc 100644 --- a/lib/Target/NVPTX/NVPTXISelLowering.cpp +++ b/lib/Target/NVPTX/NVPTXISelLowering.cpp @@ -4549,6 +4549,7 @@ NVPTXTargetObjectFile::~NVPTXTargetObjectFile() { delete static_cast(DwarfLocSection); delete static_cast(DwarfARangesSection); delete static_cast(DwarfRangesSection); + delete static_cast(DwarfMacinfoSection); } MCSection * diff --git a/lib/Target/NVPTX/NVPTXTargetObjectFile.h b/lib/Target/NVPTX/NVPTXTargetObjectFile.h index 0f88ddfaa93..683b9a3f49f 100644 --- a/lib/Target/NVPTX/NVPTXTargetObjectFile.h +++ b/lib/Target/NVPTX/NVPTXTargetObjectFile.h @@ -41,6 +41,7 @@ public: DwarfLocSection = nullptr; DwarfARangesSection = nullptr; DwarfRangesSection = nullptr; + DwarfMacinfoSection = nullptr; } virtual ~NVPTXTargetObjectFile(); @@ -81,6 +82,8 @@ public: 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, diff --git a/test/DebugInfo/X86/debug-macro.ll b/test/DebugInfo/X86/debug-macro.ll new file mode 100644 index 00000000000..b79e2de5ca4 --- /dev/null +++ b/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: "/")