1 //===-- UnwindPlan.h --------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef liblldb_UnwindPlan_h
10 #define liblldb_UnwindPlan_h
16 #include "lldb/Core/AddressRange.h"
17 #include "lldb/Utility/ConstString.h"
18 #include "lldb/Utility/Stream.h"
19 #include "lldb/lldb-private.h"
21 namespace lldb_private {
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).
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.
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.
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.
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.
57 class RegisterLocation {
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)
74 RegisterLocation() : m_type(unspecified), m_location() {}
76 bool operator==(const RegisterLocation &rhs) const;
78 bool operator!=(const RegisterLocation &rhs) const {
79 return !(*this == rhs);
82 void SetUnspecified() { m_type = unspecified; }
84 void SetUndefined() { m_type = undefined; }
86 void SetSame() { m_type = same; }
88 bool IsSame() const { return m_type == same; }
90 bool IsUnspecified() const { return m_type == unspecified; }
92 bool IsUndefined() const { return m_type == undefined; }
94 bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; }
96 bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; }
98 bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; }
100 bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; }
102 bool IsInOtherRegister() const { return m_type == inOtherRegister; }
104 bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
106 bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
108 void SetAtCFAPlusOffset(int32_t offset) {
109 m_type = atCFAPlusOffset;
110 m_location.offset = offset;
113 void SetIsCFAPlusOffset(int32_t offset) {
114 m_type = isCFAPlusOffset;
115 m_location.offset = offset;
118 void SetAtAFAPlusOffset(int32_t offset) {
119 m_type = atAFAPlusOffset;
120 m_location.offset = offset;
123 void SetIsAFAPlusOffset(int32_t offset) {
124 m_type = isAFAPlusOffset;
125 m_location.offset = offset;
128 void SetInRegister(uint32_t reg_num) {
129 m_type = inOtherRegister;
130 m_location.reg_num = reg_num;
133 uint32_t GetRegisterNumber() const {
134 if (m_type == inOtherRegister)
135 return m_location.reg_num;
136 return LLDB_INVALID_REGNUM;
139 RestoreType GetLocationType() const { return m_type; }
141 int32_t GetOffset() const {
144 case atCFAPlusOffset:
145 case isCFAPlusOffset:
146 case atAFAPlusOffset:
147 case isAFAPlusOffset:
148 return m_location.offset;
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;
164 void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len);
166 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len);
168 const uint8_t *GetDWARFExpressionBytes() {
169 if (m_type == atDWARFExpression || m_type == isDWARFExpression)
170 return m_location.expr.opcodes;
174 int GetDWARFExpressionLength() {
175 if (m_type == atDWARFExpression || m_type == isDWARFExpression)
176 return m_location.expr.length;
180 void Dump(Stream &s, const UnwindPlan *unwind_plan,
181 const UnwindPlan::Row *row, Thread *thread, bool verbose) const;
184 RestoreType m_type; // How do we locate this register?
186 // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset
188 // For m_type == inOtherRegister
189 uint32_t reg_num; // The register number
190 // For m_type == atDWARFExpression or m_type == isDWARFExpression
192 const uint8_t *opcodes;
201 unspecified, // not specified
202 isRegisterPlusOffset, // FA = register + offset
203 isRegisterDereferenced, // FA = [reg]
204 isDWARFExpression // FA = eval(dwarf_expr)
207 FAValue() : m_type(unspecified), m_value() {}
209 bool operator==(const FAValue &rhs) const;
211 bool operator!=(const FAValue &rhs) const { return !(*this == rhs); }
213 void SetUnspecified() { m_type = unspecified; }
215 bool IsUnspecified() const { return m_type == unspecified; }
217 bool IsRegisterPlusOffset() const {
218 return m_type == isRegisterPlusOffset;
221 void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) {
222 m_type = isRegisterPlusOffset;
223 m_value.reg.reg_num = reg_num;
224 m_value.reg.offset = offset;
227 bool IsRegisterDereferenced() const {
228 return m_type == isRegisterDereferenced;
231 void SetIsRegisterDereferenced(uint32_t reg_num) {
232 m_type = isRegisterDereferenced;
233 m_value.reg.reg_num = reg_num;
236 bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
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;
244 uint32_t GetRegisterNumber() const {
245 if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset)
246 return m_value.reg.reg_num;
247 return LLDB_INVALID_REGNUM;
250 ValueType GetValueType() const { return m_type; }
252 int32_t GetOffset() const {
253 if (m_type == isRegisterPlusOffset)
254 return m_value.reg.offset;
258 void IncOffset(int32_t delta) {
259 if (m_type == isRegisterPlusOffset)
260 m_value.reg.offset += delta;
263 void SetOffset(int32_t offset) {
264 if (m_type == isRegisterPlusOffset)
265 m_value.reg.offset = offset;
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;
278 const uint8_t *GetDWARFExpressionBytes() {
279 if (m_type == isDWARFExpression)
280 return m_value.expr.opcodes;
284 int GetDWARFExpressionLength() {
285 if (m_type == isDWARFExpression)
286 return m_value.expr.length;
290 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const;
293 ValueType m_type; // How do we compute CFA value?
296 // For m_type == isRegisterPlusOffset or m_type ==
297 // isRegisterDereferenced
298 uint32_t reg_num; // The register number
299 // For m_type == isRegisterPlusOffset
302 // For m_type == isDWARFExpression
304 const uint8_t *opcodes;
313 Row(const UnwindPlan::Row &rhs) = default;
315 bool operator==(const Row &rhs) const;
317 bool GetRegisterInfo(uint32_t reg_num,
318 RegisterLocation ®ister_location) const;
320 void SetRegisterInfo(uint32_t reg_num,
321 const RegisterLocation register_location);
323 void RemoveRegisterInfo(uint32_t reg_num);
325 lldb::addr_t GetOffset() const { return m_offset; }
327 void SetOffset(lldb::addr_t offset) { m_offset = offset; }
329 void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
331 FAValue &GetCFAValue() { return m_cfa_value; }
333 FAValue &GetAFAValue() { return m_afa_value; }
335 bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset,
338 bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset,
341 bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace,
342 bool can_replace_only_if_unspecified);
344 bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace);
346 bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num,
349 bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
353 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread,
354 lldb::addr_t base_addr) const;
357 typedef std::map<uint32_t, RegisterLocation> collection;
358 lldb::addr_t m_offset; // Offset into the function for this row
362 collection m_register_locations;
366 typedef std::shared_ptr<Row> RowSP;
368 UnwindPlan(lldb::RegisterKind reg_kind)
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() {}
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));
391 ~UnwindPlan() = default;
393 void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const;
395 void AppendRow(const RowSP &row_sp);
397 void InsertRow(const RowSP &row_sp, bool replace_existing = false);
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.
404 UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const;
406 lldb::RegisterKind GetRegisterKind() const { return m_register_kind; }
408 void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; }
410 void SetReturnAddressRegister(uint32_t regnum) {
411 m_return_addr_register = regnum;
414 uint32_t GetReturnAddressRegister(void) { return m_return_addr_register; }
416 uint32_t GetInitialCFARegister() const {
417 if (m_row_list.empty())
418 return LLDB_INVALID_REGNUM;
419 return m_row_list.front()->GetCFAValue().GetRegisterNumber();
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);
427 const AddressRange &GetAddressRange() const {
428 return m_plan_valid_address_range;
431 bool PlanValidAtAddress(Address addr);
433 bool IsValidRowIndex(uint32_t idx) const;
435 const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const;
437 const UnwindPlan::RowSP GetLastRow() const;
439 lldb_private::ConstString GetSourceName() const;
441 void SetSourceName(const char *);
443 // Was this UnwindPlan emitted by a compiler?
444 lldb_private::LazyBool GetSourcedFromCompiler() const {
445 return m_plan_is_sourced_from_compiler;
448 // Was this UnwindPlan emitted by a compiler?
449 void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) {
450 m_plan_is_sourced_from_compiler = from_compiler;
453 // Is this UnwindPlan valid at all instructions? If not, then it is assumed
454 // valid at call sites, e.g. for exception handling.
455 lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const {
456 return m_plan_is_valid_at_all_instruction_locations;
459 // Is this UnwindPlan valid at all instructions? If not, then it is assumed
460 // valid at call sites, e.g. for exception handling.
461 void SetUnwindPlanValidAtAllInstructions(
462 lldb_private::LazyBool valid_at_all_insn) {
463 m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
466 int GetRowCount() const;
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();
479 const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const;
481 Address GetLSDAAddress() const { return m_lsda_address; }
483 void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; }
485 Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; }
487 void SetPersonalityFunctionPtr(Address presonality_func_ptr) {
488 m_personality_func_addr = presonality_func_ptr;
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
501 lldb_private::ConstString
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;
506 Address m_lsda_address; // Where the language specific data area exists in the
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
514 } // namespace lldb_private
516 #endif // liblldb_UnwindPlan_h