blob: 6f370de5a37a63db2eea2fa8342b723f643bd6c5 [file] [log] [blame]
Jason Molenda3a4ea242010-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 Claytoneea26402010-09-14 23:36:40 +000011#include "lldb/Target/Process.h"
Jason Molenda3a4ea242010-09-10 07:49:16 +000012#include "lldb/Target/RegisterContext.h"
Greg Claytoneea26402010-09-14 23:36:40 +000013#include "lldb/Target/Thread.h"
Jason Molenda8280cbe2010-10-25 11:12:07 +000014#include "lldb/Core/ConstString.h"
Jason Molenda3a4ea242010-09-10 07:49:16 +000015
16using namespace lldb;
17using namespace lldb_private;
18
19bool
20UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
21{
22 if (m_type != rhs.m_type)
23 return false;
24 if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset)
25 return m_location.offset == rhs.m_location.offset;
26 if (m_type == inOtherRegister)
27 return m_location.reg_num == rhs.m_location.reg_num;
28 if (m_type == atDWARFExpression || m_type == isDWARFExpression)
29 if (m_location.expr.length == rhs.m_location.expr.length)
30 return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length);
31 return false;
32}
33
34// This function doesn't copy the dwarf expression bytes; they must remain in allocated
35// memory for the lifespan of this UnwindPlan object.
36void
37UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len)
38{
39 m_type = atDWARFExpression;
40 m_location.expr.opcodes = opcodes;
41 m_location.expr.length = len;
42}
43
44// This function doesn't copy the dwarf expression bytes; they must remain in allocated
45// memory for the lifespan of this UnwindPlan object.
46void
47UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
48{
49 m_type = isDWARFExpression;
50 m_location.expr.opcodes = opcodes;
51 m_location.expr.length = len;
52}
53
54void
55UnwindPlan::Row::RegisterLocation::SetUnspecified ()
56{
57 m_type = unspecified;
58}
59
60void
61UnwindPlan::Row::RegisterLocation::SetUndefined ()
62{
63 m_type = isUndefined;
64}
65
66void
67UnwindPlan::Row::RegisterLocation::SetSame ()
68{
69 m_type = isSame;
70}
71
72
73void
74UnwindPlan::Row::RegisterLocation::SetAtCFAPlusOffset (int32_t offset)
75{
76 m_type = atCFAPlusOffset;
77 m_location.offset = offset;
78}
79
80void
81UnwindPlan::Row::RegisterLocation::SetIsCFAPlusOffset (int32_t offset)
82{
83 m_type = isCFAPlusOffset;
84 m_location.offset = offset;
85}
86
87void
88UnwindPlan::Row::RegisterLocation::SetInRegister (uint32_t reg_num)
89{
90 m_type = inOtherRegister;
91 m_location.reg_num = reg_num;
92}
93
94void
95UnwindPlan::Row::RegisterLocation::Dump (Stream &s) const
96{
97 switch (m_type)
98 {
99 case unspecified:
100 s.Printf ("unspecified");
101 break;
102 case isUndefined:
103 s.Printf ("isUndefined");
104 break;
105 case isSame:
106 s.Printf ("isSame");
107 break;
108 case atCFAPlusOffset:
109 s.Printf ("atCFAPlusOffset %d", m_location.offset);
110 break;
111 case isCFAPlusOffset:
112 s.Printf ("isCFAPlusOffset %d", m_location.offset);
113 break;
114 case inOtherRegister:
115 s.Printf ("inOtherRegister %d", m_location.reg_num);
116 break;
117 case atDWARFExpression:
118 s.Printf ("atDWARFExpression");
119 break;
120 case isDWARFExpression:
121 s.Printf ("isDWARFExpression");
122 break;
123 }
124}
125
126void
127UnwindPlan::Row::Clear ()
128{
129 m_offset = 0;
130 m_cfa_reg_num = 0;
131 m_cfa_offset = 0;
132 m_register_locations.clear();
133}
134
135void
136UnwindPlan::Row::Dump (Stream& s, int register_kind, Thread* thread) const
137{
138 RegisterContext *rctx = NULL;
139 const RegisterInfo *rinfo = NULL;
140 int translated_regnum;
141 if (thread && thread->GetRegisterContext())
142 {
143 rctx = thread->GetRegisterContext();
144 }
145 s.Printf ("offset %ld, CFA reg ", (long) GetOffset());
146 if (rctx
147 && (translated_regnum = rctx->ConvertRegisterKindToRegisterNumber (register_kind, GetCFARegister())) != -1
148 && (rinfo = rctx->GetRegisterInfoAtIndex (translated_regnum)) != NULL
149 && rinfo->name != NULL
150 && rinfo->name[0] != '\0')
151 {
152 s.Printf ("%s, ", rinfo->name);
153 }
154 else
155 {
156 s.Printf ("%d, ", (int)(int) GetCFARegister());
157 }
158 s.Printf ("CFA offset %d", (int) GetCFAOffset ());
159 for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
160 {
161 s.Printf (" [");
162 bool printed_name = false;
163 if (thread && thread->GetRegisterContext())
164 {
165 rctx = thread->GetRegisterContext();
166 translated_regnum = rctx->ConvertRegisterKindToRegisterNumber (register_kind, idx->first);
167 rinfo = rctx->GetRegisterInfoAtIndex (translated_regnum);
168 if (rinfo && rinfo->name)
169 {
170 s.Printf ("%s ", rinfo->name);
171 printed_name = true;
172 }
173 }
174 if (!printed_name)
175 {
176 s.Printf ("reg %d ", idx->first);
177 }
178 idx->second.Dump(s);
179 s.Printf ("]");
180 }
181 s.Printf ("\n");
182}
183
184UnwindPlan::Row::Row() :
185 m_offset(0),
186 m_cfa_reg_num(0),
187 m_cfa_offset(0),
188 m_register_locations()
189{
190}
191
192bool
193UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const
194{
195 collection::const_iterator pos = m_register_locations.find(reg_num);
196 if (pos != m_register_locations.end())
197 {
198 register_location = pos->second;
199 return true;
200 }
201 return false;
202}
203
204void
205UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
206{
207 m_register_locations[reg_num] = register_location;
208}
209
210
211void
212UnwindPlan::AppendRow (const UnwindPlan::Row &row)
213{
214 if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset())
215 m_row_list.push_back(row);
216 else
217 m_row_list.back() = row;
218}
219
220const UnwindPlan::Row *
221UnwindPlan::GetRowForFunctionOffset (int offset) const
222{
223 const UnwindPlan::Row *rowp = NULL;
Jason Molenda8280cbe2010-10-25 11:12:07 +0000224 if (offset == -1 && m_row_list.size() > 0)
225 {
226 return &m_row_list[m_row_list.size() - 1];
227 }
Jason Molenda3a4ea242010-09-10 07:49:16 +0000228 for (int i = 0; i < m_row_list.size(); ++i)
229 {
230 if (m_row_list[i].GetOffset() <= offset)
231 {
232 rowp = &m_row_list[i];
233 }
234 else
235 {
236 break;
237 }
238 }
239 return rowp;
240}
241
242bool
243UnwindPlan::IsValidRowIndex (uint32_t idx) const
244{
245 return idx < m_row_list.size();
246}
247
248const UnwindPlan::Row&
249UnwindPlan::GetRowAtIndex (uint32_t idx) const
250{
251 // You must call IsValidRowIndex(idx) first before calling this!!!
252 return m_row_list[idx];
253}
254
255int
256UnwindPlan::GetRowCount () const
257{
258 return m_row_list.size ();
259}
260
261void
262UnwindPlan::SetRegisterKind (uint32_t rk)
263{
264 m_register_kind = rk;
265}
266
267uint32_t
268UnwindPlan::GetRegisterKind (void) const
269{
270 return m_register_kind;
271}
272
273void
274UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
275{
Jason Molenda8280cbe2010-10-25 11:12:07 +0000276 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
277 {
278 m_plan_valid_address_range = range;
279 }
Jason Molenda3a4ea242010-09-10 07:49:16 +0000280// .GetBaseAddress() = addr;
281// m_plan_valid_address_range.SetByteSize (range.GetByteSize());
282}
283
284bool
285UnwindPlan::PlanValidAtAddress (Address addr)
286{
Jason Molenda8280cbe2010-10-25 11:12:07 +0000287 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
Jason Molenda3a4ea242010-09-10 07:49:16 +0000288 return true;
289
290 if (m_plan_valid_address_range.ContainsFileAddress (addr))
291 return true;
292
293 return false;
294}
295
296void
Greg Claytoneea26402010-09-14 23:36:40 +0000297UnwindPlan::Dump (Stream& s, Thread *thread) const
Jason Molenda3a4ea242010-09-10 07:49:16 +0000298{
Jason Molenda8280cbe2010-10-25 11:12:07 +0000299 if (!m_source_name.IsEmpty())
300 {
301 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
302 }
303 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
304 {
305 s.Printf ("Address range of this UnwindPlan: ");
306 m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset);
307 s.Printf ("\n");
308 }
309 else
310 {
311 s.Printf ("No valid address range recorded for this UnwindPlan.\n");
312 }
Jason Molenda3a4ea242010-09-10 07:49:16 +0000313 s.Printf ("UnwindPlan register kind %d", m_register_kind);
314 switch (m_register_kind)
315 {
316 case eRegisterKindGCC: s.Printf (" [eRegisterKindGCC]"); break;
317 case eRegisterKindDWARF: s.Printf (" [eRegisterKindDWARF]"); break;
318 case eRegisterKindGeneric: s.Printf (" [eRegisterKindGeneric]"); break;
319 case eRegisterKindGDB: s.Printf (" [eRegisterKindGDB]"); break;
320 case eRegisterKindLLDB: s.Printf (" [eRegisterKindLLDB]"); break;
321 default: break;
322 }
323 s.Printf ("\n");
324 for (int i = 0; IsValidRowIndex (i); i++)
325 {
326 s.Printf ("UnwindPlan row at index %d: ", i);
327 m_row_list[i].Dump(s, m_register_kind, thread);
328 }
329}
Jason Molenda8280cbe2010-10-25 11:12:07 +0000330
331void
332UnwindPlan::SetSourceName (const char *source)
333{
334 m_source_name = ConstString (source);
335}
336
337ConstString
338UnwindPlan::GetSourceName () const
339{
340 return m_source_name;
341}