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