[Lldb-commits] [lldb] r250753 - Added the concept of a Read-Eval-Print-Loop to LLDB.
Jim Ingham via lldb-commits
lldb-commits at lists.llvm.org
Mon Oct 19 16:37:51 PDT 2015
> On Oct 19, 2015, at 4:18 PM, Zachary Turner via lldb-commits <lldb-commits at lists.llvm.org> wrote:
>
> I think this is going to break the CMake build. Can you update the relevant CMakeLists.txt file?
>
> Also, are there any tests for this?
This doesn't actually add a REPL for any of the languages that the current LLDB sources support. You could probably make a fake REPL just for testing, but that seems like make-work. Seems to me better to wait till an actual REPL shows up and write tests using that.
Jim
>
> On Mon, Oct 19, 2015 at 4:13 PM Sean Callanan via lldb-commits <lldb-commits at lists.llvm.org> wrote:
> 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
> +
> _______________________________________________
> lldb-commits mailing list
> lldb-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
More information about the lldb-commits
mailing list