1 //===-- UnwindPlan.cpp ----------------------------------*- 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 #include "lldb/Symbol/UnwindPlan.h"
12 #include "lldb/Target/Process.h"
13 #include "lldb/Target/RegisterContext.h"
14 #include "lldb/Target/Thread.h"
15 #include "lldb/Utility/ConstString.h"
16 #include "lldb/Utility/Log.h"
19 using namespace lldb_private;
21 bool UnwindPlan::Row::RegisterLocation::
22 operator==(const UnwindPlan::Row::RegisterLocation &rhs) const {
23 if (m_type == rhs.m_type) {
32 return m_location.offset == rhs.m_location.offset;
35 return m_location.reg_num == rhs.m_location.reg_num;
37 case atDWARFExpression:
38 case isDWARFExpression:
39 if (m_location.expr.length == rhs.m_location.expr.length)
40 return !memcmp(m_location.expr.opcodes, rhs.m_location.expr.opcodes,
41 m_location.expr.length);
48 // This function doesn't copy the dwarf expression bytes; they must remain in
50 // memory for the lifespan of this UnwindPlan object.
51 void UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression(
52 const uint8_t *opcodes, uint32_t len) {
53 m_type = atDWARFExpression;
54 m_location.expr.opcodes = opcodes;
55 m_location.expr.length = len;
58 // This function doesn't copy the dwarf expression bytes; they must remain in
60 // memory for the lifespan of this UnwindPlan object.
61 void UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression(
62 const uint8_t *opcodes, uint32_t len) {
63 m_type = isDWARFExpression;
64 m_location.expr.opcodes = opcodes;
65 m_location.expr.length = len;
68 void UnwindPlan::Row::RegisterLocation::Dump(Stream &s,
69 const UnwindPlan *unwind_plan,
70 const UnwindPlan::Row *row,
76 s.PutCString("=<unspec>");
82 s.PutCString("=<undef>");
87 s.PutCString("= <same>");
91 case isCFAPlusOffset: {
93 if (m_type == atCFAPlusOffset)
95 s.Printf("CFA%+d", m_location.offset);
96 if (m_type == atCFAPlusOffset)
100 case inOtherRegister: {
101 const RegisterInfo *other_reg_info = nullptr;
103 other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num);
105 s.Printf("=%s", other_reg_info->name);
107 s.Printf("=reg(%u)", m_location.reg_num);
110 case atDWARFExpression:
111 case isDWARFExpression: {
113 if (m_type == atDWARFExpression)
114 s.PutCString("[dwarf-expr]");
116 s.PutCString("dwarf-expr");
121 static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,
122 Thread *thread, uint32_t reg_num) {
123 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num);
125 s.PutCString(reg_info->name);
127 s.Printf("reg(%u)", reg_num);
130 bool UnwindPlan::Row::CFAValue::
131 operator==(const UnwindPlan::Row::CFAValue &rhs) const {
132 if (m_type == rhs.m_type) {
137 case isRegisterPlusOffset:
138 return m_value.reg.offset == rhs.m_value.reg.offset;
140 case isRegisterDereferenced:
141 return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
143 case isDWARFExpression:
144 if (m_value.expr.length == rhs.m_value.expr.length)
145 return !memcmp(m_value.expr.opcodes, rhs.m_value.expr.opcodes,
146 m_value.expr.length);
153 void UnwindPlan::Row::CFAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
154 Thread *thread) const {
156 case isRegisterPlusOffset:
157 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
158 s.Printf("%+3d", m_value.reg.offset);
160 case isRegisterDereferenced:
162 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
165 case isDWARFExpression:
166 s.PutCString("dwarf-expr");
169 s.PutCString("unspecified");
174 void UnwindPlan::Row::Clear() {
175 m_cfa_value.SetUnspecified();
177 m_register_locations.clear();
180 void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
181 Thread *thread, addr_t base_addr) const {
182 if (base_addr != LLDB_INVALID_ADDRESS)
183 s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
185 s.Printf("%4" PRId64 ": CFA=", GetOffset());
187 m_cfa_value.Dump(s, unwind_plan, thread);
189 for (collection::const_iterator idx = m_register_locations.begin();
190 idx != m_register_locations.end(); ++idx) {
191 DumpRegisterName(s, unwind_plan, thread, idx->first);
192 const bool verbose = false;
193 idx->second.Dump(s, unwind_plan, this, thread, verbose);
199 UnwindPlan::Row::Row() : m_offset(0), m_cfa_value(), m_register_locations() {}
201 bool UnwindPlan::Row::GetRegisterInfo(
203 UnwindPlan::Row::RegisterLocation ®ister_location) const {
204 collection::const_iterator pos = m_register_locations.find(reg_num);
205 if (pos != m_register_locations.end()) {
206 register_location = pos->second;
212 void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) {
213 collection::const_iterator pos = m_register_locations.find(reg_num);
214 if (pos != m_register_locations.end()) {
215 m_register_locations.erase(pos);
219 void UnwindPlan::Row::SetRegisterInfo(
221 const UnwindPlan::Row::RegisterLocation register_location) {
222 m_register_locations[reg_num] = register_location;
225 bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,
229 m_register_locations.find(reg_num) != m_register_locations.end())
231 RegisterLocation reg_loc;
232 reg_loc.SetAtCFAPlusOffset(offset);
233 m_register_locations[reg_num] = reg_loc;
237 bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,
241 m_register_locations.find(reg_num) != m_register_locations.end())
243 RegisterLocation reg_loc;
244 reg_loc.SetIsCFAPlusOffset(offset);
245 m_register_locations[reg_num] = reg_loc;
249 bool UnwindPlan::Row::SetRegisterLocationToUndefined(
250 uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) {
251 collection::iterator pos = m_register_locations.find(reg_num);
252 collection::iterator end = m_register_locations.end();
257 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
260 RegisterLocation reg_loc;
261 reg_loc.SetUndefined();
262 m_register_locations[reg_num] = reg_loc;
266 bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num,
269 m_register_locations.find(reg_num) != m_register_locations.end())
271 RegisterLocation reg_loc;
272 reg_loc.SetUnspecified();
273 m_register_locations[reg_num] = reg_loc;
277 bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num,
278 uint32_t other_reg_num,
281 m_register_locations.find(reg_num) != m_register_locations.end())
283 RegisterLocation reg_loc;
284 reg_loc.SetInRegister(other_reg_num);
285 m_register_locations[reg_num] = reg_loc;
289 bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,
292 m_register_locations.find(reg_num) == m_register_locations.end())
294 RegisterLocation reg_loc;
296 m_register_locations[reg_num] = reg_loc;
300 bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
301 return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
302 m_register_locations == rhs.m_register_locations;
305 void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) {
306 if (m_row_list.empty() ||
307 m_row_list.back()->GetOffset() != row_sp->GetOffset())
308 m_row_list.push_back(row_sp);
310 m_row_list.back() = row_sp;
313 void UnwindPlan::InsertRow(const UnwindPlan::RowSP &row_sp,
314 bool replace_existing) {
315 collection::iterator it = m_row_list.begin();
316 while (it != m_row_list.end()) {
318 if (row->GetOffset() >= row_sp->GetOffset())
322 if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
323 m_row_list.insert(it, row_sp);
324 else if (replace_existing)
328 UnwindPlan::RowSP UnwindPlan::GetRowForFunctionOffset(int offset) const {
330 if (!m_row_list.empty()) {
332 row = m_row_list.back();
334 collection::const_iterator pos, end = m_row_list.end();
335 for (pos = m_row_list.begin(); pos != end; ++pos) {
336 if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
346 bool UnwindPlan::IsValidRowIndex(uint32_t idx) const {
347 return idx < m_row_list.size();
350 const UnwindPlan::RowSP UnwindPlan::GetRowAtIndex(uint32_t idx) const {
351 if (idx < m_row_list.size())
352 return m_row_list[idx];
354 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
356 log->Printf("error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index "
357 "(number rows is %u)",
358 idx, (uint32_t)m_row_list.size());
359 return UnwindPlan::RowSP();
363 const UnwindPlan::RowSP UnwindPlan::GetLastRow() const {
364 if (m_row_list.empty()) {
365 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
367 log->Printf("UnwindPlan::GetLastRow() when rows are empty");
368 return UnwindPlan::RowSP();
370 return m_row_list.back();
373 int UnwindPlan::GetRowCount() const { return m_row_list.size(); }
375 void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) {
376 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
377 m_plan_valid_address_range = range;
380 bool UnwindPlan::PlanValidAtAddress(Address addr) {
381 // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
382 if (GetRowCount() == 0) {
383 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
386 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
387 log->Printf("UnwindPlan is invalid -- no unwind rows for UnwindPlan "
388 "'%s' at address %s",
389 m_source_name.GetCString(), s.GetData());
392 "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
393 m_source_name.GetCString());
399 // If the 0th Row of unwind instructions is missing, or if it doesn't provide
400 // a register to use to find the Canonical Frame Address, this is not a valid
402 if (GetRowAtIndex(0).get() == nullptr ||
403 GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
404 Row::CFAValue::unspecified) {
405 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
408 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
409 log->Printf("UnwindPlan is invalid -- no CFA register defined in row 0 "
410 "for UnwindPlan '%s' at address %s",
411 m_source_name.GetCString(), s.GetData());
413 log->Printf("UnwindPlan is invalid -- no CFA register defined in row 0 "
414 "for UnwindPlan '%s'",
415 m_source_name.GetCString());
421 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() ||
422 m_plan_valid_address_range.GetByteSize() == 0)
428 if (m_plan_valid_address_range.ContainsFileAddress(addr))
434 void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
435 if (!m_source_name.IsEmpty()) {
436 s.Printf("This UnwindPlan originally sourced from %s\n",
437 m_source_name.GetCString());
439 if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) {
440 TargetSP target_sp(thread->CalculateTarget());
441 addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get());
442 addr_t personality_func_load_addr =
443 m_personality_func_addr.GetLoadAddress(target_sp.get());
445 if (lsda_load_addr != LLDB_INVALID_ADDRESS &&
446 personality_func_load_addr != LLDB_INVALID_ADDRESS) {
447 s.Printf("LSDA address 0x%" PRIx64
448 ", personality routine is at address 0x%" PRIx64 "\n",
449 lsda_load_addr, personality_func_load_addr);
452 s.Printf("This UnwindPlan is sourced from the compiler: ");
453 switch (m_plan_is_sourced_from_compiler) {
460 case eLazyBoolCalculate:
461 s.Printf("not specified.\n");
464 s.Printf("This UnwindPlan is valid at all instruction locations: ");
465 switch (m_plan_is_valid_at_all_instruction_locations) {
472 case eLazyBoolCalculate:
473 s.Printf("not specified.\n");
476 if (m_plan_valid_address_range.GetBaseAddress().IsValid() &&
477 m_plan_valid_address_range.GetByteSize() > 0) {
478 s.PutCString("Address range of this UnwindPlan: ");
479 TargetSP target_sp(thread->CalculateTarget());
480 m_plan_valid_address_range.Dump(&s, target_sp.get(),
481 Address::DumpStyleSectionNameOffset);
484 collection::const_iterator pos, begin = m_row_list.begin(),
485 end = m_row_list.end();
486 for (pos = begin; pos != end; ++pos) {
487 s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos));
488 (*pos)->Dump(s, this, thread, base_addr);
492 void UnwindPlan::SetSourceName(const char *source) {
493 m_source_name = ConstString(source);
496 ConstString UnwindPlan::GetSourceName() const { return m_source_name; }
498 const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread,
499 uint32_t unwind_reg) const {
501 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
504 if (m_register_kind == eRegisterKindLLDB)
507 reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind,
509 if (reg != LLDB_INVALID_REGNUM)
510 return reg_ctx->GetRegisterInfoAtIndex(reg);