xref: /freebsd/contrib/llvm-project/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h (revision c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5)
1 //===- DWARFDebugFrame.h - Parsing of .debug_frame --------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
10 #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
11 
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/iterator.h"
14 #include "llvm/ADT/SmallString.h"
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
17 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
18 #include "llvm/Support/Error.h"
19 #include <memory>
20 #include <vector>
21 
22 namespace llvm {
23 
24 class raw_ostream;
25 
26 namespace dwarf {
27 
28 /// Represent a sequence of Call Frame Information instructions that, when read
29 /// in order, construct a table mapping PC to frame state. This can also be
30 /// referred to as "CFI rules" in DWARF literature to avoid confusion with
31 /// computer programs in the broader sense, and in this context each instruction
32 /// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5
33 /// manual, "6.4.1 Structure of Call Frame Information".
34 class CFIProgram {
35 public:
36   typedef SmallVector<uint64_t, 2> Operands;
37 
38   /// An instruction consists of a DWARF CFI opcode and an optional sequence of
39   /// operands. If it refers to an expression, then this expression has its own
40   /// sequence of operations and operands handled separately by DWARFExpression.
41   struct Instruction {
42     Instruction(uint8_t Opcode) : Opcode(Opcode) {}
43 
44     uint8_t Opcode;
45     Operands Ops;
46     // Associated DWARF expression in case this instruction refers to one
47     Optional<DWARFExpression> Expression;
48   };
49 
50   using InstrList = std::vector<Instruction>;
51   using iterator = InstrList::iterator;
52   using const_iterator = InstrList::const_iterator;
53 
54   iterator begin() { return Instructions.begin(); }
55   const_iterator begin() const { return Instructions.begin(); }
56   iterator end() { return Instructions.end(); }
57   const_iterator end() const { return Instructions.end(); }
58 
59   unsigned size() const { return (unsigned)Instructions.size(); }
60   bool empty() const { return Instructions.empty(); }
61 
62   CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor,
63              Triple::ArchType Arch)
64       : CodeAlignmentFactor(CodeAlignmentFactor),
65         DataAlignmentFactor(DataAlignmentFactor),
66         Arch(Arch) {}
67 
68   /// Parse and store a sequence of CFI instructions from Data,
69   /// starting at *Offset and ending at EndOffset. *Offset is updated
70   /// to EndOffset upon successful parsing, or indicates the offset
71   /// where a problem occurred in case an error is returned.
72   Error parse(DWARFDataExtractor Data, uint64_t *Offset, uint64_t EndOffset);
73 
74   void dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI,
75             bool IsEH, unsigned IndentLevel = 1) const;
76 
77 private:
78   std::vector<Instruction> Instructions;
79   const uint64_t CodeAlignmentFactor;
80   const int64_t DataAlignmentFactor;
81   Triple::ArchType Arch;
82 
83   /// Convenience method to add a new instruction with the given opcode.
84   void addInstruction(uint8_t Opcode) {
85     Instructions.push_back(Instruction(Opcode));
86   }
87 
88   /// Add a new single-operand instruction.
89   void addInstruction(uint8_t Opcode, uint64_t Operand1) {
90     Instructions.push_back(Instruction(Opcode));
91     Instructions.back().Ops.push_back(Operand1);
92   }
93 
94   /// Add a new instruction that has two operands.
95   void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
96     Instructions.push_back(Instruction(Opcode));
97     Instructions.back().Ops.push_back(Operand1);
98     Instructions.back().Ops.push_back(Operand2);
99   }
100 
101   /// Types of operands to CFI instructions
102   /// In DWARF, this type is implicitly tied to a CFI instruction opcode and
103   /// thus this type doesn't need to be explictly written to the file (this is
104   /// not a DWARF encoding). The relationship of instrs to operand types can
105   /// be obtained from getOperandTypes() and is only used to simplify
106   /// instruction printing.
107   enum OperandType {
108     OT_Unset,
109     OT_None,
110     OT_Address,
111     OT_Offset,
112     OT_FactoredCodeOffset,
113     OT_SignedFactDataOffset,
114     OT_UnsignedFactDataOffset,
115     OT_Register,
116     OT_Expression
117   };
118 
119   /// Retrieve the array describing the types of operands according to the enum
120   /// above. This is indexed by opcode.
121   static ArrayRef<OperandType[2]> getOperandTypes();
122 
123   /// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
124   void printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
125                     const MCRegisterInfo *MRI, bool IsEH,
126                     const Instruction &Instr, unsigned OperandIdx,
127                     uint64_t Operand) const;
128 };
129 
130 /// An entry in either debug_frame or eh_frame. This entry can be a CIE or an
131 /// FDE.
132 class FrameEntry {
133 public:
134   enum FrameKind { FK_CIE, FK_FDE };
135 
136   FrameEntry(FrameKind K, bool IsDWARF64, uint64_t Offset, uint64_t Length,
137              uint64_t CodeAlign, int64_t DataAlign, Triple::ArchType Arch)
138       : Kind(K), IsDWARF64(IsDWARF64), Offset(Offset), Length(Length),
139         CFIs(CodeAlign, DataAlign, Arch) {}
140 
141   virtual ~FrameEntry() {}
142 
143   FrameKind getKind() const { return Kind; }
144   uint64_t getOffset() const { return Offset; }
145   uint64_t getLength() const { return Length; }
146   const CFIProgram &cfis() const { return CFIs; }
147   CFIProgram &cfis() { return CFIs; }
148 
149   /// Dump the instructions in this CFI fragment
150   virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts,
151                     const MCRegisterInfo *MRI, bool IsEH) const = 0;
152 
153 protected:
154   const FrameKind Kind;
155 
156   const bool IsDWARF64;
157 
158   /// Offset of this entry in the section.
159   const uint64_t Offset;
160 
161   /// Entry length as specified in DWARF.
162   const uint64_t Length;
163 
164   CFIProgram CFIs;
165 };
166 
167 /// DWARF Common Information Entry (CIE)
168 class CIE : public FrameEntry {
169 public:
170   // CIEs (and FDEs) are simply container classes, so the only sensible way to
171   // create them is by providing the full parsed contents in the constructor.
172   CIE(bool IsDWARF64, uint64_t Offset, uint64_t Length, uint8_t Version,
173       SmallString<8> Augmentation, uint8_t AddressSize,
174       uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor,
175       int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister,
176       SmallString<8> AugmentationData, uint32_t FDEPointerEncoding,
177       uint32_t LSDAPointerEncoding, Optional<uint64_t> Personality,
178       Optional<uint32_t> PersonalityEnc, Triple::ArchType Arch)
179       : FrameEntry(FK_CIE, IsDWARF64, Offset, Length, CodeAlignmentFactor,
180                    DataAlignmentFactor, Arch),
181         Version(Version), Augmentation(std::move(Augmentation)),
182         AddressSize(AddressSize), SegmentDescriptorSize(SegmentDescriptorSize),
183         CodeAlignmentFactor(CodeAlignmentFactor),
184         DataAlignmentFactor(DataAlignmentFactor),
185         ReturnAddressRegister(ReturnAddressRegister),
186         AugmentationData(std::move(AugmentationData)),
187         FDEPointerEncoding(FDEPointerEncoding),
188         LSDAPointerEncoding(LSDAPointerEncoding), Personality(Personality),
189         PersonalityEnc(PersonalityEnc) {}
190 
191   static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_CIE; }
192 
193   StringRef getAugmentationString() const { return Augmentation; }
194   uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; }
195   int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; }
196   uint8_t getVersion() const { return Version; }
197   uint64_t getReturnAddressRegister() const { return ReturnAddressRegister; }
198   Optional<uint64_t> getPersonalityAddress() const { return Personality; }
199   Optional<uint32_t> getPersonalityEncoding() const { return PersonalityEnc; }
200 
201   uint32_t getFDEPointerEncoding() const { return FDEPointerEncoding; }
202 
203   uint32_t getLSDAPointerEncoding() const { return LSDAPointerEncoding; }
204 
205   void dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI,
206             bool IsEH) const override;
207 
208 private:
209   /// The following fields are defined in section 6.4.1 of the DWARF standard v4
210   const uint8_t Version;
211   const SmallString<8> Augmentation;
212   const uint8_t AddressSize;
213   const uint8_t SegmentDescriptorSize;
214   const uint64_t CodeAlignmentFactor;
215   const int64_t DataAlignmentFactor;
216   const uint64_t ReturnAddressRegister;
217 
218   // The following are used when the CIE represents an EH frame entry.
219   const SmallString<8> AugmentationData;
220   const uint32_t FDEPointerEncoding;
221   const uint32_t LSDAPointerEncoding;
222   const Optional<uint64_t> Personality;
223   const Optional<uint32_t> PersonalityEnc;
224 };
225 
226 /// DWARF Frame Description Entry (FDE)
227 class FDE : public FrameEntry {
228 public:
229   FDE(bool IsDWARF64, uint64_t Offset, uint64_t Length, uint64_t CIEPointer,
230       uint64_t InitialLocation, uint64_t AddressRange, CIE *Cie,
231       Optional<uint64_t> LSDAAddress, Triple::ArchType Arch)
232       : FrameEntry(FK_FDE, IsDWARF64, Offset, Length,
233                    Cie ? Cie->getCodeAlignmentFactor() : 0,
234                    Cie ? Cie->getDataAlignmentFactor() : 0,
235                    Arch),
236         CIEPointer(CIEPointer), InitialLocation(InitialLocation),
237         AddressRange(AddressRange), LinkedCIE(Cie), LSDAAddress(LSDAAddress) {}
238 
239   ~FDE() override = default;
240 
241   const CIE *getLinkedCIE() const { return LinkedCIE; }
242   uint64_t getInitialLocation() const { return InitialLocation; }
243   uint64_t getAddressRange() const { return AddressRange; }
244   Optional<uint64_t> getLSDAAddress() const { return LSDAAddress; }
245 
246   void dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI,
247             bool IsEH) const override;
248 
249   static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_FDE; }
250 
251 private:
252   /// The following fields are defined in section 6.4.1 of the DWARFv3 standard.
253   /// Note that CIE pointers in EH FDEs, unlike DWARF FDEs, contain relative
254   /// offsets to the linked CIEs. See the following link for more info:
255   /// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
256   const uint64_t CIEPointer;
257   const uint64_t InitialLocation;
258   const uint64_t AddressRange;
259   const CIE *LinkedCIE;
260   const Optional<uint64_t> LSDAAddress;
261 };
262 
263 } // end namespace dwarf
264 
265 /// A parsed .debug_frame or .eh_frame section
266 class DWARFDebugFrame {
267   const Triple::ArchType Arch;
268   // True if this is parsing an eh_frame section.
269   const bool IsEH;
270   // Not zero for sane pointer values coming out of eh_frame
271   const uint64_t EHFrameAddress;
272 
273   std::vector<std::unique_ptr<dwarf::FrameEntry>> Entries;
274   using iterator = pointee_iterator<decltype(Entries)::const_iterator>;
275 
276   /// Return the entry at the given offset or nullptr.
277   dwarf::FrameEntry *getEntryAtOffset(uint64_t Offset) const;
278 
279 public:
280   // If IsEH is true, assume it is a .eh_frame section. Otherwise,
281   // it is a .debug_frame section. EHFrameAddress should be different
282   // than zero for correct parsing of .eh_frame addresses when they
283   // use a PC-relative encoding.
284   DWARFDebugFrame(Triple::ArchType Arch,
285                   bool IsEH = false, uint64_t EHFrameAddress = 0);
286   ~DWARFDebugFrame();
287 
288   /// Dump the section data into the given stream.
289   void dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI,
290             Optional<uint64_t> Offset) const;
291 
292   /// Parse the section from raw data. \p Data is assumed to contain the whole
293   /// frame section contents to be parsed.
294   Error parse(DWARFDataExtractor Data);
295 
296   /// Return whether the section has any entries.
297   bool empty() const { return Entries.empty(); }
298 
299   /// DWARF Frame entries accessors
300   iterator begin() const { return Entries.begin(); }
301   iterator end() const { return Entries.end(); }
302   iterator_range<iterator> entries() const {
303     return iterator_range<iterator>(Entries.begin(), Entries.end());
304   }
305 
306   uint64_t getEHFrameAddress() const { return EHFrameAddress; }
307 };
308 
309 } // end namespace llvm
310 
311 #endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
312