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 liblldb_UnwindPlan_h
10#define liblldb_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
21namespace 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
53class UnwindPlan {
54public:
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
74      RegisterLocation() : m_type(unspecified), m_location() {}
75
76      bool operator==(const RegisterLocation &rhs) const;
77
78      bool operator!=(const RegisterLocation &rhs) const {
79        return !(*this == rhs);
80      }
81
82      void SetUnspecified() { m_type = unspecified; }
83
84      void SetUndefined() { m_type = undefined; }
85
86      void SetSame() { m_type = same; }
87
88      bool IsSame() const { return m_type == same; }
89
90      bool IsUnspecified() const { return m_type == unspecified; }
91
92      bool IsUndefined() const { return m_type == undefined; }
93
94      bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; }
95
96      bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; }
97
98      bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; }
99
100      bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; }
101
102      bool IsInOtherRegister() const { return m_type == inOtherRegister; }
103
104      bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
105
106      bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
107
108      void SetAtCFAPlusOffset(int32_t offset) {
109        m_type = atCFAPlusOffset;
110        m_location.offset = offset;
111      }
112
113      void SetIsCFAPlusOffset(int32_t offset) {
114        m_type = isCFAPlusOffset;
115        m_location.offset = offset;
116      }
117
118      void SetAtAFAPlusOffset(int32_t offset) {
119        m_type = atAFAPlusOffset;
120        m_location.offset = offset;
121      }
122
123      void SetIsAFAPlusOffset(int32_t offset) {
124        m_type = isAFAPlusOffset;
125        m_location.offset = offset;
126      }
127
128      void SetInRegister(uint32_t reg_num) {
129        m_type = inOtherRegister;
130        m_location.reg_num = reg_num;
131      }
132
133      uint32_t GetRegisterNumber() const {
134        if (m_type == inOtherRegister)
135          return m_location.reg_num;
136        return LLDB_INVALID_REGNUM;
137      }
138
139      RestoreType GetLocationType() const { return m_type; }
140
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
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
168      const uint8_t *GetDWARFExpressionBytes() {
169        if (m_type == atDWARFExpression || m_type == isDWARFExpression)
170          return m_location.expr.opcodes;
171        return nullptr;
172      }
173
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; // 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
208      FAValue() : m_type(unspecified), m_value() {}
209
210      bool operator==(const FAValue &rhs) const;
211
212      bool operator!=(const FAValue &rhs) const { return !(*this == rhs); }
213
214      void SetUnspecified() { m_type = unspecified; }
215
216      bool IsUnspecified() const { return m_type == unspecified; }
217
218      void SetRaSearch(int32_t offset) {
219        m_type = isRaSearch;
220        m_value.ra_search_offset = offset;
221      }
222
223      bool IsRegisterPlusOffset() const {
224        return m_type == isRegisterPlusOffset;
225      }
226
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
233      bool IsRegisterDereferenced() const {
234        return m_type == isRegisterDereferenced;
235      }
236
237      void SetIsRegisterDereferenced(uint32_t reg_num) {
238        m_type = isRegisterDereferenced;
239        m_value.reg.reg_num = reg_num;
240      }
241
242      bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
243
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
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
256      ValueType GetValueType() const { return m_type; }
257
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
269      void IncOffset(int32_t delta) {
270        if (m_type == isRegisterPlusOffset)
271          m_value.reg.offset += delta;
272      }
273
274      void SetOffset(int32_t offset) {
275        if (m_type == isRegisterPlusOffset)
276          m_value.reg.offset = offset;
277      }
278
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
289      const uint8_t *GetDWARFExpressionBytes() {
290        if (m_type == isDWARFExpression)
291          return m_value.expr.opcodes;
292        return nullptr;
293      }
294
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; // 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  public:
324    Row();
325
326    Row(const UnwindPlan::Row &rhs) = default;
327
328    bool operator==(const Row &rhs) const;
329
330    bool GetRegisterInfo(uint32_t reg_num,
331                         RegisterLocation &register_location) const;
332
333    void SetRegisterInfo(uint32_t reg_num,
334                         const RegisterLocation register_location);
335
336    void RemoveRegisterInfo(uint32_t reg_num);
337
338    lldb::addr_t GetOffset() const { return m_offset; }
339
340    void SetOffset(lldb::addr_t offset) { m_offset = offset; }
341
342    void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
343
344    FAValue &GetCFAValue() { return m_cfa_value; }
345
346    FAValue &GetAFAValue() { return m_afa_value; }
347
348    bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset,
349                                              bool can_replace);
350
351    bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset,
352                                              bool can_replace);
353
354    bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace,
355                                        bool can_replace_only_if_unspecified);
356
357    bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace);
358
359    bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num,
360                                       bool can_replace);
361
362    bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
363
364    void Clear();
365
366    void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread,
367              lldb::addr_t base_addr) const;
368
369  protected:
370    typedef std::map<uint32_t, RegisterLocation> collection;
371    lldb::addr_t m_offset; // Offset into the function for this row
372
373    FAValue m_cfa_value;
374    FAValue m_afa_value;
375    collection m_register_locations;
376  }; // class Row
377
378public:
379  typedef std::shared_ptr<Row> RowSP;
380
381  UnwindPlan(lldb::RegisterKind reg_kind)
382      : m_row_list(), m_plan_valid_address_range(), m_register_kind(reg_kind),
383        m_return_addr_register(LLDB_INVALID_REGNUM), m_source_name(),
384        m_plan_is_sourced_from_compiler(eLazyBoolCalculate),
385        m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate),
386        m_plan_is_for_signal_trap(eLazyBoolCalculate),
387        m_lsda_address(), m_personality_func_addr() {}
388
389  // Performs a deep copy of the plan, including all the rows (expensive).
390  UnwindPlan(const UnwindPlan &rhs)
391      : m_plan_valid_address_range(rhs.m_plan_valid_address_range),
392        m_register_kind(rhs.m_register_kind),
393        m_return_addr_register(rhs.m_return_addr_register),
394        m_source_name(rhs.m_source_name),
395        m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler),
396        m_plan_is_valid_at_all_instruction_locations(
397            rhs.m_plan_is_valid_at_all_instruction_locations),
398        m_lsda_address(rhs.m_lsda_address),
399        m_personality_func_addr(rhs.m_personality_func_addr) {
400    m_row_list.reserve(rhs.m_row_list.size());
401    for (const RowSP &row_sp : rhs.m_row_list)
402      m_row_list.emplace_back(new Row(*row_sp));
403  }
404
405  ~UnwindPlan() = default;
406
407  void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const;
408
409  void AppendRow(const RowSP &row_sp);
410
411  void InsertRow(const RowSP &row_sp, bool replace_existing = false);
412
413  // Returns a pointer to the best row for the given offset into the function's
414  // instructions. If offset is -1 it indicates that the function start is
415  // unknown - the final row in the UnwindPlan is returned. In practice, the
416  // UnwindPlan for a function with no known start address will be the
417  // architectural default UnwindPlan which will only have one row.
418  UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const;
419
420  lldb::RegisterKind GetRegisterKind() const { return m_register_kind; }
421
422  void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; }
423
424  void SetReturnAddressRegister(uint32_t regnum) {
425    m_return_addr_register = regnum;
426  }
427
428  uint32_t GetReturnAddressRegister(void) { return m_return_addr_register; }
429
430  uint32_t GetInitialCFARegister() const {
431    if (m_row_list.empty())
432      return LLDB_INVALID_REGNUM;
433    return m_row_list.front()->GetCFAValue().GetRegisterNumber();
434  }
435
436  // This UnwindPlan may not be valid at every address of the function span.
437  // For instance, a FastUnwindPlan will not be valid at the prologue setup
438  // instructions - only in the body of the function.
439  void SetPlanValidAddressRange(const AddressRange &range);
440
441  const AddressRange &GetAddressRange() const {
442    return m_plan_valid_address_range;
443  }
444
445  bool PlanValidAtAddress(Address addr);
446
447  bool IsValidRowIndex(uint32_t idx) const;
448
449  const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const;
450
451  const UnwindPlan::RowSP GetLastRow() const;
452
453  lldb_private::ConstString GetSourceName() const;
454
455  void SetSourceName(const char *);
456
457  // Was this UnwindPlan emitted by a compiler?
458  lldb_private::LazyBool GetSourcedFromCompiler() const {
459    return m_plan_is_sourced_from_compiler;
460  }
461
462  // Was this UnwindPlan emitted by a compiler?
463  void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) {
464    m_plan_is_sourced_from_compiler = from_compiler;
465  }
466
467  // Is this UnwindPlan valid at all instructions?  If not, then it is assumed
468  // valid at call sites, e.g. for exception handling.
469  lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const {
470    return m_plan_is_valid_at_all_instruction_locations;
471  }
472
473  // Is this UnwindPlan valid at all instructions?  If not, then it is assumed
474  // valid at call sites, e.g. for exception handling.
475  void SetUnwindPlanValidAtAllInstructions(
476      lldb_private::LazyBool valid_at_all_insn) {
477    m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
478  }
479
480  // Is this UnwindPlan for a signal trap frame?  If so, then its saved pc
481  // may have been set manually by the signal dispatch code and therefore
482  // not follow a call to the child frame.
483  lldb_private::LazyBool GetUnwindPlanForSignalTrap() const {
484    return m_plan_is_for_signal_trap;
485  }
486
487  void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap) {
488    m_plan_is_for_signal_trap = is_for_signal_trap;
489  }
490
491  int GetRowCount() const;
492
493  void Clear() {
494    m_row_list.clear();
495    m_plan_valid_address_range.Clear();
496    m_register_kind = lldb::eRegisterKindDWARF;
497    m_source_name.Clear();
498    m_plan_is_sourced_from_compiler = eLazyBoolCalculate;
499    m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate;
500    m_plan_is_for_signal_trap = eLazyBoolCalculate;
501    m_lsda_address.Clear();
502    m_personality_func_addr.Clear();
503  }
504
505  const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const;
506
507  Address GetLSDAAddress() const { return m_lsda_address; }
508
509  void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; }
510
511  Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; }
512
513  void SetPersonalityFunctionPtr(Address presonality_func_ptr) {
514    m_personality_func_addr = presonality_func_ptr;
515  }
516
517private:
518  typedef std::vector<RowSP> collection;
519  collection m_row_list;
520  AddressRange m_plan_valid_address_range;
521  lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers
522                                      // are in terms of - will need to be
523  // translated to lldb native reg nums at unwind time
524  uint32_t m_return_addr_register; // The register that has the return address
525                                   // for the caller frame
526                                   // e.g. the lr on arm
527  lldb_private::ConstString
528      m_source_name; // for logging, where this UnwindPlan originated from
529  lldb_private::LazyBool m_plan_is_sourced_from_compiler;
530  lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
531  lldb_private::LazyBool m_plan_is_for_signal_trap;
532
533  Address m_lsda_address; // Where the language specific data area exists in the
534                          // module - used
535                          // in exception handling.
536  Address m_personality_func_addr; // The address of a pointer to the
537                                   // personality function - used in
538                                   // exception handling.
539};                                 // class UnwindPlan
540
541} // namespace lldb_private
542
543#endif // liblldb_UnwindPlan_h
544