https://github.com/qxy11 updated https://github.com/llvm/llvm-project/pull/160736
>From c155381f49915fa98bd6e3ea14eb77b1dfcd7dbd Mon Sep 17 00:00:00 2001 From: qxy11 <[email protected]> Date: Thu, 25 Sep 2025 09:54:50 -0700 Subject: [PATCH 1/8] 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 <[email protected]> Date: Tue, 30 Sep 2025 11:35:27 -0700 Subject: [PATCH 2/8] 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 <[email protected]> Date: Tue, 30 Sep 2025 13:29:02 -0700 Subject: [PATCH 3/8] 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 <[email protected]> Date: Tue, 30 Sep 2025 13:36:32 -0700 Subject: [PATCH 4/8] 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 <[email protected]> Date: Wed, 1 Oct 2025 23:06:32 -0700 Subject: [PATCH 5/8] 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 <[email protected]> Date: Thu, 2 Oct 2025 05:54:11 -0700 Subject: [PATCH 6/8] 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 <[email protected]> Date: Thu, 2 Oct 2025 05:56:36 -0700 Subject: [PATCH 7/8] 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 <[email protected]> Date: Thu, 2 Oct 2025 09:58:35 -0700 Subject: [PATCH 8/8] 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) _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
