[Lldb-commits] [lldb] [lldb] Upstream and adopt ReadUnsignedIntegersFromMemory in AppleObjCRuntimeV2 (PR #190564)

via lldb-commits lldb-commits at lists.llvm.org
Sun Apr 5 17:41:25 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

<details>
<summary>Changes</summary>

This PR upstreams ReadUnsignedIntegersFromMemory, which uses the MultiMemRead packet to speed up reading unsigned numbers from memory. Felipe landed this on Github because we didn't have a use-case for it upstream, until now, which uses it to batch up reading ObjC runtime symbols.

---

Patch is 23.17 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/190564.diff


4 Files Affected:

- (modified) lldb/include/lldb/Target/Process.h (+13) 
- (modified) lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp (+208-112) 
- (modified) lldb/source/Target/Process.cpp (+45) 
- (modified) lldb/unittests/Target/MemoryTest.cpp (+95) 


``````````diff
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 7fe9aa3f5ab1b..2d53a7244011c 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1695,11 +1695,24 @@ class Process : public std::enable_shared_from_this<Process>,
                                          size_t byte_size, uint64_t fail_value,
                                          Status &error);
 
+  /// Use Process::ReadMemoryRanges to efficiently read multiple unsigned
+  /// integers from memory at once.
+  /// TODO: this should be upstream once there is a use for it there.
+  llvm::SmallVector<std::optional<uint64_t>>
+  ReadUnsignedIntegersFromMemory(llvm::ArrayRef<lldb::addr_t> addresses,
+                                 unsigned byte_size);
+
   int64_t ReadSignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size,
                                       int64_t fail_value, Status &error);
 
   lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error);
 
+  /// Use Process::ReadMemoryRanges to efficiently read multiple pointers from
+  /// memory at once.
+  /// TODO: this should be upstream once there is a use for it there.
+  llvm::SmallVector<std::optional<lldb::addr_t>>
+  ReadPointersFromMemory(llvm::ArrayRef<lldb::addr_t> ptr_locs);
+
   bool WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
                             Status &error);
 
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 7ea9154bb28e0..d050721daeff9 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -59,6 +59,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/ScopeExit.h"
 
 #include <cstdint>
@@ -69,6 +70,30 @@
 using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+struct RuntimeGlobalSymbolSpec {
+  ConstString name;
+
+  /// Whether to only return the address or also the value.
+  bool read_value = true;
+
+  /// A byte size of 0 means use the process pointer size.
+  uint8_t byte_size = 0;
+
+  uint64_t default_value = LLDB_INVALID_ADDRESS;
+
+  lldb::SymbolType sym_type = lldb::eSymbolTypeData;
+};
+
+struct RuntimeGlobalSymbolResult {
+  uint64_t value = 0;
+  bool success = false;
+};
+
+/// Constant used for SmallVector.
+static constexpr uint8_t kMaxResults = 12;
+} // namespace
+
 char AppleObjCRuntimeV2::ID = 0;
 
 static const char *g_get_dynamic_class_info_name =
@@ -739,7 +764,7 @@ ExtractRuntimeGlobalSymbol(Process *process, ConstString name,
   if (!byte_size)
     byte_size = process->GetAddressByteSize();
   const Symbol *symbol =
-      module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData);
+      module_sp->FindFirstSymbolWithNameAndType(name, sym_type);
 
   if (!symbol || !symbol->ValueIsAddress()) {
     error = Status::FromErrorString("no symbol");
@@ -759,6 +784,84 @@ ExtractRuntimeGlobalSymbol(Process *process, ConstString name,
   return symbol_load_addr;
 }
 
+// Batched version of ExtractRuntimeGlobalSymbol. Resolves symbols and reads
+// their values in a single batch using ReadUnsignedIntegersFromMemory.
+static llvm::SmallVector<RuntimeGlobalSymbolResult, kMaxResults>
+ExtractRuntimeGlobalSymbolsBatched(
+    Process *process, const ModuleSP &module_sp,
+    llvm::ArrayRef<RuntimeGlobalSymbolSpec> specs) {
+  llvm::SmallVector<RuntimeGlobalSymbolResult, kMaxResults> results;
+  results.resize(specs.size());
+
+  if (!process || !module_sp) {
+    // Return all failures with default values.
+    for (size_t i = 0; i < specs.size(); ++i)
+      results[i] = {specs[i].default_value, false};
+    return results;
+  }
+
+  const uint8_t default_byte_size = process->GetAddressByteSize();
+
+  // Phase 1: Resolve all symbols to addresses. Build a work list of entries
+  // that need their values read in Phase 2.
+  struct ReadEntry {
+    size_t result_idx;
+    lldb::addr_t addr;
+    uint8_t byte_size;
+  };
+  llvm::SmallVector<ReadEntry, kMaxResults> work_list;
+  for (size_t i = 0; i < specs.size(); ++i) {
+    const auto &spec = specs[i];
+    const uint8_t size = spec.byte_size ? spec.byte_size : default_byte_size;
+    const Symbol *symbol =
+        module_sp->FindFirstSymbolWithNameAndType(spec.name, spec.sym_type);
+
+    if (!symbol || !symbol->ValueIsAddress()) {
+      results[i] = {spec.default_value, false};
+      continue;
+    }
+
+    lldb::addr_t symbol_load_addr =
+        symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());
+    if (symbol_load_addr == LLDB_INVALID_ADDRESS) {
+      results[i] = {spec.default_value, false};
+      continue;
+    }
+
+    if (!spec.read_value) {
+      results[i] = {symbol_load_addr, true};
+    } else {
+      results[i] = {spec.default_value, false};
+      work_list.push_back({i, symbol_load_addr, size});
+    }
+  }
+
+  // Phase 2: Batch read values, grouping consecutive entries with the same
+  // byte size into a single ReadUnsignedIntegersFromMemory call.
+  llvm::stable_sort(work_list, [](const ReadEntry &a, const ReadEntry &b) {
+    return a.byte_size < b.byte_size;
+  });
+
+  for (size_t i = 0; i < work_list.size();) {
+    const uint8_t byte_size = work_list[i].byte_size;
+    size_t group_start = i;
+    llvm::SmallVector<lldb::addr_t, kMaxResults> addrs;
+    while (i < work_list.size() && work_list[i].byte_size == byte_size)
+      addrs.push_back(work_list[i++].addr);
+
+    auto read_values =
+        process->ReadUnsignedIntegersFromMemory(addrs, byte_size);
+
+    for (size_t j = 0; j < addrs.size(); ++j) {
+      size_t idx = work_list[group_start + j].result_idx;
+      if (read_values[j].has_value())
+        results[idx] = {*read_values[j], true};
+    }
+  }
+
+  return results;
+}
+
 static void RegisterObjCExceptionRecognizer(Process *process);
 
 AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process,
@@ -2836,56 +2939,61 @@ AppleObjCRuntimeV2::NonPointerISACache::CreateInstance(
     AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {
   Process *process(runtime.GetProcess());
 
-  Status error;
-
   Log *log = GetLog(LLDBLog::Types);
 
-  auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_isa_magic_mask"), objc_module_sp, error);
-  if (error.Fail())
-    return nullptr;
+  // Batch read all the ISA-related symbols in one go.
+  enum ISASymbol {
+    kMagicMask,
+    kMagicValue,
+    kClassMask,
+    kIndexedMagicMask,
+    kIndexedMagicValue,
+    kIndexedIndexMask,
+    kIndexedIndexShift,
+    kIndexedClasses,
+    kISASymbolCount,
+  };
+  llvm::SmallVector<RuntimeGlobalSymbolSpec> specs = {
+      {ConstString("objc_debug_isa_magic_mask")},
+      {ConstString("objc_debug_isa_magic_value")},
+      {ConstString("objc_debug_isa_class_mask")},
+      {ConstString("objc_debug_indexed_isa_magic_mask")},
+      {ConstString("objc_debug_indexed_isa_magic_value")},
+      {ConstString("objc_debug_indexed_isa_index_mask")},
+      {ConstString("objc_debug_indexed_isa_index_shift")},
+      {ConstString("objc_indexed_classes"), /*read_value=*/false},
+  };
+  assert(specs.size() == kISASymbolCount);
 
-  auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_isa_magic_value"), objc_module_sp,
-      error);
-  if (error.Fail())
-    return nullptr;
+  auto results =
+      ExtractRuntimeGlobalSymbolsBatched(process, objc_module_sp, specs);
 
-  auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_isa_class_mask"), objc_module_sp, error);
-  if (error.Fail())
+  // Check required symbols.
+  if (!results[kMagicMask].success || !results[kMagicValue].success ||
+      !results[kClassMask].success)
     return nullptr;
 
+  auto objc_debug_isa_magic_mask = results[kMagicMask].value;
+  auto objc_debug_isa_magic_value = results[kMagicValue].value;
+  auto objc_debug_isa_class_mask = results[kClassMask].value;
+
   if (log)
     log->PutCString("AOCRT::NPI: Found all the non-indexed ISA masks");
 
-  bool foundError = false;
-  auto objc_debug_indexed_isa_magic_mask = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_indexed_isa_magic_mask"), objc_module_sp,
-      error);
-  foundError |= error.Fail();
-
-  auto objc_debug_indexed_isa_magic_value = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_indexed_isa_magic_value"),
-      objc_module_sp, error);
-  foundError |= error.Fail();
-
-  auto objc_debug_indexed_isa_index_mask = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_indexed_isa_index_mask"), objc_module_sp,
-      error);
-  foundError |= error.Fail();
-
-  auto objc_debug_indexed_isa_index_shift = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_indexed_isa_index_shift"),
-      objc_module_sp, error);
-  foundError |= error.Fail();
+  // Check optional indexed ISA symbols.
+  bool foundError = !results[kIndexedMagicMask].success ||
+                    !results[kIndexedMagicValue].success ||
+                    !results[kIndexedIndexMask].success ||
+                    !results[kIndexedIndexShift].success ||
+                    !results[kIndexedClasses].success;
 
-  auto objc_indexed_classes =
-      ExtractRuntimeGlobalSymbol(process, ConstString("objc_indexed_classes"),
-                                 objc_module_sp, error, false);
-  foundError |= error.Fail();
+  auto objc_debug_indexed_isa_magic_mask = results[kIndexedMagicMask].value;
+  auto objc_debug_indexed_isa_magic_value = results[kIndexedMagicValue].value;
+  auto objc_debug_indexed_isa_index_mask = results[kIndexedIndexMask].value;
+  auto objc_debug_indexed_isa_index_shift = results[kIndexedIndexShift].value;
+  auto objc_indexed_classes = results[kIndexedClasses].value;
 
-  if (log)
+  if (log && !foundError)
     log->PutCString("AOCRT::NPI: Found all the indexed ISA masks");
 
   // we might want to have some rules to outlaw these other values (e.g if the
@@ -2904,84 +3012,72 @@ AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance(
     AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {
   Process *process(runtime.GetProcess());
 
-  Status error;
-
-  auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_taggedpointer_mask"), objc_module_sp,
-      error);
-  if (error.Fail())
-    return new TaggedPointerVendorLegacy(runtime);
-
-  auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_taggedpointer_slot_shift"),
-      objc_module_sp, error, true, 4);
-  if (error.Fail())
-    return new TaggedPointerVendorLegacy(runtime);
-
-  auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_taggedpointer_slot_mask"),
-      objc_module_sp, error, true, 4);
-  if (error.Fail())
-    return new TaggedPointerVendorLegacy(runtime);
+  // Batch read all tagged pointer symbols in one go.
+  enum TaggedPtrSymbol {
+    kMask,
+    kSlotShift,
+    kSlotMask,
+    kPayloadLshift,
+    kPayloadRshift,
+    kClasses,
+    kExtMask,
+    kExtSlotShift,
+    kExtSlotMask,
+    kExtClasses,
+    kExtPayloadLshift,
+    kExtPayloadRshift,
+    kTaggedPtrSymbolCount,
+  };
+  llvm::SmallVector<RuntimeGlobalSymbolSpec> specs = {
+      {ConstString("objc_debug_taggedpointer_mask")},
+      {ConstString("objc_debug_taggedpointer_slot_shift"), true, 4},
+      {ConstString("objc_debug_taggedpointer_slot_mask"), true, 4},
+      {ConstString("objc_debug_taggedpointer_payload_lshift"), true, 4},
+      {ConstString("objc_debug_taggedpointer_payload_rshift"), true, 4},
+      {ConstString("objc_debug_taggedpointer_classes"), false},
+      {ConstString("objc_debug_taggedpointer_ext_mask")},
+      {ConstString("objc_debug_taggedpointer_ext_slot_shift"), true, 4},
+      {ConstString("objc_debug_taggedpointer_ext_slot_mask"), true, 4},
+      {ConstString("objc_debug_taggedpointer_ext_classes"), false},
+      {ConstString("objc_debug_taggedpointer_ext_payload_lshift"), true, 4},
+      {ConstString("objc_debug_taggedpointer_ext_payload_rshift"), true, 4},
+  };
+  assert(specs.size() == kTaggedPtrSymbolCount);
 
-  auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_taggedpointer_payload_lshift"),
-      objc_module_sp, error, true, 4);
-  if (error.Fail())
-    return new TaggedPointerVendorLegacy(runtime);
+  auto results =
+      ExtractRuntimeGlobalSymbolsBatched(process, objc_module_sp, specs);
 
-  auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_taggedpointer_payload_rshift"),
-      objc_module_sp, error, true, 4);
-  if (error.Fail())
-    return new TaggedPointerVendorLegacy(runtime);
+  // Check required symbols.
+  bool required_success =
+      results[kMask].success && results[kSlotShift].success &&
+      results[kSlotMask].success && results[kPayloadLshift].success &&
+      results[kPayloadRshift].success && results[kClasses].success;
 
-  auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol(
-      process, ConstString("objc_debug_taggedpointer_classes"), objc_module_sp,
-      error, false);
-  if (error.Fail())
+  if (!required_success)
     return new TaggedPointerVendorLegacy(runtime);
 
-  // try to detect the "extended tagged pointer" variables - if any are
-  // missing, use the non-extended vendor
-  do {
-    auto objc_debug_taggedpointer_ext_mask = ExtractRuntimeGlobalSymbol(
-        process, ConstString("objc_debug_taggedpointer_ext_mask"),
-        objc_module_sp, error);
-    if (error.Fail())
-      break;
-
-    auto objc_debug_taggedpointer_ext_slot_shift = ExtractRuntimeGlobalSymbol(
-        process, ConstString("objc_debug_taggedpointer_ext_slot_shift"),
-        objc_module_sp, error, true, 4);
-    if (error.Fail())
-      break;
-
-    auto objc_debug_taggedpointer_ext_slot_mask = ExtractRuntimeGlobalSymbol(
-        process, ConstString("objc_debug_taggedpointer_ext_slot_mask"),
-        objc_module_sp, error, true, 4);
-    if (error.Fail())
-      break;
-
-    auto objc_debug_taggedpointer_ext_classes = ExtractRuntimeGlobalSymbol(
-        process, ConstString("objc_debug_taggedpointer_ext_classes"),
-        objc_module_sp, error, false);
-    if (error.Fail())
-      break;
-
+  auto objc_debug_taggedpointer_mask = results[kMask].value;
+  auto objc_debug_taggedpointer_slot_shift = results[kSlotShift].value;
+  auto objc_debug_taggedpointer_slot_mask = results[kSlotMask].value;
+  auto objc_debug_taggedpointer_payload_lshift = results[kPayloadLshift].value;
+  auto objc_debug_taggedpointer_payload_rshift = results[kPayloadRshift].value;
+  auto objc_debug_taggedpointer_classes = results[kClasses].value;
+
+  // Check if extended symbols are all present.
+  bool extended_success =
+      results[kExtMask].success && results[kExtSlotShift].success &&
+      results[kExtSlotMask].success && results[kExtClasses].success &&
+      results[kExtPayloadLshift].success && results[kExtPayloadRshift].success;
+
+  if (extended_success) {
+    auto objc_debug_taggedpointer_ext_mask = results[kExtMask].value;
+    auto objc_debug_taggedpointer_ext_slot_shift = results[kExtSlotShift].value;
+    auto objc_debug_taggedpointer_ext_slot_mask = results[kExtSlotMask].value;
+    auto objc_debug_taggedpointer_ext_classes = results[kExtClasses].value;
     auto objc_debug_taggedpointer_ext_payload_lshift =
-        ExtractRuntimeGlobalSymbol(
-            process, ConstString("objc_debug_taggedpointer_ext_payload_lshift"),
-            objc_module_sp, error, true, 4);
-    if (error.Fail())
-      break;
-
+        results[kExtPayloadLshift].value;
     auto objc_debug_taggedpointer_ext_payload_rshift =
-        ExtractRuntimeGlobalSymbol(
-            process, ConstString("objc_debug_taggedpointer_ext_payload_rshift"),
-            objc_module_sp, error, true, 4);
-    if (error.Fail())
-      break;
+        results[kExtPayloadRshift].value;
 
     return new TaggedPointerVendorExtended(
         runtime, objc_debug_taggedpointer_mask,
@@ -2994,7 +3090,7 @@ AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance(
         objc_debug_taggedpointer_ext_payload_lshift,
         objc_debug_taggedpointer_ext_payload_rshift,
         objc_debug_taggedpointer_classes, objc_debug_taggedpointer_ext_classes);
-  } while (false);
+  }
 
   // we might want to have some rules to outlaw these values (e.g if the
   // table's address is zero)
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index ac182f1746712..5abbb82fd2521 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -2316,6 +2316,45 @@ uint64_t Process::ReadUnsignedIntegerFromMemory(lldb::addr_t vm_addr,
   return fail_value;
 }
 
+llvm::SmallVector<std::optional<uint64_t>>
+Process::ReadUnsignedIntegersFromMemory(llvm::ArrayRef<addr_t> addresses,
+                                        unsigned integer_byte_size) {
+  if (addresses.empty())
+    return {};
+  // Like ReadUnsignedIntegerFromMemory, this only supports a handful
+  // of widths.
+  if (!llvm::is_contained({1u, 2u, 4u, 8u}, integer_byte_size))
+    return llvm::SmallVector<std::optional<uint64_t>>(addresses.size(),
+                                                      std::nullopt);
+
+  llvm::SmallVector<Range<addr_t, size_t>> ranges{
+      llvm::map_range(addresses, [=](addr_t ptr) {
+        return Range<addr_t, size_t>(ptr, integer_byte_size);
+      })};
+
+  std::vector<uint8_t> buffer(integer_byte_size * addresses.size(), 0);
+  llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> memory =
+      ReadMemoryRanges(ranges, buffer);
+
+  llvm::SmallVector<std::optional<uint64_t>> result;
+  result.reserve(addresses.size());
+  const uint32_t addr_size = GetAddressByteSize();
+  const ByteOrder byte_order = GetByteOrder();
+
+  for (llvm::MutableArrayRef<uint8_t> range : memory) {
+    if (range.size() != integer_byte_size) {
+      result.push_back(std::nullopt);
+      continue;
+    }
+
+    DataExtractor data(range.data(), integer_byte_size, byte_order, addr_size);
+    offset_t offset = 0;
+    result.push_back(data.GetMaxU64(&offset, integer_byte_size));
+    assert(offset == integer_byte_size);
+  }
+  return result;
+}
+
 int64_t Process::ReadSignedIntegerFromMemory(lldb::addr_t vm_addr,
                                              size_t integer_byte_size,
                                              int64_t fail_value,
@@ -2335,6 +2374,12 @@ addr_t Process::ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error) {
   return LLDB_INVALID_ADDRESS;
 }
 
+llvm::SmallVector<std::optional<addr_t>>
+Process::ReadPointersFromMemory(llvm::ArrayRef<addr_t> ptr_locs) {
+  const size_t ptr_size = GetAddressByteSize();
+  return ReadUnsignedIntegersFromMemory(ptr_locs, ptr_size);
+}
+
 bool Process::WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
                                    Status &error) {
   Scalar scalar;
diff --git a/lldb/unittests/Target/MemoryTest.cpp b/lldb/unittests/Target/MemoryTest.cpp
index 47aa105cdfecd..21045725be84a 100644
--- a/lldb/unittests/Target/MemoryTest.cpp
+++ b/lldb/unittests/Target/MemoryTest.cpp
@@ -521,3 +521,98 @@ TEST_F(MemoryTest, TestReadCStringsFromMemory) {
        llvm::zip(expected_valid_strings, expected_answers))
     EXPECT_EQ(maybe_str, expected_answer);
 }
+
+TEST_F(MemoryTest, TestReadPointersFromMemory) {
+  ArchSpec arch("x86_64-apple-macosx-");
+  Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
+  DebuggerSP debugger_sp = Debugger::CreateInstance();
+  ASSERT_TRUE(debugger_sp);
+  TargetSP target_sp = CreateTarget(debugger_sp, arch);
+  ASSERT_TRUE(target_sp);
+  ListenerSP listener_sp(Listener::MakeListener("dummy"));
+  ProcessSP process =
+      std::make_shared<DummyReaderProcess>(target_sp, listener_sp);
+  ASSERT_TRUE(process);
+
+  // Read pointers at arbitrary addresses.
+  llvm::SmallVector<ad...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/190564


More information about the lldb-commits mailing list