diff --git a/lldb/include/lldb/API/SBCommandInterpreter.h b/lldb/include/lldb/API/SBCommandInterpreter.h index 756509ce5208..f6a839c46256 100644 --- a/lldb/include/lldb/API/SBCommandInterpreter.h +++ b/lldb/include/lldb/API/SBCommandInterpreter.h @@ -33,6 +33,12 @@ public: ~SBCommandInterpreter (); + static const char * + GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type); + + static const char * + GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type); + bool IsValid() const; diff --git a/lldb/include/lldb/Core/StreamTee.h b/lldb/include/lldb/Core/StreamTee.h index aa1b579d0dde..28951d17f6e2 100644 --- a/lldb/include/lldb/Core/StreamTee.h +++ b/lldb/include/lldb/Core/StreamTee.h @@ -11,6 +11,7 @@ #define liblldb_StreamTee_h_ #include "lldb/Core/Stream.h" +#include "lldb/Host/Mutex.h" namespace lldb_private { @@ -18,20 +19,42 @@ class StreamTee : public Stream { public: StreamTee () : - Stream() + Stream (), + m_streams_mutex (Mutex::eMutexTypeRecursive), + m_streams () { } - StreamTee (lldb::StreamSP &stream_1_sp, lldb::StreamSP &stream_2_sp): - m_stream_1_sp (stream_1_sp), - m_stream_2_sp (stream_2_sp) + StreamTee (lldb::StreamSP &stream_sp): + Stream (), + m_streams_mutex (Mutex::eMutexTypeRecursive), + m_streams () { + // No need to lock mutex during construction + if (stream_sp) + m_streams.push_back (stream_sp); } + - StreamTee (lldb::StreamSP &stream_1_sp): - m_stream_1_sp (stream_1_sp), - m_stream_2_sp () + StreamTee (lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp) : + Stream (), + m_streams_mutex (Mutex::eMutexTypeRecursive), + m_streams () { + // No need to lock mutex during construction + if (stream_sp) + m_streams.push_back (stream_sp); + if (stream_2_sp) + m_streams.push_back (stream_2_sp); + } + + StreamTee (const StreamTee &rhs) : + Stream (rhs), + m_streams_mutex (Mutex::eMutexTypeRecursive), + m_streams() // Don't copy until we lock down "rhs" + { + Mutex::Locker locker (rhs.m_streams_mutex); + m_streams = rhs.m_streams; } virtual @@ -39,58 +62,109 @@ public: { } + StreamTee & + operator = (const StreamTee &rhs) + { + if (this != &rhs) { + Stream::operator=(rhs); + Mutex::Locker lhs_locker (m_streams_mutex); + Mutex::Locker rhs_locker (rhs.m_streams_mutex); + m_streams = rhs.m_streams; + } + return *this; + } + virtual void Flush () { - if (m_stream_1_sp) - m_stream_1_sp->Flush (); - - if (m_stream_2_sp) - m_stream_2_sp->Flush (); + Mutex::Locker locker (m_streams_mutex); + collection::iterator pos, end; + for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) + { + // Allow for our collection to contain NULL streams. This allows + // the StreamTee to be used with hard coded indexes for clients + // that might want N total streams with only a few that are set + // to valid values. + Stream *strm = pos->get(); + if (strm) + strm->Flush (); + } } virtual int Write (const void *s, size_t length) { - int ret_1; - int ret_2; - if (m_stream_1_sp) - ret_1 = m_stream_1_sp->Write (s, length); - - if (m_stream_2_sp) - ret_2 = m_stream_2_sp->Write (s, length); - - return ret_1 < ret_2 ? ret_1 : ret_2; + Mutex::Locker locker (m_streams_mutex); + if (m_streams.empty()) + return 0; + + int min_bytes_written = INT_MAX; + collection::iterator pos, end; + for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) + { + // Allow for our collection to contain NULL streams. This allows + // the StreamTee to be used with hard coded indexes for clients + // that might want N total streams with only a few that are set + // to valid values. + Stream *strm = pos->get(); + if (strm) + { + int bytes_written = strm->Write (s, length); + if (min_bytes_written > bytes_written) + min_bytes_written = bytes_written; + } + } + return min_bytes_written; + } + + size_t + AppendStream (const lldb::StreamSP &stream_sp) + { + size_t new_idx = m_streams.size(); + Mutex::Locker locker (m_streams_mutex); + m_streams.push_back (stream_sp); + return new_idx; + } + + size_t + GetNumStreams () const + { + size_t result = 0; + { + Mutex::Locker locker (m_streams_mutex); + result = m_streams.size(); + } + return result; + } + + lldb::StreamSP + GetStreamAtIndex (uint32_t idx) + { + lldb::StreamSP stream_sp; + Mutex::Locker locker (m_streams_mutex); + if (idx < m_streams.size()) + stream_sp = m_streams[idx]; + return stream_sp; } void - SetStream1 (lldb::StreamSP &stream_1_sp) + SetStreamAtIndex (uint32_t idx, const lldb::StreamSP& stream_sp) { - m_stream_1_sp = stream_1_sp; - } - - void - SetStream2 (lldb::StreamSP &stream_2_sp) - { - m_stream_2_sp = stream_2_sp; - } - - lldb::StreamSP & - GetStream1 () - { - return m_stream_1_sp; - } - - lldb::StreamSP & - GetStream2 () - { - return m_stream_2_sp; + Mutex::Locker locker (m_streams_mutex); + // Resize our stream vector as necessary to fit as many streams + // as needed. This also allows this class to be used with hard + // coded indexes that can be used contain many streams, not all + // of which are valid. + if (idx >= m_streams.size()) + m_streams.resize(idx + 1); + m_streams[idx] = stream_sp; } + protected: - lldb::StreamSP m_stream_1_sp; - lldb::StreamSP m_stream_2_sp; - + typedef std::vector collection; + mutable Mutex m_streams_mutex; + collection m_streams; }; } // namespace lldb_private diff --git a/lldb/include/lldb/Interpreter/CommandObject.h b/lldb/include/lldb/Interpreter/CommandObject.h index d30e91349dc9..4822cc31c26e 100644 --- a/lldb/include/lldb/Interpreter/CommandObject.h +++ b/lldb/include/lldb/Interpreter/CommandObject.h @@ -59,6 +59,13 @@ public: virtual ~CommandObject (); + + static const char * + GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type); + + static const char * + GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type); + CommandInterpreter & GetCommandInterpreter () { diff --git a/lldb/include/lldb/Interpreter/CommandReturnObject.h b/lldb/include/lldb/Interpreter/CommandReturnObject.h index e63ea796939f..c05aa0bb3b03 100644 --- a/lldb/include/lldb/Interpreter/CommandReturnObject.h +++ b/lldb/include/lldb/Interpreter/CommandReturnObject.h @@ -34,17 +34,18 @@ public: const char * GetOutputData () { - if (m_output_stream_string_sp) - return static_cast(m_output_stream_string_sp.get())->GetData(); - else - return ""; + lldb::StreamSP stream_sp (m_out_stream.GetStreamAtIndex (eStreamStringIndex)); + if (stream_sp) + return static_cast(stream_sp.get())->GetData(); + return ""; } const char * GetErrorData () { - if (m_error_stream_string_sp) - return static_cast(m_error_stream_string_sp.get())->GetData(); + lldb::StreamSP stream_sp (m_err_stream.GetStreamAtIndex (eStreamStringIndex)); + if (stream_sp) + return static_cast(stream_sp.get())->GetData(); else return ""; } @@ -52,63 +53,66 @@ public: Stream & GetOutputStream () { - if (!m_output_stream_string_sp) + // Make sure we at least have our normal string stream output stream + lldb::StreamSP stream_sp (m_out_stream.GetStreamAtIndex (eStreamStringIndex)); + if (!stream_sp) { - StreamString *new_stream = new StreamString(); - m_output_stream_string_sp.reset (new_stream); - m_output_stream.SetStream1 (m_output_stream_string_sp); + stream_sp.reset (new StreamString()); + m_out_stream.SetStreamAtIndex (eStreamStringIndex, stream_sp); } - return m_output_stream; + return m_out_stream; } Stream & GetErrorStream () { - if (!m_error_stream_string_sp) + // Make sure we at least have our normal string stream output stream + lldb::StreamSP stream_sp (m_err_stream.GetStreamAtIndex (eStreamStringIndex)); + if (!stream_sp) { - StreamString *new_stream = new StreamString(); - m_error_stream_string_sp.reset (new_stream); - m_error_stream.SetStream1 (m_error_stream_string_sp); + stream_sp.reset (new StreamString()); + m_err_stream.SetStreamAtIndex (eStreamStringIndex, stream_sp); } - return m_error_stream; + return m_err_stream; } void - SetImmediateOutputFile (FILE *fh) + SetImmediateOutputFile (FILE *fh, bool transfer_fh_ownership = false) { - lldb::StreamSP new_stream_sp (new StreamFile (fh, false)); - m_output_stream.SetStream2 (new_stream_sp); + lldb::StreamSP stream_sp (new StreamFile (fh, transfer_fh_ownership)); + m_out_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp); } void - SetImmediateErrorFile (FILE *fh) + SetImmediateErrorFile (FILE *fh, bool transfer_fh_ownership = false) { - lldb::StreamSP new_stream_sp (new StreamFile (fh, false)); - SetImmediateOutputStream (new_stream_sp); + lldb::StreamSP stream_sp (new StreamFile (fh, transfer_fh_ownership)); + m_out_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp); } void - SetImmediateOutputStream (lldb::StreamSP &new_stream_sp) + SetImmediateOutputStream (const lldb::StreamSP &stream_sp) { - m_output_stream.SetStream2 (new_stream_sp); + m_out_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp); } void - SetImmediateErrorStream (lldb::StreamSP &new_stream_sp) + SetImmediateErrorStream (const lldb::StreamSP &stream_sp) { - m_error_stream.SetStream2 (new_stream_sp); + // Ensure we always have our normal output stream + m_err_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp); } - lldb::StreamSP & + lldb::StreamSP GetImmediateOutputStream () { - return m_output_stream.GetStream2 (); + return m_out_stream.GetStreamAtIndex (eImmediateStreamIndex); } - lldb::StreamSP & + lldb::StreamSP GetImmediateErrorStream () { - return m_error_stream.GetStream2 (); + return m_err_stream.GetStreamAtIndex (eImmediateStreamIndex); } void @@ -155,10 +159,14 @@ public: void SetDidChangeProcessState (bool b); private: - lldb::StreamSP m_output_stream_string_sp; - lldb::StreamSP m_error_stream_string_sp; - StreamTee m_output_stream; - StreamTee m_error_stream; + enum + { + eStreamStringIndex = 0, + eImmediateStreamIndex = 1 + }; + + StreamTee m_out_stream; + StreamTee m_err_stream; lldb::ReturnStatus m_status; bool m_did_change_process_state; diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp index ddd26cf84663..443545df9728 100644 --- a/lldb/source/API/SBCommandInterpreter.cpp +++ b/lldb/source/API/SBCommandInterpreter.cpp @@ -292,3 +292,17 @@ SBCommandInterpreter::GetBroadcaster () return broadcaster; } +const char * +SBCommandInterpreter::GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type) +{ + return CommandObject::GetArgumentTypeAsCString (arg_type); +} + +const char * +SBCommandInterpreter::GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type) +{ + return CommandObject::GetArgumentDescriptionAsCString (arg_type); +} + + + diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index a6906709340b..fbe47d2c2105 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -92,27 +92,27 @@ CommandInterpreter::Initialize () LoadCommandDictionary (); // Set up some initial aliases. - result.Clear(); HandleCommand ("command alias q quit", false, result); - result.Clear(); HandleCommand ("command alias run process launch --", false, result); - result.Clear(); HandleCommand ("command alias r process launch --", false, result); - result.Clear(); HandleCommand ("command alias c process continue", false, result); - result.Clear(); HandleCommand ("command alias continue process continue", false, result); - result.Clear(); HandleCommand ("command alias expr expression", false, result); - result.Clear(); HandleCommand ("command alias exit quit", false, result); - result.Clear(); HandleCommand ("command alias b regexp-break", false, result); - result.Clear(); HandleCommand ("command alias bt thread backtrace", false, result); - result.Clear(); HandleCommand ("command alias si thread step-inst", false, result); - result.Clear(); HandleCommand ("command alias step thread step-in", false, result); - result.Clear(); HandleCommand ("command alias s thread step-in", false, result); - result.Clear(); HandleCommand ("command alias next thread step-over", false, result); - result.Clear(); HandleCommand ("command alias n thread step-over", false, result); - result.Clear(); HandleCommand ("command alias finish thread step-out", false, result); - result.Clear(); HandleCommand ("command alias x memory read", false, result); - result.Clear(); HandleCommand ("command alias l source list", false, result); - result.Clear(); HandleCommand ("command alias list source list", false, result); - result.Clear(); HandleCommand ("command alias p frame variable", false, result); - result.Clear(); HandleCommand ("command alias print frame variable", false, result); - result.Clear(); HandleCommand ("command alias po expression -o --", false, result); + HandleCommand ("command alias q quit", false, result); + HandleCommand ("command alias run process launch --", false, result); + HandleCommand ("command alias r process launch --", false, result); + HandleCommand ("command alias c process continue", false, result); + HandleCommand ("command alias continue process continue", false, result); + HandleCommand ("command alias expr expression", false, result); + HandleCommand ("command alias exit quit", false, result); + HandleCommand ("command alias b regexp-break", false, result); + HandleCommand ("command alias bt thread backtrace", false, result); + HandleCommand ("command alias si thread step-inst", false, result); + HandleCommand ("command alias step thread step-in", false, result); + HandleCommand ("command alias s thread step-in", false, result); + HandleCommand ("command alias next thread step-over", false, result); + HandleCommand ("command alias n thread step-over", false, result); + HandleCommand ("command alias finish thread step-out", false, result); + HandleCommand ("command alias x memory read", false, result); + HandleCommand ("command alias l source list", false, result); + HandleCommand ("command alias list source list", false, result); + HandleCommand ("command alias p frame variable", false, result); + HandleCommand ("command alias print frame variable", false, result); + HandleCommand ("command alias po expression -o --", false, result); } const char * @@ -1517,9 +1517,6 @@ CommandInterpreter::HandleCommands (StringList &commands, CommandReturnObject &result) { size_t num_lines = commands.GetSize(); - CommandReturnObject tmp_result; - tmp_result.SetImmediateOutputStream (result.GetImmediateOutputStream ()); - tmp_result.SetImmediateErrorStream (result.GetImmediateErrorStream ()); // If we are going to continue past a "continue" then we need to run the commands synchronously. // Make sure you reset this value anywhere you return from the function. @@ -1543,7 +1540,6 @@ CommandInterpreter::HandleCommands (StringList &commands, if (cmd[0] == '\0') continue; - tmp_result.Clear(); if (echo_commands) { result.AppendMessageWithFormat ("%s %s\n", @@ -1551,6 +1547,9 @@ CommandInterpreter::HandleCommands (StringList &commands, cmd); } + CommandReturnObject tmp_result; + tmp_result.SetImmediateOutputStream (result.GetImmediateOutputStream ()); + tmp_result.SetImmediateErrorStream (result.GetImmediateErrorStream ()); bool success = HandleCommand(cmd, false, tmp_result, NULL); if (print_results) diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp index 2f88a4893c0e..b0446d05a455 100644 --- a/lldb/source/Interpreter/CommandObject.cpp +++ b/lldb/source/Interpreter/CommandObject.cpp @@ -600,6 +600,23 @@ BreakpointIDRangeHelpTextCallback () return "A 'breakpoint id list' is a manner of specifying multiple breakpoints. This can be done through several mechanisms. The easiest way is to just enter a space-separated list of breakpoint ids. To specify all the breakpoint locations under a major breakpoint, you can use the major breakpoint number followed by '.*', eg. '5.*' means all the locations under breakpoint 5. You can also indicate a range of breakpoints by using - . The start-bp-id and end-bp-id for a range can be any valid breakpoint ids. It is not legal, however, to specify a range using specific locations that cross major breakpoint numbers. I.e. 3.2 - 3.7 is legal; 2 - 5 is legal; but 3.2 - 4.4 is not legal."; } +const char * +CommandObject::GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type) +{ + if (arg_type >=0 && arg_type < eArgTypeLastArg) + return g_arguments_data[arg_type].arg_name; + return NULL; + +} + +const char * +CommandObject::GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type) +{ + if (arg_type >=0 && arg_type < eArgTypeLastArg) + return g_arguments_data[arg_type].help_text; + return NULL; +} + CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = { @@ -667,6 +684,8 @@ CommandObject::g_arguments_data[] = const CommandObject::ArgumentTableEntry* CommandObject::GetArgumentTable () { + // If this assertion fires, then the table above is out of date with the CommandArgumentType enumeration + assert ((sizeof (CommandObject::g_arguments_data) / sizeof (CommandObject::ArgumentTableEntry)) == eArgTypeLastArg); return CommandObject::g_arguments_data; } diff --git a/lldb/source/Interpreter/CommandReturnObject.cpp b/lldb/source/Interpreter/CommandReturnObject.cpp index 3faf912bd7d4..9d32279edab8 100644 --- a/lldb/source/Interpreter/CommandReturnObject.cpp +++ b/lldb/source/Interpreter/CommandReturnObject.cpp @@ -19,10 +19,8 @@ using namespace lldb; using namespace lldb_private; CommandReturnObject::CommandReturnObject () : - m_error_stream_string_sp (), - m_output_stream_string_sp (), - m_output_stream (), - m_error_stream (), + m_out_stream (), + m_err_stream (), m_status (eReturnStatusStarted), m_did_change_process_state (false) { @@ -145,11 +143,15 @@ CommandReturnObject::HasResult () void CommandReturnObject::Clear() { - if (m_output_stream_string_sp) - static_cast(m_output_stream_string_sp.get())->Clear(); - if (m_error_stream_string_sp) - static_cast(m_error_stream_string_sp.get())->Clear(); + lldb::StreamSP stream_sp; + stream_sp = m_out_stream.GetStreamAtIndex (eStreamStringIndex); + if (stream_sp) + static_cast(stream_sp.get())->Clear(); + stream_sp = m_err_stream.GetStreamAtIndex (eStreamStringIndex); + if (stream_sp) + static_cast(stream_sp.get())->Clear(); m_status = eReturnStatusStarted; + m_did_change_process_state = false; } bool diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 04e69e45e169..3ec2c2fd6d60 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -181,35 +181,6 @@ OutputFormattedUsageText (FILE *out, int indent, const char *text, int output_ma } } -void -GetArgumentName (const CommandArgumentType arg_type, std::string &arg_name) -{ - //Fudge this function here, since we can't call the "real" version in lldb_private::CommandObject... - - switch (arg_type) - { - // Make cases for all the arg_types used in Driver.cpp - - case eArgTypeNone: - arg_name = ""; - break; - - case eArgTypeArchitecture: - arg_name = "architecture"; - break; - - case eArgTypeScriptLang: - arg_name = "script-language"; - break; - - case eArgTypeFilename: - arg_name = "filename"; - break; - } - return; -} - - void ShowUsage (FILE *out, lldb::OptionDefinition *option_table, Driver::OptionData data) { @@ -265,23 +236,22 @@ ShowUsage (FILE *out, lldb::OptionDefinition *option_table, Driver::OptionData d if (option_table[i].usage_mask & opt_set_mask) { CommandArgumentType arg_type = option_table[i].argument_type; - std::string arg_name; - GetArgumentName (arg_type, arg_name); + const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString (arg_type); if (option_table[i].required) { if (option_table[i].option_has_arg == required_argument) - fprintf (out, " -%c <%s>", option_table[i].short_option, arg_name.c_str()); + fprintf (out, " -%c <%s>", option_table[i].short_option, arg_name); else if (option_table[i].option_has_arg == optional_argument) - fprintf (out, " -%c [<%s>]", option_table[i].short_option, arg_name.c_str()); + fprintf (out, " -%c [<%s>]", option_table[i].short_option, arg_name); else fprintf (out, " -%c", option_table[i].short_option); } else { if (option_table[i].option_has_arg == required_argument) - fprintf (out, " [-%c <%s>]", option_table[i].short_option, arg_name.c_str()); + fprintf (out, " [-%c <%s>]", option_table[i].short_option, arg_name); else if (option_table[i].option_has_arg == optional_argument) - fprintf (out, " [-%c [<%s>]]", option_table[i].short_option, arg_name.c_str()); + fprintf (out, " [-%c [<%s>]]", option_table[i].short_option, arg_name); else fprintf (out, " [-%c]", option_table[i].short_option); } @@ -311,17 +281,16 @@ ShowUsage (FILE *out, lldb::OptionDefinition *option_table, Driver::OptionData d if (pos == options_seen.end()) { CommandArgumentType arg_type = option_table[i].argument_type; - std::string arg_name; - GetArgumentName (arg_type, arg_name); + const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString (arg_type); options_seen.insert (option_table[i].short_option); fprintf (out, "%*s-%c ", indent_level, "", option_table[i].short_option); if (arg_type != eArgTypeNone) - fprintf (out, "<%s>", arg_name.c_str()); + fprintf (out, "<%s>", arg_name); fprintf (out, "\n"); fprintf (out, "%*s--%s ", indent_level, "", option_table[i].long_option); if (arg_type != eArgTypeNone) - fprintf (out, "<%s>", arg_name.c_str()); + fprintf (out, "<%s>", arg_name); fprintf (out, "\n"); indent_level += 5; OutputFormattedUsageText (out, indent_level, option_table[i].usage_text, screen_width);