Author: spyffe Date: Mon Oct 19 18:11:07 2015 New Revision: 250753 URL: http://llvm.org/viewvc/llvm-project?rev=250753&view=rev Log: Added the concept of a Read-Eval-Print-Loop to LLDB.
A REPL takes over the command line and typically treats input as source code. REPLs can also do code completion. The REPL class allows its subclasses to implement the language-specific functionality without having to know about the IOHandler-specific internals. Also added a PluginManager-based way of getting to a REPL given a language and a target. Also brought in some utility code and expression options that are useful for REPLs, such as line offsets for expressions, ANSI terminal coloring of errors, and a few IOHandler convenience functions. Added: lldb/trunk/include/lldb/Expression/REPL.h lldb/trunk/source/Expression/REPL.cpp Modified: lldb/trunk/include/lldb/Core/Debugger.h lldb/trunk/include/lldb/Core/IOHandler.h lldb/trunk/include/lldb/Core/PluginManager.h lldb/trunk/include/lldb/Expression/UserExpression.h lldb/trunk/include/lldb/Host/File.h lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h lldb/trunk/include/lldb/Target/Target.h lldb/trunk/include/lldb/Utility/AnsiTerminal.h lldb/trunk/include/lldb/lldb-forward.h lldb/trunk/include/lldb/lldb-private-interfaces.h lldb/trunk/lldb.xcodeproj/project.pbxproj lldb/trunk/source/Core/Debugger.cpp lldb/trunk/source/Core/PluginManager.cpp lldb/trunk/source/Expression/UserExpression.cpp lldb/trunk/source/Host/common/File.cpp lldb/trunk/source/Interpreter/CommandInterpreter.cpp lldb/trunk/source/Target/Target.cpp Modified: lldb/trunk/include/lldb/Core/Debugger.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Debugger.h?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/Debugger.h (original) +++ lldb/trunk/include/lldb/Core/Debugger.h Mon Oct 19 18:11:07 2015 @@ -203,6 +203,10 @@ public: bool IsTopIOHandler (const lldb::IOHandlerSP& reader_sp); + + bool + CheckTopIOHandlerTypes (IOHandler::Type top_type, + IOHandler::Type second_top_type); void PrintAsync (const char *s, size_t len, bool is_stdout); @@ -322,6 +326,24 @@ public: GetAutoOneLineSummaries () const; bool + GetAutoIndent () const; + + bool + SetAutoIndent (bool b); + + bool + GetPrintDecls () const; + + bool + SetPrintDecls (bool b); + + uint32_t + GetTabSize () const; + + bool + SetTabSize (uint32_t tab_size); + + bool GetEscapeNonPrintables () const; bool @@ -362,6 +384,7 @@ public: protected: friend class CommandInterpreter; + friend class REPL; bool StartEventHandlerThread(); @@ -373,11 +396,17 @@ protected: EventHandlerThread (lldb::thread_arg_t arg); bool + HasIOHandlerThread(); + + bool StartIOHandlerThread(); void StopIOHandlerThread(); + void + JoinIOHandlerThread(); + static lldb::thread_result_t IOHandlerThread (lldb::thread_arg_t arg); Modified: lldb/trunk/include/lldb/Core/IOHandler.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/IOHandler.h?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/IOHandler.h (original) +++ lldb/trunk/include/lldb/Core/IOHandler.h Mon Oct 19 18:11:07 2015 @@ -42,6 +42,7 @@ namespace lldb_private { Confirm, Curses, Expression, + REPL, ProcessIO, PythonInterpreter, PythonCode, Modified: lldb/trunk/include/lldb/Core/PluginManager.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/PluginManager.h?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/PluginManager.h (original) +++ lldb/trunk/include/lldb/Core/PluginManager.h Mon Oct 19 18:11:07 2015 @@ -444,6 +444,23 @@ public: GetTypeSystemEnumerateSupportedLanguagesCallbackForPluginName (const ConstString &name); //------------------------------------------------------------------ + // REPL + //------------------------------------------------------------------ + static bool + RegisterPlugin (const ConstString &name, + const char *description, + REPLCreateInstance create_callback); + + static bool + UnregisterPlugin (REPLCreateInstance create_callback); + + static REPLCreateInstance + GetREPLCreateCallbackAtIndex (uint32_t idx); + + static REPLCreateInstance + GetREPLCreateCallbackForPluginName (const ConstString &name); + + //------------------------------------------------------------------ // Some plug-ins might register a DebuggerInitializeCallback // callback when registering the plug-in. After a new Debugger // instance is created, this DebuggerInitialize function will get Added: lldb/trunk/include/lldb/Expression/REPL.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/REPL.h?rev=250753&view=auto ============================================================================== --- lldb/trunk/include/lldb/Expression/REPL.h (added) +++ lldb/trunk/include/lldb/Expression/REPL.h Mon Oct 19 18:11:07 2015 @@ -0,0 +1,185 @@ +//===-- REPL.h --------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#ifndef lldb_REPL_h +#define lldb_REPL_h + +#include "lldb/Interpreter/OptionGroupFormat.h" +#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" +#include "lldb/../../source/Commands/CommandObjectExpression.h" + +namespace lldb_private +{ + +class REPL : public IOHandlerDelegate +{ +public: + //---------------------------------------------------------------------- + // See TypeSystem.h for how to add subclasses to this. + //---------------------------------------------------------------------- + enum LLVMCastKind { + eKindClang, + eKindSwift, + eKindGo, + kNumKinds + }; + + LLVMCastKind getKind() const { return m_kind; } + + REPL(LLVMCastKind kind, Target &target); + + virtual ~REPL(); + + static lldb::REPLSP + Create (lldb::LanguageType language, Target *target); + + void + SetFormatOptions (const OptionGroupFormat &options) + { + m_format_options = options; + } + + void + SetValueObjectDisplayOptions (const OptionGroupValueObjectDisplay &options) + { + m_varobj_options = options; + } + + void + SetCommandOptions (const CommandObjectExpression::CommandOptions &options) + { + m_command_options = options; + } + + void + SetCompilerOptions (const char *options) + { + if (options) + m_compiler_options = options; + } + + lldb::IOHandlerSP + GetIOHandler (); + + Error + RunLoop (); + + //------------------------------------------------------------------ + // IOHandler::Delegate functions + //------------------------------------------------------------------ + void + IOHandlerActivated (IOHandler &io_handler) override; + + bool + IOHandlerInterrupt (IOHandler &io_handler) override; + + void + IOHandlerInputInterrupted (IOHandler &io_handler, + std::string &line) override; + + const char * + IOHandlerGetFixIndentationCharacters () override; + + ConstString + IOHandlerGetControlSequence (char ch) override; + + const char * + IOHandlerGetCommandPrefix () override; + + const char * + IOHandlerGetHelpPrologue () override; + + bool + IOHandlerIsInputComplete (IOHandler &io_handler, + StringList &lines) override; + + int + IOHandlerFixIndentation (IOHandler &io_handler, + const StringList &lines, + int cursor_position) override; + + void + IOHandlerInputComplete (IOHandler &io_handler, + std::string &line) override; + + int + IOHandlerComplete (IOHandler &io_handler, + const char *current_line, + const char *cursor, + const char *last_char, + int skip_first_n_matches, + int max_matches, + StringList &matches) override; + +private: + std::string + GetSourcePath(); + +protected: + static int + CalculateActualIndentation (const StringList &lines); + + //---------------------------------------------------------------------- + // Subclasses should override these functions to implement a functional REPL. + //---------------------------------------------------------------------- + + virtual Error + DoInitialization () = 0; + + virtual ConstString + GetSourceFileBasename () = 0; + + virtual const char * + GetAutoIndentCharacters () = 0; + + virtual bool + SourceIsComplete (const std::string &source) = 0; + + virtual lldb::offset_t + GetDesiredIndentation (const StringList &lines, + int cursor_position, + int tab_size) = 0; // LLDB_INVALID_OFFSET means no change + + virtual lldb::LanguageType + GetLanguage () = 0; + + virtual bool + PrintOneVariable (Debugger &debugger, + lldb::StreamFileSP &output_sp, + lldb::ValueObjectSP &valobj_sp, + ExpressionVariable *var = nullptr) = 0; + + virtual int + CompleteCode(const std::string ¤t_code, + StringList &matches) = 0; + + OptionGroupFormat m_format_options = OptionGroupFormat(lldb::eFormatDefault); + OptionGroupValueObjectDisplay m_varobj_options; + CommandObjectExpression::CommandOptions m_command_options; + std::string m_compiler_options; + + bool m_enable_auto_indent = true; + std::string m_indent_str; // Use this string for each level of indentation + std::string m_current_indent_str; + uint32_t m_current_indent_level = 0; + + std::string m_repl_source_path; + bool m_dedicated_repl_mode = false; + + StringList m_code; // All accumulated REPL statements are saved here + + Target &m_target; + lldb::IOHandlerSP m_io_handler_sp; + LLVMCastKind m_kind; +}; + +} + +#endif /* REPL_h */ Modified: lldb/trunk/include/lldb/Expression/UserExpression.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/UserExpression.h?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/include/lldb/Expression/UserExpression.h (original) +++ lldb/trunk/include/lldb/Expression/UserExpression.h Mon Oct 19 18:11:07 2015 @@ -273,10 +273,16 @@ public: /// @param[in,out] result_valobj_sp /// If execution is successful, the result valobj is placed here. /// - /// @param[out] + /// @param[out] error /// Filled in with an error in case the expression evaluation /// fails to parse, run, or evaluated. /// + /// @param[in] line_offset + /// The offset of the first line of the expression from the "beginning" of a virtual source file used for error reporting and debug info. + /// + /// @param[out] jit_module_sp_ptr + /// If non-NULL, used to persist the generated IR module. + /// /// @result /// A Process::ExpressionResults value. eExpressionCompleted for success. //------------------------------------------------------------------ @@ -286,7 +292,9 @@ public: const char *expr_cstr, const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp, - Error &error); + Error &error, + uint32_t line_offset = 0, + lldb::ModuleSP *jit_module_sp_ptr = NULL); static const Error::ValueType kNoResult = 0x1001; ///< ValueObject::GetError() returns this if there is no result from the expression. protected: Modified: lldb/trunk/include/lldb/Host/File.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/File.h?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/include/lldb/Host/File.h (original) +++ lldb/trunk/include/lldb/Host/File.h Mon Oct 19 18:11:07 2015 @@ -494,6 +494,9 @@ public: //------------------------------------------------------------------ bool GetIsRealTerminal (); + + bool + GetIsTerminalWithColors (); //------------------------------------------------------------------ /// Output printf formatted output to the stream. @@ -546,6 +549,7 @@ protected: bool m_own_stream; LazyBool m_is_interactive; LazyBool m_is_real_terminal; + LazyBool m_supports_colors; }; } // namespace lldb_private Modified: lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h (original) +++ lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h Mon Oct 19 18:11:07 2015 @@ -659,6 +659,9 @@ public: return m_stopped_for_crash; } + bool + GetSpaceReplPrompts () const; + protected: friend class Debugger; Modified: lldb/trunk/include/lldb/Target/Target.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/include/lldb/Target/Target.h (original) +++ lldb/trunk/include/lldb/Target/Target.h Mon Oct 19 18:11:07 2015 @@ -442,6 +442,18 @@ public: } bool + GetColorizeErrors () const + { + return m_ansi_color_errors; + } + + void + SetColorizeErrors (bool b) + { + m_ansi_color_errors = b; + } + + bool GetTrapExceptions() const { return m_trap_exceptions; @@ -453,6 +465,18 @@ public: m_trap_exceptions = b; } + bool + GetREPLEnabled() const + { + return m_repl; + } + + void + SetREPLEnabled (bool b) + { + m_repl = b; + } + void SetCancelCallback (lldb::ExpressionCancelCallback callback, void *baton) { @@ -468,6 +492,37 @@ public: else return m_cancel_callback (phase, m_cancel_callback_baton); } + + // Allows the expression contents to be remapped to point to the specified file and line + // using #line directives. + void + SetPoundLine (const char *path, uint32_t line) const + { + if (path && path[0]) + { + m_pound_line_file = path; + m_pound_line_line = line; + } + else + { + m_pound_line_file.clear(); + m_pound_line_line = 0; + } + } + + const char * + GetPoundLineFilePath () const + { + if (m_pound_line_file.empty()) + return NULL; + return m_pound_line_file.c_str(); + } + + uint32_t + GetPoundLineLine () const + { + return m_pound_line_line; + } void SetResultIsInternal (bool b) @@ -493,13 +548,20 @@ private: bool m_stop_others; bool m_debug; bool m_trap_exceptions; + bool m_repl; bool m_generate_debug_info; + bool m_ansi_color_errors; bool m_result_is_internal; lldb::DynamicValueType m_use_dynamic; uint32_t m_timeout_usec; uint32_t m_one_thread_timeout_usec; lldb::ExpressionCancelCallback m_cancel_callback; void *m_cancel_callback_baton; + // If m_pound_line_file is not empty and m_pound_line_line is non-zero, + // use #line %u "%s" before the expression content to remap where the source + // originates + mutable std::string m_pound_line_file; + mutable uint32_t m_pound_line_line; }; //---------------------------------------------------------------------- @@ -1504,8 +1566,11 @@ public: lldb::SearchFilterSP GetSearchFilterForModuleAndCUList (const FileSpecList *containingModules, const FileSpecList *containingSourceFiles); + + lldb::REPLSP + GetREPL (lldb::LanguageType, bool can_create); -protected: +protected: //------------------------------------------------------------------ // Member variables. //------------------------------------------------------------------ @@ -1528,6 +1593,9 @@ protected: PathMappingList m_image_search_paths; TypeSystemMap m_scratch_type_system_map; + typedef std::map<lldb::LanguageType, lldb::REPLSP> REPLMap; + REPLMap m_repl_map; + lldb::ClangASTImporterUP m_ast_importer_ap; lldb::ClangModulesDeclVendorUP m_clang_modules_decl_vendor_ap; Modified: lldb/trunk/include/lldb/Utility/AnsiTerminal.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Utility/AnsiTerminal.h?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/include/lldb/Utility/AnsiTerminal.h (original) +++ lldb/trunk/include/lldb/Utility/AnsiTerminal.h Mon Oct 19 18:11:07 2015 @@ -41,8 +41,13 @@ #define ANSI_CTRL_CONCEAL 8 #define ANSI_CTRL_CROSSED_OUT 9 -#define ANSI_ESC_START "\033[" -#define ANSI_ESC_END "m" +#define ANSI_ESC_START "\033[" +#define ANSI_ESC_END "m" + +#define ANSI_STR(s) #s +#define ANSI_DEF_STR(s) ANSI_STR(s) + +#define ANSI_ESCAPE1(s) ANSI_ESC_START ANSI_DEF_STR(s) ANSI_ESC_END #define ANSI_1_CTRL(ctrl1) "\033["##ctrl1 ANSI_ESC_END #define ANSI_2_CTRL(ctrl1,ctrl2) "\033["##ctrl1";"##ctrl2 ANSI_ESC_END Modified: lldb/trunk/include/lldb/lldb-forward.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/include/lldb/lldb-forward.h (original) +++ lldb/trunk/include/lldb/lldb-forward.h Mon Oct 19 18:11:07 2015 @@ -183,6 +183,7 @@ class RegisterLocation; class RegisterLocationList; class RegisterValue; class RegularExpression; +class REPL; class Scalar; class ScriptInterpreter; class ScriptInterpreterLocker; @@ -382,6 +383,7 @@ namespace lldb { typedef std::shared_ptr<lldb_private::Queue> QueueSP; typedef std::weak_ptr<lldb_private::Queue> QueueWP; typedef std::shared_ptr<lldb_private::QueueItem> QueueItemSP; + typedef std::shared_ptr<lldb_private::REPL> REPLSP; typedef std::shared_ptr<lldb_private::ScriptSummaryFormat> ScriptSummaryFormatSP; typedef std::shared_ptr<lldb_private::ScriptInterpreter> ScriptInterpreterSP; typedef std::unique_ptr<lldb_private::ScriptInterpreter> ScriptInterpreterUP; 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=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/include/lldb/lldb-private-interfaces.h (original) +++ lldb/trunk/include/lldb/lldb-private-interfaces.h Mon Oct 19 18:11:07 2015 @@ -49,6 +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 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/lldb.xcodeproj/project.pbxproj URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/lldb.xcodeproj/project.pbxproj (original) +++ lldb/trunk/lldb.xcodeproj/project.pbxproj Mon Oct 19 18:11:07 2015 @@ -668,6 +668,7 @@ 449ACC98197DEA0B008D175E /* FastDemangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 449ACC96197DE9EC008D175E /* FastDemangle.cpp */; }; 490A36C0180F0E6F00BA31F8 /* PlatformWindows.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 490A36BD180F0E6F00BA31F8 /* PlatformWindows.cpp */; }; 490A966B1628C3BF00F0002E /* SBDeclaration.h in Headers */ = {isa = PBXBuildFile; fileRef = 9452573816262CEF00325455 /* SBDeclaration.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4939EA8D1BD56B6D00084382 /* REPL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4939EA8C1BD56B6D00084382 /* REPL.cpp */; }; 494260DA14579144003C1C78 /* VerifyDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 494260D914579144003C1C78 /* VerifyDecl.cpp */; }; 4959511F1A1BC4BC00F6F8FC /* ClangModulesDeclVendor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4959511E1A1BC4BC00F6F8FC /* ClangModulesDeclVendor.cpp */; }; 4966DCC4148978A10028481B /* ClangExternalASTSourceCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4966DCC3148978A10028481B /* ClangExternalASTSourceCommon.cpp */; }; @@ -2254,6 +2255,8 @@ 491193501226386000578B7F /* ASTStructExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTStructExtractor.cpp; path = ExpressionParser/Clang/ASTStructExtractor.cpp; sourceTree = "<group>"; }; 49307AAD11DEA4D90081F992 /* IRForTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRForTarget.cpp; path = ExpressionParser/Clang/IRForTarget.cpp; sourceTree = "<group>"; }; 49307AB111DEA4F20081F992 /* IRForTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRForTarget.h; path = ExpressionParser/Clang/IRForTarget.h; sourceTree = "<group>"; }; + 4939EA8B1BD56B3700084382 /* REPL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = REPL.h; path = include/lldb/Expression/REPL.h; sourceTree = "<group>"; }; + 4939EA8C1BD56B6D00084382 /* REPL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = REPL.cpp; path = source/Expression/REPL.cpp; sourceTree = "<group>"; }; 494260D7145790D5003C1C78 /* VerifyDecl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = VerifyDecl.h; path = include/lldb/Symbol/VerifyDecl.h; sourceTree = "<group>"; }; 494260D914579144003C1C78 /* VerifyDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VerifyDecl.cpp; path = source/Symbol/VerifyDecl.cpp; sourceTree = "<group>"; }; 49445C2512245E3600C11A81 /* ClangExpressionParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangExpressionParser.cpp; path = ExpressionParser/Clang/ClangExpressionParser.cpp; sourceTree = "<group>"; }; @@ -4447,6 +4450,8 @@ 496B01581406DE8900F830D5 /* IRInterpreter.cpp */, 49DCF6FF170E6FD90092F75E /* Materializer.h */, 49DCF700170E70120092F75E /* Materializer.cpp */, + 4939EA8B1BD56B3700084382 /* REPL.h */, + 4939EA8C1BD56B6D00084382 /* REPL.cpp */, ); name = Expression; sourceTree = "<group>"; @@ -6371,6 +6376,7 @@ 2689005F13353E0E00698AC0 /* ClangFunctionCaller.cpp in Sources */, 2689006013353E0E00698AC0 /* ClangExpressionDeclMap.cpp in Sources */, 2689006113353E0E00698AC0 /* ClangExpressionParser.cpp in Sources */, + 4939EA8D1BD56B6D00084382 /* REPL.cpp in Sources */, B5EFAE861AE53B1D007059F3 /* RegisterContextFreeBSD_arm.cpp in Sources */, 2689006313353E0E00698AC0 /* ClangPersistentVariables.cpp in Sources */, 2689006413353E0E00698AC0 /* ClangUserExpression.cpp in Sources */, Modified: lldb/trunk/source/Core/Debugger.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/source/Core/Debugger.cpp (original) +++ lldb/trunk/source/Core/Debugger.cpp Mon Oct 19 18:11:07 2015 @@ -156,6 +156,9 @@ g_properties[] = { "use-external-editor", OptionValue::eTypeBoolean , true, false, NULL, NULL, "Whether to use an external editor or not." }, { "use-color", OptionValue::eTypeBoolean , true, true , NULL, NULL, "Whether to use Ansi color codes or not." }, { "auto-one-line-summaries", OptionValue::eTypeBoolean , true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." }, +{ "auto-indent", OptionValue::eTypeBoolean , true, true , NULL, NULL, "If true, LLDB will auto indent/outdent code. Currently only supported in the REPL (default: true)." }, +{ "print-decls", OptionValue::eTypeBoolean , true, true , NULL, NULL, "If true, LLDB will print the values of variables declared in an expression. Currently only supported in the REPL (default: true)." }, +{ "tab-size", OptionValue::eTypeUInt64 , true, 4 , NULL, NULL, "The tab size to use when indenting code in multi-line input mode (default: 4)." }, { "escape-non-printables", OptionValue::eTypeBoolean , true, true, NULL, NULL, "If true, LLDB will automatically escape non-printable and escape characters when formatting strings." }, { NULL, OptionValue::eTypeInvalid , true, 0 , NULL, NULL, NULL } }; @@ -177,6 +180,9 @@ enum ePropertyUseExternalEditor, ePropertyUseColor, ePropertyAutoOneLineSummaries, + ePropertyAutoIndent, + ePropertyPrintDecls, + ePropertyTabSize, ePropertyEscapeNonPrintables }; @@ -392,6 +398,49 @@ Debugger::GetEscapeNonPrintables () cons return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true); } +bool +Debugger::GetAutoIndent () const +{ + const uint32_t idx = ePropertyAutoIndent; + return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true); +} + +bool +Debugger::SetAutoIndent (bool b) +{ + const uint32_t idx = ePropertyAutoIndent; + return m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b); +} + +bool +Debugger::GetPrintDecls () const +{ + const uint32_t idx = ePropertyPrintDecls; + return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true); +} + +bool +Debugger::SetPrintDecls (bool b) +{ + const uint32_t idx = ePropertyPrintDecls; + return m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b); +} + +uint32_t +Debugger::GetTabSize () const +{ + const uint32_t idx = ePropertyTabSize; + return m_collection_sp->GetPropertyAtIndexAsUInt64 (NULL, idx, g_properties[idx].default_uint_value); +} + +bool +Debugger::SetTabSize (uint32_t tab_size) +{ + const uint32_t idx = ePropertyTabSize; + return m_collection_sp->SetPropertyAtIndexAsUInt64 (NULL, idx, tab_size); +} + + #pragma mark Debugger //const DebuggerPropertiesSP & @@ -919,6 +968,12 @@ Debugger::IsTopIOHandler (const lldb::IO return m_input_reader_stack.IsTop (reader_sp); } +bool +Debugger::CheckTopIOHandlerTypes (IOHandler::Type top_type, IOHandler::Type second_top_type) +{ + return m_input_reader_stack.CheckTopIOHandlerTypes (top_type, second_top_type); +} + void Debugger::PrintAsync (const char *s, size_t len, bool is_stdout) { @@ -1684,6 +1739,12 @@ Debugger::IOHandlerThread (lldb::thread_ } bool +Debugger::HasIOHandlerThread() +{ + return m_io_handler_thread.IsJoinable(); +} + +bool Debugger::StartIOHandlerThread() { if (!m_io_handler_thread.IsJoinable()) @@ -1706,6 +1767,17 @@ Debugger::StopIOHandlerThread() } } +void +Debugger::JoinIOHandlerThread() +{ + if (HasIOHandlerThread()) + { + thread_result_t result; + m_io_handler_thread.Join(&result); + m_io_handler_thread = LLDB_INVALID_HOST_THREAD; + } +} + Target * Debugger::GetDummyTarget() { Modified: lldb/trunk/source/Core/PluginManager.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/PluginManager.cpp?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/source/Core/PluginManager.cpp (original) +++ lldb/trunk/source/Core/PluginManager.cpp Mon Oct 19 18:11:07 2015 @@ -2648,6 +2648,106 @@ PluginManager::GetTypeSystemEnumerateSup return NULL; } +#pragma mark REPL + +struct REPLInstance +{ + REPLInstance() : + name(), + description(), + create_callback(NULL) + { + } + + ConstString name; + std::string description; + REPLCreateInstance create_callback; +}; + +typedef std::vector<REPLInstance> REPLInstances; + +static Mutex & +GetREPLMutex () +{ + static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); + return g_instances_mutex; +} + +static REPLInstances & +GetREPLInstances () +{ + static REPLInstances g_instances; + return g_instances; +} + +bool +PluginManager::RegisterPlugin (const ConstString &name, + const char *description, + REPLCreateInstance create_callback) +{ + if (create_callback) + { + REPLInstance instance; + assert ((bool)name); + instance.name = name; + if (description && description[0]) + instance.description = description; + instance.create_callback = create_callback; + Mutex::Locker locker (GetREPLMutex ()); + GetREPLInstances ().push_back (instance); + } + return false; +} + +bool +PluginManager::UnregisterPlugin (REPLCreateInstance create_callback) +{ + if (create_callback) + { + Mutex::Locker locker (GetREPLMutex ()); + REPLInstances &instances = GetREPLInstances (); + + REPLInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++ pos) + { + if (pos->create_callback == create_callback) + { + instances.erase(pos); + return true; + } + } + } + return false; +} + +REPLCreateInstance +PluginManager::GetREPLCreateCallbackAtIndex (uint32_t idx) +{ + Mutex::Locker locker (GetREPLMutex ()); + REPLInstances &instances = GetREPLInstances (); + if (idx < instances.size()) + return instances[idx].create_callback; + return NULL; +} + +REPLCreateInstance +PluginManager::GetREPLCreateCallbackForPluginName (const ConstString &name) +{ + if (name) + { + Mutex::Locker locker (GetREPLMutex ()); + REPLInstances &instances = GetREPLInstances (); + + REPLInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++ pos) + { + if (name == pos->name) + return pos->create_callback; + } + } + return NULL; +} + #pragma mark PluginManager void Added: lldb/trunk/source/Expression/REPL.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/REPL.cpp?rev=250753&view=auto ============================================================================== --- lldb/trunk/source/Expression/REPL.cpp (added) +++ lldb/trunk/source/Expression/REPL.cpp Mon Oct 19 18:11:07 2015 @@ -0,0 +1,650 @@ +//===-- REPL.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Expression/ExpressionVariable.h" +#include "lldb/Expression/REPL.h" +#include "lldb/Expression/UserExpression.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/AnsiTerminal.h" + +using namespace lldb_private; + +lldb::REPLSP +REPL::Create(lldb::LanguageType language, Target *target) +{ + uint32_t idx = 0; + lldb::REPLSP ret; + + while (REPLCreateInstance create_instance = PluginManager::GetREPLCreateCallbackAtIndex(idx++)) + { + ret = (*create_instance)(language, target); + if (ret) + { + break; + } + } + + return ret; +} + +REPL::REPL(LLVMCastKind kind, Target &target) : + m_target(target), + m_kind(kind) +{ + // Make sure all option values have sane defaults + Debugger &debugger = m_target.GetDebugger(); + CommandInterpreter &ci = debugger.GetCommandInterpreter(); + m_format_options.OptionParsingStarting(ci); + m_varobj_options.OptionParsingStarting(ci); + m_command_options.OptionParsingStarting(ci); + + // Default certain settings for REPL regardless of the global settings. + m_command_options.unwind_on_error = false; + m_command_options.ignore_breakpoints = false; + m_command_options.debug = false; +} + +std::string +REPL::GetSourcePath() +{ + ConstString file_basename = GetSourceFileBasename(); + + FileSpec tmpdir_file_spec; + if (HostInfo::GetLLDBPath (lldb::ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) + { + tmpdir_file_spec.GetFilename().SetCString(file_basename.AsCString()); + m_repl_source_path = std::move(tmpdir_file_spec.GetPath()); + } + else + { + tmpdir_file_spec = FileSpec("/tmp", false); + tmpdir_file_spec.AppendPathComponent(file_basename.AsCString()); + } + + return tmpdir_file_spec.GetPath(); +} + +REPL::~REPL() +{ +} + +lldb::IOHandlerSP +REPL::GetIOHandler() +{ + if (!m_io_handler_sp) + { + Debugger &debugger = m_target.GetDebugger(); + m_io_handler_sp.reset (new IOHandlerEditline (debugger, + IOHandler::Type::REPL, + "lldb-repl", // Name of input reader for history + "> ", // prompt + ". ", // Continuation prompt + true, // Multi-line + true, // The REPL prompt is always colored + 1, // Line number + *this)); + + // Don't exit if CTRL+C is pressed + static_cast<IOHandlerEditline *>(m_io_handler_sp.get())->SetInterruptExits(false); + + if (m_io_handler_sp->GetIsInteractive() && m_io_handler_sp->GetIsRealTerminal()) + { + m_indent_str.assign (debugger.GetTabSize(), ' '); + m_enable_auto_indent = debugger.GetAutoIndent(); + } + else + { + m_indent_str.clear(); + m_enable_auto_indent = false; + } + + } + return m_io_handler_sp; +} + +void +REPL::IOHandlerActivated (IOHandler &io_handler) +{ + lldb::ProcessSP process_sp = m_target.GetProcessSP(); + if (process_sp && process_sp->IsAlive()) + return; + lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile()); + error_sp->Printf("REPL requires a running target process.\n"); + io_handler.SetIsDone(true); +} + +bool +REPL::IOHandlerInterrupt (IOHandler &io_handler) +{ + return false; +} + +void +REPL::IOHandlerInputInterrupted (IOHandler &io_handler, + std::string &line) +{ +} + +const char * +REPL::IOHandlerGetFixIndentationCharacters () +{ + if (m_enable_auto_indent) + return GetAutoIndentCharacters(); + return NULL; +} + +ConstString +REPL::IOHandlerGetControlSequence (char ch) +{ + if (ch == 'd') + return ConstString(":quit\n"); + return ConstString(); +} + +const char * +REPL::IOHandlerGetCommandPrefix () +{ + return ":"; +} + +const char * +REPL::IOHandlerGetHelpPrologue () +{ + return "\nThe REPL (Read-Eval-Print-Loop) acts like an interpreter. " + "Valid statements, expressions, and declarations are immediately compiled and executed.\n\n" + "The complete set of LLDB debugging commands are also available as described below. Commands " + "must be prefixed with a colon at the REPL prompt (:quit for example.) Typing just a colon " + "followed by return will switch to the LLDB prompt.\n\n"; +} + +bool +REPL::IOHandlerIsInputComplete (IOHandler &io_handler, + StringList &lines) +{ + // Check for meta command + const size_t num_lines = lines.GetSize(); + if (num_lines == 1) + { + const char *first_line = lines.GetStringAtIndex(0); + if (first_line[0] == ':') + return true; // Meta command is a single line where that starts with ':' + } + + // Check if REPL input is done + std::string source_string (lines.CopyList()); + return SourceIsComplete(source_string); +} + +int +REPL::CalculateActualIndentation (const StringList &lines) +{ + std::string last_line = lines[lines.GetSize() - 1]; + + int actual_indent = 0; + for (char &ch : last_line) + { + if (ch != ' ') break; + ++actual_indent; + } + + return actual_indent; +} + +int +REPL::IOHandlerFixIndentation (IOHandler &io_handler, + const StringList &lines, + int cursor_position) +{ + if (!m_enable_auto_indent) return 0; + + if (!lines.GetSize()) + { + return 0; + } + + int tab_size = io_handler.GetDebugger().GetTabSize(); + + lldb::offset_t desired_indent = GetDesiredIndentation(lines, + cursor_position, + tab_size); + + int actual_indent = REPL::CalculateActualIndentation(lines); + + if (desired_indent == LLDB_INVALID_OFFSET) + return 0; + + return (int)desired_indent - actual_indent; +} + +void +REPL::IOHandlerInputComplete (IOHandler &io_handler, std::string &code) +{ + lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile()); + bool extra_line = false; + bool did_quit = false; + + if (code.empty()) + { + m_code.AppendString(""); + static_cast<IOHandlerEditline &>(io_handler).SetBaseLineNumber(m_code.GetSize()+1); + } + else + { + Debugger &debugger = m_target.GetDebugger(); + CommandInterpreter &ci = debugger.GetCommandInterpreter(); + extra_line = ci.GetSpaceReplPrompts(); + + ExecutionContext exe_ctx (m_target.GetProcessSP()->GetThreadList().GetSelectedThread()->GetSelectedFrame().get()); + + lldb::ProcessSP process_sp(exe_ctx.GetProcessSP()); + + if (code[0] == ':') + { + // Meta command + // Strip the ':' + code.erase(0, 1); + if (Args::StripSpaces (code)) + { + // "lldb" was followed by arguments, so just execute the command dump the results + + // Turn off prompt on quit in case the user types ":quit" + const bool saved_prompt_on_quit = ci.GetPromptOnQuit(); + if (saved_prompt_on_quit) + ci.SetPromptOnQuit(false); + + // Execute the command + CommandReturnObject result; + result.SetImmediateOutputStream(output_sp); + result.SetImmediateErrorStream(error_sp); + ci.HandleCommand(code.c_str(), eLazyBoolNo, result); + + if (saved_prompt_on_quit) + ci.SetPromptOnQuit(true); + + if (result.GetStatus() == lldb::eReturnStatusQuit) + { + did_quit = true; + io_handler.SetIsDone(true); + if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) + { + // We typed "quit" or an alias to quit so we need to check if the + // command interpreter is above us and tell it that it is done as well + // so we don't drop back into the command interpreter if we have already + // quit + lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler()); + if (io_handler_sp) + io_handler_sp->SetIsDone(true); + } + } + } + else + { + // ":" was followed by no arguments, so push the LLDB command prompt + if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) + { + // If the user wants to get back to the command interpreter and the + // command interpreter is what launched the REPL, then just let the + // REPL exit and fall back to the command interpreter. + io_handler.SetIsDone(true); + } + else + { + // The REPL wasn't launched the by the command interpreter, it is the + // base IOHandler, so we need to get the command interpreter and + lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler()); + if (io_handler_sp) + { + io_handler_sp->SetIsDone(false); + debugger.PushIOHandler(ci.GetIOHandler()); + } + } + } + } + else + { + // Unwind any expression we might have been running in case our REPL + // expression crashed and the user was looking around + if (m_dedicated_repl_mode) + { + Thread *thread = exe_ctx.GetThreadPtr(); + if (thread && thread->UnwindInnermostExpression().Success()) + { + thread->SetSelectedFrameByIndex(0, false); + exe_ctx.SetFrameSP(thread->GetSelectedFrame()); + } + } + + const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors(); + + EvaluateExpressionOptions expr_options; + expr_options.SetCoerceToId(m_varobj_options.use_objc); + expr_options.SetUnwindOnError(m_command_options.unwind_on_error); + expr_options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints); + expr_options.SetKeepInMemory(true); + expr_options.SetUseDynamic(m_varobj_options.use_dynamic); + expr_options.SetTryAllThreads(m_command_options.try_all_threads); + expr_options.SetGenerateDebugInfo(true); + expr_options.SetREPLEnabled (true); + expr_options.SetColorizeErrors(colorize_err); + expr_options.SetPoundLine(m_repl_source_path.c_str(), m_code.GetSize() + 1); + if (m_command_options.timeout > 0) + expr_options.SetTimeoutUsec(m_command_options.timeout); + else + expr_options.SetTimeoutUsec(0); + + expr_options.SetLanguage(GetLanguage()); + + PersistentExpressionState *persistent_state = m_target.GetPersistentExpressionStateForLanguage(GetLanguage()); + + const size_t var_count_before = persistent_state->GetSize(); + + const char *expr_prefix = NULL; + lldb::ValueObjectSP result_valobj_sp; + Error error; + lldb::ModuleSP jit_module_sp; + lldb::ExpressionResults execution_results = UserExpression::Evaluate (exe_ctx, + expr_options, + code.c_str(), + expr_prefix, + result_valobj_sp, + error, + 0, // Line offset + &jit_module_sp); + + //CommandInterpreter &ci = debugger.GetCommandInterpreter(); + + if (process_sp && process_sp->IsAlive()) + { + bool add_to_code = true; + bool handled = false; + if (result_valobj_sp) + { + lldb::Format format = m_format_options.GetFormat(); + + if (result_valobj_sp->GetError().Success()) + { + handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp); + } + else if (result_valobj_sp->GetError().GetError() == UserExpression::kNoResult) + { + if (format != lldb::eFormatVoid && debugger.GetNotifyVoid()) + { + error_sp->PutCString("(void)\n"); + handled = true; + } + } + } + + if (debugger.GetPrintDecls()) + { + for (size_t vi = var_count_before, ve = persistent_state->GetSize(); + vi != ve; + ++vi) + { + lldb::ExpressionVariableSP persistent_var_sp = persistent_state->GetVariableAtIndex(vi); + lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject(); + + PrintOneVariable(debugger, output_sp, valobj_sp, persistent_var_sp.get()); + } + } + + + if (!handled) + { + bool useColors = error_sp->GetFile().GetIsTerminalWithColors(); + switch (execution_results) + { + case lldb::eExpressionSetupError: + case lldb::eExpressionParseError: + add_to_code = false; + // Fall through + case lldb::eExpressionDiscarded: + error_sp->Printf("%s\n", error.AsCString()); + break; + + case lldb::eExpressionCompleted: + break; + case lldb::eExpressionInterrupted: + if (useColors) { + error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED)); + error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD)); + } + error_sp->Printf("Execution interrupted. "); + if (useColors) error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL)); + error_sp->Printf("Enter code to recover and continue.\nEnter LLDB commands to investigate (type :help for assistance.)\n"); + break; + + case lldb::eExpressionHitBreakpoint: + // Breakpoint was hit, drop into LLDB command interpreter + if (useColors) { + error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED)); + error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD)); + } + output_sp->Printf("Execution stopped at breakpoint. "); + if (useColors) error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL)); + output_sp->Printf("Enter LLDB commands to investigate (type help for assistance.)\n"); + { + lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler()); + if (io_handler_sp) + { + io_handler_sp->SetIsDone(false); + debugger.PushIOHandler(ci.GetIOHandler()); + } + } + break; + + case lldb::eExpressionTimedOut: + error_sp->Printf("error: timeout\n"); + if (error.AsCString()) + error_sp->Printf("error: %s\n", error.AsCString()); + break; + case lldb::eExpressionResultUnavailable: + // Shoulnd't happen??? + error_sp->Printf("error: could not fetch result -- %s\n", error.AsCString()); + break; + case lldb::eExpressionStoppedForDebug: + // Shoulnd't happen??? + error_sp->Printf("error: stopped for debug -- %s\n", error.AsCString()); + break; + } + } + + if (add_to_code) + { + const uint32_t new_default_line = m_code.GetSize() + 1; + + m_code.SplitIntoLines(code); + + // Update our code on disk + if (!m_repl_source_path.empty()) + { + lldb_private::File file (m_repl_source_path.c_str(), + File::eOpenOptionWrite | File::eOpenOptionTruncate | File::eOpenOptionCanCreate, + lldb::eFilePermissionsFileDefault); + std::string code (m_code.CopyList()); + code.append(1, '\n'); + size_t bytes_written = code.size(); + file.Write(code.c_str(), bytes_written); + file.Close(); + + // Now set the default file and line to the REPL source file + m_target.GetSourceManager().SetDefaultFileAndLine(FileSpec(m_repl_source_path.c_str(), false), new_default_line); + } + static_cast<IOHandlerEditline &>(io_handler).SetBaseLineNumber(m_code.GetSize()+1); + } + if (extra_line) + { + fprintf(output_sp->GetFile().GetStream(), "\n"); + } + } + } + + // Don't complain about the REPL process going away if we are in the process of quitting. + if (!did_quit && (!process_sp || !process_sp->IsAlive())) + { + error_sp->Printf("error: REPL process is no longer alive, exiting REPL\n"); + io_handler.SetIsDone(true); + } + } +} + +int +REPL::IOHandlerComplete (IOHandler &io_handler, + const char *current_line, + const char *cursor, + const char *last_char, + int skip_first_n_matches, + int max_matches, + StringList &matches) +{ + matches.Clear(); + + llvm::StringRef line (current_line, cursor - current_line); + + // Complete an LLDB command if the first character is a colon... + if (!line.empty() && line[0] == ':') + { + Debugger &debugger = m_target.GetDebugger(); + + // auto complete LLDB commands + const char *lldb_current_line = line.substr(1).data(); + return debugger.GetCommandInterpreter().HandleCompletion (lldb_current_line, + cursor, + last_char, + skip_first_n_matches, + max_matches, + matches); + } + + // Strip spaces from the line and see if we had only spaces + line = line.ltrim(); + if (line.empty()) + { + // Only spaces on this line, so just indent + matches.AppendString(m_indent_str); + return 1; + } + + std::string current_code; + current_code.append(m_code.CopyList()); + + IOHandlerEditline &editline = static_cast<IOHandlerEditline &>(io_handler); + const StringList *current_lines = editline.GetCurrentLines(); + if (current_lines) + { + const uint32_t current_line_idx = editline.GetCurrentLineIndex(); + + if (current_line_idx < current_lines->GetSize()) + { + for (uint32_t i=0; i<current_line_idx; ++i) + { + const char *line_cstr = current_lines->GetStringAtIndex(i); + if (line_cstr) + { + current_code.append("\n"); + current_code.append (line_cstr); + } + } + } + } + + if (cursor > current_line) + { + current_code.append("\n"); + current_code.append(current_line, cursor - current_line); + } + + return CompleteCode(current_code, matches); +} + +bool +QuitCommandOverrideCallback(void *baton, const char **argv) +{ + Target *target = (Target *)baton; + lldb::ProcessSP process_sp (target->GetProcessSP()); + if (process_sp) + { + process_sp->Destroy(false); + process_sp->GetTarget().GetDebugger().ClearIOHandlers(); + } + return false; +} + +Error +REPL::RunLoop () +{ + Error error; + + error = DoInitialization(); + m_repl_source_path = GetSourcePath(); + + if (!error.Success()) + return error; + + Debugger &debugger = m_target.GetDebugger(); + + lldb::IOHandlerSP io_handler_sp (GetIOHandler()); + + FileSpec save_default_file; + uint32_t save_default_line = 0; + + if (!m_repl_source_path.empty()) + { + // Save the current default file and line + m_target.GetSourceManager().GetDefaultFileAndLine(save_default_file, save_default_line); + } + + debugger.PushIOHandler(io_handler_sp); + + // Check if we are in dedicated REPL mode where LLDB was start with the "--repl" option + // from the command line. Currently we know this by checking if the debugger already + // has a IOHandler thread. + if (!debugger.HasIOHandlerThread()) + { + // The debugger doesn't have an existing IOHandler thread, so this must be + // dedicated REPL mode... + m_dedicated_repl_mode = true; + debugger.StartIOHandlerThread(); + std::string command_name_str ("quit"); + CommandObject *cmd_obj = debugger.GetCommandInterpreter().GetCommandObjectForCommand(command_name_str); + if (cmd_obj) + { + assert(command_name_str.empty()); + cmd_obj->SetOverrideCallback (QuitCommandOverrideCallback, &m_target); + } + } + + // Wait for the REPL command interpreter to get popped + io_handler_sp->WaitForPop(); + + if (m_dedicated_repl_mode) + { + // If we were in dedicated REPL mode we would have started the + // IOHandler thread, and we should kill our process + lldb::ProcessSP process_sp = m_target.GetProcessSP(); + if (process_sp && process_sp->IsAlive()) + process_sp->Destroy(false); + + // Wait for the IO handler thread to exit (TODO: don't do this if the IO handler thread already exists...) + debugger.JoinIOHandlerThread(); + } + + // Restore the default file and line + if (save_default_file && save_default_line != 0) + m_target.GetSourceManager().SetDefaultFileAndLine(save_default_file, save_default_line); + return error; +} Modified: lldb/trunk/source/Expression/UserExpression.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/UserExpression.cpp?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/source/Expression/UserExpression.cpp (original) +++ lldb/trunk/source/Expression/UserExpression.cpp Mon Oct 19 18:11:07 2015 @@ -465,7 +465,9 @@ UserExpression::Evaluate (ExecutionConte const char *expr_cstr, const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp, - Error &error) + Error &error, + uint32_t line_offset, + lldb::ModuleSP *jit_module_sp_ptr) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); @@ -567,6 +569,10 @@ UserExpression::Evaluate (ExecutionConte } else { + // If a pointer to a lldb::ModuleSP was passed in, return the JIT'ed module if one was created + if (jit_module_sp_ptr && user_expression_sp->m_execution_unit_sp) + *jit_module_sp_ptr = user_expression_sp->m_execution_unit_sp->GetJITModule(); + lldb::ExpressionVariableSP expr_result; if (execution_policy == eExecutionPolicyNever && Modified: lldb/trunk/source/Host/common/File.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/File.cpp?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/source/Host/common/File.cpp (original) +++ lldb/trunk/source/Host/common/File.cpp Mon Oct 19 18:11:07 2015 @@ -22,6 +22,8 @@ #include <sys/ioctl.h> #endif +#include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors() + #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" @@ -1051,7 +1053,11 @@ File::CalculateInteractiveAndTerminal () if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0) { if (window_size.ws_col > 0) + { m_is_real_terminal = eLazyBoolYes; + if (llvm::sys::Process::FileDescriptorHasColors(fd)) + m_supports_colors = eLazyBoolYes; + } } } #endif @@ -1074,3 +1080,11 @@ File::GetIsRealTerminal () return m_is_real_terminal == eLazyBoolYes; } +bool +File::GetIsTerminalWithColors () +{ + if (m_supports_colors == eLazyBoolCalculate) + CalculateInteractiveAndTerminal(); + return m_supports_colors == eLazyBoolYes; +} + Modified: lldb/trunk/source/Interpreter/CommandInterpreter.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandInterpreter.cpp?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/CommandInterpreter.cpp (original) +++ lldb/trunk/source/Interpreter/CommandInterpreter.cpp Mon Oct 19 18:11:07 2015 @@ -85,6 +85,7 @@ g_properties[] = { "expand-regex-aliases", OptionValue::eTypeBoolean, true, false, nullptr, nullptr, "If true, regular expression alias commands will show the expanded command that will be executed. This can be used to debug new regular expression alias commands." }, { "prompt-on-quit", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case." }, { "stop-command-source-on-error", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, LLDB will stop running a 'command source' script upon encountering an error." }, + { "space-repl-prompts", OptionValue::eTypeBoolean, true, false, nullptr, nullptr, "If true, blank lines will be printed between between REPL submissions." }, { nullptr , OptionValue::eTypeInvalid, true, 0 , nullptr, nullptr, nullptr } }; @@ -92,7 +93,8 @@ enum { ePropertyExpandRegexAliases = 0, ePropertyPromptOnQuit = 1, - ePropertyStopCmdSourceOnError = 2 + ePropertyStopCmdSourceOnError = 2, + eSpaceReplPrompts = 3 }; ConstString & @@ -167,6 +169,13 @@ CommandInterpreter::GetStopCmdSourceOnEr return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0); } +bool +CommandInterpreter::GetSpaceReplPrompts () const +{ + const uint32_t idx = eSpaceReplPrompts; + return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0); +} + void CommandInterpreter::Initialize () { Modified: lldb/trunk/source/Target/Target.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=250753&r1=250752&r2=250753&view=diff ============================================================================== --- lldb/trunk/source/Target/Target.cpp (original) +++ lldb/trunk/source/Target/Target.cpp Mon Oct 19 18:11:07 2015 @@ -31,6 +31,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" #include "lldb/Core/ValueObject.h" +#include "lldb/Expression/REPL.h" #include "lldb/Expression/UserExpression.h" #include "Plugins/ExpressionParser/Clang/ClangASTSource.h" #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" @@ -211,6 +212,37 @@ Target::GetProcessSP () const return m_process_sp; } +lldb::REPLSP +Target::GetREPL (lldb::LanguageType language, bool can_create) +{ + if (language == eLanguageTypeUnknown) + { + return REPLSP(); // must provide a language + } + + REPLMap::iterator pos = m_repl_map.find(language); + + if (pos != m_repl_map.end()) + { + return pos->second; + } + + if (!can_create) + { + return lldb::REPLSP(); + } + + lldb::REPLSP ret = REPL::Create(language, this); + + if (ret) + { + m_repl_map[language] = ret; + return m_repl_map[language]; + } + + return nullptr; +} + void Target::Destroy() { _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits