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