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