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