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