[Lldb-commits] [lldb] Lldb address space apertures (PR #232588)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Oct 15 21:07:50 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: halehri
<details>
<summary>Changes</summary>
In heterogeneous and non-flat target architectures (such as GPUs, DSPs, and accelerators), memory spaces can have distinct addressing schemes, non-byte pointer units, or memory mapped into specific apertures of a flat process address space.
This change extends `jAddressSpacesInfo` / `AddressSpaceInfo` with optional flat aperture metadata (`dwarf_address_class`, `flat_base`, `flat_size`, `pointer_unit`). When evaluating pointers or references qualified with a DWARF address class (added in #<!-- -->230555), `ValueObject` translates the target pointer value to and from the process load address via `Process::PointerToLoadAddress` and `Process::LoadAddressToPointer`. This enables LLDB value inspection, dereferencing, and address-of operations to work on multi-address-space targets while preserving identity mapping on flat architectures.
Testing:
- Added `AddressSpaceTest.ApertureRoundTrip` in `lldb/unittests/Utility/AddressSpaceTest.cpp`
- Added `MemoryTest.TestPointerToLoadAddressApertures` in `lldb/unittests/Target/MemoryTest.cpp`
Assisted-by: Gemini
---
Patch is 29.29 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/232588.diff
18 Files Affected:
- (modified) lldb/include/lldb/Symbol/CompilerType.h (+3)
- (modified) lldb/include/lldb/Symbol/TypeSystem.h (+7)
- (modified) lldb/include/lldb/Target/Process.h (+13)
- (modified) lldb/include/lldb/Utility/AddressSpace.h (+13)
- (modified) lldb/include/lldb/ValueObject/ValueObject.h (+4)
- (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+6-1)
- (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp (+23)
- (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h (+2)
- (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+24)
- (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h (+7)
- (modified) lldb/source/Symbol/CompilerType.cpp (+7)
- (modified) lldb/source/Target/Process.cpp (+45)
- (modified) lldb/source/Utility/AddressSpace.cpp (+16-4)
- (modified) lldb/source/ValueObject/ValueObject.cpp (+35-3)
- (modified) lldb/unittests/Symbol/TestTypeSystemClang.cpp (+32)
- (modified) lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp (+120)
- (modified) lldb/unittests/Target/MemoryTest.cpp (+60)
- (modified) lldb/unittests/Utility/AddressSpaceTest.cpp (+31)
``````````diff
diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h
index 168946cf17475e..03f59ec04cba0d 100644
--- a/lldb/include/lldb/Symbol/CompilerType.h
+++ b/lldb/include/lldb/Symbol/CompilerType.h
@@ -206,6 +206,9 @@ class CompilerType {
bool HasPointerAuthQualifier() const;
+ /// The target address space of this type, if it is not the default one.
+ std::optional<uint32_t> GetTargetAddressSpace() const;
+
/// This is used when you don't care about the signedness of the integer.
bool IsInteger() const;
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h
index 9ec0f13814975a..927b267c0176d3 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -207,6 +207,13 @@ class TypeSystem : public PluginInterface,
return false;
}
+ /// Returns the target address space (the DWARF address class) of \p type,
+ /// or std::nullopt if it lives in the default address space.
+ virtual std::optional<uint32_t>
+ GetTargetAddressSpace(lldb::opaque_compiler_type_t type) {
+ return std::nullopt;
+ }
+
virtual bool CanPassInRegisters(const CompilerType &type) = 0;
// TypeSystems can support more than one language
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 226c58034dd655..aa765d95370a42 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -2034,6 +2034,19 @@ class Process : public std::enable_shared_from_this<Process>,
llvm::Expected<AddressSpaceInfo>
GetAddressSpaceInfo(lldb::addr_space_t address_space_id);
+ /// Maps \p pointer, a pointer value read from the target whose pointee is
+ /// in DWARF address class \p address_class (0 for none), to the address
+ /// lldb uses to access the pointee. This is the identity unless the server
+ /// published a flat aperture for that class (see AddressSpaceInfo).
+ lldb::addr_t PointerToLoadAddress(lldb::addr_t pointer,
+ uint32_t address_class);
+
+ /// Inverse of PointerToLoadAddress: returns the target pointer value for
+ /// \p address if it lies in the flat aperture of \p address_class, and
+ /// \p address unchanged otherwise.
+ lldb::addr_t LoadAddressToPointer(lldb::addr_t address,
+ uint32_t address_class);
+
/// Get the number of watchpoints supported by this target.
///
/// We may be able to determine the number of watchpoints available
diff --git a/lldb/include/lldb/Utility/AddressSpace.h b/lldb/include/lldb/Utility/AddressSpace.h
index f4ab9647dd10f6..ee20e84607fdd3 100644
--- a/lldb/include/lldb/Utility/AddressSpace.h
+++ b/lldb/include/lldb/Utility/AddressSpace.h
@@ -11,6 +11,7 @@
#include "lldb/lldb-types.h"
#include "llvm/Support/JSON.h"
+#include <optional>
#include <string>
#include <vector>
@@ -21,6 +22,18 @@ struct AddressSpaceInfo {
std::string name;
lldb::addr_space_t space_id = 0;
bool is_thread_specific = false;
+
+ /// Optional flat aperture: pointers whose pointee has DWARF address class
+ /// \a dwarf_address_class hold a value in units of \a pointer_unit bytes
+ /// that maps to the process address flat_base + value * pointer_unit. This
+ /// lets value objects dereference pointers into memories that are not byte
+ /// addressed or not in the default address space (e.g. GPU, DSP, or accelerator).
+ /// Address class 0 (default / flat) has no aperture; 0 is the NULL pointer.
+ std::optional<uint32_t> dwarf_address_class;
+ std::optional<lldb::addr_t> flat_base;
+ /// Size in bytes of the flat aperture; 0 means unbounded.
+ uint64_t flat_size = 0;
+ uint64_t pointer_unit = 1;
};
bool fromJSON(const llvm::json::Value &value, AddressSpaceInfo &data,
diff --git a/lldb/include/lldb/ValueObject/ValueObject.h b/lldb/include/lldb/ValueObject/ValueObject.h
index c336213c84e25d..82ca483e31d4aa 100644
--- a/lldb/include/lldb/ValueObject/ValueObject.h
+++ b/lldb/include/lldb/ValueObject/ValueObject.h
@@ -588,6 +588,10 @@ class ValueObject {
AddrAndType GetPointerValue();
+ /// Maps a pointer value of this (pointer or reference typed) object to the
+ /// process address of its pointee, honoring the pointee's address space.
+ AddrAndType MapPointerToLoadAddress(AddrAndType pointer);
+
lldb::ValueObjectSP GetSyntheticChild(ConstString key) const;
lldb::ValueObjectSP GetSyntheticArrayMember(size_t index, bool can_create);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index ea8e94c116a111..0fcf1942de62d8 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -2372,7 +2372,12 @@ bool CPlusPlusLanguage::IsNilReference(ValueObject &valobj) {
return false;
bool canReadValue = true;
bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0;
- return canReadValue && isZero;
+ // Address class 0 (default / flat) has no aperture; 0 is the NULL pointer.
+ // In an address space whose pointer value 0 maps to real memory (a flat
+ // aperture), a zero pointer is not a null reference.
+ if (!canReadValue || !isZero)
+ return false;
+ return valobj.GetPointerValue().address == 0;
}
bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index b60f1d9e41958a..260de0e0b95a4e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -469,6 +469,10 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
decl.SetColumn(form_value.Unsigned());
break;
+ case DW_AT_address_class:
+ address_class = form_value.Unsigned();
+ break;
+
case DW_AT_declaration:
is_forward_declaration = form_value.Boolean();
break;
@@ -946,6 +950,25 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc,
}
}
+ // A pointer with DW_AT_address_class points into a target address space
+ // (e.g. a GPU, DSP, or accelerator memory). Record it as an address-space
+ // qualifier on the pointee so value objects can map the pointer to a process
+ // address.
+ if (!clang_type && tag == DW_TAG_pointer_type && attrs.address_class != 0 &&
+ attrs.type.IsValid()) {
+ if (Type *pointee_type =
+ dwarf->ResolveTypeUID(attrs.type.Reference(), true)) {
+ CompilerType pointee = m_ast.AddAddressSpaceModifier(
+ pointee_type->GetForwardCompilerType(), attrs.address_class);
+ if (pointee) {
+ clang_type = pointee.GetPointerType();
+ encoding_data_type = Type::eEncodingIsUID;
+ attrs.type.Clear();
+ resolve_state = Type::ResolveState::Full;
+ }
+ }
+ }
+
return dwarf->MakeType(die.GetID(), attrs.name, attrs.byte_size, nullptr,
attrs.type.Reference().GetID(), encoding_data_type,
&attrs.decl, clang_type, resolve_state, payload);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
index 03c431c73fb6ff..b16c5e0e702285 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
@@ -571,6 +571,8 @@ struct ParsedDWARFTypeAttributes {
uint32_t bit_stride = 0;
uint32_t byte_stride = 0;
uint32_t encoding = 0;
+ /// DW_AT_address_class of a pointer or reference type (0 = none).
+ uint32_t address_class = 0;
///< Indicates ref-qualifier of C++ member function if present.
///< Is RQ_None otherwise.
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index ee7415354bb479..eca8386f8a36b8 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -3750,6 +3750,30 @@ bool TypeSystemClang::HasPointerAuthQualifier(
return GetCanonicalQualType(type).getPointerAuth().isPresent();
}
+std::optional<uint32_t>
+TypeSystemClang::GetTargetAddressSpace(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return std::nullopt;
+ clang::LangAS as = GetCanonicalQualType(type).getAddressSpace();
+ if (!clang::isTargetAddressSpace(as))
+ return std::nullopt;
+ return clang::toTargetAddressSpace(as);
+}
+
+CompilerType TypeSystemClang::AddAddressSpaceModifier(const CompilerType &type,
+ uint32_t address_space) {
+ if (!type || address_space == 0)
+ return type;
+ auto ts = type.GetTypeSystem<TypeSystemClang>();
+ if (!ts || ts.get() != this)
+ return type;
+ clang::QualType qual_type = ClangUtil::GetQualType(type);
+ if (qual_type.hasAddressSpace())
+ return type;
+ return GetType(getASTContext().getAddrSpaceQualType(
+ qual_type, clang::getLangASFromTargetAS(address_space)));
+}
+
bool TypeSystemClang::CanPassInRegisters(const CompilerType &type) {
if (auto *record_decl =
TypeSystemClang::GetAsRecordDecl(type)) {
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index ef6d5a9c595b97..2abfe6989ff484 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -725,6 +725,13 @@ class TypeSystemClang : public TypeSystem {
bool HasPointerAuthQualifier(lldb::opaque_compiler_type_t type) override;
+ std::optional<uint32_t>
+ GetTargetAddressSpace(lldb::opaque_compiler_type_t type) override;
+
+ /// Returns \p type qualified with target address space \p address_space.
+ CompilerType AddAddressSpaceModifier(const CompilerType &type,
+ uint32_t address_space);
+
bool CanPassInRegisters(const CompilerType &type) override;
bool SupportsLanguage(lldb::LanguageType language) override;
diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp
index 6f20bfa89ed38c..0c25c9a2db95e7 100644
--- a/lldb/source/Symbol/CompilerType.cpp
+++ b/lldb/source/Symbol/CompilerType.cpp
@@ -325,6 +325,13 @@ bool CompilerType::HasPointerAuthQualifier() const {
return false;
}
+std::optional<uint32_t> CompilerType::GetTargetAddressSpace() const {
+ if (IsValid())
+ if (auto type_system_sp = GetTypeSystem())
+ return type_system_sp->GetTargetAddressSpace(m_type);
+ return std::nullopt;
+}
+
bool CompilerType::IsPointerToScalarType() const {
if (!IsValid())
return false;
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index c1343fa196f6e8..301ea56b0c5b12 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include <atomic>
+#include <limits>
#include <memory>
#include <mutex>
#include <optional>
@@ -7256,3 +7257,47 @@ Process::GetAddressSpaceInfo(lldb::addr_space_t address_space_id) {
", expected one of: %s",
address_space_id, ids.c_str());
}
+
+// Address class 0 (default / flat) has no aperture; 0 is the NULL pointer.
+static const AddressSpaceInfo *
+FindFlatAperture(const std::vector<AddressSpaceInfo> &address_spaces,
+ uint32_t address_class) {
+ for (const AddressSpaceInfo &info : address_spaces) {
+ if (info.flat_base && info.pointer_unit != 0 &&
+ info.dwarf_address_class == address_class)
+ return &info;
+ }
+ return nullptr;
+}
+
+lldb::addr_t Process::PointerToLoadAddress(lldb::addr_t pointer,
+ uint32_t address_class) {
+ if (pointer == LLDB_INVALID_ADDRESS)
+ return pointer;
+ const AddressSpaceInfo *info =
+ FindFlatAperture(m_address_spaces, address_class);
+ if (!info)
+ return pointer;
+ // Bounds check against aperture size and overflow check.
+ if (info->flat_size != 0 &&
+ pointer > (info->flat_size - 1) / info->pointer_unit)
+ return LLDB_INVALID_ADDRESS;
+ if (pointer > std::numeric_limits<lldb::addr_t>::max() / info->pointer_unit)
+ return LLDB_INVALID_ADDRESS;
+ lldb::addr_t offset = pointer * info->pointer_unit;
+ if (std::numeric_limits<lldb::addr_t>::max() - *info->flat_base < offset)
+ return LLDB_INVALID_ADDRESS;
+ return *info->flat_base + offset;
+}
+
+lldb::addr_t Process::LoadAddressToPointer(lldb::addr_t address,
+ uint32_t address_class) {
+ if (address == LLDB_INVALID_ADDRESS)
+ return address;
+ const AddressSpaceInfo *info =
+ FindFlatAperture(m_address_spaces, address_class);
+ if (!info || address < *info->flat_base ||
+ (info->flat_size != 0 && address - *info->flat_base >= info->flat_size))
+ return address;
+ return (address - *info->flat_base) / info->pointer_unit;
+}
diff --git a/lldb/source/Utility/AddressSpace.cpp b/lldb/source/Utility/AddressSpace.cpp
index 38d7878e5abd15..bd6813bb18fee5 100644
--- a/lldb/source/Utility/AddressSpace.cpp
+++ b/lldb/source/Utility/AddressSpace.cpp
@@ -16,13 +16,25 @@ namespace lldb_private {
bool fromJSON(const json::Value &value, AddressSpaceInfo &data, Path path) {
ObjectMapper o(value, path);
return o && o.map("name", data.name) && o.map("space_id", data.space_id) &&
- o.map("is_thread_specific", data.is_thread_specific);
+ o.map("is_thread_specific", data.is_thread_specific) &&
+ o.mapOptional("dwarf_address_class", data.dwarf_address_class) &&
+ o.mapOptional("flat_base", data.flat_base) &&
+ o.mapOptional("flat_size", data.flat_size) &&
+ o.mapOptional("pointer_unit", data.pointer_unit);
}
json::Value toJSON(const AddressSpaceInfo &data) {
- return json::Value(Object{{"name", data.name},
- {"space_id", data.space_id},
- {"is_thread_specific", data.is_thread_specific}});
+ Object object{{"name", data.name},
+ {"space_id", data.space_id},
+ {"is_thread_specific", data.is_thread_specific}};
+ if (data.dwarf_address_class)
+ object["dwarf_address_class"] = *data.dwarf_address_class;
+ if (data.flat_base) {
+ object["flat_base"] = *data.flat_base;
+ object["flat_size"] = data.flat_size;
+ object["pointer_unit"] = data.pointer_unit;
+ }
+ return json::Value(std::move(object));
}
} // namespace lldb_private
diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp
index 989ad64a9a65c0..297d855c698f0d 100644
--- a/lldb/source/ValueObject/ValueObject.cpp
+++ b/lldb/source/ValueObject/ValueObject.cpp
@@ -1704,6 +1704,29 @@ std::optional<addr_t> ValueObject::GetStrippedPointerValue(addr_t address) {
return std::nullopt;
}
+/// Returns the DWARF address class of the pointee of \p type, or 0.
+static uint32_t GetPointeeAddressClass(const CompilerType &type) {
+ CompilerType pointee;
+ if (!type.IsPointerOrReferenceType(&pointee))
+ return 0;
+ return pointee.GetTargetAddressSpace().value_or(0);
+}
+
+ValueObject::AddrAndType
+ValueObject::MapPointerToLoadAddress(AddrAndType pointer) {
+ if (pointer.address == LLDB_INVALID_ADDRESS ||
+ pointer.type != eAddressTypeLoad)
+ return pointer;
+ CompilerType type = GetCompilerType();
+ if (!type.IsPointerOrReferenceType())
+ return pointer;
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ if (Process *process = exe_ctx.GetProcessPtr())
+ pointer.address = process->PointerToLoadAddress(
+ pointer.address, GetPointeeAddressClass(type));
+ return pointer;
+}
+
ValueObject::AddrAndType ValueObject::GetPointerValue() {
if (!UpdateValueIfNeeded(false))
return {};
@@ -1712,14 +1735,16 @@ ValueObject::AddrAndType ValueObject::GetPointerValue() {
case Value::ValueType::Invalid:
return {};
case Value::ValueType::Scalar:
- return {m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS),
- GetAddressTypeOfChildren()};
+ return MapPointerToLoadAddress(
+ {m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS),
+ GetAddressTypeOfChildren()});
case Value::ValueType::HostAddress:
case Value::ValueType::LoadAddress:
case Value::ValueType::FileAddress: {
lldb::offset_t data_offset = 0;
- return {m_data.GetAddress(&data_offset), GetAddressTypeOfChildren()};
+ return MapPointerToLoadAddress(
+ {m_data.GetAddress(&data_offset), GetAddressTypeOfChildren()});
}
}
@@ -2961,6 +2986,13 @@ ValueObjectSP ValueObject::AddressOf(Status &error) {
name.append(m_name.AsCString(""));
ExecutionContext exe_ctx(GetExecutionContextRef());
+ // The resulting pointer holds the target's pointer encoding of addr.
+ if (address_type == eAddressTypeLoad) {
+ if (Process *process = exe_ctx.GetProcessPtr())
+ addr = process->LoadAddressToPointer(
+ addr, GetCompilerType().GetTargetAddressSpace().value_or(0));
+ }
+
lldb::DataBufferSP buffer(
new lldb_private::DataBufferHeap(&addr, sizeof(lldb::addr_t)));
m_addr_of_valobj_sp = ValueObjectConstResult::Create(
diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
index 314f8e2c97e199..60bde43decabb6 100644
--- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -1554,3 +1554,35 @@ TEST_F(TestTypeSystemClang, TestIsMemberDataPointerType) {
EXPECT_FALSE(int_type.IsMemberDataPointerType());
EXPECT_FALSE(int_type.IsMemberFunctionPointerType());
}
+
+TEST_F(TestTypeSystemClang, TestAddressSpaceModifier) {
+ CompilerType invalid_type;
+ EXPECT_EQ(invalid_type.GetTargetAddressSpace(), std::nullopt);
+ EXPECT_FALSE(m_ast->AddAddressSpaceModifier(invalid_type, 3).IsValid());
+
+ CompilerType int_type = m_ast->GetBasicType(lldb::eBasicTypeInt);
+ ASSERT_TRUE(int_type.IsValid());
+ EXPECT_EQ(int_type.GetTargetAddressSpace(), std::nullopt);
+
+ // Address space 0 is the default address space (no qualifier added).
+ CompilerType zero_as_type = m_ast->AddAddressSpaceModifier(int_type, 0);
+ EXPECT_EQ(zero_as_type.GetTargetAddressSpace(), std::nullopt);
+
+ // Qualifying with a non-zero target address space records it on the type.
+ CompilerType as3_int = m_ast->AddAddressSpaceModifier(int_type, 3);
+ ASSERT_TRUE(as3_int.IsValid());
+ EXPECT_EQ(as3_int.GetTargetAddressSpace(), std::optional<uint32_t>(3U));
+
+ // Re-qualifying an already address-space-qualified type preserves the
+ // existing address space.
+ CompilerType re_qualified = m_ast->AddAddressSpaceModifier(as3_int, 5);
+ EXPECT_EQ(re_qualified.GetTargetAddressSpace(), std::optional<uint32_t>(3U));
+
+ // A pointer to an address-space-qualified type carries the qualifier on
+ // the pointee, while the pointer itself lives in the default space.
+ CompilerType ptr_to_as3_int = as3_int.GetPointerType();
+ ASSERT_TRUE(ptr_to_as3_int.IsPointerType());
+ EXPECT_EQ(ptr_to_as3_int.GetTargetAddressSpace(), std::nullopt);
+ EXPECT_EQ(ptr_to_as3_int.GetPointeeType().GetTargetAddressSpace(),
+ std::optional<uint32_t>(3U));
+}
diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
index 729b47c7d08d08..f8578d7e229209 100644
--- a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
+++ b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
@@ -2245,3 +2245,123 @@ TEST_F(DWARFASTParserClangTests, TestRustVariantMember) {
// 29352461300415899028694309177919734273
ASSERT_EQ(f_name, "$variant$29352461300415899028694309177919734273");
}
+
+TEST_F(DWARFASTParserClangTests, TestAddressClassPointerParsing) {
+ // Tests that DW_TAG_pointer_type with a non-zero DW_AT_address_class
+ // qualifies the pointee type with the corresponding target address space,
+ // while DW_AT_address_class == 0 or omitted leaves the pointee in the
+ // default address space.
+ cons...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/232588
More information about the lldb-commits
mailing list