LLDB mainline
UnwindPlan.cpp
Go to the documentation of this file.
1//===-- UnwindPlan.cpp ----------------------------------------------------===//
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
10
11#include "lldb/Target/Process.h"
13#include "lldb/Target/Target.h"
14#include "lldb/Target/Thread.h"
17#include "lldb/Utility/Log.h"
18#include "llvm/DebugInfo/DIContext.h"
19#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
20#include <optional>
21
22using namespace lldb;
23using namespace lldb_private;
24
27 if (m_type == rhs.m_type) {
28 switch (m_type) {
29 case unspecified:
30 case undefined:
31 case same:
32 return true;
33
34 case atCFAPlusOffset:
35 case isCFAPlusOffset:
36 case atAFAPlusOffset:
37 case isAFAPlusOffset:
38 return m_location.offset == rhs.m_location.offset;
39
40 case inOtherRegister:
41 return m_location.reg_num == rhs.m_location.reg_num;
42
45 if (m_location.expr.length == rhs.m_location.expr.length)
46 return !memcmp(m_location.expr.opcodes, rhs.m_location.expr.opcodes,
47 m_location.expr.length);
48 break;
49 }
50 }
51 return false;
52}
53
54// This function doesn't copy the dwarf expression bytes; they must remain in
55// allocated memory for the lifespan of this UnwindPlan object.
57 const uint8_t *opcodes, uint32_t len) {
58 m_type = atDWARFExpression;
59 m_location.expr.opcodes = opcodes;
60 m_location.expr.length = len;
61}
62
63// This function doesn't copy the dwarf expression bytes; they must remain in
64// allocated memory for the lifespan of this UnwindPlan object.
66 const uint8_t *opcodes, uint32_t len) {
67 m_type = isDWARFExpression;
68 m_location.expr.opcodes = opcodes;
69 m_location.expr.length = len;
70}
71
72static std::optional<std::pair<lldb::ByteOrder, uint32_t>>
74 if (!thread)
75 return std::nullopt;
76 ProcessSP process_sp = thread->GetProcess();
77 if (!process_sp)
78 return std::nullopt;
79 ArchSpec arch = process_sp->GetTarget().GetArchitecture();
80 return std::make_pair(arch.GetByteOrder(), arch.GetAddressByteSize());
81}
82
83static void DumpDWARFExpr(Stream &s, llvm::ArrayRef<uint8_t> expr, Thread *thread) {
84 if (auto order_and_width = GetByteOrderAndAddrSize(thread)) {
85 llvm::DataExtractor data(expr, order_and_width->first == eByteOrderLittle,
86 order_and_width->second);
87 llvm::DWARFExpression(data, order_and_width->second, llvm::dwarf::DWARF32)
88 .print(s.AsRawOstream(), llvm::DIDumpOptions(), nullptr);
89 } else
90 s.PutCString("dwarf-expr");
91}
92
94 const UnwindPlan *unwind_plan,
95 const UnwindPlan::Row *row,
96 Thread *thread,
97 bool verbose) const {
98 switch (m_type) {
99 case unspecified:
100 if (verbose)
101 s.PutCString("=<unspec>");
102 else
103 s.PutCString("=!");
104 break;
105 case undefined:
106 if (verbose)
107 s.PutCString("=<undef>");
108 else
109 s.PutCString("=?");
110 break;
111 case same:
112 s.PutCString("= <same>");
113 break;
114
115 case atCFAPlusOffset:
116 case isCFAPlusOffset: {
117 s.PutChar('=');
118 if (m_type == atCFAPlusOffset)
119 s.PutChar('[');
120 s.Printf("CFA%+d", m_location.offset);
121 if (m_type == atCFAPlusOffset)
122 s.PutChar(']');
123 } break;
124
125 case atAFAPlusOffset:
126 case isAFAPlusOffset: {
127 s.PutChar('=');
128 if (m_type == atAFAPlusOffset)
129 s.PutChar('[');
130 s.Printf("AFA%+d", m_location.offset);
131 if (m_type == atAFAPlusOffset)
132 s.PutChar(']');
133 } break;
134
135 case inOtherRegister: {
136 const RegisterInfo *other_reg_info = nullptr;
137 if (unwind_plan)
138 other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num);
139 if (other_reg_info)
140 s.Printf("=%s", other_reg_info->name);
141 else
142 s.Printf("=reg(%u)", m_location.reg_num);
143 } break;
144
145 case atDWARFExpression:
146 case isDWARFExpression: {
147 s.PutChar('=');
148 if (m_type == atDWARFExpression)
149 s.PutChar('[');
151 s, llvm::ArrayRef(m_location.expr.opcodes, m_location.expr.length),
152 thread);
153 if (m_type == atDWARFExpression)
154 s.PutChar(']');
155 } break;
156 }
157}
158
159static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,
160 Thread *thread, uint32_t reg_num) {
161 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num);
162 if (reg_info)
163 s.PutCString(reg_info->name);
164 else
165 s.Printf("reg(%u)", reg_num);
166}
167
169operator==(const UnwindPlan::Row::FAValue &rhs) const {
170 if (m_type == rhs.m_type) {
171 switch (m_type) {
172 case unspecified:
173 case isRaSearch:
174 return m_value.ra_search_offset == rhs.m_value.ra_search_offset;
175
176 case isRegisterPlusOffset:
177 return m_value.reg.offset == rhs.m_value.reg.offset;
178
179 case isRegisterDereferenced:
180 return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
181
182 case isDWARFExpression:
183 if (m_value.expr.length == rhs.m_value.expr.length)
184 return !memcmp(m_value.expr.opcodes, rhs.m_value.expr.opcodes,
185 m_value.expr.length);
186 break;
187 }
188 }
189 return false;
190}
191
193 Thread *thread) const {
194 switch (m_type) {
195 case isRegisterPlusOffset:
196 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
197 s.Printf("%+3d", m_value.reg.offset);
198 break;
199 case isRegisterDereferenced:
200 s.PutChar('[');
201 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
202 s.PutChar(']');
203 break;
204 case isDWARFExpression:
205 DumpDWARFExpr(s, llvm::ArrayRef(m_value.expr.opcodes, m_value.expr.length),
206 thread);
207 break;
208 case unspecified:
209 s.PutCString("unspecified");
210 break;
211 case isRaSearch:
212 s.Printf("RaSearch@SP%+d", m_value.ra_search_offset);
213 break;
214 }
215}
216
220 m_offset = 0;
222 m_register_locations.clear();
223}
224
225void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
226 Thread *thread, addr_t base_addr) const {
227 if (base_addr != LLDB_INVALID_ADDRESS)
228 s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
229 else
230 s.Printf("%4" PRId64 ": CFA=", GetOffset());
231
232 m_cfa_value.Dump(s, unwind_plan, thread);
233
234 if (!m_afa_value.IsUnspecified()) {
235 s.Printf(" AFA=");
236 m_afa_value.Dump(s, unwind_plan, thread);
237 }
238
239 s.Printf(" => ");
240 for (collection::const_iterator idx = m_register_locations.begin();
241 idx != m_register_locations.end(); ++idx) {
242 DumpRegisterName(s, unwind_plan, thread, idx->first);
243 const bool verbose = false;
244 idx->second.Dump(s, unwind_plan, this, thread, verbose);
245 s.PutChar(' ');
246 }
247}
248
250
252 uint32_t reg_num,
253 UnwindPlan::Row::RegisterLocation &register_location) const {
254 collection::const_iterator pos = m_register_locations.find(reg_num);
255 if (pos != m_register_locations.end()) {
256 register_location = pos->second;
257 return true;
258 }
259 if (m_unspecified_registers_are_undefined) {
260 register_location.SetUndefined();
261 return true;
262 }
263 return false;
264}
265
267 collection::const_iterator pos = m_register_locations.find(reg_num);
268 if (pos != m_register_locations.end()) {
269 m_register_locations.erase(pos);
270 }
271}
272
274 uint32_t reg_num,
275 const UnwindPlan::Row::RegisterLocation register_location) {
276 m_register_locations[reg_num] = register_location;
277}
278
280 int32_t offset,
281 bool can_replace) {
282 if (!can_replace &&
283 m_register_locations.find(reg_num) != m_register_locations.end())
284 return false;
285 RegisterLocation reg_loc;
286 reg_loc.SetAtCFAPlusOffset(offset);
287 m_register_locations[reg_num] = reg_loc;
288 return true;
289}
290
292 int32_t offset,
293 bool can_replace) {
294 if (!can_replace &&
295 m_register_locations.find(reg_num) != m_register_locations.end())
296 return false;
297 RegisterLocation reg_loc;
298 reg_loc.SetIsCFAPlusOffset(offset);
299 m_register_locations[reg_num] = reg_loc;
300 return true;
301}
302
304 uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) {
305 collection::iterator pos = m_register_locations.find(reg_num);
306 collection::iterator end = m_register_locations.end();
307
308 if (pos != end) {
309 if (!can_replace)
310 return false;
311 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
312 return false;
313 }
314 RegisterLocation reg_loc;
315 reg_loc.SetUndefined();
316 m_register_locations[reg_num] = reg_loc;
317 return true;
318}
319
321 bool can_replace) {
322 if (!can_replace &&
323 m_register_locations.find(reg_num) != m_register_locations.end())
324 return false;
325 RegisterLocation reg_loc;
326 reg_loc.SetUnspecified();
327 m_register_locations[reg_num] = reg_loc;
328 return true;
329}
330
332 uint32_t other_reg_num,
333 bool can_replace) {
334 if (!can_replace &&
335 m_register_locations.find(reg_num) != m_register_locations.end())
336 return false;
337 RegisterLocation reg_loc;
338 reg_loc.SetInRegister(other_reg_num);
339 m_register_locations[reg_num] = reg_loc;
340 return true;
341}
342
344 bool must_replace) {
345 if (must_replace &&
346 m_register_locations.find(reg_num) == m_register_locations.end())
347 return false;
348 RegisterLocation reg_loc;
349 reg_loc.SetSame();
350 m_register_locations[reg_num] = reg_loc;
351 return true;
352}
353
355 return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
356 m_afa_value == rhs.m_afa_value &&
357 m_unspecified_registers_are_undefined ==
359 m_register_locations == rhs.m_register_locations;
360}
361
363 if (m_row_list.empty() ||
364 m_row_list.back()->GetOffset() != row_sp->GetOffset())
365 m_row_list.push_back(row_sp);
366 else
367 m_row_list.back() = row_sp;
368}
369
371 bool replace_existing) {
372 collection::iterator it = m_row_list.begin();
373 while (it != m_row_list.end()) {
374 RowSP row = *it;
375 if (row->GetOffset() >= row_sp->GetOffset())
376 break;
377 it++;
378 }
379 if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
380 m_row_list.insert(it, row_sp);
381 else if (replace_existing)
382 *it = row_sp;
383}
384
386 RowSP row;
387 if (!m_row_list.empty()) {
388 if (offset == -1)
389 row = m_row_list.back();
390 else {
391 collection::const_iterator pos, end = m_row_list.end();
392 for (pos = m_row_list.begin(); pos != end; ++pos) {
393 if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
394 row = *pos;
395 else
396 break;
397 }
398 }
399 }
400 return row;
401}
402
404 return idx < m_row_list.size();
405}
406
408 if (idx < m_row_list.size())
409 return m_row_list[idx];
410 else {
411 Log *log = GetLog(LLDBLog::Unwind);
412 LLDB_LOGF(log,
413 "error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index "
414 "(number rows is %u)",
415 idx, (uint32_t)m_row_list.size());
416 return UnwindPlan::RowSP();
417 }
418}
419
421 if (m_row_list.empty()) {
422 Log *log = GetLog(LLDBLog::Unwind);
423 LLDB_LOGF(log, "UnwindPlan::GetLastRow() when rows are empty");
424 return UnwindPlan::RowSP();
425 }
426 return m_row_list.back();
427}
428
429int UnwindPlan::GetRowCount() const { return m_row_list.size(); }
430
432 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
434}
435
437 // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
438 if (GetRowCount() == 0) {
439 Log *log = GetLog(LLDBLog::Unwind);
440 if (log) {
441 StreamString s;
442 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
443 LLDB_LOGF(log,
444 "UnwindPlan is invalid -- no unwind rows for UnwindPlan "
445 "'%s' at address %s",
447 } else {
448 LLDB_LOGF(log,
449 "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
451 }
452 }
453 return false;
454 }
455
456 // If the 0th Row of unwind instructions is missing, or if it doesn't provide
457 // a register to use to find the Canonical Frame Address, this is not a valid
458 // UnwindPlan.
459 if (GetRowAtIndex(0).get() == nullptr ||
460 GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
462 Log *log = GetLog(LLDBLog::Unwind);
463 if (log) {
464 StreamString s;
465 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
466 LLDB_LOGF(log,
467 "UnwindPlan is invalid -- no CFA register defined in row 0 "
468 "for UnwindPlan '%s' at address %s",
470 } else {
471 LLDB_LOGF(log,
472 "UnwindPlan is invalid -- no CFA register defined in row 0 "
473 "for UnwindPlan '%s'",
475 }
476 }
477 return false;
478 }
479
482 return true;
483
484 if (!addr.IsValid())
485 return true;
486
488 return true;
489
490 return false;
491}
492
493void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
494 if (!m_source_name.IsEmpty()) {
495 s.Printf("This UnwindPlan originally sourced from %s\n",
497 }
499 TargetSP target_sp(thread->CalculateTarget());
500 addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get());
501 addr_t personality_func_load_addr =
503
504 if (lsda_load_addr != LLDB_INVALID_ADDRESS &&
505 personality_func_load_addr != LLDB_INVALID_ADDRESS) {
506 s.Printf("LSDA address 0x%" PRIx64
507 ", personality routine is at address 0x%" PRIx64 "\n",
508 lsda_load_addr, personality_func_load_addr);
509 }
510 }
511 s.Printf("This UnwindPlan is sourced from the compiler: ");
513 case eLazyBoolYes:
514 s.Printf("yes.\n");
515 break;
516 case eLazyBoolNo:
517 s.Printf("no.\n");
518 break;
520 s.Printf("not specified.\n");
521 break;
522 }
523 s.Printf("This UnwindPlan is valid at all instruction locations: ");
525 case eLazyBoolYes:
526 s.Printf("yes.\n");
527 break;
528 case eLazyBoolNo:
529 s.Printf("no.\n");
530 break;
532 s.Printf("not specified.\n");
533 break;
534 }
535 s.Printf("This UnwindPlan is for a trap handler function: ");
537 case eLazyBoolYes:
538 s.Printf("yes.\n");
539 break;
540 case eLazyBoolNo:
541 s.Printf("no.\n");
542 break;
544 s.Printf("not specified.\n");
545 break;
546 }
549 s.PutCString("Address range of this UnwindPlan: ");
550 TargetSP target_sp(thread->CalculateTarget());
551 m_plan_valid_address_range.Dump(&s, target_sp.get(),
553 s.EOL();
554 }
555 collection::const_iterator pos, begin = m_row_list.begin(),
556 end = m_row_list.end();
557 for (pos = begin; pos != end; ++pos) {
558 s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos));
559 (*pos)->Dump(s, this, thread, base_addr);
560 s.Printf("\n");
561 }
562}
563
564void UnwindPlan::SetSourceName(const char *source) {
565 m_source_name = ConstString(source);
566}
567
569
570const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread,
571 uint32_t unwind_reg) const {
572 if (thread) {
573 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
574 if (reg_ctx) {
575 uint32_t reg;
577 reg = unwind_reg;
578 else
580 unwind_reg);
581 if (reg != LLDB_INVALID_REGNUM)
582 return reg_ctx->GetRegisterInfoAtIndex(reg);
583 }
584 }
585 return nullptr;
586}
#define LLDB_LOGF(log,...)
Definition: Log.h:344
static std::optional< std::pair< lldb::ByteOrder, uint32_t > > GetByteOrderAndAddrSize(Thread *thread)
Definition: UnwindPlan.cpp:73
static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan, Thread *thread, uint32_t reg_num)
Definition: UnwindPlan.cpp:159
static void DumpDWARFExpr(Stream &s, llvm::ArrayRef< uint8_t > expr, Thread *thread)
Definition: UnwindPlan.cpp:83
A section + offset based address range class.
Definition: AddressRange.h:25
Address & GetBaseAddress()
Get accessor for the base address of the range.
Definition: AddressRange.h:209
bool ContainsFileAddress(const Address &so_addr) const
Check if a section offset address is contained in this range.
bool Dump(Stream *s, Target *target, Address::DumpStyle style, Address::DumpStyle fallback_style=Address::DumpStyleInvalid) const
Dump a description of this object to a Stream.
lldb::addr_t GetByteSize() const
Get accessor for the byte size of this range.
Definition: AddressRange.h:221
A section + offset based address class.
Definition: Address.h:59
lldb::addr_t GetLoadAddress(Target *target) const
Get the load address.
Definition: Address.cpp:311
@ DumpStyleSectionNameOffset
Display as the section name + offset.
Definition: Address.h:71
bool Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style=DumpStyleInvalid, uint32_t addr_byte_size=UINT32_MAX, bool all_ranges=false) const
Dump a description of this object to a Stream.
Definition: Address.cpp:406
bool IsValid() const
Check if the object state is valid.
Definition: Address.h:345
An architecture specification class.
Definition: ArchSpec.h:32
uint32_t GetAddressByteSize() const
Returns the size in bytes of an address of the current architecture.
Definition: ArchSpec.cpp:694
lldb::ByteOrder GetByteOrder() const
Returns the byte order for the architecture specification.
Definition: ArchSpec.cpp:741
A uniqued constant string class.
Definition: ConstString.h:39
bool IsEmpty() const
Test for empty string.
Definition: ConstString.h:303
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:215
virtual uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num)
Convert from a given register numbering scheme to the lldb register numbering scheme.
virtual const RegisterInfo * GetRegisterInfoAtIndex(size_t reg)=0
const char * GetData() const
Definition: StreamString.h:43
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
Definition: Stream.h:357
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:63
size_t PutChar(char ch)
Definition: Stream.cpp:104
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:128
virtual lldb::RegisterContextSP GetRegisterContext()=0
lldb::TargetSP CalculateTarget() override
Definition: Thread.cpp:1406
lldb::ProcessSP GetProcess() const
Definition: Thread.h:153
void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const
Definition: UnwindPlan.cpp:192
struct lldb_private::UnwindPlan::Row::FAValue::@27::@28 reg
struct lldb_private::UnwindPlan::Row::FAValue::@27::@29 expr
bool operator==(const FAValue &rhs) const
Definition: UnwindPlan.cpp:169
union lldb_private::UnwindPlan::Row::FAValue::@27 m_value
bool operator==(const RegisterLocation &rhs) const
Definition: UnwindPlan.cpp:26
void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len)
Definition: UnwindPlan.cpp:56
void Dump(Stream &s, const UnwindPlan *unwind_plan, const UnwindPlan::Row *row, Thread *thread, bool verbose) const
Definition: UnwindPlan.cpp:93
void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len)
Definition: UnwindPlan.cpp:65
union lldb_private::UnwindPlan::Row::RegisterLocation::@25 m_location
struct lldb_private::UnwindPlan::Row::RegisterLocation::@25::@26 expr
bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset, bool can_replace)
Definition: UnwindPlan.cpp:291
bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace)
Definition: UnwindPlan.cpp:343
bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset, bool can_replace)
Definition: UnwindPlan.cpp:279
bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num, bool can_replace)
Definition: UnwindPlan.cpp:331
void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread, lldb::addr_t base_addr) const
Definition: UnwindPlan.cpp:225
bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace)
Definition: UnwindPlan.cpp:320
void RemoveRegisterInfo(uint32_t reg_num)
Definition: UnwindPlan.cpp:266
lldb::addr_t GetOffset() const
Definition: UnwindPlan.h:335
bool operator==(const Row &rhs) const
Definition: UnwindPlan.cpp:354
bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified)
Definition: UnwindPlan.cpp:303
bool GetRegisterInfo(uint32_t reg_num, RegisterLocation &register_location) const
Definition: UnwindPlan.cpp:251
void SetRegisterInfo(uint32_t reg_num, const RegisterLocation register_location)
Definition: UnwindPlan.cpp:273
void InsertRow(const RowSP &row_sp, bool replace_existing=false)
Definition: UnwindPlan.cpp:370
const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const
Definition: UnwindPlan.cpp:407
lldb::RegisterKind m_register_kind
Definition: UnwindPlan.h:536
const RegisterInfo * GetRegisterInfo(Thread *thread, uint32_t reg_num) const
Definition: UnwindPlan.cpp:570
lldb_private::LazyBool m_plan_is_for_signal_trap
Definition: UnwindPlan.h:546
const UnwindPlan::RowSP GetLastRow() const
Definition: UnwindPlan.cpp:420
void SetPlanValidAddressRange(const AddressRange &range)
Definition: UnwindPlan.cpp:431
AddressRange m_plan_valid_address_range
Definition: UnwindPlan.h:535
bool IsValidRowIndex(uint32_t idx) const
Definition: UnwindPlan.cpp:403
void AppendRow(const RowSP &row_sp)
Definition: UnwindPlan.cpp:362
lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations
Definition: UnwindPlan.h:545
UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const
Definition: UnwindPlan.cpp:385
std::shared_ptr< Row > RowSP
Definition: UnwindPlan.h:395
lldb_private::ConstString m_source_name
Definition: UnwindPlan.h:543
bool PlanValidAtAddress(Address addr)
Definition: UnwindPlan.cpp:436
void SetSourceName(const char *)
Definition: UnwindPlan.cpp:564
void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const
Definition: UnwindPlan.cpp:493
lldb_private::ConstString GetSourceName() const
Definition: UnwindPlan.cpp:568
lldb_private::LazyBool m_plan_is_sourced_from_compiler
Definition: UnwindPlan.h:544
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:74
#define LLDB_INVALID_REGNUM
Definition: lldb-defines.h:79
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:309
Definition: SBAddress.h:15
uint64_t offset_t
Definition: lldb-types.h:87
@ eByteOrderLittle
uint64_t addr_t
Definition: lldb-types.h:83
@ eRegisterKindLLDB
lldb's internal register numbers