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/Target/Process.h"
14 #include "lldb/Target/RegisterContext.h"
15 #include "lldb/Target/Thread.h"
18 using namespace lldb_private;
21 UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
23 if (m_type == rhs.m_type)
34 return m_location.offset == rhs.m_location.offset;
37 return m_location.reg_num == rhs.m_location.reg_num;
39 case atDWARFExpression:
40 case isDWARFExpression:
41 if (m_location.expr.length == rhs.m_location.expr.length)
42 return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length);
49 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
50 // memory for the lifespan of this UnwindPlan object.
52 UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len)
54 m_type = atDWARFExpression;
55 m_location.expr.opcodes = opcodes;
56 m_location.expr.length = len;
59 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
60 // memory for the lifespan of this UnwindPlan object.
62 UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
64 m_type = isDWARFExpression;
65 m_location.expr.opcodes = opcodes;
66 m_location.expr.length = len;
70 UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_plan, const UnwindPlan::Row* row, Thread* thread, bool verbose) const
76 s.PutCString ("=<unspec>");
82 s.PutCString ("=<undef>");
87 s.PutCString ("= <same>");
94 if (m_type == atCFAPlusOffset)
97 s.Printf ("CFA%+d", m_location.offset);
99 if (unwind_plan && row)
101 const uint32_t cfa_reg = row->GetCFARegister();
102 const RegisterInfo *cfa_reg_info = unwind_plan->GetRegisterInfo (thread, cfa_reg);
103 const int32_t offset = row->GetCFAOffset() + m_location.offset;
107 s.Printf (" (%s%+d)", cfa_reg_info->name, offset);
109 s.Printf (" (reg(%u)%+d)", cfa_reg, offset);
114 s.Printf ("%s", cfa_reg_info->name);
116 s.Printf ("reg(%u)", cfa_reg);
118 s.Printf ("%+d", offset);
121 if (m_type == atCFAPlusOffset)
126 case inOtherRegister:
128 const RegisterInfo *other_reg_info = NULL;
130 other_reg_info = unwind_plan->GetRegisterInfo (thread, m_location.reg_num);
132 s.Printf ("=%s", other_reg_info->name);
134 s.Printf ("=reg(%u)", m_location.reg_num);
138 case atDWARFExpression:
139 case isDWARFExpression:
142 if (m_type == atDWARFExpression)
143 s.PutCString("[dwarf-expr]");
145 s.PutCString("dwarf-expr");
153 UnwindPlan::Row::Clear ()
156 m_cfa_reg_num = LLDB_INVALID_REGNUM;
158 m_register_locations.clear();
162 UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const
164 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister());
166 if (base_addr != LLDB_INVALID_ADDRESS)
167 s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
169 s.Printf ("0x%8.8" PRIx64 ": CFA=", GetOffset());
172 s.Printf ("%s", reg_info->name);
174 s.Printf ("reg(%u)", GetCFARegister());
175 s.Printf ("%+3d => ", GetCFAOffset ());
176 for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
178 reg_info = unwind_plan->GetRegisterInfo (thread, idx->first);
180 s.Printf ("%s", reg_info->name);
182 s.Printf ("reg(%u)", idx->first);
183 const bool verbose = false;
184 idx->second.Dump(s, unwind_plan, this, thread, verbose);
190 UnwindPlan::Row::Row() :
192 m_cfa_reg_num(LLDB_INVALID_REGNUM),
194 m_register_locations()
199 UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const
201 collection::const_iterator pos = m_register_locations.find(reg_num);
202 if (pos != m_register_locations.end())
204 register_location = pos->second;
211 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
213 m_register_locations[reg_num] = register_location;
217 UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
219 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
221 RegisterLocation reg_loc;
222 reg_loc.SetAtCFAPlusOffset(offset);
223 m_register_locations[reg_num] = reg_loc;
228 UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
230 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
232 RegisterLocation reg_loc;
233 reg_loc.SetIsCFAPlusOffset(offset);
234 m_register_locations[reg_num] = reg_loc;
239 UnwindPlan::Row::SetRegisterLocationToUndefined (uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified)
241 collection::iterator pos = m_register_locations.find(reg_num);
242 collection::iterator end = m_register_locations.end();
248 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
251 RegisterLocation reg_loc;
252 reg_loc.SetUndefined();
253 m_register_locations[reg_num] = reg_loc;
258 UnwindPlan::Row::SetRegisterLocationToUnspecified (uint32_t reg_num, bool can_replace)
260 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
262 RegisterLocation reg_loc;
263 reg_loc.SetUnspecified();
264 m_register_locations[reg_num] = reg_loc;
269 UnwindPlan::Row::SetRegisterLocationToRegister (uint32_t reg_num,
270 uint32_t other_reg_num,
273 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
275 RegisterLocation reg_loc;
276 reg_loc.SetInRegister(other_reg_num);
277 m_register_locations[reg_num] = reg_loc;
282 UnwindPlan::Row::SetRegisterLocationToSame (uint32_t reg_num, bool must_replace)
284 if (must_replace && m_register_locations.find(reg_num) == m_register_locations.end())
286 RegisterLocation reg_loc;
288 m_register_locations[reg_num] = reg_loc;
293 UnwindPlan::Row::SetCFARegister (uint32_t reg_num)
295 m_cfa_reg_num = reg_num;
299 UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const
301 if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset)
303 return m_register_locations == rhs.m_register_locations;
307 UnwindPlan::AppendRow (const UnwindPlan::RowSP &row_sp)
309 if (m_row_list.empty() || m_row_list.back()->GetOffset() != row_sp->GetOffset())
310 m_row_list.push_back(row_sp);
312 m_row_list.back() = row_sp;
316 UnwindPlan::GetRowForFunctionOffset (int offset) const
319 if (!m_row_list.empty())
322 row = m_row_list.back();
325 collection::const_iterator pos, end = m_row_list.end();
326 for (pos = m_row_list.begin(); pos != end; ++pos)
328 if ((*pos)->GetOffset() <= offset)
339 UnwindPlan::IsValidRowIndex (uint32_t idx) const
341 return idx < m_row_list.size();
344 const UnwindPlan::RowSP
345 UnwindPlan::GetRowAtIndex (uint32_t idx) const
347 // You must call IsValidRowIndex(idx) first before calling this!!!
348 assert (idx < m_row_list.size());
349 return m_row_list[idx];
352 const UnwindPlan::RowSP
353 UnwindPlan::GetLastRow () const
355 // You must call GetRowCount() first to make sure there is at least one row
356 assert (!m_row_list.empty());
357 return m_row_list.back();
361 UnwindPlan::GetRowCount () const
363 return m_row_list.size ();
367 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
369 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
370 m_plan_valid_address_range = range;
374 UnwindPlan::PlanValidAtAddress (Address addr)
376 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
382 if (m_plan_valid_address_range.ContainsFileAddress (addr))
389 UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
391 if (!m_source_name.IsEmpty())
393 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
395 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
397 s.PutCString ("Address range of this UnwindPlan: ");
398 TargetSP target_sp(thread->CalculateTarget());
399 m_plan_valid_address_range.Dump (&s, target_sp.get(), Address::DumpStyleSectionNameOffset);
402 collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end();
403 for (pos = begin; pos != end; ++pos)
405 s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos));
406 (*pos)->Dump(s, this, thread, base_addr);
411 UnwindPlan::SetSourceName (const char *source)
413 m_source_name = ConstString (source);
417 UnwindPlan::GetSourceName () const
419 return m_source_name;
423 UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
427 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
431 if (m_register_kind == eRegisterKindLLDB)
434 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg);
435 if (reg != LLDB_INVALID_REGNUM)
436 return reg_ctx->GetRegisterInfoAtIndex (reg);