diff options
Diffstat (limited to 'lldb')
73 files changed, 3062 insertions, 1957 deletions
diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/lldb/include/lldb/Breakpoint/BreakpointLocation.h index b2b8ebdc55e..c8b66629317 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointLocation.h +++ b/lldb/include/lldb/Breakpoint/BreakpointLocation.h @@ -74,6 +74,9 @@ public: //------------------------------------------------------------------ Breakpoint & GetBreakpoint (); + + Target & + GetTarget(); //------------------------------------------------------------------ /// Determines whether we should stop due to a hit at this @@ -458,7 +461,7 @@ private: Breakpoint &m_owner; ///< The breakpoint that produced this object. std::unique_ptr<BreakpointOptions> m_options_ap; ///< Breakpoint options pointer, NULL if we're using our breakpoint's options. lldb::BreakpointSiteSP m_bp_site_sp; ///< Our breakpoint site (it may be shared by more than one location.) - lldb::ClangUserExpressionSP m_user_expression_sp; ///< The compiled expression to use in testing our condition. + lldb::UserExpressionSP m_user_expression_sp; ///< The compiled expression to use in testing our condition. Mutex m_condition_mutex; ///< Guards parsing and evaluation of the condition, which could be evaluated by multiple processes. size_t m_condition_hash; ///< For testing whether the condition source code changed. diff --git a/lldb/include/lldb/Breakpoint/Watchpoint.h b/lldb/include/lldb/Breakpoint/Watchpoint.h index 14c2ae75b71..b6c3c1c9fc8 100644 --- a/lldb/include/lldb/Breakpoint/Watchpoint.h +++ b/lldb/include/lldb/Breakpoint/Watchpoint.h @@ -243,7 +243,7 @@ private: // the callback machinery. bool m_being_created; - std::unique_ptr<ClangUserExpression> m_condition_ap; // The condition to test. + std::unique_ptr<UserExpression> m_condition_ap; // The condition to test. void SetID(lldb::watch_id_t id) { m_loc_id = id; } diff --git a/lldb/include/lldb/Expression/ASTStructExtractor.h b/lldb/include/lldb/Expression/ASTStructExtractor.h index 1cba98b9ef3..af327ecfd01 100644 --- a/lldb/include/lldb/Expression/ASTStructExtractor.h +++ b/lldb/include/lldb/Expression/ASTStructExtractor.h @@ -13,7 +13,7 @@ #include "clang/Sema/SemaConsumer.h" #include "lldb/Core/ClangForward.h" #include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h" -#include "lldb/Expression/ClangFunction.h" +#include "lldb/Expression/ClangFunctionCaller.h" namespace lldb_private { @@ -21,9 +21,9 @@ namespace lldb_private { /// @class ASTStructExtractor ASTStructExtractor.h "lldb/Expression/ASTStructExtractor.h" /// @brief Extracts and describes the argument structure for a wrapped function. /// -/// This pass integrates with ClangFunction, which calls functions with custom +/// This pass integrates with ClangFunctionCaller, which calls functions with custom /// sets of arguments. To avoid having to implement the full calling convention -/// for the target's architecture, ClangFunction writes a simple wrapper +/// for the target's architecture, ClangFunctionCaller writes a simple wrapper /// function that takes a pointer to an argument structure that contains room /// for the address of the function to be called, the values of all its /// arguments, and room for the function's return value. @@ -49,12 +49,12 @@ public: /// /// @param[in] function /// The caller object whose members should be populated with information - /// about the argument struct. ClangFunction friends ASTStructExtractor + /// about the argument struct. ClangFunctionCaller friends ASTStructExtractor /// for this purpose. //---------------------------------------------------------------------- ASTStructExtractor(clang::ASTConsumer *passthrough, const char *struct_name, - ClangFunction &function); + ClangFunctionCaller &function); //---------------------------------------------------------------------- /// Destructor @@ -148,7 +148,7 @@ private: clang::Sema *m_sema; ///< The Sema to use. clang::Action *m_action; ///< The Sema to use, cast to an Action so it's usable. - ClangFunction &m_function; ///< The function to populate with information about the argument structure. + ClangFunctionCaller &m_function; ///< The function to populate with information about the argument structure. std::string m_struct_name; ///< The name of the structure to extract. }; diff --git a/lldb/include/lldb/Expression/ClangExpressionHelper.h b/lldb/include/lldb/Expression/ClangExpressionHelper.h new file mode 100644 index 00000000000..bb620def691 --- /dev/null +++ b/lldb/include/lldb/Expression/ClangExpressionHelper.h @@ -0,0 +1,79 @@ +//===-- ClangExpression.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ClangExpression_h_ +#define liblldb_ClangExpression_h_ + +// C Includes +// C++ Includes +#include <string> +#include <map> +#include <vector> + +// Other libraries and framework includes +// Project includes + +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" +#include "lldb/Core/ClangForward.h" +#include "lldb/Expression/ExpressionTypeSystemHelper.h" + +namespace lldb_private { + +class RecordingMemoryManager; + +//---------------------------------------------------------------------- +// ClangExpressionHelper +//---------------------------------------------------------------------- +class ClangExpressionHelper : public ExpressionTypeSystemHelper +{ +public: + static bool classof(const ExpressionTypeSystemHelper *ts) + { + return ts->getKind() == eKindClangHelper; + } + + ClangExpressionHelper () : + ExpressionTypeSystemHelper(ExpressionTypeSystemHelper::LLVMCastKind::eKindClangHelper) + { + } + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + virtual ~ClangExpressionHelper () + { + } + + //------------------------------------------------------------------ + /// Return the object that the parser should use when resolving external + /// values. May be NULL if everything should be self-contained. + //------------------------------------------------------------------ + virtual ClangExpressionDeclMap * + DeclMap () = 0; + + //------------------------------------------------------------------ + /// Return the object that the parser should allow to access ASTs. + /// May be NULL if the ASTs do not need to be transformed. + /// + /// @param[in] passthrough + /// The ASTConsumer that the returned transformer should send + /// the ASTs to after transformation. + //------------------------------------------------------------------ + virtual clang::ASTConsumer * + ASTTransformer (clang::ASTConsumer *passthrough) = 0; + + +protected: + +}; + +} // namespace lldb_private + +#endif // liblldb_ClangExpression_h_ diff --git a/lldb/include/lldb/Expression/ClangExpressionParser.h b/lldb/include/lldb/Expression/ClangExpressionParser.h index 1b78cb8d1e9..e828d1b6597 100644 --- a/lldb/include/lldb/Expression/ClangExpressionParser.h +++ b/lldb/include/lldb/Expression/ClangExpressionParser.h @@ -14,6 +14,7 @@ #include "lldb/Core/ArchSpec.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/Error.h" +#include "lldb/Expression/ExpressionParser.h" #include "lldb/Expression/IRForTarget.h" #include <string> @@ -34,7 +35,7 @@ class IRExecutionUnit; /// conversion to formats (DWARF bytecode, or JIT compiled machine code) /// that can be executed. //---------------------------------------------------------------------- -class ClangExpressionParser +class ClangExpressionParser : public ExpressionParser { public: //------------------------------------------------------------------ @@ -51,13 +52,13 @@ public: /// The expression to be parsed. //------------------------------------------------------------------ ClangExpressionParser (ExecutionContextScope *exe_scope, - ClangExpression &expr, + Expression &expr, bool generate_debug_info); //------------------------------------------------------------------ /// Destructor //------------------------------------------------------------------ - ~ClangExpressionParser (); + ~ClangExpressionParser () override; //------------------------------------------------------------------ /// Parse a single expression and convert it to IR using Clang. Don't @@ -71,7 +72,7 @@ public: /// success. //------------------------------------------------------------------ unsigned - Parse (Stream &stream); + Parse (Stream &stream) override; //------------------------------------------------------------------ /// Ready an already-parsed expression for execution, possibly @@ -116,30 +117,9 @@ public: std::shared_ptr<IRExecutionUnit> &execution_unit_sp, ExecutionContext &exe_ctx, bool &can_interpret, - lldb_private::ExecutionPolicy execution_policy); + lldb_private::ExecutionPolicy execution_policy) override; - //------------------------------------------------------------------ - /// Disassemble the machine code for a JITted function from the target - /// process's memory and print the result to a stream. - /// - /// @param[in] stream - /// The stream to print disassembly to. - /// - /// @param[in] exc_context - /// The execution context to get the machine code from. - /// - /// @return - /// The error generated. If .Success() is true, disassembly succeeded. - //------------------------------------------------------------------ - Error - DisassembleFunction (Stream &stream, - ExecutionContext &exe_ctx); - - bool - GetGenerateDebugInfo () const; - private: - ClangExpression & m_expr; ///< The expression to be parsed std::unique_ptr<llvm::LLVMContext> m_llvm_context; ///< The LLVM context to generate IR into std::unique_ptr<clang::FileManager> m_file_manager; ///< The Clang file manager object used by the compiler std::unique_ptr<clang::CompilerInstance> m_compiler; ///< The Clang compiler used to parse expressions into IR diff --git a/lldb/include/lldb/Expression/ClangFunctionCaller.h b/lldb/include/lldb/Expression/ClangFunctionCaller.h new file mode 100644 index 00000000000..7922f14edd8 --- /dev/null +++ b/lldb/include/lldb/Expression/ClangFunctionCaller.h @@ -0,0 +1,175 @@ +//===-- ClangFunctionCaller.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ClangFunctionCaller_h_ +#define liblldb_ClangFunctionCaller_h_ + +// C Includes +// C++ Includes +#include <vector> +#include <list> +// Other libraries and framework includes +// Project includes +#include "lldb/Core/ClangForward.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectList.h" +#include "lldb/Expression/ClangExpressionHelper.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Target/Process.h" + +namespace lldb_private +{ + +class ASTStructExtractor; +class ClangExpressionParser; + +//---------------------------------------------------------------------- +/// @class ClangFunctionCaller ClangFunctionCaller.h "lldb/Expression/ClangFunctionCaller.h" +/// @brief Encapsulates a function that can be called. +/// +/// A given ClangFunctionCaller object can handle a single function signature. +/// Once constructed, it can set up any number of concurrent calls to +/// functions with that signature. +/// +/// It performs the call by synthesizing a structure that contains the pointer +/// to the function and the arguments that should be passed to that function, +/// and producing a special-purpose JIT-compiled function that accepts a void* +/// pointing to this struct as its only argument and calls the function in the +/// struct with the written arguments. This method lets Clang handle the +/// vagaries of function calling conventions. +/// +/// The simplest use of the ClangFunctionCaller is to construct it with a +/// function representative of the signature you want to use, then call +/// ExecuteFunction(ExecutionContext &, Stream &, Value &). +/// +/// If you need to reuse the arguments for several calls, you can call +/// InsertFunction() followed by WriteFunctionArguments(), which will return +/// the location of the args struct for the wrapper function in args_addr_ref. +/// +/// If you need to call the function on the thread plan stack, you can also +/// call InsertFunction() followed by GetThreadPlanToCallFunction(). +/// +/// Any of the methods that take arg_addr_ptr or arg_addr_ref can be passed +/// a pointer set to LLDB_INVALID_ADDRESS and new structure will be allocated +/// and its address returned in that variable. +/// +/// Any of the methods that take arg_addr_ptr can be passed NULL, and the +/// argument space will be managed for you. +//---------------------------------------------------------------------- +class ClangFunctionCaller : public FunctionCaller +{ + friend class ASTStructExtractor; + + class ClangFunctionCallerHelper : public ClangExpressionHelper + { + public: + ClangFunctionCallerHelper (ClangFunctionCaller &owner) : + m_owner(owner) + { + } + + ~ClangFunctionCallerHelper() {} + + //------------------------------------------------------------------ + /// Return the object that the parser should use when resolving external + /// values. May be NULL if everything should be self-contained. + //------------------------------------------------------------------ + ClangExpressionDeclMap * + DeclMap() override + { + return NULL; + } + + //------------------------------------------------------------------ + /// Return the object that the parser should allow to access ASTs. + /// May be NULL if the ASTs do not need to be transformed. + /// + /// @param[in] passthrough + /// The ASTConsumer that the returned transformer should send + /// the ASTs to after transformation. + //------------------------------------------------------------------ + clang::ASTConsumer * + ASTTransformer(clang::ASTConsumer *passthrough) override; + private: + ClangFunctionCaller &m_owner; + std::unique_ptr<ASTStructExtractor> m_struct_extractor; ///< The class that generates the argument struct layout. + }; + +public: + //------------------------------------------------------------------ + /// Constructor + /// + /// @param[in] exe_scope + /// An execution context scope that gets us at least a target and + /// process. + /// + /// @param[in] ast_context + /// The AST context to evaluate argument types in. + /// + /// @param[in] return_qualtype + /// An opaque Clang QualType for the function result. Should be + /// defined in ast_context. + /// + /// @param[in] function_address + /// The address of the function to call. + /// + /// @param[in] arg_value_list + /// The default values to use when calling this function. Can + /// be overridden using WriteFunctionArguments(). + //------------------------------------------------------------------ + ClangFunctionCaller (ExecutionContextScope &exe_scope, + const CompilerType &return_type, + const Address& function_address, + const ValueList &arg_value_list, + const char *name); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~ClangFunctionCaller() override; + + //------------------------------------------------------------------ + /// Compile the wrapper function + /// + /// @param[in] errors + /// The stream to print parser errors to. + /// + /// @return + /// The number of errors. + //------------------------------------------------------------------ + unsigned + CompileFunction (Stream &errors) override; + + ExpressionTypeSystemHelper * + GetTypeSystemHelper () override + { + return &m_type_system_helper; + } +protected: + const char *GetWrapperStructName() + { + return m_wrapper_struct_name.c_str(); + } +private: + //------------------------------------------------------------------ + // For ClangFunctionCaller only + //------------------------------------------------------------------ + + // Note: the parser needs to be destructed before the execution unit, so + // declare the execution unit first. + ClangFunctionCallerHelper m_type_system_helper; + +}; + +} // Namespace lldb_private + +#endif // liblldb_ClangFunctionCaller_h_ diff --git a/lldb/include/lldb/Expression/ClangUserExpression.h b/lldb/include/lldb/Expression/ClangUserExpression.h index 176a9e23036..169e2194534 100644 --- a/lldb/include/lldb/Expression/ClangUserExpression.h +++ b/lldb/include/lldb/Expression/ClangUserExpression.h @@ -23,7 +23,9 @@ #include "lldb/lldb-private.h" #include "lldb/Core/Address.h" #include "lldb/Core/ClangForward.h" -#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/UserExpression.h" +#include "lldb/Expression/ClangExpressionHelper.h" +#include "lldb/Expression/ASTStructExtractor.h" #include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h" #include "lldb/Expression/IRForTarget.h" #include "lldb/Expression/Materializer.h" @@ -42,11 +44,59 @@ namespace lldb_private /// the objects needed to parse and interpret or JIT an expression. It /// uses the Clang parser to produce LLVM IR from the expression. //---------------------------------------------------------------------- -class ClangUserExpression : public ClangExpression +class ClangUserExpression : public UserExpression { public: enum { kDefaultTimeout = 500000u }; + + + class ClangUserExpressionHelper : public ClangExpressionHelper + { + public: + ClangUserExpressionHelper (Target &target) : + m_target(target) + { + } + + ~ClangUserExpressionHelper() {} + + //------------------------------------------------------------------ + /// Return the object that the parser should use when resolving external + /// values. May be NULL if everything should be self-contained. + //------------------------------------------------------------------ + ClangExpressionDeclMap * + DeclMap() override + { + return m_expr_decl_map_up.get(); + } + + void + ResetDeclMap() + { + m_expr_decl_map_up.reset(); + } + + void + ResetDeclMap (ExecutionContext & exe_ctx, bool keep_result_in_memory); + + //------------------------------------------------------------------ + /// Return the object that the parser should allow to access ASTs. + /// May be NULL if the ASTs do not need to be transformed. + /// + /// @param[in] passthrough + /// The ASTConsumer that the returned transformer should send + /// the ASTs to after transformation. + //------------------------------------------------------------------ + clang::ASTConsumer * + ASTTransformer(clang::ASTConsumer *passthrough) override; + private: + Target &m_target; + std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map_up; + std::unique_ptr<ASTStructExtractor> m_struct_extractor_up; ///< The class that generates the argument struct layout. + std::unique_ptr<ASTResultSynthesizer> m_result_synthesizer_up; + }; + //------------------------------------------------------------------ /// Constructor /// @@ -66,7 +116,8 @@ public: /// If not eResultTypeAny, the type to use for the expression /// result. //------------------------------------------------------------------ - ClangUserExpression (const char *expr, + ClangUserExpression (ExecutionContextScope &exe_scope, + const char *expr, const char *expr_prefix, lldb::LanguageType language, ResultType desired_type); @@ -102,207 +153,32 @@ public: ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory, - bool generate_debug_info); - - bool - CanInterpret () - { - return m_can_interpret; - } - - bool - MatchesContext (ExecutionContext &exe_ctx); - - //------------------------------------------------------------------ - /// Execute the parsed expression - /// - /// @param[in] error_stream - /// A stream to print errors to. - /// - /// @param[in] exe_ctx - /// The execution context to use when looking up entities that - /// are needed for parsing (locations of variables, etc.) - /// - /// @param[in] options - /// Expression evaluation options. - /// - /// @param[in] shared_ptr_to_me - /// This is a shared pointer to this ClangUserExpression. This is - /// needed because Execute can push a thread plan that will hold onto - /// the ClangUserExpression for an unbounded period of time. So you - /// need to give the thread plan a reference to this object that can - /// keep it alive. - /// - /// @param[in] result - /// A pointer to direct at the persistent variable in which the - /// expression's result is stored. - /// - /// @return - /// A Process::Execution results value. - //------------------------------------------------------------------ - lldb::ExpressionResults - Execute (Stream &error_stream, - ExecutionContext &exe_ctx, - const EvaluateExpressionOptions& options, - lldb::ClangUserExpressionSP &shared_ptr_to_me, - lldb::ExpressionVariableSP &result); - - //------------------------------------------------------------------ - /// Apply the side effects of the function to program state. - /// - /// @param[in] error_stream - /// A stream to print errors to. - /// - /// @param[in] exe_ctx - /// The execution context to use when looking up entities that - /// are needed for parsing (locations of variables, etc.) - /// - /// @param[in] result - /// A pointer to direct at the persistent variable in which the - /// expression's result is stored. - /// - /// @param[in] function_stack_pointer - /// A pointer to the base of the function's stack frame. This - /// is used to determine whether the expression result resides in - /// memory that will still be valid, or whether it needs to be - /// treated as homeless for the purpose of future expressions. - /// - /// @return - /// A Process::Execution results value. - //------------------------------------------------------------------ - bool - FinalizeJITExecution (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb::ExpressionVariableSP &result, - lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS, - lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS); - - //------------------------------------------------------------------ - /// Return the string that the parser should parse. Must be a full - /// translation unit. - //------------------------------------------------------------------ - const char * - Text() override - { - return m_transformed_text.c_str(); - } - - //------------------------------------------------------------------ - /// Return the string that the user typed. - //------------------------------------------------------------------ - const char * - GetUserText () - { - return m_expr_text.c_str(); - } - - //------------------------------------------------------------------ - /// Return the function name that should be used for executing the - /// expression. Text() should contain the definition of this - /// function. - //------------------------------------------------------------------ - const char * - FunctionName() override - { - return "$__lldb_expr"; - } + bool generate_debug_info) override; - //------------------------------------------------------------------ - /// Return the language that should be used when parsing. To use - /// the default, return eLanguageTypeUnknown. - //------------------------------------------------------------------ - lldb::LanguageType - Language() override + ExpressionTypeSystemHelper * + GetTypeSystemHelper () override { - return m_language; + return &m_type_system_helper; } - - //------------------------------------------------------------------ - /// Return the object that the parser should use when resolving external - /// values. May be NULL if everything should be self-contained. - //------------------------------------------------------------------ + ClangExpressionDeclMap * - DeclMap() override + DeclMap () { - return m_expr_decl_map.get(); + return m_type_system_helper.DeclMap(); } - - //------------------------------------------------------------------ - /// Return the object that the parser should allow to access ASTs. - /// May be NULL if the ASTs do not need to be transformed. - /// - /// @param[in] passthrough - /// The ASTConsumer that the returned transformer should send - /// the ASTs to after transformation. - //------------------------------------------------------------------ - clang::ASTConsumer * - ASTTransformer(clang::ASTConsumer *passthrough) override; - - //------------------------------------------------------------------ - /// Return the desired result type of the function, or - /// eResultTypeAny if indifferent. - //------------------------------------------------------------------ - ResultType - DesiredResultType() override - { - return m_desired_type; - } - - //------------------------------------------------------------------ - /// Return true if validation code should be inserted into the - /// expression. - //------------------------------------------------------------------ - bool - NeedsValidation() override + + void + ResetDeclMap () { - return true; + m_type_system_helper.ResetDeclMap(); } - - //------------------------------------------------------------------ - /// Return true if external variables in the expression should be - /// resolved. - //------------------------------------------------------------------ - bool - NeedsVariableResolution() override + + void + ResetDeclMap (ExecutionContext & exe_ctx, bool keep_result_in_memory) { - return true; + m_type_system_helper.ResetDeclMap(exe_ctx, keep_result_in_memory); } - - //------------------------------------------------------------------ - /// Evaluate one expression and return its result. - /// - /// @param[in] exe_ctx - /// The execution context to use when evaluating the expression. - /// - /// @param[in] options - /// Expression evaluation options. - /// - /// @param[in] expr_cstr - /// A C string containing the expression to be evaluated. - /// - /// @param[in] expr_prefix - /// If non-NULL, a C string containing translation-unit level - /// definitions to be included when the expression is parsed. - /// - /// @param[in,out] result_valobj_sp - /// If execution is successful, the result valobj is placed here. - /// - /// @param[out] - /// Filled in with an error in case the expression evaluation - /// fails to parse, run, or evaluated. - /// - /// @result - /// A Process::ExpressionResults value. eExpressionCompleted for success. - //------------------------------------------------------------------ - static lldb::ExpressionResults - Evaluate (ExecutionContext &exe_ctx, - const EvaluateExpressionOptions& options, - const char *expr_cstr, - const char *expr_prefix, - lldb::ValueObjectSP &result_valobj_sp, - Error &error); - - static const Error::ValueType kNoResult = 0x1001; ///< ValueObject::GetError() returns this if there is no result from the expression. + private: //------------------------------------------------------------------ /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the environment. @@ -310,53 +186,14 @@ private: void ScanContext (ExecutionContext &exe_ctx, - lldb_private::Error &err); - - bool - PrepareToExecuteJITExpression (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb::addr_t &struct_address, - lldb::addr_t &object_ptr, - lldb::addr_t &cmd_ptr); - - void - InstallContext (ExecutionContext &exe_ctx); + lldb_private::Error &err) override; bool - LockAndCheckContext (ExecutionContext &exe_ctx, - lldb::TargetSP &target_sp, - lldb::ProcessSP &process_sp, - lldb::StackFrameSP &frame_sp); - - lldb::ProcessWP m_process_wp; ///< The process used as the context for the expression. - Address m_address; ///< The address the process is stopped in. - lldb::addr_t m_stack_frame_bottom; ///< The bottom of the allocated stack frame. - lldb::addr_t m_stack_frame_top; ///< The top of the allocated stack frame. - - std::string m_expr_text; ///< The text of the expression, as typed by the user - std::string m_expr_prefix; ///< The text of the translation-level definitions, as provided by the user - lldb::LanguageType m_language; ///< The language to use when parsing (eLanguageTypeUnknown means use defaults) - bool m_allow_cxx; ///< True if the language allows C++. - bool m_allow_objc; ///< True if the language allows Objective-C. - std::string m_transformed_text; ///< The text of the expression, as send to the parser - ResultType m_desired_type; ///< The type to coerce the expression's result to. If eResultTypeAny, inferred from the expression. - - std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing the expression. - std::shared_ptr<IRExecutionUnit> m_execution_unit_sp; ///< The execution unit the expression is stored in. - std::unique_ptr<Materializer> m_materializer_ap; ///< The materializer to use when running the expression. - std::unique_ptr<ASTResultSynthesizer> m_result_synthesizer; ///< The result synthesizer, if one is needed. - lldb::ModuleWP m_jit_module_wp; - bool m_enforce_valid_object; ///< True if the expression parser should enforce the presence of a valid class pointer in order to generate the expression as a method. - bool m_in_cplusplus_method; ///< True if the expression is compiled as a C++ member function (true if it was parsed when exe_ctx was in a C++ method). - bool m_in_objectivec_method; ///< True if the expression is compiled as an Objective-C method (true if it was parsed when exe_ctx was in an Objective-C method). - bool m_in_static_method; ///< True if the expression is compiled as a static (or class) method (currently true if it was parsed when exe_ctx was in an Objective-C class method). - bool m_needs_object_ptr; ///< True if "this" or "self" must be looked up and passed in. False if the expression doesn't really use them and they can be NULL. - bool m_const_object; ///< True if "this" is const. - Target *m_target; ///< The target for storing persistent data like types and variables. - - bool m_can_interpret; ///< True if the expression could be evaluated statically; false otherwise. - lldb::addr_t m_materialized_address; ///< The address at which the arguments to the expression have been materialized. - Materializer::DematerializerSP m_dematerializer_sp; ///< The dematerializer. + AddInitialArguments (ExecutionContext &exe_ctx, + std::vector<lldb::addr_t> &args, + Stream &error_stream) override; + + ClangUserExpressionHelper m_type_system_helper; }; } // namespace lldb_private diff --git a/lldb/include/lldb/Expression/ClangUtilityFunction.h b/lldb/include/lldb/Expression/ClangUtilityFunction.h index 1a028174810..37b1ebbba12 100644 --- a/lldb/include/lldb/Expression/ClangUtilityFunction.h +++ b/lldb/include/lldb/Expression/ClangUtilityFunction.h @@ -22,7 +22,8 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" #include "lldb/Core/ClangForward.h" -#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/ClangExpressionHelper.h" +#include "lldb/Expression/UtilityFunction.h" namespace lldb_private { @@ -34,11 +35,57 @@ namespace lldb_private /// LLDB uses expressions for various purposes, notably to call functions /// and as a backend for the expr command. ClangUtilityFunction encapsulates /// a self-contained function meant to be used from other code. Utility -/// functions can perform error-checking for ClangUserExpressions, +/// functions can perform error-checking for ClangUserExpressions, or can +/// simply provide a way to push a function into the target for the debugger to +/// call later on. //---------------------------------------------------------------------- -class ClangUtilityFunction : public ClangExpression +class ClangUtilityFunction : public UtilityFunction { public: + class ClangUtilityFunctionHelper : public ClangExpressionHelper + { + public: + ClangUtilityFunctionHelper () + { + } + + ~ClangUtilityFunctionHelper() override {} + + //------------------------------------------------------------------ + /// Return the object that the parser should use when resolving external + /// values. May be NULL if everything should be self-contained. + //------------------------------------------------------------------ + ClangExpressionDeclMap * + DeclMap() override + { + return m_expr_decl_map_up.get(); + } + + void + ResetDeclMap() + { + m_expr_decl_map_up.reset(); + } + + void + ResetDeclMap (ExecutionContext & exe_ctx, bool keep_result_in_memory); + + //------------------------------------------------------------------ + /// Return the object that the parser should allow to access ASTs. + /// May be NULL if the ASTs do not need to be transformed. + /// + /// @param[in] passthrough + /// The ASTConsumer that the returned transformer should send + /// the ASTs to after transformation. + //------------------------------------------------------------------ + clang::ASTConsumer * + ASTTransformer(clang::ASTConsumer *passthrough) override + { + return nullptr; + } + private: + std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map_up; + }; //------------------------------------------------------------------ /// Constructor /// @@ -48,129 +95,41 @@ public: /// @param[in] name /// The name of the function, as used in the text. //------------------------------------------------------------------ - ClangUtilityFunction (const char *text, + ClangUtilityFunction (ExecutionContextScope &exe_scope, + const char *text, const char *name); ~ClangUtilityFunction() override; - - //------------------------------------------------------------------ - /// Install the utility function into a process - /// - /// @param[in] error_stream - /// A stream to print parse errors and warnings to. - /// - /// @param[in] exe_ctx - /// The execution context to install the utility function to. - /// - /// @return - /// True on success (no errors); false otherwise. - //------------------------------------------------------------------ - bool - Install (Stream &error_stream, ExecutionContext &exe_ctx); - - //------------------------------------------------------------------ - /// Check whether the given PC is inside the function - /// - /// Especially useful if the function dereferences NULL to indicate a failed - /// assert. - /// - /// @param[in] pc - /// The program counter to check. - /// - /// @return - /// True if the program counter falls within the function's bounds; - /// false if not (or the function is not JIT compiled) - //------------------------------------------------------------------ - bool - ContainsAddress (lldb::addr_t address) - { - // nothing is both >= LLDB_INVALID_ADDRESS and < LLDB_INVALID_ADDRESS, - // so this always returns false if the function is not JIT compiled yet - return (address >= m_jit_start_addr && address < m_jit_end_addr); - } - - //------------------------------------------------------------------ - /// Return the string that the parser should parse. Must be a full - /// translation unit. - //------------------------------------------------------------------ - const char * - Text() override + ExpressionTypeSystemHelper * + GetTypeSystemHelper () override { - return m_function_text.c_str(); + return &m_type_system_helper; } - - //------------------------------------------------------------------ - /// Return the function name that should be used for executing the - /// expression. Text() should contain the definition of this - /// function. - //------------------------------------------------------------------ - const char * - FunctionName() override - { - return m_function_name.c_str(); - } - - //------------------------------------------------------------------ - /// Return the object that the parser should use when resolving external - /// values. May be NULL if everything should be self-contained. - //------------------------------------------------------------------ + ClangExpressionDeclMap * - DeclMap() override + DeclMap() { - return m_expr_decl_map.get(); + return m_type_system_helper.DeclMap(); } - - //------------------------------------------------------------------ - /// Return the object that the parser should use when registering - /// local variables. May be NULL if the Expression doesn't care. - //------------------------------------------------------------------ - ExpressionVariableList * - LocalVariables () - { - return NULL; - } - - //------------------------------------------------------------------ - /// Return the object that the parser should allow to access ASTs. - /// May be NULL if the ASTs do not need to be transformed. - /// - /// @param[in] passthrough - /// The ASTConsumer that the returned transformer should send - /// the ASTs to after transformation. - //------------------------------------------------------------------ - clang::ASTConsumer * - ASTTransformer(clang::ASTConsumer *passthrough) override + + void + ResetDeclMap () { - return NULL; + m_type_system_helper.ResetDeclMap(); } - //------------------------------------------------------------------ - /// Return true if validation code should be inserted into the - /// expression. - //------------------------------------------------------------------ - bool - NeedsValidation() override + void + ResetDeclMap (ExecutionContext & exe_ctx, bool keep_result_in_memory) { - return false; + m_type_system_helper.ResetDeclMap(exe_ctx, keep_result_in_memory); } - //------------------------------------------------------------------ - /// Return true if external variables in the expression should be - /// resolved. - //------------------------------------------------------------------ bool - NeedsVariableResolution() override - { - return false; - } + Install (Stream &error_stream, ExecutionContext &exe_ctx) override; private: - std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression. - std::shared_ptr<IRExecutionUnit> m_execution_unit_sp; - lldb::ModuleWP m_jit_module_wp; - std::string m_function_text; ///< The text of the function. Must be a well-formed translation unit. - std::string m_function_name; ///< The name of the function. + ClangUtilityFunctionHelper m_type_system_helper; ///< The map to use when parsing and materializing the expression. }; } // namespace lldb_private diff --git a/lldb/include/lldb/Expression/ClangExpression.h b/lldb/include/lldb/Expression/Expression.h index 6e831e4471e..12f15b5f3c7 100644 --- a/lldb/include/lldb/Expression/ClangExpression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -1,4 +1,4 @@ -//===-- ClangExpression.h ---------------------------------------*- C++ -*-===// +//===-- Expression.h --------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangExpression_h_ -#define liblldb_ClangExpression_h_ +#ifndef liblldb_Expression_h_ +#define liblldb_Expression_h_ // C Includes // C++ Includes @@ -22,22 +22,23 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" #include "lldb/Core/ClangForward.h" -#include "lldb/Target/Process.h" +#include "lldb/Expression/ExpressionTypeSystemHelper.h" namespace lldb_private { class RecordingMemoryManager; //---------------------------------------------------------------------- -/// @class ClangExpression ClangExpression.h "lldb/Expression/ClangExpression.h" -/// @brief Encapsulates a single expression for use with Clang +/// @class Expression Expression.h "lldb/Expression/Expression.h" +/// @brief Encapsulates a single expression for use in lldb /// /// LLDB uses expressions for various purposes, notably to call functions -/// and as a backend for the expr command. ClangExpression encapsulates +/// and as a backend for the expr command. Expression encapsulates /// the objects needed to parse and interpret or JIT an expression. It -/// uses the Clang parser to produce LLVM IR from the expression. +/// uses the expression parser appropriate to the language of the expression +/// to produce LLVM IR from the expression. //---------------------------------------------------------------------- -class ClangExpression +class Expression { public: enum ResultType { @@ -45,17 +46,14 @@ public: eResultTypeId }; - ClangExpression () : - m_jit_process_wp(), - m_jit_start_addr (LLDB_INVALID_ADDRESS), - m_jit_end_addr (LLDB_INVALID_ADDRESS) - { - } - + Expression (Target &target); + + Expression (ExecutionContextScope &exe_scope); + //------------------------------------------------------------------ /// Destructor //------------------------------------------------------------------ - virtual ~ClangExpression () + virtual ~Expression () { } @@ -85,24 +83,6 @@ public: } //------------------------------------------------------------------ - /// Return the object that the parser should use when resolving external - /// values. May be NULL if everything should be self-contained. - //------------------------------------------------------------------ - virtual ClangExpressionDeclMap * - DeclMap () = 0; - - //------------------------------------------------------------------ - /// Return the object that the parser should allow to access ASTs. - /// May be NULL if the ASTs do not need to be transformed. - /// - /// @param[in] passthrough - /// The ASTConsumer that the returned transformer should send - /// the ASTs to after transformation. - //------------------------------------------------------------------ - virtual clang::ASTConsumer * - ASTTransformer (clang::ASTConsumer *passthrough) = 0; - - //------------------------------------------------------------------ /// Return the desired result type of the function, or /// eResultTypeAny if indifferent. //------------------------------------------------------------------ @@ -139,10 +119,17 @@ public: { return m_jit_start_addr; } + + virtual ExpressionTypeSystemHelper * + GetTypeSystemHelper () + { + return nullptr; + } protected: - lldb::ProcessWP m_jit_process_wp; + lldb::TargetWP m_target_wp; /// Expression's always have to have a target... + lldb::ProcessWP m_jit_process_wp; /// An expression might have a process, but it doesn't need to (e.g. calculator mode.) lldb::addr_t m_jit_start_addr; ///< The address of the JITted function within the JIT allocation. LLDB_INVALID_ADDRESS if invalid. lldb::addr_t m_jit_end_addr; ///< The address of the JITted function within the JIT allocation. LLDB_INVALID_ADDRESS if invalid. @@ -150,4 +137,4 @@ protected: } // namespace lldb_private -#endif // liblldb_ClangExpression_h_ +#endif // liblldb_Expression_h_ diff --git a/lldb/include/lldb/Expression/ExpressionParser.h b/lldb/include/lldb/Expression/ExpressionParser.h new file mode 100644 index 00000000000..e49525a624d --- /dev/null +++ b/lldb/include/lldb/Expression/ExpressionParser.h @@ -0,0 +1,129 @@ +//===-- ExpressionParser.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ExpressionParser_h_ +#define liblldb_ExpressionParser_h_ + +#include "lldb/lldb-public.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/ClangForward.h" +#include "lldb/Core/Error.h" +#include "lldb/Expression/IRForTarget.h" + +#include <string> +#include <vector> + +namespace lldb_private +{ + +class IRExecutionUnit; + +//---------------------------------------------------------------------- +/// @class ExpressionParser ExpressionParser.h "lldb/Expression/ExpressionParser.h" +/// @brief Encapsulates an instance of a compiler that can parse expressions. +/// +/// ExpressionParser is the base class for llvm based Expression parsers. +//---------------------------------------------------------------------- +class ExpressionParser +{ +public: + //------------------------------------------------------------------ + /// Constructor + /// + /// Initializes class variables. + /// + /// @param[in] exe_scope, + /// If non-NULL, an execution context scope that can help to + /// correctly create an expression with a valid process for + /// optional tuning Objective-C runtime support. Can be NULL. + /// + /// @param[in] expr + /// The expression to be parsed. + //------------------------------------------------------------------ + ExpressionParser (ExecutionContextScope *exe_scope, + Expression &expr, + bool generate_debug_info) : + m_expr(expr), + m_generate_debug_info(generate_debug_info) + { + } + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + virtual ~ExpressionParser () {}; + + //------------------------------------------------------------------ + /// Parse a single expression and convert it to IR using Clang. Don't + /// wrap the expression in anything at all. + /// + /// @param[in] stream + /// The stream to print errors to. + /// + /// @return + /// The number of errors encountered during parsing. 0 means + /// success. + //------------------------------------------------------------------ + virtual unsigned + Parse (Stream &stream) = 0; + + //------------------------------------------------------------------ + /// Ready an already-parsed expression for execution, possibly + /// evaluating it statically. + /// + /// @param[out] func_addr + /// The address to which the function has been written. + /// + /// @param[out] func_end + /// The end of the function's allocated memory region. (func_addr + /// and func_end do not delimit an allocated region; the allocated + /// region may begin before func_addr.) + /// + /// @param[in] execution_unit_sp + /// After parsing, ownership of the execution unit for + /// for the expression is handed to this shared pointer. + /// + /// @param[in] exe_ctx + /// The execution context to write the function into. + /// + /// @param[out] can_interpret + /// Set to true if the expression could be interpreted statically; + /// untouched otherwise. + /// + /// @param[in] execution_policy + /// Determines whether the expression must be JIT-compiled, must be + /// evaluated statically, or whether this decision may be made + /// opportunistically. + /// + /// @return + /// An error code indicating the success or failure of the operation. + /// Test with Success(). + //------------------------------------------------------------------ + virtual Error + PrepareForExecution (lldb::addr_t &func_addr, + lldb::addr_t &func_end, + std::shared_ptr<IRExecutionUnit> &execution_unit_sp, + ExecutionContext &exe_ctx, + bool &can_interpret, + lldb_private::ExecutionPolicy execution_policy) = 0; + + bool + GetGenerateDebugInfo () const + { + return m_generate_debug_info; + } + +protected: + Expression & m_expr; ///< The expression to be parsed + bool m_generate_debug_info; +}; + +} + +#endif // liblldb_ExpressionParser_h_ diff --git a/lldb/include/lldb/Expression/ExpressionTypeSystemHelper.h b/lldb/include/lldb/Expression/ExpressionTypeSystemHelper.h new file mode 100644 index 00000000000..cb560c9b5a4 --- /dev/null +++ b/lldb/include/lldb/Expression/ExpressionTypeSystemHelper.h @@ -0,0 +1,54 @@ +//===-- ExpressionTypeSystemHelper.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef ExpressionTypeSystemHelper_h +#define ExpressionTypeSystemHelper_h + +#include "llvm/Support/Casting.h" + +namespace lldb_private +{ + +//---------------------------------------------------------------------- +/// @class ExpressionTypeSystemHelper ExpressionTypeSystemHelper.h "lldb/Expression/ExpressionTypeSystemHelper.h" +/// @brief A helper object that the Expression can pass to its ExpressionParser to provide generic information that +/// any type of expression will need to supply. It's only job is to support dyn_cast so that the expression parser +/// can cast it back to the requisite specific type. +/// +//---------------------------------------------------------------------- + +class ExpressionTypeSystemHelper +{ +public: + enum LLVMCastKind { + eKindClangHelper, + eKindSwiftHelper, + eKindGoHelper, + kNumKinds + }; + + LLVMCastKind getKind() const { return m_kind; } + + ExpressionTypeSystemHelper (LLVMCastKind kind) : + m_kind(kind) + { + } + + ~ExpressionTypeSystemHelper () {} + +protected: + LLVMCastKind m_kind; +}; + + + + +} // namespace lldb_private + +#endif /* ExpressionTypeSystemHelper_h */ diff --git a/lldb/include/lldb/Expression/ClangFunction.h b/lldb/include/lldb/Expression/FunctionCaller.h index 10a623eaeeb..2510e10bde8 100644 --- a/lldb/include/lldb/Expression/ClangFunction.h +++ b/lldb/include/lldb/Expression/FunctionCaller.h @@ -1,4 +1,4 @@ -//===-- ClangFunction.h -----------------------------------------*- C++ -*-===// +//===-- FunctionCaller.h -----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangFunction_h_ -#define liblldb_ClangFunction_h_ +#ifndef liblldb_FunctionCaller_h_ +#define liblldb_FunctionCaller_h_ // C Includes // C++ Includes @@ -21,7 +21,8 @@ #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectList.h" -#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/Expression.h" +#include "lldb/Expression/ExpressionParser.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Process.h" @@ -32,10 +33,10 @@ class ASTStructExtractor; class ClangExpressionParser; //---------------------------------------------------------------------- -/// @class ClangFunction ClangFunction.h "lldb/Expression/ClangFunction.h" +/// @class FunctionCaller FunctionCaller.h "lldb/Expression/FunctionCaller.h" /// @brief Encapsulates a function that can be called. /// -/// A given ClangFunction object can handle a single function signature. +/// A given FunctionCaller object can handle a single function signature. /// Once constructed, it can set up any number of concurrent calls to /// functions with that signature. /// @@ -46,7 +47,7 @@ class ClangExpressionParser; /// struct with the written arguments. This method lets Clang handle the /// vagaries of function calling conventions. /// -/// The simplest use of the ClangFunction is to construct it with a +/// The simplest use of the FunctionCaller is to construct it with a /// function representative of the signature you want to use, then call /// ExecuteFunction(ExecutionContext &, Stream &, Value &). /// @@ -64,9 +65,8 @@ class ClangExpressionParser; /// Any of the methods that take arg_addr_ptr can be passed NULL, and the /// argument space will be managed for you. //---------------------------------------------------------------------- -class ClangFunction : public ClangExpression +class FunctionCaller : public Expression { - friend class ASTStructExtractor; public: //------------------------------------------------------------------ /// Constructor @@ -75,30 +75,6 @@ public: /// An execution context scope that gets us at least a target and /// process. /// - /// @param[in] function_ptr - /// The default function to be called. Can be overridden using - /// WriteFunctionArguments(). - /// - /// @param[in] ast_context - /// The AST context to evaluate argument types in. - /// - /// @param[in] arg_value_list - /// The default values to use when calling this function. Can - /// be overridden using WriteFunctionArguments(). - //------------------------------------------------------------------ - ClangFunction (ExecutionContextScope &exe_scope, - Function &function_ptr, - ClangASTContext *ast_context, - const ValueList &arg_value_list, - const char *name); - - //------------------------------------------------------------------ - /// Constructor - /// - /// @param[in] exe_scope - /// An execution context scope that gets us at least a target and - /// process. - /// /// @param[in] ast_context /// The AST context to evaluate argument types in. /// @@ -113,7 +89,7 @@ public: /// The default values to use when calling this function. Can /// be overridden using WriteFunctionArguments(). //------------------------------------------------------------------ - ClangFunction (ExecutionContextScope &exe_scope, + FunctionCaller (ExecutionContextScope &exe_scope, const CompilerType &return_type, const Address& function_address, const ValueList &arg_value_list, @@ -122,7 +98,7 @@ public: //------------------------------------------------------------------ /// Destructor //------------------------------------------------------------------ - ~ClangFunction() override; + ~FunctionCaller() override; //------------------------------------------------------------------ /// Compile the wrapper function @@ -133,8 +109,8 @@ public: /// @return /// The number of errors. //------------------------------------------------------------------ - unsigned - CompileFunction (Stream &errors); + virtual unsigned + CompileFunction (Stream &errors) = 0; //------------------------------------------------------------------ /// Insert the default function wrapper and its default argument struct @@ -208,10 +184,7 @@ public: /// @param[in,out] args_addr_ref /// The address of the structure to write the arguments into. May /// be LLDB_INVALID_ADDRESS; if it is, a new structure is allocated - /// and args_addr_ref is pointed to it. - /// - /// @param[in] function_address - /// The address of the function to call. + /// and args_addr_ref is pointed at it. /// /// @param[in] arg_values /// The values of the function's arguments. @@ -224,12 +197,11 @@ public: //------------------------------------------------------------------ bool WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, - Address function_address, - ValueList &arg_values, + ValueList &arg_values, Stream &errors); //------------------------------------------------------------------ - /// Run the function this ClangFunction was created with. + /// Run the function this FunctionCaller was created with. /// /// This is the full version. /// @@ -263,7 +235,7 @@ public: Value &results); //------------------------------------------------------------------ - /// Get a thread plan to run the function this ClangFunction was created with. + /// Get a thread plan to run the function this FunctionCaller was created with. /// /// @param[in] exe_ctx /// The execution context to insert the function and its arguments @@ -351,16 +323,6 @@ public: } //------------------------------------------------------------------ - /// Return the object that the parser should use when resolving external - /// values. May be NULL if everything should be self-contained. - //------------------------------------------------------------------ - ClangExpressionDeclMap * - DeclMap() override - { - return NULL; - } - - //------------------------------------------------------------------ /// Return the object that the parser should use when registering /// local variables. May be NULL if the Expression doesn't care. //------------------------------------------------------------------ @@ -371,17 +333,6 @@ public: } //------------------------------------------------------------------ - /// Return the object that the parser should allow to access ASTs. - /// May be NULL if the ASTs do not need to be transformed. - /// - /// @param[in] passthrough - /// The ASTConsumer that the returned transformer should send - /// the ASTs to after transformation. - //------------------------------------------------------------------ - clang::ASTConsumer * - ASTTransformer(clang::ASTConsumer *passthrough) override; - - //------------------------------------------------------------------ /// Return true if validation code should be inserted into the /// expression. //------------------------------------------------------------------ @@ -406,15 +357,18 @@ public: { return m_arg_values; } -private: +protected: //------------------------------------------------------------------ - // For ClangFunction only + // For FunctionCaller only //------------------------------------------------------------------ // Note: the parser needs to be destructed before the execution unit, so // declare the execution unit first. std::shared_ptr<IRExecutionUnit> m_execution_unit_sp; - std::unique_ptr<ClangExpressionParser> m_parser; ///< The parser responsible for compiling the function. + std::unique_ptr<ExpressionParser> m_parser; ///< The parser responsible for compiling the function. + ///< This will get made in CompileFunction, so it is + ///< safe to access it after that. + lldb::ModuleWP m_jit_module_wp; std::string m_name; ///< The name of this clang function - for debugging purposes. @@ -447,4 +401,4 @@ private: } // Namespace lldb_private -#endif // liblldb_ClangFunction_h_ +#endif // liblldb_FunctionCaller_h_ diff --git a/lldb/include/lldb/Expression/IRDynamicChecks.h b/lldb/include/lldb/Expression/IRDynamicChecks.h index 914e0df38e8..ef77d55f4b3 100644 --- a/lldb/include/lldb/Expression/IRDynamicChecks.h +++ b/lldb/include/lldb/Expression/IRDynamicChecks.h @@ -28,7 +28,6 @@ namespace lldb_private { class ClangExpressionDeclMap; -class ClangUtilityFunction; class ExecutionContext; class Stream; @@ -77,8 +76,8 @@ public: bool DoCheckersExplainStop (lldb::addr_t addr, Stream &message); - std::unique_ptr<ClangUtilityFunction> m_valid_pointer_check; - std::unique_ptr<ClangUtilityFunction> m_objc_object_check; + std::unique_ptr<UtilityFunction> m_valid_pointer_check; + std::unique_ptr<UtilityFunction> m_objc_object_check; }; //---------------------------------------------------------------------- diff --git a/lldb/include/lldb/Expression/IRExecutionUnit.h b/lldb/include/lldb/Expression/IRExecutionUnit.h index a0e0f508775..6389b76d47c 100644 --- a/lldb/include/lldb/Expression/IRExecutionUnit.h +++ b/lldb/include/lldb/Expression/IRExecutionUnit.h @@ -26,7 +26,6 @@ #include "lldb/Core/ClangForward.h" #include "lldb/Core/DataBufferHeap.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "lldb/Expression/ClangExpression.h" #include "lldb/Expression/ClangExpressionParser.h" #include "lldb/Expression/IRMemoryMap.h" #include "lldb/Host/Mutex.h" diff --git a/lldb/include/lldb/Expression/UserExpression.h b/lldb/include/lldb/Expression/UserExpression.h new file mode 100644 index 00000000000..1a325eab05f --- /dev/null +++ b/lldb/include/lldb/Expression/UserExpression.h @@ -0,0 +1,361 @@ +//===-- UserExpression.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_UserExpression_h_ +#define liblldb_UserExpression_h_ + +// C Includes +// C++ Includes +#include <string> +#include <map> +#include <vector> + +// Other libraries and framework includes + +#include "llvm/ADT/ArrayRef.h" + +// Project includes + +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/ClangForward.h" +#include "lldb/Expression/ClangExpressionHelper.h" +#include "lldb/Expression/Expression.h" +#include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h" +#include "lldb/Expression/IRForTarget.h" +#include "lldb/Expression/Materializer.h" +#include "lldb/Symbol/TaggedASTType.h" +#include "lldb/Target/ExecutionContext.h" + +namespace lldb_private +{ + +//---------------------------------------------------------------------- +/// @class UserExpression UserExpression.h "lldb/Expression/UserExpression.h" +/// @brief Encapsulates a one-time expression for use in lldb. +/// +/// LLDB uses expressions for various purposes, notably to call functions +/// and as a backend for the expr command. UserExpression is a virtual base +/// class that encapsulates the objects needed to parse and interpret or +/// JIT an expression. The actual parsing part will be provided by the specific +/// implementations of UserExpression - which will be vended through the +/// appropriate TypeSystem. +//---------------------------------------------------------------------- +class UserExpression : public Expression +{ +public: + + enum { kDefaultTimeout = 500000u }; + //------------------------------------------------------------------ + /// Constructor + /// + /// @param[in] expr + /// The expression to parse. + /// + /// @param[in] expr_prefix + /// If non-NULL, a C string containing translation-unit level + /// definitions to be included when the expression is parsed. + /// + /// @param[in] language + /// If not eLanguageTypeUnknown, a language to use when parsing + /// the expression. Currently restricted to those languages + /// supported by Clang. + /// + /// @param[in] desired_type + /// If not eResultTypeAny, the type to use for the expression + /// result. + //------------------------------------------------------------------ + UserExpression (ExecutionContextScope &exe_scope, + const char *expr, + const char *expr_prefix, + lldb::LanguageType language, + ResultType desired_type); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~UserExpression() override; + + //------------------------------------------------------------------ + /// Parse the expression + /// + /// @param[in] error_stream + /// A stream to print parse errors and warnings to. + /// + /// @param[in] exe_ctx + /// The execution context to use when looking up entities that + /// are needed for parsing (locations of functions, types of + /// variables, persistent variables, etc.) + /// + /// @param[in] execution_policy + /// Determines whether interpretation is possible or mandatory. + /// + /// @param[in] keep_result_in_memory + /// True if the resulting persistent variable should reside in + /// target memory, if applicable. + /// + /// @return + /// True on success (no errors); false otherwise. + //------------------------------------------------------------------ + virtual bool + Parse (Stream &error_stream, + ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, + bool generate_debug_info) = 0; + + bool + CanInterpret () + { + return m_can_interpret; + } + + bool + MatchesContext (ExecutionContext &exe_ctx); + + //------------------------------------------------------------------ + /// Execute the parsed expression + /// + /// @param[in] error_stream + /// A stream to print errors to. + /// + /// @param[in] exe_ctx + /// The execution context to use when looking up entities that + /// are needed for parsing (locations of variables, etc.) + /// + /// @param[in] options + /// Expression evaluation options. + /// + /// @param[in] shared_ptr_to_me + /// This is a shared pointer to this UserExpression. This is + /// needed because Execute can push a thread plan that will hold onto + /// the UserExpression for an unbounded period of time. So you + /// need to give the thread plan a reference to this object that can + /// keep it alive. + /// + /// @param[in] result + /// A pointer to direct at the persistent variable in which the + /// expression's result is stored. + /// + /// @return + /// A Process::Execution results value. + //------------------------------------------------------------------ + lldb::ExpressionResults + Execute (Stream &error_stream, + ExecutionContext &exe_ctx, + const EvaluateExpressionOptions& options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result); + + //------------------------------------------------------------------ + /// Apply the side effects of the function to program state. + /// + /// @param[in] error_stream + /// A stream to print errors to. + /// + /// @param[in] exe_ctx + /// The execution context to use when looking up entities that + /// are needed for parsing (locations of variables, etc.) + /// + /// @param[in] result + /// A pointer to direct at the persistent variable in which the + /// expression's result is stored. + /// + /// @param[in] function_stack_pointer + /// A pointer to the base of the function's stack frame. This + /// is used to determine whether the expression result resides in + /// memory that will still be valid, or whether it needs to be + /// treated as homeless for the purpose of future expressions. + /// + /// @return + /// A Process::Execution results value. + //------------------------------------------------------------------ + bool + FinalizeJITExecution (Stream &error_stream, + ExecutionContext &exe_ctx, + lldb::ExpressionVariableSP &result, + lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS, + lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS); + + //------------------------------------------------------------------ + /// Return the string that the parser should parse. Must be a full + /// translation unit. + //------------------------------------------------------------------ + const char * + Text() override + { + return m_transformed_text.c_str(); + } + + //------------------------------------------------------------------ + /// Return the string that the user typed. + //------------------------------------------------------------------ + const char * + GetUserText () + { + return m_expr_text.c_str(); + } + + //------------------------------------------------------------------ + /// Return the function name that should be used for executing the + /// expression. Text() should contain the definition of this + /// function. + //------------------------------------------------------------------ + const char * + FunctionName() override + { + return "$__lldb_expr"; + } + + //------------------------------------------------------------------ + /// Return the language that should be used when parsing. To use + /// the default, return eLanguageTypeUnknown. + //------------------------------------------------------------------ + lldb::LanguageType + Language() override + { + return m_language; + } + + //------------------------------------------------------------------ + /// Return the desired result type of the function, or + /// eResultTypeAny if indifferent. + //------------------------------------------------------------------ + ResultType + DesiredResultType() override + { + return m_desired_type; + } + + //------------------------------------------------------------------ + /// Return true if validation code should be inserted into the + /// expression. + //------------------------------------------------------------------ + bool + NeedsValidation() override + { + return true; + } + + //------------------------------------------------------------------ + /// Return true if external variables in the expression should be + /// resolved. + //------------------------------------------------------------------ + bool + NeedsVariableResolution() override + { + return true; + } + + //------------------------------------------------------------------ + /// Evaluate one expression in the scratch context of the + /// target passed in the exe_ctx and return its result. + /// + /// @param[in] exe_ctx + /// The execution context to use when evaluating the expression. + /// + /// @param[in] options + /// Expression evaluation options. N.B. The language in the + /// evaluation options will be used to determine the language used for + /// expression evaluation. + /// + /// @param[in] expr_cstr + /// A C string containing the expression to be evaluated. + /// + /// @param[in] expr_prefix + /// If non-NULL, a C string containing translation-unit level + /// definitions to be included when the expression is parsed. + /// + /// @param[in,out] result_valobj_sp + /// If execution is successful, the result valobj is placed here. + /// + /// @param[out] + /// Filled in with an error in case the expression evaluation + /// fails to parse, run, or evaluated. + /// + /// @result + /// A Process::ExpressionResults value. eExpressionCompleted for success. + //------------------------------------------------------------------ + static lldb::ExpressionResults + Evaluate (ExecutionContext &exe_ctx, + const EvaluateExpressionOptions& options, + const char *expr_cstr, + const char *expr_prefix, + lldb::ValueObjectSP &result_valobj_sp, + Error &error); + + static const Error::ValueType kNoResult = 0x1001; ///< ValueObject::GetError() returns this if there is no result from the expression. +protected: + static lldb::addr_t + GetObjectPointer (lldb::StackFrameSP frame_sp, + ConstString &object_name, + Error &err); + + //------------------------------------------------------------------ + /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the environment. + //------------------------------------------------------------------ + + virtual void + ScanContext (ExecutionContext &exe_ctx, + lldb_private::Error &err) = 0; + + bool + PrepareToExecuteJITExpression (Stream &error_stream, + ExecutionContext &exe_ctx, + lldb::addr_t &struct_address); + + virtual bool + AddInitialArguments (ExecutionContext &exe_ctx, + std::vector<lldb::addr_t> &args, + Stream &error_stream) + { + return true; + } + + void + InstallContext (ExecutionContext &exe_ctx); + + bool + LockAndCheckContext (ExecutionContext &exe_ctx, + lldb::TargetSP &target_sp, + lldb::ProcessSP &process_sp, + lldb::StackFrameSP &frame_sp); + + Address m_address; ///< The address the process is stopped in. + lldb::addr_t m_stack_frame_bottom; ///< The bottom of the allocated stack frame. + lldb::addr_t m_stack_frame_top; ///< The top of the allocated stack frame. + + std::string m_expr_text; ///< The text of the expression, as typed by the user + std::string m_expr_prefix; ///< The text of the translation-level definitions, as provided by the user + lldb::LanguageType m_language; ///< The language to use when parsing (eLanguageTypeUnknown means use defaults) + bool m_allow_cxx; ///< True if the language allows C++. + bool m_allow_objc; ///< True if the language allows Objective-C. + std::string m_transformed_text; ///< The text of the expression, as send to the parser + ResultType m_desired_type; ///< The type to coerce the expression's result to. If eResultTypeAny, inferred from the expression. + + std::shared_ptr<IRExecutionUnit> m_execution_unit_sp; ///< The execution unit the expression is stored in. + std::unique_ptr<Materializer> m_materializer_ap; ///< The materializer to use when running the expression. + lldb::ModuleWP m_jit_module_wp; + bool m_enforce_valid_object; ///< True if the expression parser should enforce the presence of a valid class pointer in order to generate the expression as a method. + bool m_in_cplusplus_method; ///< True if the expression is compiled as a C++ member function (true if it was parsed when exe_ctx was in a C++ method). + bool m_in_objectivec_method; ///< True if the expression is compiled as an Objective-C method (true if it was parsed when exe_ctx was in an Objective-C method). + bool m_in_static_method; ///< True if the expression is compiled as a static (or class) method (currently true if it was parsed when exe_ctx was in an Objective-C class method). + bool m_needs_object_ptr; ///< True if "this" or "self" must be looked up and passed in. False if the expression doesn't really use them and they can be NULL. + bool m_const_object; ///< True if "this" is const. + Target *m_target; ///< The target for storing persistent data like types and variables. + + bool m_can_interpret; ///< True if the expression could be evaluated statically; false otherwise. + lldb::addr_t m_materialized_address; ///< The address at which the arguments to the expression have been materialized. + Materializer::DematerializerSP m_dematerializer_sp; ///< The dematerializer. +}; + +} // namespace lldb_private + +#endif // liblldb_UserExpression_h_ diff --git a/lldb/include/lldb/Expression/UtilityFunction.h b/lldb/include/lldb/Expression/UtilityFunction.h new file mode 100644 index 00000000000..12c7bc28bad --- /dev/null +++ b/lldb/include/lldb/Expression/UtilityFunction.h @@ -0,0 +1,166 @@ +//===-- UtilityFunction.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_UtilityFunction_h_ +#define liblldb_UtilityFunction_h_ + +// C Includes +// C++ Includes +#include <string> +#include <map> +#include <vector> + +// Other libraries and framework includes +// Project includes + +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" +#include "lldb/Core/ClangForward.h" +#include "lldb/Expression/Expression.h" + +namespace lldb_private +{ + +//---------------------------------------------------------------------- +/// @class UtilityFunction UtilityFunction.h "lldb/Expression/UtilityFunction.h" +/// @brief Encapsulates a bit of source code that provides a function that is callable +/// +/// LLDB uses expressions for various purposes, notably to call functions +/// and as a backend for the expr command. UtilityFunction encapsulates +/// a self-contained function meant to be used from other code. Utility +/// functions can perform error-checking for ClangUserExpressions, +//---------------------------------------------------------------------- +class UtilityFunction : public Expression +{ +public: + //------------------------------------------------------------------ + /// Constructor + /// + /// @param[in] text + /// The text of the function. Must be a full translation unit. + /// + /// @param[in] name + /// The name of the function, as used in the text. + //------------------------------------------------------------------ + UtilityFunction (ExecutionContextScope &exe_scope, + const char *text, + const char *name); + + ~UtilityFunction() override; + + //------------------------------------------------------------------ + /// Install the utility function into a process + /// + /// @param[in] error_stream + /// A stream to print parse errors and warnings to. + /// + /// @param[in] exe_ctx + /// The execution context to install the utility function to. + /// + /// @return + /// True on success (no errors); false otherwise. + //------------------------------------------------------------------ + virtual bool + Install (Stream &error_stream, ExecutionContext &exe_ctx) = 0; + + //------------------------------------------------------------------ + /// Check whether the given PC is inside the function + /// + /// Especially useful if the function dereferences NULL to indicate a failed + /// assert. + /// + /// @param[in] pc + /// The program counter to check. + /// + /// @return + /// True if the program counter falls within the function's bounds; + /// false if not (or the function is not JIT compiled) + //------------------------------------------------------------------ + bool + ContainsAddress (lldb::addr_t address) + { + // nothing is both >= LLDB_INVALID_ADDRESS and < LLDB_INVALID_ADDRESS, + // so this always returns false if the function is not JIT compiled yet + return (address >= m_jit_start_addr && address < m_jit_end_addr); + } + + + //------------------------------------------------------------------ + /// Return the string that the parser should parse. Must be a full + /// translation unit. + //------------------------------------------------------------------ + const char * + Text() override + { + return m_function_text.c_str(); + } + + //------------------------------------------------------------------ + /// Return the function name that should be used for executing the + /// expression. Text() should contain the definition of this + /// function. + //------------------------------------------------------------------ + const char * + FunctionName() override + { + return m_function_name.c_str(); + } + + //------------------------------------------------------------------ + /// Return the object that the parser should use when registering + /// local variables. May be NULL if the Expression doesn't care. + //------------------------------------------------------------------ + ExpressionVariableList * + LocalVariables () + { + return NULL; + } + + //------------------------------------------------------------------ + /// Return true if validation code should be inserted into the + /// expression. + //------------------------------------------------------------------ + bool + NeedsValidation() override + { + return false; + } + + //------------------------------------------------------------------ + /// Return true if external variables in the expression should be + /// resolved. + //------------------------------------------------------------------ + bool + NeedsVariableResolution() override + { + return false; + } + + // This makes the function caller function. + FunctionCaller * + MakeFunctionCaller(const CompilerType &return_type, const ValueList &arg_value_list, Error &error); + + // This one retrieves the function caller that is already made. If you haven't made it yet, this returns nullptr + FunctionCaller * + GetFunctionCaller() + { + return m_caller_up.get(); + } + +protected: + std::shared_ptr<IRExecutionUnit> m_execution_unit_sp; + lldb::ModuleWP m_jit_module_wp; + std::string m_function_text; ///< The text of the function. Must be a well-formed translation unit. + std::string m_function_name; ///< The name of the function. + std::unique_ptr<FunctionCaller> m_caller_up; +}; + +} // namespace lldb_private + +#endif // liblldb_UtilityFunction_h_ diff --git a/lldb/include/lldb/Symbol/ClangASTContext.h b/lldb/include/lldb/Symbol/ClangASTContext.h index 1735a483923..214ef8ff46b 100644 --- a/lldb/include/lldb/Symbol/ClangASTContext.h +++ b/lldb/include/lldb/Symbol/ClangASTContext.h @@ -1109,6 +1109,7 @@ protected: void * m_callback_baton; uint32_t m_pointer_byte_size; bool m_ast_owned; + bool m_can_evaluate_expressions; private: //------------------------------------------------------------------ @@ -1118,6 +1119,31 @@ private: const ClangASTContext& operator=(const ClangASTContext&); }; +class ClangASTContextForExpressions : public ClangASTContext +{ +public: + ClangASTContextForExpressions (Target &target); + + virtual ~ClangASTContextForExpressions () {} + + UserExpression * + GetUserExpression (const char *expr, + const char *expr_prefix, + lldb::LanguageType language, + Expression::ResultType desired_type) override; + + FunctionCaller * + GetFunctionCaller (const CompilerType &return_type, + const Address& function_address, + const ValueList &arg_value_list, + const char *name) override; + + UtilityFunction * + GetUtilityFunction(const char *text, const char *name) override; +private: + lldb::TargetWP m_target_wp; +}; + } // namespace lldb_private #endif // liblldb_ClangASTContext_h_ diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index a5d25f99f0d..657b8a512ba 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -14,6 +14,7 @@ #include <string> #include "lldb/lldb-private.h" #include "lldb/Core/ClangForward.h" +#include "lldb/Expression/Expression.h" #include "lldb/Symbol/CompilerDeclContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Type.h" @@ -438,6 +439,31 @@ public: virtual bool IsReferenceType (void *type, CompilerType *pointee_type, bool* is_rvalue) = 0; + + virtual UserExpression * + GetUserExpression (const char *expr, + const char *expr_prefix, + lldb::LanguageType language, + Expression::ResultType desired_type) + { + return nullptr; + } + + virtual FunctionCaller * + GetFunctionCaller (const CompilerType &return_type, + const Address& function_address, + const ValueList &arg_value_list, + const char *name) + { + return nullptr; + } + + virtual UtilityFunction * + GetUtilityFunction(const char *text, const char *name) + { + return nullptr; + } + protected: const LLVMCastKind m_kind; // Support for llvm casting SymbolFile *m_sym_file; diff --git a/lldb/include/lldb/Target/LanguageRuntime.h b/lldb/include/lldb/Target/LanguageRuntime.h index 57770ff487e..cdf0fbd8f45 100644 --- a/lldb/include/lldb/Target/LanguageRuntime.h +++ b/lldb/include/lldb/Target/LanguageRuntime.h @@ -97,6 +97,12 @@ public: { return m_process; } + + Target& + GetTargetRef() + { + return m_process->GetTarget(); + } virtual lldb::BreakpointResolverSP CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp) = 0; diff --git a/lldb/include/lldb/Target/ObjCLanguageRuntime.h b/lldb/include/lldb/Target/ObjCLanguageRuntime.h index a45f39098ab..b8973af84da 100644 --- a/lldb/include/lldb/Target/ObjCLanguageRuntime.h +++ b/lldb/include/lldb/Target/ObjCLanguageRuntime.h @@ -30,7 +30,7 @@ class CommandObjectObjC_ClassTable_Dump; namespace lldb_private { -class ClangUtilityFunction; +class UtilityFunction; class ObjCLanguageRuntime : public LanguageRuntime @@ -289,7 +289,7 @@ public: lldb::TypeSP LookupInCompleteClassCache (ConstString &name); - virtual ClangUtilityFunction * + virtual UtilityFunction * CreateObjectChecker (const char *) = 0; virtual ObjCRuntimeVersions diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 8612c3f8a70..90eb372a28e 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -742,7 +742,7 @@ class Process : public ExecutionContextScope, public PluginInterface { - friend class ClangFunction; // For WaitForStateChangeEventsPrivate + friend class FunctionCaller; // For WaitForStateChangeEventsPrivate friend class Debugger; // For PopProcessIOHandler and ProcessIOHandlerIsActive friend class ProcessEventData; friend class StopInfo; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 824d51c0487..c8df9ca069c 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -24,6 +24,7 @@ #include "lldb/Core/Disassembler.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/UserSettingsController.h" +#include "lldb/Expression/Expression.h" #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/PathMappingList.h" #include "lldb/Target/ProcessLaunchInfo.h" @@ -1227,12 +1228,47 @@ public: PathMappingList & GetImageSearchPathList (); + TypeSystem * + GetScratchTypeSystemForLanguage (lldb::LanguageType language, bool create_on_demand = true); + + // Creates a UserExpression for the given language, the rest of the parameters have the + // same meaning as for the UserExpression constructor. + // Returns a new-ed object which the caller owns. + + UserExpression * + GetUserExpressionForLanguage(const char *expr, + const char *expr_prefix, + lldb::LanguageType language, + Expression::ResultType desired_type, + Error &error); + + // Creates a FunctionCaller for the given language, the rest of the parameters have the + // same meaning as for the FunctionCaller constructor. Since a FunctionCaller can't be + // IR Interpreted, it makes no sense to call this with an ExecutionContextScope that lacks + // a Process. + // Returns a new-ed object which the caller owns. + + FunctionCaller * + GetFunctionCallerForLanguage (lldb::LanguageType language, + const CompilerType &return_type, + const Address& function_address, + const ValueList &arg_value_list, + const char *name, + Error &error); + + // Creates a UtilityFunction for the given language, the rest of the parameters have the + // same meaning as for the UtilityFunction constructor. + // Returns a new-ed object which the caller owns. + + UtilityFunction * + GetUtilityFunctionForLanguage (const char *expr, + lldb::LanguageType language, + const char *name, + Error &error); + ClangASTContext * GetScratchClangASTContext(bool create_on_demand=true); - TypeSystem* - GetTypeSystemForLanguage (lldb::LanguageType language); - ClangASTImporter * GetClangASTImporter(); diff --git a/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/lldb/include/lldb/Target/ThreadPlanCallFunction.h index c2876937419..47eee2808f1 100644 --- a/lldb/include/lldb/Target/ThreadPlanCallFunction.h +++ b/lldb/include/lldb/Target/ThreadPlanCallFunction.h @@ -92,7 +92,7 @@ public: return m_function_sp; } - // Classes that derive from ClangFunction, and implement + // Classes that derive from FunctionCaller, and implement // their own WillPop methods should call this so that the // thread state gets restored if the plan gets discarded. void diff --git a/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h b/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h index a1eba4a1d67..bb261d9c96b 100644 --- a/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h +++ b/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h @@ -30,7 +30,7 @@ public: Address &function, llvm::ArrayRef<lldb::addr_t> args, const EvaluateExpressionOptions &options, - lldb::ClangUserExpressionSP &user_expression_sp); + lldb::UserExpressionSP &user_expression_sp); ~ThreadPlanCallUserExpression() override; @@ -60,7 +60,7 @@ public: protected: private: - lldb::ClangUserExpressionSP m_user_expression_sp; // This is currently just used to ensure the + lldb::UserExpressionSP m_user_expression_sp; // This is currently just used to ensure the // User expression the initiated this ThreadPlan // lives as long as the thread plan does. bool m_manage_materialization = false; diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index 10bd5bc5cc7..787001a3307 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -27,6 +27,7 @@ class AddressResolver; class ArchSpec; class Args; class ASTResultSynthesizer; +class ASTStructExtractor; class Baton; class Block; class Breakpoint; @@ -48,16 +49,12 @@ class ClangASTContext; class ClangASTImporter; class ClangASTMetadata; class ClangASTSource; -class ClangExpression; class ClangExpressionDeclMap; class ClangExpressionParser; class ClangExpressionVariable; class ClangExpressionVariables; -class ClangFunction; class ClangModulesDeclVendor; class ClangPersistentVariables; -class ClangUserExpression; -class ClangUtilityFunction; class CommandInterpreter; class CommandInterpreterRunOptions; class CommandObject; @@ -93,8 +90,10 @@ class ExecutionContext; class ExecutionContextRef; class ExecutionContextRefLocker; class ExecutionContextScope; +class Expression; class ExpressionVariable; class ExpressionVariableList; +class ExpressionTypeSystemHelper; class File; class FileSpec; class FileSpecList; @@ -163,6 +162,7 @@ class OptionValueUInt64; class OptionValueUUID; class NamedOption; class PathMappingList; +class FunctionCaller; class Platform; class Process; class ProcessAttachInfo; @@ -268,6 +268,8 @@ class Unwind; class UnwindAssembly; class UnwindPlan; class UnwindTable; +class UserExpression; +class UtilityFunction; class VMRange; class Value; class ValueList; @@ -308,7 +310,7 @@ namespace lldb { typedef std::unique_ptr<lldb_private::ClangASTSource> ClangASTSourceUP; typedef std::unique_ptr<lldb_private::ClangModulesDeclVendor> ClangModulesDeclVendorUP; typedef std::unique_ptr<lldb_private::ClangPersistentVariables> ClangPersistentVariablesUP; - typedef std::shared_ptr<lldb_private::ClangUserExpression> ClangUserExpressionSP; + typedef std::shared_ptr<lldb_private::UserExpression> UserExpressionSP; typedef std::shared_ptr<lldb_private::CommandObject> CommandObjectSP; typedef std::shared_ptr<lldb_private::Communication> CommunicationSP; typedef std::shared_ptr<lldb_private::Connection> ConnectionSP; @@ -326,6 +328,7 @@ namespace lldb { typedef std::shared_ptr<lldb_private::ExpressionVariable> ExpressionVariableSP; typedef std::shared_ptr<lldb_private::File> FileSP; typedef std::shared_ptr<lldb_private::Function> FunctionSP; + typedef std::shared_ptr<lldb_private::FunctionCaller> FunctionCallerSP; typedef std::shared_ptr<lldb_private::FuncUnwinders> FuncUnwindersSP; typedef std::unique_ptr<lldb_private::GoASTContext> GoASTContextUP; typedef std::shared_ptr<lldb_private::InlineFunctionInfo> InlineFunctionInfoSP; @@ -434,6 +437,7 @@ namespace lldb { typedef std::weak_ptr<lldb_private::UnixSignals> UnixSignalsWP; typedef std::shared_ptr<lldb_private::UnwindAssembly> UnwindAssemblySP; typedef std::shared_ptr<lldb_private::UnwindPlan> UnwindPlanSP; + typedef std::shared_ptr<lldb_private::UtilityFunction> UtilityFunctionSP; typedef lldb_private::SharingPtr<lldb_private::ValueObject> ValueObjectSP; typedef std::shared_ptr<lldb_private::Value> ValueSP; typedef std::shared_ptr<lldb_private::ValueList> ValueListSP; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index e48a6875cce..6b960a6c637 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -387,7 +387,7 @@ 2689005C13353E0400698AC0 /* ValueObjectVariable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */; }; 2689005D13353E0400698AC0 /* VMRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9E10F1B85900F91463 /* VMRange.cpp */; }; 2689005E13353E0E00698AC0 /* ClangASTSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49D7072811B5AD11001AD875 /* ClangASTSource.cpp */; }; - 2689005F13353E0E00698AC0 /* ClangFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */; }; + 2689005F13353E0E00698AC0 /* ClangFunctionCaller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3DA118FB96F00E575D0 /* ClangFunctionCaller.cpp */; }; 2689006013353E0E00698AC0 /* ClangExpressionDeclMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49F1A74511B3388F003ED505 /* ClangExpressionDeclMap.cpp */; }; 2689006113353E0E00698AC0 /* ClangExpressionParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49445C2512245E3600C11A81 /* ClangExpressionParser.cpp */; }; 2689006313353E0E00698AC0 /* ClangPersistentVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49D4FE871210B61C00CDB854 /* ClangPersistentVariables.cpp */; }; @@ -680,11 +680,15 @@ 49DA65031485C92A005FF180 /* AppleObjCDeclVendor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DA65021485C92A005FF180 /* AppleObjCDeclVendor.cpp */; }; 49DCF6FE170E6B4A0092F75E /* IRMemoryMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DCF6FD170E6B4A0092F75E /* IRMemoryMap.cpp */; }; 49DCF702170E70120092F75E /* Materializer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DCF700170E70120092F75E /* Materializer.cpp */; }; + 4C0083401B9F9BA900D5CF24 /* UtilityFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C00833F1B9F9BA900D5CF24 /* UtilityFunction.cpp */; settings = {ASSET_TAGS = (); }; }; + 4C2479BD1BA39295009C9A7B /* FunctionCaller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C0083321B9A5DE200D5CF24 /* FunctionCaller.cpp */; settings = {ASSET_TAGS = (); }; }; 4C3ADCD61810D88B00357218 /* BreakpointResolverFileRegex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CAA56141422D986001FFA01 /* BreakpointResolverFileRegex.cpp */; }; 4C56543119D1EFAA002E9C44 /* ThreadPlanPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C56543019D1EFAA002E9C44 /* ThreadPlanPython.cpp */; }; 4C56543519D2297A002E9C44 /* SBThreadPlan.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C56543419D2297A002E9C44 /* SBThreadPlan.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4C56543719D22B32002E9C44 /* SBThreadPlan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C56543619D22B32002E9C44 /* SBThreadPlan.cpp */; }; 4C6649A314EEE81000B0316F /* StreamCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C6649A214EEE81000B0316F /* StreamCallback.cpp */; }; + 4C88BC2A1BA3722B00AA0964 /* Expression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C88BC291BA3722B00AA0964 /* Expression.cpp */; settings = {ASSET_TAGS = (); }; }; + 4C88BC2D1BA391B000AA0964 /* UserExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C0083331B9A5DE200D5CF24 /* UserExpression.cpp */; settings = {ASSET_TAGS = (); }; }; 4CABA9E0134A8BCD00539BDD /* ValueObjectMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */; }; 4CCA644D13B40B82003BDF98 /* ItaniumABILanguageRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CCA643D13B40B82003BDF98 /* ItaniumABILanguageRuntime.cpp */; }; 4CCA645013B40B82003BDF98 /* AppleObjCRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CCA644213B40B82003BDF98 /* AppleObjCRuntime.cpp */; }; @@ -1875,7 +1879,7 @@ 26BC7D8410F1B77400F91463 /* ValueObjectList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectList.h; path = include/lldb/Core/ValueObjectList.h; sourceTree = "<group>"; }; 26BC7D8510F1B77400F91463 /* ValueObjectVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectVariable.h; path = include/lldb/Core/ValueObjectVariable.h; sourceTree = "<group>"; }; 26BC7D8610F1B77400F91463 /* VMRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VMRange.h; path = include/lldb/Core/VMRange.h; sourceTree = "<group>"; }; - 26BC7DC010F1B79500F91463 /* ClangExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangExpression.h; path = include/lldb/Expression/ClangExpression.h; sourceTree = "<group>"; }; + 26BC7DC010F1B79500F91463 /* ClangExpressionHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangExpressionHelper.h; path = include/lldb/Expression/ClangExpressionHelper.h; sourceTree = "<group>"; }; 26BC7DC310F1B79500F91463 /* DWARFExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DWARFExpression.h; path = include/lldb/Expression/DWARFExpression.h; sourceTree = "<group>"; }; 26BC7DD210F1B7D500F91463 /* Condition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Condition.h; path = include/lldb/Host/Condition.h; sourceTree = "<group>"; }; 26BC7DD310F1B7D500F91463 /* Endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Endian.h; path = include/lldb/Host/Endian.h; sourceTree = "<group>"; }; @@ -2289,12 +2293,21 @@ 49EC3E9C118F90D400B1265E /* ThreadPlanCallFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanCallFunction.h; path = include/lldb/Target/ThreadPlanCallFunction.h; sourceTree = "<group>"; }; 49F1A74511B3388F003ED505 /* ClangExpressionDeclMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangExpressionDeclMap.cpp; path = source/Expression/ClangExpressionDeclMap.cpp; sourceTree = "<group>"; }; 49F1A74911B338AE003ED505 /* ClangExpressionDeclMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangExpressionDeclMap.h; path = include/lldb/Expression/ClangExpressionDeclMap.h; sourceTree = "<group>"; }; + 4C00832C1B9A58A700D5CF24 /* Expression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Expression.h; path = include/lldb/Expression/Expression.h; sourceTree = "<group>"; }; + 4C00832D1B9A58A700D5CF24 /* FunctionCaller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FunctionCaller.h; path = include/lldb/Expression/FunctionCaller.h; sourceTree = "<group>"; }; + 4C00832E1B9A58A700D5CF24 /* UserExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UserExpression.h; path = include/lldb/Expression/UserExpression.h; sourceTree = "<group>"; }; + 4C0083321B9A5DE200D5CF24 /* FunctionCaller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FunctionCaller.cpp; path = source/Expression/FunctionCaller.cpp; sourceTree = "<group>"; }; + 4C0083331B9A5DE200D5CF24 /* UserExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UserExpression.cpp; path = source/Expression/UserExpression.cpp; sourceTree = "<group>"; }; + 4C00833D1B9F9B8400D5CF24 /* UtilityFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UtilityFunction.h; path = include/lldb/Expression/UtilityFunction.h; sourceTree = "<group>"; }; + 4C00833F1B9F9BA900D5CF24 /* UtilityFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UtilityFunction.cpp; path = source/Expression/UtilityFunction.cpp; sourceTree = "<group>"; }; 4C00986F11500B4300F316B0 /* UnixSignals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnixSignals.h; path = include/lldb/Target/UnixSignals.h; sourceTree = "<group>"; }; 4C00987011500B4300F316B0 /* UnixSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnixSignals.cpp; path = source/Target/UnixSignals.cpp; sourceTree = "<group>"; }; 4C08CDE711C81EF8001610A8 /* ThreadSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadSpec.cpp; path = source/Target/ThreadSpec.cpp; sourceTree = "<group>"; }; 4C08CDEB11C81F1E001610A8 /* ThreadSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadSpec.h; path = include/lldb/Target/ThreadSpec.h; sourceTree = "<group>"; }; 4C09CB73116BD98B00C7A725 /* CommandCompletions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandCompletions.h; path = include/lldb/Interpreter/CommandCompletions.h; sourceTree = "<group>"; }; 4C09CB74116BD98B00C7A725 /* CommandCompletions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandCompletions.cpp; path = source/Commands/CommandCompletions.cpp; sourceTree = "<group>"; }; + 4C2479BE1BA39843009C9A7B /* ExpressionParser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ExpressionParser.h; path = include/lldb/Expression/ExpressionParser.h; sourceTree = "<group>"; }; + 4C29E77D1BA2403F00DFF855 /* ExpressionTypeSystemHelper.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ExpressionTypeSystemHelper.h; path = include/lldb/Expression/ExpressionTypeSystemHelper.h; sourceTree = "<group>"; }; 4C2FAE2E135E3A70001EDE44 /* SharedCluster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharedCluster.h; path = include/lldb/Utility/SharedCluster.h; sourceTree = "<group>"; }; 4C43DEF9110641F300E55CBF /* ThreadPlanShouldStopHere.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanShouldStopHere.h; path = include/lldb/Target/ThreadPlanShouldStopHere.h; sourceTree = "<group>"; }; 4C43DEFA110641F300E55CBF /* ThreadPlanShouldStopHere.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanShouldStopHere.cpp; path = source/Target/ThreadPlanShouldStopHere.cpp; sourceTree = "<group>"; }; @@ -2315,9 +2328,10 @@ 4C73152119B7D71700F865A4 /* Iterable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Iterable.h; path = include/lldb/Utility/Iterable.h; sourceTree = "<group>"; }; 4C7CF7E31295E10E00B4FBB5 /* ThreadPlanCallUserExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanCallUserExpression.h; path = include/lldb/Target/ThreadPlanCallUserExpression.h; sourceTree = "<group>"; }; 4C7CF7E51295E12B00B4FBB5 /* ThreadPlanCallUserExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanCallUserExpression.cpp; path = source/Target/ThreadPlanCallUserExpression.cpp; sourceTree = "<group>"; }; - 4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangFunction.cpp; path = source/Expression/ClangFunction.cpp; sourceTree = "<group>"; }; + 4C88BC291BA3722B00AA0964 /* Expression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Expression.cpp; path = source/Expression/Expression.cpp; sourceTree = "<group>"; }; + 4C98D3DA118FB96F00E575D0 /* ClangFunctionCaller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangFunctionCaller.cpp; path = source/Expression/ClangFunctionCaller.cpp; sourceTree = "<group>"; }; 4C98D3DB118FB96F00E575D0 /* IRExecutionUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRExecutionUnit.cpp; path = source/Expression/IRExecutionUnit.cpp; sourceTree = "<group>"; }; - 4C98D3E0118FB98F00E575D0 /* ClangFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangFunction.h; path = include/lldb/Expression/ClangFunction.h; sourceTree = "<group>"; }; + 4C98D3E0118FB98F00E575D0 /* ClangFunctionCaller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangFunctionCaller.h; path = include/lldb/Expression/ClangFunctionCaller.h; sourceTree = "<group>"; }; 4C98D3E1118FB98F00E575D0 /* IRExecutionUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRExecutionUnit.h; path = include/lldb/Expression/IRExecutionUnit.h; sourceTree = "<group>"; }; 4CA9637911B6E99A00780E28 /* CommandObjectApropos.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectApropos.cpp; path = source/Commands/CommandObjectApropos.cpp; sourceTree = "<group>"; }; 4CA9637A11B6E99A00780E28 /* CommandObjectApropos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectApropos.h; path = source/Commands/CommandObjectApropos.h; sourceTree = "<group>"; }; @@ -4374,27 +4388,37 @@ 26BC7DBE10F1B78200F91463 /* Expression */ = { isa = PBXGroup; children = ( + 4C00832C1B9A58A700D5CF24 /* Expression.h */, + 4C88BC291BA3722B00AA0964 /* Expression.cpp */, + 4C29E77D1BA2403F00DFF855 /* ExpressionTypeSystemHelper.h */, + 26BC7DC010F1B79500F91463 /* ClangExpressionHelper.h */, + 4C00832D1B9A58A700D5CF24 /* FunctionCaller.h */, + 4C0083321B9A5DE200D5CF24 /* FunctionCaller.cpp */, + 4C98D3E0118FB98F00E575D0 /* ClangFunctionCaller.h */, + 4C98D3DA118FB96F00E575D0 /* ClangFunctionCaller.cpp */, + 4C00832E1B9A58A700D5CF24 /* UserExpression.h */, + 4C0083331B9A5DE200D5CF24 /* UserExpression.cpp */, + 49445E341225AB6A00C11A81 /* ClangUserExpression.h */, + 26BC7ED510F1B86700F91463 /* ClangUserExpression.cpp */, + 497C86C1122823F300B54702 /* ClangUtilityFunction.h */, + 497C86BD122823D800B54702 /* ClangUtilityFunction.cpp */, + 4C00833D1B9F9B8400D5CF24 /* UtilityFunction.h */, + 4C00833F1B9F9BA900D5CF24 /* UtilityFunction.cpp */, 49A1CAC11430E21D00306AC9 /* ExpressionSourceCode.h */, 49A1CAC31430E8BD00306AC9 /* ExpressionSourceCode.cpp */, 4984BA171B979C08008658D4 /* ExpressionVariable.h */, 4984BA151B979973008658D4 /* ExpressionVariable.cpp */, 49D7072611B5AD03001AD875 /* ClangASTSource.h */, 49D7072811B5AD11001AD875 /* ClangASTSource.cpp */, - 26BC7DC010F1B79500F91463 /* ClangExpression.h */, - 4C98D3E0118FB98F00E575D0 /* ClangFunction.h */, - 4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */, 49F1A74911B338AE003ED505 /* ClangExpressionDeclMap.h */, 49F1A74511B3388F003ED505 /* ClangExpressionDeclMap.cpp */, + 4C2479BE1BA39843009C9A7B /* ExpressionParser.h */, 49445C2912245E5500C11A81 /* ClangExpressionParser.h */, 49445C2512245E3600C11A81 /* ClangExpressionParser.cpp */, 4959511B1A1BC48100F6F8FC /* ClangModulesDeclVendor.h */, 4959511E1A1BC4BC00F6F8FC /* ClangModulesDeclVendor.cpp */, 49D4FE821210B5FB00CDB854 /* ClangPersistentVariables.h */, 49D4FE871210B61C00CDB854 /* ClangPersistentVariables.cpp */, - 49445E341225AB6A00C11A81 /* ClangUserExpression.h */, - 26BC7ED510F1B86700F91463 /* ClangUserExpression.cpp */, - 497C86C1122823F300B54702 /* ClangUtilityFunction.h */, - 497C86BD122823D800B54702 /* ClangUtilityFunction.cpp */, 26BC7DC310F1B79500F91463 /* DWARFExpression.h */, 26BC7ED810F1B86700F91463 /* DWARFExpression.cpp */, 4906FD4412F2257600A2A77C /* ASTDumper.h */, @@ -6124,6 +6148,7 @@ 33E5E8471A674FB60024ED68 /* StringConvert.cpp in Sources */, 26D1804216CEDF0700EDFB5B /* TimeSpecTimeout.cpp in Sources */, 2689FFDA13353D9D00698AC0 /* lldb.cpp in Sources */, + 4C0083401B9F9BA900D5CF24 /* UtilityFunction.cpp in Sources */, 26474CCD18D0CB5B0073DEBA /* RegisterContextPOSIX_x86.cpp in Sources */, 2689FFEF13353DB600698AC0 /* Breakpoint.cpp in Sources */, 267A47FB1B1411C40021A5BC /* NativeRegisterContext.cpp in Sources */, @@ -6159,6 +6184,7 @@ 2689000F13353DB600698AC0 /* StoppointLocation.cpp in Sources */, 2689001113353DB600698AC0 /* Watchpoint.cpp in Sources */, 2689001213353DDE00698AC0 /* CommandObjectApropos.cpp in Sources */, + 4C88BC2A1BA3722B00AA0964 /* Expression.cpp in Sources */, 23042D121976CA1D00621B2C /* PlatformKalimba.cpp in Sources */, 2689001313353DDE00698AC0 /* CommandObjectArgs.cpp in Sources */, 2689001413353DDE00698AC0 /* CommandObjectBreakpoint.cpp in Sources */, @@ -6278,7 +6304,7 @@ 2689005D13353E0400698AC0 /* VMRange.cpp in Sources */, 2689005E13353E0E00698AC0 /* ClangASTSource.cpp in Sources */, 3FDFED0F19B7D269009756A7 /* ThisThread.cpp in Sources */, - 2689005F13353E0E00698AC0 /* ClangFunction.cpp in Sources */, + 2689005F13353E0E00698AC0 /* ClangFunctionCaller.cpp in Sources */, 2689006013353E0E00698AC0 /* ClangExpressionDeclMap.cpp in Sources */, 2689006113353E0E00698AC0 /* ClangExpressionParser.cpp in Sources */, B5EFAE861AE53B1D007059F3 /* RegisterContextFreeBSD_arm.cpp in Sources */, @@ -6402,6 +6428,7 @@ 268900CC13353E5F00698AC0 /* SymbolFileDWARFDebugMap.cpp in Sources */, 268900CD13353E5F00698AC0 /* UniqueDWARFASTType.cpp in Sources */, 944372DC171F6B4300E57C32 /* RegisterContextDummy.cpp in Sources */, + 4C88BC2D1BA391B000AA0964 /* UserExpression.cpp in Sources */, 268900CE13353E5F00698AC0 /* SymbolFileSymtab.cpp in Sources */, 266E82971B8CE3AC008FCA06 /* DWARFDIE.cpp in Sources */, 268900CF13353E5F00698AC0 /* SymbolVendorMacOSX.cpp in Sources */, @@ -6444,6 +6471,7 @@ 268900EC13353E6F00698AC0 /* LanguageRuntime.cpp in Sources */, 268900ED13353E6F00698AC0 /* ObjCLanguageRuntime.cpp in Sources */, 268900EE13353E6F00698AC0 /* PathMappingList.cpp in Sources */, + 4C2479BD1BA39295009C9A7B /* FunctionCaller.cpp in Sources */, 268900EF13353E6F00698AC0 /* Platform.cpp in Sources */, 268900F013353E6F00698AC0 /* Process.cpp in Sources */, 26BC17AD18C7F4CB00D2196D /* RegisterContextPOSIXCore_mips64.cpp in Sources */, diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp index df6cc51ed07..ee467402569 100644 --- a/lldb/source/API/SBFrame.cpp +++ b/lldb/source/API/SBFrame.cpp @@ -22,7 +22,7 @@ #include "lldb/Core/ValueObjectRegister.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Expression/ClangPersistentVariables.h" -#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Expression/UserExpression.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/Function.h" diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp index 1d082f69416..0dab0e16bf1 100644 --- a/lldb/source/Breakpoint/BreakpointLocation.cpp +++ b/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -21,9 +21,10 @@ #include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/ValueObject.h" -#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Expression/UserExpression.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Target.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" @@ -88,6 +89,12 @@ BreakpointLocation::GetBreakpoint () return m_owner; } +Target & +BreakpointLocation::GetTarget() +{ + return m_owner.GetTarget(); +} + bool BreakpointLocation::IsEnabled () const { @@ -278,10 +285,26 @@ BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error) !m_user_expression_sp || !m_user_expression_sp->MatchesContext(exe_ctx)) { - m_user_expression_sp.reset(new ClangUserExpression(condition_text, - NULL, - lldb::eLanguageTypeUnknown, - ClangUserExpression::eResultTypeAny)); + LanguageType language = eLanguageTypeUnknown; + // See if we can figure out the language from the frame, otherwise use the default language: + CompileUnit *comp_unit = m_address.CalculateSymbolContextCompileUnit(); + if (comp_unit) + language = comp_unit->GetLanguage(); + + Error error; + m_user_expression_sp.reset(GetTarget().GetUserExpressionForLanguage(condition_text, + NULL, + language, + Expression::eResultTypeAny, + error)); + if (error.Fail()) + { + if (log) + log->Printf("Error getting condition expression: %s.", error.AsCString()); + m_user_expression_sp.reset(); + return true; + } + StreamString errors; diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp index db76ffb8685..99a4d47a8d9 100644 --- a/lldb/source/Breakpoint/BreakpointOptions.cpp +++ b/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -20,7 +20,6 @@ #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadSpec.h" -#include "lldb/Expression/ClangUserExpression.h" using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp index af9cfaff6a2..41b24fd67df 100644 --- a/lldb/source/Breakpoint/Watchpoint.cpp +++ b/lldb/source/Breakpoint/Watchpoint.cpp @@ -22,7 +22,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadSpec.h" -#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Expression/UserExpression.h" using namespace lldb; using namespace lldb_private; @@ -371,7 +371,17 @@ Watchpoint::SetCondition (const char *condition) else { // Pass NULL for expr_prefix (no translation-unit level definitions). - m_condition_ap.reset(new ClangUserExpression (condition, NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny)); + Error error; + m_condition_ap.reset(m_target.GetUserExpressionForLanguage (condition, + NULL, + lldb::eLanguageTypeUnknown, + UserExpression::eResultTypeAny, + error)); + if (error.Fail()) + { + // FIXME: Log something... + m_condition_ap.reset(); + } } SendWatchpointChangedEvent (eWatchpointEventTypeConditionChanged); } diff --git a/lldb/source/Breakpoint/WatchpointOptions.cpp b/lldb/source/Breakpoint/WatchpointOptions.cpp index c2c9696c4ce..d11c8f74f94 100644 --- a/lldb/source/Breakpoint/WatchpointOptions.cpp +++ b/lldb/source/Breakpoint/WatchpointOptions.cpp @@ -20,7 +20,6 @@ #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadSpec.h" -#include "lldb/Expression/ClangUserExpression.h" using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Commands/CommandObjectArgs.cpp b/lldb/source/Commands/CommandObjectArgs.cpp index 39dcba07cca..c4db97caa6a 100644 --- a/lldb/source/Commands/CommandObjectArgs.cpp +++ b/lldb/source/Commands/CommandObjectArgs.cpp @@ -17,9 +17,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" -#include "lldb/Expression/ClangExpression.h" #include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h" -#include "lldb/Expression/ClangFunction.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 7e787bce8c9..96dd90e7ecc 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -17,8 +17,7 @@ #include "lldb/Core/ValueObjectVariable.h" #include "lldb/DataFormatters/ValueObjectPrinter.h" #include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h" -#include "lldb/Expression/ClangUserExpression.h" -#include "lldb/Expression/ClangFunction.h" +#include "lldb/Expression/UserExpression.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Host/Host.h" #include "lldb/Host/StringConvert.h" @@ -345,7 +344,7 @@ CommandObjectExpression::EvaluateExpression } else { - if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult) + if (result_valobj_sp->GetError().GetError() == UserExpression::kNoResult) { if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid()) { diff --git a/lldb/source/DataFormatters/VectorType.cpp b/lldb/source/DataFormatters/VectorType.cpp index faef33de909..56ca3ceac2a 100644 --- a/lldb/source/DataFormatters/VectorType.cpp +++ b/lldb/source/DataFormatters/VectorType.cpp @@ -235,7 +235,7 @@ namespace lldb_private { TargetSP target_sp(m_backend.GetTargetSP()); m_child_type = ::GetCompilerTypeForFormat(m_parent_format, element_type, - target_sp ? target_sp->GetTypeSystemForLanguage(lldb::eLanguageTypeC) : nullptr); + target_sp ? target_sp->GetScratchTypeSystemForLanguage(lldb::eLanguageTypeC) : nullptr); m_num_children = ::CalculateNumChildren(parent_type, m_child_type); m_item_format = GetItemFormatForFormat(m_parent_format, diff --git a/lldb/source/Expression/ASTStructExtractor.cpp b/lldb/source/Expression/ASTStructExtractor.cpp index 98628dbc92b..049173e32f3 100644 --- a/lldb/source/Expression/ASTStructExtractor.cpp +++ b/lldb/source/Expression/ASTStructExtractor.cpp @@ -28,7 +28,7 @@ using namespace lldb_private; ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough, const char *struct_name, - ClangFunction &function) : + ClangFunctionCaller &function) : m_ast_context (NULL), m_passthrough (passthrough), m_passthrough_sema (NULL), diff --git a/lldb/source/Expression/CMakeLists.txt b/lldb/source/Expression/CMakeLists.txt index 92f8f0863bf..4b689da027b 100644 --- a/lldb/source/Expression/CMakeLists.txt +++ b/lldb/source/Expression/CMakeLists.txt @@ -5,18 +5,22 @@ add_lldb_library(lldbExpression ClangASTSource.cpp ClangExpressionDeclMap.cpp ClangExpressionParser.cpp - ClangFunction.cpp + ClangFunctionCaller.cpp ClangModulesDeclVendor.cpp ClangPersistentVariables.cpp ClangUserExpression.cpp ClangUtilityFunction.cpp DWARFExpression.cpp + Expression.cpp ExpressionSourceCode.cpp ExpressionVariable.cpp + FunctionCaller.cpp IRDynamicChecks.cpp IRExecutionUnit.cpp IRForTarget.cpp IRInterpreter.cpp IRMemoryMap.cpp Materializer.cpp + UserExpression.cpp + UtilityFunction.cpp ) diff --git a/lldb/source/Expression/ClangASTSource.cpp b/lldb/source/Expression/ClangASTSource.cpp index ef778a1bca4..e6ddaa7e506 100644 --- a/lldb/source/Expression/ClangASTSource.cpp +++ b/lldb/source/Expression/ClangASTSource.cpp @@ -15,7 +15,6 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Expression/ASTDumper.h" #include "lldb/Expression/ClangASTSource.h" -#include "lldb/Expression/ClangExpression.h" #include "lldb/Expression/ClangModulesDeclVendor.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompilerDeclContext.h" diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp index d5dbaf16b4a..2a4663966cf 100644 --- a/lldb/source/Expression/ClangExpressionParser.cpp +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -19,7 +19,7 @@ #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Expression/ClangASTSource.h" -#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/ClangExpressionHelper.h" #include "lldb/Expression/ClangExpressionDeclMap.h" #include "lldb/Expression/ClangModulesDeclVendor.h" #include "lldb/Expression/ClangPersistentVariables.h" @@ -37,6 +37,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ExternalASTSource.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" #include "clang/CodeGen/CodeGenAction.h" @@ -108,7 +109,7 @@ public: } virtual void moduleImport(SourceLocation import_location, - ModuleIdPath path, + clang::ModuleIdPath path, const clang::Module * /*null*/) { std::vector<ConstString> string_path; @@ -149,9 +150,9 @@ public: //===----------------------------------------------------------------------===// ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, - ClangExpression &expr, + Expression &expr, bool generate_debug_info) : - m_expr (expr), + ExpressionParser (exe_scope, expr, generate_debug_info), m_compiler (), m_code_generator (), m_pp_callbacks(nullptr) @@ -255,7 +256,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, m_compiler->getLangOpts().WChar = true; m_compiler->getLangOpts().Blocks = true; m_compiler->getLangOpts().DebuggerSupport = true; // Features specifically for debugger clients - if (expr.DesiredResultType() == ClangExpression::eResultTypeId) + if (expr.DesiredResultType() == Expression::eResultTypeId) m_compiler->getLangOpts().DebuggerCastResultToId = true; m_compiler->getLangOpts().CharIsSigned = @@ -346,7 +347,8 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, ast_context->InitBuiltinTypes(m_compiler->getTarget()); - ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); + ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); + ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); if (decl_map) { @@ -430,9 +432,11 @@ ClangExpressionParser::Parse (Stream &stream) diag_buf->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor()); - ASTConsumer *ast_transformer = m_expr.ASTTransformer(m_code_generator.get()); + ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); - if (ClangExpressionDeclMap *decl_map = m_expr.DeclMap()) + ASTConsumer *ast_transformer = type_system_helper->ASTTransformer(m_code_generator.get()); + + if (ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap()) decl_map->InstallCodeGenerator(m_code_generator.get()); if (ast_transformer) @@ -479,7 +483,7 @@ ClangExpressionParser::Parse (Stream &stream) if (!num_errors) { - if (m_expr.DeclMap() && !m_expr.DeclMap()->ResolveUnknownTypes()) + if (type_system_helper->DeclMap() && !type_system_helper->DeclMap()->ResolveUnknownTypes()) { stream.Printf("error: Couldn't infer the type of a variable\n"); num_errors++; @@ -552,7 +556,8 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, exe_ctx.GetTargetSP(), m_compiler->getTargetOpts().Features)); - ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); // result can be NULL + ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); + ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); // result can be NULL if (decl_map) { @@ -640,11 +645,3 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, return err; } - -bool -ClangExpressionParser::GetGenerateDebugInfo () const -{ - if (m_compiler) - return m_compiler->getCodeGenOpts().getDebugInfo() == CodeGenOptions::FullDebugInfo; - return false; -} diff --git a/lldb/source/Expression/ClangFunctionCaller.cpp b/lldb/source/Expression/ClangFunctionCaller.cpp new file mode 100644 index 00000000000..628952fe6b8 --- /dev/null +++ b/lldb/source/Expression/ClangFunctionCaller.cpp @@ -0,0 +1,220 @@ +//===-- ClangFunctionCallerCaller.cpp ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" +#include "clang/CodeGen/CodeGenAction.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/IR/Module.h" + +// Project includes +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/State.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectList.h" +#include "lldb/Expression/ASTStructExtractor.h" +#include "lldb/Expression/ClangExpressionParser.h" +#include "lldb/Expression/ClangFunctionCaller.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallFunction.h" + +using namespace lldb_private; + +//---------------------------------------------------------------------- +// ClangFunctionCaller constructor +//---------------------------------------------------------------------- +ClangFunctionCaller::ClangFunctionCaller +( + ExecutionContextScope &exe_scope, + const CompilerType &return_type, + const Address& functionAddress, + const ValueList &arg_value_list, + const char *name +) : + FunctionCaller(exe_scope, return_type, functionAddress, arg_value_list, name), + m_type_system_helper (*this) +{ + m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess()); + // Can't make a ClangFunctionCaller without a process. + assert (m_jit_process_wp.lock()); +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +ClangFunctionCaller::~ClangFunctionCaller() +{ +} + +unsigned +ClangFunctionCaller::CompileFunction (Stream &errors) +{ + if (m_compiled) + return 0; + + // FIXME: How does clang tell us there's no return value? We need to handle that case. + unsigned num_errors = 0; + + std::string return_type_str (m_function_return_type.GetTypeName().AsCString("")); + + // Cons up the function we're going to wrap our call in, then compile it... + // We declare the function "extern "C"" because the compiler might be in C++ + // mode which would mangle the name and then we couldn't find it again... + m_wrapper_function_text.clear(); + m_wrapper_function_text.append ("extern \"C\" void "); + m_wrapper_function_text.append (m_wrapper_function_name); + m_wrapper_function_text.append (" (void *input)\n{\n struct "); + m_wrapper_function_text.append (m_wrapper_struct_name); + m_wrapper_function_text.append (" \n {\n"); + m_wrapper_function_text.append (" "); + m_wrapper_function_text.append (return_type_str); + m_wrapper_function_text.append (" (*fn_ptr) ("); + + // Get the number of arguments. If we have a function type and it is prototyped, + // trust that, otherwise use the values we were given. + + // FIXME: This will need to be extended to handle Variadic functions. We'll need + // to pull the defined arguments out of the function, then add the types from the + // arguments list for the variable arguments. + + uint32_t num_args = UINT32_MAX; + bool trust_function = false; + // GetArgumentCount returns -1 for an unprototyped function. + CompilerType function_clang_type; + if (m_function_ptr) + { + function_clang_type = m_function_ptr->GetCompilerType(); + if (function_clang_type) + { + int num_func_args = function_clang_type.GetFunctionArgumentCount(); + if (num_func_args >= 0) + { + trust_function = true; + num_args = num_func_args; + } + } + } + + if (num_args == UINT32_MAX) + num_args = m_arg_values.GetSize(); + + std::string args_buffer; // This one stores the definition of all the args in "struct caller". + std::string args_list_buffer; // This one stores the argument list called from the structure. + for (size_t i = 0; i < num_args; i++) + { + std::string type_name; + + if (trust_function) + { + type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i).GetTypeName().AsCString(""); + } + else + { + CompilerType clang_qual_type = m_arg_values.GetValueAtIndex(i)->GetCompilerType (); + if (clang_qual_type) + { + type_name = clang_qual_type.GetTypeName().AsCString(""); + } + else + { + errors.Printf("Could not determine type of input value %" PRIu64 ".", (uint64_t)i); + return 1; + } + } + + m_wrapper_function_text.append (type_name); + if (i < num_args - 1) + m_wrapper_function_text.append (", "); + + char arg_buf[32]; + args_buffer.append (" "); + args_buffer.append (type_name); + snprintf(arg_buf, 31, "arg_%" PRIu64, (uint64_t)i); + args_buffer.push_back (' '); + args_buffer.append (arg_buf); + args_buffer.append (";\n"); + + args_list_buffer.append ("__lldb_fn_data->"); + args_list_buffer.append (arg_buf); + if (i < num_args - 1) + args_list_buffer.append (", "); + + } + m_wrapper_function_text.append (");\n"); // Close off the function calling prototype. + + m_wrapper_function_text.append (args_buffer); + + m_wrapper_function_text.append (" "); + m_wrapper_function_text.append (return_type_str); + m_wrapper_function_text.append (" return_value;"); + m_wrapper_function_text.append ("\n };\n struct "); + m_wrapper_function_text.append (m_wrapper_struct_name); + m_wrapper_function_text.append ("* __lldb_fn_data = (struct "); + m_wrapper_function_text.append (m_wrapper_struct_name); + m_wrapper_function_text.append (" *) input;\n"); + + m_wrapper_function_text.append (" __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr ("); + m_wrapper_function_text.append (args_list_buffer); + m_wrapper_function_text.append (");\n}\n"); + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + if (log) + log->Printf ("Expression: \n\n%s\n\n", m_wrapper_function_text.c_str()); + + // Okay, now compile this expression + + lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); + if (jit_process_sp) + { + const bool generate_debug_info = true; + m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this, generate_debug_info)); + + num_errors = m_parser->Parse (errors); + } + else + { + errors.Printf("no process - unable to inject function"); + num_errors = 1; + } + + m_compiled = (num_errors == 0); + + if (!m_compiled) + return num_errors; + + return num_errors; +} + +clang::ASTConsumer * +ClangFunctionCaller::ClangFunctionCallerHelper::ASTTransformer (clang::ASTConsumer *passthrough) +{ + m_struct_extractor.reset(new ASTStructExtractor(passthrough, m_owner.GetWrapperStructName(), m_owner)); + + return m_struct_extractor.get(); +} diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 9239389753e..a6e5923bf28 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -25,7 +25,6 @@ #include "lldb/Expression/ASTResultSynthesizer.h" #include "lldb/Expression/ClangExpressionDeclMap.h" #include "lldb/Expression/ClangExpressionParser.h" -#include "lldb/Expression/ClangFunction.h" #include "lldb/Expression/ClangModulesDeclVendor.h" #include "lldb/Expression/ClangPersistentVariables.h" #include "lldb/Expression/ClangUserExpression.h" @@ -54,32 +53,13 @@ using namespace lldb_private; -ClangUserExpression::ClangUserExpression (const char *expr, +ClangUserExpression::ClangUserExpression (ExecutionContextScope &exe_scope, + const char *expr, const char *expr_prefix, lldb::LanguageType language, ResultType desired_type) : - ClangExpression (), - m_stack_frame_bottom (LLDB_INVALID_ADDRESS), - m_stack_frame_top (LLDB_INVALID_ADDRESS), - m_expr_text (expr), - m_expr_prefix (expr_prefix ? expr_prefix : ""), - m_language (language), - m_transformed_text (), - m_desired_type (desired_type), - m_expr_decl_map(), - m_execution_unit_sp(), - m_materializer_ap(), - m_result_synthesizer(), - m_jit_module_wp(), - m_enforce_valid_object (true), - m_in_cplusplus_method (false), - m_in_objectivec_method (false), - m_in_static_method(false), - m_needs_object_ptr (false), - m_const_object (false), - m_target (NULL), - m_can_interpret (false), - m_materialized_address (LLDB_INVALID_ADDRESS) + UserExpression (exe_scope, expr, expr_prefix, language, desired_type), + m_type_system_helper(*m_target_wp.lock().get()) { switch (m_language) { @@ -99,21 +79,6 @@ ClangUserExpression::ClangUserExpression (const char *expr, ClangUserExpression::~ClangUserExpression () { - if (m_target) - { - lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); - if (jit_module_sp) - m_target->GetImages().Remove(jit_module_sp); - } -} - -clang::ASTConsumer * -ClangUserExpression::ASTTransformer (clang::ASTConsumer *passthrough) -{ - m_result_synthesizer.reset(new ASTResultSynthesizer(passthrough, - *m_target)); - - return m_result_synthesizer.get(); } void @@ -338,54 +303,6 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err) } } -void -ClangUserExpression::InstallContext (ExecutionContext &exe_ctx) -{ - m_process_wp = exe_ctx.GetProcessSP(); - - lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP(); - - if (frame_sp) - m_address = frame_sp->GetFrameCodeAddress(); -} - -bool -ClangUserExpression::LockAndCheckContext (ExecutionContext &exe_ctx, - lldb::TargetSP &target_sp, - lldb::ProcessSP &process_sp, - lldb::StackFrameSP &frame_sp) -{ - lldb::ProcessSP expected_process_sp = m_process_wp.lock(); - process_sp = exe_ctx.GetProcessSP(); - - if (process_sp != expected_process_sp) - return false; - - process_sp = exe_ctx.GetProcessSP(); - target_sp = exe_ctx.GetTargetSP(); - frame_sp = exe_ctx.GetFrameSP(); - - if (m_address.IsValid()) - { - if (!frame_sp) - return false; - else - return (0 == Address::CompareLoadAddress(m_address, frame_sp->GetFrameCodeAddress(), target_sp.get())); - } - - return true; -} - -bool -ClangUserExpression::MatchesContext (ExecutionContext &exe_ctx) -{ - lldb::TargetSP target_sp; - lldb::ProcessSP process_sp; - lldb::StackFrameSP frame_sp; - - return LockAndCheckContext(exe_ctx, target_sp, process_sp, frame_sp); -} - // This is a really nasty hack, meant to fix Objective-C expressions of the form // (int)[myArray count]. Right now, because the type information for count is // not available, [myArray count] returns id, which can't be directly cast to @@ -405,26 +322,6 @@ ApplyObjcCastHack(std::string &expr) #undef OBJC_CAST_HACK_FROM } -// Another hack, meant to allow use of unichar despite it not being available in -// the type information. Although we could special-case it in type lookup, -// hopefully we'll figure out a way to #include the same environment as is -// present in the original source file rather than try to hack specific type -// definitions in as needed. -//static void -//ApplyUnicharHack(std::string &expr) -//{ -//#define UNICHAR_HACK_FROM "unichar" -//#define UNICHAR_HACK_TO "unsigned short" -// -// size_t from_offset; -// -// while ((from_offset = expr.find(UNICHAR_HACK_FROM)) != expr.npos) -// expr.replace(from_offset, sizeof(UNICHAR_HACK_FROM) - 1, UNICHAR_HACK_TO); -// -//#undef UNICHAR_HACK_TO -//#undef UNICHAR_HACK_FROM -//} - bool ClangUserExpression::Parse (Stream &error_stream, ExecutionContext &exe_ctx, @@ -525,7 +422,7 @@ ClangUserExpression::Parse (Stream &error_stream, m_materializer_ap.reset(new Materializer()); - m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx)); + ResetDeclMap(exe_ctx, keep_result_in_memory); class OnExit { @@ -545,13 +442,13 @@ ClangUserExpression::Parse (Stream &error_stream, Callback m_callback; }; - OnExit on_exit([this]() { m_expr_decl_map.reset(); }); + OnExit on_exit([this]() { ResetDeclMap(); }); - if (!m_expr_decl_map->WillParse(exe_ctx, m_materializer_ap.get())) + if (!DeclMap()->WillParse(exe_ctx, m_materializer_ap.get())) { error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n"); - m_expr_decl_map.reset(); // We are being careful here in the case of breakpoint conditions. + ResetDeclMap(); // We are being careful here in the case of breakpoint conditions. return false; } @@ -570,7 +467,7 @@ ClangUserExpression::Parse (Stream &error_stream, { error_stream.Printf ("error: %d errors parsing expression\n", num_errors); - m_expr_decl_map.reset(); // We are being careful here in the case of breakpoint conditions. + ResetDeclMap(); // We are being careful here in the case of breakpoint conditions. return false; } @@ -617,7 +514,7 @@ ClangUserExpression::Parse (Stream &error_stream, // } } - m_expr_decl_map.reset(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any ClangASTImporter::Minions. + ResetDeclMap(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any ClangASTImporter::Minions. if (jit_error.Success()) { @@ -636,537 +533,81 @@ ClangUserExpression::Parse (Stream &error_stream, } } -static lldb::addr_t -GetObjectPointer (lldb::StackFrameSP frame_sp, - ConstString &object_name, - Error &err) -{ - err.Clear(); - - if (!frame_sp) - { - err.SetErrorStringWithFormat("Couldn't load '%s' because the context is incomplete", object_name.AsCString()); - return LLDB_INVALID_ADDRESS; - } - - lldb::VariableSP var_sp; - lldb::ValueObjectSP valobj_sp; - - valobj_sp = frame_sp->GetValueForVariableExpressionPath(object_name.AsCString(), - lldb::eNoDynamicValues, - StackFrame::eExpressionPathOptionCheckPtrVsMember | - StackFrame::eExpressionPathOptionsNoFragileObjcIvar | - StackFrame::eExpressionPathOptionsNoSyntheticChildren | - StackFrame::eExpressionPathOptionsNoSyntheticArrayRange, - var_sp, - err); - - if (!err.Success() || !valobj_sp.get()) - return LLDB_INVALID_ADDRESS; - - lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); - - if (ret == LLDB_INVALID_ADDRESS) - { - err.SetErrorStringWithFormat("Couldn't load '%s' because its value couldn't be evaluated", object_name.AsCString()); - return LLDB_INVALID_ADDRESS; - } - - return ret; -} - bool -ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb::addr_t &struct_address, - lldb::addr_t &object_ptr, - lldb::addr_t &cmd_ptr) +ClangUserExpression::AddInitialArguments (ExecutionContext &exe_ctx, + std::vector<lldb::addr_t> &args, + Stream &error_stream) { - lldb::TargetSP target; - lldb::ProcessSP process; - lldb::StackFrameSP frame; - - if (!LockAndCheckContext(exe_ctx, - target, - process, - frame)) - { - error_stream.Printf("The context has changed before we could JIT the expression!\n"); - return false; - } - - if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) + lldb::addr_t object_ptr = LLDB_INVALID_ADDRESS; + lldb::addr_t cmd_ptr = LLDB_INVALID_ADDRESS; + + if (m_needs_object_ptr) { - if (m_needs_object_ptr) - { - ConstString object_name; - - if (m_in_cplusplus_method) - { - object_name.SetCString("this"); - } - else if (m_in_objectivec_method) - { - object_name.SetCString("self"); - } - else - { - error_stream.Printf("Need object pointer but don't know the language\n"); - return false; - } - - Error object_ptr_error; - - object_ptr = GetObjectPointer(frame, object_name, object_ptr_error); - - if (!object_ptr_error.Success()) - { - error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); - object_ptr = 0; - } - - if (m_in_objectivec_method) - { - ConstString cmd_name("_cmd"); - - cmd_ptr = GetObjectPointer(frame, cmd_name, object_ptr_error); - - if (!object_ptr_error.Success()) - { - error_stream.Printf("warning: couldn't get cmd pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); - cmd_ptr = 0; - } - } - } + lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP(); + if (!frame_sp) + return true; + + ConstString object_name; - if (m_materialized_address == LLDB_INVALID_ADDRESS) + if (m_in_cplusplus_method) { - Error alloc_error; - - IRMemoryMap::AllocationPolicy policy = m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror; - - m_materialized_address = m_execution_unit_sp->Malloc(m_materializer_ap->GetStructByteSize(), - m_materializer_ap->GetStructAlignment(), - lldb::ePermissionsReadable | lldb::ePermissionsWritable, - policy, - alloc_error); - - if (!alloc_error.Success()) - { - error_stream.Printf("Couldn't allocate space for materialized struct: %s\n", alloc_error.AsCString()); - return false; - } + object_name.SetCString("this"); } - - struct_address = m_materialized_address; - - if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS) + else if (m_in_objectivec_method) { - Error alloc_error; - - const size_t stack_frame_size = 512 * 1024; - - m_stack_frame_bottom = m_execution_unit_sp->Malloc(stack_frame_size, - 8, - lldb::ePermissionsReadable | lldb::ePermissionsWritable, - IRMemoryMap::eAllocationPolicyHostOnly, - alloc_error); - - m_stack_frame_top = m_stack_frame_bottom + stack_frame_size; - - if (!alloc_error.Success()) - { - error_stream.Printf("Couldn't allocate space for the stack frame: %s\n", alloc_error.AsCString()); - return false; - } + object_name.SetCString("self"); } - - Error materialize_error; - - m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_sp, struct_address, materialize_error); - - if (!materialize_error.Success()) + else { - error_stream.Printf("Couldn't materialize: %s\n", materialize_error.AsCString()); + error_stream.Printf("Need object pointer but don't know the language\n"); return false; } - } - return true; -} - -bool -ClangUserExpression::FinalizeJITExecution (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb::ExpressionVariableSP &result, - lldb::addr_t function_stack_bottom, - lldb::addr_t function_stack_top) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (log) - log->Printf("-- [ClangUserExpression::FinalizeJITExecution] Dematerializing after execution --"); - if (!m_dematerializer_sp) - { - error_stream.Printf ("Couldn't apply expression side effects : no dematerializer is present"); - return false; - } - - Error dematerialize_error; - - m_dematerializer_sp->Dematerialize(dematerialize_error, result, function_stack_bottom, function_stack_top); - - if (!dematerialize_error.Success()) - { - error_stream.Printf ("Couldn't apply expression side effects : %s\n", dematerialize_error.AsCString("unknown error")); - return false; - } - - if (result) - result->TransferAddress(); - - m_dematerializer_sp.reset(); - - return true; -} - -lldb::ExpressionResults -ClangUserExpression::Execute (Stream &error_stream, - ExecutionContext &exe_ctx, - const EvaluateExpressionOptions& options, - lldb::ClangUserExpressionSP &shared_ptr_to_me, - lldb::ExpressionVariableSP &result) -{ - // The expression log is quite verbose, and if you're just tracking the execution of the - // expression, it's quite convenient to have these logs come out with the STEP log as well. - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); - - if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) - { - lldb::addr_t struct_address = LLDB_INVALID_ADDRESS; + Error object_ptr_error; - lldb::addr_t object_ptr = 0; - lldb::addr_t cmd_ptr = 0; + object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error); - if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_ptr)) + if (!object_ptr_error.Success()) { - error_stream.Printf("Errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__); - return lldb::eExpressionSetupError; + error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); + object_ptr = 0; } - lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS; - lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS; - - if (m_can_interpret) + if (m_in_objectivec_method) { - llvm::Module *module = m_execution_unit_sp->GetModule(); - llvm::Function *function = m_execution_unit_sp->GetFunction(); - - if (!module || !function) - { - error_stream.Printf("Supposed to interpret, but nothing is there"); - return lldb::eExpressionSetupError; - } - - Error interpreter_error; - - llvm::SmallVector <lldb::addr_t, 3> args; - - if (m_needs_object_ptr) - { - args.push_back(object_ptr); + ConstString cmd_name("_cmd"); - if (m_in_objectivec_method) - args.push_back(cmd_ptr); - } - - args.push_back(struct_address); - - function_stack_bottom = m_stack_frame_bottom; - function_stack_top = m_stack_frame_top; - - IRInterpreter::Interpret (*module, - *function, - args, - *m_execution_unit_sp.get(), - interpreter_error, - function_stack_bottom, - function_stack_top, - exe_ctx); + cmd_ptr = GetObjectPointer(frame_sp, cmd_name, object_ptr_error); - if (!interpreter_error.Success()) + if (!object_ptr_error.Success()) { - error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString()); - return lldb::eExpressionDiscarded; + error_stream.Printf("warning: couldn't get cmd pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); + cmd_ptr = 0; } } - else - { - if (!exe_ctx.HasThreadScope()) - { - error_stream.Printf("ClangUserExpression::Execute called with no thread selected."); - return lldb::eExpressionSetupError; - } - - Address wrapper_address (m_jit_start_addr); - - llvm::SmallVector <lldb::addr_t, 3> args; - - if (m_needs_object_ptr) { - args.push_back(object_ptr); - if (m_in_objectivec_method) - args.push_back(cmd_ptr); - } - - args.push_back(struct_address); - - lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), - wrapper_address, - args, - options, - shared_ptr_to_me)); - - if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream)) - return lldb::eExpressionSetupError; - - ThreadPlanCallUserExpression *user_expression_plan = static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get()); - - lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer(); - - function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); - function_stack_top = function_stack_pointer; - - if (log) - log->Printf("-- [ClangUserExpression::Execute] Execution of expression begins --"); - - if (exe_ctx.GetProcessPtr()) - exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); - - lldb::ExpressionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, - call_plan_sp, - options, - error_stream); - - if (exe_ctx.GetProcessPtr()) - exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); - - if (log) - log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --"); + if (object_ptr) + args.push_back(object_ptr); - if (execution_result == lldb::eExpressionInterrupted || execution_result == lldb::eExpressionHitBreakpoint) - { - const char *error_desc = NULL; - - if (call_plan_sp) - { - lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo(); - if (real_stop_info_sp) - error_desc = real_stop_info_sp->GetDescription(); - } - if (error_desc) - error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc); - else - error_stream.PutCString ("Execution was interrupted."); - - if ((execution_result == lldb::eExpressionInterrupted && options.DoesUnwindOnError()) - || (execution_result == lldb::eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints())) - error_stream.PutCString ("\nThe process has been returned to the state before expression evaluation."); - else - { - if (execution_result == lldb::eExpressionHitBreakpoint) - user_expression_plan->TransferExpressionOwnership(); - error_stream.PutCString ("\nThe process has been left at the point where it was interrupted, " - "use \"thread return -x\" to return to the state before expression evaluation."); - } + if (m_in_objectivec_method) + args.push_back(cmd_ptr); - return execution_result; - } - else if (execution_result == lldb::eExpressionStoppedForDebug) - { - error_stream.PutCString ("Execution was halted at the first instruction of the expression " - "function because \"debug\" was requested.\n" - "Use \"thread return -x\" to return to the state before expression evaluation."); - return execution_result; - } - else if (execution_result != lldb::eExpressionCompleted) - { - error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result)); - return execution_result; - } - } - if (FinalizeJITExecution (error_stream, exe_ctx, result, function_stack_bottom, function_stack_top)) - { - return lldb::eExpressionCompleted; - } - else - { - return lldb::eExpressionResultUnavailable; - } - } - else - { - error_stream.Printf("Expression can't be run, because there is no JIT compiled function"); - return lldb::eExpressionSetupError; } + return true; } -lldb::ExpressionResults -ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, - const EvaluateExpressionOptions& options, - const char *expr_cstr, - const char *expr_prefix, - lldb::ValueObjectSP &result_valobj_sp, - Error &error) +void +ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); - - lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); - const lldb::LanguageType language = options.GetLanguage(); - const ResultType desired_type = options.DoesCoerceToId() ? ClangUserExpression::eResultTypeId : ClangUserExpression::eResultTypeAny; - lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; - - Process *process = exe_ctx.GetProcessPtr(); - - if (process == NULL || process->GetState() != lldb::eStateStopped) - { - if (execution_policy == eExecutionPolicyAlways) - { - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant =="); - - error.SetErrorString ("expression needed to run but couldn't"); - - return execution_results; - } - } - - if (process == NULL || !process->CanJIT()) - execution_policy = eExecutionPolicyNever; - - const char *full_prefix = NULL; - const char *option_prefix = options.GetPrefix(); - std::string full_prefix_storage; - if (expr_prefix && option_prefix) - { - full_prefix_storage.assign(expr_prefix); - full_prefix_storage.append(option_prefix); - if (!full_prefix_storage.empty()) - full_prefix = full_prefix_storage.c_str(); - } - else if (expr_prefix) - full_prefix = expr_prefix; - else - full_prefix = option_prefix; - - lldb::ClangUserExpressionSP user_expression_sp (new ClangUserExpression (expr_cstr, full_prefix, language, desired_type)); - - StreamString error_stream; - - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Parsing expression %s ==", expr_cstr); - - const bool keep_expression_in_memory = true; - const bool generate_debug_info = options.GetGenerateDebugInfo(); - - if (options.InvokeCancelCallback (lldb::eExpressionEvaluationParse)) - { - error.SetErrorString ("expression interrupted by callback before parse"); - result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); - return lldb::eExpressionInterrupted; - } - - if (!user_expression_sp->Parse (error_stream, - exe_ctx, - execution_policy, - keep_expression_in_memory, - generate_debug_info)) - { - execution_results = lldb::eExpressionParseError; - if (error_stream.GetString().empty()) - error.SetExpressionError (execution_results, "expression failed to parse, unknown error"); - else - error.SetExpressionError (execution_results, error_stream.GetString().c_str()); - } - else - { - lldb::ExpressionVariableSP expr_result; - - if (execution_policy == eExecutionPolicyNever && - !user_expression_sp->CanInterpret()) - { - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant =="); - - if (error_stream.GetString().empty()) - error.SetExpressionError (lldb::eExpressionSetupError, "expression needed to run but couldn't"); - } - else - { - if (options.InvokeCancelCallback (lldb::eExpressionEvaluationExecution)) - { - error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback before execution"); - result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); - return lldb::eExpressionInterrupted; - } - - error_stream.GetString().clear(); - - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Executing expression =="); - - execution_results = user_expression_sp->Execute (error_stream, - exe_ctx, - options, - user_expression_sp, - expr_result); - - if (options.GetResultIsInternal() && expr_result && process) - { - process->GetTarget().GetPersistentVariables().RemovePersistentVariable (expr_result); - } - - if (execution_results != lldb::eExpressionCompleted) - { - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Execution completed abnormally =="); - - if (error_stream.GetString().empty()) - error.SetExpressionError (execution_results, "expression failed to execute, unknown error"); - else - error.SetExpressionError (execution_results, error_stream.GetString().c_str()); - } - else - { - if (expr_result) - { - result_valobj_sp = expr_result->GetValueObject(); - - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with result %s ==", - result_valobj_sp->GetValueAsCString()); - } - else - { - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with no result =="); - - error.SetError(ClangUserExpression::kNoResult, lldb::eErrorTypeGeneric); - } - } - } - } - - if (options.InvokeCancelCallback(lldb::eExpressionEvaluationComplete)) - { - error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback after complete"); - return lldb::eExpressionInterrupted; - } + m_expr_decl_map_up.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx)); +} - if (result_valobj_sp.get() == NULL) - { - result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); - } +clang::ASTConsumer * +ClangUserExpression::ClangUserExpressionHelper::ASTTransformer (clang::ASTConsumer *passthrough) +{ + m_result_synthesizer_up.reset(new ASTResultSynthesizer(passthrough, + m_target)); - return execution_results; + return m_result_synthesizer_up.get(); } + diff --git a/lldb/source/Expression/ClangUtilityFunction.cpp b/lldb/source/Expression/ClangUtilityFunction.cpp index de5b0c1b03f..2a07a428803 100644 --- a/lldb/source/Expression/ClangUtilityFunction.cpp +++ b/lldb/source/Expression/ClangUtilityFunction.cpp @@ -40,29 +40,15 @@ using namespace lldb_private; /// @param[in] name /// The name of the function, as used in the text. //------------------------------------------------------------------ -ClangUtilityFunction::ClangUtilityFunction (const char *text, +ClangUtilityFunction::ClangUtilityFunction (ExecutionContextScope &exe_scope, + const char *text, const char *name) : - ClangExpression (), - m_expr_decl_map (), - m_execution_unit_sp (), - m_jit_module_wp (), - m_function_text (ExpressionSourceCode::g_expression_prefix), - m_function_name (name) + UtilityFunction (exe_scope, text, name) { - if (text && text[0]) - m_function_text.append (text); } ClangUtilityFunction::~ClangUtilityFunction () { - lldb::ProcessSP process_sp (m_jit_process_wp.lock()); - if (process_sp) - { - lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); - if (jit_module_sp) - process_sp->GetTarget().GetImages().Remove(jit_module_sp); - } - } //------------------------------------------------------------------ @@ -113,9 +99,9 @@ ClangUtilityFunction::Install (Stream &error_stream, bool keep_result_in_memory = false; - m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx)); + ResetDeclMap(exe_ctx, keep_result_in_memory); - if (!m_expr_decl_map->WillParse(exe_ctx, NULL)) + if (!DeclMap()->WillParse(exe_ctx, NULL)) { error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n"); return false; @@ -130,7 +116,7 @@ ClangUtilityFunction::Install (Stream &error_stream, { error_stream.Printf ("error: %d errors parsing expression\n", num_errors); - m_expr_decl_map.reset(); + ResetDeclMap(); return false; } @@ -176,9 +162,9 @@ ClangUtilityFunction::Install (Stream &error_stream, m_function_text.c_str()); #endif - m_expr_decl_map->DidParse(); + DeclMap()->DidParse(); - m_expr_decl_map.reset(); + ResetDeclMap(); if (jit_error.Success()) { @@ -195,4 +181,8 @@ ClangUtilityFunction::Install (Stream &error_stream, } } - +void +ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory) +{ + m_expr_decl_map_up.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx)); +} diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp new file mode 100644 index 00000000000..e5dd9c03db7 --- /dev/null +++ b/lldb/source/Expression/Expression.cpp @@ -0,0 +1,32 @@ +//===-- Expression.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Expression/Expression.h" +#include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/Target.h" + +using namespace lldb_private; + +Expression::Expression (Target &target) : + m_target_wp (target.shared_from_this()), + m_jit_start_addr (LLDB_INVALID_ADDRESS), + m_jit_end_addr (LLDB_INVALID_ADDRESS) +{ + // Can't make any kind of expression without a target. + assert (m_target_wp.lock()); +} + +Expression::Expression (ExecutionContextScope &exe_scope) : + m_target_wp (exe_scope.CalculateTarget()), + m_jit_start_addr (LLDB_INVALID_ADDRESS), + m_jit_end_addr (LLDB_INVALID_ADDRESS) +{ + assert (m_target_wp.lock()); +} + diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/FunctionCaller.cpp index 3798c212059..acfc71c146e 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/FunctionCaller.cpp @@ -1,4 +1,4 @@ -//===-- ClangFunction.cpp ---------------------------------------*- C++ -*-===// +//===-- FunctionCaller.cpp ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -30,7 +30,7 @@ #include "lldb/Core/ValueObjectList.h" #include "lldb/Expression/ASTStructExtractor.h" #include "lldb/Expression/ClangExpressionParser.h" -#include "lldb/Expression/ClangFunction.h" +#include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Symbol/ClangASTContext.h" @@ -47,9 +47,9 @@ using namespace lldb_private; //---------------------------------------------------------------------- -// ClangFunction constructor +// FunctionCaller constructor //---------------------------------------------------------------------- -ClangFunction::ClangFunction +FunctionCaller::FunctionCaller ( ExecutionContextScope &exe_scope, const CompilerType &return_type, @@ -57,6 +57,7 @@ ClangFunction::ClangFunction const ValueList &arg_value_list, const char *name ) : + Expression (exe_scope), m_execution_unit_sp(), m_parser(), m_jit_module_wp(), @@ -72,41 +73,14 @@ ClangFunction::ClangFunction m_JITted (false) { m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess()); - // Can't make a ClangFunction without a process. + // Can't make a FunctionCaller without a process. assert (m_jit_process_wp.lock()); } -ClangFunction::ClangFunction -( - ExecutionContextScope &exe_scope, - Function &function, - ClangASTContext *ast_context, - const ValueList &arg_value_list, - const char *name -) : - m_name (name ? name : "<unknown>"), - m_function_ptr (&function), - m_function_addr (), - m_function_return_type (), - m_wrapper_function_name ("__lldb_function_caller"), - m_wrapper_struct_name ("__lldb_caller_struct"), - m_wrapper_args_addrs (), - m_arg_values (arg_value_list), - m_compiled (false), - m_JITted (false) -{ - m_jit_process_wp = exe_scope.CalculateProcess(); - // Can't make a ClangFunction without a process. - assert (m_jit_process_wp.lock()); - - m_function_addr = m_function_ptr->GetAddressRange().GetBaseAddress(); - m_function_return_type = m_function_ptr->GetCompilerType().GetFunctionReturnType(); -} - //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -ClangFunction::~ClangFunction() +FunctionCaller::~FunctionCaller() { lldb::ProcessSP process_sp (m_jit_process_wp.lock()); if (process_sp) @@ -117,147 +91,8 @@ ClangFunction::~ClangFunction() } } -unsigned -ClangFunction::CompileFunction (Stream &errors) -{ - if (m_compiled) - return 0; - - // FIXME: How does clang tell us there's no return value? We need to handle that case. - unsigned num_errors = 0; - - std::string return_type_str (m_function_return_type.GetTypeName().AsCString("")); - - // Cons up the function we're going to wrap our call in, then compile it... - // We declare the function "extern "C"" because the compiler might be in C++ - // mode which would mangle the name and then we couldn't find it again... - m_wrapper_function_text.clear(); - m_wrapper_function_text.append ("extern \"C\" void "); - m_wrapper_function_text.append (m_wrapper_function_name); - m_wrapper_function_text.append (" (void *input)\n{\n struct "); - m_wrapper_function_text.append (m_wrapper_struct_name); - m_wrapper_function_text.append (" \n {\n"); - m_wrapper_function_text.append (" "); - m_wrapper_function_text.append (return_type_str); - m_wrapper_function_text.append (" (*fn_ptr) ("); - - // Get the number of arguments. If we have a function type and it is prototyped, - // trust that, otherwise use the values we were given. - - // FIXME: This will need to be extended to handle Variadic functions. We'll need - // to pull the defined arguments out of the function, then add the types from the - // arguments list for the variable arguments. - - uint32_t num_args = UINT32_MAX; - bool trust_function = false; - // GetArgumentCount returns -1 for an unprototyped function. - CompilerType function_clang_type; - if (m_function_ptr) - { - function_clang_type = m_function_ptr->GetCompilerType(); - if (function_clang_type) - { - int num_func_args = function_clang_type.GetFunctionArgumentCount(); - if (num_func_args >= 0) - { - trust_function = true; - num_args = num_func_args; - } - } - } - - if (num_args == UINT32_MAX) - num_args = m_arg_values.GetSize(); - - std::string args_buffer; // This one stores the definition of all the args in "struct caller". - std::string args_list_buffer; // This one stores the argument list called from the structure. - for (size_t i = 0; i < num_args; i++) - { - std::string type_name; - - if (trust_function) - { - type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i).GetTypeName().AsCString(""); - } - else - { - CompilerType clang_qual_type = m_arg_values.GetValueAtIndex(i)->GetCompilerType (); - if (clang_qual_type) - { - type_name = clang_qual_type.GetTypeName().AsCString(""); - } - else - { - errors.Printf("Could not determine type of input value %" PRIu64 ".", (uint64_t)i); - return 1; - } - } - - m_wrapper_function_text.append (type_name); - if (i < num_args - 1) - m_wrapper_function_text.append (", "); - - char arg_buf[32]; - args_buffer.append (" "); - args_buffer.append (type_name); - snprintf(arg_buf, 31, "arg_%" PRIu64, (uint64_t)i); - args_buffer.push_back (' '); - args_buffer.append (arg_buf); - args_buffer.append (";\n"); - - args_list_buffer.append ("__lldb_fn_data->"); - args_list_buffer.append (arg_buf); - if (i < num_args - 1) - args_list_buffer.append (", "); - - } - m_wrapper_function_text.append (");\n"); // Close off the function calling prototype. - - m_wrapper_function_text.append (args_buffer); - - m_wrapper_function_text.append (" "); - m_wrapper_function_text.append (return_type_str); - m_wrapper_function_text.append (" return_value;"); - m_wrapper_function_text.append ("\n };\n struct "); - m_wrapper_function_text.append (m_wrapper_struct_name); - m_wrapper_function_text.append ("* __lldb_fn_data = (struct "); - m_wrapper_function_text.append (m_wrapper_struct_name); - m_wrapper_function_text.append (" *) input;\n"); - - m_wrapper_function_text.append (" __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr ("); - m_wrapper_function_text.append (args_list_buffer); - m_wrapper_function_text.append (");\n}\n"); - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - if (log) - log->Printf ("Expression: \n\n%s\n\n", m_wrapper_function_text.c_str()); - - // Okay, now compile this expression - - lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); - if (jit_process_sp) - { - const bool generate_debug_info = true; - m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this, generate_debug_info)); - - num_errors = m_parser->Parse (errors); - } - else - { - errors.Printf("no process - unable to inject function"); - num_errors = 1; - } - - m_compiled = (num_errors == 0); - - if (!m_compiled) - return num_errors; - - return num_errors; -} - bool -ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) +FunctionCaller::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) { Process *process = exe_ctx.GetProcessPtr(); @@ -310,18 +145,17 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) } bool -ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors) +FunctionCaller::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors) { - return WriteFunctionArguments(exe_ctx, args_addr_ref, m_function_addr, m_arg_values, errors); + return WriteFunctionArguments(exe_ctx, args_addr_ref, m_arg_values, errors); } // FIXME: Assure that the ValueList we were passed in is consistent with the one that defined this function. bool -ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, +FunctionCaller::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, - Address function_address, - ValueList &arg_values, + ValueList &arg_values, Stream &errors) { // All the information to reconstruct the struct is provided by the @@ -363,7 +197,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, } // TODO: verify fun_addr needs to be a callable address - Scalar fun_addr (function_address.GetCallableLoadAddress(exe_ctx.GetTargetPtr())); + Scalar fun_addr (m_function_addr.GetCallableLoadAddress(exe_ctx.GetTargetPtr())); uint64_t first_offset = m_member_offsets[0]; process->WriteScalarToMemory(args_addr_ref + first_offset, fun_addr, process->GetAddressByteSize(), error); @@ -404,7 +238,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, } bool -ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors) +FunctionCaller::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors) { using namespace clang; @@ -423,7 +257,7 @@ ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_add } lldb::ThreadPlanSP -ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, +FunctionCaller::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, lldb::addr_t args_addr, const EvaluateExpressionOptions &options, Stream &errors) @@ -431,7 +265,7 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); if (log) - log->Printf("-- [ClangFunction::GetThreadPlanToCallFunction] Creating thread plan to call function \"%s\" --", m_name.c_str()); + log->Printf("-- [FunctionCaller::GetThreadPlanToCallFunction] Creating thread plan to call function \"%s\" --", m_name.c_str()); // FIXME: Use the errors Stream for better error reporting. Thread *thread = exe_ctx.GetThreadPtr(); @@ -458,7 +292,7 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, } bool -ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr, Value &ret_value) +FunctionCaller::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr, Value &ret_value) { // Read the return value - it is the last field in the struct: // FIXME: How does clang tell us there's no return value? We need to handle that case. @@ -468,7 +302,7 @@ ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t arg Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); if (log) - log->Printf("-- [ClangFunction::FetchFunctionResults] Fetching function results for \"%s\"--", m_name.c_str()); + log->Printf("-- [FunctionCaller::FetchFunctionResults] Fetching function results for \"%s\"--", m_name.c_str()); Process *process = exe_ctx.GetProcessPtr(); @@ -492,7 +326,7 @@ ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t arg } void -ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr) +FunctionCaller::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr) { std::list<lldb::addr_t>::iterator pos; pos = std::find(m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), args_addr); @@ -503,7 +337,7 @@ ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_ } lldb::ExpressionResults -ClangFunction::ExecuteFunction( +FunctionCaller::ExecuteFunction( ExecutionContext &exe_ctx, lldb::addr_t *args_addr_ptr, const EvaluateExpressionOptions &options, @@ -513,7 +347,7 @@ ClangFunction::ExecuteFunction( using namespace clang; lldb::ExpressionResults return_value = lldb::eExpressionSetupError; - // ClangFunction::ExecuteFunction execution is always just to get the result. Do make sure we ignore + // FunctionCaller::ExecuteFunction execution is always just to get the result. Do make sure we ignore // breakpoints, unwind on error, and don't try to debug it. EvaluateExpressionOptions real_options = options; real_options.SetDebug(false); @@ -539,7 +373,7 @@ ClangFunction::ExecuteFunction( Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); if (log) - log->Printf("== [ClangFunction::ExecuteFunction] Executing function \"%s\" ==", m_name.c_str()); + log->Printf("== [FunctionCaller::ExecuteFunction] Executing function \"%s\" ==", m_name.c_str()); lldb::ThreadPlanSP call_plan_sp = GetThreadPlanToCallFunction (exe_ctx, args_addr, @@ -562,11 +396,11 @@ ClangFunction::ExecuteFunction( { if (return_value != lldb::eExpressionCompleted) { - log->Printf("== [ClangFunction::ExecuteFunction] Execution of \"%s\" completed abnormally ==", m_name.c_str()); + log->Printf("== [FunctionCaller::ExecuteFunction] Execution of \"%s\" completed abnormally ==", m_name.c_str()); } else { - log->Printf("== [ClangFunction::ExecuteFunction] Execution of \"%s\" completed normally ==", m_name.c_str()); + log->Printf("== [FunctionCaller::ExecuteFunction] Execution of \"%s\" completed normally ==", m_name.c_str()); } } @@ -586,11 +420,3 @@ ClangFunction::ExecuteFunction( return lldb::eExpressionCompleted; } - -clang::ASTConsumer * -ClangFunction::ASTTransformer (clang::ASTConsumer *passthrough) -{ - m_struct_extractor.reset(new ASTStructExtractor(passthrough, m_wrapper_struct_name.c_str(), *this)); - - return m_struct_extractor.get(); -} diff --git a/lldb/source/Expression/IRDynamicChecks.cpp b/lldb/source/Expression/IRDynamicChecks.cpp index aa5d28bb8aa..5c8d0e5288b 100644 --- a/lldb/source/Expression/IRDynamicChecks.cpp +++ b/lldb/source/Expression/IRDynamicChecks.cpp @@ -11,11 +11,12 @@ #include "lldb/Core/ConstString.h" #include "lldb/Core/Log.h" -#include "lldb/Expression/ClangUtilityFunction.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" #include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/Constants.h" @@ -52,8 +53,14 @@ bool DynamicCheckerFunctions::Install(Stream &error_stream, ExecutionContext &exe_ctx) { - m_valid_pointer_check.reset(new ClangUtilityFunction(g_valid_pointer_check_text, - VALID_POINTER_CHECK_NAME)); + Error error; + m_valid_pointer_check.reset(exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(g_valid_pointer_check_text, + lldb::eLanguageTypeC, + VALID_POINTER_CHECK_NAME, + error)); + if (error.Fail()) + return false; + if (!m_valid_pointer_check->Install(error_stream, exe_ctx)) return false; diff --git a/lldb/source/Expression/UserExpression.cpp b/lldb/source/Expression/UserExpression.cpp new file mode 100644 index 00000000000..547c02a1317 --- /dev/null +++ b/lldb/source/Expression/UserExpression.cpp @@ -0,0 +1,644 @@ +//===-- UserExpression.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include <cstdlib> +#include <string> +#include <map> + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Expression/ASTResultSynthesizer.h" +#include "lldb/Expression/ClangExpressionDeclMap.h" +#include "lldb/Expression/ClangExpressionParser.h" +#include "lldb/Expression/ClangModulesDeclVendor.h" +#include "lldb/Expression/ClangPersistentVariables.h" +#include "lldb/Expression/ExpressionSourceCode.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Expression/IRInterpreter.h" +#include "lldb/Expression/Materializer.h" +#include "lldb/Expression/UserExpression.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallUserExpression.h" + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" + +using namespace lldb_private; + +UserExpression::UserExpression (ExecutionContextScope &exe_scope, + const char *expr, + const char *expr_prefix, + lldb::LanguageType language, + ResultType desired_type) : + Expression (exe_scope), + m_stack_frame_bottom (LLDB_INVALID_ADDRESS), + m_stack_frame_top (LLDB_INVALID_ADDRESS), + m_expr_text (expr), + m_expr_prefix (expr_prefix ? expr_prefix : ""), + m_language (language), + m_transformed_text (), + m_desired_type (desired_type), + m_execution_unit_sp(), + m_materializer_ap(), + m_jit_module_wp(), + m_enforce_valid_object (true), + m_in_cplusplus_method (false), + m_in_objectivec_method (false), + m_in_static_method(false), + m_needs_object_ptr (false), + m_const_object (false), + m_target (NULL), + m_can_interpret (false), + m_materialized_address (LLDB_INVALID_ADDRESS) +{ +} + +UserExpression::~UserExpression () +{ + if (m_target) + { + lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); + if (jit_module_sp) + m_target->GetImages().Remove(jit_module_sp); + } +} + +void +UserExpression::InstallContext (ExecutionContext &exe_ctx) +{ + m_jit_process_wp = exe_ctx.GetProcessSP(); + + lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP(); + + if (frame_sp) + m_address = frame_sp->GetFrameCodeAddress(); +} + +bool +UserExpression::LockAndCheckContext (ExecutionContext &exe_ctx, + lldb::TargetSP &target_sp, + lldb::ProcessSP &process_sp, + lldb::StackFrameSP &frame_sp) +{ + lldb::ProcessSP expected_process_sp = m_jit_process_wp.lock(); + process_sp = exe_ctx.GetProcessSP(); + + if (process_sp != expected_process_sp) + return false; + + process_sp = exe_ctx.GetProcessSP(); + target_sp = exe_ctx.GetTargetSP(); + frame_sp = exe_ctx.GetFrameSP(); + + if (m_address.IsValid()) + { + if (!frame_sp) + return false; + else + return (0 == Address::CompareLoadAddress(m_address, frame_sp->GetFrameCodeAddress(), target_sp.get())); + } + + return true; +} + +bool +UserExpression::MatchesContext (ExecutionContext &exe_ctx) +{ + lldb::TargetSP target_sp; + lldb::ProcessSP process_sp; + lldb::StackFrameSP frame_sp; + + return LockAndCheckContext(exe_ctx, target_sp, process_sp, frame_sp); +} + +lldb::addr_t +UserExpression::GetObjectPointer (lldb::StackFrameSP frame_sp, + ConstString &object_name, + Error &err) +{ + err.Clear(); + + if (!frame_sp) + { + err.SetErrorStringWithFormat("Couldn't load '%s' because the context is incomplete", object_name.AsCString()); + return LLDB_INVALID_ADDRESS; + } + + lldb::VariableSP var_sp; + lldb::ValueObjectSP valobj_sp; + + valobj_sp = frame_sp->GetValueForVariableExpressionPath(object_name.AsCString(), + lldb::eNoDynamicValues, + StackFrame::eExpressionPathOptionCheckPtrVsMember | + StackFrame::eExpressionPathOptionsNoFragileObjcIvar | + StackFrame::eExpressionPathOptionsNoSyntheticChildren | + StackFrame::eExpressionPathOptionsNoSyntheticArrayRange, + var_sp, + err); + + if (!err.Success() || !valobj_sp.get()) + return LLDB_INVALID_ADDRESS; + + lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + + if (ret == LLDB_INVALID_ADDRESS) + { + err.SetErrorStringWithFormat("Couldn't load '%s' because its value couldn't be evaluated", object_name.AsCString()); + return LLDB_INVALID_ADDRESS; + } + + return ret; +} + +bool +UserExpression::PrepareToExecuteJITExpression (Stream &error_stream, + ExecutionContext &exe_ctx, + lldb::addr_t &struct_address) +{ + lldb::TargetSP target; + lldb::ProcessSP process; + lldb::StackFrameSP frame; + + if (!LockAndCheckContext(exe_ctx, + target, + process, + frame)) + { + error_stream.Printf("The context has changed before we could JIT the expression!\n"); + return false; + } + + if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) + { + if (m_materialized_address == LLDB_INVALID_ADDRESS) + { + Error alloc_error; + + IRMemoryMap::AllocationPolicy policy = m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror; + + m_materialized_address = m_execution_unit_sp->Malloc(m_materializer_ap->GetStructByteSize(), + m_materializer_ap->GetStructAlignment(), + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + policy, + alloc_error); + + if (!alloc_error.Success()) + { + error_stream.Printf("Couldn't allocate space for materialized struct: %s\n", alloc_error.AsCString()); + return false; + } + } + + struct_address = m_materialized_address; + + if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS) + { + Error alloc_error; + + const size_t stack_frame_size = 512 * 1024; + + m_stack_frame_bottom = m_execution_unit_sp->Malloc(stack_frame_size, + 8, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + IRMemoryMap::eAllocationPolicyHostOnly, + alloc_error); + + m_stack_frame_top = m_stack_frame_bottom + stack_frame_size; + + if (!alloc_error.Success()) + { + error_stream.Printf("Couldn't allocate space for the stack frame: %s\n", alloc_error.AsCString()); + return false; + } + } + + Error materialize_error; + + m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_sp, struct_address, materialize_error); + + if (!materialize_error.Success()) + { + error_stream.Printf("Couldn't materialize: %s\n", materialize_error.AsCString()); + return false; + } + } + return true; +} + +bool +UserExpression::FinalizeJITExecution (Stream &error_stream, + ExecutionContext &exe_ctx, + lldb::ExpressionVariableSP &result, + lldb::addr_t function_stack_bottom, + lldb::addr_t function_stack_top) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + log->Printf("-- [UserExpression::FinalizeJITExecution] Dematerializing after execution --"); + + if (!m_dematerializer_sp) + { + error_stream.Printf ("Couldn't apply expression side effects : no dematerializer is present"); + return false; + } + + Error dematerialize_error; + + m_dematerializer_sp->Dematerialize(dematerialize_error, result, function_stack_bottom, function_stack_top); + + if (!dematerialize_error.Success()) + { + error_stream.Printf ("Couldn't apply expression side effects : %s\n", dematerialize_error.AsCString("unknown error")); + return false; + } + + if (result) + result->TransferAddress(); + + m_dematerializer_sp.reset(); + + return true; +} + +lldb::ExpressionResults +UserExpression::Execute (Stream &error_stream, + ExecutionContext &exe_ctx, + const EvaluateExpressionOptions& options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result) +{ + // The expression log is quite verbose, and if you're just tracking the execution of the + // expression, it's quite convenient to have these logs come out with the STEP log as well. + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); + + if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) + { + lldb::addr_t struct_address = LLDB_INVALID_ADDRESS; + + if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address)) + { + error_stream.Printf("Errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS; + lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS; + + if (m_can_interpret) + { + llvm::Module *module = m_execution_unit_sp->GetModule(); + llvm::Function *function = m_execution_unit_sp->GetFunction(); + + if (!module || !function) + { + error_stream.Printf("Supposed to interpret, but nothing is there"); + return lldb::eExpressionSetupError; + } + + Error interpreter_error; + + std::vector<lldb::addr_t> args; + + if (!AddInitialArguments(exe_ctx, args, error_stream)) + { + error_stream.Printf ("Errored out in %s, couldn't AddInitialArguments", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + args.push_back(struct_address); + + function_stack_bottom = m_stack_frame_bottom; + function_stack_top = m_stack_frame_top; + + IRInterpreter::Interpret (*module, + *function, + args, + *m_execution_unit_sp.get(), + interpreter_error, + function_stack_bottom, + function_stack_top, + exe_ctx); + + if (!interpreter_error.Success()) + { + error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString()); + return lldb::eExpressionDiscarded; + } + } + else + { + if (!exe_ctx.HasThreadScope()) + { + error_stream.Printf("UserExpression::Execute called with no thread selected."); + return lldb::eExpressionSetupError; + } + + Address wrapper_address (m_jit_start_addr); + + std::vector<lldb::addr_t> args; + + if (!AddInitialArguments(exe_ctx, args, error_stream)) + { + error_stream.Printf ("Errored out in %s, couldn't AddInitialArguments", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + args.push_back(struct_address); + + lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), + wrapper_address, + args, + options, + shared_ptr_to_me)); + + if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream)) + return lldb::eExpressionSetupError; + + ThreadPlanCallUserExpression *user_expression_plan = static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get()); + + lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer(); + + function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); + function_stack_top = function_stack_pointer; + + if (log) + log->Printf("-- [UserExpression::Execute] Execution of expression begins --"); + + if (exe_ctx.GetProcessPtr()) + exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); + + lldb::ExpressionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, + call_plan_sp, + options, + error_stream); + + if (exe_ctx.GetProcessPtr()) + exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); + + if (log) + log->Printf("-- [UserExpression::Execute] Execution of expression completed --"); + + if (execution_result == lldb::eExpressionInterrupted || execution_result == lldb::eExpressionHitBreakpoint) + { + const char *error_desc = NULL; + + if (call_plan_sp) + { + lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo(); + if (real_stop_info_sp) + error_desc = real_stop_info_sp->GetDescription(); + } + if (error_desc) + error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc); + else + error_stream.PutCString ("Execution was interrupted."); + + if ((execution_result == lldb::eExpressionInterrupted && options.DoesUnwindOnError()) + || (execution_result == lldb::eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints())) + error_stream.PutCString ("\nThe process has been returned to the state before expression evaluation."); + else + { + if (execution_result == lldb::eExpressionHitBreakpoint) + user_expression_plan->TransferExpressionOwnership(); + error_stream.PutCString ("\nThe process has been left at the point where it was interrupted, " + "use \"thread return -x\" to return to the state before expression evaluation."); + } + + return execution_result; + } + else if (execution_result == lldb::eExpressionStoppedForDebug) + { + error_stream.PutCString ("Execution was halted at the first instruction of the expression " + "function because \"debug\" was requested.\n" + "Use \"thread return -x\" to return to the state before expression evaluation."); + return execution_result; + } + else if (execution_result != lldb::eExpressionCompleted) + { + error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result)); + return execution_result; + } + } + + if (FinalizeJITExecution (error_stream, exe_ctx, result, function_stack_bottom, function_stack_top)) + { + return lldb::eExpressionCompleted; + } + else + { + return lldb::eExpressionResultUnavailable; + } + } + else + { + error_stream.Printf("Expression can't be run, because there is no JIT compiled function"); + return lldb::eExpressionSetupError; + } +} + +lldb::ExpressionResults +UserExpression::Evaluate (ExecutionContext &exe_ctx, + const EvaluateExpressionOptions& options, + const char *expr_cstr, + const char *expr_prefix, + lldb::ValueObjectSP &result_valobj_sp, + Error &error) +{ + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); + + lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); + const lldb::LanguageType language = options.GetLanguage(); + const ResultType desired_type = options.DoesCoerceToId() ? UserExpression::eResultTypeId : UserExpression::eResultTypeAny; + lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; + + Target *target = exe_ctx.GetTargetPtr(); + if (!target) + { + if (log) + log->Printf("== [UserExpression::Evaluate] Passed a NULL target, can't run expressions."); + return lldb::eExpressionSetupError; + } + + Process *process = exe_ctx.GetProcessPtr(); + + if (process == NULL || process->GetState() != lldb::eStateStopped) + { + if (execution_policy == eExecutionPolicyAlways) + { + if (log) + log->Printf("== [UserExpression::Evaluate] Expression may not run, but is not constant =="); + + error.SetErrorString ("expression needed to run but couldn't"); + + return execution_results; + } + } + + if (process == NULL || !process->CanJIT()) + execution_policy = eExecutionPolicyNever; + + const char *full_prefix = NULL; + const char *option_prefix = options.GetPrefix(); + std::string full_prefix_storage; + if (expr_prefix && option_prefix) + { + full_prefix_storage.assign(expr_prefix); + full_prefix_storage.append(option_prefix); + if (!full_prefix_storage.empty()) + full_prefix = full_prefix_storage.c_str(); + } + else if (expr_prefix) + full_prefix = expr_prefix; + else + full_prefix = option_prefix; + + lldb::UserExpressionSP user_expression_sp(target->GetUserExpressionForLanguage (expr_cstr, + full_prefix, + language, + desired_type, + error)); + if (error.Fail()) + { + if (log) + log->Printf ("== [UserExpression::Evaluate] Getting expression: %s ==", error.AsCString()); + return lldb::eExpressionSetupError; + } + + StreamString error_stream; + + if (log) + log->Printf("== [UserExpression::Evaluate] Parsing expression %s ==", expr_cstr); + + const bool keep_expression_in_memory = true; + const bool generate_debug_info = options.GetGenerateDebugInfo(); + + if (options.InvokeCancelCallback (lldb::eExpressionEvaluationParse)) + { + error.SetErrorString ("expression interrupted by callback before parse"); + result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); + return lldb::eExpressionInterrupted; + } + + if (!user_expression_sp->Parse (error_stream, + exe_ctx, + execution_policy, + keep_expression_in_memory, + generate_debug_info)) + { + execution_results = lldb::eExpressionParseError; + if (error_stream.GetString().empty()) + error.SetExpressionError (execution_results, "expression failed to parse, unknown error"); + else + error.SetExpressionError (execution_results, error_stream.GetString().c_str()); + } + else + { + lldb::ExpressionVariableSP expr_result; + + if (execution_policy == eExecutionPolicyNever && + !user_expression_sp->CanInterpret()) + { + if (log) + log->Printf("== [UserExpression::Evaluate] Expression may not run, but is not constant =="); + + if (error_stream.GetString().empty()) + error.SetExpressionError (lldb::eExpressionSetupError, "expression needed to run but couldn't"); + } + else + { + if (options.InvokeCancelCallback (lldb::eExpressionEvaluationExecution)) + { + error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback before execution"); + result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); + return lldb::eExpressionInterrupted; + } + + error_stream.GetString().clear(); + + if (log) + log->Printf("== [UserExpression::Evaluate] Executing expression =="); + + execution_results = user_expression_sp->Execute (error_stream, + exe_ctx, + options, + user_expression_sp, + expr_result); + + if (options.GetResultIsInternal() && expr_result && process) + { + process->GetTarget().GetPersistentVariables().RemovePersistentVariable (expr_result); + } + + if (execution_results != lldb::eExpressionCompleted) + { + if (log) + log->Printf("== [UserExpression::Evaluate] Execution completed abnormally =="); + + if (error_stream.GetString().empty()) + error.SetExpressionError (execution_results, "expression failed to execute, unknown error"); + else + error.SetExpressionError (execution_results, error_stream.GetString().c_str()); + } + else + { + if (expr_result) + { + result_valobj_sp = expr_result->GetValueObject(); + + if (log) + log->Printf("== [UserExpression::Evaluate] Execution completed normally with result %s ==", + result_valobj_sp->GetValueAsCString()); + } + else + { + if (log) + log->Printf("== [UserExpression::Evaluate] Execution completed normally with no result =="); + + error.SetError(UserExpression::kNoResult, lldb::eErrorTypeGeneric); + } + } + } + } + + if (options.InvokeCancelCallback(lldb::eExpressionEvaluationComplete)) + { + error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback after complete"); + return lldb::eExpressionInterrupted; + } + + if (result_valobj_sp.get() == NULL) + { + result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); + } + + return execution_results; +} diff --git a/lldb/source/Expression/UtilityFunction.cpp b/lldb/source/Expression/UtilityFunction.cpp new file mode 100644 index 00000000000..fad6e2f2568 --- /dev/null +++ b/lldb/source/Expression/UtilityFunction.cpp @@ -0,0 +1,123 @@ +//===-- ClangUserExpression.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include <stdio.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +// C++ Includes + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Expression/UtilityFunction.h" +#include "lldb/Expression/ExpressionSourceCode.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Host/Host.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" + +using namespace lldb_private; +using namespace lldb; + +//------------------------------------------------------------------ +/// Constructor +/// +/// @param[in] text +/// The text of the function. Must be a full translation unit. +/// +/// @param[in] name +/// The name of the function, as used in the text. +//------------------------------------------------------------------ +UtilityFunction::UtilityFunction (ExecutionContextScope &exe_scope, + const char *text, + const char *name) : + Expression (exe_scope), + m_execution_unit_sp (), + m_jit_module_wp (), + m_function_text (ExpressionSourceCode::g_expression_prefix), + m_function_name (name) +{ + if (text && text[0]) + m_function_text.append (text); +} + +UtilityFunction::~UtilityFunction () +{ + lldb::ProcessSP process_sp (m_jit_process_wp.lock()); + if (process_sp) + { + lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); + if (jit_module_sp) + process_sp->GetTarget().GetImages().Remove(jit_module_sp); + } + +} + +// FIXME: We should check that every time this is called it is called with the same return type & arguments... + +FunctionCaller * +UtilityFunction::MakeFunctionCaller (const CompilerType &return_type, const ValueList &arg_value_list, Error &error) +{ + if (m_caller_up) + return m_caller_up.get(); + + ProcessSP process_sp = m_jit_process_wp.lock(); + if (!process_sp) + return nullptr; + + Address impl_code_address; + impl_code_address.SetOffset(StartAddress()); + std::string name(m_function_name); + name.append("-caller"); + + m_caller_up.reset (process_sp->GetTarget().GetFunctionCallerForLanguage (Language(), + return_type, + impl_code_address, + arg_value_list, + name.c_str(), + error)); + if (error.Fail()) + { + + return nullptr; + } + if (m_caller_up) + { + StreamString errors; + errors.Clear(); + unsigned num_errors = m_caller_up->CompileFunction(errors); + if (num_errors) + { + error.SetErrorStringWithFormat ("Error compiling %s caller function: \"%s\".", + m_function_name.c_str(), + errors.GetData()); + m_caller_up.reset(); + return nullptr; + } + + errors.Clear(); + ExecutionContext exe_ctx(process_sp); + + if (!m_caller_up->WriteFunctionWrapper(exe_ctx, errors)) + { + error.SetErrorStringWithFormat ("Error inserting caller function for %s: \"%s\".", + m_function_name.c_str(), + errors.GetData()); + m_caller_up.reset(); + return nullptr; + } + } + return m_caller_up.get(); +} diff --git a/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp b/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp index bc7a93314c4..14123af27ca 100644 --- a/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp +++ b/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp @@ -25,7 +25,7 @@ lldb_private::formatters::CMTimeSummaryProvider (ValueObject& valobj, Stream& st if (!type.IsValid()) return false; - TypeSystem *type_system = valobj.GetExecutionContextRef().GetTargetSP()->GetTypeSystemForLanguage(lldb::eLanguageTypeC); + TypeSystem *type_system = valobj.GetExecutionContextRef().GetTargetSP()->GetScratchTypeSystemForLanguage(lldb::eLanguageTypeC); if (!type_system) return false; diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp index d5466ed4c8d..c6db27e93d4 100644 --- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -15,6 +15,7 @@ #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Expression/FunctionCaller.h" #include "lldb/Host/Endian.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/ObjCLanguageRuntime.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp index 7a519532036..925e49883b5 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp @@ -8,7 +8,9 @@ //===----------------------------------------------------------------------===// #include "AppleObjCClassDescriptorV2.h" + #include "lldb/Core/Log.h" +#include "lldb/Expression/FunctionCaller.h" using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index 81ae61841ae..b4b725ea3cc 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -1,4 +1,4 @@ -//===-- AppleObjCRuntime.cpp --------------------------------------*- C++ -*-===// +//===-- AppleObjCRuntime.cpp -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -22,7 +22,8 @@ #include "lldb/Core/Scalar.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamString.h" -#include "lldb/Expression/ClangFunction.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Expression/FunctionCaller.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ExecutionContext.h" @@ -39,6 +40,10 @@ using namespace lldb_private; #define PO_FUNCTION_TIMEOUT_USEC 15*1000*1000 +AppleObjCRuntime::~AppleObjCRuntime() +{ +} + AppleObjCRuntime::AppleObjCRuntime(Process *process) : ObjCLanguageRuntime (process), m_read_objc_library (false), @@ -135,16 +140,36 @@ AppleObjCRuntime::GetObjectDescription (Stream &strm, Value &value, ExecutionCon } // Now we're ready to call the function: - ClangFunction func (*exe_ctx.GetBestExecutionContextScope(), - return_clang_type, - *function_address, - arg_value_list, - "objc-object-description"); - - StreamString error_stream; + StreamString error_stream; lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS; - func.InsertFunction(exe_ctx, wrapper_struct_addr, error_stream); + + if (!m_print_object_caller_up) + { + Error error; + m_print_object_caller_up.reset(exe_scope->CalculateTarget()->GetFunctionCallerForLanguage (eLanguageTypeObjC, + return_clang_type, + *function_address, + arg_value_list, + "objc-object-description", + error)); + if (error.Fail()) + { + m_print_object_caller_up.reset(); + strm.Printf("Could not get function runner to call print for debugger function: %s.", error.AsCString()); + return false; + } + m_print_object_caller_up->InsertFunction(exe_ctx, wrapper_struct_addr, error_stream); + } + else + { + m_print_object_caller_up->WriteFunctionArguments(exe_ctx, + wrapper_struct_addr, + arg_value_list, + error_stream); + } + + EvaluateExpressionOptions options; options.SetUnwindOnError(true); @@ -153,11 +178,11 @@ AppleObjCRuntime::GetObjectDescription (Stream &strm, Value &value, ExecutionCon options.SetIgnoreBreakpoints(true); options.SetTimeoutUsec(PO_FUNCTION_TIMEOUT_USEC); - ExpressionResults results = func.ExecuteFunction (exe_ctx, - &wrapper_struct_addr, - options, - error_stream, - ret); + ExpressionResults results = m_print_object_caller_up->ExecuteFunction (exe_ctx, + &wrapper_struct_addr, + options, + error_stream, + ret); if (results != eExpressionCompleted) { strm.Printf("Error evaluating Print Object function: %d.\n", results); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h index f8f73bae865..424058ee0b7 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h @@ -20,7 +20,6 @@ #include "lldb/lldb-private.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/ObjCLanguageRuntime.h" -#include "lldb/Core/ValueObject.h" #include "AppleObjCTrampolineHandler.h" #include "AppleThreadPlanStepThroughObjCTrampoline.h" @@ -31,7 +30,7 @@ class AppleObjCRuntime : { public: - virtual ~AppleObjCRuntime() { } + virtual ~AppleObjCRuntime(); // These are generic runtime functions: bool @@ -127,6 +126,7 @@ protected: std::unique_ptr<lldb_private::AppleObjCTrampolineHandler> m_objc_trampoline_handler_ap; lldb::BreakpointSP m_objc_exception_bp_sp; lldb::ModuleWP m_objc_module_wp; + std::unique_ptr<FunctionCaller> m_print_object_caller_up; llvm::Optional<uint32_t> m_Foundation_major; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index 17aa03e4a64..85729e827f5 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -21,8 +21,8 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Scalar.h" #include "lldb/Core/StreamString.h" -#include "lldb/Expression/ClangFunction.h" -#include "lldb/Expression/ClangUtilityFunction.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" @@ -143,7 +143,7 @@ struct BufStruct { char contents[2048]; }; -ClangUtilityFunction * +UtilityFunction * AppleObjCRuntimeV1::CreateObjectChecker(const char *name) { std::unique_ptr<BufStruct> buf(new BufStruct); @@ -170,7 +170,8 @@ AppleObjCRuntimeV1::CreateObjectChecker(const char *name) "} \n", name) < (int)sizeof(buf->contents)); - return new ClangUtilityFunction(buf->contents, name); + Error error; + return GetTargetRef().GetUtilityFunctionForLanguage(buf->contents, eLanguageTypeObjC, name, error); } AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ValueObject &isa_pointer) diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h index f98f065f6a7..73e8607286f 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h @@ -102,7 +102,7 @@ public: TypeAndOrName &class_type_or_name, Address &address); - virtual ClangUtilityFunction * + virtual UtilityFunction * CreateObjectChecker (const char *); //------------------------------------------------------------------ diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 4817d57a353..ac643064415 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -28,8 +28,8 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" #include "lldb/Core/ValueObjectVariable.h" -#include "lldb/Expression/ClangFunction.h" -#include "lldb/Expression/ClangUtilityFunction.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" @@ -348,11 +348,9 @@ ExtractRuntimeGlobalSymbol (Process* process, AppleObjCRuntimeV2::AppleObjCRuntimeV2 (Process *process, const ModuleSP &objc_module_sp) : AppleObjCRuntime (process), - m_get_class_info_function(), m_get_class_info_code(), m_get_class_info_args (LLDB_INVALID_ADDRESS), m_get_class_info_args_mutex (Mutex::eMutexTypeNormal), - m_get_shared_cache_class_info_function(), m_get_shared_cache_class_info_code(), m_get_shared_cache_class_info_args (LLDB_INVALID_ADDRESS), m_get_shared_cache_class_info_args_mutex (Mutex::eMutexTypeNormal), @@ -722,7 +720,7 @@ AppleObjCRuntimeV2::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bo return resolver_sp; } -ClangUtilityFunction * +UtilityFunction * AppleObjCRuntimeV2::CreateObjectChecker(const char *name) { char check_function_code[2048]; @@ -780,7 +778,8 @@ AppleObjCRuntimeV2::CreateObjectChecker(const char *name) assert (len < (int)sizeof(check_function_code)); - return new ClangUtilityFunction(check_function_code, name); + Error error; + return GetTargetRef().GetUtilityFunctionForLanguage(check_function_code, eLanguageTypeObjC, name, error); } size_t @@ -1248,75 +1247,74 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table CompilerType clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); CompilerType clang_void_pointer_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); + ValueList arguments; + FunctionCaller *get_class_info_function = nullptr; + if (!m_get_class_info_code.get()) { - m_get_class_info_code.reset (new ClangUtilityFunction (g_get_dynamic_class_info_body, - g_get_dynamic_class_info_name)); - - errors.Clear(); - - if (!m_get_class_info_code->Install(errors, exe_ctx)) + Error error; + m_get_class_info_code.reset (GetTargetRef().GetUtilityFunctionForLanguage (g_get_dynamic_class_info_body, + eLanguageTypeObjC, + g_get_dynamic_class_info_name, + error)); + if (error.Fail()) { if (log) - log->Printf ("Failed to install implementation lookup: %s.", errors.GetData()); + log->Printf ("Failed to get Utility Function for implementation lookup: %s", error.AsCString()); m_get_class_info_code.reset(); } - } - - if (m_get_class_info_code.get()) - function_address.SetOffset(m_get_class_info_code->StartAddress()); - else - return false; - - ValueList arguments; - - // Next make the runner function for our implementation utility function. - if (!m_get_class_info_function.get()) - { + else + { + errors.Clear(); + + if (!m_get_class_info_code->Install(errors, exe_ctx)) + { + if (log) + log->Printf ("Failed to install implementation lookup: %s.", errors.GetData()); + m_get_class_info_code.reset(); + } + } + if (!m_get_class_info_code.get()) + return false; + + // Next make the runner function for our implementation utility function. Value value; value.SetValueType (Value::eValueTypeScalar); -// value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type); value.SetCompilerType (clang_void_pointer_type); arguments.PushValue (value); arguments.PushValue (value); value.SetValueType (Value::eValueTypeScalar); -// value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type); value.SetCompilerType (clang_uint32_t_type); arguments.PushValue (value); - m_get_class_info_function.reset(new ClangFunction (*m_process, - clang_uint32_t_type, - function_address, - arguments, - "objc-v2-isa-to-descriptor")); - - if (m_get_class_info_function.get() == NULL) - return false; - - errors.Clear(); + get_class_info_function = m_get_class_info_code->MakeFunctionCaller(clang_uint32_t_type, + arguments, + error); - unsigned num_errors = m_get_class_info_function->CompileFunction(errors); - if (num_errors) + if (error.Fail()) { if (log) - log->Printf ("Error compiling function: \"%s\".", errors.GetData()); + log->Printf("Failed to make function caller for implementation lookup: %s.", error.AsCString()); return false; } - - errors.Clear(); - - if (!m_get_class_info_function->WriteFunctionWrapper(exe_ctx, errors)) + } + else + { + get_class_info_function = m_get_class_info_code->GetFunctionCaller(); + if (!get_class_info_function) { if (log) - log->Printf ("Error Inserting function: \"%s\".", errors.GetData()); + log->Printf ("Failed to get implementation lookup function caller: %s.", errors.GetData()); return false; } + arguments = get_class_info_function->GetArgumentValues(); } - else - { - arguments = m_get_class_info_function->GetArgumentValues (); - } + + + + + errors.Clear(); const uint32_t class_info_byte_size = addr_size + 4; const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; @@ -1339,9 +1337,8 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table errors.Clear(); // Write our function arguments into the process so we can run our function - if (m_get_class_info_function->WriteFunctionArguments (exe_ctx, + if (get_class_info_function->WriteFunctionArguments (exe_ctx, m_get_class_info_args, - function_address, arguments, errors)) { @@ -1361,11 +1358,11 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table errors.Clear(); // Run the function - ExpressionResults results = m_get_class_info_function->ExecuteFunction (exe_ctx, - &m_get_class_info_args, - options, - errors, - return_value); + ExpressionResults results = get_class_info_function->ExecuteFunction (exe_ctx, + &m_get_class_info_args, + options, + errors, + return_value); if (results == eExpressionCompleted) { @@ -1502,31 +1499,38 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() CompilerType clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); CompilerType clang_void_pointer_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); + ValueList arguments; + FunctionCaller *get_shared_cache_class_info_function = nullptr; + if (!m_get_shared_cache_class_info_code.get()) { - m_get_shared_cache_class_info_code.reset (new ClangUtilityFunction (g_get_shared_cache_class_info_body, - g_get_shared_cache_class_info_name)); - - errors.Clear(); - - if (!m_get_shared_cache_class_info_code->Install(errors, exe_ctx)) + Error error; + m_get_shared_cache_class_info_code.reset (GetTargetRef().GetUtilityFunctionForLanguage (g_get_shared_cache_class_info_body, + eLanguageTypeObjC, + g_get_shared_cache_class_info_name, + error)); + if (error.Fail()) { if (log) - log->Printf ("Failed to install implementation lookup: %s.", errors.GetData()); + log->Printf ("Failed to get Utility function for implementation lookup: %s.", error.AsCString()); m_get_shared_cache_class_info_code.reset(); } - } - - if (m_get_shared_cache_class_info_code.get()) - function_address.SetOffset(m_get_shared_cache_class_info_code->StartAddress()); - else - return DescriptorMapUpdateResult::Fail(); - - ValueList arguments; + else + { + errors.Clear(); + + if (!m_get_shared_cache_class_info_code->Install(errors, exe_ctx)) + { + if (log) + log->Printf ("Failed to install implementation lookup: %s.", errors.GetData()); + m_get_shared_cache_class_info_code.reset(); + } + } + + if (!m_get_shared_cache_class_info_code.get()) + return DescriptorMapUpdateResult::Fail(); - // Next make the runner function for our implementation utility function. - if (!m_get_shared_cache_class_info_function.get()) - { + // Next make the function caller for our implementation utility function. Value value; value.SetValueType (Value::eValueTypeScalar); //value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type); @@ -1539,39 +1543,24 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() value.SetCompilerType (clang_uint32_t_type); arguments.PushValue (value); - m_get_shared_cache_class_info_function.reset(new ClangFunction (*m_process, - clang_uint32_t_type, - function_address, - arguments, - "objc-isa-to-descriptor-shared-cache")); - - if (m_get_shared_cache_class_info_function.get() == NULL) - return DescriptorMapUpdateResult::Fail(); - - errors.Clear(); - - unsigned num_errors = m_get_shared_cache_class_info_function->CompileFunction(errors); - if (num_errors) - { - if (log) - log->Printf ("Error compiling function: \"%s\".", errors.GetData()); - return DescriptorMapUpdateResult::Fail(); - } - - errors.Clear(); + get_shared_cache_class_info_function = m_get_shared_cache_class_info_code->MakeFunctionCaller(clang_uint32_t_type, + arguments, + error); - if (!m_get_shared_cache_class_info_function->WriteFunctionWrapper(exe_ctx, errors)) - { - if (log) - log->Printf ("Error Inserting function: \"%s\".", errors.GetData()); + if (get_shared_cache_class_info_function == nullptr) return DescriptorMapUpdateResult::Fail(); - } + } else { - arguments = m_get_shared_cache_class_info_function->GetArgumentValues (); + get_shared_cache_class_info_function = m_get_shared_cache_class_info_code->GetFunctionCaller(); + if (get_shared_cache_class_info_function == nullptr) + return DescriptorMapUpdateResult::Fail(); + arguments = get_shared_cache_class_info_function->GetArgumentValues(); } + errors.Clear(); + const uint32_t class_info_byte_size = addr_size + 4; const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; lldb::addr_t class_infos_addr = process->AllocateMemory (class_infos_byte_size, @@ -1594,11 +1583,10 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() errors.Clear(); // Write our function arguments into the process so we can run our function - if (m_get_shared_cache_class_info_function->WriteFunctionArguments (exe_ctx, - m_get_shared_cache_class_info_args, - function_address, - arguments, - errors)) + if (get_shared_cache_class_info_function->WriteFunctionArguments (exe_ctx, + m_get_shared_cache_class_info_args, + arguments, + errors)) { EvaluateExpressionOptions options; options.SetUnwindOnError(true); @@ -1616,11 +1604,11 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() errors.Clear(); // Run the function - ExpressionResults results = m_get_shared_cache_class_info_function->ExecuteFunction (exe_ctx, - &m_get_shared_cache_class_info_args, - options, - errors, - return_value); + ExpressionResults results = get_shared_cache_class_info_function->ExecuteFunction (exe_ctx, + &m_get_shared_cache_class_info_args, + options, + errors, + return_value); if (results == eExpressionCompleted) { diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h index 6d981f72d8c..feaf9d4d6f0 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -39,7 +39,7 @@ public: TypeAndOrName &class_type_or_name, Address &address); - virtual ClangUtilityFunction * + virtual UtilityFunction * CreateObjectChecker (const char *); @@ -299,22 +299,20 @@ private: friend class ClassDescriptorV2; - std::unique_ptr<ClangFunction> m_get_class_info_function; - std::unique_ptr<ClangUtilityFunction> m_get_class_info_code; + std::unique_ptr<UtilityFunction> m_get_class_info_code; lldb::addr_t m_get_class_info_args; Mutex m_get_class_info_args_mutex; - std::unique_ptr<ClangFunction> m_get_shared_cache_class_info_function; - std::unique_ptr<ClangUtilityFunction> m_get_shared_cache_class_info_code; + std::unique_ptr<UtilityFunction> m_get_shared_cache_class_info_code; lldb::addr_t m_get_shared_cache_class_info_args; Mutex m_get_shared_cache_class_info_args_mutex; - std::unique_ptr<DeclVendor> m_decl_vendor_ap; + std::unique_ptr<DeclVendor> m_decl_vendor_ap; lldb::addr_t m_isa_hash_table_ptr; HashTableSignature m_hash_signature; bool m_has_object_getClass; bool m_loaded_objc_opt; - std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_ap; + std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_ap; std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_ap; EncodingToTypeSP m_encoding_to_type_sp; bool m_noclasses_warning_emitted; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index db5b7f0a406..d38a076ad5d 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -22,9 +22,9 @@ #include "lldb/Core/Module.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/Value.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangFunction.h" -#include "lldb/Expression/ClangUtilityFunction.h" +#include "lldb/Expression/UserExpression.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Host/FileSpec.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Symbol.h" @@ -741,10 +741,10 @@ lldb::addr_t AppleObjCTrampolineHandler::SetupDispatchFunction (Thread &thread, ValueList &dispatch_values) { ExecutionContext exe_ctx (thread.shared_from_this()); - Address impl_code_address; StreamString errors; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; + FunctionCaller *impl_function_caller = nullptr; // Scope for mutex locker: { @@ -752,38 +752,23 @@ AppleObjCTrampolineHandler::SetupDispatchFunction (Thread &thread, ValueList &di // First stage is to make the ClangUtility to hold our injected function: - #define USE_BUILTIN_FUNCTION 0 // Define this to 1 and we will use the get_implementation function found in the target. - // This is useful for debugging additions to the get_impl function 'cause you don't have - // to bother with string-ifying the code into g_lookup_implementation_function_code. - - if (USE_BUILTIN_FUNCTION) - { - ConstString our_utility_function_name("__lldb_objc_find_implementation_for_selector"); - SymbolContextList sc_list; - - exe_ctx.GetTargetRef().GetImages().FindSymbolsWithNameAndType (our_utility_function_name, eSymbolTypeCode, sc_list); - if (sc_list.GetSize() == 1) - { - SymbolContext sc; - sc_list.GetContextAtIndex(0, sc); - if (sc.symbol != NULL) - impl_code_address = sc.symbol->GetAddress(); - - //lldb::addr_t addr = impl_code_address.GetOpcodeLoadAddress (exe_ctx.GetTargetPtr()); - //printf ("Getting address for our_utility_function: 0x%" PRIx64 ".\n", addr); - } - else - { - //printf ("Could not find implementation function address.\n"); - return args_addr; - } - } - else if (!m_impl_code.get()) + if (!m_impl_code.get()) { if (g_lookup_implementation_function_code != NULL) { - m_impl_code.reset (new ClangUtilityFunction (g_lookup_implementation_function_code, - g_lookup_implementation_function_name)); + Error error; + m_impl_code.reset (exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage (g_lookup_implementation_function_code, + eLanguageTypeObjC, + g_lookup_implementation_function_name, + error)); + if (error.Fail()) + { + if (log) + log->Printf ("Failed to get Utility Function for implementation lookup: %s.", error.AsCString()); + m_impl_code.reset(); + return args_addr; + } + if (!m_impl_code->Install(errors, exe_ctx)) { if (log) @@ -800,43 +785,26 @@ AppleObjCTrampolineHandler::SetupDispatchFunction (Thread &thread, ValueList &di return LLDB_INVALID_ADDRESS; } - impl_code_address.Clear(); - impl_code_address.SetOffset(m_impl_code->StartAddress()); - } - else - { - impl_code_address.Clear(); - impl_code_address.SetOffset(m_impl_code->StartAddress()); - } - // Next make the runner function for our implementation utility function. - if (!m_impl_function.get()) - { + // Next make the runner function for our implementation utility function. ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext(); CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - m_impl_function.reset(new ClangFunction (thread, - clang_void_ptr_type, - impl_code_address, - dispatch_values, - "objc-dispatch-lookup")); + Error error; - errors.Clear(); - unsigned num_errors = m_impl_function->CompileFunction(errors); - if (num_errors) + impl_function_caller = m_impl_code->MakeFunctionCaller(clang_void_ptr_type, + dispatch_values, + error); + if (error.Fail()) { if (log) - log->Printf ("Error compiling function: \"%s\".", errors.GetData()); - return args_addr; - } - - errors.Clear(); - if (!m_impl_function->WriteFunctionWrapper(exe_ctx, errors)) - { - if (log) - log->Printf ("Error Inserting function: \"%s\".", errors.GetData()); + log->Printf ("Error getting function caller for dispatch lookup: \"%s\".", error.AsCString()); return args_addr; } } + else + { + impl_function_caller = m_impl_code->GetFunctionCaller(); + } } errors.Clear(); @@ -845,7 +813,7 @@ AppleObjCTrampolineHandler::SetupDispatchFunction (Thread &thread, ValueList &di // if other threads were calling into here, but actually it isn't because we allocate a new args structure for // this call by passing args_addr = LLDB_INVALID_ADDRESS... - if (!m_impl_function->WriteFunctionArguments (exe_ctx, args_addr, impl_code_address, dispatch_values, errors)) + if (impl_function_caller->WriteFunctionArguments (exe_ctx, args_addr, dispatch_values, errors)) { if (log) log->Printf ("Error writing function arguments: \"%s\".", errors.GetData()); @@ -1169,8 +1137,8 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan (Thread &thread, bool sto return ret_plan_sp; } -ClangFunction * -AppleObjCTrampolineHandler::GetLookupImplementationWrapperFunction () +FunctionCaller * +AppleObjCTrampolineHandler::GetLookupImplementationFunctionCaller () { - return m_impl_function.get(); + return m_impl_code->GetFunctionCaller(); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h index c9d0e19ed2b..0ddb540439d 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h @@ -35,8 +35,8 @@ public: GetStepThroughDispatchPlan (Thread &thread, bool stop_others); - ClangFunction * - GetLookupImplementationWrapperFunction (); + FunctionCaller * + GetLookupImplementationFunctionCaller (); bool AddrIsMsgForward (lldb::addr_t addr) const @@ -198,8 +198,7 @@ private: MsgsendMap m_msgSend_map; lldb::ProcessWP m_process_wp; lldb::ModuleSP m_objc_module_sp; - std::unique_ptr<ClangFunction> m_impl_function; - std::unique_ptr<ClangUtilityFunction> m_impl_code; + std::unique_ptr<UtilityFunction> m_impl_code; Mutex m_impl_function_mutex; lldb::addr_t m_impl_fn_addr; lldb::addr_t m_impl_stret_fn_addr; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index fe364faefe3..285786a09db 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -15,8 +15,8 @@ #include "AppleObjCTrampolineHandler.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangFunction.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/ThreadPlanRunToAddress.h" @@ -67,11 +67,11 @@ AppleThreadPlanStepThroughObjCTrampoline::DidPush () { // Setting up the memory space for the called function text might require allocations, // i.e. a nested function call. This needs to be done as a PreResumeAction. - m_thread.GetProcess()->AddPreResumeAction (PreResumeInitializeClangFunction, (void *) this); + m_thread.GetProcess()->AddPreResumeAction (PreResumeInitializeFunctionCaller, (void *) this); } bool -AppleThreadPlanStepThroughObjCTrampoline::InitializeClangFunction () +AppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller () { if (!m_func_sp) { @@ -82,7 +82,7 @@ AppleThreadPlanStepThroughObjCTrampoline::InitializeClangFunction () { return false; } - m_impl_function = m_trampoline_handler->GetLookupImplementationWrapperFunction(); + m_impl_function = m_trampoline_handler->GetLookupImplementationFunctionCaller(); ExecutionContext exc_ctx; EvaluateExpressionOptions options; options.SetUnwindOnError(true); @@ -100,10 +100,10 @@ AppleThreadPlanStepThroughObjCTrampoline::InitializeClangFunction () } bool -AppleThreadPlanStepThroughObjCTrampoline::PreResumeInitializeClangFunction(void *void_myself) +AppleThreadPlanStepThroughObjCTrampoline::PreResumeInitializeFunctionCaller(void *void_myself) { AppleThreadPlanStepThroughObjCTrampoline *myself = static_cast<AppleThreadPlanStepThroughObjCTrampoline *>(void_myself); - return myself->InitializeClangFunction(); + return myself->InitializeFunctionCaller(); } void diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h index 253190991ce..2ad181e553f 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h @@ -66,7 +66,7 @@ public: DidPush(); static bool - PreResumeInitializeClangFunction(void *myself); + PreResumeInitializeFunctionCaller(void *myself); virtual bool WillStop(); @@ -82,7 +82,7 @@ protected: private: bool - InitializeClangFunction (); + InitializeFunctionCaller (); //------------------------------------------------------------------ // For AppleThreadPlanStepThroughObjCTrampoline only @@ -96,7 +96,7 @@ private: lldb::ThreadPlanSP m_func_sp; // This is the function call plan. We fill it at start, then set it // to NULL when this plan is done. That way we know to go to: lldb::ThreadPlanSP m_run_to_sp; // The plan that runs to the target. - ClangFunction *m_impl_function; // This is a pointer to a impl function that + FunctionCaller *m_impl_function; // This is a pointer to a impl function that // is owned by the client that pushes this plan. bool m_stop_others; }; diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp index a882b7e3e87..66b8b8bcf59 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp @@ -22,9 +22,8 @@ #include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/Value.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangFunction.h" -#include "lldb/Expression/ClangUtilityFunction.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" @@ -101,7 +100,6 @@ extern \"C\" AppleGetItemInfoHandler::AppleGetItemInfoHandler (Process *process) : m_process (process), - m_get_item_info_function (), m_get_item_info_impl_code (), m_get_item_info_function_mutex(), m_get_item_info_return_buffer_addr (LLDB_INVALID_ADDRESS), @@ -140,49 +138,33 @@ lldb::addr_t AppleGetItemInfoHandler::SetupGetItemInfoFunction (Thread &thread, ValueList &get_item_info_arglist) { ExecutionContext exe_ctx (thread.shared_from_this()); - Address impl_code_address; StreamString errors; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME)); lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; + FunctionCaller *get_item_info_caller = nullptr; // Scope for mutex locker: { Mutex::Locker locker(m_get_item_info_function_mutex); - // First stage is to make the ClangUtility to hold our injected function: + // First stage is to make the UtilityFunction to hold our injected function: -#define USE_BUILTIN_FUNCTION 0 // Define this to 1 and we will use the get_implementation function found in the target. - // This is useful for debugging additions to the get_impl function 'cause you don't have - // to bother with string-ifying the code into g_get_item_info_function_code. - - if (USE_BUILTIN_FUNCTION) - { - ConstString our_utility_function_name("__lldb_backtrace_recording_get_item_info"); - SymbolContextList sc_list; - - exe_ctx.GetTargetRef().GetImages().FindSymbolsWithNameAndType (our_utility_function_name, eSymbolTypeCode, sc_list); - if (sc_list.GetSize() == 1) - { - SymbolContext sc; - sc_list.GetContextAtIndex(0, sc); - if (sc.symbol != NULL) - impl_code_address = sc.symbol->GetAddress(); - - //lldb::addr_t addr = impl_code_address.GetOpcodeLoadAddress (exe_ctx.GetTargetPtr()); - //printf ("Getting address for our_utility_function: 0x%" PRIx64 ".\n", addr); - } - else - { - //printf ("Could not find queues introspection function address.\n"); - return args_addr; - } - } - else if (!m_get_item_info_impl_code.get()) + if (!m_get_item_info_impl_code.get()) { if (g_get_item_info_function_code != NULL) { - m_get_item_info_impl_code.reset (new ClangUtilityFunction (g_get_item_info_function_code, - g_get_item_info_function_name)); + Error error; + m_get_item_info_impl_code.reset(exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage (g_get_item_info_function_code, + eLanguageTypeObjC, + g_get_item_info_function_name, + error)); + if (error.Fail()) + { + if (log) + log->Printf ("Failed to get utility function: %s.", error.AsCString()); + return args_addr; + } + if (!m_get_item_info_impl_code->Install(errors, exe_ctx)) { if (log) @@ -198,41 +180,32 @@ AppleGetItemInfoHandler::SetupGetItemInfoFunction (Thread &thread, ValueList &ge errors.Printf ("No get-item-info introspection code found."); return LLDB_INVALID_ADDRESS; } - - impl_code_address.Clear(); - impl_code_address.SetOffset(m_get_item_info_impl_code->StartAddress()); - } - else - { - impl_code_address.Clear(); - impl_code_address.SetOffset(m_get_item_info_impl_code->StartAddress()); - } - // Next make the runner function for our implementation utility function. - if (!m_get_item_info_function.get()) - { - ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext(); - CompilerType get_item_info_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - m_get_item_info_function.reset(new ClangFunction (thread, - get_item_info_return_type, - impl_code_address, - get_item_info_arglist, - "queue-bt-item-info")); + // Next make the runner function for our implementation utility function. + Error error; + + TypeSystem *type_system = thread.GetProcess()->GetTarget().GetScratchTypeSystemForLanguage(eLanguageTypeC); + CompilerType get_item_info_return_type = type_system->GetBasicTypeFromAST(eBasicTypeVoid).GetPointerType(); - errors.Clear(); - unsigned num_errors = m_get_item_info_function->CompileFunction(errors); - if (num_errors) + get_item_info_caller = m_get_item_info_impl_code->MakeFunctionCaller(get_item_info_return_type, + get_item_info_arglist, + error); + if (error.Fail()) { if (log) - log->Printf ("Error compiling get-item-info function: \"%s\".", errors.GetData()); + log->Printf ("Error Inserting get-item-info function: \"%s\".", error.AsCString()); return args_addr; } - - errors.Clear(); - if (!m_get_item_info_function->WriteFunctionWrapper(exe_ctx, errors)) + } + else + { + // If it's already made, then we can just retrieve the caller: + get_item_info_caller = m_get_item_info_impl_code->GetFunctionCaller(); + if (!get_item_info_caller) { if (log) - log->Printf ("Error Inserting get-item-info function: \"%s\".", errors.GetData()); + log->Printf ("Failed to get get-item-info introspection caller."); + m_get_item_info_impl_code.reset(); return args_addr; } } @@ -244,7 +217,7 @@ AppleGetItemInfoHandler::SetupGetItemInfoFunction (Thread &thread, ValueList &ge // if other threads were calling into here, but actually it isn't because we allocate a new args structure for // this call by passing args_addr = LLDB_INVALID_ADDRESS... - if (!m_get_item_info_function->WriteFunctionArguments (exe_ctx, args_addr, impl_code_address, get_item_info_arglist, errors)) + if (!get_item_info_caller->WriteFunctionArguments (exe_ctx, args_addr, get_item_info_arglist, errors)) { if (log) log->Printf ("Error writing get-item-info function arguments: \"%s\".", errors.GetData()); @@ -364,7 +337,7 @@ AppleGetItemInfoHandler::GetItemInfo (Thread &thread, uint64_t item, addr_t page options.SetTryAllThreads (false); thread.CalculateExecutionContext (exe_ctx); - if (m_get_item_info_function == NULL) + if (!m_get_item_info_impl_code) { error.SetErrorString ("Unable to compile function to call __introspection_dispatch_queue_item_get_info"); return return_value; @@ -373,7 +346,16 @@ AppleGetItemInfoHandler::GetItemInfo (Thread &thread, uint64_t item, addr_t page ExpressionResults func_call_ret; Value results; - func_call_ret = m_get_item_info_function->ExecuteFunction (exe_ctx, &args_addr, options, errors, results); + FunctionCaller *func_caller = m_get_item_info_impl_code->GetFunctionCaller(); + if (!func_caller) + { + if (log) + log->Printf ("Could not retrieve function caller for __introspection_dispatch_queue_item_get_info."); + error.SetErrorString("Could not retrieve function caller for __introspection_dispatch_queue_item_get_info."); + return return_value; + } + + func_call_ret = func_caller->ExecuteFunction (exe_ctx, &args_addr, options, errors, results); if (func_call_ret != eExpressionCompleted || !error.Success()) { if (log) diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h index 5c086c61978..51182a62493 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h @@ -18,11 +18,11 @@ // Project includes #include "lldb/lldb-public.h" #include "lldb/Core/Error.h" -#include "lldb/Expression/ClangFunction.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Host/Mutex.h" #include "lldb/Symbol/CompilerType.h" -// This class will insert a ClangUtilityFunction into the inferior process for +// This class will insert a UtilityFunction into the inferior process for // calling libBacktraceRecording's __introspection_dispatch_queue_item_get_info() // function. The function in the inferior will return a struct by value // with these members: @@ -37,7 +37,7 @@ // space (item_buffer_size in size) which must be mach_vm_deallocate'd by // lldb. // -// The AppleGetItemInfoHandler object should persist so that the ClangUtilityFunction +// The AppleGetItemInfoHandler object should persist so that the UtilityFunction // can be reused multiple times. namespace lldb_private @@ -104,8 +104,7 @@ private: static const char *g_get_item_info_function_code; lldb_private::Process *m_process; - std::unique_ptr<ClangFunction> m_get_item_info_function; - std::unique_ptr<ClangUtilityFunction> m_get_item_info_impl_code; + std::unique_ptr<UtilityFunction> m_get_item_info_impl_code; Mutex m_get_item_info_function_mutex; lldb::addr_t m_get_item_info_return_buffer_addr; diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp index c3e68eaa0a6..3e3a2620013 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp @@ -22,9 +22,8 @@ #include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/Value.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangFunction.h" -#include "lldb/Expression/ClangUtilityFunction.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" @@ -105,7 +104,6 @@ extern \"C\" AppleGetPendingItemsHandler::AppleGetPendingItemsHandler (Process *process) : m_process (process), - m_get_pending_items_function (), m_get_pending_items_impl_code (), m_get_pending_items_function_mutex(), m_get_pending_items_return_buffer_addr (LLDB_INVALID_ADDRESS), @@ -144,49 +142,33 @@ lldb::addr_t AppleGetPendingItemsHandler::SetupGetPendingItemsFunction (Thread &thread, ValueList &get_pending_items_arglist) { ExecutionContext exe_ctx (thread.shared_from_this()); - Address impl_code_address; StreamString errors; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME)); lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; - + FunctionCaller *get_pending_items_caller = nullptr; + // Scope for mutex locker: { Mutex::Locker locker(m_get_pending_items_function_mutex); // First stage is to make the ClangUtility to hold our injected function: -#define USE_BUILTIN_FUNCTION 0 // Define this to 1 and we will use the get_implementation function found in the target. - // This is useful for debugging additions to the get_impl function 'cause you don't have - // to bother with string-ifying the code into g_get_pending_items_function_code. - - if (USE_BUILTIN_FUNCTION) - { - ConstString our_utility_function_name("__lldb_backtrace_recording_get_pending_items"); - SymbolContextList sc_list; - - exe_ctx.GetTargetRef().GetImages().FindSymbolsWithNameAndType (our_utility_function_name, eSymbolTypeCode, sc_list); - if (sc_list.GetSize() == 1) - { - SymbolContext sc; - sc_list.GetContextAtIndex(0, sc); - if (sc.symbol != NULL) - impl_code_address = sc.symbol->GetAddress(); - - //lldb::addr_t addr = impl_code_address.GetOpcodeLoadAddress (exe_ctx.GetTargetPtr()); - //printf ("Getting address for our_utility_function: 0x%" PRIx64 ".\n", addr); - } - else - { - //printf ("Could not find queues introspection function address.\n"); - return args_addr; - } - } - else if (!m_get_pending_items_impl_code.get()) + if (!m_get_pending_items_impl_code.get()) { if (g_get_pending_items_function_code != NULL) { - m_get_pending_items_impl_code.reset (new ClangUtilityFunction (g_get_pending_items_function_code, - g_get_pending_items_function_name)); + Error error; + m_get_pending_items_impl_code.reset (exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(g_get_pending_items_function_code, + eLanguageTypeObjC, + g_get_pending_items_function_name, + error)); + if (error.Fail()) + { + if (log) + log->Printf ("Failed to get UtilityFunction for pending-items introspection: %s.", error.AsCString()); + return args_addr; + } + if (!m_get_pending_items_impl_code->Install(errors, exe_ctx)) { if (log) @@ -203,43 +185,22 @@ AppleGetPendingItemsHandler::SetupGetPendingItemsFunction (Thread &thread, Value return LLDB_INVALID_ADDRESS; } - impl_code_address.Clear(); - impl_code_address.SetOffset(m_get_pending_items_impl_code->StartAddress()); - } - else - { - impl_code_address.Clear(); - impl_code_address.SetOffset(m_get_pending_items_impl_code->StartAddress()); - } - - // Next make the runner function for our implementation utility function. - if (!m_get_pending_items_function.get()) - { + // Next make the runner function for our implementation utility function. + Error error; ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext(); CompilerType get_pending_items_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - m_get_pending_items_function.reset(new ClangFunction (thread, - get_pending_items_return_type, - impl_code_address, - get_pending_items_arglist, - "queue-pending-items")); - - errors.Clear(); - unsigned num_errors = m_get_pending_items_function->CompileFunction(errors); - if (num_errors) + get_pending_items_caller = m_get_pending_items_impl_code->MakeFunctionCaller (get_pending_items_return_type, + get_pending_items_arglist, + error); + if (error.Fail()) { if (log) - log->Printf ("Error compiling pending-items function: \"%s\".", errors.GetData()); - return args_addr; - } - - errors.Clear(); - if (!m_get_pending_items_function->WriteFunctionWrapper(exe_ctx, errors)) - { - if (log) - log->Printf ("Error Inserting pending-items function: \"%s\".", errors.GetData()); + log->Printf ("Failed to install pending-items introspection function caller: %s.", error.AsCString()); + m_get_pending_items_impl_code.reset(); return args_addr; } } + } errors.Clear(); @@ -248,7 +209,7 @@ AppleGetPendingItemsHandler::SetupGetPendingItemsFunction (Thread &thread, Value // if other threads were calling into here, but actually it isn't because we allocate a new args structure for // this call by passing args_addr = LLDB_INVALID_ADDRESS... - if (!m_get_pending_items_function->WriteFunctionArguments (exe_ctx, args_addr, impl_code_address, get_pending_items_arglist, errors)) + if (!get_pending_items_caller->WriteFunctionArguments (exe_ctx, args_addr, get_pending_items_arglist, errors)) { if (log) log->Printf ("Error writing pending-items function arguments: \"%s\".", errors.GetData()); @@ -362,6 +323,8 @@ AppleGetPendingItemsHandler::GetPendingItems (Thread &thread, addr_t queue, addr StreamString errors; ExecutionContext exe_ctx; + FunctionCaller *get_pending_items_caller = m_get_pending_items_impl_code->GetFunctionCaller(); + EvaluateExpressionOptions options; options.SetUnwindOnError (true); options.SetIgnoreBreakpoints (true); @@ -370,7 +333,7 @@ AppleGetPendingItemsHandler::GetPendingItems (Thread &thread, addr_t queue, addr options.SetTryAllThreads (false); thread.CalculateExecutionContext (exe_ctx); - if (m_get_pending_items_function == NULL) + if (get_pending_items_caller == NULL) { error.SetErrorString ("Unable to compile function to call __introspection_dispatch_queue_get_pending_items"); return return_value; @@ -379,7 +342,7 @@ AppleGetPendingItemsHandler::GetPendingItems (Thread &thread, addr_t queue, addr ExpressionResults func_call_ret; Value results; - func_call_ret = m_get_pending_items_function->ExecuteFunction (exe_ctx, &args_addr, options, errors, results); + func_call_ret = get_pending_items_caller->ExecuteFunction (exe_ctx, &args_addr, options, errors, results); if (func_call_ret != eExpressionCompleted || !error.Success()) { if (log) diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h index 22ab1f6132c..445c4a0fb82 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h @@ -18,11 +18,10 @@ // Project includes #include "lldb/lldb-public.h" #include "lldb/Core/Error.h" -#include "lldb/Expression/ClangFunction.h" #include "lldb/Host/Mutex.h" #include "lldb/Symbol/CompilerType.h" -// This class will insert a ClangUtilityFunction into the inferior process for +// This class will insert a UtilityFunction into the inferior process for // calling libBacktraceRecording's __introspection_dispatch_queue_get_pending_items() // function. The function in the inferior will return a struct by value // with these members: @@ -38,7 +37,7 @@ // space (items_buffer_size in size) which must be mach_vm_deallocate'd by // lldb. count is the number of items that were stored in the buffer. // -// The AppleGetPendingItemsHandler object should persist so that the ClangUtilityFunction +// The AppleGetPendingItemsHandler object should persist so that the UtilityFunction // can be reused multiple times. namespace lldb_private @@ -107,8 +106,7 @@ private: static const char *g_get_pending_items_function_code; lldb_private::Process *m_process; - std::unique_ptr<ClangFunction> m_get_pending_items_function; - std::unique_ptr<ClangUtilityFunction> m_get_pending_items_impl_code; + std::unique_ptr<UtilityFunction> m_get_pending_items_impl_code; Mutex m_get_pending_items_function_mutex; lldb::addr_t m_get_pending_items_return_buffer_addr; diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp index d5b1380e273..6d7eaf72191 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp @@ -21,9 +21,8 @@ #include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/Value.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangFunction.h" -#include "lldb/Expression/ClangUtilityFunction.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" @@ -101,8 +100,7 @@ extern \"C\" AppleGetQueuesHandler::AppleGetQueuesHandler (Process *process) : m_process (process), - m_get_queues_function (), - m_get_queues_impl_code (), + m_get_queues_impl_code_up (), m_get_queues_function_mutex(), m_get_queues_return_buffer_addr (LLDB_INVALID_ADDRESS), m_get_queues_retbuffer_mutex() @@ -156,6 +154,8 @@ AppleGetQueuesHandler::SetupGetQueuesFunction (Thread &thread, ValueList &get_qu StreamString errors; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME)); lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; + + FunctionCaller *get_queues_caller = nullptr; // Scope for mutex locker: { @@ -163,43 +163,27 @@ AppleGetQueuesHandler::SetupGetQueuesFunction (Thread &thread, ValueList &get_qu // First stage is to make the ClangUtility to hold our injected function: -#define USE_BUILTIN_FUNCTION 0 // Define this to 1 and we will use the get_implementation function found in the target. - // This is useful for debugging additions to the get_impl function 'cause you don't have - // to bother with string-ifying the code into g_get_current_queues_function_code. - - if (USE_BUILTIN_FUNCTION) - { - ConstString our_utility_function_name("__lldb_backtrace_recording_get_current_queues"); - SymbolContextList sc_list; - - exe_ctx.GetTargetRef().GetImages().FindSymbolsWithNameAndType (our_utility_function_name, eSymbolTypeCode, sc_list); - if (sc_list.GetSize() == 1) - { - SymbolContext sc; - sc_list.GetContextAtIndex(0, sc); - if (sc.symbol != NULL) - impl_code_address = sc.symbol->GetAddress(); - - //lldb::addr_t addr = impl_code_address.GetOpcodeLoadAddress (exe_ctx.GetTargetPtr()); - //printf ("Getting address for our_utility_function: 0x%" PRIx64 ".\n", addr); - } - else - { - //printf ("Could not find queues introspection function address.\n"); - return args_addr; - } - } - else if (!m_get_queues_impl_code.get()) + if (!m_get_queues_impl_code_up.get()) { if (g_get_current_queues_function_code != NULL) { - m_get_queues_impl_code.reset (new ClangUtilityFunction (g_get_current_queues_function_code, - g_get_current_queues_function_name)); - if (!m_get_queues_impl_code->Install(errors, exe_ctx)) + Error error; + m_get_queues_impl_code_up.reset (exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(g_get_current_queues_function_code, + eLanguageTypeC, + g_get_current_queues_function_name, + error)); + if (error.Fail()) + { + if (log) + log->Printf ("Failed to get UtilityFunction for queues introspection: %s.", error.AsCString()); + return args_addr; + } + + if (!m_get_queues_impl_code_up->Install(errors, exe_ctx)) { if (log) log->Printf ("Failed to install queues introspection: %s.", errors.GetData()); - m_get_queues_impl_code.reset(); + m_get_queues_impl_code_up.reset(); return args_addr; } } @@ -210,43 +194,20 @@ AppleGetQueuesHandler::SetupGetQueuesFunction (Thread &thread, ValueList &get_qu errors.Printf ("No queues introspection code found."); return LLDB_INVALID_ADDRESS; } - - impl_code_address.Clear(); - impl_code_address.SetOffset(m_get_queues_impl_code->StartAddress()); - } - else - { - impl_code_address.Clear(); - impl_code_address.SetOffset(m_get_queues_impl_code->StartAddress()); } - + // Next make the runner function for our implementation utility function. - if (!m_get_queues_function.get()) + ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext(); + CompilerType get_queues_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); + Error error; + get_queues_caller = m_get_queues_impl_code_up->MakeFunctionCaller (get_queues_return_type, + get_queues_arglist, + error); + if (error.Fail()) { - ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext(); - CompilerType get_queues_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - m_get_queues_function.reset(new ClangFunction (thread, - get_queues_return_type, - impl_code_address, - get_queues_arglist, - "queue-fetch-queues")); - - errors.Clear(); - unsigned num_errors = m_get_queues_function->CompileFunction(errors); - if (num_errors) - { - if (log) - log->Printf ("Error compiling get-queues function: \"%s\".", errors.GetData()); - return args_addr; - } - - errors.Clear(); - if (!m_get_queues_function->WriteFunctionWrapper(exe_ctx, errors)) - { - if (log) - log->Printf ("Error Inserting get-queues function: \"%s\".", errors.GetData()); - return args_addr; - } + if (log) + log->Printf ("Could not get function caller for get-queues function: %s.", error.AsCString()); + return args_addr; } } @@ -256,7 +217,7 @@ AppleGetQueuesHandler::SetupGetQueuesFunction (Thread &thread, ValueList &get_qu // if other threads were calling into here, but actually it isn't because we allocate a new args structure for // this call by passing args_addr = LLDB_INVALID_ADDRESS... - if (!m_get_queues_function->WriteFunctionArguments (exe_ctx, args_addr, impl_code_address, get_queues_arglist, errors)) + if (!get_queues_caller->WriteFunctionArguments (exe_ctx, args_addr, get_queues_arglist, errors)) { if (log) log->Printf ("Error writing get-queues function arguments: \"%s\".", errors.GetData()); @@ -360,9 +321,17 @@ AppleGetQueuesHandler::GetCurrentQueues (Thread &thread, addr_t page_to_free, ui addr_t args_addr = SetupGetQueuesFunction (thread, argument_values); - if (m_get_queues_function == NULL) + if (!m_get_queues_impl_code_up) + { + error.SetErrorString ("Unable to compile __introspection_dispatch_get_queues."); + return return_value; + } + + FunctionCaller *get_queues_caller = m_get_queues_impl_code_up->GetFunctionCaller(); + + if (get_queues_caller == NULL) { - error.SetErrorString ("Unable to compile function to call __introspection_dispatch_get_queues"); + error.SetErrorString ("Unable to get caller for call __introspection_dispatch_get_queues"); return return_value; } @@ -378,7 +347,7 @@ AppleGetQueuesHandler::GetCurrentQueues (Thread &thread, addr_t page_to_free, ui ExpressionResults func_call_ret; Value results; - func_call_ret = m_get_queues_function->ExecuteFunction (exe_ctx, &args_addr, options, errors, results); + func_call_ret = get_queues_caller->ExecuteFunction (exe_ctx, &args_addr, options, errors, results); if (func_call_ret != eExpressionCompleted || !error.Success()) { if (log) diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h index 83730b58374..6f3df5f6280 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h @@ -18,11 +18,10 @@ // Project includes #include "lldb/lldb-public.h" #include "lldb/Core/Error.h" -#include "lldb/Expression/ClangFunction.h" #include "lldb/Host/Mutex.h" #include "lldb/Symbol/CompilerType.h" -// This class will insert a ClangUtilityFunction into the inferior process for +// This class will insert a UtilityFunction into the inferior process for // calling libBacktraceRecording's introspection_get_dispatch_queues() // function. The function in the inferior will return a struct by value // with these members: @@ -38,7 +37,7 @@ // space (queues_buffer_size in size) which must be mach_vm_deallocate'd by // lldb. count is the number of queues that were stored in the buffer. // -// The AppleGetQueuesHandler object should persist so that the ClangUtilityFunction +// The AppleGetQueuesHandler object should persist so that the UtilityFunction // can be reused multiple times. namespace lldb_private @@ -104,8 +103,7 @@ private: static const char *g_get_current_queues_function_code; lldb_private::Process *m_process; - std::unique_ptr<ClangFunction> m_get_queues_function; - std::unique_ptr<ClangUtilityFunction> m_get_queues_impl_code; + std::unique_ptr<UtilityFunction> m_get_queues_impl_code_up; Mutex m_get_queues_function_mutex; lldb::addr_t m_get_queues_return_buffer_addr; diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp index 2509b3ba0ef..ea7014147b6 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -17,18 +17,20 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "lldb/lldb-private.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/Value.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangFunction.h" -#include "lldb/Expression/ClangUtilityFunction.h" +#include "lldb/Expression/Expression.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -105,7 +107,6 @@ extern \"C\" AppleGetThreadItemInfoHandler::AppleGetThreadItemInfoHandler (Process *process) : m_process (process), - m_get_thread_item_info_function (), m_get_thread_item_info_impl_code (), m_get_thread_item_info_function_mutex(), m_get_thread_item_info_return_buffer_addr (LLDB_INVALID_ADDRESS), @@ -148,6 +149,7 @@ AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction (Thread &thread, V StreamString errors; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME)); lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; + FunctionCaller *get_thread_item_info_caller = nullptr; // Scope for mutex locker: { @@ -155,38 +157,24 @@ AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction (Thread &thread, V // First stage is to make the ClangUtility to hold our injected function: -#define USE_BUILTIN_FUNCTION 0 // Define this to 1 and we will use the get_implementation function found in the target. - // This is useful for debugging additions to the get_impl function 'cause you don't have - // to bother with string-ifying the code into g_get_thread_item_info_function_code. - - if (USE_BUILTIN_FUNCTION) - { - ConstString our_utility_function_name("__lldb_backtrace_recording_get_thread_item_info"); - SymbolContextList sc_list; - - exe_ctx.GetTargetRef().GetImages().FindSymbolsWithNameAndType (our_utility_function_name, eSymbolTypeCode, sc_list); - if (sc_list.GetSize() == 1) - { - SymbolContext sc; - sc_list.GetContextAtIndex(0, sc); - if (sc.symbol != NULL) - impl_code_address = sc.symbol->GetAddress(); - - //lldb::addr_t addr = impl_code_address.GetOpcodeLoadAddress (exe_ctx.GetTargetPtr()); - //printf ("Getting address for our_utility_function: 0x%" PRIx64 ".\n", addr); - } - else - { - //printf ("Could not find queues introspection function address.\n"); - return args_addr; - } - } - else if (!m_get_thread_item_info_impl_code.get()) + if (!m_get_thread_item_info_impl_code.get()) { + Error error; if (g_get_thread_item_info_function_code != NULL) { - m_get_thread_item_info_impl_code.reset (new ClangUtilityFunction (g_get_thread_item_info_function_code, - g_get_thread_item_info_function_name)); + m_get_thread_item_info_impl_code.reset (exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage (g_get_thread_item_info_function_code, + eLanguageTypeC, + g_get_thread_item_info_function_name, + error)); + if (error.Fail()) + { + if (log) + log->Printf ("Failed to get UtilityFunction for get-thread-item-info introspection: %s.", + error.AsCString()); + m_get_thread_item_info_impl_code.reset(); + return args_addr; + } + if (!m_get_thread_item_info_impl_code->Install(errors, exe_ctx)) { if (log) @@ -203,42 +191,26 @@ AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction (Thread &thread, V return LLDB_INVALID_ADDRESS; } - impl_code_address.Clear(); - impl_code_address.SetOffset(m_get_thread_item_info_impl_code->StartAddress()); - } - else - { - impl_code_address.Clear(); - impl_code_address.SetOffset(m_get_thread_item_info_impl_code->StartAddress()); - } - - // Next make the runner function for our implementation utility function. - if (!m_get_thread_item_info_function.get()) - { + // Also make the FunctionCaller for this UtilityFunction: + ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext(); CompilerType get_thread_item_info_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - m_get_thread_item_info_function.reset(new ClangFunction (thread, - get_thread_item_info_return_type, - impl_code_address, - get_thread_item_info_arglist, - "queue-thread-item-info")); - errors.Clear(); - unsigned num_errors = m_get_thread_item_info_function->CompileFunction(errors); - if (num_errors) + get_thread_item_info_caller = m_get_thread_item_info_impl_code->MakeFunctionCaller (get_thread_item_info_return_type, + get_thread_item_info_arglist, + error); + if (error.Fail()) { if (log) - log->Printf ("Error compiling get-thread-item-info function: \"%s\".", errors.GetData()); + log->Printf ("Failed to install get-thread-item-info introspection caller: %s.", error.AsCString()); + m_get_thread_item_info_impl_code.reset(); return args_addr; } - errors.Clear(); - if (!m_get_thread_item_info_function->WriteFunctionWrapper(exe_ctx, errors)) - { - if (log) - log->Printf ("Error Inserting get-thread-item-info function: \"%s\".", errors.GetData()); - return args_addr; - } + } + else + { + get_thread_item_info_caller = m_get_thread_item_info_impl_code->GetFunctionCaller(); } } @@ -248,7 +220,7 @@ AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction (Thread &thread, V // if other threads were calling into here, but actually it isn't because we allocate a new args structure for // this call by passing args_addr = LLDB_INVALID_ADDRESS... - if (!m_get_thread_item_info_function->WriteFunctionArguments (exe_ctx, args_addr, impl_code_address, get_thread_item_info_arglist, errors)) + if (!get_thread_item_info_caller->WriteFunctionArguments (exe_ctx, args_addr, get_thread_item_info_arglist, errors)) { if (log) log->Printf ("Error writing get-thread-item-info function arguments: \"%s\".", errors.GetData()); @@ -360,6 +332,8 @@ AppleGetThreadItemInfoHandler::GetThreadItemInfo (Thread &thread, tid_t thread_i StreamString errors; ExecutionContext exe_ctx; EvaluateExpressionOptions options; + FunctionCaller *get_thread_item_info_caller = nullptr; + options.SetUnwindOnError (true); options.SetIgnoreBreakpoints (true); options.SetStopOthers (true); @@ -367,16 +341,23 @@ AppleGetThreadItemInfoHandler::GetThreadItemInfo (Thread &thread, tid_t thread_i options.SetTryAllThreads (false); thread.CalculateExecutionContext (exe_ctx); - if (m_get_thread_item_info_function == NULL) + if (!m_get_thread_item_info_impl_code) { error.SetErrorString ("Unable to compile function to call __introspection_dispatch_thread_get_item_info"); return return_value; } + get_thread_item_info_caller = m_get_thread_item_info_impl_code->GetFunctionCaller(); + + if (!get_thread_item_info_caller) + { + error.SetErrorString ("Unable to compile function caller for __introspection_dispatch_thread_get_item_info"); + return return_value; + } ExpressionResults func_call_ret; Value results; - func_call_ret = m_get_thread_item_info_function->ExecuteFunction (exe_ctx, &args_addr, options, errors, results); + func_call_ret = get_thread_item_info_caller->ExecuteFunction (exe_ctx, &args_addr, options, errors, results); if (func_call_ret != eExpressionCompleted || !error.Success()) { if (log) diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h index 6ced39ae851..c1798fb515b 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h @@ -18,11 +18,10 @@ // Project includes #include "lldb/lldb-public.h" #include "lldb/Core/Error.h" -#include "lldb/Expression/ClangFunction.h" #include "lldb/Host/Mutex.h" #include "lldb/Symbol/CompilerType.h" -// This class will insert a ClangUtilityFunction into the inferior process for +// This class will insert a UtilityFunction into the inferior process for // calling libBacktraceRecording's __introspection_dispatch_thread_get_item_info() // function. The function in the inferior will return a struct by value // with these members: @@ -37,7 +36,7 @@ // space (item_buffer_size in size) which must be mach_vm_deallocate'd by // lldb. // -// The AppleGetThreadItemInfoHandler object should persist so that the ClangUtilityFunction +// The AppleGetThreadItemInfoHandler object should persist so that the UtilityFunction // can be reused multiple times. namespace lldb_private @@ -101,8 +100,7 @@ private: static const char *g_get_thread_item_info_function_code; lldb_private::Process *m_process; - std::unique_ptr<ClangFunction> m_get_thread_item_info_function; - std::unique_ptr<ClangUtilityFunction> m_get_thread_item_info_impl_code; + std::unique_ptr<UtilityFunction> m_get_thread_item_info_impl_code; Mutex m_get_thread_item_info_function_mutex; lldb::addr_t m_get_thread_item_info_return_buffer_addr; diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp index 90271f29c71..11b47df87d0 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp @@ -17,8 +17,6 @@ #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamString.h" -#include "lldb/Expression/ClangFunction.h" -#include "lldb/Expression/ClangUtilityFunction.h" #include "lldb/Host/FileSpec.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ObjectFile.h" diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index b7157bd9aac..ccff1c19431 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -69,14 +69,20 @@ #include "lldb/Core/ThreadSafeDenseMap.h" #include "lldb/Core/UniqueCStringMap.h" #include "lldb/Expression/ASTDumper.h" +#include "lldb/Expression/ASTResultSynthesizer.h" +#include "lldb/Expression/ClangExpressionDeclMap.h" +#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Expression/ClangFunctionCaller.h" +#include "lldb/Expression/ClangUtilityFunction.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" #include "lldb/Symbol/ClangExternalASTSourceCommon.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/VerifyDecl.h" #include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/Process.h" #include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" #include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" @@ -8942,3 +8948,49 @@ ClangASTContext::DeclContextGetClangASTContext (const CompilerDeclContext &dc) return nullptr; } +ClangASTContextForExpressions::ClangASTContextForExpressions (Target &target) : + ClangASTContext (target.GetArchitecture().GetTriple().getTriple().c_str()), + m_target_wp(target.shared_from_this()) +{ +} + +UserExpression * +ClangASTContextForExpressions::GetUserExpression (const char *expr, + const char *expr_prefix, + lldb::LanguageType language, + Expression::ResultType desired_type) +{ + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return nullptr; + + return new ClangUserExpression(*target_sp.get(), expr, expr_prefix, language, desired_type); +} + +FunctionCaller * +ClangASTContextForExpressions::GetFunctionCaller (const CompilerType &return_type, + const Address& function_address, + const ValueList &arg_value_list, + const char *name) +{ + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return nullptr; + + Process *process = target_sp->GetProcessSP().get(); + if (!process) + return nullptr; + + return new ClangFunctionCaller (*process, return_type, function_address, arg_value_list, name); +} + +UtilityFunction * +ClangASTContextForExpressions::GetUtilityFunction (const char *text, + const char *name) +{ + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return nullptr; + + return new ClangUtilityFunction(*target_sp.get(), text, name); +} diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 0fd8d53a24e..e2bb2e48c41 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -18,7 +18,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamFile.h" -#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Expression/UserExpression.h" #include "lldb/Expression/IRDynamicChecks.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Host.h" @@ -1917,6 +1917,7 @@ Process::LoadImage (const FileSpec &image_spec, Error &error) expr_options.SetIgnoreBreakpoints(true); expr_options.SetExecutionPolicy(eExecutionPolicyAlways); expr_options.SetResultIsInternal(true); + expr_options.SetLanguage(eLanguageTypeC_plus_plus); StreamString expr; expr.Printf(R"( @@ -1939,12 +1940,12 @@ Process::LoadImage (const FileSpec &image_spec, Error &error) )"; lldb::ValueObjectSP result_valobj_sp; Error expr_error; - ClangUserExpression::Evaluate (exe_ctx, - expr_options, - expr.GetData(), - prefix, - result_valobj_sp, - expr_error); + UserExpression::Evaluate (exe_ctx, + expr_options, + expr.GetData(), + prefix, + result_valobj_sp, + expr_error); if (expr_error.Success()) { error = result_valobj_sp->GetError(); @@ -2044,17 +2045,19 @@ Process::UnloadImage (uint32_t image_token) expr_options.SetUnwindOnError(true); expr_options.SetIgnoreBreakpoints(true); expr_options.SetExecutionPolicy(eExecutionPolicyAlways); + expr_options.SetLanguage(eLanguageTypeC_plus_plus); + StreamString expr; expr.Printf("dlclose ((void *)0x%" PRIx64 ")", image_addr); const char *prefix = "extern \"C\" int dlclose(void* handle);\n"; lldb::ValueObjectSP result_valobj_sp; Error expr_error; - ClangUserExpression::Evaluate (exe_ctx, - expr_options, - expr.GetData(), - prefix, - result_valobj_sp, - expr_error); + UserExpression::Evaluate (exe_ctx, + expr_options, + expr.GetData(), + prefix, + result_valobj_sp, + expr_error); if (result_valobj_sp->GetError().Success()) { Scalar scalar; diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 00fd79aa8fd..fc1cb9af238 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -23,7 +23,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/ValueObject.h" -#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Expression/UserExpression.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" @@ -770,12 +770,13 @@ protected: expr_options.SetIgnoreBreakpoints(true); ValueObjectSP result_value_sp; Error error; - result_code = ClangUserExpression::Evaluate (exe_ctx, - expr_options, - wp_sp->GetConditionText(), - NULL, - result_value_sp, - error); + result_code = UserExpression::Evaluate (exe_ctx, + expr_options, + wp_sp->GetConditionText(), + NULL, + result_value_sp, + error); + if (result_code == eExpressionCompleted) { if (result_value_sp) diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index aca6605f2af..993706fa889 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -33,7 +33,7 @@ #include "lldb/Core/ValueObject.h" #include "lldb/Expression/ClangASTSource.h" #include "lldb/Expression/ClangPersistentVariables.h" -#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Expression/UserExpression.h" #include "lldb/Expression/ClangModulesDeclVendor.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" @@ -46,6 +46,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Language.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" @@ -1891,13 +1892,95 @@ Target::ImageSearchPathsChanged target->SetExecutableModule (exe_module_sp, true); } +TypeSystem * +Target::GetScratchTypeSystemForLanguage (lldb::LanguageType language, bool create_on_demand) +{ + if (Language::LanguageIsC(language) + || Language::LanguageIsObjC(language) + || Language::LanguageIsCPlusPlus(language) + || language == eLanguageTypeUnknown) + return GetScratchClangASTContext(create_on_demand); + else + return NULL; +} + +UserExpression * +Target::GetUserExpressionForLanguage(const char *expr, + const char *expr_prefix, + lldb::LanguageType language, + Expression::ResultType desired_type, + Error &error) +{ + TypeSystem *type_system = GetScratchTypeSystemForLanguage (language); + UserExpression *user_expr = nullptr; + + if (!type_system) + { + error.SetErrorStringWithFormat("Could not find type system for language: %s", Language::GetNameForLanguageType(language)); + return nullptr; + } + + user_expr = type_system->GetUserExpression(expr, expr_prefix, language, desired_type); + if (!user_expr) + error.SetErrorStringWithFormat("Could not create an expression for language %s", Language::GetNameForLanguageType(language)); + + return user_expr; +} + +FunctionCaller * +Target::GetFunctionCallerForLanguage (lldb::LanguageType language, + const CompilerType &return_type, + const Address& function_address, + const ValueList &arg_value_list, + const char *name, + Error &error) +{ + TypeSystem *type_system = GetScratchTypeSystemForLanguage (language); + FunctionCaller *persistent_fn = nullptr; + + if (!type_system) + { + error.SetErrorStringWithFormat("Could not find type system for language: %s", Language::GetNameForLanguageType(language)); + return persistent_fn; + } + + persistent_fn = type_system->GetFunctionCaller (return_type, function_address, arg_value_list, name); + if (!persistent_fn) + error.SetErrorStringWithFormat("Could not create an expression for language %s", Language::GetNameForLanguageType(language)); + + return persistent_fn; +} + +UtilityFunction * +Target::GetUtilityFunctionForLanguage (const char *text, + lldb::LanguageType language, + const char *name, + Error &error) +{ + TypeSystem *type_system = GetScratchTypeSystemForLanguage (language); + UtilityFunction *utility_fn = nullptr; + + if (!type_system) + { + error.SetErrorStringWithFormat("Could not find type system for language: %s", Language::GetNameForLanguageType(language)); + return utility_fn; + } + + utility_fn = type_system->GetUtilityFunction (text, name); + if (!utility_fn) + error.SetErrorStringWithFormat("Could not create an expression for language %s", Language::GetNameForLanguageType(language)); + + return utility_fn; +} + + ClangASTContext * Target::GetScratchClangASTContext(bool create_on_demand) { // Now see if we know the target triple, and if so, create our scratch AST context: if (m_scratch_ast_context_ap.get() == NULL && m_arch.IsValid() && create_on_demand) { - m_scratch_ast_context_ap.reset (new ClangASTContext(m_arch.GetTriple().str().c_str())); + m_scratch_ast_context_ap.reset (new ClangASTContextForExpressions(*this)); m_scratch_ast_source_ap.reset (new ClangASTSource(shared_from_this())); m_scratch_ast_source_ap->InstallASTContext(m_scratch_ast_context_ap->getASTContext()); llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> proxy_ast_source(m_scratch_ast_source_ap->CreateProxy()); @@ -1906,27 +1989,6 @@ Target::GetScratchClangASTContext(bool create_on_demand) return m_scratch_ast_context_ap.get(); } -TypeSystem* -Target::GetTypeSystemForLanguage (lldb::LanguageType language) -{ - switch (language) - { - case lldb::eLanguageTypeC: - case lldb::eLanguageTypeC11: - case lldb::eLanguageTypeC89: - case lldb::eLanguageTypeC99: - case lldb::eLanguageTypeC_plus_plus: - case lldb::eLanguageTypeC_plus_plus_03: - case lldb::eLanguageTypeC_plus_plus_11: - case lldb::eLanguageTypeC_plus_plus_14: - case lldb::eLanguageTypeObjC: - case lldb::eLanguageTypeObjC_plus_plus: - return GetScratchClangASTContext(true); - default: - return nullptr; - } -} - ClangASTImporter * Target::GetClangASTImporter() { @@ -2067,12 +2129,12 @@ Target::EvaluateExpression { const char *prefix = GetExpressionPrefixContentsAsCString(); Error error; - execution_results = ClangUserExpression::Evaluate (exe_ctx, - options, - expr_cstr, - prefix, - result_valobj_sp, - error); + execution_results = UserExpression::Evaluate (exe_ctx, + options, + expr_cstr, + prefix, + result_valobj_sp, + error); } m_suppress_stop_hooks = old_suppress_value; diff --git a/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/lldb/source/Target/ThreadPlanCallUserExpression.cpp index 3ec3284afb4..b24f74b10df 100644 --- a/lldb/source/Target/ThreadPlanCallUserExpression.cpp +++ b/lldb/source/Target/ThreadPlanCallUserExpression.cpp @@ -19,7 +19,7 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Log.h" #include "lldb/Core/Stream.h" -#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Expression/UserExpression.h" #include "lldb/Expression/IRDynamicChecks.h" #include "lldb/Host/HostInfo.h" #include "lldb/Target/LanguageRuntime.h" @@ -41,7 +41,7 @@ ThreadPlanCallUserExpression::ThreadPlanCallUserExpression (Thread &thread, Address &function, llvm::ArrayRef<lldb::addr_t> args, const EvaluateExpressionOptions &options, - lldb::ClangUserExpressionSP &user_expression_sp) : + lldb::UserExpressionSP &user_expression_sp) : ThreadPlanCallFunction (thread, function, CompilerType(), args, options), m_user_expression_sp (user_expression_sp) { |