LLDB  mainline
UnwindPlan.h
Go to the documentation of this file.
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"
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:
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 
129  m_type = inOtherRegister;
130  m_location.reg_num = reg_num;
131  }
132 
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 
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;
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  };
206 
207  FAValue() : m_type(unspecified), m_value() {}
208 
209  bool operator==(const FAValue &rhs) const;
210 
211  bool operator!=(const FAValue &rhs) const { return !(*this == rhs); }
212 
213  void SetUnspecified() { m_type = unspecified; }
214 
215  bool IsUnspecified() const { return m_type == unspecified; }
216 
217  bool IsRegisterPlusOffset() const {
218  return m_type == isRegisterPlusOffset;
219  }
220 
222  m_type = isRegisterPlusOffset;
223  m_value.reg.reg_num = reg_num;
224  m_value.reg.offset = offset;
225  }
226 
227  bool IsRegisterDereferenced() const {
228  return m_type == isRegisterDereferenced;
229  }
230 
232  m_type = isRegisterDereferenced;
233  m_value.reg.reg_num = reg_num;
234  }
235 
236  bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
237 
238  void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) {
239  m_type = isDWARFExpression;
240  m_value.expr.opcodes = opcodes;
241  m_value.expr.length = len;
242  }
243 
245  if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset)
246  return m_value.reg.reg_num;
247  return LLDB_INVALID_REGNUM;
248  }
249 
250  ValueType GetValueType() const { return m_type; }
251 
252  int32_t GetOffset() const {
253  if (m_type == isRegisterPlusOffset)
254  return m_value.reg.offset;
255  return 0;
256  }
257 
258  void IncOffset(int32_t delta) {
259  if (m_type == isRegisterPlusOffset)
260  m_value.reg.offset += delta;
261  }
262 
263  void SetOffset(int32_t offset) {
264  if (m_type == isRegisterPlusOffset)
265  m_value.reg.offset = offset;
266  }
267 
268  void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
269  if (m_type == isDWARFExpression) {
270  *opcodes = m_value.expr.opcodes;
271  len = m_value.expr.length;
272  } else {
273  *opcodes = nullptr;
274  len = 0;
275  }
276  }
277 
278  const uint8_t *GetDWARFExpressionBytes() {
279  if (m_type == isDWARFExpression)
280  return m_value.expr.opcodes;
281  return nullptr;
282  }
283 
285  if (m_type == isDWARFExpression)
286  return m_value.expr.length;
287  return 0;
288  }
289 
290  void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const;
291 
292  private:
293  ValueType m_type; // How do we compute CFA value?
294  union {
295  struct {
296  // For m_type == isRegisterPlusOffset or m_type ==
297  // isRegisterDereferenced
298  uint32_t reg_num; // The register number
299  // For m_type == isRegisterPlusOffset
300  int32_t offset;
301  } reg;
302  // For m_type == isDWARFExpression
303  struct {
304  const uint8_t *opcodes;
306  } expr;
307  } m_value;
308  }; // class FAValue
309 
310  public:
311  Row();
312 
313  Row(const UnwindPlan::Row &rhs) = default;
314 
315  bool operator==(const Row &rhs) const;
316 
318  RegisterLocation &register_location) const;
319 
321  const RegisterLocation register_location);
322 
324 
325  lldb::addr_t GetOffset() const { return m_offset; }
326 
328 
330 
332 
334 
336  bool can_replace);
337 
338  bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset,
339  bool can_replace);
340 
341  bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace,
342  bool can_replace_only_if_unspecified);
343 
344  bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace);
345 
346  bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num,
347  bool can_replace);
348 
349  bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
350 
351  void Clear();
352 
353  void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread,
354  lldb::addr_t base_addr) const;
355 
356  protected:
357  typedef std::map<uint32_t, RegisterLocation> collection;
358  lldb::addr_t m_offset; // Offset into the function for this row
359 
363  }; // class Row
364 
365 public:
366  typedef std::shared_ptr<Row> RowSP;
367 
369  : m_row_list(), m_plan_valid_address_range(), m_register_kind(reg_kind),
370  m_return_addr_register(LLDB_INVALID_REGNUM), m_source_name(),
371  m_plan_is_sourced_from_compiler(eLazyBoolCalculate),
372  m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate),
373  m_lsda_address(), m_personality_func_addr() {}
374 
375  // Performs a deep copy of the plan, including all the rows (expensive).
376  UnwindPlan(const UnwindPlan &rhs)
377  : m_plan_valid_address_range(rhs.m_plan_valid_address_range),
378  m_register_kind(rhs.m_register_kind),
379  m_return_addr_register(rhs.m_return_addr_register),
380  m_source_name(rhs.m_source_name),
381  m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler),
382  m_plan_is_valid_at_all_instruction_locations(
383  rhs.m_plan_is_valid_at_all_instruction_locations),
384  m_lsda_address(rhs.m_lsda_address),
385  m_personality_func_addr(rhs.m_personality_func_addr) {
386  m_row_list.reserve(rhs.m_row_list.size());
387  for (const RowSP &row_sp : rhs.m_row_list)
388  m_row_list.emplace_back(new Row(*row_sp));
389  }
390 
391  ~UnwindPlan() = default;
392 
393  void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const;
394 
395  void AppendRow(const RowSP &row_sp);
396 
397  void InsertRow(const RowSP &row_sp, bool replace_existing = false);
398 
399  // Returns a pointer to the best row for the given offset into the function's
400  // instructions. If offset is -1 it indicates that the function start is
401  // unknown - the final row in the UnwindPlan is returned. In practice, the
402  // UnwindPlan for a function with no known start address will be the
403  // architectural default UnwindPlan which will only have one row.
405 
406  lldb::RegisterKind GetRegisterKind() const { return m_register_kind; }
407 
408  void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; }
409 
411  m_return_addr_register = regnum;
412  }
413 
414  uint32_t GetReturnAddressRegister(void) { return m_return_addr_register; }
415 
417  if (m_row_list.empty())
418  return LLDB_INVALID_REGNUM;
419  return m_row_list.front()->GetCFAValue().GetRegisterNumber();
420  }
421 
422  // This UnwindPlan may not be valid at every address of the function span.
423  // For instance, a FastUnwindPlan will not be valid at the prologue setup
424  // instructions - only in the body of the function.
425  void SetPlanValidAddressRange(const AddressRange &range);
426 
427  const AddressRange &GetAddressRange() const {
428  return m_plan_valid_address_range;
429  }
430 
431  bool PlanValidAtAddress(Address addr);
432 
433  bool IsValidRowIndex(uint32_t idx) const;
434 
435  const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const;
436 
437  const UnwindPlan::RowSP GetLastRow() const;
438 
440 
441  void SetSourceName(const char *);
442 
443  // Was this UnwindPlan emitted by a compiler?
445  return m_plan_is_sourced_from_compiler;
446  }
447 
448  // Was this UnwindPlan emitted by a compiler?
450  m_plan_is_sourced_from_compiler = from_compiler;
451  }
452 
453  // Is this UnwindPlan valid at all instructions? If not, then it is assumed
454  // valid at call sites, e.g. for exception handling.
456  return m_plan_is_valid_at_all_instruction_locations;
457  }
458 
459  // Is this UnwindPlan valid at all instructions? If not, then it is assumed
460  // valid at call sites, e.g. for exception handling.
462  lldb_private::LazyBool valid_at_all_insn) {
463  m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
464  }
465 
466  int GetRowCount() const;
467 
468  void Clear() {
469  m_row_list.clear();
470  m_plan_valid_address_range.Clear();
471  m_register_kind = lldb::eRegisterKindDWARF;
472  m_source_name.Clear();
473  m_plan_is_sourced_from_compiler = eLazyBoolCalculate;
474  m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate;
475  m_lsda_address.Clear();
476  m_personality_func_addr.Clear();
477  }
478 
479  const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const;
480 
481  Address GetLSDAAddress() const { return m_lsda_address; }
482 
483  void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; }
484 
485  Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; }
486 
487  void SetPersonalityFunctionPtr(Address presonality_func_ptr) {
488  m_personality_func_addr = presonality_func_ptr;
489  }
490 
491 private:
492  typedef std::vector<RowSP> collection;
493  collection m_row_list;
494  AddressRange m_plan_valid_address_range;
495  lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers
496  // are in terms of - will need to be
497  // translated to lldb native reg nums at unwind time
498  uint32_t m_return_addr_register; // The register that has the return address
499  // for the caller frame
500  // e.g. the lr on arm
502  m_source_name; // for logging, where this UnwindPlan originated from
503  lldb_private::LazyBool m_plan_is_sourced_from_compiler;
504  lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
505 
506  Address m_lsda_address; // Where the language specific data area exists in the
507  // module - used
508  // in exception handling.
509  Address m_personality_func_addr; // The address of a pointer to the
510  // personality function - used in
511  // exception handling.
512 }; // class UnwindPlan
513 
514 } // namespace lldb_private
515 
516 #endif // liblldb_UnwindPlan_h
std::map< uint32_t, RegisterLocation > collection
Definition: UnwindPlan.h:357
void SetOffset(lldb::addr_t offset)
Definition: UnwindPlan.h:327
lldb::RegisterKind GetRegisterKind() const
Definition: UnwindPlan.h:406
UnwindPlan(const UnwindPlan &rhs)
Definition: UnwindPlan.h:376
void SlideOffset(lldb::addr_t offset)
Definition: UnwindPlan.h:329
void SetSourceName(const char *)
Definition: UnwindPlan.cpp:542
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
void InsertRow(const RowSP &row_sp, bool replace_existing=false)
Definition: UnwindPlan.cpp:363
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
const uint8_t * GetDWARFExpressionBytes()
Definition: UnwindPlan.h:278
uint32_t GetInitialCFARegister() const
Definition: UnwindPlan.h:416
bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified)
Definition: UnwindPlan.cpp:297
void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len)
Definition: UnwindPlan.cpp:53
lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const
Definition: UnwindPlan.h:455
const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const
Definition: UnwindPlan.cpp:400
void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const
Definition: UnwindPlan.h:154
void SetRegisterInfo(uint32_t reg_num, const RegisterLocation register_location)
Definition: UnwindPlan.cpp:267
bool IsValidRowIndex(uint32_t idx) const
Definition: UnwindPlan.cpp:396
void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset)
Definition: UnwindPlan.h:221
bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num, bool can_replace)
Definition: UnwindPlan.cpp:325
void Dump(Stream &s, const UnwindPlan *unwind_plan, const UnwindPlan::Row *row, Thread *thread, bool verbose) const
Definition: UnwindPlan.cpp:93
void SetPlanValidAddressRange(const AddressRange &range)
Definition: UnwindPlan.cpp:425
void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len)
Definition: UnwindPlan.h:238
bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset, bool can_replace)
Definition: UnwindPlan.cpp:285
void RemoveRegisterInfo(uint32_t reg_num)
Definition: UnwindPlan.cpp:260
Address GetLSDAAddress() const
Definition: UnwindPlan.h:481
uint32_t GetReturnAddressRegister(void)
Definition: UnwindPlan.h:414
std::shared_ptr< Row > RowSP
Definition: UnwindPlan.h:366
void AppendRow(const RowSP &row_sp)
Definition: UnwindPlan.cpp:355
lldb_private::LazyBool GetSourcedFromCompiler() const
Definition: UnwindPlan.h:444
void SetRegisterKind(lldb::RegisterKind kind)
Definition: UnwindPlan.h:408
void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const
Definition: UnwindPlan.h:268
A section + offset based address class.
Definition: Address.h:80
bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset, bool can_replace)
Definition: UnwindPlan.cpp:273
void SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)
Definition: UnwindPlan.h:461
lldb_private::ConstString GetSourceName() const
Definition: UnwindPlan.cpp:546
void SetLSDAAddress(Address lsda_addr)
Definition: UnwindPlan.h:483
UnwindPlan(lldb::RegisterKind reg_kind)
Definition: UnwindPlan.h:368
const UnwindPlan::RowSP GetLastRow() const
Definition: UnwindPlan.cpp:413
uint64_t addr_t
Definition: lldb-types.h:83
bool GetRegisterInfo(uint32_t reg_num, RegisterLocation &register_location) const
Definition: UnwindPlan.cpp:249
bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace)
Definition: UnwindPlan.cpp:314
struct lldb_private::UnwindPlan::Row::RegisterLocation::@26::@27 expr
A uniqued constant string class.
Definition: ConstString.h:38
bool operator!=(const FAValue &rhs) const
Definition: UnwindPlan.h:211
bool operator!=(const RegisterLocation &rhs) const
Definition: UnwindPlan.h:78
bool operator==(const RegisterLocation &rhs) const
Definition: UnwindPlan.cpp:23
void SetPersonalityFunctionPtr(Address presonality_func_ptr)
Definition: UnwindPlan.h:487
Address GetPersonalityFunctionPtr() const
Definition: UnwindPlan.h:485
UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const
Definition: UnwindPlan.cpp:378
A section + offset based address range class.
Definition: AddressRange.h:32
void SetIsRegisterDereferenced(uint32_t reg_num)
Definition: UnwindPlan.h:231
void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)
Definition: UnwindPlan.h:449
bool PlanValidAtAddress(Address addr)
Definition: UnwindPlan.cpp:430
void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len)
Definition: UnwindPlan.cpp:62
lldb::addr_t GetOffset() const
Definition: UnwindPlan.h:325
const AddressRange & GetAddressRange() const
Definition: UnwindPlan.h:427
void SetReturnAddressRegister(uint32_t regnum)
Definition: UnwindPlan.h:410
bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace)
Definition: UnwindPlan.cpp:337
#define LLDB_INVALID_REGNUM
Definition: lldb-defines.h:90