1321369Sdim//===- DWARFDebugFrame.h - Parsing of .debug_frame --------------*- C++ -*-===//
2283625Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6283625Sdim//
7283625Sdim//===----------------------------------------------------------------------===//
8283625Sdim
9321369Sdim#ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
10321369Sdim#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
11283625Sdim
12341825Sdim#include "llvm/ADT/ArrayRef.h"
13341825Sdim#include "llvm/ADT/iterator.h"
14341825Sdim#include "llvm/ADT/SmallString.h"
15344779Sdim#include "llvm/ADT/Triple.h"
16341825Sdim#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
17341825Sdim#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
18341825Sdim#include "llvm/Support/Error.h"
19283625Sdim#include <memory>
20283625Sdim#include <vector>
21283625Sdim
22283625Sdimnamespace llvm {
23283625Sdim
24321369Sdimclass raw_ostream;
25283625Sdim
26341825Sdimnamespace dwarf {
27341825Sdim
28341825Sdim/// Represent a sequence of Call Frame Information instructions that, when read
29341825Sdim/// in order, construct a table mapping PC to frame state. This can also be
30341825Sdim/// referred to as "CFI rules" in DWARF literature to avoid confusion with
31341825Sdim/// computer programs in the broader sense, and in this context each instruction
32341825Sdim/// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5
33341825Sdim/// manual, "6.4.1 Structure of Call Frame Information".
34341825Sdimclass CFIProgram {
35341825Sdimpublic:
36341825Sdim  typedef SmallVector<uint64_t, 2> Operands;
37341825Sdim
38341825Sdim  /// An instruction consists of a DWARF CFI opcode and an optional sequence of
39341825Sdim  /// operands. If it refers to an expression, then this expression has its own
40341825Sdim  /// sequence of operations and operands handled separately by DWARFExpression.
41341825Sdim  struct Instruction {
42341825Sdim    Instruction(uint8_t Opcode) : Opcode(Opcode) {}
43341825Sdim
44341825Sdim    uint8_t Opcode;
45341825Sdim    Operands Ops;
46341825Sdim    // Associated DWARF expression in case this instruction refers to one
47341825Sdim    Optional<DWARFExpression> Expression;
48341825Sdim  };
49341825Sdim
50341825Sdim  using InstrList = std::vector<Instruction>;
51341825Sdim  using iterator = InstrList::iterator;
52341825Sdim  using const_iterator = InstrList::const_iterator;
53341825Sdim
54341825Sdim  iterator begin() { return Instructions.begin(); }
55341825Sdim  const_iterator begin() const { return Instructions.begin(); }
56341825Sdim  iterator end() { return Instructions.end(); }
57341825Sdim  const_iterator end() const { return Instructions.end(); }
58341825Sdim
59341825Sdim  unsigned size() const { return (unsigned)Instructions.size(); }
60341825Sdim  bool empty() const { return Instructions.empty(); }
61341825Sdim
62344779Sdim  CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor,
63344779Sdim             Triple::ArchType Arch)
64341825Sdim      : CodeAlignmentFactor(CodeAlignmentFactor),
65344779Sdim        DataAlignmentFactor(DataAlignmentFactor),
66344779Sdim        Arch(Arch) {}
67341825Sdim
68341825Sdim  /// Parse and store a sequence of CFI instructions from Data,
69341825Sdim  /// starting at *Offset and ending at EndOffset. *Offset is updated
70341825Sdim  /// to EndOffset upon successful parsing, or indicates the offset
71341825Sdim  /// where a problem occurred in case an error is returned.
72360784Sdim  Error parse(DWARFDataExtractor Data, uint64_t *Offset, uint64_t EndOffset);
73341825Sdim
74341825Sdim  void dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
75341825Sdim            unsigned IndentLevel = 1) const;
76341825Sdim
77341825Sdimprivate:
78341825Sdim  std::vector<Instruction> Instructions;
79341825Sdim  const uint64_t CodeAlignmentFactor;
80341825Sdim  const int64_t DataAlignmentFactor;
81344779Sdim  Triple::ArchType Arch;
82341825Sdim
83341825Sdim  /// Convenience method to add a new instruction with the given opcode.
84341825Sdim  void addInstruction(uint8_t Opcode) {
85341825Sdim    Instructions.push_back(Instruction(Opcode));
86341825Sdim  }
87341825Sdim
88341825Sdim  /// Add a new single-operand instruction.
89341825Sdim  void addInstruction(uint8_t Opcode, uint64_t Operand1) {
90341825Sdim    Instructions.push_back(Instruction(Opcode));
91341825Sdim    Instructions.back().Ops.push_back(Operand1);
92341825Sdim  }
93341825Sdim
94341825Sdim  /// Add a new instruction that has two operands.
95341825Sdim  void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
96341825Sdim    Instructions.push_back(Instruction(Opcode));
97341825Sdim    Instructions.back().Ops.push_back(Operand1);
98341825Sdim    Instructions.back().Ops.push_back(Operand2);
99341825Sdim  }
100341825Sdim
101341825Sdim  /// Types of operands to CFI instructions
102341825Sdim  /// In DWARF, this type is implicitly tied to a CFI instruction opcode and
103341825Sdim  /// thus this type doesn't need to be explictly written to the file (this is
104341825Sdim  /// not a DWARF encoding). The relationship of instrs to operand types can
105341825Sdim  /// be obtained from getOperandTypes() and is only used to simplify
106341825Sdim  /// instruction printing.
107341825Sdim  enum OperandType {
108341825Sdim    OT_Unset,
109341825Sdim    OT_None,
110341825Sdim    OT_Address,
111341825Sdim    OT_Offset,
112341825Sdim    OT_FactoredCodeOffset,
113341825Sdim    OT_SignedFactDataOffset,
114341825Sdim    OT_UnsignedFactDataOffset,
115341825Sdim    OT_Register,
116341825Sdim    OT_Expression
117341825Sdim  };
118341825Sdim
119341825Sdim  /// Retrieve the array describing the types of operands according to the enum
120341825Sdim  /// above. This is indexed by opcode.
121341825Sdim  static ArrayRef<OperandType[2]> getOperandTypes();
122341825Sdim
123341825Sdim  /// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
124341825Sdim  void printOperand(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
125341825Sdim                    const Instruction &Instr, unsigned OperandIdx,
126341825Sdim                    uint64_t Operand) const;
127341825Sdim};
128341825Sdim
129341825Sdim/// An entry in either debug_frame or eh_frame. This entry can be a CIE or an
130341825Sdim/// FDE.
131341825Sdimclass FrameEntry {
132341825Sdimpublic:
133341825Sdim  enum FrameKind { FK_CIE, FK_FDE };
134341825Sdim
135341825Sdim  FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length, uint64_t CodeAlign,
136344779Sdim             int64_t DataAlign, Triple::ArchType Arch)
137344779Sdim      : Kind(K), Offset(Offset), Length(Length),
138344779Sdim        CFIs(CodeAlign, DataAlign, Arch) {}
139341825Sdim
140341825Sdim  virtual ~FrameEntry() {}
141341825Sdim
142341825Sdim  FrameKind getKind() const { return Kind; }
143341825Sdim  uint64_t getOffset() const { return Offset; }
144341825Sdim  uint64_t getLength() const { return Length; }
145341825Sdim  const CFIProgram &cfis() const { return CFIs; }
146341825Sdim  CFIProgram &cfis() { return CFIs; }
147341825Sdim
148341825Sdim  /// Dump the instructions in this CFI fragment
149341825Sdim  virtual void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
150341825Sdim                    bool IsEH) const = 0;
151341825Sdim
152341825Sdimprotected:
153341825Sdim  const FrameKind Kind;
154341825Sdim
155341825Sdim  /// Offset of this entry in the section.
156341825Sdim  const uint64_t Offset;
157341825Sdim
158341825Sdim  /// Entry length as specified in DWARF.
159341825Sdim  const uint64_t Length;
160341825Sdim
161341825Sdim  CFIProgram CFIs;
162341825Sdim};
163341825Sdim
164341825Sdim/// DWARF Common Information Entry (CIE)
165341825Sdimclass CIE : public FrameEntry {
166341825Sdimpublic:
167341825Sdim  // CIEs (and FDEs) are simply container classes, so the only sensible way to
168341825Sdim  // create them is by providing the full parsed contents in the constructor.
169341825Sdim  CIE(uint64_t Offset, uint64_t Length, uint8_t Version,
170341825Sdim      SmallString<8> Augmentation, uint8_t AddressSize,
171341825Sdim      uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor,
172341825Sdim      int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister,
173341825Sdim      SmallString<8> AugmentationData, uint32_t FDEPointerEncoding,
174341825Sdim      uint32_t LSDAPointerEncoding, Optional<uint64_t> Personality,
175344779Sdim      Optional<uint32_t> PersonalityEnc, Triple::ArchType Arch)
176341825Sdim      : FrameEntry(FK_CIE, Offset, Length, CodeAlignmentFactor,
177344779Sdim                   DataAlignmentFactor, Arch),
178341825Sdim        Version(Version), Augmentation(std::move(Augmentation)),
179341825Sdim        AddressSize(AddressSize), SegmentDescriptorSize(SegmentDescriptorSize),
180341825Sdim        CodeAlignmentFactor(CodeAlignmentFactor),
181341825Sdim        DataAlignmentFactor(DataAlignmentFactor),
182341825Sdim        ReturnAddressRegister(ReturnAddressRegister),
183341825Sdim        AugmentationData(std::move(AugmentationData)),
184341825Sdim        FDEPointerEncoding(FDEPointerEncoding),
185341825Sdim        LSDAPointerEncoding(LSDAPointerEncoding), Personality(Personality),
186341825Sdim        PersonalityEnc(PersonalityEnc) {}
187341825Sdim
188341825Sdim  static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_CIE; }
189341825Sdim
190341825Sdim  StringRef getAugmentationString() const { return Augmentation; }
191341825Sdim  uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; }
192341825Sdim  int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; }
193341825Sdim  uint8_t getVersion() const { return Version; }
194341825Sdim  uint64_t getReturnAddressRegister() const { return ReturnAddressRegister; }
195341825Sdim  Optional<uint64_t> getPersonalityAddress() const { return Personality; }
196341825Sdim  Optional<uint32_t> getPersonalityEncoding() const { return PersonalityEnc; }
197341825Sdim
198341825Sdim  uint32_t getFDEPointerEncoding() const { return FDEPointerEncoding; }
199341825Sdim
200341825Sdim  uint32_t getLSDAPointerEncoding() const { return LSDAPointerEncoding; }
201341825Sdim
202341825Sdim  void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
203341825Sdim            bool IsEH) const override;
204341825Sdim
205341825Sdimprivate:
206341825Sdim  /// The following fields are defined in section 6.4.1 of the DWARF standard v4
207341825Sdim  const uint8_t Version;
208341825Sdim  const SmallString<8> Augmentation;
209341825Sdim  const uint8_t AddressSize;
210341825Sdim  const uint8_t SegmentDescriptorSize;
211341825Sdim  const uint64_t CodeAlignmentFactor;
212341825Sdim  const int64_t DataAlignmentFactor;
213341825Sdim  const uint64_t ReturnAddressRegister;
214341825Sdim
215341825Sdim  // The following are used when the CIE represents an EH frame entry.
216341825Sdim  const SmallString<8> AugmentationData;
217341825Sdim  const uint32_t FDEPointerEncoding;
218341825Sdim  const uint32_t LSDAPointerEncoding;
219341825Sdim  const Optional<uint64_t> Personality;
220341825Sdim  const Optional<uint32_t> PersonalityEnc;
221341825Sdim};
222341825Sdim
223341825Sdim/// DWARF Frame Description Entry (FDE)
224341825Sdimclass FDE : public FrameEntry {
225341825Sdimpublic:
226341825Sdim  // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with
227341825Sdim  // an offset to the CIE (provided by parsing the FDE header). The CIE itself
228341825Sdim  // is obtained lazily once it's actually required.
229341825Sdim  FDE(uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset,
230341825Sdim      uint64_t InitialLocation, uint64_t AddressRange, CIE *Cie,
231344779Sdim      Optional<uint64_t> LSDAAddress, Triple::ArchType Arch)
232341825Sdim      : FrameEntry(FK_FDE, Offset, Length,
233341825Sdim                   Cie ? Cie->getCodeAlignmentFactor() : 0,
234344779Sdim                   Cie ? Cie->getDataAlignmentFactor() : 0,
235344779Sdim                   Arch),
236341825Sdim        LinkedCIEOffset(LinkedCIEOffset), InitialLocation(InitialLocation),
237341825Sdim        AddressRange(AddressRange), LinkedCIE(Cie), LSDAAddress(LSDAAddress) {}
238341825Sdim
239341825Sdim  ~FDE() override = default;
240341825Sdim
241341825Sdim  const CIE *getLinkedCIE() const { return LinkedCIE; }
242341825Sdim  uint64_t getInitialLocation() const { return InitialLocation; }
243341825Sdim  uint64_t getAddressRange() const { return AddressRange; }
244341825Sdim  Optional<uint64_t> getLSDAAddress() const { return LSDAAddress; }
245341825Sdim
246341825Sdim  void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
247341825Sdim            bool IsEH) const override;
248341825Sdim
249341825Sdim  static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_FDE; }
250341825Sdim
251341825Sdimprivate:
252341825Sdim  /// The following fields are defined in section 6.4.1 of the DWARF standard v3
253341825Sdim  const uint64_t LinkedCIEOffset;
254341825Sdim  const uint64_t InitialLocation;
255341825Sdim  const uint64_t AddressRange;
256341825Sdim  const CIE *LinkedCIE;
257341825Sdim  const Optional<uint64_t> LSDAAddress;
258341825Sdim};
259341825Sdim
260341825Sdim} // end namespace dwarf
261341825Sdim
262341825Sdim/// A parsed .debug_frame or .eh_frame section
263283625Sdimclass DWARFDebugFrame {
264344779Sdim  const Triple::ArchType Arch;
265309124Sdim  // True if this is parsing an eh_frame section.
266341825Sdim  const bool IsEH;
267341825Sdim  // Not zero for sane pointer values coming out of eh_frame
268341825Sdim  const uint64_t EHFrameAddress;
269321369Sdim
270341825Sdim  std::vector<std::unique_ptr<dwarf::FrameEntry>> Entries;
271341825Sdim  using iterator = pointee_iterator<decltype(Entries)::const_iterator>;
272341825Sdim
273341825Sdim  /// Return the entry at the given offset or nullptr.
274341825Sdim  dwarf::FrameEntry *getEntryAtOffset(uint64_t Offset) const;
275341825Sdim
276283625Sdimpublic:
277341825Sdim  // If IsEH is true, assume it is a .eh_frame section. Otherwise,
278341825Sdim  // it is a .debug_frame section. EHFrameAddress should be different
279341825Sdim  // than zero for correct parsing of .eh_frame addresses when they
280341825Sdim  // use a PC-relative encoding.
281344779Sdim  DWARFDebugFrame(Triple::ArchType Arch,
282344779Sdim                  bool IsEH = false, uint64_t EHFrameAddress = 0);
283283625Sdim  ~DWARFDebugFrame();
284283625Sdim
285327952Sdim  /// Dump the section data into the given stream.
286341825Sdim  void dump(raw_ostream &OS, const MCRegisterInfo *MRI,
287341825Sdim            Optional<uint64_t> Offset) const;
288283625Sdim
289341825Sdim  /// Parse the section from raw data. \p Data is assumed to contain the whole
290341825Sdim  /// frame section contents to be parsed.
291341825Sdim  void parse(DWARFDataExtractor Data);
292283625Sdim
293327952Sdim  /// Return whether the section has any entries.
294327952Sdim  bool empty() const { return Entries.empty(); }
295327952Sdim
296341825Sdim  /// DWARF Frame entries accessors
297341825Sdim  iterator begin() const { return Entries.begin(); }
298341825Sdim  iterator end() const { return Entries.end(); }
299341825Sdim  iterator_range<iterator> entries() const {
300341825Sdim    return iterator_range<iterator>(Entries.begin(), Entries.end());
301341825Sdim  }
302327952Sdim
303341825Sdim  uint64_t getEHFrameAddress() const { return EHFrameAddress; }
304283625Sdim};
305283625Sdim
306321369Sdim} // end namespace llvm
307283625Sdim
308321369Sdim#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H
309