[Lldb-commits] [lldb] [lldb] Add support for unique target ids (PR #160736)
Janet Yang via lldb-commits
lldb-commits at lists.llvm.org
Tue Oct 7 06:02:40 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/9] 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/9] 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/9] 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/9] 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/9] 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)
>From c9b766ee9bb85e05e3572d389db4906302640152 Mon Sep 17 00:00:00 2001
From: qxy11 <qxy11 at fb.com>
Date: Thu, 2 Oct 2025 05:54:11 -0700
Subject: [PATCH 6/9] Fix formatting
---
lldb/include/lldb/API/SBTarget.h | 25 +++--
.../python_api/debugger/TestDebuggerAPI.py | 98 +++++++++++--------
2 files changed, 73 insertions(+), 50 deletions(-)
diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index 5e9dcd2498ed7..b601e7acd7b46 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -665,14 +665,15 @@ 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,
@@ -709,21 +710,23 @@ 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,
@@ -782,8 +785,10 @@ 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/test/API/python_api/debugger/TestDebuggerAPI.py b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
index 98e04e6a77a71..ead3ec3468036 100644
--- a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
+++ b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
@@ -173,22 +173,25 @@ def test_AddDestroyCallback(self):
def foo(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal called
- called += [('foo', dbg_id)]
+ called += [("foo", dbg_id)]
def bar(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal called
- called += [('bar', dbg_id)]
+ called += [("bar", dbg_id)]
token_foo = self.dbg.AddDestroyCallback(foo)
token_bar = self.dbg.AddDestroyCallback(bar)
self.dbg.Destroy(self.dbg)
# Should call both `foo()` and `bar()`.
- self.assertEqual(called, [
- ('foo', original_dbg_id),
- ('bar', original_dbg_id),
- ])
+ self.assertEqual(
+ called,
+ [
+ ("foo", original_dbg_id),
+ ("bar", original_dbg_id),
+ ],
+ )
def test_RemoveDestroyCallback(self):
original_dbg_id = self.dbg.GetID()
@@ -197,12 +200,12 @@ def test_RemoveDestroyCallback(self):
def foo(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal called
- called += [('foo', dbg_id)]
+ called += [("foo", dbg_id)]
def bar(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal called
- called += [('bar', dbg_id)]
+ called += [("bar", dbg_id)]
token_foo = self.dbg.AddDestroyCallback(foo)
token_bar = self.dbg.AddDestroyCallback(bar)
@@ -212,7 +215,7 @@ def bar(dbg_id):
# `Remove` should be successful
self.assertTrue(ret)
# Should only call `bar()`
- self.assertEqual(called, [('bar', original_dbg_id)])
+ self.assertEqual(called, [("bar", original_dbg_id)])
def test_RemoveDestroyCallback_invalid_token(self):
original_dbg_id = self.dbg.GetID()
@@ -222,7 +225,7 @@ def test_RemoveDestroyCallback_invalid_token(self):
def foo(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal called
- called += [('foo', dbg_id)]
+ called += [("foo", dbg_id)]
token_foo = self.dbg.AddDestroyCallback(foo)
ret = self.dbg.RemoveDestroyCallback(magic_token_that_should_not_exist)
@@ -231,7 +234,7 @@ def foo(dbg_id):
# `Remove` should be unsuccessful
self.assertFalse(ret)
# Should call `foo()`
- self.assertEqual(called, [('foo', original_dbg_id)])
+ self.assertEqual(called, [("foo", original_dbg_id)])
def test_HandleDestroyCallback(self):
"""
@@ -246,46 +249,52 @@ def test_HandleDestroyCallback(self):
def foo(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal events
- events.append(('foo called', dbg_id))
+ events.append(("foo called", dbg_id))
def bar(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal events
- events.append(('bar called', dbg_id))
+ events.append(("bar called", dbg_id))
def add_foo(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal events
- events.append(('add_foo called', dbg_id))
- events.append(('foo token', self.dbg.AddDestroyCallback(foo)))
+ events.append(("add_foo called", dbg_id))
+ events.append(("foo token", self.dbg.AddDestroyCallback(foo)))
def remove_bar(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal events
- events.append(('remove_bar called', dbg_id))
- events.append(('remove bar ret', self.dbg.RemoveDestroyCallback(bar_token)))
+ events.append(("remove_bar called", dbg_id))
+ events.append(("remove bar ret", self.dbg.RemoveDestroyCallback(bar_token)))
# Setup
- events.append(('add_foo token', self.dbg.AddDestroyCallback(add_foo)))
+ events.append(("add_foo token", self.dbg.AddDestroyCallback(add_foo)))
bar_token = self.dbg.AddDestroyCallback(bar)
- events.append(('bar token', bar_token))
- events.append(('remove_bar token', self.dbg.AddDestroyCallback(remove_bar)))
+ events.append(("bar token", bar_token))
+ events.append(("remove_bar token", self.dbg.AddDestroyCallback(remove_bar)))
# Destroy
self.dbg.Destroy(self.dbg)
- self.assertEqual(events, [
- # Setup
- ('add_foo token', 0), # add_foo should be added
- ('bar token', 1), # bar should be added
- ('remove_bar token', 2), # remove_bar should be added
- # Destroy
- ('add_foo called', original_dbg_id), # add_foo should be called
- ('foo token', 3), # foo should be added
- ('bar called', original_dbg_id), # bar should be called
- ('remove_bar called', original_dbg_id), # remove_bar should be called
- ('remove bar ret', False), # remove_bar should fail, because it's already invoked and removed
- ('foo called', original_dbg_id), # foo should be called
- ])
+ self.assertEqual(
+ events,
+ [
+ # Setup
+ ("add_foo token", 0), # add_foo should be added
+ ("bar token", 1), # bar should be added
+ ("remove_bar token", 2), # remove_bar should be added
+ # Destroy
+ ("add_foo called", original_dbg_id), # add_foo should be called
+ ("foo token", 3), # foo should be added
+ ("bar called", original_dbg_id), # bar should be called
+ ("remove_bar called", original_dbg_id), # remove_bar should be called
+ (
+ "remove bar ret",
+ False,
+ ), # remove_bar should fail, because it's already invoked and removed
+ ("foo called", original_dbg_id), # foo should be called
+ ],
+ )
def test_version(self):
instance_str = self.dbg.GetVersionString()
@@ -406,23 +415,32 @@ def test_target_globally_unique_id_across_debuggers(self):
# 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.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 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())
+ self.assertTrue(
+ found.IsValid(), "Target should be found by its unique ID"
+ )
+ self.assertEqual(
+ found.GetGloballyUniqueID(), target.GetGloballyUniqueID()
+ )
# Clean up
lldb.SBDebugger.Destroy(debugger1)
>From 2b9de97797db461f1faac026fea5a3434bf3bdcb Mon Sep 17 00:00:00 2001
From: qxy11 <qxy11 at fb.com>
Date: Thu, 2 Oct 2025 05:56:36 -0700
Subject: [PATCH 7/9] Remove unnecessary formatting
---
.../python_api/debugger/TestDebuggerAPI.py | 75 ++++++++-----------
1 file changed, 33 insertions(+), 42 deletions(-)
diff --git a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
index ead3ec3468036..a35b80159aa70 100644
--- a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
+++ b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
@@ -173,25 +173,22 @@ def test_AddDestroyCallback(self):
def foo(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal called
- called += [("foo", dbg_id)]
+ called += [('foo', dbg_id)]
def bar(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal called
- called += [("bar", dbg_id)]
+ called += [('bar', dbg_id)]
token_foo = self.dbg.AddDestroyCallback(foo)
token_bar = self.dbg.AddDestroyCallback(bar)
self.dbg.Destroy(self.dbg)
# Should call both `foo()` and `bar()`.
- self.assertEqual(
- called,
- [
- ("foo", original_dbg_id),
- ("bar", original_dbg_id),
- ],
- )
+ self.assertEqual(called, [
+ ('foo', original_dbg_id),
+ ('bar', original_dbg_id),
+ ])
def test_RemoveDestroyCallback(self):
original_dbg_id = self.dbg.GetID()
@@ -200,12 +197,12 @@ def test_RemoveDestroyCallback(self):
def foo(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal called
- called += [("foo", dbg_id)]
+ called += [('foo', dbg_id)]
def bar(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal called
- called += [("bar", dbg_id)]
+ called += [('bar', dbg_id)]
token_foo = self.dbg.AddDestroyCallback(foo)
token_bar = self.dbg.AddDestroyCallback(bar)
@@ -215,7 +212,7 @@ def bar(dbg_id):
# `Remove` should be successful
self.assertTrue(ret)
# Should only call `bar()`
- self.assertEqual(called, [("bar", original_dbg_id)])
+ self.assertEqual(called, [('bar', original_dbg_id)])
def test_RemoveDestroyCallback_invalid_token(self):
original_dbg_id = self.dbg.GetID()
@@ -225,7 +222,7 @@ def test_RemoveDestroyCallback_invalid_token(self):
def foo(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal called
- called += [("foo", dbg_id)]
+ called += [('foo', dbg_id)]
token_foo = self.dbg.AddDestroyCallback(foo)
ret = self.dbg.RemoveDestroyCallback(magic_token_that_should_not_exist)
@@ -234,7 +231,7 @@ def foo(dbg_id):
# `Remove` should be unsuccessful
self.assertFalse(ret)
# Should call `foo()`
- self.assertEqual(called, [("foo", original_dbg_id)])
+ self.assertEqual(called, [('foo', original_dbg_id)])
def test_HandleDestroyCallback(self):
"""
@@ -249,52 +246,46 @@ def test_HandleDestroyCallback(self):
def foo(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal events
- events.append(("foo called", dbg_id))
+ events.append(('foo called', dbg_id))
def bar(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal events
- events.append(("bar called", dbg_id))
+ events.append(('bar called', dbg_id))
def add_foo(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal events
- events.append(("add_foo called", dbg_id))
- events.append(("foo token", self.dbg.AddDestroyCallback(foo)))
+ events.append(('add_foo called', dbg_id))
+ events.append(('foo token', self.dbg.AddDestroyCallback(foo)))
def remove_bar(dbg_id):
# Need nonlocal to modify closure variable.
nonlocal events
- events.append(("remove_bar called", dbg_id))
- events.append(("remove bar ret", self.dbg.RemoveDestroyCallback(bar_token)))
+ events.append(('remove_bar called', dbg_id))
+ events.append(('remove bar ret', self.dbg.RemoveDestroyCallback(bar_token)))
# Setup
- events.append(("add_foo token", self.dbg.AddDestroyCallback(add_foo)))
+ events.append(('add_foo token', self.dbg.AddDestroyCallback(add_foo)))
bar_token = self.dbg.AddDestroyCallback(bar)
- events.append(("bar token", bar_token))
- events.append(("remove_bar token", self.dbg.AddDestroyCallback(remove_bar)))
+ events.append(('bar token', bar_token))
+ events.append(('remove_bar token', self.dbg.AddDestroyCallback(remove_bar)))
# Destroy
self.dbg.Destroy(self.dbg)
- self.assertEqual(
- events,
- [
- # Setup
- ("add_foo token", 0), # add_foo should be added
- ("bar token", 1), # bar should be added
- ("remove_bar token", 2), # remove_bar should be added
- # Destroy
- ("add_foo called", original_dbg_id), # add_foo should be called
- ("foo token", 3), # foo should be added
- ("bar called", original_dbg_id), # bar should be called
- ("remove_bar called", original_dbg_id), # remove_bar should be called
- (
- "remove bar ret",
- False,
- ), # remove_bar should fail, because it's already invoked and removed
- ("foo called", original_dbg_id), # foo should be called
- ],
- )
+ self.assertEqual(events, [
+ # Setup
+ ('add_foo token', 0), # add_foo should be added
+ ('bar token', 1), # bar should be added
+ ('remove_bar token', 2), # remove_bar should be added
+ # Destroy
+ ('add_foo called', original_dbg_id), # add_foo should be called
+ ('foo token', 3), # foo should be added
+ ('bar called', original_dbg_id), # bar should be called
+ ('remove_bar called', original_dbg_id), # remove_bar should be called
+ ('remove bar ret', False), # remove_bar should fail, because it's already invoked and removed
+ ('foo called', original_dbg_id), # foo should be called
+ ])
def test_version(self):
instance_str = self.dbg.GetVersionString()
>From ac1fe664b33e411795335ac1b9313e2c2ea7e5d2 Mon Sep 17 00:00:00 2001
From: qxy11 <qxy11 at fb.com>
Date: Thu, 2 Oct 2025 09:58:35 -0700
Subject: [PATCH 8/9] FindTargetWithUniqueID -> FindTargetByGloballyUniqueID
and test case cleanup
---
lldb/include/lldb/API/SBDebugger.h | 2 +-
lldb/include/lldb/API/SBTarget.h | 7 ++--
lldb/include/lldb/Target/Target.h | 5 ++-
lldb/include/lldb/Target/TargetList.h | 2 +-
lldb/include/lldb/lldb-defines.h | 2 +-
lldb/source/API/SBDebugger.cpp | 5 ++-
lldb/source/API/SBTarget.cpp | 2 +-
lldb/source/Target/TargetList.cpp | 2 +-
.../python_api/debugger/TestDebuggerAPI.py | 37 +++++++++++--------
9 files changed, 36 insertions(+), 28 deletions(-)
diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h
index 89d1fcd56069f..dade2e0dabe95 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(lldb::user_id_t id);
+ lldb::SBTarget FindTargetByGloballyUniqueID(lldb::user_id_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 b601e7acd7b46..173fd05b54a13 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -357,11 +357,12 @@ class LLDB_API SBTarget {
const char *GetLabel() const;
- /// Get the globally unique ID for this target.
+ /// Get the globally unique ID for this target. This ID is unique
+ /// across all debugger instances within the same lldb process.
///
/// \return
- /// The globally unique ID for this target, or LLDB_INVALID_TARGET_ID if
- /// the target is invalid.
+ /// The globally unique ID for this target, or
+ /// LLDB_INVALID_GLOBALLY_UNIQUE_TARGET_ID if the target is invalid.
lldb::user_id_t GetGloballyUniqueID() const;
SBError SetLabel(const char *label);
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index f360634acc314..f4a09237ce897 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -603,7 +603,7 @@ class Target : public std::enable_shared_from_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
+ /// within the same lldb process. 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.
///
@@ -1663,7 +1663,8 @@ class Target : public std::enable_shared_from_this<Target>,
bool m_is_dummy_target;
unsigned m_next_persistent_variable_index = 0;
lldb::user_id_t m_target_unique_id =
- LLDB_INVALID_TARGET_ID; /// The unique ID assigned to this target
+ LLDB_INVALID_GLOBALLY_UNIQUE_TARGET_ID; /// The globally 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 5a35ec89a8b5d..79b24faa10504 100644
--- a/lldb/include/lldb/Target/TargetList.h
+++ b/lldb/include/lldb/Target/TargetList.h
@@ -168,7 +168,7 @@ class TargetList : public Broadcaster {
/// 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 FindTargetByGloballyUniqueID(lldb::user_id_t id) const;
lldb::TargetSP GetTargetSP(Target *target) const;
diff --git a/lldb/include/lldb/lldb-defines.h b/lldb/include/lldb/lldb-defines.h
index 4a916a83c4fa0..c54ef884b01dc 100644
--- a/lldb/include/lldb/lldb-defines.h
+++ b/lldb/include/lldb/lldb-defines.h
@@ -96,7 +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
+#define LLDB_INVALID_GLOBALLY_UNIQUE_TARGET_ID 0
/// CPU Type definitions
#define LLDB_ARCH_DEFAULT "systemArch"
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index 4533a1a20de79..5c4c653d95a81 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -983,12 +983,13 @@ uint32_t SBDebugger::GetIndexOfTarget(lldb::SBTarget target) {
return m_opaque_sp->GetTargetList().GetIndexOfTarget(target.GetSP());
}
-SBTarget SBDebugger::FindTargetWithUniqueID(lldb::user_id_t id) {
+SBTarget SBDebugger::FindTargetByGloballyUniqueID(lldb::user_id_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));
+ sb_target.SetSP(
+ m_opaque_sp->GetTargetList().FindTargetByGloballyUniqueID(id));
}
return sb_target;
}
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 5a37a1b218715..f949ba224b8dc 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1637,7 +1637,7 @@ lldb::user_id_t SBTarget::GetGloballyUniqueID() const {
if (TargetSP target_sp = GetSP())
return target_sp->GetGloballyUniqueID();
- return LLDB_INVALID_TARGET_ID;
+ return LLDB_INVALID_GLOBALLY_UNIQUE_TARGET_ID;
}
SBError SBTarget::SetLabel(const char *label) {
diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp
index 31cb6ea76c562..188c2508a71ed 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(lldb::user_id_t id) const {
+TargetSP TargetList::FindTargetByGloballyUniqueID(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->GetGloballyUniqueID() == id;
diff --git a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
index a35b80159aa70..44b1183288017 100644
--- a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
+++ b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
@@ -296,14 +296,14 @@ def test_version(self):
self.assertEqual(class_str, property_str)
def test_find_target_with_unique_id(self):
- """Test SBDebugger.FindTargetWithUniqueID() functionality."""
+ """Test SBDebugger.FindTargetByGloballyUniqueID() functionality."""
# Test with invalid ID - should return invalid target
- invalid_target = self.dbg.FindTargetWithUniqueID(999999)
+ invalid_target = self.dbg.FindTargetByGloballyUniqueID(999999)
self.assertFalse(invalid_target.IsValid())
# Test with ID 0 - should return invalid target
- zero_target = self.dbg.FindTargetWithUniqueID(0)
+ zero_target = self.dbg.FindTargetByGloballyUniqueID(0)
self.assertFalse(zero_target.IsValid())
# Build a real executable and create target with it
@@ -314,8 +314,8 @@ def test_find_target_with_unique_id(self):
# Find the target using its unique ID
unique_id = target.GetGloballyUniqueID()
- self.assertNotEqual(unique_id, 0)
- found_target = self.dbg.FindTargetWithUniqueID(unique_id)
+ self.assertNotEqual(unique_id, lldb.LLDB_INVALID_GLOBALLY_UNIQUE_TARGET_ID)
+ found_target = self.dbg.FindTargetByGloballyUniqueID(unique_id)
self.assertTrue(found_target.IsValid())
self.assertEqual(
self.dbg.GetIndexOfTarget(target), self.dbg.GetIndexOfTarget(found_target)
@@ -349,7 +349,7 @@ def test_target_unique_id_uniqueness(self):
# Verify all targets can still be found by their IDs
for target in targets:
unique_id = target.GetGloballyUniqueID()
- found = self.dbg.FindTargetWithUniqueID(unique_id)
+ found = self.dbg.FindTargetByGloballyUniqueID(unique_id)
self.assertTrue(found.IsValid())
self.assertEqual(found.GetGloballyUniqueID(), unique_id)
@@ -370,8 +370,8 @@ def test_target_unique_id_uniqueness_after_deletion(self):
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)
+ found_target1 = self.dbg.FindTargetByGloballyUniqueID(unique_id1)
+ found_target2 = self.dbg.FindTargetByGloballyUniqueID(unique_id2)
self.assertTrue(found_target1.IsValid())
self.assertTrue(found_target2.IsValid())
target2_index = self.dbg.GetIndexOfTarget(target2)
@@ -381,7 +381,7 @@ def test_target_unique_id_uniqueness_after_deletion(self):
self.assertTrue(deleted)
# Try to find the deleted target - should not be found
- not_found_target = self.dbg.FindTargetWithUniqueID(unique_id2)
+ not_found_target = self.dbg.FindTargetByGloballyUniqueID(unique_id2)
self.assertFalse(not_found_target.IsValid())
# Create a new target
@@ -395,7 +395,9 @@ def test_target_unique_id_uniqueness_after_deletion(self):
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.GetGloballyUniqueID())
+ found_target3 = self.dbg.FindTargetByGloballyUniqueID(
+ target3.GetGloballyUniqueID()
+ )
self.assertTrue(found_target3.IsValid())
def test_target_globally_unique_id_across_debuggers(self):
@@ -406,6 +408,8 @@ def test_target_globally_unique_id_across_debuggers(self):
# Create two debuggers with targets each
debugger1 = lldb.SBDebugger.Create()
debugger2 = lldb.SBDebugger.Create()
+ self.addTearDownHook(lambda: lldb.SBDebugger.Destroy(debugger1))
+ self.addTearDownHook(lambda: lldb.SBDebugger.Destroy(debugger2))
# Create 2 targets per debugger
targets_d1 = [debugger1.CreateTarget(exe), debugger1.CreateTarget(exe)]
@@ -417,7 +421,10 @@ def test_target_globally_unique_id_across_debuggers(self):
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")
+ self.assertTrue(
+ all(uid != lldb.LLDB_INVALID_GLOBALLY_UNIQUE_TARGET_ID for uid in ids),
+ "All IDs should be valid",
+ )
# Verify targets can be found by their IDs in respective debuggers
for debugger, target_pair in [
@@ -425,14 +432,12 @@ def test_target_globally_unique_id_across_debuggers(self):
(debugger2, targets[2:]),
]:
for target in target_pair:
- found = debugger.FindTargetWithUniqueID(target.GetGloballyUniqueID())
+ found = debugger.FindTargetByGloballyUniqueID(
+ 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)
>From 7f7f76345f2cf9dd1b297c71d4a0ddb4527522c4 Mon Sep 17 00:00:00 2001
From: qxy11 <qxy11 at fb.com>
Date: Tue, 7 Oct 2025 06:01:46 -0700
Subject: [PATCH 9/9] Add missing periods.
---
lldb/include/lldb/API/SBDebugger.h | 2 +-
lldb/include/lldb/Target/TargetList.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h
index dade2e0dabe95..7a08a08262207 100644
--- a/lldb/include/lldb/API/SBDebugger.h
+++ b/lldb/include/lldb/API/SBDebugger.h
@@ -359,7 +359,7 @@ class LLDB_API SBDebugger {
lldb::SBTarget FindTargetWithFileAndArch(const char *filename,
const char *arch);
- /// Find a target with the specified unique ID
+ /// Find a target with the specified unique ID.
lldb::SBTarget FindTargetByGloballyUniqueID(lldb::user_id_t id);
/// Get the number of targets in the debugger.
diff --git a/lldb/include/lldb/Target/TargetList.h b/lldb/include/lldb/Target/TargetList.h
index 79b24faa10504..88272512bcc0f 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;
- /// Find the target that has a globally unique ID that matches ID \a id
+ /// 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.
More information about the lldb-commits
mailing list