aboutsummaryrefslogtreecommitdiff
path: root/lldb
diff options
context:
space:
mode:
authorcmtice <cmtice@google.com>2024-06-13 09:14:17 -0700
committerGitHub <noreply@github.com>2024-06-13 09:14:17 -0700
commit9f70cd83897b36e5628057dfef2855a0b9045766 (patch)
tree13659c94b9efa748931055277c86846aa57da8ca /lldb
parentabcbbe711410da051126ca5b11a1ea227cb238f8 (diff)
downloadllvm-9f70cd83897b36e5628057dfef2855a0b9045766.zip
llvm-9f70cd83897b36e5628057dfef2855a0b9045766.tar.gz
llvm-9f70cd83897b36e5628057dfef2855a0b9045766.tar.bz2
[LLDB] Add more helper functions to ValueObject class. (#87197)
Create additional helper functions for the ValueObject class, for: - returning the value as an APSInt or APFloat - additional type casting options - additional ways to create ValueObjects from various types of data - dereferencing a ValueObject These helper functions are needed for implementing the Data Inspection Language, described in https://discourse.llvm.org/t/rfc-data-inspection-language/69893
Diffstat (limited to 'lldb')
-rw-r--r--lldb/include/lldb/Core/ValueObject.h82
-rw-r--r--lldb/include/lldb/Utility/Scalar.h4
-rw-r--r--lldb/source/API/SBValue.cpp22
-rw-r--r--lldb/source/Core/ValueObject.cpp587
4 files changed, 670 insertions, 25 deletions
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 1e8c7c9..db1fdae 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -441,6 +441,30 @@ public:
virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr);
+ /// If the current ValueObject is of an appropriate type, convert the
+ /// value to an APSInt and return that. Otherwise return an error.
+ llvm::Expected<llvm::APSInt> GetValueAsAPSInt();
+
+ /// If the current ValueObject is of an appropriate type, convert the
+ /// value to an APFloat and return that. Otherwise return an error.
+ llvm::Expected<llvm::APFloat> GetValueAsAPFloat();
+
+ /// If the current ValueObject is of an appropriate type, convert the
+ /// value to a boolean and return that. Otherwise return an error.
+ llvm::Expected<bool> GetValueAsBool();
+
+ /// Update an existing integer ValueObject with a new integer value. This
+ /// is only intended to be used with 'temporary' ValueObjects, i.e. ones that
+ /// are not associated with program variables. It does not update program
+ /// memory, registers, stack, etc.
+ void SetValueFromInteger(const llvm::APInt &value, Status &error);
+
+ /// Update an existing integer ValueObject with an integer value created
+ /// frome 'new_val_sp'. This is only intended to be used with 'temporary'
+ /// ValueObjects, i.e. ones that are not associated with program variables.
+ /// It does not update program memory, registers, stack, etc.
+ void SetValueFromInteger(lldb::ValueObjectSP new_val_sp, Status &error);
+
virtual bool SetValueFromCString(const char *value_str, Status &error);
/// Return the module associated with this value object in case the value is
@@ -618,6 +642,32 @@ public:
virtual lldb::ValueObjectSP CastPointerType(const char *name,
lldb::TypeSP &type_sp);
+ /// Return the target load address associated with this value object.
+ lldb::addr_t GetLoadAddress();
+
+ /// Take a ValueObject whose type is an inherited class, and cast it to
+ /// 'type', which should be one of its base classes. 'base_type_indices'
+ /// contains the indices of direct base classes on the path from the
+ /// ValueObject's current type to 'type'
+ llvm::Expected<lldb::ValueObjectSP>
+ CastDerivedToBaseType(CompilerType type,
+ const llvm::ArrayRef<uint32_t> &base_type_indices);
+
+ /// Take a ValueObject whose type is a base class, and cast it to 'type',
+ /// which should be one of its derived classes. 'base_type_indices'
+ /// contains the indices of direct base classes on the path from the
+ /// ValueObject's current type to 'type'
+ llvm::Expected<lldb::ValueObjectSP> CastBaseToDerivedType(CompilerType type,
+ uint64_t offset);
+
+ // Take a ValueObject that contains a scalar, enum or pointer type, and
+ // cast it to a "basic" type (integer, float or boolean).
+ lldb::ValueObjectSP CastToBasicType(CompilerType type);
+
+ // Take a ValueObject that contain an integer, float or enum, and cast it
+ // to an enum.
+ lldb::ValueObjectSP CastToEnumType(CompilerType type);
+
/// If this object represents a C++ class with a vtable, return an object
/// that represents the virtual function table. If the object isn't a class
/// with a vtable, return a valid ValueObject with the error set correctly.
@@ -659,15 +709,41 @@ public:
const ExecutionContext &exe_ctx,
const EvaluateExpressionOptions &options);
+ /// Given an address either create a value object containing the value at
+ /// that address, or create a value object containing the address itself
+ /// (pointer value), depending on whether the parameter 'do_deref' is true or
+ /// false.
static lldb::ValueObjectSP
CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address,
const ExecutionContext &exe_ctx,
- CompilerType type);
+ CompilerType type, bool do_deref = true);
static lldb::ValueObjectSP
CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data,
const ExecutionContext &exe_ctx, CompilerType type);
+ /// Create a value object containing the given APInt value.
+ static lldb::ValueObjectSP CreateValueObjectFromAPInt(lldb::TargetSP target,
+ const llvm::APInt &v,
+ CompilerType type,
+ llvm::StringRef name);
+
+ /// Create a value object containing the given APFloat value.
+ static lldb::ValueObjectSP
+ CreateValueObjectFromAPFloat(lldb::TargetSP target, const llvm::APFloat &v,
+ CompilerType type, llvm::StringRef name);
+
+ /// Create a value object containing the given boolean value.
+ static lldb::ValueObjectSP CreateValueObjectFromBool(lldb::TargetSP target,
+ bool value,
+ llvm::StringRef name);
+
+ /// Create a nullptr value object with the specified type (must be a
+ /// nullptr type).
+ static lldb::ValueObjectSP CreateValueObjectFromNullptr(lldb::TargetSP target,
+ CompilerType type,
+ llvm::StringRef name);
+
lldb::ValueObjectSP Persist();
/// Returns true if this is a char* or a char[] if it is a char* and
@@ -719,6 +795,10 @@ public:
ClearUserVisibleData(eClearUserVisibleDataItemsSummary);
}
+ void SetDerefValobj(ValueObject *deref) { m_deref_valobj = deref; }
+
+ ValueObject *GetDerefValobj() { return m_deref_valobj; }
+
void SetValueFormat(lldb::TypeFormatImplSP format) {
m_type_format_sp = std::move(format);
ClearUserVisibleData(eClearUserVisibleDataItemsValue);
diff --git a/lldb/include/lldb/Utility/Scalar.h b/lldb/include/lldb/Utility/Scalar.h
index d715588..0d8eba3 100644
--- a/lldb/include/lldb/Utility/Scalar.h
+++ b/lldb/include/lldb/Utility/Scalar.h
@@ -181,6 +181,10 @@ public:
long double LongDouble(long double fail_value = 0.0) const;
+ llvm::APSInt GetAPSInt() const { return m_integer; }
+
+ llvm::APFloat GetAPFloat() const { return m_float; }
+
Status SetValueFromCString(const char *s, lldb::Encoding encoding,
size_t byte_size);
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index c53ec5a..9d7efba 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -1281,26 +1281,8 @@ lldb::addr_t SBValue::GetLoadAddress() {
lldb::addr_t value = LLDB_INVALID_ADDRESS;
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
- if (value_sp) {
- TargetSP target_sp(value_sp->GetTargetSP());
- if (target_sp) {
- const bool scalar_is_load_address = true;
- AddressType addr_type;
- value = value_sp->GetAddressOf(scalar_is_load_address, &addr_type);
- if (addr_type == eAddressTypeFile) {
- ModuleSP module_sp(value_sp->GetModule());
- if (!module_sp)
- value = LLDB_INVALID_ADDRESS;
- else {
- Address addr;
- module_sp->ResolveFileAddress(value, addr);
- value = addr.GetLoadAddress(target_sp.get());
- }
- } else if (addr_type == eAddressTypeHost ||
- addr_type == eAddressTypeInvalid)
- value = LLDB_INVALID_ADDRESS;
- }
- }
+ if (value_sp)
+ return value_sp->GetLoadAddress();
return value;
}
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index f32cb82..1c69145 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -1116,6 +1116,153 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) {
return fail_value;
}
+llvm::Expected<llvm::APSInt> ValueObject::GetValueAsAPSInt() {
+ // Make sure the type can be converted to an APSInt.
+ if (!GetCompilerType().IsInteger() &&
+ !GetCompilerType().IsScopedEnumerationType() &&
+ !GetCompilerType().IsEnumerationType() &&
+ !GetCompilerType().IsPointerType() &&
+ !GetCompilerType().IsNullPtrType() &&
+ !GetCompilerType().IsReferenceType() && !GetCompilerType().IsBoolean())
+ return llvm::make_error<llvm::StringError>(
+ "type cannot be converted to APSInt", llvm::inconvertibleErrorCode());
+
+ if (CanProvideValue()) {
+ Scalar scalar;
+ if (ResolveValue(scalar))
+ return scalar.GetAPSInt();
+ }
+
+ return llvm::make_error<llvm::StringError>(
+ "error occurred; unable to convert to APSInt",
+ llvm::inconvertibleErrorCode());
+}
+
+llvm::Expected<llvm::APFloat> ValueObject::GetValueAsAPFloat() {
+ if (!GetCompilerType().IsFloat())
+ return llvm::make_error<llvm::StringError>(
+ "type cannot be converted to APFloat", llvm::inconvertibleErrorCode());
+
+ if (CanProvideValue()) {
+ Scalar scalar;
+ if (ResolveValue(scalar))
+ return scalar.GetAPFloat();
+ }
+
+ return llvm::make_error<llvm::StringError>(
+ "error occurred; unable to convert to APFloat",
+ llvm::inconvertibleErrorCode());
+}
+
+llvm::Expected<bool> ValueObject::GetValueAsBool() {
+ CompilerType val_type = GetCompilerType();
+ if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() ||
+ val_type.IsPointerType()) {
+ auto value_or_err = GetValueAsAPSInt();
+ if (value_or_err)
+ return value_or_err->getBoolValue();
+ }
+ if (val_type.IsFloat()) {
+ auto value_or_err = GetValueAsAPFloat();
+ if (value_or_err)
+ return value_or_err->isNonZero();
+ }
+ if (val_type.IsArrayType())
+ return GetAddressOf() != 0;
+
+ return llvm::make_error<llvm::StringError>("type cannot be converted to bool",
+ llvm::inconvertibleErrorCode());
+}
+
+void ValueObject::SetValueFromInteger(const llvm::APInt &value, Status &error) {
+ // Verify the current object is an integer object
+ CompilerType val_type = GetCompilerType();
+ if (!val_type.IsInteger() && !val_type.IsUnscopedEnumerationType() &&
+ !val_type.IsFloat() && !val_type.IsPointerType() &&
+ !val_type.IsScalarType()) {
+ error.SetErrorString("current value object is not an integer objet");
+ return;
+ }
+
+ // Verify the current object is not actually associated with any program
+ // variable.
+ if (GetVariable()) {
+ error.SetErrorString("current value object is not a temporary object");
+ return;
+ }
+
+ // Verify the proposed new value is the right size.
+ lldb::TargetSP target = GetTargetSP();
+ uint64_t byte_size = 0;
+ if (auto temp = GetCompilerType().GetByteSize(target.get()))
+ byte_size = temp.value();
+ if (value.getBitWidth() != byte_size * CHAR_BIT) {
+ error.SetErrorString(
+ "illegal argument: new value should be of the same size");
+ return;
+ }
+
+ lldb::DataExtractorSP data_sp;
+ data_sp->SetData(value.getRawData(), byte_size,
+ target->GetArchitecture().GetByteOrder());
+ data_sp->SetAddressByteSize(
+ static_cast<uint8_t>(target->GetArchitecture().GetAddressByteSize()));
+ SetData(*data_sp, error);
+}
+
+void ValueObject::SetValueFromInteger(lldb::ValueObjectSP new_val_sp,
+ Status &error) {
+ // Verify the current object is an integer object
+ CompilerType val_type = GetCompilerType();
+ if (!val_type.IsInteger() && !val_type.IsUnscopedEnumerationType() &&
+ !val_type.IsFloat() && !val_type.IsPointerType() &&
+ !val_type.IsScalarType()) {
+ error.SetErrorString("current value object is not an integer objet");
+ return;
+ }
+
+ // Verify the current object is not actually associated with any program
+ // variable.
+ if (GetVariable()) {
+ error.SetErrorString("current value object is not a temporary object");
+ return;
+ }
+
+ // Verify the proposed new value is the right type.
+ CompilerType new_val_type = new_val_sp->GetCompilerType();
+ if (!new_val_type.IsInteger() && !new_val_type.IsFloat() &&
+ !new_val_type.IsPointerType()) {
+ error.SetErrorString(
+ "illegal argument: new value should be of the same size");
+ return;
+ }
+
+ if (new_val_type.IsInteger()) {
+ auto value_or_err = new_val_sp->GetValueAsAPSInt();
+ if (value_or_err)
+ SetValueFromInteger(*value_or_err, error);
+ else
+ error.SetErrorString("error getting APSInt from new_val_sp");
+ } else if (new_val_type.IsFloat()) {
+ auto value_or_err = new_val_sp->GetValueAsAPFloat();
+ if (value_or_err)
+ SetValueFromInteger(value_or_err->bitcastToAPInt(), error);
+ else
+ error.SetErrorString("error getting APFloat from new_val_sp");
+ } else if (new_val_type.IsPointerType()) {
+ bool success = true;
+ uint64_t int_val = new_val_sp->GetValueAsUnsigned(0, &success);
+ if (success) {
+ lldb::TargetSP target = GetTargetSP();
+ uint64_t num_bits = 0;
+ if (auto temp = new_val_sp->GetCompilerType().GetBitSize(target.get()))
+ num_bits = temp.value();
+ SetValueFromInteger(llvm::APInt(num_bits, int_val), error);
+ } else
+ error.SetErrorString("error converting new_val_sp to integer");
+ }
+}
+
// if any more "special cases" are added to
// ValueObject::DumpPrintableRepresentation() please keep this call up to date
// by returning true for your new special cases. We will eventually move to
@@ -2843,6 +2990,374 @@ ValueObjectSP ValueObject::CastPointerType(const char *name, TypeSP &type_sp) {
return valobj_sp;
}
+lldb::addr_t ValueObject::GetLoadAddress() {
+ lldb::addr_t addr_value = LLDB_INVALID_ADDRESS;
+ if (auto target_sp = GetTargetSP()) {
+ const bool scalar_is_load_address = true;
+ AddressType addr_type;
+ addr_value = GetAddressOf(scalar_is_load_address, &addr_type);
+ if (addr_type == eAddressTypeFile) {
+ lldb::ModuleSP module_sp(GetModule());
+ if (!module_sp)
+ addr_value = LLDB_INVALID_ADDRESS;
+ else {
+ Address tmp_addr;
+ module_sp->ResolveFileAddress(addr_value, tmp_addr);
+ addr_value = tmp_addr.GetLoadAddress(target_sp.get());
+ }
+ } else if (addr_type == eAddressTypeHost ||
+ addr_type == eAddressTypeInvalid)
+ addr_value = LLDB_INVALID_ADDRESS;
+ }
+ return addr_value;
+}
+
+llvm::Expected<lldb::ValueObjectSP> ValueObject::CastDerivedToBaseType(
+ CompilerType type, const llvm::ArrayRef<uint32_t> &base_type_indices) {
+ // Make sure the starting type and the target type are both valid for this
+ // type of cast; otherwise return the shared pointer to the original
+ // (unchanged) ValueObject.
+ if (!type.IsPointerType() && !type.IsReferenceType())
+ return llvm::make_error<llvm::StringError>(
+ "Invalid target type: should be a pointer or a reference",
+ llvm::inconvertibleErrorCode());
+
+ CompilerType start_type = GetCompilerType();
+ if (start_type.IsReferenceType())
+ start_type = start_type.GetNonReferenceType();
+
+ auto target_record_type =
+ type.IsPointerType() ? type.GetPointeeType() : type.GetNonReferenceType();
+ auto start_record_type =
+ start_type.IsPointerType() ? start_type.GetPointeeType() : start_type;
+
+ if (!target_record_type.IsRecordType() || !start_record_type.IsRecordType())
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be record types",
+ llvm::inconvertibleErrorCode());
+
+ if (target_record_type.CompareTypes(start_record_type))
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be different",
+ llvm::inconvertibleErrorCode());
+
+ if (base_type_indices.empty())
+ return llvm::make_error<llvm::StringError>(
+ "Children sequence must be non-empty", llvm::inconvertibleErrorCode());
+
+ // Both the starting & target types are valid for the cast, and the list of
+ // base class indices is non-empty, so we can proceed with the cast.
+
+ lldb::TargetSP target = GetTargetSP();
+ // The `value` can be a pointer, but GetChildAtIndex works for pointers too.
+ lldb::ValueObjectSP inner_value = GetSP();
+
+ for (const uint32_t i : base_type_indices)
+ // Create synthetic value if needed.
+ inner_value =
+ inner_value->GetChildAtIndex(i, /*can_create_synthetic*/ true);
+
+ // At this point type of `inner_value` should be the dereferenced target
+ // type.
+ CompilerType inner_value_type = inner_value->GetCompilerType();
+ if (type.IsPointerType()) {
+ if (!inner_value_type.CompareTypes(type.GetPointeeType()))
+ return llvm::make_error<llvm::StringError>(
+ "casted value doesn't match the desired type",
+ llvm::inconvertibleErrorCode());
+
+ uintptr_t addr = inner_value->GetLoadAddress();
+ llvm::StringRef name = "";
+ ExecutionContext exe_ctx(target.get(), false);
+ return ValueObject::CreateValueObjectFromAddress(name, addr, exe_ctx, type,
+ /* do deref */ false);
+ }
+
+ // At this point the target type should be a reference.
+ if (!inner_value_type.CompareTypes(type.GetNonReferenceType()))
+ return llvm::make_error<llvm::StringError>(
+ "casted value doesn't match the desired type",
+ llvm::inconvertibleErrorCode());
+
+ return lldb::ValueObjectSP(inner_value->Cast(type.GetNonReferenceType()));
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+ValueObject::CastBaseToDerivedType(CompilerType type, uint64_t offset) {
+ // Make sure the starting type and the target type are both valid for this
+ // type of cast; otherwise return the shared pointer to the original
+ // (unchanged) ValueObject.
+ if (!type.IsPointerType() && !type.IsReferenceType())
+ return llvm::make_error<llvm::StringError>(
+ "Invalid target type: should be a pointer or a reference",
+ llvm::inconvertibleErrorCode());
+
+ CompilerType start_type = GetCompilerType();
+ if (start_type.IsReferenceType())
+ start_type = start_type.GetNonReferenceType();
+
+ auto target_record_type =
+ type.IsPointerType() ? type.GetPointeeType() : type.GetNonReferenceType();
+ auto start_record_type =
+ start_type.IsPointerType() ? start_type.GetPointeeType() : start_type;
+
+ if (!target_record_type.IsRecordType() || !start_record_type.IsRecordType())
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be record types",
+ llvm::inconvertibleErrorCode());
+
+ if (target_record_type.CompareTypes(start_record_type))
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be different",
+ llvm::inconvertibleErrorCode());
+
+ CompilerType virtual_base;
+ if (target_record_type.IsVirtualBase(start_record_type, &virtual_base)) {
+ if (!virtual_base.IsValid())
+ return llvm::make_error<llvm::StringError>(
+ "virtual base should be valid", llvm::inconvertibleErrorCode());
+ return llvm::make_error<llvm::StringError>(
+ llvm::Twine("cannot cast " + start_type.TypeDescription() + " to " +
+ type.TypeDescription() + " via virtual base " +
+ virtual_base.TypeDescription()),
+ llvm::inconvertibleErrorCode());
+ }
+
+ // Both the starting & target types are valid for the cast, so we can
+ // proceed with the cast.
+
+ lldb::TargetSP target = GetTargetSP();
+ auto pointer_type =
+ type.IsPointerType() ? type : type.GetNonReferenceType().GetPointerType();
+
+ uintptr_t addr =
+ type.IsPointerType() ? GetValueAsUnsigned(0) : GetLoadAddress();
+
+ llvm::StringRef name = "";
+ ExecutionContext exe_ctx(target.get(), false);
+ lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromAddress(
+ name, addr - offset, exe_ctx, pointer_type, /* do_deref */ false);
+
+ if (type.IsPointerType())
+ return value;
+
+ // At this point the target type is a reference. Since `value` is a pointer,
+ // it has to be dereferenced.
+ Status error;
+ return value->Dereference(error);
+}
+
+lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) {
+ bool is_scalar = GetCompilerType().IsScalarType();
+ bool is_enum = GetCompilerType().IsEnumerationType();
+ bool is_pointer =
+ GetCompilerType().IsPointerType() || GetCompilerType().IsNullPtrType();
+ bool is_float = GetCompilerType().IsFloat();
+ bool is_integer = GetCompilerType().IsInteger();
+
+ if (!type.IsScalarType()) {
+ m_error.SetErrorString("target type must be a scalar");
+ return GetSP();
+ }
+
+ if (!is_scalar && !is_enum && !is_pointer) {
+ m_error.SetErrorString("argument must be a scalar, enum, or pointer");
+ return GetSP();
+ }
+
+ lldb::TargetSP target = GetTargetSP();
+ uint64_t type_byte_size = 0;
+ uint64_t val_byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ type_byte_size = temp.value();
+ if (auto temp = GetCompilerType().GetByteSize(target.get()))
+ val_byte_size = temp.value();
+
+ if (is_pointer) {
+ if (!type.IsInteger() && !type.IsBoolean()) {
+ m_error.SetErrorString("target type must be an integer or boolean");
+ return GetSP();
+ }
+ if (!type.IsBoolean() && type_byte_size < val_byte_size) {
+ m_error.SetErrorString(
+ "target type cannot be smaller than the pointer type");
+ return GetSP();
+ }
+ }
+
+ if (type.IsBoolean()) {
+ if (!is_scalar || is_integer)
+ return ValueObject::CreateValueObjectFromBool(
+ target, GetValueAsUnsigned(0) != 0, "result");
+ else if (is_scalar && is_float) {
+ auto float_value_or_err = GetValueAsAPFloat();
+ if (float_value_or_err)
+ return ValueObject::CreateValueObjectFromBool(
+ target, !float_value_or_err->isZero(), "result");
+ else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APFloat: %s",
+ llvm::toString(float_value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ }
+ }
+
+ if (type.IsInteger()) {
+ if (!is_scalar || is_integer) {
+ auto int_value_or_err = GetValueAsAPSInt();
+ if (int_value_or_err) {
+ // Get the value as APSInt and extend or truncate it to the requested
+ // size.
+ llvm::APSInt ext =
+ int_value_or_err->extOrTrunc(type_byte_size * CHAR_BIT);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
+ "result");
+ } else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(int_value_or_err.takeError()).c_str());
+ ;
+ return GetSP();
+ }
+ } else if (is_scalar && is_float) {
+ llvm::APSInt integer(type_byte_size * CHAR_BIT, !type.IsSigned());
+ bool is_exact;
+ auto float_value_or_err = GetValueAsAPFloat();
+ if (float_value_or_err) {
+ llvm::APFloatBase::opStatus status =
+ float_value_or_err->convertToInteger(
+ integer, llvm::APFloat::rmTowardZero, &is_exact);
+
+ // Casting floating point values that are out of bounds of the target
+ // type is undefined behaviour.
+ if (status & llvm::APFloatBase::opInvalidOp) {
+ m_error.SetErrorStringWithFormat(
+ "invalid type cast detected: %s",
+ llvm::toString(float_value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
+ "result");
+ }
+ }
+ }
+
+ if (type.IsFloat()) {
+ if (!is_scalar) {
+ auto int_value_or_err = GetValueAsAPSInt();
+ if (int_value_or_err) {
+ llvm::APSInt ext =
+ int_value_or_err->extOrTrunc(type_byte_size * CHAR_BIT);
+ Scalar scalar_int(ext);
+ llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+ "result");
+ } else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(int_value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ } else {
+ if (is_integer) {
+ auto int_value_or_err = GetValueAsAPSInt();
+ if (int_value_or_err) {
+ Scalar scalar_int(*int_value_or_err);
+ llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+ "result");
+ } else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(int_value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ }
+ if (is_float) {
+ auto float_value_or_err = GetValueAsAPFloat();
+ if (float_value_or_err) {
+ Scalar scalar_float(*float_value_or_err);
+ llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+ "result");
+ } else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APFloat: %s",
+ llvm::toString(float_value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ }
+ }
+ }
+
+ m_error.SetErrorString("Unable to perform requested cast");
+ return GetSP();
+}
+
+lldb::ValueObjectSP ValueObject::CastToEnumType(CompilerType type) {
+ bool is_enum = GetCompilerType().IsEnumerationType();
+ bool is_integer = GetCompilerType().IsInteger();
+ bool is_float = GetCompilerType().IsFloat();
+
+ if (!is_enum && !is_integer && !is_float) {
+ m_error.SetErrorString("argument must be an integer, a float, or an enum");
+ return GetSP();
+ }
+
+ if (!type.IsEnumerationType()) {
+ m_error.SetErrorString("target type must be an enum");
+ return GetSP();
+ }
+
+ lldb::TargetSP target = GetTargetSP();
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+
+ if (is_float) {
+ llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
+ bool is_exact;
+ auto value_or_err = GetValueAsAPFloat();
+ if (value_or_err) {
+ llvm::APFloatBase::opStatus status = value_or_err->convertToInteger(
+ integer, llvm::APFloat::rmTowardZero, &is_exact);
+
+ // Casting floating point values that are out of bounds of the target
+ // type is undefined behaviour.
+ if (status & llvm::APFloatBase::opInvalidOp) {
+ m_error.SetErrorStringWithFormat(
+ "invalid type cast detected: %s",
+ llvm::toString(value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
+ "result");
+ } else {
+ m_error.SetErrorString("cannot get value as APFloat");
+ return GetSP();
+ }
+ } else {
+ // Get the value as APSInt and extend or truncate it to the requested size.
+ auto value_or_err = GetValueAsAPSInt();
+ if (value_or_err) {
+ llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
+ "result");
+ } else {
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(value_or_err.takeError()).c_str());
+ return GetSP();
+ }
+ }
+ m_error.SetErrorString("Cannot perform requested cast");
+ return GetSP();
+}
+
ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {}
ValueObject::EvaluationPoint::EvaluationPoint(ExecutionContextScope *exe_scope,
@@ -3028,9 +3543,11 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromExpression(
lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
- CompilerType type) {
+ CompilerType type, bool do_deref) {
if (type) {
CompilerType pointer_type(type.GetPointerType());
+ if (!do_deref)
+ pointer_type = type;
if (pointer_type) {
lldb::DataBufferSP buffer(
new lldb_private::DataBufferHeap(&address, sizeof(lldb::addr_t)));
@@ -3039,10 +3556,12 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
ConstString(name), buffer, exe_ctx.GetByteOrder(),
exe_ctx.GetAddressByteSize()));
if (ptr_result_valobj_sp) {
- ptr_result_valobj_sp->GetValue().SetValueType(
- Value::ValueType::LoadAddress);
+ if (do_deref)
+ ptr_result_valobj_sp->GetValue().SetValueType(
+ Value::ValueType::LoadAddress);
Status err;
- ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
+ if (do_deref)
+ ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
if (ptr_result_valobj_sp && !name.empty())
ptr_result_valobj_sp->SetName(ConstString(name));
}
@@ -3065,6 +3584,66 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromData(
return new_value_sp;
}
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromAPInt(lldb::TargetSP target,
+ const llvm::APInt &v, CompilerType type,
+ llvm::StringRef name) {
+ ExecutionContext exe_ctx(target.get(), false);
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+ reinterpret_cast<const void *>(v.getRawData()), byte_size,
+ exe_ctx.GetByteOrder(), exe_ctx.GetAddressByteSize());
+ return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type);
+}
+
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPFloat(
+ lldb::TargetSP target, const llvm::APFloat &v, CompilerType type,
+ llvm::StringRef name) {
+ return CreateValueObjectFromAPInt(target, v.bitcastToAPInt(), type, name);
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromBool(lldb::TargetSP target, bool value,
+ llvm::StringRef name) {
+ CompilerType target_type;
+ if (target) {
+ for (auto type_system_sp : target->GetScratchTypeSystems())
+ if (auto compiler_type =
+ type_system_sp->GetBasicTypeFromAST(lldb::eBasicTypeBool)) {
+ target_type = compiler_type;
+ break;
+ }
+ }
+ ExecutionContext exe_ctx(target.get(), false);
+ uint64_t byte_size = 0;
+ if (auto temp = target_type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+ reinterpret_cast<const void *>(&value), byte_size, exe_ctx.GetByteOrder(),
+ exe_ctx.GetAddressByteSize());
+ return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx,
+ target_type);
+}
+
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromNullptr(
+ lldb::TargetSP target, CompilerType type, llvm::StringRef name) {
+ if (!type.IsNullPtrType()) {
+ lldb::ValueObjectSP ret_val;
+ return ret_val;
+ }
+ uintptr_t zero = 0;
+ ExecutionContext exe_ctx(target.get(), false);
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+ reinterpret_cast<const void *>(zero), byte_size, exe_ctx.GetByteOrder(),
+ exe_ctx.GetAddressByteSize());
+ return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type);
+}
+
ModuleSP ValueObject::GetModule() {
ValueObject *root(GetRoot());
if (root != this)