Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 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/SmallString.h" |
||
14 | #include "llvm/ADT/Triple.h" |
||
15 | #include "llvm/ADT/iterator.h" |
||
16 | #include "llvm/DebugInfo/DWARF/DWARFExpression.h" |
||
17 | #include "llvm/Support/Error.h" |
||
18 | #include <map> |
||
19 | #include <memory> |
||
20 | #include <vector> |
||
21 | |||
22 | namespace llvm { |
||
23 | |||
24 | class raw_ostream; |
||
25 | class DWARFDataExtractor; |
||
26 | class MCRegisterInfo; |
||
27 | struct DIDumpOptions; |
||
28 | |||
29 | namespace dwarf { |
||
30 | |||
31 | constexpr uint32_t InvalidRegisterNumber = UINT32_MAX; |
||
32 | |||
33 | /// A class that represents a location for the Call Frame Address (CFA) or a |
||
34 | /// register. This is decoded from the DWARF Call Frame Information |
||
35 | /// instructions and put into an UnwindRow. |
||
36 | class UnwindLocation { |
||
37 | public: |
||
38 | enum Location { |
||
39 | /// Not specified. |
||
40 | Unspecified, |
||
41 | /// Register is not available and can't be recovered. |
||
42 | Undefined, |
||
43 | /// Register value is in the register, nothing needs to be done to unwind |
||
44 | /// it: |
||
45 | /// reg = reg |
||
46 | Same, |
||
47 | /// Register is in or at the CFA plus an offset: |
||
48 | /// reg = CFA + offset |
||
49 | /// reg = defef(CFA + offset) |
||
50 | CFAPlusOffset, |
||
51 | /// Register or CFA is in or at a register plus offset, optionally in |
||
52 | /// an address space: |
||
53 | /// reg = reg + offset [in addrspace] |
||
54 | /// reg = deref(reg + offset [in addrspace]) |
||
55 | RegPlusOffset, |
||
56 | /// Register or CFA value is in or at a value found by evaluating a DWARF |
||
57 | /// expression: |
||
58 | /// reg = eval(dwarf_expr) |
||
59 | /// reg = deref(eval(dwarf_expr)) |
||
60 | DWARFExpr, |
||
61 | /// Value is a constant value contained in "Offset": |
||
62 | /// reg = Offset |
||
63 | Constant, |
||
64 | }; |
||
65 | |||
66 | private: |
||
67 | Location Kind; /// The type of the location that describes how to unwind it. |
||
68 | uint32_t RegNum; /// The register number for Kind == RegPlusOffset. |
||
69 | int32_t Offset; /// The offset for Kind == CFAPlusOffset or RegPlusOffset. |
||
70 | std::optional<uint32_t> AddrSpace; /// The address space for Kind == |
||
71 | /// RegPlusOffset for CFA. |
||
72 | std::optional<DWARFExpression> Expr; /// The DWARF expression for Kind == |
||
73 | /// DWARFExpression. |
||
74 | bool Dereference; /// If true, the resulting location must be dereferenced |
||
75 | /// after the location value is computed. |
||
76 | |||
77 | // Constructors are private to force people to use the create static |
||
78 | // functions. |
||
79 | UnwindLocation(Location K) |
||
80 | : Kind(K), RegNum(InvalidRegisterNumber), Offset(0), |
||
81 | AddrSpace(std::nullopt), Dereference(false) {} |
||
82 | |||
83 | UnwindLocation(Location K, uint32_t Reg, int32_t Off, |
||
84 | std::optional<uint32_t> AS, bool Deref) |
||
85 | : Kind(K), RegNum(Reg), Offset(Off), AddrSpace(AS), Dereference(Deref) {} |
||
86 | |||
87 | UnwindLocation(DWARFExpression E, bool Deref) |
||
88 | : Kind(DWARFExpr), RegNum(InvalidRegisterNumber), Offset(0), Expr(E), |
||
89 | Dereference(Deref) {} |
||
90 | |||
91 | public: |
||
92 | /// Create a location whose rule is set to Unspecified. This means the |
||
93 | /// register value might be in the same register but it wasn't specified in |
||
94 | /// the unwind opcodes. |
||
95 | static UnwindLocation createUnspecified(); |
||
96 | /// Create a location where the value is undefined and not available. This can |
||
97 | /// happen when a register is volatile and can't be recovered. |
||
98 | static UnwindLocation createUndefined(); |
||
99 | /// Create a location where the value is known to be in the register itself. |
||
100 | static UnwindLocation createSame(); |
||
101 | /// Create a location that is in (Deref == false) or at (Deref == true) the |
||
102 | /// CFA plus an offset. Most registers that are spilled onto the stack use |
||
103 | /// this rule. The rule for the register will use this rule and specify a |
||
104 | /// unique offset from the CFA with \a Deref set to true. This value will be |
||
105 | /// relative to a CFA value which is typically defined using the register |
||
106 | /// plus offset location. \see createRegisterPlusOffset(...) for more |
||
107 | /// information. |
||
108 | static UnwindLocation createIsCFAPlusOffset(int32_t Off); |
||
109 | static UnwindLocation createAtCFAPlusOffset(int32_t Off); |
||
110 | /// Create a location where the saved value is in (Deref == false) or at |
||
111 | /// (Deref == true) a regiser plus an offset and, optionally, in the specified |
||
112 | /// address space (used mostly for the CFA). |
||
113 | /// |
||
114 | /// The CFA is usually defined using this rule by using the stack pointer or |
||
115 | /// frame pointer as the register, with an offset that accounts for all |
||
116 | /// spilled registers and all local variables in a function, and Deref == |
||
117 | /// false. |
||
118 | static UnwindLocation |
||
119 | createIsRegisterPlusOffset(uint32_t Reg, int32_t Off, |
||
120 | std::optional<uint32_t> AddrSpace = std::nullopt); |
||
121 | static UnwindLocation |
||
122 | createAtRegisterPlusOffset(uint32_t Reg, int32_t Off, |
||
123 | std::optional<uint32_t> AddrSpace = std::nullopt); |
||
124 | /// Create a location whose value is the result of evaluating a DWARF |
||
125 | /// expression. This allows complex expressions to be evaluated in order to |
||
126 | /// unwind a register or CFA value. |
||
127 | static UnwindLocation createIsDWARFExpression(DWARFExpression Expr); |
||
128 | static UnwindLocation createAtDWARFExpression(DWARFExpression Expr); |
||
129 | static UnwindLocation createIsConstant(int32_t Value); |
||
130 | |||
131 | Location getLocation() const { return Kind; } |
||
132 | uint32_t getRegister() const { return RegNum; } |
||
133 | int32_t getOffset() const { return Offset; } |
||
134 | uint32_t getAddressSpace() const { |
||
135 | assert(Kind == RegPlusOffset && AddrSpace); |
||
136 | return *AddrSpace; |
||
137 | } |
||
138 | int32_t getConstant() const { return Offset; } |
||
139 | /// Some opcodes will modify the CFA location's register only, so we need |
||
140 | /// to be able to modify the CFA register when evaluating DWARF Call Frame |
||
141 | /// Information opcodes. |
||
142 | void setRegister(uint32_t NewRegNum) { RegNum = NewRegNum; } |
||
143 | /// Some opcodes will modify the CFA location's offset only, so we need |
||
144 | /// to be able to modify the CFA offset when evaluating DWARF Call Frame |
||
145 | /// Information opcodes. |
||
146 | void setOffset(int32_t NewOffset) { Offset = NewOffset; } |
||
147 | /// Some opcodes modify a constant value and we need to be able to update |
||
148 | /// the constant value (DW_CFA_GNU_window_save which is also known as |
||
149 | // DW_CFA_AARCH64_negate_ra_state). |
||
150 | void setConstant(int32_t Value) { Offset = Value; } |
||
151 | |||
152 | std::optional<DWARFExpression> getDWARFExpressionBytes() const { |
||
153 | return Expr; |
||
154 | } |
||
155 | /// Dump a location expression as text and use the register information if |
||
156 | /// some is provided. |
||
157 | /// |
||
158 | /// \param OS the stream to use for output. |
||
159 | /// |
||
160 | /// \param MRI register information that helps emit register names insteead |
||
161 | /// of raw register numbers. |
||
162 | /// |
||
163 | /// \param IsEH true if the DWARF Call Frame Information is from .eh_frame |
||
164 | /// instead of from .debug_frame. This is needed for register number |
||
165 | /// conversion because some register numbers differ between the two sections |
||
166 | /// for certain architectures like x86. |
||
167 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const; |
||
168 | |||
169 | bool operator==(const UnwindLocation &RHS) const; |
||
170 | }; |
||
171 | |||
172 | raw_ostream &operator<<(raw_ostream &OS, const UnwindLocation &R); |
||
173 | |||
174 | /// A class that can track all registers with locations in a UnwindRow object. |
||
175 | /// |
||
176 | /// Register locations use a map where the key is the register number and the |
||
177 | /// the value is a UnwindLocation. |
||
178 | /// |
||
179 | /// The register maps are put into a class so that all register locations can |
||
180 | /// be copied when parsing the unwind opcodes DW_CFA_remember_state and |
||
181 | /// DW_CFA_restore_state. |
||
182 | class RegisterLocations { |
||
183 | std::map<uint32_t, UnwindLocation> Locations; |
||
184 | |||
185 | public: |
||
186 | /// Return the location for the register in \a RegNum if there is a location. |
||
187 | /// |
||
188 | /// \param RegNum the register number to find a location for. |
||
189 | /// |
||
190 | /// \returns A location if one is available for \a RegNum, or std::nullopt |
||
191 | /// otherwise. |
||
192 | std::optional<UnwindLocation> getRegisterLocation(uint32_t RegNum) const { |
||
193 | auto Pos = Locations.find(RegNum); |
||
194 | if (Pos == Locations.end()) |
||
195 | return std::nullopt; |
||
196 | return Pos->second; |
||
197 | } |
||
198 | |||
199 | /// Set the location for the register in \a RegNum to \a Location. |
||
200 | /// |
||
201 | /// \param RegNum the register number to set the location for. |
||
202 | /// |
||
203 | /// \param Location the UnwindLocation that describes how to unwind the value. |
||
204 | void setRegisterLocation(uint32_t RegNum, const UnwindLocation &Location) { |
||
205 | Locations.erase(RegNum); |
||
206 | Locations.insert(std::make_pair(RegNum, Location)); |
||
207 | } |
||
208 | |||
209 | /// Removes any rule for the register in \a RegNum. |
||
210 | /// |
||
211 | /// \param RegNum the register number to remove the location for. |
||
212 | void removeRegisterLocation(uint32_t RegNum) { Locations.erase(RegNum); } |
||
213 | |||
214 | /// Dump all registers + locations that are currently defined in this object. |
||
215 | /// |
||
216 | /// \param OS the stream to use for output. |
||
217 | /// |
||
218 | /// \param MRI register information that helps emit register names insteead |
||
219 | /// of raw register numbers. |
||
220 | /// |
||
221 | /// \param IsEH true if the DWARF Call Frame Information is from .eh_frame |
||
222 | /// instead of from .debug_frame. This is needed for register number |
||
223 | /// conversion because some register numbers differ between the two sections |
||
224 | /// for certain architectures like x86. |
||
225 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const; |
||
226 | |||
227 | /// Returns true if we have any register locations in this object. |
||
228 | bool hasLocations() const { return !Locations.empty(); } |
||
229 | |||
230 | size_t size() const { return Locations.size(); } |
||
231 | |||
232 | bool operator==(const RegisterLocations &RHS) const { |
||
233 | return Locations == RHS.Locations; |
||
234 | } |
||
235 | }; |
||
236 | |||
237 | raw_ostream &operator<<(raw_ostream &OS, const RegisterLocations &RL); |
||
238 | |||
239 | /// A class that represents a single row in the unwind table that is decoded by |
||
240 | /// parsing the DWARF Call Frame Information opcodes. |
||
241 | /// |
||
242 | /// The row consists of an optional address, the rule to unwind the CFA and all |
||
243 | /// rules to unwind any registers. If the address doesn't have a value, this |
||
244 | /// row represents the initial instructions for a CIE. If the address has a |
||
245 | /// value the UnwindRow represents a row in the UnwindTable for a FDE. The |
||
246 | /// address is the first address for which the CFA location and register rules |
||
247 | /// are valid within a function. |
||
248 | /// |
||
249 | /// UnwindRow objects are created by parsing opcodes in the DWARF Call Frame |
||
250 | /// Information and UnwindRow objects are lazily populated and pushed onto a |
||
251 | /// stack in the UnwindTable when evaluating this state machine. Accessors are |
||
252 | /// needed for the address, CFA value, and register locations as the opcodes |
||
253 | /// encode a state machine that produces a sorted array of UnwindRow objects |
||
254 | /// \see UnwindTable. |
||
255 | class UnwindRow { |
||
256 | /// The address will be valid when parsing the instructions in a FDE. If |
||
257 | /// invalid, this object represents the initial instructions of a CIE. |
||
258 | std::optional<uint64_t> Address; ///< Address for row in FDE, invalid for CIE. |
||
259 | UnwindLocation CFAValue; ///< How to unwind the Call Frame Address (CFA). |
||
260 | RegisterLocations RegLocs; ///< How to unwind all registers in this list. |
||
261 | |||
262 | public: |
||
263 | UnwindRow() : CFAValue(UnwindLocation::createUnspecified()) {} |
||
264 | |||
265 | /// Returns true if the address is valid in this object. |
||
266 | bool hasAddress() const { return Address.has_value(); } |
||
267 | |||
268 | /// Get the address for this row. |
||
269 | /// |
||
270 | /// Clients should only call this function after verifying it has a valid |
||
271 | /// address with a call to \see hasAddress(). |
||
272 | uint64_t getAddress() const { return *Address; } |
||
273 | |||
274 | /// Set the address for this UnwindRow. |
||
275 | /// |
||
276 | /// The address represents the first address for which the CFAValue and |
||
277 | /// RegLocs are valid within a function. |
||
278 | void setAddress(uint64_t Addr) { Address = Addr; } |
||
279 | |||
280 | /// Offset the address for this UnwindRow. |
||
281 | /// |
||
282 | /// The address represents the first address for which the CFAValue and |
||
283 | /// RegLocs are valid within a function. Clients must ensure that this object |
||
284 | /// already has an address (\see hasAddress()) prior to calling this |
||
285 | /// function. |
||
286 | void slideAddress(uint64_t Offset) { *Address += Offset; } |
||
287 | UnwindLocation &getCFAValue() { return CFAValue; } |
||
288 | const UnwindLocation &getCFAValue() const { return CFAValue; } |
||
289 | RegisterLocations &getRegisterLocations() { return RegLocs; } |
||
290 | const RegisterLocations &getRegisterLocations() const { return RegLocs; } |
||
291 | |||
292 | /// Dump the UnwindRow to the stream. |
||
293 | /// |
||
294 | /// \param OS the stream to use for output. |
||
295 | /// |
||
296 | /// \param MRI register information that helps emit register names insteead |
||
297 | /// of raw register numbers. |
||
298 | /// |
||
299 | /// \param IsEH true if the DWARF Call Frame Information is from .eh_frame |
||
300 | /// instead of from .debug_frame. This is needed for register number |
||
301 | /// conversion because some register numbers differ between the two sections |
||
302 | /// for certain architectures like x86. |
||
303 | /// |
||
304 | /// \param IndentLevel specify the indent level as an integer. The UnwindRow |
||
305 | /// will be output to the stream preceded by 2 * IndentLevel number of spaces. |
||
306 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts, |
||
307 | unsigned IndentLevel = 0) const; |
||
308 | }; |
||
309 | |||
310 | raw_ostream &operator<<(raw_ostream &OS, const UnwindRow &Row); |
||
311 | |||
312 | class CFIProgram; |
||
313 | class CIE; |
||
314 | class FDE; |
||
315 | |||
316 | /// A class that contains all UnwindRow objects for an FDE or a single unwind |
||
317 | /// row for a CIE. To unwind an address the rows, which are sorted by start |
||
318 | /// address, can be searched to find the UnwindRow with the lowest starting |
||
319 | /// address that is greater than or equal to the address that is being looked |
||
320 | /// up. |
||
321 | class UnwindTable { |
||
322 | public: |
||
323 | using RowContainer = std::vector<UnwindRow>; |
||
324 | using iterator = RowContainer::iterator; |
||
325 | using const_iterator = RowContainer::const_iterator; |
||
326 | |||
327 | size_t size() const { return Rows.size(); } |
||
328 | iterator begin() { return Rows.begin(); } |
||
329 | const_iterator begin() const { return Rows.begin(); } |
||
330 | iterator end() { return Rows.end(); } |
||
331 | const_iterator end() const { return Rows.end(); } |
||
332 | const UnwindRow &operator[](size_t Index) const { |
||
333 | assert(Index < size()); |
||
334 | return Rows[Index]; |
||
335 | } |
||
336 | |||
337 | /// Dump the UnwindTable to the stream. |
||
338 | /// |
||
339 | /// \param OS the stream to use for output. |
||
340 | /// |
||
341 | /// \param MRI register information that helps emit register names insteead |
||
342 | /// of raw register numbers. |
||
343 | /// |
||
344 | /// \param IsEH true if the DWARF Call Frame Information is from .eh_frame |
||
345 | /// instead of from .debug_frame. This is needed for register number |
||
346 | /// conversion because some register numbers differ between the two sections |
||
347 | /// for certain architectures like x86. |
||
348 | /// |
||
349 | /// \param IndentLevel specify the indent level as an integer. The UnwindRow |
||
350 | /// will be output to the stream preceded by 2 * IndentLevel number of spaces. |
||
351 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts, |
||
352 | unsigned IndentLevel = 0) const; |
||
353 | |||
354 | /// Create an UnwindTable from a Common Information Entry (CIE). |
||
355 | /// |
||
356 | /// \param Cie The Common Information Entry to extract the table from. The |
||
357 | /// CFIProgram is retrieved from the \a Cie object and used to create the |
||
358 | /// UnwindTable. |
||
359 | /// |
||
360 | /// \returns An error if the DWARF Call Frame Information opcodes have state |
||
361 | /// machine errors, or a valid UnwindTable otherwise. |
||
362 | static Expected<UnwindTable> create(const CIE *Cie); |
||
363 | |||
364 | /// Create an UnwindTable from a Frame Descriptor Entry (FDE). |
||
365 | /// |
||
366 | /// \param Fde The Frame Descriptor Entry to extract the table from. The |
||
367 | /// CFIProgram is retrieved from the \a Fde object and used to create the |
||
368 | /// UnwindTable. |
||
369 | /// |
||
370 | /// \returns An error if the DWARF Call Frame Information opcodes have state |
||
371 | /// machine errors, or a valid UnwindTable otherwise. |
||
372 | static Expected<UnwindTable> create(const FDE *Fde); |
||
373 | |||
374 | private: |
||
375 | RowContainer Rows; |
||
376 | /// The end address when data is extracted from a FDE. This value will be |
||
377 | /// invalid when a UnwindTable is extracted from a CIE. |
||
378 | std::optional<uint64_t> EndAddress; |
||
379 | |||
380 | /// Parse the information in the CFIProgram and update the CurrRow object |
||
381 | /// that the state machine describes. |
||
382 | /// |
||
383 | /// This is an internal implementation that emulates the state machine |
||
384 | /// described in the DWARF Call Frame Information opcodes and will push |
||
385 | /// CurrRow onto the Rows container when needed. |
||
386 | /// |
||
387 | /// \param CFIP the CFI program that contains the opcodes from a CIE or FDE. |
||
388 | /// |
||
389 | /// \param CurrRow the current row to modify while parsing the state machine. |
||
390 | /// |
||
391 | /// \param InitialLocs If non-NULL, we are parsing a FDE and this contains |
||
392 | /// the initial register locations from the CIE. If NULL, then a CIE's |
||
393 | /// opcodes are being parsed and this is not needed. This is used for the |
||
394 | /// DW_CFA_restore and DW_CFA_restore_extended opcodes. |
||
395 | Error parseRows(const CFIProgram &CFIP, UnwindRow &CurrRow, |
||
396 | const RegisterLocations *InitialLocs); |
||
397 | }; |
||
398 | |||
399 | raw_ostream &operator<<(raw_ostream &OS, const UnwindTable &Rows); |
||
400 | |||
401 | /// Represent a sequence of Call Frame Information instructions that, when read |
||
402 | /// in order, construct a table mapping PC to frame state. This can also be |
||
403 | /// referred to as "CFI rules" in DWARF literature to avoid confusion with |
||
404 | /// computer programs in the broader sense, and in this context each instruction |
||
405 | /// would be a rule to establish the mapping. Refer to pg. 172 in the DWARF5 |
||
406 | /// manual, "6.4.1 Structure of Call Frame Information". |
||
407 | class CFIProgram { |
||
408 | public: |
||
409 | static constexpr size_t MaxOperands = 3; |
||
410 | typedef SmallVector<uint64_t, MaxOperands> Operands; |
||
411 | |||
412 | /// An instruction consists of a DWARF CFI opcode and an optional sequence of |
||
413 | /// operands. If it refers to an expression, then this expression has its own |
||
414 | /// sequence of operations and operands handled separately by DWARFExpression. |
||
415 | struct Instruction { |
||
416 | Instruction(uint8_t Opcode) : Opcode(Opcode) {} |
||
417 | |||
418 | uint8_t Opcode; |
||
419 | Operands Ops; |
||
420 | // Associated DWARF expression in case this instruction refers to one |
||
421 | std::optional<DWARFExpression> Expression; |
||
422 | |||
423 | Expected<uint64_t> getOperandAsUnsigned(const CFIProgram &CFIP, |
||
424 | uint32_t OperandIdx) const; |
||
425 | |||
426 | Expected<int64_t> getOperandAsSigned(const CFIProgram &CFIP, |
||
427 | uint32_t OperandIdx) const; |
||
428 | }; |
||
429 | |||
430 | using InstrList = std::vector<Instruction>; |
||
431 | using iterator = InstrList::iterator; |
||
432 | using const_iterator = InstrList::const_iterator; |
||
433 | |||
434 | iterator begin() { return Instructions.begin(); } |
||
435 | const_iterator begin() const { return Instructions.begin(); } |
||
436 | iterator end() { return Instructions.end(); } |
||
437 | const_iterator end() const { return Instructions.end(); } |
||
438 | |||
439 | unsigned size() const { return (unsigned)Instructions.size(); } |
||
440 | bool empty() const { return Instructions.empty(); } |
||
441 | uint64_t codeAlign() const { return CodeAlignmentFactor; } |
||
442 | int64_t dataAlign() const { return DataAlignmentFactor; } |
||
443 | Triple::ArchType triple() const { return Arch; } |
||
444 | |||
445 | CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor, |
||
446 | Triple::ArchType Arch) |
||
447 | : CodeAlignmentFactor(CodeAlignmentFactor), |
||
448 | DataAlignmentFactor(DataAlignmentFactor), |
||
449 | Arch(Arch) {} |
||
450 | |||
451 | /// Parse and store a sequence of CFI instructions from Data, |
||
452 | /// starting at *Offset and ending at EndOffset. *Offset is updated |
||
453 | /// to EndOffset upon successful parsing, or indicates the offset |
||
454 | /// where a problem occurred in case an error is returned. |
||
455 | Error parse(DWARFDataExtractor Data, uint64_t *Offset, uint64_t EndOffset); |
||
456 | |||
457 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts, |
||
458 | unsigned IndentLevel = 1) const; |
||
459 | |||
460 | void addInstruction(const Instruction &I) { Instructions.push_back(I); } |
||
461 | |||
462 | /// Get a DWARF CFI call frame string for the given DW_CFA opcode. |
||
463 | StringRef callFrameString(unsigned Opcode) const; |
||
464 | |||
465 | private: |
||
466 | std::vector<Instruction> Instructions; |
||
467 | const uint64_t CodeAlignmentFactor; |
||
468 | const int64_t DataAlignmentFactor; |
||
469 | Triple::ArchType Arch; |
||
470 | |||
471 | /// Convenience method to add a new instruction with the given opcode. |
||
472 | void addInstruction(uint8_t Opcode) { |
||
473 | Instructions.push_back(Instruction(Opcode)); |
||
474 | } |
||
475 | |||
476 | /// Add a new single-operand instruction. |
||
477 | void addInstruction(uint8_t Opcode, uint64_t Operand1) { |
||
478 | Instructions.push_back(Instruction(Opcode)); |
||
479 | Instructions.back().Ops.push_back(Operand1); |
||
480 | } |
||
481 | |||
482 | /// Add a new instruction that has two operands. |
||
483 | void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) { |
||
484 | Instructions.push_back(Instruction(Opcode)); |
||
485 | Instructions.back().Ops.push_back(Operand1); |
||
486 | Instructions.back().Ops.push_back(Operand2); |
||
487 | } |
||
488 | |||
489 | /// Add a new instruction that has three operands. |
||
490 | void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2, |
||
491 | uint64_t Operand3) { |
||
492 | Instructions.push_back(Instruction(Opcode)); |
||
493 | Instructions.back().Ops.push_back(Operand1); |
||
494 | Instructions.back().Ops.push_back(Operand2); |
||
495 | Instructions.back().Ops.push_back(Operand3); |
||
496 | } |
||
497 | |||
498 | /// Types of operands to CFI instructions |
||
499 | /// In DWARF, this type is implicitly tied to a CFI instruction opcode and |
||
500 | /// thus this type doesn't need to be explictly written to the file (this is |
||
501 | /// not a DWARF encoding). The relationship of instrs to operand types can |
||
502 | /// be obtained from getOperandTypes() and is only used to simplify |
||
503 | /// instruction printing. |
||
504 | enum OperandType { |
||
505 | OT_Unset, |
||
506 | OT_None, |
||
507 | OT_Address, |
||
508 | OT_Offset, |
||
509 | OT_FactoredCodeOffset, |
||
510 | OT_SignedFactDataOffset, |
||
511 | OT_UnsignedFactDataOffset, |
||
512 | OT_Register, |
||
513 | OT_AddressSpace, |
||
514 | OT_Expression |
||
515 | }; |
||
516 | |||
517 | /// Get the OperandType as a "const char *". |
||
518 | static const char *operandTypeString(OperandType OT); |
||
519 | |||
520 | /// Retrieve the array describing the types of operands according to the enum |
||
521 | /// above. This is indexed by opcode. |
||
522 | static ArrayRef<OperandType[MaxOperands]> getOperandTypes(); |
||
523 | |||
524 | /// Print \p Opcode's operand number \p OperandIdx which has value \p Operand. |
||
525 | void printOperand(raw_ostream &OS, DIDumpOptions DumpOpts, |
||
526 | const Instruction &Instr, unsigned OperandIdx, |
||
527 | uint64_t Operand) const; |
||
528 | }; |
||
529 | |||
530 | /// An entry in either debug_frame or eh_frame. This entry can be a CIE or an |
||
531 | /// FDE. |
||
532 | class FrameEntry { |
||
533 | public: |
||
534 | enum FrameKind { FK_CIE, FK_FDE }; |
||
535 | |||
536 | FrameEntry(FrameKind K, bool IsDWARF64, uint64_t Offset, uint64_t Length, |
||
537 | uint64_t CodeAlign, int64_t DataAlign, Triple::ArchType Arch) |
||
538 | : Kind(K), IsDWARF64(IsDWARF64), Offset(Offset), Length(Length), |
||
539 | CFIs(CodeAlign, DataAlign, Arch) {} |
||
540 | |||
541 | virtual ~FrameEntry() = default; |
||
542 | |||
543 | FrameKind getKind() const { return Kind; } |
||
544 | uint64_t getOffset() const { return Offset; } |
||
545 | uint64_t getLength() const { return Length; } |
||
546 | const CFIProgram &cfis() const { return CFIs; } |
||
547 | CFIProgram &cfis() { return CFIs; } |
||
548 | |||
549 | /// Dump the instructions in this CFI fragment |
||
550 | virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const = 0; |
||
551 | |||
552 | protected: |
||
553 | const FrameKind Kind; |
||
554 | |||
555 | const bool IsDWARF64; |
||
556 | |||
557 | /// Offset of this entry in the section. |
||
558 | const uint64_t Offset; |
||
559 | |||
560 | /// Entry length as specified in DWARF. |
||
561 | const uint64_t Length; |
||
562 | |||
563 | CFIProgram CFIs; |
||
564 | }; |
||
565 | |||
566 | /// DWARF Common Information Entry (CIE) |
||
567 | class CIE : public FrameEntry { |
||
568 | public: |
||
569 | // CIEs (and FDEs) are simply container classes, so the only sensible way to |
||
570 | // create them is by providing the full parsed contents in the constructor. |
||
571 | CIE(bool IsDWARF64, uint64_t Offset, uint64_t Length, uint8_t Version, |
||
572 | SmallString<8> Augmentation, uint8_t AddressSize, |
||
573 | uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor, |
||
574 | int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister, |
||
575 | SmallString<8> AugmentationData, uint32_t FDEPointerEncoding, |
||
576 | uint32_t LSDAPointerEncoding, std::optional<uint64_t> Personality, |
||
577 | std::optional<uint32_t> PersonalityEnc, Triple::ArchType Arch) |
||
578 | : FrameEntry(FK_CIE, IsDWARF64, Offset, Length, CodeAlignmentFactor, |
||
579 | DataAlignmentFactor, Arch), |
||
580 | Version(Version), Augmentation(std::move(Augmentation)), |
||
581 | AddressSize(AddressSize), SegmentDescriptorSize(SegmentDescriptorSize), |
||
582 | CodeAlignmentFactor(CodeAlignmentFactor), |
||
583 | DataAlignmentFactor(DataAlignmentFactor), |
||
584 | ReturnAddressRegister(ReturnAddressRegister), |
||
585 | AugmentationData(std::move(AugmentationData)), |
||
586 | FDEPointerEncoding(FDEPointerEncoding), |
||
587 | LSDAPointerEncoding(LSDAPointerEncoding), Personality(Personality), |
||
588 | PersonalityEnc(PersonalityEnc) {} |
||
589 | |||
590 | static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_CIE; } |
||
591 | |||
592 | StringRef getAugmentationString() const { return Augmentation; } |
||
593 | uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; } |
||
594 | int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; } |
||
595 | uint8_t getVersion() const { return Version; } |
||
596 | uint64_t getReturnAddressRegister() const { return ReturnAddressRegister; } |
||
597 | std::optional<uint64_t> getPersonalityAddress() const { return Personality; } |
||
598 | std::optional<uint32_t> getPersonalityEncoding() const { |
||
599 | return PersonalityEnc; |
||
600 | } |
||
601 | |||
602 | StringRef getAugmentationData() const { return AugmentationData; } |
||
603 | |||
604 | uint32_t getFDEPointerEncoding() const { return FDEPointerEncoding; } |
||
605 | |||
606 | uint32_t getLSDAPointerEncoding() const { return LSDAPointerEncoding; } |
||
607 | |||
608 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const override; |
||
609 | |||
610 | private: |
||
611 | /// The following fields are defined in section 6.4.1 of the DWARF standard v4 |
||
612 | const uint8_t Version; |
||
613 | const SmallString<8> Augmentation; |
||
614 | const uint8_t AddressSize; |
||
615 | const uint8_t SegmentDescriptorSize; |
||
616 | const uint64_t CodeAlignmentFactor; |
||
617 | const int64_t DataAlignmentFactor; |
||
618 | const uint64_t ReturnAddressRegister; |
||
619 | |||
620 | // The following are used when the CIE represents an EH frame entry. |
||
621 | const SmallString<8> AugmentationData; |
||
622 | const uint32_t FDEPointerEncoding; |
||
623 | const uint32_t LSDAPointerEncoding; |
||
624 | const std::optional<uint64_t> Personality; |
||
625 | const std::optional<uint32_t> PersonalityEnc; |
||
626 | }; |
||
627 | |||
628 | /// DWARF Frame Description Entry (FDE) |
||
629 | class FDE : public FrameEntry { |
||
630 | public: |
||
631 | FDE(bool IsDWARF64, uint64_t Offset, uint64_t Length, uint64_t CIEPointer, |
||
632 | uint64_t InitialLocation, uint64_t AddressRange, CIE *Cie, |
||
633 | std::optional<uint64_t> LSDAAddress, Triple::ArchType Arch) |
||
634 | : FrameEntry(FK_FDE, IsDWARF64, Offset, Length, |
||
635 | Cie ? Cie->getCodeAlignmentFactor() : 0, |
||
636 | Cie ? Cie->getDataAlignmentFactor() : 0, Arch), |
||
637 | CIEPointer(CIEPointer), InitialLocation(InitialLocation), |
||
638 | AddressRange(AddressRange), LinkedCIE(Cie), LSDAAddress(LSDAAddress) {} |
||
639 | |||
640 | ~FDE() override = default; |
||
641 | |||
642 | const CIE *getLinkedCIE() const { return LinkedCIE; } |
||
643 | uint64_t getCIEPointer() const { return CIEPointer; } |
||
644 | uint64_t getInitialLocation() const { return InitialLocation; } |
||
645 | uint64_t getAddressRange() const { return AddressRange; } |
||
646 | std::optional<uint64_t> getLSDAAddress() const { return LSDAAddress; } |
||
647 | |||
648 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const override; |
||
649 | |||
650 | static bool classof(const FrameEntry *FE) { return FE->getKind() == FK_FDE; } |
||
651 | |||
652 | private: |
||
653 | /// The following fields are defined in section 6.4.1 of the DWARFv3 standard. |
||
654 | /// Note that CIE pointers in EH FDEs, unlike DWARF FDEs, contain relative |
||
655 | /// offsets to the linked CIEs. See the following link for more info: |
||
656 | /// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html |
||
657 | const uint64_t CIEPointer; |
||
658 | const uint64_t InitialLocation; |
||
659 | const uint64_t AddressRange; |
||
660 | const CIE *LinkedCIE; |
||
661 | const std::optional<uint64_t> LSDAAddress; |
||
662 | }; |
||
663 | |||
664 | } // end namespace dwarf |
||
665 | |||
666 | /// A parsed .debug_frame or .eh_frame section |
||
667 | class DWARFDebugFrame { |
||
668 | const Triple::ArchType Arch; |
||
669 | // True if this is parsing an eh_frame section. |
||
670 | const bool IsEH; |
||
671 | // Not zero for sane pointer values coming out of eh_frame |
||
672 | const uint64_t EHFrameAddress; |
||
673 | |||
674 | std::vector<std::unique_ptr<dwarf::FrameEntry>> Entries; |
||
675 | using iterator = pointee_iterator<decltype(Entries)::const_iterator>; |
||
676 | |||
677 | /// Return the entry at the given offset or nullptr. |
||
678 | dwarf::FrameEntry *getEntryAtOffset(uint64_t Offset) const; |
||
679 | |||
680 | public: |
||
681 | // If IsEH is true, assume it is a .eh_frame section. Otherwise, |
||
682 | // it is a .debug_frame section. EHFrameAddress should be different |
||
683 | // than zero for correct parsing of .eh_frame addresses when they |
||
684 | // use a PC-relative encoding. |
||
685 | DWARFDebugFrame(Triple::ArchType Arch, |
||
686 | bool IsEH = false, uint64_t EHFrameAddress = 0); |
||
687 | ~DWARFDebugFrame(); |
||
688 | |||
689 | /// Dump the section data into the given stream. |
||
690 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts, |
||
691 | std::optional<uint64_t> Offset) const; |
||
692 | |||
693 | /// Parse the section from raw data. \p Data is assumed to contain the whole |
||
694 | /// frame section contents to be parsed. |
||
695 | Error parse(DWARFDataExtractor Data); |
||
696 | |||
697 | /// Return whether the section has any entries. |
||
698 | bool empty() const { return Entries.empty(); } |
||
699 | |||
700 | /// DWARF Frame entries accessors |
||
701 | iterator begin() const { return Entries.begin(); } |
||
702 | iterator end() const { return Entries.end(); } |
||
703 | iterator_range<iterator> entries() const { |
||
704 | return iterator_range<iterator>(Entries.begin(), Entries.end()); |
||
705 | } |
||
706 | |||
707 | uint64_t getEHFrameAddress() const { return EHFrameAddress; } |
||
708 | }; |
||
709 | |||
710 | } // end namespace llvm |
||
711 | |||
712 | #endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGFRAME_H |