[Lldb-commits] [lldb] [lldb] Add support for unique target ids (PR #160736)

Janet Yang via lldb-commits lldb-commits at lists.llvm.org
Thu Oct 2 05:48:50 PDT 2025


https://github.com/qxy11 updated https://github.com/llvm/llvm-project/pull/160736

>From c155381f49915fa98bd6e3ea14eb77b1dfcd7dbd Mon Sep 17 00:00:00 2001
From: qxy11 <qxy11 at fb.com>
Date: Thu, 25 Sep 2025 09:54:50 -0700
Subject: [PATCH 1/5] Add support for unique target ids

---
 lldb/include/lldb/API/SBDebugger.h            |   3 +
 lldb/include/lldb/API/SBTarget.h              |   2 +
 lldb/include/lldb/Target/Target.h             |   7 ++
 lldb/include/lldb/Target/TargetList.h         |   2 +
 lldb/source/API/SBDebugger.cpp                |  10 ++
 lldb/source/API/SBTarget.cpp                  |   8 ++
 lldb/source/Target/TargetList.cpp             |  16 +++
 .../python_api/debugger/TestDebuggerAPI.py    | 103 ++++++++++++++++++
 8 files changed, 151 insertions(+)

diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h
index f77b0c1d7f0ee..efd95677d1d36 100644
--- a/lldb/include/lldb/API/SBDebugger.h
+++ b/lldb/include/lldb/API/SBDebugger.h
@@ -359,6 +359,9 @@ class LLDB_API SBDebugger {
   lldb::SBTarget FindTargetWithFileAndArch(const char *filename,
                                            const char *arch);
 
+  /// Find a target with the specified unique ID
+  lldb::SBTarget FindTargetWithUniqueID(uint32_t id);
+
   /// Get the number of targets in the debugger.
   uint32_t GetNumTargets();
 
diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index 62cdd342a05e4..1eef9368dceaf 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -357,6 +357,8 @@ class LLDB_API SBTarget {
 
   const char *GetLabel() const;
 
+  uint32_t GetUniqueID() const;
+
   SBError SetLabel(const char *label);
 
   /// Architecture opcode byte size width accessor
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 14a09f29094d5..14375929688e4 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -600,6 +600,12 @@ class Target : public std::enable_shared_from_this<Target>,
 
   bool IsDummyTarget() const { return m_is_dummy_target; }
 
+  /// Get the unique ID for this target.
+  ///
+  /// \return
+  ///     The unique ID for this target, or 0 if no ID has been assigned.
+  uint32_t GetUniqueID() const { return m_target_unique_id; }
+
   const std::string &GetLabel() const { return m_label; }
 
   /// Set a label for a target.
@@ -1651,6 +1657,7 @@ class Target : public std::enable_shared_from_this<Target>,
   bool m_suppress_stop_hooks; /// Used to not run stop hooks for expressions
   bool m_is_dummy_target;
   unsigned m_next_persistent_variable_index = 0;
+  uint32_t m_target_unique_id = 0; /// The unique ID assigned to this target
   /// An optional \a lldb_private::Trace object containing processor trace
   /// information of this target.
   lldb::TraceSP m_trace_sp;
diff --git a/lldb/include/lldb/Target/TargetList.h b/lldb/include/lldb/Target/TargetList.h
index 080a6039c7ff8..343fc1676ec30 100644
--- a/lldb/include/lldb/Target/TargetList.h
+++ b/lldb/include/lldb/Target/TargetList.h
@@ -159,6 +159,8 @@ class TargetList : public Broadcaster {
 
   lldb::TargetSP FindTargetWithProcess(lldb_private::Process *process) const;
 
+  lldb::TargetSP FindTargetWithUniqueID(uint32_t id) const;
+
   lldb::TargetSP GetTargetSP(Target *target) const;
 
   /// Send an async interrupt to one or all processes.
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index 603e306497841..f4b46cc3b1873 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -983,6 +983,16 @@ uint32_t SBDebugger::GetIndexOfTarget(lldb::SBTarget target) {
   return m_opaque_sp->GetTargetList().GetIndexOfTarget(target.GetSP());
 }
 
+SBTarget SBDebugger::FindTargetWithUniqueID(uint32_t id) {
+  LLDB_INSTRUMENT_VA(this, id);
+  SBTarget sb_target;
+  if (m_opaque_sp) {
+    // No need to lock, the target list is thread safe
+    sb_target.SetSP(m_opaque_sp->GetTargetList().FindTargetWithUniqueID(id));
+  }
+  return sb_target;
+}
+
 SBTarget SBDebugger::FindTargetWithProcessID(lldb::pid_t pid) {
   LLDB_INSTRUMENT_VA(this, pid);
 
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index eb56337de3c44..affde64a389af 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1632,6 +1632,14 @@ const char *SBTarget::GetLabel() const {
   return nullptr;
 }
 
+uint32_t SBTarget::GetUniqueID() const {
+  LLDB_INSTRUMENT_VA(this);
+
+  if (TargetSP target_sp = GetSP())
+    return target_sp->GetUniqueID();
+  return 0;
+}
+
 SBError SBTarget::SetLabel(const char *label) {
   LLDB_INSTRUMENT_VA(this, label);
 
diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp
index 7037dc2bea3cc..3ae61df3460b7 100644
--- a/lldb/source/Target/TargetList.cpp
+++ b/lldb/source/Target/TargetList.cpp
@@ -256,6 +256,8 @@ Status TargetList::CreateTargetInternal(Debugger &debugger,
   Status error;
   const bool is_dummy_target = false;
 
+  static uint32_t g_target_unique_id = 0;
+
   ArchSpec arch(specified_arch);
 
   if (arch.IsValid()) {
@@ -344,6 +346,8 @@ Status TargetList::CreateTargetInternal(Debugger &debugger,
   if (!target_sp)
     return error;
 
+  target_sp->m_target_unique_id = ++g_target_unique_id;
+
   // Set argv0 with what the user typed, unless the user specified a
   // directory. If the user specified a directory, then it is probably a
   // bundle that was resolved and we need to use the resolved bundle path
@@ -428,6 +432,18 @@ TargetSP TargetList::FindTargetWithProcess(Process *process) const {
   return target_sp;
 }
 
+TargetSP TargetList::FindTargetWithUniqueID(uint32_t id) const {
+  std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
+  auto it = llvm::find_if(m_target_list, [id](const TargetSP &item) {
+    return item->GetUniqueID() == id;
+  });
+
+  if (it != m_target_list.end())
+    return *it;
+
+  return TargetSP();
+}
+
 TargetSP TargetList::GetTargetSP(Target *target) const {
   TargetSP target_sp;
   if (!target)
diff --git a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
index 43f45f330ee2a..4d82fdc83b2cf 100644
--- a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
+++ b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
@@ -294,3 +294,106 @@ def test_version(self):
 
         self.assertEqual(instance_str, class_str)
         self.assertEqual(class_str, property_str)
+
+    def test_find_target_with_unique_id(self):
+        """Test SBDebugger.FindTargetWithUniqueID() functionality."""
+
+        # Test with invalid ID - should return invalid target
+        invalid_target = self.dbg.FindTargetWithUniqueID(999999)
+        self.assertFalse(invalid_target.IsValid())
+
+        # Test with ID 0 - should return invalid target
+        zero_target = self.dbg.FindTargetWithUniqueID(0)
+        self.assertFalse(zero_target.IsValid())
+
+        # Build a real executable and create target with it
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target.IsValid())
+
+        # Find the target using its unique ID
+        unique_id = target.GetUniqueID()
+        self.assertNotEqual(unique_id, 0)
+        found_target = self.dbg.FindTargetWithUniqueID(unique_id)
+        self.assertTrue(found_target.IsValid())
+        self.assertEqual(
+            self.dbg.GetIndexOfTarget(target), self.dbg.GetIndexOfTarget(found_target)
+        )
+        self.assertEqual(found_target.GetUniqueID(), unique_id)
+
+    def test_target_unique_id_uniqueness(self):
+        """Test that Target.GetUniqueID() returns unique values across multiple targets."""
+
+        # Create multiple targets and verify they all have unique IDs
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        targets = []
+        unique_ids = set()
+
+        for i in range(10):
+            target = self.dbg.CreateTarget(exe)
+            self.assertTrue(target.IsValid())
+
+            unique_id = target.GetUniqueID()
+            self.assertNotEqual(unique_id, 0)
+
+            # Verify this ID hasn't been used before
+            self.assertNotIn(
+                unique_id, unique_ids, f"Duplicate unique ID found: {unique_id}"
+            )
+
+            unique_ids.add(unique_id)
+            targets.append(target)
+
+        # Verify all targets can still be found by their IDs
+        for target in targets:
+            unique_id = target.GetUniqueID()
+            found = self.dbg.FindTargetWithUniqueID(unique_id)
+            self.assertTrue(found.IsValid())
+            self.assertEqual(found.GetUniqueID(), unique_id)
+
+    def test_target_unique_id_uniqueness_after_deletion(self):
+        """Test finding targets have unique ID after target deletion."""
+        # Create two targets
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target1 = self.dbg.CreateTarget(exe)
+        target2 = self.dbg.CreateTarget(exe)
+        self.assertTrue(target1.IsValid())
+        self.assertTrue(target2.IsValid())
+
+        unique_id1 = target1.GetUniqueID()
+        unique_id2 = target2.GetUniqueID()
+        self.assertNotEqual(unique_id1, 0)
+        self.assertNotEqual(unique_id2, 0)
+        self.assertNotEqual(unique_id1, unique_id2)
+
+        # Verify we can find them initially
+        found_target1 = self.dbg.FindTargetWithUniqueID(unique_id1)
+        found_target2 = self.dbg.FindTargetWithUniqueID(unique_id2)
+        self.assertTrue(found_target1.IsValid())
+        self.assertTrue(found_target2.IsValid())
+        target2_index = self.dbg.GetIndexOfTarget(target2)
+
+        # Delete target 2
+        deleted = self.dbg.DeleteTarget(target2)
+        self.assertTrue(deleted)
+
+        # Try to find the deleted target - should not be found
+        not_found_target = self.dbg.FindTargetWithUniqueID(unique_id2)
+        self.assertFalse(not_found_target.IsValid())
+
+        # Create a new target
+        target3 = self.dbg.CreateTarget(exe)
+        self.assertTrue(target3.IsValid())
+        # Target list index of target3 should be the same as target2's
+        # since it was deleted, but it should have a distinct unique ID
+        target3_index = self.dbg.GetIndexOfTarget(target3)
+        unique_id3 = target3.GetUniqueID()
+        self.assertEqual(target3_index, target2_index)
+        self.assertNotEqual(unique_id3, unique_id2)
+        self.assertNotEqual(unique_id3, unique_id1)
+        # Make sure we can find the new target
+        found_target3 = self.dbg.FindTargetWithUniqueID(target3.GetUniqueID())
+        self.assertTrue(found_target3.IsValid())

>From 87c941846df70b1c0fca1c4d2111bd079624169a Mon Sep 17 00:00:00 2001
From: qxy11 <qxy11 at fb.com>
Date: Tue, 30 Sep 2025 11:35:27 -0700
Subject: [PATCH 2/5] Set unique ID in Target constructor

---
 lldb/include/lldb/Target/Target.h | 3 ++-
 lldb/include/lldb/lldb-defines.h  | 1 +
 lldb/source/API/SBTarget.cpp      | 2 +-
 lldb/source/Target/Target.cpp     | 3 +++
 lldb/source/Target/TargetList.cpp | 4 ----
 5 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 14375929688e4..ff95de71bdef6 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -1657,7 +1657,8 @@ class Target : public std::enable_shared_from_this<Target>,
   bool m_suppress_stop_hooks; /// Used to not run stop hooks for expressions
   bool m_is_dummy_target;
   unsigned m_next_persistent_variable_index = 0;
-  uint32_t m_target_unique_id = 0; /// The unique ID assigned to this target
+  uint32_t m_target_unique_id =
+      LLDB_INVALID_TARGET_ID; /// The unique ID assigned to this target
   /// An optional \a lldb_private::Trace object containing processor trace
   /// information of this target.
   lldb::TraceSP m_trace_sp;
diff --git a/lldb/include/lldb/lldb-defines.h b/lldb/include/lldb/lldb-defines.h
index c7bd019c5c90e..4a916a83c4fa0 100644
--- a/lldb/include/lldb/lldb-defines.h
+++ b/lldb/include/lldb/lldb-defines.h
@@ -96,6 +96,7 @@
 #define LLDB_INVALID_QUEUE_ID 0
 #define LLDB_INVALID_CPU_ID UINT32_MAX
 #define LLDB_INVALID_WATCHPOINT_RESOURCE_ID UINT32_MAX
+#define LLDB_INVALID_TARGET_ID 0
 
 /// CPU Type definitions
 #define LLDB_ARCH_DEFAULT "systemArch"
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index affde64a389af..de4bbe66f17fb 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1637,7 +1637,7 @@ uint32_t SBTarget::GetUniqueID() const {
 
   if (TargetSP target_sp = GetSP())
     return target_sp->GetUniqueID();
-  return 0;
+  return LLDB_INVALID_TARGET_ID;
 }
 
 SBError SBTarget::SetLabel(const char *label) {
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index fa98c24606492..d282ba2df471f 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -139,6 +139,8 @@ struct MainExecutableInstaller {
 };
 } // namespace
 
+static uint32_t g_target_unique_id = 1;
+
 template <typename Installer>
 static Status installExecutable(const Installer &installer) {
   if (!installer.m_local_file || !installer.m_remote_file)
@@ -183,6 +185,7 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch,
       m_source_manager_up(), m_stop_hooks(), m_stop_hook_next_id(0),
       m_latest_stop_hook_id(0), m_valid(true), m_suppress_stop_hooks(false),
       m_is_dummy_target(is_dummy_target),
+      m_target_unique_id(g_target_unique_id++),
       m_frame_recognizer_manager_up(
           std::make_unique<StackFrameRecognizerManager>()) {
   SetEventName(eBroadcastBitBreakpointChanged, "breakpoint-changed");
diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp
index 3ae61df3460b7..fa86b3b609e59 100644
--- a/lldb/source/Target/TargetList.cpp
+++ b/lldb/source/Target/TargetList.cpp
@@ -256,8 +256,6 @@ Status TargetList::CreateTargetInternal(Debugger &debugger,
   Status error;
   const bool is_dummy_target = false;
 
-  static uint32_t g_target_unique_id = 0;
-
   ArchSpec arch(specified_arch);
 
   if (arch.IsValid()) {
@@ -346,8 +344,6 @@ Status TargetList::CreateTargetInternal(Debugger &debugger,
   if (!target_sp)
     return error;
 
-  target_sp->m_target_unique_id = ++g_target_unique_id;
-
   // Set argv0 with what the user typed, unless the user specified a
   // directory. If the user specified a directory, then it is probably a
   // bundle that was resolved and we need to use the resolved bundle path

>From dfe2644c4b2cd9f6b0062f57afdd9ff3bfdc7bf6 Mon Sep 17 00:00:00 2001
From: qxy11 <qxy11 at fb.com>
Date: Tue, 30 Sep 2025 13:29:02 -0700
Subject: [PATCH 3/5] Use atomic counter for target id

Summary:
Also use lldb::user_id_t throughout instead of uint32_t. It seems to be the custom around the codebase to use this type for unique ids rather than a uint32_t
---
 lldb/include/lldb/API/SBTarget.h  | 2 +-
 lldb/include/lldb/Target/Target.h | 6 +++---
 lldb/source/API/SBTarget.cpp      | 2 +-
 lldb/source/Target/Target.cpp     | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index 1eef9368dceaf..18a6d12be15b0 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -357,7 +357,7 @@ class LLDB_API SBTarget {
 
   const char *GetLabel() const;
 
-  uint32_t GetUniqueID() const;
+  lldb::user_id_t GetUniqueID() const;
 
   SBError SetLabel(const char *label);
 
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index ff95de71bdef6..5b83c66779d13 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -603,8 +603,8 @@ class Target : public std::enable_shared_from_this<Target>,
   /// Get the unique ID for this target.
   ///
   /// \return
-  ///     The unique ID for this target, or 0 if no ID has been assigned.
-  uint32_t GetUniqueID() const { return m_target_unique_id; }
+  ///     The unique ID for this target.
+  lldb::user_id_t GetUniqueID() const { return m_target_unique_id; }
 
   const std::string &GetLabel() const { return m_label; }
 
@@ -1657,7 +1657,7 @@ class Target : public std::enable_shared_from_this<Target>,
   bool m_suppress_stop_hooks; /// Used to not run stop hooks for expressions
   bool m_is_dummy_target;
   unsigned m_next_persistent_variable_index = 0;
-  uint32_t m_target_unique_id =
+  lldb::user_id_t m_target_unique_id =
       LLDB_INVALID_TARGET_ID; /// The unique ID assigned to this target
   /// An optional \a lldb_private::Trace object containing processor trace
   /// information of this target.
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index de4bbe66f17fb..28c05fa33990f 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1632,7 +1632,7 @@ const char *SBTarget::GetLabel() const {
   return nullptr;
 }
 
-uint32_t SBTarget::GetUniqueID() const {
+lldb::user_id_t SBTarget::GetUniqueID() const {
   LLDB_INSTRUMENT_VA(this);
 
   if (TargetSP target_sp = GetSP())
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index d282ba2df471f..e0286c4576ae5 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -139,7 +139,7 @@ struct MainExecutableInstaller {
 };
 } // namespace
 
-static uint32_t g_target_unique_id = 1;
+static std::atomic<lldb::user_id_t> g_target_unique_id{1};
 
 template <typename Installer>
 static Status installExecutable(const Installer &installer) {

>From a363167b57275b957694ccab7c0177cd8234c0dd Mon Sep 17 00:00:00 2001
From: qxy11 <qxy11 at fb.com>
Date: Tue, 30 Sep 2025 13:36:32 -0700
Subject: [PATCH 4/5] use lldb::user_id_t instead of uint32_t

---
 lldb/include/lldb/API/SBDebugger.h    | 2 +-
 lldb/include/lldb/Target/TargetList.h | 2 +-
 lldb/source/API/SBDebugger.cpp        | 2 +-
 lldb/source/Target/TargetList.cpp     | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h
index efd95677d1d36..89d1fcd56069f 100644
--- a/lldb/include/lldb/API/SBDebugger.h
+++ b/lldb/include/lldb/API/SBDebugger.h
@@ -360,7 +360,7 @@ class LLDB_API SBDebugger {
                                            const char *arch);
 
   /// Find a target with the specified unique ID
-  lldb::SBTarget FindTargetWithUniqueID(uint32_t id);
+  lldb::SBTarget FindTargetWithUniqueID(lldb::user_id_t id);
 
   /// Get the number of targets in the debugger.
   uint32_t GetNumTargets();
diff --git a/lldb/include/lldb/Target/TargetList.h b/lldb/include/lldb/Target/TargetList.h
index 343fc1676ec30..b193cc863e9e4 100644
--- a/lldb/include/lldb/Target/TargetList.h
+++ b/lldb/include/lldb/Target/TargetList.h
@@ -159,7 +159,7 @@ class TargetList : public Broadcaster {
 
   lldb::TargetSP FindTargetWithProcess(lldb_private::Process *process) const;
 
-  lldb::TargetSP FindTargetWithUniqueID(uint32_t id) const;
+  lldb::TargetSP FindTargetWithUniqueID(lldb::user_id_t id) const;
 
   lldb::TargetSP GetTargetSP(Target *target) const;
 
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index f4b46cc3b1873..4533a1a20de79 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -983,7 +983,7 @@ uint32_t SBDebugger::GetIndexOfTarget(lldb::SBTarget target) {
   return m_opaque_sp->GetTargetList().GetIndexOfTarget(target.GetSP());
 }
 
-SBTarget SBDebugger::FindTargetWithUniqueID(uint32_t id) {
+SBTarget SBDebugger::FindTargetWithUniqueID(lldb::user_id_t id) {
   LLDB_INSTRUMENT_VA(this, id);
   SBTarget sb_target;
   if (m_opaque_sp) {
diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp
index fa86b3b609e59..1f0dc7d3ffaa3 100644
--- a/lldb/source/Target/TargetList.cpp
+++ b/lldb/source/Target/TargetList.cpp
@@ -428,7 +428,7 @@ TargetSP TargetList::FindTargetWithProcess(Process *process) const {
   return target_sp;
 }
 
-TargetSP TargetList::FindTargetWithUniqueID(uint32_t id) const {
+TargetSP TargetList::FindTargetWithUniqueID(lldb::user_id_t id) const {
   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
   auto it = llvm::find_if(m_target_list, [id](const TargetSP &item) {
     return item->GetUniqueID() == id;

>From 2beeaab4451ce4134a05bf892dcbce66d0111e73 Mon Sep 17 00:00:00 2001
From: qxy11 <qxy11 at fb.com>
Date: Wed, 1 Oct 2025 23:06:32 -0700
Subject: [PATCH 5/5] Add another unit test and change GetUniqueID ->
 GetGloballyUniqueID

---
 lldb/include/lldb/API/SBTarget.h              | 32 ++++++------
 lldb/include/lldb/Target/Target.h             | 11 ++--
 lldb/include/lldb/Target/TargetList.h         |  9 ++++
 lldb/source/API/SBTarget.cpp                  |  4 +-
 lldb/source/Target/TargetList.cpp             |  2 +-
 .../python_api/debugger/TestDebuggerAPI.py    | 50 +++++++++++++++----
 6 files changed, 76 insertions(+), 32 deletions(-)

diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index 18a6d12be15b0..5e9dcd2498ed7 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -357,7 +357,12 @@ class LLDB_API SBTarget {
 
   const char *GetLabel() const;
 
-  lldb::user_id_t GetUniqueID() const;
+  /// Get the globally unique ID for this target.
+  ///
+  /// \return
+  ///     The globally unique ID for this target, or LLDB_INVALID_TARGET_ID if
+  ///     the target is invalid.
+  lldb::user_id_t GetGloballyUniqueID() const;
 
   SBError SetLabel(const char *label);
 
@@ -660,15 +665,14 @@ class LLDB_API SBTarget {
       const char *symbol_name,
       uint32_t
           name_type_mask, // Logical OR one or more FunctionNameType enum bits
-      const SBFileSpecList &module_list,
-      const SBFileSpecList &comp_unit_list);
+      const SBFileSpecList &module_list, const SBFileSpecList &comp_unit_list);
 
   lldb::SBBreakpoint BreakpointCreateByName(
       const char *symbol_name,
       uint32_t
           name_type_mask, // Logical OR one or more FunctionNameType enum bits
-      lldb::LanguageType symbol_language,
-      const SBFileSpecList &module_list, const SBFileSpecList &comp_unit_list);
+      lldb::LanguageType symbol_language, const SBFileSpecList &module_list,
+      const SBFileSpecList &comp_unit_list);
 
   lldb::SBBreakpoint BreakpointCreateByName(
       const char *symbol_name,
@@ -705,23 +709,21 @@ class LLDB_API SBTarget {
       const char *symbol_name[], uint32_t num_names,
       uint32_t
           name_type_mask, // Logical OR one or more FunctionNameType enum bits
-      const SBFileSpecList &module_list,
-      const SBFileSpecList &comp_unit_list);
+      const SBFileSpecList &module_list, const SBFileSpecList &comp_unit_list);
 
   lldb::SBBreakpoint BreakpointCreateByNames(
       const char *symbol_name[], uint32_t num_names,
       uint32_t
           name_type_mask, // Logical OR one or more FunctionNameType enum bits
-      lldb::LanguageType symbol_language,
-      const SBFileSpecList &module_list, const SBFileSpecList &comp_unit_list);
+      lldb::LanguageType symbol_language, const SBFileSpecList &module_list,
+      const SBFileSpecList &comp_unit_list);
 
   lldb::SBBreakpoint BreakpointCreateByNames(
       const char *symbol_name[], uint32_t num_names,
       uint32_t
           name_type_mask, // Logical OR one or more FunctionNameType enum bits
-      lldb::LanguageType symbol_language,
-      lldb::addr_t offset, const SBFileSpecList &module_list,
-      const SBFileSpecList &comp_unit_list);
+      lldb::LanguageType symbol_language, lldb::addr_t offset,
+      const SBFileSpecList &module_list, const SBFileSpecList &comp_unit_list);
 #endif
 
   lldb::SBBreakpoint BreakpointCreateByRegex(const char *symbol_name_regex,
@@ -780,10 +782,8 @@ class LLDB_API SBTarget {
   ///     An SBBreakpoint that will set locations based on the logic in the
   ///     resolver's search callback.
   lldb::SBBreakpoint BreakpointCreateFromScript(
-      const char *class_name,
-      SBStructuredData &extra_args,
-      const SBFileSpecList &module_list,
-      const SBFileSpecList &file_list,
+      const char *class_name, SBStructuredData &extra_args,
+      const SBFileSpecList &module_list, const SBFileSpecList &file_list,
       bool request_hardware = false);
 
   /// Read breakpoints from source_file and return the newly created
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 5b83c66779d13..f360634acc314 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -600,11 +600,16 @@ class Target : public std::enable_shared_from_this<Target>,
 
   bool IsDummyTarget() const { return m_is_dummy_target; }
 
-  /// Get the unique ID for this target.
+  /// Get the globally unique ID for this target.
+  ///
+  /// This ID is unique across all debugger instances and all targets,
+  /// not just within this debugger's target list. The ID is assigned
+  /// during target construction and remains constant for the target's lifetime.
+  /// The first target created (typically the dummy target) gets ID 1.
   ///
   /// \return
-  ///     The unique ID for this target.
-  lldb::user_id_t GetUniqueID() const { return m_target_unique_id; }
+  ///     The globally unique ID for this target.
+  lldb::user_id_t GetGloballyUniqueID() const { return m_target_unique_id; }
 
   const std::string &GetLabel() const { return m_label; }
 
diff --git a/lldb/include/lldb/Target/TargetList.h b/lldb/include/lldb/Target/TargetList.h
index b193cc863e9e4..5a35ec89a8b5d 100644
--- a/lldb/include/lldb/Target/TargetList.h
+++ b/lldb/include/lldb/Target/TargetList.h
@@ -159,6 +159,15 @@ class TargetList : public Broadcaster {
 
   lldb::TargetSP FindTargetWithProcess(lldb_private::Process *process) const;
 
+  /// Find the target that has a globally unique ID that matches ID \a id
+  ///
+  /// \param[in] id
+  ///     The globally unique target ID to search our target list for.
+  ///
+  /// \return
+  ///     A shared pointer to a target object. The returned shared
+  ///     pointer will contain nullptr if no target objects has a
+  ///     matching target ID.
   lldb::TargetSP FindTargetWithUniqueID(lldb::user_id_t id) const;
 
   lldb::TargetSP GetTargetSP(Target *target) const;
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 28c05fa33990f..5a37a1b218715 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1632,11 +1632,11 @@ const char *SBTarget::GetLabel() const {
   return nullptr;
 }
 
-lldb::user_id_t SBTarget::GetUniqueID() const {
+lldb::user_id_t SBTarget::GetGloballyUniqueID() const {
   LLDB_INSTRUMENT_VA(this);
 
   if (TargetSP target_sp = GetSP())
-    return target_sp->GetUniqueID();
+    return target_sp->GetGloballyUniqueID();
   return LLDB_INVALID_TARGET_ID;
 }
 
diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp
index 1f0dc7d3ffaa3..31cb6ea76c562 100644
--- a/lldb/source/Target/TargetList.cpp
+++ b/lldb/source/Target/TargetList.cpp
@@ -431,7 +431,7 @@ TargetSP TargetList::FindTargetWithProcess(Process *process) const {
 TargetSP TargetList::FindTargetWithUniqueID(lldb::user_id_t id) const {
   std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
   auto it = llvm::find_if(m_target_list, [id](const TargetSP &item) {
-    return item->GetUniqueID() == id;
+    return item->GetGloballyUniqueID() == id;
   });
 
   if (it != m_target_list.end())
diff --git a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
index 4d82fdc83b2cf..98e04e6a77a71 100644
--- a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
+++ b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
@@ -313,17 +313,17 @@ def test_find_target_with_unique_id(self):
         self.assertTrue(target.IsValid())
 
         # Find the target using its unique ID
-        unique_id = target.GetUniqueID()
+        unique_id = target.GetGloballyUniqueID()
         self.assertNotEqual(unique_id, 0)
         found_target = self.dbg.FindTargetWithUniqueID(unique_id)
         self.assertTrue(found_target.IsValid())
         self.assertEqual(
             self.dbg.GetIndexOfTarget(target), self.dbg.GetIndexOfTarget(found_target)
         )
-        self.assertEqual(found_target.GetUniqueID(), unique_id)
+        self.assertEqual(found_target.GetGloballyUniqueID(), unique_id)
 
     def test_target_unique_id_uniqueness(self):
-        """Test that Target.GetUniqueID() returns unique values across multiple targets."""
+        """Test that Target.GetGloballyUniqueID() returns unique values across multiple targets."""
 
         # Create multiple targets and verify they all have unique IDs
         self.build()
@@ -335,7 +335,7 @@ def test_target_unique_id_uniqueness(self):
             target = self.dbg.CreateTarget(exe)
             self.assertTrue(target.IsValid())
 
-            unique_id = target.GetUniqueID()
+            unique_id = target.GetGloballyUniqueID()
             self.assertNotEqual(unique_id, 0)
 
             # Verify this ID hasn't been used before
@@ -348,10 +348,10 @@ def test_target_unique_id_uniqueness(self):
 
         # Verify all targets can still be found by their IDs
         for target in targets:
-            unique_id = target.GetUniqueID()
+            unique_id = target.GetGloballyUniqueID()
             found = self.dbg.FindTargetWithUniqueID(unique_id)
             self.assertTrue(found.IsValid())
-            self.assertEqual(found.GetUniqueID(), unique_id)
+            self.assertEqual(found.GetGloballyUniqueID(), unique_id)
 
     def test_target_unique_id_uniqueness_after_deletion(self):
         """Test finding targets have unique ID after target deletion."""
@@ -363,8 +363,8 @@ def test_target_unique_id_uniqueness_after_deletion(self):
         self.assertTrue(target1.IsValid())
         self.assertTrue(target2.IsValid())
 
-        unique_id1 = target1.GetUniqueID()
-        unique_id2 = target2.GetUniqueID()
+        unique_id1 = target1.GetGloballyUniqueID()
+        unique_id2 = target2.GetGloballyUniqueID()
         self.assertNotEqual(unique_id1, 0)
         self.assertNotEqual(unique_id2, 0)
         self.assertNotEqual(unique_id1, unique_id2)
@@ -390,10 +390,40 @@ def test_target_unique_id_uniqueness_after_deletion(self):
         # Target list index of target3 should be the same as target2's
         # since it was deleted, but it should have a distinct unique ID
         target3_index = self.dbg.GetIndexOfTarget(target3)
-        unique_id3 = target3.GetUniqueID()
+        unique_id3 = target3.GetGloballyUniqueID()
         self.assertEqual(target3_index, target2_index)
         self.assertNotEqual(unique_id3, unique_id2)
         self.assertNotEqual(unique_id3, unique_id1)
         # Make sure we can find the new target
-        found_target3 = self.dbg.FindTargetWithUniqueID(target3.GetUniqueID())
+        found_target3 = self.dbg.FindTargetWithUniqueID(target3.GetGloballyUniqueID())
         self.assertTrue(found_target3.IsValid())
+
+    def test_target_globally_unique_id_across_debuggers(self):
+        """Test that target IDs are globally unique across multiple debuggers."""
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+
+        # Create two debuggers with targets each
+        debugger1 = lldb.SBDebugger.Create()
+        debugger2 = lldb.SBDebugger.Create()
+        
+        # Create 2 targets per debugger
+        targets_d1 = [debugger1.CreateTarget(exe), debugger1.CreateTarget(exe)]
+        targets_d2 = [debugger2.CreateTarget(exe), debugger2.CreateTarget(exe)]
+        targets = targets_d1 + targets_d2
+        
+        # Get all IDs and verify they're unique
+        ids = [target.GetGloballyUniqueID() for target in targets]
+        self.assertEqual(len(set(ids)), len(ids), f"IDs should be globally unique: {ids}")
+        self.assertTrue(all(uid > 0 for uid in ids), "All IDs should be non-zero")
+        
+        # Verify targets can be found by their IDs in respective debuggers
+        for debugger, target_pair in [(debugger1, targets[:2]), (debugger2, targets[2:])]:
+            for target in target_pair:
+                found = debugger.FindTargetWithUniqueID(target.GetGloballyUniqueID())
+                self.assertTrue(found.IsValid(), "Target should be found by its unique ID")
+                self.assertEqual(found.GetGloballyUniqueID(), target.GetGloballyUniqueID())
+
+        # Clean up
+        lldb.SBDebugger.Destroy(debugger1)
+        lldb.SBDebugger.Destroy(debugger2)



More information about the lldb-commits mailing list