]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Symbol/UnwindPlan.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Symbol / UnwindPlan.cpp
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/Target/Process.h"
13 #include "lldb/Target/RegisterContext.h"
14 #include "lldb/Target/Thread.h"
15 #include "lldb/Utility/ConstString.h"
16 #include "lldb/Utility/Log.h"
17
18 using namespace lldb;
19 using namespace lldb_private;
20
21 bool UnwindPlan::Row::RegisterLocation::
22 operator==(const UnwindPlan::Row::RegisterLocation &rhs) const {
23   if (m_type == rhs.m_type) {
24     switch (m_type) {
25     case unspecified:
26     case undefined:
27     case same:
28       return true;
29
30     case atCFAPlusOffset:
31     case isCFAPlusOffset:
32     case atAFAPlusOffset:
33     case isAFAPlusOffset:
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,
43                        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
51 // allocated memory for the lifespan of this UnwindPlan object.
52 void UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression(
53     const uint8_t *opcodes, uint32_t len) {
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
60 // allocated memory for the lifespan of this UnwindPlan object.
61 void UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression(
62     const uint8_t *opcodes, uint32_t len) {
63   m_type = isDWARFExpression;
64   m_location.expr.opcodes = opcodes;
65   m_location.expr.length = len;
66 }
67
68 void UnwindPlan::Row::RegisterLocation::Dump(Stream &s,
69                                              const UnwindPlan *unwind_plan,
70                                              const UnwindPlan::Row *row,
71                                              Thread *thread,
72                                              bool verbose) const {
73   switch (m_type) {
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     s.PutChar('=');
93     if (m_type == atCFAPlusOffset)
94       s.PutChar('[');
95     s.Printf("CFA%+d", m_location.offset);
96     if (m_type == atCFAPlusOffset)
97       s.PutChar(']');
98   } break;
99
100   case atAFAPlusOffset:
101   case isAFAPlusOffset: {
102     s.PutChar('=');
103     if (m_type == atAFAPlusOffset)
104       s.PutChar('[');
105     s.Printf("AFA%+d", m_location.offset);
106     if (m_type == atAFAPlusOffset)
107       s.PutChar(']');
108   } break;
109
110   case inOtherRegister: {
111     const RegisterInfo *other_reg_info = nullptr;
112     if (unwind_plan)
113       other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num);
114     if (other_reg_info)
115       s.Printf("=%s", other_reg_info->name);
116     else
117       s.Printf("=reg(%u)", m_location.reg_num);
118   } break;
119
120   case atDWARFExpression:
121   case isDWARFExpression: {
122     s.PutChar('=');
123     if (m_type == atDWARFExpression)
124       s.PutCString("[dwarf-expr]");
125     else
126       s.PutCString("dwarf-expr");
127   } break;
128   }
129 }
130
131 static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,
132                              Thread *thread, uint32_t reg_num) {
133   const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num);
134   if (reg_info)
135     s.PutCString(reg_info->name);
136   else
137     s.Printf("reg(%u)", reg_num);
138 }
139
140 bool UnwindPlan::Row::FAValue::
141 operator==(const UnwindPlan::Row::FAValue &rhs) const {
142   if (m_type == rhs.m_type) {
143     switch (m_type) {
144     case unspecified:
145       return true;
146
147     case isRegisterPlusOffset:
148       return m_value.reg.offset == rhs.m_value.reg.offset;
149
150     case isRegisterDereferenced:
151       return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
152
153     case isDWARFExpression:
154       if (m_value.expr.length == rhs.m_value.expr.length)
155         return !memcmp(m_value.expr.opcodes, rhs.m_value.expr.opcodes,
156                        m_value.expr.length);
157       break;
158     }
159   }
160   return false;
161 }
162
163 void UnwindPlan::Row::FAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
164                                      Thread *thread) const {
165   switch (m_type) {
166   case isRegisterPlusOffset:
167     DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
168     s.Printf("%+3d", m_value.reg.offset);
169     break;
170   case isRegisterDereferenced:
171     s.PutChar('[');
172     DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
173     s.PutChar(']');
174     break;
175   case isDWARFExpression:
176     s.PutCString("dwarf-expr");
177     break;
178   default:
179     s.PutCString("unspecified");
180     break;
181   }
182 }
183
184 void UnwindPlan::Row::Clear() {
185   m_cfa_value.SetUnspecified();
186   m_afa_value.SetUnspecified();
187   m_offset = 0;
188   m_register_locations.clear();
189 }
190
191 void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
192                            Thread *thread, addr_t base_addr) const {
193   if (base_addr != LLDB_INVALID_ADDRESS)
194     s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
195   else
196     s.Printf("%4" PRId64 ": CFA=", GetOffset());
197
198   m_cfa_value.Dump(s, unwind_plan, thread);
199
200   if (!m_afa_value.IsUnspecified()) {
201     s.Printf(" AFA=");
202     m_afa_value.Dump(s, unwind_plan, thread);
203   }
204
205   s.Printf(" => ");
206   for (collection::const_iterator idx = m_register_locations.begin();
207        idx != m_register_locations.end(); ++idx) {
208     DumpRegisterName(s, unwind_plan, thread, idx->first);
209     const bool verbose = false;
210     idx->second.Dump(s, unwind_plan, this, thread, verbose);
211     s.PutChar(' ');
212   }
213   s.EOL();
214 }
215
216 UnwindPlan::Row::Row()
217     : m_offset(0), m_cfa_value(), m_afa_value(), m_register_locations() {}
218
219 bool UnwindPlan::Row::GetRegisterInfo(
220     uint32_t reg_num,
221     UnwindPlan::Row::RegisterLocation &register_location) const {
222   collection::const_iterator pos = m_register_locations.find(reg_num);
223   if (pos != m_register_locations.end()) {
224     register_location = pos->second;
225     return true;
226   }
227   return false;
228 }
229
230 void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) {
231   collection::const_iterator pos = m_register_locations.find(reg_num);
232   if (pos != m_register_locations.end()) {
233     m_register_locations.erase(pos);
234   }
235 }
236
237 void UnwindPlan::Row::SetRegisterInfo(
238     uint32_t reg_num,
239     const UnwindPlan::Row::RegisterLocation register_location) {
240   m_register_locations[reg_num] = register_location;
241 }
242
243 bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,
244                                                            int32_t offset,
245                                                            bool can_replace) {
246   if (!can_replace &&
247       m_register_locations.find(reg_num) != m_register_locations.end())
248     return false;
249   RegisterLocation reg_loc;
250   reg_loc.SetAtCFAPlusOffset(offset);
251   m_register_locations[reg_num] = reg_loc;
252   return true;
253 }
254
255 bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,
256                                                            int32_t offset,
257                                                            bool can_replace) {
258   if (!can_replace &&
259       m_register_locations.find(reg_num) != m_register_locations.end())
260     return false;
261   RegisterLocation reg_loc;
262   reg_loc.SetIsCFAPlusOffset(offset);
263   m_register_locations[reg_num] = reg_loc;
264   return true;
265 }
266
267 bool UnwindPlan::Row::SetRegisterLocationToUndefined(
268     uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) {
269   collection::iterator pos = m_register_locations.find(reg_num);
270   collection::iterator end = m_register_locations.end();
271
272   if (pos != end) {
273     if (!can_replace)
274       return false;
275     if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
276       return false;
277   }
278   RegisterLocation reg_loc;
279   reg_loc.SetUndefined();
280   m_register_locations[reg_num] = reg_loc;
281   return true;
282 }
283
284 bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num,
285                                                        bool can_replace) {
286   if (!can_replace &&
287       m_register_locations.find(reg_num) != m_register_locations.end())
288     return false;
289   RegisterLocation reg_loc;
290   reg_loc.SetUnspecified();
291   m_register_locations[reg_num] = reg_loc;
292   return true;
293 }
294
295 bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num,
296                                                     uint32_t other_reg_num,
297                                                     bool can_replace) {
298   if (!can_replace &&
299       m_register_locations.find(reg_num) != m_register_locations.end())
300     return false;
301   RegisterLocation reg_loc;
302   reg_loc.SetInRegister(other_reg_num);
303   m_register_locations[reg_num] = reg_loc;
304   return true;
305 }
306
307 bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,
308                                                 bool must_replace) {
309   if (must_replace &&
310       m_register_locations.find(reg_num) == m_register_locations.end())
311     return false;
312   RegisterLocation reg_loc;
313   reg_loc.SetSame();
314   m_register_locations[reg_num] = reg_loc;
315   return true;
316 }
317
318 bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
319   return m_offset == rhs.m_offset &&
320       m_cfa_value == rhs.m_cfa_value &&
321       m_afa_value == rhs.m_afa_value &&
322       m_register_locations == rhs.m_register_locations;
323 }
324
325 void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) {
326   if (m_row_list.empty() ||
327       m_row_list.back()->GetOffset() != row_sp->GetOffset())
328     m_row_list.push_back(row_sp);
329   else
330     m_row_list.back() = row_sp;
331 }
332
333 void UnwindPlan::InsertRow(const UnwindPlan::RowSP &row_sp,
334                            bool replace_existing) {
335   collection::iterator it = m_row_list.begin();
336   while (it != m_row_list.end()) {
337     RowSP row = *it;
338     if (row->GetOffset() >= row_sp->GetOffset())
339       break;
340     it++;
341   }
342   if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
343     m_row_list.insert(it, row_sp);
344   else if (replace_existing)
345     *it = row_sp;
346 }
347
348 UnwindPlan::RowSP UnwindPlan::GetRowForFunctionOffset(int offset) const {
349   RowSP row;
350   if (!m_row_list.empty()) {
351     if (offset == -1)
352       row = m_row_list.back();
353     else {
354       collection::const_iterator pos, end = m_row_list.end();
355       for (pos = m_row_list.begin(); pos != end; ++pos) {
356         if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
357           row = *pos;
358         else
359           break;
360       }
361     }
362   }
363   return row;
364 }
365
366 bool UnwindPlan::IsValidRowIndex(uint32_t idx) const {
367   return idx < m_row_list.size();
368 }
369
370 const UnwindPlan::RowSP UnwindPlan::GetRowAtIndex(uint32_t idx) const {
371   if (idx < m_row_list.size())
372     return m_row_list[idx];
373   else {
374     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
375     if (log)
376       log->Printf("error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index "
377                   "(number rows is %u)",
378                   idx, (uint32_t)m_row_list.size());
379     return UnwindPlan::RowSP();
380   }
381 }
382
383 const UnwindPlan::RowSP UnwindPlan::GetLastRow() const {
384   if (m_row_list.empty()) {
385     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
386     if (log)
387       log->Printf("UnwindPlan::GetLastRow() when rows are empty");
388     return UnwindPlan::RowSP();
389   }
390   return m_row_list.back();
391 }
392
393 int UnwindPlan::GetRowCount() const { return m_row_list.size(); }
394
395 void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) {
396   if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
397     m_plan_valid_address_range = range;
398 }
399
400 bool UnwindPlan::PlanValidAtAddress(Address addr) {
401   // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
402   if (GetRowCount() == 0) {
403     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
404     if (log) {
405       StreamString s;
406       if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
407         log->Printf("UnwindPlan is invalid -- no unwind rows for UnwindPlan "
408                     "'%s' at address %s",
409                     m_source_name.GetCString(), s.GetData());
410       } else {
411         log->Printf(
412             "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
413             m_source_name.GetCString());
414       }
415     }
416     return false;
417   }
418
419   // If the 0th Row of unwind instructions is missing, or if it doesn't provide
420   // a register to use to find the Canonical Frame Address, this is not a valid
421   // UnwindPlan.
422   if (GetRowAtIndex(0).get() == nullptr ||
423       GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
424           Row::FAValue::unspecified) {
425     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
426     if (log) {
427       StreamString s;
428       if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
429         log->Printf("UnwindPlan is invalid -- no CFA register defined in row 0 "
430                     "for UnwindPlan '%s' at address %s",
431                     m_source_name.GetCString(), s.GetData());
432       } else {
433         log->Printf("UnwindPlan is invalid -- no CFA register defined in row 0 "
434                     "for UnwindPlan '%s'",
435                     m_source_name.GetCString());
436       }
437     }
438     return false;
439   }
440
441   if (!m_plan_valid_address_range.GetBaseAddress().IsValid() ||
442       m_plan_valid_address_range.GetByteSize() == 0)
443     return true;
444
445   if (!addr.IsValid())
446     return true;
447
448   if (m_plan_valid_address_range.ContainsFileAddress(addr))
449     return true;
450
451   return false;
452 }
453
454 void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
455   if (!m_source_name.IsEmpty()) {
456     s.Printf("This UnwindPlan originally sourced from %s\n",
457              m_source_name.GetCString());
458   }
459   if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) {
460     TargetSP target_sp(thread->CalculateTarget());
461     addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get());
462     addr_t personality_func_load_addr =
463         m_personality_func_addr.GetLoadAddress(target_sp.get());
464
465     if (lsda_load_addr != LLDB_INVALID_ADDRESS &&
466         personality_func_load_addr != LLDB_INVALID_ADDRESS) {
467       s.Printf("LSDA address 0x%" PRIx64
468                ", personality routine is at address 0x%" PRIx64 "\n",
469                lsda_load_addr, personality_func_load_addr);
470     }
471   }
472   s.Printf("This UnwindPlan is sourced from the compiler: ");
473   switch (m_plan_is_sourced_from_compiler) {
474   case eLazyBoolYes:
475     s.Printf("yes.\n");
476     break;
477   case eLazyBoolNo:
478     s.Printf("no.\n");
479     break;
480   case eLazyBoolCalculate:
481     s.Printf("not specified.\n");
482     break;
483   }
484   s.Printf("This UnwindPlan is valid at all instruction locations: ");
485   switch (m_plan_is_valid_at_all_instruction_locations) {
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   if (m_plan_valid_address_range.GetBaseAddress().IsValid() &&
497       m_plan_valid_address_range.GetByteSize() > 0) {
498     s.PutCString("Address range of this UnwindPlan: ");
499     TargetSP target_sp(thread->CalculateTarget());
500     m_plan_valid_address_range.Dump(&s, target_sp.get(),
501                                     Address::DumpStyleSectionNameOffset);
502     s.EOL();
503   }
504   collection::const_iterator pos, begin = m_row_list.begin(),
505                                   end = m_row_list.end();
506   for (pos = begin; pos != end; ++pos) {
507     s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos));
508     (*pos)->Dump(s, this, thread, base_addr);
509   }
510 }
511
512 void UnwindPlan::SetSourceName(const char *source) {
513   m_source_name = ConstString(source);
514 }
515
516 ConstString UnwindPlan::GetSourceName() const { return m_source_name; }
517
518 const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread,
519                                                 uint32_t unwind_reg) const {
520   if (thread) {
521     RegisterContext *reg_ctx = thread->GetRegisterContext().get();
522     if (reg_ctx) {
523       uint32_t reg;
524       if (m_register_kind == eRegisterKindLLDB)
525         reg = unwind_reg;
526       else
527         reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind,
528                                                            unwind_reg);
529       if (reg != LLDB_INVALID_REGNUM)
530         return reg_ctx->GetRegisterInfoAtIndex(reg);
531     }
532   }
533   return nullptr;
534 }