[Lldb-commits] [lldb] [lldb] Introduce DynamicRegisterInfo::RegisterSetWithStorage (PR #225555)

Alex Langford via lldb-commits lldb-commits at lists.llvm.org
Tue Sep 22 16:58:23 PDT 2026


https://github.com/bulbazord created https://github.com/llvm/llvm-project/pull/225555

The RegisterSet struct is created in 2 different ways:
1.) Statically in headers/source files for register sets that are known
    ahead of time.
2.) Dynamically according to input from outside of LLDB. Usually this is
    through the gdb-remote stub, but may also come from a python script or
    by determining an ISA variant's features (e.g. in RISCV).

This PR aims to address the lifetime of strings in RegisterSet. In scenario (1), the lifetime of all data in a RegisterSet is static and there is no concern about dangling pointers. However, in scenario (2), DynamicRegisterInfo maintains a vector of RegisterSets. Until now, it has relied on ConstString to persist the storage for the strings indefinitely. As part of my quest to remove ConstString, I am introducing a new struct wrapping RegisterSet that is responsible for the storage and lifetime of the underlying RegisterSet strings.

>From 13ae15e37023236cf867b50620cc04044ffb110a Mon Sep 17 00:00:00 2001
From: Alex Langford <alangford at apple.com>
Date: Tue, 22 Sep 2026 15:04:48 -0700
Subject: [PATCH] [lldb] Introduce DynamicRegisterInfo::RegisterSetWithStorage

The RegisterSet struct is created in 2 different ways:
1.) Statically in headers/source files for register sets that are known
    ahead of time.
2.) Dynamically according to input from outside of LLDB. Usually this is
    through the gdb-remote stub, but may also come from a python script or
    by determining an ISA variant's features (e.g. in RISCV).

This PR aims to address the lifetime of strings in RegisterSet. In
scenario (1), the lifetime of all data in a RegisterSet is static and
there is no concern about dangling pointers. However, in scenario (2),
DynamicRegisterInfo maintains a vector of RegisterSets. Until now, it
has relied on ConstString to persist the storage for the strings
indefinitely. As part of my quest to remove ConstString, I am
introducing a new struct wrapping RegisterSet that is responsible for
the storage and lifetime of the underlying RegisterSet strings.
---
 .../include/lldb/Target/DynamicRegisterInfo.h | 35 ++++++++++++++++++-
 lldb/source/Target/DynamicRegisterInfo.cpp    | 21 ++++++-----
 2 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/lldb/include/lldb/Target/DynamicRegisterInfo.h b/lldb/include/lldb/Target/DynamicRegisterInfo.h
index c7bd47a720fac9..dbb5181194c506 100644
--- a/lldb/include/lldb/Target/DynamicRegisterInfo.h
+++ b/lldb/include/lldb/Target/DynamicRegisterInfo.h
@@ -98,8 +98,41 @@ class DynamicRegisterInfo {
   void ConfigureOffsets();
 
 protected:
+  struct RegisterSetWithStorage {
+    RegisterSetWithStorage(std::string name, std::string short_name,
+                           size_t num_registers, const uint32_t *registers)
+        : m_name(std::move(name)), m_short_name(std::move(short_name)) {
+      m_set.name = m_name.c_str();
+      m_set.short_name = m_short_name.c_str();
+      m_set.num_registers = num_registers;
+      m_set.registers = registers;
+    }
+
+    RegisterSetWithStorage(const RegisterSetWithStorage &rhs)
+        : m_name(rhs.m_name), m_short_name(rhs.m_short_name) {
+      m_set = rhs.m_set;
+      // m_set's strings must be re-set, otherwise they will still point to
+      // strings in rhs.
+      m_set.name = m_name.c_str();
+      m_set.short_name = m_short_name.c_str();
+    }
+
+    RegisterSetWithStorage(RegisterSetWithStorage &&rhs)
+        : m_set(rhs.m_set), m_name(std::move(rhs.m_name)),
+          m_short_name(std::move(rhs.m_short_name)) {
+      // m_set's strings must be re-set, otherwise they will still point to
+      // strings in rhs.
+      m_set.name = m_name.c_str();
+      m_set.short_name = m_short_name.c_str();
+    }
+
+    lldb_private::RegisterSet m_set;
+    std::string m_name;
+    std::string m_short_name;
+  };
+
   // Classes that inherit from DynamicRegisterInfo can see and modify these
-  typedef std::vector<lldb_private::RegisterSet> set_collection;
+  typedef std::vector<RegisterSetWithStorage> set_collection;
   typedef std::vector<uint32_t> reg_num_collection;
   typedef std::vector<reg_num_collection> set_reg_num_collection;
   typedef std::map<uint32_t, reg_num_collection> reg_to_regs_map;
diff --git a/lldb/source/Target/DynamicRegisterInfo.cpp b/lldb/source/Target/DynamicRegisterInfo.cpp
index 2c83674893b5c0..ee6abe4dbb7a66 100644
--- a/lldb/source/Target/DynamicRegisterInfo.cpp
+++ b/lldb/source/Target/DynamicRegisterInfo.cpp
@@ -56,7 +56,7 @@ void DynamicRegisterInfo::MoveFrom(DynamicRegisterInfo &&info) {
   if (m_finalized) {
     const size_t num_sets = m_sets.size();
     for (size_t set = 0; set < num_sets; ++set)
-      m_sets[set].registers = m_set_reg_nums[set].data();
+      m_sets[set].m_set.registers = m_set_reg_nums[set].data();
   }
 
   info.Clear();
@@ -208,8 +208,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
       std::optional<llvm::StringRef> maybe_set_name =
           sets->GetItemAtIndexAsString(i);
       if (maybe_set_name && !maybe_set_name->empty()) {
-        m_sets.push_back({ConstString(*maybe_set_name).AsCString(nullptr),
-                          nullptr, 0, nullptr});
+        m_sets.push_back({maybe_set_name->str(), std::string(), 0, nullptr});
       } else {
         Clear();
         printf("error: register sets must have valid names\n");
@@ -436,8 +435,8 @@ size_t DynamicRegisterInfo::SetRegisterInfo(
 
       set_name_to_idx.insert({reg.set_name, next_idx++});
       m_set_reg_nums.resize(m_set_reg_nums.size() + 1);
-      RegisterSet new_set = {reg.set_name.GetCString(), nullptr, 0, nullptr};
-      m_sets.push_back(new_set);
+      m_sets.push_back(
+          {reg.set_name.GetStringRef().str(), std::string(), 0, nullptr});
     } else {
       set_idx = set_name_to_idx.lookup(reg.set_name);
     }
@@ -459,8 +458,8 @@ void DynamicRegisterInfo::Finalize(const ArchSpec &arch) {
   const size_t num_sets = m_sets.size();
   for (size_t set = 0; set < num_sets; ++set) {
     assert(m_sets.size() == m_set_reg_nums.size());
-    m_sets[set].num_registers = m_set_reg_nums[set].size();
-    m_sets[set].registers = m_set_reg_nums[set].data();
+    m_sets[set].m_set.num_registers = m_set_reg_nums[set].size();
+    m_sets[set].m_set.registers = m_set_reg_nums[set].data();
   }
 
   // make sure value_regs are terminated with LLDB_INVALID_REGNUM
@@ -718,7 +717,7 @@ const RegisterInfo *DynamicRegisterInfo::GetRegisterInfo(uint32_t kind,
 
 const RegisterSet *DynamicRegisterInfo::GetRegisterSet(uint32_t i) const {
   if (i < m_sets.size())
-    return &m_sets[i];
+    return &(m_sets[i].m_set);
   return nullptr;
 }
 
@@ -787,9 +786,9 @@ void DynamicRegisterInfo::Dump(Stream &s) const {
            static_cast<const void *>(this), static_cast<uint64_t>(num_sets));
   for (size_t i = 0; i < num_sets; ++i) {
     s.Printf("set[%" PRIu64 "] name = %s, regs = [", (uint64_t)i,
-             m_sets[i].name);
-    for (size_t idx = 0; idx < m_sets[i].num_registers; ++idx) {
-      s.Printf("%s ", m_regs[m_sets[i].registers[idx]].name);
+             m_sets[i].m_name.c_str());
+    for (size_t idx = 0; idx < m_sets[i].m_set.num_registers; ++idx) {
+      s.Printf("%s ", m_regs[m_sets[i].m_set.registers[idx]].name);
     }
     s.PutCString("]\n");
   }



More information about the lldb-commits mailing list