forked from OSchip/llvm-project
1079 lines
31 KiB
C++
1079 lines
31 KiB
C++
//===-- RegisterValue.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/Core/RegisterValue.h"
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
// Other libraries and framework includes
|
|
// Project includes
|
|
#include "lldb/Core/DataExtractor.h"
|
|
#include "lldb/Core/Error.h"
|
|
#include "lldb/Core/Scalar.h"
|
|
#include "lldb/Core/Stream.h"
|
|
#include "lldb/Core/StreamString.h"
|
|
#include "lldb/Interpreter/Args.h"
|
|
#include "lldb/Host/StringConvert.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
|
|
bool
|
|
RegisterValue::Dump (Stream *s,
|
|
const RegisterInfo *reg_info,
|
|
bool prefix_with_name,
|
|
bool prefix_with_alt_name,
|
|
Format format,
|
|
uint32_t reg_name_right_align_at) const
|
|
{
|
|
DataExtractor data;
|
|
if (GetData (data))
|
|
{
|
|
bool name_printed = false;
|
|
// For simplicity, alignment of the register name printing applies only
|
|
// in the most common case where:
|
|
//
|
|
// prefix_with_name^prefix_with_alt_name is true
|
|
//
|
|
StreamString format_string;
|
|
if (reg_name_right_align_at && (prefix_with_name^prefix_with_alt_name))
|
|
format_string.Printf("%%%us", reg_name_right_align_at);
|
|
else
|
|
format_string.Printf("%%s");
|
|
const char *fmt = format_string.GetData();
|
|
if (prefix_with_name)
|
|
{
|
|
if (reg_info->name)
|
|
{
|
|
s->Printf (fmt, reg_info->name);
|
|
name_printed = true;
|
|
}
|
|
else if (reg_info->alt_name)
|
|
{
|
|
s->Printf (fmt, reg_info->alt_name);
|
|
prefix_with_alt_name = false;
|
|
name_printed = true;
|
|
}
|
|
}
|
|
if (prefix_with_alt_name)
|
|
{
|
|
if (name_printed)
|
|
s->PutChar ('/');
|
|
if (reg_info->alt_name)
|
|
{
|
|
s->Printf (fmt, reg_info->alt_name);
|
|
name_printed = true;
|
|
}
|
|
else if (!name_printed)
|
|
{
|
|
// No alternate name but we were asked to display a name, so show the main name
|
|
s->Printf (fmt, reg_info->name);
|
|
name_printed = true;
|
|
}
|
|
}
|
|
if (name_printed)
|
|
s->PutCString (" = ");
|
|
|
|
if (format == eFormatDefault)
|
|
format = reg_info->format;
|
|
|
|
data.Dump (s,
|
|
0, // Offset in "data"
|
|
format, // Format to use when dumping
|
|
reg_info->byte_size, // item_byte_size
|
|
1, // item_count
|
|
UINT32_MAX, // num_per_line
|
|
LLDB_INVALID_ADDRESS, // base_addr
|
|
0, // item_bit_size
|
|
0); // item_bit_offset
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool
|
|
RegisterValue::GetData (DataExtractor &data) const
|
|
{
|
|
return data.SetData(GetBytes(), GetByteSize(), GetByteOrder()) > 0;
|
|
}
|
|
|
|
|
|
uint32_t
|
|
RegisterValue::GetAsMemoryData (const RegisterInfo *reg_info,
|
|
void *dst,
|
|
uint32_t dst_len,
|
|
lldb::ByteOrder dst_byte_order,
|
|
Error &error) const
|
|
{
|
|
if (reg_info == NULL)
|
|
{
|
|
error.SetErrorString ("invalid register info argument.");
|
|
return 0;
|
|
}
|
|
|
|
// ReadRegister should have already been called on this object prior to
|
|
// calling this.
|
|
if (GetType() == eTypeInvalid)
|
|
{
|
|
// No value has been read into this object...
|
|
error.SetErrorStringWithFormat("invalid register value type for register %s", reg_info->name);
|
|
return 0;
|
|
}
|
|
|
|
if (dst_len > kMaxRegisterByteSize)
|
|
{
|
|
error.SetErrorString ("destination is too big");
|
|
return 0;
|
|
}
|
|
|
|
const uint32_t src_len = reg_info->byte_size;
|
|
|
|
// Extract the register data into a data extractor
|
|
DataExtractor reg_data;
|
|
if (!GetData(reg_data))
|
|
{
|
|
error.SetErrorString ("invalid register value to copy into");
|
|
return 0;
|
|
}
|
|
|
|
// Prepare a memory buffer that contains some or all of the register value
|
|
const uint32_t bytes_copied = reg_data.CopyByteOrderedData (0, // src offset
|
|
src_len, // src length
|
|
dst, // dst buffer
|
|
dst_len, // dst length
|
|
dst_byte_order); // dst byte order
|
|
if (bytes_copied == 0)
|
|
error.SetErrorStringWithFormat("failed to copy data for register write of %s", reg_info->name);
|
|
|
|
return bytes_copied;
|
|
}
|
|
|
|
uint32_t
|
|
RegisterValue::SetFromMemoryData (const RegisterInfo *reg_info,
|
|
const void *src,
|
|
uint32_t src_len,
|
|
lldb::ByteOrder src_byte_order,
|
|
Error &error)
|
|
{
|
|
if (reg_info == NULL)
|
|
{
|
|
error.SetErrorString ("invalid register info argument.");
|
|
return 0;
|
|
}
|
|
|
|
// Moving from addr into a register
|
|
//
|
|
// Case 1: src_len == dst_len
|
|
//
|
|
// |AABBCCDD| Address contents
|
|
// |AABBCCDD| Register contents
|
|
//
|
|
// Case 2: src_len > dst_len
|
|
//
|
|
// Error! (The register should always be big enough to hold the data)
|
|
//
|
|
// Case 3: src_len < dst_len
|
|
//
|
|
// |AABB| Address contents
|
|
// |AABB0000| Register contents [on little-endian hardware]
|
|
// |0000AABB| Register contents [on big-endian hardware]
|
|
if (src_len > kMaxRegisterByteSize)
|
|
{
|
|
error.SetErrorStringWithFormat ("register buffer is too small to receive %u bytes of data.", src_len);
|
|
return 0;
|
|
}
|
|
|
|
const uint32_t dst_len = reg_info->byte_size;
|
|
|
|
if (src_len > dst_len)
|
|
{
|
|
error.SetErrorStringWithFormat("%u bytes is too big to store in register %s (%u bytes)", src_len, reg_info->name, dst_len);
|
|
return 0;
|
|
}
|
|
|
|
// Use a data extractor to correctly copy and pad the bytes read into the
|
|
// register value
|
|
DataExtractor src_data (src, src_len, src_byte_order, 4);
|
|
|
|
// Given the register info, set the value type of this RegisterValue object
|
|
SetType (reg_info);
|
|
// And make sure we were able to figure out what that register value was
|
|
RegisterValue::Type value_type = GetType();
|
|
if (value_type == eTypeInvalid)
|
|
{
|
|
// No value has been read into this object...
|
|
error.SetErrorStringWithFormat("invalid register value type for register %s", reg_info->name);
|
|
return 0;
|
|
}
|
|
else if (value_type == eTypeBytes)
|
|
{
|
|
buffer.byte_order = src_byte_order;
|
|
// Make sure to set the buffer length of the destination buffer to avoid
|
|
// problems due to uninitalized variables.
|
|
buffer.length = src_len;
|
|
}
|
|
|
|
const uint32_t bytes_copied = src_data.CopyByteOrderedData (0, // src offset
|
|
src_len, // src length
|
|
GetBytes(), // dst buffer
|
|
GetByteSize(), // dst length
|
|
GetByteOrder()); // dst byte order
|
|
if (bytes_copied == 0)
|
|
error.SetErrorStringWithFormat("failed to copy data for register write of %s", reg_info->name);
|
|
|
|
return bytes_copied;
|
|
}
|
|
|
|
bool
|
|
RegisterValue::GetScalarValue (Scalar &scalar) const
|
|
{
|
|
switch (m_type)
|
|
{
|
|
case eTypeInvalid: break;
|
|
case eTypeBytes:
|
|
{
|
|
switch (buffer.length)
|
|
{
|
|
default: break;
|
|
case 1: scalar = *(const uint8_t *)buffer.bytes; return true;
|
|
case 2: scalar = *(const uint16_t *)buffer.bytes; return true;
|
|
case 4: scalar = *(const uint32_t *)buffer.bytes; return true;
|
|
case 8: scalar = *(const uint64_t *)buffer.bytes; return true;
|
|
}
|
|
}
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble: scalar = m_scalar; return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void
|
|
RegisterValue::Clear()
|
|
{
|
|
m_type = eTypeInvalid;
|
|
}
|
|
|
|
RegisterValue::Type
|
|
RegisterValue::SetType (const RegisterInfo *reg_info)
|
|
{
|
|
m_type = eTypeInvalid;
|
|
const uint32_t byte_size = reg_info->byte_size;
|
|
switch (reg_info->encoding)
|
|
{
|
|
case eEncodingInvalid:
|
|
break;
|
|
|
|
case eEncodingUint:
|
|
case eEncodingSint:
|
|
if (byte_size == 1)
|
|
m_type = eTypeUInt8;
|
|
else if (byte_size <= 2)
|
|
m_type = eTypeUInt16;
|
|
else if (byte_size <= 4)
|
|
m_type = eTypeUInt32;
|
|
else if (byte_size <= 8)
|
|
m_type = eTypeUInt64;
|
|
else if (byte_size <= 16)
|
|
m_type = eTypeUInt128;
|
|
break;
|
|
|
|
case eEncodingIEEE754:
|
|
if (byte_size == sizeof(float))
|
|
m_type = eTypeFloat;
|
|
else if (byte_size == sizeof(double))
|
|
m_type = eTypeDouble;
|
|
else if (byte_size == sizeof(long double))
|
|
m_type = eTypeLongDouble;
|
|
break;
|
|
|
|
case eEncodingVector:
|
|
m_type = eTypeBytes;
|
|
break;
|
|
}
|
|
m_scalar.SetType(reg_info);
|
|
return m_type;
|
|
}
|
|
|
|
Error
|
|
RegisterValue::SetValueFromData (const RegisterInfo *reg_info, DataExtractor &src, lldb::offset_t src_offset, bool partial_data_ok)
|
|
{
|
|
Error error;
|
|
|
|
if (src.GetByteSize() == 0)
|
|
{
|
|
error.SetErrorString ("empty data.");
|
|
return error;
|
|
}
|
|
|
|
if (reg_info->byte_size == 0)
|
|
{
|
|
error.SetErrorString ("invalid register info.");
|
|
return error;
|
|
}
|
|
|
|
uint32_t src_len = src.GetByteSize() - src_offset;
|
|
|
|
if (!partial_data_ok && (src_len < reg_info->byte_size))
|
|
{
|
|
error.SetErrorString ("not enough data.");
|
|
return error;
|
|
}
|
|
|
|
// Cap the data length if there is more than enough bytes for this register
|
|
// value
|
|
if (src_len > reg_info->byte_size)
|
|
src_len = reg_info->byte_size;
|
|
|
|
// Zero out the value in case we get partial data...
|
|
memset (buffer.bytes, 0, sizeof (buffer.bytes));
|
|
|
|
type128 int128;
|
|
switch (SetType (reg_info))
|
|
{
|
|
case eTypeInvalid:
|
|
error.SetErrorString("");
|
|
break;
|
|
case eTypeUInt8: SetUInt8 (src.GetMaxU32 (&src_offset, src_len)); break;
|
|
case eTypeUInt16: SetUInt16 (src.GetMaxU32 (&src_offset, src_len)); break;
|
|
case eTypeUInt32: SetUInt32 (src.GetMaxU32 (&src_offset, src_len)); break;
|
|
case eTypeUInt64: SetUInt64 (src.GetMaxU64 (&src_offset, src_len)); break;
|
|
case eTypeUInt128:
|
|
{
|
|
if (src.GetByteSize() == eByteOrderBig)
|
|
{
|
|
int128.x[1] = src.GetU64 (&src_offset + 1);
|
|
int128.x[0] = src.GetU64 (&src_offset);
|
|
}
|
|
else
|
|
{
|
|
int128.x[0] = src.GetU64 (&src_offset);
|
|
int128.x[1] = src.GetU64 (&src_offset + 1);
|
|
}
|
|
SetUInt128 (llvm::APInt(128, 2, int128.x));
|
|
}
|
|
break;
|
|
case eTypeFloat: SetFloat (src.GetFloat (&src_offset)); break;
|
|
case eTypeDouble: SetDouble(src.GetDouble (&src_offset)); break;
|
|
case eTypeLongDouble: SetFloat (src.GetLongDouble (&src_offset)); break;
|
|
case eTypeBytes:
|
|
{
|
|
buffer.length = reg_info->byte_size;
|
|
buffer.byte_order = src.GetByteOrder();
|
|
assert (buffer.length <= kMaxRegisterByteSize);
|
|
if (buffer.length > kMaxRegisterByteSize)
|
|
buffer.length = kMaxRegisterByteSize;
|
|
if (src.CopyByteOrderedData (src_offset, // offset within "src" to start extracting data
|
|
src_len, // src length
|
|
buffer.bytes, // dst buffer
|
|
buffer.length, // dst length
|
|
buffer.byte_order) == 0)// dst byte order
|
|
{
|
|
error.SetErrorString ("data copy failed data.");
|
|
return error;
|
|
}
|
|
}
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include <vector>
|
|
static inline void StripSpaces(llvm::StringRef &Str)
|
|
{
|
|
while (!Str.empty() && isspace(Str[0]))
|
|
Str = Str.substr(1);
|
|
while (!Str.empty() && isspace(Str.back()))
|
|
Str = Str.substr(0, Str.size()-1);
|
|
}
|
|
static inline void LStrip(llvm::StringRef &Str, char c)
|
|
{
|
|
if (!Str.empty() && Str.front() == c)
|
|
Str = Str.substr(1);
|
|
}
|
|
static inline void RStrip(llvm::StringRef &Str, char c)
|
|
{
|
|
if (!Str.empty() && Str.back() == c)
|
|
Str = Str.substr(0, Str.size()-1);
|
|
}
|
|
// Helper function for RegisterValue::SetValueFromCString()
|
|
static bool
|
|
ParseVectorEncoding(const RegisterInfo *reg_info, const char *vector_str, const uint32_t byte_size, RegisterValue *reg_value)
|
|
{
|
|
// Example: vector_str = "{0x2c 0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f 0x2a 0x3e}".
|
|
llvm::StringRef Str(vector_str);
|
|
StripSpaces(Str);
|
|
LStrip(Str, '{');
|
|
RStrip(Str, '}');
|
|
StripSpaces(Str);
|
|
|
|
char Sep = ' ';
|
|
|
|
// The first split should give us:
|
|
// ('0x2c', '0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f 0x2a 0x3e').
|
|
std::pair<llvm::StringRef, llvm::StringRef> Pair = Str.split(Sep);
|
|
std::vector<uint8_t> bytes;
|
|
unsigned byte = 0;
|
|
|
|
// Using radix auto-sensing by passing 0 as the radix.
|
|
// Keep on processing the vector elements as long as the parsing succeeds and the vector size is < byte_size.
|
|
while (!Pair.first.getAsInteger(0, byte) && bytes.size() < byte_size) {
|
|
bytes.push_back(byte);
|
|
Pair = Pair.second.split(Sep);
|
|
}
|
|
|
|
// Check for vector of exact byte_size elements.
|
|
if (bytes.size() != byte_size)
|
|
return false;
|
|
|
|
reg_value->SetBytes(&(bytes.front()), byte_size, eByteOrderLittle);
|
|
return true;
|
|
}
|
|
Error
|
|
RegisterValue::SetValueFromCString (const RegisterInfo *reg_info, const char *value_str)
|
|
{
|
|
Error error;
|
|
if (reg_info == NULL)
|
|
{
|
|
error.SetErrorString ("Invalid register info argument.");
|
|
return error;
|
|
}
|
|
|
|
if (value_str == NULL || value_str[0] == '\0')
|
|
{
|
|
error.SetErrorString ("Invalid c-string value string.");
|
|
return error;
|
|
}
|
|
bool success = false;
|
|
const uint32_t byte_size = reg_info->byte_size;
|
|
static float flt_val;
|
|
static double dbl_val;
|
|
static long double ldbl_val;
|
|
switch (reg_info->encoding)
|
|
{
|
|
case eEncodingInvalid:
|
|
error.SetErrorString ("Invalid encoding.");
|
|
break;
|
|
|
|
case eEncodingUint:
|
|
if (byte_size <= sizeof (uint64_t))
|
|
{
|
|
uint64_t uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 0, &success);
|
|
if (!success)
|
|
error.SetErrorStringWithFormat ("'%s' is not a valid unsigned integer string value", value_str);
|
|
else if (!Args::UInt64ValueIsValidForByteSize (uval64, byte_size))
|
|
error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %u byte unsigned integer value", uval64, byte_size);
|
|
else
|
|
{
|
|
if (!SetUInt (uval64, reg_info->byte_size))
|
|
error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %u", byte_size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %u", byte_size);
|
|
return error;
|
|
}
|
|
break;
|
|
|
|
case eEncodingSint:
|
|
if (byte_size <= sizeof (long long))
|
|
{
|
|
uint64_t sval64 = StringConvert::ToSInt64(value_str, INT64_MAX, 0, &success);
|
|
if (!success)
|
|
error.SetErrorStringWithFormat ("'%s' is not a valid signed integer string value", value_str);
|
|
else if (!Args::SInt64ValueIsValidForByteSize (sval64, byte_size))
|
|
error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %u byte signed integer value", sval64, byte_size);
|
|
else
|
|
{
|
|
if (!SetUInt (sval64, reg_info->byte_size))
|
|
error.SetErrorStringWithFormat ("unsupported signed integer byte size: %u", byte_size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorStringWithFormat ("unsupported signed integer byte size: %u", byte_size);
|
|
return error;
|
|
}
|
|
break;
|
|
|
|
case eEncodingIEEE754:
|
|
if (byte_size == sizeof (float))
|
|
{
|
|
if (::sscanf (value_str, "%f", &flt_val) == 1)
|
|
{
|
|
m_scalar = flt_val;
|
|
m_type = eTypeFloat;
|
|
}
|
|
else
|
|
error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
|
|
}
|
|
else if (byte_size == sizeof (double))
|
|
{
|
|
if (::sscanf (value_str, "%lf", &dbl_val) == 1)
|
|
{
|
|
m_scalar = dbl_val;
|
|
m_type = eTypeDouble;
|
|
}
|
|
else
|
|
error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
|
|
}
|
|
else if (byte_size == sizeof (long double))
|
|
{
|
|
if (::sscanf (value_str, "%Lf", &ldbl_val) == 1)
|
|
{
|
|
m_scalar = ldbl_val;
|
|
m_type = eTypeLongDouble;
|
|
}
|
|
else
|
|
error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorStringWithFormat ("unsupported float byte size: %u", byte_size);
|
|
return error;
|
|
}
|
|
break;
|
|
|
|
case eEncodingVector:
|
|
if (!ParseVectorEncoding(reg_info, value_str, byte_size, this))
|
|
error.SetErrorString ("unrecognized vector encoding string value.");
|
|
break;
|
|
}
|
|
if (error.Fail())
|
|
m_type = eTypeInvalid;
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
bool
|
|
RegisterValue::SignExtend (uint32_t sign_bitpos)
|
|
{
|
|
switch (m_type)
|
|
{
|
|
case eTypeInvalid:
|
|
break;
|
|
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
return m_scalar.SignExtend(sign_bitpos);
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble:
|
|
case eTypeBytes:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
RegisterValue::CopyValue (const RegisterValue &rhs)
|
|
{
|
|
m_type = rhs.m_type;
|
|
switch (m_type)
|
|
{
|
|
case eTypeInvalid:
|
|
return false;
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble: m_scalar = rhs.m_scalar; break;
|
|
case eTypeBytes:
|
|
assert (rhs.buffer.length <= kMaxRegisterByteSize);
|
|
::memcpy (buffer.bytes, rhs.buffer.bytes, kMaxRegisterByteSize);
|
|
buffer.length = rhs.buffer.length;
|
|
buffer.byte_order = rhs.buffer.byte_order;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
uint16_t
|
|
RegisterValue::GetAsUInt16 (uint16_t fail_value, bool *success_ptr) const
|
|
{
|
|
if (success_ptr)
|
|
*success_ptr = true;
|
|
|
|
switch (m_type)
|
|
{
|
|
default: break;
|
|
case eTypeUInt8:
|
|
case eTypeUInt16: return m_scalar.UShort(fail_value);
|
|
case eTypeBytes:
|
|
{
|
|
switch (buffer.length)
|
|
{
|
|
default: break;
|
|
case 1:
|
|
case 2: return *(const uint16_t *)buffer.bytes;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (success_ptr)
|
|
*success_ptr = false;
|
|
return fail_value;
|
|
}
|
|
|
|
uint32_t
|
|
RegisterValue::GetAsUInt32 (uint32_t fail_value, bool *success_ptr) const
|
|
{
|
|
if (success_ptr)
|
|
*success_ptr = true;
|
|
switch (m_type)
|
|
{
|
|
default: break;
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble: return m_scalar.UInt(fail_value);
|
|
case eTypeBytes:
|
|
{
|
|
switch (buffer.length)
|
|
{
|
|
default: break;
|
|
case 1:
|
|
case 2:
|
|
case 4: return *(const uint32_t *)buffer.bytes;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (success_ptr)
|
|
*success_ptr = false;
|
|
return fail_value;
|
|
}
|
|
|
|
uint64_t
|
|
RegisterValue::GetAsUInt64 (uint64_t fail_value, bool *success_ptr) const
|
|
{
|
|
if (success_ptr)
|
|
*success_ptr = true;
|
|
switch (m_type)
|
|
{
|
|
default: break;
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble: return m_scalar.ULongLong(fail_value);
|
|
case eTypeBytes:
|
|
{
|
|
switch (buffer.length)
|
|
{
|
|
default: break;
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
case 8: return *(const uint64_t *)buffer.bytes;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (success_ptr)
|
|
*success_ptr = false;
|
|
return fail_value;
|
|
}
|
|
|
|
llvm::APInt
|
|
RegisterValue::GetAsUInt128 (llvm::APInt& fail_value, bool *success_ptr) const
|
|
{
|
|
if (success_ptr)
|
|
*success_ptr = true;
|
|
switch (m_type)
|
|
{
|
|
default: break;
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble: return m_scalar.UInt128(fail_value);
|
|
case eTypeBytes:
|
|
{
|
|
switch (buffer.length)
|
|
{
|
|
default:
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
case 8:
|
|
case 16:
|
|
{
|
|
return llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, ((const type128 *)buffer.bytes)->x);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (success_ptr)
|
|
*success_ptr = false;
|
|
return fail_value;
|
|
}
|
|
|
|
float
|
|
RegisterValue::GetAsFloat (float fail_value, bool *success_ptr) const
|
|
{
|
|
if (success_ptr)
|
|
*success_ptr = true;
|
|
switch (m_type)
|
|
{
|
|
default: break;
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble:
|
|
return m_scalar.Float(fail_value);
|
|
}
|
|
if (success_ptr)
|
|
*success_ptr = false;
|
|
return fail_value;
|
|
}
|
|
|
|
double
|
|
RegisterValue::GetAsDouble (double fail_value, bool *success_ptr) const
|
|
{
|
|
if (success_ptr)
|
|
*success_ptr = true;
|
|
switch (m_type)
|
|
{
|
|
default:
|
|
break;
|
|
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble:
|
|
return m_scalar.Double(fail_value);
|
|
}
|
|
if (success_ptr)
|
|
*success_ptr = false;
|
|
return fail_value;
|
|
}
|
|
|
|
long double
|
|
RegisterValue::GetAsLongDouble (long double fail_value, bool *success_ptr) const
|
|
{
|
|
if (success_ptr)
|
|
*success_ptr = true;
|
|
switch (m_type)
|
|
{
|
|
default:
|
|
break;
|
|
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble:
|
|
return m_scalar.LongDouble();
|
|
}
|
|
if (success_ptr)
|
|
*success_ptr = false;
|
|
return fail_value;
|
|
}
|
|
|
|
const void *
|
|
RegisterValue::GetBytes () const
|
|
{
|
|
switch (m_type)
|
|
{
|
|
case eTypeInvalid: break;
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble: return m_scalar.GetBytes();
|
|
case eTypeBytes: return buffer.bytes;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void *
|
|
RegisterValue::GetBytes ()
|
|
{
|
|
switch (m_type)
|
|
{
|
|
case eTypeInvalid: break;
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble: return m_scalar.GetBytes();
|
|
case eTypeBytes: return buffer.bytes;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
uint32_t
|
|
RegisterValue::GetByteSize () const
|
|
{
|
|
switch (m_type)
|
|
{
|
|
case eTypeInvalid: break;
|
|
case eTypeUInt8: return 1;
|
|
case eTypeUInt16: return 2;
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble: return m_scalar.GetByteSize();
|
|
case eTypeBytes: return buffer.length;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool
|
|
RegisterValue::SetUInt (uint64_t uint, uint32_t byte_size)
|
|
{
|
|
if (byte_size == 0)
|
|
{
|
|
SetUInt64 (uint);
|
|
}
|
|
else if (byte_size == 1)
|
|
{
|
|
SetUInt8 (uint);
|
|
}
|
|
else if (byte_size <= 2)
|
|
{
|
|
SetUInt16 (uint);
|
|
}
|
|
else if (byte_size <= 4)
|
|
{
|
|
SetUInt32 (uint);
|
|
}
|
|
else if (byte_size <= 8)
|
|
{
|
|
SetUInt64 (uint);
|
|
}
|
|
else if (byte_size <= 16)
|
|
{
|
|
SetUInt128 (llvm::APInt(64, uint));
|
|
}
|
|
else
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void
|
|
RegisterValue::SetBytes (const void *bytes, size_t length, lldb::ByteOrder byte_order)
|
|
{
|
|
// If this assertion fires off we need to increase the size of
|
|
// buffer.bytes, or make it something that is allocated on
|
|
// the heap. Since the data buffer is in a union, we can't make it
|
|
// a collection class like SmallVector...
|
|
if (bytes && length > 0)
|
|
{
|
|
assert (length <= sizeof (buffer.bytes) && "Storing too many bytes in a RegisterValue.");
|
|
m_type = eTypeBytes;
|
|
buffer.length = length;
|
|
memcpy (buffer.bytes, bytes, length);
|
|
buffer.byte_order = byte_order;
|
|
}
|
|
else
|
|
{
|
|
m_type = eTypeInvalid;
|
|
buffer.length = 0;
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
RegisterValue::operator == (const RegisterValue &rhs) const
|
|
{
|
|
if (m_type == rhs.m_type)
|
|
{
|
|
switch (m_type)
|
|
{
|
|
case eTypeInvalid: return true;
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble: return m_scalar == rhs.m_scalar;
|
|
case eTypeBytes:
|
|
if (buffer.length != rhs.buffer.length)
|
|
return false;
|
|
else
|
|
{
|
|
uint8_t length = buffer.length;
|
|
if (length > kMaxRegisterByteSize)
|
|
length = kMaxRegisterByteSize;
|
|
return memcmp (buffer.bytes, rhs.buffer.bytes, length) == 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
RegisterValue::operator != (const RegisterValue &rhs) const
|
|
{
|
|
if (m_type != rhs.m_type)
|
|
return true;
|
|
switch (m_type)
|
|
{
|
|
case eTypeInvalid: return false;
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble: return m_scalar != rhs.m_scalar;
|
|
case eTypeBytes:
|
|
if (buffer.length != rhs.buffer.length)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
uint8_t length = buffer.length;
|
|
if (length > kMaxRegisterByteSize)
|
|
length = kMaxRegisterByteSize;
|
|
return memcmp (buffer.bytes, rhs.buffer.bytes, length) != 0;
|
|
}
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
RegisterValue::ClearBit (uint32_t bit)
|
|
{
|
|
switch (m_type)
|
|
{
|
|
case eTypeInvalid:
|
|
break;
|
|
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
if (bit < (GetByteSize() * 8))
|
|
{
|
|
return m_scalar.ClearBit(bit);
|
|
}
|
|
break;
|
|
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble:
|
|
break;
|
|
|
|
case eTypeBytes:
|
|
if (buffer.byte_order == eByteOrderBig || buffer.byte_order == eByteOrderLittle)
|
|
{
|
|
uint32_t byte_idx;
|
|
if (buffer.byte_order == eByteOrderBig)
|
|
byte_idx = buffer.length - (bit / 8) - 1;
|
|
else
|
|
byte_idx = bit / 8;
|
|
|
|
const uint32_t byte_bit = bit % 8;
|
|
if (byte_idx < buffer.length)
|
|
{
|
|
buffer.bytes[byte_idx] &= ~(1u << byte_bit);
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool
|
|
RegisterValue::SetBit (uint32_t bit)
|
|
{
|
|
switch (m_type)
|
|
{
|
|
case eTypeInvalid:
|
|
break;
|
|
|
|
case eTypeUInt8:
|
|
case eTypeUInt16:
|
|
case eTypeUInt32:
|
|
case eTypeUInt64:
|
|
case eTypeUInt128:
|
|
if (bit < (GetByteSize() * 8))
|
|
{
|
|
return m_scalar.SetBit(bit);
|
|
}
|
|
break;
|
|
|
|
case eTypeFloat:
|
|
case eTypeDouble:
|
|
case eTypeLongDouble:
|
|
break;
|
|
|
|
case eTypeBytes:
|
|
if (buffer.byte_order == eByteOrderBig || buffer.byte_order == eByteOrderLittle)
|
|
{
|
|
uint32_t byte_idx;
|
|
if (buffer.byte_order == eByteOrderBig)
|
|
byte_idx = buffer.length - (bit / 8) - 1;
|
|
else
|
|
byte_idx = bit / 8;
|
|
|
|
const uint32_t byte_bit = bit % 8;
|
|
if (byte_idx < buffer.length)
|
|
{
|
|
buffer.bytes[byte_idx] |= (1u << byte_bit);
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|