diff options
Diffstat (limited to 'source/Core/Debugger.cpp')
-rw-r--r-- | source/Core/Debugger.cpp | 488 |
1 files changed, 172 insertions, 316 deletions
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp index 1a69fc582d0c3..18397d00dcaa6 100644 --- a/source/Core/Debugger.cpp +++ b/source/Core/Debugger.cpp @@ -93,22 +93,47 @@ static DebuggerList *g_debugger_list_ptr = nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain static constexpr 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."} }; + { + 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.", + }, +}; static constexpr 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."} }; + { + 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.", + }, +}; #define MODULE_WITH_FUNC \ "{ " \ @@ -189,133 +214,39 @@ static constexpr OptionEnumValueElement g_language_enumerators[] = { // without-args}}:\n}{${current-pc-arrow} }{${addr-file-or-load}}: static constexpr 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."}}; - -static constexpr PropertyDefinition g_properties[] = { - {"auto-confirm", OptionValue::eTypeBoolean, true, false, nullptr, {}, - "If true all confirmation prompts will receive their default reply."}, - {"disassembly-format", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_DISASSEMBLY_FORMAT, {}, - "The default disassembly format " - "string to use when disassembling " - "instruction sequences."}, - {"frame-format", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_FRAME_FORMAT, {}, - "The default frame format string to use " - "when displaying stack frame information " - "for threads."}, - {"notify-void", OptionValue::eTypeBoolean, true, false, nullptr, {}, - "Notify the user explicitly if an expression returns void (default: " - "false)."}, - {"prompt", OptionValue::eTypeString, true, - OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", {}, - "The debugger command line prompt displayed for the user."}, - {"script-lang", OptionValue::eTypeEnum, true, eScriptLanguagePython, - nullptr, OptionEnumValues(g_language_enumerators), - "The script language to be used for evaluating user-written scripts."}, - {"stop-disassembly-count", OptionValue::eTypeSInt64, true, 4, nullptr, {}, - "The number of disassembly lines to show when displaying a " - "stopped context."}, - {"stop-disassembly-display", OptionValue::eTypeEnum, true, - Debugger::eStopDisassemblyTypeNoDebugInfo, nullptr, - OptionEnumValues(g_show_disassembly_enum_values), - "Control when to display disassembly when displaying a stopped context."}, - {"stop-line-count-after", OptionValue::eTypeSInt64, true, 3, 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, {}, - "The number of sources lines to display that come before the " - "current source line when displaying a stopped context."}, - {"highlight-source", OptionValue::eTypeBoolean, true, true, nullptr, {}, - "If true, LLDB will highlight the displayed source code."}, - {"stop-show-column", OptionValue::eTypeEnum, false, - eStopShowColumnAnsiOrCaret, nullptr, OptionEnumValues(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::eTypeString, true, 0, - "${ansi.underline}", {}, - "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::eTypeString, true, 0, - "${ansi.normal}", {}, - "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, {}, - "The maximum number of columns to use for displaying text."}, - {"thread-format", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_THREAD_FORMAT, {}, - "The default thread format string to use " - "when displaying thread information."}, - {"thread-stop-format", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_THREAD_STOP_FORMAT, {}, - "The default thread format " - "string to use when displaying thread " - "information as part of the stop display."}, - {"use-external-editor", OptionValue::eTypeBoolean, true, false, nullptr, {}, - "Whether to use an external editor or not."}, - {"use-color", OptionValue::eTypeBoolean, true, true, nullptr, {}, - "Whether to use Ansi color codes or not."}, - {"auto-one-line-summaries", OptionValue::eTypeBoolean, true, true, nullptr, - {}, - "If true, LLDB will automatically display small structs in " - "one-liner format (default: true)."}, - {"auto-indent", OptionValue::eTypeBoolean, true, true, nullptr, {}, - "If true, LLDB will auto indent/outdent code. Currently only supported in " - "the REPL (default: true)."}, - {"print-decls", OptionValue::eTypeBoolean, true, true, 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, {}, - "The tab size to use when indenting code in multi-line input mode " - "(default: 4)."}, - {"escape-non-printables", OptionValue::eTypeBoolean, true, true, nullptr, - {}, - "If true, LLDB will automatically escape non-printable and " - "escape characters when formatting strings."}, - {"frame-format-unique", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_FRAME_FORMAT_NO_ARGS, {}, - "The default frame format string to use when displaying stack frame" - "information for threads from thread backtrace unique."}}; + { + 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.", + }, +}; + +#define LLDB_PROPERTIES_debugger +#include "CoreProperties.inc" enum { - ePropertyAutoConfirm = 0, - ePropertyDisassemblyFormat, - ePropertyFrameFormat, - ePropertyNotiftVoid, - ePropertyPrompt, - ePropertyScriptLanguage, - ePropertyStopDisassemblyCount, - ePropertyStopDisassemblyDisplay, - ePropertyStopLineCountAfter, - ePropertyStopLineCountBefore, - ePropertyHighlightSource, - ePropertyStopShowColumn, - ePropertyStopShowColumnAnsiPrefix, - ePropertyStopShowColumnAnsiSuffix, - ePropertyTerminalWidth, - ePropertyThreadFormat, - ePropertyThreadStopFormat, - ePropertyUseExternalEditor, - ePropertyUseColor, - ePropertyAutoOneLineSummaries, - ePropertyAutoIndent, - ePropertyPrintDecls, - ePropertyTabSize, - ePropertyEscapeNonPrintables, - ePropertyFrameFormatUnique, +#define LLDB_PROPERTIES_debugger +#include "CorePropertiesEnum.inc" }; LoadPluginCallbackType Debugger::g_load_plugin_callback = nullptr; @@ -324,8 +255,16 @@ Status 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"); + bool is_load_script = + (property_path == "target.load-script-from-symbol-file"); + // These properties might change how we visualize data. + bool invalidate_data_vis = (property_path == "escape-non-printables"); + invalidate_data_vis |= + (property_path == "target.max-zero-padding-in-float-format"); + if (invalidate_data_vis) { + DataVisualization::ForceUpdate(); + } + TargetSP target_sp; LoadScriptFromSymFile load_script_old_value; if (is_load_script && exe_ctx->GetTargetSP()) { @@ -336,18 +275,18 @@ Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx, Status 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) { + if (property_path == g_debugger_properties[ePropertyPrompt].name) { llvm::StringRef new_prompt = GetPrompt(); - std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes( + std::string str = lldb_private::ansi::FormatAnsiTerminalCodes( new_prompt, GetUseColor()); if (str.length()) new_prompt = str; GetCommandInterpreter().UpdatePrompt(new_prompt); - auto bytes = llvm::make_unique<EventDataBytes>(new_prompt); + auto bytes = std::make_unique<EventDataBytes>(new_prompt); auto prompt_change_event_sp = std::make_shared<Event>( CommandInterpreter::eBroadcastBitResetPrompt, bytes.release()); GetCommandInterpreter().BroadcastEvent(prompt_change_event_sp); - } else if (property_path == g_properties[ePropertyUseColor].name) { + } else if (property_path == g_debugger_properties[ePropertyUseColor].name) { // use-color changed. Ping the prompt so it can reset the ansi terminal // codes. SetPrompt(GetPrompt()); @@ -358,18 +297,14 @@ Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx, std::list<Status> 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()); + Stream &s = GetErrorStream(); + for (auto error : errors) { + s.Printf("%s\n", error.AsCString()); } + if (feedback_stream.GetSize()) + s.PutCString(feedback_stream.GetString()); } } - } else if (is_escape_non_printables) { - DataVisualization::ForceUpdate(); } } return error; @@ -378,7 +313,7 @@ Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx, bool Debugger::GetAutoConfirm() const { const uint32_t idx = ePropertyAutoConfirm; return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_properties[idx].default_uint_value != 0); + nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); } const FormatEntity::Entry *Debugger::GetDisassemblyFormat() const { @@ -399,13 +334,13 @@ const FormatEntity::Entry *Debugger::GetFrameFormatUnique() const { bool Debugger::GetNotifyVoid() const { const uint32_t idx = ePropertyNotiftVoid; return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_properties[idx].default_uint_value != 0); + nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); } llvm::StringRef Debugger::GetPrompt() const { const uint32_t idx = ePropertyPrompt; return m_collection_sp->GetPropertyAtIndexAsString( - nullptr, idx, g_properties[idx].default_cstr_value); + nullptr, idx, g_debugger_properties[idx].default_cstr_value); } void Debugger::SetPrompt(llvm::StringRef p) { @@ -413,7 +348,7 @@ void Debugger::SetPrompt(llvm::StringRef p) { m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p); llvm::StringRef new_prompt = GetPrompt(); std::string str = - lldb_utility::ansi::FormatAnsiTerminalCodes(new_prompt, GetUseColor()); + lldb_private::ansi::FormatAnsiTerminalCodes(new_prompt, GetUseColor()); if (str.length()) new_prompt = str; GetCommandInterpreter().UpdatePrompt(new_prompt); @@ -437,7 +372,7 @@ const FormatEntity::Entry *Debugger::GetThreadStopFormat() const { 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); + nullptr, idx, g_debugger_properties[idx].default_uint_value); } bool Debugger::SetScriptLanguage(lldb::ScriptLanguage script_lang) { @@ -449,7 +384,7 @@ bool Debugger::SetScriptLanguage(lldb::ScriptLanguage script_lang) { uint32_t Debugger::GetTerminalWidth() const { const uint32_t idx = ePropertyTerminalWidth; return m_collection_sp->GetPropertyAtIndexAsSInt64( - nullptr, idx, g_properties[idx].default_uint_value); + nullptr, idx, g_debugger_properties[idx].default_uint_value); } bool Debugger::SetTerminalWidth(uint32_t term_width) { @@ -460,7 +395,7 @@ bool Debugger::SetTerminalWidth(uint32_t term_width) { bool Debugger::GetUseExternalEditor() const { const uint32_t idx = ePropertyUseExternalEditor; return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_properties[idx].default_uint_value != 0); + nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); } bool Debugger::SetUseExternalEditor(bool b) { @@ -471,7 +406,7 @@ bool Debugger::SetUseExternalEditor(bool b) { bool Debugger::GetUseColor() const { const uint32_t idx = ePropertyUseColor; return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_properties[idx].default_uint_value != 0); + nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); } bool Debugger::SetUseColor(bool b) { @@ -484,13 +419,13 @@ bool Debugger::SetUseColor(bool b) { bool Debugger::GetHighlightSource() const { const uint32_t idx = ePropertyHighlightSource; return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_properties[idx].default_uint_value); + nullptr, idx, g_debugger_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); + nullptr, idx, g_debugger_properties[idx].default_uint_value); } llvm::StringRef Debugger::GetStopShowColumnAnsiPrefix() const { @@ -507,20 +442,20 @@ 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); + nullptr, idx, g_debugger_properties[idx].default_uint_value); } 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); + nullptr, idx, g_debugger_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); + nullptr, idx, g_debugger_properties[idx].default_uint_value); } bool Debugger::GetAutoOneLineSummaries() const { @@ -556,7 +491,7 @@ bool Debugger::SetPrintDecls(bool b) { uint32_t Debugger::GetTabSize() const { const uint32_t idx = ePropertyTabSize; return m_collection_sp->GetPropertyAtIndexAsUInt64( - nullptr, idx, g_properties[idx].default_uint_value); + nullptr, idx, g_debugger_properties[idx].default_uint_value); } bool Debugger::SetTabSize(uint32_t tab_size) { @@ -717,8 +652,7 @@ void Debugger::Destroy(DebuggerSP &debugger_sp) { } } -DebuggerSP -Debugger::FindDebuggerWithInstanceName(ConstString instance_name) { +DebuggerSP Debugger::FindDebuggerWithInstanceName(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); @@ -764,16 +698,16 @@ TargetSP Debugger::FindTargetWithProcess(Process *process) { Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) : UserID(g_unique_id++), Properties(std::make_shared<OptionValueProperties>()), - m_input_file_sp(std::make_shared<StreamFile>(stdin, false)), - m_output_file_sp(std::make_shared<StreamFile>(stdout, false)), - m_error_file_sp(std::make_shared<StreamFile>(stderr, false)), + m_input_file_sp(std::make_shared<NativeFile>(stdin, false)), + m_output_stream_sp(std::make_shared<StreamFile>(stdout, false)), + m_error_stream_sp(std::make_shared<StreamFile>(stderr, false)), m_input_recorder(nullptr), 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_up(), m_source_file_cache(), m_command_interpreter_up( - llvm::make_unique<CommandInterpreter>(*this, false)), + std::make_unique<CommandInterpreter>(*this, false)), m_script_interpreter_sp(), 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"), @@ -790,7 +724,10 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) assert(default_platform_sp); m_platform_list.Append(default_platform_sp, true); - m_collection_sp->Initialize(g_properties); + m_dummy_target_sp = m_target_list.GetDummyTarget(*this); + assert(m_dummy_target_sp.get() && "Couldn't construct dummy target?"); + + m_collection_sp->Initialize(g_debugger_properties); m_collection_sp->AppendProperty( ConstString("target"), ConstString("Settings specify to debugging targets."), true, @@ -818,7 +755,7 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) if (term && !strcmp(term, "dumb")) SetUseColor(false); // Turn off use-color if we don't write to a terminal with color support. - if (!m_output_file_sp->GetFile().GetIsTerminalWithColors()) + if (!GetOutputFile().GetIsTerminalWithColors()) SetUseColor(false); #if defined(_WIN32) && defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) @@ -859,8 +796,7 @@ void Debugger::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(); + GetInputFile().Close(); m_command_interpreter_up->Clear(); }); @@ -885,57 +821,29 @@ void Debugger::SetAsyncExecution(bool async_execution) { repro::DataRecorder *Debugger::GetInputRecorder() { return m_input_recorder; } -void Debugger::SetInputFileHandle(FILE *fh, bool tranfer_ownership, - repro::DataRecorder *recorder) { +void Debugger::SetInputFile(FileSP file_sp, repro::DataRecorder *recorder) { + assert(file_sp && file_sp->IsValid()); m_input_recorder = recorder; - if (m_input_file_sp) - m_input_file_sp->GetFile().SetStream(fh, tranfer_ownership); - else - m_input_file_sp = std::make_shared<StreamFile>(fh, tranfer_ownership); - - File &in_file = m_input_file_sp->GetFile(); - if (!in_file.IsValid()) - in_file.SetStream(stdin, true); - + m_input_file_sp = file_sp; // Save away the terminal state if that is relevant, so that we can restore // it in RestoreInputState. SaveInputTerminalState(); } -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 = std::make_shared<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. - if (ScriptInterpreter *script_interpreter = - GetScriptInterpreter(/*can_create=*/false)) - script_interpreter->ResetOutputFileHandle(fh); +void Debugger::SetOutputFile(FileSP file_sp) { + assert(file_sp && file_sp->IsValid()); + m_output_stream_sp = std::make_shared<StreamFile>(file_sp); } -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 = std::make_shared<StreamFile>(fh, tranfer_ownership); - - File &err_file = m_error_file_sp->GetFile(); - if (!err_file.IsValid()) - err_file.SetStream(stderr, false); +void Debugger::SetErrorFile(FileSP file_sp) { + assert(file_sp && file_sp->IsValid()); + m_error_stream_sp = std::make_shared<StreamFile>(file_sp); } 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); - } + int fd = GetInputFile().GetDescriptor(); + if (fd != File::kInvalidDescriptor) + m_terminal_state.Save(fd, true); } void Debugger::RestoreInputTerminalState() { m_terminal_state.Restore(); } @@ -1016,8 +924,9 @@ bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type 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); + lldb_private::StreamFile &stream = + is_stdout ? GetOutputStream() : GetErrorStream(); + m_input_reader_stack.PrintAsync(&stream, s, len); } ConstString Debugger::GetTopIOHandlerControlSequence(char ch) { @@ -1054,8 +963,7 @@ void Debugger::RunIOHandler(const IOHandlerSP &reader_sp) { } } -void Debugger::AdoptTopIOHandlerFilesIfInvalid(StreamFileSP &in, - StreamFileSP &out, +void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &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 @@ -1065,37 +973,34 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(StreamFileSP &in, 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 (!in || !in->IsValid()) { if (top_reader_sp) - in = top_reader_sp->GetInputStreamFile(); + in = top_reader_sp->GetInputFileSP(); else - in = GetInputFile(); - + in = GetInputFileSP(); // If there is nothing, use stdin if (!in) - in = std::make_shared<StreamFile>(stdin, false); + in = std::make_shared<NativeFile>(stdin, false); } // If no STDOUT has been set, then set it appropriately - if (!out) { + if (!out || !out->GetFile().IsValid()) { if (top_reader_sp) - out = top_reader_sp->GetOutputStreamFile(); + out = top_reader_sp->GetOutputStreamFileSP(); else - out = GetOutputFile(); - + out = GetOutputStreamSP(); // If there is nothing, use stdout if (!out) out = std::make_shared<StreamFile>(stdout, false); } // If no STDERR has been set, then set it appropriately - if (!err) { + if (!err || !err->GetFile().IsValid()) { if (top_reader_sp) - err = top_reader_sp->GetErrorStreamFile(); + err = top_reader_sp->GetErrorStreamFileSP(); else - err = GetErrorFile(); - + err = GetErrorStreamSP(); // If there is nothing, use stderr if (!err) - err = std::make_shared<StreamFile>(stdout, false); + err = std::make_shared<StreamFile>(stderr, false); } } @@ -1263,15 +1168,15 @@ bool Debugger::EnableLog(llvm::StringRef channel, LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME; } else if (log_file.empty()) { log_stream_sp = std::make_shared<llvm::raw_fd_ostream>( - GetOutputFile()->GetFile().GetDescriptor(), !should_close, unbuffered); + GetOutputFile().GetDescriptor(), !should_close, unbuffered); } else { auto pos = m_log_streams.find(log_file); if (pos != m_log_streams.end()) log_stream_sp = pos->second.lock(); if (!log_stream_sp) { - llvm::sys::fs::OpenFlags flags = llvm::sys::fs::F_Text; + llvm::sys::fs::OpenFlags flags = llvm::sys::fs::OF_Text; if (log_options & LLDB_LOG_OPTION_APPEND) - flags |= llvm::sys::fs::F_Append; + flags |= llvm::sys::fs::OF_Append; int FD; if (std::error_code ec = llvm::sys::fs::openFileForWrite( log_file, FD, llvm::sys::fs::CD_CreateAlways, flags)) { @@ -1308,7 +1213,7 @@ ScriptInterpreter *Debugger::GetScriptInterpreter(bool can_create) { SourceManager &Debugger::GetSourceManager() { if (!m_source_manager_up) - m_source_manager_up = llvm::make_unique<SourceManager>(shared_from_this()); + m_source_manager_up = std::make_unique<SourceManager>(shared_from_this()); return *m_source_manager_up; } @@ -1360,60 +1265,23 @@ void Debugger::HandleBreakpointEvent(const EventSP &event_sp) { // } } -size_t Debugger::GetProcessSTDOUT(Process *process, Stream *stream) { - size_t total_bytes = 0; - if (stream == nullptr) - stream = GetOutputFile().get(); +void Debugger::FlushProcessOutput(Process &process, bool flush_stdout, + bool flush_stderr) { + const auto &flush = [&](Stream &stream, + size_t (Process::*get)(char *, size_t, Status &)) { + Status error; + size_t len; + char buffer[1024]; + while ((len = (process.*get)(buffer, sizeof(buffer), error)) > 0) + stream.Write(buffer, len); + stream.Flush(); + }; - 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) { - Status 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(); - } - if (process) { - Status 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; + std::lock_guard<std::mutex> guard(m_output_flush_mutex); + if (flush_stdout) + flush(*GetAsyncOutputStream(), &Process::GetSTDOUT); + if (flush_stderr) + flush(*GetAsyncErrorStream(), &Process::GetSTDERR); } // This function handles events that were broadcast by the process. @@ -1453,15 +1321,9 @@ void Debugger::HandleProcessEvent(const EventSP &event_sp) { 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()); - } + // Now display STDOUT and STDERR + FlushProcessOutput(*process_sp, got_stdout || got_state_changed, + got_stderr || got_state_changed); // Give structured data events an opportunity to display. if (got_structured_data) { @@ -1638,8 +1500,9 @@ bool Debugger::StartEventHandlerThread() { eBroadcastBitEventThreadIsListening); auto thread_name = - full_name.GetLength() < llvm::get_max_thread_name_length() ? - full_name.AsCString() : "dbg.evt-handler"; + full_name.GetLength() < llvm::get_max_thread_name_length() + ? full_name.AsCString() + : "dbg.evt-handler"; // Use larger 8MB stack for this thread llvm::Expected<HostThread> event_handler_thread = @@ -1700,8 +1563,7 @@ bool Debugger::StartIOHandlerThread() { void Debugger::StopIOHandlerThread() { if (m_io_handler_thread.IsJoinable()) { - if (m_input_file_sp) - m_input_file_sp->GetFile().Close(); + GetInputFile().Close(); m_io_handler_thread.Join(nullptr); } } @@ -1714,10 +1576,6 @@ void Debugger::JoinIOHandlerThread() { } } -Target *Debugger::GetDummyTarget() { - return m_target_list.GetDummyTarget(*this).get(); -} - Target *Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) { Target *target = nullptr; if (!prefer_dummy) { @@ -1734,13 +1592,11 @@ Status Debugger::RunREPL(LanguageType language, const char *repl_options) { FileSpec repl_executable; if (language == eLanguageTypeUnknown) { - std::set<LanguageType> repl_languages; - - Language::GetLanguagesSupportingREPLs(repl_languages); + LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs(); - if (repl_languages.size() == 1) { - language = *repl_languages.begin(); - } else if (repl_languages.empty()) { + if (auto single_lang = repl_languages.GetSingularLanguage()) { + language = *single_lang; + } else if (repl_languages.Empty()) { err.SetErrorStringWithFormat( "LLDB isn't configured with REPL support for any languages."); return err; |