Files
llvm/lldb/source/Symbol/UnwindPlan.cpp
Greg Clayton 31f1d2f535 Moved all code from ArchDefaultUnwindPlan and ArchVolatileRegs into their
respective ABI plugins as they were plug-ins that supplied ABI specfic info.

Also hookep up the UnwindAssemblyInstEmulation so that it can generate the
unwind plans for ARM.

Changed the way ABI plug-ins are handed out when you get an instance from
the plug-in manager. They used to return pointers that would be mananged
individually by each client that requested them, but now they are handed out
as shared pointers since there is no state in the ABI objects, they can be
shared.

llvm-svn: 131193
2011-05-11 18:39:18 +00:00

448 lines
13 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)
{
switch (m_type)
{
case unspecified:
case undefined:
case same:
return true;
case atCFAPlusOffset:
case isCFAPlusOffset:
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;
}
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('[');
if (verbose)
s.Printf ("CFA%+d", m_location.offset);
if (unwind_plan && row)
{
const uint32_t cfa_reg = row->GetCFARegister();
const RegisterInfo *cfa_reg_info = unwind_plan->GetRegisterInfo (thread, cfa_reg);
const int32_t offset = row->GetCFAOffset() + m_location.offset;
if (verbose)
{
if (cfa_reg_info)
s.Printf (" (%s%+d)", cfa_reg_info->name, offset);
else
s.Printf (" (reg(%u)%+d)", cfa_reg_info->name, offset);
}
else
{
if (cfa_reg_info)
s.Printf ("%s", cfa_reg_info->name);
else
s.Printf ("reg(%u)", cfa_reg_info->name);
if (offset != 0)
s.Printf ("%+d", offset);
}
}
if (m_type == atCFAPlusOffset)
s.PutChar(']');
}
break;
case inOtherRegister:
{
const RegisterInfo *other_reg_info = NULL;
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.PutCString("[dwarf-expr]");
else
s.PutCString("dwarf-expr");
}
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, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const
{
const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister());
if (base_addr != LLDB_INVALID_ADDRESS)
s.Printf ("0x%16.16llx: CFA=", base_addr + GetOffset());
else
s.Printf ("0x%8.8x: CFA=", GetOffset());
if (reg_info)
s.Printf ("%s", reg_info->name);
else
s.Printf ("reg(%u)", GetCFARegister());
s.Printf ("%+3d =>", GetCFAOffset ());
for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
{
reg_info = unwind_plan->GetRegisterInfo (thread, idx->first);
if (reg_info)
s.Printf ("%s", reg_info->name);
else
s.Printf ("reg(%u)", 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_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;
}
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;
}
void
UnwindPlan::Row::SetCFARegister (uint32_t reg_num)
{
m_cfa_reg_num = reg_num;
}
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];
}
const UnwindPlan::Row&
UnwindPlan::GetLastRow () const
{
// You must call GetRowCount() first to make sure there is at least one row
assert (!m_row_list.empty());
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 (!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_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: s.PutCString (" [eRegisterKind???]"); break;
}
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 NULL;
}