xref: /freebsd-src/contrib/llvm-project/lldb/source/Symbol/UnwindPlan.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
15ffd83dbSDimitry Andric //===-- UnwindPlan.cpp ----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Symbol/UnwindPlan.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/Target/Process.h"
120b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
130b57cec5SDimitry Andric #include "lldb/Target/Target.h"
140b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
150b57cec5SDimitry Andric #include "lldb/Utility/ConstString.h"
1681ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
170b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
1881ad6265SDimitry Andric #include "llvm/DebugInfo/DIContext.h"
195ffd83dbSDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
20*bdd1243dSDimitry Andric #include <optional>
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric using namespace lldb;
230b57cec5SDimitry Andric using namespace lldb_private;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric bool UnwindPlan::Row::RegisterLocation::
operator ==(const UnwindPlan::Row::RegisterLocation & rhs) const260b57cec5SDimitry Andric operator==(const UnwindPlan::Row::RegisterLocation &rhs) const {
270b57cec5SDimitry Andric   if (m_type == rhs.m_type) {
280b57cec5SDimitry Andric     switch (m_type) {
290b57cec5SDimitry Andric     case unspecified:
300b57cec5SDimitry Andric     case undefined:
310b57cec5SDimitry Andric     case same:
320b57cec5SDimitry Andric       return true;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric     case atCFAPlusOffset:
350b57cec5SDimitry Andric     case isCFAPlusOffset:
360b57cec5SDimitry Andric     case atAFAPlusOffset:
370b57cec5SDimitry Andric     case isAFAPlusOffset:
380b57cec5SDimitry Andric       return m_location.offset == rhs.m_location.offset;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric     case inOtherRegister:
410b57cec5SDimitry Andric       return m_location.reg_num == rhs.m_location.reg_num;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric     case atDWARFExpression:
440b57cec5SDimitry Andric     case isDWARFExpression:
450b57cec5SDimitry Andric       if (m_location.expr.length == rhs.m_location.expr.length)
460b57cec5SDimitry Andric         return !memcmp(m_location.expr.opcodes, rhs.m_location.expr.opcodes,
470b57cec5SDimitry Andric                        m_location.expr.length);
480b57cec5SDimitry Andric       break;
490b57cec5SDimitry Andric     }
500b57cec5SDimitry Andric   }
510b57cec5SDimitry Andric   return false;
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric // This function doesn't copy the dwarf expression bytes; they must remain in
550b57cec5SDimitry Andric // allocated memory for the lifespan of this UnwindPlan object.
SetAtDWARFExpression(const uint8_t * opcodes,uint32_t len)560b57cec5SDimitry Andric void UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression(
570b57cec5SDimitry Andric     const uint8_t *opcodes, uint32_t len) {
580b57cec5SDimitry Andric   m_type = atDWARFExpression;
590b57cec5SDimitry Andric   m_location.expr.opcodes = opcodes;
600b57cec5SDimitry Andric   m_location.expr.length = len;
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric // This function doesn't copy the dwarf expression bytes; they must remain in
640b57cec5SDimitry Andric // allocated memory for the lifespan of this UnwindPlan object.
SetIsDWARFExpression(const uint8_t * opcodes,uint32_t len)650b57cec5SDimitry Andric void UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression(
660b57cec5SDimitry Andric     const uint8_t *opcodes, uint32_t len) {
670b57cec5SDimitry Andric   m_type = isDWARFExpression;
680b57cec5SDimitry Andric   m_location.expr.opcodes = opcodes;
690b57cec5SDimitry Andric   m_location.expr.length = len;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
72*bdd1243dSDimitry Andric static std::optional<std::pair<lldb::ByteOrder, uint32_t>>
GetByteOrderAndAddrSize(Thread * thread)730b57cec5SDimitry Andric GetByteOrderAndAddrSize(Thread *thread) {
740b57cec5SDimitry Andric   if (!thread)
75*bdd1243dSDimitry Andric     return std::nullopt;
760b57cec5SDimitry Andric   ProcessSP process_sp = thread->GetProcess();
770b57cec5SDimitry Andric   if (!process_sp)
78*bdd1243dSDimitry Andric     return std::nullopt;
790b57cec5SDimitry Andric   ArchSpec arch = process_sp->GetTarget().GetArchitecture();
800b57cec5SDimitry Andric   return std::make_pair(arch.GetByteOrder(), arch.GetAddressByteSize());
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
DumpDWARFExpr(Stream & s,llvm::ArrayRef<uint8_t> expr,Thread * thread)830b57cec5SDimitry Andric static void DumpDWARFExpr(Stream &s, llvm::ArrayRef<uint8_t> expr, Thread *thread) {
840b57cec5SDimitry Andric   if (auto order_and_width = GetByteOrderAndAddrSize(thread)) {
855ffd83dbSDimitry Andric     llvm::DataExtractor data(expr, order_and_width->first == eByteOrderLittle,
860b57cec5SDimitry Andric                              order_and_width->second);
875ffd83dbSDimitry Andric     llvm::DWARFExpression(data, order_and_width->second, llvm::dwarf::DWARF32)
88*bdd1243dSDimitry Andric         .print(s.AsRawOstream(), llvm::DIDumpOptions(), nullptr);
890b57cec5SDimitry Andric   } else
900b57cec5SDimitry Andric     s.PutCString("dwarf-expr");
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric 
Dump(Stream & s,const UnwindPlan * unwind_plan,const UnwindPlan::Row * row,Thread * thread,bool verbose) const930b57cec5SDimitry Andric void UnwindPlan::Row::RegisterLocation::Dump(Stream &s,
940b57cec5SDimitry Andric                                              const UnwindPlan *unwind_plan,
950b57cec5SDimitry Andric                                              const UnwindPlan::Row *row,
960b57cec5SDimitry Andric                                              Thread *thread,
970b57cec5SDimitry Andric                                              bool verbose) const {
980b57cec5SDimitry Andric   switch (m_type) {
990b57cec5SDimitry Andric   case unspecified:
1000b57cec5SDimitry Andric     if (verbose)
1010b57cec5SDimitry Andric       s.PutCString("=<unspec>");
1020b57cec5SDimitry Andric     else
1030b57cec5SDimitry Andric       s.PutCString("=!");
1040b57cec5SDimitry Andric     break;
1050b57cec5SDimitry Andric   case undefined:
1060b57cec5SDimitry Andric     if (verbose)
1070b57cec5SDimitry Andric       s.PutCString("=<undef>");
1080b57cec5SDimitry Andric     else
1090b57cec5SDimitry Andric       s.PutCString("=?");
1100b57cec5SDimitry Andric     break;
1110b57cec5SDimitry Andric   case same:
1120b57cec5SDimitry Andric     s.PutCString("= <same>");
1130b57cec5SDimitry Andric     break;
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   case atCFAPlusOffset:
1160b57cec5SDimitry Andric   case isCFAPlusOffset: {
1170b57cec5SDimitry Andric     s.PutChar('=');
1180b57cec5SDimitry Andric     if (m_type == atCFAPlusOffset)
1190b57cec5SDimitry Andric       s.PutChar('[');
1200b57cec5SDimitry Andric     s.Printf("CFA%+d", m_location.offset);
1210b57cec5SDimitry Andric     if (m_type == atCFAPlusOffset)
1220b57cec5SDimitry Andric       s.PutChar(']');
1230b57cec5SDimitry Andric   } break;
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   case atAFAPlusOffset:
1260b57cec5SDimitry Andric   case isAFAPlusOffset: {
1270b57cec5SDimitry Andric     s.PutChar('=');
1280b57cec5SDimitry Andric     if (m_type == atAFAPlusOffset)
1290b57cec5SDimitry Andric       s.PutChar('[');
1300b57cec5SDimitry Andric     s.Printf("AFA%+d", m_location.offset);
1310b57cec5SDimitry Andric     if (m_type == atAFAPlusOffset)
1320b57cec5SDimitry Andric       s.PutChar(']');
1330b57cec5SDimitry Andric   } break;
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric   case inOtherRegister: {
1360b57cec5SDimitry Andric     const RegisterInfo *other_reg_info = nullptr;
1370b57cec5SDimitry Andric     if (unwind_plan)
1380b57cec5SDimitry Andric       other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num);
1390b57cec5SDimitry Andric     if (other_reg_info)
1400b57cec5SDimitry Andric       s.Printf("=%s", other_reg_info->name);
1410b57cec5SDimitry Andric     else
1420b57cec5SDimitry Andric       s.Printf("=reg(%u)", m_location.reg_num);
1430b57cec5SDimitry Andric   } break;
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   case atDWARFExpression:
1460b57cec5SDimitry Andric   case isDWARFExpression: {
1470b57cec5SDimitry Andric     s.PutChar('=');
1480b57cec5SDimitry Andric     if (m_type == atDWARFExpression)
1490b57cec5SDimitry Andric       s.PutChar('[');
1500b57cec5SDimitry Andric     DumpDWARFExpr(
151*bdd1243dSDimitry Andric         s, llvm::ArrayRef(m_location.expr.opcodes, m_location.expr.length),
1520b57cec5SDimitry Andric         thread);
1530b57cec5SDimitry Andric     if (m_type == atDWARFExpression)
1540b57cec5SDimitry Andric       s.PutChar(']');
1550b57cec5SDimitry Andric   } break;
1560b57cec5SDimitry Andric   }
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric 
DumpRegisterName(Stream & s,const UnwindPlan * unwind_plan,Thread * thread,uint32_t reg_num)1590b57cec5SDimitry Andric static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,
1600b57cec5SDimitry Andric                              Thread *thread, uint32_t reg_num) {
1610b57cec5SDimitry Andric   const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num);
1620b57cec5SDimitry Andric   if (reg_info)
1630b57cec5SDimitry Andric     s.PutCString(reg_info->name);
1640b57cec5SDimitry Andric   else
1650b57cec5SDimitry Andric     s.Printf("reg(%u)", reg_num);
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric bool UnwindPlan::Row::FAValue::
operator ==(const UnwindPlan::Row::FAValue & rhs) const1690b57cec5SDimitry Andric operator==(const UnwindPlan::Row::FAValue &rhs) const {
1700b57cec5SDimitry Andric   if (m_type == rhs.m_type) {
1710b57cec5SDimitry Andric     switch (m_type) {
1720b57cec5SDimitry Andric     case unspecified:
1739dba64beSDimitry Andric     case isRaSearch:
1749dba64beSDimitry Andric       return m_value.ra_search_offset == rhs.m_value.ra_search_offset;
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric     case isRegisterPlusOffset:
1770b57cec5SDimitry Andric       return m_value.reg.offset == rhs.m_value.reg.offset;
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric     case isRegisterDereferenced:
1800b57cec5SDimitry Andric       return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric     case isDWARFExpression:
1830b57cec5SDimitry Andric       if (m_value.expr.length == rhs.m_value.expr.length)
1840b57cec5SDimitry Andric         return !memcmp(m_value.expr.opcodes, rhs.m_value.expr.opcodes,
1850b57cec5SDimitry Andric                        m_value.expr.length);
1860b57cec5SDimitry Andric       break;
1870b57cec5SDimitry Andric     }
1880b57cec5SDimitry Andric   }
1890b57cec5SDimitry Andric   return false;
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
Dump(Stream & s,const UnwindPlan * unwind_plan,Thread * thread) const1920b57cec5SDimitry Andric void UnwindPlan::Row::FAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
1930b57cec5SDimitry Andric                                      Thread *thread) const {
1940b57cec5SDimitry Andric   switch (m_type) {
1950b57cec5SDimitry Andric   case isRegisterPlusOffset:
1960b57cec5SDimitry Andric     DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
1970b57cec5SDimitry Andric     s.Printf("%+3d", m_value.reg.offset);
1980b57cec5SDimitry Andric     break;
1990b57cec5SDimitry Andric   case isRegisterDereferenced:
2000b57cec5SDimitry Andric     s.PutChar('[');
2010b57cec5SDimitry Andric     DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
2020b57cec5SDimitry Andric     s.PutChar(']');
2030b57cec5SDimitry Andric     break;
2040b57cec5SDimitry Andric   case isDWARFExpression:
205*bdd1243dSDimitry Andric     DumpDWARFExpr(s, llvm::ArrayRef(m_value.expr.opcodes, m_value.expr.length),
2060b57cec5SDimitry Andric                   thread);
2070b57cec5SDimitry Andric     break;
2089dba64beSDimitry Andric   case unspecified:
2090b57cec5SDimitry Andric     s.PutCString("unspecified");
2100b57cec5SDimitry Andric     break;
2119dba64beSDimitry Andric   case isRaSearch:
2129dba64beSDimitry Andric     s.Printf("RaSearch@SP%+d", m_value.ra_search_offset);
2139dba64beSDimitry Andric     break;
2140b57cec5SDimitry Andric   }
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric 
Clear()2170b57cec5SDimitry Andric void UnwindPlan::Row::Clear() {
2180b57cec5SDimitry Andric   m_cfa_value.SetUnspecified();
2190b57cec5SDimitry Andric   m_afa_value.SetUnspecified();
2200b57cec5SDimitry Andric   m_offset = 0;
221fe6060f1SDimitry Andric   m_unspecified_registers_are_undefined = false;
2220b57cec5SDimitry Andric   m_register_locations.clear();
2230b57cec5SDimitry Andric }
2240b57cec5SDimitry Andric 
Dump(Stream & s,const UnwindPlan * unwind_plan,Thread * thread,addr_t base_addr) const2250b57cec5SDimitry Andric void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
2260b57cec5SDimitry Andric                            Thread *thread, addr_t base_addr) const {
2270b57cec5SDimitry Andric   if (base_addr != LLDB_INVALID_ADDRESS)
2280b57cec5SDimitry Andric     s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
2290b57cec5SDimitry Andric   else
2300b57cec5SDimitry Andric     s.Printf("%4" PRId64 ": CFA=", GetOffset());
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   m_cfa_value.Dump(s, unwind_plan, thread);
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   if (!m_afa_value.IsUnspecified()) {
2350b57cec5SDimitry Andric     s.Printf(" AFA=");
2360b57cec5SDimitry Andric     m_afa_value.Dump(s, unwind_plan, thread);
2370b57cec5SDimitry Andric   }
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   s.Printf(" => ");
2400b57cec5SDimitry Andric   for (collection::const_iterator idx = m_register_locations.begin();
2410b57cec5SDimitry Andric        idx != m_register_locations.end(); ++idx) {
2420b57cec5SDimitry Andric     DumpRegisterName(s, unwind_plan, thread, idx->first);
2430b57cec5SDimitry Andric     const bool verbose = false;
2440b57cec5SDimitry Andric     idx->second.Dump(s, unwind_plan, this, thread, verbose);
2450b57cec5SDimitry Andric     s.PutChar(' ');
2460b57cec5SDimitry Andric   }
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric 
Row()249fe6060f1SDimitry Andric UnwindPlan::Row::Row() : m_cfa_value(), m_afa_value(), m_register_locations() {}
2500b57cec5SDimitry Andric 
GetRegisterInfo(uint32_t reg_num,UnwindPlan::Row::RegisterLocation & register_location) const2510b57cec5SDimitry Andric bool UnwindPlan::Row::GetRegisterInfo(
2520b57cec5SDimitry Andric     uint32_t reg_num,
2530b57cec5SDimitry Andric     UnwindPlan::Row::RegisterLocation &register_location) const {
2540b57cec5SDimitry Andric   collection::const_iterator pos = m_register_locations.find(reg_num);
2550b57cec5SDimitry Andric   if (pos != m_register_locations.end()) {
2560b57cec5SDimitry Andric     register_location = pos->second;
2570b57cec5SDimitry Andric     return true;
2580b57cec5SDimitry Andric   }
259fe6060f1SDimitry Andric   if (m_unspecified_registers_are_undefined) {
260fe6060f1SDimitry Andric     register_location.SetUndefined();
261fe6060f1SDimitry Andric     return true;
262fe6060f1SDimitry Andric   }
2630b57cec5SDimitry Andric   return false;
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric 
RemoveRegisterInfo(uint32_t reg_num)2660b57cec5SDimitry Andric void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) {
2670b57cec5SDimitry Andric   collection::const_iterator pos = m_register_locations.find(reg_num);
2680b57cec5SDimitry Andric   if (pos != m_register_locations.end()) {
2690b57cec5SDimitry Andric     m_register_locations.erase(pos);
2700b57cec5SDimitry Andric   }
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric 
SetRegisterInfo(uint32_t reg_num,const UnwindPlan::Row::RegisterLocation register_location)2730b57cec5SDimitry Andric void UnwindPlan::Row::SetRegisterInfo(
2740b57cec5SDimitry Andric     uint32_t reg_num,
2750b57cec5SDimitry Andric     const UnwindPlan::Row::RegisterLocation register_location) {
2760b57cec5SDimitry Andric   m_register_locations[reg_num] = register_location;
2770b57cec5SDimitry Andric }
2780b57cec5SDimitry Andric 
SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)2790b57cec5SDimitry Andric bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,
2800b57cec5SDimitry Andric                                                            int32_t offset,
2810b57cec5SDimitry Andric                                                            bool can_replace) {
2820b57cec5SDimitry Andric   if (!can_replace &&
2830b57cec5SDimitry Andric       m_register_locations.find(reg_num) != m_register_locations.end())
2840b57cec5SDimitry Andric     return false;
2850b57cec5SDimitry Andric   RegisterLocation reg_loc;
2860b57cec5SDimitry Andric   reg_loc.SetAtCFAPlusOffset(offset);
2870b57cec5SDimitry Andric   m_register_locations[reg_num] = reg_loc;
2880b57cec5SDimitry Andric   return true;
2890b57cec5SDimitry Andric }
2900b57cec5SDimitry Andric 
SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,int32_t offset,bool can_replace)2910b57cec5SDimitry Andric bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,
2920b57cec5SDimitry Andric                                                            int32_t offset,
2930b57cec5SDimitry Andric                                                            bool can_replace) {
2940b57cec5SDimitry Andric   if (!can_replace &&
2950b57cec5SDimitry Andric       m_register_locations.find(reg_num) != m_register_locations.end())
2960b57cec5SDimitry Andric     return false;
2970b57cec5SDimitry Andric   RegisterLocation reg_loc;
2980b57cec5SDimitry Andric   reg_loc.SetIsCFAPlusOffset(offset);
2990b57cec5SDimitry Andric   m_register_locations[reg_num] = reg_loc;
3000b57cec5SDimitry Andric   return true;
3010b57cec5SDimitry Andric }
3020b57cec5SDimitry Andric 
SetRegisterLocationToUndefined(uint32_t reg_num,bool can_replace,bool can_replace_only_if_unspecified)3030b57cec5SDimitry Andric bool UnwindPlan::Row::SetRegisterLocationToUndefined(
3040b57cec5SDimitry Andric     uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) {
3050b57cec5SDimitry Andric   collection::iterator pos = m_register_locations.find(reg_num);
3060b57cec5SDimitry Andric   collection::iterator end = m_register_locations.end();
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric   if (pos != end) {
3090b57cec5SDimitry Andric     if (!can_replace)
3100b57cec5SDimitry Andric       return false;
3110b57cec5SDimitry Andric     if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
3120b57cec5SDimitry Andric       return false;
3130b57cec5SDimitry Andric   }
3140b57cec5SDimitry Andric   RegisterLocation reg_loc;
3150b57cec5SDimitry Andric   reg_loc.SetUndefined();
3160b57cec5SDimitry Andric   m_register_locations[reg_num] = reg_loc;
3170b57cec5SDimitry Andric   return true;
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric 
SetRegisterLocationToUnspecified(uint32_t reg_num,bool can_replace)3200b57cec5SDimitry Andric bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num,
3210b57cec5SDimitry Andric                                                        bool can_replace) {
3220b57cec5SDimitry Andric   if (!can_replace &&
3230b57cec5SDimitry Andric       m_register_locations.find(reg_num) != m_register_locations.end())
3240b57cec5SDimitry Andric     return false;
3250b57cec5SDimitry Andric   RegisterLocation reg_loc;
3260b57cec5SDimitry Andric   reg_loc.SetUnspecified();
3270b57cec5SDimitry Andric   m_register_locations[reg_num] = reg_loc;
3280b57cec5SDimitry Andric   return true;
3290b57cec5SDimitry Andric }
3300b57cec5SDimitry Andric 
SetRegisterLocationToRegister(uint32_t reg_num,uint32_t other_reg_num,bool can_replace)3310b57cec5SDimitry Andric bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num,
3320b57cec5SDimitry Andric                                                     uint32_t other_reg_num,
3330b57cec5SDimitry Andric                                                     bool can_replace) {
3340b57cec5SDimitry Andric   if (!can_replace &&
3350b57cec5SDimitry Andric       m_register_locations.find(reg_num) != m_register_locations.end())
3360b57cec5SDimitry Andric     return false;
3370b57cec5SDimitry Andric   RegisterLocation reg_loc;
3380b57cec5SDimitry Andric   reg_loc.SetInRegister(other_reg_num);
3390b57cec5SDimitry Andric   m_register_locations[reg_num] = reg_loc;
3400b57cec5SDimitry Andric   return true;
3410b57cec5SDimitry Andric }
3420b57cec5SDimitry Andric 
SetRegisterLocationToSame(uint32_t reg_num,bool must_replace)3430b57cec5SDimitry Andric bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,
3440b57cec5SDimitry Andric                                                 bool must_replace) {
3450b57cec5SDimitry Andric   if (must_replace &&
3460b57cec5SDimitry Andric       m_register_locations.find(reg_num) == m_register_locations.end())
3470b57cec5SDimitry Andric     return false;
3480b57cec5SDimitry Andric   RegisterLocation reg_loc;
3490b57cec5SDimitry Andric   reg_loc.SetSame();
3500b57cec5SDimitry Andric   m_register_locations[reg_num] = reg_loc;
3510b57cec5SDimitry Andric   return true;
3520b57cec5SDimitry Andric }
3530b57cec5SDimitry Andric 
operator ==(const UnwindPlan::Row & rhs) const3540b57cec5SDimitry Andric bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
355fe6060f1SDimitry Andric   return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
3560b57cec5SDimitry Andric          m_afa_value == rhs.m_afa_value &&
357fe6060f1SDimitry Andric          m_unspecified_registers_are_undefined ==
358fe6060f1SDimitry Andric              rhs.m_unspecified_registers_are_undefined &&
3590b57cec5SDimitry Andric          m_register_locations == rhs.m_register_locations;
3600b57cec5SDimitry Andric }
3610b57cec5SDimitry Andric 
AppendRow(const UnwindPlan::RowSP & row_sp)3620b57cec5SDimitry Andric void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) {
3630b57cec5SDimitry Andric   if (m_row_list.empty() ||
3640b57cec5SDimitry Andric       m_row_list.back()->GetOffset() != row_sp->GetOffset())
3650b57cec5SDimitry Andric     m_row_list.push_back(row_sp);
3660b57cec5SDimitry Andric   else
3670b57cec5SDimitry Andric     m_row_list.back() = row_sp;
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric 
InsertRow(const UnwindPlan::RowSP & row_sp,bool replace_existing)3700b57cec5SDimitry Andric void UnwindPlan::InsertRow(const UnwindPlan::RowSP &row_sp,
3710b57cec5SDimitry Andric                            bool replace_existing) {
3720b57cec5SDimitry Andric   collection::iterator it = m_row_list.begin();
3730b57cec5SDimitry Andric   while (it != m_row_list.end()) {
3740b57cec5SDimitry Andric     RowSP row = *it;
3750b57cec5SDimitry Andric     if (row->GetOffset() >= row_sp->GetOffset())
3760b57cec5SDimitry Andric       break;
3770b57cec5SDimitry Andric     it++;
3780b57cec5SDimitry Andric   }
3790b57cec5SDimitry Andric   if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
3800b57cec5SDimitry Andric     m_row_list.insert(it, row_sp);
3810b57cec5SDimitry Andric   else if (replace_existing)
3820b57cec5SDimitry Andric     *it = row_sp;
3830b57cec5SDimitry Andric }
3840b57cec5SDimitry Andric 
GetRowForFunctionOffset(int offset) const3850b57cec5SDimitry Andric UnwindPlan::RowSP UnwindPlan::GetRowForFunctionOffset(int offset) const {
3860b57cec5SDimitry Andric   RowSP row;
3870b57cec5SDimitry Andric   if (!m_row_list.empty()) {
3880b57cec5SDimitry Andric     if (offset == -1)
3890b57cec5SDimitry Andric       row = m_row_list.back();
3900b57cec5SDimitry Andric     else {
3910b57cec5SDimitry Andric       collection::const_iterator pos, end = m_row_list.end();
3920b57cec5SDimitry Andric       for (pos = m_row_list.begin(); pos != end; ++pos) {
3930b57cec5SDimitry Andric         if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
3940b57cec5SDimitry Andric           row = *pos;
3950b57cec5SDimitry Andric         else
3960b57cec5SDimitry Andric           break;
3970b57cec5SDimitry Andric       }
3980b57cec5SDimitry Andric     }
3990b57cec5SDimitry Andric   }
4000b57cec5SDimitry Andric   return row;
4010b57cec5SDimitry Andric }
4020b57cec5SDimitry Andric 
IsValidRowIndex(uint32_t idx) const4030b57cec5SDimitry Andric bool UnwindPlan::IsValidRowIndex(uint32_t idx) const {
4040b57cec5SDimitry Andric   return idx < m_row_list.size();
4050b57cec5SDimitry Andric }
4060b57cec5SDimitry Andric 
GetRowAtIndex(uint32_t idx) const4070b57cec5SDimitry Andric const UnwindPlan::RowSP UnwindPlan::GetRowAtIndex(uint32_t idx) const {
4080b57cec5SDimitry Andric   if (idx < m_row_list.size())
4090b57cec5SDimitry Andric     return m_row_list[idx];
4100b57cec5SDimitry Andric   else {
41181ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Unwind);
4129dba64beSDimitry Andric     LLDB_LOGF(log,
4139dba64beSDimitry Andric               "error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index "
4140b57cec5SDimitry Andric               "(number rows is %u)",
4150b57cec5SDimitry Andric               idx, (uint32_t)m_row_list.size());
4160b57cec5SDimitry Andric     return UnwindPlan::RowSP();
4170b57cec5SDimitry Andric   }
4180b57cec5SDimitry Andric }
4190b57cec5SDimitry Andric 
GetLastRow() const4200b57cec5SDimitry Andric const UnwindPlan::RowSP UnwindPlan::GetLastRow() const {
4210b57cec5SDimitry Andric   if (m_row_list.empty()) {
42281ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Unwind);
4239dba64beSDimitry Andric     LLDB_LOGF(log, "UnwindPlan::GetLastRow() when rows are empty");
4240b57cec5SDimitry Andric     return UnwindPlan::RowSP();
4250b57cec5SDimitry Andric   }
4260b57cec5SDimitry Andric   return m_row_list.back();
4270b57cec5SDimitry Andric }
4280b57cec5SDimitry Andric 
GetRowCount() const4290b57cec5SDimitry Andric int UnwindPlan::GetRowCount() const { return m_row_list.size(); }
4300b57cec5SDimitry Andric 
SetPlanValidAddressRange(const AddressRange & range)4310b57cec5SDimitry Andric void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) {
4320b57cec5SDimitry Andric   if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
4330b57cec5SDimitry Andric     m_plan_valid_address_range = range;
4340b57cec5SDimitry Andric }
4350b57cec5SDimitry Andric 
PlanValidAtAddress(Address addr)4360b57cec5SDimitry Andric bool UnwindPlan::PlanValidAtAddress(Address addr) {
4370b57cec5SDimitry Andric   // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
4380b57cec5SDimitry Andric   if (GetRowCount() == 0) {
43981ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Unwind);
4400b57cec5SDimitry Andric     if (log) {
4410b57cec5SDimitry Andric       StreamString s;
4420b57cec5SDimitry Andric       if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
4439dba64beSDimitry Andric         LLDB_LOGF(log,
4449dba64beSDimitry Andric                   "UnwindPlan is invalid -- no unwind rows for UnwindPlan "
4450b57cec5SDimitry Andric                   "'%s' at address %s",
4460b57cec5SDimitry Andric                   m_source_name.GetCString(), s.GetData());
4470b57cec5SDimitry Andric       } else {
4489dba64beSDimitry Andric         LLDB_LOGF(log,
4490b57cec5SDimitry Andric                   "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
4500b57cec5SDimitry Andric                   m_source_name.GetCString());
4510b57cec5SDimitry Andric       }
4520b57cec5SDimitry Andric     }
4530b57cec5SDimitry Andric     return false;
4540b57cec5SDimitry Andric   }
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric   // If the 0th Row of unwind instructions is missing, or if it doesn't provide
4570b57cec5SDimitry Andric   // a register to use to find the Canonical Frame Address, this is not a valid
4580b57cec5SDimitry Andric   // UnwindPlan.
4590b57cec5SDimitry Andric   if (GetRowAtIndex(0).get() == nullptr ||
4600b57cec5SDimitry Andric       GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
4610b57cec5SDimitry Andric           Row::FAValue::unspecified) {
46281ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Unwind);
4630b57cec5SDimitry Andric     if (log) {
4640b57cec5SDimitry Andric       StreamString s;
4650b57cec5SDimitry Andric       if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
4669dba64beSDimitry Andric         LLDB_LOGF(log,
4679dba64beSDimitry Andric                   "UnwindPlan is invalid -- no CFA register defined in row 0 "
4680b57cec5SDimitry Andric                   "for UnwindPlan '%s' at address %s",
4690b57cec5SDimitry Andric                   m_source_name.GetCString(), s.GetData());
4700b57cec5SDimitry Andric       } else {
4719dba64beSDimitry Andric         LLDB_LOGF(log,
4729dba64beSDimitry Andric                   "UnwindPlan is invalid -- no CFA register defined in row 0 "
4730b57cec5SDimitry Andric                   "for UnwindPlan '%s'",
4740b57cec5SDimitry Andric                   m_source_name.GetCString());
4750b57cec5SDimitry Andric       }
4760b57cec5SDimitry Andric     }
4770b57cec5SDimitry Andric     return false;
4780b57cec5SDimitry Andric   }
4790b57cec5SDimitry Andric 
4800b57cec5SDimitry Andric   if (!m_plan_valid_address_range.GetBaseAddress().IsValid() ||
4810b57cec5SDimitry Andric       m_plan_valid_address_range.GetByteSize() == 0)
4820b57cec5SDimitry Andric     return true;
4830b57cec5SDimitry Andric 
4840b57cec5SDimitry Andric   if (!addr.IsValid())
4850b57cec5SDimitry Andric     return true;
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric   if (m_plan_valid_address_range.ContainsFileAddress(addr))
4880b57cec5SDimitry Andric     return true;
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric   return false;
4910b57cec5SDimitry Andric }
4920b57cec5SDimitry Andric 
Dump(Stream & s,Thread * thread,lldb::addr_t base_addr) const4930b57cec5SDimitry Andric void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
4940b57cec5SDimitry Andric   if (!m_source_name.IsEmpty()) {
4950b57cec5SDimitry Andric     s.Printf("This UnwindPlan originally sourced from %s\n",
4960b57cec5SDimitry Andric              m_source_name.GetCString());
4970b57cec5SDimitry Andric   }
4980b57cec5SDimitry Andric   if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) {
4990b57cec5SDimitry Andric     TargetSP target_sp(thread->CalculateTarget());
5000b57cec5SDimitry Andric     addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get());
5010b57cec5SDimitry Andric     addr_t personality_func_load_addr =
5020b57cec5SDimitry Andric         m_personality_func_addr.GetLoadAddress(target_sp.get());
5030b57cec5SDimitry Andric 
5040b57cec5SDimitry Andric     if (lsda_load_addr != LLDB_INVALID_ADDRESS &&
5050b57cec5SDimitry Andric         personality_func_load_addr != LLDB_INVALID_ADDRESS) {
5060b57cec5SDimitry Andric       s.Printf("LSDA address 0x%" PRIx64
5070b57cec5SDimitry Andric                ", personality routine is at address 0x%" PRIx64 "\n",
5080b57cec5SDimitry Andric                lsda_load_addr, personality_func_load_addr);
5090b57cec5SDimitry Andric     }
5100b57cec5SDimitry Andric   }
5110b57cec5SDimitry Andric   s.Printf("This UnwindPlan is sourced from the compiler: ");
5120b57cec5SDimitry Andric   switch (m_plan_is_sourced_from_compiler) {
5130b57cec5SDimitry Andric   case eLazyBoolYes:
5140b57cec5SDimitry Andric     s.Printf("yes.\n");
5150b57cec5SDimitry Andric     break;
5160b57cec5SDimitry Andric   case eLazyBoolNo:
5170b57cec5SDimitry Andric     s.Printf("no.\n");
5180b57cec5SDimitry Andric     break;
5190b57cec5SDimitry Andric   case eLazyBoolCalculate:
5200b57cec5SDimitry Andric     s.Printf("not specified.\n");
5210b57cec5SDimitry Andric     break;
5220b57cec5SDimitry Andric   }
5230b57cec5SDimitry Andric   s.Printf("This UnwindPlan is valid at all instruction locations: ");
5240b57cec5SDimitry Andric   switch (m_plan_is_valid_at_all_instruction_locations) {
5250b57cec5SDimitry Andric   case eLazyBoolYes:
5260b57cec5SDimitry Andric     s.Printf("yes.\n");
5270b57cec5SDimitry Andric     break;
5280b57cec5SDimitry Andric   case eLazyBoolNo:
5290b57cec5SDimitry Andric     s.Printf("no.\n");
5300b57cec5SDimitry Andric     break;
5310b57cec5SDimitry Andric   case eLazyBoolCalculate:
5320b57cec5SDimitry Andric     s.Printf("not specified.\n");
5330b57cec5SDimitry Andric     break;
5340b57cec5SDimitry Andric   }
535e8d8bef9SDimitry Andric   s.Printf("This UnwindPlan is for a trap handler function: ");
536e8d8bef9SDimitry Andric   switch (m_plan_is_for_signal_trap) {
537e8d8bef9SDimitry Andric   case eLazyBoolYes:
538e8d8bef9SDimitry Andric     s.Printf("yes.\n");
539e8d8bef9SDimitry Andric     break;
540e8d8bef9SDimitry Andric   case eLazyBoolNo:
541e8d8bef9SDimitry Andric     s.Printf("no.\n");
542e8d8bef9SDimitry Andric     break;
543e8d8bef9SDimitry Andric   case eLazyBoolCalculate:
544e8d8bef9SDimitry Andric     s.Printf("not specified.\n");
545e8d8bef9SDimitry Andric     break;
546e8d8bef9SDimitry Andric   }
5470b57cec5SDimitry Andric   if (m_plan_valid_address_range.GetBaseAddress().IsValid() &&
5480b57cec5SDimitry Andric       m_plan_valid_address_range.GetByteSize() > 0) {
5490b57cec5SDimitry Andric     s.PutCString("Address range of this UnwindPlan: ");
5500b57cec5SDimitry Andric     TargetSP target_sp(thread->CalculateTarget());
5510b57cec5SDimitry Andric     m_plan_valid_address_range.Dump(&s, target_sp.get(),
5520b57cec5SDimitry Andric                                     Address::DumpStyleSectionNameOffset);
5530b57cec5SDimitry Andric     s.EOL();
5540b57cec5SDimitry Andric   }
5550b57cec5SDimitry Andric   collection::const_iterator pos, begin = m_row_list.begin(),
5560b57cec5SDimitry Andric                                   end = m_row_list.end();
5570b57cec5SDimitry Andric   for (pos = begin; pos != end; ++pos) {
5580b57cec5SDimitry Andric     s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos));
5590b57cec5SDimitry Andric     (*pos)->Dump(s, this, thread, base_addr);
560fe6060f1SDimitry Andric     s.Printf("\n");
5610b57cec5SDimitry Andric   }
5620b57cec5SDimitry Andric }
5630b57cec5SDimitry Andric 
SetSourceName(const char * source)5640b57cec5SDimitry Andric void UnwindPlan::SetSourceName(const char *source) {
5650b57cec5SDimitry Andric   m_source_name = ConstString(source);
5660b57cec5SDimitry Andric }
5670b57cec5SDimitry Andric 
GetSourceName() const5680b57cec5SDimitry Andric ConstString UnwindPlan::GetSourceName() const { return m_source_name; }
5690b57cec5SDimitry Andric 
GetRegisterInfo(Thread * thread,uint32_t unwind_reg) const5700b57cec5SDimitry Andric const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread,
5710b57cec5SDimitry Andric                                                 uint32_t unwind_reg) const {
5720b57cec5SDimitry Andric   if (thread) {
5730b57cec5SDimitry Andric     RegisterContext *reg_ctx = thread->GetRegisterContext().get();
5740b57cec5SDimitry Andric     if (reg_ctx) {
5750b57cec5SDimitry Andric       uint32_t reg;
5760b57cec5SDimitry Andric       if (m_register_kind == eRegisterKindLLDB)
5770b57cec5SDimitry Andric         reg = unwind_reg;
5780b57cec5SDimitry Andric       else
5790b57cec5SDimitry Andric         reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind,
5800b57cec5SDimitry Andric                                                            unwind_reg);
5810b57cec5SDimitry Andric       if (reg != LLDB_INVALID_REGNUM)
5820b57cec5SDimitry Andric         return reg_ctx->GetRegisterInfoAtIndex(reg);
5830b57cec5SDimitry Andric     }
5840b57cec5SDimitry Andric   }
5850b57cec5SDimitry Andric   return nullptr;
5860b57cec5SDimitry Andric }
587