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