llvm-project/lldb/source/Symbol/UnwindPlan.cpp

311 lines
8.1 KiB
C++

//===-- UnwindPlan.cpp ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.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)
return false;
if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset)
return m_location.offset == rhs.m_location.offset;
if (m_type == inOtherRegister)
return m_location.reg_num == rhs.m_location.reg_num;
if (m_type == atDWARFExpression || m_type == 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);
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;
}
void
UnwindPlan::Row::RegisterLocation::SetUnspecified ()
{
m_type = unspecified;
}
void
UnwindPlan::Row::RegisterLocation::SetUndefined ()
{
m_type = isUndefined;
}
void
UnwindPlan::Row::RegisterLocation::SetSame ()
{
m_type = isSame;
}
void
UnwindPlan::Row::RegisterLocation::SetAtCFAPlusOffset (int32_t offset)
{
m_type = atCFAPlusOffset;
m_location.offset = offset;
}
void
UnwindPlan::Row::RegisterLocation::SetIsCFAPlusOffset (int32_t offset)
{
m_type = isCFAPlusOffset;
m_location.offset = offset;
}
void
UnwindPlan::Row::RegisterLocation::SetInRegister (uint32_t reg_num)
{
m_type = inOtherRegister;
m_location.reg_num = reg_num;
}
void
UnwindPlan::Row::RegisterLocation::Dump (Stream &s) const
{
switch (m_type)
{
case unspecified:
s.Printf ("unspecified");
break;
case isUndefined:
s.Printf ("isUndefined");
break;
case isSame:
s.Printf ("isSame");
break;
case atCFAPlusOffset:
s.Printf ("atCFAPlusOffset %d", m_location.offset);
break;
case isCFAPlusOffset:
s.Printf ("isCFAPlusOffset %d", m_location.offset);
break;
case inOtherRegister:
s.Printf ("inOtherRegister %d", m_location.reg_num);
break;
case atDWARFExpression:
s.Printf ("atDWARFExpression");
break;
case isDWARFExpression:
s.Printf ("isDWARFExpression");
break;
}
}
void
UnwindPlan::Row::Clear ()
{
m_offset = 0;
m_cfa_reg_num = 0;
m_cfa_offset = 0;
m_register_locations.clear();
}
void
UnwindPlan::Row::Dump (Stream& s, int register_kind, Thread* thread) const
{
RegisterContext *rctx = NULL;
const RegisterInfo *rinfo = NULL;
int translated_regnum;
if (thread && thread->GetRegisterContext())
{
rctx = thread->GetRegisterContext();
}
s.Printf ("offset %ld, CFA reg ", (long) GetOffset());
if (rctx
&& (translated_regnum = rctx->ConvertRegisterKindToRegisterNumber (register_kind, GetCFARegister())) != -1
&& (rinfo = rctx->GetRegisterInfoAtIndex (translated_regnum)) != NULL
&& rinfo->name != NULL
&& rinfo->name[0] != '\0')
{
s.Printf ("%s, ", rinfo->name);
}
else
{
s.Printf ("%d, ", (int)(int) GetCFARegister());
}
s.Printf ("CFA offset %d", (int) GetCFAOffset ());
for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
{
s.Printf (" [");
bool printed_name = false;
if (thread && thread->GetRegisterContext())
{
rctx = thread->GetRegisterContext();
translated_regnum = rctx->ConvertRegisterKindToRegisterNumber (register_kind, idx->first);
rinfo = rctx->GetRegisterInfoAtIndex (translated_regnum);
if (rinfo && rinfo->name)
{
s.Printf ("%s ", rinfo->name);
printed_name = true;
}
}
if (!printed_name)
{
s.Printf ("reg %d ", idx->first);
}
idx->second.Dump(s);
s.Printf ("]");
}
s.Printf ("\n");
}
UnwindPlan::Row::Row() :
m_offset(0),
m_cfa_reg_num(0),
m_cfa_offset(0),
m_register_locations()
{
}
bool
UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_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::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
{
m_register_locations[reg_num] = register_location;
}
void
UnwindPlan::AppendRow (const UnwindPlan::Row &row)
{
if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset())
m_row_list.push_back(row);
else
m_row_list.back() = row;
}
const UnwindPlan::Row *
UnwindPlan::GetRowForFunctionOffset (int offset) const
{
const UnwindPlan::Row *rowp = NULL;
for (int i = 0; i < m_row_list.size(); ++i)
{
if (m_row_list[i].GetOffset() <= offset)
{
rowp = &m_row_list[i];
}
else
{
break;
}
}
return rowp;
}
bool
UnwindPlan::IsValidRowIndex (uint32_t idx) const
{
return idx < m_row_list.size();
}
const UnwindPlan::Row&
UnwindPlan::GetRowAtIndex (uint32_t idx) const
{
// You must call IsValidRowIndex(idx) first before calling this!!!
return m_row_list[idx];
}
int
UnwindPlan::GetRowCount () const
{
return m_row_list.size ();
}
void
UnwindPlan::SetRegisterKind (uint32_t rk)
{
m_register_kind = rk;
}
uint32_t
UnwindPlan::GetRegisterKind (void) const
{
return m_register_kind;
}
void
UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
{
m_plan_valid_address_range = range;
// .GetBaseAddress() = addr;
// m_plan_valid_address_range.SetByteSize (range.GetByteSize());
}
bool
UnwindPlan::PlanValidAtAddress (Address addr)
{
if (!m_plan_valid_address_range.GetBaseAddress().IsValid())
return true;
if (m_plan_valid_address_range.ContainsFileAddress (addr))
return true;
return false;
}
void
UnwindPlan::Dump (Stream& s, Thread *thread) const
{
s.Printf ("Address range of this UnwindPlan: ");
m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset);
s.Printf ("\n");
s.Printf ("UnwindPlan register kind %d", m_register_kind);
switch (m_register_kind)
{
case eRegisterKindGCC: s.Printf (" [eRegisterKindGCC]"); break;
case eRegisterKindDWARF: s.Printf (" [eRegisterKindDWARF]"); break;
case eRegisterKindGeneric: s.Printf (" [eRegisterKindGeneric]"); break;
case eRegisterKindGDB: s.Printf (" [eRegisterKindGDB]"); break;
case eRegisterKindLLDB: s.Printf (" [eRegisterKindLLDB]"); break;
default: break;
}
s.Printf ("\n");
for (int i = 0; IsValidRowIndex (i); i++)
{
s.Printf ("UnwindPlan row at index %d: ", i);
m_row_list[i].Dump(s, m_register_kind, thread);
}
}