blob: 96bba7e9b99080d26676aefc1e5b8c8e7d7504e5 [file] [log] [blame]
//===-- LibUnwindRegisterContext.cpp ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "LibUnwindRegisterContext.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Target/Thread.h"
// Project includes
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// LibUnwindRegisterContext constructor
//----------------------------------------------------------------------
LibUnwindRegisterContext::LibUnwindRegisterContext
(
Thread &thread,
StackFrame *frame,
const lldb_private::unw_cursor_t& unwind_cursor
) :
RegisterContext (thread, frame),
m_unwind_cursor (unwind_cursor),
m_unwind_cursor_is_valid (true)
{
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
LibUnwindRegisterContext::~LibUnwindRegisterContext()
{
}
void
LibUnwindRegisterContext::Invalidate ()
{
m_unwind_cursor_is_valid = false;
}
size_t
LibUnwindRegisterContext::GetRegisterCount ()
{
return m_thread.GetRegisterContext()->GetRegisterCount();
}
const lldb::RegisterInfo *
LibUnwindRegisterContext::GetRegisterInfoAtIndex (uint32_t reg)
{
return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg);
}
size_t
LibUnwindRegisterContext::GetRegisterSetCount ()
{
return m_thread.GetRegisterContext()->GetRegisterSetCount();
}
const lldb::RegisterSet *
LibUnwindRegisterContext::GetRegisterSet (uint32_t reg_set)
{
return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
}
bool
LibUnwindRegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value)
{
if (m_unwind_cursor_is_valid == false)
return false;
// Read the register
unw_word_t reg_value;
if (unw_get_reg (&m_unwind_cursor, reg, &reg_value) != UNW_ESUCCESS)
return false;
const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
switch (reg_info->encoding)
{
case eEncodingUint:
switch (reg_info->byte_size)
{
case 1:
case 2:
case 4:
value = (uint32_t)reg_value;
return true;
case 8:
value = (uint64_t)reg_value;
return true;
}
break;
case eEncodingSint:
switch (reg_info->byte_size)
{
case 1:
case 2:
case 4:
value = (int32_t)reg_value;
return true;
case 8:
value = (int64_t)reg_value;
return true;
}
break;
case eEncodingIEEE754:
if (reg_info->byte_size > sizeof(unw_word_t))
return false;
switch (reg_info->byte_size)
{
case sizeof (float):
if (sizeof (float) == sizeof(uint32_t))
{
value = (uint32_t)reg_value;
return true;
}
else if (sizeof (float) == sizeof(uint64_t))
{
value = (uint64_t)reg_value;
return true;
}
break;
case sizeof (double):
if (sizeof (double) == sizeof(uint32_t))
{
value = (uint32_t)reg_value;
return true;
}
else if (sizeof (double) == sizeof(uint64_t))
{
value = (uint64_t)reg_value;
return true;
}
break;
case sizeof (long double):
if (sizeof (long double) == sizeof(uint32_t))
{
value = (uint32_t)reg_value;
return true;
}
else if (sizeof (long double) == sizeof(uint64_t))
{
value = (uint64_t)reg_value;
return true;
}
break;
}
break;
default:
break;
}
return false;
}
bool
LibUnwindRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
{
Scalar reg_value;
if (ReadRegisterValue (reg, reg_value))
{
if (reg_value.GetData(data))
{
// "reg_value" is local and now "data" points to the data within
// "reg_value", so we must make a copy that will live within "data"
DataBufferSP data_sp (new DataBufferHeap (data.GetDataStart(), data.GetByteSize()));
data.SetData (data_sp, 0, data.GetByteSize());
return true;
}
}
return false;
}
bool
LibUnwindRegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value)
{
const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
if (reg_info == NULL)
return false;
unw_word_t reg_value = 0;
switch (value.GetType())
{
case Scalar::e_void:
return false;
case Scalar::e_sint: reg_value = value.SInt(); break;
case Scalar::e_uint: reg_value = value.UInt(); break;
case Scalar::e_slong: reg_value = value.SLong(); break;
case Scalar::e_ulong: reg_value = value.ULong(); break;
case Scalar::e_slonglong: reg_value = value.SLongLong(); break;
case Scalar::e_ulonglong: reg_value = value.ULongLong(); break;
case Scalar::e_float:
if (sizeof (float) == sizeof (unsigned int))
reg_value = value.UInt();
else if (sizeof (float) == sizeof (unsigned long))
reg_value = value.ULong();
else if (sizeof (float) == sizeof (unsigned long long))
reg_value = value.ULongLong();
else
return false;
break;
case Scalar::e_double:
if (sizeof (double) == sizeof (unsigned int))
reg_value = value.UInt();
else if (sizeof (double) == sizeof (unsigned long))
reg_value = value.ULong();
else if (sizeof (double) == sizeof (unsigned long long))
reg_value = value.ULongLong();
else
return false;
break;
case Scalar::e_long_double:
if (sizeof (long double) == sizeof (unsigned int))
reg_value = value.UInt();
else if (sizeof (long double) == sizeof (unsigned long))
reg_value = value.ULong();
else if (sizeof (long double) == sizeof (unsigned long long))
reg_value = value.ULongLong();
else
return false;
break;
}
return unw_set_reg (&m_unwind_cursor, reg, reg_value) == UNW_ESUCCESS;
}
bool
LibUnwindRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
{
const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
if (reg_info == NULL)
return false;
if (reg_info->byte_size > sizeof (unw_word_t))
return false;
Scalar value;
uint32_t offset = data_offset;
switch (reg_info->encoding)
{
case eEncodingUint:
if (reg_info->byte_size <= 4)
value = data.GetMaxU32 (&offset, reg_info->byte_size);
else if (reg_info->byte_size <= 8)
value = data.GetMaxU64 (&offset, reg_info->byte_size);
else
return false;
break;
case eEncodingSint:
if (reg_info->byte_size <= 4)
value = (int32_t)data.GetMaxU32 (&offset, reg_info->byte_size);
else if (reg_info->byte_size <= 8)
value = data.GetMaxS64 (&offset, reg_info->byte_size);
else
return false;
break;
case eEncodingIEEE754:
switch (reg_info->byte_size)
{
case sizeof (float):
value = data.GetFloat (&offset);
break;
case sizeof (double):
value = data.GetDouble (&offset);
break;
case sizeof (long double):
value = data.GetLongDouble (&offset);
break;
default:
return false;
}
default:
return false;
}
return WriteRegisterValue (reg, value);
}
bool
LibUnwindRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
{
// libunwind frames can't handle this it doesn't always have all register
// values. This call should only be called on frame zero anyway so there
// shouldn't be any problem
return false;
}
bool
LibUnwindRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
{
// Since this class doesn't respond to "ReadAllRegisterValues()", it must
// not have been the one that saved all the register values. So we just let
// the thread's register context (the register context for frame zero) do
// the writing.
return m_thread.GetRegisterContext()->WriteAllRegisterValues(data_sp);
}
uint32_t
LibUnwindRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
{
return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
}