blob: 691b05410f27627b623c2e67b032d64789296ff3 [file] [log] [blame]
//===-- 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"
#include "lldb/Core/ConstString.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;
}