[Lldb-commits] [lldb] [lldb] Don't crash when attempting to parse breakpoint id `N.` as `N.*` (PR #87263)
https://github.com/rupprecht created https://github.com/llvm/llvm-project/pull/87263 We check if the next character after `N.` is `*` before we check its length. Using `split` on the string is cleaner and less error prone than using indices with `find` and `substr`. Note: this does not make `N.` mean anything, it just prevents assertion failures. `N.` is treated the same as an unrecognized breakpoint name: ``` (lldb) breakpoint enable 1 1 breakpoints enabled. (lldb) breakpoint enable 1.* 1 breakpoints enabled. (lldb) breakpoint enable 1. 0 breakpoints enabled. (lldb) breakpoint enable xyz 0 breakpoints enabled. ``` Found via LLDB fuzzers. >From dc0aac066ec882d564dfc09acfae4b3dca5c8091 Mon Sep 17 00:00:00 2001 From: Jordan Rupprecht Date: Mon, 1 Apr 2024 16:44:09 + Subject: [PATCH] [lldb] Don't crash when attempting to parse breakpoint id `N.` as `N.*` We check if the next character after `N.` is `*` before we check its length. Using `split` on the string is cleaner and less error prone than using indices with `find` and `substr`. Note: this does not make `N.` mean anything, it just prevents assertion failures. `N.` is treated the same as an unrecognized breakpoint name: ``` (lldb) breakpoint enable 1 1 breakpoints enabled. (lldb) breakpoint enable 1.* 1 breakpoints enabled. (lldb) breakpoint enable 1. 0 breakpoints enabled. (lldb) breakpoint enable xyz 0 breakpoints enabled. ``` Found via LLDB fuzzers. --- lldb/source/Breakpoint/BreakpointIDList.cpp | 48 +-- .../TestBreakpointLocations.py| 6 +++ 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/lldb/source/Breakpoint/BreakpointIDList.cpp b/lldb/source/Breakpoint/BreakpointIDList.cpp index 851d074e753588..97af1d40eb7a58 100644 --- a/lldb/source/Breakpoint/BreakpointIDList.cpp +++ b/lldb/source/Breakpoint/BreakpointIDList.cpp @@ -16,6 +16,7 @@ #include "lldb/Utility/StreamString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" using namespace lldb; using namespace lldb_private; @@ -111,32 +112,27 @@ llvm::Error BreakpointIDList::FindAndReplaceIDRanges( } else { // See if user has specified id.* llvm::StringRef tmp_str = old_args[i].ref(); - size_t pos = tmp_str.find('.'); - if (pos != llvm::StringRef::npos) { -llvm::StringRef bp_id_str = tmp_str.substr(0, pos); -if (BreakpointID::IsValidIDExpression(bp_id_str) && -tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) { - - BreakpointSP breakpoint_sp; - auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str); - if (bp_id) -breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID()); - if (!breakpoint_sp) { -new_args.Clear(); -return llvm::createStringError( -llvm::inconvertibleErrorCode(), -"'%d' is not a valid breakpoint ID.\n", -bp_id->GetBreakpointID()); - } - const size_t num_locations = breakpoint_sp->GetNumLocations(); - for (size_t j = 0; j < num_locations; ++j) { -BreakpointLocation *bp_loc = -breakpoint_sp->GetLocationAtIndex(j).get(); -StreamString canonical_id_str; -BreakpointID::GetCanonicalReference( -&canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID()); -new_args.AppendArgument(canonical_id_str.GetString()); - } + auto [prefix, suffix] = tmp_str.split('.'); + if (suffix == "*" && BreakpointID::IsValidIDExpression(prefix)) { + +BreakpointSP breakpoint_sp; +auto bp_id = BreakpointID::ParseCanonicalReference(prefix); +if (bp_id) + breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID()); +if (!breakpoint_sp) { + new_args.Clear(); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "'%d' is not a valid breakpoint ID.\n", + bp_id->GetBreakpointID()); +} +const size_t num_locations = breakpoint_sp->GetNumLocations(); +for (size_t j = 0; j < num_locations; ++j) { + BreakpointLocation *bp_loc = + breakpoint_sp->GetLocationAtIndex(j).get(); + StreamString canonical_id_str; + BreakpointID::GetCanonicalReference( + &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID()); + new_args.AppendArgument(canonical_id_str.GetString()); } } } diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py b/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py index 8930bea619bb6e..d87e6275f7b51e 100644 --- a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py +++ b/lldb/test/API/functionalities/breakpoin
[Lldb-commits] [lldb] [lldb] Don't crash when attempting to parse breakpoint id `N.` as `N.*` (PR #87263)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jordan Rupprecht (rupprecht) Changes We check if the next character after `N.` is `*` before we check its length. Using `split` on the string is cleaner and less error prone than using indices with `find` and `substr`. Note: this does not make `N.` mean anything, it just prevents assertion failures. `N.` is treated the same as an unrecognized breakpoint name: ``` (lldb) breakpoint enable 1 1 breakpoints enabled. (lldb) breakpoint enable 1.* 1 breakpoints enabled. (lldb) breakpoint enable 1. 0 breakpoints enabled. (lldb) breakpoint enable xyz 0 breakpoints enabled. ``` Found via LLDB fuzzers. --- Full diff: https://github.com/llvm/llvm-project/pull/87263.diff 2 Files Affected: - (modified) lldb/source/Breakpoint/BreakpointIDList.cpp (+22-26) - (modified) lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py (+6) ``diff diff --git a/lldb/source/Breakpoint/BreakpointIDList.cpp b/lldb/source/Breakpoint/BreakpointIDList.cpp index 851d074e753588..97af1d40eb7a58 100644 --- a/lldb/source/Breakpoint/BreakpointIDList.cpp +++ b/lldb/source/Breakpoint/BreakpointIDList.cpp @@ -16,6 +16,7 @@ #include "lldb/Utility/StreamString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" using namespace lldb; using namespace lldb_private; @@ -111,32 +112,27 @@ llvm::Error BreakpointIDList::FindAndReplaceIDRanges( } else { // See if user has specified id.* llvm::StringRef tmp_str = old_args[i].ref(); - size_t pos = tmp_str.find('.'); - if (pos != llvm::StringRef::npos) { -llvm::StringRef bp_id_str = tmp_str.substr(0, pos); -if (BreakpointID::IsValidIDExpression(bp_id_str) && -tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) { - - BreakpointSP breakpoint_sp; - auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str); - if (bp_id) -breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID()); - if (!breakpoint_sp) { -new_args.Clear(); -return llvm::createStringError( -llvm::inconvertibleErrorCode(), -"'%d' is not a valid breakpoint ID.\n", -bp_id->GetBreakpointID()); - } - const size_t num_locations = breakpoint_sp->GetNumLocations(); - for (size_t j = 0; j < num_locations; ++j) { -BreakpointLocation *bp_loc = -breakpoint_sp->GetLocationAtIndex(j).get(); -StreamString canonical_id_str; -BreakpointID::GetCanonicalReference( -&canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID()); -new_args.AppendArgument(canonical_id_str.GetString()); - } + auto [prefix, suffix] = tmp_str.split('.'); + if (suffix == "*" && BreakpointID::IsValidIDExpression(prefix)) { + +BreakpointSP breakpoint_sp; +auto bp_id = BreakpointID::ParseCanonicalReference(prefix); +if (bp_id) + breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID()); +if (!breakpoint_sp) { + new_args.Clear(); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "'%d' is not a valid breakpoint ID.\n", + bp_id->GetBreakpointID()); +} +const size_t num_locations = breakpoint_sp->GetNumLocations(); +for (size_t j = 0; j < num_locations; ++j) { + BreakpointLocation *bp_loc = + breakpoint_sp->GetLocationAtIndex(j).get(); + StreamString canonical_id_str; + BreakpointID::GetCanonicalReference( + &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID()); + new_args.AppendArgument(canonical_id_str.GetString()); } } } diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py b/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py index 8930bea619bb6e..d87e6275f7b51e 100644 --- a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py @@ -293,6 +293,12 @@ def breakpoint_locations_test(self): startstr="3 breakpoints enabled.", ) +# The 'breakpoint enable 1.' command should not crash. +self.expect( +"breakpoint enable 1.", +startstr="0 breakpoints enabled.", +) + # The 'breakpoint disable 1.1' command should disable 1 location. self.expect( "breakpoint disable 1.1", `` https://github.com/llvm/llvm-project/pull/87263 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/m
[Lldb-commits] [lldb] [lldb] Don't crash when attempting to parse breakpoint id `N.` as `N.*` (PR #87263)
https://github.com/jimingham approved this pull request. LGMT https://github.com/llvm/llvm-project/pull/87263 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -441,6 +441,19 @@ class ValueObject { virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr); + llvm::APSInt GetValueAsAPSInt(); jimingham wrote: Not all SBValues are representable as Int's or Floats, Bool's etc. But I don't see any way to report errors with these new API's. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -618,6 +631,24 @@ class ValueObject { virtual lldb::ValueObjectSP CastPointerType(const char *name, lldb::TypeSP &type_sp); + /// Return the target load address assocaited with this value object. + lldb::addr_t GetLoadAddress(); + + lldb::ValueObjectSP CastDerivedToBaseType(CompilerType type, +const std::vector &idx); + + lldb::ValueObjectSP CastBaseToDerivedType(CompilerType type, uint64_t offset); + + lldb::ValueObjectSP CastScalarToBasicType(CompilerType type, Status &error); + + lldb::ValueObjectSP CastEnumToBasicType(CompilerType type); + + lldb::ValueObjectSP CastPointerToBasicType(CompilerType type); + + lldb::ValueObjectSP CastIntegerOrEnumToEnumType(CompilerType type); + + lldb::ValueObjectSP CastFloatToEnumType(CompilerType type, Status &error); jimingham wrote: You don't need an error parameter for anything that returns a ValueObject. ValueObjects carry their errors in the ValueObject (ValueObject::GetError()). https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -668,6 +699,32 @@ class ValueObject { CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type); + static lldb::ValueObjectSP jimingham wrote: Given targets can be big or little-endian, I'm a little worried about a "const void *bytes" that says nothing about what is in the bytes. This is what DataBuffer's are for, why couldn't you use them? https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -441,6 +441,19 @@ class ValueObject { virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr); + llvm::APSInt GetValueAsAPSInt(); adrian-prantl wrote: if these errors matter to users then `llvm::Expected` would be the right choice. Otherwise std::optional is the way to go. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -441,6 +441,19 @@ class ValueObject { virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr); + llvm::APSInt GetValueAsAPSInt(); + + llvm::APFloat GetValueAsFloat(); adrian-prantl wrote: same here https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -441,6 +441,19 @@ class ValueObject { virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr); + llvm::APSInt GetValueAsAPSInt(); + + llvm::APFloat GetValueAsFloat(); + + bool GetValueAsBool(); adrian-prantl wrote: same here https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -668,6 +699,32 @@ class ValueObject { CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type); + static lldb::ValueObjectSP + CreateValueObjectFromBytes(lldb::TargetSP target_sp, const void *bytes, + CompilerType type); + + static lldb::ValueObjectSP CreateValueObjectFromBytes(lldb::TargetSP target, adrian-prantl wrote: These functions could all benefit from Doxygen comments. If we can use a StringRef, or DataExtractor/Buffer instead a raw pointer, that would likely also be safer. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -668,6 +699,32 @@ class ValueObject { CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type); + static lldb::ValueObjectSP + CreateValueObjectFromBytes(lldb::TargetSP target_sp, const void *bytes, + CompilerType type); + + static lldb::ValueObjectSP CreateValueObjectFromBytes(lldb::TargetSP target, +const void *bytes, +lldb::BasicType type); + + static lldb::ValueObjectSP CreateValueObjectFromAPInt(lldb::TargetSP target, +const llvm::APInt &v, +CompilerType type); + + static lldb::ValueObjectSP + CreateValueObjectFromAPFloat(lldb::TargetSP target, const llvm::APFloat &v, + CompilerType type); + + static lldb::ValueObjectSP CreateValueObjectFromPointer(lldb::TargetSP target, jimingham wrote: How is this different from CreateValueObjectFromAddress? https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -719,6 +776,10 @@ class ValueObject { ClearUserVisibleData(eClearUserVisibleDataItemsSummary); } + void SetDerefValobj(ValueObject *deref) { m_deref_valobj = deref; } jimingham wrote: Synthetic child providers also have a way to provide the deref ValueObject dynamically. How do these two ways of doing that job work together? https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
https://github.com/bulbazord edited https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
https://github.com/bulbazord requested changes to this pull request. +1 to all of Jim and Adrian's comments. High level comments: 1. I'm a little concerned about the use of assertions in this patch. I generally like assertions when they are used to assert internal consistency. It looks like you're using them as an error-checking and parameter-checking mechanism. This seems pretty fragile, especially since it will be difficult to enforce that these functions are called "correctly" in all cases from all contributors. 2. There isn't a lot of documentation. It would be helpful to know the expected behavior for a lot of these methods (especially for people like me who aren't super familiar with the ValueObject class and all of its tendrils). 3. Is there a way you can add some tests for the new functionality? I'm not sure how you could trigger these new methods from an API test, but a unit test might be possible? https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); +} + +llvm::APFloat ValueObject::GetValueAsFloat() { bulbazord wrote: 2 issues and a small nitpick: Nit: The name could be `GetValueAsAPFloat` to differentiate between it and a potential function that would return a `float`/`double`? 1. I don't think assertions are the right way to make sure we have good data. `GetData` has error handling through its `Status &` out parameter, we should handle that appropriately instead of asserting that we got good data. What happens when we compile out the assertions for release builds? Reading data from the `DataExtractor` will fail and crash regardless. 2. This function has no way of returning a value that would indicate failure. Suggestion: Return `std::optional` or `llvm::Expected`. There's no way to return an invalid `APFloat` from looking at the header, so that doesn't appear to be an option. Then if any of the steps fail, you can return either `std::nullopt` or an appropriate `llvm::Error`. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -618,6 +631,24 @@ class ValueObject { virtual lldb::ValueObjectSP CastPointerType(const char *name, lldb::TypeSP &type_sp); + /// Return the target load address assocaited with this value object. bulbazord wrote: typo: `associated` https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); +} + +llvm::APFloat ValueObject::GetValueAsFloat() { + lldb::BasicType basic_type = + GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration(); + lldb::DataExtractorSP data_sp(new DataExtractor()); + Status error; + + switch (basic_type) { + case lldb::eBasicTypeFloat: { +float v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read float data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + case lldb::eBasicTypeDouble: +// No way to get more precision at the moment. + case lldb::eBasicTypeLongDouble: { +double v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read long double data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + default: +return llvm::APFloat(NAN); bulbazord wrote: Where is `NAN` coming from? I don't see it in this file or the `APFloat` header. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); +} + +llvm::APFloat ValueObject::GetValueAsFloat() { + lldb::BasicType basic_type = + GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration(); + lldb::DataExtractorSP data_sp(new DataExtractor()); + Status error; + + switch (basic_type) { + case lldb::eBasicTypeFloat: { +float v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read float data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + case lldb::eBasicTypeDouble: +// No way to get more precision at the moment. + case lldb::eBasicTypeLongDouble: { +double v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read long double data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + default: +return llvm::APFloat(NAN); + } +} + +bool ValueObject::GetValueAsBool() { + CompilerType val_type = GetCompilerType(); + if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() || + val_type.IsPointerType()) { +return GetValueAsAPSInt().getBoolValue(); + } + if (val_type.IsFloat()) { +return GetValueAsFloat().isNonZero(); + } + if (val_type.IsArrayType()) { +lldb::ValueObjectSP new_val = +ValueObject::ValueObject::CreateValueObjectFromAddress( +GetName().GetStringRef(), GetAddressOf(), GetExecutionContextRef(), +val_type); +return new_val->GetValueAsUnsigned(0) != 0; + } + return false; +} + +void ValueObject::UpdateIntegerValue(const llvm::APInt &value) { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + assert(value.getBitWidth() == byte_size * CHAR_BIT && + "illegal argument: new value should be of the same size"); + + lldb::DataExtractorSP data_sp; + Status error; + data_sp->SetData(value.getRawData(), byte_size, + target->GetArchitecture().GetByteOrder()); + data_sp->SetAddressByteSize( + static_cast(target->GetArchitecture().GetAddressByteSize())); + SetData(*data_sp, error); +} + +void ValueObject::UpdateIntegerValue(lldb::ValueObjectSP new_val_sp) { + CompilerType new_val_type = new_val_sp->GetCompilerType(); + assert((new_val_type.IsInteger() || new_val_type.IsFloat() || + new_val_type.IsPointerType()) && + "illegal argument: new value should be of the same size"); + + if (new_val_type.IsInteger()) { +UpdateIntegerValue(new_val_sp->GetValueAsAPSInt()); + } else if (new_val_type.IsFloat()) { +UpdateIntegerValue(new_val_sp->GetValueAsFloat().bitcastToAPInt()); + } else if (new_val_type.IsPointerType()) { +UpdateIntegerValue(llvm::APInt(64, new_val_sp->GetValueAsUnsigned(0))); bulbazord wrote: Is there a way we can get the width of a pointer type? 64 will work on most platforms, but there are definitely 32-bit platforms (e.g. ARM) that may want to use this code. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); bulbazord wrote: If `GetValueAsUnsigned` fails, this will give you an `APSInt` that looks like 0, meaning there's no way to distinguish between a `ValueObject` that represents 0 and a failure value. Suggestion: Either return an invalid `APSInt` (via default constructor) or return a `std::optional` or `llvm::Expected` if you want an error message back. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -2809,6 +2919,243 @@ 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; + lldb::TargetSP target_sp = GetTargetSP(); + if (target_sp) { +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 == eAddressTypeHost) + addr_value = LLDB_INVALID_ADDRESS; + } + return addr_value; +} + +lldb::ValueObjectSP +ValueObject::CastDerivedToBaseType(CompilerType type, + const std::vector &idx) { + + lldb::TargetSP target = GetTargetSP(); + assert((type.IsPointerType() || type.IsReferenceType()) && + "invalid ast: target type should be a pointer or a reference"); + assert(!idx.empty() && "invalid ast: children sequence should be non-empty"); + + // The `value` can be a pointer, but GetChildAtIndex works for pointers too. + lldb::ValueObjectSP inner_value; + + for (const uint32_t i : idx) { +// Force static value, otherwise we can end up with the "real" type. +inner_value = GetChildAtIndex(i, /*can_create_synthetic*/ false); + } + + // At this point type of `inner_value` should be the dereferenced target type. + CompilerType inner_value_type = inner_value->GetCompilerType(); + if (type.IsPointerType()) { +assert(inner_value_type.CompareTypes(type.GetPointeeType()) && + "casted value doesn't match the desired type"); + +uintptr_t addr = inner_value->GetLoadAddress(); +return ValueObject::CreateValueObjectFromPointer(target, addr, type); + } + + // At this point the target type should be a reference. + assert(inner_value_type.CompareTypes(type.GetNonReferenceType()) && + "casted value doesn't match the desired type"); + + return lldb::ValueObjectSP(inner_value->Cast(type.GetNonReferenceType())); +} + +lldb::ValueObjectSP ValueObject::CastBaseToDerivedType(CompilerType type, + uint64_t offset) { + lldb::TargetSP target = GetTargetSP(); + + assert((type.IsPointerType() || type.IsReferenceType()) && + "invalid ast: target type should be a pointer or a reference"); + + auto pointer_type = + type.IsPointerType() ? type : type.GetNonReferenceType().GetPointerType(); + + uintptr_t addr = + type.IsPointerType() ? GetValueAsUnsigned(0) : GetLoadAddress(); + + lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromPointer( + target, addr - offset, pointer_type); + + 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::CastScalarToBasicType(CompilerType type, + Status &error) { + assert(type.IsScalarType() && "target type must be an scalar"); + assert(GetCompilerType().IsScalarType() && "argument must be a scalar"); + + lldb::TargetSP target = GetTargetSP(); + if (type.IsBoolean()) { +if (GetCompilerType().IsInteger()) { + return ValueObject::CreateValueObjectFromBool(target, +GetValueAsUnsigned(0) != 0); +} +if (GetCompilerType().IsFloat()) { + return ValueObject::CreateValueObjectFromBool( + target, !GetValueAsFloat().isZero()); +} + } + if (type.IsInteger()) { +if (GetCompilerType().IsInteger()) { + uint64_t byte_size = 0; + if (auto temp = type.GetByteSize(target.get())) +byte_size = temp.value(); + llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT); + return ValueObject::CreateValueObjectFromAPInt(target, ext, type); +} +if (GetCompilerType().IsFloat()) { + uint64_t byte_size = 0; + if (auto temp = type.GetByteSize(target.get())) +byte_size = temp.value(); + llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned()); + bool is_exact; + llvm::APFloatBase::opStatus status = GetValueAsFloat().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) { +error.SetErrorString("invalid type cast detected"); + } + + return ValueObject::CreateValueObjectFromAPInt(
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); +} + +llvm::APFloat ValueObject::GetValueAsFloat() { + lldb::BasicType basic_type = + GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration(); + lldb::DataExtractorSP data_sp(new DataExtractor()); + Status error; + + switch (basic_type) { + case lldb::eBasicTypeFloat: { +float v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read float data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + case lldb::eBasicTypeDouble: +// No way to get more precision at the moment. + case lldb::eBasicTypeLongDouble: { +double v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read long double data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + default: +return llvm::APFloat(NAN); + } +} + +bool ValueObject::GetValueAsBool() { + CompilerType val_type = GetCompilerType(); + if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() || + val_type.IsPointerType()) { +return GetValueAsAPSInt().getBoolValue(); + } + if (val_type.IsFloat()) { +return GetValueAsFloat().isNonZero(); + } + if (val_type.IsArrayType()) { +lldb::ValueObjectSP new_val = +ValueObject::ValueObject::CreateValueObjectFromAddress( +GetName().GetStringRef(), GetAddressOf(), GetExecutionContextRef(), +val_type); +return new_val->GetValueAsUnsigned(0) != 0; + } + return false; +} + +void ValueObject::UpdateIntegerValue(const llvm::APInt &value) { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + assert(value.getBitWidth() == byte_size * CHAR_BIT && + "illegal argument: new value should be of the same size"); + + lldb::DataExtractorSP data_sp; + Status error; + data_sp->SetData(value.getRawData(), byte_size, + target->GetArchitecture().GetByteOrder()); + data_sp->SetAddressByteSize( + static_cast(target->GetArchitecture().GetAddressByteSize())); + SetData(*data_sp, error); +} + +void ValueObject::UpdateIntegerValue(lldb::ValueObjectSP new_val_sp) { + CompilerType new_val_type = new_val_sp->GetCompilerType(); + assert((new_val_type.IsInteger() || new_val_type.IsFloat() || + new_val_type.IsPointerType()) && + "illegal argument: new value should be of the same size"); bulbazord wrote: Same as above for this assertion. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -2809,6 +2919,243 @@ 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; + lldb::TargetSP target_sp = GetTargetSP(); + if (target_sp) { +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 == eAddressTypeHost) + addr_value = LLDB_INVALID_ADDRESS; + } + return addr_value; +} + +lldb::ValueObjectSP +ValueObject::CastDerivedToBaseType(CompilerType type, + const std::vector &idx) { + + lldb::TargetSP target = GetTargetSP(); + assert((type.IsPointerType() || type.IsReferenceType()) && + "invalid ast: target type should be a pointer or a reference"); + assert(!idx.empty() && "invalid ast: children sequence should be non-empty"); bulbazord wrote: Same for these assertions as above. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -618,6 +631,24 @@ class ValueObject { virtual lldb::ValueObjectSP CastPointerType(const char *name, lldb::TypeSP &type_sp); + /// Return the target load address assocaited with this value object. + lldb::addr_t GetLoadAddress(); + + lldb::ValueObjectSP CastDerivedToBaseType(CompilerType type, +const std::vector &idx); + + lldb::ValueObjectSP CastBaseToDerivedType(CompilerType type, uint64_t offset); + + lldb::ValueObjectSP CastScalarToBasicType(CompilerType type, Status &error); + + lldb::ValueObjectSP CastEnumToBasicType(CompilerType type); + + lldb::ValueObjectSP CastPointerToBasicType(CompilerType type); + + lldb::ValueObjectSP CastIntegerOrEnumToEnumType(CompilerType type); + + lldb::ValueObjectSP CastFloatToEnumType(CompilerType type, Status &error); bulbazord wrote: Can you add some doxygen comments to these methods? It would help clarify the intent behind them as well as the purpose of some of the parameter (e.g. What does `idx` correspond to in `CastDerivedToBaseType`?) https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -2809,6 +2919,243 @@ 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; + lldb::TargetSP target_sp = GetTargetSP(); + if (target_sp) { +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 == eAddressTypeHost) + addr_value = LLDB_INVALID_ADDRESS; + } + return addr_value; +} + +lldb::ValueObjectSP +ValueObject::CastDerivedToBaseType(CompilerType type, + const std::vector &idx) { + + lldb::TargetSP target = GetTargetSP(); + assert((type.IsPointerType() || type.IsReferenceType()) && + "invalid ast: target type should be a pointer or a reference"); + assert(!idx.empty() && "invalid ast: children sequence should be non-empty"); + + // The `value` can be a pointer, but GetChildAtIndex works for pointers too. + lldb::ValueObjectSP inner_value; + + for (const uint32_t i : idx) { +// Force static value, otherwise we can end up with the "real" type. +inner_value = GetChildAtIndex(i, /*can_create_synthetic*/ false); + } + + // At this point type of `inner_value` should be the dereferenced target type. + CompilerType inner_value_type = inner_value->GetCompilerType(); + if (type.IsPointerType()) { +assert(inner_value_type.CompareTypes(type.GetPointeeType()) && + "casted value doesn't match the desired type"); + +uintptr_t addr = inner_value->GetLoadAddress(); +return ValueObject::CreateValueObjectFromPointer(target, addr, type); + } + + // At this point the target type should be a reference. + assert(inner_value_type.CompareTypes(type.GetNonReferenceType()) && + "casted value doesn't match the desired type"); bulbazord wrote: Same w/ this assertion. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -2809,6 +2919,243 @@ 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; + lldb::TargetSP target_sp = GetTargetSP(); + if (target_sp) { +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 == eAddressTypeHost) + addr_value = LLDB_INVALID_ADDRESS; + } + return addr_value; +} + +lldb::ValueObjectSP +ValueObject::CastDerivedToBaseType(CompilerType type, + const std::vector &idx) { + + lldb::TargetSP target = GetTargetSP(); + assert((type.IsPointerType() || type.IsReferenceType()) && + "invalid ast: target type should be a pointer or a reference"); + assert(!idx.empty() && "invalid ast: children sequence should be non-empty"); + + // The `value` can be a pointer, but GetChildAtIndex works for pointers too. + lldb::ValueObjectSP inner_value; + + for (const uint32_t i : idx) { +// Force static value, otherwise we can end up with the "real" type. +inner_value = GetChildAtIndex(i, /*can_create_synthetic*/ false); + } + + // At this point type of `inner_value` should be the dereferenced target type. + CompilerType inner_value_type = inner_value->GetCompilerType(); + if (type.IsPointerType()) { +assert(inner_value_type.CompareTypes(type.GetPointeeType()) && + "casted value doesn't match the desired type"); + +uintptr_t addr = inner_value->GetLoadAddress(); +return ValueObject::CreateValueObjectFromPointer(target, addr, type); + } + + // At this point the target type should be a reference. + assert(inner_value_type.CompareTypes(type.GetNonReferenceType()) && + "casted value doesn't match the desired type"); + + return lldb::ValueObjectSP(inner_value->Cast(type.GetNonReferenceType())); +} + +lldb::ValueObjectSP ValueObject::CastBaseToDerivedType(CompilerType type, + uint64_t offset) { + lldb::TargetSP target = GetTargetSP(); + + assert((type.IsPointerType() || type.IsReferenceType()) && + "invalid ast: target type should be a pointer or a reference"); bulbazord wrote: Same w/ this assertion https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); bulbazord wrote: nit: `const` the bool. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -2809,6 +2919,243 @@ 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; + lldb::TargetSP target_sp = GetTargetSP(); + if (target_sp) { bulbazord wrote: nit: These lines can be rolled into one ``` if (auto target_sp = GetTargetSP()) { ``` (use of auto is personal preference) https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); +} + +llvm::APFloat ValueObject::GetValueAsFloat() { + lldb::BasicType basic_type = + GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration(); + lldb::DataExtractorSP data_sp(new DataExtractor()); + Status error; + + switch (basic_type) { + case lldb::eBasicTypeFloat: { +float v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read float data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + case lldb::eBasicTypeDouble: +// No way to get more precision at the moment. + case lldb::eBasicTypeLongDouble: { +double v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read long double data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + default: +return llvm::APFloat(NAN); + } +} + +bool ValueObject::GetValueAsBool() { + CompilerType val_type = GetCompilerType(); + if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() || + val_type.IsPointerType()) { +return GetValueAsAPSInt().getBoolValue(); + } + if (val_type.IsFloat()) { +return GetValueAsFloat().isNonZero(); + } + if (val_type.IsArrayType()) { +lldb::ValueObjectSP new_val = +ValueObject::ValueObject::CreateValueObjectFromAddress( +GetName().GetStringRef(), GetAddressOf(), GetExecutionContextRef(), +val_type); +return new_val->GetValueAsUnsigned(0) != 0; + } + return false; +} + +void ValueObject::UpdateIntegerValue(const llvm::APInt &value) { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + assert(value.getBitWidth() == byte_size * CHAR_BIT && bulbazord wrote: Instead of asserting this, why not have this function return an `llvm::Error`? If this invariant is not met, this can return this exact error message. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Don't crash when attempting to parse breakpoint id `N.` as `N.*` (PR #87263)
https://github.com/bulbazord approved this pull request. Rewriting this has been on my backlog for a few months now. This looks better than what I had in mind. Thank you! 😄 https://github.com/llvm/llvm-project/pull/87263 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -618,6 +631,24 @@ class ValueObject { virtual lldb::ValueObjectSP CastPointerType(const char *name, lldb::TypeSP &type_sp); + /// Return the target load address assocaited with this value object. + lldb::addr_t GetLoadAddress(); + + lldb::ValueObjectSP CastDerivedToBaseType(CompilerType type, +const std::vector &idx); clayborg wrote: Maybe use `const llvm::ArrayRef` instead of `const std::vector`? Some headerdoc on what this does might be nice. I would guess `idx` contains a base class index path? Maybe renamed `idx` to something more descriptive? https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -668,6 +699,32 @@ class ValueObject { CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type); + static lldb::ValueObjectSP + CreateValueObjectFromBytes(lldb::TargetSP target_sp, const void *bytes, + CompilerType type); + + static lldb::ValueObjectSP CreateValueObjectFromBytes(lldb::TargetSP target, clayborg wrote: Do we need to be able to add a name for the value object? Some the creation APIs allow users to specify names and the native synthetic child providers could use these APIs if they can specify a name. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -618,6 +631,24 @@ class ValueObject { virtual lldb::ValueObjectSP CastPointerType(const char *name, lldb::TypeSP &type_sp); + /// Return the target load address assocaited with this value object. + lldb::addr_t GetLoadAddress(); + + lldb::ValueObjectSP CastDerivedToBaseType(CompilerType type, +const std::vector &idx); + + lldb::ValueObjectSP CastBaseToDerivedType(CompilerType type, uint64_t offset); + + lldb::ValueObjectSP CastScalarToBasicType(CompilerType type, Status &error); clayborg wrote: Same comment as Jim made below where the returned `lldb::ValueObjectSP` can have its error set correctly. Also, we have a bunch of `CastTo` calls added below. Do we really need all of these? Can we just have one `lldb::ValueObjectSP Cast(CompilerType type)` function and deduce what should be done internally and fail gracefully? Or if we do need functions specific to `Scalar` and `Enum` we can add just `lldb::ValueObjectSP CastScalar(CompilerType type)` and `lldb::ValueObjectSP CastEnum(CompilerType type)`. It would be great if we just have a single `lldb::ValueObjectSP Cast(CompilerType type)` function that works for everything. We should be able to figure out internally how things are stored (scalar, enum would be deduced from the current `ValueObject`, and figure out what we are casting it to with by looking at `CompilerType` https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -618,6 +631,24 @@ class ValueObject { virtual lldb::ValueObjectSP CastPointerType(const char *name, lldb::TypeSP &type_sp); + /// Return the target load address assocaited with this value object. + lldb::addr_t GetLoadAddress(); clayborg wrote: Is this function just a copy of the contents of `lldb::addr_t SBValue::GetLoadAddress()`? If so, we should also fix that function to call this function. Might be nice to have this return `std::optional` for internal use as if the `ValueObject` is a variable that is in a register, this will need to return `LLDB_INVALID_ADDRESS`. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -441,6 +441,19 @@ class ValueObject { virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr); + llvm::APSInt GetValueAsAPSInt(); + + llvm::APFloat GetValueAsFloat(); + + bool GetValueAsBool(); + + /// Update the value of the current object to be the integer in the 'value' + /// parameter. + void UpdateIntegerValue(const llvm::APInt &value); + + /// Assign the integer value 'new_val_sp' to the current object. + void UpdateIntegerValue(lldb::ValueObjectSP new_val_sp); clayborg wrote: What does this function actually do? Are we wanting the current `ValueObject` to copy the integer value from `lldb::ValueObjectSP new_val_sp`? Seems like we should just be able to use the above `void UpdateIntegerValue(const llvm::APInt &value);`? Can you elaborate on why this is needed? https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -441,6 +441,19 @@ class ValueObject { virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr); + llvm::APSInt GetValueAsAPSInt(); + + llvm::APFloat GetValueAsFloat(); + + bool GetValueAsBool(); clayborg wrote: Do we need `GetValueAsBool()` or can we just use `GetValueAsAPSInt()` and make sure bool gets converted to a suitable integer? https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -668,6 +699,32 @@ class ValueObject { CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type); + static lldb::ValueObjectSP + CreateValueObjectFromBytes(lldb::TargetSP target_sp, const void *bytes, + CompilerType type); + + static lldb::ValueObjectSP CreateValueObjectFromBytes(lldb::TargetSP target, +const void *bytes, +lldb::BasicType type); + + static lldb::ValueObjectSP CreateValueObjectFromAPInt(lldb::TargetSP target, +const llvm::APInt &v, +CompilerType type); + + static lldb::ValueObjectSP + CreateValueObjectFromAPFloat(lldb::TargetSP target, const llvm::APFloat &v, + CompilerType type); + + static lldb::ValueObjectSP CreateValueObjectFromPointer(lldb::TargetSP target, + uintptr_t addr, + CompilerType type); + + static lldb::ValueObjectSP CreateValueObjectFromBool(lldb::TargetSP target, + bool value); + + static lldb::ValueObjectSP CreateValueObjectFromNullptr(lldb::TargetSP target, clayborg wrote: name arg? https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); +} + +llvm::APFloat ValueObject::GetValueAsFloat() { + lldb::BasicType basic_type = + GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration(); + lldb::DataExtractorSP data_sp(new DataExtractor()); + Status error; + + switch (basic_type) { + case lldb::eBasicTypeFloat: { +float v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read float data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + case lldb::eBasicTypeDouble: +// No way to get more precision at the moment. + case lldb::eBasicTypeLongDouble: { +double v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read long double data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + default: +return llvm::APFloat(NAN); + } +} + +bool ValueObject::GetValueAsBool() { + CompilerType val_type = GetCompilerType(); + if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() || + val_type.IsPointerType()) { +return GetValueAsAPSInt().getBoolValue(); + } + if (val_type.IsFloat()) { +return GetValueAsFloat().isNonZero(); + } + if (val_type.IsArrayType()) { +lldb::ValueObjectSP new_val = +ValueObject::ValueObject::CreateValueObjectFromAddress( +GetName().GetStringRef(), GetAddressOf(), GetExecutionContextRef(), +val_type); +return new_val->GetValueAsUnsigned(0) != 0; + } + return false; +} + +void ValueObject::UpdateIntegerValue(const llvm::APInt &value) { clayborg wrote: If I look at this API, I would expect this function to change the integer value of any ValueObject. The value object might have a variable that lives in memory (on the stack or heap), or if it lives in a register (update the register) or if there is already a local buffer, replace the bytes in the local buffer. This function seems to replace the integer value always with a local buffer? https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -441,6 +441,19 @@ class ValueObject { virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr); + llvm::APSInt GetValueAsAPSInt(); + + llvm::APFloat GetValueAsFloat(); + + bool GetValueAsBool(); + + /// Update the value of the current object to be the integer in the 'value' + /// parameter. + void UpdateIntegerValue(const llvm::APInt &value); clayborg wrote: Should we name this similar to `SetValueFromCString(...)`? Something like: `SetValue(const llvm::APInt &value)` or `SetValueFromInteger(const llvm::APInt &value)`? Do we want an error to be returned in case this fails? https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -668,6 +699,32 @@ class ValueObject { CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type); + static lldb::ValueObjectSP + CreateValueObjectFromBytes(lldb::TargetSP target_sp, const void *bytes, + CompilerType type); + + static lldb::ValueObjectSP CreateValueObjectFromBytes(lldb::TargetSP target, +const void *bytes, +lldb::BasicType type); + + static lldb::ValueObjectSP CreateValueObjectFromAPInt(lldb::TargetSP target, +const llvm::APInt &v, +CompilerType type); + + static lldb::ValueObjectSP + CreateValueObjectFromAPFloat(lldb::TargetSP target, const llvm::APFloat &v, clayborg wrote: ditto for adding a name parameter. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); +} + +llvm::APFloat ValueObject::GetValueAsFloat() { + lldb::BasicType basic_type = + GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration(); + lldb::DataExtractorSP data_sp(new DataExtractor()); + Status error; + + switch (basic_type) { + case lldb::eBasicTypeFloat: { +float v = 0; clayborg wrote: We really don't want to use native float types, we want to use real APFloat values that are correctly encoded. For instance if we are debugging from x86_64, we don't want to create a 10 byte Intel float and do the math with the native float, we want to use the value from the Scalar that is already set correctly. If we are cross debugging to an iPhone, we want the floating point values to match exactly, which requires us to use the APFloat and not do any manually create a native float and convert it. This all works for the value objects when they get the float as a string, and will be similar where we resolve the scalar and then can just use the Scalar::m_float directly. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); clayborg wrote: Extract the `APInt` from the contained `Scalar` value directly. No need to create a location uint64_t and then try to re-create, the `Scalar` ivar already contains an `APInt`. So just do: ``` if (CanProvideValue()) { Scalar scalar; if (ResolveValue(scalar)) { if (success) *success = true; scalar.MakeUnsigned(); return scalar.m_integer; // Might need to provide an accessor for Scalar::m_integer } } ``` https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); +} + +llvm::APFloat ValueObject::GetValueAsFloat() { + lldb::BasicType basic_type = + GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration(); + lldb::DataExtractorSP data_sp(new DataExtractor()); + Status error; + + switch (basic_type) { + case lldb::eBasicTypeFloat: { +float v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read float data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + case lldb::eBasicTypeDouble: +// No way to get more precision at the moment. + case lldb::eBasicTypeLongDouble: { +double v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read long double data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + default: +return llvm::APFloat(NAN); + } +} + +bool ValueObject::GetValueAsBool() { + CompilerType val_type = GetCompilerType(); + if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() || + val_type.IsPointerType()) { +return GetValueAsAPSInt().getBoolValue(); + } + if (val_type.IsFloat()) { +return GetValueAsFloat().isNonZero(); + } + if (val_type.IsArrayType()) { +lldb::ValueObjectSP new_val = +ValueObject::ValueObject::CreateValueObjectFromAddress( +GetName().GetStringRef(), GetAddressOf(), GetExecutionContextRef(), +val_type); +return new_val->GetValueAsUnsigned(0) != 0; + } clayborg wrote: What is this attempting to do? It looks like this is taking an array type and returning an array pointer and trying to return `true` if the array is in memory? https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); +} + +llvm::APFloat ValueObject::GetValueAsFloat() { + lldb::BasicType basic_type = + GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration(); + lldb::DataExtractorSP data_sp(new DataExtractor()); + Status error; + + switch (basic_type) { + case lldb::eBasicTypeFloat: { +float v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read float data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + case lldb::eBasicTypeDouble: +// No way to get more precision at the moment. + case lldb::eBasicTypeLongDouble: { +double v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read long double data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + default: +return llvm::APFloat(NAN); + } +} + +bool ValueObject::GetValueAsBool() { + CompilerType val_type = GetCompilerType(); + if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() || + val_type.IsPointerType()) { +return GetValueAsAPSInt().getBoolValue(); + } + if (val_type.IsFloat()) { +return GetValueAsFloat().isNonZero(); + } + if (val_type.IsArrayType()) { +lldb::ValueObjectSP new_val = +ValueObject::ValueObject::CreateValueObjectFromAddress( +GetName().GetStringRef(), GetAddressOf(), GetExecutionContextRef(), +val_type); +return new_val->GetValueAsUnsigned(0) != 0; + } + return false; +} + +void ValueObject::UpdateIntegerValue(const llvm::APInt &value) { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + assert(value.getBitWidth() == byte_size * CHAR_BIT && + "illegal argument: new value should be of the same size"); + + lldb::DataExtractorSP data_sp; + Status error; + data_sp->SetData(value.getRawData(), byte_size, + target->GetArchitecture().GetByteOrder()); clayborg wrote: This will crash, `data_sp` is never constructed or assigned. We also need to figure out if we are going to want the integer value to be replaced always with a local copy, or updated in the actual program memory, register, or local buffer. I realize many of these APIs are probably only intended to be used in the new ValueObject based expression parser, but there are APIs being added to ValueObject so they should work regardless of where they come from or originate. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -2809,6 +2919,243 @@ 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; + lldb::TargetSP target_sp = GetTargetSP(); + if (target_sp) { +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 == eAddressTypeHost) clayborg wrote: Double check for `eAddressTypeHost`, I am guessing the second one was meant to be `eAddressTypeInvalid`. We should also change `lldb::addr_t SBValue::GetLoadAddress()` to call this function https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); +} + +llvm::APFloat ValueObject::GetValueAsFloat() { clayborg wrote: Resolving the float value already builds a `APFloat` in a `Scalar`, so no need to redo all of this. Should be very similar to `llvm::APSInt ValueObject::GetValueAsAPSInt()` suggestions above https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::APSInt ValueObject::GetValueAsAPSInt() { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + unsigned bit_width = static_cast(byte_size * CHAR_BIT); + bool success = true; + uint64_t fail_value = 0; + uint64_t ret_val = GetValueAsUnsigned(fail_value, &success); + uint64_t new_value = fail_value; + if (success) +new_value = ret_val; + bool is_signed = GetCompilerType().IsSigned(); + + return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed); +} + +llvm::APFloat ValueObject::GetValueAsFloat() { + lldb::BasicType basic_type = + GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration(); + lldb::DataExtractorSP data_sp(new DataExtractor()); + Status error; + + switch (basic_type) { + case lldb::eBasicTypeFloat: { +float v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read float data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + case lldb::eBasicTypeDouble: +// No way to get more precision at the moment. + case lldb::eBasicTypeLongDouble: { +double v = 0; +GetData(*data_sp, error); +assert(error.Success() && "Unable to read long double data from value"); + +lldb::offset_t offset = 0; +uint32_t old_offset = offset; +void *ok = nullptr; +ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double)); +assert(offset != old_offset && ok != nullptr && "unable to read data"); + +return llvm::APFloat(v); + } + default: +return llvm::APFloat(NAN); + } +} + +bool ValueObject::GetValueAsBool() { + CompilerType val_type = GetCompilerType(); + if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() || + val_type.IsPointerType()) { +return GetValueAsAPSInt().getBoolValue(); + } + if (val_type.IsFloat()) { +return GetValueAsFloat().isNonZero(); + } + if (val_type.IsArrayType()) { +lldb::ValueObjectSP new_val = +ValueObject::ValueObject::CreateValueObjectFromAddress( +GetName().GetStringRef(), GetAddressOf(), GetExecutionContextRef(), +val_type); +return new_val->GetValueAsUnsigned(0) != 0; + } + return false; +} + +void ValueObject::UpdateIntegerValue(const llvm::APInt &value) { + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) +byte_size = temp.value(); + + assert(value.getBitWidth() == byte_size * CHAR_BIT && clayborg wrote: yes, no asserts and add error propagation. https://github.com/llvm/llvm-project/pull/87197 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] a6cacee - [lldb] Don't crash when attempting to parse breakpoint id `N.` as `N.*` (#87263)
Author: Jordan Rupprecht Date: 2024-04-01T16:02:12-05:00 New Revision: a6caceed8d27d4ebd44c517c3114a36a64ebddfe URL: https://github.com/llvm/llvm-project/commit/a6caceed8d27d4ebd44c517c3114a36a64ebddfe DIFF: https://github.com/llvm/llvm-project/commit/a6caceed8d27d4ebd44c517c3114a36a64ebddfe.diff LOG: [lldb] Don't crash when attempting to parse breakpoint id `N.` as `N.*` (#87263) We check if the next character after `N.` is `*` before we check its length. Using `split` on the string is cleaner and less error prone than using indices with `find` and `substr`. Note: this does not make `N.` mean anything, it just prevents assertion failures. `N.` is treated the same as an unrecognized breakpoint name: ``` (lldb) breakpoint enable 1 1 breakpoints enabled. (lldb) breakpoint enable 1.* 1 breakpoints enabled. (lldb) breakpoint enable 1. 0 breakpoints enabled. (lldb) breakpoint enable xyz 0 breakpoints enabled. ``` Found via LLDB fuzzers. Added: Modified: lldb/source/Breakpoint/BreakpointIDList.cpp lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py Removed: diff --git a/lldb/source/Breakpoint/BreakpointIDList.cpp b/lldb/source/Breakpoint/BreakpointIDList.cpp index 851d074e753588..97af1d40eb7a58 100644 --- a/lldb/source/Breakpoint/BreakpointIDList.cpp +++ b/lldb/source/Breakpoint/BreakpointIDList.cpp @@ -16,6 +16,7 @@ #include "lldb/Utility/StreamString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" using namespace lldb; using namespace lldb_private; @@ -111,32 +112,27 @@ llvm::Error BreakpointIDList::FindAndReplaceIDRanges( } else { // See if user has specified id.* llvm::StringRef tmp_str = old_args[i].ref(); - size_t pos = tmp_str.find('.'); - if (pos != llvm::StringRef::npos) { -llvm::StringRef bp_id_str = tmp_str.substr(0, pos); -if (BreakpointID::IsValidIDExpression(bp_id_str) && -tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) { - - BreakpointSP breakpoint_sp; - auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str); - if (bp_id) -breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID()); - if (!breakpoint_sp) { -new_args.Clear(); -return llvm::createStringError( -llvm::inconvertibleErrorCode(), -"'%d' is not a valid breakpoint ID.\n", -bp_id->GetBreakpointID()); - } - const size_t num_locations = breakpoint_sp->GetNumLocations(); - for (size_t j = 0; j < num_locations; ++j) { -BreakpointLocation *bp_loc = -breakpoint_sp->GetLocationAtIndex(j).get(); -StreamString canonical_id_str; -BreakpointID::GetCanonicalReference( -&canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID()); -new_args.AppendArgument(canonical_id_str.GetString()); - } + auto [prefix, suffix] = tmp_str.split('.'); + if (suffix == "*" && BreakpointID::IsValidIDExpression(prefix)) { + +BreakpointSP breakpoint_sp; +auto bp_id = BreakpointID::ParseCanonicalReference(prefix); +if (bp_id) + breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID()); +if (!breakpoint_sp) { + new_args.Clear(); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "'%d' is not a valid breakpoint ID.\n", + bp_id->GetBreakpointID()); +} +const size_t num_locations = breakpoint_sp->GetNumLocations(); +for (size_t j = 0; j < num_locations; ++j) { + BreakpointLocation *bp_loc = + breakpoint_sp->GetLocationAtIndex(j).get(); + StreamString canonical_id_str; + BreakpointID::GetCanonicalReference( + &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID()); + new_args.AppendArgument(canonical_id_str.GetString()); } } } diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py b/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py index 8930bea619bb6e..d87e6275f7b51e 100644 --- a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py @@ -293,6 +293,12 @@ def breakpoint_locations_test(self): startstr="3 breakpoints enabled.", ) +# The 'breakpoint enable 1.' command should not crash. +self.expect( +"breakpoint enable 1.", +startstr="0 breakpoints enabled.", +) + # The 'breakpoint disable 1.1' command should
[Lldb-commits] [lldb] [lldb] Don't crash when attempting to parse breakpoint id `N.` as `N.*` (PR #87263)
https://github.com/rupprecht closed https://github.com/llvm/llvm-project/pull/87263 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] 9df19ce - Add uncovered enums in switches caused by 9434c083475e42f47383f3067fe2a155db5c6a30
Author: David Blaikie Date: 2024-04-01T23:07:01Z New Revision: 9df19ce40281551bd348b262a131085cf98dadf5 URL: https://github.com/llvm/llvm-project/commit/9df19ce40281551bd348b262a131085cf98dadf5 DIFF: https://github.com/llvm/llvm-project/commit/9df19ce40281551bd348b262a131085cf98dadf5.diff LOG: Add uncovered enums in switches caused by 9434c083475e42f47383f3067fe2a155db5c6a30 These are probably actually unreachable - perhaps an lldb developer would be interested in rephrasing this change to move the new cases into some unreachable/unsupported bucket, rather than my half-hearted guess at what the desired behavior would be (completely untested, because they're probably untestable/unreachable - maybe debugging from modules?) Added: Modified: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp Removed: diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index ebcc3bc99a801f..4a1c8d57655215 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -4097,6 +4097,8 @@ TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) { return lldb::eTypeClassArray; case clang::Type::DependentSizedArray: return lldb::eTypeClassArray; + case clang::Type::ArrayParameter: +return lldb::eTypeClassArray; case clang::Type::DependentSizedExtVector: return lldb::eTypeClassVector; case clang::Type::DependentVector: @@ -4776,6 +4778,7 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::Type::IncompleteArray: case clang::Type::VariableArray: + case clang::Type::ArrayParameter: break; case clang::Type::ConstantArray: @@ -5109,6 +5112,7 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) { case clang::Type::IncompleteArray: case clang::Type::VariableArray: + case clang::Type::ArrayParameter: break; case clang::Type::ConstantArray: ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits