blob: 7848f784d8f2bd904ecd6100537a694d2c4a23b7 [file] [log] [blame]
//===-- RegisterValue.cpp -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/Scalar.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-private-types.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include <cstdint>
#include <string>
#include <tuple>
#include <vector>
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
using namespace lldb;
using namespace lldb_private;
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,
Status &error) const {
if (reg_info == nullptr) {
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,
Status &error) {
if (reg_info == nullptr) {
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
//
// Status! (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);
error = SetValueFromData(reg_info, src_data, 0, true);
if (error.Fail())
return 0;
// If SetValueFromData succeeded, we must have copied all of src_len
return src_len;
}
bool RegisterValue::GetScalarValue(Scalar &scalar) const {
switch (m_type) {
case eTypeInvalid:
break;
case eTypeBytes: {
DataExtractor data(buffer.bytes, buffer.length, buffer.byte_order, 1);
if (scalar.SetValueFromData(data, lldb::eEncodingUint,
buffer.length).Success())
return true;
} break;
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) {
// To change the type, we simply copy the data in again, using the new format
RegisterValue copy;
DataExtractor copy_data;
if (copy.CopyValue(*this) && copy.GetData(copy_data))
SetValueFromData(reg_info, copy_data, 0, true);
return m_type;
}
Status RegisterValue::SetValueFromData(const RegisterInfo *reg_info,
DataExtractor &src,
lldb::offset_t src_offset,
bool partial_data_ok) {
Status 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;
m_type = eTypeInvalid;
switch (reg_info->encoding) {
case eEncodingInvalid:
break;
case eEncodingUint:
case eEncodingSint:
if (reg_info->byte_size == 1)
SetUInt8(src.GetMaxU32(&src_offset, src_len));
else if (reg_info->byte_size <= 2)
SetUInt16(src.GetMaxU32(&src_offset, src_len));
else if (reg_info->byte_size <= 4)
SetUInt32(src.GetMaxU32(&src_offset, src_len));
else if (reg_info->byte_size <= 8)
SetUInt64(src.GetMaxU64(&src_offset, src_len));
else if (reg_info->byte_size <= 16) {
uint64_t data1 = src.GetU64(&src_offset);
uint64_t data2 = src.GetU64(&src_offset);
if (src.GetByteSize() == eByteOrderBig) {
int128.x[0] = data1;
int128.x[1] = data2;
} else {
int128.x[0] = data2;
int128.x[1] = data1;
}
SetUInt128(llvm::APInt(128, 2, int128.x));
}
break;
case eEncodingIEEE754:
if (reg_info->byte_size == sizeof(float))
SetFloat(src.GetFloat(&src_offset));
else if (reg_info->byte_size == sizeof(double))
SetDouble(src.GetDouble(&src_offset));
else if (reg_info->byte_size == sizeof(long double))
SetLongDouble(src.GetLongDouble(&src_offset));
break;
case eEncodingVector: {
m_type = 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.SetErrorStringWithFormat(
"failed to copy data for register write of %s", reg_info->name);
return error;
}
}
}
if (m_type == eTypeInvalid)
error.SetErrorStringWithFormat(
"invalid register value type for register %s", reg_info->name);
return error;
}
// Helper function for RegisterValue::SetValueFromString()
static bool ParseVectorEncoding(const RegisterInfo *reg_info,
llvm::StringRef 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}".
vector_str = vector_str.trim();
vector_str.consume_front("{");
vector_str.consume_back("}");
vector_str = vector_str.trim();
char Sep = ' ';
// The first split should give us:
// ('0x2c', '0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f
// 0x2a 0x3e').
llvm::StringRef car;
llvm::StringRef cdr = vector_str;
std::tie(car, cdr) = vector_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 (!car.getAsInteger(0, byte) && bytes.size() < byte_size) {
bytes.push_back(byte);
std::tie(car, cdr) = cdr.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;
}
static bool UInt64ValueIsValidForByteSize(uint64_t uval64,
size_t total_byte_size) {
if (total_byte_size > 8)
return false;
if (total_byte_size == 8)
return true;
const uint64_t max =
(static_cast<uint64_t>(1) << static_cast<uint64_t>(total_byte_size * 8)) -
1;
return uval64 <= max;
}
static bool SInt64ValueIsValidForByteSize(int64_t sval64,
size_t total_byte_size) {
if (total_byte_size > 8)
return false;
if (total_byte_size == 8)
return true;
const int64_t max = (static_cast<int64_t>(1)
<< static_cast<uint64_t>(total_byte_size * 8 - 1)) -
1;
const int64_t min = ~(max);
return min <= sval64 && sval64 <= max;
}
Status RegisterValue::SetValueFromString(const RegisterInfo *reg_info,
llvm::StringRef value_str) {
Status error;
if (reg_info == nullptr) {
error.SetErrorString("Invalid register info argument.");
return error;
}
m_type = eTypeInvalid;
if (value_str.empty()) {
error.SetErrorString("Invalid c-string value string.");
return error;
}
const uint32_t byte_size = reg_info->byte_size;
uint64_t uval64;
int64_t ival64;
float flt_val;
double dbl_val;
long double ldbl_val;
switch (reg_info->encoding) {
case eEncodingInvalid:
error.SetErrorString("Invalid encoding.");
break;
case eEncodingUint:
if (byte_size > sizeof(uint64_t)) {
error.SetErrorStringWithFormat(
"unsupported unsigned integer byte size: %u", byte_size);
break;
}
if (value_str.getAsInteger(0, uval64)) {
error.SetErrorStringWithFormat(
"'%s' is not a valid unsigned integer string value",
value_str.str().c_str());
break;
}
if (!UInt64ValueIsValidForByteSize(uval64, byte_size)) {
error.SetErrorStringWithFormat(
"value 0x%" PRIx64
" is too large to fit in a %u byte unsigned integer value",
uval64, byte_size);
break;
}
if (!SetUInt(uval64, reg_info->byte_size)) {
error.SetErrorStringWithFormat(
"unsupported unsigned integer byte size: %u", byte_size);
break;
}
break;
case eEncodingSint:
if (byte_size > sizeof(long long)) {
error.SetErrorStringWithFormat("unsupported signed integer byte size: %u",
byte_size);
break;
}
if (value_str.getAsInteger(0, ival64)) {
error.SetErrorStringWithFormat(
"'%s' is not a valid signed integer string value",
value_str.str().c_str());
break;
}
if (!SInt64ValueIsValidForByteSize(ival64, byte_size)) {
error.SetErrorStringWithFormat(
"value 0x%" PRIx64
" is too large to fit in a %u byte signed integer value",
ival64, byte_size);
break;
}
if (!SetUInt(ival64, reg_info->byte_size)) {
error.SetErrorStringWithFormat("unsupported signed integer byte size: %u",
byte_size);
break;
}
break;
case eEncodingIEEE754: {
std::string value_string = std::string(value_str);
if (byte_size == sizeof(float)) {
if (::sscanf(value_string.c_str(), "%f", &flt_val) != 1) {
error.SetErrorStringWithFormat("'%s' is not a valid float string value",
value_string.c_str());
break;
}
m_scalar = flt_val;
m_type = eTypeFloat;
} else if (byte_size == sizeof(double)) {
if (::sscanf(value_string.c_str(), "%lf", &dbl_val) != 1) {
error.SetErrorStringWithFormat("'%s' is not a valid float string value",
value_string.c_str());
break;
}
m_scalar = dbl_val;
m_type = eTypeDouble;
} else if (byte_size == sizeof(long double)) {
if (::sscanf(value_string.c_str(), "%Lf", &ldbl_val) != 1) {
error.SetErrorStringWithFormat("'%s' is not a valid float string value",
value_string.c_str());
break;
}
m_scalar = ldbl_val;
m_type = eTypeLongDouble;
} 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;
}
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) {
if (this == &rhs)
return rhs.m_type != eTypeInvalid;
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 *reinterpret_cast<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 *reinterpret_cast<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:
return *(const uint8_t *)buffer.bytes;
case 2:
return *reinterpret_cast<const uint16_t *>(buffer.bytes);
case 4:
return *reinterpret_cast<const uint32_t *>(buffer.bytes);
case 8:
return *reinterpret_cast<const uint64_t *>(buffer.bytes);
}
} break;
}
if (success_ptr)
*success_ptr = false;
return fail_value;
}
llvm::APInt RegisterValue::GetAsUInt128(const 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,
(reinterpret_cast<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:
m_scalar.GetBytes(buffer.bytes);
return buffer.bytes;
case eTypeBytes:
return buffer.bytes;
}
return nullptr;
}
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(128, 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 {
uint16_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 {
return !(*this == rhs);
}
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;
}