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