| Kevin Enderby | 7cbf73a | 2010-07-28 20:55:35 +0000 | [diff] [blame] | 1 | //===- lib/MC/MCDwarf.cpp - MCDwarf implementation ------------------------===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 |  | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 10 | #include "llvm/ADT/FoldingSet.h" | 
| Rafael Espindola | 767b1be | 2010-12-04 00:31:13 +0000 | [diff] [blame] | 11 | #include "llvm/MC/MCAsmInfo.h" | 
| Kevin Enderby | 7cbf73a | 2010-07-28 20:55:35 +0000 | [diff] [blame] | 12 | #include "llvm/MC/MCDwarf.h" | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 13 | #include "llvm/MC/MCAssembler.h" | 
| Rafael Espindola | ad8aaa0 | 2010-11-22 11:53:17 +0000 | [diff] [blame] | 14 | #include "llvm/MC/MCStreamer.h" | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 15 | #include "llvm/MC/MCSymbol.h" | 
|  | 16 | #include "llvm/MC/MCExpr.h" | 
|  | 17 | #include "llvm/MC/MCContext.h" | 
|  | 18 | #include "llvm/MC/MCObjectWriter.h" | 
|  | 19 | #include "llvm/ADT/SmallString.h" | 
| Kevin Enderby | 7cbf73a | 2010-07-28 20:55:35 +0000 | [diff] [blame] | 20 | #include "llvm/Support/Debug.h" | 
| Rafael Espindola | fe024d0 | 2010-12-28 18:36:23 +0000 | [diff] [blame] | 21 | #include "llvm/Support/ErrorHandling.h" | 
| Kevin Enderby | 7cbf73a | 2010-07-28 20:55:35 +0000 | [diff] [blame] | 22 | #include "llvm/Support/raw_ostream.h" | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 23 | #include "llvm/Target/TargetAsmBackend.h" | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 24 | #include "llvm/Target/TargetAsmInfo.h" | 
| Kevin Enderby | 7cbf73a | 2010-07-28 20:55:35 +0000 | [diff] [blame] | 25 | using namespace llvm; | 
|  | 26 |  | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 27 | // Given a special op, return the address skip amount (in units of | 
|  | 28 | // DWARF2_LINE_MIN_INSN_LENGTH. | 
|  | 29 | #define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE) | 
|  | 30 |  | 
|  | 31 | // The maximum address skip amount that can be encoded with a special op. | 
|  | 32 | #define MAX_SPECIAL_ADDR_DELTA		SPECIAL_ADDR(255) | 
|  | 33 |  | 
|  | 34 | // First special line opcode - leave room for the standard opcodes. | 
|  | 35 | // Note: If you want to change this, you'll have to update the | 
|  | 36 | // "standard_opcode_lengths" table that is emitted in DwarfFileTable::Emit(). | 
|  | 37 | #define DWARF2_LINE_OPCODE_BASE		13 | 
|  | 38 |  | 
|  | 39 | // Minimum line offset in a special line info. opcode.  This value | 
|  | 40 | // was chosen to give a reasonable range of values. | 
|  | 41 | #define DWARF2_LINE_BASE		-5 | 
|  | 42 |  | 
|  | 43 | // Range of line offsets in a special line info. opcode. | 
|  | 44 | # define DWARF2_LINE_RANGE		14 | 
|  | 45 |  | 
|  | 46 | // Define the architecture-dependent minimum instruction length (in bytes). | 
|  | 47 | // This value should be rather too small than too big. | 
|  | 48 | # define DWARF2_LINE_MIN_INSN_LENGTH	1 | 
|  | 49 |  | 
|  | 50 | // Note: when DWARF2_LINE_MIN_INSN_LENGTH == 1 which is the current setting, | 
|  | 51 | // this routine is a nop and will be optimized away. | 
|  | 52 | static inline uint64_t ScaleAddrDelta(uint64_t AddrDelta) | 
|  | 53 | { | 
|  | 54 | if (DWARF2_LINE_MIN_INSN_LENGTH == 1) | 
|  | 55 | return AddrDelta; | 
|  | 56 | if (AddrDelta % DWARF2_LINE_MIN_INSN_LENGTH != 0) { | 
|  | 57 | // TODO: report this error, but really only once. | 
|  | 58 | ; | 
|  | 59 | } | 
|  | 60 | return AddrDelta / DWARF2_LINE_MIN_INSN_LENGTH; | 
|  | 61 | } | 
|  | 62 |  | 
|  | 63 | // | 
|  | 64 | // This is called when an instruction is assembled into the specified section | 
|  | 65 | // and if there is information from the last .loc directive that has yet to have | 
|  | 66 | // a line entry made for it is made. | 
|  | 67 | // | 
| Rafael Espindola | 195a0ce | 2010-11-19 02:26:16 +0000 | [diff] [blame] | 68 | void MCLineEntry::Make(MCStreamer *MCOS, const MCSection *Section) { | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 69 | if (!MCOS->getContext().getDwarfLocSeen()) | 
|  | 70 | return; | 
|  | 71 |  | 
|  | 72 | // Create a symbol at in the current section for use in the line entry. | 
|  | 73 | MCSymbol *LineSym = MCOS->getContext().CreateTempSymbol(); | 
|  | 74 | // Set the value of the symbol to use for the MCLineEntry. | 
|  | 75 | MCOS->EmitLabel(LineSym); | 
|  | 76 |  | 
|  | 77 | // Get the current .loc info saved in the context. | 
|  | 78 | const MCDwarfLoc &DwarfLoc = MCOS->getContext().getCurrentDwarfLoc(); | 
|  | 79 |  | 
|  | 80 | // Create a (local) line entry with the symbol and the current .loc info. | 
|  | 81 | MCLineEntry LineEntry(LineSym, DwarfLoc); | 
|  | 82 |  | 
|  | 83 | // clear DwarfLocSeen saying the current .loc info is now used. | 
| Kevin Enderby | 3f55c24 | 2010-10-04 20:17:24 +0000 | [diff] [blame] | 84 | MCOS->getContext().ClearDwarfLocSeen(); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 85 |  | 
|  | 86 | // Get the MCLineSection for this section, if one does not exist for this | 
|  | 87 | // section create it. | 
| Rafael Espindola | 17fd7bd | 2010-11-19 07:41:23 +0000 | [diff] [blame] | 88 | const DenseMap<const MCSection *, MCLineSection *> &MCLineSections = | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 89 | MCOS->getContext().getMCLineSections(); | 
| Rafael Espindola | 17fd7bd | 2010-11-19 07:41:23 +0000 | [diff] [blame] | 90 | MCLineSection *LineSection = MCLineSections.lookup(Section); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 91 | if (!LineSection) { | 
|  | 92 | // Create a new MCLineSection.  This will be deleted after the dwarf line | 
|  | 93 | // table is created using it by iterating through the MCLineSections | 
|  | 94 | // DenseMap. | 
|  | 95 | LineSection = new MCLineSection; | 
|  | 96 | // Save a pointer to the new LineSection into the MCLineSections DenseMap. | 
| Rafael Espindola | 17fd7bd | 2010-11-19 07:41:23 +0000 | [diff] [blame] | 97 | MCOS->getContext().addMCLineSection(Section, LineSection); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 98 | } | 
|  | 99 |  | 
|  | 100 | // Add the line entry to this section's entries. | 
|  | 101 | LineSection->addLineEntry(LineEntry); | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | // | 
|  | 105 | // This helper routine returns an expression of End - Start + IntVal . | 
|  | 106 | // | 
| Rafael Espindola | 5fad7a9 | 2010-12-09 23:08:35 +0000 | [diff] [blame] | 107 | static inline const MCExpr *MakeStartMinusEndExpr(const MCStreamer &MCOS, | 
|  | 108 | const MCSymbol &Start, | 
|  | 109 | const MCSymbol &End, | 
|  | 110 | int IntVal) { | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 111 | MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; | 
|  | 112 | const MCExpr *Res = | 
| Rafael Espindola | 5fad7a9 | 2010-12-09 23:08:35 +0000 | [diff] [blame] | 113 | MCSymbolRefExpr::Create(&End, Variant, MCOS.getContext()); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 114 | const MCExpr *RHS = | 
| Rafael Espindola | 5fad7a9 | 2010-12-09 23:08:35 +0000 | [diff] [blame] | 115 | MCSymbolRefExpr::Create(&Start, Variant, MCOS.getContext()); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 116 | const MCExpr *Res1 = | 
| Rafael Espindola | 5fad7a9 | 2010-12-09 23:08:35 +0000 | [diff] [blame] | 117 | MCBinaryExpr::Create(MCBinaryExpr::Sub, Res, RHS, MCOS.getContext()); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 118 | const MCExpr *Res2 = | 
| Rafael Espindola | 5fad7a9 | 2010-12-09 23:08:35 +0000 | [diff] [blame] | 119 | MCConstantExpr::Create(IntVal, MCOS.getContext()); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 120 | const MCExpr *Res3 = | 
| Rafael Espindola | 5fad7a9 | 2010-12-09 23:08:35 +0000 | [diff] [blame] | 121 | MCBinaryExpr::Create(MCBinaryExpr::Sub, Res1, Res2, MCOS.getContext()); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 122 | return Res3; | 
|  | 123 | } | 
|  | 124 |  | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 125 | // | 
|  | 126 | // This emits the Dwarf line table for the specified section from the entries | 
|  | 127 | // in the LineSection. | 
|  | 128 | // | 
| Rafael Espindola | 195a0ce | 2010-11-19 02:26:16 +0000 | [diff] [blame] | 129 | static inline void EmitDwarfLineTable(MCStreamer *MCOS, | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 130 | const MCSection *Section, | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 131 | const MCLineSection *LineSection) { | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 132 | unsigned FileNum = 1; | 
|  | 133 | unsigned LastLine = 1; | 
|  | 134 | unsigned Column = 0; | 
|  | 135 | unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; | 
|  | 136 | unsigned Isa = 0; | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 137 | MCSymbol *LastLabel = NULL; | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 138 |  | 
|  | 139 | // Loop through each MCLineEntry and encode the dwarf line number table. | 
| Rafael Espindola | 17fd7bd | 2010-11-19 07:41:23 +0000 | [diff] [blame] | 140 | for (MCLineSection::const_iterator | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 141 | it = LineSection->getMCLineEntries()->begin(), | 
|  | 142 | ie = LineSection->getMCLineEntries()->end(); it != ie; ++it) { | 
|  | 143 |  | 
|  | 144 | if (FileNum != it->getFileNum()) { | 
|  | 145 | FileNum = it->getFileNum(); | 
|  | 146 | MCOS->EmitIntValue(dwarf::DW_LNS_set_file, 1); | 
| Rafael Espindola | 3ff5709 | 2010-11-02 17:22:24 +0000 | [diff] [blame] | 147 | MCOS->EmitULEB128IntValue(FileNum); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 148 | } | 
|  | 149 | if (Column != it->getColumn()) { | 
|  | 150 | Column = it->getColumn(); | 
|  | 151 | MCOS->EmitIntValue(dwarf::DW_LNS_set_column, 1); | 
| Rafael Espindola | 3ff5709 | 2010-11-02 17:22:24 +0000 | [diff] [blame] | 152 | MCOS->EmitULEB128IntValue(Column); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 153 | } | 
|  | 154 | if (Isa != it->getIsa()) { | 
|  | 155 | Isa = it->getIsa(); | 
|  | 156 | MCOS->EmitIntValue(dwarf::DW_LNS_set_isa, 1); | 
| Rafael Espindola | 3ff5709 | 2010-11-02 17:22:24 +0000 | [diff] [blame] | 157 | MCOS->EmitULEB128IntValue(Isa); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 158 | } | 
|  | 159 | if ((it->getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) { | 
|  | 160 | Flags = it->getFlags(); | 
|  | 161 | MCOS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1); | 
|  | 162 | } | 
|  | 163 | if (it->getFlags() & DWARF2_FLAG_BASIC_BLOCK) | 
|  | 164 | MCOS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1); | 
|  | 165 | if (it->getFlags() & DWARF2_FLAG_PROLOGUE_END) | 
|  | 166 | MCOS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1); | 
|  | 167 | if (it->getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN) | 
|  | 168 | MCOS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1); | 
|  | 169 |  | 
| Rafael Espindola | 64185cc | 2010-11-13 01:06:27 +0000 | [diff] [blame] | 170 | int64_t LineDelta = static_cast<int64_t>(it->getLine()) - LastLine; | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 171 | MCSymbol *Label = it->getLabel(); | 
|  | 172 |  | 
|  | 173 | // At this point we want to emit/create the sequence to encode the delta in | 
|  | 174 | // line numbers and the increment of the address from the previous Label | 
|  | 175 | // and the current Label. | 
| Rafael Espindola | 32a006e | 2010-12-03 00:55:40 +0000 | [diff] [blame] | 176 | MCOS->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 177 |  | 
|  | 178 | LastLine = it->getLine(); | 
|  | 179 | LastLabel = Label; | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 180 | } | 
|  | 181 |  | 
|  | 182 | // Emit a DW_LNE_end_sequence for the end of the section. | 
|  | 183 | // Using the pointer Section create a temporary label at the end of the | 
|  | 184 | // section and use that and the LastLabel to compute the address delta | 
|  | 185 | // and use INT64_MAX as the line delta which is the signal that this is | 
|  | 186 | // actually a DW_LNE_end_sequence. | 
|  | 187 |  | 
|  | 188 | // Switch to the section to be able to create a symbol at its end. | 
|  | 189 | MCOS->SwitchSection(Section); | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 190 |  | 
|  | 191 | MCContext &context = MCOS->getContext(); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 192 | // Create a symbol at the end of the section. | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 193 | MCSymbol *SectionEnd = context.CreateTempSymbol(); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 194 | // Set the value of the symbol, as we are at the end of the section. | 
|  | 195 | MCOS->EmitLabel(SectionEnd); | 
|  | 196 |  | 
|  | 197 | // Switch back the the dwarf line section. | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 198 | MCOS->SwitchSection(context.getTargetAsmInfo().getDwarfLineSection()); | 
| Rafael Espindola | 195a0ce | 2010-11-19 02:26:16 +0000 | [diff] [blame] | 199 |  | 
| Rafael Espindola | 32a006e | 2010-12-03 00:55:40 +0000 | [diff] [blame] | 200 | MCOS->EmitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 201 | } | 
|  | 202 |  | 
|  | 203 | // | 
|  | 204 | // This emits the Dwarf file and the line tables. | 
|  | 205 | // | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 206 | void MCDwarfFileTable::Emit(MCStreamer *MCOS) { | 
|  | 207 | MCContext &context = MCOS->getContext(); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 208 | // Switch to the section where the table will be emitted into. | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 209 | MCOS->SwitchSection(context.getTargetAsmInfo().getDwarfLineSection()); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 210 |  | 
|  | 211 | // Create a symbol at the beginning of this section. | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 212 | MCSymbol *LineStartSym = context.CreateTempSymbol(); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 213 | // Set the value of the symbol, as we are at the start of the section. | 
|  | 214 | MCOS->EmitLabel(LineStartSym); | 
|  | 215 |  | 
|  | 216 | // Create a symbol for the end of the section (to be set when we get there). | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 217 | MCSymbol *LineEndSym = context.CreateTempSymbol(); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 218 |  | 
|  | 219 | // The first 4 bytes is the total length of the information for this | 
|  | 220 | // compilation unit (not including these 4 bytes for the length). | 
| Rafael Espindola | 5fad7a9 | 2010-12-09 23:08:35 +0000 | [diff] [blame] | 221 | MCOS->EmitAbsValue(MakeStartMinusEndExpr(*MCOS, *LineStartSym, *LineEndSym,4), | 
| Rafael Espindola | 0bbe0b4 | 2010-12-06 17:27:56 +0000 | [diff] [blame] | 222 | 4); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 223 |  | 
|  | 224 | // Next 2 bytes is the Version, which is Dwarf 2. | 
|  | 225 | MCOS->EmitIntValue(2, 2); | 
|  | 226 |  | 
|  | 227 | // Create a symbol for the end of the prologue (to be set when we get there). | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 228 | MCSymbol *ProEndSym = context.CreateTempSymbol(); // Lprologue_end | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 229 |  | 
|  | 230 | // Length of the prologue, is the next 4 bytes.  Which is the start of the | 
|  | 231 | // section to the end of the prologue.  Not including the 4 bytes for the | 
|  | 232 | // total length, the 2 bytes for the version, and these 4 bytes for the | 
|  | 233 | // length of the prologue. | 
| Rafael Espindola | 5fad7a9 | 2010-12-09 23:08:35 +0000 | [diff] [blame] | 234 | MCOS->EmitAbsValue(MakeStartMinusEndExpr(*MCOS, *LineStartSym, *ProEndSym, | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 235 | (4 + 2 + 4)), | 
| Rafael Espindola | 5d4918d | 2010-12-04 03:21:47 +0000 | [diff] [blame] | 236 | 4, 0); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 237 |  | 
|  | 238 | // Parameters of the state machine, are next. | 
|  | 239 | MCOS->EmitIntValue(DWARF2_LINE_MIN_INSN_LENGTH, 1); | 
|  | 240 | MCOS->EmitIntValue(DWARF2_LINE_DEFAULT_IS_STMT, 1); | 
|  | 241 | MCOS->EmitIntValue(DWARF2_LINE_BASE, 1); | 
|  | 242 | MCOS->EmitIntValue(DWARF2_LINE_RANGE, 1); | 
|  | 243 | MCOS->EmitIntValue(DWARF2_LINE_OPCODE_BASE, 1); | 
|  | 244 |  | 
|  | 245 | // Standard opcode lengths | 
|  | 246 | MCOS->EmitIntValue(0, 1); // length of DW_LNS_copy | 
|  | 247 | MCOS->EmitIntValue(1, 1); // length of DW_LNS_advance_pc | 
|  | 248 | MCOS->EmitIntValue(1, 1); // length of DW_LNS_advance_line | 
|  | 249 | MCOS->EmitIntValue(1, 1); // length of DW_LNS_set_file | 
|  | 250 | MCOS->EmitIntValue(1, 1); // length of DW_LNS_set_column | 
|  | 251 | MCOS->EmitIntValue(0, 1); // length of DW_LNS_negate_stmt | 
|  | 252 | MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_basic_block | 
|  | 253 | MCOS->EmitIntValue(0, 1); // length of DW_LNS_const_add_pc | 
|  | 254 | MCOS->EmitIntValue(1, 1); // length of DW_LNS_fixed_advance_pc | 
|  | 255 | MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_prologue_end | 
|  | 256 | MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_epilogue_begin | 
|  | 257 | MCOS->EmitIntValue(1, 1); // DW_LNS_set_isa | 
|  | 258 |  | 
|  | 259 | // Put out the directory and file tables. | 
|  | 260 |  | 
|  | 261 | // First the directory table. | 
|  | 262 | const std::vector<StringRef> &MCDwarfDirs = | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 263 | context.getMCDwarfDirs(); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 264 | for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { | 
|  | 265 | MCOS->EmitBytes(MCDwarfDirs[i], 0); // the DirectoryName | 
|  | 266 | MCOS->EmitBytes(StringRef("\0", 1), 0); // the null term. of the string | 
|  | 267 | } | 
|  | 268 | MCOS->EmitIntValue(0, 1); // Terminate the directory list | 
|  | 269 |  | 
|  | 270 | // Second the file table. | 
|  | 271 | const std::vector<MCDwarfFile *> &MCDwarfFiles = | 
|  | 272 | MCOS->getContext().getMCDwarfFiles(); | 
|  | 273 | for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { | 
|  | 274 | MCOS->EmitBytes(MCDwarfFiles[i]->getName(), 0); // FileName | 
|  | 275 | MCOS->EmitBytes(StringRef("\0", 1), 0); // the null term. of the string | 
| Rafael Espindola | 3ff5709 | 2010-11-02 17:22:24 +0000 | [diff] [blame] | 276 | // the Directory num | 
|  | 277 | MCOS->EmitULEB128IntValue(MCDwarfFiles[i]->getDirIndex()); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 278 | MCOS->EmitIntValue(0, 1); // last modification timestamp (always 0) | 
|  | 279 | MCOS->EmitIntValue(0, 1); // filesize (always 0) | 
|  | 280 | } | 
|  | 281 | MCOS->EmitIntValue(0, 1); // Terminate the file list | 
|  | 282 |  | 
|  | 283 | // This is the end of the prologue, so set the value of the symbol at the | 
|  | 284 | // end of the prologue (that was used in a previous expression). | 
|  | 285 | MCOS->EmitLabel(ProEndSym); | 
|  | 286 |  | 
|  | 287 | // Put out the line tables. | 
| Rafael Espindola | 17fd7bd | 2010-11-19 07:41:23 +0000 | [diff] [blame] | 288 | const DenseMap<const MCSection *, MCLineSection *> &MCLineSections = | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 289 | MCOS->getContext().getMCLineSections(); | 
| Rafael Espindola | 17fd7bd | 2010-11-19 07:41:23 +0000 | [diff] [blame] | 290 | const std::vector<const MCSection *> &MCLineSectionOrder = | 
|  | 291 | MCOS->getContext().getMCLineSectionOrder(); | 
|  | 292 | for (std::vector<const MCSection*>::const_iterator it = | 
|  | 293 | MCLineSectionOrder.begin(), ie = MCLineSectionOrder.end(); it != ie; | 
|  | 294 | ++it) { | 
|  | 295 | const MCSection *Sec = *it; | 
|  | 296 | const MCLineSection *Line = MCLineSections.lookup(Sec); | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 297 | EmitDwarfLineTable(MCOS, Sec, Line); | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 298 |  | 
|  | 299 | // Now delete the MCLineSections that were created in MCLineEntry::Make() | 
|  | 300 | // and used to emit the line table. | 
| Rafael Espindola | 17fd7bd | 2010-11-19 07:41:23 +0000 | [diff] [blame] | 301 | delete Line; | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 302 | } | 
|  | 303 |  | 
| Rafael Espindola | 767b1be | 2010-12-04 00:31:13 +0000 | [diff] [blame] | 304 | if (MCOS->getContext().getAsmInfo().getLinkerRequiresNonEmptyDwarfLines() | 
|  | 305 | && MCLineSectionOrder.begin() == MCLineSectionOrder.end()) { | 
| Rafael Espindola | a8de83c | 2010-12-03 23:36:59 +0000 | [diff] [blame] | 306 | // The darwin9 linker has a bug (see PR8715). For for 32-bit architectures | 
|  | 307 | // it requires: | 
|  | 308 | // total_length >= prologue_length + 10 | 
|  | 309 | // We are 4 bytes short, since we have total_length = 51 and | 
|  | 310 | // prologue_length = 45 | 
| Devang Patel | 5113cdb | 2010-12-03 00:10:48 +0000 | [diff] [blame] | 311 |  | 
| Rafael Espindola | a8de83c | 2010-12-03 23:36:59 +0000 | [diff] [blame] | 312 | // The regular end_sequence should be sufficient. | 
|  | 313 | MCDwarfLineAddr::Emit(MCOS, INT64_MAX, 0); | 
| Devang Patel | 5113cdb | 2010-12-03 00:10:48 +0000 | [diff] [blame] | 314 | } | 
|  | 315 |  | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 316 | // This is the end of the section, so set the value of the symbol at the end | 
|  | 317 | // of this section (that was used in a previous expression). | 
|  | 318 | MCOS->EmitLabel(LineEndSym); | 
|  | 319 | } | 
|  | 320 |  | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 321 | /// Utility function to write the encoding to an object writer. | 
|  | 322 | void MCDwarfLineAddr::Write(MCObjectWriter *OW, int64_t LineDelta, | 
|  | 323 | uint64_t AddrDelta) { | 
|  | 324 | SmallString<256> Tmp; | 
|  | 325 | raw_svector_ostream OS(Tmp); | 
|  | 326 | MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OS); | 
|  | 327 | OW->WriteBytes(OS.str()); | 
|  | 328 | } | 
|  | 329 |  | 
|  | 330 | /// Utility function to emit the encoding to a streamer. | 
| Rafael Espindola | 195a0ce | 2010-11-19 02:26:16 +0000 | [diff] [blame] | 331 | void MCDwarfLineAddr::Emit(MCStreamer *MCOS, int64_t LineDelta, | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 332 | uint64_t AddrDelta) { | 
|  | 333 | SmallString<256> Tmp; | 
|  | 334 | raw_svector_ostream OS(Tmp); | 
|  | 335 | MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OS); | 
|  | 336 | MCOS->EmitBytes(OS.str(), /*AddrSpace=*/0); | 
|  | 337 | } | 
|  | 338 |  | 
|  | 339 | /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas. | 
|  | 340 | void MCDwarfLineAddr::Encode(int64_t LineDelta, uint64_t AddrDelta, | 
|  | 341 | raw_ostream &OS) { | 
|  | 342 | uint64_t Temp, Opcode; | 
|  | 343 | bool NeedCopy = false; | 
|  | 344 |  | 
|  | 345 | // Scale the address delta by the minimum instruction length. | 
|  | 346 | AddrDelta = ScaleAddrDelta(AddrDelta); | 
|  | 347 |  | 
|  | 348 | // A LineDelta of INT64_MAX is a signal that this is actually a | 
|  | 349 | // DW_LNE_end_sequence. We cannot use special opcodes here, since we want the | 
|  | 350 | // end_sequence to emit the matrix entry. | 
|  | 351 | if (LineDelta == INT64_MAX) { | 
|  | 352 | if (AddrDelta == MAX_SPECIAL_ADDR_DELTA) | 
|  | 353 | OS << char(dwarf::DW_LNS_const_add_pc); | 
|  | 354 | else { | 
|  | 355 | OS << char(dwarf::DW_LNS_advance_pc); | 
|  | 356 | SmallString<32> Tmp; | 
|  | 357 | raw_svector_ostream OSE(Tmp); | 
|  | 358 | MCObjectWriter::EncodeULEB128(AddrDelta, OSE); | 
|  | 359 | OS << OSE.str(); | 
|  | 360 | } | 
|  | 361 | OS << char(dwarf::DW_LNS_extended_op); | 
|  | 362 | OS << char(1); | 
|  | 363 | OS << char(dwarf::DW_LNE_end_sequence); | 
|  | 364 | return; | 
|  | 365 | } | 
|  | 366 |  | 
|  | 367 | // Bias the line delta by the base. | 
|  | 368 | Temp = LineDelta - DWARF2_LINE_BASE; | 
|  | 369 |  | 
|  | 370 | // If the line increment is out of range of a special opcode, we must encode | 
|  | 371 | // it with DW_LNS_advance_line. | 
|  | 372 | if (Temp >= DWARF2_LINE_RANGE) { | 
|  | 373 | OS << char(dwarf::DW_LNS_advance_line); | 
|  | 374 | SmallString<32> Tmp; | 
|  | 375 | raw_svector_ostream OSE(Tmp); | 
|  | 376 | MCObjectWriter::EncodeSLEB128(LineDelta, OSE); | 
|  | 377 | OS << OSE.str(); | 
|  | 378 |  | 
|  | 379 | LineDelta = 0; | 
|  | 380 | Temp = 0 - DWARF2_LINE_BASE; | 
|  | 381 | NeedCopy = true; | 
|  | 382 | } | 
|  | 383 |  | 
|  | 384 | // Use DW_LNS_copy instead of a "line +0, addr +0" special opcode. | 
|  | 385 | if (LineDelta == 0 && AddrDelta == 0) { | 
|  | 386 | OS << char(dwarf::DW_LNS_copy); | 
|  | 387 | return; | 
|  | 388 | } | 
|  | 389 |  | 
|  | 390 | // Bias the opcode by the special opcode base. | 
|  | 391 | Temp += DWARF2_LINE_OPCODE_BASE; | 
|  | 392 |  | 
|  | 393 | // Avoid overflow when addr_delta is large. | 
|  | 394 | if (AddrDelta < 256 + MAX_SPECIAL_ADDR_DELTA) { | 
|  | 395 | // Try using a special opcode. | 
|  | 396 | Opcode = Temp + AddrDelta * DWARF2_LINE_RANGE; | 
|  | 397 | if (Opcode <= 255) { | 
|  | 398 | OS << char(Opcode); | 
|  | 399 | return; | 
|  | 400 | } | 
|  | 401 |  | 
|  | 402 | // Try using DW_LNS_const_add_pc followed by special op. | 
|  | 403 | Opcode = Temp + (AddrDelta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE; | 
|  | 404 | if (Opcode <= 255) { | 
|  | 405 | OS << char(dwarf::DW_LNS_const_add_pc); | 
|  | 406 | OS << char(Opcode); | 
|  | 407 | return; | 
|  | 408 | } | 
|  | 409 | } | 
|  | 410 |  | 
|  | 411 | // Otherwise use DW_LNS_advance_pc. | 
|  | 412 | OS << char(dwarf::DW_LNS_advance_pc); | 
|  | 413 | SmallString<32> Tmp; | 
|  | 414 | raw_svector_ostream OSE(Tmp); | 
|  | 415 | MCObjectWriter::EncodeULEB128(AddrDelta, OSE); | 
|  | 416 | OS << OSE.str(); | 
|  | 417 |  | 
|  | 418 | if (NeedCopy) | 
|  | 419 | OS << char(dwarf::DW_LNS_copy); | 
|  | 420 | else | 
|  | 421 | OS << char(Temp); | 
|  | 422 | } | 
|  | 423 |  | 
| Kevin Enderby | 7cbf73a | 2010-07-28 20:55:35 +0000 | [diff] [blame] | 424 | void MCDwarfFile::print(raw_ostream &OS) const { | 
|  | 425 | OS << '"' << getName() << '"'; | 
|  | 426 | } | 
|  | 427 |  | 
|  | 428 | void MCDwarfFile::dump() const { | 
|  | 429 | print(dbgs()); | 
|  | 430 | } | 
| Kevin Enderby | c095793 | 2010-09-30 16:52:03 +0000 | [diff] [blame] | 431 |  | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 432 | static int getDataAlignmentFactor(MCStreamer &streamer) { | 
|  | 433 | MCContext &context = streamer.getContext(); | 
|  | 434 | const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); | 
|  | 435 | int size = asmInfo.getPointerSize(); | 
| Anton Korobeynikov | 16c29b5 | 2011-01-10 12:39:04 +0000 | [diff] [blame] | 436 | if (asmInfo.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp) | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 437 | return size; | 
|  | 438 | else | 
|  | 439 | return -size; | 
|  | 440 | } | 
|  | 441 |  | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 442 | static void EmitSymbol(MCStreamer &streamer, const MCSymbol &symbol, | 
|  | 443 | unsigned symbolEncoding) { | 
|  | 444 | MCContext &context = streamer.getContext(); | 
|  | 445 | const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); | 
|  | 446 | unsigned format = symbolEncoding & 0x0f; | 
| Rafael Espindola | caf1158 | 2010-12-29 04:31:26 +0000 | [diff] [blame] | 447 | unsigned application = symbolEncoding & 0x70; | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 448 | unsigned size; | 
|  | 449 | switch (format) { | 
|  | 450 | default: | 
|  | 451 | assert(0 && "Unknown Encoding"); | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 452 | case dwarf::DW_EH_PE_absptr: | 
|  | 453 | case dwarf::DW_EH_PE_signed: | 
|  | 454 | size = asmInfo.getPointerSize(); | 
|  | 455 | break; | 
|  | 456 | case dwarf::DW_EH_PE_udata2: | 
|  | 457 | case dwarf::DW_EH_PE_sdata2: | 
|  | 458 | size = 2; | 
|  | 459 | break; | 
|  | 460 | case dwarf::DW_EH_PE_udata4: | 
|  | 461 | case dwarf::DW_EH_PE_sdata4: | 
|  | 462 | size = 4; | 
|  | 463 | break; | 
|  | 464 | case dwarf::DW_EH_PE_udata8: | 
|  | 465 | case dwarf::DW_EH_PE_sdata8: | 
|  | 466 | size = 8; | 
|  | 467 | break; | 
|  | 468 | } | 
|  | 469 | switch (application) { | 
|  | 470 | default: | 
|  | 471 | assert(0 && "Unknown Encoding"); | 
|  | 472 | break; | 
|  | 473 | case 0: | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 474 | streamer.EmitSymbolValue(&symbol, size); | 
|  | 475 | break; | 
|  | 476 | case dwarf::DW_EH_PE_pcrel: | 
|  | 477 | streamer.EmitPCRelSymbolValue(&symbol, size); | 
|  | 478 | break; | 
|  | 479 | } | 
|  | 480 | } | 
|  | 481 |  | 
| Rafael Espindola | b40a71f | 2010-12-29 01:42:56 +0000 | [diff] [blame] | 482 | static const MachineLocation TranslateMachineLocation( | 
|  | 483 | const TargetAsmInfo &AsmInfo, | 
|  | 484 | const MachineLocation &Loc) { | 
|  | 485 | unsigned Reg = Loc.getReg() == MachineLocation::VirtualFP ? | 
|  | 486 | MachineLocation::VirtualFP : | 
|  | 487 | unsigned(AsmInfo.getDwarfRegNum(Loc.getReg(), true)); | 
|  | 488 | const MachineLocation &NewLoc = Loc.isReg() ? | 
|  | 489 | MachineLocation(Reg) : MachineLocation(Reg, Loc.getOffset()); | 
|  | 490 | return NewLoc; | 
|  | 491 | } | 
|  | 492 |  | 
| Rafael Espindola | 25f492e | 2011-04-12 16:12:03 +0000 | [diff] [blame^] | 493 | namespace { | 
|  | 494 | class FrameEmitterImpl { | 
|  | 495 | int CFAOffset; | 
|  | 496 |  | 
|  | 497 | public: | 
|  | 498 | FrameEmitterImpl() : CFAOffset(0) { | 
|  | 499 | } | 
|  | 500 |  | 
|  | 501 | const MCSymbol &EmitCIE(MCStreamer &streamer, | 
|  | 502 | const MCSymbol *personality, | 
|  | 503 | unsigned personalityEncoding, | 
|  | 504 | const MCSymbol *lsda, | 
|  | 505 | unsigned lsdaEncoding); | 
|  | 506 | MCSymbol *EmitFDE(MCStreamer &streamer, | 
|  | 507 | const MCSymbol &cieStart, | 
|  | 508 | const MCDwarfFrameInfo &frame); | 
|  | 509 | void EmitCFIInstructions(MCStreamer &streamer, | 
|  | 510 | const std::vector<MCCFIInstruction> &Instrs, | 
|  | 511 | MCSymbol *BaseLabel); | 
|  | 512 | void EmitCFIInstruction(MCStreamer &Streamer, | 
|  | 513 | const MCCFIInstruction &Instr); | 
|  | 514 | }; | 
|  | 515 | } | 
|  | 516 |  | 
|  | 517 | void FrameEmitterImpl::EmitCFIInstruction(MCStreamer &Streamer, | 
|  | 518 | const MCCFIInstruction &Instr) { | 
|  | 519 | int dataAlignmentFactor = getDataAlignmentFactor(Streamer); | 
|  | 520 |  | 
|  | 521 | switch (Instr.getOperation()) { | 
|  | 522 | case MCCFIInstruction::Move: | 
|  | 523 | case MCCFIInstruction::RelMove: { | 
|  | 524 | const MachineLocation &Dst = Instr.getDestination(); | 
|  | 525 | const MachineLocation &Src = Instr.getSource(); | 
|  | 526 |  | 
|  | 527 | // If advancing cfa. | 
|  | 528 | if (Dst.isReg() && Dst.getReg() == MachineLocation::VirtualFP) { | 
|  | 529 | assert(!Src.isReg() && "Machine move not supported yet."); | 
|  | 530 |  | 
|  | 531 | if (Src.getReg() == MachineLocation::VirtualFP) { | 
|  | 532 | Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_offset, 1); | 
|  | 533 | } else { | 
|  | 534 | Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1); | 
|  | 535 | Streamer.EmitULEB128IntValue(Src.getReg()); | 
|  | 536 | } | 
|  | 537 |  | 
|  | 538 | CFAOffset = -Src.getOffset(); | 
|  | 539 | Streamer.EmitULEB128IntValue(CFAOffset, 1); | 
|  | 540 | return; | 
|  | 541 | } | 
|  | 542 |  | 
|  | 543 | if (Src.isReg() && Src.getReg() == MachineLocation::VirtualFP) { | 
|  | 544 | assert(Dst.isReg() && "Machine move not supported yet."); | 
|  | 545 | Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1); | 
|  | 546 | Streamer.EmitULEB128IntValue(Dst.getReg()); | 
|  | 547 | return; | 
|  | 548 | } | 
|  | 549 |  | 
|  | 550 | unsigned Reg = Src.getReg(); | 
|  | 551 |  | 
|  | 552 | const bool IsRelative = Instr.getOperation() == MCCFIInstruction::RelMove; | 
|  | 553 | int Offset = Dst.getOffset(); | 
|  | 554 | if (IsRelative) | 
|  | 555 | Offset -= CFAOffset; | 
|  | 556 | Offset = Offset / dataAlignmentFactor; | 
|  | 557 |  | 
|  | 558 | if (Offset < 0) { | 
|  | 559 | Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended_sf, 1); | 
|  | 560 | Streamer.EmitULEB128IntValue(Reg); | 
|  | 561 | Streamer.EmitSLEB128IntValue(Offset); | 
|  | 562 | } else if (Reg < 64) { | 
|  | 563 | Streamer.EmitIntValue(dwarf::DW_CFA_offset + Reg, 1); | 
|  | 564 | Streamer.EmitULEB128IntValue(Offset, 1); | 
|  | 565 | } else { | 
|  | 566 | Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended, 1); | 
|  | 567 | Streamer.EmitULEB128IntValue(Reg, 1); | 
|  | 568 | Streamer.EmitULEB128IntValue(Offset, 1); | 
|  | 569 | } | 
|  | 570 | return; | 
|  | 571 | } | 
|  | 572 | case MCCFIInstruction::Remember: | 
|  | 573 | Streamer.EmitIntValue(dwarf::DW_CFA_remember_state, 1); | 
|  | 574 | return; | 
|  | 575 | case MCCFIInstruction::Restore: | 
|  | 576 | Streamer.EmitIntValue(dwarf::DW_CFA_restore_state, 1); | 
|  | 577 | return; | 
|  | 578 | case MCCFIInstruction::SameValue: { | 
|  | 579 | unsigned Reg = Instr.getDestination().getReg(); | 
|  | 580 | Streamer.EmitIntValue(dwarf::DW_CFA_same_value, 1); | 
|  | 581 | Streamer.EmitULEB128IntValue(Reg, 1); | 
|  | 582 | return; | 
|  | 583 | } | 
|  | 584 | } | 
|  | 585 | llvm_unreachable("Unhandled case in switch"); | 
|  | 586 | } | 
|  | 587 |  | 
|  | 588 | /// EmitFrameMoves - Emit frame instructions to describe the layout of the | 
|  | 589 | /// frame. | 
|  | 590 | void FrameEmitterImpl::EmitCFIInstructions(MCStreamer &streamer, | 
|  | 591 | const std::vector<MCCFIInstruction> &Instrs, | 
|  | 592 | MCSymbol *BaseLabel) { | 
|  | 593 | for (unsigned i = 0, N = Instrs.size(); i < N; ++i) { | 
|  | 594 | const MCCFIInstruction &Instr = Instrs[i]; | 
|  | 595 | MCSymbol *Label = Instr.getLabel(); | 
|  | 596 | // Throw out move if the label is invalid. | 
|  | 597 | if (Label && !Label->isDefined()) continue; // Not emitted, in dead code. | 
|  | 598 |  | 
|  | 599 | // Advance row if new location. | 
|  | 600 | if (BaseLabel && Label) { | 
|  | 601 | MCSymbol *ThisSym = Label; | 
|  | 602 | if (ThisSym != BaseLabel) { | 
|  | 603 | streamer.EmitDwarfAdvanceFrameAddr(BaseLabel, ThisSym); | 
|  | 604 | BaseLabel = ThisSym; | 
|  | 605 | } | 
|  | 606 | } | 
|  | 607 |  | 
|  | 608 | EmitCFIInstruction(streamer, Instr); | 
|  | 609 | } | 
|  | 610 | } | 
|  | 611 |  | 
|  | 612 | const MCSymbol &FrameEmitterImpl::EmitCIE(MCStreamer &streamer, | 
|  | 613 | const MCSymbol *personality, | 
|  | 614 | unsigned personalityEncoding, | 
|  | 615 | const MCSymbol *lsda, | 
|  | 616 | unsigned lsdaEncoding) { | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 617 | MCContext &context = streamer.getContext(); | 
|  | 618 | const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); | 
|  | 619 | const MCSection §ion = *asmInfo.getEHFrameSection(); | 
|  | 620 | streamer.SwitchSection(§ion); | 
|  | 621 | MCSymbol *sectionStart = streamer.getContext().CreateTempSymbol(); | 
|  | 622 | MCSymbol *sectionEnd = streamer.getContext().CreateTempSymbol(); | 
|  | 623 |  | 
|  | 624 | // Length | 
|  | 625 | const MCExpr *Length = MakeStartMinusEndExpr(streamer, *sectionStart, | 
|  | 626 | *sectionEnd, 4); | 
|  | 627 | streamer.EmitLabel(sectionStart); | 
|  | 628 | streamer.EmitValue(Length, 4); | 
|  | 629 |  | 
|  | 630 | // CIE ID | 
|  | 631 | streamer.EmitIntValue(0, 4); | 
|  | 632 |  | 
|  | 633 | // Version | 
|  | 634 | streamer.EmitIntValue(dwarf::DW_CIE_VERSION, 1); | 
|  | 635 |  | 
|  | 636 | // Augmentation String | 
|  | 637 | SmallString<8> Augmentation; | 
| Rafael Espindola | d7c8cca | 2010-12-26 20:20:31 +0000 | [diff] [blame] | 638 | Augmentation += "z"; | 
|  | 639 | if (personality) | 
|  | 640 | Augmentation += "P"; | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 641 | if (lsda) | 
|  | 642 | Augmentation += "L"; | 
| Rafael Espindola | d7c8cca | 2010-12-26 20:20:31 +0000 | [diff] [blame] | 643 | Augmentation += "R"; | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 644 | streamer.EmitBytes(Augmentation.str(), 0); | 
|  | 645 | streamer.EmitIntValue(0, 1); | 
|  | 646 |  | 
|  | 647 | // Code Alignment Factor | 
|  | 648 | streamer.EmitULEB128IntValue(1); | 
|  | 649 |  | 
|  | 650 | // Data Alignment Factor | 
|  | 651 | streamer.EmitSLEB128IntValue(getDataAlignmentFactor(streamer)); | 
|  | 652 |  | 
|  | 653 | // Return Address Register | 
|  | 654 | streamer.EmitULEB128IntValue(asmInfo.getDwarfRARegNum(true)); | 
|  | 655 |  | 
|  | 656 | // Augmentation Data Length (optional) | 
|  | 657 | MCSymbol *augmentationStart = streamer.getContext().CreateTempSymbol(); | 
|  | 658 | MCSymbol *augmentationEnd = streamer.getContext().CreateTempSymbol(); | 
|  | 659 | const MCExpr *augmentationLength = MakeStartMinusEndExpr(streamer, | 
|  | 660 | *augmentationStart, | 
|  | 661 | *augmentationEnd, 0); | 
|  | 662 | streamer.EmitULEB128Value(augmentationLength); | 
|  | 663 |  | 
|  | 664 | // Augmentation Data (optional) | 
|  | 665 | streamer.EmitLabel(augmentationStart); | 
| Rafael Espindola | d7c8cca | 2010-12-26 20:20:31 +0000 | [diff] [blame] | 666 | if (personality) { | 
|  | 667 | // Personality Encoding | 
| Rafael Espindola | 3a83c40 | 2010-12-27 00:36:05 +0000 | [diff] [blame] | 668 | streamer.EmitIntValue(personalityEncoding, 1); | 
| Rafael Espindola | d7c8cca | 2010-12-26 20:20:31 +0000 | [diff] [blame] | 669 | // Personality | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 670 | EmitSymbol(streamer, *personality, personalityEncoding); | 
|  | 671 | } | 
|  | 672 | if (lsda) { | 
|  | 673 | // LSDA Encoding | 
|  | 674 | streamer.EmitIntValue(lsdaEncoding, 1); | 
| Rafael Espindola | d7c8cca | 2010-12-26 20:20:31 +0000 | [diff] [blame] | 675 | } | 
|  | 676 | // Encoding of the FDE pointers | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 677 | streamer.EmitIntValue(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4, 1); | 
|  | 678 | streamer.EmitLabel(augmentationEnd); | 
|  | 679 |  | 
|  | 680 | // Initial Instructions | 
|  | 681 |  | 
|  | 682 | const std::vector<MachineMove> Moves = asmInfo.getInitialFrameState(); | 
| Rafael Espindola | fe024d0 | 2010-12-28 18:36:23 +0000 | [diff] [blame] | 683 | std::vector<MCCFIInstruction> Instructions; | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 684 |  | 
| Rafael Espindola | fe024d0 | 2010-12-28 18:36:23 +0000 | [diff] [blame] | 685 | for (int i = 0, n = Moves.size(); i != n; ++i) { | 
| Rafael Espindola | b40a71f | 2010-12-29 01:42:56 +0000 | [diff] [blame] | 686 | MCSymbol *Label = Moves[i].getLabel(); | 
|  | 687 | const MachineLocation &Dst = | 
|  | 688 | TranslateMachineLocation(asmInfo, Moves[i].getDestination()); | 
|  | 689 | const MachineLocation &Src = | 
|  | 690 | TranslateMachineLocation(asmInfo, Moves[i].getSource()); | 
|  | 691 | MCCFIInstruction Inst(Label, Dst, Src); | 
| Rafael Espindola | fe024d0 | 2010-12-28 18:36:23 +0000 | [diff] [blame] | 692 | Instructions.push_back(Inst); | 
|  | 693 | } | 
|  | 694 |  | 
| Rafael Espindola | b40a71f | 2010-12-29 01:42:56 +0000 | [diff] [blame] | 695 | EmitCFIInstructions(streamer, Instructions, NULL); | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 696 |  | 
|  | 697 | // Padding | 
| Rafael Espindola | d7c8cca | 2010-12-26 20:20:31 +0000 | [diff] [blame] | 698 | streamer.EmitValueToAlignment(4); | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 699 |  | 
|  | 700 | streamer.EmitLabel(sectionEnd); | 
|  | 701 | return *sectionStart; | 
|  | 702 | } | 
|  | 703 |  | 
| Rafael Espindola | 25f492e | 2011-04-12 16:12:03 +0000 | [diff] [blame^] | 704 | MCSymbol *FrameEmitterImpl::EmitFDE(MCStreamer &streamer, | 
|  | 705 | const MCSymbol &cieStart, | 
|  | 706 | const MCDwarfFrameInfo &frame) { | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 707 | MCContext &context = streamer.getContext(); | 
|  | 708 | MCSymbol *fdeStart = context.CreateTempSymbol(); | 
|  | 709 | MCSymbol *fdeEnd = context.CreateTempSymbol(); | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 710 |  | 
|  | 711 | // Length | 
|  | 712 | const MCExpr *Length = MakeStartMinusEndExpr(streamer, *fdeStart, *fdeEnd, 0); | 
|  | 713 | streamer.EmitValue(Length, 4); | 
|  | 714 |  | 
|  | 715 | streamer.EmitLabel(fdeStart); | 
|  | 716 | // CIE Pointer | 
|  | 717 | const MCExpr *offset = MakeStartMinusEndExpr(streamer, cieStart, *fdeStart, | 
|  | 718 | 0); | 
|  | 719 | streamer.EmitValue(offset, 4); | 
|  | 720 |  | 
|  | 721 | // PC Begin | 
|  | 722 | streamer.EmitPCRelSymbolValue(frame.Begin, 4); | 
|  | 723 |  | 
|  | 724 | // PC Range | 
|  | 725 | const MCExpr *Range = MakeStartMinusEndExpr(streamer, *frame.Begin, | 
|  | 726 | *frame.End, 0); | 
|  | 727 | streamer.EmitValue(Range, 4); | 
|  | 728 |  | 
|  | 729 | // Augmentation Data Length | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 730 | MCSymbol *augmentationStart = streamer.getContext().CreateTempSymbol(); | 
|  | 731 | MCSymbol *augmentationEnd = streamer.getContext().CreateTempSymbol(); | 
|  | 732 | const MCExpr *augmentationLength = MakeStartMinusEndExpr(streamer, | 
|  | 733 | *augmentationStart, | 
|  | 734 | *augmentationEnd, 0); | 
|  | 735 | streamer.EmitULEB128Value(augmentationLength); | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 736 |  | 
|  | 737 | // Augmentation Data | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 738 | streamer.EmitLabel(augmentationStart); | 
|  | 739 | if (frame.Lsda) | 
|  | 740 | EmitSymbol(streamer, *frame.Lsda, frame.LsdaEncoding); | 
|  | 741 | streamer.EmitLabel(augmentationEnd); | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 742 | // Call Frame Instructions | 
|  | 743 |  | 
| Rafael Espindola | b40a71f | 2010-12-29 01:42:56 +0000 | [diff] [blame] | 744 | EmitCFIInstructions(streamer, frame.Instructions, frame.Begin); | 
| Rafael Espindola | 5bba084 | 2010-12-28 04:15:37 +0000 | [diff] [blame] | 745 |  | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 746 | // Padding | 
| Rafael Espindola | dfe125c | 2010-12-17 00:28:02 +0000 | [diff] [blame] | 747 | streamer.EmitValueToAlignment(4); | 
|  | 748 |  | 
|  | 749 | return fdeEnd; | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 750 | } | 
|  | 751 |  | 
| Benjamin Kramer | 1928236 | 2010-12-30 22:34:44 +0000 | [diff] [blame] | 752 | namespace { | 
|  | 753 | struct CIEKey { | 
|  | 754 | static const CIEKey getEmptyKey() { return CIEKey(0, 0, -1); } | 
|  | 755 | static const CIEKey getTombstoneKey() { return CIEKey(0, -1, 0); } | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 756 |  | 
| Benjamin Kramer | 1928236 | 2010-12-30 22:34:44 +0000 | [diff] [blame] | 757 | CIEKey(const MCSymbol* Personality_, unsigned PersonalityEncoding_, | 
|  | 758 | unsigned LsdaEncoding_) : Personality(Personality_), | 
|  | 759 | PersonalityEncoding(PersonalityEncoding_), | 
|  | 760 | LsdaEncoding(LsdaEncoding_) { | 
|  | 761 | } | 
|  | 762 | const MCSymbol* Personality; | 
|  | 763 | unsigned PersonalityEncoding; | 
|  | 764 | unsigned LsdaEncoding; | 
|  | 765 | }; | 
|  | 766 | } | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 767 |  | 
|  | 768 | namespace llvm { | 
|  | 769 | template <> | 
|  | 770 | struct DenseMapInfo<CIEKey> { | 
|  | 771 | static CIEKey getEmptyKey() { | 
| Benjamin Kramer | 1928236 | 2010-12-30 22:34:44 +0000 | [diff] [blame] | 772 | return CIEKey::getEmptyKey(); | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 773 | } | 
|  | 774 | static CIEKey getTombstoneKey() { | 
| Benjamin Kramer | 1928236 | 2010-12-30 22:34:44 +0000 | [diff] [blame] | 775 | return CIEKey::getTombstoneKey(); | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 776 | } | 
|  | 777 | static unsigned getHashValue(const CIEKey &Key) { | 
|  | 778 | FoldingSetNodeID ID; | 
|  | 779 | ID.AddPointer(Key.Personality); | 
|  | 780 | ID.AddInteger(Key.PersonalityEncoding); | 
|  | 781 | ID.AddInteger(Key.LsdaEncoding); | 
|  | 782 | return ID.ComputeHash(); | 
|  | 783 | } | 
|  | 784 | static bool isEqual(const CIEKey &LHS, | 
|  | 785 | const CIEKey &RHS) { | 
|  | 786 | return LHS.Personality == RHS.Personality && | 
|  | 787 | LHS.PersonalityEncoding == RHS.PersonalityEncoding && | 
|  | 788 | LHS.LsdaEncoding == RHS.LsdaEncoding; | 
|  | 789 | } | 
|  | 790 | }; | 
|  | 791 | } | 
|  | 792 |  | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 793 | void MCDwarfFrameEmitter::Emit(MCStreamer &streamer) { | 
| Rafael Espindola | dfe125c | 2010-12-17 00:28:02 +0000 | [diff] [blame] | 794 | const MCContext &context = streamer.getContext(); | 
|  | 795 | const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); | 
| Rafael Espindola | dfe125c | 2010-12-17 00:28:02 +0000 | [diff] [blame] | 796 | MCSymbol *fdeEnd = NULL; | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 797 | DenseMap<CIEKey, const MCSymbol*> CIEStarts; | 
| Rafael Espindola | 25f492e | 2011-04-12 16:12:03 +0000 | [diff] [blame^] | 798 | FrameEmitterImpl Emitter; | 
| Rafael Espindola | d7c8cca | 2010-12-26 20:20:31 +0000 | [diff] [blame] | 799 |  | 
| Rafael Espindola | dfe125c | 2010-12-17 00:28:02 +0000 | [diff] [blame] | 800 | for (unsigned i = 0, n = streamer.getNumFrameInfos(); i < n; ++i) { | 
| Rafael Espindola | d7c8cca | 2010-12-26 20:20:31 +0000 | [diff] [blame] | 801 | const MCDwarfFrameInfo &frame = streamer.getFrameInfo(i); | 
| Rafael Espindola | bdc3167 | 2010-12-27 15:56:22 +0000 | [diff] [blame] | 802 | CIEKey key(frame.Personality, frame.PersonalityEncoding, | 
|  | 803 | frame.LsdaEncoding); | 
|  | 804 | const MCSymbol *&cieStart = CIEStarts[key]; | 
| Rafael Espindola | d7c8cca | 2010-12-26 20:20:31 +0000 | [diff] [blame] | 805 | if (!cieStart) | 
| Rafael Espindola | 25f492e | 2011-04-12 16:12:03 +0000 | [diff] [blame^] | 806 | cieStart = &Emitter.EmitCIE(streamer, frame.Personality, | 
|  | 807 | frame.PersonalityEncoding, frame.Lsda, | 
|  | 808 | frame.LsdaEncoding); | 
|  | 809 | fdeEnd = Emitter.EmitFDE(streamer, *cieStart, frame); | 
| Rafael Espindola | dfe125c | 2010-12-17 00:28:02 +0000 | [diff] [blame] | 810 | if (i != n - 1) | 
|  | 811 | streamer.EmitLabel(fdeEnd); | 
|  | 812 | } | 
| Rafael Espindola | d7c8cca | 2010-12-26 20:20:31 +0000 | [diff] [blame] | 813 |  | 
| Rafael Espindola | dfe125c | 2010-12-17 00:28:02 +0000 | [diff] [blame] | 814 | streamer.EmitValueToAlignment(asmInfo.getPointerSize()); | 
|  | 815 | if (fdeEnd) | 
|  | 816 | streamer.EmitLabel(fdeEnd); | 
| Rafael Espindola | 89b9372 | 2010-12-10 07:39:47 +0000 | [diff] [blame] | 817 | } | 
| Rafael Espindola | 245a1e2 | 2010-12-28 05:39:27 +0000 | [diff] [blame] | 818 |  | 
|  | 819 | void MCDwarfFrameEmitter::EmitAdvanceLoc(MCStreamer &Streamer, | 
|  | 820 | uint64_t AddrDelta) { | 
|  | 821 | SmallString<256> Tmp; | 
|  | 822 | raw_svector_ostream OS(Tmp); | 
|  | 823 | MCDwarfFrameEmitter::EncodeAdvanceLoc(AddrDelta, OS); | 
|  | 824 | Streamer.EmitBytes(OS.str(), /*AddrSpace=*/0); | 
|  | 825 | } | 
|  | 826 |  | 
|  | 827 | void MCDwarfFrameEmitter::EncodeAdvanceLoc(uint64_t AddrDelta, | 
|  | 828 | raw_ostream &OS) { | 
|  | 829 | // FIXME: Assumes the code alignment factor is 1. | 
| Rafael Espindola | 3b78cdc | 2010-12-28 23:38:03 +0000 | [diff] [blame] | 830 | if (AddrDelta == 0) { | 
|  | 831 | } else if (isUIntN(6, AddrDelta)) { | 
| Rafael Espindola | 245a1e2 | 2010-12-28 05:39:27 +0000 | [diff] [blame] | 832 | uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta; | 
|  | 833 | OS << Opcode; | 
|  | 834 | } else if (isUInt<8>(AddrDelta)) { | 
|  | 835 | OS << uint8_t(dwarf::DW_CFA_advance_loc1); | 
|  | 836 | OS << uint8_t(AddrDelta); | 
|  | 837 | } else if (isUInt<16>(AddrDelta)) { | 
| Rafael Espindola | a7e4505 | 2010-12-29 02:30:49 +0000 | [diff] [blame] | 838 | // FIXME: check what is the correct behavior on a big endian machine. | 
| Rafael Espindola | 245a1e2 | 2010-12-28 05:39:27 +0000 | [diff] [blame] | 839 | OS << uint8_t(dwarf::DW_CFA_advance_loc2); | 
| Rafael Espindola | a7e4505 | 2010-12-29 02:30:49 +0000 | [diff] [blame] | 840 | OS << uint8_t( AddrDelta       & 0xff); | 
|  | 841 | OS << uint8_t((AddrDelta >> 8) & 0xff); | 
| Rafael Espindola | 245a1e2 | 2010-12-28 05:39:27 +0000 | [diff] [blame] | 842 | } else { | 
| Rafael Espindola | a7e4505 | 2010-12-29 02:30:49 +0000 | [diff] [blame] | 843 | // FIXME: check what is the correct behavior on a big endian machine. | 
| Rafael Espindola | 245a1e2 | 2010-12-28 05:39:27 +0000 | [diff] [blame] | 844 | assert(isUInt<32>(AddrDelta)); | 
|  | 845 | OS << uint8_t(dwarf::DW_CFA_advance_loc4); | 
| Rafael Espindola | a7e4505 | 2010-12-29 02:30:49 +0000 | [diff] [blame] | 846 | OS << uint8_t( AddrDelta        & 0xff); | 
|  | 847 | OS << uint8_t((AddrDelta >> 8)  & 0xff); | 
|  | 848 | OS << uint8_t((AddrDelta >> 16) & 0xff); | 
|  | 849 | OS << uint8_t((AddrDelta >> 24) & 0xff); | 
|  | 850 |  | 
| Rafael Espindola | 245a1e2 | 2010-12-28 05:39:27 +0000 | [diff] [blame] | 851 | } | 
|  | 852 | } |