| //===-- Scalar.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/Scalar.h" |
| #include "lldb/Utility/DataBufferHeap.h" |
| #include "lldb/Utility/DataExtractor.h" |
| #include "lldb/Utility/Endian.h" |
| #include "lldb/Utility/Status.h" |
| #include "lldb/Utility/Stream.h" |
| #include "lldb/Utility/StreamString.h" |
| #include "lldb/lldb-types.h" |
| #include "llvm/ADT/APSInt.h" |
| #include "llvm/ADT/SmallString.h" |
| |
| #include <cinttypes> |
| #include <cstdio> |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| using llvm::APFloat; |
| using llvm::APInt; |
| using llvm::APSInt; |
| |
| Scalar::PromotionKey Scalar::GetPromoKey() const { |
| switch (m_type) { |
| case e_void: |
| return PromotionKey{e_void, 0, false}; |
| case e_int: |
| return PromotionKey{e_int, m_integer.getBitWidth(), m_integer.isUnsigned()}; |
| case e_float: |
| return GetFloatPromoKey(m_float.getSemantics()); |
| } |
| llvm_unreachable("Unhandled category!"); |
| } |
| |
| Scalar::PromotionKey Scalar::GetFloatPromoKey(const llvm::fltSemantics &sem) { |
| static const llvm::fltSemantics *const order[] = { |
| &APFloat::IEEEsingle(), &APFloat::IEEEdouble(), |
| &APFloat::x87DoubleExtended()}; |
| for (const auto &entry : llvm::enumerate(order)) { |
| if (entry.value() == &sem) |
| return PromotionKey{e_float, entry.index(), false}; |
| } |
| llvm_unreachable("Unsupported semantics!"); |
| } |
| |
| // Promote to max type currently follows the ANSI C rule for type promotion in |
| // expressions. |
| Scalar::Type Scalar::PromoteToMaxType(Scalar &lhs, Scalar &rhs) { |
| const auto &Promote = [](Scalar &a, const Scalar &b) { |
| switch (b.GetType()) { |
| case e_void: |
| break; |
| case e_int: |
| a.IntegralPromote(b.m_integer.getBitWidth(), b.m_integer.isSigned()); |
| break; |
| case e_float: |
| a.FloatPromote(b.m_float.getSemantics()); |
| } |
| }; |
| |
| PromotionKey lhs_key = lhs.GetPromoKey(); |
| PromotionKey rhs_key = rhs.GetPromoKey(); |
| |
| if (lhs_key > rhs_key) |
| Promote(rhs, lhs); |
| else if (rhs_key > lhs_key) |
| Promote(lhs, rhs); |
| |
| // Make sure our type promotion worked as expected |
| if (lhs.GetPromoKey() == rhs.GetPromoKey()) |
| return lhs.GetType(); // Return the resulting type |
| |
| // Return the void type (zero) if we fail to promote either of the values. |
| return Scalar::e_void; |
| } |
| |
| bool Scalar::GetData(DataExtractor &data, size_t limit_byte_size) const { |
| size_t byte_size = GetByteSize(); |
| if (byte_size == 0) { |
| data.Clear(); |
| return false; |
| } |
| auto buffer_up = std::make_unique<DataBufferHeap>(byte_size, 0); |
| GetBytes(buffer_up->GetData()); |
| lldb::offset_t offset = 0; |
| |
| if (limit_byte_size < byte_size) { |
| if (endian::InlHostByteOrder() == eByteOrderLittle) { |
| // On little endian systems if we want fewer bytes from the current |
| // type we just specify fewer bytes since the LSByte is first... |
| byte_size = limit_byte_size; |
| } else if (endian::InlHostByteOrder() == eByteOrderBig) { |
| // On big endian systems if we want fewer bytes from the current type |
| // have to advance our initial byte pointer and trim down the number of |
| // bytes since the MSByte is first |
| offset = byte_size - limit_byte_size; |
| byte_size = limit_byte_size; |
| } |
| } |
| |
| data.SetData(std::move(buffer_up), offset, byte_size); |
| data.SetByteOrder(endian::InlHostByteOrder()); |
| return true; |
| } |
| |
| void Scalar::GetBytes(llvm::MutableArrayRef<uint8_t> storage) const { |
| assert(storage.size() >= GetByteSize()); |
| |
| const auto &store = [&](const llvm::APInt &val) { |
| StoreIntToMemory(val, storage.data(), (val.getBitWidth() + 7) / 8); |
| }; |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| store(m_integer); |
| break; |
| case e_float: |
| store(m_float.bitcastToAPInt()); |
| break; |
| } |
| } |
| |
| size_t Scalar::GetByteSize() const { |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| return (m_integer.getBitWidth() / 8); |
| case e_float: |
| return m_float.bitcastToAPInt().getBitWidth() / 8; |
| } |
| return 0; |
| } |
| |
| bool Scalar::IsZero() const { |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| return m_integer.isNullValue(); |
| case e_float: |
| return m_float.isZero(); |
| } |
| return false; |
| } |
| |
| void Scalar::GetValue(Stream *s, bool show_type) const { |
| if (show_type) |
| s->Printf("(%s) ", GetTypeAsCString()); |
| |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| s->PutCString(llvm::toString(m_integer, 10)); |
| break; |
| case e_float: |
| llvm::SmallString<24> string; |
| m_float.toString(string); |
| s->PutCString(string); |
| break; |
| } |
| } |
| |
| void Scalar::TruncOrExtendTo(uint16_t bits, bool sign) { |
| m_integer.setIsSigned(sign); |
| m_integer = m_integer.extOrTrunc(bits); |
| } |
| |
| bool Scalar::IntegralPromote(uint16_t bits, bool sign) { |
| switch (m_type) { |
| case e_void: |
| case e_float: |
| break; |
| case e_int: |
| if (GetPromoKey() > PromotionKey(e_int, bits, !sign)) |
| break; |
| m_integer = m_integer.extOrTrunc(bits); |
| m_integer.setIsSigned(sign); |
| return true; |
| } |
| return false; |
| } |
| |
| bool Scalar::FloatPromote(const llvm::fltSemantics &semantics) { |
| bool success = false; |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| m_float = llvm::APFloat(semantics); |
| m_float.convertFromAPInt(m_integer, m_integer.isSigned(), |
| llvm::APFloat::rmNearestTiesToEven); |
| success = true; |
| break; |
| case e_float: |
| if (GetFloatPromoKey(semantics) < GetFloatPromoKey(m_float.getSemantics())) |
| break; |
| bool ignore; |
| success = true; |
| m_float.convert(semantics, llvm::APFloat::rmNearestTiesToEven, &ignore); |
| } |
| |
| if (success) |
| m_type = e_float; |
| return success; |
| } |
| |
| const char *Scalar::GetValueTypeAsCString(Scalar::Type type) { |
| switch (type) { |
| case e_void: |
| return "void"; |
| case e_int: |
| return "int"; |
| case e_float: |
| return "float"; |
| } |
| return "???"; |
| } |
| |
| bool Scalar::IsSigned() const { |
| switch (m_type) { |
| case e_void: |
| return false; |
| case e_int: |
| return m_integer.isSigned(); |
| case e_float: |
| return true; |
| } |
| llvm_unreachable("Unrecognized type!"); |
| } |
| |
| bool Scalar::MakeSigned() { |
| bool success = false; |
| |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| m_integer.setIsSigned(true); |
| success = true; |
| break; |
| case e_float: |
| success = true; |
| break; |
| } |
| |
| return success; |
| } |
| |
| bool Scalar::MakeUnsigned() { |
| bool success = false; |
| |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| m_integer.setIsUnsigned(true); |
| success = true; |
| break; |
| case e_float: |
| success = true; |
| break; |
| } |
| |
| return success; |
| } |
| |
| static llvm::APInt ToAPInt(const llvm::APFloat &f, unsigned bits, |
| bool is_unsigned) { |
| llvm::APSInt result(bits, is_unsigned); |
| bool isExact; |
| f.convertToInteger(result, llvm::APFloat::rmTowardZero, &isExact); |
| return std::move(result); |
| } |
| |
| template <typename T> T Scalar::GetAs(T fail_value) const { |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: { |
| APSInt ext = m_integer.extOrTrunc(sizeof(T) * 8); |
| if (ext.isSigned()) |
| return ext.getSExtValue(); |
| return ext.getZExtValue(); |
| } |
| case e_float: |
| return ToAPInt(m_float, sizeof(T) * 8, std::is_unsigned<T>::value) |
| .getSExtValue(); |
| } |
| return fail_value; |
| } |
| |
| signed char Scalar::SChar(signed char fail_value) const { |
| return GetAs<signed char>(fail_value); |
| } |
| |
| unsigned char Scalar::UChar(unsigned char fail_value) const { |
| return GetAs<unsigned char>(fail_value); |
| } |
| |
| short Scalar::SShort(short fail_value) const { |
| return GetAs<short>(fail_value); |
| } |
| |
| unsigned short Scalar::UShort(unsigned short fail_value) const { |
| return GetAs<unsigned short>(fail_value); |
| } |
| |
| int Scalar::SInt(int fail_value) const { return GetAs<int>(fail_value); } |
| |
| unsigned int Scalar::UInt(unsigned int fail_value) const { |
| return GetAs<unsigned int>(fail_value); |
| } |
| |
| long Scalar::SLong(long fail_value) const { return GetAs<long>(fail_value); } |
| |
| unsigned long Scalar::ULong(unsigned long fail_value) const { |
| return GetAs<unsigned long>(fail_value); |
| } |
| |
| long long Scalar::SLongLong(long long fail_value) const { |
| return GetAs<long long>(fail_value); |
| } |
| |
| unsigned long long Scalar::ULongLong(unsigned long long fail_value) const { |
| return GetAs<unsigned long long>(fail_value); |
| } |
| |
| llvm::APInt Scalar::SInt128(const llvm::APInt &fail_value) const { |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| return m_integer; |
| case e_float: |
| return ToAPInt(m_float, 128, /*is_unsigned=*/false); |
| } |
| return fail_value; |
| } |
| |
| llvm::APInt Scalar::UInt128(const llvm::APInt &fail_value) const { |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| return m_integer; |
| case e_float: |
| return ToAPInt(m_float, 128, /*is_unsigned=*/true); |
| } |
| return fail_value; |
| } |
| |
| float Scalar::Float(float fail_value) const { |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| if (m_integer.isSigned()) |
| return llvm::APIntOps::RoundSignedAPIntToFloat(m_integer); |
| return llvm::APIntOps::RoundAPIntToFloat(m_integer); |
| |
| case e_float: { |
| APFloat result = m_float; |
| bool losesInfo; |
| result.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, |
| &losesInfo); |
| return result.convertToFloat(); |
| } |
| } |
| return fail_value; |
| } |
| |
| double Scalar::Double(double fail_value) const { |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| if (m_integer.isSigned()) |
| return llvm::APIntOps::RoundSignedAPIntToDouble(m_integer); |
| return llvm::APIntOps::RoundAPIntToDouble(m_integer); |
| |
| case e_float: { |
| APFloat result = m_float; |
| bool losesInfo; |
| result.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, |
| &losesInfo); |
| return result.convertToDouble(); |
| } |
| } |
| return fail_value; |
| } |
| |
| long double Scalar::LongDouble(long double fail_value) const { |
| /// No way to get more precision at the moment. |
| return static_cast<long double>(Double(fail_value)); |
| } |
| |
| Scalar &Scalar::operator+=(Scalar rhs) { |
| Scalar copy = *this; |
| if ((m_type = PromoteToMaxType(copy, rhs)) != Scalar::e_void) { |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| m_integer = copy.m_integer + rhs.m_integer; |
| break; |
| |
| case e_float: |
| m_float = copy.m_float + rhs.m_float; |
| break; |
| } |
| } |
| return *this; |
| } |
| |
| Scalar &Scalar::operator<<=(const Scalar &rhs) { |
| if (m_type == e_int && rhs.m_type == e_int) |
| static_cast<APInt &>(m_integer) <<= rhs.m_integer; |
| else |
| m_type = e_void; |
| return *this; |
| } |
| |
| bool Scalar::ShiftRightLogical(const Scalar &rhs) { |
| if (m_type == e_int && rhs.m_type == e_int) { |
| m_integer = m_integer.lshr(rhs.m_integer); |
| return true; |
| } |
| m_type = e_void; |
| return false; |
| } |
| |
| Scalar &Scalar::operator>>=(const Scalar &rhs) { |
| switch (m_type) { |
| case e_void: |
| case e_float: |
| m_type = e_void; |
| break; |
| |
| case e_int: |
| switch (rhs.m_type) { |
| case e_void: |
| case e_float: |
| m_type = e_void; |
| break; |
| case e_int: |
| m_integer = m_integer.ashr(rhs.m_integer); |
| break; |
| } |
| break; |
| } |
| return *this; |
| } |
| |
| Scalar &Scalar::operator&=(const Scalar &rhs) { |
| if (m_type == e_int && rhs.m_type == e_int) |
| m_integer &= rhs.m_integer; |
| else |
| m_type = e_void; |
| return *this; |
| } |
| |
| bool Scalar::AbsoluteValue() { |
| switch (m_type) { |
| case e_void: |
| break; |
| |
| case e_int: |
| if (m_integer.isNegative()) |
| m_integer = -m_integer; |
| return true; |
| |
| case e_float: |
| m_float.clearSign(); |
| return true; |
| } |
| return false; |
| } |
| |
| bool Scalar::UnaryNegate() { |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| m_integer = -m_integer; |
| return true; |
| case e_float: |
| m_float.changeSign(); |
| return true; |
| } |
| return false; |
| } |
| |
| bool Scalar::OnesComplement() { |
| if (m_type == e_int) { |
| m_integer = ~m_integer; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| const Scalar lldb_private::operator+(const Scalar &lhs, const Scalar &rhs) { |
| Scalar result = lhs; |
| result += rhs; |
| return result; |
| } |
| |
| const Scalar lldb_private::operator-(Scalar lhs, Scalar rhs) { |
| Scalar result; |
| if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { |
| switch (result.m_type) { |
| case Scalar::e_void: |
| break; |
| case Scalar::e_int: |
| result.m_integer = lhs.m_integer - rhs.m_integer; |
| break; |
| case Scalar::e_float: |
| result.m_float = lhs.m_float - rhs.m_float; |
| break; |
| } |
| } |
| return result; |
| } |
| |
| const Scalar lldb_private::operator/(Scalar lhs, Scalar rhs) { |
| Scalar result; |
| if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void && |
| !rhs.IsZero()) { |
| switch (result.m_type) { |
| case Scalar::e_void: |
| break; |
| case Scalar::e_int: |
| result.m_integer = lhs.m_integer / rhs.m_integer; |
| return result; |
| case Scalar::e_float: |
| result.m_float = lhs.m_float / rhs.m_float; |
| return result; |
| } |
| } |
| // For division only, the only way it should make it here is if a promotion |
| // failed, or if we are trying to do a divide by zero. |
| result.m_type = Scalar::e_void; |
| return result; |
| } |
| |
| const Scalar lldb_private::operator*(Scalar lhs, Scalar rhs) { |
| Scalar result; |
| if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { |
| switch (result.m_type) { |
| case Scalar::e_void: |
| break; |
| case Scalar::e_int: |
| result.m_integer = lhs.m_integer * rhs.m_integer; |
| break; |
| case Scalar::e_float: |
| result.m_float = lhs.m_float * rhs.m_float; |
| break; |
| } |
| } |
| return result; |
| } |
| |
| const Scalar lldb_private::operator&(Scalar lhs, Scalar rhs) { |
| Scalar result; |
| if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { |
| if (result.m_type == Scalar::e_int) |
| result.m_integer = lhs.m_integer & rhs.m_integer; |
| else |
| result.m_type = Scalar::e_void; |
| } |
| return result; |
| } |
| |
| const Scalar lldb_private::operator|(Scalar lhs, Scalar rhs) { |
| Scalar result; |
| if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { |
| if (result.m_type == Scalar::e_int) |
| result.m_integer = lhs.m_integer | rhs.m_integer; |
| else |
| result.m_type = Scalar::e_void; |
| } |
| return result; |
| } |
| |
| const Scalar lldb_private::operator%(Scalar lhs, Scalar rhs) { |
| Scalar result; |
| if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { |
| if (!rhs.IsZero() && result.m_type == Scalar::e_int) { |
| result.m_integer = lhs.m_integer % rhs.m_integer; |
| return result; |
| } |
| } |
| result.m_type = Scalar::e_void; |
| return result; |
| } |
| |
| const Scalar lldb_private::operator^(Scalar lhs, Scalar rhs) { |
| Scalar result; |
| if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { |
| if (result.m_type == Scalar::e_int) |
| result.m_integer = lhs.m_integer ^ rhs.m_integer; |
| else |
| result.m_type = Scalar::e_void; |
| } |
| return result; |
| } |
| |
| const Scalar lldb_private::operator<<(const Scalar &lhs, const Scalar &rhs) { |
| Scalar result = lhs; |
| result <<= rhs; |
| return result; |
| } |
| |
| const Scalar lldb_private::operator>>(const Scalar &lhs, const Scalar &rhs) { |
| Scalar result = lhs; |
| result >>= rhs; |
| return result; |
| } |
| |
| Status Scalar::SetValueFromCString(const char *value_str, Encoding encoding, |
| size_t byte_size) { |
| Status error; |
| if (value_str == nullptr || value_str[0] == '\0') { |
| error.SetErrorString("Invalid c-string value string."); |
| return error; |
| } |
| switch (encoding) { |
| case eEncodingInvalid: |
| error.SetErrorString("Invalid encoding."); |
| break; |
| |
| case eEncodingSint: |
| case eEncodingUint: { |
| llvm::StringRef str = value_str; |
| bool is_signed = encoding == eEncodingSint; |
| bool is_negative = is_signed && str.consume_front("-"); |
| APInt integer; |
| if (str.getAsInteger(0, integer)) { |
| error.SetErrorStringWithFormatv( |
| "'{0}' is not a valid integer string value", value_str); |
| break; |
| } |
| bool fits; |
| if (is_signed) { |
| integer = integer.zext(integer.getBitWidth() + 1); |
| if (is_negative) |
| integer.negate(); |
| fits = integer.isSignedIntN(byte_size * 8); |
| } else |
| fits = integer.isIntN(byte_size * 8); |
| if (!fits) { |
| error.SetErrorStringWithFormatv( |
| "value {0} is too large to fit in a {1} byte integer value", |
| value_str, byte_size); |
| break; |
| } |
| m_type = e_int; |
| m_integer = |
| APSInt(std::move(integer), !is_signed).extOrTrunc(8 * byte_size); |
| break; |
| } |
| |
| case eEncodingIEEE754: { |
| // FIXME: It's not possible to unambiguously map a byte size to a floating |
| // point type. This function should be refactored to take an explicit |
| // semantics argument. |
| const llvm::fltSemantics &sem = |
| byte_size <= 4 ? APFloat::IEEEsingle() |
| : byte_size <= 8 ? APFloat::IEEEdouble() |
| : APFloat::x87DoubleExtended(); |
| APFloat f(sem); |
| if (llvm::Expected<APFloat::opStatus> op = |
| f.convertFromString(value_str, APFloat::rmNearestTiesToEven)) { |
| m_type = e_float; |
| m_float = std::move(f); |
| } else |
| error = op.takeError(); |
| break; |
| } |
| |
| case eEncodingVector: |
| error.SetErrorString("vector encoding unsupported."); |
| break; |
| } |
| if (error.Fail()) |
| m_type = e_void; |
| |
| return error; |
| } |
| |
| Status Scalar::SetValueFromData(const DataExtractor &data, |
| lldb::Encoding encoding, size_t byte_size) { |
| Status error; |
| switch (encoding) { |
| case lldb::eEncodingInvalid: |
| error.SetErrorString("invalid encoding"); |
| break; |
| case lldb::eEncodingVector: |
| error.SetErrorString("vector encoding unsupported"); |
| break; |
| case lldb::eEncodingUint: |
| case lldb::eEncodingSint: { |
| if (data.GetByteSize() < byte_size) |
| return Status("insufficient data"); |
| m_type = e_int; |
| m_integer = |
| APSInt(APInt::getZero(8 * byte_size), encoding == eEncodingUint); |
| if (data.GetByteOrder() == endian::InlHostByteOrder()) { |
| llvm::LoadIntFromMemory(m_integer, data.GetDataStart(), byte_size); |
| } else { |
| std::vector<uint8_t> buffer(byte_size); |
| std::copy_n(data.GetDataStart(), byte_size, buffer.rbegin()); |
| llvm::LoadIntFromMemory(m_integer, buffer.data(), byte_size); |
| } |
| break; |
| } |
| case lldb::eEncodingIEEE754: { |
| lldb::offset_t offset = 0; |
| |
| if (byte_size == sizeof(float)) |
| operator=(data.GetFloat(&offset)); |
| else if (byte_size == sizeof(double)) |
| operator=(data.GetDouble(&offset)); |
| else if (byte_size == sizeof(long double)) |
| operator=(data.GetLongDouble(&offset)); |
| else |
| error.SetErrorStringWithFormat("unsupported float byte size: %" PRIu64 "", |
| static_cast<uint64_t>(byte_size)); |
| } break; |
| } |
| |
| return error; |
| } |
| |
| bool Scalar::SignExtend(uint32_t sign_bit_pos) { |
| const uint32_t max_bit_pos = GetByteSize() * 8; |
| |
| if (sign_bit_pos < max_bit_pos) { |
| switch (m_type) { |
| case Scalar::e_void: |
| case Scalar::e_float: |
| return false; |
| |
| case Scalar::e_int: |
| if (max_bit_pos == sign_bit_pos) |
| return true; |
| else if (sign_bit_pos < (max_bit_pos - 1)) { |
| llvm::APInt sign_bit = llvm::APInt::getSignMask(sign_bit_pos + 1); |
| llvm::APInt bitwize_and = m_integer & sign_bit; |
| if (bitwize_and.getBoolValue()) { |
| llvm::APInt mask = |
| ~(sign_bit) + llvm::APInt(m_integer.getBitWidth(), 1); |
| m_integer |= APSInt(std::move(mask), m_integer.isUnsigned()); |
| } |
| return true; |
| } |
| break; |
| } |
| } |
| return false; |
| } |
| |
| size_t Scalar::GetAsMemoryData(void *dst, size_t dst_len, |
| lldb::ByteOrder dst_byte_order, |
| Status &error) const { |
| // Get a data extractor that points to the native scalar data |
| DataExtractor data; |
| if (!GetData(data)) { |
| error.SetErrorString("invalid scalar value"); |
| return 0; |
| } |
| |
| const size_t src_len = data.GetByteSize(); |
| |
| // Prepare a memory buffer that contains some or all of the register value |
| const size_t bytes_copied = |
| 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.SetErrorString("failed to copy data"); |
| |
| return bytes_copied; |
| } |
| |
| bool Scalar::ExtractBitfield(uint32_t bit_size, uint32_t bit_offset) { |
| if (bit_size == 0) |
| return true; |
| |
| switch (m_type) { |
| case Scalar::e_void: |
| case Scalar::e_float: |
| break; |
| |
| case Scalar::e_int: |
| m_integer >>= bit_offset; |
| m_integer = m_integer.extOrTrunc(bit_size).extOrTrunc(8 * GetByteSize()); |
| return true; |
| } |
| return false; |
| } |
| |
| bool lldb_private::operator==(Scalar lhs, Scalar rhs) { |
| // If either entry is void then we can just compare the types |
| if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void) |
| return lhs.m_type == rhs.m_type; |
| |
| llvm::APFloat::cmpResult result; |
| switch (Scalar::PromoteToMaxType(lhs, rhs)) { |
| case Scalar::e_void: |
| break; |
| case Scalar::e_int: |
| return lhs.m_integer == rhs.m_integer; |
| case Scalar::e_float: |
| result = lhs.m_float.compare(rhs.m_float); |
| if (result == llvm::APFloat::cmpEqual) |
| return true; |
| } |
| return false; |
| } |
| |
| bool lldb_private::operator!=(const Scalar &lhs, const Scalar &rhs) { |
| return !(lhs == rhs); |
| } |
| |
| bool lldb_private::operator<(Scalar lhs, Scalar rhs) { |
| if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void) |
| return false; |
| |
| llvm::APFloat::cmpResult result; |
| switch (Scalar::PromoteToMaxType(lhs, rhs)) { |
| case Scalar::e_void: |
| break; |
| case Scalar::e_int: |
| return lhs.m_integer < rhs.m_integer; |
| case Scalar::e_float: |
| result = lhs.m_float.compare(rhs.m_float); |
| if (result == llvm::APFloat::cmpLessThan) |
| return true; |
| } |
| return false; |
| } |
| |
| bool lldb_private::operator<=(const Scalar &lhs, const Scalar &rhs) { |
| return !(rhs < lhs); |
| } |
| |
| bool lldb_private::operator>(const Scalar &lhs, const Scalar &rhs) { |
| return rhs < lhs; |
| } |
| |
| bool lldb_private::operator>=(const Scalar &lhs, const Scalar &rhs) { |
| return !(lhs < rhs); |
| } |
| |
| bool Scalar::ClearBit(uint32_t bit) { |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| m_integer.clearBit(bit); |
| return true; |
| case e_float: |
| break; |
| } |
| return false; |
| } |
| |
| bool Scalar::SetBit(uint32_t bit) { |
| switch (m_type) { |
| case e_void: |
| break; |
| case e_int: |
| m_integer.setBit(bit); |
| return true; |
| case e_float: |
| break; |
| } |
| return false; |
| } |
| |
| llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &os, const Scalar &scalar) { |
| StreamString s; |
| scalar.GetValue(&s, /*show_type*/ true); |
| return os << s.GetString(); |
| } |