1 //===-- 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"
11
12 #include "lldb/Core/ConstString.h"
13 #include "lldb/Target/Process.h"
14 #include "lldb/Target/RegisterContext.h"
15 #include "lldb/Target/Thread.h"
16
17 using namespace lldb;
18 using namespace lldb_private;
19
20 bool
operator ==(const UnwindPlan::Row::RegisterLocation & rhs) const21 UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
22 {
23 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 }
46 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.
51 void
SetAtDWARFExpression(const uint8_t * opcodes,uint32_t len)52 UnwindPlan::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.
61 void
SetIsDWARFExpression(const uint8_t * opcodes,uint32_t len)62 UnwindPlan::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
69 void
Dump(Stream & s,const UnwindPlan * unwind_plan,const UnwindPlan::Row * row,Thread * thread,bool verbose) const70 UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_plan, const UnwindPlan::Row* row, Thread* thread, bool verbose) const
71 {
72 switch (m_type)
73 {
74 case unspecified:
75 if (verbose)
76 s.PutCString ("=<unspec>");
77 else
78 s.PutCString ("=!");
79 break;
80 case undefined:
81 if (verbose)
82 s.PutCString ("=<undef>");
83 else
84 s.PutCString ("=?");
85 break;
86 case same:
87 s.PutCString ("= <same>");
88 break;
89
90 case atCFAPlusOffset:
91 case isCFAPlusOffset:
92 {
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, 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);
117 if (offset != 0)
118 s.Printf ("%+d", offset);
119 }
120 }
121 if (m_type == atCFAPlusOffset)
122 s.PutChar(']');
123 }
124 break;
125
126 case inOtherRegister:
127 {
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 }
136 break;
137
138 case atDWARFExpression:
139 case isDWARFExpression:
140 {
141 s.PutChar('=');
142 if (m_type == atDWARFExpression)
143 s.PutCString("[dwarf-expr]");
144 else
145 s.PutCString("dwarf-expr");
146 }
147 break;
148
149 }
150 }
151
152 void
Clear()153 UnwindPlan::Row::Clear ()
154 {
155 m_offset = 0;
156 m_cfa_reg_num = LLDB_INVALID_REGNUM;
157 m_cfa_offset = 0;
158 m_register_locations.clear();
159 }
160
161 void
Dump(Stream & s,const UnwindPlan * unwind_plan,Thread * thread,addr_t base_addr) const162 UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const
163 {
164 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister());
165
166 if (base_addr != LLDB_INVALID_ADDRESS)
167 s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
168 else
169 s.Printf ("0x%8.8" PRIx64 ": 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 ());
176 for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
177 {
178 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 (' ');
186 }
187 s.EOL();
188 }
189
Row()190 UnwindPlan::Row::Row() :
191 m_offset(0),
192 m_cfa_reg_num(LLDB_INVALID_REGNUM),
193 m_cfa_offset(0),
194 m_register_locations()
195 {
196 }
197
198 bool
GetRegisterInfo(uint32_t reg_num,UnwindPlan::Row::RegisterLocation & register_location) const199 UnwindPlan::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
210 void
SetRegisterInfo(uint32_t reg_num,const UnwindPlan::Row::RegisterLocation register_location)211 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
212 {
213 m_register_locations[reg_num] = register_location;
214 }
215
216 bool
SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)217 UnwindPlan::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
227 bool
SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)228 UnwindPlan::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
238 bool
SetRegisterLocationToUndefined(uint32_t reg_num,bool can_replace,bool can_replace_only_if_unspecified)239 UnwindPlan::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
257 bool
SetRegisterLocationToUnspecified(uint32_t reg_num,bool can_replace)258 UnwindPlan::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
268 bool
SetRegisterLocationToRegister(uint32_t reg_num,uint32_t other_reg_num,bool can_replace)269 UnwindPlan::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
281 bool
SetRegisterLocationToSame(uint32_t reg_num,bool must_replace)282 UnwindPlan::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
292 void
SetCFARegister(uint32_t reg_num)293 UnwindPlan::Row::SetCFARegister (uint32_t reg_num)
294 {
295 m_cfa_reg_num = reg_num;
296 }
297
298 bool
operator ==(const UnwindPlan::Row & rhs) const299 UnwindPlan::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 return m_register_locations == rhs.m_register_locations;
304 }
305
306 void
AppendRow(const UnwindPlan::RowSP & row_sp)307 UnwindPlan::AppendRow (const UnwindPlan::RowSP &row_sp)
308 {
309 if (m_row_list.empty() || m_row_list.back()->GetOffset() != row_sp->GetOffset())
310 m_row_list.push_back(row_sp);
311 else
312 m_row_list.back() = row_sp;
313 }
314
315 UnwindPlan::RowSP
GetRowForFunctionOffset(int offset) const316 UnwindPlan::GetRowForFunctionOffset (int offset) const
317 {
318 RowSP row;
319 if (!m_row_list.empty())
320 {
321 if (offset == -1)
322 row = m_row_list.back();
323 else
324 {
325 collection::const_iterator pos, end = m_row_list.end();
326 for (pos = m_row_list.begin(); pos != end; ++pos)
327 {
328 if ((*pos)->GetOffset() <= offset)
329 row = *pos;
330 else
331 break;
332 }
333 }
334 }
335 return row;
336 }
337
338 bool
IsValidRowIndex(uint32_t idx) const339 UnwindPlan::IsValidRowIndex (uint32_t idx) const
340 {
341 return idx < m_row_list.size();
342 }
343
344 const UnwindPlan::RowSP
GetRowAtIndex(uint32_t idx) const345 UnwindPlan::GetRowAtIndex (uint32_t idx) const
346 {
347 // You must call IsValidRowIndex(idx) first before calling this!!!
348 assert (idx < m_row_list.size());
349 return m_row_list[idx];
350 }
351
352 const UnwindPlan::RowSP
GetLastRow() const353 UnwindPlan::GetLastRow () const
354 {
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();
358 }
359
360 int
GetRowCount() const361 UnwindPlan::GetRowCount () const
362 {
363 return m_row_list.size ();
364 }
365
366 void
SetPlanValidAddressRange(const AddressRange & range)367 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
368 {
369 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
370 m_plan_valid_address_range = range;
371 }
372
373 bool
PlanValidAtAddress(Address addr)374 UnwindPlan::PlanValidAtAddress (Address addr)
375 {
376 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
377 return true;
378
379 if (!addr.IsValid())
380 return true;
381
382 if (m_plan_valid_address_range.ContainsFileAddress (addr))
383 return true;
384
385 return false;
386 }
387
388 void
Dump(Stream & s,Thread * thread,lldb::addr_t base_addr) const389 UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
390 {
391 if (!m_source_name.IsEmpty())
392 {
393 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
394 }
395 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
396 {
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);
400 s.EOL();
401 }
402 collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end();
403 for (pos = begin; pos != end; ++pos)
404 {
405 s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos));
406 (*pos)->Dump(s, this, thread, base_addr);
407 }
408 }
409
410 void
SetSourceName(const char * source)411 UnwindPlan::SetSourceName (const char *source)
412 {
413 m_source_name = ConstString (source);
414 }
415
416 ConstString
GetSourceName() const417 UnwindPlan::GetSourceName () const
418 {
419 return m_source_name;
420 }
421
422 const RegisterInfo *
GetRegisterInfo(Thread * thread,uint32_t unwind_reg) const423 UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
424 {
425 if (thread)
426 {
427 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
428 if (reg_ctx)
429 {
430 uint32_t reg;
431 if (m_register_kind == eRegisterKindLLDB)
432 reg = unwind_reg;
433 else
434 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg);
435 if (reg != LLDB_INVALID_REGNUM)
436 return reg_ctx->GetRegisterInfoAtIndex (reg);
437 }
438 }
439 return NULL;
440 }
441
442