[Lldb-commits] [lldb] Add SBDebugger::AddCreateCallback API (PR #111206)
via lldb-commits
lldb-commits at lists.llvm.org
Tue Oct 8 12:11:00 PDT 2024
https://github.com/jeffreytan81 updated https://github.com/llvm/llvm-project/pull/111206
>From 6e84ab9a14e63c58e1facdbf9a695c093882b37b Mon Sep 17 00:00:00 2001
From: jeffreytan81 <jeffreytan at fb.com>
Date: Mon, 19 Aug 2024 10:57:35 -0700
Subject: [PATCH 1/2] Fix StartDebuggingRequestHandler/ReplModeRequestHandler
in lldb-dap
---
lldb/tools/lldb-dap/DAP.h | 2 --
lldb/tools/lldb-dap/lldb-dap.cpp | 4 ++--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 57562a14983519..7828272aa15a7d 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -192,8 +192,6 @@ struct DAP {
std::mutex call_mutex;
std::map<int /* request_seq */, ResponseCallback /* reply handler */>
inflight_reverse_requests;
- StartDebuggingRequestHandler start_debugging_request_handler;
- ReplModeRequestHandler repl_mode_request_handler;
ReplMode repl_mode;
std::string command_escape_prefix = "`";
lldb::SBFormat frame_format;
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index ea84f31aec3a6c..f50a6c17310739 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -1627,12 +1627,12 @@ void request_initialize(const llvm::json::Object &request) {
"lldb-dap", "Commands for managing lldb-dap.");
if (GetBoolean(arguments, "supportsStartDebuggingRequest", false)) {
cmd.AddCommand(
- "startDebugging", &g_dap.start_debugging_request_handler,
+ "startDebugging", new StartDebuggingRequestHandler(),
"Sends a startDebugging request from the debug adapter to the client "
"to start a child debug session of the same type as the caller.");
}
cmd.AddCommand(
- "repl-mode", &g_dap.repl_mode_request_handler,
+ "repl-mode", new ReplModeRequestHandler(),
"Get or set the repl behavior of lldb-dap evaluation requests.");
g_dap.progress_event_thread = std::thread(ProgressEventThreadFunction);
>From d5820bd77da828e6a51180473a2df00c236cc6db Mon Sep 17 00:00:00 2001
From: jeffreytan81 <jeffreytan at fb.com>
Date: Tue, 8 Oct 2024 12:10:29 -0700
Subject: [PATCH 2/2] Add SBDebugger::AddNotificationCallback
---
lldb/bindings/python/python-swigsafecast.swig | 10 ++
lldb/bindings/python/python-typemaps.swig | 19 +++
lldb/bindings/python/python-wrapper.swig | 40 ++++++
lldb/include/lldb/API/SBDebugger.h | 11 ++
lldb/include/lldb/API/SBDefines.h | 5 +-
lldb/include/lldb/API/SBExecutionContext.h | 1 +
lldb/include/lldb/Core/Debugger.h | 49 +++++--
lldb/include/lldb/lldb-enumerations.h | 6 +
lldb/include/lldb/lldb-private-types.h | 4 +
lldb/source/API/SBDebugger.cpp | 24 ++++
lldb/source/Core/Debugger.cpp | 45 ++++++-
.../Python/SWIGPythonBridge.h | 6 +
lldb/source/Target/Statistics.cpp | 7 +-
.../python_api/debugger/TestDebuggerAPI.py | 122 +++++++++++++-----
14 files changed, 302 insertions(+), 47 deletions(-)
diff --git a/lldb/bindings/python/python-swigsafecast.swig b/lldb/bindings/python/python-swigsafecast.swig
index 0127ac6bfa4681..2dd03d5f2a4b50 100644
--- a/lldb/bindings/python/python-swigsafecast.swig
+++ b/lldb/bindings/python/python-swigsafecast.swig
@@ -133,5 +133,15 @@ PythonObject SWIGBridge::ToSWIGWrapper(
return ToSWIGHelper(module_spec_sb.release(), SWIGTYPE_p_lldb__SBModuleSpec);
}
+PythonObject SWIGBridge::ToSWIGWrapper(
+ std::unique_ptr<lldb::SBDebugger> debugger_sb) {
+ return ToSWIGHelper(debugger_sb.release(), SWIGTYPE_p_lldb__SBDebugger);
+}
+
+PythonObject SWIGBridge::ToSWIGWrapper(
+ std::unique_ptr<lldb::SBExecutionContext> exe_ctx_sb) {
+ return ToSWIGHelper(exe_ctx_sb.release(), SWIGTYPE_p_lldb__SBExecutionContext);
+}
+
} // namespace python
} // namespace lldb_private
diff --git a/lldb/bindings/python/python-typemaps.swig b/lldb/bindings/python/python-typemaps.swig
index f8c33e15c03e66..d67172155cee21 100644
--- a/lldb/bindings/python/python-typemaps.swig
+++ b/lldb/bindings/python/python-typemaps.swig
@@ -452,6 +452,25 @@ template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) {
$1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input));
}
+// For lldb::SBNotificationCallback
+%typemap(in) (lldb::SBNotificationCallback notification_callback, void *baton) {
+ if (!($input == Py_None ||
+ PyCallable_Check(reinterpret_cast<PyObject *>($input)))) {
+ PyErr_SetString(PyExc_TypeError, "Need a callable object or None!");
+ SWIG_fail;
+ }
+
+ // Don't lose the callback reference
+ Py_INCREF($input);
+ $1 = LLDBSwigPythonCallPythonSBNotificationCallback;
+ $2 = $input;
+}
+
+%typemap(typecheck) (lldb::SBNotificationCallback notification_callback, void *baton) {
+ $1 = $input == Py_None;
+ $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input));
+}
+
// For lldb::SBDebuggerDestroyCallback
%typemap(in) (lldb::SBDebuggerDestroyCallback destroy_callback, void *baton) {
if (!($input == Py_None ||
diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig
index 810673aaec5d19..8fbca0f4161676 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -1024,6 +1024,46 @@ static void LLDBSwigPythonCallPythonLogOutputCallback(const char *str,
}
}
+// For NotificationCallback functions
+static void LLDBSwigPythonCallPythonSBNotificationCallback(
+ lldb::NotificationType type, lldb::SBDebugger &debugger,
+ lldb::SBExecutionContext &exe_ctx, void *baton) {
+
+ if (baton != Py_None) {
+ SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+
+ // Convert debugger and exe_ctx to Python objects
+ PythonObject debugger_arg = SWIGBridge::ToSWIGWrapper(
+ std::make_unique<SBDebugger>(debugger)); // Wrap debugger reference
+
+ PythonObject exe_ctx_arg = SWIGBridge::ToSWIGWrapper(
+ std::make_unique<SBExecutionContext>(exe_ctx)); // Wrap ExecutionContext
+
+ // Create a tuple of arguments (type, debugger, exe_ctx)
+ PyObject *args = PyTuple_New(3);
+
+ // Add NotificationType as an integer to the tuple
+ PyTuple_SetItem(args, 0, PyLong_FromLong(static_cast<long>(type)));
+
+ // Add debugger and exe_ctx to the tuple
+ Py_INCREF(debugger_arg.get());
+ PyTuple_SetItem(args, 1, debugger_arg.get());
+
+ Py_INCREF(exe_ctx_arg.get());
+ PyTuple_SetItem(args, 2, exe_ctx_arg.get());
+
+ // Call the Python function with the tuple of arguments (type, debugger, exe_ctx)
+ PyObject *result = PyObject_CallFunction(
+ reinterpret_cast<PyObject *>(baton), const_cast<char *>("O"), args);
+
+ // Clean up
+ Py_XDECREF(result);
+ Py_DECREF(args); // Decrement reference count for args
+
+ SWIG_PYTHON_THREAD_END_BLOCK;
+ }
+}
+
// For DebuggerTerminateCallback functions
static void LLDBSwigPythonCallPythonSBDebuggerTerminateCallback(lldb::user_id_t debugger_id,
void *baton) {
diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h
index 84ea9c0f772e16..dbaafeddfc192a 100644
--- a/lldb/include/lldb/API/SBDebugger.h
+++ b/lldb/include/lldb/API/SBDebugger.h
@@ -336,6 +336,17 @@ class LLDB_API SBDebugger {
void SetDestroyCallback(lldb::SBDebuggerDestroyCallback destroy_callback,
void *baton);
+ /// Add a notification callback when notification type event happens. Return a
+ /// token, which can be used to remove said callback. Multiple callbacks can
+ /// be added by calling this function multiple times, and will be invoked in
+ /// FIFO order.
+ static lldb::callback_token_t
+ AddNotificationCallback(lldb::NotificationType notification_type,
+ lldb::SBNotificationCallback notification_callback,
+ void *baton);
+ /// Remove the specified callback. Return true if successful.
+ static bool RemoveNotificationCallback(lldb::callback_token_t token);
+
/// Add a callback for when the debugger is destroyed. Return a token, which
/// can be used to remove said callback. Multiple callbacks can be added by
/// calling this function multiple times, and will be invoked in FIFO order.
diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h
index 9543ebc08a320f..f208f2a2b6f317 100644
--- a/lldb/include/lldb/API/SBDefines.h
+++ b/lldb/include/lldb/API/SBDefines.h
@@ -138,7 +138,10 @@ class LLDB_API SBUnixSignals;
typedef bool (*SBBreakpointHitCallback)(void *baton, lldb::SBProcess &process,
lldb::SBThread &thread,
lldb::SBBreakpointLocation &location);
-
+typedef void (*SBNotificationCallback)(lldb::NotificationType type,
+ lldb::SBDebugger &,
+ lldb::SBExecutionContext &exe_ctx,
+ void *baton);
typedef void (*SBDebuggerDestroyCallback)(lldb::user_id_t debugger_id,
void *baton);
diff --git a/lldb/include/lldb/API/SBExecutionContext.h b/lldb/include/lldb/API/SBExecutionContext.h
index e8de2ebe58785e..62fd637da93ff6 100644
--- a/lldb/include/lldb/API/SBExecutionContext.h
+++ b/lldb/include/lldb/API/SBExecutionContext.h
@@ -58,6 +58,7 @@ class LLDB_API SBExecutionContext {
lldb_private::ExecutionContextRef *get() const;
+ friend class SBDebugger;
SBExecutionContext(lldb::ExecutionContextRefSP exe_ctx_ref_sp);
private:
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index a72c2596cc2c5e..fef87a0c4726ff 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -569,6 +569,18 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
SetDestroyCallback(lldb_private::DebuggerDestroyCallback destroy_callback,
void *baton);
+ /// Add a notification callback when notification type event happens. Return a
+ /// token, which can be used to remove said callback. Multiple callbacks can
+ /// be added by calling this function multiple times, and will be invoked in
+ /// FIFO order.
+ static lldb::callback_token_t AddNotificationCallback(
+ lldb::NotificationType type,
+ lldb_private::NotificationCallback notification_callback, void *baton,
+ void *original_callback);
+
+ /// Remove the specified callback. Return true if successful.
+ static bool RemoveNotificationCallback(lldb::callback_token_t token);
+
/// Add a callback for when the debugger is destroyed. Return a token, which
/// can be used to remove said callback. Multiple callbacks can be added by
/// calling this function multiple times, and will be invoked in FIFO order.
@@ -683,6 +695,9 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
void InstanceInitialize();
+ static void InvokeNotificationCallbacks(lldb::DebuggerSP debugger_sp,
+ lldb::NotificationType notify_type);
+
// these should never be NULL
lldb::FileSP m_input_file_sp;
lldb::StreamFileSP m_output_stream_sp;
@@ -737,19 +752,35 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
lldb::TargetSP m_dummy_target_sp;
Diagnostics::CallbackID m_diagnostics_callback_id;
- std::mutex m_destroy_callback_mutex;
- lldb::callback_token_t m_destroy_callback_next_token = 0;
- struct DestroyCallbackInfo {
- DestroyCallbackInfo() {}
- DestroyCallbackInfo(lldb::callback_token_t token,
- lldb_private::DebuggerDestroyCallback callback,
- void *baton)
+ template <typename T> struct CallbackInfo {
+ CallbackInfo() {}
+ CallbackInfo(lldb::callback_token_t token, T callback, void *baton)
: token(token), callback(callback), baton(baton) {}
lldb::callback_token_t token;
- lldb_private::DebuggerDestroyCallback callback;
+ T callback;
void *baton;
};
- llvm::SmallVector<DestroyCallbackInfo, 2> m_destroy_callbacks;
+ template <typename T>
+ struct NotificationCallbackInfo : public CallbackInfo<T> {
+ NotificationCallbackInfo() {}
+ NotificationCallbackInfo(lldb::callback_token_t token,
+ lldb::NotificationType type, T callback,
+ void *baton, void *original_callback)
+ : CallbackInfo<T>(token, callback, baton), type(type),
+ original_callback(original_callback) {}
+ lldb::NotificationType type;
+ void *original_callback;
+ };
+ static std::mutex s_notification_callback_mutex;
+ static lldb::callback_token_t s_notification_callback_next_token;
+ static llvm::SmallVector<
+ NotificationCallbackInfo<lldb_private::NotificationCallback>, 2>
+ s_notification_callbacks;
+
+ std::mutex m_destroy_callback_mutex;
+ lldb::callback_token_t m_destroy_callback_next_token = 0;
+ llvm::SmallVector<CallbackInfo<lldb_private::DebuggerDestroyCallback>, 2>
+ m_destroy_callbacks;
uint32_t m_interrupt_requested = 0; ///< Tracks interrupt requests
std::mutex m_interrupt_mutex;
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 938f6e3abe8f2a..7dd65b07c1dc3f 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -1362,6 +1362,12 @@ enum Severity {
eSeverityInfo, // Equivalent to Remark used in clang.
};
+enum NotificationType {
+ eDebuggerWillBeCreated = (1 << 0),
+ eDebuggerWillBeDestroyed =
+ (1 << 1), // Call before debugger object is destroyed
+};
+
} // namespace lldb
#endif // LLDB_LLDB_ENUMERATIONS_H
diff --git a/lldb/include/lldb/lldb-private-types.h b/lldb/include/lldb/lldb-private-types.h
index b82a2b8aa05744..b96d4981f6fe3d 100644
--- a/lldb/include/lldb/lldb-private-types.h
+++ b/lldb/include/lldb/lldb-private-types.h
@@ -143,6 +143,10 @@ typedef struct type256 { uint64_t x[4]; } type256;
using ValueObjectProviderTy =
std::function<lldb::ValueObjectSP(ConstString, StackFrame *)>;
+typedef void (*NotificationCallback)(lldb::NotificationType type,
+ lldb::DebuggerSP debugger,
+ lldb::ExecutionContextRefSP exe_ctx,
+ void *baton, void *original_callback);
typedef void (*DebuggerDestroyCallback)(lldb::user_id_t debugger_id,
void *baton);
typedef bool (*CommandOverrideCallbackWithResult)(
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index 6b72994fc96afb..560c929760705f 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -1703,6 +1703,30 @@ void SBDebugger::SetDestroyCallback(
}
}
+lldb::callback_token_t SBDebugger::AddNotificationCallback(
+ lldb::NotificationType type,
+ lldb::SBNotificationCallback notification_callback, void *baton) {
+ LLDB_INSTRUMENT_VA(type, notification_callback, baton);
+
+ NotificationCallback callback = [](lldb::NotificationType type,
+ lldb::DebuggerSP debugger,
+ lldb::ExecutionContextRefSP exe_ctx,
+ void *baton, void *original_callback) {
+ SBDebugger sb_debugger(debugger);
+ lldb::SBNotificationCallback original_callback_func =
+ (lldb::SBNotificationCallback)original_callback;
+ SBExecutionContext sb_exe_ctx(exe_ctx);
+ original_callback_func(type, sb_debugger, sb_exe_ctx, baton);
+ };
+ return Debugger::AddNotificationCallback(type, callback, baton,
+ (void *)notification_callback);
+}
+
+bool SBDebugger::RemoveNotificationCallback(lldb::callback_token_t token) {
+ LLDB_INSTRUMENT_VA(token);
+ return Debugger::RemoveNotificationCallback(token);
+}
+
lldb::callback_token_t
SBDebugger::AddDestroyCallback(lldb::SBDebuggerDestroyCallback destroy_callback,
void *baton) {
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index 9bdc5a3949751d..651ae3f639ebdd 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -106,6 +106,12 @@ static Debugger::DebuggerList *g_debugger_list_ptr =
nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain
static llvm::DefaultThreadPool *g_thread_pool = nullptr;
+std::mutex Debugger::s_notification_callback_mutex;
+lldb::callback_token_t Debugger::s_notification_callback_next_token = 0;
+llvm::SmallVector<
+ Debugger::NotificationCallbackInfo<lldb_private::NotificationCallback>, 2>
+ Debugger::s_notification_callbacks;
+
static constexpr OptionEnumValueElement g_show_disassembly_enum_values[] = {
{
Debugger::eStopDisassemblyTypeNever,
@@ -739,16 +745,29 @@ DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback,
g_debugger_list_ptr->push_back(debugger_sp);
}
debugger_sp->InstanceInitialize();
+
+ InvokeNotificationCallbacks(debugger_sp, lldb::eDebuggerWillBeCreated);
return debugger_sp;
}
+void Debugger::InvokeNotificationCallbacks(DebuggerSP debugger_sp,
+ lldb::NotificationType notify_type) {
+ std::lock_guard<std::mutex> guard(s_notification_callback_mutex);
+ for (const auto &callback_info : s_notification_callbacks) {
+ if ((callback_info.type & notify_type) == notify_type)
+ callback_info.callback(notify_type, debugger_sp, nullptr,
+ callback_info.baton,
+ callback_info.original_callback);
+ }
+}
+
void Debugger::HandleDestroyCallback() {
const lldb::user_id_t user_id = GetID();
// Invoke and remove all the callbacks in an FIFO order. Callbacks which are
// added during this loop will be appended, invoked and then removed last.
// Callbacks which are removed during this loop will not be invoked.
while (true) {
- DestroyCallbackInfo callback_info;
+ CallbackInfo<DebuggerDestroyCallback> callback_info;
{
std::lock_guard<std::mutex> guard(m_destroy_callback_mutex);
if (m_destroy_callbacks.empty())
@@ -766,6 +785,7 @@ void Debugger::Destroy(DebuggerSP &debugger_sp) {
if (!debugger_sp)
return;
+ InvokeNotificationCallbacks(debugger_sp, lldb::eDebuggerWillBeDestroyed);
debugger_sp->HandleDestroyCallback();
CommandInterpreter &cmd_interpreter = debugger_sp->GetCommandInterpreter();
@@ -1447,6 +1467,29 @@ void Debugger::SetDestroyCallback(
m_destroy_callbacks.emplace_back(token, destroy_callback, baton);
}
+lldb::callback_token_t Debugger::AddNotificationCallback(
+ lldb::NotificationType type,
+ lldb_private::NotificationCallback notification_callback, void *baton,
+ void *original_callback) {
+ std::lock_guard<std::mutex> guard(s_notification_callback_mutex);
+ const lldb::callback_token_t token = s_notification_callback_next_token++;
+ s_notification_callbacks.emplace_back(token, type, notification_callback,
+ baton, original_callback);
+ return token;
+}
+
+bool Debugger::RemoveNotificationCallback(lldb::callback_token_t token) {
+ std::lock_guard<std::mutex> guard(s_notification_callback_mutex);
+ for (auto it = s_notification_callbacks.begin();
+ it != s_notification_callbacks.end(); ++it) {
+ if (it->token == token) {
+ s_notification_callbacks.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
lldb::callback_token_t Debugger::AddDestroyCallback(
lldb_private::DebuggerDestroyCallback destroy_callback, void *baton) {
std::lock_guard<std::mutex> guard(m_destroy_callback_mutex);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index 97a3837fd7aa62..9ea42465361088 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -33,6 +33,8 @@ class SBStructuredData;
class SBFileSpec;
class SBModuleSpec;
class SBStringList;
+class SBDebugger;
+class SBExecutionContext;
} // namespace lldb
namespace lldb_private {
@@ -111,6 +113,10 @@ class SWIGBridge {
ToSWIGWrapper(std::unique_ptr<lldb::SBFileSpec> file_spec_sb);
static PythonObject
ToSWIGWrapper(std::unique_ptr<lldb::SBModuleSpec> module_spec_sb);
+ static PythonObject
+ ToSWIGWrapper(std::unique_ptr<lldb::SBDebugger> debugger_sb);
+ static PythonObject
+ ToSWIGWrapper(std::unique_ptr<lldb::SBExecutionContext> exe_ctx_sb);
static python::ScopedPythonObject<lldb::SBCommandReturnObject>
ToSWIGWrapper(CommandReturnObject &cmd_retobj);
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index d619f92122cb9d..0752dab30d80f1 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -261,14 +261,15 @@ llvm::json::Value DebuggerStats::ReportStatistics(
std::vector<ModuleStats> modules;
std::lock_guard<std::recursive_mutex> guard(
Module::GetAllocationModuleCollectionMutex());
- const uint64_t num_modules = Module::GetNumberAllocatedModules();
+ const ModuleList &target_modules = target->GetImages();
+ const uint64_t num_modules = target_modules.GetSize();
uint32_t num_debug_info_enabled_modules = 0;
uint32_t num_modules_has_debug_info = 0;
uint32_t num_modules_with_variable_errors = 0;
uint32_t num_modules_with_incomplete_types = 0;
uint32_t num_stripped_modules = 0;
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
- Module *module = Module::GetAllocatedModuleAtIndex(image_idx);
+ ModuleSP module = target_modules.GetModuleAtIndex(image_idx);
ModuleStats module_stat;
module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();
module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();
@@ -333,7 +334,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
++num_modules_with_incomplete_types;
if (include_modules) {
- module_stat.identifier = (intptr_t)module;
+ module_stat.identifier = (intptr_t)module.get();
module_stat.path = module->GetFileSpec().GetPath();
if (ConstString object_name = module->GetObjectName()) {
module_stat.path.append(1, '(');
diff --git a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py
index 646ccce36530d4..945b0c79b9a0fe 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,43 +249,96 @@ 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_AddRemoveNotificationCallback(self):
+ """
+ Test SBDebugger::AddNotificationCallback and SBDebugger::RemoveNotificationCallback
+ """
+ created_debuggers = []
+
+ def debugger_create_notification_callback(type, debugger, exe_ctx):
+ created_debuggers.append(debugger)
+
+ destroyed_debugger_ids = []
+
+ def debugger_destroy_notification_callback(type, debugger, exe_ctx):
+ destroyed_debugger_ids.append(debugger.GetID())
+
+ create_callback_token = lldb.SBDebugger.AddNotificationCallback(
+ lldb.eDebuggerWillBeCreated, debugger_create_notification_callback
+ )
+ debugger1 = lldb.SBDebugger.Create()
+ debugger2 = lldb.SBDebugger.Create()
+
+ # Remove create callback before creating 3rd debugger
+ lldb.SBDebugger.RemoveNotificationCallback(create_callback_token)
+
+ debugger3 = lldb.SBDebugger.Create()
+
+ self.assertNotEqual(debugger1.GetID(), debugger2.GetID())
+ self.assertNotEqual(debugger1.GetID(), debugger3.GetID())
+
+ self.assertEqual(len(created_debuggers), 2)
+ self.assertEqual(debugger1.GetID(), created_debuggers[0].GetID())
+ self.assertEqual(debugger2.GetID(), created_debuggers[1].GetID())
+
+ lldb.SBDebugger.Destroy(debugger1)
+ lldb.SBDebugger.Destroy(debugger2)
+
+ # Add destroy callback after destroying the first two debuggers but
+ # before creating 3rd debugger
+ lldb.SBDebugger.AddNotificationCallback(
+ lldb.eDebuggerWillBeDestroyed, debugger_destroy_notification_callback
+ )
+
+ self.assertEqual(len(destroyed_debugger_ids), 0)
+ debugger3_id = debugger3.GetID()
+ lldb.SBDebugger.Destroy(debugger3)
+ self.assertEqual(len(destroyed_debugger_ids), 1)
+ self.assertEqual(debugger3_id, destroyed_debugger_ids[0])
More information about the lldb-commits
mailing list