diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h index 192fbee9c0c6d..6a2f76f2d5685 100644 --- a/lldb/include/lldb/API/SBDebugger.h +++ b/lldb/include/lldb/API/SBDebugger.h @@ -319,6 +319,8 @@ class LLDB_API SBDebugger { bool SetShowInlineDiagnostics(bool); + bool SetClearSharedModules(bool); + bool SetUseSourceCache(bool use_source_cache); bool GetUseSourceCache() const; diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index 504f936fe317a..4cf7fc75bafd4 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -373,6 +373,10 @@ class Debugger : public std::enable_shared_from_this, bool SetShowInlineDiagnostics(bool); + bool GetClearSharedModules() const; + + bool SetClearSharedModules(bool); + bool LoadPlugin(const FileSpec &spec, Status &error); void RunIOHandlers(); diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h index 909ee08f9ba62..587843dd05a4d 100644 --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -482,6 +482,9 @@ class ModuleList { static bool RemoveSharedModuleIfOrphaned(const Module *module_ptr); + /// Empty global cache of modules to release memory, file locks, etc. + static void ClearSharedModules(); + /// Applies 'callback' to each module in this ModuleList. /// If 'callback' returns false, iteration terminates. /// The 'module_sp' passed to 'callback' is guaranteed to diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp index 603e306497841..221c02cfe66ed 100644 --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -1466,6 +1466,12 @@ bool SBDebugger::SetShowInlineDiagnostics(bool value) { return (m_opaque_sp ? m_opaque_sp->SetShowInlineDiagnostics(value) : false); } +bool SBDebugger::SetClearSharedModules(bool value) { + LLDB_INSTRUMENT_VA(this, value); + + return (m_opaque_sp ? m_opaque_sp->SetClearSharedModules(value) : false); +} + bool SBDebugger::SetUseSourceCache(bool value) { LLDB_INSTRUMENT_VA(this, value); diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td index 53dd333f045c9..1a6ba1a9af84e 100644 --- a/lldb/source/Core/CoreProperties.td +++ b/lldb/source/Core/CoreProperties.td @@ -268,4 +268,8 @@ let Definition = "debugger" in { Global, DefaultFalse, Desc<"Controls whether diagnostics can refer directly to the command input, drawing arrows to it. If false, diagnostics will echo the input.">; + def ClearSharedModules: Property<"clear-shared-modules", "Boolean">, + Global, + DefaultFalse, + Desc<"Controls whether the debugger clears internal shared modules as it exits.">; } diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index ed674ee1275c7..0bc6c8f274fec 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -700,6 +700,17 @@ bool Debugger::SetShowInlineDiagnostics(bool b) { return SetPropertyAtIndex(idx, b); } +bool Debugger::GetClearSharedModules() const { + const uint32_t idx = ePropertyClearSharedModules; + return GetPropertyAtIndexAs( + idx, g_debugger_properties[idx].default_uint_value); +} + +bool Debugger::SetClearSharedModules(bool b) { + const uint32_t idx = ePropertyClearSharedModules; + return SetPropertyAtIndex(idx, b); +} + #pragma mark Debugger // const DebuggerPropertiesSP & @@ -1099,6 +1110,10 @@ void Debugger::Clear() { target_sp->Destroy(); } } + + if (GetClearSharedModules()) + ModuleList::RemoveOrphanSharedModules(/*mandatory=*/true); + m_broadcaster_manager_sp->Clear(); // Close the input file _before_ we close the input read communications diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index d5ddf6e846112..92baee85b1582 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -782,7 +782,13 @@ lldb::ModuleSP ModuleList::FindSharedModule(const UUID &uuid) { } size_t ModuleList::RemoveOrphanSharedModules(bool mandatory) { - return GetSharedModuleList().RemoveOrphans(mandatory); + size_t removed = GetSharedModuleList().RemoveOrphans(mandatory); + Log *log = GetLog(LLDBLog::Modules); + if (log != nullptr) { + LLDB_LOGF(log, "removed %lu shared modules, %lu modules remain", removed, + GetSharedModuleList().GetSize()); + } + return removed; } Status diff --git a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py index 43f45f330ee2a..a6939e629689e 100644 --- a/lldb/test/API/python_api/debugger/TestDebuggerAPI.py +++ b/lldb/test/API/python_api/debugger/TestDebuggerAPI.py @@ -294,3 +294,39 @@ def test_version(self): self.assertEqual(instance_str, class_str) self.assertEqual(class_str, property_str) + + def test_default_SetClearSharedModules(self): + """Check that that SBDebugger does not clear shared modules by + default. + """ + messages = list() + self.dbg.SetLoggingCallback(messages.append) + self.runCmd("log enable lldb module") + self.dbg.Destroy(self.dbg) + self.assertFalse( + any("removed 0 shared modules, 0 modules remain" in msg for msg in messages) + ) + + def test_enable_SetClearSharedModules(self): + """Check that SetClearSharedModule(true) clears shared module cache.""" + messages = list() + self.dbg.SetLoggingCallback(messages.append) + self.dbg.SetClearSharedModules(True) + self.runCmd("log enable lldb module") + self.dbg.Destroy(self.dbg) + self.assertTrue( + any("removed 0 shared modules, 0 modules remain" in msg for msg in messages) + ) + + def test_enable_clear_shared_modules(self): + """Check that clear-shared-module setting is equivalent + to SetClearSharedModules(true). + """ + messages = list() + self.dbg.SetLoggingCallback(messages.append) + self.runCmd("settings set clear-shared-modules true") + self.runCmd("log enable lldb module") + self.dbg.Destroy(self.dbg) + self.assertTrue( + any("removed 0 shared modules, 0 modules remain" in msg for msg in messages) + )