xref: /freebsd/contrib/llvm-project/lldb/include/lldb/Symbol/UnwindPlan.h (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
1 //===-- UnwindPlan.h --------------------------------------------*- 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 LLDB_SYMBOL_UNWINDPLAN_H
10 #define LLDB_SYMBOL_UNWINDPLAN_H
11 
12 #include <map>
13 #include <memory>
14 #include <vector>
15 
16 #include "lldb/Core/AddressRange.h"
17 #include "lldb/Utility/ConstString.h"
18 #include "lldb/Utility/Stream.h"
19 #include "lldb/lldb-private.h"
20 
21 namespace lldb_private {
22 
23 // The UnwindPlan object specifies how to unwind out of a function - where this
24 // function saves the caller's register values before modifying them (for non-
25 // volatile aka saved registers) and how to find this frame's Canonical Frame
26 // Address (CFA) or Aligned Frame Address (AFA).
27 
28 // CFA is a DWARF's Canonical Frame Address.
29 // Most commonly, registers are saved on the stack, offset some bytes from the
30 // Canonical Frame Address, or CFA, which is the starting address of this
31 // function's stack frame (the CFA is same as the eh_frame's CFA, whatever that
32 // may be on a given architecture). The CFA address for the stack frame does
33 // not change during the lifetime of the function.
34 
35 // AFA is an artificially introduced Aligned Frame Address.
36 // It is used only for stack frames with realignment (e.g. when some of the
37 // locals has an alignment requirement higher than the stack alignment right
38 // after the function call). It is used to access register values saved on the
39 // stack after the realignment (and so they are inaccessible through the CFA).
40 // AFA usually equals the stack pointer value right after the realignment.
41 
42 // Internally, the UnwindPlan is structured as a vector of register locations
43 // organized by code address in the function, showing which registers have been
44 // saved at that point and where they are saved. It can be thought of as the
45 // expanded table form of the DWARF CFI encoded information.
46 
47 // Other unwind information sources will be converted into UnwindPlans before
48 // being added to a FuncUnwinders object.  The unwind source may be an eh_frame
49 // FDE, a DWARF debug_frame FDE, or assembly language based prologue analysis.
50 // The UnwindPlan is the canonical form of this information that the unwinder
51 // code will use when walking the stack.
52 
53 class UnwindPlan {
54 public:
55   class Row {
56   public:
57     class RegisterLocation {
58     public:
59       enum RestoreType {
60         unspecified,       // not specified, we may be able to assume this
61                            // is the same register. gcc doesn't specify all
62                            // initial values so we really don't know...
63         undefined,         // reg is not available, e.g. volatile reg
64         same,              // reg is unchanged
65         atCFAPlusOffset,   // reg = deref(CFA + offset)
66         isCFAPlusOffset,   // reg = CFA + offset
67         atAFAPlusOffset,   // reg = deref(AFA + offset)
68         isAFAPlusOffset,   // reg = AFA + offset
69         inOtherRegister,   // reg = other reg
70         atDWARFExpression, // reg = deref(eval(dwarf_expr))
71         isDWARFExpression  // reg = eval(dwarf_expr)
72       };
73 
RegisterLocation()74       RegisterLocation() : m_location() {}
75 
76       bool operator==(const RegisterLocation &rhs) const;
77 
78       bool operator!=(const RegisterLocation &rhs) const {
79         return !(*this == rhs);
80       }
81 
SetUnspecified()82       void SetUnspecified() { m_type = unspecified; }
83 
SetUndefined()84       void SetUndefined() { m_type = undefined; }
85 
SetSame()86       void SetSame() { m_type = same; }
87 
IsSame()88       bool IsSame() const { return m_type == same; }
89 
IsUnspecified()90       bool IsUnspecified() const { return m_type == unspecified; }
91 
IsUndefined()92       bool IsUndefined() const { return m_type == undefined; }
93 
IsCFAPlusOffset()94       bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; }
95 
IsAtCFAPlusOffset()96       bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; }
97 
IsAFAPlusOffset()98       bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; }
99 
IsAtAFAPlusOffset()100       bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; }
101 
IsInOtherRegister()102       bool IsInOtherRegister() const { return m_type == inOtherRegister; }
103 
IsAtDWARFExpression()104       bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
105 
IsDWARFExpression()106       bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
107 
SetAtCFAPlusOffset(int32_t offset)108       void SetAtCFAPlusOffset(int32_t offset) {
109         m_type = atCFAPlusOffset;
110         m_location.offset = offset;
111       }
112 
SetIsCFAPlusOffset(int32_t offset)113       void SetIsCFAPlusOffset(int32_t offset) {
114         m_type = isCFAPlusOffset;
115         m_location.offset = offset;
116       }
117 
SetAtAFAPlusOffset(int32_t offset)118       void SetAtAFAPlusOffset(int32_t offset) {
119         m_type = atAFAPlusOffset;
120         m_location.offset = offset;
121       }
122 
SetIsAFAPlusOffset(int32_t offset)123       void SetIsAFAPlusOffset(int32_t offset) {
124         m_type = isAFAPlusOffset;
125         m_location.offset = offset;
126       }
127 
SetInRegister(uint32_t reg_num)128       void SetInRegister(uint32_t reg_num) {
129         m_type = inOtherRegister;
130         m_location.reg_num = reg_num;
131       }
132 
GetRegisterNumber()133       uint32_t GetRegisterNumber() const {
134         if (m_type == inOtherRegister)
135           return m_location.reg_num;
136         return LLDB_INVALID_REGNUM;
137       }
138 
GetLocationType()139       RestoreType GetLocationType() const { return m_type; }
140 
GetOffset()141       int32_t GetOffset() const {
142         switch(m_type)
143         {
144         case atCFAPlusOffset:
145         case isCFAPlusOffset:
146         case atAFAPlusOffset:
147         case isAFAPlusOffset:
148           return m_location.offset;
149         default:
150           return 0;
151         }
152       }
153 
GetDWARFExpr(const uint8_t ** opcodes,uint16_t & len)154       void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
155         if (m_type == atDWARFExpression || m_type == isDWARFExpression) {
156           *opcodes = m_location.expr.opcodes;
157           len = m_location.expr.length;
158         } else {
159           *opcodes = nullptr;
160           len = 0;
161         }
162       }
163 
164       void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len);
165 
166       void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len);
167 
GetDWARFExpressionBytes()168       const uint8_t *GetDWARFExpressionBytes() {
169         if (m_type == atDWARFExpression || m_type == isDWARFExpression)
170           return m_location.expr.opcodes;
171         return nullptr;
172       }
173 
GetDWARFExpressionLength()174       int GetDWARFExpressionLength() {
175         if (m_type == atDWARFExpression || m_type == isDWARFExpression)
176           return m_location.expr.length;
177         return 0;
178       }
179 
180       void Dump(Stream &s, const UnwindPlan *unwind_plan,
181                 const UnwindPlan::Row *row, Thread *thread, bool verbose) const;
182 
183     private:
184       RestoreType m_type = unspecified; // How do we locate this register?
185       union {
186         // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset
187         int32_t offset;
188         // For m_type == inOtherRegister
189         uint32_t reg_num; // The register number
190         // For m_type == atDWARFExpression or m_type == isDWARFExpression
191         struct {
192           const uint8_t *opcodes;
193           uint16_t length;
194         } expr;
195       } m_location;
196     };
197 
198     class FAValue {
199     public:
200       enum ValueType {
201         unspecified,            // not specified
202         isRegisterPlusOffset,   // FA = register + offset
203         isRegisterDereferenced, // FA = [reg]
204         isDWARFExpression,      // FA = eval(dwarf_expr)
205         isRaSearch,             // FA = SP + offset + ???
206       };
207 
FAValue()208       FAValue() : m_value() {}
209 
210       bool operator==(const FAValue &rhs) const;
211 
212       bool operator!=(const FAValue &rhs) const { return !(*this == rhs); }
213 
SetUnspecified()214       void SetUnspecified() { m_type = unspecified; }
215 
IsUnspecified()216       bool IsUnspecified() const { return m_type == unspecified; }
217 
SetRaSearch(int32_t offset)218       void SetRaSearch(int32_t offset) {
219         m_type = isRaSearch;
220         m_value.ra_search_offset = offset;
221       }
222 
IsRegisterPlusOffset()223       bool IsRegisterPlusOffset() const {
224         return m_type == isRegisterPlusOffset;
225       }
226 
SetIsRegisterPlusOffset(uint32_t reg_num,int32_t offset)227       void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) {
228         m_type = isRegisterPlusOffset;
229         m_value.reg.reg_num = reg_num;
230         m_value.reg.offset = offset;
231       }
232 
IsRegisterDereferenced()233       bool IsRegisterDereferenced() const {
234         return m_type == isRegisterDereferenced;
235       }
236 
SetIsRegisterDereferenced(uint32_t reg_num)237       void SetIsRegisterDereferenced(uint32_t reg_num) {
238         m_type = isRegisterDereferenced;
239         m_value.reg.reg_num = reg_num;
240       }
241 
IsDWARFExpression()242       bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
243 
SetIsDWARFExpression(const uint8_t * opcodes,uint32_t len)244       void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) {
245         m_type = isDWARFExpression;
246         m_value.expr.opcodes = opcodes;
247         m_value.expr.length = len;
248       }
249 
GetRegisterNumber()250       uint32_t GetRegisterNumber() const {
251         if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset)
252           return m_value.reg.reg_num;
253         return LLDB_INVALID_REGNUM;
254       }
255 
GetValueType()256       ValueType GetValueType() const { return m_type; }
257 
GetOffset()258       int32_t GetOffset() const {
259         switch (m_type) {
260           case isRegisterPlusOffset:
261             return m_value.reg.offset;
262           case isRaSearch:
263             return m_value.ra_search_offset;
264           default:
265             return 0;
266         }
267       }
268 
IncOffset(int32_t delta)269       void IncOffset(int32_t delta) {
270         if (m_type == isRegisterPlusOffset)
271           m_value.reg.offset += delta;
272       }
273 
SetOffset(int32_t offset)274       void SetOffset(int32_t offset) {
275         if (m_type == isRegisterPlusOffset)
276           m_value.reg.offset = offset;
277       }
278 
GetDWARFExpr(const uint8_t ** opcodes,uint16_t & len)279       void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
280         if (m_type == isDWARFExpression) {
281           *opcodes = m_value.expr.opcodes;
282           len = m_value.expr.length;
283         } else {
284           *opcodes = nullptr;
285           len = 0;
286         }
287       }
288 
GetDWARFExpressionBytes()289       const uint8_t *GetDWARFExpressionBytes() {
290         if (m_type == isDWARFExpression)
291           return m_value.expr.opcodes;
292         return nullptr;
293       }
294 
GetDWARFExpressionLength()295       int GetDWARFExpressionLength() {
296         if (m_type == isDWARFExpression)
297           return m_value.expr.length;
298         return 0;
299       }
300 
301       void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const;
302 
303     private:
304       ValueType m_type = unspecified; // How do we compute CFA value?
305       union {
306         struct {
307           // For m_type == isRegisterPlusOffset or m_type ==
308           // isRegisterDereferenced
309           uint32_t reg_num; // The register number
310           // For m_type == isRegisterPlusOffset
311           int32_t offset;
312         } reg;
313         // For m_type == isDWARFExpression
314         struct {
315           const uint8_t *opcodes;
316           uint16_t length;
317         } expr;
318         // For m_type == isRaSearch
319         int32_t ra_search_offset;
320       } m_value;
321     }; // class FAValue
322 
323     Row();
324 
325     bool operator==(const Row &rhs) const;
326 
327     bool GetRegisterInfo(uint32_t reg_num,
328                          RegisterLocation &register_location) const;
329 
330     void SetRegisterInfo(uint32_t reg_num,
331                          const RegisterLocation register_location);
332 
333     void RemoveRegisterInfo(uint32_t reg_num);
334 
GetOffset()335     lldb::addr_t GetOffset() const { return m_offset; }
336 
SetOffset(lldb::addr_t offset)337     void SetOffset(lldb::addr_t offset) { m_offset = offset; }
338 
SlideOffset(lldb::addr_t offset)339     void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
340 
GetCFAValue()341     FAValue &GetCFAValue() { return m_cfa_value; }
342 
GetAFAValue()343     FAValue &GetAFAValue() { return m_afa_value; }
344 
345     bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset,
346                                               bool can_replace);
347 
348     bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset,
349                                               bool can_replace);
350 
351     bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace,
352                                         bool can_replace_only_if_unspecified);
353 
354     bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace);
355 
356     bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num,
357                                        bool can_replace);
358 
359     bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
360 
361     // When this UnspecifiedRegistersAreUndefined mode is
362     // set, any register that is not specified by this Row will
363     // be described as Undefined.
364     // This will prevent the unwinder from iterating down the
365     // stack looking for a spill location, or a live register value
366     // at frame 0.
367     // It would be used for an UnwindPlan row where we can't track
368     // spilled registers -- for instance a jitted stack frame where
369     // we have no unwind information or start address -- and registers
370     // MAY have been spilled and overwritten, so providing the
371     // spilled/live value from a newer frame may show an incorrect value.
SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef)372     void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef) {
373       m_unspecified_registers_are_undefined = unspec_is_undef;
374     }
375 
GetUnspecifiedRegistersAreUndefined()376     bool GetUnspecifiedRegistersAreUndefined() {
377       return m_unspecified_registers_are_undefined;
378     }
379 
380     void Clear();
381 
382     void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread,
383               lldb::addr_t base_addr) const;
384 
385   protected:
386     typedef std::map<uint32_t, RegisterLocation> collection;
387     lldb::addr_t m_offset = 0; // Offset into the function for this row
388 
389     FAValue m_cfa_value;
390     FAValue m_afa_value;
391     collection m_register_locations;
392     bool m_unspecified_registers_are_undefined = false;
393   }; // class Row
394 
395   typedef std::shared_ptr<Row> RowSP;
396 
UnwindPlan(lldb::RegisterKind reg_kind)397   UnwindPlan(lldb::RegisterKind reg_kind)
398       : m_register_kind(reg_kind), m_return_addr_register(LLDB_INVALID_REGNUM),
399         m_plan_is_sourced_from_compiler(eLazyBoolCalculate),
400         m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate),
401         m_plan_is_for_signal_trap(eLazyBoolCalculate) {}
402 
403   // Performs a deep copy of the plan, including all the rows (expensive).
UnwindPlan(const UnwindPlan & rhs)404   UnwindPlan(const UnwindPlan &rhs)
405       : m_plan_valid_address_range(rhs.m_plan_valid_address_range),
406         m_register_kind(rhs.m_register_kind),
407         m_return_addr_register(rhs.m_return_addr_register),
408         m_source_name(rhs.m_source_name),
409         m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler),
410         m_plan_is_valid_at_all_instruction_locations(
411             rhs.m_plan_is_valid_at_all_instruction_locations),
412         m_plan_is_for_signal_trap(rhs.m_plan_is_for_signal_trap),
413         m_lsda_address(rhs.m_lsda_address),
414         m_personality_func_addr(rhs.m_personality_func_addr) {
415     m_row_list.reserve(rhs.m_row_list.size());
416     for (const RowSP &row_sp : rhs.m_row_list)
417       m_row_list.emplace_back(new Row(*row_sp));
418   }
419 
420   ~UnwindPlan() = default;
421 
422   void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const;
423 
424   void AppendRow(const RowSP &row_sp);
425 
426   void InsertRow(const RowSP &row_sp, bool replace_existing = false);
427 
428   // Returns a pointer to the best row for the given offset into the function's
429   // instructions. If offset is -1 it indicates that the function start is
430   // unknown - the final row in the UnwindPlan is returned. In practice, the
431   // UnwindPlan for a function with no known start address will be the
432   // architectural default UnwindPlan which will only have one row.
433   UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const;
434 
GetRegisterKind()435   lldb::RegisterKind GetRegisterKind() const { return m_register_kind; }
436 
SetRegisterKind(lldb::RegisterKind kind)437   void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; }
438 
SetReturnAddressRegister(uint32_t regnum)439   void SetReturnAddressRegister(uint32_t regnum) {
440     m_return_addr_register = regnum;
441   }
442 
GetReturnAddressRegister()443   uint32_t GetReturnAddressRegister() { return m_return_addr_register; }
444 
GetInitialCFARegister()445   uint32_t GetInitialCFARegister() const {
446     if (m_row_list.empty())
447       return LLDB_INVALID_REGNUM;
448     return m_row_list.front()->GetCFAValue().GetRegisterNumber();
449   }
450 
451   // This UnwindPlan may not be valid at every address of the function span.
452   // For instance, a FastUnwindPlan will not be valid at the prologue setup
453   // instructions - only in the body of the function.
454   void SetPlanValidAddressRange(const AddressRange &range);
455 
GetAddressRange()456   const AddressRange &GetAddressRange() const {
457     return m_plan_valid_address_range;
458   }
459 
460   bool PlanValidAtAddress(Address addr);
461 
462   bool IsValidRowIndex(uint32_t idx) const;
463 
464   const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const;
465 
466   const UnwindPlan::RowSP GetLastRow() const;
467 
468   lldb_private::ConstString GetSourceName() const;
469 
470   void SetSourceName(const char *);
471 
472   // Was this UnwindPlan emitted by a compiler?
GetSourcedFromCompiler()473   lldb_private::LazyBool GetSourcedFromCompiler() const {
474     return m_plan_is_sourced_from_compiler;
475   }
476 
477   // Was this UnwindPlan emitted by a compiler?
SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)478   void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) {
479     m_plan_is_sourced_from_compiler = from_compiler;
480   }
481 
482   // Is this UnwindPlan valid at all instructions?  If not, then it is assumed
483   // valid at call sites, e.g. for exception handling.
GetUnwindPlanValidAtAllInstructions()484   lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const {
485     return m_plan_is_valid_at_all_instruction_locations;
486   }
487 
488   // Is this UnwindPlan valid at all instructions?  If not, then it is assumed
489   // valid at call sites, e.g. for exception handling.
SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)490   void SetUnwindPlanValidAtAllInstructions(
491       lldb_private::LazyBool valid_at_all_insn) {
492     m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
493   }
494 
495   // Is this UnwindPlan for a signal trap frame?  If so, then its saved pc
496   // may have been set manually by the signal dispatch code and therefore
497   // not follow a call to the child frame.
GetUnwindPlanForSignalTrap()498   lldb_private::LazyBool GetUnwindPlanForSignalTrap() const {
499     return m_plan_is_for_signal_trap;
500   }
501 
SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap)502   void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap) {
503     m_plan_is_for_signal_trap = is_for_signal_trap;
504   }
505 
506   int GetRowCount() const;
507 
Clear()508   void Clear() {
509     m_row_list.clear();
510     m_plan_valid_address_range.Clear();
511     m_register_kind = lldb::eRegisterKindDWARF;
512     m_source_name.Clear();
513     m_plan_is_sourced_from_compiler = eLazyBoolCalculate;
514     m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate;
515     m_plan_is_for_signal_trap = eLazyBoolCalculate;
516     m_lsda_address.Clear();
517     m_personality_func_addr.Clear();
518   }
519 
520   const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const;
521 
GetLSDAAddress()522   Address GetLSDAAddress() const { return m_lsda_address; }
523 
SetLSDAAddress(Address lsda_addr)524   void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; }
525 
GetPersonalityFunctionPtr()526   Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; }
527 
SetPersonalityFunctionPtr(Address presonality_func_ptr)528   void SetPersonalityFunctionPtr(Address presonality_func_ptr) {
529     m_personality_func_addr = presonality_func_ptr;
530   }
531 
532 private:
533   typedef std::vector<RowSP> collection;
534   collection m_row_list;
535   AddressRange m_plan_valid_address_range;
536   lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers
537                                       // are in terms of - will need to be
538   // translated to lldb native reg nums at unwind time
539   uint32_t m_return_addr_register; // The register that has the return address
540                                    // for the caller frame
541                                    // e.g. the lr on arm
542   lldb_private::ConstString
543       m_source_name; // for logging, where this UnwindPlan originated from
544   lldb_private::LazyBool m_plan_is_sourced_from_compiler;
545   lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
546   lldb_private::LazyBool m_plan_is_for_signal_trap;
547 
548   Address m_lsda_address; // Where the language specific data area exists in the
549                           // module - used
550                           // in exception handling.
551   Address m_personality_func_addr; // The address of a pointer to the
552                                    // personality function - used in
553                                    // exception handling.
554 };                                 // class UnwindPlan
555 
556 } // namespace lldb_private
557 
558 #endif // LLDB_SYMBOL_UNWINDPLAN_H
559