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