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/Core/Log.h"
14 #include "lldb/Target/Process.h"
15 #include "lldb/Target/RegisterContext.h"
16 #include "lldb/Target/Thread.h"
17
18 using namespace lldb;
19 using namespace lldb_private;
20
21 bool
operator ==(const UnwindPlan::Row::RegisterLocation & rhs) const22 UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
23 {
24 if (m_type == rhs.m_type)
25 {
26 switch (m_type)
27 {
28 case unspecified:
29 case undefined:
30 case same:
31 return true;
32
33 case atCFAPlusOffset:
34 case isCFAPlusOffset:
35 return m_location.offset == rhs.m_location.offset;
36
37 case inOtherRegister:
38 return m_location.reg_num == rhs.m_location.reg_num;
39
40 case atDWARFExpression:
41 case isDWARFExpression:
42 if (m_location.expr.length == rhs.m_location.expr.length)
43 return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length);
44 break;
45 }
46 }
47 return false;
48 }
49
50 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
51 // memory for the lifespan of this UnwindPlan object.
52 void
SetAtDWARFExpression(const uint8_t * opcodes,uint32_t len)53 UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len)
54 {
55 m_type = atDWARFExpression;
56 m_location.expr.opcodes = opcodes;
57 m_location.expr.length = len;
58 }
59
60 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
61 // memory for the lifespan of this UnwindPlan object.
62 void
SetIsDWARFExpression(const uint8_t * opcodes,uint32_t len)63 UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
64 {
65 m_type = isDWARFExpression;
66 m_location.expr.opcodes = opcodes;
67 m_location.expr.length = len;
68 }
69
70 void
Dump(Stream & s,const UnwindPlan * unwind_plan,const UnwindPlan::Row * row,Thread * thread,bool verbose) const71 UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_plan, const UnwindPlan::Row* row, Thread* thread, bool verbose) const
72 {
73 switch (m_type)
74 {
75 case unspecified:
76 if (verbose)
77 s.PutCString ("=<unspec>");
78 else
79 s.PutCString ("=!");
80 break;
81 case undefined:
82 if (verbose)
83 s.PutCString ("=<undef>");
84 else
85 s.PutCString ("=?");
86 break;
87 case same:
88 s.PutCString ("= <same>");
89 break;
90
91 case atCFAPlusOffset:
92 case isCFAPlusOffset:
93 {
94 s.PutChar('=');
95 if (m_type == atCFAPlusOffset)
96 s.PutChar('[');
97 if (verbose)
98 s.Printf ("CFA%+d", m_location.offset);
99
100 if (unwind_plan && row)
101 {
102 const uint32_t cfa_reg = row->GetCFARegister();
103 const RegisterInfo *cfa_reg_info = unwind_plan->GetRegisterInfo (thread, cfa_reg);
104 const int32_t offset = row->GetCFAOffset() + m_location.offset;
105 if (verbose)
106 {
107 if (cfa_reg_info)
108 s.Printf (" (%s%+d)", cfa_reg_info->name, offset);
109 else
110 s.Printf (" (reg(%u)%+d)", cfa_reg, offset);
111 }
112 else
113 {
114 if (cfa_reg_info)
115 s.Printf ("%s", cfa_reg_info->name);
116 else
117 s.Printf ("reg(%u)", cfa_reg);
118 if (offset != 0)
119 s.Printf ("%+d", offset);
120 }
121 }
122 if (m_type == atCFAPlusOffset)
123 s.PutChar(']');
124 }
125 break;
126
127 case inOtherRegister:
128 {
129 const RegisterInfo *other_reg_info = NULL;
130 if (unwind_plan)
131 other_reg_info = unwind_plan->GetRegisterInfo (thread, m_location.reg_num);
132 if (other_reg_info)
133 s.Printf ("=%s", other_reg_info->name);
134 else
135 s.Printf ("=reg(%u)", m_location.reg_num);
136 }
137 break;
138
139 case atDWARFExpression:
140 case isDWARFExpression:
141 {
142 s.PutChar('=');
143 if (m_type == atDWARFExpression)
144 s.PutCString("[dwarf-expr]");
145 else
146 s.PutCString("dwarf-expr");
147 }
148 break;
149
150 }
151 }
152
153 void
Clear()154 UnwindPlan::Row::Clear ()
155 {
156 m_offset = 0;
157 m_cfa_reg_num = LLDB_INVALID_REGNUM;
158 m_cfa_offset = 0;
159 m_register_locations.clear();
160 }
161
162 void
Dump(Stream & s,const UnwindPlan * unwind_plan,Thread * thread,addr_t base_addr) const163 UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const
164 {
165 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister());
166
167 if (base_addr != LLDB_INVALID_ADDRESS)
168 s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
169 else
170 s.Printf ("0x%8.8" PRIx64 ": CFA=", GetOffset());
171
172 if (reg_info)
173 s.Printf ("%s", reg_info->name);
174 else
175 s.Printf ("reg(%u)", GetCFARegister());
176 s.Printf ("%+3d => ", GetCFAOffset ());
177 for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
178 {
179 reg_info = unwind_plan->GetRegisterInfo (thread, idx->first);
180 if (reg_info)
181 s.Printf ("%s", reg_info->name);
182 else
183 s.Printf ("reg(%u)", idx->first);
184 const bool verbose = false;
185 idx->second.Dump(s, unwind_plan, this, thread, verbose);
186 s.PutChar (' ');
187 }
188 s.EOL();
189 }
190
Row()191 UnwindPlan::Row::Row() :
192 m_offset(0),
193 m_cfa_reg_num(LLDB_INVALID_REGNUM),
194 m_cfa_offset(0),
195 m_register_locations()
196 {
197 }
198
199 bool
GetRegisterInfo(uint32_t reg_num,UnwindPlan::Row::RegisterLocation & register_location) const200 UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const
201 {
202 collection::const_iterator pos = m_register_locations.find(reg_num);
203 if (pos != m_register_locations.end())
204 {
205 register_location = pos->second;
206 return true;
207 }
208 return false;
209 }
210
211 void
SetRegisterInfo(uint32_t reg_num,const UnwindPlan::Row::RegisterLocation register_location)212 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
213 {
214 m_register_locations[reg_num] = register_location;
215 }
216
217 bool
SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)218 UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
219 {
220 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
221 return false;
222 RegisterLocation reg_loc;
223 reg_loc.SetAtCFAPlusOffset(offset);
224 m_register_locations[reg_num] = reg_loc;
225 return true;
226 }
227
228 bool
SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)229 UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
230 {
231 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
232 return false;
233 RegisterLocation reg_loc;
234 reg_loc.SetIsCFAPlusOffset(offset);
235 m_register_locations[reg_num] = reg_loc;
236 return true;
237 }
238
239 bool
SetRegisterLocationToUndefined(uint32_t reg_num,bool can_replace,bool can_replace_only_if_unspecified)240 UnwindPlan::Row::SetRegisterLocationToUndefined (uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified)
241 {
242 collection::iterator pos = m_register_locations.find(reg_num);
243 collection::iterator end = m_register_locations.end();
244
245 if (pos != end)
246 {
247 if (!can_replace)
248 return false;
249 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
250 return false;
251 }
252 RegisterLocation reg_loc;
253 reg_loc.SetUndefined();
254 m_register_locations[reg_num] = reg_loc;
255 return true;
256 }
257
258 bool
SetRegisterLocationToUnspecified(uint32_t reg_num,bool can_replace)259 UnwindPlan::Row::SetRegisterLocationToUnspecified (uint32_t reg_num, bool can_replace)
260 {
261 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
262 return false;
263 RegisterLocation reg_loc;
264 reg_loc.SetUnspecified();
265 m_register_locations[reg_num] = reg_loc;
266 return true;
267 }
268
269 bool
SetRegisterLocationToRegister(uint32_t reg_num,uint32_t other_reg_num,bool can_replace)270 UnwindPlan::Row::SetRegisterLocationToRegister (uint32_t reg_num,
271 uint32_t other_reg_num,
272 bool can_replace)
273 {
274 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
275 return false;
276 RegisterLocation reg_loc;
277 reg_loc.SetInRegister(other_reg_num);
278 m_register_locations[reg_num] = reg_loc;
279 return true;
280 }
281
282 bool
SetRegisterLocationToSame(uint32_t reg_num,bool must_replace)283 UnwindPlan::Row::SetRegisterLocationToSame (uint32_t reg_num, bool must_replace)
284 {
285 if (must_replace && m_register_locations.find(reg_num) == m_register_locations.end())
286 return false;
287 RegisterLocation reg_loc;
288 reg_loc.SetSame();
289 m_register_locations[reg_num] = reg_loc;
290 return true;
291 }
292
293 void
SetCFARegister(uint32_t reg_num)294 UnwindPlan::Row::SetCFARegister (uint32_t reg_num)
295 {
296 m_cfa_reg_num = reg_num;
297 }
298
299 bool
operator ==(const UnwindPlan::Row & rhs) const300 UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const
301 {
302 if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset)
303 return false;
304 return m_register_locations == rhs.m_register_locations;
305 }
306
307 void
AppendRow(const UnwindPlan::RowSP & row_sp)308 UnwindPlan::AppendRow (const UnwindPlan::RowSP &row_sp)
309 {
310 if (m_row_list.empty() || m_row_list.back()->GetOffset() != row_sp->GetOffset())
311 m_row_list.push_back(row_sp);
312 else
313 m_row_list.back() = row_sp;
314 }
315
316 UnwindPlan::RowSP
GetRowForFunctionOffset(int offset) const317 UnwindPlan::GetRowForFunctionOffset (int offset) const
318 {
319 RowSP row;
320 if (!m_row_list.empty())
321 {
322 if (offset == -1)
323 row = m_row_list.back();
324 else
325 {
326 collection::const_iterator pos, end = m_row_list.end();
327 for (pos = m_row_list.begin(); pos != end; ++pos)
328 {
329 if ((*pos)->GetOffset() <= offset)
330 row = *pos;
331 else
332 break;
333 }
334 }
335 }
336 return row;
337 }
338
339 bool
IsValidRowIndex(uint32_t idx) const340 UnwindPlan::IsValidRowIndex (uint32_t idx) const
341 {
342 return idx < m_row_list.size();
343 }
344
345 const UnwindPlan::RowSP
GetRowAtIndex(uint32_t idx) const346 UnwindPlan::GetRowAtIndex (uint32_t idx) const
347 {
348 // You must call IsValidRowIndex(idx) first before calling this!!!
349 assert (idx < m_row_list.size());
350 return m_row_list[idx];
351 }
352
353 const UnwindPlan::RowSP
GetLastRow() const354 UnwindPlan::GetLastRow () const
355 {
356 // You must call GetRowCount() first to make sure there is at least one row
357 assert (!m_row_list.empty());
358 return m_row_list.back();
359 }
360
361 int
GetRowCount() const362 UnwindPlan::GetRowCount () const
363 {
364 return m_row_list.size ();
365 }
366
367 void
SetPlanValidAddressRange(const AddressRange & range)368 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
369 {
370 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
371 m_plan_valid_address_range = range;
372 }
373
374 bool
PlanValidAtAddress(Address addr)375 UnwindPlan::PlanValidAtAddress (Address addr)
376 {
377 // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
378 if (GetRowCount() == 0)
379 {
380 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
381 if (log)
382 {
383 StreamString s;
384 if (addr.Dump (&s, NULL, Address::DumpStyleSectionNameOffset))
385 {
386 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s' at address %s",
387 m_source_name.GetCString(), s.GetData());
388 }
389 else
390 {
391 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
392 m_source_name.GetCString());
393 }
394 }
395 return false;
396 }
397
398 // If the 0th Row of unwind instructions is missing, or if it doesn't provide
399 // a register to use to find the Canonical Frame Address, this is not a valid UnwindPlan.
400 if (GetRowAtIndex(0).get() == NULL || GetRowAtIndex(0)->GetCFARegister() == LLDB_INVALID_REGNUM)
401 {
402 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
403 if (log)
404 {
405 StreamString s;
406 if (addr.Dump (&s, NULL, Address::DumpStyleSectionNameOffset))
407 {
408 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s' at address %s",
409 m_source_name.GetCString(), s.GetData());
410 }
411 else
412 {
413 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s'",
414 m_source_name.GetCString());
415 }
416 }
417 return false;
418 }
419
420 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
421 return true;
422
423 if (!addr.IsValid())
424 return true;
425
426 if (m_plan_valid_address_range.ContainsFileAddress (addr))
427 return true;
428
429 return false;
430 }
431
432 void
Dump(Stream & s,Thread * thread,lldb::addr_t base_addr) const433 UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
434 {
435 if (!m_source_name.IsEmpty())
436 {
437 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
438 }
439 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
440 {
441 s.PutCString ("Address range of this UnwindPlan: ");
442 TargetSP target_sp(thread->CalculateTarget());
443 m_plan_valid_address_range.Dump (&s, target_sp.get(), Address::DumpStyleSectionNameOffset);
444 s.EOL();
445 }
446 collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end();
447 for (pos = begin; pos != end; ++pos)
448 {
449 s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos));
450 (*pos)->Dump(s, this, thread, base_addr);
451 }
452 }
453
454 void
SetSourceName(const char * source)455 UnwindPlan::SetSourceName (const char *source)
456 {
457 m_source_name = ConstString (source);
458 }
459
460 ConstString
GetSourceName() const461 UnwindPlan::GetSourceName () const
462 {
463 return m_source_name;
464 }
465
466 const RegisterInfo *
GetRegisterInfo(Thread * thread,uint32_t unwind_reg) const467 UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
468 {
469 if (thread)
470 {
471 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
472 if (reg_ctx)
473 {
474 uint32_t reg;
475 if (m_register_kind == eRegisterKindLLDB)
476 reg = unwind_reg;
477 else
478 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg);
479 if (reg != LLDB_INVALID_REGNUM)
480 return reg_ctx->GetRegisterInfoAtIndex (reg);
481 }
482 }
483 return NULL;
484 }
485
486