diff options
author | 2020-08-03 14:33:06 +0000 | |
---|---|---|
committer | 2020-08-03 14:33:06 +0000 | |
commit | 061da546b983eb767bad15e67af1174fb0bcf31c (patch) | |
tree | 83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/source/Utility/RegisterValue.cpp | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/source/Utility/RegisterValue.cpp')
-rw-r--r-- | gnu/llvm/lldb/source/Utility/RegisterValue.cpp | 906 |
1 files changed, 906 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Utility/RegisterValue.cpp b/gnu/llvm/lldb/source/Utility/RegisterValue.cpp new file mode 100644 index 00000000000..36790f5d8ef --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/RegisterValue.cpp @@ -0,0 +1,906 @@ +//===-- RegisterValue.cpp ---------------------------------------*- C++ -*-===// +// +// 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: { + switch (buffer.length) { + default: + break; + case 1: + scalar = *(const uint8_t *)buffer.bytes; + return true; + case 2: + scalar = *reinterpret_cast<const uint16_t *>(buffer.bytes); + return true; + case 4: + scalar = *reinterpret_cast<const uint32_t *>(buffer.bytes); + return true; + case 8: + scalar = *reinterpret_cast<const uint64_t *>(buffer.bytes); + return true; + case 16: + case 32: + case 64: + 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<uint64_t>( + reinterpret_cast<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; +} + +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 = 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: + 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 { + 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; +} |