Author: spyffe Date: Mon Oct 19 19:23:46 2015 New Revision: 250773 URL: http://llvm.org/viewvc/llvm-project?rev=250773&view=rev Log: Added support for the "--repl" argument to LLDB.
This makes LLDB launch and create a REPL, specifying no target so that the REPL can create one for itself. Also added the "--repl-language" option, which specifies the language to use. Plumbed the relevant arguments and errors through the REPL creation mechanism. Modified: lldb/trunk/include/lldb/API/SBDebugger.h lldb/trunk/include/lldb/Core/Debugger.h lldb/trunk/include/lldb/Expression/REPL.h lldb/trunk/include/lldb/Target/Target.h lldb/trunk/include/lldb/lldb-private-interfaces.h lldb/trunk/scripts/interface/SBDebugger.i lldb/trunk/source/API/SBDebugger.cpp lldb/trunk/source/Core/Debugger.cpp lldb/trunk/source/Expression/REPL.cpp lldb/trunk/source/Target/Target.cpp lldb/trunk/tools/driver/Driver.cpp lldb/trunk/tools/driver/Driver.h Modified: lldb/trunk/include/lldb/API/SBDebugger.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBDebugger.h?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/include/lldb/API/SBDebugger.h (original) +++ lldb/trunk/include/lldb/API/SBDebugger.h Mon Oct 19 19:23:46 2015 @@ -329,6 +329,9 @@ public: int &num_errors, bool &quit_requested, bool &stopped_for_crash); + + SBError + RunREPL (lldb::LanguageType language, const char *repl_options); private: friend class SBCommandInterpreter; Modified: lldb/trunk/include/lldb/Core/Debugger.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Debugger.h?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/Debugger.h (original) +++ lldb/trunk/include/lldb/Core/Debugger.h Mon Oct 19 19:23:46 2015 @@ -375,6 +375,9 @@ public: { return m_event_handler_thread.IsJoinable(); } + + Error + RunREPL (lldb::LanguageType language, const char *repl_options); // This is for use in the command interpreter, when you either want the selected target, or if no target // is present you want to prime the dummy target with entities that will be copied over to new targets. Modified: lldb/trunk/include/lldb/Expression/REPL.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/REPL.h?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/include/lldb/Expression/REPL.h (original) +++ lldb/trunk/include/lldb/Expression/REPL.h Mon Oct 19 19:23:46 2015 @@ -37,8 +37,26 @@ public: virtual ~REPL(); + //------------------------------------------------------------------ + /// Get a REPL with an (optional) existing target, and (optional) extra arguments for the compiler. + /// + /// @param[out] error + /// If this language is supported but the REPL couldn't be created, this error is populated with the reason. + /// + /// @param[in] language + /// The language to create a REPL for. + /// + /// @param[in] target + /// If provided, the target to put the REPL inside. + /// + /// @param[in] repl_options + /// If provided, additional options for the compiler when parsing REPL expressions. + /// + /// @return + /// The range of the containing object in the target process. + //------------------------------------------------------------------ static lldb::REPLSP - Create (lldb::LanguageType language, Target *target); + Create (Error &Error, lldb::LanguageType language, Target *target, const char *repl_options); void SetFormatOptions (const OptionGroupFormat &options) Modified: lldb/trunk/include/lldb/Target/Target.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/include/lldb/Target/Target.h (original) +++ lldb/trunk/include/lldb/Target/Target.h Mon Oct 19 19:23:46 2015 @@ -1568,7 +1568,7 @@ public: GetSearchFilterForModuleAndCUList (const FileSpecList *containingModules, const FileSpecList *containingSourceFiles); lldb::REPLSP - GetREPL (lldb::LanguageType, bool can_create); + GetREPL (Error &err, lldb::LanguageType language, const char *repl_options, bool can_create); protected: //------------------------------------------------------------------ Modified: lldb/trunk/include/lldb/lldb-private-interfaces.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-interfaces.h?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/include/lldb/lldb-private-interfaces.h (original) +++ lldb/trunk/include/lldb/lldb-private-interfaces.h Mon Oct 19 19:23:46 2015 @@ -49,7 +49,7 @@ namespace lldb_private typedef lldb::InstrumentationRuntimeType (*InstrumentationRuntimeGetType) (); typedef lldb::InstrumentationRuntimeSP (*InstrumentationRuntimeCreateInstance) (const lldb::ProcessSP &process_sp); typedef lldb::TypeSystemSP (*TypeSystemCreateInstance) (lldb::LanguageType language, Module *module, Target *target); - typedef lldb::REPLSP (*REPLCreateInstance) (lldb::LanguageType language, Target *target); + typedef lldb::REPLSP (*REPLCreateInstance) (Error &error, lldb::LanguageType language, Target *target, const char *repl_options); typedef void (*TypeSystemEnumerateSupportedLanguages) (std::set<lldb::LanguageType> &languages_for_types, std::set<lldb::LanguageType> &languages_for_expressions); typedef int (*ComparisonFunction)(const void *, const void *); typedef void (*DebuggerInitializeCallback)(Debugger &debugger); Modified: lldb/trunk/scripts/interface/SBDebugger.i URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/interface/SBDebugger.i?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/scripts/interface/SBDebugger.i (original) +++ lldb/trunk/scripts/interface/SBDebugger.i Mon Oct 19 19:23:46 2015 @@ -377,6 +377,9 @@ public: int &num_errors, bool &quit_requested, bool &stopped_for_crash); + + lldb::SBError + RunREPL (lldb::LanguageType language, const char *repl_options); }; // class SBDebugger } // namespace lldb Modified: lldb/trunk/source/API/SBDebugger.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBDebugger.cpp?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/source/API/SBDebugger.cpp (original) +++ lldb/trunk/source/API/SBDebugger.cpp Mon Oct 19 19:23:46 2015 @@ -1000,6 +1000,17 @@ SBDebugger::RunCommandInterpreter (bool } } +SBError +SBDebugger::RunREPL (lldb::LanguageType language, const char *repl_options) +{ + SBError error; + if (m_opaque_sp) + error.ref() = m_opaque_sp->RunREPL(language, repl_options); + else + error.SetErrorString ("invalid debugger"); + return error; +} + void SBDebugger::reset (const DebuggerSP &debugger_sp) { Modified: lldb/trunk/source/Core/Debugger.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/source/Core/Debugger.cpp (original) +++ lldb/trunk/source/Core/Debugger.cpp Mon Oct 19 19:23:46 2015 @@ -31,6 +31,7 @@ #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/DataFormatters/FormatManager.h" #include "lldb/DataFormatters/TypeSummary.h" +#include "lldb/Expression/REPL.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/Terminal.h" @@ -44,6 +45,7 @@ #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/TargetList.h" +#include "lldb/Target/Language.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/SectionLoadList.h" @@ -1798,3 +1800,35 @@ Debugger::GetSelectedOrDummyTarget(bool return GetDummyTarget(); } +Error +Debugger::RunREPL (LanguageType language, const char *repl_options) +{ + Error err; + FileSpec repl_executable; + if (language == eLanguageTypeUnknown) + { + err.SetErrorString ("must specify a language for a REPL"); // TODO make it possible to specify a default language + return err; + } + + Target *const target = nullptr; // passing in an empty target means the REPL must create one + + REPLSP repl_sp(REPL::Create(err, language, target, repl_options)); + + if (!err.Success()) + { + return err; + } + + if (!repl_sp) + { + err.SetErrorStringWithFormat("couldn't find a REPL for %s", Language::GetNameForLanguageType(language)); + return err; + } + + repl_sp->SetCompilerOptions(repl_options); + repl_sp->RunLoop(); + + return err; +} + Modified: lldb/trunk/source/Expression/REPL.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/REPL.cpp?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/source/Expression/REPL.cpp (original) +++ lldb/trunk/source/Expression/REPL.cpp Mon Oct 19 19:23:46 2015 @@ -23,14 +23,14 @@ using namespace lldb_private; lldb::REPLSP -REPL::Create(lldb::LanguageType language, Target *target) +REPL::Create(Error &err, lldb::LanguageType language, Target *target, const char *repl_options) { uint32_t idx = 0; lldb::REPLSP ret; while (REPLCreateInstance create_instance = PluginManager::GetREPLCreateCallbackAtIndex(idx++)) { - ret = (*create_instance)(language, target); + ret = (*create_instance)(err, language, target, repl_options); if (ret) { break; Modified: lldb/trunk/source/Target/Target.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/source/Target/Target.cpp (original) +++ lldb/trunk/source/Target/Target.cpp Mon Oct 19 19:23:46 2015 @@ -213,7 +213,7 @@ Target::GetProcessSP () const } lldb::REPLSP -Target::GetREPL (lldb::LanguageType language, bool can_create) +Target::GetREPL (Error &err, lldb::LanguageType language, const char *repl_options, bool can_create) { if (language == eLanguageTypeUnknown) { @@ -229,10 +229,11 @@ Target::GetREPL (lldb::LanguageType lang if (!can_create) { + err.SetErrorStringWithFormat("Couldn't find an existing REPL for %s, and can't create a new one", Language::GetNameForLanguageType(language)); return lldb::REPLSP(); } - lldb::REPLSP ret = REPL::Create(language, this); + lldb::REPLSP ret = REPL::Create(err, language, this, repl_options); if (ret) { @@ -240,7 +241,12 @@ Target::GetREPL (lldb::LanguageType lang return m_repl_map[language]; } - return nullptr; + if (err.Success()) + { + err.SetErrorStringWithFormat("Couldn't create a REPL for %s", Language::GetNameForLanguageType(language)); + } + + return lldb::REPLSP(); } void Modified: lldb/trunk/tools/driver/Driver.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/Driver.cpp?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/tools/driver/Driver.cpp (original) +++ lldb/trunk/tools/driver/Driver.cpp Mon Oct 19 19:23:46 2015 @@ -35,6 +35,7 @@ #include "lldb/API/SBDebugger.h" #include "lldb/API/SBEvent.h" #include "lldb/API/SBHostOS.h" +#include "lldb/API/SBLanguageRuntime.h" #include "lldb/API/SBListener.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBTarget.h" @@ -132,6 +133,10 @@ static OptionDefinition g_options[] = "extensions have been implemented." }, { LLDB_3_TO_5, false, "debug" , 'd', no_argument , 0, eArgTypeNone, "Tells the debugger to print out extra information for debugging itself." }, + { LLDB_OPT_SET_7, true , "repl" , 'r', optional_argument, 0, eArgTypeNone, + "Runs lldb in REPL mode with a stub process." }, + { LLDB_OPT_SET_7, true , "repl-language" , 'R', required_argument, 0, eArgTypeNone, + "Chooses the language for the REPL." }, { 0, false, NULL , 0 , 0 , 0, eArgTypeNone, NULL } }; @@ -408,6 +413,9 @@ Driver::OptionData::OptionData () : m_print_python_path (false), m_print_help (false), m_wait_for(false), + m_repl (false), + m_repl_lang (eLanguageTypeUnknown), + m_repl_options (), m_process_name(), m_process_pid(LLDB_INVALID_PROCESS_ID), m_use_external_editor(false), @@ -769,6 +777,23 @@ Driver::ParseArgs (int argc, const char optarg); } break; + + case 'r': + m_option_data.m_repl = true; + if (optarg && optarg[0]) + m_option_data.m_repl_options = optarg; + else + m_option_data.m_repl_options.clear(); + break; + + case 'R': + m_option_data.m_repl_lang = SBLanguageRuntime::GetLanguageTypeFromString (optarg); + if (m_option_data.m_repl_lang == eLanguageTypeUnknown) + { + error.SetErrorStringWithFormat ("Unrecognized language name: \"%s\"", optarg); + } + break; + case 's': m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, true, error); break; @@ -1056,96 +1081,114 @@ Driver::MainLoop () bool handle_events = true; bool spawn_thread = false; - // Check if we have any data in the commands stream, and if so, save it to a temp file - // so we can then run the command interpreter using the file contents. - const char *commands_data = commands_stream.GetData(); - const size_t commands_size = commands_stream.GetSize(); - - // The command file might have requested that we quit, this variable will track that. - bool quit_requested = false; - bool stopped_for_crash = false; - if (commands_data && commands_size) - { - int initial_commands_fds[2]; - bool success = true; - FILE *commands_file = PrepareCommandsForSourcing (commands_data, commands_size, initial_commands_fds); - if (commands_file) + if (m_option_data.m_repl) + { + const char *repl_options = NULL; + if (!m_option_data.m_repl_options.empty()) + repl_options = m_option_data.m_repl_options.c_str(); + SBError error (m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options)); + if (error.Fail()) { - m_debugger.SetInputFileHandle (commands_file, true); + const char *error_cstr = error.GetCString(); + if (error_cstr && error_cstr[0]) + fprintf (stderr, "error: %s\n", error_cstr); + else + fprintf (stderr, "error: %u\n", error.GetError()); + } + } + else + { + // Check if we have any data in the commands stream, and if so, save it to a temp file + // so we can then run the command interpreter using the file contents. + const char *commands_data = commands_stream.GetData(); + const size_t commands_size = commands_stream.GetSize(); + + // The command file might have requested that we quit, this variable will track that. + bool quit_requested = false; + bool stopped_for_crash = false; + if (commands_data && commands_size) + { + int initial_commands_fds[2]; + bool success = true; + FILE *commands_file = PrepareCommandsForSourcing (commands_data, commands_size, initial_commands_fds); + if (commands_file) + { + m_debugger.SetInputFileHandle (commands_file, true); - // Set the debugger into Sync mode when running the command file. Otherwise command files - // that run the target won't run in a sensible way. - bool old_async = m_debugger.GetAsync(); - m_debugger.SetAsync(false); - int num_errors; - - SBCommandInterpreterRunOptions options; - options.SetStopOnError (true); - if (m_option_data.m_batch) - options.SetStopOnCrash (true); - - m_debugger.RunCommandInterpreter(handle_events, - spawn_thread, - options, - num_errors, - quit_requested, - stopped_for_crash); + // Set the debugger into Sync mode when running the command file. Otherwise command files + // that run the target won't run in a sensible way. + bool old_async = m_debugger.GetAsync(); + m_debugger.SetAsync(false); + int num_errors; + + SBCommandInterpreterRunOptions options; + options.SetStopOnError (true); + if (m_option_data.m_batch) + options.SetStopOnCrash (true); + + m_debugger.RunCommandInterpreter(handle_events, + spawn_thread, + options, + num_errors, + quit_requested, + stopped_for_crash); - if (m_option_data.m_batch && stopped_for_crash && !m_option_data.m_after_crash_commands.empty()) - { - int crash_command_fds[2]; - SBStream crash_commands_stream; - WriteCommandsForSourcing (eCommandPlacementAfterCrash, crash_commands_stream); - const char *crash_commands_data = crash_commands_stream.GetData(); - const size_t crash_commands_size = crash_commands_stream.GetSize(); - commands_file = PrepareCommandsForSourcing (crash_commands_data, crash_commands_size, crash_command_fds); - if (commands_file) + if (m_option_data.m_batch && stopped_for_crash && !m_option_data.m_after_crash_commands.empty()) { - bool local_quit_requested; - bool local_stopped_for_crash; - m_debugger.SetInputFileHandle (commands_file, true); - - m_debugger.RunCommandInterpreter(handle_events, - spawn_thread, - options, - num_errors, - local_quit_requested, - local_stopped_for_crash); - if (local_quit_requested) - quit_requested = true; + int crash_command_fds[2]; + SBStream crash_commands_stream; + WriteCommandsForSourcing (eCommandPlacementAfterCrash, crash_commands_stream); + const char *crash_commands_data = crash_commands_stream.GetData(); + const size_t crash_commands_size = crash_commands_stream.GetSize(); + commands_file = PrepareCommandsForSourcing (crash_commands_data, crash_commands_size, crash_command_fds); + if (commands_file) + { + bool local_quit_requested; + bool local_stopped_for_crash; + m_debugger.SetInputFileHandle (commands_file, true); + + m_debugger.RunCommandInterpreter(handle_events, + spawn_thread, + options, + num_errors, + local_quit_requested, + local_stopped_for_crash); + if (local_quit_requested) + quit_requested = true; + } } + m_debugger.SetAsync(old_async); } - m_debugger.SetAsync(old_async); - } - else - success = false; + else + success = false; - // Close any pipes that we still have ownership of - CleanupAfterCommandSourcing(initial_commands_fds); + // Close any pipes that we still have ownership of + CleanupAfterCommandSourcing(initial_commands_fds); - // Something went wrong with command pipe - if (!success) - { - exit(1); - } + // Something went wrong with command pipe + if (!success) + { + exit(1); + } - } + } - // Now set the input file handle to STDIN and run the command - // interpreter again in interactive mode and let the debugger - // take ownership of stdin - - bool go_interactive = true; - if (quit_requested) - go_interactive = false; - else if (m_option_data.m_batch && !stopped_for_crash) - go_interactive = false; + // Now set the input file handle to STDIN and run the command + // interpreter again in interactive mode and let the debugger + // take ownership of stdin + + bool go_interactive = true; + if (quit_requested) + go_interactive = false; + else if (m_option_data.m_batch && !stopped_for_crash) + go_interactive = false; - if (go_interactive) - { - m_debugger.SetInputFileHandle (stdin, true); - m_debugger.RunCommandInterpreter(handle_events, spawn_thread); + if (go_interactive) + { + m_debugger.SetInputFileHandle (stdin, true); + m_debugger.RunCommandInterpreter(handle_events, spawn_thread); + } } reset_stdin_termios(); Modified: lldb/trunk/tools/driver/Driver.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/Driver.h?rev=250773&r1=250772&r2=250773&view=diff ============================================================================== --- lldb/trunk/tools/driver/Driver.h (original) +++ lldb/trunk/tools/driver/Driver.h Mon Oct 19 19:23:46 2015 @@ -105,6 +105,9 @@ public: bool m_print_python_path; bool m_print_help; bool m_wait_for; + bool m_repl; + lldb::LanguageType m_repl_lang; + std::string m_repl_options; std::string m_process_name; lldb::pid_t m_process_pid; bool m_use_external_editor; // FIXME: When we have set/show variables we can remove this from here. _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits