Files
clang-p2996/lldb/source/Symbol/UnwindPlan.cpp
Jason Molenda 5976200d43 Handle the case where no eh_frame section is present.
RegisterContextLLDB holds a reference to the SymbolContext
in the vector of Cursors that UnwindLLDB maintains.  Switch
UnwindLLDB to hold a vector of shared pointers of Cursors
so this reference doesn't become invalid.

Correctly falling back from the "fast" UnwindPlan to the
"full" UnwindPlan when additional registers need to be
retrieved.

llvm-svn: 118218
2010-11-04 00:53:20 +00:00

345 lines
8.9 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"
#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.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;
if (offset == -1 && m_row_list.size() > 0)
{
return &m_row_list[m_row_list.size() - 1];
}
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)
{
if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
{
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() || 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.Printf ("Address range of this UnwindPlan: ");
m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset);
s.Printf ("\n");
}
else
{
s.Printf ("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.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);
}
}
void
UnwindPlan::SetSourceName (const char *source)
{
m_source_name = ConstString (source);
}
ConstString
UnwindPlan::GetSourceName () const
{
return m_source_name;
}