#ifndef liblldb_UnwindPlan_h
#define liblldb_UnwindPlan_h
#include "lldb/lldb-private.h"
#include "lldb/Core/AddressRange.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/ConstString.h"
#include <map>
#include <vector>
namespace lldb_private {
class UnwindPlan {
public:
class Row {
public:
class RegisterLocation
{
public:
enum RestoreType
{
unspecified, undefined, same, atCFAPlusOffset, isCFAPlusOffset, inOtherRegister, atDWARFExpression, isDWARFExpression };
RegisterLocation() :
m_type(unspecified),
m_location()
{
}
bool
operator == (const RegisterLocation& rhs) const;
bool
operator != (const RegisterLocation &rhs) const
{
return !(*this == rhs);
}
void
SetUnspecified()
{
m_type = unspecified;
}
void
SetUndefined()
{
m_type = undefined;
}
void
SetSame()
{
m_type = same;
}
bool
IsSame () const
{
return m_type == same;
}
bool
IsUnspecified () const
{
return m_type == unspecified;
}
bool
IsCFAPlusOffset () const
{
return m_type == isCFAPlusOffset;
}
bool
IsAtCFAPlusOffset () const
{
return m_type == atCFAPlusOffset;
}
bool
IsInOtherRegister () const
{
return m_type == inOtherRegister;
}
bool
IsAtDWARFExpression () const
{
return m_type == atDWARFExpression;
}
bool
IsDWARFExpression () const
{
return m_type == isDWARFExpression;
}
void
SetAtCFAPlusOffset (int32_t offset)
{
m_type = atCFAPlusOffset;
m_location.offset = offset;
}
void
SetIsCFAPlusOffset (int32_t offset)
{
m_type = isCFAPlusOffset;
m_location.offset = offset;
}
void
SetInRegister (uint32_t reg_num)
{
m_type = inOtherRegister;
m_location.reg_num = reg_num;
}
uint32_t
GetRegisterNumber () const
{
if (m_type == inOtherRegister)
return m_location.reg_num;
return LLDB_INVALID_REGNUM;
}
RestoreType
GetLocationType () const
{
return m_type;
}
int32_t
GetOffset () const
{
if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset)
return m_location.offset;
return 0;
}
void
GetDWARFExpr (const uint8_t **opcodes, uint16_t& len) const
{
if (m_type == atDWARFExpression || m_type == isDWARFExpression)
{
*opcodes = m_location.expr.opcodes;
len = m_location.expr.length;
}
else
{
*opcodes = NULL;
len = 0;
}
}
void
SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len);
void
SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len);
const uint8_t *
GetDWARFExpressionBytes ()
{
if (m_type == atDWARFExpression || m_type == isDWARFExpression)
return m_location.expr.opcodes;
return NULL;
}
int
GetDWARFExpressionLength ()
{
if (m_type == atDWARFExpression || m_type == isDWARFExpression)
return m_location.expr.length;
return 0;
}
void
Dump (Stream &s,
const UnwindPlan* unwind_plan,
const UnwindPlan::Row* row,
Thread* thread,
bool verbose) const;
private:
RestoreType m_type; union
{
int32_t offset;
uint32_t reg_num; struct {
const uint8_t *opcodes;
uint16_t length;
} expr;
} m_location;
};
public:
Row ();
bool
GetRegisterInfo (uint32_t reg_num, RegisterLocation& register_location) const;
void
SetRegisterInfo (uint32_t reg_num, const RegisterLocation register_location);
lldb::addr_t
GetOffset() const
{
return m_offset;
}
void
SetOffset(lldb::addr_t offset)
{
m_offset = offset;
}
void
SlideOffset(lldb::addr_t offset)
{
m_offset += offset;
}
uint32_t
GetCFARegister () const
{
return m_cfa_reg_num;
}
bool
SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num,
int32_t offset,
bool can_replace);
bool
SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num,
int32_t offset,
bool can_replace);
bool
SetRegisterLocationToUndefined (uint32_t reg_num,
bool can_replace,
bool can_replace_only_if_unspecified);
bool
SetRegisterLocationToUnspecified (uint32_t reg_num,
bool can_replace);
bool
SetRegisterLocationToRegister (uint32_t reg_num,
uint32_t other_reg_num,
bool can_replace);
bool
SetRegisterLocationToSame (uint32_t reg_num,
bool must_replace);
void
SetCFARegister (uint32_t reg_num);
int32_t
GetCFAOffset () const
{
return m_cfa_offset;
}
void
SetCFAOffset (int32_t offset)
{
m_cfa_offset = offset;
}
int
GetRegisterCount () const
{
return m_register_locations.size();
}
void
Clear ();
void
Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, lldb::addr_t base_addr) const;
bool
operator == (const Row &rhs) const
{
if (m_offset == rhs.m_offset &&
m_cfa_reg_num != rhs.m_cfa_reg_num &&
m_cfa_offset != rhs.m_cfa_offset)
return m_register_locations == rhs.m_register_locations;
return false;
}
bool
operator != (const Row &rhs) const
{
if (m_offset != rhs.m_offset ||
m_cfa_reg_num != rhs.m_cfa_reg_num ||
m_cfa_offset != rhs.m_cfa_offset)
return true;
return m_register_locations != rhs.m_register_locations;
}
protected:
typedef std::map<uint32_t, RegisterLocation> collection;
lldb::addr_t m_offset; uint32_t m_cfa_reg_num; int32_t m_cfa_offset; collection m_register_locations;
};
public:
UnwindPlan (uint32_t reg_kind) :
m_row_list (),
m_plan_valid_address_range (),
m_register_kind (reg_kind),
m_source_name ()
{
}
~UnwindPlan ()
{
}
void
Dump (Stream& s, Thread* thread, lldb::addr_t base_addr) const;
void
AppendRow (const Row& row);
const Row*
GetRowForFunctionOffset (int offset) const;
uint32_t
GetRegisterKind () const
{
return m_register_kind;
}
void
SetRegisterKind (uint32_t kind)
{
m_register_kind = kind;
}
uint32_t
GetInitialCFARegister () const
{
if (m_row_list.empty())
return LLDB_INVALID_REGNUM;
return m_row_list.front().GetCFARegister();
}
void
SetPlanValidAddressRange (const AddressRange& range);
const AddressRange &
GetAddressRange () const
{
return m_plan_valid_address_range;
}
bool
PlanValidAtAddress (Address addr);
bool
IsValidRowIndex (uint32_t idx) const;
const UnwindPlan::Row&
GetRowAtIndex (uint32_t idx) const;
const UnwindPlan::Row&
GetLastRow () const;
lldb_private::ConstString
GetSourceName () const;
void
SetSourceName (const char *);
int
GetRowCount () const;
void
Clear()
{
m_row_list.clear();
m_plan_valid_address_range.Clear();
m_register_kind = lldb::eRegisterKindDWARF;
m_source_name.Clear();
}
const RegisterInfo *
GetRegisterInfo (Thread* thread, uint32_t reg_num) const;
private:
typedef std::vector<Row> collection;
collection m_row_list;
AddressRange m_plan_valid_address_range;
uint32_t m_register_kind; lldb_private::ConstString m_source_name; };
}
#endif //liblldb_UnwindPlan_h