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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===- DWARFDebugFrame.h - Parsing of .debug_frame --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Triple.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/Support/Error.h"
#include <memory>
#include <vector>
namespace llvm {
class raw_ostream;
namespace dwarf {
/// Represent a sequence of Call Frame Information instructions that, when read
/// in order, construct a table mapping PC to frame state. This can also be
/// referred to as "CFI rules" in DWARF literature to avoid confusion with
/// computer programs in the broader sense, and in this context each instruction
/// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5
/// manual, "6.4.1 Structure of Call Frame Information".
class CFIProgram {
public:
typedef SmallVector<uint64_t, 2> Operands;
/// An instruction consists of a DWARF CFI opcode and an optional sequence of
/// operands. If it refers to an expression, then this expression has its own
/// sequence of operations and operands handled separately by DWARFExpression.
struct Instruction {
Instruction(uint8_t Opcode) : Opcode(Opcode) {}
uint8_t Opcode;
Operands Ops;
// Associated DWARF expression in case this instruction refers to one
Optional<DWARFExpression> Expression;
};
using InstrList = std::vector<Instruction>;
using iterator = InstrList::iterator;
using const_iterator = InstrList::const_iterator;
iterator begin() { return Instructions.begin(); }
const_iterator begin() const { return Instructions.begin(); }
iterator end() { return Instructions.end(); }
const_iterator end() const { return Instructions.end(); }
unsigned size() const { return (unsigned)Instructions.size(); }
bool empty() const { return Instructions.empty(); }
CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor,
Triple::ArchType Arch)
: CodeAlignmentFactor(CodeAlignmentFactor),
DataAlignmentFactor(DataAlignmentFactor),
Arch(Arch) {}
/// Parse and store a sequence of CFI instructions from Data,
/// starting at *Offset and ending at EndOffset. *Offset is updated
/// to EndOffset upon successful parsing, or indicates the offset
/// where a problem occurred in case an error is returned.
Error parse(DWARFDataExtractor Data, uint64_t *Offset, uint64_t EndOffset);
void dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI,
bool IsEH, unsigned IndentLevel = 1) const;
private:
std::vector<Instruction> Instructions;
const uint64_t CodeAlignmentFactor;
const int64_t DataAlignmentFactor;
Triple::ArchType Arch;
/// Convenience method to add a new instruction with the given opcode.
void addInstruction(uint8_t Opcode) {
Instructions.push_back(Instruction(Opcode));
}
/// Add a new single-operand instruction.
void addInstruction(uint8_t Opcode, uint64_t Operand1) {
Instructions.push_back(Instruction(Opcode));
Instructions.back().Ops.push_back(Operand1);
}
/// Add a new instruction that has two operands.
void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
Instructions.push_back(Instruction(Opcode));
Instructions.back().Ops.push_back(Operand1);
Instructions.back().Ops.push_back(Operand2);
}
/// Types of operands to CFI instructions
/// In DWARF, this type is implicitly tied to a CFI instruction opcode and
/// thus this type doesn't need to be explictly written to the file (this is
/// not a DWARF encoding). The relationship of instrs to operand types can
/// be obtained from getOperandTypes() and is only used to simplify
/// instruction printing.
enum OperandType {
OT_Unset,
OT_None,
OT_Address,
OT_Offset,
OT_FactoredCodeOffset,
OT_SignedFactDataOffset,
OT_UnsignedFactDataOffset,
OT_Register,
OT_Expression
};
/// Retrieve the array describing the types of operands according to the enum
/// above. This is indexed by opcode.
static ArrayRef<OperandType[2]> getOperandTypes();
/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
void printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
const MCRegisterInfo *MRI, bool IsEH,
const Instruction &Instr, unsigned OperandIdx,
uint64_t Operand) const;
};
/// An entry in either debug_frame or eh_frame. This entry can be a CIE or an
/// FDE.
class FrameEntry {
public:
enum FrameKind { FK_CIE, FK_FDE };
FrameEntry(FrameKind K, bool IsDWARF64, uint64_t Offset, uint64_t Length,
uint64_t CodeAlign, int64_t DataAlign, Triple::ArchType Arch)
: Kind(K), IsDWARF64(IsDWARF64), Offset(Offset), Length(Length),
CFIs(CodeAlign, DataAlign, Arch) {}
virtual ~FrameEntry() {}
FrameKind getKind() const { return Kind; }
uint64_t getOffset() const { return Offset; }
uint64_t getLength() const { return Length; }
const CFIProgram &cfis() const { return CFIs; }
CFIProgram &cfis() { return CFIs; }
/// Dump the instructions in this CFI fragment
virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts,
const MCRegisterInfo *MRI, bool IsEH) const = 0;
protected:
const FrameKind Kind;
const bool IsDWARF64;
/// Offset of this entry in the section.
const uint64_t Offset;
/// Entry length as specified in DWARF.
const uint64_t Length;
CFIProgram CFIs;
};
/// DWARF Common Information Entry (CIE)
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(bool IsDWARF64, uint64_t Offset, uint64_t Length, uint8_t Version,
SmallString<8> Augmentation, uint8_t AddressSize,
uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor,
int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister,
SmallString<8> AugmentationData, uint32_t FDEPointerEncoding,
uint32_t LSDAPointerEncoding, Optional<uint64_t> Personality,
Optional<uint32_t> PersonalityEnc, Triple::ArchType Arch)
: FrameEntry(FK_CIE, IsDWARF64, Offset, Length, CodeAlignmentFactor,
DataAlignmentFactor, Arch),
Version(Version), Augmentation(std::move(Augmentation)),
AddressSize(AddressSize), SegmentDescriptorSize(SegmentDescriptorSize),
CodeAlignmentFactor(CodeAlignmentFactor),
DataAlignmentFactor(DataAlignmentFactor),
ReturnAddressRegister(ReturnAddressRegister),
AugmentationData(std::move(AugmentationData)),
FDEPointerEncoding(FDEPointerEncoding),
LSDAPointerEncoding(LSDAPointerEncoding), Personality(Personality),
PersonalityEnc(PersonalityEnc) {}
static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_CIE; }
StringRef getAugmentationString() const { return Augmentation; }
uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; }
int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; }
uint8_t getVersion() const { return Version; }
uint64_t getReturnAddressRegister() const { return ReturnAddressRegister; }
Optional<uint64_t> getPersonalityAddress() const { return Personality; }
Optional<uint32_t> getPersonalityEncoding() const { return PersonalityEnc; }
uint32_t getFDEPointerEncoding() const { return FDEPointerEncoding; }
uint32_t getLSDAPointerEncoding() const { return LSDAPointerEncoding; }
void dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI,
bool IsEH) const override;
private:
/// The following fields are defined in section 6.4.1 of the DWARF standard v4
const uint8_t Version;
const SmallString<8> Augmentation;
const uint8_t AddressSize;
const uint8_t SegmentDescriptorSize;
const uint64_t CodeAlignmentFactor;
const int64_t DataAlignmentFactor;
const uint64_t ReturnAddressRegister;
// The following are used when the CIE represents an EH frame entry.
const SmallString<8> AugmentationData;
const uint32_t FDEPointerEncoding;
const uint32_t LSDAPointerEncoding;
const Optional<uint64_t> Personality;
const Optional<uint32_t> PersonalityEnc;
};
/// DWARF Frame Description Entry (FDE)
class FDE : public FrameEntry {
public:
FDE(bool IsDWARF64, uint64_t Offset, uint64_t Length, uint64_t CIEPointer,
uint64_t InitialLocation, uint64_t AddressRange, CIE *Cie,
Optional<uint64_t> LSDAAddress, Triple::ArchType Arch)
: FrameEntry(FK_FDE, IsDWARF64, Offset, Length,
Cie ? Cie->getCodeAlignmentFactor() : 0,
Cie ? Cie->getDataAlignmentFactor() : 0,
Arch),
CIEPointer(CIEPointer), InitialLocation(InitialLocation),
AddressRange(AddressRange), LinkedCIE(Cie), LSDAAddress(LSDAAddress) {}
~FDE() override = default;
const CIE *getLinkedCIE() const { return LinkedCIE; }
uint64_t getInitialLocation() const { return InitialLocation; }
uint64_t getAddressRange() const { return AddressRange; }
Optional<uint64_t> getLSDAAddress() const { return LSDAAddress; }
void dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI,
bool IsEH) const override;
static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_FDE; }
private:
/// The following fields are defined in section 6.4.1 of the DWARFv3 standard.
/// Note that CIE pointers in EH FDEs, unlike DWARF FDEs, contain relative
/// offsets to the linked CIEs. See the following link for more info:
/// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
const uint64_t CIEPointer;
const uint64_t InitialLocation;
const uint64_t AddressRange;
const CIE *LinkedCIE;
const Optional<uint64_t> LSDAAddress;
};
} // end namespace dwarf
/// A parsed .debug_frame or .eh_frame section
class DWARFDebugFrame {
const Triple::ArchType Arch;
// True if this is parsing an eh_frame section.
const bool IsEH;
// Not zero for sane pointer values coming out of eh_frame
const uint64_t EHFrameAddress;
std::vector<std::unique_ptr<dwarf::FrameEntry>> Entries;
using iterator = pointee_iterator<decltype(Entries)::const_iterator>;
/// Return the entry at the given offset or nullptr.
dwarf::FrameEntry *getEntryAtOffset(uint64_t Offset) const;
public:
// If IsEH is true, assume it is a .eh_frame section. Otherwise,
// it is a .debug_frame section. EHFrameAddress should be different
// than zero for correct parsing of .eh_frame addresses when they
// use a PC-relative encoding.
DWARFDebugFrame(Triple::ArchType Arch,
bool IsEH = false, uint64_t EHFrameAddress = 0);
~DWARFDebugFrame();
/// Dump the section data into the given stream.
void dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI,
Optional<uint64_t> Offset) const;
/// Parse the section from raw data. \p Data is assumed to contain the whole
/// frame section contents to be parsed.
Error parse(DWARFDataExtractor Data);
/// Return whether the section has any entries.
bool empty() const { return Entries.empty(); }
/// DWARF Frame entries accessors
iterator begin() const { return Entries.begin(); }
iterator end() const { return Entries.end(); }
iterator_range<iterator> entries() const {
return iterator_range<iterator>(Entries.begin(), Entries.end());
}
uint64_t getEHFrameAddress() const { return EHFrameAddress; }
};
} // end namespace llvm
#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|