aboutsummaryrefslogtreecommitdiffstats
path: root/lib/DebugInfo/DWARFDebugFrame.cpp
blob: 0b78cce1dd3b0ea22a582c85289cd51ae4a5a6b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "DWARFDebugFrame.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Format.h"

using namespace llvm;
using namespace dwarf;


class llvm::FrameEntry {
public:
  enum FrameKind {FK_CIE, FK_FDE};
  FrameEntry(FrameKind K, DataExtractor D, uint64_t Offset, uint64_t Length)
    : Kind(K), Data(D), Offset(Offset), Length(Length)
  {}

  FrameKind getKind() const { return Kind; }

  virtual void dumpHeader(raw_ostream &OS) const = 0;
protected:
  const FrameKind Kind;
  DataExtractor Data;
  uint64_t Offset;
  uint64_t Length;
};


class CIE : public FrameEntry {
public:
  // CIEs (and FDEs) are simply container classes, so the only sensible way to
  // create them is by providing the full parsed contents in the constructor.
  CIE(DataExtractor D, uint64_t Offset, uint64_t Length, uint8_t Version,
      SmallString<8> Augmentation, uint64_t CodeAlignmentFactor,
      int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister)
   : FrameEntry(FK_CIE, D, Offset, Length), Version(Version),
     Augmentation(Augmentation), CodeAlignmentFactor(CodeAlignmentFactor),
     DataAlignmentFactor(DataAlignmentFactor),
     ReturnAddressRegister(ReturnAddressRegister)
  {}

  void dumpHeader(raw_ostream &OS) const {
    OS << format("%08x %08x %08x CIE", Offset, Length, DW_CIE_ID) << "\n";
    OS << format("  Version:               %d\n", Version);
    OS << "  Augmentation:          \"" << Augmentation << "\"\n";
    OS << format("  Code alignment factor: %u\n", CodeAlignmentFactor);
    OS << format("  Data alignment factor: %d\n", DataAlignmentFactor);
    OS << format("  Return address column: %d\n", ReturnAddressRegister);
    OS << "\n";
  }

  static bool classof(const FrameEntry *FE) {
    return FE->getKind() == FK_CIE;
  } 
private:
  uint8_t Version;
  SmallString<8> Augmentation;
  uint64_t CodeAlignmentFactor;
  int64_t DataAlignmentFactor;
  uint64_t ReturnAddressRegister;
};


class FDE : public FrameEntry {
public:
  // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with
  // an offset to the CIE (provided by parsing the FDE header). The CIE itself
  // is obtained lazily once it's actually required.
  FDE(DataExtractor D, uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset,
      uint64_t InitialLocation, uint64_t AddressRange)
   : FrameEntry(FK_FDE, D, Offset, Length), LinkedCIEOffset(LinkedCIEOffset),
     InitialLocation(InitialLocation), AddressRange(AddressRange),
     LinkedCIE(NULL)
  {}

  void dumpHeader(raw_ostream &OS) const {
    OS << format("%08x %08x %08x FDE ", Offset, Length, LinkedCIEOffset);
    OS << format("cie=%08x pc=%08x...%08x\n",
                 LinkedCIEOffset, InitialLocation,
                 InitialLocation + AddressRange);
    OS << "\n";
  }

  static bool classof(const FrameEntry *FE) {
    return FE->getKind() == FK_FDE;
  } 
private:
  uint64_t LinkedCIEOffset;
  uint64_t InitialLocation;
  uint64_t AddressRange;
  CIE *LinkedCIE;
};


DWARFDebugFrame::DWARFDebugFrame()
{
}


DWARFDebugFrame::~DWARFDebugFrame()
{
  for (EntryVector::iterator I = Entries.begin(), E = Entries.end();
       I != E; ++I) {
    delete *I;
  }
}


static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
                                              uint32_t Offset, int Length) {
  errs() << "DUMP: ";
  for (int i = 0; i < Length; ++i) {
    uint8_t c = Data.getU8(&Offset);
    errs().write_hex(c); errs() << " ";
  }
  errs() << "\n";
}


void DWARFDebugFrame::parse(DataExtractor Data) {
  uint32_t Offset = 0;

  while (Data.isValidOffset(Offset)) {
    uint32_t StartOffset = Offset;

    bool IsDWARF64 = false;
    uint64_t Length = Data.getU32(&Offset);
    uint64_t Id;

    if (Length == UINT32_MAX) {
      // DWARF-64 is distinguished by the first 32 bits of the initial length
      // field being 0xffffffff. Then, the next 64 bits are the actual entry
      // length.
      IsDWARF64 = true;
      Length = Data.getU64(&Offset);
    }

    // At this point, Offset points to the next field after Length.
    // Length is the structure size excluding itself. Compute an offset one
    // past the end of the structure (needed to know how many instructions to
    // read).
    // TODO: For honest DWARF64 support, DataExtractor will have to treat
    //       offset_ptr as uint64_t*
    uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length);

    // The Id field's size depends on the DWARF format
    Id = Data.getUnsigned(&Offset, IsDWARF64 ? 8 : 4);
    bool IsCIE = ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID);

    if (IsCIE) {
      // Note: this is specifically DWARFv3 CIE header structure. It was
      // changed in DWARFv4.
      uint8_t Version = Data.getU8(&Offset);
      const char *Augmentation = Data.getCStr(&Offset);
      uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
      int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
      uint64_t ReturnAddressRegister = Data.getULEB128(&Offset);

      CIE *NewCIE = new CIE(Data, StartOffset, Length, Version,
                            StringRef(Augmentation), CodeAlignmentFactor,
                            DataAlignmentFactor, ReturnAddressRegister);
      Entries.push_back(NewCIE);
    } else {
      // FDE
      uint64_t CIEPointer = Id;
      uint64_t InitialLocation = Data.getAddress(&Offset);
      uint64_t AddressRange = Data.getAddress(&Offset);

      FDE *NewFDE = new FDE(Data, StartOffset, Length, CIEPointer,
                            InitialLocation, AddressRange);
      Entries.push_back(NewFDE);
    }

    Offset = EndStructureOffset;
  }
}


void DWARFDebugFrame::dump(raw_ostream &OS) const {
  OS << "\n";
  for (EntryVector::const_iterator I = Entries.begin(), E = Entries.end();
       I != E; ++I) {
    (*I)->dumpHeader(OS);
  }
}