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
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
54public:
55 class Row {
56 public:
58 public:
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 isConstant // reg = constant
73 };
74
76
77 bool operator==(const AbstractRegisterLocation &rhs) const;
78
79 bool operator!=(const AbstractRegisterLocation &rhs) const {
80 return !(*this == rhs);
81 }
82
84
86
87 void SetSame() { m_type = same; }
88
89 bool IsSame() const { return m_type == same; }
90
91 bool IsUnspecified() const { return m_type == unspecified; }
92
93 bool IsUndefined() const { return m_type == undefined; }
94
95 bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; }
96
97 bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; }
98
99 bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; }
100
101 bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; }
102
103 bool IsInOtherRegister() const { return m_type == inOtherRegister; }
104
105 bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
106
107 bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
108
109 bool IsConstant() const { return m_type == isConstant; }
110
111 void SetIsConstant(uint64_t value) {
113 m_location.constant_value = value;
114 }
115
116 uint64_t GetConstant() const { return m_location.constant_value; }
117
120 m_location.offset = offset;
121 }
122
125 m_location.offset = offset;
126 }
127
130 m_location.offset = offset;
131 }
132
135 m_location.offset = offset;
136 }
137
138 void SetInRegister(uint32_t reg_num) {
140 m_location.reg_num = reg_num;
141 }
142
143 uint32_t GetRegisterNumber() const {
144 if (m_type == inOtherRegister)
145 return m_location.reg_num;
146 return LLDB_INVALID_REGNUM;
147 }
148
150
151 int32_t GetOffset() const {
152 switch(m_type)
153 {
154 case atCFAPlusOffset:
155 case isCFAPlusOffset:
156 case atAFAPlusOffset:
157 case isAFAPlusOffset:
158 return m_location.offset;
159 default:
160 return 0;
161 }
162 }
163
164 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
166 *opcodes = m_location.expr.opcodes;
167 len = m_location.expr.length;
168 } else {
169 *opcodes = nullptr;
170 len = 0;
171 }
172 }
173
174 void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len);
175
176 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len);
177
178 const uint8_t *GetDWARFExpressionBytes() const {
180 return m_location.expr.opcodes;
181 return nullptr;
182 }
183
186 return m_location.expr.length;
187 return 0;
188 }
189
190 void Dump(Stream &s, const UnwindPlan *unwind_plan,
191 const UnwindPlan::Row *row, Thread *thread, bool verbose) const;
192
193 private:
194 RestoreType m_type = unspecified; // How do we locate this register?
195 union {
196 // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset
197 int32_t offset;
198 // For m_type == inOtherRegister
199 uint32_t reg_num; // The register number
200 // For m_type == atDWARFExpression or m_type == isDWARFExpression
201 struct {
202 const uint8_t *opcodes;
203 uint16_t length;
205 // For m_type == isConstant
208 };
209
210 class FAValue {
211 public:
213 unspecified, // not specified
214 isRegisterPlusOffset, // FA = register + offset
216 isDWARFExpression, // FA = eval(dwarf_expr)
217 isRaSearch, // FA = SP + offset + ???
218 isConstant, // FA = constant
219 };
220
222
223 bool operator==(const FAValue &rhs) const;
224
225 bool operator!=(const FAValue &rhs) const { return !(*this == rhs); }
226
228
229 bool IsUnspecified() const { return m_type == unspecified; }
230
231 void SetRaSearch(int32_t offset) {
233 m_value.ra_search_offset = offset;
234 }
235
236 bool IsRegisterPlusOffset() const {
238 }
239
240 void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) {
242 m_value.reg.reg_num = reg_num;
243 m_value.reg.offset = offset;
244 }
245
248 }
249
252 m_value.reg.reg_num = reg_num;
253 }
254
255 bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
256
257 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) {
259 m_value.expr.opcodes = opcodes;
260 m_value.expr.length = len;
261 }
262
263 bool IsConstant() const { return m_type == isConstant; }
264
265 void SetIsConstant(uint64_t constant) {
267 m_value.constant = constant;
268 }
269
270 uint64_t GetConstant() const { return m_value.constant; }
271
272 uint32_t GetRegisterNumber() const {
274 return m_value.reg.reg_num;
275 return LLDB_INVALID_REGNUM;
276 }
277
278 ValueType GetValueType() const { return m_type; }
279
280 int32_t GetOffset() const {
281 switch (m_type) {
283 return m_value.reg.offset;
284 case isRaSearch:
285 return m_value.ra_search_offset;
286 default:
287 return 0;
288 }
289 }
290
291 void IncOffset(int32_t delta) {
293 m_value.reg.offset += delta;
294 }
295
296 void SetOffset(int32_t offset) {
298 m_value.reg.offset = offset;
299 }
300
301 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
302 if (m_type == isDWARFExpression) {
303 *opcodes = m_value.expr.opcodes;
304 len = m_value.expr.length;
305 } else {
306 *opcodes = nullptr;
307 len = 0;
308 }
309 }
310
311 const uint8_t *GetDWARFExpressionBytes() const {
313 return m_value.expr.opcodes;
314 return nullptr;
315 }
316
319 return m_value.expr.length;
320 return 0;
321 }
322
323 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const;
324
325 private:
326 ValueType m_type = unspecified; // How do we compute CFA value?
327 union {
328 struct {
329 // For m_type == isRegisterPlusOffset or m_type ==
330 // isRegisterDereferenced
331 uint32_t reg_num; // The register number
332 // For m_type == isRegisterPlusOffset
333 int32_t offset;
335 // For m_type == isDWARFExpression
336 struct {
337 const uint8_t *opcodes;
338 uint16_t length;
340 // For m_type == isRaSearch
342 // For m_type = isConstant
343 uint64_t constant;
345 }; // class FAValue
346
347 Row();
348
349 bool operator==(const Row &rhs) const;
350
351 bool GetRegisterInfo(uint32_t reg_num,
352 AbstractRegisterLocation &register_location) const;
353
354 void SetRegisterInfo(uint32_t reg_num,
355 const AbstractRegisterLocation register_location);
356
357 void RemoveRegisterInfo(uint32_t reg_num);
358
359 int64_t GetOffset() const { return m_offset; }
360
361 void SetOffset(int64_t offset) { m_offset = offset; }
362
363 void SlideOffset(int64_t offset) { m_offset += offset; }
364
365 const FAValue &GetCFAValue() const { return m_cfa_value; }
367
368 const FAValue &GetAFAValue() const { return m_afa_value; }
370
371 bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset,
372 bool can_replace);
373
374 bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset,
375 bool can_replace);
376
377 bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace,
378 bool can_replace_only_if_unspecified);
379
380 bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace);
381
382 bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num,
383 bool can_replace);
384
385 bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
386
387 /// This method does not make a copy of the \a opcodes memory, it is
388 /// assumed to have the same lifetime as the Module this UnwindPlan will
389 /// be registered in.
390 bool SetRegisterLocationToIsDWARFExpression(uint32_t reg_num,
391 const uint8_t *opcodes,
392 uint32_t len, bool can_replace);
393
394 bool SetRegisterLocationToIsConstant(uint32_t reg_num, uint64_t constant,
395 bool can_replace);
396
397 // When this UnspecifiedRegistersAreUndefined mode is
398 // set, any register that is not specified by this Row will
399 // be described as Undefined.
400 // This will prevent the unwinder from iterating down the
401 // stack looking for a spill location, or a live register value
402 // at frame 0.
403 // It would be used for an UnwindPlan row where we can't track
404 // spilled registers -- for instance a jitted stack frame where
405 // we have no unwind information or start address -- and registers
406 // MAY have been spilled and overwritten, so providing the
407 // spilled/live value from a newer frame may show an incorrect value.
408 void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef) {
410 }
411
415
416 void Clear();
417
418 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread,
419 lldb::addr_t base_addr) const;
420
421 protected:
422 typedef std::map<uint32_t, AbstractRegisterLocation> collection;
423 int64_t m_offset = 0; // Offset into the function for this row
424
429 }; // class Row
430
436
437 // Performs a deep copy of the plan, including all the rows (expensive).
438 UnwindPlan(const UnwindPlan &rhs) = default;
439 UnwindPlan &operator=(const UnwindPlan &rhs) = default;
440
441 UnwindPlan(UnwindPlan &&rhs) = default;
443
444 ~UnwindPlan() = default;
445
446 void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const;
447
448 void AppendRow(Row row);
449
450 void InsertRow(Row row, bool replace_existing = false);
451
452 // Returns a pointer to the best row for the given offset into the function's
453 // instructions. If offset is std::nullopt it indicates that the function
454 // start is unknown - the final row in the UnwindPlan is returned. In
455 // practice, the UnwindPlan for a function with no known start address will be
456 // the architectural default UnwindPlan which will only have one row.
457 const UnwindPlan::Row *
458 GetRowForFunctionOffset(std::optional<int64_t> offset) const;
459
461
463
464 void SetReturnAddressRegister(uint32_t regnum) {
465 m_return_addr_register = regnum;
466 }
467
469
470 uint32_t GetInitialCFARegister() const {
471 if (m_row_list.empty())
472 return LLDB_INVALID_REGNUM;
473 return m_row_list.front().GetCFAValue().GetRegisterNumber();
474 }
475
476 // This UnwindPlan may not be valid at every address of the function span.
477 // For instance, a FastUnwindPlan will not be valid at the prologue setup
478 // instructions - only in the body of the function.
479 void SetPlanValidAddressRanges(std::vector<AddressRange> ranges) {
480 m_plan_valid_ranges = std::move(ranges);
481 }
482
483 bool PlanValidAtAddress(Address addr) const;
484
485 bool IsValidRowIndex(uint32_t idx) const;
486
487 const UnwindPlan::Row *GetRowAtIndex(uint32_t idx) const;
488
489 const UnwindPlan::Row *GetLastRow() const;
490
492
493 void SetSourceName(const char *);
494
495 // Was this UnwindPlan emitted by a compiler?
499
500 // Was this UnwindPlan emitted by a compiler?
502 m_plan_is_sourced_from_compiler = from_compiler;
503 }
504
505 // Is this UnwindPlan valid at all instructions? If not, then it is assumed
506 // valid at call sites, e.g. for exception handling.
510
511 // Is this UnwindPlan valid at all instructions? If not, then it is assumed
512 // valid at call sites, e.g. for exception handling.
517
518 // Is this UnwindPlan for a signal trap frame? If so, then its saved pc
519 // may have been set manually by the signal dispatch code and therefore
520 // not follow a call to the child frame.
524
526 m_plan_is_for_signal_trap = is_for_signal_trap;
527 }
528
529 int GetRowCount() const { return m_row_list.size(); }
530
540
541 const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const;
542
543private:
544 std::vector<Row> m_row_list;
545 std::vector<AddressRange> m_plan_valid_ranges;
546 lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers
547 // are in terms of - will need to be
548 // translated to lldb native reg nums at unwind time
549 uint32_t m_return_addr_register; // The register that has the return address
550 // for the caller frame
551 // e.g. the lr on arm
553 m_source_name; // for logging, where this UnwindPlan originated from
557}; // class UnwindPlan
558
559} // namespace lldb_private
560
561#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:164
bool operator!=(const AbstractRegisterLocation &rhs) const
Definition UnwindPlan.h:79
union lldb_private::UnwindPlan::Row::AbstractRegisterLocation::@225201031247227020145212152105175123074115111335 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::@225201031247227020145212152105175123074115111335::@274041013243136340101366216255135217113225313354 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:257
void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const
const uint8_t * GetDWARFExpressionBytes() const
Definition UnwindPlan.h:311
bool operator==(const FAValue &rhs) const
void SetIsRegisterDereferenced(uint32_t reg_num)
Definition UnwindPlan.h:250
union lldb_private::UnwindPlan::Row::FAValue::@131017011041341220266230364377327125216211117206 m_value
struct lldb_private::UnwindPlan::Row::FAValue::@131017011041341220266230364377327125216211117206::@302167274322137005337330072303015152064264174351 expr
void SetIsConstant(uint64_t constant)
Definition UnwindPlan.h:265
bool operator!=(const FAValue &rhs) const
Definition UnwindPlan.h:225
struct lldb_private::UnwindPlan::Row::FAValue::@131017011041341220266230364377327125216211117206::@224067032354375070144176053364000367340265231113 reg
void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const
Definition UnwindPlan.h:301
void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset)
Definition UnwindPlan.h:240
const FAValue & GetAFAValue() const
Definition UnwindPlan.h:368
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:363
void SetOffset(int64_t offset)
Definition UnwindPlan.h:361
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:365
bool GetRegisterInfo(uint32_t reg_num, AbstractRegisterLocation &register_location) const
std::map< uint32_t, AbstractRegisterLocation > collection
Definition UnwindPlan.h:422
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)
void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef)
Definition UnwindPlan.h:408
void SetRegisterInfo(uint32_t reg_num, const AbstractRegisterLocation register_location)
lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const
Definition UnwindPlan.h:507
std::vector< Row > m_row_list
Definition UnwindPlan.h:544
void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap)
Definition UnwindPlan.h:525
UnwindPlan & operator=(UnwindPlan &&)=default
lldb::RegisterKind m_register_kind
Definition UnwindPlan.h:546
void SetRegisterKind(lldb::RegisterKind kind)
Definition UnwindPlan.h:462
UnwindPlan(const UnwindPlan &rhs)=default
UnwindPlan(lldb::RegisterKind reg_kind)
Definition UnwindPlan.h:431
uint32_t GetInitialCFARegister() const
Definition UnwindPlan.h:470
uint32_t GetReturnAddressRegister() const
Definition UnwindPlan.h:468
const RegisterInfo * GetRegisterInfo(Thread *thread, uint32_t reg_num) const
lldb_private::LazyBool m_plan_is_for_signal_trap
Definition UnwindPlan.h:556
void SetReturnAddressRegister(uint32_t regnum)
Definition UnwindPlan.h:464
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:555
lldb::RegisterKind GetRegisterKind() const
Definition UnwindPlan.h:460
std::vector< AddressRange > m_plan_valid_ranges
Definition UnwindPlan.h:545
const UnwindPlan::Row * GetRowForFunctionOffset(std::optional< int64_t > offset) const
bool PlanValidAtAddress(Address addr) const
lldb_private::ConstString m_source_name
Definition UnwindPlan.h:553
void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)
Definition UnwindPlan.h:501
const UnwindPlan::Row * GetLastRow() const
void SetSourceName(const char *)
void SetPlanValidAddressRanges(std::vector< AddressRange > ranges)
Definition UnwindPlan.h:479
lldb_private::LazyBool GetUnwindPlanForSignalTrap() const
Definition UnwindPlan.h:521
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:496
void SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)
Definition UnwindPlan.h:513
lldb_private::LazyBool m_plan_is_sourced_from_compiler
Definition UnwindPlan.h:554
#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),...