X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FMC%2FMCDwarf.cpp;h=4a075376580beda5fff68fa5d10a9acc913c0e38;hb=8a2ce5d32987f99185f40eb3085a8972291f8d5c;hp=49828080e01e1fb208accdbf6be6d8c88e2377a6;hpb=70be28a5adba5bcae0c6dcd63f17592864c351fc;p=oota-llvm.git diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 49828080e01..4a075376580 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -19,9 +19,13 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/ADT/Hashing.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 @@ -33,7 +37,7 @@ using namespace llvm; // 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(). +// "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 @@ -102,7 +106,7 @@ void MCLineEntry::Make(MCStreamer *MCOS, const MCSection *Section) { // // This helper routine returns an expression of End - Start + IntVal . -// +// static inline const MCExpr *MakeStartMinusEndExpr(const MCStreamer &MCOS, const MCSymbol &Start, const MCSymbol &End, @@ -195,7 +199,7 @@ static inline void EmitDwarfLineTable(MCStreamer *MCOS, // 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. + // Switch back the dwarf line section. MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfLineSection()); const MCAsmInfo &asmInfo = MCOS->getContext().getAsmInfo(); @@ -206,7 +210,7 @@ static inline void EmitDwarfLineTable(MCStreamer *MCOS, // // This emits the Dwarf file and the line tables. // -void MCDwarfFileTable::Emit(MCStreamer *MCOS) { +const MCSymbol *MCDwarfFileTable::Emit(MCStreamer *MCOS) { MCContext &context = MCOS->getContext(); // Switch to the section where the table will be emitted into. MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfLineSection()); @@ -307,7 +311,7 @@ void MCDwarfFileTable::Emit(MCStreamer *MCOS) { if (MCOS->getContext().getAsmInfo().getLinkerRequiresNonEmptyDwarfLines() && MCLineSectionOrder.begin() == MCLineSectionOrder.end()) { // The darwin9 linker has a bug (see PR8715). For for 32-bit architectures - // it requires: + // it requires: // total_length >= prologue_length + 10 // We are 4 bytes short, since we have total_length = 51 and // prologue_length = 45 @@ -319,6 +323,8 @@ void MCDwarfFileTable::Emit(MCStreamer *MCOS) { // 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); + + return LineStartSym; } /// Utility function to write the encoding to an object writer. @@ -349,14 +355,14 @@ void MCDwarfLineAddr::Encode(int64_t LineDelta, uint64_t AddrDelta, 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 + // 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); - MCObjectWriter::EncodeULEB128(AddrDelta, OS); + encodeULEB128(AddrDelta, OS); } OS << char(dwarf::DW_LNS_extended_op); OS << char(1); @@ -371,10 +377,7 @@ void MCDwarfLineAddr::Encode(int64_t LineDelta, uint64_t AddrDelta, // 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(); + encodeSLEB128(LineDelta, OS); LineDelta = 0; Temp = 0 - DWARF2_LINE_BASE; @@ -410,10 +413,7 @@ void MCDwarfLineAddr::Encode(int64_t LineDelta, uint64_t AddrDelta, // 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(); + encodeULEB128(AddrDelta, OS); if (NeedCopy) OS << char(dwarf::DW_LNS_copy); @@ -425,9 +425,364 @@ void MCDwarfFile::print(raw_ostream &OS) const { OS << '"' << getName() << '"'; } +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void MCDwarfFile::dump() const { print(dbgs()); } +#endif + +// 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_label DIE abbrev (2). + MCOS->EmitULEB128IntValue(2); + MCOS->EmitULEB128IntValue(dwarf::DW_TAG_label); + 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_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, + const MCSymbol *InfoSectionSymbol) { + 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. + if (InfoSectionSymbol) + MCOS->EmitSymbolValue(InfoSectionSymbol, 4); + else + 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 label DIEs. +static void EmitGenDwarfInfo(MCStreamer *MCOS, + const MCSymbol *AbbrevSectionSymbol, + const MCSymbol *LineSectionSymbol) { + 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. + if (AbbrevSectionSymbol) { + MCOS->EmitSymbolValue(AbbrevSectionSymbol, 4); + } else { + 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. + if (LineSectionSymbol) { + MCOS->EmitSymbolValue(LineSectionSymbol, 4); + } else { + 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 &MCDwarfDirs = + context.getMCDwarfDirs(); + if (MCDwarfDirs.size() > 0) { + MCOS->EmitBytes(MCDwarfDirs[0], 0); + MCOS->EmitBytes("/", 0); + } + const std::vector &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 label DIEs. + + // Loop on saved info for dwarf labels and create the DIEs for them. + const std::vector &Entries = + MCOS->getContext().getMCGenDwarfLabelEntries(); + for (std::vector::const_iterator it = + Entries.begin(), ie = Entries.end(); it != ie; + ++it) { + const MCGenDwarfLabelEntry *Entry = *it; + + // The DW_TAG_label 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); + + // 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 MCGenDwarfLabelEntry classes that saved away the info + // for the dwarf labels. + for (std::vector::const_iterator it = + Entries.begin(), ie = Entries.end(); it != ie; + ++it) { + const MCGenDwarfLabelEntry *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, const MCSymbol *LineSectionSymbol) { + // Create the dwarf sections in this order (.debug_line already created). + MCContext &context = MCOS->getContext(); + const MCAsmInfo &AsmInfo = context.getAsmInfo(); + bool CreateDwarfSectionSymbols = + AsmInfo.doesDwarfUseRelocationsAcrossSections(); + if (!CreateDwarfSectionSymbols) + LineSectionSymbol = NULL; + MCSymbol *AbbrevSectionSymbol = NULL; + MCSymbol *InfoSectionSymbol = NULL; + MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfInfoSection()); + if (CreateDwarfSectionSymbols) { + InfoSectionSymbol = context.CreateTempSymbol(); + MCOS->EmitLabel(InfoSectionSymbol); + } + MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfAbbrevSection()); + if (CreateDwarfSectionSymbols) { + AbbrevSectionSymbol = context.CreateTempSymbol(); + MCOS->EmitLabel(AbbrevSectionSymbol); + } + 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, InfoSectionSymbol); + + // Output the data for .debug_abbrev section. + EmitGenDwarfAbbrev(MCOS); + + // Output the data for .debug_info section. + EmitGenDwarfInfo(MCOS, AbbrevSectionSymbol, LineSectionSymbol); +} + +// +// 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 label. +// +void MCGenDwarfLabelEntry::Make(MCSymbol *Symbol, MCStreamer *MCOS, + SourceMgr &SrcMgr, SMLoc &Loc) { + // We won't create dwarf labels 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 label'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 label. + 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 label. + 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. + MCGenDwarfLabelEntry *Entry = + new MCGenDwarfLabelEntry(Name, FileNumber, LineNumber, Label); + MCOS->getContext().addMCGenDwarfLabelEntry(Entry); +} static int getDataAlignmentFactor(MCStreamer &streamer) { MCContext &context = streamer.getContext(); @@ -444,8 +799,7 @@ static unsigned getSizeForEncoding(MCStreamer &streamer, MCContext &context = streamer.getContext(); unsigned format = symbolEncoding & 0x0f; switch (format) { - default: - assert(0 && "Unknown Encoding"); + default: llvm_unreachable("Unknown Encoding"); case dwarf::DW_EH_PE_absptr: case dwarf::DW_EH_PE_signed: return context.getAsmInfo().getPointerSize(); @@ -519,6 +873,7 @@ namespace { const MCSymbol *personality, unsigned personalityEncoding, const MCSymbol *lsda, + bool IsSignalFrame, unsigned lsdaEncoding); MCSymbol *EmitFDE(MCStreamer &streamer, const MCSymbol &cieStart, @@ -535,28 +890,40 @@ namespace { static void EmitEncodingByte(MCStreamer &Streamer, unsigned Encoding, StringRef Prefix) { if (Streamer.isVerboseAsm()) { - const char *EncStr = 0; + const char *EncStr; switch (Encoding) { - default: EncStr = ""; - case dwarf::DW_EH_PE_absptr: EncStr = "absptr"; - case dwarf::DW_EH_PE_omit: EncStr = "omit"; - case dwarf::DW_EH_PE_pcrel: EncStr = "pcrel"; - case dwarf::DW_EH_PE_udata4: EncStr = "udata4"; - case dwarf::DW_EH_PE_udata8: EncStr = "udata8"; - case dwarf::DW_EH_PE_sdata4: EncStr = "sdata4"; - case dwarf::DW_EH_PE_sdata8: EncStr = "sdata8"; - case dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_udata4: EncStr = "pcrel udata4"; - case dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_sdata4: EncStr = "pcrel sdata4"; - case dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_udata8: EncStr = "pcrel udata8"; - case dwarf::DW_EH_PE_pcrel |dwarf::DW_EH_PE_sdata8: EncStr = "pcrel sdata8"; + default: EncStr = ""; break; + case dwarf::DW_EH_PE_absptr: EncStr = "absptr"; break; + case dwarf::DW_EH_PE_omit: EncStr = "omit"; break; + case dwarf::DW_EH_PE_pcrel: EncStr = "pcrel"; break; + case dwarf::DW_EH_PE_udata4: EncStr = "udata4"; break; + case dwarf::DW_EH_PE_udata8: EncStr = "udata8"; break; + case dwarf::DW_EH_PE_sdata4: EncStr = "sdata4"; break; + case dwarf::DW_EH_PE_sdata8: EncStr = "sdata8"; break; + case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata4: + EncStr = "pcrel udata4"; + break; + case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4: + EncStr = "pcrel sdata4"; + break; + case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8: + EncStr = "pcrel udata8"; + break; + case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8: + EncStr = "screl sdata8"; + break; case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_udata4: EncStr = "indirect pcrel udata4"; + break; case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_sdata4: EncStr = "indirect pcrel sdata4"; + break; case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_udata8: EncStr = "indirect pcrel udata8"; + break; case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_sdata8: EncStr = "indirect pcrel sdata8"; + break; } Streamer.AddComment(Twine(Prefix) + " = " + EncStr); @@ -571,46 +938,73 @@ void FrameEmitterImpl::EmitCFIInstruction(MCStreamer &Streamer, bool VerboseAsm = Streamer.isVerboseAsm(); switch (Instr.getOperation()) { - case MCCFIInstruction::Move: - case MCCFIInstruction::RelMove: { - const MachineLocation &Dst = Instr.getDestination(); - const MachineLocation &Src = Instr.getSource(); - const bool IsRelative = Instr.getOperation() == MCCFIInstruction::RelMove; - - // If advancing cfa. - if (Dst.isReg() && Dst.getReg() == MachineLocation::VirtualFP) { - if (Src.getReg() == MachineLocation::VirtualFP) { - if (VerboseAsm) Streamer.AddComment("DW_CFA_def_cfa_offset"); - Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_offset, 1); - } else { - if (VerboseAsm) Streamer.AddComment("DW_CFA_def_cfa"); - Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1); - if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + - Twine(Src.getReg())); - Streamer.EmitULEB128IntValue(Src.getReg()); - } + case MCCFIInstruction::OpUndefined: { + unsigned Reg = Instr.getRegister(); + if (VerboseAsm) { + Streamer.AddComment("DW_CFA_undefined"); + Streamer.AddComment(Twine("Reg ") + Twine(Reg)); + } + Streamer.EmitIntValue(dwarf::DW_CFA_undefined, 1); + Streamer.EmitULEB128IntValue(Reg); + return; + } + case MCCFIInstruction::OpAdjustCfaOffset: + case MCCFIInstruction::OpDefCfaOffset: { + const bool IsRelative = + Instr.getOperation() == MCCFIInstruction::OpAdjustCfaOffset; - if (IsRelative) - CFAOffset += Src.getOffset(); - else - CFAOffset = -Src.getOffset(); + if (VerboseAsm) + Streamer.AddComment("DW_CFA_def_cfa_offset"); + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_offset, 1); - if (VerboseAsm) Streamer.AddComment(Twine("Offset " + Twine(CFAOffset))); - Streamer.EmitULEB128IntValue(CFAOffset); - return; - } + if (IsRelative) + CFAOffset += Instr.getOffset(); + else + CFAOffset = -Instr.getOffset(); - if (Src.isReg() && Src.getReg() == MachineLocation::VirtualFP) { - assert(Dst.isReg() && "Machine move not supported yet."); - if (VerboseAsm) Streamer.AddComment("DW_CFA_def_cfa_register"); - Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1); - if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Dst.getReg())); - Streamer.EmitULEB128IntValue(Dst.getReg()); - return; - } + if (VerboseAsm) + Streamer.AddComment(Twine("Offset " + Twine(CFAOffset))); + Streamer.EmitULEB128IntValue(CFAOffset); + + return; + } + case MCCFIInstruction::OpDefCfa: { + if (VerboseAsm) + Streamer.AddComment("DW_CFA_def_cfa"); + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1); + + if (VerboseAsm) + Streamer.AddComment(Twine("Reg ") + Twine(Instr.getRegister())); + Streamer.EmitULEB128IntValue(Instr.getRegister()); + + CFAOffset = -Instr.getOffset(); + + if (VerboseAsm) + Streamer.AddComment(Twine("Offset " + Twine(CFAOffset))); + Streamer.EmitULEB128IntValue(CFAOffset); + + return; + } - unsigned Reg = Src.getReg(); - int Offset = Dst.getOffset(); + case MCCFIInstruction::OpDefCfaRegister: { + if (VerboseAsm) + Streamer.AddComment("DW_CFA_def_cfa_register"); + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1); + + if (VerboseAsm) + Streamer.AddComment(Twine("Reg ") + Twine(Instr.getRegister())); + Streamer.EmitULEB128IntValue(Instr.getRegister()); + + return; + } + + case MCCFIInstruction::OpOffset: + case MCCFIInstruction::OpRelOffset: { + const bool IsRelative = + Instr.getOperation() == MCCFIInstruction::OpRelOffset; + + unsigned Reg = Instr.getRegister(); + int Offset = Instr.getOffset(); if (IsRelative) Offset -= CFAOffset; Offset = Offset / dataAlignmentFactor; @@ -638,22 +1032,35 @@ void FrameEmitterImpl::EmitCFIInstruction(MCStreamer &Streamer, } return; } - case MCCFIInstruction::Remember: + case MCCFIInstruction::OpRememberState: if (VerboseAsm) Streamer.AddComment("DW_CFA_remember_state"); Streamer.EmitIntValue(dwarf::DW_CFA_remember_state, 1); return; - case MCCFIInstruction::Restore: + case MCCFIInstruction::OpRestoreState: if (VerboseAsm) Streamer.AddComment("DW_CFA_restore_state"); Streamer.EmitIntValue(dwarf::DW_CFA_restore_state, 1); return; - case MCCFIInstruction::SameValue: { - unsigned Reg = Instr.getDestination().getReg(); + case MCCFIInstruction::OpSameValue: { + unsigned Reg = Instr.getRegister(); if (VerboseAsm) Streamer.AddComment("DW_CFA_same_value"); Streamer.EmitIntValue(dwarf::DW_CFA_same_value, 1); if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Reg)); Streamer.EmitULEB128IntValue(Reg); return; } + case MCCFIInstruction::OpRestore: { + unsigned Reg = Instr.getRegister(); + if (VerboseAsm) { + Streamer.AddComment("DW_CFA_restore"); + Streamer.AddComment(Twine("Reg ") + Twine(Reg)); + } + Streamer.EmitIntValue(dwarf::DW_CFA_restore | Reg, 1); + return; + } + case MCCFIInstruction::OpEscape: + if (VerboseAsm) Streamer.AddComment("Escape bytes"); + Streamer.EmitBytes(Instr.getValues(), 0); + return; } llvm_unreachable("Unhandled case in switch"); } @@ -765,6 +1172,7 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(MCStreamer &streamer, const MCSymbol *personality, unsigned personalityEncoding, const MCSymbol *lsda, + bool IsSignalFrame, unsigned lsdaEncoding) { MCContext &context = streamer.getContext(); const MCRegisterInfo &MRI = context.getRegisterInfo(); @@ -807,6 +1215,8 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(MCStreamer &streamer, if (lsda) Augmentation += "L"; Augmentation += "R"; + if (IsSignalFrame) + Augmentation += "S"; streamer.EmitBytes(Augmentation.str(), 0); } streamer.EmitIntValue(0, 1); @@ -871,8 +1281,21 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(MCStreamer &streamer, TranslateMachineLocation(MRI, Moves[i].getDestination()); const MachineLocation &Src = TranslateMachineLocation(MRI, Moves[i].getSource()); - MCCFIInstruction Inst(Label, Dst, Src); - Instructions.push_back(Inst); + + if (Dst.isReg()) { + assert(Dst.getReg() == MachineLocation::VirtualFP); + assert(!Src.isReg()); + MCCFIInstruction Inst = + MCCFIInstruction::createDefCfa(Label, Src.getReg(), -Src.getOffset()); + Instructions.push_back(Inst); + } else { + assert(Src.isReg()); + unsigned Reg = Src.getReg(); + int Offset = Dst.getOffset(); + MCCFIInstruction Inst = + MCCFIInstruction::createOffset(Label, Reg, Offset); + Instructions.push_back(Inst); + } } EmitCFIInstructions(streamer, Instructions, NULL); @@ -915,7 +1338,7 @@ MCSymbol *FrameEmitterImpl::EmitFDE(MCStreamer &streamer, 0); if (verboseAsm) streamer.AddComment("FDE CIE Offset"); streamer.EmitAbsValue(offset, 4); - } else if (!asmInfo.doesDwarfRequireRelocationForSectionOffset()) { + } else if (!asmInfo.doesDwarfUseRelocationsAcrossSections()) { const MCExpr *offset = MakeStartMinusEndExpr(streamer, *SectionStart, cieStart, 0); streamer.EmitAbsValue(offset, 4); @@ -923,20 +1346,17 @@ MCSymbol *FrameEmitterImpl::EmitFDE(MCStreamer &streamer, streamer.EmitSymbolValue(&cieStart, 4); } - unsigned fdeEncoding = MOFI->getFDEEncoding(UsingCFI); - unsigned size = getSizeForEncoding(streamer, fdeEncoding); - // PC Begin - unsigned PCBeginEncoding = IsEH ? fdeEncoding : - (unsigned)dwarf::DW_EH_PE_absptr; - unsigned PCBeginSize = getSizeForEncoding(streamer, PCBeginEncoding); - EmitSymbol(streamer, *frame.Begin, PCBeginEncoding, "FDE initial location"); + unsigned PCEncoding = IsEH ? MOFI->getFDEEncoding(UsingCFI) + : (unsigned)dwarf::DW_EH_PE_absptr; + unsigned PCSize = getSizeForEncoding(streamer, PCEncoding); + EmitSymbol(streamer, *frame.Begin, PCEncoding, "FDE initial location"); // PC Range const MCExpr *Range = MakeStartMinusEndExpr(streamer, *frame.Begin, *frame.End, 0); if (verboseAsm) streamer.AddComment("FDE address range"); - streamer.EmitAbsValue(Range, size); + streamer.EmitAbsValue(Range, PCSize); if (IsEH) { // Augmentation Data Length @@ -959,24 +1379,25 @@ MCSymbol *FrameEmitterImpl::EmitFDE(MCStreamer &streamer, EmitCFIInstructions(streamer, frame.Instructions, frame.Begin); // Padding - streamer.EmitValueToAlignment(PCBeginSize); + streamer.EmitValueToAlignment(PCSize); return fdeEnd; } namespace { struct CIEKey { - static const CIEKey getEmptyKey() { return CIEKey(0, 0, -1); } - static const CIEKey getTombstoneKey() { return CIEKey(0, -1, 0); } + static const CIEKey getEmptyKey() { return CIEKey(0, 0, -1, false); } + static const CIEKey getTombstoneKey() { return CIEKey(0, -1, 0, false); } CIEKey(const MCSymbol* Personality_, unsigned PersonalityEncoding_, - unsigned LsdaEncoding_) : Personality(Personality_), - PersonalityEncoding(PersonalityEncoding_), - LsdaEncoding(LsdaEncoding_) { + unsigned LsdaEncoding_, bool IsSignalFrame_) : + Personality(Personality_), PersonalityEncoding(PersonalityEncoding_), + LsdaEncoding(LsdaEncoding_), IsSignalFrame(IsSignalFrame_) { } const MCSymbol* Personality; unsigned PersonalityEncoding; unsigned LsdaEncoding; + bool IsSignalFrame; }; } @@ -990,17 +1411,17 @@ namespace llvm { return CIEKey::getTombstoneKey(); } static unsigned getHashValue(const CIEKey &Key) { - FoldingSetNodeID ID; - ID.AddPointer(Key.Personality); - ID.AddInteger(Key.PersonalityEncoding); - ID.AddInteger(Key.LsdaEncoding); - return ID.ComputeHash(); + return static_cast(hash_combine(Key.Personality, + Key.PersonalityEncoding, + Key.LsdaEncoding, + Key.IsSignalFrame)); } static bool isEqual(const CIEKey &LHS, const CIEKey &RHS) { return LHS.Personality == RHS.Personality && LHS.PersonalityEncoding == RHS.PersonalityEncoding && - LHS.LsdaEncoding == RHS.LsdaEncoding; + LHS.LsdaEncoding == RHS.LsdaEncoding && + LHS.IsSignalFrame == RHS.IsSignalFrame; } }; } @@ -1015,12 +1436,10 @@ void MCDwarfFrameEmitter::Emit(MCStreamer &Streamer, ArrayRef FrameArray = Streamer.getFrameInfos(); // Emit the compact unwind info if available. - // FIXME: This emits both the compact unwind and the old CIE/FDE - // information. Only one of those is needed. if (IsEH && MOFI->getCompactUnwindSection()) for (unsigned i = 0, n = Streamer.getNumFrameInfos(); i < n; ++i) { const MCDwarfFrameInfo &Frame = Streamer.getFrameInfo(i); - if (!Frame.CompactUnwindEncoding) + if (Frame.CompactUnwindEncoding) Emitter.EmitCompactUnwind(Streamer, Frame); } @@ -1038,11 +1457,12 @@ void MCDwarfFrameEmitter::Emit(MCStreamer &Streamer, for (unsigned i = 0, n = FrameArray.size(); i < n; ++i) { const MCDwarfFrameInfo &Frame = FrameArray[i]; CIEKey Key(Frame.Personality, Frame.PersonalityEncoding, - Frame.LsdaEncoding); + Frame.LsdaEncoding, Frame.IsSignalFrame); const MCSymbol *&CIEStart = IsEH ? CIEStarts[Key] : DummyDebugKey; if (!CIEStart) CIEStart = &Emitter.EmitCIE(Streamer, Frame.Personality, Frame.PersonalityEncoding, Frame.Lsda, + Frame.IsSignalFrame, Frame.LsdaEncoding); FDEEnd = Emitter.EmitFDE(Streamer, *CIEStart, Frame);