//===-- 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 #include // Other libraries and framework includes #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" // 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 == 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, Error &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 // // 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); 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: { 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 16: case 32: if (buffer.length % sizeof(uint64_t) == 0) { const auto length_in_bits = buffer.length * 8; const auto length_in_uint64 = buffer.length / sizeof(uint64_t); scalar = llvm::APInt(length_in_bits, llvm::ArrayRef((const uint64_t *)buffer.bytes, length_in_uint64)); return true; } break; } } 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; } 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; 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; } 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 Pair = Str.split(Sep); std::vector 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 == nullptr) { error.SetErrorString ("Invalid register info argument."); return error; } if (value_str == nullptr || 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: return *(const uint8_t *)buffer.bytes; case 2: return *(const uint16_t *)buffer.bytes; case 4: return *(const uint32_t *)buffer.bytes; case 8: return *(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, ((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 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 { 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; }