blob: d5ed73f83ed4decbf3175e966ce01cc9a97df5fd [file] [log] [blame]
Jason Molendafbcb7f22010-09-10 07:49:16 +00001//===-- UnwindPlan.cpp ----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/Symbol/UnwindPlan.h"
Greg Clayton79ea8782011-04-26 23:48:45 +000011
12#include "lldb/Core/ConstString.h"
Greg Claytonf5e56de2010-09-14 23:36:40 +000013#include "lldb/Target/Process.h"
Jason Molendafbcb7f22010-09-10 07:49:16 +000014#include "lldb/Target/RegisterContext.h"
Greg Claytonf5e56de2010-09-14 23:36:40 +000015#include "lldb/Target/Thread.h"
Jason Molendafbcb7f22010-09-10 07:49:16 +000016
17using namespace lldb;
18using namespace lldb_private;
19
20bool
21UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
22{
Greg Clayton31f1d2f2011-05-11 18:39:18 +000023 if (m_type == rhs.m_type)
24 {
25 switch (m_type)
26 {
27 case unspecified:
28 case undefined:
29 case same:
30 return true;
31
32 case atCFAPlusOffset:
33 case isCFAPlusOffset:
34 return m_location.offset == rhs.m_location.offset;
35
36 case inOtherRegister:
37 return m_location.reg_num == rhs.m_location.reg_num;
38
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);
43 break;
44 }
45 }
Jason Molendafbcb7f22010-09-10 07:49:16 +000046 return false;
47}
48
49// This function doesn't copy the dwarf expression bytes; they must remain in allocated
50// memory for the lifespan of this UnwindPlan object.
51void
52UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len)
53{
54 m_type = atDWARFExpression;
55 m_location.expr.opcodes = opcodes;
56 m_location.expr.length = len;
57}
58
59// This function doesn't copy the dwarf expression bytes; they must remain in allocated
60// memory for the lifespan of this UnwindPlan object.
61void
62UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
63{
64 m_type = isDWARFExpression;
65 m_location.expr.opcodes = opcodes;
66 m_location.expr.length = len;
67}
68
69void
Greg Clayton31f1d2f2011-05-11 18:39:18 +000070UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_plan, const UnwindPlan::Row* row, Thread* thread, bool verbose) const
Jason Molendafbcb7f22010-09-10 07:49:16 +000071{
72 switch (m_type)
73 {
74 case unspecified:
Greg Clayton31f1d2f2011-05-11 18:39:18 +000075 if (verbose)
76 s.PutCString ("=<unspec>");
77 else
78 s.PutCString ("=!");
Jason Molendafbcb7f22010-09-10 07:49:16 +000079 break;
Greg Clayton31f1d2f2011-05-11 18:39:18 +000080 case undefined:
81 if (verbose)
82 s.PutCString ("=<undef>");
83 else
84 s.PutCString ("=?");
Jason Molendafbcb7f22010-09-10 07:49:16 +000085 break;
Greg Clayton31f1d2f2011-05-11 18:39:18 +000086 case same:
87 s.PutCString ("= <same>");
Jason Molendafbcb7f22010-09-10 07:49:16 +000088 break;
Greg Clayton31f1d2f2011-05-11 18:39:18 +000089
Jason Molendafbcb7f22010-09-10 07:49:16 +000090 case atCFAPlusOffset:
Jason Molendafbcb7f22010-09-10 07:49:16 +000091 case isCFAPlusOffset:
Greg Clayton31f1d2f2011-05-11 18:39:18 +000092 {
93 s.PutChar('=');
94 if (m_type == atCFAPlusOffset)
95 s.PutChar('[');
96 if (verbose)
97 s.Printf ("CFA%+d", m_location.offset);
98
99 if (unwind_plan && row)
100 {
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;
104 if (verbose)
105 {
106 if (cfa_reg_info)
107 s.Printf (" (%s%+d)", cfa_reg_info->name, offset);
108 else
Johnny Chend397dc82011-08-12 00:02:24 +0000109 s.Printf (" (reg(%u)%+d)", cfa_reg, offset);
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000110 }
111 else
112 {
113 if (cfa_reg_info)
114 s.Printf ("%s", cfa_reg_info->name);
115 else
Johnny Chend397dc82011-08-12 00:02:24 +0000116 s.Printf ("reg(%u)", cfa_reg);
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000117 if (offset != 0)
118 s.Printf ("%+d", offset);
119 }
120 }
121 if (m_type == atCFAPlusOffset)
122 s.PutChar(']');
123 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000124 break;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000125
Jason Molendafbcb7f22010-09-10 07:49:16 +0000126 case inOtherRegister:
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000127 {
128 const RegisterInfo *other_reg_info = NULL;
129 if (unwind_plan)
130 other_reg_info = unwind_plan->GetRegisterInfo (thread, m_location.reg_num);
131 if (other_reg_info)
132 s.Printf ("=%s", other_reg_info->name);
133 else
134 s.Printf ("=reg(%u)", m_location.reg_num);
135 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000136 break;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000137
Jason Molendafbcb7f22010-09-10 07:49:16 +0000138 case atDWARFExpression:
Jason Molendafbcb7f22010-09-10 07:49:16 +0000139 case isDWARFExpression:
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000140 {
141 s.PutChar('=');
142 if (m_type == atDWARFExpression)
143 s.PutCString("[dwarf-expr]");
144 else
145 s.PutCString("dwarf-expr");
146 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000147 break;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000148
Jason Molendafbcb7f22010-09-10 07:49:16 +0000149 }
150}
151
152void
153UnwindPlan::Row::Clear ()
154{
155 m_offset = 0;
156 m_cfa_reg_num = 0;
157 m_cfa_offset = 0;
158 m_register_locations.clear();
159}
160
161void
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000162UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const
Jason Molendafbcb7f22010-09-10 07:49:16 +0000163{
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000164 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister());
Greg Clayton5ccbd292011-01-06 22:15:06 +0000165
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000166 if (base_addr != LLDB_INVALID_ADDRESS)
167 s.Printf ("0x%16.16llx: CFA=", base_addr + GetOffset());
Jason Molendafbcb7f22010-09-10 07:49:16 +0000168 else
Jason Molendafd54b362011-09-20 21:44:10 +0000169 s.Printf ("0x%8.8llx: CFA=", GetOffset());
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000170
171 if (reg_info)
172 s.Printf ("%s", reg_info->name);
173 else
174 s.Printf ("reg(%u)", GetCFARegister());
175 s.Printf ("%+3d =>", GetCFAOffset ());
Jason Molendafbcb7f22010-09-10 07:49:16 +0000176 for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
177 {
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000178 reg_info = unwind_plan->GetRegisterInfo (thread, idx->first);
179 if (reg_info)
180 s.Printf ("%s", reg_info->name);
181 else
182 s.Printf ("reg(%u)", idx->first);
183 const bool verbose = false;
184 idx->second.Dump(s, unwind_plan, this, thread, verbose);
185 s.PutChar (' ');
Jason Molendafbcb7f22010-09-10 07:49:16 +0000186 }
Greg Clayton877aaa52011-01-08 21:19:00 +0000187 s.EOL();
Jason Molendafbcb7f22010-09-10 07:49:16 +0000188}
189
190UnwindPlan::Row::Row() :
191 m_offset(0),
192 m_cfa_reg_num(0),
193 m_cfa_offset(0),
194 m_register_locations()
195{
196}
197
198bool
199UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const
200{
201 collection::const_iterator pos = m_register_locations.find(reg_num);
202 if (pos != m_register_locations.end())
203 {
204 register_location = pos->second;
205 return true;
206 }
207 return false;
208}
209
210void
211UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
212{
213 m_register_locations[reg_num] = register_location;
214}
215
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000216bool
217UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
218{
219 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
220 return false;
221 RegisterLocation reg_loc;
222 reg_loc.SetAtCFAPlusOffset(offset);
223 m_register_locations[reg_num] = reg_loc;
224 return true;
225}
226
227bool
228UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
229{
230 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
231 return false;
232 RegisterLocation reg_loc;
233 reg_loc.SetIsCFAPlusOffset(offset);
234 m_register_locations[reg_num] = reg_loc;
235 return true;
236}
237
238bool
239UnwindPlan::Row::SetRegisterLocationToUndefined (uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified)
240{
241 collection::iterator pos = m_register_locations.find(reg_num);
242 collection::iterator end = m_register_locations.end();
243
244 if (pos != end)
245 {
246 if (!can_replace)
247 return false;
248 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
249 return false;
250 }
251 RegisterLocation reg_loc;
252 reg_loc.SetUndefined();
253 m_register_locations[reg_num] = reg_loc;
254 return true;
255}
256
257bool
258UnwindPlan::Row::SetRegisterLocationToUnspecified (uint32_t reg_num, bool can_replace)
259{
260 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
261 return false;
262 RegisterLocation reg_loc;
263 reg_loc.SetUnspecified();
264 m_register_locations[reg_num] = reg_loc;
265 return true;
266}
267
268bool
269UnwindPlan::Row::SetRegisterLocationToRegister (uint32_t reg_num,
270 uint32_t other_reg_num,
271 bool can_replace)
272{
273 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
274 return false;
275 RegisterLocation reg_loc;
276 reg_loc.SetInRegister(other_reg_num);
277 m_register_locations[reg_num] = reg_loc;
278 return true;
279}
280
281bool
282UnwindPlan::Row::SetRegisterLocationToSame (uint32_t reg_num, bool must_replace)
283{
284 if (must_replace && m_register_locations.find(reg_num) == m_register_locations.end())
285 return false;
286 RegisterLocation reg_loc;
287 reg_loc.SetSame();
288 m_register_locations[reg_num] = reg_loc;
289 return true;
290}
291
292void
293UnwindPlan::Row::SetCFARegister (uint32_t reg_num)
294{
295 m_cfa_reg_num = reg_num;
296}
Jason Molendafbcb7f22010-09-10 07:49:16 +0000297
Jason Molenda24a83782012-07-17 01:57:24 +0000298bool
299UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const
300{
301 if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset)
302 return false;
303 if (m_register_locations.size() != rhs.m_register_locations.size())
304 return false;
305 for (collection::const_iterator idx = m_register_locations.begin(); idx != m_register_locations.end(); ++idx)
306 {
307 collection::const_iterator lhs_pos = m_register_locations.find(idx->first);
308 collection::const_iterator rhs_pos = rhs.m_register_locations.find(idx->first);
309 if (lhs_pos->second != rhs_pos->second)
310 return false;
311 }
312 return true;
313}
314
Jason Molendafbcb7f22010-09-10 07:49:16 +0000315void
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000316UnwindPlan::AppendRow (UnwindPlan::RowSP row)
Jason Molendafbcb7f22010-09-10 07:49:16 +0000317{
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000318 if (m_row_list.empty() || m_row_list.back()->GetOffset() != row->GetOffset())
Jason Molendafbcb7f22010-09-10 07:49:16 +0000319 m_row_list.push_back(row);
320 else
321 m_row_list.back() = row;
322}
323
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000324UnwindPlan::RowSP
Jason Molendafbcb7f22010-09-10 07:49:16 +0000325UnwindPlan::GetRowForFunctionOffset (int offset) const
326{
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000327 RowSP row;
Greg Clayton877aaa52011-01-08 21:19:00 +0000328 if (!m_row_list.empty())
Jason Molendaab4f1922010-10-25 11:12:07 +0000329 {
Greg Clayton877aaa52011-01-08 21:19:00 +0000330 if (offset == -1)
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000331 row = m_row_list.back();
Jason Molendafbcb7f22010-09-10 07:49:16 +0000332 else
333 {
Greg Clayton877aaa52011-01-08 21:19:00 +0000334 collection::const_iterator pos, end = m_row_list.end();
335 for (pos = m_row_list.begin(); pos != end; ++pos)
336 {
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000337 if ((*pos)->GetOffset() <= offset)
338 row = *pos;
Greg Clayton877aaa52011-01-08 21:19:00 +0000339 else
340 break;
341 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000342 }
343 }
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000344 return row;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000345}
346
347bool
348UnwindPlan::IsValidRowIndex (uint32_t idx) const
349{
350 return idx < m_row_list.size();
351}
352
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000353const UnwindPlan::RowSP
Jason Molendafbcb7f22010-09-10 07:49:16 +0000354UnwindPlan::GetRowAtIndex (uint32_t idx) const
355{
356 // You must call IsValidRowIndex(idx) first before calling this!!!
Greg Clayton877aaa52011-01-08 21:19:00 +0000357 assert (idx < m_row_list.size());
Jason Molendafbcb7f22010-09-10 07:49:16 +0000358 return m_row_list[idx];
359}
360
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000361const UnwindPlan::RowSP
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000362UnwindPlan::GetLastRow () const
363{
364 // You must call GetRowCount() first to make sure there is at least one row
365 assert (!m_row_list.empty());
366 return m_row_list.back();
367}
368
Jason Molendafbcb7f22010-09-10 07:49:16 +0000369int
370UnwindPlan::GetRowCount () const
371{
372 return m_row_list.size ();
373}
374
375void
Jason Molendafbcb7f22010-09-10 07:49:16 +0000376UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
377{
Jason Molendaab4f1922010-10-25 11:12:07 +0000378 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
Jason Molendaab4f1922010-10-25 11:12:07 +0000379 m_plan_valid_address_range = range;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000380}
381
382bool
383UnwindPlan::PlanValidAtAddress (Address addr)
384{
Jason Molendaab4f1922010-10-25 11:12:07 +0000385 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
Jason Molendafbcb7f22010-09-10 07:49:16 +0000386 return true;
387
Jason Molenda59762002010-11-04 00:53:20 +0000388 if (!addr.IsValid())
389 return true;
390
Jason Molendafbcb7f22010-09-10 07:49:16 +0000391 if (m_plan_valid_address_range.ContainsFileAddress (addr))
392 return true;
393
394 return false;
395}
396
397void
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000398UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
Jason Molendafbcb7f22010-09-10 07:49:16 +0000399{
Jason Molendaab4f1922010-10-25 11:12:07 +0000400 if (!m_source_name.IsEmpty())
401 {
402 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
403 }
404 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
405 {
Greg Clayton877aaa52011-01-08 21:19:00 +0000406 s.PutCString ("Address range of this UnwindPlan: ");
Greg Clayton1ac04c32012-02-21 00:09:25 +0000407 TargetSP target_sp(thread->CalculateTarget());
408 m_plan_valid_address_range.Dump (&s, target_sp.get(), Address::DumpStyleSectionNameOffset);
Greg Clayton877aaa52011-01-08 21:19:00 +0000409 s.EOL();
Jason Molendaab4f1922010-10-25 11:12:07 +0000410 }
411 else
412 {
Greg Clayton877aaa52011-01-08 21:19:00 +0000413 s.PutCString ("No valid address range recorded for this UnwindPlan.\n");
Jason Molendaab4f1922010-10-25 11:12:07 +0000414 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000415 s.Printf ("UnwindPlan register kind %d", m_register_kind);
416 switch (m_register_kind)
417 {
Greg Clayton877aaa52011-01-08 21:19:00 +0000418 case eRegisterKindGCC: s.PutCString (" [eRegisterKindGCC]"); break;
419 case eRegisterKindDWARF: s.PutCString (" [eRegisterKindDWARF]"); break;
420 case eRegisterKindGeneric: s.PutCString (" [eRegisterKindGeneric]"); break;
421 case eRegisterKindGDB: s.PutCString (" [eRegisterKindGDB]"); break;
422 case eRegisterKindLLDB: s.PutCString (" [eRegisterKindLLDB]"); break;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000423 default: s.PutCString (" [eRegisterKind???]"); break;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000424 }
Greg Clayton877aaa52011-01-08 21:19:00 +0000425 s.EOL();
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000426 collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end();
427 for (pos = begin; pos != end; ++pos)
Jason Molendafbcb7f22010-09-10 07:49:16 +0000428 {
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000429 s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos));
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000430 (*pos)->Dump(s, this, thread, base_addr);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000431 }
432}
Jason Molendaab4f1922010-10-25 11:12:07 +0000433
434void
435UnwindPlan::SetSourceName (const char *source)
436{
437 m_source_name = ConstString (source);
438}
439
440ConstString
441UnwindPlan::GetSourceName () const
442{
443 return m_source_name;
444}
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000445
446const RegisterInfo *
447UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
448{
449 if (thread)
450 {
451 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
452 if (reg_ctx)
453 {
454 uint32_t reg;
455 if (m_register_kind == eRegisterKindLLDB)
456 reg = unwind_reg;
457 else
458 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg);
459 if (reg != LLDB_INVALID_REGNUM)
460 return reg_ctx->GetRegisterInfoAtIndex (reg);
461 }
462 }
463 return NULL;
464}
465