| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 1 | //===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===// | 
|  | 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 |  | 
|  | 10 | #include "DWARFDebugFrame.h" | 
|  | 11 | #include "llvm/ADT/SmallString.h" | 
|  | 12 | #include "llvm/Support/DataTypes.h" | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 13 | #include "llvm/Support/ErrorHandling.h" | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 14 | #include "llvm/Support/Dwarf.h" | 
|  | 15 | #include "llvm/Support/Format.h" | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 16 | #include "llvm/Support/raw_ostream.h" | 
|  | 17 | #include <string> | 
|  | 18 | #include <vector> | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 19 |  | 
|  | 20 | using namespace llvm; | 
|  | 21 | using namespace dwarf; | 
|  | 22 |  | 
|  | 23 |  | 
| Eli Bendersky | 5823206 | 2013-02-06 16:20:31 +0000 | [diff] [blame] | 24 | /// \brief Abstract frame entry defining the common interface concrete | 
|  | 25 | /// entries implement. | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 26 | class llvm::FrameEntry { | 
|  | 27 | public: | 
|  | 28 | enum FrameKind {FK_CIE, FK_FDE}; | 
|  | 29 | FrameEntry(FrameKind K, DataExtractor D, uint64_t Offset, uint64_t Length) | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 30 | : Kind(K), Data(D), Offset(Offset), Length(Length) {} | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 31 |  | 
| Eli Bendersky | 0b04cb0 | 2013-02-06 03:08:02 +0000 | [diff] [blame] | 32 | virtual ~FrameEntry() { | 
|  | 33 | } | 
|  | 34 |  | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 35 | FrameKind getKind() const { return Kind; } | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 36 | virtual uint64_t getOffset() const { return Offset; } | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 37 |  | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 38 | /// \brief Parse and store a sequence of CFI instructions from our data | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 39 | /// stream, starting at *Offset and ending at EndOffset. If everything | 
|  | 40 | /// goes well, *Offset should be equal to EndOffset when this method | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 41 | /// returns. Otherwise, an error occurred. | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 42 | virtual void parseInstructions(uint32_t *Offset, uint32_t EndOffset); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 43 |  | 
|  | 44 | /// \brief Dump the entry header to the given output stream. | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 45 | virtual void dumpHeader(raw_ostream &OS) const = 0; | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 46 |  | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 47 | /// \brief Dump the entry's instructions to the given output stream. | 
|  | 48 | virtual void dumpInstructions(raw_ostream &OS) const; | 
|  | 49 |  | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 50 | protected: | 
|  | 51 | const FrameKind Kind; | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 52 |  | 
|  | 53 | /// \brief The data stream holding the section from which the entry was | 
|  | 54 | /// parsed. | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 55 | DataExtractor Data; | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 56 |  | 
|  | 57 | /// \brief Offset of this entry in the section. | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 58 | uint64_t Offset; | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 59 |  | 
|  | 60 | /// \brief Entry length as specified in DWARF. | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 61 | uint64_t Length; | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 62 |  | 
|  | 63 | /// An entry may contain CFI instructions. An instruction consists of an | 
|  | 64 | /// opcode and an optional sequence of operands. | 
|  | 65 | typedef std::vector<uint64_t> Operands; | 
|  | 66 | struct Instruction { | 
|  | 67 | Instruction(uint8_t Opcode) | 
|  | 68 | : Opcode(Opcode) | 
|  | 69 | {} | 
|  | 70 |  | 
|  | 71 | uint8_t Opcode; | 
|  | 72 | Operands Ops; | 
|  | 73 | }; | 
|  | 74 |  | 
|  | 75 | std::vector<Instruction> Instructions; | 
|  | 76 |  | 
|  | 77 | /// Convenience methods to add a new instruction with the given opcode and | 
|  | 78 | /// operands to the Instructions vector. | 
|  | 79 | void addInstruction(uint8_t Opcode) { | 
|  | 80 | Instructions.push_back(Instruction(Opcode)); | 
|  | 81 | } | 
|  | 82 |  | 
|  | 83 | void addInstruction(uint8_t Opcode, uint64_t Operand1) { | 
|  | 84 | Instructions.push_back(Instruction(Opcode)); | 
|  | 85 | Instructions.back().Ops.push_back(Operand1); | 
|  | 86 | } | 
|  | 87 |  | 
|  | 88 | void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) { | 
|  | 89 | Instructions.push_back(Instruction(Opcode)); | 
|  | 90 | Instructions.back().Ops.push_back(Operand1); | 
|  | 91 | Instructions.back().Ops.push_back(Operand2); | 
|  | 92 | } | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 93 | }; | 
|  | 94 |  | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 95 |  | 
|  | 96 | // See DWARF standard v3, section 7.23 | 
|  | 97 | const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0; | 
|  | 98 | const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f; | 
|  | 99 |  | 
|  | 100 |  | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 101 | void FrameEntry::parseInstructions(uint32_t *Offset, uint32_t EndOffset) { | 
|  | 102 | while (*Offset < EndOffset) { | 
|  | 103 | uint8_t Opcode = Data.getU8(Offset); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 104 | // Some instructions have a primary opcode encoded in the top bits. | 
|  | 105 | uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK; | 
|  | 106 |  | 
|  | 107 | if (Primary) { | 
|  | 108 | // If it's a primary opcode, the first operand is encoded in the bottom | 
|  | 109 | // bits of the opcode itself. | 
|  | 110 | uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK; | 
|  | 111 | switch (Primary) { | 
|  | 112 | default: llvm_unreachable("Impossible primary CFI opcode"); | 
|  | 113 | case DW_CFA_advance_loc: | 
|  | 114 | case DW_CFA_restore: | 
|  | 115 | addInstruction(Primary, Op1); | 
|  | 116 | break; | 
|  | 117 | case DW_CFA_offset: | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 118 | addInstruction(Primary, Op1, Data.getULEB128(Offset)); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 119 | break; | 
|  | 120 | } | 
|  | 121 | } else { | 
|  | 122 | // Extended opcode - its value is Opcode itself. | 
|  | 123 | switch (Opcode) { | 
|  | 124 | default: llvm_unreachable("Invalid extended CFI opcode"); | 
|  | 125 | case DW_CFA_nop: | 
|  | 126 | case DW_CFA_remember_state: | 
|  | 127 | case DW_CFA_restore_state: | 
|  | 128 | // No operands | 
|  | 129 | addInstruction(Opcode); | 
|  | 130 | break; | 
|  | 131 | case DW_CFA_set_loc: | 
|  | 132 | // Operands: Address | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 133 | addInstruction(Opcode, Data.getAddress(Offset)); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 134 | break; | 
|  | 135 | case DW_CFA_advance_loc1: | 
|  | 136 | // Operands: 1-byte delta | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 137 | addInstruction(Opcode, Data.getU8(Offset)); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 138 | break; | 
|  | 139 | case DW_CFA_advance_loc2: | 
|  | 140 | // Operands: 2-byte delta | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 141 | addInstruction(Opcode, Data.getU16(Offset)); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 142 | break; | 
|  | 143 | case DW_CFA_advance_loc4: | 
|  | 144 | // Operands: 4-byte delta | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 145 | addInstruction(Opcode, Data.getU32(Offset)); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 146 | break; | 
|  | 147 | case DW_CFA_restore_extended: | 
|  | 148 | case DW_CFA_undefined: | 
|  | 149 | case DW_CFA_same_value: | 
|  | 150 | case DW_CFA_def_cfa_register: | 
|  | 151 | case DW_CFA_def_cfa_offset: | 
|  | 152 | // Operands: ULEB128 | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 153 | addInstruction(Opcode, Data.getULEB128(Offset)); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 154 | break; | 
|  | 155 | case DW_CFA_def_cfa_offset_sf: | 
|  | 156 | // Operands: SLEB128 | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 157 | addInstruction(Opcode, Data.getSLEB128(Offset)); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 158 | break; | 
|  | 159 | case DW_CFA_offset_extended: | 
|  | 160 | case DW_CFA_register: | 
|  | 161 | case DW_CFA_def_cfa: | 
|  | 162 | case DW_CFA_val_offset: | 
|  | 163 | // Operands: ULEB128, ULEB128 | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 164 | addInstruction(Opcode, Data.getULEB128(Offset), | 
|  | 165 | Data.getULEB128(Offset)); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 166 | break; | 
|  | 167 | case DW_CFA_offset_extended_sf: | 
|  | 168 | case DW_CFA_def_cfa_sf: | 
|  | 169 | case DW_CFA_val_offset_sf: | 
|  | 170 | // Operands: ULEB128, SLEB128 | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 171 | addInstruction(Opcode, Data.getULEB128(Offset), | 
|  | 172 | Data.getSLEB128(Offset)); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 173 | break; | 
|  | 174 | case DW_CFA_def_cfa_expression: | 
|  | 175 | case DW_CFA_expression: | 
|  | 176 | case DW_CFA_val_expression: | 
|  | 177 | // TODO: implement this | 
|  | 178 | report_fatal_error("Values with expressions not implemented yet!"); | 
|  | 179 | } | 
|  | 180 | } | 
|  | 181 | } | 
|  | 182 | } | 
|  | 183 |  | 
|  | 184 |  | 
|  | 185 | void FrameEntry::dumpInstructions(raw_ostream &OS) const { | 
|  | 186 | // TODO: at the moment only instruction names are dumped. Expand this to | 
|  | 187 | // dump operands as well. | 
|  | 188 | for (std::vector<Instruction>::const_iterator I = Instructions.begin(), | 
|  | 189 | E = Instructions.end(); | 
|  | 190 | I != E; ++I) { | 
|  | 191 | uint8_t Opcode = I->Opcode; | 
|  | 192 | if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) | 
|  | 193 | Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK; | 
|  | 194 | OS << "  " << CallFrameString(Opcode) << ":\n"; | 
|  | 195 | } | 
|  | 196 | } | 
|  | 197 |  | 
|  | 198 |  | 
| Benjamin Kramer | 6ecb1e7 | 2013-02-15 12:30:38 +0000 | [diff] [blame] | 199 | namespace { | 
| Eli Bendersky | 5823206 | 2013-02-06 16:20:31 +0000 | [diff] [blame] | 200 | /// \brief DWARF Common Information Entry (CIE) | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 201 | class CIE : public FrameEntry { | 
|  | 202 | public: | 
|  | 203 | // CIEs (and FDEs) are simply container classes, so the only sensible way to | 
|  | 204 | // create them is by providing the full parsed contents in the constructor. | 
|  | 205 | CIE(DataExtractor D, uint64_t Offset, uint64_t Length, uint8_t Version, | 
|  | 206 | SmallString<8> Augmentation, uint64_t CodeAlignmentFactor, | 
|  | 207 | int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister) | 
|  | 208 | : FrameEntry(FK_CIE, D, Offset, Length), Version(Version), | 
|  | 209 | Augmentation(Augmentation), CodeAlignmentFactor(CodeAlignmentFactor), | 
|  | 210 | DataAlignmentFactor(DataAlignmentFactor), | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 211 | ReturnAddressRegister(ReturnAddressRegister) {} | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 212 |  | 
| Eli Bendersky | 0b04cb0 | 2013-02-06 03:08:02 +0000 | [diff] [blame] | 213 | ~CIE() { | 
|  | 214 | } | 
|  | 215 |  | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 216 | void dumpHeader(raw_ostream &OS) const { | 
| NAKAMURA Takumi | 56ac51a | 2013-02-07 02:02:27 +0000 | [diff] [blame] | 217 | OS << format("%08x %08x %08x CIE", | 
|  | 218 | (uint32_t)Offset, (uint32_t)Length, DW_CIE_ID) | 
|  | 219 | << "\n"; | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 220 | OS << format("  Version:               %d\n", Version); | 
|  | 221 | OS << "  Augmentation:          \"" << Augmentation << "\"\n"; | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 222 | OS << format("  Code alignment factor: %u\n", | 
|  | 223 | (uint32_t)CodeAlignmentFactor); | 
|  | 224 | OS << format("  Data alignment factor: %d\n", | 
|  | 225 | (int32_t)DataAlignmentFactor); | 
|  | 226 | OS << format("  Return address column: %d\n", | 
|  | 227 | (int32_t)ReturnAddressRegister); | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 228 | OS << "\n"; | 
|  | 229 | } | 
|  | 230 |  | 
|  | 231 | static bool classof(const FrameEntry *FE) { | 
|  | 232 | return FE->getKind() == FK_CIE; | 
|  | 233 | } | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 234 |  | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 235 | private: | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 236 | /// The following fields are defined in section 6.4.1 of the DWARF standard v3 | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 237 | uint8_t Version; | 
|  | 238 | SmallString<8> Augmentation; | 
|  | 239 | uint64_t CodeAlignmentFactor; | 
|  | 240 | int64_t DataAlignmentFactor; | 
|  | 241 | uint64_t ReturnAddressRegister; | 
|  | 242 | }; | 
|  | 243 |  | 
|  | 244 |  | 
| Eli Bendersky | 5823206 | 2013-02-06 16:20:31 +0000 | [diff] [blame] | 245 | /// \brief DWARF Frame Description Entry (FDE) | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 246 | class FDE : public FrameEntry { | 
|  | 247 | public: | 
|  | 248 | // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with | 
|  | 249 | // an offset to the CIE (provided by parsing the FDE header). The CIE itself | 
|  | 250 | // is obtained lazily once it's actually required. | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 251 | FDE(DataExtractor D, uint64_t Offset, uint64_t Length, | 
|  | 252 | int64_t LinkedCIEOffset, uint64_t InitialLocation, uint64_t AddressRange) | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 253 | : FrameEntry(FK_FDE, D, Offset, Length), LinkedCIEOffset(LinkedCIEOffset), | 
|  | 254 | InitialLocation(InitialLocation), AddressRange(AddressRange), | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 255 | LinkedCIE(NULL) {} | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 256 |  | 
| Eli Bendersky | 0b04cb0 | 2013-02-06 03:08:02 +0000 | [diff] [blame] | 257 | ~FDE() { | 
|  | 258 | } | 
|  | 259 |  | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 260 | void dumpHeader(raw_ostream &OS) const { | 
| NAKAMURA Takumi | 56ac51a | 2013-02-07 02:02:27 +0000 | [diff] [blame] | 261 | OS << format("%08x %08x %08x FDE ", | 
| NAKAMURA Takumi | 14727d7 | 2013-02-07 14:54:42 +0000 | [diff] [blame] | 262 | (uint32_t)Offset, (uint32_t)Length, (int32_t)LinkedCIEOffset); | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 263 | OS << format("cie=%08x pc=%08x...%08x\n", | 
| NAKAMURA Takumi | 14727d7 | 2013-02-07 14:54:42 +0000 | [diff] [blame] | 264 | (int32_t)LinkedCIEOffset, | 
| NAKAMURA Takumi | 94651f9 | 2013-02-07 10:57:42 +0000 | [diff] [blame] | 265 | (uint32_t)InitialLocation, | 
|  | 266 | (uint32_t)InitialLocation + (uint32_t)AddressRange); | 
| Eli Bendersky | 4e6d811 | 2013-02-06 05:37:46 +0000 | [diff] [blame] | 267 | if (LinkedCIE) { | 
|  | 268 | OS << format("%p\n", LinkedCIE); | 
|  | 269 | } | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 270 | } | 
|  | 271 |  | 
|  | 272 | static bool classof(const FrameEntry *FE) { | 
|  | 273 | return FE->getKind() == FK_FDE; | 
|  | 274 | } | 
|  | 275 | private: | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 276 |  | 
|  | 277 | /// The following fields are defined in section 6.4.1 of the DWARF standard v3 | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 278 | uint64_t LinkedCIEOffset; | 
|  | 279 | uint64_t InitialLocation; | 
|  | 280 | uint64_t AddressRange; | 
|  | 281 | CIE *LinkedCIE; | 
|  | 282 | }; | 
| Benjamin Kramer | 6ecb1e7 | 2013-02-15 12:30:38 +0000 | [diff] [blame] | 283 | } // end anonymous namespace | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 284 |  | 
|  | 285 |  | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 286 | DWARFDebugFrame::DWARFDebugFrame() { | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 287 | } | 
|  | 288 |  | 
|  | 289 |  | 
| Eli Bendersky | 1aa265d | 2013-02-06 00:20:38 +0000 | [diff] [blame] | 290 | DWARFDebugFrame::~DWARFDebugFrame() { | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 291 | for (EntryVector::iterator I = Entries.begin(), E = Entries.end(); | 
|  | 292 | I != E; ++I) { | 
|  | 293 | delete *I; | 
|  | 294 | } | 
|  | 295 | } | 
|  | 296 |  | 
|  | 297 |  | 
|  | 298 | static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data, | 
|  | 299 | uint32_t Offset, int Length) { | 
|  | 300 | errs() << "DUMP: "; | 
|  | 301 | for (int i = 0; i < Length; ++i) { | 
|  | 302 | uint8_t c = Data.getU8(&Offset); | 
|  | 303 | errs().write_hex(c); errs() << " "; | 
|  | 304 | } | 
|  | 305 | errs() << "\n"; | 
|  | 306 | } | 
|  | 307 |  | 
|  | 308 |  | 
|  | 309 | void DWARFDebugFrame::parse(DataExtractor Data) { | 
|  | 310 | uint32_t Offset = 0; | 
|  | 311 |  | 
|  | 312 | while (Data.isValidOffset(Offset)) { | 
|  | 313 | uint32_t StartOffset = Offset; | 
|  | 314 |  | 
|  | 315 | bool IsDWARF64 = false; | 
|  | 316 | uint64_t Length = Data.getU32(&Offset); | 
|  | 317 | uint64_t Id; | 
|  | 318 |  | 
|  | 319 | if (Length == UINT32_MAX) { | 
|  | 320 | // DWARF-64 is distinguished by the first 32 bits of the initial length | 
|  | 321 | // field being 0xffffffff. Then, the next 64 bits are the actual entry | 
|  | 322 | // length. | 
|  | 323 | IsDWARF64 = true; | 
|  | 324 | Length = Data.getU64(&Offset); | 
|  | 325 | } | 
|  | 326 |  | 
|  | 327 | // At this point, Offset points to the next field after Length. | 
|  | 328 | // Length is the structure size excluding itself. Compute an offset one | 
|  | 329 | // past the end of the structure (needed to know how many instructions to | 
|  | 330 | // read). | 
|  | 331 | // TODO: For honest DWARF64 support, DataExtractor will have to treat | 
|  | 332 | //       offset_ptr as uint64_t* | 
|  | 333 | uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length); | 
|  | 334 |  | 
|  | 335 | // The Id field's size depends on the DWARF format | 
|  | 336 | Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4); | 
|  | 337 | bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID); | 
|  | 338 |  | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 339 | FrameEntry *Entry = 0; | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 340 | if (IsCIE) { | 
|  | 341 | // Note: this is specifically DWARFv3 CIE header structure. It was | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 342 | // changed in DWARFv4. We currently don't support reading DWARFv4 | 
|  | 343 | // here because LLVM itself does not emit it (and LLDB doesn't | 
|  | 344 | // support it either). | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 345 | uint8_t Version = Data.getU8(&Offset); | 
|  | 346 | const char *Augmentation = Data.getCStr(&Offset); | 
|  | 347 | uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset); | 
|  | 348 | int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); | 
|  | 349 | uint64_t ReturnAddressRegister = Data.getULEB128(&Offset); | 
|  | 350 |  | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 351 | Entry = new CIE(Data, StartOffset, Length, Version, | 
|  | 352 | StringRef(Augmentation), CodeAlignmentFactor, | 
|  | 353 | DataAlignmentFactor, ReturnAddressRegister); | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 354 | } else { | 
|  | 355 | // FDE | 
|  | 356 | uint64_t CIEPointer = Id; | 
|  | 357 | uint64_t InitialLocation = Data.getAddress(&Offset); | 
|  | 358 | uint64_t AddressRange = Data.getAddress(&Offset); | 
|  | 359 |  | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 360 | Entry = new FDE(Data, StartOffset, Length, CIEPointer, | 
|  | 361 | InitialLocation, AddressRange); | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 362 | } | 
|  | 363 |  | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 364 | assert(Entry && "Expected Entry to be populated with CIE or FDE"); | 
|  | 365 | Entry->parseInstructions(&Offset, EndStructureOffset); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 366 |  | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 367 | if (Offset == EndStructureOffset) { | 
|  | 368 | // Entry instrucitons parsed successfully. | 
|  | 369 | Entries.push_back(Entry); | 
|  | 370 | } else { | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 371 | std::string Str; | 
|  | 372 | raw_string_ostream OS(Str); | 
|  | 373 | OS << format("Parsing entry instructions at %lx failed", | 
| Eli Bendersky | 8e352e3 | 2013-02-22 00:50:48 +0000 | [diff] [blame] | 374 | Entry->getOffset()); | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 375 | report_fatal_error(Str); | 
|  | 376 | } | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 377 | } | 
|  | 378 | } | 
|  | 379 |  | 
|  | 380 |  | 
|  | 381 | void DWARFDebugFrame::dump(raw_ostream &OS) const { | 
|  | 382 | OS << "\n"; | 
|  | 383 | for (EntryVector::const_iterator I = Entries.begin(), E = Entries.end(); | 
|  | 384 | I != E; ++I) { | 
| Eli Bendersky | 705085d | 2013-02-21 22:53:19 +0000 | [diff] [blame] | 385 | FrameEntry *Entry = *I; | 
|  | 386 | Entry->dumpHeader(OS); | 
|  | 387 | Entry->dumpInstructions(OS); | 
|  | 388 | OS << "\n"; | 
| Eli Bendersky | fd08bc1 | 2013-02-05 23:30:58 +0000 | [diff] [blame] | 389 | } | 
|  | 390 | } | 
|  | 391 |  |