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