diff options
Diffstat (limited to 'source/Core/Debugger.cpp')
-rw-r--r-- | source/Core/Debugger.cpp | 459 |
1 files changed, 223 insertions, 236 deletions
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp index d36800e20bc0f..34608d0193fc7 100644 --- a/source/Core/Debugger.cpp +++ b/source/Core/Debugger.cpp @@ -9,10 +9,16 @@ #include "lldb/Core/Debugger.h" +// C Includes +// C++ Includes #include <map> +#include <mutex> +// Other libraries and framework includes #include "llvm/ADT/StringRef.h" +#include "llvm/Support/DynamicLibrary.h" +// Project includes #include "lldb/lldb-private.h" #include "lldb/Core/FormatEntity.h" #include "lldb/Core/Module.h" @@ -54,34 +60,17 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/AnsiTerminal.h" -#include "llvm/Support/DynamicLibrary.h" - using namespace lldb; using namespace lldb_private; - static lldb::user_id_t g_unique_id = 1; static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024; #pragma mark Static Functions -static Mutex & -GetDebuggerListMutex () -{ - static Mutex g_mutex(Mutex::eMutexTypeRecursive); - return g_mutex; -} - typedef std::vector<DebuggerSP> DebuggerList; - -static DebuggerList & -GetDebuggerList() -{ - // hide the static debugger list inside a singleton accessor to avoid - // global init constructors - static DebuggerList g_list; - return g_list; -} +static std::recursive_mutex *g_debugger_list_mutex_ptr = nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain +static DebuggerList *g_debugger_list_ptr = nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain OptionEnumValueElement g_show_disassembly_enum_values[] = @@ -90,7 +79,7 @@ g_show_disassembly_enum_values[] = { Debugger::eStopDisassemblyTypeNoDebugInfo, "no-debuginfo", "Show disassembly when there is no debug information."}, { Debugger::eStopDisassemblyTypeNoSource, "no-source", "Show disassembly when there is no source information, or the source file is missing when displaying a stop context."}, { Debugger::eStopDisassemblyTypeAlways, "always", "Always show disassembly when displaying a stop context."}, - { 0, NULL, NULL } + { 0, nullptr, nullptr } }; OptionEnumValueElement @@ -99,7 +88,7 @@ g_language_enumerators[] = { eScriptLanguageNone, "none", "Disable scripting languages."}, { eScriptLanguagePython, "python", "Select python as the default scripting language."}, { eScriptLanguageDefault, "default", "Select the lldb default as the default scripting language."}, - { 0, NULL, NULL } + { 0, nullptr, nullptr } }; #define MODULE_WITH_FUNC "{ ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}" @@ -140,30 +129,29 @@ g_language_enumerators[] = // lldb's original format for disassembly would look like this format string - // {${function.initial-function}{${module.file.basename}`}{${function.name-without-args}}:\n}{${function.changed}\n{${module.file.basename}`}{${function.name-without-args}}:\n}{${current-pc-arrow} }{${addr-file-or-load}}: - static PropertyDefinition g_properties[] = { -{ "auto-confirm", OptionValue::eTypeBoolean , true, false, NULL, NULL, "If true all confirmation prompts will receive their default reply." }, -{ "disassembly-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_DISASSEMBLY_FORMAT, NULL, "The default disassembly format string to use when disassembling instruction sequences." }, -{ "frame-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_FRAME_FORMAT, NULL, "The default frame format string to use when displaying stack frame information for threads." }, -{ "notify-void", OptionValue::eTypeBoolean , true, false, NULL, NULL, "Notify the user explicitly if an expression returns void (default: false)." }, -{ "prompt", OptionValue::eTypeString , true, OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", NULL, "The debugger command line prompt displayed for the user." }, -{ "script-lang", OptionValue::eTypeEnum , true, eScriptLanguagePython, NULL, g_language_enumerators, "The script language to be used for evaluating user-written scripts." }, -{ "stop-disassembly-count", OptionValue::eTypeSInt64 , true, 4 , NULL, NULL, "The number of disassembly lines to show when displaying a stopped context." }, -{ "stop-disassembly-display", OptionValue::eTypeEnum , true, Debugger::eStopDisassemblyTypeNoDebugInfo, NULL, g_show_disassembly_enum_values, "Control when to display disassembly when displaying a stopped context." }, -{ "stop-line-count-after", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come after the current source line when displaying a stopped context." }, -{ "stop-line-count-before", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come before the current source line when displaying a stopped context." }, -{ "term-width", OptionValue::eTypeSInt64 , true, 80 , NULL, NULL, "The maximum number of columns to use for displaying text." }, -{ "thread-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_THREAD_FORMAT, NULL, "The default thread format string to use when displaying thread information." }, -{ "use-external-editor", OptionValue::eTypeBoolean , true, false, NULL, NULL, "Whether to use an external editor or not." }, -{ "use-color", OptionValue::eTypeBoolean , true, true , NULL, NULL, "Whether to use Ansi color codes or not." }, -{ "auto-one-line-summaries", OptionValue::eTypeBoolean , true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." }, -{ "auto-indent", OptionValue::eTypeBoolean , true, true , NULL, NULL, "If true, LLDB will auto indent/outdent code. Currently only supported in the REPL (default: true)." }, -{ "print-decls", OptionValue::eTypeBoolean , true, true , NULL, NULL, "If true, LLDB will print the values of variables declared in an expression. Currently only supported in the REPL (default: true)." }, -{ "tab-size", OptionValue::eTypeUInt64 , true, 4 , NULL, NULL, "The tab size to use when indenting code in multi-line input mode (default: 4)." }, -{ "escape-non-printables", OptionValue::eTypeBoolean , true, true, NULL, NULL, "If true, LLDB will automatically escape non-printable and escape characters when formatting strings." }, -{ NULL, OptionValue::eTypeInvalid , true, 0 , NULL, NULL, NULL } +{ "auto-confirm", OptionValue::eTypeBoolean , true, false, nullptr, nullptr, "If true all confirmation prompts will receive their default reply." }, +{ "disassembly-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_DISASSEMBLY_FORMAT, nullptr, "The default disassembly format string to use when disassembling instruction sequences." }, +{ "frame-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_FRAME_FORMAT, nullptr, "The default frame format string to use when displaying stack frame information for threads." }, +{ "notify-void", OptionValue::eTypeBoolean , true, false, nullptr, nullptr, "Notify the user explicitly if an expression returns void (default: false)." }, +{ "prompt", OptionValue::eTypeString , true, OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", nullptr, "The debugger command line prompt displayed for the user." }, +{ "script-lang", OptionValue::eTypeEnum , true, eScriptLanguagePython, nullptr, g_language_enumerators, "The script language to be used for evaluating user-written scripts." }, +{ "stop-disassembly-count", OptionValue::eTypeSInt64 , true, 4 , nullptr, nullptr, "The number of disassembly lines to show when displaying a stopped context." }, +{ "stop-disassembly-display", OptionValue::eTypeEnum , true, Debugger::eStopDisassemblyTypeNoDebugInfo, nullptr, g_show_disassembly_enum_values, "Control when to display disassembly when displaying a stopped context." }, +{ "stop-line-count-after", OptionValue::eTypeSInt64 , true, 3 , nullptr, nullptr, "The number of sources lines to display that come after the current source line when displaying a stopped context." }, +{ "stop-line-count-before", OptionValue::eTypeSInt64 , true, 3 , nullptr, nullptr, "The number of sources lines to display that come before the current source line when displaying a stopped context." }, +{ "term-width", OptionValue::eTypeSInt64 , true, 80 , nullptr, nullptr, "The maximum number of columns to use for displaying text." }, +{ "thread-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_THREAD_FORMAT, nullptr, "The default thread format string to use when displaying thread information." }, +{ "use-external-editor", OptionValue::eTypeBoolean , true, false, nullptr, nullptr, "Whether to use an external editor or not." }, +{ "use-color", OptionValue::eTypeBoolean , true, true , nullptr, nullptr, "Whether to use Ansi color codes or not." }, +{ "auto-one-line-summaries", OptionValue::eTypeBoolean , true, true, nullptr, nullptr, "If true, LLDB will automatically display small structs in one-liner format (default: true)." }, +{ "auto-indent", OptionValue::eTypeBoolean , true, true , nullptr, nullptr, "If true, LLDB will auto indent/outdent code. Currently only supported in the REPL (default: true)." }, +{ "print-decls", OptionValue::eTypeBoolean , true, true , nullptr, nullptr, "If true, LLDB will print the values of variables declared in an expression. Currently only supported in the REPL (default: true)." }, +{ "tab-size", OptionValue::eTypeUInt64 , true, 4 , nullptr, nullptr, "The tab size to use when indenting code in multi-line input mode (default: 4)." }, +{ "escape-non-printables", OptionValue::eTypeBoolean , true, true, nullptr, nullptr, "If true, LLDB will automatically escape non-printable and escape characters when formatting strings." }, +{ nullptr, OptionValue::eTypeInvalid , true, 0 , nullptr, nullptr, nullptr } }; enum @@ -189,7 +177,7 @@ enum ePropertyEscapeNonPrintables }; -LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL; +LoadPluginCallbackType Debugger::g_load_plugin_callback = nullptr; Error Debugger::SetPropertyValue (const ExecutionContext *exe_ctx, @@ -258,42 +246,42 @@ bool Debugger::GetAutoConfirm () const { const uint32_t idx = ePropertyAutoConfirm; - return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); } const FormatEntity::Entry * Debugger::GetDisassemblyFormat() const { const uint32_t idx = ePropertyDisassemblyFormat; - return m_collection_sp->GetPropertyAtIndexAsFormatEntity(NULL, idx); + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); } const FormatEntity::Entry * Debugger::GetFrameFormat() const { const uint32_t idx = ePropertyFrameFormat; - return m_collection_sp->GetPropertyAtIndexAsFormatEntity(NULL, idx); + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); } bool Debugger::GetNotifyVoid () const { const uint32_t idx = ePropertyNotiftVoid; - return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); } const char * Debugger::GetPrompt() const { const uint32_t idx = ePropertyPrompt; - return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value); + return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, g_properties[idx].default_cstr_value); } void Debugger::SetPrompt(const char *p) { const uint32_t idx = ePropertyPrompt; - m_collection_sp->SetPropertyAtIndexAsString (NULL, idx, p); + m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p); const char *new_prompt = GetPrompt(); std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes (new_prompt, GetUseColor()); if (str.length()) @@ -305,63 +293,63 @@ const FormatEntity::Entry * Debugger::GetThreadFormat() const { const uint32_t idx = ePropertyThreadFormat; - return m_collection_sp->GetPropertyAtIndexAsFormatEntity(NULL, idx); + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); } lldb::ScriptLanguage Debugger::GetScriptLanguage() const { const uint32_t idx = ePropertyScriptLanguage; - return (lldb::ScriptLanguage)m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value); + return (lldb::ScriptLanguage)m_collection_sp->GetPropertyAtIndexAsEnumeration(nullptr, idx, g_properties[idx].default_uint_value); } bool Debugger::SetScriptLanguage (lldb::ScriptLanguage script_lang) { const uint32_t idx = ePropertyScriptLanguage; - return m_collection_sp->SetPropertyAtIndexAsEnumeration (NULL, idx, script_lang); + return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx, script_lang); } uint32_t Debugger::GetTerminalWidth () const { const uint32_t idx = ePropertyTerminalWidth; - return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value); + return m_collection_sp->GetPropertyAtIndexAsSInt64(nullptr, idx, g_properties[idx].default_uint_value); } bool Debugger::SetTerminalWidth (uint32_t term_width) { const uint32_t idx = ePropertyTerminalWidth; - return m_collection_sp->SetPropertyAtIndexAsSInt64 (NULL, idx, term_width); + return m_collection_sp->SetPropertyAtIndexAsSInt64(nullptr, idx, term_width); } bool Debugger::GetUseExternalEditor () const { const uint32_t idx = ePropertyUseExternalEditor; - return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); } bool Debugger::SetUseExternalEditor (bool b) { const uint32_t idx = ePropertyUseExternalEditor; - return m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b); + return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } bool Debugger::GetUseColor () const { const uint32_t idx = ePropertyUseColor; - return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); } bool Debugger::SetUseColor (bool b) { const uint32_t idx = ePropertyUseColor; - bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b); + bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); SetPrompt (GetPrompt()); return ret; } @@ -370,80 +358,79 @@ uint32_t Debugger::GetStopSourceLineCount (bool before) const { const uint32_t idx = before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter; - return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value); + return m_collection_sp->GetPropertyAtIndexAsSInt64(nullptr, idx, g_properties[idx].default_uint_value); } Debugger::StopDisassemblyType Debugger::GetStopDisassemblyDisplay () const { const uint32_t idx = ePropertyStopDisassemblyDisplay; - return (Debugger::StopDisassemblyType)m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value); + return (Debugger::StopDisassemblyType)m_collection_sp->GetPropertyAtIndexAsEnumeration(nullptr, idx, g_properties[idx].default_uint_value); } uint32_t Debugger::GetDisassemblyLineCount () const { const uint32_t idx = ePropertyStopDisassemblyCount; - return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value); + return m_collection_sp->GetPropertyAtIndexAsSInt64(nullptr, idx, g_properties[idx].default_uint_value); } bool Debugger::GetAutoOneLineSummaries () const { const uint32_t idx = ePropertyAutoOneLineSummaries; - return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true); + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); } bool Debugger::GetEscapeNonPrintables () const { const uint32_t idx = ePropertyEscapeNonPrintables; - return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true); + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); } bool Debugger::GetAutoIndent () const { const uint32_t idx = ePropertyAutoIndent; - return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true); + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); } bool Debugger::SetAutoIndent (bool b) { const uint32_t idx = ePropertyAutoIndent; - return m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b); + return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } bool Debugger::GetPrintDecls () const { const uint32_t idx = ePropertyPrintDecls; - return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true); + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); } bool Debugger::SetPrintDecls (bool b) { const uint32_t idx = ePropertyPrintDecls; - return m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b); + return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } uint32_t Debugger::GetTabSize () const { const uint32_t idx = ePropertyTabSize; - return m_collection_sp->GetPropertyAtIndexAsUInt64 (NULL, idx, g_properties[idx].default_uint_value); + return m_collection_sp->GetPropertyAtIndexAsUInt64(nullptr, idx, g_properties[idx].default_uint_value); } bool Debugger::SetTabSize (uint32_t tab_size) { const uint32_t idx = ePropertyTabSize; - return m_collection_sp->SetPropertyAtIndexAsUInt64 (NULL, idx, tab_size); + return m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, tab_size); } - #pragma mark Debugger //const DebuggerPropertiesSP & @@ -453,28 +440,30 @@ Debugger::SetTabSize (uint32_t tab_size) //} // -static bool lldb_initialized = false; void Debugger::Initialize(LoadPluginCallbackType load_plugin_callback) { - assert(!lldb_initialized && "Debugger::Initialize called more than once!"); - - lldb_initialized = true; + assert(g_debugger_list_ptr == nullptr && "Debugger::Initialize called more than once!"); + g_debugger_list_mutex_ptr = new std::recursive_mutex(); + g_debugger_list_ptr = new DebuggerList(); g_load_plugin_callback = load_plugin_callback; } void Debugger::Terminate () { - assert(lldb_initialized && "Debugger::Terminate called without a matching Debugger::Initialize!"); - - // Clear our master list of debugger objects - Mutex::Locker locker (GetDebuggerListMutex ()); - auto& debuggers = GetDebuggerList(); - for (const auto& debugger: debuggers) - debugger->Clear(); + assert(g_debugger_list_ptr && "Debugger::Terminate called without a matching Debugger::Initialize!"); - debuggers.clear(); + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) + { + // Clear our master list of debugger objects + { + std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); + for (const auto& debugger: *g_debugger_list_ptr) + debugger->Clear(); + g_debugger_list_ptr->clear(); + } + } } void @@ -512,12 +501,9 @@ Debugger::LoadPlugin (const FileSpec& spec, Error& error) } static FileSpec::EnumerateDirectoryResult -LoadPluginCallback -( - void *baton, - FileSpec::FileType file_type, - const FileSpec &file_spec - ) +LoadPluginCallback(void *baton, + FileSpec::FileType file_type, + const FileSpec &file_spec) { Error error; @@ -551,7 +537,6 @@ LoadPluginCallback return FileSpec::eEnumerateDirectoryResultNext; } - else if (file_type == FileSpec::eFileTypeUnknown || file_type == FileSpec::eFileTypeDirectory || file_type == FileSpec::eFileTypeSymbolicLink ) @@ -607,10 +592,10 @@ DebuggerSP Debugger::CreateInstance (lldb::LogOutputCallback log_callback, void *baton) { DebuggerSP debugger_sp (new Debugger(log_callback, baton)); - if (lldb_initialized) + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { - Mutex::Locker locker (GetDebuggerListMutex ()); - GetDebuggerList().push_back(debugger_sp); + std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); + g_debugger_list_ptr->push_back(debugger_sp); } debugger_sp->InstanceInitialize (); return debugger_sp; @@ -619,21 +604,20 @@ Debugger::CreateInstance (lldb::LogOutputCallback log_callback, void *baton) void Debugger::Destroy (DebuggerSP &debugger_sp) { - if (debugger_sp.get() == NULL) + if (!debugger_sp) return; debugger_sp->Clear(); - if (lldb_initialized) + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { - Mutex::Locker locker (GetDebuggerListMutex ()); - DebuggerList &debugger_list = GetDebuggerList (); - DebuggerList::iterator pos, end = debugger_list.end(); - for (pos = debugger_list.begin (); pos != end; ++pos) + std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); + DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); + for (pos = g_debugger_list_ptr->begin (); pos != end; ++pos) { if ((*pos).get() == debugger_sp.get()) { - debugger_list.erase (pos); + g_debugger_list_ptr->erase (pos); return; } } @@ -644,15 +628,13 @@ DebuggerSP Debugger::FindDebuggerWithInstanceName (const ConstString &instance_name) { DebuggerSP debugger_sp; - if (lldb_initialized) + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { - Mutex::Locker locker (GetDebuggerListMutex ()); - DebuggerList &debugger_list = GetDebuggerList(); - DebuggerList::iterator pos, end = debugger_list.end(); - - for (pos = debugger_list.begin(); pos != end; ++pos) + std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); + DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); + for (pos = g_debugger_list_ptr->begin (); pos != end; ++pos) { - if ((*pos).get()->m_instance_name == instance_name) + if ((*pos)->m_instance_name == instance_name) { debugger_sp = *pos; break; @@ -666,12 +648,11 @@ TargetSP Debugger::FindTargetWithProcessID (lldb::pid_t pid) { TargetSP target_sp; - if (lldb_initialized) + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { - Mutex::Locker locker (GetDebuggerListMutex ()); - DebuggerList &debugger_list = GetDebuggerList(); - DebuggerList::iterator pos, end = debugger_list.end(); - for (pos = debugger_list.begin(); pos != end; ++pos) + std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); + DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); + for (pos = g_debugger_list_ptr->begin (); pos != end; ++pos) { target_sp = (*pos)->GetTargetList().FindTargetWithProcessID (pid); if (target_sp) @@ -685,12 +666,11 @@ TargetSP Debugger::FindTargetWithProcess (Process *process) { TargetSP target_sp; - if (lldb_initialized) + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { - Mutex::Locker locker (GetDebuggerListMutex ()); - DebuggerList &debugger_list = GetDebuggerList(); - DebuggerList::iterator pos, end = debugger_list.end(); - for (pos = debugger_list.begin(); pos != end; ++pos) + std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); + DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); + for (pos = g_debugger_list_ptr->begin (); pos != end; ++pos) { target_sp = (*pos)->GetTargetList().FindTargetWithProcess (process); if (target_sp) @@ -706,19 +686,22 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) : m_input_file_sp(new StreamFile(stdin, false)), m_output_file_sp(new StreamFile(stdout, false)), m_error_file_sp(new StreamFile(stderr, false)), + m_broadcaster_manager_sp(BroadcasterManager::MakeBroadcasterManager()), m_terminal_state(), m_target_list(*this), m_platform_list(), - m_listener("lldb.Debugger"), + m_listener_sp(Listener::MakeListener("lldb.Debugger")), m_source_manager_ap(), m_source_file_cache(), m_command_interpreter_ap(new CommandInterpreter(*this, eScriptLanguageDefault, false)), m_input_reader_stack(), m_instance_name(), m_loaded_plugins(), - m_event_handler_thread (), - m_io_handler_thread (), - m_sync_broadcaster (NULL, "lldb.debugger.sync") + m_event_handler_thread(), + m_io_handler_thread(), + m_sync_broadcaster(nullptr, "lldb.debugger.sync"), + m_forward_listener_sp(), + m_clear_once() { char instance_cstr[256]; snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID()); @@ -728,7 +711,7 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) : m_command_interpreter_ap->Initialize (); // Always add our default platform to the platform list PlatformSP default_platform_sp (Platform::GetHostPlatform()); - assert (default_platform_sp.get()); + assert(default_platform_sp); m_platform_list.Append (default_platform_sp, true); m_collection_sp->Initialize (g_properties); @@ -740,14 +723,14 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) : ConstString("Platform settings."), true, Platform::GetGlobalPlatformProperties()->GetValueProperties()); - if (m_command_interpreter_ap.get()) + if (m_command_interpreter_ap) { m_collection_sp->AppendProperty (ConstString("interpreter"), ConstString("Settings specify to the debugger's command interpreter."), true, m_command_interpreter_ap->GetValueProperties()); } - OptionValueSInt64 *term_width = m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64 (NULL, ePropertyTerminalWidth); + OptionValueSInt64 *term_width = m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64(nullptr, ePropertyTerminalWidth); term_width->SetMinimumValue(10); term_width->SetMaximumValue(1024); @@ -765,31 +748,44 @@ Debugger::~Debugger () void Debugger::Clear() { - ClearIOHandlers(); - StopIOHandlerThread(); - StopEventHandlerThread(); - m_listener.Clear(); - int num_targets = m_target_list.GetNumTargets(); - for (int i = 0; i < num_targets; i++) - { - TargetSP target_sp (m_target_list.GetTargetAtIndex (i)); - if (target_sp) + //---------------------------------------------------------------------- + // Make sure we call this function only once. With the C++ global + // destructor chain having a list of debuggers and with code that can be + // running on other threads, we need to ensure this doesn't happen + // multiple times. + // + // The following functions call Debugger::Clear(): + // Debugger::~Debugger(); + // static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp); + // static void Debugger::Terminate(); + //---------------------------------------------------------------------- + std::call_once(m_clear_once, [this]() { + ClearIOHandlers(); + StopIOHandlerThread(); + StopEventHandlerThread(); + m_listener_sp->Clear(); + int num_targets = m_target_list.GetNumTargets(); + for (int i = 0; i < num_targets; i++) { - ProcessSP process_sp (target_sp->GetProcessSP()); - if (process_sp) - process_sp->Finalize(); - target_sp->Destroy(); + TargetSP target_sp (m_target_list.GetTargetAtIndex (i)); + if (target_sp) + { + ProcessSP process_sp (target_sp->GetProcessSP()); + if (process_sp) + process_sp->Finalize(); + target_sp->Destroy(); + } } - } - BroadcasterManager::Clear (); - - // Close the input file _before_ we close the input read communications class - // as it does NOT own the input file, our m_input_file does. - m_terminal_state.Clear(); - if (m_input_file_sp) - m_input_file_sp->GetFile().Close (); - - m_command_interpreter_ap->Clear(); + m_broadcaster_manager_sp->Clear (); + + // Close the input file _before_ we close the input read communications class + // as it does NOT own the input file, our m_input_file does. + m_terminal_state.Clear(); + if (m_input_file_sp) + m_input_file_sp->GetFile().Close (); + + m_command_interpreter_ap->Clear(); + }); } bool @@ -817,7 +813,6 @@ Debugger::SetAsyncExecution (bool async_execution) m_command_interpreter_ap->SetSynchronous (!async_execution); } - void Debugger::SetInputFileHandle (FILE *fh, bool tranfer_ownership) { @@ -827,7 +822,7 @@ Debugger::SetInputFileHandle (FILE *fh, bool tranfer_ownership) m_input_file_sp.reset (new StreamFile (fh, tranfer_ownership)); File &in_file = m_input_file_sp->GetFile(); - if (in_file.IsValid() == false) + if (!in_file.IsValid()) in_file.SetStream (stdin, true); // Save away the terminal state if that is relevant, so that we can restore it in RestoreInputState. @@ -843,7 +838,7 @@ Debugger::SetOutputFileHandle (FILE *fh, bool tranfer_ownership) m_output_file_sp.reset (new StreamFile (fh, tranfer_ownership)); File &out_file = m_output_file_sp->GetFile(); - if (out_file.IsValid() == false) + if (!out_file.IsValid()) out_file.SetStream (stdout, false); // do not create the ScriptInterpreter just for setting the output file handle @@ -863,7 +858,7 @@ Debugger::SetErrorFileHandle (FILE *fh, bool tranfer_ownership) m_error_file_sp.reset (new StreamFile (fh, tranfer_ownership)); File &err_file = m_error_file_sp->GetFile(); - if (err_file.IsValid() == false) + if (!err_file.IsValid()) err_file.SetStream (stderr, false); } @@ -895,14 +890,14 @@ Debugger::GetSelectedExecutionContext () { ProcessSP process_sp (target_sp->GetProcessSP()); exe_ctx.SetProcessSP (process_sp); - if (process_sp && process_sp->IsRunning() == false) + if (process_sp && !process_sp->IsRunning()) { ThreadSP thread_sp (process_sp->GetThreadList().GetSelectedThread()); if (thread_sp) { exe_ctx.SetThreadSP (thread_sp); exe_ctx.SetFrameSP (thread_sp->GetSelectedFrame()); - if (exe_ctx.GetFramePtr() == NULL) + if (exe_ctx.GetFramePtr() == nullptr) exe_ctx.SetFrameSP (thread_sp->GetStackFrameAtIndex (0)); } } @@ -911,40 +906,40 @@ Debugger::GetSelectedExecutionContext () } void -Debugger::DispatchInputInterrupt () +Debugger::DispatchInputInterrupt() { - Mutex::Locker locker (m_input_reader_stack.GetMutex()); - IOHandlerSP reader_sp (m_input_reader_stack.Top()); + std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex()); + IOHandlerSP reader_sp(m_input_reader_stack.Top()); if (reader_sp) reader_sp->Interrupt(); } void -Debugger::DispatchInputEndOfFile () +Debugger::DispatchInputEndOfFile() { - Mutex::Locker locker (m_input_reader_stack.GetMutex()); - IOHandlerSP reader_sp (m_input_reader_stack.Top()); + std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex()); + IOHandlerSP reader_sp(m_input_reader_stack.Top()); if (reader_sp) reader_sp->GotEOF(); } void -Debugger::ClearIOHandlers () +Debugger::ClearIOHandlers() { // The bottom input reader should be the main debugger input reader. We do not want to close that one here. - Mutex::Locker locker (m_input_reader_stack.GetMutex()); + std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex()); while (m_input_reader_stack.GetSize() > 1) { - IOHandlerSP reader_sp (m_input_reader_stack.Top()); + IOHandlerSP reader_sp(m_input_reader_stack.Top()); if (reader_sp) - PopIOHandler (reader_sp); + PopIOHandler(reader_sp); } } void Debugger::ExecuteIOHandlers() { - while (1) + while (true) { IOHandlerSP reader_sp(m_input_reader_stack.Top()); if (!reader_sp) @@ -953,7 +948,7 @@ Debugger::ExecuteIOHandlers() reader_sp->Run(); // Remove all input readers that are done from the top of the stack - while (1) + while (true) { IOHandlerSP top_reader_sp = m_input_reader_stack.Top(); if (top_reader_sp && top_reader_sp->GetIsDone()) @@ -1018,7 +1013,7 @@ Debugger::RunIOHandler (const IOHandlerSP& reader_sp) break; } - while (1) + while (true) { top_reader_sp = m_input_reader_stack.Top(); if (top_reader_sp && top_reader_sp->GetIsDone()) @@ -1030,16 +1025,16 @@ Debugger::RunIOHandler (const IOHandlerSP& reader_sp) } void -Debugger::AdoptTopIOHandlerFilesIfInvalid (StreamFileSP &in, StreamFileSP &out, StreamFileSP &err) +Debugger::AdoptTopIOHandlerFilesIfInvalid(StreamFileSP &in, StreamFileSP &out, StreamFileSP &err) { // Before an IOHandler runs, it must have in/out/err streams. // This function is called when one ore more of the streams - // are NULL. We use the top input reader's in/out/err streams, + // are nullptr. We use the top input reader's in/out/err streams, // or fall back to the debugger file handles, or we fall back // onto stdin/stdout/stderr as a last resort. - - Mutex::Locker locker (m_input_reader_stack.GetMutex()); - IOHandlerSP top_reader_sp (m_input_reader_stack.Top()); + + std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex()); + IOHandlerSP top_reader_sp(m_input_reader_stack.Top()); // If no STDIN has been set, then set it appropriately if (!in) { @@ -1047,7 +1042,7 @@ Debugger::AdoptTopIOHandlerFilesIfInvalid (StreamFileSP &in, StreamFileSP &out, in = top_reader_sp->GetInputStreamFile(); else in = GetInputFile(); - + // If there is nothing, use stdin if (!in) in = StreamFileSP(new StreamFile(stdin, false)); @@ -1059,7 +1054,7 @@ Debugger::AdoptTopIOHandlerFilesIfInvalid (StreamFileSP &in, StreamFileSP &out, out = top_reader_sp->GetOutputStreamFile(); else out = GetOutputFile(); - + // If there is nothing, use stdout if (!out) out = StreamFileSP(new StreamFile(stdout, false)); @@ -1071,31 +1066,30 @@ Debugger::AdoptTopIOHandlerFilesIfInvalid (StreamFileSP &in, StreamFileSP &out, err = top_reader_sp->GetErrorStreamFile(); else err = GetErrorFile(); - + // If there is nothing, use stderr if (!err) err = StreamFileSP(new StreamFile(stdout, false)); - } } void -Debugger::PushIOHandler (const IOHandlerSP& reader_sp) +Debugger::PushIOHandler(const IOHandlerSP &reader_sp) { if (!reader_sp) return; - - Mutex::Locker locker (m_input_reader_stack.GetMutex()); + + std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex()); // Get the current top input reader... - IOHandlerSP top_reader_sp (m_input_reader_stack.Top()); - + IOHandlerSP top_reader_sp(m_input_reader_stack.Top()); + // Don't push the same IO handler twice... if (reader_sp == top_reader_sp) return; // Push our new input reader - m_input_reader_stack.Push (reader_sp); + m_input_reader_stack.Push(reader_sp); reader_sp->Activate(); // Interrupt the top input reader to it will exit its Run() function @@ -1108,12 +1102,12 @@ Debugger::PushIOHandler (const IOHandlerSP& reader_sp) } bool -Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp) +Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) { - if (! pop_reader_sp) + if (!pop_reader_sp) return false; - Mutex::Locker locker (m_input_reader_stack.GetMutex()); + std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex()); // The reader on the stop of the stack is done, so let the next // read on the stack refresh its prompt and if there is one... @@ -1127,7 +1121,7 @@ Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp) reader_sp->Deactivate(); reader_sp->Cancel(); - m_input_reader_stack.Pop (); + m_input_reader_stack.Pop(); reader_sp = m_input_reader_stack.Top(); if (reader_sp) @@ -1151,10 +1145,10 @@ Debugger::GetAsyncErrorStream () size_t Debugger::GetNumDebuggers() { - if (lldb_initialized) + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { - Mutex::Locker locker (GetDebuggerListMutex ()); - return GetDebuggerList().size(); + std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); + return g_debugger_list_ptr->size(); } return 0; } @@ -1164,13 +1158,11 @@ Debugger::GetDebuggerAtIndex (size_t index) { DebuggerSP debugger_sp; - if (lldb_initialized) + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { - Mutex::Locker locker (GetDebuggerListMutex ()); - DebuggerList &debugger_list = GetDebuggerList(); - - if (index < debugger_list.size()) - debugger_sp = debugger_list[index]; + std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); + if (index < g_debugger_list_ptr->size()) + debugger_sp = g_debugger_list_ptr->at(index); } return debugger_sp; @@ -1181,14 +1173,13 @@ Debugger::FindDebuggerWithID (lldb::user_id_t id) { DebuggerSP debugger_sp; - if (lldb_initialized) + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { - Mutex::Locker locker (GetDebuggerListMutex ()); - DebuggerList &debugger_list = GetDebuggerList(); - DebuggerList::iterator pos, end = debugger_list.end(); - for (pos = debugger_list.begin(); pos != end; ++pos) + std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); + DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); + for (pos = g_debugger_list_ptr->begin (); pos != end; ++pos) { - if ((*pos).get()->GetID() == id) + if ((*pos)->GetID() == id) { debugger_sp = *pos; break; @@ -1202,7 +1193,7 @@ Debugger::FindDebuggerWithID (lldb::user_id_t id) static void TestPromptFormats (StackFrame *frame) { - if (frame == NULL) + if (frame == nullptr) return; StreamString s; @@ -1277,11 +1268,11 @@ Debugger::FormatDisassemblerAddress (const FormatEntity::Entry *format, { FormatEntity::Entry format_entry; - if (format == NULL) + if (format == nullptr) { - if (exe_ctx != NULL && exe_ctx->HasTargetScope()) + if (exe_ctx != nullptr && exe_ctx->HasTargetScope()) format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat(); - if (format == NULL) + if (format == nullptr) { FormatEntity::Parse("${addr}: ", format_entry); format = &format_entry; @@ -1313,14 +1304,13 @@ Debugger::FormatDisassemblerAddress (const FormatEntity::Entry *format, // has no Function or Symbol -- if SymbolContext had an IsValid() method, it // would return false. But we do get a prev_sc pointer. if ((sc && (sc->function || sc->symbol)) - && prev_sc && (prev_sc->function == NULL && prev_sc->symbol == NULL)) + && prev_sc && (prev_sc->function == nullptr && prev_sc->symbol == nullptr)) { initial_function = true; } - return FormatEntity::Format(*format, s, sc, exe_ctx, addr, NULL, function_changed, initial_function); + return FormatEntity::Format(*format, s, sc, exe_ctx, addr, nullptr, function_changed, initial_function); } - void Debugger::SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton) { @@ -1340,7 +1330,7 @@ Debugger::EnableLog (const char *channel, const char **categories, const char *l // For now when using the callback mode you always get thread & timestamp. log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME; } - else if (log_file == NULL || *log_file == '\0') + else if (log_file == nullptr || *log_file == '\0') { log_stream_sp = GetOutputFile(); } @@ -1360,7 +1350,7 @@ Debugger::EnableLog (const char *channel, const char **categories, const char *l m_log_streams[log_file] = log_stream_sp; } } - assert (log_stream_sp.get()); + assert(log_stream_sp); if (log_options == 0) log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE; @@ -1371,13 +1361,11 @@ Debugger::EnableLog (const char *channel, const char **categories, const char *l SourceManager & Debugger::GetSourceManager () { - if (m_source_manager_ap.get() == NULL) + if (!m_source_manager_ap) m_source_manager_ap.reset (new SourceManager (shared_from_this())); return *m_source_manager_ap; } - - // This function handles events that were broadcast by the process. void Debugger::HandleBreakpointEvent (const EventSP &event_sp) @@ -1428,13 +1416,13 @@ size_t Debugger::GetProcessSTDOUT (Process *process, Stream *stream) { size_t total_bytes = 0; - if (stream == NULL) + if (stream == nullptr) stream = GetOutputFile().get(); if (stream) { // The process has stuff waiting for stdout; get it and write it out to the appropriate place. - if (process == NULL) + if (process == nullptr) { TargetSP target_sp = GetTargetList().GetSelectedTarget(); if (target_sp) @@ -1460,13 +1448,13 @@ size_t Debugger::GetProcessSTDERR (Process *process, Stream *stream) { size_t total_bytes = 0; - if (stream == NULL) + if (stream == nullptr) stream = GetOutputFile().get(); if (stream) { // The process has stuff waiting for stderr; get it and write it out to the appropriate place. - if (process == NULL) + if (process == nullptr) { TargetSP target_sp = GetTargetList().GetSelectedTarget(); if (target_sp) @@ -1588,7 +1576,7 @@ Debugger::CancelForwardEvents (const ListenerSP &listener_sp) void Debugger::DefaultEventHandler() { - Listener& listener(GetListener()); + ListenerSP listener_sp(GetListener()); ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass()); ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass()); ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass()); @@ -1604,10 +1592,10 @@ Debugger::DefaultEventHandler() Thread::eBroadcastBitStackChanged | Thread::eBroadcastBitThreadSelected ); - listener.StartListeningForEventSpec (*this, target_event_spec); - listener.StartListeningForEventSpec (*this, process_event_spec); - listener.StartListeningForEventSpec (*this, thread_event_spec); - listener.StartListeningForEvents (m_command_interpreter_ap.get(), + listener_sp->StartListeningForEventSpec (m_broadcaster_manager_sp, target_event_spec); + listener_sp->StartListeningForEventSpec (m_broadcaster_manager_sp, process_event_spec); + listener_sp->StartListeningForEventSpec (m_broadcaster_manager_sp, thread_event_spec); + listener_sp->StartListeningForEvents (m_command_interpreter_ap.get(), CommandInterpreter::eBroadcastBitQuitCommandReceived | CommandInterpreter::eBroadcastBitAsynchronousOutputData | CommandInterpreter::eBroadcastBitAsynchronousErrorData ); @@ -1620,7 +1608,7 @@ Debugger::DefaultEventHandler() while (!done) { EventSP event_sp; - if (listener.WaitForEvent(NULL, event_sp)) + if (listener_sp->WaitForEvent(nullptr, event_sp)) { if (event_sp) { @@ -1702,21 +1690,22 @@ Debugger::StartEventHandlerThread() // it is up and running and listening to events before we return from // this function. We do this by listening to events for the // eBroadcastBitEventThreadIsListening from the m_sync_broadcaster - Listener listener("lldb.debugger.event-handler"); - listener.StartListeningForEvents(&m_sync_broadcaster, eBroadcastBitEventThreadIsListening); + ListenerSP listener_sp(Listener::MakeListener("lldb.debugger.event-handler")); + listener_sp->StartListeningForEvents(&m_sync_broadcaster, eBroadcastBitEventThreadIsListening); // Use larger 8MB stack for this thread - m_event_handler_thread = ThreadLauncher::LaunchThread("lldb.debugger.event-handler", EventHandlerThread, + m_event_handler_thread = ThreadLauncher::LaunchThread("lldb.debugger.event-handler", + EventHandlerThread, this, - NULL, + nullptr, g_debugger_event_thread_stack_bytes); // Make sure DefaultEventHandler() is running and listening to events before we return // from this function. We are only listening for events of type // eBroadcastBitEventThreadIsListening so we don't need to check the event, we just need - // to wait an infinite amount of time for it (NULL timeout as the first parameter) + // to wait an infinite amount of time for it (nullptr timeout as the first parameter) lldb::EventSP event_sp; - listener.WaitForEvent(NULL, event_sp); + listener_sp->WaitForEvent(nullptr, event_sp); } return m_event_handler_thread.IsJoinable(); } @@ -1731,7 +1720,6 @@ Debugger::StopEventHandlerThread() } } - lldb::thread_result_t Debugger::IOHandlerThread (lldb::thread_arg_t arg) { @@ -1751,11 +1739,11 @@ bool Debugger::StartIOHandlerThread() { if (!m_io_handler_thread.IsJoinable()) - m_io_handler_thread = ThreadLauncher::LaunchThread ("lldb.debugger.io-handler", - IOHandlerThread, - this, - NULL, - 8*1024*1024); // Use larger 8MB stack for this thread + m_io_handler_thread = ThreadLauncher::LaunchThread("lldb.debugger.io-handler", + IOHandlerThread, + this, + nullptr, + 8*1024*1024); // Use larger 8MB stack for this thread return m_io_handler_thread.IsJoinable(); } @@ -1817,9 +1805,9 @@ Debugger::RunREPL (LanguageType language, const char *repl_options) { language = *repl_languages.begin(); } - else if (repl_languages.size() == 0) + else if (repl_languages.empty()) { - err.SetErrorStringWithFormat("LLDB isn't configured with support support for any REPLs."); + err.SetErrorStringWithFormat("LLDB isn't configured with REPL support for any languages."); return err; } else @@ -1849,4 +1837,3 @@ Debugger::RunREPL (LanguageType language, const char *repl_options) return err; } - |