blob: a4651717681e9c03931a8d50ba4e350d67a02a8d [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
109 s.Printf (" (reg(%u)%+d)", cfa_reg_info->name, offset);
110 }
111 else
112 {
113 if (cfa_reg_info)
114 s.Printf ("%s", cfa_reg_info->name);
115 else
116 s.Printf ("reg(%u)", cfa_reg_info->name);
117 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
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000169 s.Printf ("0x%8.8x: CFA=", GetOffset());
170
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
298void
299UnwindPlan::AppendRow (const UnwindPlan::Row &row)
300{
301 if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset())
302 m_row_list.push_back(row);
303 else
304 m_row_list.back() = row;
305}
306
307const UnwindPlan::Row *
308UnwindPlan::GetRowForFunctionOffset (int offset) const
309{
Greg Clayton877aaa52011-01-08 21:19:00 +0000310 const UnwindPlan::Row *row_ptr = NULL;
311 if (!m_row_list.empty())
Jason Molendaab4f1922010-10-25 11:12:07 +0000312 {
Greg Clayton877aaa52011-01-08 21:19:00 +0000313 if (offset == -1)
314 row_ptr = &m_row_list.back();
Jason Molendafbcb7f22010-09-10 07:49:16 +0000315 else
316 {
Greg Clayton877aaa52011-01-08 21:19:00 +0000317 collection::const_iterator pos, end = m_row_list.end();
318 for (pos = m_row_list.begin(); pos != end; ++pos)
319 {
320 if (pos->GetOffset() <= offset)
321 row_ptr = &*pos;
322 else
323 break;
324 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000325 }
326 }
Greg Clayton877aaa52011-01-08 21:19:00 +0000327 return row_ptr;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000328}
329
330bool
331UnwindPlan::IsValidRowIndex (uint32_t idx) const
332{
333 return idx < m_row_list.size();
334}
335
336const UnwindPlan::Row&
337UnwindPlan::GetRowAtIndex (uint32_t idx) const
338{
339 // You must call IsValidRowIndex(idx) first before calling this!!!
Greg Clayton877aaa52011-01-08 21:19:00 +0000340 assert (idx < m_row_list.size());
Jason Molendafbcb7f22010-09-10 07:49:16 +0000341 return m_row_list[idx];
342}
343
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000344const UnwindPlan::Row&
345UnwindPlan::GetLastRow () const
346{
347 // You must call GetRowCount() first to make sure there is at least one row
348 assert (!m_row_list.empty());
349 return m_row_list.back();
350}
351
Jason Molendafbcb7f22010-09-10 07:49:16 +0000352int
353UnwindPlan::GetRowCount () const
354{
355 return m_row_list.size ();
356}
357
358void
Jason Molendafbcb7f22010-09-10 07:49:16 +0000359UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
360{
Jason Molendaab4f1922010-10-25 11:12:07 +0000361 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
Jason Molendaab4f1922010-10-25 11:12:07 +0000362 m_plan_valid_address_range = range;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000363}
364
365bool
366UnwindPlan::PlanValidAtAddress (Address addr)
367{
Jason Molendaab4f1922010-10-25 11:12:07 +0000368 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
Jason Molendafbcb7f22010-09-10 07:49:16 +0000369 return true;
370
Jason Molenda59762002010-11-04 00:53:20 +0000371 if (!addr.IsValid())
372 return true;
373
Jason Molendafbcb7f22010-09-10 07:49:16 +0000374 if (m_plan_valid_address_range.ContainsFileAddress (addr))
375 return true;
376
377 return false;
378}
379
380void
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000381UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
Jason Molendafbcb7f22010-09-10 07:49:16 +0000382{
Jason Molendaab4f1922010-10-25 11:12:07 +0000383 if (!m_source_name.IsEmpty())
384 {
385 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
386 }
387 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
388 {
Greg Clayton877aaa52011-01-08 21:19:00 +0000389 s.PutCString ("Address range of this UnwindPlan: ");
Jason Molendaab4f1922010-10-25 11:12:07 +0000390 m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset);
Greg Clayton877aaa52011-01-08 21:19:00 +0000391 s.EOL();
Jason Molendaab4f1922010-10-25 11:12:07 +0000392 }
393 else
394 {
Greg Clayton877aaa52011-01-08 21:19:00 +0000395 s.PutCString ("No valid address range recorded for this UnwindPlan.\n");
Jason Molendaab4f1922010-10-25 11:12:07 +0000396 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000397 s.Printf ("UnwindPlan register kind %d", m_register_kind);
398 switch (m_register_kind)
399 {
Greg Clayton877aaa52011-01-08 21:19:00 +0000400 case eRegisterKindGCC: s.PutCString (" [eRegisterKindGCC]"); break;
401 case eRegisterKindDWARF: s.PutCString (" [eRegisterKindDWARF]"); break;
402 case eRegisterKindGeneric: s.PutCString (" [eRegisterKindGeneric]"); break;
403 case eRegisterKindGDB: s.PutCString (" [eRegisterKindGDB]"); break;
404 case eRegisterKindLLDB: s.PutCString (" [eRegisterKindLLDB]"); break;
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000405 default: s.PutCString (" [eRegisterKind???]"); break;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000406 }
Greg Clayton877aaa52011-01-08 21:19:00 +0000407 s.EOL();
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000408 collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end();
409 for (pos = begin; pos != end; ++pos)
Jason Molendafbcb7f22010-09-10 07:49:16 +0000410 {
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000411 s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos));
412 pos->Dump(s, this, thread, base_addr);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000413 }
414}
Jason Molendaab4f1922010-10-25 11:12:07 +0000415
416void
417UnwindPlan::SetSourceName (const char *source)
418{
419 m_source_name = ConstString (source);
420}
421
422ConstString
423UnwindPlan::GetSourceName () const
424{
425 return m_source_name;
426}
Greg Clayton31f1d2f2011-05-11 18:39:18 +0000427
428const RegisterInfo *
429UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
430{
431 if (thread)
432 {
433 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
434 if (reg_ctx)
435 {
436 uint32_t reg;
437 if (m_register_kind == eRegisterKindLLDB)
438 reg = unwind_reg;
439 else
440 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg);
441 if (reg != LLDB_INVALID_REGNUM)
442 return reg_ctx->GetRegisterInfoAtIndex (reg);
443 }
444 }
445 return NULL;
446}
447