Warning: This file is not a C or C++ file. It does not have highlighting.

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
16#include "lldb/Core/AddressRange.h"
17#include "lldb/Utility/ConstString.h"
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
53class UnwindPlan {
54public:
55 class Row {
56 public:
57 class RegisterLocation {
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_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
128 void SetInRegister(uint32_t reg_num) {
129 m_type = inOtherRegister;
130 m_location.reg_num = reg_num;
131 }
132
133 uint32_t GetRegisterNumber() const {
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
174 int GetDWARFExpressionLength() {
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 = unspecified; // 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;
193 uint16_t length;
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 isRaSearch, // FA = SP + offset + ???
206 };
207
208 FAValue() : m_value() {}
209
210 bool operator==(const FAValue &rhs) const;
211
212 bool operator!=(const FAValue &rhs) const { return !(*this == rhs); }
213
214 void SetUnspecified() { m_type = unspecified; }
215
216 bool IsUnspecified() const { return m_type == unspecified; }
217
218 void SetRaSearch(int32_t offset) {
219 m_type = isRaSearch;
220 m_value.ra_search_offset = offset;
221 }
222
223 bool IsRegisterPlusOffset() const {
224 return m_type == isRegisterPlusOffset;
225 }
226
227 void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) {
228 m_type = isRegisterPlusOffset;
229 m_value.reg.reg_num = reg_num;
230 m_value.reg.offset = offset;
231 }
232
233 bool IsRegisterDereferenced() const {
234 return m_type == isRegisterDereferenced;
235 }
236
237 void SetIsRegisterDereferenced(uint32_t reg_num) {
238 m_type = isRegisterDereferenced;
239 m_value.reg.reg_num = reg_num;
240 }
241
242 bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
243
244 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) {
245 m_type = isDWARFExpression;
246 m_value.expr.opcodes = opcodes;
247 m_value.expr.length = len;
248 }
249
250 uint32_t GetRegisterNumber() const {
251 if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset)
252 return m_value.reg.reg_num;
253 return LLDB_INVALID_REGNUM;
254 }
255
256 ValueType GetValueType() const { return m_type; }
257
258 int32_t GetOffset() const {
259 switch (m_type) {
260 case isRegisterPlusOffset:
261 return m_value.reg.offset;
262 case isRaSearch:
263 return m_value.ra_search_offset;
264 default:
265 return 0;
266 }
267 }
268
269 void IncOffset(int32_t delta) {
270 if (m_type == isRegisterPlusOffset)
271 m_value.reg.offset += delta;
272 }
273
274 void SetOffset(int32_t offset) {
275 if (m_type == isRegisterPlusOffset)
276 m_value.reg.offset = offset;
277 }
278
279 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
280 if (m_type == isDWARFExpression) {
281 *opcodes = m_value.expr.opcodes;
282 len = m_value.expr.length;
283 } else {
284 *opcodes = nullptr;
285 len = 0;
286 }
287 }
288
289 const uint8_t *GetDWARFExpressionBytes() {
290 if (m_type == isDWARFExpression)
291 return m_value.expr.opcodes;
292 return nullptr;
293 }
294
295 int GetDWARFExpressionLength() {
296 if (m_type == isDWARFExpression)
297 return m_value.expr.length;
298 return 0;
299 }
300
301 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const;
302
303 private:
304 ValueType m_type = unspecified; // How do we compute CFA value?
305 union {
306 struct {
307 // For m_type == isRegisterPlusOffset or m_type ==
308 // isRegisterDereferenced
309 uint32_t reg_num; // The register number
310 // For m_type == isRegisterPlusOffset
311 int32_t offset;
312 } reg;
313 // For m_type == isDWARFExpression
314 struct {
315 const uint8_t *opcodes;
316 uint16_t length;
317 } expr;
318 // For m_type == isRaSearch
319 int32_t ra_search_offset;
320 } m_value;
321 }; // class FAValue
322
323 Row();
324
325 bool operator==(const Row &rhs) const;
326
327 bool GetRegisterInfo(uint32_t reg_num,
328 RegisterLocation &register_location) const;
329
330 void SetRegisterInfo(uint32_t reg_num,
331 const RegisterLocation register_location);
332
333 void RemoveRegisterInfo(uint32_t reg_num);
334
335 lldb::addr_t GetOffset() const { return m_offset; }
336
337 void SetOffset(lldb::addr_t offset) { m_offset = offset; }
338
339 void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
340
341 FAValue &GetCFAValue() { return m_cfa_value; }
342
343 FAValue &GetAFAValue() { return m_afa_value; }
344
345 bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset,
346 bool can_replace);
347
348 bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset,
349 bool can_replace);
350
351 bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace,
352 bool can_replace_only_if_unspecified);
353
354 bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace);
355
356 bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num,
357 bool can_replace);
358
359 bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
360
361 // When this UnspecifiedRegistersAreUndefined mode is
362 // set, any register that is not specified by this Row will
363 // be described as Undefined.
364 // This will prevent the unwinder from iterating down the
365 // stack looking for a spill location, or a live register value
366 // at frame 0.
367 // It would be used for an UnwindPlan row where we can't track
368 // spilled registers -- for instance a jitted stack frame where
369 // we have no unwind information or start address -- and registers
370 // MAY have been spilled and overwritten, so providing the
371 // spilled/live value from a newer frame may show an incorrect value.
372 void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef) {
373 m_unspecified_registers_are_undefined = unspec_is_undef;
374 }
375
376 bool GetUnspecifiedRegistersAreUndefined() {
377 return m_unspecified_registers_are_undefined;
378 }
379
380 void Clear();
381
382 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread,
383 lldb::addr_t base_addr) const;
384
385 protected:
386 typedef std::map<uint32_t, RegisterLocation> collection;
387 lldb::addr_t m_offset = 0; // Offset into the function for this row
388
389 FAValue m_cfa_value;
390 FAValue m_afa_value;
391 collection m_register_locations;
392 bool m_unspecified_registers_are_undefined = false;
393 }; // class Row
394
395 typedef std::shared_ptr<Row> RowSP;
396
397 UnwindPlan(lldb::RegisterKind reg_kind)
398 : m_register_kind(reg_kind), m_return_addr_register(LLDB_INVALID_REGNUM),
399 m_plan_is_sourced_from_compiler(eLazyBoolCalculate),
400 m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate),
401 m_plan_is_for_signal_trap(eLazyBoolCalculate) {}
402
403 // Performs a deep copy of the plan, including all the rows (expensive).
404 UnwindPlan(const UnwindPlan &rhs)
405 : m_plan_valid_address_range(rhs.m_plan_valid_address_range),
406 m_register_kind(rhs.m_register_kind),
407 m_return_addr_register(rhs.m_return_addr_register),
408 m_source_name(rhs.m_source_name),
409 m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler),
410 m_plan_is_valid_at_all_instruction_locations(
411 rhs.m_plan_is_valid_at_all_instruction_locations),
412 m_plan_is_for_signal_trap(rhs.m_plan_is_for_signal_trap),
413 m_lsda_address(rhs.m_lsda_address),
414 m_personality_func_addr(rhs.m_personality_func_addr) {
415 m_row_list.reserve(rhs.m_row_list.size());
416 for (const RowSP &row_sp : rhs.m_row_list)
417 m_row_list.emplace_back(new Row(*row_sp));
418 }
419
420 ~UnwindPlan() = default;
421
422 void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const;
423
424 void AppendRow(const RowSP &row_sp);
425
426 void InsertRow(const RowSP &row_sp, bool replace_existing = false);
427
428 // Returns a pointer to the best row for the given offset into the function's
429 // instructions. If offset is -1 it indicates that the function start is
430 // unknown - the final row in the UnwindPlan is returned. In practice, the
431 // UnwindPlan for a function with no known start address will be the
432 // architectural default UnwindPlan which will only have one row.
433 UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const;
434
435 lldb::RegisterKind GetRegisterKind() const { return m_register_kind; }
436
437 void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; }
438
439 void SetReturnAddressRegister(uint32_t regnum) {
440 m_return_addr_register = regnum;
441 }
442
443 uint32_t GetReturnAddressRegister() { return m_return_addr_register; }
444
445 uint32_t GetInitialCFARegister() const {
446 if (m_row_list.empty())
447 return LLDB_INVALID_REGNUM;
448 return m_row_list.front()->GetCFAValue().GetRegisterNumber();
449 }
450
451 // This UnwindPlan may not be valid at every address of the function span.
452 // For instance, a FastUnwindPlan will not be valid at the prologue setup
453 // instructions - only in the body of the function.
454 void SetPlanValidAddressRange(const AddressRange &range);
455
456 const AddressRange &GetAddressRange() const {
457 return m_plan_valid_address_range;
458 }
459
460 bool PlanValidAtAddress(Address addr);
461
462 bool IsValidRowIndex(uint32_t idx) const;
463
464 const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const;
465
466 const UnwindPlan::RowSP GetLastRow() const;
467
468 lldb_private::ConstString GetSourceName() const;
469
470 void SetSourceName(const char *);
471
472 // Was this UnwindPlan emitted by a compiler?
473 lldb_private::LazyBool GetSourcedFromCompiler() const {
474 return m_plan_is_sourced_from_compiler;
475 }
476
477 // Was this UnwindPlan emitted by a compiler?
478 void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) {
479 m_plan_is_sourced_from_compiler = from_compiler;
480 }
481
482 // Is this UnwindPlan valid at all instructions? If not, then it is assumed
483 // valid at call sites, e.g. for exception handling.
484 lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const {
485 return m_plan_is_valid_at_all_instruction_locations;
486 }
487
488 // Is this UnwindPlan valid at all instructions? If not, then it is assumed
489 // valid at call sites, e.g. for exception handling.
490 void SetUnwindPlanValidAtAllInstructions(
491 lldb_private::LazyBool valid_at_all_insn) {
492 m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
493 }
494
495 // Is this UnwindPlan for a signal trap frame? If so, then its saved pc
496 // may have been set manually by the signal dispatch code and therefore
497 // not follow a call to the child frame.
498 lldb_private::LazyBool GetUnwindPlanForSignalTrap() const {
499 return m_plan_is_for_signal_trap;
500 }
501
502 void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap) {
503 m_plan_is_for_signal_trap = is_for_signal_trap;
504 }
505
506 int GetRowCount() const;
507
508 void Clear() {
509 m_row_list.clear();
510 m_plan_valid_address_range.Clear();
511 m_register_kind = lldb::eRegisterKindDWARF;
512 m_source_name.Clear();
513 m_plan_is_sourced_from_compiler = eLazyBoolCalculate;
514 m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate;
515 m_plan_is_for_signal_trap = eLazyBoolCalculate;
516 m_lsda_address.Clear();
517 m_personality_func_addr.Clear();
518 }
519
520 const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const;
521
522 Address GetLSDAAddress() const { return m_lsda_address; }
523
524 void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; }
525
526 Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; }
527
528 void SetPersonalityFunctionPtr(Address presonality_func_ptr) {
529 m_personality_func_addr = presonality_func_ptr;
530 }
531
532private:
533 typedef std::vector<RowSP> collection;
534 collection m_row_list;
535 AddressRange m_plan_valid_address_range;
536 lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers
537 // are in terms of - will need to be
538 // translated to lldb native reg nums at unwind time
539 uint32_t m_return_addr_register; // The register that has the return address
540 // for the caller frame
541 // e.g. the lr on arm
542 lldb_private::ConstString
543 m_source_name; // for logging, where this UnwindPlan originated from
544 lldb_private::LazyBool m_plan_is_sourced_from_compiler;
545 lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
546 lldb_private::LazyBool m_plan_is_for_signal_trap;
547
548 Address m_lsda_address; // Where the language specific data area exists in the
549 // module - used
550 // in exception handling.
551 Address m_personality_func_addr; // The address of a pointer to the
552 // personality function - used in
553 // exception handling.
554}; // class UnwindPlan
555
556} // namespace lldb_private
557
558#endif // LLDB_SYMBOL_UNWINDPLAN_H
559

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of lldb/include/lldb/Symbol/UnwindPlan.h