diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index 899c0700e10fd..c64fc9161e76e 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -132,20 +132,15 @@ class Debugger : public std::enable_shared_from_this, void SetAsyncExecution(bool async); lldb::FileSP GetInputFileSP() { return m_input_file_sp; } - - lldb::StreamFileSP GetOutputStreamSP() { return m_output_stream_sp; } - - lldb::StreamFileSP GetErrorStreamSP() { return m_error_stream_sp; } - File &GetInputFile() { return *m_input_file_sp; } - File &GetOutputFile() { return m_output_stream_sp->GetFile(); } - - File &GetErrorFile() { return m_error_stream_sp->GetFile(); } - - StreamFile &GetOutputStream() { return *m_output_stream_sp; } + lldb::FileSP GetOutputFileSP() { + return m_output_stream_sp->GetUnlockedFileSP(); + } - StreamFile &GetErrorStream() { return *m_error_stream_sp; } + lldb::FileSP GetErrorFileSP() { + return m_error_stream_sp->GetUnlockedFileSP(); + } repro::DataRecorder *GetInputRecorder(); @@ -161,9 +156,9 @@ class Debugger : public std::enable_shared_from_this, void RestoreInputTerminalState(); - lldb::StreamSP GetAsyncOutputStream(); + lldb::StreamUP GetAsyncOutputStream(); - lldb::StreamSP GetAsyncErrorStream(); + lldb::StreamUP GetAsyncErrorStream(); CommandInterpreter &GetCommandInterpreter() { assert(m_command_interpreter_up.get()); @@ -206,8 +201,8 @@ class Debugger : public std::enable_shared_from_this, // If any of the streams are not set, set them to the in/out/err stream of // the top most input reader to ensure they at least have something void AdoptTopIOHandlerFilesIfInvalid(lldb::FileSP &in, - lldb::StreamFileSP &out, - lldb::StreamFileSP &err); + lldb::LockableStreamFileSP &out, + lldb::LockableStreamFileSP &err); /// Run the given IO handler and return immediately. void RunIOHandlerAsync(const lldb::IOHandlerSP &reader_sp, @@ -662,6 +657,14 @@ class Debugger : public std::enable_shared_from_this, void PrintProgress(const ProgressEventData &data); + /// Except for Debugger and IOHandler, GetOutputStreamSP and GetErrorStreamSP + /// should not be used directly. Use GetAsyncOutputStream and + /// GetAsyncErrorStream instead. + /// @{ + lldb::LockableStreamFileSP GetOutputStreamSP() { return m_output_stream_sp; } + lldb::LockableStreamFileSP GetErrorStreamSP() { return m_error_stream_sp; } + /// @} + void PushIOHandler(const lldb::IOHandlerSP &reader_sp, bool cancel_top_handler = true); @@ -702,8 +705,9 @@ class Debugger : public std::enable_shared_from_this, // these should never be NULL lldb::FileSP m_input_file_sp; - lldb::StreamFileSP m_output_stream_sp; - lldb::StreamFileSP m_error_stream_sp; + lldb::LockableStreamFileSP m_output_stream_sp; + lldb::LockableStreamFileSP m_error_stream_sp; + LockableStreamFile::Mutex m_output_mutex; /// Used for shadowing the input file when capturing a reproducer. repro::DataRecorder *m_input_recorder; diff --git a/lldb/include/lldb/Core/IOHandler.h b/lldb/include/lldb/Core/IOHandler.h index fef6c34903263..127d73ae73d66 100644 --- a/lldb/include/lldb/Core/IOHandler.h +++ b/lldb/include/lldb/Core/IOHandler.h @@ -32,11 +32,6 @@ namespace lldb_private { class Debugger; } // namespace lldb_private -namespace curses { -class Application; -typedef std::unique_ptr ApplicationAP; -} // namespace curses - namespace lldb_private { class IOHandler { @@ -58,8 +53,9 @@ class IOHandler { IOHandler(Debugger &debugger, IOHandler::Type type); IOHandler(Debugger &debugger, IOHandler::Type type, - const lldb::FileSP &input_sp, const lldb::StreamFileSP &output_sp, - const lldb::StreamFileSP &error_sp, uint32_t flags); + const lldb::FileSP &input_sp, + const lldb::LockableStreamFileSP &output_sp, + const lldb::LockableStreamFileSP &error_sp, uint32_t flags); virtual ~IOHandler(); @@ -117,17 +113,11 @@ class IOHandler { int GetErrorFD(); - FILE *GetInputFILE(); - - FILE *GetOutputFILE(); - - FILE *GetErrorFILE(); - lldb::FileSP GetInputFileSP(); - lldb::StreamFileSP GetOutputStreamFileSP(); + lldb::LockableStreamFileSP GetOutputStreamFileSP(); - lldb::StreamFileSP GetErrorStreamFileSP(); + lldb::LockableStreamFileSP GetErrorStreamFileSP(); Debugger &GetDebugger() { return m_debugger; } @@ -160,14 +150,11 @@ class IOHandler { virtual void PrintAsync(const char *s, size_t len, bool is_stdout); - std::recursive_mutex &GetOutputMutex() { return m_output_mutex; } - protected: Debugger &m_debugger; lldb::FileSP m_input_sp; - lldb::StreamFileSP m_output_sp; - lldb::StreamFileSP m_error_sp; - std::recursive_mutex m_output_mutex; + lldb::LockableStreamFileSP m_output_sp; + lldb::LockableStreamFileSP m_error_sp; Predicate m_popped; Flags m_flags; Type m_type; @@ -335,8 +322,8 @@ class IOHandlerEditline : public IOHandler { IOHandlerEditline(Debugger &debugger, IOHandler::Type type, const lldb::FileSP &input_sp, - const lldb::StreamFileSP &output_sp, - const lldb::StreamFileSP &error_sp, uint32_t flags, + const lldb::LockableStreamFileSP &output_sp, + const lldb::LockableStreamFileSP &error_sp, uint32_t flags, const char *editline_name, // Used for saving history files llvm::StringRef prompt, llvm::StringRef continuation_prompt, bool multi_line, bool color, @@ -350,9 +337,10 @@ class IOHandlerEditline : public IOHandler { IOHandlerDelegate &) = delete; IOHandlerEditline(Debugger &, IOHandler::Type, const lldb::FileSP &, - const lldb::StreamFileSP &, const lldb::StreamFileSP &, - uint32_t, const char *, const char *, const char *, bool, - bool, uint32_t, IOHandlerDelegate &) = delete; + const lldb::LockableStreamFileSP &, + const lldb::LockableStreamFileSP &, uint32_t, const char *, + const char *, const char *, bool, bool, uint32_t, + IOHandlerDelegate &) = delete; ~IOHandlerEditline() override; diff --git a/lldb/include/lldb/Core/IOHandlerCursesGUI.h b/lldb/include/lldb/Core/IOHandlerCursesGUI.h index 22ca735063ba1..e9871e0532194 100644 --- a/lldb/include/lldb/Core/IOHandlerCursesGUI.h +++ b/lldb/include/lldb/Core/IOHandlerCursesGUI.h @@ -12,6 +12,9 @@ #include "lldb/Core/IOHandler.h" namespace lldb_private { +namespace curses { +class Application; +} // namespace curses class IOHandlerCursesGUI : public IOHandler { public: @@ -34,7 +37,7 @@ class IOHandlerCursesGUI : public IOHandler { void TerminalSizeChanged() override; protected: - curses::ApplicationAP m_app_ap; + std::unique_ptr m_app_up; }; } // namespace lldb_private diff --git a/lldb/include/lldb/Core/StreamAsynchronousIO.h b/lldb/include/lldb/Core/StreamAsynchronousIO.h index b7adbc42096ce..7ae65757e2d73 100644 --- a/lldb/include/lldb/Core/StreamAsynchronousIO.h +++ b/lldb/include/lldb/Core/StreamAsynchronousIO.h @@ -18,9 +18,17 @@ namespace lldb_private { class Debugger; +/// A stream meant for asynchronously printing output. Output is buffered until +/// the stream is flushed or destroyed. Printing is handled by the currently +/// active IOHandler, or the debugger's output or error stream if there is none. class StreamAsynchronousIO : public Stream { public: - StreamAsynchronousIO(Debugger &debugger, bool for_stdout, bool colors); + enum ForSTDOUT : bool { + STDOUT = true, + STDERR = false, + }; + + StreamAsynchronousIO(Debugger &debugger, ForSTDOUT for_stdout); ~StreamAsynchronousIO() override; @@ -32,7 +40,7 @@ class StreamAsynchronousIO : public Stream { private: Debugger &m_debugger; std::string m_data; - bool m_for_stdout; + ForSTDOUT m_for_stdout; }; } // namespace lldb_private diff --git a/lldb/include/lldb/Host/Editline.h b/lldb/include/lldb/Host/Editline.h index 26deba38f8471..8964d37be8823 100644 --- a/lldb/include/lldb/Host/Editline.h +++ b/lldb/include/lldb/Host/Editline.h @@ -34,6 +34,7 @@ #include #include +#include "lldb/Host/StreamFile.h" #include "lldb/lldb-private.h" #if !defined(_WIN32) && !defined(__ANDROID__) @@ -151,8 +152,9 @@ using namespace line_editor; /// facility. Both single- and multi-line editing are supported. class Editline { public: - Editline(const char *editor_name, FILE *input_file, FILE *output_file, - FILE *error_file, std::recursive_mutex &output_mutex); + Editline(const char *editor_name, FILE *input_file, + lldb::LockableStreamFileSP output_stream_sp, + lldb::LockableStreamFileSP error_stream_sp, bool color); ~Editline(); @@ -212,19 +214,23 @@ class Editline { } void SetPromptAnsiPrefix(std::string prefix) { - m_prompt_ansi_prefix = std::move(prefix); + if (m_color) + m_prompt_ansi_prefix = std::move(prefix); } void SetPromptAnsiSuffix(std::string suffix) { - m_prompt_ansi_suffix = std::move(suffix); + if (m_color) + m_prompt_ansi_suffix = std::move(suffix); } void SetSuggestionAnsiPrefix(std::string prefix) { - m_suggestion_ansi_prefix = std::move(prefix); + if (m_color) + m_suggestion_ansi_prefix = std::move(prefix); } void SetSuggestionAnsiSuffix(std::string suffix) { - m_suggestion_ansi_suffix = std::move(suffix); + if (m_color) + m_suggestion_ansi_suffix = std::move(suffix); } /// Prompts for and reads a single line of user input. @@ -233,7 +239,8 @@ class Editline { /// Prompts for and reads a multi-line batch of user input. bool GetLines(int first_line_number, StringList &lines, bool &interrupted); - void PrintAsync(Stream *stream, const char *s, size_t len); + void PrintAsync(lldb::LockableStreamFileSP stream_sp, const char *s, + size_t len); /// Convert the current input lines into a UTF8 StringList StringList GetInputAsStringList(int line_count = UINT32_MAX); @@ -388,8 +395,11 @@ class Editline { volatile std::sig_atomic_t m_terminal_size_has_changed = 0; std::string m_editor_name; FILE *m_input_file; - FILE *m_output_file; - FILE *m_error_file; + lldb::LockableStreamFileSP m_output_stream_sp; + lldb::LockableStreamFileSP m_error_stream_sp; + + std::optional m_locked_output; + ConnectionFileDescriptor m_input_connection; IsInputCompleteCallbackType m_is_input_complete_callback; @@ -400,13 +410,13 @@ class Editline { CompleteCallbackType m_completion_callback; SuggestionCallbackType m_suggestion_callback; + bool m_color; std::string m_prompt_ansi_prefix; std::string m_prompt_ansi_suffix; std::string m_suggestion_ansi_prefix; std::string m_suggestion_ansi_suffix; std::size_t m_previous_autosuggestion_size = 0; - std::recursive_mutex &m_output_mutex; }; } diff --git a/lldb/include/lldb/Host/File.h b/lldb/include/lldb/Host/File.h index 5ce53c93b1b91..9e2d0abe0b1af 100644 --- a/lldb/include/lldb/Host/File.h +++ b/lldb/include/lldb/Host/File.h @@ -377,6 +377,11 @@ class File : public IOObject { class NativeFile : public File { public: + enum TransferOwnership : bool { + Owned = true, + Unowned = false, + }; + NativeFile() : m_descriptor(kInvalidDescriptor), m_stream(kInvalidStream) {} NativeFile(FILE *fh, bool transfer_ownership) diff --git a/lldb/include/lldb/Host/StreamFile.h b/lldb/include/lldb/Host/StreamFile.h index 2c96e13565a00..e37661a9938c0 100644 --- a/lldb/include/lldb/Host/StreamFile.h +++ b/lldb/include/lldb/Host/StreamFile.h @@ -13,9 +13,12 @@ #include "lldb/Utility/Stream.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" #include #include +#include +#include namespace lldb_private { @@ -52,6 +55,55 @@ class StreamFile : public Stream { const StreamFile &operator=(const StreamFile &) = delete; }; +class LockableStreamFile; +class LockedStreamFile : public StreamFile { +public: + ~LockedStreamFile() { Flush(); } + + LockedStreamFile(LockedStreamFile &&other) + : StreamFile(other.m_file_sp), m_lock(std::move(other.m_lock)) {} + +private: + LockedStreamFile(std::shared_ptr file, std::recursive_mutex &mutex) + : StreamFile(file), m_lock(mutex) {} + + friend class LockableStreamFile; + + std::unique_lock m_lock; +}; + +class LockableStreamFile { +public: + using Mutex = std::recursive_mutex; + + LockableStreamFile(std::shared_ptr stream_file_sp, Mutex &mutex) + : m_file_sp(stream_file_sp->GetFileSP()), m_mutex(mutex) {} + LockableStreamFile(StreamFile &stream_file, Mutex &mutex) + : m_file_sp(stream_file.GetFileSP()), m_mutex(mutex) {} + LockableStreamFile(FILE *fh, bool transfer_ownership, Mutex &mutex) + : m_file_sp(std::make_shared(fh, transfer_ownership)), + m_mutex(mutex) {} + LockableStreamFile(std::shared_ptr file_sp, Mutex &mutex) + : m_file_sp(file_sp), m_mutex(mutex) {} + + LockedStreamFile Lock() { return LockedStreamFile(m_file_sp, m_mutex); } + + /// Unsafe accessors to get the underlying File without a lock. Exists for + /// legacy reasons. + /// @{ + File &GetUnlockedFile() { return *m_file_sp; } + std::shared_ptr GetUnlockedFileSP() { return m_file_sp; } + /// @} + +protected: + std::shared_ptr m_file_sp; + Mutex &m_mutex; + +private: + LockableStreamFile(const LockableStreamFile &) = delete; + const LockableStreamFile &operator=(const LockableStreamFile &) = delete; +}; + } // namespace lldb_private #endif // LLDB_HOST_STREAMFILE_H diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index 7561585d9886a..c6e01475621c0 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -115,8 +115,12 @@ class ScriptInterpreterIORedirect { ~ScriptInterpreterIORedirect(); lldb::FileSP GetInputFile() const { return m_input_file_sp; } - lldb::FileSP GetOutputFile() const { return m_output_file_sp->GetFileSP(); } - lldb::FileSP GetErrorFile() const { return m_error_file_sp->GetFileSP(); } + lldb::FileSP GetOutputFile() const { + return m_output_file_sp->GetUnlockedFileSP(); + } + lldb::FileSP GetErrorFile() const { + return m_error_file_sp->GetUnlockedFileSP(); + } /// Flush our output and error file handles. void Flush(); @@ -127,8 +131,9 @@ class ScriptInterpreterIORedirect { ScriptInterpreterIORedirect(Debugger &debugger, CommandReturnObject *result); lldb::FileSP m_input_file_sp; - lldb::StreamFileSP m_output_file_sp; - lldb::StreamFileSP m_error_file_sp; + lldb::LockableStreamFileSP m_output_file_sp; + lldb::LockableStreamFileSP m_error_file_sp; + LockableStreamFile::Mutex m_output_mutex; ThreadedCommunication m_communication; bool m_disconnect; }; @@ -495,7 +500,7 @@ class ScriptInterpreter : public PluginInterface { dest.clear(); return false; } - + virtual StructuredData::ObjectSP GetOptionsForCommandObject(StructuredData::GenericSP cmd_obj_sp) { return {}; @@ -505,9 +510,9 @@ class ScriptInterpreter : public PluginInterface { GetArgumentsForCommandObject(StructuredData::GenericSP cmd_obj_sp) { return {}; } - + virtual bool SetOptionValueForCommandObject( - StructuredData::GenericSP cmd_obj_sp, ExecutionContext *exe_ctx, + StructuredData::GenericSP cmd_obj_sp, ExecutionContext *exe_ctx, llvm::StringRef long_option, llvm::StringRef value) { return false; } diff --git a/lldb/include/lldb/Target/ThreadPlanTracer.h b/lldb/include/lldb/Target/ThreadPlanTracer.h index a6fd2f031dc22..7c45e213f94f1 100644 --- a/lldb/include/lldb/Target/ThreadPlanTracer.h +++ b/lldb/include/lldb/Target/ThreadPlanTracer.h @@ -56,7 +56,7 @@ class ThreadPlanTracer { Process &m_process; lldb::tid_t m_tid; - Stream *GetLogStream(); + lldb::StreamSP GetLogStreamSP(); virtual void Log(); diff --git a/lldb/include/lldb/Utility/AnsiTerminal.h b/lldb/include/lldb/Utility/AnsiTerminal.h index 67795971d2ca8..1939c49c7b859 100644 --- a/lldb/include/lldb/Utility/AnsiTerminal.h +++ b/lldb/include/lldb/Utility/AnsiTerminal.h @@ -171,7 +171,32 @@ inline std::string FormatAnsiTerminalCodes(llvm::StringRef format, } return fmt; } + +inline std::string StripAnsiTerminalCodes(llvm::StringRef str) { + std::string stripped; + while (!str.empty()) { + llvm::StringRef left, right; + + std::tie(left, right) = str.split(ANSI_ESC_START); + stripped += left; + + // ANSI_ESC_START not found. + if (left == str && right.empty()) + break; + + size_t end = right.find_first_not_of("0123456789;"); + if (end < right.size() && (right[end] == 'm' || right[end] == 'G')) { + str = right.substr(end + 1); + } else { + // ANSI_ESC_END not found. + stripped += ANSI_ESC_START; + str = right; + } + } + return stripped; } + +} // namespace ansi } // namespace lldb_private #endif diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index b37eea80aa60f..a3550f3fe60ff 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -213,6 +213,7 @@ class StoppointCallbackContext; class Stream; class StreamFile; class StreamString; +class LockableStreamFile; class StringList; class StringTableReader; class StructuredDataImpl; @@ -427,7 +428,9 @@ typedef std::unique_ptr StackFrameRecognizerManagerUP; typedef std::shared_ptr StopInfoSP; typedef std::shared_ptr StreamSP; +typedef std::unique_ptr StreamUP; typedef std::shared_ptr StreamFileSP; +typedef std::shared_ptr LockableStreamFileSP; typedef std::shared_ptr StringTypeSummaryImplSP; typedef std::unique_ptr StructuredDataImplUP; diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp index cc9947cbd7256..8ca8b0f0bb361 100644 --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -507,39 +507,31 @@ SBFile SBDebugger::GetInputFile() { FILE *SBDebugger::GetOutputFileHandle() { LLDB_INSTRUMENT_VA(this); - if (m_opaque_sp) { - StreamFile &stream_file = m_opaque_sp->GetOutputStream(); - return stream_file.GetFile().GetStream(); - } + if (m_opaque_sp) + return m_opaque_sp->GetOutputFileSP()->GetStream(); return nullptr; } SBFile SBDebugger::GetOutputFile() { LLDB_INSTRUMENT_VA(this); - if (m_opaque_sp) { - SBFile file(m_opaque_sp->GetOutputStream().GetFileSP()); - return file; - } + if (m_opaque_sp) + return SBFile(m_opaque_sp->GetOutputFileSP()); return SBFile(); } FILE *SBDebugger::GetErrorFileHandle() { LLDB_INSTRUMENT_VA(this); - if (m_opaque_sp) { - StreamFile &stream_file = m_opaque_sp->GetErrorStream(); - return stream_file.GetFile().GetStream(); - } + if (m_opaque_sp) + return m_opaque_sp->GetErrorFileSP()->GetStream(); return nullptr; } SBFile SBDebugger::GetErrorFile() { LLDB_INSTRUMENT_VA(this); SBFile file; - if (m_opaque_sp) { - SBFile file(m_opaque_sp->GetErrorStream().GetFileSP()); - return file; - } + if (m_opaque_sp) + return SBFile(m_opaque_sp->GetErrorFileSP()); return SBFile(); } @@ -580,8 +572,8 @@ void SBDebugger::HandleCommand(const char *command) { sb_interpreter.HandleCommand(command, result, false); - result.PutError(m_opaque_sp->GetErrorStream().GetFileSP()); - result.PutOutput(m_opaque_sp->GetOutputStream().GetFileSP()); + result.PutError(m_opaque_sp->GetErrorFileSP()); + result.PutOutput(m_opaque_sp->GetOutputFileSP()); if (!m_opaque_sp->GetAsyncExecution()) { SBProcess process(GetCommandInterpreter().GetProcess()); diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp index 09abcf5e081d2..242b5b30168c5 100644 --- a/lldb/source/Breakpoint/BreakpointOptions.cpp +++ b/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -620,10 +620,8 @@ bool BreakpointOptions::BreakpointOptionsCallbackFunction( // Rig up the results secondary output stream to the debugger's, so the // output will come out synchronously if the debugger is set up that way. - StreamSP output_stream(debugger.GetAsyncOutputStream()); - StreamSP error_stream(debugger.GetAsyncErrorStream()); - result.SetImmediateOutputStream(output_stream); - result.SetImmediateErrorStream(error_stream); + result.SetImmediateOutputStream(debugger.GetAsyncOutputStream()); + result.SetImmediateErrorStream(debugger.GetAsyncErrorStream()); CommandInterpreterRunOptions options; options.SetStopOnContinue(true); diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index 1f82ad8582685..93303ac5e5db4 100644 --- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -193,10 +193,12 @@ are no syntax errors may indicate that a function was declared but never called. Options *GetOptions() override { return &m_all_options; } void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString(g_reader_instructions); - output_sp->Flush(); + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString(g_reader_instructions); + } } } diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp index f069b2feb5cb7..9510cf4d14467 100644 --- a/lldb/source/Commands/CommandObjectCommands.cpp +++ b/lldb/source/Commands/CommandObjectCommands.cpp @@ -11,6 +11,7 @@ #include "CommandObjectRegexCommand.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/IOHandler.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandHistory.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandOptionArgumentTable.h" @@ -792,12 +793,15 @@ a number follows 'f':" protected: void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString("Enter one or more sed substitution commands in " - "the form: 's///'.\nTerminate the " - "substitution list with an empty line.\n"); - output_sp->Flush(); + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString( + "Enter one or more sed substitution commands in " + "the form: 's///'.\nTerminate the " + "substitution list with an empty line.\n"); + } } } @@ -811,10 +815,9 @@ a number follows 'f':" for (const std::string &line : lines) { Status error = AppendRegexSubstitution(line, check_only); if (error.Fail()) { - if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) { - StreamSP out_stream = GetDebugger().GetAsyncOutputStream(); - out_stream->Printf("error: %s\n", error.AsCString()); - } + if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) + GetDebugger().GetAsyncOutputStream()->Printf("error: %s\n", + error.AsCString()); } } } @@ -2377,16 +2380,18 @@ class CommandObjectCommandsScriptAdd : public CommandObjectParsed, }; void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString(g_python_command_instructions); - output_sp->Flush(); + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString(g_python_command_instructions); + } } } void IOHandlerInputComplete(IOHandler &io_handler, std::string &data) override { - StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); + LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); if (interpreter) { @@ -2396,9 +2401,10 @@ class CommandObjectCommandsScriptAdd : public CommandObjectParsed, std::string funct_name_str; if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { if (funct_name_str.empty()) { - error_sp->Printf("error: unable to obtain a function name, didn't " - "add python command.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: unable to obtain a function name, didn't " + "add python command.\n"); } else { // everything should be fine now, let's add this alias @@ -2409,33 +2415,36 @@ class CommandObjectCommandsScriptAdd : public CommandObjectParsed, Status error = m_interpreter.AddUserCommand( m_cmd_name, command_obj_sp, m_overwrite); if (error.Fail()) { - error_sp->Printf("error: unable to add selected command: '%s'", - error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: unable to add selected command: '%s'", + error.AsCString()); } } else { llvm::Error llvm_error = m_container->LoadUserSubcommand( m_cmd_name, command_obj_sp, m_overwrite); if (llvm_error) { - error_sp->Printf("error: unable to add selected command: '%s'", - llvm::toString(std::move(llvm_error)).c_str()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: unable to add selected command: '%s'", + llvm::toString(std::move(llvm_error)).c_str()); } } } } else { - error_sp->Printf( + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( "error: unable to create function, didn't add python command\n"); - error_sp->Flush(); } } else { - error_sp->Printf("error: empty function, didn't add python command\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: empty function, didn't add python command\n"); } } else { - error_sp->Printf( + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( "error: script interpreter missing, didn't add python command\n"); - error_sp->Flush(); } io_handler.SetIsDone(true); diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 69a4d6be382f5..d2eaa4acbc568 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -12,6 +12,7 @@ #include "lldb/Expression/REPL.h" #include "lldb/Expression/UserExpression.h" #include "lldb/Host/OptionParser.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandOptionArgumentTable.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -22,6 +23,7 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/DiagnosticsRendering.h" #include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" // BEGIN SWIFT @@ -526,19 +528,17 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler, std::string &line) { io_handler.SetIsDone(true); - StreamFileSP output_sp = io_handler.GetOutputStreamFileSP(); - StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); + StreamSP output_stream = + GetCommandInterpreter().GetDebugger().GetAsyncOutputStream(); + StreamSP error_stream = + GetCommandInterpreter().GetDebugger().GetAsyncErrorStream(); CommandReturnObject return_obj( GetCommandInterpreter().GetDebugger().GetUseColor()); - EvaluateExpression(line.c_str(), *output_sp, *error_sp, return_obj); + EvaluateExpression(line.c_str(), *output_stream, *error_stream, return_obj); - if (output_sp) - output_sp->Flush(); - if (error_sp) { - *error_sp << return_obj.GetErrorString(); - error_sp->Flush(); - } + output_stream->Flush(); + *error_stream << return_obj.GetErrorString(); } bool CommandObjectExpression::IOHandlerIsInputComplete(IOHandler &io_handler, @@ -596,11 +596,10 @@ void CommandObjectExpression::GetMultilineExpression() { 1, // Show line numbers starting at 1 *this)); - StreamFileSP output_sp = io_handler_sp->GetOutputStreamFileSP(); - if (output_sp) { - output_sp->PutCString( + if (LockableStreamFileSP output_sp = io_handler_sp->GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString( "Enter expressions, then terminate with an empty line to evaluate:\n"); - output_sp->Flush(); } debugger.RunIOHandlerAsync(io_handler_sp); } diff --git a/lldb/source/Commands/CommandObjectGUI.cpp b/lldb/source/Commands/CommandObjectGUI.cpp index b56e49b073b03..8630171bae9d1 100644 --- a/lldb/source/Commands/CommandObjectGUI.cpp +++ b/lldb/source/Commands/CommandObjectGUI.cpp @@ -28,10 +28,10 @@ void CommandObjectGUI::DoExecute(Args &args, CommandReturnObject &result) { #if LLDB_ENABLE_CURSES Debugger &debugger = GetDebugger(); - File &input = debugger.GetInputFile(); - File &output = debugger.GetOutputFile(); - if (input.GetStream() && output.GetStream() && input.GetIsRealTerminal() && - input.GetIsInteractive()) { + FileSP input_sp = debugger.GetInputFileSP(); + FileSP output_sp = debugger.GetOutputFileSP(); + if (input_sp->GetStream() && output_sp->GetStream() && + input_sp->GetIsRealTerminal() && input_sp->GetIsInteractive()) { IOHandlerSP io_handler_sp(new IOHandlerCursesGUI(debugger)); if (io_handler_sp) debugger.RunIOHandlerAsync(io_handler_sp); diff --git a/lldb/source/Commands/CommandObjectLog.cpp b/lldb/source/Commands/CommandObjectLog.cpp index 9eb68ddb73b6e..741b13fb56202 100644 --- a/lldb/source/Commands/CommandObjectLog.cpp +++ b/lldb/source/Commands/CommandObjectLog.cpp @@ -394,7 +394,8 @@ class CommandObjectLogDump : public CommandObjectParsed { (*file)->GetDescriptor(), /*shouldClose=*/true); } else { stream_up = std::make_unique( - GetDebugger().GetOutputFile().GetDescriptor(), /*shouldClose=*/false); + GetDebugger().GetOutputFileSP()->GetDescriptor(), + /*shouldClose=*/false); } const std::string channel = std::string(args[0].ref()); diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index c72419ffef3ff..38afadc87791d 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -57,6 +57,7 @@ #include "lldb/Utility/Timer.h" #include "lldb/ValueObject/ValueObjectVariable.h" #include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" #include "clang/Frontend/CompilerInstance.h" @@ -4924,11 +4925,13 @@ Filter Options: protected: void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString( - "Enter your stop hook command(s). Type 'DONE' to end.\n"); - output_sp->Flush(); + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString( + "Enter your stop hook command(s). Type 'DONE' to end.\n"); + } } } @@ -4936,12 +4939,12 @@ Filter Options: std::string &line) override { if (m_stop_hook_sp) { if (line.empty()) { - StreamFileSP error_sp(io_handler.GetErrorStreamFileSP()); - if (error_sp) { - error_sp->Printf("error: stop hook #%" PRIu64 - " aborted, no commands.\n", - m_stop_hook_sp->GetID()); - error_sp->Flush(); + if (lldb::LockableStreamFileSP error_sp = + io_handler.GetErrorStreamFileSP()) { + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: stop hook #%" PRIu64 + " aborted, no commands.\n", + m_stop_hook_sp->GetID()); } Target *target = &GetTarget(); if (target) { @@ -4953,11 +4956,11 @@ Filter Options: static_cast(m_stop_hook_sp.get()); hook_ptr->SetActionFromString(line); - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp) { - output_sp->Printf("Stop hook #%" PRIu64 " added.\n", - m_stop_hook_sp->GetID()); - output_sp->Flush(); + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.Printf("Stop hook #%" PRIu64 " added.\n", + m_stop_hook_sp->GetID()); } } m_stop_hook_sp.reset(); diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp index 76e25f93c2c4c..923b3e7bc65b9 100644 --- a/lldb/source/Commands/CommandObjectType.cpp +++ b/lldb/source/Commands/CommandObjectType.cpp @@ -14,6 +14,7 @@ #include "lldb/DataFormatters/FormatClasses.h" #include "lldb/Host/Config.h" #include "lldb/Host/OptionParser.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandOptionArgumentTable.h" @@ -32,6 +33,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/StringList.h" +#include "lldb/lldb-forward.h" #include "llvm/ADT/STLExtras.h" @@ -167,16 +169,17 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed, "for\n" " internal_dict: an LLDB support object not to be used\"\"\"\n"; - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString(g_summary_addreader_instructions); - output_sp->Flush(); + if (interactive) { + if (LockableStreamFileSP output_sp = io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString(g_summary_addreader_instructions); + } } } void IOHandlerInputComplete(IOHandler &io_handler, std::string &data) override { - StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); + LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); #if LLDB_ENABLE_PYTHON ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); @@ -197,9 +200,10 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed, if (interpreter->GenerateTypeScriptFunction(lines, funct_name_str)) { if (funct_name_str.empty()) { - error_sp->Printf("unable to obtain a valid function name from " - "the script interpreter.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "unable to obtain a valid function name from " + "the script interpreter.\n"); } else { // now I have a valid function name, let's add this as script // for every type in the list @@ -216,8 +220,8 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed, options->m_match_type, options->m_category, &error); if (error.Fail()) { - error_sp->Printf("error: %s", error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: %s", error.AsCString()); } } @@ -228,41 +232,42 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed, CommandObjectTypeSummaryAdd::AddNamedSummary( options->m_name, script_format, &error); if (error.Fail()) { - error_sp->Printf("error: %s", error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: %s", error.AsCString()); } } else { - error_sp->Printf("error: %s", error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: %s", error.AsCString()); } } else { if (error.AsCString()) { - error_sp->Printf("error: %s", error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: %s", error.AsCString()); } } } } else { - error_sp->Printf("error: unable to generate a function.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: unable to generate a function.\n"); } } else { - error_sp->Printf("error: no script interpreter.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: no script interpreter.\n"); } } else { - error_sp->Printf("error: internal synchronization information " - "missing or invalid.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: internal synchronization information " + "missing or invalid.\n"); } } else { - error_sp->Printf("error: empty function, didn't add python command.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: empty function, didn't add python command.\n"); } } else { - error_sp->Printf( + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( "error: script interpreter missing, didn't add python command.\n"); - error_sp->Flush(); } #endif io_handler.SetIsDone(true); @@ -404,16 +409,17 @@ class CommandObjectTypeSynthAdd : public CommandObjectParsed, } void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString(g_synth_addreader_instructions); - output_sp->Flush(); + if (interactive) { + if (LockableStreamFileSP output_sp = io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString(g_synth_addreader_instructions); + } } } void IOHandlerInputComplete(IOHandler &io_handler, std::string &data) override { - StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); + LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); #if LLDB_ENABLE_PYTHON ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); @@ -433,9 +439,10 @@ class CommandObjectTypeSynthAdd : public CommandObjectParsed, std::string class_name_str; if (interpreter->GenerateTypeSynthClass(lines, class_name_str)) { if (class_name_str.empty()) { - error_sp->Printf( + + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( "error: unable to obtain a proper name for the class.\n"); - error_sp->Flush(); } else { // everything should be fine now, let's add the synth provider // class @@ -459,37 +466,39 @@ class CommandObjectTypeSynthAdd : public CommandObjectParsed, if (AddSynth(ConstString(type_name), synth_provider, options->m_match_type, options->m_category, &error)) { - error_sp->Printf("error: %s\n", error.AsCString()); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: %s\n", error.AsCString()); break; } } else { - error_sp->Printf("error: invalid type name.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: invalid type name.\n"); break; } } } } else { - error_sp->Printf("error: unable to generate a class.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: unable to generate a class.\n"); } } else { - error_sp->Printf("error: no script interpreter.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("error: no script interpreter.\n"); } } else { - error_sp->Printf("error: internal synchronization data missing.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: internal synchronization data missing.\n"); } } else { - error_sp->Printf("error: empty function, didn't add python command.\n"); - error_sp->Flush(); + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( + "error: empty function, didn't add python command.\n"); } } else { - error_sp->Printf( + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf( "error: script interpreter missing, didn't add python command.\n"); - error_sp->Flush(); } #endif @@ -952,8 +961,8 @@ class CommandObjectTypeFormatterClear : public CommandObjectParsed { class CommandObjectTypeFormatDelete : public CommandObjectTypeFormatterDelete { public: CommandObjectTypeFormatDelete(CommandInterpreter &interpreter) - : CommandObjectTypeFormatterDelete( - interpreter, eFormatCategoryItemFormat) {} + : CommandObjectTypeFormatterDelete(interpreter, + eFormatCategoryItemFormat) {} ~CommandObjectTypeFormatDelete() override = default; }; @@ -1603,8 +1612,8 @@ bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name, class CommandObjectTypeSummaryDelete : public CommandObjectTypeFormatterDelete { public: CommandObjectTypeSummaryDelete(CommandInterpreter &interpreter) - : CommandObjectTypeFormatterDelete( - interpreter, eFormatCategoryItemSummary) {} + : CommandObjectTypeFormatterDelete(interpreter, + eFormatCategoryItemSummary) {} ~CommandObjectTypeSummaryDelete() override = default; @@ -2070,8 +2079,8 @@ class CommandObjectTypeSynthList class CommandObjectTypeFilterDelete : public CommandObjectTypeFormatterDelete { public: CommandObjectTypeFilterDelete(CommandInterpreter &interpreter) - : CommandObjectTypeFormatterDelete( - interpreter, eFormatCategoryItemFilter) {} + : CommandObjectTypeFormatterDelete(interpreter, + eFormatCategoryItemFilter) {} ~CommandObjectTypeFilterDelete() override = default; }; @@ -2081,13 +2090,12 @@ class CommandObjectTypeFilterDelete : public CommandObjectTypeFormatterDelete { class CommandObjectTypeSynthDelete : public CommandObjectTypeFormatterDelete { public: CommandObjectTypeSynthDelete(CommandInterpreter &interpreter) - : CommandObjectTypeFormatterDelete( - interpreter, eFormatCategoryItemSynth) {} + : CommandObjectTypeFormatterDelete(interpreter, + eFormatCategoryItemSynth) {} ~CommandObjectTypeSynthDelete() override = default; }; - // CommandObjectTypeFilterClear class CommandObjectTypeFilterClear : public CommandObjectTypeFormatterClear { diff --git a/lldb/source/Commands/CommandObjectWatchpointCommand.cpp b/lldb/source/Commands/CommandObjectWatchpointCommand.cpp index b4dd6daa5b63e..e7dc77e313275 100644 --- a/lldb/source/Commands/CommandObjectWatchpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectWatchpointCommand.cpp @@ -14,11 +14,13 @@ #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/IOHandler.h" #include "lldb/Host/OptionParser.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandOptionArgumentTable.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Target/Target.h" +#include "lldb/lldb-forward.h" using namespace lldb; using namespace lldb_private; @@ -170,11 +172,13 @@ are no syntax errors may indicate that a function was declared but never called. Options *GetOptions() override { return &m_options; } void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString( - "Enter your debugger command(s). Type 'DONE' to end.\n"); - output_sp->Flush(); + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream.PutCString( + "Enter your debugger command(s). Type 'DONE' to end.\n"); + } } } @@ -248,10 +252,8 @@ are no syntax errors may indicate that a function was declared but never called. // Rig up the results secondary output stream to the debugger's, so the // output will come out synchronously if the debugger is set up that // way. - StreamSP output_stream(debugger.GetAsyncOutputStream()); - StreamSP error_stream(debugger.GetAsyncErrorStream()); - result.SetImmediateOutputStream(output_stream); - result.SetImmediateErrorStream(error_stream); + result.SetImmediateOutputStream(debugger.GetAsyncOutputStream()); + result.SetImmediateErrorStream(debugger.GetAsyncErrorStream()); CommandInterpreterRunOptions options; options.SetStopOnContinue(true); diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 11db7363f8334..e4edd94ce9413 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -257,12 +257,11 @@ Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx, std::list errors; StreamString feedback_stream; if (!target_sp->LoadScriptingResources(errors, feedback_stream)) { - Stream &s = GetErrorStream(); - for (auto &error : errors) { - s.Printf("%s\n", error.AsCString()); - } + lldb::StreamUP s = GetAsyncErrorStream(); + for (auto &error : errors) + s->Printf("%s\n", error.AsCString()); if (feedback_stream.GetSize()) - s.PutCString(feedback_stream.GetString()); + s->PutCString(feedback_stream.GetString()); } } } @@ -874,9 +873,11 @@ llvm::StringRef Debugger::GetStaticBroadcasterClass() { Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) : UserID(g_unique_id++), Properties(std::make_shared()), - m_input_file_sp(std::make_shared(stdin, false)), - m_output_stream_sp(std::make_shared(stdout, false)), - m_error_stream_sp(std::make_shared(stderr, false)), + m_input_file_sp(std::make_shared(stdin, NativeFile::Unowned)), + m_output_stream_sp(std::make_shared( + stdout, NativeFile::Unowned, m_output_mutex)), + m_error_stream_sp(std::make_shared( + stderr, NativeFile::Unowned, m_output_mutex)), m_input_recorder(nullptr), m_broadcaster_manager_sp(BroadcasterManager::MakeBroadcasterManager()), m_terminal_state(), m_target_list(*this), m_platform_list(), @@ -948,7 +949,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 (!GetOutputFile().GetIsTerminalWithColors()) + if (!GetOutputFileSP()->GetIsTerminalWithColors()) SetUseColor(false); if (Diagnostics::Enabled()) { @@ -1084,12 +1085,14 @@ void Debugger::SetInputFile(FileSP file_sp) { void Debugger::SetOutputFile(FileSP file_sp) { assert(file_sp && file_sp->IsValid()); - m_output_stream_sp = std::make_shared(file_sp); + m_output_stream_sp = + std::make_shared(file_sp, m_output_mutex); } void Debugger::SetErrorFile(FileSP file_sp) { assert(file_sp && file_sp->IsValid()); - m_error_stream_sp = std::make_shared(file_sp); + m_error_stream_sp = + std::make_shared(file_sp, m_output_mutex); } void Debugger::SaveInputTerminalState() { @@ -1199,9 +1202,10 @@ bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type top_type, void Debugger::PrintAsync(const char *s, size_t len, bool is_stdout) { bool printed = m_io_handler_stack.PrintAsync(s, len, is_stdout); if (!printed) { - lldb::StreamFileSP stream = + LockableStreamFileSP stream_sp = is_stdout ? m_output_stream_sp : m_error_stream_sp; - stream->Write(s, len); + LockedStreamFile locked_stream = stream_sp->Lock(); + locked_stream.Write(s, len); } } @@ -1226,8 +1230,9 @@ void Debugger::RunIOHandlerAsync(const IOHandlerSP &reader_sp, PushIOHandler(reader_sp, cancel_top_handler); } -void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out, - StreamFileSP &err) { +void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, + LockableStreamFileSP &out, + LockableStreamFileSP &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 @@ -1243,27 +1248,29 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out, in = GetInputFileSP(); // If there is nothing, use stdin if (!in) - in = std::make_shared(stdin, false); + in = std::make_shared(stdin, NativeFile::Unowned); } // If no STDOUT has been set, then set it appropriately - if (!out || !out->GetFile().IsValid()) { + if (!out || !out->GetUnlockedFile().IsValid()) { if (top_reader_sp) out = top_reader_sp->GetOutputStreamFileSP(); else out = GetOutputStreamSP(); // If there is nothing, use stdout if (!out) - out = std::make_shared(stdout, false); + out = std::make_shared(stdout, NativeFile::Unowned, + m_output_mutex); } // If no STDERR has been set, then set it appropriately - if (!err || !err->GetFile().IsValid()) { + if (!err || !err->GetUnlockedFile().IsValid()) { if (top_reader_sp) err = top_reader_sp->GetErrorStreamFileSP(); else err = GetErrorStreamSP(); // If there is nothing, use stderr if (!err) - err = std::make_shared(stderr, false); + err = std::make_shared(stderr, NativeFile::Unowned, + m_output_mutex); } } @@ -1360,12 +1367,14 @@ bool Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) { return true; } -StreamSP Debugger::GetAsyncOutputStream() { - return std::make_shared(*this, true, GetUseColor()); +StreamUP Debugger::GetAsyncOutputStream() { + return std::make_unique(*this, + StreamAsynchronousIO::STDOUT); } -StreamSP Debugger::GetAsyncErrorStream() { - return std::make_shared(*this, false, GetUseColor()); +StreamUP Debugger::GetAsyncErrorStream() { + return std::make_unique(*this, + StreamAsynchronousIO::STDERR); } void Debugger::RequestInterrupt() { @@ -1607,8 +1616,7 @@ static void PrivateReportDiagnostic(Debugger &debugger, Severity severity, // diagnostic directly to the debugger's error stream. DiagnosticEventData event_data(severity, std::move(message), debugger_specific); - StreamSP stream = debugger.GetAsyncErrorStream(); - event_data.Dump(stream.get()); + event_data.Dump(debugger.GetAsyncErrorStream().get()); return; } EventSP event_sp = std::make_shared( @@ -1718,7 +1726,7 @@ bool Debugger::EnableLog(llvm::StringRef channel, LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME; } else if (log_file.empty()) { log_handler_sp = - CreateLogHandler(log_handler_kind, GetOutputFile().GetDescriptor(), + CreateLogHandler(log_handler_kind, GetOutputFileSP()->GetDescriptor(), /*should_close=*/false, buffer_size); } else { auto pos = m_stream_handlers.find(log_file); @@ -1804,12 +1812,11 @@ void Debugger::HandleBreakpointEvent(const EventSP &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", + if (StreamUP output_up = GetAsyncOutputStream()) { + output_up->Printf("%d location%s added to breakpoint %d\n", num_new_locations, num_new_locations == 1 ? "" : "s", breakpoint->GetID()); - output_sp->Flush(); + output_up->Flush(); } } } @@ -1853,8 +1860,8 @@ void Debugger::HandleProcessEvent(const EventSP &event_sp) { ? EventDataStructuredData::GetProcessFromEvent(event_sp.get()) : Process::ProcessEventData::GetProcessFromEvent(event_sp.get()); - StreamSP output_stream_sp = GetAsyncOutputStream(); - StreamSP error_stream_sp = GetAsyncErrorStream(); + StreamUP output_stream_up = GetAsyncOutputStream(); + StreamUP error_stream_up = GetAsyncErrorStream(); const bool gui_enabled = IsForwardingEvents(); if (!gui_enabled) { @@ -1882,7 +1889,7 @@ void Debugger::HandleProcessEvent(const EventSP &event_sp) { if (got_state_changed && !state_is_stopped) { // This is a public stop which we are going to announce to the user, so // we should force the most relevant frame selection here. - Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(), + Process::HandleProcessStateChangedEvent(event_sp, output_stream_up.get(), SelectMostRelevantFrame, pop_process_io_handler, // BEGIN SWIFT @@ -1902,31 +1909,29 @@ void Debugger::HandleProcessEvent(const EventSP &event_sp) { if (plugin_sp) { auto structured_data_sp = EventDataStructuredData::GetObjectFromEvent(event_sp.get()); - if (output_stream_sp) { - StreamString content_stream; - Status 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->Format("Failed to print structured " - "data with plugin {0}: {1}", - plugin_sp->GetPluginName(), error); + StreamString content_stream; + Status 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_up->PutCString(content_stream.GetString()); } + } else { + error_stream_up->Format("Failed to print structured " + "data with plugin {0}: {1}", + plugin_sp->GetPluginName(), error); } } } // Now display any stopped state changes after any STDIO if (got_state_changed && state_is_stopped) { - Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(), + Process::HandleProcessStateChangedEvent(event_sp, output_stream_up.get(), SelectMostRelevantFrame, pop_process_io_handler, // BEGIN SWIFT @@ -1935,8 +1940,8 @@ void Debugger::HandleProcessEvent(const EventSP &event_sp) { ); } - output_stream_sp->Flush(); - error_stream_sp->Flush(); + output_stream_up->Flush(); + error_stream_up->Flush(); if (pop_process_io_handler) // BEGIN SWIFT @@ -2038,22 +2043,18 @@ lldb::thread_result_t Debugger::DefaultEventHandler() { const char *data = static_cast( EventDataBytes::GetBytesFromEvent(event_sp.get())); if (data && data[0]) { - StreamSP error_sp(GetAsyncErrorStream()); - if (error_sp) { - error_sp->PutCString(data); - error_sp->Flush(); - } + StreamUP error_up = GetAsyncErrorStream(); + error_up->PutCString(data); + error_up->Flush(); } } else if (event_type & CommandInterpreter:: eBroadcastBitAsynchronousOutputData) { const char *data = static_cast( EventDataBytes::GetBytesFromEvent(event_sp.get())); if (data && data[0]) { - StreamSP output_sp(GetAsyncOutputStream()); - if (output_sp) { - output_sp->PutCString(data); - output_sp->Flush(); - } + StreamUP output_up = GetAsyncOutputStream(); + output_up->PutCString(data); + output_up->Flush(); } } } else if (broadcaster == &m_broadcaster) { @@ -2164,11 +2165,11 @@ void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) { // Determine whether the current output file is an interactive terminal with // color support. We assume that if we support ANSI escape codes we support // vt100 escape codes. - File &file = GetOutputFile(); - if (!file.GetIsInteractive() || !file.GetIsTerminalWithColors()) + FileSP file_sp = GetOutputFileSP(); + if (!file_sp->GetIsInteractive() || !file_sp->GetIsTerminalWithColors()) return; - StreamSP output = GetAsyncOutputStream(); + StreamUP output = GetAsyncOutputStream(); // Print over previous line, if any. output->Printf("\r"); @@ -2218,8 +2219,7 @@ void Debugger::HandleDiagnosticEvent(const lldb::EventSP &event_sp) { if (!data) return; - StreamSP stream = GetAsyncErrorStream(); - data->Dump(stream.get()); + data->Dump(GetAsyncErrorStream().get()); } bool Debugger::HasIOHandlerThread() const { diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp index 7758a87403b5a..b9728625447a5 100644 --- a/lldb/source/Core/DynamicLoader.cpp +++ b/lldb/source/Core/DynamicLoader.cpp @@ -255,7 +255,7 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( module_sp = std::make_shared(module_spec); } else if (force_symbol_search && error.AsCString("") && error.AsCString("")[0] != '\0') { - target.GetDebugger().GetErrorStream() << error.AsCString(); + *target.GetDebugger().GetAsyncErrorStream() << error.AsCString(); } } @@ -320,19 +320,19 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( } } else { if (force_symbol_search) { - Stream &s = target.GetDebugger().GetErrorStream(); - s.Printf("Unable to find file"); + lldb::StreamUP s = target.GetDebugger().GetAsyncErrorStream(); + s->Printf("Unable to find file"); if (!name.empty()) - s.Printf(" %s", name.str().c_str()); + s->Printf(" %s", name.str().c_str()); if (uuid.IsValid()) - s.Printf(" with UUID %s", uuid.GetAsString().c_str()); + s->Printf(" with UUID %s", uuid.GetAsString().c_str()); if (value != LLDB_INVALID_ADDRESS) { if (value_is_offset) - s.Printf(" with slide 0x%" PRIx64, value); + s->Printf(" with slide 0x%" PRIx64, value); else - s.Printf(" at address 0x%" PRIx64, value); + s->Printf(" at address 0x%" PRIx64, value); } - s.Printf("\n"); + s->Printf("\n"); } LLDB_LOGF(log, "Unable to find binary %s with UUID %s and load it at " diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp index bf8c3887ccbfb..1ee755b4ca793 100644 --- a/lldb/source/Core/IOHandler.cpp +++ b/lldb/source/Core/IOHandler.cpp @@ -54,17 +54,17 @@ using llvm::StringRef; IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type) : IOHandler(debugger, type, - FileSP(), // Adopt STDIN from top input reader - StreamFileSP(), // Adopt STDOUT from top input reader - StreamFileSP(), // Adopt STDERR from top input reader - 0 // Flags + FileSP(), // Adopt STDIN from top input reader + LockableStreamFileSP(), // Adopt STDOUT from top input reader + LockableStreamFileSP(), // Adopt STDERR from top input reader + 0 // Flags ) {} IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type, const lldb::FileSP &input_sp, - const lldb::StreamFileSP &output_sp, - const lldb::StreamFileSP &error_sp, uint32_t flags) + const lldb::LockableStreamFileSP &output_sp, + const lldb::LockableStreamFileSP &error_sp, uint32_t flags) : m_debugger(debugger), m_input_sp(input_sp), m_output_sp(output_sp), m_error_sp(error_sp), m_popped(false), m_flags(flags), m_type(type), m_user_data(nullptr), m_done(false), m_active(false) { @@ -81,30 +81,18 @@ int IOHandler::GetInputFD() { } int IOHandler::GetOutputFD() { - return (m_output_sp ? m_output_sp->GetFile().GetDescriptor() : -1); + return (m_output_sp ? m_output_sp->GetUnlockedFile().GetDescriptor() : -1); } int IOHandler::GetErrorFD() { - return (m_error_sp ? m_error_sp->GetFile().GetDescriptor() : -1); -} - -FILE *IOHandler::GetInputFILE() { - return (m_input_sp ? m_input_sp->GetStream() : nullptr); -} - -FILE *IOHandler::GetOutputFILE() { - return (m_output_sp ? m_output_sp->GetFile().GetStream() : nullptr); -} - -FILE *IOHandler::GetErrorFILE() { - return (m_error_sp ? m_error_sp->GetFile().GetStream() : nullptr); + return (m_error_sp ? m_error_sp->GetUnlockedFile().GetDescriptor() : -1); } FileSP IOHandler::GetInputFileSP() { return m_input_sp; } -StreamFileSP IOHandler::GetOutputStreamFileSP() { return m_output_sp; } +LockableStreamFileSP IOHandler::GetOutputStreamFileSP() { return m_output_sp; } -StreamFileSP IOHandler::GetErrorStreamFileSP() { return m_error_sp; } +LockableStreamFileSP IOHandler::GetErrorStreamFileSP() { return m_error_sp; } bool IOHandler::GetIsInteractive() { return GetInputFileSP() ? GetInputFileSP()->GetIsInteractive() : false; @@ -119,10 +107,9 @@ void IOHandler::SetPopped(bool b) { m_popped.SetValue(b, eBroadcastOnChange); } void IOHandler::WaitForPop() { m_popped.WaitForValueEqualTo(true); } void IOHandler::PrintAsync(const char *s, size_t len, bool is_stdout) { - std::lock_guard guard(m_output_mutex); - lldb::StreamFileSP stream = is_stdout ? m_output_sp : m_error_sp; - stream->Write(s, len); - stream->Flush(); + lldb::LockableStreamFileSP stream_sp = is_stdout ? m_output_sp : m_error_sp; + LockedStreamFile locked_Stream = stream_sp->Lock(); + locked_Stream.Write(s, len); } bool IOHandlerStack::PrintAsync(const char *s, size_t len, bool is_stdout) { @@ -228,19 +215,20 @@ IOHandlerEditline::IOHandlerEditline( llvm::StringRef prompt, llvm::StringRef continuation_prompt, bool multi_line, bool color, uint32_t line_number_start, IOHandlerDelegate &delegate) - : IOHandlerEditline(debugger, type, - FileSP(), // Inherit input from top input reader - StreamFileSP(), // Inherit output from top input reader - StreamFileSP(), // Inherit error from top input reader - 0, // Flags - editline_name, // Used for saving history files - prompt, continuation_prompt, multi_line, color, - line_number_start, delegate) {} + : IOHandlerEditline( + debugger, type, + FileSP(), // Inherit input from top input reader + LockableStreamFileSP(), // Inherit output from top input reader + LockableStreamFileSP(), // Inherit error from top input reader + 0, // Flags + editline_name, // Used for saving history files + prompt, continuation_prompt, multi_line, color, line_number_start, + delegate) {} IOHandlerEditline::IOHandlerEditline( Debugger &debugger, IOHandler::Type type, const lldb::FileSP &input_sp, - const lldb::StreamFileSP &output_sp, const lldb::StreamFileSP &error_sp, - uint32_t flags, + const lldb::LockableStreamFileSP &output_sp, + const lldb::LockableStreamFileSP &error_sp, uint32_t flags, const char *editline_name, // Used for saving history files llvm::StringRef prompt, llvm::StringRef continuation_prompt, bool multi_line, bool color, uint32_t line_number_start, @@ -256,15 +244,12 @@ IOHandlerEditline::IOHandlerEditline( SetPrompt(prompt); #if LLDB_ENABLE_LIBEDIT - bool use_editline = false; - - use_editline = GetInputFILE() && GetOutputFILE() && GetErrorFILE() && - m_input_sp && m_input_sp->GetIsRealTerminal(); - + const bool use_editline = m_input_sp && m_output_sp && m_error_sp && + m_input_sp->GetIsRealTerminal(); if (use_editline) { - m_editline_up = std::make_unique(editline_name, GetInputFILE(), - GetOutputFILE(), GetErrorFILE(), - GetOutputMutex()); + m_editline_up = std::make_unique( + editline_name, m_input_sp ? m_input_sp->GetStream() : nullptr, + m_output_sp, m_error_sp, m_color); m_editline_up->SetIsInputCompleteCallback( [this](Editline *editline, StringList &lines) { return this->IsInputCompleteCallback(editline, lines); @@ -278,12 +263,10 @@ IOHandlerEditline::IOHandlerEditline( m_editline_up->SetSuggestionCallback([this](llvm::StringRef line) { return this->SuggestionCallback(line); }); - if (m_color) { - m_editline_up->SetSuggestionAnsiPrefix(ansi::FormatAnsiTerminalCodes( - debugger.GetAutosuggestionAnsiPrefix())); - m_editline_up->SetSuggestionAnsiSuffix(ansi::FormatAnsiTerminalCodes( - debugger.GetAutosuggestionAnsiSuffix())); - } + m_editline_up->SetSuggestionAnsiPrefix(ansi::FormatAnsiTerminalCodes( + debugger.GetAutosuggestionAnsiPrefix())); + m_editline_up->SetSuggestionAnsiSuffix(ansi::FormatAnsiTerminalCodes( + debugger.GetAutosuggestionAnsiSuffix())); } // See if the delegate supports fixing indentation const char *indent_chars = delegate.IOHandlerGetFixIndentationCharacters(); @@ -368,8 +351,8 @@ bool IOHandlerEditline::GetLine(std::string &line, bool &interrupted) { if (prompt && prompt[0]) { if (m_output_sp) { - m_output_sp->Printf("%s", prompt); - m_output_sp->Flush(); + LockedStreamFile locked_stream = m_output_sp->Lock(); + locked_stream.Printf("%s", prompt); } } } @@ -382,7 +365,7 @@ bool IOHandlerEditline::GetLine(std::string &line, bool &interrupted) { return false; } - FILE *in = GetInputFILE(); + FILE *in = m_input_sp ? m_input_sp->GetStream() : nullptr; char buffer[256]; if (!got_line && !in && m_input_sp) { @@ -478,12 +461,10 @@ bool IOHandlerEditline::SetPrompt(llvm::StringRef prompt) { #if LLDB_ENABLE_LIBEDIT if (m_editline_up) { m_editline_up->SetPrompt(m_prompt.empty() ? nullptr : m_prompt.c_str()); - if (m_color) { - m_editline_up->SetPromptAnsiPrefix( - ansi::FormatAnsiTerminalCodes(m_debugger.GetPromptAnsiPrefix())); - m_editline_up->SetPromptAnsiSuffix( - ansi::FormatAnsiTerminalCodes(m_debugger.GetPromptAnsiSuffix())); - } + m_editline_up->SetPromptAnsiPrefix( + ansi::FormatAnsiTerminalCodes(m_debugger.GetPromptAnsiPrefix())); + m_editline_up->SetPromptAnsiSuffix( + ansi::FormatAnsiTerminalCodes(m_debugger.GetPromptAnsiSuffix())); } #endif return true; @@ -549,9 +530,10 @@ bool IOHandlerEditline::GetLines(StringList &lines, bool &interrupted) { std::string line; if (m_base_line_number > 0 && GetIsInteractive()) { if (m_output_sp) { - m_output_sp->Printf("%u%s", - m_base_line_number + (uint32_t)lines.GetSize(), - GetPrompt() == nullptr ? " " : ""); + LockedStreamFile locked_stream = m_output_sp->Lock(); + locked_stream.Printf("%u%s", + m_base_line_number + (uint32_t)lines.GetSize(), + GetPrompt() == nullptr ? " " : ""); } } @@ -637,9 +619,8 @@ void IOHandlerEditline::GotEOF() { void IOHandlerEditline::PrintAsync(const char *s, size_t len, bool is_stdout) { #if LLDB_ENABLE_LIBEDIT if (m_editline_up) { - std::lock_guard guard(m_output_mutex); - lldb::StreamFileSP stream = is_stdout ? m_output_sp : m_error_sp; - m_editline_up->PrintAsync(stream.get(), s, len); + lldb::LockableStreamFileSP stream_sp = is_stdout ? m_output_sp : m_error_sp; + m_editline_up->PrintAsync(stream_sp, s, len); } else #endif { diff --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp index c3bbe91290c36..e63611c7b05c4 100644 --- a/lldb/source/Core/IOHandlerCursesGUI.cpp +++ b/lldb/source/Core/IOHandlerCursesGUI.cpp @@ -94,6 +94,7 @@ using llvm::StringRef; #define KEY_SHIFT_TAB (KEY_MAX + 1) #define KEY_ALT_ENTER (KEY_MAX + 2) +namespace lldb_private { namespace curses { class Menu; class MenuDelegate; @@ -4479,8 +4480,9 @@ class Application { }; } // namespace curses +} // namespace lldb_private -using namespace curses; +using namespace lldb_private::curses; struct Row { ValueObjectUpdater value; @@ -7571,12 +7573,14 @@ IOHandlerCursesGUI::IOHandlerCursesGUI(Debugger &debugger) void IOHandlerCursesGUI::Activate() { IOHandler::Activate(); - if (!m_app_ap) { - m_app_ap = std::make_unique(GetInputFILE(), GetOutputFILE()); + if (!m_app_up) { + m_app_up = std::make_unique( + m_input_sp ? m_input_sp->GetStream() : nullptr, + m_output_sp ? m_input_sp->GetStream() : nullptr); // This is both a window and a menu delegate std::shared_ptr app_delegate_sp( - new ApplicationDelegate(*m_app_ap, m_debugger)); + new ApplicationDelegate(*m_app_up, m_debugger)); MenuDelegateSP app_menu_delegate_sp = std::static_pointer_cast(app_delegate_sp); @@ -7650,8 +7654,8 @@ void IOHandlerCursesGUI::Activate() { help_menu_sp->AddSubmenu(MenuSP(new Menu( "GUI Help", nullptr, 'g', ApplicationDelegate::eMenuID_HelpGUIHelp))); - m_app_ap->Initialize(); - WindowSP &main_window_sp = m_app_ap->GetMainWindow(); + m_app_up->Initialize(); + WindowSP &main_window_sp = m_app_up->GetMainWindow(); MenuSP menubar_sp(new Menu(Menu::Type::Bar)); menubar_sp->AddSubmenu(lldb_menu_sp); @@ -7732,10 +7736,10 @@ void IOHandlerCursesGUI::Activate() { } } -void IOHandlerCursesGUI::Deactivate() { m_app_ap->Terminate(); } +void IOHandlerCursesGUI::Deactivate() { m_app_up->Terminate(); } void IOHandlerCursesGUI::Run() { - m_app_ap->Run(m_debugger); + m_app_up->Run(m_debugger); SetIsDone(true); } @@ -7750,7 +7754,7 @@ bool IOHandlerCursesGUI::Interrupt() { void IOHandlerCursesGUI::GotEOF() {} void IOHandlerCursesGUI::TerminalSizeChanged() { - m_app_ap->TerminalSizeChanged(); + m_app_up->TerminalSizeChanged(); } #endif // LLDB_ENABLE_CURSES diff --git a/lldb/source/Core/StreamAsynchronousIO.cpp b/lldb/source/Core/StreamAsynchronousIO.cpp index c2c64b61ab726..dbd56a69675b4 100644 --- a/lldb/source/Core/StreamAsynchronousIO.cpp +++ b/lldb/source/Core/StreamAsynchronousIO.cpp @@ -14,20 +14,20 @@ using namespace lldb; using namespace lldb_private; -StreamAsynchronousIO::StreamAsynchronousIO(Debugger &debugger, bool for_stdout, - bool colors) - : Stream(0, 4, eByteOrderBig, colors), m_debugger(debugger), m_data(), - m_for_stdout(for_stdout) {} +StreamAsynchronousIO::StreamAsynchronousIO( + Debugger &debugger, StreamAsynchronousIO::ForSTDOUT for_stdout) + : Stream(0, 4, eByteOrderBig, debugger.GetUseColor()), m_debugger(debugger), + m_data(), m_for_stdout(for_stdout) {} StreamAsynchronousIO::~StreamAsynchronousIO() { - // Flush when we destroy to make sure we display the data + // Flush when we destroy to make sure we display the data. Flush(); } void StreamAsynchronousIO::Flush() { if (!m_data.empty()) { m_debugger.PrintAsync(m_data.data(), m_data.size(), m_for_stdout); - m_data = std::string(); + m_data.clear(); } } diff --git a/lldb/source/Expression/REPL.cpp b/lldb/source/Expression/REPL.cpp index fed07ddf16102..b43c7e0f8c46e 100644 --- a/lldb/source/Expression/REPL.cpp +++ b/lldb/source/Expression/REPL.cpp @@ -103,8 +103,8 @@ void REPL::IOHandlerActivated(IOHandler &io_handler, bool interactive) { lldb::ProcessSP process_sp = m_target.GetProcessSP(); if (process_sp && process_sp->IsAlive()) return; - lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFileSP()); - error_sp->Printf("REPL requires a running target process.\n"); + LockedStreamFile locked_stream = io_handler.GetErrorStreamFileSP()->Lock(); + locked_stream.Printf("REPL requires a running target process.\n"); io_handler.SetIsDone(true); } @@ -219,8 +219,10 @@ static bool ReadCode(const std::string &path, std::string &code, } void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) { - lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFileSP()); + lldb::StreamFileSP output_sp = std::make_shared( + io_handler.GetOutputStreamFileSP()->GetUnlockedFileSP()); + lldb::StreamFileSP error_sp = std::make_shared( + io_handler.GetErrorStreamFileSP()->GetUnlockedFileSP()); bool extra_line = false; bool did_quit = false; diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp index 6e35b15d69651..5f7a8b0190a1d 100644 --- a/lldb/source/Host/common/Editline.cpp +++ b/lldb/source/Host/common/Editline.cpp @@ -14,6 +14,8 @@ #include "lldb/Host/Editline.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" +#include "lldb/Host/StreamFile.h" +#include "lldb/Utility/AnsiTerminal.h" #include "lldb/Utility/CompletionRequest.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/LLDBAssert.h" @@ -22,6 +24,7 @@ #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringList.h" #include "lldb/Utility/Timeout.h" +#include "lldb/lldb-forward.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" @@ -76,6 +79,19 @@ using namespace lldb_private::line_editor; #endif // #if LLDB_EDITLINE_USE_WCHAR +template class ScopedOptional { +public: + template + ScopedOptional(std::optional &optional, Args &&...args) + : m_optional(optional) { + m_optional.emplace(std::forward(args)...); + } + ~ScopedOptional() { m_optional.reset(); } + +private: + std::optional &m_optional; +}; + bool IsOnlySpaces(const EditLineStringType &content) { for (wchar_t ch : content) { if (ch != EditLineCharType(' ')) @@ -85,7 +101,8 @@ bool IsOnlySpaces(const EditLineStringType &content) { } static size_t ColumnWidth(llvm::StringRef str) { - return llvm::sys::locale::columnWidth(str); + std::string stripped = ansi::StripAnsiTerminalCodes(str); + return llvm::sys::locale::columnWidth(stripped); } static int GetOperation(HistoryOperation op) { @@ -387,11 +404,13 @@ void Editline::MoveCursor(CursorLocation from, CursorLocation to) { (int)((info->cursor - info->buffer) + GetPromptWidth()); int editline_cursor_row = editline_cursor_position / m_terminal_width; + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); + // Determine relative starting and ending lines int fromLine = GetLineIndexForLocation(from, editline_cursor_row); int toLine = GetLineIndexForLocation(to, editline_cursor_row); if (toLine != fromLine) { - fprintf(m_output_file, + fprintf(locked_stream.GetFile().GetStream(), (toLine > fromLine) ? ANSI_DOWN_N_ROWS : ANSI_UP_N_ROWS, std::abs(toLine - fromLine)); } @@ -407,21 +426,23 @@ void Editline::MoveCursor(CursorLocation from, CursorLocation to) { 80) + 1; } - fprintf(m_output_file, ANSI_SET_COLUMN_N, toColumn); + fprintf(locked_stream.GetFile().GetStream(), ANSI_SET_COLUMN_N, toColumn); } void Editline::DisplayInput(int firstIndex) { - fprintf(m_output_file, ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW, 1); + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); + fprintf(locked_stream.GetFile().GetStream(), + ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW, 1); int line_count = (int)m_input_lines.size(); for (int index = firstIndex; index < line_count; index++) { - fprintf(m_output_file, + fprintf(locked_stream.GetFile().GetStream(), "%s" "%s" "%s" EditLineStringFormatSpec " ", m_prompt_ansi_prefix.c_str(), PromptForIndex(index).c_str(), m_prompt_ansi_suffix.c_str(), m_input_lines[index].c_str()); if (index < line_count - 1) - fprintf(m_output_file, "\n"); + fprintf(locked_stream.GetFile().GetStream(), "\n"); } } @@ -533,8 +554,10 @@ int Editline::GetCharacter(EditLineGetCharType *c) { // Paint a ANSI formatted version of the desired prompt over the version // libedit draws. (will only be requested if colors are supported) if (m_needs_prompt_repaint) { + ScopedOptional scope(m_locked_output, + m_output_stream_sp->Lock()); MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt); - fprintf(m_output_file, + fprintf(m_locked_output->GetFile().GetStream(), "%s" "%s" "%s", @@ -572,10 +595,10 @@ int Editline::GetCharacter(EditLineGetCharType *c) { // indefinitely. This gives a chance for someone to interrupt us. After // Read returns, immediately lock the mutex again and check if we were // interrupted. - m_output_mutex.unlock(); + m_locked_output.reset(); int read_count = m_input_connection.Read(&ch, 1, std::nullopt, status, nullptr); - m_output_mutex.lock(); + m_locked_output.emplace(m_output_stream_sp->Lock()); if (m_editor_status == EditorStatus::Interrupted) { while (read_count > 0 && status == lldb::eConnectionStatusSuccess) read_count = @@ -610,7 +633,7 @@ int Editline::GetCharacter(EditLineGetCharType *c) { } const char *Editline::Prompt() { - if (!m_prompt_ansi_prefix.empty() || !m_prompt_ansi_suffix.empty()) + if (m_color) m_needs_prompt_repaint = true; return m_current_prompt.c_str(); } @@ -698,12 +721,14 @@ unsigned char Editline::EndOrAddLineCommand(int ch) { } } MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd); - fprintf(m_output_file, "\n"); + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); + fprintf(locked_stream.GetFile().GetStream(), "\n"); m_editor_status = EditorStatus::Complete; return CC_NEWLINE; } unsigned char Editline::DeleteNextCharCommand(int ch) { + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); LineInfoW *info = const_cast(el_wline(m_editline)); // Just delete the next character normally if possible @@ -717,7 +742,7 @@ unsigned char Editline::DeleteNextCharCommand(int ch) { // line is empty, in which case it is treated as EOF if (m_current_line_index == m_input_lines.size() - 1) { if (ch == 4 && info->buffer == info->lastchar) { - fprintf(m_output_file, "^D\n"); + fprintf(locked_stream.GetFile().GetStream(), "^D\n"); m_editor_status = EditorStatus::EndOfInput; return CC_EOF; } @@ -765,7 +790,8 @@ unsigned char Editline::DeletePreviousCharCommand(int ch) { priorLine + m_input_lines[m_current_line_index]; // Repaint from the new line down - fprintf(m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); + fprintf(locked_stream.GetFile().GetStream(), ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, CountRowsForLine(priorLine), 1); DisplayInput(m_current_line_index); @@ -783,17 +809,19 @@ unsigned char Editline::PreviousLineCommand(int ch) { return RecallHistory(HistoryOperation::Older); } + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); + // Start from a known location MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt); // Treat moving up from a blank last line as a deletion of that line if (m_current_line_index == m_input_lines.size() - 1 && IsOnlySpaces()) { m_input_lines.erase(m_input_lines.begin() + m_current_line_index); - fprintf(m_output_file, ANSI_CLEAR_BELOW); + fprintf(locked_stream.GetFile().GetStream(), ANSI_CLEAR_BELOW); } SetCurrentLine(m_current_line_index - 1); - fprintf(m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, + fprintf(locked_stream.GetFile().GetStream(), ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, CountRowsForLine(m_input_lines[m_current_line_index]), 1); return CC_NEWLINE; } @@ -827,9 +855,11 @@ unsigned char Editline::NextLineCommand(int ch) { const LineInfoW *info = el_wline(m_editline); int cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth()); int cursor_row = cursor_position / m_terminal_width; + + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); for (int line_count = 0; line_count < m_current_line_rows - cursor_row; line_count++) { - fprintf(m_output_file, "\n"); + fprintf(locked_stream.GetFile().GetStream(), "\n"); } return CC_NEWLINE; } @@ -1029,7 +1059,9 @@ void Editline::DisplayCompletions( Editline &editline, llvm::ArrayRef results) { assert(!results.empty()); - fprintf(editline.m_output_file, + LockedStreamFile locked_stream = editline.m_output_stream_sp->Lock(); + + fprintf(locked_stream.GetFile().GetStream(), "\n" ANSI_CLEAR_BELOW "Available completions:\n"); /// Account for the current line, the line showing "Available completions" @@ -1047,15 +1079,15 @@ void Editline::DisplayCompletions( size_t cur_pos = 0; while (cur_pos < results.size()) { - cur_pos += - PrintCompletion(editline.m_output_file, results.slice(cur_pos), max_len, - editline.GetTerminalWidth(), - all ? std::nullopt : std::optional(page_size)); + cur_pos += PrintCompletion( + locked_stream.GetFile().GetStream(), results.slice(cur_pos), max_len, + editline.GetTerminalWidth(), + all ? std::nullopt : std::optional(page_size)); if (cur_pos >= results.size()) break; - fprintf(editline.m_output_file, "More (Y/n/a): "); + fprintf(locked_stream.GetFile().GetStream(), "More (Y/n/a): "); // The type for the output and the type for the parameter are different, // to allow interoperability with older versions of libedit. The container // for the reply must be as wide as what our implementation is using, @@ -1067,11 +1099,11 @@ void Editline::DisplayCompletions( // Check for a ^C or other interruption. if (editline.m_editor_status == EditorStatus::Interrupted) { editline.m_editor_status = EditorStatus::Editing; - fprintf(editline.m_output_file, "^C\n"); + fprintf(locked_stream.GetFile().GetStream(), "^C\n"); break; } - fprintf(editline.m_output_file, "\n"); + fprintf(locked_stream.GetFile().GetStream(), "\n"); if (got_char == -1 || reply == 'n') break; if (reply == 'a') @@ -1180,17 +1212,18 @@ unsigned char Editline::TypedCharacter(int ch) { line_info->lastchar - line_info->buffer); if (std::optional to_add = m_suggestion_callback(line)) { + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); std::string to_add_color = m_suggestion_ansi_prefix + to_add.value() + m_suggestion_ansi_suffix; - fputs(typed.c_str(), m_output_file); - fputs(to_add_color.c_str(), m_output_file); + fputs(typed.c_str(), locked_stream.GetFile().GetStream()); + fputs(to_add_color.c_str(), locked_stream.GetFile().GetStream()); size_t new_autosuggestion_size = line.size() + to_add->length(); // Print spaces to hide any remains of a previous longer autosuggestion. if (new_autosuggestion_size < m_previous_autosuggestion_size) { size_t spaces_to_print = m_previous_autosuggestion_size - new_autosuggestion_size; std::string spaces = std::string(spaces_to_print, ' '); - fputs(spaces.c_str(), m_output_file); + fputs(spaces.c_str(), locked_stream.GetFile().GetStream()); } m_previous_autosuggestion_size = new_autosuggestion_size; @@ -1199,7 +1232,7 @@ unsigned char Editline::TypedCharacter(int ch) { int editline_cursor_row = editline_cursor_position / m_terminal_width; int toColumn = editline_cursor_position - (editline_cursor_row * m_terminal_width); - fprintf(m_output_file, ANSI_SET_COLUMN_N, toColumn); + fprintf(locked_stream.GetFile().GetStream(), ANSI_SET_COLUMN_N, toColumn); return CC_REFRESH; } @@ -1234,13 +1267,17 @@ void Editline::ConfigureEditor(bool multiline) { el_end(m_editline); } - m_editline = - el_init(m_editor_name.c_str(), m_input_file, m_output_file, m_error_file); + LockedStreamFile locked_output_stream = m_output_stream_sp->Lock(); + LockedStreamFile locked_error_stream = m_output_stream_sp->Lock(); + m_editline = el_init(m_editor_name.c_str(), m_input_file, + locked_output_stream.GetFile().GetStream(), + locked_error_stream.GetFile().GetStream()); ApplyTerminalSizeChange(); if (m_history_sp && m_history_sp->IsValid()) { if (!m_history_sp->Load()) { - fputs("Could not load history file\n.", m_output_file); + fputs("Could not load history file\n.", + locked_output_stream.GetFile().GetStream()); } el_wset(m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr()); } @@ -1471,12 +1508,12 @@ Editline *Editline::InstanceFor(EditLine *editline) { } Editline::Editline(const char *editline_name, FILE *input_file, - FILE *output_file, FILE *error_file, - std::recursive_mutex &output_mutex) + lldb::LockableStreamFileSP output_stream_sp, + lldb::LockableStreamFileSP error_stream_sp, bool color) : m_editor_status(EditorStatus::Complete), m_input_file(input_file), - m_output_file(output_file), m_error_file(error_file), - m_input_connection(fileno(input_file), false), - m_output_mutex(output_mutex) { + m_output_stream_sp(output_stream_sp), m_error_stream_sp(error_stream_sp), + m_input_connection(fileno(input_file), false), m_color(color) { + assert(output_stream_sp && error_stream_sp); // Get a shared history instance m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name; m_history_sp = EditlineHistory::GetHistory(m_editor_name); @@ -1550,9 +1587,9 @@ uint32_t Editline::GetCurrentLine() { return m_current_line_index; } bool Editline::Interrupt() { bool result = true; - std::lock_guard guard(m_output_mutex); + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); if (m_editor_status == EditorStatus::Editing) { - fprintf(m_output_file, "^C\n"); + fprintf(locked_stream.GetFile().GetStream(), "^C\n"); result = m_input_connection.InterruptRead(); } m_editor_status = EditorStatus::Interrupted; @@ -1561,10 +1598,10 @@ bool Editline::Interrupt() { bool Editline::Cancel() { bool result = true; - std::lock_guard guard(m_output_mutex); + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); if (m_editor_status == EditorStatus::Editing) { MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); - fprintf(m_output_file, ANSI_CLEAR_BELOW); + fprintf(locked_stream.GetFile().GetStream(), ANSI_CLEAR_BELOW); result = m_input_connection.InterruptRead(); } m_editor_status = EditorStatus::Interrupted; @@ -1576,7 +1613,8 @@ bool Editline::GetLine(std::string &line, bool &interrupted) { m_input_lines = std::vector(); m_input_lines.insert(m_input_lines.begin(), EditLineConstString("")); - std::lock_guard guard(m_output_mutex); + ScopedOptional scope(m_locked_output, + m_output_stream_sp->Lock()); lldbassert(m_editor_status != EditorStatus::Editing); if (m_editor_status == EditorStatus::Interrupted) { @@ -1596,7 +1634,7 @@ bool Editline::GetLine(std::string &line, bool &interrupted) { interrupted = m_editor_status == EditorStatus::Interrupted; if (!interrupted) { if (input == nullptr) { - fprintf(m_output_file, "\n"); + fprintf(m_locked_output->GetFile().GetStream(), "\n"); m_editor_status = EditorStatus::EndOfInput; } else { m_history_sp->Enter(input); @@ -1621,7 +1659,9 @@ bool Editline::GetLines(int first_line_number, StringList &lines, m_input_lines = std::vector(); m_input_lines.insert(m_input_lines.begin(), EditLineConstString("")); - std::lock_guard guard(m_output_mutex); + ScopedOptional scope(m_locked_output, + m_output_stream_sp->Lock()); + // Begin the line editing loop DisplayInput(); SetCurrentLine(0); @@ -1650,15 +1690,15 @@ bool Editline::GetLines(int first_line_number, StringList &lines, return m_editor_status != EditorStatus::EndOfInput; } -void Editline::PrintAsync(Stream *stream, const char *s, size_t len) { - std::lock_guard guard(m_output_mutex); +void Editline::PrintAsync(lldb::LockableStreamFileSP stream_sp, const char *s, + size_t len) { + LockedStreamFile locked_stream = m_output_stream_sp->Lock(); if (m_editor_status == EditorStatus::Editing) { SaveEditedLine(); MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); - fprintf(m_output_file, ANSI_CLEAR_BELOW); + fprintf(locked_stream.GetFile().GetStream(), ANSI_CLEAR_BELOW); } - stream->Write(s, len); - stream->Flush(); + locked_stream.Write(s, len); if (m_editor_status == EditorStatus::Editing) { DisplayInput(); MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor); diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index d7fe97077cb34..aaeff9c97fd0a 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -58,6 +58,7 @@ #include "lldb/Utility/Timer.h" #include "lldb/Host/Config.h" +#include "lldb/lldb-forward.h" #if LLDB_ENABLE_LIBEDIT #include "lldb/Host/Editline.h" #endif @@ -2849,13 +2850,13 @@ void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file, } if (flags & eHandleCommandFlagPrintResult) { - debugger.GetOutputFile().Printf("Executing commands in '%s'.\n", - cmd_file_path.c_str()); + debugger.GetOutputFileSP()->Printf("Executing commands in '%s'.\n", + cmd_file_path.c_str()); } // Used for inheriting the right settings when "command source" might // have nested "command source" commands - lldb::StreamFileSP empty_stream_sp; + lldb::LockableStreamFileSP empty_stream_sp; m_command_source_flags.push_back(flags); IOHandlerSP io_handler_sp(new IOHandlerEditline( debugger, IOHandler::Type::CommandInterpreter, input_file_sp, @@ -3112,25 +3113,26 @@ void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler, llvm::StringRef str, bool is_stdout) { - lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP() - : io_handler.GetErrorStreamFileSP(); + lldb::LockableStreamFileSP stream = is_stdout + ? io_handler.GetOutputStreamFileSP() + : io_handler.GetErrorStreamFileSP(); // Split the output into lines and poll for interrupt requests bool had_output = !str.empty(); while (!str.empty()) { llvm::StringRef line; std::tie(line, str) = str.split('\n'); { - std::lock_guard guard(io_handler.GetOutputMutex()); - stream->Write(line.data(), line.size()); - stream->Write("\n", 1); + LockedStreamFile stream_file = stream->Lock(); + stream_file.Write(line.data(), line.size()); + stream_file.Write("\n", 1); } } - std::lock_guard guard(io_handler.GetOutputMutex()); + LockedStreamFile stream_file = stream->Lock(); if (had_output && INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping command output")) - stream->Printf("\n... Interrupted.\n"); - stream->Flush(); + stream_file.Printf("\n... Interrupted.\n"); + stream_file.Flush(); } bool CommandInterpreter::EchoCommandNonInteractive( @@ -3172,9 +3174,9 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, // from a file) we need to echo the command out so we don't just see the // command output and no command... if (EchoCommandNonInteractive(line, io_handler.GetFlags())) { - std::lock_guard guard(io_handler.GetOutputMutex()); - io_handler.GetOutputStreamFileSP()->Printf( - "%s%s\n", io_handler.GetPrompt(), line.c_str()); + LockedStreamFile locked_stream = + io_handler.GetOutputStreamFileSP()->Lock(); + locked_stream.Printf("%s%s\n", io_handler.GetPrompt(), line.c_str()); } } diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp index 8b55221da6e76..1c0c97d876a9f 100644 --- a/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -200,7 +200,8 @@ ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger, ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( std::unique_ptr input, std::unique_ptr output) : m_input_file_sp(std::move(input)), - m_output_file_sp(std::make_shared(std::move(output))), + m_output_file_sp(std::make_shared(std::move(output), + m_output_mutex)), m_error_file_sp(m_output_file_sp), m_communication("lldb.ScriptInterpreterIORedirect.comm"), m_disconnect(false) {} @@ -234,13 +235,15 @@ ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( m_disconnect = true; FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w"); - m_output_file_sp = std::make_shared(outfile_handle, true); + m_output_file_sp = std::make_shared( + std::make_shared(outfile_handle, NativeFile::Owned), + m_output_mutex); m_error_file_sp = m_output_file_sp; if (outfile_handle) ::setbuf(outfile_handle, nullptr); - result->SetImmediateOutputFile(debugger.GetOutputStream().GetFileSP()); - result->SetImmediateErrorFile(debugger.GetErrorStream().GetFileSP()); + result->SetImmediateOutputFile(debugger.GetOutputFileSP()); + result->SetImmediateErrorFile(debugger.GetErrorFileSP()); } } @@ -251,9 +254,9 @@ ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( void ScriptInterpreterIORedirect::Flush() { if (m_output_file_sp) - m_output_file_sp->Flush(); + m_output_file_sp->Lock().Flush(); if (m_error_file_sp) - m_error_file_sp->Flush(); + m_error_file_sp->Lock().Flush(); } ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() { @@ -267,7 +270,7 @@ ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() { // Close the write end of the pipe since we are done with our one line // script. This should cause the read thread that output_comm is using to // exit. - m_output_file_sp->GetFile().Close(); + m_output_file_sp->GetUnlockedFile().Close(); // The close above should cause this thread to exit when it gets to the end // of file, so let it get all its data. m_communication.JoinReadThread(); diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index ab013e79047ea..97f69786e7a76 100644 --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -736,9 +736,9 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( } if (IsKernel() && m_uuid.IsValid()) { - Stream &s = target.GetDebugger().GetOutputStream(); - s.Printf("Kernel UUID: %s\n", m_uuid.GetAsString().c_str()); - s.Printf("Load Address: 0x%" PRIx64 "\n", m_load_address); + lldb::StreamUP s = target.GetDebugger().GetAsyncOutputStream(); + s->Printf("Kernel UUID: %s\n", m_uuid.GetAsString().c_str()); + s->Printf("Load Address: 0x%" PRIx64 "\n", m_load_address); // Start of a kernel debug session, we have the UUID of the kernel. // Go through the target's list of modules and if there are any kernel @@ -828,12 +828,12 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( } if (IsKernel() && !m_module_sp) { - Stream &s = target.GetDebugger().GetErrorStream(); - s.Printf("WARNING: Unable to locate kernel binary on the debugger " - "system.\n"); + lldb::StreamUP s = target.GetDebugger().GetAsyncErrorStream(); + s->Printf("WARNING: Unable to locate kernel binary on the debugger " + "system.\n"); if (kernel_search_error.Fail() && kernel_search_error.AsCString("") && kernel_search_error.AsCString("")[0] != '\0') { - s << kernel_search_error.AsCString(); + *s << kernel_search_error.AsCString(); } } } @@ -972,22 +972,19 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( bool is_loaded = IsLoaded(); if (is_loaded && m_module_sp && IsKernel()) { - Stream &s = target.GetDebugger().GetOutputStream(); + lldb::StreamUP s = target.GetDebugger().GetAsyncOutputStream(); ObjectFile *kernel_object_file = m_module_sp->GetObjectFile(); if (kernel_object_file) { addr_t file_address = kernel_object_file->GetBaseAddress().GetFileAddress(); if (m_load_address != LLDB_INVALID_ADDRESS && file_address != LLDB_INVALID_ADDRESS) { - s.Printf("Kernel slid 0x%" PRIx64 " in memory.\n", - m_load_address - file_address); + s->Printf("Kernel slid 0x%" PRIx64 " in memory.\n", + m_load_address - file_address); } } - { - s.Printf("Loaded kernel file %s\n", - m_module_sp->GetFileSpec().GetPath().c_str()); - } - s.Flush(); + s->Printf("Loaded kernel file %s\n", + m_module_sp->GetFileSpec().GetPath().c_str()); } // Notify the target about the module being added; @@ -1193,10 +1190,11 @@ bool DynamicLoaderDarwinKernel::ReadKextSummaryHeader() { lldb::offset_t offset = 0; m_kext_summary_header.version = data.GetU32(&offset); if (m_kext_summary_header.version > 128) { - Stream &s = m_process->GetTarget().GetDebugger().GetOutputStream(); - s.Printf("WARNING: Unable to read kext summary header, got " - "improbable version number %u\n", - m_kext_summary_header.version); + lldb::StreamSP s = + m_process->GetTarget().GetDebugger().GetAsyncOutputStream(); + s->Printf("WARNING: Unable to read kext summary header, got " + "improbable version number %u\n", + m_kext_summary_header.version); // If we get an improbably large version number, we're probably // getting bad memory. m_kext_summary_header_addr.Clear(); @@ -1207,11 +1205,11 @@ bool DynamicLoaderDarwinKernel::ReadKextSummaryHeader() { if (m_kext_summary_header.entry_size > 4096) { // If we get an improbably large entry_size, we're probably // getting bad memory. - Stream &s = - m_process->GetTarget().GetDebugger().GetOutputStream(); - s.Printf("WARNING: Unable to read kext summary header, got " - "improbable entry_size %u\n", - m_kext_summary_header.entry_size); + lldb::StreamSP s = + m_process->GetTarget().GetDebugger().GetAsyncOutputStream(); + s->Printf("WARNING: Unable to read kext summary header, got " + "improbable entry_size %u\n", + m_kext_summary_header.entry_size); m_kext_summary_header_addr.Clear(); return false; } @@ -1225,10 +1223,11 @@ bool DynamicLoaderDarwinKernel::ReadKextSummaryHeader() { if (m_kext_summary_header.entry_count > 10000) { // If we get an improbably large number of kexts, we're probably // getting bad memory. - Stream &s = m_process->GetTarget().GetDebugger().GetOutputStream(); - s.Printf("WARNING: Unable to read kext summary header, got " - "improbable number of kexts %u\n", - m_kext_summary_header.entry_count); + lldb::StreamSP s = + m_process->GetTarget().GetDebugger().GetAsyncOutputStream(); + s->Printf("WARNING: Unable to read kext summary header, got " + "improbable number of kexts %u\n", + m_kext_summary_header.entry_count); m_kext_summary_header_addr.Clear(); return false; } @@ -1329,17 +1328,19 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries( number_of_old_kexts_being_removed == 0) return true; - Stream &s = m_process->GetTarget().GetDebugger().GetOutputStream(); + lldb::StreamSP s = + m_process->GetTarget().GetDebugger().GetAsyncOutputStream(); if (load_kexts) { if (number_of_new_kexts_being_added > 0 && number_of_old_kexts_being_removed > 0) { - s.Printf("Loading %d kext modules and unloading %d kext modules ", - number_of_new_kexts_being_added, - number_of_old_kexts_being_removed); + s->Printf("Loading %d kext modules and unloading %d kext modules ", + number_of_new_kexts_being_added, + number_of_old_kexts_being_removed); } else if (number_of_new_kexts_being_added > 0) { - s.Printf("Loading %d kext modules ", number_of_new_kexts_being_added); + s->Printf("Loading %d kext modules ", number_of_new_kexts_being_added); } else if (number_of_old_kexts_being_removed > 0) { - s.Printf("Unloading %d kext modules ", number_of_old_kexts_being_removed); + s->Printf("Unloading %d kext modules ", + number_of_old_kexts_being_removed); } } @@ -1403,7 +1404,7 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries( if (image_info.GetModule()) { unloaded_module_list.AppendIfNeeded(image_info.GetModule()); } - s.Printf("."); + s->Printf("."); image_info.Clear(); // should pull it out of the KextImageInfos vector but that would // mutate the list and invalidate the to_be_removed bool vector; @@ -1415,11 +1416,11 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries( } if (load_kexts) { - s.Printf(" done.\n"); + s->Printf(" done.\n"); if (kexts_failed_to_load.size() > 0 && number_of_new_kexts_being_added > 0) { - s.Printf("Failed to load %d of %d kexts:\n", - (int)kexts_failed_to_load.size(), - number_of_new_kexts_being_added); + s->Printf("Failed to load %d of %d kexts:\n", + (int)kexts_failed_to_load.size(), + number_of_new_kexts_being_added); // print a sorted list of kexts which failed to load unsigned longest_name = 0; std::sort(kexts_failed_to_load.begin(), kexts_failed_to_load.end()); @@ -1431,10 +1432,9 @@ bool DynamicLoaderDarwinKernel::ParseKextSummaries( std::string uuid; if (ku.second.IsValid()) uuid = ku.second.GetAsString(); - s.Printf(" %-*s %s\n", longest_name, ku.first.c_str(), uuid.c_str()); + s->Printf(" %-*s %s\n", longest_name, ku.first.c_str(), uuid.c_str()); } } - s.Flush(); } return true; diff --git a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp index 7c678faaae7fd..40c871c3f393b 100644 --- a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp @@ -327,9 +327,9 @@ bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingMemoryModule( Target &target = process->GetTarget(); if (IsKernel() && m_uuid.IsValid()) { - Stream &s = target.GetDebugger().GetOutputStream(); - s.Printf("Kernel UUID: %s\n", m_uuid.GetAsString().c_str()); - s.Printf("Load Address: 0x%" PRIx64 "\n", m_load_address); + lldb::StreamUP s = target.GetDebugger().GetAsyncOutputStream(); + s->Printf("Kernel UUID: %s\n", m_uuid.GetAsString().c_str()); + s->Printf("Load Address: 0x%" PRIx64 "\n", m_load_address); } // Test if the module is loaded into the taget, @@ -355,9 +355,9 @@ bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingMemoryModule( if (!m_module_sp) m_module_sp = target.GetOrCreateModule(module_spec, true); if (IsKernel() && !m_module_sp) { - Stream &s = target.GetDebugger().GetOutputStream(); - s.Printf("WARNING: Unable to locate kernel binary on the debugger " - "system.\n"); + target.GetDebugger().GetAsyncOutputStream()->Printf( + "WARNING: Unable to locate kernel binary on the debugger " + "system.\n"); } } @@ -464,20 +464,19 @@ bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingMemoryModule( } if (IsLoaded() && m_module_sp && IsKernel()) { - Stream &s = target.GetDebugger().GetOutputStream(); + lldb::StreamUP s = target.GetDebugger().GetAsyncOutputStream(); ObjectFile *kernel_object_file = m_module_sp->GetObjectFile(); if (kernel_object_file) { addr_t file_address = kernel_object_file->GetBaseAddress().GetFileAddress(); if (m_load_address != LLDB_INVALID_ADDRESS && file_address != LLDB_INVALID_ADDRESS) { - s.Printf("Kernel slide 0x%" PRIx64 " in memory.\n", - m_load_address - file_address); - s.Printf("Loaded kernel file %s\n", - m_module_sp->GetFileSpec().GetPath().c_str()); + s->Printf("Kernel slide 0x%" PRIx64 " in memory.\n", + m_load_address - file_address); + s->Printf("Loaded kernel file %s\n", + m_module_sp->GetFileSpec().GetPath().c_str()); } } - s.Flush(); } return IsLoaded(); diff --git a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp index 72ece72aa6f98..f034d6e2dd3ab 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp @@ -895,13 +895,14 @@ bool InstrumentationRuntimeTSan::NotifyBreakpointHit( CreateStopReasonWithInstrumentationData( *thread_sp, stop_reason_description, report)); - StreamFile &s = process_sp->GetTarget().GetDebugger().GetOutputStream(); - s.Printf("ThreadSanitizer report breakpoint hit. Use 'thread " - "info -s' to get extended information about the " - "report.\n"); + lldb::StreamSP s = + process_sp->GetTarget().GetDebugger().GetAsyncOutputStream(); + s->Printf("ThreadSanitizer report breakpoint hit. Use 'thread " + "info -s' to get extended information about the " + "report.\n"); return true; // Return true to stop the target - } else + } return false; // Let target run } diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp index 8c2700cf21de9..c2db3540a797b 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp @@ -116,8 +116,6 @@ StructuredData::ObjectSP InstrumentationRuntimeUBSan::RetrieveReportData( if (!frame_sp) return StructuredData::ObjectSP(); - StreamFileSP Stream = target.GetDebugger().GetOutputStreamSP(); - EvaluateExpressionOptions options; options.SetUnwindOnError(true); options.SetTryAllThreads(true); diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp index 00761327a694b..3cd4630728a6f 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp @@ -217,8 +217,8 @@ bool ReportRetriever::NotifyBreakpointHit(ProcessSP process_sp, InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData( *thread_sp, description, report)); - if (StreamFileSP stream_sp = StreamFileSP( - process_sp->GetTarget().GetDebugger().GetOutputStreamSP())) + if (StreamSP stream_sp = + process_sp->GetTarget().GetDebugger().GetAsyncOutputStream()) stream_sp->Printf("AddressSanitizer report breakpoint hit. Use 'thread " "info -s' to get extended information about the " "report.\n"); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index 2b8adeae10d14..7774eb843c62d 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -622,14 +622,14 @@ AppleObjCTrampolineHandler::AppleObjCTrampolineHandler( // step through any method dispatches. Warn to that effect and get out of // here. if (process_sp->CanJIT()) { - process_sp->GetTarget().GetDebugger().GetErrorStream().Printf( + process_sp->GetTarget().GetDebugger().GetAsyncErrorStream()->Printf( "Could not find implementation lookup function \"%s\"" " step in through ObjC method dispatch will not work.\n", get_impl_name.AsCString()); } return; } - + // We will either set the implementation to the _stret or non_stret version, // so either way it's safe to start filling the m_lookup_..._code here. m_lookup_implementation_function_code.assign( diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp index 9b2907c680996..406e1d45dc39a 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -321,20 +321,10 @@ Status ProcessKDP::DoConnectRemote(llvm::StringRef remote_url) { SetID(1); GetThreadList(); SetPrivateState(eStateStopped); - StreamSP async_strm_sp(target.GetDebugger().GetAsyncOutputStream()); - if (async_strm_sp) { - const char *cstr; - if ((cstr = m_comm.GetKernelVersion()) != NULL) { - async_strm_sp->Printf("Version: %s\n", cstr); - async_strm_sp->Flush(); - } - // if ((cstr = m_comm.GetImagePath ()) != NULL) - // { - // async_strm_sp->Printf ("Image Path: - // %s\n", cstr); - // async_strm_sp->Flush(); - // } - } + const char *cstr; + if ((cstr = m_comm.GetKernelVersion()) != NULL) + target.GetDebugger().GetAsyncOutputStream()->Printf("Version: %s\n", + cstr); } else { return Status::FromErrorString("KDP_REATTACH failed"); } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 49a3935d47f18..ba0384be51c70 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -5468,8 +5468,7 @@ class CommandObjectProcessGDBRemoteSpeedTest : public CommandObjectParsed { if (process) { StreamSP output_stream_sp = result.GetImmediateOutputStream(); if (!output_stream_sp) - output_stream_sp = - StreamSP(m_interpreter.GetDebugger().GetAsyncOutputStream()); + output_stream_sp = m_interpreter.GetDebugger().GetAsyncOutputStream(); result.SetImmediateOutputStream(output_stream_sp); const uint32_t num_packets = diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp index ea74a500518e3..d4df74ad98b6a 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp @@ -17,6 +17,7 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/StringList.h" #include "lldb/Utility/Timer.h" +#include "lldb/lldb-forward.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FormatAdapters.h" #include @@ -45,8 +46,8 @@ class IOHandlerLuaInterpreter : public IOHandlerDelegate, m_script_interpreter(script_interpreter), m_active_io_handler(active_io_handler) { llvm::cantFail(m_script_interpreter.GetLua().ChangeIO( - debugger.GetOutputFile().GetStream(), - debugger.GetErrorFile().GetStream())); + debugger.GetOutputFileSP()->GetStream(), + debugger.GetErrorFileSP()->GetStream())); llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID())); } @@ -76,8 +77,13 @@ class IOHandlerLuaInterpreter : public IOHandlerDelegate, } if (instructions == nullptr) return; - if (interactive) - *io_handler.GetOutputStreamFileSP() << instructions; + if (interactive) { + if (lldb::LockableStreamFileSP output_sp = + io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = output_sp->Lock(); + locked_stream << instructions; + } + } } bool IOHandlerIsInputComplete(IOHandler &io_handler, @@ -112,8 +118,11 @@ class IOHandlerLuaInterpreter : public IOHandlerDelegate, for (BreakpointOptions &bp_options : *bp_options_vec) { Status error = m_script_interpreter.SetBreakpointCommandCallback( bp_options, data.c_str(), /*is_callback=*/false); - if (error.Fail()) - *io_handler.GetErrorStreamFileSP() << error.AsCString() << '\n'; + if (error.Fail()) { + LockedStreamFile locked_stream = + io_handler.GetErrorStreamFileSP()->Lock(); + locked_stream << error.AsCString() << '\n'; + } } io_handler.SetIsDone(true); } break; @@ -130,8 +139,11 @@ class IOHandlerLuaInterpreter : public IOHandlerDelegate, io_handler.SetIsDone(true); return; } - if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) - *io_handler.GetErrorStreamFileSP() << toString(std::move(error)); + if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) { + LockedStreamFile locked_stream = + io_handler.GetErrorStreamFileSP()->Lock(); + locked_stream << toString(std::move(error)); + } break; } } @@ -289,7 +301,7 @@ bool ScriptInterpreterLua::BreakpointCallbackFunction( llvm::Expected BoolOrErr = lua.CallBreakpointCallback( baton, stop_frame_sp, bp_loc_sp, bp_option_data->m_extra_args_sp); if (llvm::Error E = BoolOrErr.takeError()) { - debugger.GetErrorStream() << toString(std::move(E)); + *debugger.GetAsyncErrorStream() << toString(std::move(E)); return true; } @@ -316,7 +328,7 @@ bool ScriptInterpreterLua::WatchpointCallbackFunction( llvm::Expected BoolOrErr = lua.CallWatchpointCallback(baton, stop_frame_sp, wp_sp); if (llvm::Error E = BoolOrErr.takeError()) { - debugger.GetErrorStream() << toString(std::move(E)); + *debugger.GetAsyncErrorStream() << toString(std::move(E)); return true; } diff --git a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp index 7aeee6e403954..d0c3df05e6320 100644 --- a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp @@ -33,12 +33,12 @@ static const char *no_interpreter_err_msg = bool ScriptInterpreterNone::ExecuteOneLine(llvm::StringRef command, CommandReturnObject *, const ExecuteScriptOptions &) { - m_debugger.GetErrorStream().PutCString(no_interpreter_err_msg); + m_debugger.GetAsyncErrorStream()->PutCString(no_interpreter_err_msg); return false; } void ScriptInterpreterNone::ExecuteInterpreterLoop() { - m_debugger.GetErrorStream().PutCString(no_interpreter_err_msg); + m_debugger.GetAsyncErrorStream()->PutCString(no_interpreter_err_msg); } void ScriptInterpreterNone::Initialize() { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 88c90262c9b86..4b4fedc7507f3 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" -#include "lldb/lldb-enumerations.h" #if LLDB_ENABLE_PYTHON @@ -33,6 +32,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/Pipe.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Target/Thread.h" @@ -41,6 +41,8 @@ #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Timer.h" #include "lldb/ValueObject/ValueObject.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -505,11 +507,11 @@ def function (frame, bp_loc, internal_dict): break; } - if (instructions) { - StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); - if (output_sp && interactive) { - output_sp->PutCString(instructions); - output_sp->Flush(); + if (instructions && interactive) { + if (LockableStreamFileSP stream_sp = io_handler.GetOutputStreamFileSP()) { + LockedStreamFile locked_stream = stream_sp->Lock(); + locked_stream.PutCString(instructions); + locked_stream.Flush(); } } } @@ -543,10 +545,9 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, bp_options.SetCallback( ScriptInterpreterPythonImpl::BreakpointCallbackFunction, baton_sp); } else if (!batch_mode) { - StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); - if (error_sp) { - error_sp->Printf("Warning: No command attached to breakpoint.\n"); - error_sp->Flush(); + if (LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP()) { + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("Warning: No command attached to breakpoint.\n"); } } } @@ -566,10 +567,9 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, wp_options->SetCallback( ScriptInterpreterPythonImpl::WatchpointCallbackFunction, baton_sp); } else if (!batch_mode) { - StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); - if (error_sp) { - error_sp->Printf("Warning: No command attached to breakpoint.\n"); - error_sp->Flush(); + if (LockableStreamFileSP error_sp = io_handler.GetErrorStreamFileSP()) { + LockedStreamFile locked_stream = error_sp->Lock(); + locked_stream.Printf("Warning: No command attached to breakpoint.\n"); } } m_active_io_handler = eIOHandlerNone; @@ -696,7 +696,7 @@ bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags, PythonDictionary &sys_module_dict = GetSysModuleDictionary(); if (sys_module_dict.IsValid()) { lldb::FileSP top_in_sp; - lldb::StreamFileSP top_out_sp, top_err_sp; + lldb::LockableStreamFileSP top_out_sp, top_err_sp; if (!in_sp || !out_sp || !err_sp || !*in_sp || !*out_sp || !*err_sp) m_debugger.AdoptTopIOHandlerFilesIfInvalid(top_in_sp, top_out_sp, top_err_sp); @@ -712,12 +712,14 @@ bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags, if (!SetStdHandle(out_sp, "stdout", m_saved_stdout, "w")) { if (top_out_sp) - SetStdHandle(top_out_sp->GetFileSP(), "stdout", m_saved_stdout, "w"); + SetStdHandle(top_out_sp->GetUnlockedFileSP(), "stdout", m_saved_stdout, + "w"); } if (!SetStdHandle(err_sp, "stderr", m_saved_stderr, "w")) { if (top_err_sp) - SetStdHandle(top_err_sp->GetFileSP(), "stderr", m_saved_stderr, "w"); + SetStdHandle(top_err_sp->GetUnlockedFileSP(), "stderr", m_saved_stderr, + "w"); } } @@ -1976,10 +1978,10 @@ bool ScriptInterpreterPythonImpl::BreakpointCallbackFunction( llvm::handleAllErrors( maybe_ret_val.takeError(), [&](PythonException &E) { - debugger.GetErrorStream() << E.ReadBacktrace(); + *debugger.GetAsyncErrorStream() << E.ReadBacktrace(); }, [&](const llvm::ErrorInfoBase &E) { - debugger.GetErrorStream() << E.message(); + *debugger.GetAsyncErrorStream() << E.message(); }); } else { diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 1633d873b10b5..2942d2babd2fe 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -1810,7 +1810,7 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &constituent, Address symbol_address = symbol->GetAddress(); load_addr = ResolveIndirectFunction(&symbol_address, error); if (!error.Success() && show_error) { - GetTarget().GetDebugger().GetErrorStream().Printf( + GetTarget().GetDebugger().GetAsyncErrorStream()->Printf( "warning: failed to resolve indirect function at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", symbol->GetLoadAddress(&GetTarget()), @@ -1849,7 +1849,7 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &constituent, } else { if (show_error || use_hardware) { // Report error for setting breakpoint... - GetTarget().GetDebugger().GetErrorStream().Printf( + GetTarget().GetDebugger().GetAsyncErrorStream()->Printf( "warning: failed to set breakpoint site at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", load_addr, constituent->GetBreakpoint().GetID(), @@ -2888,10 +2888,9 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, // Now that we know the process type, update its signal responses from the // ones stored in the Target: - if (m_unix_signals_sp) { - StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream(); - GetTarget().UpdateSignalsFromDummy(m_unix_signals_sp, warning_strm); - } + if (m_unix_signals_sp) + GetTarget().UpdateSignalsFromDummy( + m_unix_signals_sp, GetTarget().GetDebugger().GetAsyncErrorStream()); DynamicLoader *dyld = GetDynamicLoader(); if (dyld) @@ -3276,10 +3275,9 @@ void Process::CompleteAttach() { } // Now that we know the process type, update its signal responses from the // ones stored in the Target: - if (m_unix_signals_sp) { - StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream(); - GetTarget().UpdateSignalsFromDummy(m_unix_signals_sp, warning_strm); - } + if (m_unix_signals_sp) + GetTarget().UpdateSignalsFromDummy( + m_unix_signals_sp, GetTarget().GetDebugger().GetAsyncErrorStream()); // We have completed the attach, now it is time to find the dynamic loader // plug-in diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index d12d1c8bced3e..bd086550f4d82 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -1016,11 +1016,9 @@ class StopInfoWatchpoint : public StopInfo { wp_sp->CaptureWatchedValue(exe_ctx); Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); - StreamSP output_sp = debugger.GetAsyncOutputStream(); - if (wp_sp->DumpSnapshots(output_sp.get())) { - output_sp->EOL(); - output_sp->Flush(); - } + StreamUP output_up = debugger.GetAsyncOutputStream(); + if (wp_sp->DumpSnapshots(output_up.get())) + output_up->EOL(); } } else { diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index a596e1176ce7f..6d4a2ec68ba11 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -1475,15 +1475,15 @@ static void LoadScriptingResourceForModule(const ModuleSP &module_sp, if (module_sp && !module_sp->LoadScriptingResourceInTarget(target, error, feedback_stream)) { if (error.AsCString()) - target->GetDebugger().GetErrorStream().Printf( + target->GetDebugger().GetAsyncErrorStream()->Printf( "unable to load scripting data for module %s - error reported was " "%s\n", module_sp->GetFileSpec().GetFileNameStrippingExtension().GetCString(), error.AsCString()); } if (feedback_stream.GetSize()) - target->GetDebugger().GetErrorStream().Printf("%s\n", - feedback_stream.GetData()); + target->GetDebugger().GetAsyncErrorStream()->Printf( + "%s\n", feedback_stream.GetData()); } void Target::ClearModules(bool delete_locations) { diff --git a/lldb/source/Target/ThreadPlanTracer.cpp b/lldb/source/Target/ThreadPlanTracer.cpp index ff9f49c6d4bb6..9f661b3c59478 100644 --- a/lldb/source/Target/ThreadPlanTracer.cpp +++ b/lldb/source/Target/ThreadPlanTracer.cpp @@ -27,6 +27,7 @@ #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/State.h" +#include "lldb/lldb-forward.h" using namespace lldb; using namespace lldb_private; @@ -41,13 +42,13 @@ ThreadPlanTracer::ThreadPlanTracer(Thread &thread) : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), m_enabled(false), m_stream_sp(), m_thread(nullptr) {} -Stream *ThreadPlanTracer::GetLogStream() { +StreamSP ThreadPlanTracer::GetLogStreamSP() { if (m_stream_sp) - return m_stream_sp.get(); + return m_stream_sp; else { TargetSP target_sp(GetThread().CalculateTarget()); if (target_sp) - return &(target_sp->GetDebugger().GetOutputStream()); + return target_sp->GetDebugger().GetAsyncOutputStream(); } return nullptr; } @@ -65,12 +66,11 @@ void ThreadPlanTracer::Log() { bool show_frame_index = false; bool show_fullpaths = false; - Stream *stream = GetLogStream(); - if (stream) { - GetThread().GetStackFrameAtIndex(0)->Dump(stream, show_frame_index, + if (StreamSP stream_sp = GetLogStreamSP()) { + GetThread().GetStackFrameAtIndex(0)->Dump(stream_sp.get(), show_frame_index, show_fullpaths); - stream->Printf("\n"); - stream->Flush(); + stream_sp->Printf("\n"); + stream_sp->Flush(); } } @@ -129,9 +129,9 @@ void ThreadPlanAssemblyTracer::TracingStarted() { void ThreadPlanAssemblyTracer::TracingEnded() { m_register_values.clear(); } void ThreadPlanAssemblyTracer::Log() { - Stream *stream = GetLogStream(); + StreamSP stream_sp = GetLogStreamSP(); - if (!stream) + if (!stream_sp) return; RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); @@ -143,9 +143,10 @@ void ThreadPlanAssemblyTracer::Log() { addr_valid = m_process.GetTarget().GetSectionLoadList().ResolveLoadAddress( pc, pc_addr); - pc_addr.Dump(stream, &GetThread(), Address::DumpStyleResolvedDescription, + pc_addr.Dump(stream_sp.get(), &GetThread(), + Address::DumpStyleResolvedDescription, Address::DumpStyleModuleWithFileAddress); - stream->PutCString(" "); + stream_sp->PutCString(" "); Disassembler *disassembler = GetDisassembler(); if (disassembler) { @@ -176,7 +177,7 @@ void ThreadPlanAssemblyTracer::Log() { instruction_list.GetInstructionAtIndex(0).get(); const FormatEntity::Entry *disassemble_format = m_process.GetTarget().GetDebugger().GetDisassemblyFormat(); - instruction->Dump(stream, max_opcode_byte_size, show_address, + instruction->Dump(stream_sp.get(), max_opcode_byte_size, show_address, show_bytes, show_control_flow_kind, nullptr, nullptr, nullptr, disassemble_format, 0); } @@ -199,12 +200,12 @@ void ThreadPlanAssemblyTracer::Log() { if (abi->GetArgumentValues(GetThread(), value_list)) { for (int arg_index = 0; arg_index < num_args; ++arg_index) { - stream->Printf( + stream_sp->Printf( "\n\targ[%d]=%llx", arg_index, value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong()); if (arg_index + 1 < num_args) - stream->PutCString(", "); + stream_sp->PutCString(", "); } } } @@ -223,14 +224,14 @@ void ThreadPlanAssemblyTracer::Log() { if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid || reg_value != m_register_values[reg_num]) { if (reg_value.GetType() != RegisterValue::eTypeInvalid) { - stream->PutCString("\n\t"); - DumpRegisterValue(reg_value, *stream, *reg_info, true, false, + stream_sp->PutCString("\n\t"); + DumpRegisterValue(reg_value, *stream_sp, *reg_info, true, false, eFormatDefault); } } m_register_values[reg_num] = reg_value; } } - stream->EOL(); - stream->Flush(); + stream_sp->EOL(); + stream_sp->Flush(); } diff --git a/lldb/test/API/terminal/TestEditline.py b/lldb/test/API/terminal/TestEditline.py index aa7d827e59944..ddaa441d5f7c1 100644 --- a/lldb/test/API/terminal/TestEditline.py +++ b/lldb/test/API/terminal/TestEditline.py @@ -2,7 +2,6 @@ Test that the lldb editline handling is configured correctly. """ - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * @@ -69,6 +68,22 @@ def test_prompt_color(self): # Column: 1....6.8 self.child.expect(re.escape("\x1b[31m(lldb) \x1b[0m\x1b[8G")) + @skipIfAsan + @skipIfEditlineSupportMissing + def test_prompt_format_color(self): + """Test that we can change the prompt color with a format string.""" + self.launch(use_colors=True) + # Clear the prefix and suffix setting to simplify the output. + self.expect('settings set prompt-ansi-prefix ""') + self.expect('settings set prompt-ansi-suffix ""') + self.expect('settings set prompt "${ansi.fg.red}(lldb) ${ansi.normal}"') + self.child.send("foo") + # Make sure this change is reflected immediately. Check that the color + # is set (31) and the cursor position (8) is correct. + # Prompt: (lldb) _ + # Column: 1....6.8 + self.child.expect(re.escape("\x1b[31m(lldb) \x1b[0m\x1b[8Gfoo")) + @skipIfAsan @skipIfEditlineSupportMissing def test_prompt_no_color(self): diff --git a/lldb/unittests/Editline/EditlineTest.cpp b/lldb/unittests/Editline/EditlineTest.cpp index 333ad77a0a16f..6c5a0c907a33e 100644 --- a/lldb/unittests/Editline/EditlineTest.cpp +++ b/lldb/unittests/Editline/EditlineTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" +#include "lldb/Host/File.h" #if LLDB_ENABLE_LIBEDIT @@ -25,6 +26,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/Pipe.h" #include "lldb/Host/PseudoTerminal.h" +#include "lldb/Host/StreamFile.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StringList.h" @@ -115,10 +117,17 @@ EditlineAdapter::EditlineAdapter() if (*_el_secondary_file == nullptr) return; + lldb::LockableStreamFileSP output_stream_sp = + std::make_shared(*_el_secondary_file, + NativeFile::Unowned, output_mutex); + lldb::LockableStreamFileSP error_stream_sp = + std::make_shared(*_el_secondary_file, + NativeFile::Unowned, output_mutex); + // Create an Editline instance. _editline_sp.reset(new lldb_private::Editline( - "gtest editor", *_el_secondary_file, *_el_secondary_file, - *_el_secondary_file, output_mutex)); + "gtest editor", *_el_secondary_file, output_stream_sp, error_stream_sp, + /*color=*/false)); _editline_sp->SetPrompt("> "); // Hookup our input complete callback. diff --git a/lldb/unittests/Utility/AnsiTerminalTest.cpp b/lldb/unittests/Utility/AnsiTerminalTest.cpp index a6dbfd6106142..1ba9565c3f6af 100644 --- a/lldb/unittests/Utility/AnsiTerminalTest.cpp +++ b/lldb/unittests/Utility/AnsiTerminalTest.cpp @@ -16,16 +16,21 @@ TEST(AnsiTerminal, Empty) { EXPECT_EQ("", ansi::FormatAnsiTerminalCodes("")); } TEST(AnsiTerminal, WhiteSpace) { EXPECT_EQ(" ", ansi::FormatAnsiTerminalCodes(" ")); + EXPECT_EQ(" ", ansi::StripAnsiTerminalCodes(" ")); } TEST(AnsiTerminal, AtEnd) { EXPECT_EQ("abc\x1B[30m", ansi::FormatAnsiTerminalCodes("abc${ansi.fg.black}")); + + EXPECT_EQ("abc", ansi::StripAnsiTerminalCodes("abc\x1B[30m")); } TEST(AnsiTerminal, AtStart) { EXPECT_EQ("\x1B[30mabc", ansi::FormatAnsiTerminalCodes("${ansi.fg.black}abc")); + + EXPECT_EQ("abc", ansi::StripAnsiTerminalCodes("\x1B[30mabc")); } TEST(AnsiTerminal, KnownPrefix) { @@ -45,10 +50,20 @@ TEST(AnsiTerminal, Incomplete) { TEST(AnsiTerminal, Twice) { EXPECT_EQ("\x1B[30m\x1B[31mabc", ansi::FormatAnsiTerminalCodes("${ansi.fg.black}${ansi.fg.red}abc")); + + EXPECT_EQ("abc", ansi::StripAnsiTerminalCodes("\x1B[30m\x1B[31mabc")); } TEST(AnsiTerminal, Basic) { EXPECT_EQ( "abc\x1B[31mabc\x1B[0mabc", ansi::FormatAnsiTerminalCodes("abc${ansi.fg.red}abc${ansi.normal}abc")); + + EXPECT_EQ("abcabcabc", + ansi::StripAnsiTerminalCodes("abc\x1B[31mabc\x1B[0mabc")); +} + +TEST(AnsiTerminal, InvalidEscapeCode) { + EXPECT_EQ("abc\x1B[31kabcabc", + ansi::StripAnsiTerminalCodes("abc\x1B[31kabc\x1B[0mabc")); }