forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			571 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			571 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- UnwindPlan.cpp ----------------------------------------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "lldb/Symbol/UnwindPlan.h"
 | 
						|
 | 
						|
#include "lldb/Expression/DWARFExpression.h"
 | 
						|
#include "lldb/Target/Process.h"
 | 
						|
#include "lldb/Target/RegisterContext.h"
 | 
						|
#include "lldb/Target/Target.h"
 | 
						|
#include "lldb/Target/Thread.h"
 | 
						|
#include "lldb/Utility/ConstString.h"
 | 
						|
#include "lldb/Utility/Log.h"
 | 
						|
 | 
						|
using namespace lldb;
 | 
						|
using namespace lldb_private;
 | 
						|
 | 
						|
bool UnwindPlan::Row::RegisterLocation::
 | 
						|
operator==(const UnwindPlan::Row::RegisterLocation &rhs) const {
 | 
						|
  if (m_type == rhs.m_type) {
 | 
						|
    switch (m_type) {
 | 
						|
    case unspecified:
 | 
						|
    case undefined:
 | 
						|
    case same:
 | 
						|
      return true;
 | 
						|
 | 
						|
    case atCFAPlusOffset:
 | 
						|
    case isCFAPlusOffset:
 | 
						|
    case atAFAPlusOffset:
 | 
						|
    case isAFAPlusOffset:
 | 
						|
      return m_location.offset == rhs.m_location.offset;
 | 
						|
 | 
						|
    case inOtherRegister:
 | 
						|
      return m_location.reg_num == rhs.m_location.reg_num;
 | 
						|
 | 
						|
    case atDWARFExpression:
 | 
						|
    case isDWARFExpression:
 | 
						|
      if (m_location.expr.length == rhs.m_location.expr.length)
 | 
						|
        return !memcmp(m_location.expr.opcodes, rhs.m_location.expr.opcodes,
 | 
						|
                       m_location.expr.length);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
// This function doesn't copy the dwarf expression bytes; they must remain in
 | 
						|
// allocated memory for the lifespan of this UnwindPlan object.
 | 
						|
void UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression(
 | 
						|
    const uint8_t *opcodes, uint32_t len) {
 | 
						|
  m_type = atDWARFExpression;
 | 
						|
  m_location.expr.opcodes = opcodes;
 | 
						|
  m_location.expr.length = len;
 | 
						|
}
 | 
						|
 | 
						|
// This function doesn't copy the dwarf expression bytes; they must remain in
 | 
						|
// allocated memory for the lifespan of this UnwindPlan object.
 | 
						|
void UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression(
 | 
						|
    const uint8_t *opcodes, uint32_t len) {
 | 
						|
  m_type = isDWARFExpression;
 | 
						|
  m_location.expr.opcodes = opcodes;
 | 
						|
  m_location.expr.length = len;
 | 
						|
}
 | 
						|
 | 
						|
static llvm::Optional<std::pair<lldb::ByteOrder, uint32_t>>
 | 
						|
GetByteOrderAndAddrSize(Thread *thread) {
 | 
						|
  if (!thread)
 | 
						|
    return llvm::None;
 | 
						|
  ProcessSP process_sp = thread->GetProcess();
 | 
						|
  if (!process_sp)
 | 
						|
    return llvm::None;
 | 
						|
  ArchSpec arch = process_sp->GetTarget().GetArchitecture();
 | 
						|
  return std::make_pair(arch.GetByteOrder(), arch.GetAddressByteSize());
 | 
						|
}
 | 
						|
 | 
						|
static void DumpDWARFExpr(Stream &s, llvm::ArrayRef<uint8_t> expr, Thread *thread) {
 | 
						|
  if (auto order_and_width = GetByteOrderAndAddrSize(thread)) {
 | 
						|
    DataExtractor extractor(expr.data(), expr.size(), order_and_width->first,
 | 
						|
                            order_and_width->second);
 | 
						|
    if (!DWARFExpression::PrintDWARFExpression(s, extractor,
 | 
						|
                                               order_and_width->second,
 | 
						|
                                               /*dwarf_ref_size*/ 4,
 | 
						|
                                               /*location_expression*/ false))
 | 
						|
      s.PutCString("invalid-dwarf-expr");
 | 
						|
  } else
 | 
						|
    s.PutCString("dwarf-expr");
 | 
						|
}
 | 
						|
 | 
						|
void UnwindPlan::Row::RegisterLocation::Dump(Stream &s,
 | 
						|
                                             const UnwindPlan *unwind_plan,
 | 
						|
                                             const UnwindPlan::Row *row,
 | 
						|
                                             Thread *thread,
 | 
						|
                                             bool verbose) const {
 | 
						|
  switch (m_type) {
 | 
						|
  case unspecified:
 | 
						|
    if (verbose)
 | 
						|
      s.PutCString("=<unspec>");
 | 
						|
    else
 | 
						|
      s.PutCString("=!");
 | 
						|
    break;
 | 
						|
  case undefined:
 | 
						|
    if (verbose)
 | 
						|
      s.PutCString("=<undef>");
 | 
						|
    else
 | 
						|
      s.PutCString("=?");
 | 
						|
    break;
 | 
						|
  case same:
 | 
						|
    s.PutCString("= <same>");
 | 
						|
    break;
 | 
						|
 | 
						|
  case atCFAPlusOffset:
 | 
						|
  case isCFAPlusOffset: {
 | 
						|
    s.PutChar('=');
 | 
						|
    if (m_type == atCFAPlusOffset)
 | 
						|
      s.PutChar('[');
 | 
						|
    s.Printf("CFA%+d", m_location.offset);
 | 
						|
    if (m_type == atCFAPlusOffset)
 | 
						|
      s.PutChar(']');
 | 
						|
  } break;
 | 
						|
 | 
						|
  case atAFAPlusOffset:
 | 
						|
  case isAFAPlusOffset: {
 | 
						|
    s.PutChar('=');
 | 
						|
    if (m_type == atAFAPlusOffset)
 | 
						|
      s.PutChar('[');
 | 
						|
    s.Printf("AFA%+d", m_location.offset);
 | 
						|
    if (m_type == atAFAPlusOffset)
 | 
						|
      s.PutChar(']');
 | 
						|
  } break;
 | 
						|
 | 
						|
  case inOtherRegister: {
 | 
						|
    const RegisterInfo *other_reg_info = nullptr;
 | 
						|
    if (unwind_plan)
 | 
						|
      other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num);
 | 
						|
    if (other_reg_info)
 | 
						|
      s.Printf("=%s", other_reg_info->name);
 | 
						|
    else
 | 
						|
      s.Printf("=reg(%u)", m_location.reg_num);
 | 
						|
  } break;
 | 
						|
 | 
						|
  case atDWARFExpression:
 | 
						|
  case isDWARFExpression: {
 | 
						|
    s.PutChar('=');
 | 
						|
    if (m_type == atDWARFExpression)
 | 
						|
      s.PutChar('[');
 | 
						|
    DumpDWARFExpr(
 | 
						|
        s, llvm::makeArrayRef(m_location.expr.opcodes, m_location.expr.length),
 | 
						|
        thread);
 | 
						|
    if (m_type == atDWARFExpression)
 | 
						|
      s.PutChar(']');
 | 
						|
  } break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,
 | 
						|
                             Thread *thread, uint32_t reg_num) {
 | 
						|
  const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num);
 | 
						|
  if (reg_info)
 | 
						|
    s.PutCString(reg_info->name);
 | 
						|
  else
 | 
						|
    s.Printf("reg(%u)", reg_num);
 | 
						|
}
 | 
						|
 | 
						|
bool UnwindPlan::Row::FAValue::
 | 
						|
operator==(const UnwindPlan::Row::FAValue &rhs) const {
 | 
						|
  if (m_type == rhs.m_type) {
 | 
						|
    switch (m_type) {
 | 
						|
    case unspecified:
 | 
						|
    case isRaSearch:
 | 
						|
      return m_value.ra_search_offset == rhs.m_value.ra_search_offset;
 | 
						|
 | 
						|
    case isRegisterPlusOffset:
 | 
						|
      return m_value.reg.offset == rhs.m_value.reg.offset;
 | 
						|
 | 
						|
    case isRegisterDereferenced:
 | 
						|
      return m_value.reg.reg_num == rhs.m_value.reg.reg_num;
 | 
						|
 | 
						|
    case isDWARFExpression:
 | 
						|
      if (m_value.expr.length == rhs.m_value.expr.length)
 | 
						|
        return !memcmp(m_value.expr.opcodes, rhs.m_value.expr.opcodes,
 | 
						|
                       m_value.expr.length);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void UnwindPlan::Row::FAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
 | 
						|
                                     Thread *thread) const {
 | 
						|
  switch (m_type) {
 | 
						|
  case isRegisterPlusOffset:
 | 
						|
    DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
 | 
						|
    s.Printf("%+3d", m_value.reg.offset);
 | 
						|
    break;
 | 
						|
  case isRegisterDereferenced:
 | 
						|
    s.PutChar('[');
 | 
						|
    DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);
 | 
						|
    s.PutChar(']');
 | 
						|
    break;
 | 
						|
  case isDWARFExpression:
 | 
						|
    DumpDWARFExpr(s,
 | 
						|
                  llvm::makeArrayRef(m_value.expr.opcodes, m_value.expr.length),
 | 
						|
                  thread);
 | 
						|
    break;
 | 
						|
  case unspecified:
 | 
						|
    s.PutCString("unspecified");
 | 
						|
    break;
 | 
						|
  case isRaSearch:
 | 
						|
    s.Printf("RaSearch@SP%+d", m_value.ra_search_offset);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void UnwindPlan::Row::Clear() {
 | 
						|
  m_cfa_value.SetUnspecified();
 | 
						|
  m_afa_value.SetUnspecified();
 | 
						|
  m_offset = 0;
 | 
						|
  m_register_locations.clear();
 | 
						|
}
 | 
						|
 | 
						|
void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
 | 
						|
                           Thread *thread, addr_t base_addr) const {
 | 
						|
  if (base_addr != LLDB_INVALID_ADDRESS)
 | 
						|
    s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
 | 
						|
  else
 | 
						|
    s.Printf("%4" PRId64 ": CFA=", GetOffset());
 | 
						|
 | 
						|
  m_cfa_value.Dump(s, unwind_plan, thread);
 | 
						|
 | 
						|
  if (!m_afa_value.IsUnspecified()) {
 | 
						|
    s.Printf(" AFA=");
 | 
						|
    m_afa_value.Dump(s, unwind_plan, thread);
 | 
						|
  }
 | 
						|
 | 
						|
  s.Printf(" => ");
 | 
						|
  for (collection::const_iterator idx = m_register_locations.begin();
 | 
						|
       idx != m_register_locations.end(); ++idx) {
 | 
						|
    DumpRegisterName(s, unwind_plan, thread, idx->first);
 | 
						|
    const bool verbose = false;
 | 
						|
    idx->second.Dump(s, unwind_plan, this, thread, verbose);
 | 
						|
    s.PutChar(' ');
 | 
						|
  }
 | 
						|
  s.EOL();
 | 
						|
}
 | 
						|
 | 
						|
UnwindPlan::Row::Row()
 | 
						|
    : m_offset(0), m_cfa_value(), m_afa_value(), m_register_locations() {}
 | 
						|
 | 
						|
bool UnwindPlan::Row::GetRegisterInfo(
 | 
						|
    uint32_t reg_num,
 | 
						|
    UnwindPlan::Row::RegisterLocation ®ister_location) const {
 | 
						|
  collection::const_iterator pos = m_register_locations.find(reg_num);
 | 
						|
  if (pos != m_register_locations.end()) {
 | 
						|
    register_location = pos->second;
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) {
 | 
						|
  collection::const_iterator pos = m_register_locations.find(reg_num);
 | 
						|
  if (pos != m_register_locations.end()) {
 | 
						|
    m_register_locations.erase(pos);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void UnwindPlan::Row::SetRegisterInfo(
 | 
						|
    uint32_t reg_num,
 | 
						|
    const UnwindPlan::Row::RegisterLocation register_location) {
 | 
						|
  m_register_locations[reg_num] = register_location;
 | 
						|
}
 | 
						|
 | 
						|
bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,
 | 
						|
                                                           int32_t offset,
 | 
						|
                                                           bool can_replace) {
 | 
						|
  if (!can_replace &&
 | 
						|
      m_register_locations.find(reg_num) != m_register_locations.end())
 | 
						|
    return false;
 | 
						|
  RegisterLocation reg_loc;
 | 
						|
  reg_loc.SetAtCFAPlusOffset(offset);
 | 
						|
  m_register_locations[reg_num] = reg_loc;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,
 | 
						|
                                                           int32_t offset,
 | 
						|
                                                           bool can_replace) {
 | 
						|
  if (!can_replace &&
 | 
						|
      m_register_locations.find(reg_num) != m_register_locations.end())
 | 
						|
    return false;
 | 
						|
  RegisterLocation reg_loc;
 | 
						|
  reg_loc.SetIsCFAPlusOffset(offset);
 | 
						|
  m_register_locations[reg_num] = reg_loc;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool UnwindPlan::Row::SetRegisterLocationToUndefined(
 | 
						|
    uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) {
 | 
						|
  collection::iterator pos = m_register_locations.find(reg_num);
 | 
						|
  collection::iterator end = m_register_locations.end();
 | 
						|
 | 
						|
  if (pos != end) {
 | 
						|
    if (!can_replace)
 | 
						|
      return false;
 | 
						|
    if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
 | 
						|
      return false;
 | 
						|
  }
 | 
						|
  RegisterLocation reg_loc;
 | 
						|
  reg_loc.SetUndefined();
 | 
						|
  m_register_locations[reg_num] = reg_loc;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num,
 | 
						|
                                                       bool can_replace) {
 | 
						|
  if (!can_replace &&
 | 
						|
      m_register_locations.find(reg_num) != m_register_locations.end())
 | 
						|
    return false;
 | 
						|
  RegisterLocation reg_loc;
 | 
						|
  reg_loc.SetUnspecified();
 | 
						|
  m_register_locations[reg_num] = reg_loc;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num,
 | 
						|
                                                    uint32_t other_reg_num,
 | 
						|
                                                    bool can_replace) {
 | 
						|
  if (!can_replace &&
 | 
						|
      m_register_locations.find(reg_num) != m_register_locations.end())
 | 
						|
    return false;
 | 
						|
  RegisterLocation reg_loc;
 | 
						|
  reg_loc.SetInRegister(other_reg_num);
 | 
						|
  m_register_locations[reg_num] = reg_loc;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,
 | 
						|
                                                bool must_replace) {
 | 
						|
  if (must_replace &&
 | 
						|
      m_register_locations.find(reg_num) == m_register_locations.end())
 | 
						|
    return false;
 | 
						|
  RegisterLocation reg_loc;
 | 
						|
  reg_loc.SetSame();
 | 
						|
  m_register_locations[reg_num] = reg_loc;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
 | 
						|
  return m_offset == rhs.m_offset &&
 | 
						|
      m_cfa_value == rhs.m_cfa_value &&
 | 
						|
      m_afa_value == rhs.m_afa_value &&
 | 
						|
      m_register_locations == rhs.m_register_locations;
 | 
						|
}
 | 
						|
 | 
						|
void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) {
 | 
						|
  if (m_row_list.empty() ||
 | 
						|
      m_row_list.back()->GetOffset() != row_sp->GetOffset())
 | 
						|
    m_row_list.push_back(row_sp);
 | 
						|
  else
 | 
						|
    m_row_list.back() = row_sp;
 | 
						|
}
 | 
						|
 | 
						|
void UnwindPlan::InsertRow(const UnwindPlan::RowSP &row_sp,
 | 
						|
                           bool replace_existing) {
 | 
						|
  collection::iterator it = m_row_list.begin();
 | 
						|
  while (it != m_row_list.end()) {
 | 
						|
    RowSP row = *it;
 | 
						|
    if (row->GetOffset() >= row_sp->GetOffset())
 | 
						|
      break;
 | 
						|
    it++;
 | 
						|
  }
 | 
						|
  if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
 | 
						|
    m_row_list.insert(it, row_sp);
 | 
						|
  else if (replace_existing)
 | 
						|
    *it = row_sp;
 | 
						|
}
 | 
						|
 | 
						|
UnwindPlan::RowSP UnwindPlan::GetRowForFunctionOffset(int offset) const {
 | 
						|
  RowSP row;
 | 
						|
  if (!m_row_list.empty()) {
 | 
						|
    if (offset == -1)
 | 
						|
      row = m_row_list.back();
 | 
						|
    else {
 | 
						|
      collection::const_iterator pos, end = m_row_list.end();
 | 
						|
      for (pos = m_row_list.begin(); pos != end; ++pos) {
 | 
						|
        if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset))
 | 
						|
          row = *pos;
 | 
						|
        else
 | 
						|
          break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return row;
 | 
						|
}
 | 
						|
 | 
						|
bool UnwindPlan::IsValidRowIndex(uint32_t idx) const {
 | 
						|
  return idx < m_row_list.size();
 | 
						|
}
 | 
						|
 | 
						|
const UnwindPlan::RowSP UnwindPlan::GetRowAtIndex(uint32_t idx) const {
 | 
						|
  if (idx < m_row_list.size())
 | 
						|
    return m_row_list[idx];
 | 
						|
  else {
 | 
						|
    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
 | 
						|
    LLDB_LOGF(log,
 | 
						|
              "error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index "
 | 
						|
              "(number rows is %u)",
 | 
						|
              idx, (uint32_t)m_row_list.size());
 | 
						|
    return UnwindPlan::RowSP();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
const UnwindPlan::RowSP UnwindPlan::GetLastRow() const {
 | 
						|
  if (m_row_list.empty()) {
 | 
						|
    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
 | 
						|
    LLDB_LOGF(log, "UnwindPlan::GetLastRow() when rows are empty");
 | 
						|
    return UnwindPlan::RowSP();
 | 
						|
  }
 | 
						|
  return m_row_list.back();
 | 
						|
}
 | 
						|
 | 
						|
int UnwindPlan::GetRowCount() const { return m_row_list.size(); }
 | 
						|
 | 
						|
void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) {
 | 
						|
  if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
 | 
						|
    m_plan_valid_address_range = range;
 | 
						|
}
 | 
						|
 | 
						|
bool UnwindPlan::PlanValidAtAddress(Address addr) {
 | 
						|
  // If this UnwindPlan has no rows, it is an invalid UnwindPlan.
 | 
						|
  if (GetRowCount() == 0) {
 | 
						|
    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
 | 
						|
    if (log) {
 | 
						|
      StreamString s;
 | 
						|
      if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
 | 
						|
        LLDB_LOGF(log,
 | 
						|
                  "UnwindPlan is invalid -- no unwind rows for UnwindPlan "
 | 
						|
                  "'%s' at address %s",
 | 
						|
                  m_source_name.GetCString(), s.GetData());
 | 
						|
      } else {
 | 
						|
        LLDB_LOGF(log,
 | 
						|
                  "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",
 | 
						|
                  m_source_name.GetCString());
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // If the 0th Row of unwind instructions is missing, or if it doesn't provide
 | 
						|
  // a register to use to find the Canonical Frame Address, this is not a valid
 | 
						|
  // UnwindPlan.
 | 
						|
  if (GetRowAtIndex(0).get() == nullptr ||
 | 
						|
      GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
 | 
						|
          Row::FAValue::unspecified) {
 | 
						|
    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
 | 
						|
    if (log) {
 | 
						|
      StreamString s;
 | 
						|
      if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {
 | 
						|
        LLDB_LOGF(log,
 | 
						|
                  "UnwindPlan is invalid -- no CFA register defined in row 0 "
 | 
						|
                  "for UnwindPlan '%s' at address %s",
 | 
						|
                  m_source_name.GetCString(), s.GetData());
 | 
						|
      } else {
 | 
						|
        LLDB_LOGF(log,
 | 
						|
                  "UnwindPlan is invalid -- no CFA register defined in row 0 "
 | 
						|
                  "for UnwindPlan '%s'",
 | 
						|
                  m_source_name.GetCString());
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!m_plan_valid_address_range.GetBaseAddress().IsValid() ||
 | 
						|
      m_plan_valid_address_range.GetByteSize() == 0)
 | 
						|
    return true;
 | 
						|
 | 
						|
  if (!addr.IsValid())
 | 
						|
    return true;
 | 
						|
 | 
						|
  if (m_plan_valid_address_range.ContainsFileAddress(addr))
 | 
						|
    return true;
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
 | 
						|
  if (!m_source_name.IsEmpty()) {
 | 
						|
    s.Printf("This UnwindPlan originally sourced from %s\n",
 | 
						|
             m_source_name.GetCString());
 | 
						|
  }
 | 
						|
  if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) {
 | 
						|
    TargetSP target_sp(thread->CalculateTarget());
 | 
						|
    addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get());
 | 
						|
    addr_t personality_func_load_addr =
 | 
						|
        m_personality_func_addr.GetLoadAddress(target_sp.get());
 | 
						|
 | 
						|
    if (lsda_load_addr != LLDB_INVALID_ADDRESS &&
 | 
						|
        personality_func_load_addr != LLDB_INVALID_ADDRESS) {
 | 
						|
      s.Printf("LSDA address 0x%" PRIx64
 | 
						|
               ", personality routine is at address 0x%" PRIx64 "\n",
 | 
						|
               lsda_load_addr, personality_func_load_addr);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  s.Printf("This UnwindPlan is sourced from the compiler: ");
 | 
						|
  switch (m_plan_is_sourced_from_compiler) {
 | 
						|
  case eLazyBoolYes:
 | 
						|
    s.Printf("yes.\n");
 | 
						|
    break;
 | 
						|
  case eLazyBoolNo:
 | 
						|
    s.Printf("no.\n");
 | 
						|
    break;
 | 
						|
  case eLazyBoolCalculate:
 | 
						|
    s.Printf("not specified.\n");
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  s.Printf("This UnwindPlan is valid at all instruction locations: ");
 | 
						|
  switch (m_plan_is_valid_at_all_instruction_locations) {
 | 
						|
  case eLazyBoolYes:
 | 
						|
    s.Printf("yes.\n");
 | 
						|
    break;
 | 
						|
  case eLazyBoolNo:
 | 
						|
    s.Printf("no.\n");
 | 
						|
    break;
 | 
						|
  case eLazyBoolCalculate:
 | 
						|
    s.Printf("not specified.\n");
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  if (m_plan_valid_address_range.GetBaseAddress().IsValid() &&
 | 
						|
      m_plan_valid_address_range.GetByteSize() > 0) {
 | 
						|
    s.PutCString("Address range of this UnwindPlan: ");
 | 
						|
    TargetSP target_sp(thread->CalculateTarget());
 | 
						|
    m_plan_valid_address_range.Dump(&s, target_sp.get(),
 | 
						|
                                    Address::DumpStyleSectionNameOffset);
 | 
						|
    s.EOL();
 | 
						|
  }
 | 
						|
  collection::const_iterator pos, begin = m_row_list.begin(),
 | 
						|
                                  end = m_row_list.end();
 | 
						|
  for (pos = begin; pos != end; ++pos) {
 | 
						|
    s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos));
 | 
						|
    (*pos)->Dump(s, this, thread, base_addr);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void UnwindPlan::SetSourceName(const char *source) {
 | 
						|
  m_source_name = ConstString(source);
 | 
						|
}
 | 
						|
 | 
						|
ConstString UnwindPlan::GetSourceName() const { return m_source_name; }
 | 
						|
 | 
						|
const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread,
 | 
						|
                                                uint32_t unwind_reg) const {
 | 
						|
  if (thread) {
 | 
						|
    RegisterContext *reg_ctx = thread->GetRegisterContext().get();
 | 
						|
    if (reg_ctx) {
 | 
						|
      uint32_t reg;
 | 
						|
      if (m_register_kind == eRegisterKindLLDB)
 | 
						|
        reg = unwind_reg;
 | 
						|
      else
 | 
						|
        reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind,
 | 
						|
                                                           unwind_reg);
 | 
						|
      if (reg != LLDB_INVALID_REGNUM)
 | 
						|
        return reg_ctx->GetRegisterInfoAtIndex(reg);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return nullptr;
 | 
						|
}
 |