Added support for macro emission in dwarf (supporting DWARF version 4).
authorAmjad Aboud <amjad.aboud@intel.com>
Thu, 7 Jan 2016 14:28:20 +0000 (14:28 +0000)
committerAmjad Aboud <amjad.aboud@intel.com>
Thu, 7 Jan 2016 14:28:20 +0000 (14:28 +0000)
Differential Revision: http://reviews.llvm.org/D15495

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257060 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/DIE.h
include/llvm/MC/MCObjectFileInfo.h
lib/CodeGen/AsmPrinter/DIE.cpp
lib/CodeGen/AsmPrinter/DwarfDebug.cpp
lib/CodeGen/AsmPrinter/DwarfDebug.h
lib/IR/Verifier.cpp
lib/MC/MCObjectFileInfo.cpp
lib/Target/NVPTX/NVPTXISelLowering.cpp
lib/Target/NVPTX/NVPTXTargetObjectFile.h
test/DebugInfo/X86/debug-macro.ll [new file with mode: 0644]

index fa612d9..72b3adc 100644 (file)
@@ -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.
index cf2c3f1..8a3a6af 100644 (file)
@@ -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 {
index bf794f7..7b0cdbd 100644 (file)
 #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
 //===----------------------------------------------------------------------===//
index 3466f34..b8fec2b 100644 (file)
@@ -561,6 +561,8 @@ void DwarfDebug::finalizeModuleInfo() {
   // Collect info for variables that were optimized out.
   collectDeadVariables();
 
+  unsigned MacroOffset = 0;
+  std::unique_ptr<AsmStreamerBase> 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<DICompileUnit>(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<DIMacro>(MN))
+      Size += emitMacro(AS, *M);
+    else if (auto *F = dyn_cast<DIMacroFile>(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<AsmStreamerBase> 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<DICompileUnit>(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,
index 4c613a9..460c186 100644 (file)
@@ -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.
index fb42ea1..64d7575 100644 (file)
@@ -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) {
index 34f49ca..f86f7e4 100644 (file)
@@ -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 |
index 7663696..be735f6 100644 (file)
@@ -4549,6 +4549,7 @@ NVPTXTargetObjectFile::~NVPTXTargetObjectFile() {
   delete static_cast<NVPTXSection *>(DwarfLocSection);
   delete static_cast<NVPTXSection *>(DwarfARangesSection);
   delete static_cast<NVPTXSection *>(DwarfRangesSection);
+  delete static_cast<NVPTXSection *>(DwarfMacinfoSection);
 }
 
 MCSection *
index 0f88ddf..683b9a3 100644 (file)
@@ -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 (file)
index 0000000..b79e2de
--- /dev/null
@@ -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: "/")