diff options
-rw-r--r-- | lib/MC/MCAssembler.cpp | 38 | ||||
-rw-r--r-- | lib/MC/MCDwarf.cpp | 469 | ||||
-rw-r--r-- | lib/MC/MCMachOStreamer.cpp | 221 | ||||
-rw-r--r-- | lib/MC/MCObjectWriter.cpp | 26 | ||||
-rw-r--r-- | lib/MC/MCParser/AsmParser.cpp | 2 | ||||
-rw-r--r-- | lib/MC/MCStreamer.cpp | 19 |
6 files changed, 570 insertions, 205 deletions
diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 3d9dcba52d..9cd0a12c12 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -13,8 +13,10 @@ #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" @@ -349,6 +351,20 @@ uint64_t MCAssembler::ComputeFragmentSize(MCAsmLayout &Layout, return Offset; } + + case MCFragment::FT_Dwarf: { + const MCDwarfLineAddrFragment &OF = cast<MCDwarfLineAddrFragment>(F); + + // The AddrDelta is really unsigned and it can only increase. + int64_t AddrDelta; + + OF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, &Layout); + + int64_t LineDelta; + LineDelta = OF.getLineDelta(); + + return MCDwarfLineAddr::ComputeSize(LineDelta, AddrDelta); + } } assert(0 && "invalid fragment kind"); @@ -506,6 +522,20 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout, break; } + + case MCFragment::FT_Dwarf: { + const MCDwarfLineAddrFragment &OF = cast<MCDwarfLineAddrFragment>(F); + + // The AddrDelta is really unsigned and it can only increase. + int64_t AddrDelta; + OF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, &Layout); + + int64_t LineDelta; + LineDelta = OF.getLineDelta(); + + MCDwarfLineAddr::Write(OW, LineDelta, (uint64_t)AddrDelta); + break; + } } assert(OW->getStream().tell() - Start == FragmentSize); @@ -872,6 +902,7 @@ void MCFragment::dump() { case MCFragment::FT_Fill: OS << "MCFillFragment"; break; case MCFragment::FT_Inst: OS << "MCInstFragment"; break; case MCFragment::FT_Org: OS << "MCOrgFragment"; break; + case MCFragment::FT_Dwarf: OS << "MCDwarfFragment"; break; } OS << "<MCFragment " << (void*) this << " LayoutOrder:" << LayoutOrder @@ -932,6 +963,13 @@ void MCFragment::dump() { OS << " Offset:" << OF->getOffset() << " Value:" << OF->getValue(); break; } + case MCFragment::FT_Dwarf: { + const MCDwarfLineAddrFragment *OF = cast<MCDwarfLineAddrFragment>(this); + OS << "\n "; + OS << " AddrDelta:" << OF->getAddrDelta() + << " LineDelta:" << OF->getLineDelta(); + break; + } } OS << ">"; } diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 2da71f96c6..faa2df0ae9 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -8,10 +8,478 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmBackend.h" using namespace llvm; +// Given a special op, return the address skip amount (in units of +// DWARF2_LINE_MIN_INSN_LENGTH. +#define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE) + +// The maximum address skip amount that can be encoded with a special op. +#define MAX_SPECIAL_ADDR_DELTA SPECIAL_ADDR(255) + +// First special line opcode - leave room for the standard opcodes. +// Note: If you want to change this, you'll have to update the +// "standard_opcode_lengths" table that is emitted in DwarfFileTable::Emit(). +#define DWARF2_LINE_OPCODE_BASE 13 + +// Minimum line offset in a special line info. opcode. This value +// was chosen to give a reasonable range of values. +#define DWARF2_LINE_BASE -5 + +// Range of line offsets in a special line info. opcode. +# define DWARF2_LINE_RANGE 14 + +// Define the architecture-dependent minimum instruction length (in bytes). +// This value should be rather too small than too big. +# define DWARF2_LINE_MIN_INSN_LENGTH 1 + +// Note: when DWARF2_LINE_MIN_INSN_LENGTH == 1 which is the current setting, +// this routine is a nop and will be optimized away. +static inline uint64_t ScaleAddrDelta(uint64_t AddrDelta) +{ + if (DWARF2_LINE_MIN_INSN_LENGTH == 1) + return AddrDelta; + if (AddrDelta % DWARF2_LINE_MIN_INSN_LENGTH != 0) { + // TODO: report this error, but really only once. + ; + } + return AddrDelta / DWARF2_LINE_MIN_INSN_LENGTH; +} + +// +// This is called when an instruction is assembled into the specified section +// and if there is information from the last .loc directive that has yet to have +// a line entry made for it is made. +// +void MCLineEntry::Make(MCObjectStreamer *MCOS, const MCSection *Section) { + if (!MCOS->getContext().getDwarfLocSeen()) + return; + + // Create a symbol at in the current section for use in the line entry. + MCSymbol *LineSym = MCOS->getContext().CreateTempSymbol(); + // Set the value of the symbol to use for the MCLineEntry. + MCOS->EmitLabel(LineSym); + + // Get the current .loc info saved in the context. + const MCDwarfLoc &DwarfLoc = MCOS->getContext().getCurrentDwarfLoc(); + + // Create a (local) line entry with the symbol and the current .loc info. + MCLineEntry LineEntry(LineSym, DwarfLoc); + + // clear DwarfLocSeen saying the current .loc info is now used. + MCOS->getContext().clearDwarfLocSeen(); + + // Get the MCLineSection for this section, if one does not exist for this + // section create it. + DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + MCOS->getContext().getMCLineSections(); + MCLineSection *LineSection = MCLineSections[Section]; + if (!LineSection) { + // Create a new MCLineSection. This will be deleted after the dwarf line + // table is created using it by iterating through the MCLineSections + // DenseMap. + LineSection = new MCLineSection; + // Save a pointer to the new LineSection into the MCLineSections DenseMap. + MCLineSections[Section] = LineSection; + } + + // Add the line entry to this section's entries. + LineSection->addLineEntry(LineEntry); +} + +// +// This helper routine returns an expression of End - Start + IntVal . +// +static inline const MCExpr *MakeStartMinusEndExpr(MCObjectStreamer *MCOS, + MCSymbol *Start, + MCSymbol *End, int IntVal) { + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *Res = + MCSymbolRefExpr::Create(End, Variant, MCOS->getContext()); + const MCExpr *RHS = + MCSymbolRefExpr::Create(Start, Variant, MCOS->getContext()); + const MCExpr *Res1 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res, RHS, MCOS->getContext()); + const MCExpr *Res2 = + MCConstantExpr::Create(IntVal, MCOS->getContext()); + const MCExpr *Res3 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res1, Res2, MCOS->getContext()); + return Res3; +} + +// +// This emits an "absolute" address used in the start of a dwarf line number +// table. This will result in a relocatation entry for the address. +// +static inline void EmitDwarfSetAddress(MCObjectStreamer *MCOS, + MCSymbol *Symbol) { + MCOS->EmitIntValue(dwarf::DW_LNS_extended_op, 1); + + int sizeof_address = MCOS->getAssembler().getBackend().getPointerSize(); + MCOS->EmitULEB128Value(sizeof_address + 1); + + MCOS->EmitIntValue(dwarf::DW_LNE_set_address, 1); + MCOS->EmitSymbolValue(Symbol, sizeof_address); +} + +// +// This emits the Dwarf line table for the specified section from the entries +// in the LineSection. +// +static inline bool EmitDwarfLineTable(MCObjectStreamer *MCOS, + const MCSection *Section, + MCLineSection *LineSection, + const MCSection *DwarfLineSection) { + unsigned FileNum = 1; + unsigned LastLine = 1; + unsigned Column = 0; + unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; + unsigned Isa = 0; + bool EmittedLineTable = false; + MCSymbol *LastLabel = NULL; + MCSectionData &DLS = + MCOS->getAssembler().getOrCreateSectionData(*DwarfLineSection); + + // Loop through each MCLineEntry and encode the dwarf line number table. + for (MCLineSection::iterator + it = LineSection->getMCLineEntries()->begin(), + ie = LineSection->getMCLineEntries()->end(); it != ie; ++it) { + + if (FileNum != it->getFileNum()) { + FileNum = it->getFileNum(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_file, 1); + MCOS->EmitULEB128Value(FileNum); + } + if (Column != it->getColumn()) { + Column = it->getColumn(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_column, 1); + MCOS->EmitULEB128Value(Column); + } + if (Isa != it->getIsa()) { + Isa = it->getIsa(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_isa, 1); + MCOS->EmitULEB128Value(Isa); + } + if ((it->getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) { + Flags = it->getFlags(); + MCOS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1); + } + if (it->getFlags() & DWARF2_FLAG_BASIC_BLOCK) + MCOS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1); + if (it->getFlags() & DWARF2_FLAG_PROLOGUE_END) + MCOS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1); + if (it->getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN) + MCOS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1); + + int64_t LineDelta = it->getLine() - LastLine; + MCSymbol *Label = it->getLabel(); + + // At this point we want to emit/create the sequence to encode the delta in + // line numbers and the increment of the address from the previous Label + // and the current Label. + if (LastLabel == NULL) { + // emit the sequence to set the address + EmitDwarfSetAddress(MCOS, Label); + // emit the sequence for the LineDelta (from 1) and a zero address delta. + MCDwarfLineAddr::Emit(MCOS, LineDelta, 0); + } + else { + // Create an expression for the address delta from the LastLabel and + // this Label (plus 0). + const MCExpr *AddrDelta = MakeStartMinusEndExpr(MCOS, LastLabel, Label,0); + // Create a Dwarf Line fragment for the LineDelta and AddrDelta. + new MCDwarfLineAddrFragment(LineDelta, *AddrDelta, &DLS); + } + + LastLine = it->getLine(); + LastLabel = Label; + EmittedLineTable = true; + } + + // Emit a DW_LNE_end_sequence for the end of the section. + // Using the pointer Section create a temporary label at the end of the + // section and use that and the LastLabel to compute the address delta + // and use INT64_MAX as the line delta which is the signal that this is + // actually a DW_LNE_end_sequence. + + // Switch to the section to be able to create a symbol at its end. + MCOS->SwitchSection(Section); + // Create a symbol at the end of the section. + MCSymbol *SectionEnd = MCOS->getContext().CreateTempSymbol(); + // Set the value of the symbol, as we are at the end of the section. + MCOS->EmitLabel(SectionEnd); + + // Switch back the the dwarf line section. + MCOS->SwitchSection(DwarfLineSection); + // Create an expression for the address delta from the LastLabel and this + // SectionEnd label. + const MCExpr *AddrDelta = MakeStartMinusEndExpr(MCOS, LastLabel, SectionEnd, + 0); + // Create a Dwarf Line fragment for the LineDelta and AddrDelta. + new MCDwarfLineAddrFragment(INT64_MAX, *AddrDelta, &DLS); + + return EmittedLineTable; +} + +// +// This emits the Dwarf file and the line tables. +// +void MCDwarfFileTable::Emit(MCObjectStreamer *MCOS, + const MCSection *DwarfLineSection) { + // Switch to the section where the table will be emitted into. + MCOS->SwitchSection(DwarfLineSection); + + // Create a symbol at the beginning of this section. + MCSymbol *LineStartSym = MCOS->getContext().CreateTempSymbol(); + // Set the value of the symbol, as we are at the start of the section. + MCOS->EmitLabel(LineStartSym); + + // Create a symbol for the end of the section (to be set when we get there). + MCSymbol *LineEndSym = MCOS->getContext().CreateTempSymbol(); + + // The first 4 bytes is the total length of the information for this + // compilation unit (not including these 4 bytes for the length). + MCOS->EmitValue(MakeStartMinusEndExpr(MCOS, LineStartSym, LineEndSym, 4), + 4, 0); + + // Next 2 bytes is the Version, which is Dwarf 2. + MCOS->EmitIntValue(2, 2); + + // Create a symbol for the end of the prologue (to be set when we get there). + MCSymbol *ProEndSym = MCOS->getContext().CreateTempSymbol(); // Lprologue_end + + // Length of the prologue, is the next 4 bytes. Which is the start of the + // section to the end of the prologue. Not including the 4 bytes for the + // total length, the 2 bytes for the version, and these 4 bytes for the + // length of the prologue. + MCOS->EmitValue(MakeStartMinusEndExpr(MCOS, LineStartSym, ProEndSym, + (4 + 2 + 4)), + 4, 0); + + // Parameters of the state machine, are next. + MCOS->EmitIntValue(DWARF2_LINE_MIN_INSN_LENGTH, 1); + MCOS->EmitIntValue(DWARF2_LINE_DEFAULT_IS_STMT, 1); + MCOS->EmitIntValue(DWARF2_LINE_BASE, 1); + MCOS->EmitIntValue(DWARF2_LINE_RANGE, 1); + MCOS->EmitIntValue(DWARF2_LINE_OPCODE_BASE, 1); + + // Standard opcode lengths + MCOS->EmitIntValue(0, 1); // length of DW_LNS_copy + MCOS->EmitIntValue(1, 1); // length of DW_LNS_advance_pc + MCOS->EmitIntValue(1, 1); // length of DW_LNS_advance_line + MCOS->EmitIntValue(1, 1); // length of DW_LNS_set_file + MCOS->EmitIntValue(1, 1); // length of DW_LNS_set_column + MCOS->EmitIntValue(0, 1); // length of DW_LNS_negate_stmt + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_basic_block + MCOS->EmitIntValue(0, 1); // length of DW_LNS_const_add_pc + MCOS->EmitIntValue(1, 1); // length of DW_LNS_fixed_advance_pc + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_prologue_end + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_epilogue_begin + MCOS->EmitIntValue(1, 1); // DW_LNS_set_isa + + // Put out the directory and file tables. + + // First the directory table. + const std::vector<StringRef> &MCDwarfDirs = + MCOS->getContext().getMCDwarfDirs(); + for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { + MCOS->EmitBytes(MCDwarfDirs[i], 0); // the DirectoryName + MCOS->EmitBytes(StringRef("\0", 1), 0); // the null term. of the string + } + MCOS->EmitIntValue(0, 1); // Terminate the directory list + + // Second the file table. + const std::vector<MCDwarfFile *> &MCDwarfFiles = + MCOS->getContext().getMCDwarfFiles(); + for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { + MCOS->EmitBytes(MCDwarfFiles[i]->getName(), 0); // FileName + MCOS->EmitBytes(StringRef("\0", 1), 0); // the null term. of the string + MCOS->EmitULEB128Value(MCDwarfFiles[i]->getDirIndex()); // the Directory num + MCOS->EmitIntValue(0, 1); // last modification timestamp (always 0) + MCOS->EmitIntValue(0, 1); // filesize (always 0) + } + MCOS->EmitIntValue(0, 1); // Terminate the file list + + // This is the end of the prologue, so set the value of the symbol at the + // end of the prologue (that was used in a previous expression). + MCOS->EmitLabel(ProEndSym); + + // Put out the line tables. + bool EmittedLineTable = false; + DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + MCOS->getContext().getMCLineSections(); + for (DenseMap<const MCSection *, MCLineSection *>::iterator it = + MCLineSections.begin(), ie = MCLineSections.end(); it != ie; ++it) { + EmittedLineTable = EmitDwarfLineTable(MCOS, it->first, it->second, + DwarfLineSection); + + // Now delete the MCLineSections that were created in MCLineEntry::Make() + // and used to emit the line table. + delete it->second; + } + + // If there are no line tables emited then we emit: + // The following DW_LNE_set_address sequence to set the address to zero and + // the DW_LNE_end_sequence. + if (EmittedLineTable == false) { + if (MCOS->getAssembler().getBackend().getPointerSize() == 8) { + // This is the DW_LNE_set_address sequence for 64-bit code. + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(9, 1); + MCOS->EmitIntValue(2, 1); + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(0, 1); + } + else { + // This is the DW_LNE_set_address sequence for 32-bit code. + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(5, 1); + MCOS->EmitIntValue(2, 1); + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(0, 1); + MCOS->EmitIntValue(0, 1); + } + + // Lastly emit the DW_LNE_end_sequence which consists of 3 bytes '00 01 01' + // (00 is the code for extended opcodes, followed by a ULEB128 length of the + // extended opcode (01), and the DW_LNE_end_sequence (01). + MCOS->EmitIntValue(0, 1); // DW_LNS_extended_op + MCOS->EmitIntValue(1, 1); // ULEB128 length of the extended opcode + MCOS->EmitIntValue(1, 1); // DW_LNE_end_sequence + } + + // This is the end of the section, so set the value of the symbol at the end + // of this section (that was used in a previous expression). + MCOS->EmitLabel(LineEndSym); +} + +/// Utility function to compute the size of the encoding. +uint64_t MCDwarfLineAddr::ComputeSize(int64_t LineDelta, uint64_t AddrDelta) { + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OS); + return OS.GetNumBytesInBuffer(); +} + +/// Utility function to write the encoding to an object writer. +void MCDwarfLineAddr::Write(MCObjectWriter *OW, int64_t LineDelta, + uint64_t AddrDelta) { + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OS); + OW->WriteBytes(OS.str()); +} + +/// Utility function to emit the encoding to a streamer. +void MCDwarfLineAddr::Emit(MCObjectStreamer *MCOS, int64_t LineDelta, + uint64_t AddrDelta) { + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OS); + MCOS->EmitBytes(OS.str(), /*AddrSpace=*/0); +} + +/// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas. +void MCDwarfLineAddr::Encode(int64_t LineDelta, uint64_t AddrDelta, + raw_ostream &OS) { + uint64_t Temp, Opcode; + bool NeedCopy = false; + + // Scale the address delta by the minimum instruction length. + AddrDelta = ScaleAddrDelta(AddrDelta); + + // A LineDelta of INT64_MAX is a signal that this is actually a + // DW_LNE_end_sequence. We cannot use special opcodes here, since we want the + // end_sequence to emit the matrix entry. + if (LineDelta == INT64_MAX) { + if (AddrDelta == MAX_SPECIAL_ADDR_DELTA) + OS << char(dwarf::DW_LNS_const_add_pc); + else { + OS << char(dwarf::DW_LNS_advance_pc); + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeULEB128(AddrDelta, OSE); + OS << OSE.str(); + } + OS << char(dwarf::DW_LNS_extended_op); + OS << char(1); + OS << char(dwarf::DW_LNE_end_sequence); + return; + } + + // Bias the line delta by the base. + Temp = LineDelta - DWARF2_LINE_BASE; + + // If the line increment is out of range of a special opcode, we must encode + // it with DW_LNS_advance_line. + if (Temp >= DWARF2_LINE_RANGE) { + OS << char(dwarf::DW_LNS_advance_line); + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeSLEB128(LineDelta, OSE); + OS << OSE.str(); + + LineDelta = 0; + Temp = 0 - DWARF2_LINE_BASE; + NeedCopy = true; + } + + // Use DW_LNS_copy instead of a "line +0, addr +0" special opcode. + if (LineDelta == 0 && AddrDelta == 0) { + OS << char(dwarf::DW_LNS_copy); + return; + } + + // Bias the opcode by the special opcode base. + Temp += DWARF2_LINE_OPCODE_BASE; + + // Avoid overflow when addr_delta is large. + if (AddrDelta < 256 + MAX_SPECIAL_ADDR_DELTA) { + // Try using a special opcode. + Opcode = Temp + AddrDelta * DWARF2_LINE_RANGE; + if (Opcode <= 255) { + OS << char(Opcode); + return; + } + + // Try using DW_LNS_const_add_pc followed by special op. + Opcode = Temp + (AddrDelta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE; + if (Opcode <= 255) { + OS << char(dwarf::DW_LNS_const_add_pc); + OS << char(Opcode); + return; + } + } + + // Otherwise use DW_LNS_advance_pc. + OS << char(dwarf::DW_LNS_advance_pc); + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeULEB128(AddrDelta, OSE); + OS << OSE.str(); + + if (NeedCopy) + OS << char(dwarf::DW_LNS_copy); + else + OS << char(Temp); +} + void MCDwarfFile::print(raw_ostream &OS) const { OS << '"' << getName() << '"'; } @@ -19,3 +487,4 @@ void MCDwarfFile::print(raw_ostream &OS) const { void MCDwarfFile::dump() const { print(dbgs()); } + diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index a0695058e2..42de0ae1b5 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -20,6 +20,7 @@ #include "llvm/MC/MCMachOSymbolFlags.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCDwarf.h" +#include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" @@ -32,11 +33,6 @@ class MCMachOStreamer : public MCObjectStreamer { private: void EmitInstToFragment(const MCInst &Inst); void EmitInstToData(const MCInst &Inst); - // FIXME: These will likely moved to a better place. - void MakeLineEntryForSection(const MCSection *Section); - const MCExpr * MakeStartMinusEndExpr(MCSymbol *Start, MCSymbol *End, - int IntVal); - void EmitDwarfFileTable(void); public: MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB, @@ -420,7 +416,7 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { // Now that a machine instruction has been assembled into this section, make // a line entry for any .loc directive that has been seen. - MakeLineEntryForSection(getCurrentSection()); + MCLineEntry::Make(this, getCurrentSection()); // If this instruction doesn't need relaxation, just emit it as data. if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { @@ -443,206 +439,23 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { EmitInstToFragment(Inst); } -// -// This is called when an instruction is assembled into the specified section -// and if there is information from the last .loc directive that has yet to have -// a line entry made for it is made. -// -void MCMachOStreamer::MakeLineEntryForSection(const MCSection *Section) { - if (!getContext().getDwarfLocSeen()) - return; - - // Create a symbol at in the current section for use in the line entry. - MCSymbol *LineSym = getContext().CreateTempSymbol(); - // Set the value of the symbol to use for the MCLineEntry. - EmitLabel(LineSym); - - // Get the current .loc info saved in the context. - const MCDwarfLoc &DwarfLoc = getContext().getCurrentDwarfLoc(); - - // Create a (local) line entry with the symbol and the current .loc info. - MCLineEntry LineEntry(LineSym, DwarfLoc); - - // clear DwarfLocSeen saying the current .loc info is now used. - getContext().clearDwarfLocSeen(); - - // Get the MCLineSection for this section, if one does not exist for this - // section create it. - DenseMap<const MCSection *, MCLineSection *> &MCLineSections = - getContext().getMCLineSections(); - MCLineSection *LineSection = MCLineSections[Section]; - if (!LineSection) { - // Create a new MCLineSection. This will be deleted after the dwarf line - // table is created using it by iterating through the MCLineSections - // DenseMap. - LineSection = new MCLineSection; - // Save a pointer to the new LineSection into the MCLineSections DenseMap. - MCLineSections[Section] = LineSection; - } - - // Add the line entry to this section's entries. - LineSection->addLineEntry(LineEntry); -} - -// -// This helper routine returns an expression of End - Start + IntVal for use -// by EmitDwarfFileTable() below. -// -const MCExpr * MCMachOStreamer::MakeStartMinusEndExpr(MCSymbol *Start, - MCSymbol *End, - int IntVal) { - MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; - const MCExpr *Res = - MCSymbolRefExpr::Create(End, Variant, getContext()); - const MCExpr *RHS = - MCSymbolRefExpr::Create(Start, Variant, getContext()); - const MCExpr *Res1 = - MCBinaryExpr::Create(MCBinaryExpr::Sub, Res, RHS,getContext()); - const MCExpr *Res2 = - MCConstantExpr::Create(IntVal, getContext()); - const MCExpr *Res3 = - MCBinaryExpr::Create(MCBinaryExpr::Sub, Res1, Res2, getContext()); - return Res3; -} - -// -// This emits the Dwarf file (and eventually the line) table. -// -void MCMachOStreamer::EmitDwarfFileTable(void) { - // For now make sure we don't put out the Dwarf file table if no .file - // directives were seen. - const std::vector<MCDwarfFile *> &MCDwarfFiles = - getContext().getMCDwarfFiles(); - if (MCDwarfFiles.size() == 0) - return; - - // This is the Mach-O section, for ELF it is the .debug_line section. - SwitchSection(getContext().getMachOSection("__DWARF", "__debug_line", +void MCMachOStreamer::Finish() { + // Dump out the dwarf file & directory tables and line tables. + if (getContext().hasDwarfFiles() && + // TODO: This not enabled for 64-bit Mach-O targets. As there are needed + // changes in the handling of 64-bit relocation entries for dwarf Mach-O + // sections that need to made. Currently it gets + // LLVM ERROR: unsupported local relocations in difference + // due dealing with "a-b" expressions made up for dwarf line entries + // because the line section has no non-local symbols thus it can't find + // an atom symbol for the base. + getAssembler().getBackend().getPointerSize() != 8) { + const MCSection *DwarfLineSection = getContext().getMachOSection("__DWARF", + "__debug_line", MCSectionMachO::S_ATTR_DEBUG, - 0, SectionKind::getDataRelLocal())); - - // Create a symbol at the beginning of this section. - MCSymbol *LineStartSym = getContext().CreateTempSymbol(); - // Set the value of the symbol, as we are at the start of the section. - EmitLabel(LineStartSym); - - // Create a symbol for the end of the section (to be set when we get there). - MCSymbol *LineEndSym = getContext().CreateTempSymbol(); - - // The first 4 bytes is the total length of the information for this - // compilation unit (not including these 4 bytes for the length). - EmitValue(MakeStartMinusEndExpr(LineStartSym, LineEndSym, 4), 4, 0); - - // Next 2 bytes is the Version, which is Dwarf 2. - EmitIntValue(2, 2); - - // Create a symbol for the end of the prologue (to be set when we get there). - MCSymbol *ProEndSym = getContext().CreateTempSymbol(); // Lprologue_end - - // Length of the prologue, is the next 4 bytes. Which is the start of the - // section to the end of the prologue. Not including the 4 bytes for the - // total length, the 2 bytes for the version, and these 4 bytes for the - // length of the prologue. - EmitValue(MakeStartMinusEndExpr(LineStartSym, ProEndSym, (4 + 2 + 4)), 4, 0); - - // Parameters of the state machine, are next. - // Define the architecture-dependent minimum instruction length (in - // bytes). This value should be rather too small than too big. */ - // DWARF2_LINE_MIN_INSN_LENGTH - EmitIntValue(1, 1); - // Flag that indicates the initial value of the is_stmt_start flag. - // DWARF2_LINE_DEFAULT_IS_STMT - EmitIntValue(1, 1); - // Minimum line offset in a special line info. opcode. This value - // was chosen to give a reasonable range of values. */ - // DWARF2_LINE_BASE - EmitIntValue(uint64_t(-5), 1); - // Range of line offsets in a special line info. opcode. - // DWARF2_LINE_RANGE - EmitIntValue(14, 1); - // First special line opcode - leave room for the standard opcodes. - // DWARF2_LINE_OPCODE_BASE - EmitIntValue(13, 1); - - // Standard opcode lengths - EmitIntValue(0, 1); // length of DW_LNS_copy - EmitIntValue(1, 1); // length of DW_LNS_advance_pc - EmitIntValue(1, 1); // length of DW_LNS_advance_line - EmitIntValue(1, 1); // length of DW_LNS_set_file - EmitIntValue(1, 1); // length of DW_LNS_set_column - EmitIntValue(0, 1); // length of DW_LNS_negate_stmt - EmitIntValue(0, 1); // length of DW_LNS_set_basic_block - EmitIntValue(0, 1); // length of DW_LNS_const_add_pc - EmitIntValue(1, 1); // length of DW_LNS_fixed_advance_pc - EmitIntValue(0, 1); // length of DW_LNS_set_prologue_end - EmitIntValue(0, 1); // length of DW_LNS_set_epilogue_begin - EmitIntValue(1, 1); // DW_LNS_set_isa - - // Put out the directory and file tables. - - // First the directory table. - const std::vector<StringRef> &MCDwarfDirs = - getContext().getMCDwarfDirs(); - for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { - EmitBytes(MCDwarfDirs[i], 0); // the DirectoryName - EmitBytes(StringRef("\0", 1), 0); // the null termination of the string - } - EmitIntValue(0, 1); // Terminate the directory list - - // Second the file table. - for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { - EmitBytes(MCDwarfFiles[i]->getName(), 0); // FileName - EmitBytes(StringRef("\0", 1), 0); // the null termination of the string - // FIXME the Directory number should be a .uleb128 not a .byte - EmitIntValue(MCDwarfFiles[i]->getDirIndex(), 1); - EmitIntValue(0, 1); // last modification timestamp (always 0) - EmitIntValue(0, 1); // filesize (always 0) + 0, SectionKind::getDataRelLocal()); + MCDwarfFileTable::Emit(this, DwarfLineSection); } - EmitIntValue(0, 1); // Terminate the file list - - // This is the end of the prologue, so set the value of the symbol at the - // end of the prologue (that was used in a previous expression). - EmitLabel(ProEndSym); - - // TODO: This is the point where the line tables would be emitted. - - // Delete the MCLineSections that were created in - // MCMachOStreamer::MakeLineEntryForSection() and used to emit the line - // tables. - DenseMap<const MCSection *, MCLineSection *> &MCLineSections = - getContext().getMCLineSections(); - for (DenseMap<const MCSection *, MCLineSection *>::iterator it = - MCLineSections.begin(), ie = MCLineSections.end(); it != ie; ++it) { - delete it->second; - } - - // If there are no line tables emited then we emit: - // The following DW_LNE_set_address sequence to set the address to zero - // TODO test for 32-bit or 64-bit output - // This is the sequence for 32-bit code - EmitIntValue(0, 1); - EmitIntValue(5, 1); - EmitIntValue(2, 1); - EmitIntValue(0, 1); - EmitIntValue(0, 1); - EmitIntValue(0, 1); - EmitIntValue(0, 1); - - // Lastly emit the DW_LNE_end_sequence which consists of 3 bytes '00 01 01' - // (00 is the code for extended opcodes, followed by a ULEB128 length of the - // extended opcode (01), and the DW_LNE_end_sequence (01). - EmitIntValue(0, 1); // DW_LNS_extended_op - EmitIntValue(1, 1); // ULEB128 length of the extended opcode - EmitIntValue(1, 1); // DW_LNE_end_sequence - - // This is the end of the section, so set the value of the symbol at the end - // of this section (that was used in a previous expression). - EmitLabel(LineEndSym); -} - -void MCMachOStreamer::Finish() { - // Dump out the dwarf file and directory tables (soon to include line table) - EmitDwarfFileTable(); // We have to set the fragment atom associations so we can relax properly for // Mach-O. diff --git a/lib/MC/MCObjectWriter.cpp b/lib/MC/MCObjectWriter.cpp index d117e82b8a..6cee76d040 100644 --- a/lib/MC/MCObjectWriter.cpp +++ b/lib/MC/MCObjectWriter.cpp @@ -13,3 +13,29 @@ using namespace llvm; MCObjectWriter::~MCObjectWriter() { } + +/// Utility function to encode a SLEB128 value. +void MCObjectWriter::EncodeSLEB128(int64_t Value, raw_ostream &OS) { + bool More; + do { + uint8_t Byte = Value & 0x7f; + // NOTE: this assumes that this signed shift is an arithmetic right shift. + Value >>= 7; + More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || + ((Value == -1) && ((Byte & 0x40) != 0)))); + if (More) + Byte |= 0x80; // Mark this byte that that more bytes will follow. + OS << char(Byte); + } while (More); +} + +/// Utility function to encode a ULEB128 value. +void MCObjectWriter::EncodeULEB128(uint64_t Value, raw_ostream &OS) { + do { + uint8_t Byte = Value & 0x7f; + Value >>= 7; + if (Value != 0) + Byte |= 0x80; // Mark this byte that that more bytes will follow. + OS << char(Byte); + } while (Value != 0); +} diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index cb12af1ef9..fbac34a15e 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -2056,7 +2056,7 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { Lex(); } - unsigned Flags = 0; + unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; unsigned Isa = 0; if (getLexer().isNot(AsmToken::EndOfStatement)) { for (;;) { diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index 3e9d02ea5a..54071eba46 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -9,6 +9,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" @@ -35,6 +36,24 @@ void MCStreamer::EmitIntValue(uint64_t Value, unsigned Size, EmitValue(MCConstantExpr::Create(Value, getContext()), Size, AddrSpace); } +// EmitULEB128Value - Special case of EmitValue that emits a ULEB128 of the +// Value as the sequence of ULEB128 encoded bytes. +void MCStreamer::EmitULEB128Value(uint64_t Value, unsigned AddrSpace) { + SmallString<32> Tmp; + raw_svector_ostream OS(Tmp); + MCObjectWriter::EncodeULEB128(Value, OS); + EmitBytes(OS.str(), AddrSpac |