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/Core/ConstString.h"
13 #include "lldb/Core/Log.h"
14 #include "lldb/Target/Process.h"
15 #include "lldb/Target/RegisterContext.h"
16 #include "lldb/Target/Thread.h"
19 using namespace lldb_private;
22 UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
24 if (m_type == rhs.m_type)
35 return m_location.offset == rhs.m_location.offset;
38 return m_location.reg_num == rhs.m_location.reg_num;
40 case atDWARFExpression:
41 case isDWARFExpression:
42 if (m_location.expr.length == rhs.m_location.expr.length)
43 return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length);
50 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
51 // memory for the lifespan of this UnwindPlan object.
53 UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len)
55 m_type = atDWARFExpression;
56 m_location.expr.opcodes = opcodes;
57 m_location.expr.length = len;
60 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
61 // memory for the lifespan of this UnwindPlan object.
63 UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
65 m_type = isDWARFExpression;
66 m_location.expr.opcodes = opcodes;
67 m_location.expr.length = len;
71 UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_plan, const UnwindPlan::Row* row, Thread* thread, bool verbose) const
77 s.PutCString ("=<unspec>");
83 s.PutCString ("=<undef>");
88 s.PutCString ("= <same>");
95 if (m_type == atCFAPlusOffset)
97 s.Printf ("CFA%+d", m_location.offset);
98 if (m_type == atCFAPlusOffset)
103 case inOtherRegister:
105 const RegisterInfo *other_reg_info = nullptr;
107 other_reg_info = unwind_plan->GetRegisterInfo (thread, m_location.reg_num);
109 s.Printf ("=%s", other_reg_info->name);
111 s.Printf ("=reg(%u)", m_location.reg_num);
115 case atDWARFExpression:
116 case isDWARFExpression:
119 if (m_type == atDWARFExpression)
120 s.PutCString("[dwarf-expr]");
122 s.PutCString("dwarf-expr");
130 DumpRegisterName (Stream &s, const UnwindPlan* unwind_plan, Thread *thread, uint32_t reg_num) {
131 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, reg_num);
133 s.PutCString (reg_info->name);
135 s.Printf ("reg(%u)", reg_num);
139 UnwindPlan::Row::CFAValue::operator == (const UnwindPlan::Row::CFAValue& rhs) const
141 if (m_type == rhs.m_type)
148 case isRegisterPlusOffset:
149 return m_value.reg.offset == rhs.m_value.reg.offset;
151 case isRegisterDereferenced:
152 return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
154 case isDWARFExpression:
155 if (m_value.expr.length == rhs.m_value.expr.length)
156 return !memcmp (m_value.expr.opcodes, rhs.m_value.expr.opcodes, m_value.expr.length);
164 UnwindPlan::Row::CFAValue::Dump(Stream &s, const UnwindPlan* unwind_plan, Thread* thread) const
167 case isRegisterPlusOffset:
168 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
169 s.Printf ("%+3d", m_value.reg.offset);
171 case isRegisterDereferenced:
173 DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
176 case isDWARFExpression:
177 s.PutCString ("dwarf-expr");
180 s.PutCString ("unspecified");
186 UnwindPlan::Row::Clear ()
188 m_cfa_value.SetUnspecified();
190 m_register_locations.clear();
194 UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const
196 if (base_addr != LLDB_INVALID_ADDRESS)
197 s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
199 s.Printf ("%4" PRId64 ": CFA=", GetOffset());
201 m_cfa_value.Dump(s, unwind_plan, thread);
203 for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
205 DumpRegisterName(s, unwind_plan, thread, idx->first);
206 const bool verbose = false;
207 idx->second.Dump(s, unwind_plan, this, thread, verbose);
213 UnwindPlan::Row::Row() :
216 m_register_locations ()
221 UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const
223 collection::const_iterator pos = m_register_locations.find(reg_num);
224 if (pos != m_register_locations.end())
226 register_location = pos->second;
233 UnwindPlan::Row::RemoveRegisterInfo (uint32_t reg_num)
235 collection::const_iterator pos = m_register_locations.find(reg_num);
236 if (pos != m_register_locations.end())
238 m_register_locations.erase(pos);
243 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
245 m_register_locations[reg_num] = register_location;
249 UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
251 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
253 RegisterLocation reg_loc;
254 reg_loc.SetAtCFAPlusOffset(offset);
255 m_register_locations[reg_num] = reg_loc;
260 UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
262 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
264 RegisterLocation reg_loc;
265 reg_loc.SetIsCFAPlusOffset(offset);
266 m_register_locations[reg_num] = reg_loc;
271 UnwindPlan::Row::SetRegisterLocationToUndefined (uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified)
273 collection::iterator pos = m_register_locations.find(reg_num);
274 collection::iterator end = m_register_locations.end();
280 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
283 RegisterLocation reg_loc;
284 reg_loc.SetUndefined();
285 m_register_locations[reg_num] = reg_loc;
290 UnwindPlan::Row::SetRegisterLocationToUnspecified (uint32_t reg_num, bool can_replace)
292 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
294 RegisterLocation reg_loc;
295 reg_loc.SetUnspecified();
296 m_register_locations[reg_num] = reg_loc;
301 UnwindPlan::Row::SetRegisterLocationToRegister (uint32_t reg_num,
302 uint32_t other_reg_num,
305 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
307 RegisterLocation reg_loc;
308 reg_loc.SetInRegister(other_reg_num);
309 m_register_locations[reg_num] = reg_loc;
314 UnwindPlan::Row::SetRegisterLocationToSame (uint32_t reg_num, bool must_replace)
316 if (must_replace && m_register_locations.find(reg_num) == m_register_locations.end())
318 RegisterLocation reg_loc;
320 m_register_locations[reg_num] = reg_loc;
325 UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const
327 return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
328 m_register_locations == rhs.m_register_locations;
332 UnwindPlan::AppendRow (const UnwindPlan::RowSP &row_sp)
334 if (m_row_list.empty() || m_row_list.back()->GetOffset() != row_sp->GetOffset())
335 m_row_list.push_back(row_sp);
337 m_row_list.back() = row_sp;
341 UnwindPlan::InsertRow (const UnwindPlan::RowSP &row_sp)
343 collection::iterator it = m_row_list.begin();
344 while (it != m_row_list.end()) {
346 if (row->GetOffset() >= row_sp->GetOffset())
350 if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
351 m_row_list.insert(it, row_sp);
355 UnwindPlan::GetRowForFunctionOffset (int offset) const
358 if (!m_row_list.empty())
361 row = m_row_list.back();
364 collection::const_iterator pos, end = m_row_list.end();
365 for (pos = m_row_list.begin(); pos != end; ++pos)
367 if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
378 UnwindPlan::IsValidRowIndex (uint32_t idx) const
380 return idx < m_row_list.size();
383 const UnwindPlan::RowSP
384 UnwindPlan::GetRowAtIndex (uint32_t idx) const
386 // You must call IsValidRowIndex(idx) first before calling this!!!
387 assert (idx < m_row_list.size());
388 return m_row_list[idx];
391 const UnwindPlan::RowSP
392 UnwindPlan::GetLastRow () const
394 // You must call GetRowCount() first to make sure there is at least one row
395 assert (!m_row_list.empty());
396 return m_row_list.back();
400 UnwindPlan::GetRowCount () const
402 return m_row_list.size ();
406 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
408 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
409 m_plan_valid_address_range = range;
413 UnwindPlan::PlanValidAtAddress (Address addr)
415 // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
416 if (GetRowCount() == 0)
418 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
422 if (addr.Dump (&s, nullptr, Address::DumpStyleSectionNameOffset))
424 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s' at address %s",
425 m_source_name.GetCString(), s.GetData());
429 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
430 m_source_name.GetCString());
436 // If the 0th Row of unwind instructions is missing, or if it doesn't provide
437 // a register to use to find the Canonical Frame Address, this is not a valid UnwindPlan.
438 if (GetRowAtIndex(0).get() == nullptr ||
439 GetRowAtIndex(0)->GetCFAValue().GetValueType() == Row::CFAValue::unspecified)
441 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
445 if (addr.Dump (&s, nullptr, Address::DumpStyleSectionNameOffset))
447 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s' at address %s",
448 m_source_name.GetCString(), s.GetData());
452 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s'",
453 m_source_name.GetCString());
459 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
465 if (m_plan_valid_address_range.ContainsFileAddress (addr))
472 UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
474 if (!m_source_name.IsEmpty())
476 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
478 if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid())
480 TargetSP target_sp(thread->CalculateTarget());
481 addr_t lsda_load_addr = m_lsda_address.GetLoadAddress (target_sp.get());
482 addr_t personality_func_load_addr = m_personality_func_addr.GetLoadAddress (target_sp.get());
484 if (lsda_load_addr != LLDB_INVALID_ADDRESS && personality_func_load_addr != LLDB_INVALID_ADDRESS)
486 s.Printf("LSDA address 0x%" PRIx64 ", personality routine is at address 0x%" PRIx64 "\n",
487 lsda_load_addr, personality_func_load_addr);
490 s.Printf ("This UnwindPlan is sourced from the compiler: ");
491 switch (m_plan_is_sourced_from_compiler)
499 case eLazyBoolCalculate:
500 s.Printf ("not specified.\n");
503 s.Printf ("This UnwindPlan is valid at all instruction locations: ");
504 switch (m_plan_is_valid_at_all_instruction_locations)
512 case eLazyBoolCalculate:
513 s.Printf ("not specified.\n");
516 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
518 s.PutCString ("Address range of this UnwindPlan: ");
519 TargetSP target_sp(thread->CalculateTarget());
520 m_plan_valid_address_range.Dump (&s, target_sp.get(), Address::DumpStyleSectionNameOffset);
523 collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end();
524 for (pos = begin; pos != end; ++pos)
526 s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos));
527 (*pos)->Dump(s, this, thread, base_addr);
532 UnwindPlan::SetSourceName (const char *source)
534 m_source_name = ConstString (source);
538 UnwindPlan::GetSourceName () const
540 return m_source_name;
544 UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
548 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
552 if (m_register_kind == eRegisterKindLLDB)
555 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg);
556 if (reg != LLDB_INVALID_REGNUM)
557 return reg_ctx->GetRegisterInfoAtIndex (reg);