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
22 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
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
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
71 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 = nullptr;
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
154 UnwindPlan::Row::Clear ()
155 {
156     m_cfa_type = CFAIsRegisterPlusOffset;
157     m_offset = 0;
158     m_cfa_reg_num = LLDB_INVALID_REGNUM;
159     m_cfa_offset = 0;
160     m_register_locations.clear();
161 }
162 
163 void
164 UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const
165 {
166     const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister());
167 
168     if (base_addr != LLDB_INVALID_ADDRESS)
169         s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
170     else
171         s.Printf ("0x%8.8" PRIx64 ": CFA=", GetOffset());
172 
173     if (reg_info)
174         s.Printf ("%s", reg_info->name);
175     else
176         s.Printf ("reg(%u)", GetCFARegister());
177     s.Printf ("%+3d => ", GetCFAOffset ());
178     for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
179     {
180         reg_info = unwind_plan->GetRegisterInfo (thread, idx->first);
181         if (reg_info)
182             s.Printf ("%s", reg_info->name);
183         else
184             s.Printf ("reg(%u)", idx->first);
185         const bool verbose = false;
186         idx->second.Dump(s, unwind_plan, this, thread, verbose);
187         s.PutChar (' ');
188     }
189     s.EOL();
190 }
191 
192 UnwindPlan::Row::Row() :
193     m_offset (0),
194     m_cfa_type (CFAIsRegisterPlusOffset),
195     m_cfa_reg_num (LLDB_INVALID_REGNUM),
196     m_cfa_offset (0),
197     m_register_locations ()
198 {
199 }
200 
201 bool
202 UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const
203 {
204     collection::const_iterator pos = m_register_locations.find(reg_num);
205     if (pos != m_register_locations.end())
206     {
207         register_location = pos->second;
208         return true;
209     }
210     return false;
211 }
212 
213 void
214 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
215 {
216     m_register_locations[reg_num] = register_location;
217 }
218 
219 bool
220 UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
221 {
222     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
223         return false;
224     RegisterLocation reg_loc;
225     reg_loc.SetAtCFAPlusOffset(offset);
226     m_register_locations[reg_num] = reg_loc;
227     return true;
228 }
229 
230 bool
231 UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
232 {
233     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
234         return false;
235     RegisterLocation reg_loc;
236     reg_loc.SetIsCFAPlusOffset(offset);
237     m_register_locations[reg_num] = reg_loc;
238     return true;
239 }
240 
241 bool
242 UnwindPlan::Row::SetRegisterLocationToUndefined (uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified)
243 {
244     collection::iterator pos = m_register_locations.find(reg_num);
245     collection::iterator end = m_register_locations.end();
246 
247     if (pos != end)
248     {
249         if (!can_replace)
250             return false;
251         if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
252             return false;
253     }
254     RegisterLocation reg_loc;
255     reg_loc.SetUndefined();
256     m_register_locations[reg_num] = reg_loc;
257     return true;
258 }
259 
260 bool
261 UnwindPlan::Row::SetRegisterLocationToUnspecified (uint32_t reg_num, bool can_replace)
262 {
263     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
264         return false;
265     RegisterLocation reg_loc;
266     reg_loc.SetUnspecified();
267     m_register_locations[reg_num] = reg_loc;
268     return true;
269 }
270 
271 bool
272 UnwindPlan::Row::SetRegisterLocationToRegister (uint32_t reg_num,
273                                                 uint32_t other_reg_num,
274                                                 bool can_replace)
275 {
276     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
277         return false;
278     RegisterLocation reg_loc;
279     reg_loc.SetInRegister(other_reg_num);
280     m_register_locations[reg_num] = reg_loc;
281     return true;
282 }
283 
284 bool
285 UnwindPlan::Row::SetRegisterLocationToSame (uint32_t reg_num, bool must_replace)
286 {
287     if (must_replace && m_register_locations.find(reg_num) == m_register_locations.end())
288         return false;
289     RegisterLocation reg_loc;
290     reg_loc.SetSame();
291     m_register_locations[reg_num] = reg_loc;
292     return true;
293 }
294 
295 void
296 UnwindPlan::Row::SetCFARegister (uint32_t reg_num)
297 {
298     m_cfa_reg_num = reg_num;
299 }
300 
301 bool
302 UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const
303 {
304     if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset)
305         return false;
306 
307     if (m_cfa_type != rhs.m_cfa_type)
308         return false;
309 
310     if (m_cfa_type == CFAIsRegisterPlusOffset)
311     {
312         if (m_cfa_reg_num != rhs.m_cfa_reg_num)
313             return false;
314         if (m_cfa_offset != rhs.m_cfa_offset)
315             return false;
316     }
317     if (m_cfa_type == CFAIsRegisterDereferenced)
318     {
319         if (m_cfa_reg_num != rhs.m_cfa_reg_num)
320             return false;
321     }
322 
323     return m_register_locations == rhs.m_register_locations;
324 }
325 
326 void
327 UnwindPlan::AppendRow (const UnwindPlan::RowSP &row_sp)
328 {
329     if (m_row_list.empty() || m_row_list.back()->GetOffset() != row_sp->GetOffset())
330         m_row_list.push_back(row_sp);
331     else
332         m_row_list.back() = row_sp;
333 }
334 
335 void
336 UnwindPlan::InsertRow (const UnwindPlan::RowSP &row_sp)
337 {
338     collection::iterator it = m_row_list.begin();
339     while (it != m_row_list.end()) {
340         RowSP row = *it;
341         if (row->GetOffset() > row_sp->GetOffset())
342             break;
343         it++;
344     }
345     m_row_list.insert(it, row_sp);
346 }
347 
348 UnwindPlan::RowSP
349 UnwindPlan::GetRowForFunctionOffset (int offset) const
350 {
351     RowSP row;
352     if (!m_row_list.empty())
353     {
354         if (offset == -1)
355             row = m_row_list.back();
356         else
357         {
358             collection::const_iterator pos, end = m_row_list.end();
359             for (pos = m_row_list.begin(); pos != end; ++pos)
360             {
361                 if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
362                     row = *pos;
363                 else
364                     break;
365             }
366         }
367     }
368     return row;
369 }
370 
371 bool
372 UnwindPlan::IsValidRowIndex (uint32_t idx) const
373 {
374     return idx < m_row_list.size();
375 }
376 
377 const UnwindPlan::RowSP
378 UnwindPlan::GetRowAtIndex (uint32_t idx) const
379 {
380     // You must call IsValidRowIndex(idx) first before calling this!!!
381     assert (idx < m_row_list.size());
382     return m_row_list[idx];
383 }
384 
385 const UnwindPlan::RowSP
386 UnwindPlan::GetLastRow () const
387 {
388     // You must call GetRowCount() first to make sure there is at least one row
389     assert (!m_row_list.empty());
390     return m_row_list.back();
391 }
392 
393 int
394 UnwindPlan::GetRowCount () const
395 {
396     return m_row_list.size ();
397 }
398 
399 void
400 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
401 {
402    if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
403        m_plan_valid_address_range = range;
404 }
405 
406 bool
407 UnwindPlan::PlanValidAtAddress (Address addr)
408 {
409     // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
410     if (GetRowCount() == 0)
411     {
412         Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
413         if (log)
414         {
415             StreamString s;
416             if (addr.Dump (&s, nullptr, Address::DumpStyleSectionNameOffset))
417             {
418                 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s' at address %s",
419                              m_source_name.GetCString(), s.GetData());
420             }
421             else
422             {
423                 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
424                              m_source_name.GetCString());
425             }
426         }
427         return false;
428     }
429 
430     // If the 0th Row of unwind instructions is missing, or if it doesn't provide
431     // a register to use to find the Canonical Frame Address, this is not a valid UnwindPlan.
432     if (GetRowAtIndex(0).get() == nullptr || GetRowAtIndex(0)->GetCFARegister() == LLDB_INVALID_REGNUM)
433     {
434         Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
435         if (log)
436         {
437             StreamString s;
438             if (addr.Dump (&s, nullptr, Address::DumpStyleSectionNameOffset))
439             {
440                 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s' at address %s",
441                              m_source_name.GetCString(), s.GetData());
442             }
443             else
444             {
445                 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s'",
446                              m_source_name.GetCString());
447             }
448         }
449         return false;
450     }
451 
452     if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
453         return true;
454 
455     if (!addr.IsValid())
456         return true;
457 
458     if (m_plan_valid_address_range.ContainsFileAddress (addr))
459         return true;
460 
461     return false;
462 }
463 
464 void
465 UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
466 {
467     if (!m_source_name.IsEmpty())
468     {
469         s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
470     }
471     if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid())
472     {
473         TargetSP target_sp(thread->CalculateTarget());
474         addr_t lsda_load_addr = m_lsda_address.GetLoadAddress (target_sp.get());
475         addr_t personality_func_load_addr = m_personality_func_addr.GetLoadAddress (target_sp.get());
476 
477         if (lsda_load_addr != LLDB_INVALID_ADDRESS && personality_func_load_addr != LLDB_INVALID_ADDRESS)
478         {
479             s.Printf("LSDA address 0x%" PRIx64 ", personality routine is at address 0x%" PRIx64 "\n",
480                      lsda_load_addr, personality_func_load_addr);
481         }
482     }
483     s.Printf ("This UnwindPlan is sourced from the compiler: ");
484     switch (m_plan_is_sourced_from_compiler)
485     {
486         case eLazyBoolYes:
487             s.Printf ("yes.\n");
488             break;
489         case eLazyBoolNo:
490             s.Printf ("no.\n");
491             break;
492         case eLazyBoolCalculate:
493             s.Printf ("not specified.\n");
494             break;
495     }
496     s.Printf ("This UnwindPlan is valid at all instruction locations: ");
497     switch (m_plan_is_valid_at_all_instruction_locations)
498     {
499         case eLazyBoolYes:
500             s.Printf ("yes.\n");
501             break;
502         case eLazyBoolNo:
503             s.Printf ("no.\n");
504             break;
505         case eLazyBoolCalculate:
506             s.Printf ("not specified.\n");
507             break;
508     }
509     if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
510     {
511         s.PutCString ("Address range of this UnwindPlan: ");
512         TargetSP target_sp(thread->CalculateTarget());
513         m_plan_valid_address_range.Dump (&s, target_sp.get(), Address::DumpStyleSectionNameOffset);
514         s.EOL();
515     }
516     collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end();
517     for (pos = begin; pos != end; ++pos)
518     {
519         s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos));
520         (*pos)->Dump(s, this, thread, base_addr);
521     }
522 }
523 
524 void
525 UnwindPlan::SetSourceName (const char *source)
526 {
527     m_source_name = ConstString (source);
528 }
529 
530 ConstString
531 UnwindPlan::GetSourceName () const
532 {
533     return m_source_name;
534 }
535 
536 const RegisterInfo *
537 UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
538 {
539     if (thread)
540     {
541         RegisterContext *reg_ctx = thread->GetRegisterContext().get();
542         if (reg_ctx)
543         {
544             uint32_t reg;
545             if (m_register_kind == eRegisterKindLLDB)
546                 reg = unwind_reg;
547             else
548                 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg);
549             if (reg != LLDB_INVALID_REGNUM)
550                 return reg_ctx->GetRegisterInfoAtIndex (reg);
551         }
552     }
553     return nullptr;
554 }
555 
556