diff options
Diffstat (limited to 'source/Core/Debugger.cpp')
-rw-r--r-- | source/Core/Debugger.cpp | 2792 |
1 files changed, 1337 insertions, 1455 deletions
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp index 34608d0193fc..8f888a518d5b 100644 --- a/source/Core/Debugger.cpp +++ b/source/Core/Debugger.cpp @@ -19,7 +19,6 @@ #include "llvm/Support/DynamicLibrary.h" // Project includes -#include "lldb/lldb-private.h" #include "lldb/Core/FormatEntity.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginInterface.h" @@ -50,15 +49,17 @@ #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/VariableList.h" -#include "lldb/Target/TargetList.h" #include "lldb/Target/Language.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StopInfo.h" +#include "lldb/Target/StructuredDataPlugin.h" #include "lldb/Target/Target.h" +#include "lldb/Target/TargetList.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/AnsiTerminal.h" +#include "lldb/lldb-private.h" using namespace lldb; using namespace lldb_private; @@ -69,1124 +70,1052 @@ static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024; #pragma mark Static Functions typedef std::vector<DebuggerSP> DebuggerList; -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[] = -{ - { Debugger::eStopDisassemblyTypeNever, "never", "Never show disassembly when displaying a stop context."}, - { 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, nullptr, nullptr } -}; - -OptionEnumValueElement -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, nullptr, nullptr } -}; - -#define MODULE_WITH_FUNC "{ ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}" +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[] = { + {Debugger::eStopDisassemblyTypeNever, "never", + "Never show disassembly when displaying a stop context."}, + {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, nullptr, nullptr}}; + +OptionEnumValueElement 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, nullptr, nullptr}}; + +#define MODULE_WITH_FUNC \ + "{ " \ + "${module.file.basename}{`${function.name-with-args}" \ + "{${frame.no-debug}${function.pc-offset}}}}" #define FILE_AND_LINE "{ at ${line.file.basename}:${line.number}}" #define IS_OPTIMIZED "{${function.is-optimized} [opt]}" -#define DEFAULT_THREAD_FORMAT "thread #${thread.index}: tid = ${thread.id%tid}"\ - "{, ${frame.pc}}"\ - MODULE_WITH_FUNC\ - FILE_AND_LINE\ - "{, name = '${thread.name}'}"\ - "{, queue = '${thread.queue}'}"\ - "{, activity = '${thread.info.activity.name}'}" \ - "{, ${thread.info.trace_messages} messages}" \ - "{, stop reason = ${thread.stop-reason}}"\ - "{\\nReturn value: ${thread.return-value}}"\ - "{\\nCompleted expression: ${thread.completed-expression}}"\ - "\\n" - -#define DEFAULT_FRAME_FORMAT "frame #${frame.index}: ${frame.pc}"\ - MODULE_WITH_FUNC\ - FILE_AND_LINE\ - IS_OPTIMIZED\ - "\\n" +#define DEFAULT_THREAD_FORMAT \ + "thread #${thread.index}: tid = ${thread.id%tid}" \ + "{, ${frame.pc}}" MODULE_WITH_FUNC FILE_AND_LINE \ + "{, name = '${thread.name}'}" \ + "{, queue = '${thread.queue}'}" \ + "{, activity = '${thread.info.activity.name}'}" \ + "{, ${thread.info.trace_messages} messages}" \ + "{, stop reason = ${thread.stop-reason}}" \ + "{\\nReturn value: ${thread.return-value}}" \ + "{\\nCompleted expression: ${thread.completed-expression}}" \ + "\\n" + +#define DEFAULT_THREAD_STOP_FORMAT \ + "thread #${thread.index}{, name = '${thread.name}'}" \ + "{, queue = '${thread.queue}'}" \ + "{, activity = '${thread.info.activity.name}'}" \ + "{, ${thread.info.trace_messages} messages}" \ + "{, stop reason = ${thread.stop-reason}}" \ + "{\\nReturn value: ${thread.return-value}}" \ + "{\\nCompleted expression: ${thread.completed-expression}}" \ + "\\n" + +#define DEFAULT_FRAME_FORMAT \ + "frame #${frame.index}:{ ${frame.no-debug}${frame.pc}}" MODULE_WITH_FUNC FILE_AND_LINE \ + IS_OPTIMIZED "\\n" // Three parts to this disassembly format specification: // 1. If this is a new function/symbol (no previous symbol/function), print // dylib`funcname:\n -// 2. If this is a symbol context change (different from previous symbol/function), print +// 2. If this is a symbol context change (different from previous +// symbol/function), print // dylib`funcname:\n -// 3. print -// address <+offset>: -#define DEFAULT_DISASSEMBLY_FORMAT "{${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}{ <${function.concrete-only-addr-offset-no-padding}>}: " +// 3. print +// address <+offset>: +#define DEFAULT_DISASSEMBLY_FORMAT \ + "{${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}{ " \ + "<${function.concrete-only-addr-offset-no-padding}>}: " // gdb's disassembly format can be emulated with -// ${current-pc-arrow}${addr-file-or-load}{ <${function.name-without-args}${function.concrete-only-addr-offset-no-padding}>}: +// ${current-pc-arrow}${addr-file-or-load}{ +// <${function.name-without-args}${function.concrete-only-addr-offset-no-padding}>}: // 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, 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 -{ - ePropertyAutoConfirm = 0, - ePropertyDisassemblyFormat, - ePropertyFrameFormat, - ePropertyNotiftVoid, - ePropertyPrompt, - ePropertyScriptLanguage, - ePropertyStopDisassemblyCount, - ePropertyStopDisassemblyDisplay, - ePropertyStopLineCountAfter, - ePropertyStopLineCountBefore, - ePropertyTerminalWidth, - ePropertyThreadFormat, - ePropertyUseExternalEditor, - ePropertyUseColor, - ePropertyAutoOneLineSummaries, - ePropertyAutoIndent, - ePropertyPrintDecls, - ePropertyTabSize, - ePropertyEscapeNonPrintables +// {${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}}: + +#define DEFAULT_STOP_SHOW_COLUMN_ANSI_PREFIX "${ansi.underline}" +#define DEFAULT_STOP_SHOW_COLUMN_ANSI_SUFFIX "${ansi.normal}" + +static OptionEnumValueElement s_stop_show_column_values[] = { + {eStopShowColumnAnsiOrCaret, "ansi-or-caret", + "Highlight the stop column with ANSI terminal codes when color/ANSI mode " + "is enabled; otherwise, fall back to using a text-only caret (^) as if " + "\"caret-only\" mode was selected."}, + {eStopShowColumnAnsi, "ansi", "Highlight the stop column with ANSI " + "terminal codes when running LLDB with " + "color/ANSI enabled."}, + {eStopShowColumnCaret, "caret", + "Highlight the stop column with a caret character (^) underneath the stop " + "column. This method introduces a new line in source listings that " + "display thread stop locations."}, + {eStopShowColumnNone, "none", "Do not highlight the stop column."}, + {0, nullptr, nullptr}}; + +static PropertyDefinition g_properties[] = { + {"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."}, + {"stop-show-column", OptionValue::eTypeEnum, false, + eStopShowColumnAnsiOrCaret, nullptr, s_stop_show_column_values, + "If true, LLDB will use the column information from the debug info to " + "mark the current position when displaying a stopped context."}, + {"stop-show-column-ansi-prefix", OptionValue::eTypeFormatEntity, true, 0, + DEFAULT_STOP_SHOW_COLUMN_ANSI_PREFIX, nullptr, + "When displaying the column marker in a color-enabled (i.e. ANSI) " + "terminal, use the ANSI terminal code specified in this format at the " + "immediately before the column to be marked."}, + {"stop-show-column-ansi-suffix", OptionValue::eTypeFormatEntity, true, 0, + DEFAULT_STOP_SHOW_COLUMN_ANSI_SUFFIX, nullptr, + "When displaying the column marker in a color-enabled (i.e. ANSI) " + "terminal, use the ANSI terminal code specified in this format " + "immediately after the column to be marked."}, + {"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."}, + {"thread-stop-format", OptionValue::eTypeFormatEntity, true, 0, + DEFAULT_THREAD_STOP_FORMAT, nullptr, "The default thread format " + "string to usewhen displaying thread " + "information as part of the stop display."}, + {"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 { + ePropertyAutoConfirm = 0, + ePropertyDisassemblyFormat, + ePropertyFrameFormat, + ePropertyNotiftVoid, + ePropertyPrompt, + ePropertyScriptLanguage, + ePropertyStopDisassemblyCount, + ePropertyStopDisassemblyDisplay, + ePropertyStopLineCountAfter, + ePropertyStopLineCountBefore, + ePropertyStopShowColumn, + ePropertyStopShowColumnAnsiPrefix, + ePropertyStopShowColumnAnsiSuffix, + ePropertyTerminalWidth, + ePropertyThreadFormat, + ePropertyThreadStopFormat, + ePropertyUseExternalEditor, + ePropertyUseColor, + ePropertyAutoOneLineSummaries, + ePropertyAutoIndent, + ePropertyPrintDecls, + ePropertyTabSize, + ePropertyEscapeNonPrintables }; LoadPluginCallbackType Debugger::g_load_plugin_callback = nullptr; -Error -Debugger::SetPropertyValue (const ExecutionContext *exe_ctx, - VarSetOperationType op, - const char *property_path, - const char *value) -{ - bool is_load_script = strcmp(property_path,"target.load-script-from-symbol-file") == 0; - bool is_escape_non_printables = strcmp(property_path, "escape-non-printables") == 0; - TargetSP target_sp; - LoadScriptFromSymFile load_script_old_value; - if (is_load_script && exe_ctx->GetTargetSP()) - { - target_sp = exe_ctx->GetTargetSP(); - load_script_old_value = target_sp->TargetProperties::GetLoadScriptFromSymbolFile(); - } - Error error (Properties::SetPropertyValue (exe_ctx, op, property_path, value)); - if (error.Success()) - { - // FIXME it would be nice to have "on-change" callbacks for properties - if (strcmp(property_path, g_properties[ePropertyPrompt].name) == 0) - { - const char *new_prompt = GetPrompt(); - std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes (new_prompt, GetUseColor()); - if (str.length()) - new_prompt = str.c_str(); - GetCommandInterpreter().UpdatePrompt(new_prompt); - EventSP prompt_change_event_sp (new Event(CommandInterpreter::eBroadcastBitResetPrompt, new EventDataBytes (new_prompt))); - GetCommandInterpreter().BroadcastEvent (prompt_change_event_sp); - } - else if (strcmp(property_path, g_properties[ePropertyUseColor].name) == 0) - { - // use-color changed. Ping the prompt so it can reset the ansi terminal codes. - SetPrompt (GetPrompt()); - } - else if (is_load_script && target_sp && load_script_old_value == eLoadScriptFromSymFileWarn) - { - if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() == eLoadScriptFromSymFileTrue) - { - std::list<Error> errors; - StreamString feedback_stream; - if (!target_sp->LoadScriptingResources(errors,&feedback_stream)) - { - StreamFileSP stream_sp (GetErrorFile()); - if (stream_sp) - { - for (auto error : errors) - { - stream_sp->Printf("%s\n",error.AsCString()); - } - if (feedback_stream.GetSize()) - stream_sp->Printf("%s",feedback_stream.GetData()); - } - } +Error Debugger::SetPropertyValue(const ExecutionContext *exe_ctx, + VarSetOperationType op, + llvm::StringRef property_path, llvm::StringRef value) { + bool is_load_script = (property_path == "target.load-script-from-symbol-file"); + bool is_escape_non_printables = (property_path == "escape-non-printables"); + TargetSP target_sp; + LoadScriptFromSymFile load_script_old_value; + if (is_load_script && exe_ctx->GetTargetSP()) { + target_sp = exe_ctx->GetTargetSP(); + load_script_old_value = + target_sp->TargetProperties::GetLoadScriptFromSymbolFile(); + } + Error error(Properties::SetPropertyValue(exe_ctx, op, property_path, value)); + if (error.Success()) { + // FIXME it would be nice to have "on-change" callbacks for properties + if (property_path == g_properties[ePropertyPrompt].name) { + llvm::StringRef new_prompt = GetPrompt(); + std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes( + new_prompt, GetUseColor()); + if (str.length()) + new_prompt = str; + GetCommandInterpreter().UpdatePrompt(new_prompt); + EventSP prompt_change_event_sp( + new Event(CommandInterpreter::eBroadcastBitResetPrompt, + new EventDataBytes(new_prompt))); + GetCommandInterpreter().BroadcastEvent(prompt_change_event_sp); + } else if (property_path == g_properties[ePropertyUseColor].name) { + // use-color changed. Ping the prompt so it can reset the ansi terminal + // codes. + SetPrompt(GetPrompt()); + } else if (is_load_script && target_sp && + load_script_old_value == eLoadScriptFromSymFileWarn) { + if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() == + eLoadScriptFromSymFileTrue) { + std::list<Error> errors; + StreamString feedback_stream; + if (!target_sp->LoadScriptingResources(errors, &feedback_stream)) { + StreamFileSP stream_sp(GetErrorFile()); + if (stream_sp) { + for (auto error : errors) { + stream_sp->Printf("%s\n", error.AsCString()); } + if (feedback_stream.GetSize()) + stream_sp->PutCString(feedback_stream.GetString()); + } } - else if (is_escape_non_printables) - { - DataVisualization::ForceUpdate(); - } + } + } else if (is_escape_non_printables) { + DataVisualization::ForceUpdate(); } - return error; + } + return error; } -bool -Debugger::GetAutoConfirm () const -{ - const uint32_t idx = ePropertyAutoConfirm; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +bool Debugger::GetAutoConfirm() const { + const uint32_t idx = ePropertyAutoConfirm; + 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(nullptr, idx); +const FormatEntity::Entry *Debugger::GetDisassemblyFormat() const { + const uint32_t idx = ePropertyDisassemblyFormat; + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); } -const FormatEntity::Entry * -Debugger::GetFrameFormat() const -{ - const uint32_t idx = ePropertyFrameFormat; - return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); +const FormatEntity::Entry *Debugger::GetFrameFormat() const { + const uint32_t idx = ePropertyFrameFormat; + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); } -bool -Debugger::GetNotifyVoid () const -{ - const uint32_t idx = ePropertyNotiftVoid; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +bool Debugger::GetNotifyVoid() const { + const uint32_t idx = ePropertyNotiftVoid; + 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(nullptr, idx, g_properties[idx].default_cstr_value); +llvm::StringRef Debugger::GetPrompt() const { + const uint32_t idx = ePropertyPrompt; + 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(nullptr, idx, p); - const char *new_prompt = GetPrompt(); - std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes (new_prompt, GetUseColor()); - if (str.length()) - new_prompt = str.c_str(); - GetCommandInterpreter().UpdatePrompt(new_prompt); +void Debugger::SetPrompt(llvm::StringRef p) { + const uint32_t idx = ePropertyPrompt; + m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p); + llvm::StringRef new_prompt = GetPrompt(); + std::string str = + lldb_utility::ansi::FormatAnsiTerminalCodes(new_prompt, GetUseColor()); + if (str.length()) + new_prompt = str; + GetCommandInterpreter().UpdatePrompt(new_prompt); } -const FormatEntity::Entry * -Debugger::GetThreadFormat() const -{ - const uint32_t idx = ePropertyThreadFormat; - return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); +const FormatEntity::Entry *Debugger::GetThreadFormat() const { + const uint32_t idx = ePropertyThreadFormat; + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); } -lldb::ScriptLanguage -Debugger::GetScriptLanguage() const -{ - const uint32_t idx = ePropertyScriptLanguage; - return (lldb::ScriptLanguage)m_collection_sp->GetPropertyAtIndexAsEnumeration(nullptr, idx, g_properties[idx].default_uint_value); +const FormatEntity::Entry *Debugger::GetThreadStopFormat() const { + const uint32_t idx = ePropertyThreadStopFormat; + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); } -bool -Debugger::SetScriptLanguage (lldb::ScriptLanguage script_lang) -{ - const uint32_t idx = ePropertyScriptLanguage; - return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx, script_lang); +lldb::ScriptLanguage Debugger::GetScriptLanguage() const { + const uint32_t idx = ePropertyScriptLanguage; + return (lldb::ScriptLanguage)m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_properties[idx].default_uint_value); } -uint32_t -Debugger::GetTerminalWidth () const -{ - const uint32_t idx = ePropertyTerminalWidth; - return m_collection_sp->GetPropertyAtIndexAsSInt64(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(nullptr, idx, + script_lang); } -bool -Debugger::SetTerminalWidth (uint32_t term_width) -{ - const uint32_t idx = ePropertyTerminalWidth; - return m_collection_sp->SetPropertyAtIndexAsSInt64(nullptr, idx, term_width); +uint32_t Debugger::GetTerminalWidth() const { + const uint32_t idx = ePropertyTerminalWidth; + return m_collection_sp->GetPropertyAtIndexAsSInt64( + nullptr, idx, g_properties[idx].default_uint_value); } -bool -Debugger::GetUseExternalEditor () const -{ - const uint32_t idx = ePropertyUseExternalEditor; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +bool Debugger::SetTerminalWidth(uint32_t term_width) { + const uint32_t idx = ePropertyTerminalWidth; + return m_collection_sp->SetPropertyAtIndexAsSInt64(nullptr, idx, term_width); } -bool -Debugger::SetUseExternalEditor (bool b) -{ - const uint32_t idx = ePropertyUseExternalEditor; - return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +bool Debugger::GetUseExternalEditor() const { + const uint32_t idx = ePropertyUseExternalEditor; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -bool -Debugger::GetUseColor () const -{ - const uint32_t idx = ePropertyUseColor; - 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(nullptr, idx, b); } -bool -Debugger::SetUseColor (bool b) -{ - const uint32_t idx = ePropertyUseColor; - bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); - SetPrompt (GetPrompt()); - return ret; +bool Debugger::GetUseColor() const { + const uint32_t idx = ePropertyUseColor; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -uint32_t -Debugger::GetStopSourceLineCount (bool before) const -{ - const uint32_t idx = before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter; - return m_collection_sp->GetPropertyAtIndexAsSInt64(nullptr, idx, g_properties[idx].default_uint_value); +bool Debugger::SetUseColor(bool b) { + const uint32_t idx = ePropertyUseColor; + bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); + SetPrompt(GetPrompt()); + return ret; } -Debugger::StopDisassemblyType -Debugger::GetStopDisassemblyDisplay () const -{ - const uint32_t idx = ePropertyStopDisassemblyDisplay; - return (Debugger::StopDisassemblyType)m_collection_sp->GetPropertyAtIndexAsEnumeration(nullptr, idx, g_properties[idx].default_uint_value); +StopShowColumn Debugger::GetStopShowColumn() const { + const uint32_t idx = ePropertyStopShowColumn; + return (lldb::StopShowColumn)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(nullptr, idx, g_properties[idx].default_uint_value); +const FormatEntity::Entry *Debugger::GetStopShowColumnAnsiPrefix() const { + const uint32_t idx = ePropertyStopShowColumnAnsiPrefix; + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); } -bool -Debugger::GetAutoOneLineSummaries () const -{ - const uint32_t idx = ePropertyAutoOneLineSummaries; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); +const FormatEntity::Entry *Debugger::GetStopShowColumnAnsiSuffix() const { + const uint32_t idx = ePropertyStopShowColumnAnsiSuffix; + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); } -bool -Debugger::GetEscapeNonPrintables () const -{ - const uint32_t idx = ePropertyEscapeNonPrintables; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); +uint32_t Debugger::GetStopSourceLineCount(bool before) const { + const uint32_t idx = + before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter; + return m_collection_sp->GetPropertyAtIndexAsSInt64( + nullptr, idx, g_properties[idx].default_uint_value); } -bool -Debugger::GetAutoIndent () const -{ - const uint32_t idx = ePropertyAutoIndent; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); +Debugger::StopDisassemblyType Debugger::GetStopDisassemblyDisplay() const { + const uint32_t idx = ePropertyStopDisassemblyDisplay; + return (Debugger::StopDisassemblyType) + m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_properties[idx].default_uint_value); } -bool -Debugger::SetAutoIndent (bool b) -{ - const uint32_t idx = ePropertyAutoIndent; - return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +uint32_t Debugger::GetDisassemblyLineCount() const { + const uint32_t idx = ePropertyStopDisassemblyCount; + return m_collection_sp->GetPropertyAtIndexAsSInt64( + nullptr, idx, g_properties[idx].default_uint_value); } -bool -Debugger::GetPrintDecls () const -{ - const uint32_t idx = ePropertyPrintDecls; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); +bool Debugger::GetAutoOneLineSummaries() const { + const uint32_t idx = ePropertyAutoOneLineSummaries; + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); } -bool -Debugger::SetPrintDecls (bool b) -{ - const uint32_t idx = ePropertyPrintDecls; - return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +bool Debugger::GetEscapeNonPrintables() const { + const uint32_t idx = ePropertyEscapeNonPrintables; + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); } -uint32_t -Debugger::GetTabSize () const -{ - const uint32_t idx = ePropertyTabSize; - return m_collection_sp->GetPropertyAtIndexAsUInt64(nullptr, idx, g_properties[idx].default_uint_value); +bool Debugger::GetAutoIndent() const { + const uint32_t idx = ePropertyAutoIndent; + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); } -bool -Debugger::SetTabSize (uint32_t tab_size) -{ - const uint32_t idx = ePropertyTabSize; - return m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, tab_size); +bool Debugger::SetAutoIndent(bool b) { + const uint32_t idx = ePropertyAutoIndent; + return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +} + +bool Debugger::GetPrintDecls() const { + const uint32_t idx = ePropertyPrintDecls; + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); +} + +bool Debugger::SetPrintDecls(bool b) { + const uint32_t idx = ePropertyPrintDecls; + return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +} + +uint32_t Debugger::GetTabSize() const { + const uint32_t idx = ePropertyTabSize; + 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(nullptr, idx, tab_size); } #pragma mark Debugger -//const DebuggerPropertiesSP & -//Debugger::GetSettings() const +// const DebuggerPropertiesSP & +// Debugger::GetSettings() const //{ // return m_properties_sp; //} // -void -Debugger::Initialize(LoadPluginCallbackType load_plugin_callback) -{ - 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::Initialize(LoadPluginCallbackType load_plugin_callback) { + 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(g_debugger_list_ptr && "Debugger::Terminate called without a matching Debugger::Initialize!"); +void Debugger::Terminate() { + assert(g_debugger_list_ptr && + "Debugger::Terminate called without a matching Debugger::Initialize!"); - if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { + // Clear our master list of debugger objects { - // 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(); - } + 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 -Debugger::SettingsInitialize () -{ - Target::SettingsInitialize (); -} +void Debugger::SettingsInitialize() { Target::SettingsInitialize(); } -void -Debugger::SettingsTerminate () -{ - Target::SettingsTerminate (); -} +void Debugger::SettingsTerminate() { Target::SettingsTerminate(); } -bool -Debugger::LoadPlugin (const FileSpec& spec, Error& error) -{ - if (g_load_plugin_callback) - { - llvm::sys::DynamicLibrary dynlib = g_load_plugin_callback (shared_from_this(), spec, error); - if (dynlib.isValid()) - { - m_loaded_plugins.push_back(dynlib); - return true; - } +bool Debugger::LoadPlugin(const FileSpec &spec, Error &error) { + if (g_load_plugin_callback) { + llvm::sys::DynamicLibrary dynlib = + g_load_plugin_callback(shared_from_this(), spec, error); + if (dynlib.isValid()) { + m_loaded_plugins.push_back(dynlib); + return true; } - else - { - // The g_load_plugin_callback is registered in SBDebugger::Initialize() - // and if the public API layer isn't available (code is linking against - // all of the internal LLDB static libraries), then we can't load plugins - error.SetErrorString("Public API layer is not available"); - } - return false; + } else { + // The g_load_plugin_callback is registered in SBDebugger::Initialize() + // and if the public API layer isn't available (code is linking against + // all of the internal LLDB static libraries), then we can't load plugins + error.SetErrorString("Public API layer is not available"); + } + return false; } static FileSpec::EnumerateDirectoryResult -LoadPluginCallback(void *baton, - FileSpec::FileType file_type, - const FileSpec &file_spec) -{ - Error error; - - static ConstString g_dylibext("dylib"); - static ConstString g_solibext("so"); - - if (!baton) - return FileSpec::eEnumerateDirectoryResultQuit; - - Debugger *debugger = (Debugger*)baton; - - // If we have a regular file, a symbolic link or unknown file type, try - // and process the file. We must handle unknown as sometimes the directory - // enumeration might be enumerating a file system that doesn't have correct - // file type information. - if (file_type == FileSpec::eFileTypeRegular || - file_type == FileSpec::eFileTypeSymbolicLink || - file_type == FileSpec::eFileTypeUnknown ) - { - FileSpec plugin_file_spec (file_spec); - plugin_file_spec.ResolvePath (); - - if (plugin_file_spec.GetFileNameExtension() != g_dylibext && - plugin_file_spec.GetFileNameExtension() != g_solibext) - { - return FileSpec::eEnumerateDirectoryResultNext; - } - - Error plugin_load_error; - debugger->LoadPlugin (plugin_file_spec, plugin_load_error); - - return FileSpec::eEnumerateDirectoryResultNext; - } - else if (file_type == FileSpec::eFileTypeUnknown || - file_type == FileSpec::eFileTypeDirectory || - file_type == FileSpec::eFileTypeSymbolicLink ) - { - // Try and recurse into anything that a directory or symbolic link. - // We must also do this for unknown as sometimes the directory enumeration - // might be enumerating a file system that doesn't have correct file type - // information. - return FileSpec::eEnumerateDirectoryResultEnter; +LoadPluginCallback(void *baton, FileSpec::FileType file_type, + const FileSpec &file_spec) { + Error error; + + static ConstString g_dylibext("dylib"); + static ConstString g_solibext("so"); + + if (!baton) + return FileSpec::eEnumerateDirectoryResultQuit; + + Debugger *debugger = (Debugger *)baton; + + // If we have a regular file, a symbolic link or unknown file type, try + // and process the file. We must handle unknown as sometimes the directory + // enumeration might be enumerating a file system that doesn't have correct + // file type information. + if (file_type == FileSpec::eFileTypeRegular || + file_type == FileSpec::eFileTypeSymbolicLink || + file_type == FileSpec::eFileTypeUnknown) { + FileSpec plugin_file_spec(file_spec); + plugin_file_spec.ResolvePath(); + + if (plugin_file_spec.GetFileNameExtension() != g_dylibext && + plugin_file_spec.GetFileNameExtension() != g_solibext) { + return FileSpec::eEnumerateDirectoryResultNext; } - - return FileSpec::eEnumerateDirectoryResultNext; -} -void -Debugger::InstanceInitialize () -{ - FileSpec dir_spec; - const bool find_directories = true; - const bool find_files = true; - const bool find_other = true; - char dir_path[PATH_MAX]; - if (HostInfo::GetLLDBPath(ePathTypeLLDBSystemPlugins, dir_spec)) - { - if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) - { - FileSpec::EnumerateDirectory (dir_path, - find_directories, - find_files, - find_other, - LoadPluginCallback, - this); - } + Error plugin_load_error; + debugger->LoadPlugin(plugin_file_spec, plugin_load_error); + + return FileSpec::eEnumerateDirectoryResultNext; + } else if (file_type == FileSpec::eFileTypeUnknown || + file_type == FileSpec::eFileTypeDirectory || + file_type == FileSpec::eFileTypeSymbolicLink) { + // Try and recurse into anything that a directory or symbolic link. + // We must also do this for unknown as sometimes the directory enumeration + // might be enumerating a file system that doesn't have correct file type + // information. + return FileSpec::eEnumerateDirectoryResultEnter; + } + + return FileSpec::eEnumerateDirectoryResultNext; +} + +void Debugger::InstanceInitialize() { + FileSpec dir_spec; + const bool find_directories = true; + const bool find_files = true; + const bool find_other = true; + char dir_path[PATH_MAX]; + if (HostInfo::GetLLDBPath(ePathTypeLLDBSystemPlugins, dir_spec)) { + if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) { + FileSpec::EnumerateDirectory(dir_path, find_directories, find_files, + find_other, LoadPluginCallback, this); } + } - if (HostInfo::GetLLDBPath(ePathTypeLLDBUserPlugins, dir_spec)) - { - if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) - { - FileSpec::EnumerateDirectory (dir_path, - find_directories, - find_files, - find_other, - LoadPluginCallback, - this); - } + if (HostInfo::GetLLDBPath(ePathTypeLLDBUserPlugins, dir_spec)) { + if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) { + FileSpec::EnumerateDirectory(dir_path, find_directories, find_files, + find_other, LoadPluginCallback, this); } - - PluginManager::DebuggerInitialize (*this); + } + + PluginManager::DebuggerInitialize(*this); } -DebuggerSP -Debugger::CreateInstance (lldb::LogOutputCallback log_callback, void *baton) -{ - DebuggerSP debugger_sp (new Debugger(log_callback, baton)); - if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) - { - 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; +DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback, + void *baton) { + DebuggerSP debugger_sp(new Debugger(log_callback, baton)); + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { + 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; } -void -Debugger::Destroy (DebuggerSP &debugger_sp) -{ - if (!debugger_sp) - return; - - debugger_sp->Clear(); +void Debugger::Destroy(DebuggerSP &debugger_sp) { + if (!debugger_sp) + return; - if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) - { - 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()) - { - g_debugger_list_ptr->erase (pos); - return; - } - } + debugger_sp->Clear(); + + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { + 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()) { + g_debugger_list_ptr->erase(pos); + return; + } } + } } DebuggerSP -Debugger::FindDebuggerWithInstanceName (const ConstString &instance_name) -{ - DebuggerSP debugger_sp; - if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) - { - 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)->m_instance_name == instance_name) - { - debugger_sp = *pos; - break; - } - } +Debugger::FindDebuggerWithInstanceName(const ConstString &instance_name) { + DebuggerSP debugger_sp; + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { + 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)->m_instance_name == instance_name) { + debugger_sp = *pos; + break; + } } - return debugger_sp; -} - -TargetSP -Debugger::FindTargetWithProcessID (lldb::pid_t pid) -{ - TargetSP target_sp; - if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) - { - 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) - break; - } + } + return debugger_sp; +} + +TargetSP Debugger::FindTargetWithProcessID(lldb::pid_t pid) { + TargetSP target_sp; + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { + 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) + break; } - return target_sp; -} - -TargetSP -Debugger::FindTargetWithProcess (Process *process) -{ - TargetSP target_sp; - if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) - { - 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) - break; - } + } + return target_sp; +} + +TargetSP Debugger::FindTargetWithProcess(Process *process) { + TargetSP target_sp; + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { + 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) + break; } - return target_sp; -} - -Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) : - UserID(g_unique_id++), - Properties(OptionValuePropertiesSP(new OptionValueProperties())), - 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_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(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()); - m_instance_name.SetCString(instance_cstr); - if (log_callback) - m_log_callback_stream_sp.reset (new StreamCallback (log_callback, 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); - m_platform_list.Append (default_platform_sp, true); - - m_collection_sp->Initialize (g_properties); - m_collection_sp->AppendProperty (ConstString("target"), - ConstString("Settings specify to debugging targets."), - true, - Target::GetGlobalProperties()->GetValueProperties()); - m_collection_sp->AppendProperty (ConstString("platform"), - ConstString("Platform settings."), - true, - Platform::GetGlobalPlatformProperties()->GetValueProperties()); - 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()); + } + return target_sp; +} + +Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) + : UserID(g_unique_id++), + Properties(OptionValuePropertiesSP(new OptionValueProperties())), + 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_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(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()); + m_instance_name.SetCString(instance_cstr); + if (log_callback) + m_log_callback_stream_sp.reset(new StreamCallback(log_callback, 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); + m_platform_list.Append(default_platform_sp, true); + + m_collection_sp->Initialize(g_properties); + m_collection_sp->AppendProperty( + ConstString("target"), + ConstString("Settings specify to debugging targets."), true, + Target::GetGlobalProperties()->GetValueProperties()); + m_collection_sp->AppendProperty( + ConstString("platform"), ConstString("Platform settings."), true, + Platform::GetGlobalPlatformProperties()->GetValueProperties()); + 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( + nullptr, ePropertyTerminalWidth); + term_width->SetMinimumValue(10); + term_width->SetMaximumValue(1024); + + // Turn off use-color if this is a dumb terminal. + const char *term = getenv("TERM"); + if (term && !strcmp(term, "dumb")) + SetUseColor(false); +} + +Debugger::~Debugger() { Clear(); } + +void Debugger::Clear() { + //---------------------------------------------------------------------- + // 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++) { + 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(); + } } - OptionValueSInt64 *term_width = m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64(nullptr, ePropertyTerminalWidth); - term_width->SetMinimumValue(10); - term_width->SetMaximumValue(1024); + 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(); - // Turn off use-color if this is a dumb terminal. - const char *term = getenv ("TERM"); - if (term && !strcmp (term, "dumb")) - SetUseColor (false); + m_command_interpreter_ap->Clear(); + }); } -Debugger::~Debugger () -{ - Clear(); +bool Debugger::GetCloseInputOnEOF() const { + // return m_input_comm.GetCloseOnEOF(); + return false; } -void -Debugger::Clear() -{ - //---------------------------------------------------------------------- - // 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++) - { - 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(); - } - } - 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 -Debugger::GetCloseInputOnEOF () const -{ -// return m_input_comm.GetCloseOnEOF(); - return false; +void Debugger::SetCloseInputOnEOF(bool b) { + // m_input_comm.SetCloseOnEOF(b); } -void -Debugger::SetCloseInputOnEOF (bool b) -{ -// m_input_comm.SetCloseOnEOF(b); +bool Debugger::GetAsyncExecution() { + return !m_command_interpreter_ap->GetSynchronous(); } -bool -Debugger::GetAsyncExecution () -{ - return !m_command_interpreter_ap->GetSynchronous(); +void Debugger::SetAsyncExecution(bool async_execution) { + m_command_interpreter_ap->SetSynchronous(!async_execution); } -void -Debugger::SetAsyncExecution (bool async_execution) -{ - m_command_interpreter_ap->SetSynchronous (!async_execution); +void Debugger::SetInputFileHandle(FILE *fh, bool tranfer_ownership) { + if (m_input_file_sp) + m_input_file_sp->GetFile().SetStream(fh, tranfer_ownership); + else + m_input_file_sp.reset(new StreamFile(fh, tranfer_ownership)); + + File &in_file = m_input_file_sp->GetFile(); + 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. + SaveInputTerminalState(); } -void -Debugger::SetInputFileHandle (FILE *fh, bool tranfer_ownership) -{ - if (m_input_file_sp) - m_input_file_sp->GetFile().SetStream (fh, tranfer_ownership); - else - m_input_file_sp.reset (new StreamFile (fh, tranfer_ownership)); +void Debugger::SetOutputFileHandle(FILE *fh, bool tranfer_ownership) { + if (m_output_file_sp) + m_output_file_sp->GetFile().SetStream(fh, tranfer_ownership); + else + m_output_file_sp.reset(new StreamFile(fh, tranfer_ownership)); - File &in_file = m_input_file_sp->GetFile(); - if (!in_file.IsValid()) - in_file.SetStream (stdin, true); + File &out_file = m_output_file_sp->GetFile(); + if (!out_file.IsValid()) + out_file.SetStream(stdout, false); - // Save away the terminal state if that is relevant, so that we can restore it in RestoreInputState. - SaveInputTerminalState (); + // do not create the ScriptInterpreter just for setting the output file handle + // as the constructor will know how to do the right thing on its own + const bool can_create = false; + ScriptInterpreter *script_interpreter = + GetCommandInterpreter().GetScriptInterpreter(can_create); + if (script_interpreter) + script_interpreter->ResetOutputFileHandle(fh); } -void -Debugger::SetOutputFileHandle (FILE *fh, bool tranfer_ownership) -{ - if (m_output_file_sp) - m_output_file_sp->GetFile().SetStream (fh, tranfer_ownership); - else - m_output_file_sp.reset (new StreamFile (fh, tranfer_ownership)); - - File &out_file = m_output_file_sp->GetFile(); - if (!out_file.IsValid()) - out_file.SetStream (stdout, false); - - // do not create the ScriptInterpreter just for setting the output file handle - // as the constructor will know how to do the right thing on its own - const bool can_create = false; - ScriptInterpreter* script_interpreter = GetCommandInterpreter().GetScriptInterpreter(can_create); - if (script_interpreter) - script_interpreter->ResetOutputFileHandle (fh); -} - -void -Debugger::SetErrorFileHandle (FILE *fh, bool tranfer_ownership) -{ - if (m_error_file_sp) - m_error_file_sp->GetFile().SetStream (fh, tranfer_ownership); - else - m_error_file_sp.reset (new StreamFile (fh, tranfer_ownership)); - - File &err_file = m_error_file_sp->GetFile(); - if (!err_file.IsValid()) - err_file.SetStream (stderr, false); +void Debugger::SetErrorFileHandle(FILE *fh, bool tranfer_ownership) { + if (m_error_file_sp) + m_error_file_sp->GetFile().SetStream(fh, tranfer_ownership); + else + m_error_file_sp.reset(new StreamFile(fh, tranfer_ownership)); + + File &err_file = m_error_file_sp->GetFile(); + if (!err_file.IsValid()) + err_file.SetStream(stderr, false); } -void -Debugger::SaveInputTerminalState () -{ - if (m_input_file_sp) - { - File &in_file = m_input_file_sp->GetFile(); - if (in_file.GetDescriptor() != File::kInvalidDescriptor) - m_terminal_state.Save(in_file.GetDescriptor(), true); +void Debugger::SaveInputTerminalState() { + if (m_input_file_sp) { + File &in_file = m_input_file_sp->GetFile(); + if (in_file.GetDescriptor() != File::kInvalidDescriptor) + m_terminal_state.Save(in_file.GetDescriptor(), true); + } +} + +void Debugger::RestoreInputTerminalState() { m_terminal_state.Restore(); } + +ExecutionContext Debugger::GetSelectedExecutionContext() { + ExecutionContext exe_ctx; + TargetSP target_sp(GetSelectedTarget()); + exe_ctx.SetTargetSP(target_sp); + + if (target_sp) { + ProcessSP process_sp(target_sp->GetProcessSP()); + exe_ctx.SetProcessSP(process_sp); + 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() == nullptr) + exe_ctx.SetFrameSP(thread_sp->GetStackFrameAtIndex(0)); + } } + } + return exe_ctx; } -void -Debugger::RestoreInputTerminalState () -{ - m_terminal_state.Restore(); +void Debugger::DispatchInputInterrupt() { + 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(); } -ExecutionContext -Debugger::GetSelectedExecutionContext () -{ - ExecutionContext exe_ctx; - TargetSP target_sp(GetSelectedTarget()); - exe_ctx.SetTargetSP (target_sp); - - if (target_sp) - { - ProcessSP process_sp (target_sp->GetProcessSP()); - exe_ctx.SetProcessSP (process_sp); - 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() == nullptr) - exe_ctx.SetFrameSP (thread_sp->GetStackFrameAtIndex (0)); - } - } - } - return exe_ctx; +void Debugger::DispatchInputEndOfFile() { + 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::DispatchInputInterrupt() -{ - std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex()); +void Debugger::ClearIOHandlers() { + // The bottom input reader should be the main debugger input reader. We do + // not want to close that one here. + 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()); if (reader_sp) - reader_sp->Interrupt(); + PopIOHandler(reader_sp); + } } -void -Debugger::DispatchInputEndOfFile() -{ - std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex()); +void Debugger::ExecuteIOHandlers() { + while (true) { IOHandlerSP reader_sp(m_input_reader_stack.Top()); - if (reader_sp) - reader_sp->GotEOF(); -} + if (!reader_sp) + break; -void -Debugger::ClearIOHandlers() -{ - // The bottom input reader should be the main debugger input reader. We do not want to close that one here. - 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()); - if (reader_sp) - PopIOHandler(reader_sp); - } -} + reader_sp->Run(); -void -Debugger::ExecuteIOHandlers() -{ - while (true) - { - IOHandlerSP reader_sp(m_input_reader_stack.Top()); - if (!reader_sp) - break; - - reader_sp->Run(); - - // Remove all input readers that are done from the top of the stack - while (true) - { - IOHandlerSP top_reader_sp = m_input_reader_stack.Top(); - if (top_reader_sp && top_reader_sp->GetIsDone()) - PopIOHandler (top_reader_sp); - else - break; - } + // Remove all input readers that are done from the top of the stack + while (true) { + IOHandlerSP top_reader_sp = m_input_reader_stack.Top(); + if (top_reader_sp && top_reader_sp->GetIsDone()) + PopIOHandler(top_reader_sp); + else + break; } - ClearIOHandlers(); + } + ClearIOHandlers(); } -bool -Debugger::IsTopIOHandler (const lldb::IOHandlerSP& reader_sp) -{ - return m_input_reader_stack.IsTop (reader_sp); +bool Debugger::IsTopIOHandler(const lldb::IOHandlerSP &reader_sp) { + return m_input_reader_stack.IsTop(reader_sp); } -bool -Debugger::CheckTopIOHandlerTypes (IOHandler::Type top_type, IOHandler::Type second_top_type) -{ - return m_input_reader_stack.CheckTopIOHandlerTypes (top_type, second_top_type); +bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type top_type, + IOHandler::Type second_top_type) { + return m_input_reader_stack.CheckTopIOHandlerTypes(top_type, second_top_type); } -void -Debugger::PrintAsync (const char *s, size_t len, bool is_stdout) -{ - lldb::StreamFileSP stream = is_stdout ? GetOutputFile() : GetErrorFile(); - m_input_reader_stack.PrintAsync(stream.get(), s, len); +void Debugger::PrintAsync(const char *s, size_t len, bool is_stdout) { + lldb::StreamFileSP stream = is_stdout ? GetOutputFile() : GetErrorFile(); + m_input_reader_stack.PrintAsync(stream.get(), s, len); } -ConstString -Debugger::GetTopIOHandlerControlSequence(char ch) -{ - return m_input_reader_stack.GetTopIOHandlerControlSequence (ch); +ConstString Debugger::GetTopIOHandlerControlSequence(char ch) { + return m_input_reader_stack.GetTopIOHandlerControlSequence(ch); } -const char * -Debugger::GetIOHandlerCommandPrefix() -{ - return m_input_reader_stack.GetTopIOHandlerCommandPrefix(); +const char *Debugger::GetIOHandlerCommandPrefix() { + return m_input_reader_stack.GetTopIOHandlerCommandPrefix(); } -const char * -Debugger::GetIOHandlerHelpPrologue() -{ - return m_input_reader_stack.GetTopIOHandlerHelpPrologue(); +const char *Debugger::GetIOHandlerHelpPrologue() { + return m_input_reader_stack.GetTopIOHandlerHelpPrologue(); } -void -Debugger::RunIOHandler (const IOHandlerSP& reader_sp) -{ - PushIOHandler (reader_sp); +void Debugger::RunIOHandler(const IOHandlerSP &reader_sp) { + PushIOHandler(reader_sp); - IOHandlerSP top_reader_sp = reader_sp; - while (top_reader_sp) - { - top_reader_sp->Run(); + IOHandlerSP top_reader_sp = reader_sp; + while (top_reader_sp) { + top_reader_sp->Run(); - if (top_reader_sp.get() == reader_sp.get()) - { - if (PopIOHandler (reader_sp)) - break; - } + if (top_reader_sp.get() == reader_sp.get()) { + if (PopIOHandler(reader_sp)) + break; + } - while (true) - { - top_reader_sp = m_input_reader_stack.Top(); - if (top_reader_sp && top_reader_sp->GetIsDone()) - PopIOHandler (top_reader_sp); - else - break; - } + while (true) { + top_reader_sp = m_input_reader_stack.Top(); + if (top_reader_sp && top_reader_sp->GetIsDone()) + PopIOHandler(top_reader_sp); + else + break; } -} + } +} + +void 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 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. + + 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) { + if (top_reader_sp) + in = top_reader_sp->GetInputStreamFile(); + else + in = GetInputFile(); -void -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 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. - - 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 there is nothing, use stdin if (!in) - { - if (top_reader_sp) - in = top_reader_sp->GetInputStreamFile(); - else - in = GetInputFile(); - - // If there is nothing, use stdin - if (!in) - in = StreamFileSP(new StreamFile(stdin, false)); - } - // If no STDOUT has been set, then set it appropriately + in = StreamFileSP(new StreamFile(stdin, false)); + } + // If no STDOUT has been set, then set it appropriately + if (!out) { + if (top_reader_sp) + out = top_reader_sp->GetOutputStreamFile(); + else + out = GetOutputFile(); + + // If there is nothing, use stdout if (!out) - { - if (top_reader_sp) - out = top_reader_sp->GetOutputStreamFile(); - else - out = GetOutputFile(); - - // If there is nothing, use stdout - if (!out) - out = StreamFileSP(new StreamFile(stdout, false)); - } - // If no STDERR has been set, then set it appropriately + out = StreamFileSP(new StreamFile(stdout, false)); + } + // If no STDERR has been set, then set it appropriately + if (!err) { + if (top_reader_sp) + err = top_reader_sp->GetErrorStreamFile(); + else + err = GetErrorFile(); + + // If there is nothing, use stderr if (!err) - { - if (top_reader_sp) - err = top_reader_sp->GetErrorStreamFile(); - else - err = GetErrorFile(); - - // If there is nothing, use stderr - if (!err) - err = StreamFileSP(new StreamFile(stdout, false)); - } + err = StreamFileSP(new StreamFile(stdout, false)); + } } -void -Debugger::PushIOHandler(const IOHandlerSP &reader_sp) -{ - if (!reader_sp) - return; +void Debugger::PushIOHandler(const IOHandlerSP &reader_sp) { + if (!reader_sp) + return; - std::lock_guard<std::recursive_mutex> guard(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()); + // Get the current top input reader... + IOHandlerSP top_reader_sp(m_input_reader_stack.Top()); - // Don't push the same IO handler twice... - if (reader_sp == top_reader_sp) - return; + // 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); - reader_sp->Activate(); + // Push our new input reader + m_input_reader_stack.Push(reader_sp); + reader_sp->Activate(); - // Interrupt the top input reader to it will exit its Run() function - // and let this new input reader take over - if (top_reader_sp) - { - top_reader_sp->Deactivate(); - top_reader_sp->Cancel(); - } + // Interrupt the top input reader to it will exit its Run() function + // and let this new input reader take over + if (top_reader_sp) { + top_reader_sp->Deactivate(); + top_reader_sp->Cancel(); + } } -bool -Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) -{ - if (!pop_reader_sp) - return false; +bool Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) { + if (!pop_reader_sp) + return false; - std::lock_guard<std::recursive_mutex> guard(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... - if (m_input_reader_stack.IsEmpty()) - return false; + // 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... + if (m_input_reader_stack.IsEmpty()) + return false; - IOHandlerSP reader_sp(m_input_reader_stack.Top()); + IOHandlerSP reader_sp(m_input_reader_stack.Top()); - if (pop_reader_sp != reader_sp) - return false; + if (pop_reader_sp != reader_sp) + return false; - reader_sp->Deactivate(); - reader_sp->Cancel(); - m_input_reader_stack.Pop(); + reader_sp->Deactivate(); + reader_sp->Cancel(); + m_input_reader_stack.Pop(); - reader_sp = m_input_reader_stack.Top(); - if (reader_sp) - reader_sp->Activate(); + reader_sp = m_input_reader_stack.Top(); + if (reader_sp) + reader_sp->Activate(); - return true; + return true; } -StreamSP -Debugger::GetAsyncOutputStream () -{ - return StreamSP (new StreamAsynchronousIO (*this, true)); +StreamSP Debugger::GetAsyncOutputStream() { + return StreamSP(new StreamAsynchronousIO(*this, true)); } -StreamSP -Debugger::GetAsyncErrorStream () -{ - return StreamSP (new StreamAsynchronousIO (*this, false)); -} +StreamSP Debugger::GetAsyncErrorStream() { + return StreamSP(new StreamAsynchronousIO(*this, false)); +} -size_t -Debugger::GetNumDebuggers() -{ - if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) - { - std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); - return g_debugger_list_ptr->size(); - } - return 0; +size_t Debugger::GetNumDebuggers() { + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { + std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); + return g_debugger_list_ptr->size(); + } + return 0; } -lldb::DebuggerSP -Debugger::GetDebuggerAtIndex (size_t index) -{ - DebuggerSP debugger_sp; - - if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) - { - 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); - } +lldb::DebuggerSP Debugger::GetDebuggerAtIndex(size_t index) { + DebuggerSP debugger_sp; - return debugger_sp; + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { + 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; } -DebuggerSP -Debugger::FindDebuggerWithID (lldb::user_id_t id) -{ - DebuggerSP debugger_sp; +DebuggerSP Debugger::FindDebuggerWithID(lldb::user_id_t id) { + DebuggerSP debugger_sp; - if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) - { - 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)->GetID() == id) - { - debugger_sp = *pos; - break; - } - } + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { + 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)->GetID() == id) { + debugger_sp = *pos; + break; + } } - return debugger_sp; + } + return debugger_sp; } #if 0 @@ -1258,582 +1187,535 @@ TestPromptFormats (StackFrame *frame) } #endif -bool -Debugger::FormatDisassemblerAddress (const FormatEntity::Entry *format, - const SymbolContext *sc, - const SymbolContext *prev_sc, - const ExecutionContext *exe_ctx, - const Address *addr, - Stream &s) -{ - FormatEntity::Entry format_entry; - - if (format == nullptr) - { - if (exe_ctx != nullptr && exe_ctx->HasTargetScope()) - format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat(); - if (format == nullptr) - { - FormatEntity::Parse("${addr}: ", format_entry); - format = &format_entry; - } +bool Debugger::FormatDisassemblerAddress(const FormatEntity::Entry *format, + const SymbolContext *sc, + const SymbolContext *prev_sc, + const ExecutionContext *exe_ctx, + const Address *addr, Stream &s) { + FormatEntity::Entry format_entry; + + if (format == nullptr) { + if (exe_ctx != nullptr && exe_ctx->HasTargetScope()) + format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat(); + if (format == nullptr) { + FormatEntity::Parse("${addr}: ", format_entry); + format = &format_entry; } - bool function_changed = false; - bool initial_function = false; - if (prev_sc && (prev_sc->function || prev_sc->symbol)) - { - if (sc && (sc->function || sc->symbol)) - { - if (prev_sc->symbol && sc->symbol) - { - if (!sc->symbol->Compare (prev_sc->symbol->GetName(), prev_sc->symbol->GetType())) - { - function_changed = true; - } - } - else if (prev_sc->function && sc->function) - { - if (prev_sc->function->GetMangled() != sc->function->GetMangled()) - { - function_changed = true; - } - } + } + bool function_changed = false; + bool initial_function = false; + if (prev_sc && (prev_sc->function || prev_sc->symbol)) { + if (sc && (sc->function || sc->symbol)) { + if (prev_sc->symbol && sc->symbol) { + if (!sc->symbol->Compare(prev_sc->symbol->GetName(), + prev_sc->symbol->GetType())) { + function_changed = true; + } + } else if (prev_sc->function && sc->function) { + if (prev_sc->function->GetMangled() != sc->function->GetMangled()) { + function_changed = true; } + } } - // The first context on a list of instructions will have a prev_sc that - // 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 == nullptr && prev_sc->symbol == nullptr)) - { - initial_function = true; + } + // The first context on a list of instructions will have a prev_sc that + // 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 == nullptr && prev_sc->symbol == nullptr)) { + initial_function = true; + } + return FormatEntity::Format(*format, s, sc, exe_ctx, addr, nullptr, + function_changed, initial_function); +} + +void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback, + void *baton) { + // For simplicity's sake, I am not going to deal with how to close down any + // open logging streams, I just redirect everything from here on out to the + // callback. + m_log_callback_stream_sp.reset(new StreamCallback(log_callback, baton)); +} + +bool Debugger::EnableLog(const char *channel, const char **categories, + const char *log_file, uint32_t log_options, + Stream &error_stream) { + StreamSP log_stream_sp; + if (m_log_callback_stream_sp) { + log_stream_sp = m_log_callback_stream_sp; + // 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 == nullptr || *log_file == '\0') { + log_stream_sp = GetOutputFile(); + } else { + LogStreamMap::iterator pos = m_log_streams.find(log_file); + if (pos != m_log_streams.end()) + log_stream_sp = pos->second.lock(); + if (!log_stream_sp) { + uint32_t options = File::eOpenOptionWrite | File::eOpenOptionCanCreate | + File::eOpenOptionCloseOnExec | File::eOpenOptionAppend; + if (!(log_options & LLDB_LOG_OPTION_APPEND)) + options |= File::eOpenOptionTruncate; + + log_stream_sp.reset(new StreamFile(log_file, options)); + m_log_streams[log_file] = log_stream_sp; } - return FormatEntity::Format(*format, s, sc, exe_ctx, addr, nullptr, function_changed, initial_function); -} + } + assert(log_stream_sp); -void -Debugger::SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton) -{ - // For simplicity's sake, I am not going to deal with how to close down any - // open logging streams, I just redirect everything from here on out to the - // callback. - m_log_callback_stream_sp.reset (new StreamCallback (log_callback, baton)); -} + if (log_options == 0) + log_options = + LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE; -bool -Debugger::EnableLog (const char *channel, const char **categories, const char *log_file, uint32_t log_options, Stream &error_stream) -{ - StreamSP log_stream_sp; - if (m_log_callback_stream_sp) - { - log_stream_sp = m_log_callback_stream_sp; - // 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 == nullptr || *log_file == '\0') - { - log_stream_sp = GetOutputFile(); - } - else - { - LogStreamMap::iterator pos = m_log_streams.find(log_file); - if (pos != m_log_streams.end()) - log_stream_sp = pos->second.lock(); - if (!log_stream_sp) - { - uint32_t options = File::eOpenOptionWrite | File::eOpenOptionCanCreate - | File::eOpenOptionCloseOnExec | File::eOpenOptionAppend; - if (! (log_options & LLDB_LOG_OPTION_APPEND)) - options |= File::eOpenOptionTruncate; - - log_stream_sp.reset (new StreamFile (log_file, options)); - m_log_streams[log_file] = log_stream_sp; - } - } - assert(log_stream_sp); - - if (log_options == 0) - log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE; - - return Log::EnableLogChannel(log_stream_sp, log_options, channel, categories, error_stream); + return Log::EnableLogChannel(log_stream_sp, log_options, channel, categories, + error_stream); } -SourceManager & -Debugger::GetSourceManager () -{ - if (!m_source_manager_ap) - m_source_manager_ap.reset (new SourceManager (shared_from_this())); - return *m_source_manager_ap; +SourceManager &Debugger::GetSourceManager() { + 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) -{ - using namespace lldb; - const uint32_t event_type = Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent (event_sp); - -// if (event_type & eBreakpointEventTypeAdded -// || event_type & eBreakpointEventTypeRemoved -// || event_type & eBreakpointEventTypeEnabled -// || event_type & eBreakpointEventTypeDisabled -// || event_type & eBreakpointEventTypeCommandChanged -// || event_type & eBreakpointEventTypeConditionChanged -// || event_type & eBreakpointEventTypeIgnoreChanged -// || event_type & eBreakpointEventTypeLocationsResolved) -// { -// // Don't do anything about these events, since the breakpoint commands already echo these actions. -// } -// - if (event_type & eBreakpointEventTypeLocationsAdded) - { - uint32_t num_new_locations = Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent(event_sp); - if (num_new_locations > 0) - { - BreakpointSP breakpoint = Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp); - StreamSP output_sp (GetAsyncOutputStream()); - if (output_sp) - { - output_sp->Printf("%d location%s added to breakpoint %d\n", - num_new_locations, - num_new_locations == 1 ? "" : "s", - breakpoint->GetID()); - output_sp->Flush(); - } - } +void Debugger::HandleBreakpointEvent(const EventSP &event_sp) { + using namespace lldb; + const uint32_t event_type = + Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent( + event_sp); + + // if (event_type & eBreakpointEventTypeAdded + // || event_type & eBreakpointEventTypeRemoved + // || event_type & eBreakpointEventTypeEnabled + // || event_type & eBreakpointEventTypeDisabled + // || event_type & eBreakpointEventTypeCommandChanged + // || event_type & eBreakpointEventTypeConditionChanged + // || event_type & eBreakpointEventTypeIgnoreChanged + // || event_type & eBreakpointEventTypeLocationsResolved) + // { + // // Don't do anything about these events, since the breakpoint + // commands already echo these actions. + // } + // + if (event_type & eBreakpointEventTypeLocationsAdded) { + uint32_t num_new_locations = + Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent( + event_sp); + if (num_new_locations > 0) { + BreakpointSP breakpoint = + Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp); + StreamSP output_sp(GetAsyncOutputStream()); + if (output_sp) { + output_sp->Printf("%d location%s added to breakpoint %d\n", + num_new_locations, num_new_locations == 1 ? "" : "s", + breakpoint->GetID()); + output_sp->Flush(); + } } -// else if (event_type & eBreakpointEventTypeLocationsRemoved) -// { -// // These locations just get disabled, not sure it is worth spamming folks about this on the command line. -// } -// else if (event_type & eBreakpointEventTypeLocationsResolved) -// { -// // This might be an interesting thing to note, but I'm going to leave it quiet for now, it just looked noisy. -// } -} - -size_t -Debugger::GetProcessSTDOUT (Process *process, Stream *stream) -{ - size_t total_bytes = 0; - 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 == nullptr) - { - TargetSP target_sp = GetTargetList().GetSelectedTarget(); - if (target_sp) - process = target_sp->GetProcessSP().get(); - } - if (process) - { - Error error; - size_t len; - char stdio_buffer[1024]; - while ((len = process->GetSTDOUT (stdio_buffer, sizeof (stdio_buffer), error)) > 0) - { - stream->Write(stdio_buffer, len); - total_bytes += len; - } - } - stream->Flush(); + } + // else if (event_type & eBreakpointEventTypeLocationsRemoved) + // { + // // These locations just get disabled, not sure it is worth spamming + // folks about this on the command line. + // } + // else if (event_type & eBreakpointEventTypeLocationsResolved) + // { + // // This might be an interesting thing to note, but I'm going to + // leave it quiet for now, it just looked noisy. + // } +} + +size_t Debugger::GetProcessSTDOUT(Process *process, Stream *stream) { + size_t total_bytes = 0; + 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 == nullptr) { + TargetSP target_sp = GetTargetList().GetSelectedTarget(); + if (target_sp) + process = target_sp->GetProcessSP().get(); } - return total_bytes; -} - -size_t -Debugger::GetProcessSTDERR (Process *process, Stream *stream) -{ - size_t total_bytes = 0; - 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 == nullptr) - { - TargetSP target_sp = GetTargetList().GetSelectedTarget(); - if (target_sp) - process = target_sp->GetProcessSP().get(); - } - if (process) - { - Error error; - size_t len; - char stdio_buffer[1024]; - while ((len = process->GetSTDERR (stdio_buffer, sizeof (stdio_buffer), error)) > 0) - { - stream->Write(stdio_buffer, len); - total_bytes += len; - } - } - stream->Flush(); + if (process) { + Error error; + size_t len; + char stdio_buffer[1024]; + while ((len = process->GetSTDOUT(stdio_buffer, sizeof(stdio_buffer), + error)) > 0) { + stream->Write(stdio_buffer, len); + total_bytes += len; + } + } + stream->Flush(); + } + return total_bytes; +} + +size_t Debugger::GetProcessSTDERR(Process *process, Stream *stream) { + size_t total_bytes = 0; + 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 == nullptr) { + TargetSP target_sp = GetTargetList().GetSelectedTarget(); + if (target_sp) + process = target_sp->GetProcessSP().get(); } - return total_bytes; + if (process) { + Error error; + size_t len; + char stdio_buffer[1024]; + while ((len = process->GetSTDERR(stdio_buffer, sizeof(stdio_buffer), + error)) > 0) { + stream->Write(stdio_buffer, len); + total_bytes += len; + } + } + stream->Flush(); + } + return total_bytes; } - // This function handles events that were broadcast by the process. -void -Debugger::HandleProcessEvent (const EventSP &event_sp) -{ - using namespace lldb; - const uint32_t event_type = event_sp->GetType(); - ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get()); - - StreamSP output_stream_sp = GetAsyncOutputStream(); - StreamSP error_stream_sp = GetAsyncErrorStream(); - const bool gui_enabled = IsForwardingEvents(); - - if (!gui_enabled) - { - bool pop_process_io_handler = false; - assert (process_sp); - - bool state_is_stopped = false; - const bool got_state_changed = (event_type & Process::eBroadcastBitStateChanged) != 0; - const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0; - const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0; - if (got_state_changed) - { - StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get()); - state_is_stopped = StateIsStoppedState(event_state, false); - } - - // Display running state changes first before any STDIO - if (got_state_changed && !state_is_stopped) - { - Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler); - } - - // Now display and STDOUT - if (got_stdout || got_state_changed) - { - GetProcessSTDOUT (process_sp.get(), output_stream_sp.get()); - } - - // Now display and STDERR - if (got_stderr || got_state_changed) - { - GetProcessSTDERR (process_sp.get(), error_stream_sp.get()); - } +void Debugger::HandleProcessEvent(const EventSP &event_sp) { + using namespace lldb; + const uint32_t event_type = event_sp->GetType(); + ProcessSP process_sp = + (event_type == Process::eBroadcastBitStructuredData) + ? EventDataStructuredData::GetProcessFromEvent(event_sp.get()) + : Process::ProcessEventData::GetProcessFromEvent(event_sp.get()); + + StreamSP output_stream_sp = GetAsyncOutputStream(); + StreamSP error_stream_sp = GetAsyncErrorStream(); + const bool gui_enabled = IsForwardingEvents(); + + if (!gui_enabled) { + bool pop_process_io_handler = false; + assert(process_sp); + + bool state_is_stopped = false; + const bool got_state_changed = + (event_type & Process::eBroadcastBitStateChanged) != 0; + const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0; + const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0; + const bool got_structured_data = + (event_type & Process::eBroadcastBitStructuredData) != 0; + + if (got_state_changed) { + StateType event_state = + Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + state_is_stopped = StateIsStoppedState(event_state, false); + } - // Now display any stopped state changes after any STDIO - if (got_state_changed && state_is_stopped) - { - Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler); - } + // Display running state changes first before any STDIO + if (got_state_changed && !state_is_stopped) { + Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(), + pop_process_io_handler); + } - output_stream_sp->Flush(); - error_stream_sp->Flush(); + // Now display and STDOUT + if (got_stdout || got_state_changed) { + GetProcessSTDOUT(process_sp.get(), output_stream_sp.get()); + } - if (pop_process_io_handler) - process_sp->PopProcessIOHandler(); + // Now display and STDERR + if (got_stderr || got_state_changed) { + GetProcessSTDERR(process_sp.get(), error_stream_sp.get()); } -} -void -Debugger::HandleThreadEvent (const EventSP &event_sp) -{ - // At present the only thread event we handle is the Frame Changed event, - // and all we do for that is just reprint the thread status for that thread. - using namespace lldb; - const uint32_t event_type = event_sp->GetType(); - if (event_type == Thread::eBroadcastBitStackChanged || - event_type == Thread::eBroadcastBitThreadSelected ) - { - ThreadSP thread_sp (Thread::ThreadEventData::GetThreadFromEvent (event_sp.get())); - if (thread_sp) - { - thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1); + // Give structured data events an opportunity to display. + if (got_structured_data) { + StructuredDataPluginSP plugin_sp = + EventDataStructuredData::GetPluginFromEvent(event_sp.get()); + if (plugin_sp) { + auto structured_data_sp = + EventDataStructuredData::GetObjectFromEvent(event_sp.get()); + if (output_stream_sp) { + StreamString content_stream; + Error error = + plugin_sp->GetDescription(structured_data_sp, content_stream); + if (error.Success()) { + if (!content_stream.GetString().empty()) { + // Add newline. + content_stream.PutChar('\n'); + content_stream.Flush(); + + // Print it. + output_stream_sp->PutCString(content_stream.GetString()); + } + } else { + error_stream_sp->Printf("Failed to print structured " + "data with plugin %s: %s", + plugin_sp->GetPluginName().AsCString(), + error.AsCString()); + } } + } } -} - -bool -Debugger::IsForwardingEvents () -{ - return (bool)m_forward_listener_sp; -} - -void -Debugger::EnableForwardEvents (const ListenerSP &listener_sp) -{ - m_forward_listener_sp = listener_sp; -} - -void -Debugger::CancelForwardEvents (const ListenerSP &listener_sp) -{ - m_forward_listener_sp.reset(); -} + // Now display any stopped state changes after any STDIO + if (got_state_changed && state_is_stopped) { + Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(), + pop_process_io_handler); + } -void -Debugger::DefaultEventHandler() -{ - ListenerSP listener_sp(GetListener()); - ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass()); - ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass()); - ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass()); - BroadcastEventSpec target_event_spec (broadcaster_class_target, - Target::eBroadcastBitBreakpointChanged); - - BroadcastEventSpec process_event_spec (broadcaster_class_process, - Process::eBroadcastBitStateChanged | - Process::eBroadcastBitSTDOUT | - Process::eBroadcastBitSTDERR); - - BroadcastEventSpec thread_event_spec (broadcaster_class_thread, - Thread::eBroadcastBitStackChanged | - Thread::eBroadcastBitThreadSelected ); - - 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 ); - - // Let the thread that spawned us know that we have started up and - // that we are now listening to all required events so no events get missed - m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening); - - bool done = false; - while (!done) - { - EventSP event_sp; - if (listener_sp->WaitForEvent(nullptr, event_sp)) - { - if (event_sp) - { - Broadcaster *broadcaster = event_sp->GetBroadcaster(); - if (broadcaster) - { - uint32_t event_type = event_sp->GetType(); - ConstString broadcaster_class (broadcaster->GetBroadcasterClass()); - if (broadcaster_class == broadcaster_class_process) - { - HandleProcessEvent (event_sp); - } - else if (broadcaster_class == broadcaster_class_target) - { - if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(event_sp.get())) - { - HandleBreakpointEvent (event_sp); - } - } - else if (broadcaster_class == broadcaster_class_thread) - { - HandleThreadEvent (event_sp); - } - else if (broadcaster == m_command_interpreter_ap.get()) - { - if (event_type & CommandInterpreter::eBroadcastBitQuitCommandReceived) - { - done = true; - } - else if (event_type & CommandInterpreter::eBroadcastBitAsynchronousErrorData) - { - const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get())); - if (data && data[0]) - { - StreamSP error_sp (GetAsyncErrorStream()); - if (error_sp) - { - error_sp->PutCString(data); - error_sp->Flush(); - } - } - } - else if (event_type & CommandInterpreter::eBroadcastBitAsynchronousOutputData) - { - const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get())); - if (data && data[0]) - { - StreamSP output_sp (GetAsyncOutputStream()); - if (output_sp) - { - output_sp->PutCString(data); - output_sp->Flush(); - } - } - } - } + output_stream_sp->Flush(); + error_stream_sp->Flush(); + + if (pop_process_io_handler) + process_sp->PopProcessIOHandler(); + } +} + +void Debugger::HandleThreadEvent(const EventSP &event_sp) { + // At present the only thread event we handle is the Frame Changed event, + // and all we do for that is just reprint the thread status for that thread. + using namespace lldb; + const uint32_t event_type = event_sp->GetType(); + const bool stop_format = true; + if (event_type == Thread::eBroadcastBitStackChanged || + event_type == Thread::eBroadcastBitThreadSelected) { + ThreadSP thread_sp( + Thread::ThreadEventData::GetThreadFromEvent(event_sp.get())); + if (thread_sp) { + thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1, stop_format); + } + } +} + +bool Debugger::IsForwardingEvents() { return (bool)m_forward_listener_sp; } + +void Debugger::EnableForwardEvents(const ListenerSP &listener_sp) { + m_forward_listener_sp = listener_sp; +} + +void Debugger::CancelForwardEvents(const ListenerSP &listener_sp) { + m_forward_listener_sp.reset(); +} + +void Debugger::DefaultEventHandler() { + ListenerSP listener_sp(GetListener()); + ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass()); + ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass()); + ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass()); + BroadcastEventSpec target_event_spec(broadcaster_class_target, + Target::eBroadcastBitBreakpointChanged); + + BroadcastEventSpec process_event_spec( + broadcaster_class_process, + Process::eBroadcastBitStateChanged | Process::eBroadcastBitSTDOUT | + Process::eBroadcastBitSTDERR | Process::eBroadcastBitStructuredData); + + BroadcastEventSpec thread_event_spec(broadcaster_class_thread, + Thread::eBroadcastBitStackChanged | + Thread::eBroadcastBitThreadSelected); + + 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); + + // Let the thread that spawned us know that we have started up and + // that we are now listening to all required events so no events get missed + m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening); + + bool done = false; + while (!done) { + EventSP event_sp; + if (listener_sp->GetEvent(event_sp, llvm::None)) { + if (event_sp) { + Broadcaster *broadcaster = event_sp->GetBroadcaster(); + if (broadcaster) { + uint32_t event_type = event_sp->GetType(); + ConstString broadcaster_class(broadcaster->GetBroadcasterClass()); + if (broadcaster_class == broadcaster_class_process) { + HandleProcessEvent(event_sp); + } else if (broadcaster_class == broadcaster_class_target) { + if (Breakpoint::BreakpointEventData::GetEventDataFromEvent( + event_sp.get())) { + HandleBreakpointEvent(event_sp); + } + } else if (broadcaster_class == broadcaster_class_thread) { + HandleThreadEvent(event_sp); + } else if (broadcaster == m_command_interpreter_ap.get()) { + if (event_type & + CommandInterpreter::eBroadcastBitQuitCommandReceived) { + done = true; + } else if (event_type & + CommandInterpreter::eBroadcastBitAsynchronousErrorData) { + const char *data = reinterpret_cast<const char *>( + EventDataBytes::GetBytesFromEvent(event_sp.get())); + if (data && data[0]) { + StreamSP error_sp(GetAsyncErrorStream()); + if (error_sp) { + error_sp->PutCString(data); + error_sp->Flush(); + } + } + } else if (event_type & CommandInterpreter:: + eBroadcastBitAsynchronousOutputData) { + const char *data = reinterpret_cast<const char *>( + EventDataBytes::GetBytesFromEvent(event_sp.get())); + if (data && data[0]) { + StreamSP output_sp(GetAsyncOutputStream()); + if (output_sp) { + output_sp->PutCString(data); + output_sp->Flush(); } - - if (m_forward_listener_sp) - m_forward_listener_sp->AddEvent(event_sp); + } } + } } - } -} - -lldb::thread_result_t -Debugger::EventHandlerThread (lldb::thread_arg_t arg) -{ - ((Debugger *)arg)->DefaultEventHandler(); - return NULL; -} -bool -Debugger::StartEventHandlerThread() -{ - if (!m_event_handler_thread.IsJoinable()) - { - // We must synchronize with the DefaultEventHandler() thread to ensure - // 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 - 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, - this, - 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 (nullptr timeout as the first parameter) - lldb::EventSP event_sp; - listener_sp->WaitForEvent(nullptr, event_sp); + if (m_forward_listener_sp) + m_forward_listener_sp->AddEvent(event_sp); + } } - return m_event_handler_thread.IsJoinable(); + } +} + +lldb::thread_result_t Debugger::EventHandlerThread(lldb::thread_arg_t arg) { + ((Debugger *)arg)->DefaultEventHandler(); + return NULL; +} + +bool Debugger::StartEventHandlerThread() { + if (!m_event_handler_thread.IsJoinable()) { + // We must synchronize with the DefaultEventHandler() thread to ensure + // 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 + 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, this, 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 (nullptr timeout as the first + // parameter) + lldb::EventSP event_sp; + listener_sp->GetEvent(event_sp, llvm::None); + } + return m_event_handler_thread.IsJoinable(); +} + +void Debugger::StopEventHandlerThread() { + if (m_event_handler_thread.IsJoinable()) { + GetCommandInterpreter().BroadcastEvent( + CommandInterpreter::eBroadcastBitQuitCommandReceived); + m_event_handler_thread.Join(nullptr); + } +} + +lldb::thread_result_t Debugger::IOHandlerThread(lldb::thread_arg_t arg) { + Debugger *debugger = (Debugger *)arg; + debugger->ExecuteIOHandlers(); + debugger->StopEventHandlerThread(); + return NULL; +} + +bool Debugger::HasIOHandlerThread() { return m_io_handler_thread.IsJoinable(); } + +bool Debugger::StartIOHandlerThread() { + if (!m_io_handler_thread.IsJoinable()) + 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(); +} + +void Debugger::StopIOHandlerThread() { + if (m_io_handler_thread.IsJoinable()) { + if (m_input_file_sp) + m_input_file_sp->GetFile().Close(); + m_io_handler_thread.Join(nullptr); + } } -void -Debugger::StopEventHandlerThread() -{ - if (m_event_handler_thread.IsJoinable()) - { - GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived); - m_event_handler_thread.Join(nullptr); - } +void Debugger::JoinIOHandlerThread() { + if (HasIOHandlerThread()) { + thread_result_t result; + m_io_handler_thread.Join(&result); + m_io_handler_thread = LLDB_INVALID_HOST_THREAD; + } } -lldb::thread_result_t -Debugger::IOHandlerThread (lldb::thread_arg_t arg) -{ - Debugger *debugger = (Debugger *)arg; - debugger->ExecuteIOHandlers(); - debugger->StopEventHandlerThread(); - return NULL; +Target *Debugger::GetDummyTarget() { + return m_target_list.GetDummyTarget(*this).get(); } -bool -Debugger::HasIOHandlerThread() -{ - return m_io_handler_thread.IsJoinable(); -} +Target *Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) { + Target *target = nullptr; + if (!prefer_dummy) { + target = m_target_list.GetSelectedTarget().get(); + if (target) + return target; + } -bool -Debugger::StartIOHandlerThread() -{ - if (!m_io_handler_thread.IsJoinable()) - 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(); + return GetDummyTarget(); } -void -Debugger::StopIOHandlerThread() -{ - if (m_io_handler_thread.IsJoinable()) - { - if (m_input_file_sp) - m_input_file_sp->GetFile().Close(); - m_io_handler_thread.Join(nullptr); - } -} +Error Debugger::RunREPL(LanguageType language, const char *repl_options) { + Error err; + FileSpec repl_executable; -void -Debugger::JoinIOHandlerThread() -{ - if (HasIOHandlerThread()) - { - thread_result_t result; - m_io_handler_thread.Join(&result); - m_io_handler_thread = LLDB_INVALID_HOST_THREAD; - } -} + if (language == eLanguageTypeUnknown) { + std::set<LanguageType> repl_languages; -Target * -Debugger::GetDummyTarget() -{ - return m_target_list.GetDummyTarget (*this).get(); -} + Language::GetLanguagesSupportingREPLs(repl_languages); -Target * -Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) -{ - Target *target = nullptr; - if (!prefer_dummy) - { - target = m_target_list.GetSelectedTarget().get(); - if (target) - return target; + if (repl_languages.size() == 1) { + language = *repl_languages.begin(); + } else if (repl_languages.empty()) { + err.SetErrorStringWithFormat( + "LLDB isn't configured with REPL support for any languages."); + return err; + } else { + err.SetErrorStringWithFormat( + "Multiple possible REPL languages. Please specify a language."); + return err; } - - return GetDummyTarget(); -} + } -Error -Debugger::RunREPL (LanguageType language, const char *repl_options) -{ - Error err; - FileSpec repl_executable; - - if (language == eLanguageTypeUnknown) - { - std::set<LanguageType> repl_languages; - - Language::GetLanguagesSupportingREPLs(repl_languages); - - if (repl_languages.size() == 1) - { - language = *repl_languages.begin(); - } - else if (repl_languages.empty()) - { - err.SetErrorStringWithFormat("LLDB isn't configured with REPL support for any languages."); - return err; - } - else - { - err.SetErrorStringWithFormat("Multiple possible REPL languages. Please specify a language."); - return err; - } - } + Target *const target = + nullptr; // passing in an empty target means the REPL must create one - Target *const target = nullptr; // passing in an empty target means the REPL must create one - - REPLSP repl_sp(REPL::Create(err, language, this, target, repl_options)); + REPLSP repl_sp(REPL::Create(err, language, this, target, repl_options)); - if (!err.Success()) - { - return err; - } - - if (!repl_sp) - { - err.SetErrorStringWithFormat("couldn't find a REPL for %s", Language::GetNameForLanguageType(language)); - return err; - } - - repl_sp->SetCompilerOptions(repl_options); - repl_sp->RunLoop(); - + if (!err.Success()) { + return err; + } + + if (!repl_sp) { + err.SetErrorStringWithFormat("couldn't find a REPL for %s", + Language::GetNameForLanguageType(language)); return err; + } + + repl_sp->SetCompilerOptions(repl_options); + repl_sp->RunLoop(); + + return err; } |