The second part of support for generating dwarf for assembly source files. This
authorKevin Enderby <enderby@apple.com>
Fri, 9 Dec 2011 18:09:40 +0000 (18:09 +0000)
committerKevin Enderby <enderby@apple.com>
Fri, 9 Dec 2011 18:09:40 +0000 (18:09 +0000)
generates the dwarf Compile Unit DIE and a dwarf subprogram DIE for each
non-temporary label.

The next part will be to get the clang driver to enable this when assembling
a .s file.  rdar://9275556

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

include/llvm/MC/MCContext.h
include/llvm/MC/MCDwarf.h
include/llvm/Support/Dwarf.h
lib/MC/MCAsmStreamer.cpp
lib/MC/MCDwarf.cpp
lib/MC/MCObjectStreamer.cpp
lib/MC/MCParser/AsmParser.cpp
test/MC/MachO/gen-dwarf.s [new file with mode: 0644]
tools/llvm-mc/llvm-mc.cpp

index d45b0c8ca61567a9db8bf183c76aebc146215e5b..455b45ea234357dadf65186769dac722fa3b9fac 100644 (file)
@@ -108,6 +108,16 @@ namespace llvm {
     /// The default initial text section that we generate dwarf debugging line
     /// info for when generating dwarf assembly source files.
     const MCSection *GenDwarfSection;
+    /// Symbols created for the start and end of this section.
+    MCSymbol *GenDwarfSectionStartSym, *GenDwarfSectionEndSym;
+
+    /// The information gathered from labels that will have dwarf subprogram
+    /// entries when generating dwarf assembly source files.
+    std::vector<const MCGenDwarfSubprogramEntry *> MCGenDwarfSubprogramEntries;
+
+    /// The string to embed in the debug information for the compile unit, if
+    /// non-empty.
+    StringRef DwarfDebugFlags;
 
     /// Honor temporary labels, this is useful for debugging semantic
     /// differences between temporary and non-temporary labels (primarily on
@@ -269,6 +279,24 @@ namespace llvm {
     unsigned nextGenDwarfFileNumber() { return ++GenDwarfFileNumber; }
     const MCSection *getGenDwarfSection() { return GenDwarfSection; }
     void setGenDwarfSection(const MCSection *Sec) { GenDwarfSection = Sec; }
+    MCSymbol *getGenDwarfSectionStartSym() { return GenDwarfSectionStartSym; }
+    void setGenDwarfSectionStartSym(MCSymbol *Sym) {
+      GenDwarfSectionStartSym = Sym;
+    }
+    MCSymbol *getGenDwarfSectionEndSym() { return GenDwarfSectionEndSym; }
+    void setGenDwarfSectionEndSym(MCSymbol *Sym) {
+      GenDwarfSectionEndSym = Sym;
+    }
+    const std::vector<const MCGenDwarfSubprogramEntry *>
+      &getMCGenDwarfSubprogramEntries() const {
+      return MCGenDwarfSubprogramEntries;
+    }
+    void addMCGenDwarfSubprogramEntry(const MCGenDwarfSubprogramEntry *E) {
+      MCGenDwarfSubprogramEntries.push_back(E);
+    }
+
+    void setDwarfDebugFlags(StringRef S) { DwarfDebugFlags = S; }
+    StringRef getDwarfDebugFlags() { return DwarfDebugFlags; }
 
     /// @}
 
index 431e3c4da86a7fffd091db1e929ca7a6f2ff27fb..9c77218215219b4385a55748403954f7b95a783d 100644 (file)
@@ -31,6 +31,8 @@ namespace llvm {
   class MCSymbol;
   class MCObjectStreamer;
   class raw_ostream;
+  class SourceMgr;
+  class SMLoc;
 
   /// MCDwarfFile - Instances of this class represent the name of the dwarf
   /// .file directive and its associated dwarf file number in the MC file,
@@ -227,6 +229,46 @@ namespace llvm {
                       int64_t LineDelta, uint64_t AddrDelta);
   };
 
+  class MCGenDwarfInfo {
+  public:
+    //
+    // When generating dwarf for assembly source files this emits the Dwarf
+    // sections.
+    //
+    static void Emit(MCStreamer *MCOS);
+  };
+
+  // When generating dwarf for assembly source files this is the info that is
+  // needed to be gathered for each symbol that will have a dwarf2_subprogram.
+  class MCGenDwarfSubprogramEntry {
+  private:
+    // Name of the symbol without a leading underbar, if any.
+    StringRef Name;
+    // The dwarf file number this symbol is in.
+    unsigned FileNumber;
+    // The line number this symbol is at.
+    unsigned LineNumber;
+    // The low_pc for the dwarf2_subprogram is taken from this symbol.  The
+    // high_pc is taken from the next symbol's value or the end of the section
+    // for the last symbol
+    MCSymbol *Label;
+
+  public:
+    MCGenDwarfSubprogramEntry(StringRef name, unsigned fileNumber,
+                              unsigned lineNumber, MCSymbol *label) :
+      Name(name), FileNumber(fileNumber), LineNumber(lineNumber), Label(label){}
+
+    StringRef getName() const { return Name; }
+    unsigned getFileNumber() const { return FileNumber; }
+    unsigned getLineNumber() const { return LineNumber; }
+    MCSymbol *getLabel() const { return Label; }
+
+    // This is called when label is created when we are generating dwarf for
+    // assembly source files.
+    static void Make(MCSymbol *Symbol, MCStreamer *MCOS, SourceMgr &SrcMgr,
+                     SMLoc &Loc);
+  };
+
   class MCCFIInstruction {
   public:
     enum OpType { SameValue, Remember, Restore, Move, RelMove };
index 30f91874db2072de0fea7fb9143119154860c9fa..357f555a396301decf5c0e8874edddbe3806c119 100644 (file)
@@ -526,6 +526,7 @@ enum dwarf_constants {
   DW_LANG_D = 0x0013,
   DW_LANG_Python = 0x0014,
   DW_LANG_lo_user = 0x8000,
+  DW_LANG_Mips_Assembler = 0x8001,
   DW_LANG_hi_user = 0xffff,
 
   // Identifier case codes
index d90f7b2ad2db0fd6fa5e432047db1f23efcf4738..c785c032231c646b28231d3156fd3af2f20b1326 100644 (file)
@@ -1284,6 +1284,10 @@ void MCAsmStreamer::Finish() {
   if (getContext().hasDwarfFiles() && !UseLoc)
     MCDwarfFileTable::Emit(this);
 
+  // If we are generating dwarf for assembly source files dump out the sections.
+  if (getContext().getGenDwarfForAssembly())
+    MCGenDwarfInfo::Emit(this);
+
   if (!UseCFI)
     EmitFrames(false);
 }
index 8157b4177a11837e869887b08044c9818ca72380..46ab65ffeb44f80836f9745aa5f7b75fcceeed3b 100644 (file)
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/SourceMgr.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Config/config.h"
 using namespace llvm;
 
 // Given a special op, return the address skip amount (in units of
@@ -423,6 +426,342 @@ void MCDwarfFile::dump() const {
   print(dbgs());
 }
 
+// Utility function to write a tuple for .debug_abbrev.
+static void EmitAbbrev(MCStreamer *MCOS, uint64_t Name, uint64_t Form) {
+  MCOS->EmitULEB128IntValue(Name);
+  MCOS->EmitULEB128IntValue(Form);
+}
+
+// When generating dwarf for assembly source files this emits
+// the data for .debug_abbrev section which contains three DIEs.
+static void EmitGenDwarfAbbrev(MCStreamer *MCOS) {
+  MCContext &context = MCOS->getContext();
+  MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfAbbrevSection());
+
+  // DW_TAG_compile_unit DIE abbrev (1).
+  MCOS->EmitULEB128IntValue(1);
+  MCOS->EmitULEB128IntValue(dwarf::DW_TAG_compile_unit);
+  MCOS->EmitIntValue(dwarf::DW_CHILDREN_yes, 1);
+  EmitAbbrev(MCOS, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4);
+  EmitAbbrev(MCOS, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr);
+  EmitAbbrev(MCOS, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr);
+  EmitAbbrev(MCOS, dwarf::DW_AT_name, dwarf::DW_FORM_string);
+  EmitAbbrev(MCOS, dwarf::DW_AT_comp_dir, dwarf::DW_FORM_string);
+  StringRef DwarfDebugFlags = context.getDwarfDebugFlags();
+  if (!DwarfDebugFlags.empty())
+    EmitAbbrev(MCOS, dwarf::DW_AT_APPLE_flags, dwarf::DW_FORM_string);
+  EmitAbbrev(MCOS, dwarf::DW_AT_producer, dwarf::DW_FORM_string);
+  EmitAbbrev(MCOS, dwarf::DW_AT_language, dwarf::DW_FORM_data2);
+  EmitAbbrev(MCOS, 0, 0);
+
+  // DW_TAG_subprogram DIE abbrev (2).
+  MCOS->EmitULEB128IntValue(2);
+  MCOS->EmitULEB128IntValue(dwarf::DW_TAG_subprogram);
+  MCOS->EmitIntValue(dwarf::DW_CHILDREN_yes, 1);
+  EmitAbbrev(MCOS, dwarf::DW_AT_name, dwarf::DW_FORM_string);
+  EmitAbbrev(MCOS, dwarf::DW_AT_decl_file, dwarf::DW_FORM_data4);
+  EmitAbbrev(MCOS, dwarf::DW_AT_decl_line, dwarf::DW_FORM_data4);
+  EmitAbbrev(MCOS, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr);
+  EmitAbbrev(MCOS, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr);
+  EmitAbbrev(MCOS, dwarf::DW_AT_prototyped, dwarf::DW_FORM_flag);
+  EmitAbbrev(MCOS, 0, 0);
+
+  // DW_TAG_unspecified_parameters DIE abbrev (3).
+  MCOS->EmitULEB128IntValue(3);
+  MCOS->EmitULEB128IntValue(dwarf::DW_TAG_unspecified_parameters);
+  MCOS->EmitIntValue(dwarf::DW_CHILDREN_no, 1);
+  EmitAbbrev(MCOS, 0, 0);
+
+  // Terminate the abbreviations for this compilation unit.
+  MCOS->EmitIntValue(0, 1);
+}
+
+// When generating dwarf for assembly source files this emits the data for
+// .debug_aranges section.  Which contains a header and a table of pairs of
+// PointerSize'ed values for the address and size of section(s) with line table
+// entries (just the default .text in our case) and a terminating pair of zeros.
+static void EmitGenDwarfAranges(MCStreamer *MCOS) {
+  MCContext &context = MCOS->getContext();
+
+  // Create a symbol at the end of the section that we are creating the dwarf
+  // debugging info to use later in here as part of the expression to calculate
+  // the size of the section for the table.
+  MCOS->SwitchSection(context.getGenDwarfSection());
+  MCSymbol *SectionEndSym = context.CreateTempSymbol();
+  MCOS->EmitLabel(SectionEndSym);
+  context.setGenDwarfSectionEndSym(SectionEndSym);
+
+  MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfARangesSection());
+
+  // This will be the length of the .debug_aranges section, first account for
+  // the size of each item in the header (see below where we emit these items).
+  int Length = 4 + 2 + 4 + 1 + 1;
+
+  // Figure the padding after the header before the table of address and size
+  // pairs who's values are PointerSize'ed.
+  const MCAsmInfo &asmInfo = context.getAsmInfo();
+  int AddrSize = asmInfo.getPointerSize();
+  int Pad = 2 * AddrSize - (Length & (2 * AddrSize - 1));
+  if (Pad == 2 * AddrSize)
+    Pad = 0;
+  Length += Pad;
+
+  // Add the size of the pair of PointerSize'ed values for the address and size
+  // of the one default .text section we have in the table.
+  Length += 2 * AddrSize;
+  // And the pair of terminating zeros.
+  Length += 2 * AddrSize;
+
+
+  // Emit the header for this section.
+  // The 4 byte length not including the 4 byte value for the length.
+  MCOS->EmitIntValue(Length - 4, 4);
+  // The 2 byte version, which is 2.
+  MCOS->EmitIntValue(2, 2);
+  // The 4 byte offset to the compile unit in the .debug_info from the start
+  // of the .debug_info, it is at the start of that section so this is zero.
+  MCOS->EmitIntValue(0, 4);
+  // The 1 byte size of an address.
+  MCOS->EmitIntValue(AddrSize, 1);
+  // The 1 byte size of a segment descriptor, we use a value of zero.
+  MCOS->EmitIntValue(0, 1);
+  // Align the header with the padding if needed, before we put out the table.
+  for(int i = 0; i < Pad; i++)
+    MCOS->EmitIntValue(0, 1);
+
+  // Now emit the table of pairs of PointerSize'ed values for the section(s)
+  // address and size, in our case just the one default .text section.
+  const MCExpr *Addr = MCSymbolRefExpr::Create(
+    context.getGenDwarfSectionStartSym(), MCSymbolRefExpr::VK_None, context);
+  const MCExpr *Size = MakeStartMinusEndExpr(*MCOS,
+    *context.getGenDwarfSectionStartSym(), *SectionEndSym, 0);
+  MCOS->EmitAbsValue(Addr, AddrSize);
+  MCOS->EmitAbsValue(Size, AddrSize);
+
+  // And finally the pair of terminating zeros.
+  MCOS->EmitIntValue(0, AddrSize);
+  MCOS->EmitIntValue(0, AddrSize);
+}
+
+// When generating dwarf for assembly source files this emits the data for
+// .debug_info section which contains three parts.  The header, the compile_unit
+// DIE and a list of subprogram DIEs.
+static void EmitGenDwarfInfo(MCStreamer *MCOS) {
+  MCContext &context = MCOS->getContext();
+
+  MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfInfoSection()); 
+
+  // Create a symbol at the start and end of this section used in here for the
+  // expression to calculate the length in the header.
+  MCSymbol *InfoStart = context.CreateTempSymbol();
+  MCOS->EmitLabel(InfoStart);
+  MCSymbol *InfoEnd = context.CreateTempSymbol();
+
+  // First part: the header.
+
+  // The 4 byte total length of the information for this compilation unit, not
+  // including these 4 bytes.
+  const MCExpr *Length = MakeStartMinusEndExpr(*MCOS, *InfoStart, *InfoEnd, 4);
+  MCOS->EmitAbsValue(Length, 4);
+
+  // The 2 byte DWARF version, which is 2.
+  MCOS->EmitIntValue(2, 2);
+
+  // The 4 byte offset to the debug abbrevs from the start of the .debug_abbrev,
+  // it is at the start of that section so this is zero.
+  MCOS->EmitIntValue(0, 4);
+
+  const MCAsmInfo &asmInfo = context.getAsmInfo();
+  int AddrSize = asmInfo.getPointerSize();
+  // The 1 byte size of an address.
+  MCOS->EmitIntValue(AddrSize, 1);
+
+  // Second part: the compile_unit DIE.
+
+  // The DW_TAG_compile_unit DIE abbrev (1).
+  MCOS->EmitULEB128IntValue(1);
+
+  // DW_AT_stmt_list, a 4 byte offset from the start of the .debug_line section,
+  // which is at the start of that section so this is zero.
+  MCOS->EmitIntValue(0, 4);
+
+  // AT_low_pc, the first address of the default .text section.
+  const MCExpr *Start = MCSymbolRefExpr::Create(
+    context.getGenDwarfSectionStartSym(), MCSymbolRefExpr::VK_None, context);
+  MCOS->EmitAbsValue(Start, AddrSize);
+
+  // AT_high_pc, the last address of the default .text section.
+  const MCExpr *End = MCSymbolRefExpr::Create(
+    context.getGenDwarfSectionEndSym(), MCSymbolRefExpr::VK_None, context);
+  MCOS->EmitAbsValue(End, AddrSize);
+
+  // AT_name, the name of the source file.  Reconstruct from the first directory
+  // and file table entries.
+  const std::vector<StringRef> &MCDwarfDirs =
+    context.getMCDwarfDirs();
+  if (MCDwarfDirs.size() > 0) {
+    MCOS->EmitBytes(MCDwarfDirs[0], 0);
+    MCOS->EmitBytes("/", 0);
+  }
+  const std::vector<MCDwarfFile *> &MCDwarfFiles =
+    MCOS->getContext().getMCDwarfFiles();
+  MCOS->EmitBytes(MCDwarfFiles[1]->getName(), 0);
+  MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+
+  // AT_comp_dir, the working directory the assembly was done in.
+  llvm::sys::Path CWD = llvm::sys::Path::GetCurrentDirectory();
+  MCOS->EmitBytes(StringRef(CWD.c_str()), 0);
+  MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+
+  // AT_APPLE_flags, the command line arguments of the assembler tool.
+  StringRef DwarfDebugFlags = context.getDwarfDebugFlags();
+  if (!DwarfDebugFlags.empty()){
+    MCOS->EmitBytes(DwarfDebugFlags, 0);
+    MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+  }
+
+  // AT_producer, the version of the assembler tool.
+  MCOS->EmitBytes(StringRef("llvm-mc (based on LLVM "), 0);
+  MCOS->EmitBytes(StringRef(PACKAGE_VERSION), 0);
+  MCOS->EmitBytes(StringRef(")"), 0);
+  MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+
+  // AT_language, a 4 byte value.  We use DW_LANG_Mips_Assembler as the dwarf2
+  // draft has no standard code for assembler.
+  MCOS->EmitIntValue(dwarf::DW_LANG_Mips_Assembler, 2);
+
+  // Third part: the list of subprogram DIEs.
+
+  // Loop on saved info for dwarf subprograms and create the DIEs for them.
+  const std::vector<const MCGenDwarfSubprogramEntry *> &Entries =
+    MCOS->getContext().getMCGenDwarfSubprogramEntries();
+  for (std::vector<const MCGenDwarfSubprogramEntry *>::const_iterator it =
+       Entries.begin(), ie = Entries.end(); it != ie;
+       ++it) {
+    const MCGenDwarfSubprogramEntry *Entry = *it;
+
+    // The DW_TAG_subprogram DIE abbrev (2).
+    MCOS->EmitULEB128IntValue(2);
+
+    // AT_name, of the label without any leading underbar.
+    MCOS->EmitBytes(Entry->getName(), 0);
+    MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+
+    // AT_decl_file, index into the file table.
+    MCOS->EmitIntValue(Entry->getFileNumber(), 4);
+
+    // AT_decl_line, source line number.
+    MCOS->EmitIntValue(Entry->getLineNumber(), 4);
+
+    // AT_low_pc, start address of the label.
+    const MCExpr *AT_low_pc = MCSymbolRefExpr::Create(Entry->getLabel(),
+                                             MCSymbolRefExpr::VK_None, context);
+    MCOS->EmitAbsValue(AT_low_pc, AddrSize);
+
+    // AT_high_pc, end address which is the next label or end of the section.
+    std::vector<const MCGenDwarfSubprogramEntry *>::const_iterator next = it+1;
+    if (next != Entries.end()){
+      const MCGenDwarfSubprogramEntry *NextEntry = *next;
+      const MCExpr *AT_high_pc = MCSymbolRefExpr::Create(NextEntry->getLabel(),
+                                             MCSymbolRefExpr::VK_None, context);
+      MCOS->EmitAbsValue(AT_high_pc, AddrSize);
+    } else {
+      MCOS->EmitAbsValue(End, AddrSize);
+    }
+
+    // DW_AT_prototyped, a one byte flag value of 0 saying we have no prototype.
+    MCOS->EmitIntValue(0, 1);
+
+    // The DW_TAG_unspecified_parameters DIE abbrev (3).
+    MCOS->EmitULEB128IntValue(3);
+
+    // Add the NULL DIE terminating the DW_TAG_unspecified_parameters DIE's.
+    MCOS->EmitIntValue(0, 1);
+  }
+  // Deallocate the MCGenDwarfSubprogramEntry classes that saved away the info
+  // for the dwarf subprograms.
+  for (std::vector<const MCGenDwarfSubprogramEntry *>::const_iterator it =
+       Entries.begin(), ie = Entries.end(); it != ie;
+       ++it) {
+    const MCGenDwarfSubprogramEntry *Entry = *it;
+    delete Entry;
+  }
+
+  // Add the NULL DIE terminating the Compile Unit DIE's.
+  MCOS->EmitIntValue(0, 1);
+
+  // Now set the value of the symbol at the end of the info section.
+  MCOS->EmitLabel(InfoEnd);
+}
+
+//
+// When generating dwarf for assembly source files this emits the Dwarf
+// sections.
+//
+void MCGenDwarfInfo::Emit(MCStreamer *MCOS) {
+  // Create the dwarf sections in this order (.debug_line already created).
+  MCContext &context = MCOS->getContext();
+  MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfInfoSection());
+  MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfAbbrevSection());
+  MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfARangesSection());
+
+  // If there are no line table entries then do not emit any section contents.
+  if (context.getMCLineSections().empty())
+    return;
+
+  // Output the data for .debug_aranges section.
+  EmitGenDwarfAranges(MCOS);
+
+  // Output the data for .debug_abbrev section.
+  EmitGenDwarfAbbrev(MCOS);
+
+  // Output the data for .debug_info section.
+  EmitGenDwarfInfo(MCOS);
+}
+
+//
+// When generating dwarf for assembly source files this is called when symbol
+// for a label is created.  If this symbol is not a temporary and is in the
+// section that dwarf is being generated for, save the needed info to create
+// a dwarf subprogram.
+//
+void MCGenDwarfSubprogramEntry::Make(MCSymbol *Symbol, MCStreamer *MCOS,
+                                     SourceMgr &SrcMgr, SMLoc &Loc) {
+  // We won't create dwarf subprogram's for temporary symbols or symbols not in
+  // the default text.
+  if (Symbol->isTemporary())
+    return;
+  MCContext &context = MCOS->getContext();
+  if (context.getGenDwarfSection() != MCOS->getCurrentSection())
+    return;
+
+  // The dwarf subprogram's name does not have the symbol name's leading
+  // underbar if any.
+  StringRef Name = Symbol->getName();
+  if (Name.startswith("_"))
+    Name = Name.substr(1, Name.size()-1);
+
+  // Get the dwarf file number to be used for the dwarf subprogram.
+  unsigned FileNumber = context.getGenDwarfFileNumber();
+
+  // Finding the line number is the expensive part which is why we just don't
+  // pass it in as for some symbols we won't create a dwarf subprogram.
+  int CurBuffer = SrcMgr.FindBufferContainingLoc(Loc);
+  unsigned LineNumber = SrcMgr.FindLineNumber(Loc, CurBuffer);
+
+  // We create a temporary symbol for use for the AT_high_pc and AT_low_pc
+  // values so that they don't have things like an ARM thumb bit from the
+  // original symbol. So when used they won't get a low bit set after
+  // relocation.
+  MCSymbol *Label = context.CreateTempSymbol();
+  MCOS->EmitLabel(Label);
+
+  // Create and entry for the info and add it to the other entries.
+  MCGenDwarfSubprogramEntry *Entry = 
+    new MCGenDwarfSubprogramEntry(Name, FileNumber, LineNumber, Label);
+  MCOS->getContext().addMCGenDwarfSubprogramEntry(Entry);
+}
+
 static int getDataAlignmentFactor(MCStreamer &streamer) {
   MCContext &context = streamer.getContext();
   const MCAsmInfo &asmInfo = context.getAsmInfo();
index 90c957f7be8a2e28a8676950f67ee766b64df2d8..663d0ca491171ed4ec05f5037d4b1e36ba515870 100644 (file)
@@ -260,5 +260,9 @@ void MCObjectStreamer::Finish() {
   if (getContext().hasDwarfFiles())
     MCDwarfFileTable::Emit(this);
 
+  // If we are generating dwarf for assembly source files dump out the sections.
+  if (getContext().getGenDwarfForAssembly())
+    MCGenDwarfInfo::Emit(this);
+
   getAssembler().Finish();
 }
index 78838937276dfbc2dc7a02d7b9f174944875a4bc..943f270a0a719af8daf3f452dacdf41f78e48449 100644 (file)
@@ -468,6 +468,9 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) {
   // section and generate a .file directive.
   if (getContext().getGenDwarfForAssembly()) {
     getContext().setGenDwarfSection(getStreamer().getCurrentSection());
+    MCSymbol *SectionStartSym = getContext().CreateTempSymbol();
+    getStreamer().EmitLabel(SectionStartSym);
+    getContext().setGenDwarfSectionStartSym(SectionStartSym);
     getStreamer().EmitDwarfFileDirective(getContext().nextGenDwarfFileNumber(),
       StringRef(), SrcMgr.getMemoryBuffer(CurBuffer)->getBufferIdentifier());
   }
@@ -1047,6 +1050,12 @@ bool AsmParser::ParseStatement() {
     // Emit the label.
     Out.EmitLabel(Sym);
 
+    // If we are generating dwarf for assembly source files then gather the
+    // info to make a dwarf subprogram entry for this label if needed.
+    if (getContext().getGenDwarfForAssembly())
+      MCGenDwarfSubprogramEntry::Make(Sym, &getStreamer(), getSourceManager(),
+                                      IDLoc);
+
     // Consume any end of statement token, if present, to avoid spurious
     // AddBlankLine calls().
     if (Lexer.is(AsmToken::EndOfStatement)) {
diff --git a/test/MC/MachO/gen-dwarf.s b/test/MC/MachO/gen-dwarf.s
new file mode 100644 (file)
index 0000000..6b85135
--- /dev/null
@@ -0,0 +1,113 @@
+// RUN: llvm-mc -g -triple i386-apple-darwin10 %s -filetype=obj -o %t
+// RUN: llvm-dwarfdump %t | FileCheck %s
+
+.globl _bar
+_bar:
+       movl    $0, %eax
+L1:    leave
+       ret
+_foo:
+       nop
+.data
+_x:    .long 1
+
+// CHECK: file format Mach-O 32-bit i386
+
+// CHECK: .debug_abbrev contents:
+// CHECK: Abbrev table for offset: 0x00000000
+// CHECK: [1] DW_TAG_compile_unit      DW_CHILDREN_yes
+// CHECK:      DW_AT_stmt_list DW_FORM_data4
+// CHECK:      DW_AT_low_pc    DW_FORM_addr
+// CHECK:      DW_AT_high_pc   DW_FORM_addr
+// CHECK:      DW_AT_name      DW_FORM_string
+// CHECK:      DW_AT_comp_dir  DW_FORM_string
+// CHECK:      DW_AT_producer  DW_FORM_string
+// CHECK:      DW_AT_language  DW_FORM_data2
+
+// CHECK: [2] DW_TAG_subprogram        DW_CHILDREN_yes
+// CHECK:      DW_AT_name      DW_FORM_string
+// CHECK:      DW_AT_decl_file DW_FORM_data4
+// CHECK:      DW_AT_decl_line DW_FORM_data4
+// CHECK:      DW_AT_low_pc    DW_FORM_addr
+// CHECK:      DW_AT_high_pc   DW_FORM_addr
+// CHECK:      DW_AT_prototyped        DW_FORM_flag
+
+// CHECK: [3] DW_TAG_unspecified_parameters    DW_CHILDREN_no
+
+
+// CHECK: .debug_info contents:
+
+// We don't check the leading addresses these are at.
+// CHECK:  DW_TAG_compile_unit [1] *
+// CHECK:    DW_AT_stmt_list [DW_FORM_data4]   (0x00000000)
+// CHECK:    DW_AT_low_pc [DW_FORM_addr]       (0x0000000000000000)
+// CHECK:    DW_AT_high_pc [DW_FORM_addr]      (0x0000000000000008)
+// We don't check the file name as it is a temp directory
+// CHECK:    DW_AT_name [DW_FORM_string]
+// We don't check the DW_AT_comp_dir which is the current working directory
+// CHECK:    DW_AT_producer [DW_FORM_string]   ("llvm-mc (based on LLVM 3.1svn)")
+// CHECK:    DW_AT_language [DW_FORM_data2]    (0x8001)
+
+// CHECK:    DW_TAG_subprogram [2] *
+// CHECK:      DW_AT_name [DW_FORM_string]     ("bar")
+// CHECK:      DW_AT_decl_file [DW_FORM_data4] (0x00000001)
+// CHECK:      DW_AT_decl_line [DW_FORM_data4] (0x00000005)
+// CHECK:      DW_AT_low_pc [DW_FORM_addr]     (0x0000000000000000)
+// CHECK:      DW_AT_high_pc [DW_FORM_addr]    (0x0000000000000007)
+// CHECK:      DW_AT_prototyped [DW_FORM_flag] (0x00)
+
+// CHECK:      DW_TAG_unspecified_parameters [3]  
+
+// CHECK:      NULL
+
+// CHECK:    DW_TAG_subprogram [2] *
+// CHECK:      DW_AT_name [DW_FORM_string]     ("foo")
+// CHECK:      DW_AT_decl_file [DW_FORM_data4] (0x00000001)
+// CHECK:      DW_AT_decl_line [DW_FORM_data4] (0x00000009)
+// CHECK:      DW_AT_low_pc [DW_FORM_addr]     (0x0000000000000007)
+// CHECK:      DW_AT_high_pc [DW_FORM_addr]    (0x0000000000000008)
+// CHECK:      DW_AT_prototyped [DW_FORM_flag] (0x00)
+
+// CHECK:      DW_TAG_unspecified_parameters [3]  
+
+// CHECK:      NULL
+
+// CHECK:    NULL
+
+// CHECK: .debug_aranges contents:
+// CHECK: Address Range Header: length = 0x0000001c, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x04, seg_size = 0x00
+
+// CHECK: .debug_lines contents:
+// CHECK: Line table prologue:
+// We don't check the total_length as it includes lengths of temp paths
+// CHECK:         version: 2
+// We don't check the prologue_length as it too includes lengths of temp paths
+// CHECK: min_inst_length: 1
+// CHECK: default_is_stmt: 1
+// CHECK:       line_base: -5
+// CHECK:      line_range: 14
+// CHECK:     opcode_base: 13
+// CHECK: standard_opcode_lengths[DW_LNS_copy] = 0
+// CHECK: standard_opcode_lengths[DW_LNS_advance_pc] = 1
+// CHECK: standard_opcode_lengths[DW_LNS_advance_line] = 1
+// CHECK: standard_opcode_lengths[DW_LNS_set_file] = 1
+// CHECK: standard_opcode_lengths[DW_LNS_set_column] = 1
+// CHECK: standard_opcode_lengths[DW_LNS_negate_stmt] = 0
+// CHECK: standard_opcode_lengths[DW_LNS_set_basic_block] = 0
+// CHECK: standard_opcode_lengths[DW_LNS_const_add_pc] = 0
+// CHECK: standard_opcode_lengths[DW_LNS_fixed_advance_pc] = 1
+// CHECK: standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+// CHECK: standard_opcode_lengths[DW_LNS_set_epilogue_begin] = 0
+// CHECK: standard_opcode_lengths[DW_LNS_set_isa] = 1
+// We don't check include_directories as it has a temp path
+// CHECK:                 Dir  Mod Time   File Len   File Name
+// CHECK:                 ---- ---------- ---------- ---------------------------
+// CHECK: file_names[  1]    1 0x00000000 0x00000000 gen-dwarf.s
+
+// CHECK: Address            Line   Column File   ISA Flags
+// CHECK: ------------------ ------ ------ ------ --- -------------
+// CHECK: 0x0000000000000000      6      0      1   0  is_stmt
+// CHECK: 0x0000000000000005      7      0      1   0  is_stmt
+// CHECK: 0x0000000000000006      8      0      1   0  is_stmt
+// CHECK: 0x0000000000000007     10      0      1   0  is_stmt
+// CHECK: 0x0000000000000008     10      0      1   0  is_stmt end_sequence
index 1139e36e26defa8a8d9f488e3635e07d89a3a2c3..428125954901189559bd87f2aef9aa1d6fe4c974 100644 (file)
@@ -234,6 +234,17 @@ static tool_output_file *GetOutputStream() {
   return Out;
 }
 
+static std::string DwarfDebugFlags;
+static void setDwarfDebugFlags(int argc, char **argv) {
+  if (!getenv("RC_DEBUG_OPTIONS"))
+    return;
+  for (int i = 0; i < argc; i++) {
+    DwarfDebugFlags += argv[i];
+    if (i + 1 < argc)
+      DwarfDebugFlags += " ";
+  }
+}
+
 static int AsLexInput(const char *ProgName) {
   OwningPtr<MemoryBuffer> BufferPtr;
   if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr)) {
@@ -382,6 +393,8 @@ static int AssembleInput(const char *ProgName) {
     Ctx.setAllowTemporaryLabels(false);
 
   Ctx.setGenDwarfForAssembly(GenDwarfForAssembly);
+  if (!DwarfDebugFlags.empty()) 
+    Ctx.setDwarfDebugFlags(StringRef(DwarfDebugFlags));
 
   // Package up features to be passed to target/subtarget
   std::string FeaturesStr;
@@ -508,6 +521,7 @@ int main(int argc, char **argv) {
 
   cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n");
   TripleName = Triple::normalize(TripleName);
+  setDwarfDebugFlags(argc, argv);
 
   switch (Action) {
   default: