mirror of
https://github.com/intel/llvm.git
synced 2026-01-21 03:21:40 +08:00
Switch the EmulateInstruction to use the standard RegisterInfo structure that is defined in the lldb private types intead of passing the reg kind and reg num everywhere. EmulateInstruction subclasses also need to provide RegisterInfo structs given a reg kind and reg num. This eliminates the need for the GetRegisterName() virtual function and allows more complete information to be passed around in the read/write register callbacks. Subclasses should always provide RegiterInfo structs with the generic register info filled in as well as at least one kind of register number in the RegisterInfo.kinds[] array. llvm-svn: 130256
342 lines
9.0 KiB
C++
342 lines
9.0 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/Core/ConstString.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.PutCString ("unspecified");
|
|
break;
|
|
case isUndefined:
|
|
s.PutCString ("isUndefined");
|
|
break;
|
|
case isSame:
|
|
s.PutCString ("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.PutCString ("atDWARFExpression");
|
|
break;
|
|
case isDWARFExpression:
|
|
s.PutCString ("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 *reg_ctx = NULL;
|
|
const RegisterInfo *rinfo = NULL;
|
|
int translated_regnum;
|
|
if (thread && thread->GetRegisterContext())
|
|
reg_ctx = thread->GetRegisterContext().get();
|
|
|
|
s.Printf ("offset %ld, CFA reg ", (long) GetOffset());
|
|
if (reg_ctx
|
|
&& (translated_regnum = reg_ctx->ConvertRegisterKindToRegisterNumber (register_kind, GetCFARegister())) != -1
|
|
&& (rinfo = reg_ctx->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.PutCString (" [");
|
|
bool printed_name = false;
|
|
if (reg_ctx)
|
|
{
|
|
translated_regnum = reg_ctx->ConvertRegisterKindToRegisterNumber (register_kind, idx->first);
|
|
rinfo = reg_ctx->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.PutCString ("]");
|
|
}
|
|
s.EOL();
|
|
}
|
|
|
|
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 *row_ptr = NULL;
|
|
if (!m_row_list.empty())
|
|
{
|
|
if (offset == -1)
|
|
row_ptr = &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() <= offset)
|
|
row_ptr = &*pos;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return row_ptr;
|
|
}
|
|
|
|
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!!!
|
|
assert (idx < m_row_list.size());
|
|
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)
|
|
{
|
|
if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
|
|
m_plan_valid_address_range = range;
|
|
}
|
|
|
|
bool
|
|
UnwindPlan::PlanValidAtAddress (Address addr)
|
|
{
|
|
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) const
|
|
{
|
|
if (!m_source_name.IsEmpty())
|
|
{
|
|
s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
|
|
}
|
|
if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
|
|
{
|
|
s.PutCString ("Address range of this UnwindPlan: ");
|
|
m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset);
|
|
s.EOL();
|
|
}
|
|
else
|
|
{
|
|
s.PutCString ("No valid address range recorded for this UnwindPlan.\n");
|
|
}
|
|
s.Printf ("UnwindPlan register kind %d", m_register_kind);
|
|
switch (m_register_kind)
|
|
{
|
|
case eRegisterKindGCC: s.PutCString (" [eRegisterKindGCC]"); break;
|
|
case eRegisterKindDWARF: s.PutCString (" [eRegisterKindDWARF]"); break;
|
|
case eRegisterKindGeneric: s.PutCString (" [eRegisterKindGeneric]"); break;
|
|
case eRegisterKindGDB: s.PutCString (" [eRegisterKindGDB]"); break;
|
|
case eRegisterKindLLDB: s.PutCString (" [eRegisterKindLLDB]"); break;
|
|
default: break;
|
|
}
|
|
s.EOL();
|
|
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);
|
|
}
|
|
}
|
|
|
|
void
|
|
UnwindPlan::SetSourceName (const char *source)
|
|
{
|
|
m_source_name = ConstString (source);
|
|
}
|
|
|
|
ConstString
|
|
UnwindPlan::GetSourceName () const
|
|
{
|
|
return m_source_name;
|
|
}
|