1 //===-- UnwindPlan.h --------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef liblldb_UnwindPlan_h
11 #define liblldb_UnwindPlan_h
19 // Other libraries and framework includes
21 #include "lldb/Core/AddressRange.h"
22 #include "lldb/Utility/ConstString.h"
23 #include "lldb/Utility/Stream.h"
24 #include "lldb/lldb-private.h"
26 namespace lldb_private {
28 // The UnwindPlan object specifies how to unwind out of a function - where
29 // this function saves the caller's register values before modifying them
30 // (for non-volatile aka saved registers) and how to find this frame's
31 // Canonical Frame Address (CFA).
33 // Most commonly, registers are saved on the stack, offset some bytes from
34 // the Canonical Frame Address, or CFA, which is the starting address of
35 // this function's stack frame (the CFA is same as the eh_frame's CFA,
36 // whatever that may be on a given architecture).
37 // The CFA address for the stack frame does not change during
38 // the lifetime of the function.
40 // Internally, the UnwindPlan is structured as a vector of register locations
41 // organized by code address in the function, showing which registers have been
42 // saved at that point and where they are saved.
43 // It can be thought of as the expanded table form of the DWARF CFI
44 // encoded information.
46 // Other unwind information sources will be converted into UnwindPlans before
47 // being added to a FuncUnwinders object. The unwind source may be
48 // an eh_frame FDE, a DWARF debug_frame FDE, or assembly language based
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 inOtherRegister, // reg = other reg
68 atDWARFExpression, // reg = deref(eval(dwarf_expr))
69 isDWARFExpression // reg = eval(dwarf_expr)
72 RegisterLocation() : m_type(unspecified), m_location() {}
74 bool operator==(const RegisterLocation &rhs) const;
76 bool operator!=(const RegisterLocation &rhs) const {
77 return !(*this == rhs);
80 void SetUnspecified() { m_type = unspecified; }
82 void SetUndefined() { m_type = undefined; }
84 void SetSame() { m_type = same; }
86 bool IsSame() const { return m_type == same; }
88 bool IsUnspecified() const { return m_type == unspecified; }
90 bool IsUndefined() const { return m_type == undefined; }
92 bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; }
94 bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; }
96 bool IsInOtherRegister() const { return m_type == inOtherRegister; }
98 bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
100 bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
102 void SetAtCFAPlusOffset(int32_t offset) {
103 m_type = atCFAPlusOffset;
104 m_location.offset = offset;
107 void SetIsCFAPlusOffset(int32_t offset) {
108 m_type = isCFAPlusOffset;
109 m_location.offset = offset;
112 void SetInRegister(uint32_t reg_num) {
113 m_type = inOtherRegister;
114 m_location.reg_num = reg_num;
117 uint32_t GetRegisterNumber() const {
118 if (m_type == inOtherRegister)
119 return m_location.reg_num;
120 return LLDB_INVALID_REGNUM;
123 RestoreType GetLocationType() const { return m_type; }
125 int32_t GetOffset() const {
126 if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset)
127 return m_location.offset;
131 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
132 if (m_type == atDWARFExpression || m_type == isDWARFExpression) {
133 *opcodes = m_location.expr.opcodes;
134 len = m_location.expr.length;
141 void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len);
143 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len);
145 const uint8_t *GetDWARFExpressionBytes() {
146 if (m_type == atDWARFExpression || m_type == isDWARFExpression)
147 return m_location.expr.opcodes;
151 int GetDWARFExpressionLength() {
152 if (m_type == atDWARFExpression || m_type == isDWARFExpression)
153 return m_location.expr.length;
157 void Dump(Stream &s, const UnwindPlan *unwind_plan,
158 const UnwindPlan::Row *row, Thread *thread, bool verbose) const;
161 RestoreType m_type; // How do we locate this register?
163 // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset
165 // For m_type == inOtherRegister
166 uint32_t reg_num; // The register number
167 // For m_type == atDWARFExpression or m_type == isDWARFExpression
169 const uint8_t *opcodes;
178 unspecified, // not specified
179 isRegisterPlusOffset, // CFA = register + offset
180 isRegisterDereferenced, // CFA = [reg]
181 isDWARFExpression // CFA = eval(dwarf_expr)
184 CFAValue() : m_type(unspecified), m_value() {}
186 bool operator==(const CFAValue &rhs) const;
188 bool operator!=(const CFAValue &rhs) const { return !(*this == rhs); }
190 void SetUnspecified() { m_type = unspecified; }
192 bool IsUnspecified() const { return m_type == unspecified; }
194 bool IsRegisterPlusOffset() const {
195 return m_type == isRegisterPlusOffset;
198 void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) {
199 m_type = isRegisterPlusOffset;
200 m_value.reg.reg_num = reg_num;
201 m_value.reg.offset = offset;
204 bool IsRegisterDereferenced() const {
205 return m_type == isRegisterDereferenced;
208 void SetIsRegisterDereferenced(uint32_t reg_num) {
209 m_type = isRegisterDereferenced;
210 m_value.reg.reg_num = reg_num;
213 bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
215 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) {
216 m_type = isDWARFExpression;
217 m_value.expr.opcodes = opcodes;
218 m_value.expr.length = len;
221 uint32_t GetRegisterNumber() const {
222 if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset)
223 return m_value.reg.reg_num;
224 return LLDB_INVALID_REGNUM;
227 ValueType GetValueType() const { return m_type; }
229 int32_t GetOffset() const {
230 if (m_type == isRegisterPlusOffset)
231 return m_value.reg.offset;
235 void IncOffset(int32_t delta) {
236 if (m_type == isRegisterPlusOffset)
237 m_value.reg.offset += delta;
240 void SetOffset(int32_t offset) {
241 if (m_type == isRegisterPlusOffset)
242 m_value.reg.offset = offset;
245 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
246 if (m_type == isDWARFExpression) {
247 *opcodes = m_value.expr.opcodes;
248 len = m_value.expr.length;
255 const uint8_t *GetDWARFExpressionBytes() {
256 if (m_type == isDWARFExpression)
257 return m_value.expr.opcodes;
261 int GetDWARFExpressionLength() {
262 if (m_type == isDWARFExpression)
263 return m_value.expr.length;
267 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const;
270 ValueType m_type; // How do we compute CFA value?
273 // For m_type == isRegisterPlusOffset or m_type ==
274 // isRegisterDereferenced
275 uint32_t reg_num; // The register number
276 // For m_type == isRegisterPlusOffset
279 // For m_type == isDWARFExpression
281 const uint8_t *opcodes;
290 Row(const UnwindPlan::Row &rhs) = default;
292 bool operator==(const Row &rhs) const;
294 bool GetRegisterInfo(uint32_t reg_num,
295 RegisterLocation ®ister_location) const;
297 void SetRegisterInfo(uint32_t reg_num,
298 const RegisterLocation register_location);
300 void RemoveRegisterInfo(uint32_t reg_num);
302 lldb::addr_t GetOffset() const { return m_offset; }
304 void SetOffset(lldb::addr_t offset) { m_offset = offset; }
306 void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
308 CFAValue &GetCFAValue() { return m_cfa_value; }
310 bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset,
313 bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset,
316 bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace,
317 bool can_replace_only_if_unspecified);
319 bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace);
321 bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num,
324 bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
328 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread,
329 lldb::addr_t base_addr) const;
332 typedef std::map<uint32_t, RegisterLocation> collection;
333 lldb::addr_t m_offset; // Offset into the function for this row
335 CFAValue m_cfa_value;
336 collection m_register_locations;
340 typedef std::shared_ptr<Row> RowSP;
342 UnwindPlan(lldb::RegisterKind reg_kind)
343 : m_row_list(), m_plan_valid_address_range(), m_register_kind(reg_kind),
344 m_return_addr_register(LLDB_INVALID_REGNUM), m_source_name(),
345 m_plan_is_sourced_from_compiler(eLazyBoolCalculate),
346 m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate),
347 m_lsda_address(), m_personality_func_addr() {}
349 // Performs a deep copy of the plan, including all the rows (expensive).
350 UnwindPlan(const UnwindPlan &rhs)
351 : m_plan_valid_address_range(rhs.m_plan_valid_address_range),
352 m_register_kind(rhs.m_register_kind),
353 m_return_addr_register(rhs.m_return_addr_register),
354 m_source_name(rhs.m_source_name),
355 m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler),
356 m_plan_is_valid_at_all_instruction_locations(
357 rhs.m_plan_is_valid_at_all_instruction_locations),
358 m_lsda_address(rhs.m_lsda_address),
359 m_personality_func_addr(rhs.m_personality_func_addr) {
360 m_row_list.reserve(rhs.m_row_list.size());
361 for (const RowSP &row_sp : rhs.m_row_list)
362 m_row_list.emplace_back(new Row(*row_sp));
365 ~UnwindPlan() = default;
367 void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const;
369 void AppendRow(const RowSP &row_sp);
371 void InsertRow(const RowSP &row_sp, bool replace_existing = false);
373 // Returns a pointer to the best row for the given offset into the function's
375 // If offset is -1 it indicates that the function start is unknown - the final
376 // row in the UnwindPlan is returned.
377 // In practice, the UnwindPlan for a function with no known start address will
378 // be the architectural default
379 // UnwindPlan which will only have one row.
380 UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const;
382 lldb::RegisterKind GetRegisterKind() const { return m_register_kind; }
384 void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; }
386 void SetReturnAddressRegister(uint32_t regnum) {
387 m_return_addr_register = regnum;
390 uint32_t GetReturnAddressRegister(void) { return m_return_addr_register; }
392 uint32_t GetInitialCFARegister() const {
393 if (m_row_list.empty())
394 return LLDB_INVALID_REGNUM;
395 return m_row_list.front()->GetCFAValue().GetRegisterNumber();
398 // This UnwindPlan may not be valid at every address of the function span.
399 // For instance, a FastUnwindPlan will not be valid at the prologue setup
400 // instructions - only in the body of the function.
401 void SetPlanValidAddressRange(const AddressRange &range);
403 const AddressRange &GetAddressRange() const {
404 return m_plan_valid_address_range;
407 bool PlanValidAtAddress(Address addr);
409 bool IsValidRowIndex(uint32_t idx) const;
411 const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const;
413 const UnwindPlan::RowSP GetLastRow() const;
415 lldb_private::ConstString GetSourceName() const;
417 void SetSourceName(const char *);
419 // Was this UnwindPlan emitted by a compiler?
420 lldb_private::LazyBool GetSourcedFromCompiler() const {
421 return m_plan_is_sourced_from_compiler;
424 // Was this UnwindPlan emitted by a compiler?
425 void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) {
426 m_plan_is_sourced_from_compiler = from_compiler;
429 // Is this UnwindPlan valid at all instructions? If not, then it is assumed
430 // valid at call sites,
431 // e.g. for exception handling.
432 lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const {
433 return m_plan_is_valid_at_all_instruction_locations;
436 // Is this UnwindPlan valid at all instructions? If not, then it is assumed
437 // valid at call sites,
438 // e.g. for exception handling.
439 void SetUnwindPlanValidAtAllInstructions(
440 lldb_private::LazyBool valid_at_all_insn) {
441 m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
444 int GetRowCount() const;
448 m_plan_valid_address_range.Clear();
449 m_register_kind = lldb::eRegisterKindDWARF;
450 m_source_name.Clear();
451 m_plan_is_sourced_from_compiler = eLazyBoolCalculate;
452 m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate;
453 m_lsda_address.Clear();
454 m_personality_func_addr.Clear();
457 const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const;
459 Address GetLSDAAddress() const { return m_lsda_address; }
461 void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; }
463 Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; }
465 void SetPersonalityFunctionPtr(Address presonality_func_ptr) {
466 m_personality_func_addr = presonality_func_ptr;
470 typedef std::vector<RowSP> collection;
471 collection m_row_list;
472 AddressRange m_plan_valid_address_range;
473 lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers
474 // are in terms of - will need to be
475 // translated to lldb native reg nums at unwind time
476 uint32_t m_return_addr_register; // The register that has the return address
477 // for the caller frame
478 // e.g. the lr on arm
479 lldb_private::ConstString
480 m_source_name; // for logging, where this UnwindPlan originated from
481 lldb_private::LazyBool m_plan_is_sourced_from_compiler;
482 lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
484 Address m_lsda_address; // Where the language specific data area exists in the
486 // in exception handling.
487 Address m_personality_func_addr; // The address of a pointer to the
488 // personality function - used in
489 // exception handling.
490 }; // class UnwindPlan
492 } // namespace lldb_private
494 #endif // liblldb_UnwindPlan_h