diff options
23 files changed, 2288 insertions, 1535 deletions
diff --git a/lldb/include/lldb/Core/ClangForward.h b/lldb/include/lldb/Core/ClangForward.h index ab5166fc09d..4c6722973fd 100644 --- a/lldb/include/lldb/Core/ClangForward.h +++ b/lldb/include/lldb/Core/ClangForward.h @@ -25,6 +25,7 @@ namespace clang } class Action; + class ASTConsumer; class ASTContext; class ASTRecordLayout; class AddrLabelExpr; @@ -52,6 +53,7 @@ namespace clang class DiagnosticOptions; class EnumDecl; class Expr; + class ExternalASTSource; class ExtVectorElementExpr; class FieldDecl; class FloatingLiteral; diff --git a/lldb/include/lldb/Expression/ClangResultSynthesizer.h b/lldb/include/lldb/Expression/ASTResultSynthesizer.h index 3b24061046e..9953ec8bc90 100644 --- a/lldb/include/lldb/Expression/ClangResultSynthesizer.h +++ b/lldb/include/lldb/Expression/ASTResultSynthesizer.h @@ -1,4 +1,4 @@ -//===-- ClangResultSynthesizer.h --------------------------------*- C++ -*-===// +//===-- ASTResultSynthesizer.h ----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangResultSynthesizer_h_ -#define liblldb_ClangResultSynthesizer_h_ +#ifndef liblldb_ASTResultSynthesizer_h_ +#define liblldb_ASTResultSynthesizer_h_ #include "clang/Sema/SemaConsumer.h" #include "lldb/Core/ClangForward.h" @@ -16,7 +16,7 @@ namespace lldb_private { //---------------------------------------------------------------------- -/// @class ClangResultSynthesizer ClangResultSynthesizer.h "lldb/Expression/ClangResultSynthesizer.h" +/// @class ASTResultSynthesizer ASTResultSynthesizer.h "lldb/Expression/ASTResultSynthesizer.h" /// @brief Adds a result variable declaration to the ASTs for an expression. /// /// Users expect the expression "i + 3" to return a result, even if a result @@ -24,11 +24,11 @@ namespace lldb_private { /// a result variable to the expression, transforming it to /// "int ___clang_expr_result = i + 3." The IR transformers ensure that the /// resulting variable is mapped to the right piece of memory. -/// ClangResultSynthesizer's job is to add the variable and its initialization to +/// ASTResultSynthesizer's job is to add the variable and its initialization to /// the ASTs for the expression, and it does so by acting as a SemaConsumer for /// Clang. //---------------------------------------------------------------------- -class ClangResultSynthesizer : public clang::SemaConsumer +class ASTResultSynthesizer : public clang::SemaConsumer { public: //---------------------------------------------------------------------- @@ -40,12 +40,12 @@ public: /// pass to the next step in the chain after processing. Passthrough is /// the next ASTConsumer, or NULL if none is required. //---------------------------------------------------------------------- - ClangResultSynthesizer(clang::ASTConsumer *passthrough); + ASTResultSynthesizer(clang::ASTConsumer *passthrough); //---------------------------------------------------------------------- /// Destructor //---------------------------------------------------------------------- - ~ClangResultSynthesizer(); + ~ASTResultSynthesizer(); //---------------------------------------------------------------------- /// Link this consumer with a particular AST context diff --git a/lldb/include/lldb/Expression/ASTStructExtractor.h b/lldb/include/lldb/Expression/ASTStructExtractor.h new file mode 100644 index 00000000000..4e344d9ac17 --- /dev/null +++ b/lldb/include/lldb/Expression/ASTStructExtractor.h @@ -0,0 +1,156 @@ +//===-- ASTStructExtractor.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_ASTStructExtractor_h_ +#define liblldb_ASTStructExtractor_h_ + +#include "clang/Sema/SemaConsumer.h" +#include "lldb/Core/ClangForward.h" +#include "lldb/Expression/ClangExpressionVariable.h" +#include "lldb/Expression/ClangFunction.h" + +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 +/// sets of arguments. To avoid having to implement the full calling convention +/// for the target's architecture, ClangFunction 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. +/// +/// The definition of this struct is itself in the body of the wrapper function, +/// so Clang does the structure layout itself. ASTStructExtractor reads through +/// the AST for the wrapper funtion and finds the struct. +//---------------------------------------------------------------------- +class ASTStructExtractor : public clang::SemaConsumer +{ +public: + //---------------------------------------------------------------------- + /// Constructor + /// + /// @param[in] passthrough + /// Since the ASTs must typically go through to the Clang code generator + /// in order to produce LLVM IR, this SemaConsumer must allow them to + /// pass to the next step in the chain after processing. Passthrough is + /// the next ASTConsumer, or NULL if none is required. + /// + /// @param[in] struct_name + /// The name of the structure to extract from the wrapper function. + /// + /// @param[in] function + /// The caller object whose members should be populated with information + /// about the argument struct. ClangFunction friends ASTStructExtractor + /// for this purpose. + //---------------------------------------------------------------------- + ASTStructExtractor(clang::ASTConsumer *passthrough, + const char *struct_name, + ClangFunction &function); + + //---------------------------------------------------------------------- + /// Destructor + //---------------------------------------------------------------------- + ~ASTStructExtractor(); + + //---------------------------------------------------------------------- + /// Link this consumer with a particular AST context + /// + /// @param[in] Context + /// This AST context will be used for types and identifiers, and also + /// forwarded to the passthrough consumer, if one exists. + //---------------------------------------------------------------------- + void Initialize(clang::ASTContext &Context); + + //---------------------------------------------------------------------- + /// Examine a list of Decls to find the function ___clang_expr and + /// transform its code + /// + /// @param[in] D + /// The list of Decls to search. These may contain LinkageSpecDecls, + /// which need to be searched recursively. That job falls to + /// TransformTopLevelDecl. + //---------------------------------------------------------------------- + void HandleTopLevelDecl(clang::DeclGroupRef D); + + //---------------------------------------------------------------------- + /// Passthrough stub + //---------------------------------------------------------------------- + void HandleTranslationUnit(clang::ASTContext &Ctx); + + //---------------------------------------------------------------------- + /// Passthrough stub + //---------------------------------------------------------------------- + void HandleTagDeclDefinition(clang::TagDecl *D); + + //---------------------------------------------------------------------- + /// Passthrough stub + //---------------------------------------------------------------------- + void CompleteTentativeDefinition(clang::VarDecl *D); + + //---------------------------------------------------------------------- + /// Passthrough stub + //---------------------------------------------------------------------- + void HandleVTable(clang::CXXRecordDecl *RD, bool DefinitionRequired); + + //---------------------------------------------------------------------- + /// Passthrough stub + //---------------------------------------------------------------------- + void PrintStats(); + + //---------------------------------------------------------------------- + /// Set the Sema object to use when performing transforms, and pass it on + /// + /// @param[in] S + /// The Sema to use. Because Sema isn't externally visible, this class + /// casts it to an Action for actual use. + //---------------------------------------------------------------------- + void InitializeSema(clang::Sema &S); + + //---------------------------------------------------------------------- + /// Reset the Sema to NULL now that transformations are done + //---------------------------------------------------------------------- + void ForgetSema(); +private: + //---------------------------------------------------------------------- + /// Hunt the given FunctionDecl for the argument struct and place + /// information about it into m_function + /// + /// @param[in] F + /// The FunctionDecl to hunt. + //---------------------------------------------------------------------- + void + ExtractFromFunctionDecl(clang::FunctionDecl* F); + + //---------------------------------------------------------------------- + /// Hunt the given Decl for FunctionDecls named the same as the wrapper + /// function name, recursing as necessary through LinkageSpecDecls, and + /// calling ExtractFromFunctionDecl on anything that was found + /// + /// @param[in] D + /// The Decl to hunt. + //---------------------------------------------------------------------- + void + ExtractFromTopLevelDecl(clang::Decl* D); + + clang::ASTContext *m_ast_context; ///< The AST context to use for identifiers and types. + clang::ASTConsumer *m_passthrough; ///< The ASTConsumer down the chain, for passthrough. NULL if it's a SemaConsumer. + clang::SemaConsumer *m_passthrough_sema; ///< The SemaConsumer down the chain, for passthrough. NULL if it's an ASTConsumer. + 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. + std::string m_struct_name; ///< The name of the structure to extract. +}; + +} + +#endif
\ No newline at end of file diff --git a/lldb/include/lldb/Expression/ClangExpression.h b/lldb/include/lldb/Expression/ClangExpression.h index e222fd011b7..176167889a0 100644 --- a/lldb/include/lldb/Expression/ClangExpression.h +++ b/lldb/include/lldb/Expression/ClangExpression.h @@ -25,12 +25,6 @@ #include "lldb/Core/ClangForward.h" #include "llvm/ExecutionEngine/JITMemoryManager.h" -namespace llvm -{ - class ExecutionEngine; - class StringRef; -} - namespace lldb_private { class RecordingMemoryManager; @@ -48,245 +42,51 @@ class ClangExpression { public: //------------------------------------------------------------------ - /// Constructor - /// - /// Initializes class variabes. - /// - /// @param[in] target_triple - /// The LLVM-friendly target triple for use in initializing the - /// compiler. - /// - /// @param[in] expr_decl_map - /// The object that looks up externally-defined names in LLDB's - /// debug information. - //------------------------------------------------------------------ - ClangExpression(const char *target_triple, - ClangExpressionDeclMap *expr_decl_map); - - //------------------------------------------------------------------ - /// Destructor + /// Return the string that the parser should parse. Must be a full + /// translation unit. //------------------------------------------------------------------ - ~ClangExpression(); + virtual const char * + Text () = 0; //------------------------------------------------------------------ - /// Parse a single expression and convert it to IR using Clang. Wrap - /// the expression in a function with signature void ___clang_expr(void*). - /// - /// @param[in] expr_text - /// The text of the expression to be parsed. - /// - /// @param[in] stream - /// The stream to print errors to. - /// - /// @param[in] add_result_var - /// True if a special result variable should be generated for - /// the expression. - /// - /// @return - /// The number of errors encountered during parsing. 0 means - /// success. - //------------------------------------------------------------------ - unsigned - ParseExpression (const char *expr_text, - Stream &stream, - bool add_result_var = false); - - //------------------------------------------------------------------ - /// Parse a single expression and convert it to IR using Clang. Don't - /// wrap the expression in anything at all. - /// - /// @param[in] expr_text - /// The text of the expression to be parsed. - /// - /// @param[in] stream - /// The stream to print errors to. - /// - /// @param[in] add_result_var - /// True if a special result variable should be generated for - /// the expression. - /// - /// @return - /// The number of errors encountered during parsing. 0 means - /// success. + /// Return the function name that should be used for executing the + /// expression. Text() should contain the definition of this + /// function. //------------------------------------------------------------------ - unsigned - ParseBareExpression (llvm::StringRef expr_text, - Stream &stream, - bool add_result_var = false); + virtual const char * + FunctionName () = 0; //------------------------------------------------------------------ - /// Convert the IR for an already-parsed expression to DWARF if possible. - /// - /// @param[in] expr_local_variable_list - /// The list of local variables the expression uses, with types, for - /// use by the DWARF parser. - /// - /// @param[in] dwarf_opcode_strm - /// The stream to place the resulting DWARF code into. - /// - /// @return - /// True on success; false on failure. On failure, it may be appropriate - /// to call PrepareIRForTarget(). + /// Return the object that the parser should use when resolving external + /// values. May be NULL if everything should be self-contained. //------------------------------------------------------------------ - bool - ConvertIRToDWARF (ClangExpressionVariableList &excpr_local_variable_list, - StreamString &dwarf_opcode_strm); + virtual ClangExpressionDeclMap * + DeclMap () = 0; //------------------------------------------------------------------ - /// Prepare the IR for an already-parsed expression for execution in the - /// target process by (among other things) making all externally-defined - /// variables point to offsets from the void* argument. - /// - /// @return - /// True on success; false on failure. On failure, this expression - /// cannot be executed by LLDB. - //------------------------------------------------------------------ - bool - PrepareIRForTarget (); - - //------------------------------------------------------------------ - /// Use the JIT to compile an already-prepared expression from IR into - /// machine code, but keep the code in the current process for now. - /// - /// @param[in] func_name - /// The name of the function to be JITted. By default, the function - /// wrapped by ParseExpression(). - /// - /// @return - /// True on success; false otherwise. - //------------------------------------------------------------------ - bool - JITFunction (const char *func_name = "___clang_expr"); - - //------------------------------------------------------------------ - /// Write the machine code generated by the JIT into the target's memory. - /// - /// @param[in] exc_context - /// The execution context that the JITted code must be copied into. - /// - /// @return - /// True on success; false otherwise. - //------------------------------------------------------------------ - bool - WriteJITCode (const ExecutionContext &exc_context); - - //------------------------------------------------------------------ - /// Write the machine code generated by the JIT into the target process. - /// - /// @param[in] func_name - /// The name of the function whose address is being requested. - /// By default, the function wrapped by ParseExpression(). - /// - /// @return - /// True on success; false otherwise. + /// Return the object that the parser should use when registering + /// local variables. May be NULL if the Expression doesn't care. //------------------------------------------------------------------ - lldb::addr_t - GetFunctionAddress (const char *func_name = "___clang_expr"); + virtual ClangExpressionVariableStore * + LocalVariables () = 0; //------------------------------------------------------------------ - /// 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. - /// - /// @param[in] func_name - /// The name of the function to be disassembled. By default, the - /// function wrapped by ParseExpression(). - /// - /// @return - /// The error generated. If .Success() is true, disassembly succeeded. - //------------------------------------------------------------------ - Error - DisassembleFunction (Stream &stream, ExecutionContext &exc_context, const char *func_name = "___clang_expr"); - - //------------------------------------------------------------------ - /// Return the Clang compiler instance being used by this expression. - //------------------------------------------------------------------ - clang::CompilerInstance * - GetCompilerInstance () - { - return m_clang_ap.get(); - } - - //------------------------------------------------------------------ - /// Return the AST context being used by this expression. - //------------------------------------------------------------------ - clang::ASTContext * - GetASTContext (); - - //------------------------------------------------------------------ - /// Return the mutex being used to serialize access to Clang. - //------------------------------------------------------------------ - static Mutex & - GetClangMutex (); -protected: - //------------------------------------------------------------------ - // Classes that inherit from ClangExpression can see and modify these - //------------------------------------------------------------------ - - //---------------------------------------------------------------------- - /// @class JittedFunction ClangExpression.h "lldb/Expression/ClangExpression.h" - /// @brief Encapsulates a single function that has been generated by the JIT. + /// Return the object that the parser should allow to access ASTs. + /// May be NULL if the ASTs do not need to be transformed. /// - /// Functions that have been generated by the JIT are first resident in the - /// local process, and then placed in the target process. JittedFunction - /// represents a function possibly resident in both. - //---------------------------------------------------------------------- - struct JittedFunction { - std::string m_name; ///< The function's name - lldb::addr_t m_local_addr; ///< The address of the function in LLDB's memory - lldb::addr_t m_remote_addr; ///< The address of the function in the target's memory - - //------------------------------------------------------------------ - /// Constructor - /// - /// Initializes class variabes. - /// - /// @param[in] name - /// The name of the function. - /// - /// @param[in] local_addr - /// The address of the function in LLDB, or LLDB_INVALID_ADDRESS if - /// it is not present in LLDB's memory. - /// - /// @param[in] remote_addr - /// The address of the function in the target, or LLDB_INVALID_ADDRESS - /// if it is not present in the target's memory. - //------------------------------------------------------------------ - JittedFunction (const char *name, - lldb::addr_t local_addr = LLDB_INVALID_ADDRESS, - lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) : - m_name (name), - m_local_addr (local_addr), - m_remote_addr (remote_addr) {} - }; - - std::string m_target_triple; ///< The target triple used to initialize LLVM - ClangExpressionDeclMap *m_decl_map; ///< The class used to look up entities defined in the debug info - std::auto_ptr<clang::CompilerInstance> m_clang_ap; ///< The Clang compiler used to parse expressions into IR - clang::CodeGenerator *m_code_generator_ptr; ///< [owned by the Execution Engine] The Clang object that generates IR - RecordingMemoryManager *m_jit_mm_ptr; ///< [owned by the Execution Engine] The memory manager that allocates code pages on the JIT's behalf - std::auto_ptr<llvm::ExecutionEngine> m_execution_engine; ///< The LLVM JIT - std::vector<JittedFunction> m_jitted_functions; ///< A vector of all functions that have been JITted into machine code (just one, if ParseExpression() was called) -private: + /// @param[in] passthrough + /// The ASTConsumer that the returned transformer should send + /// the ASTs to after transformation. //------------------------------------------------------------------ - /// Initialize m_clang_ap to a compiler instance with all the options - /// required by the expression parser. - /// - /// @return - /// True on success; false otherwise. - //------------------------------------------------------------------ - bool CreateCompilerInstance(); - + virtual clang::ASTConsumer * + ASTTransformer (clang::ASTConsumer *passthrough) = 0; + //------------------------------------------------------------------ - // For ClangExpression only + /// Return the stream that the parser should use to write DWARF + /// opcodes. //------------------------------------------------------------------ - ClangExpression(const ClangExpression&); - const ClangExpression& operator=(const ClangExpression&); + virtual StreamString & + DwarfOpcodeStream () = 0; }; } // namespace lldb_private diff --git a/lldb/include/lldb/Expression/ClangExpressionParser.h b/lldb/include/lldb/Expression/ClangExpressionParser.h new file mode 100644 index 00000000000..63bd4cd66aa --- /dev/null +++ b/lldb/include/lldb/Expression/ClangExpressionParser.h @@ -0,0 +1,182 @@ +//===-- ClangExpressionParser.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_ClangExpressionParser_h_ +#define liblldb_ClangExpressionParser_h_ + +#include "lldb/lldb-include.h" +#include "lldb/Core/ClangForward.h" +#include "lldb/Core/Error.h" + +#include <string> +#include <vector> + +namespace llvm +{ + class ExecutionEngine; +} + +namespace lldb_private +{ + +class RecordingMemoryManager; + +//---------------------------------------------------------------------- +/// @class ClangExpressionParser ClangExpressionParser.h "lldb/Expression/ClangExpressionParser.h" +/// @brief Encapsulates an instance of Clang that can parse expressions. +/// +/// ClangExpressionParser is responsible for preparing an instance of +/// ClangExpression for execution. ClangExpressionParser uses ClangExpression +/// as a glorified parameter list, performing the required parsing and +/// conversion to formats (DWARF bytecode, or JIT compiled machine code) +/// that can be executed. +//---------------------------------------------------------------------- +class ClangExpressionParser +{ +public: + //------------------------------------------------------------------ + /// Constructor + /// + /// Initializes class variabes. + /// + /// @param[in] target_triple + /// The LLVM-friendly target triple for use in initializing the + /// compiler. + /// + /// @param[in] expr + /// The expression to be parsed. + //------------------------------------------------------------------ + ClangExpressionParser (const char *target_triple, + ClangExpression &expr); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~ClangExpressionParser (); + + //------------------------------------------------------------------ + /// 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. + //------------------------------------------------------------------ + unsigned + Parse (Stream &stream); + + //------------------------------------------------------------------ + /// Convert the IR for an already-parsed expression to DWARF if possible. + /// + /// @param[in] dwarf_opcode_strm + /// The stream to place the resulting DWARF code into. + /// + /// @return + /// An error code indicating the success or failure of the operation. + /// Test with Success(). + //------------------------------------------------------------------ + Error + MakeDWARF (); + + //------------------------------------------------------------------ + /// JIT-compile the IR for an already-parsed expression. + /// + /// @param[out] func_addr + /// The address to which the function has been written. + /// + /// @para[in] exe_ctx + /// The execution context to write the function into. + /// + /// @return + /// An error code indicating the success or failure of the operation. + /// Test with Success(). + //------------------------------------------------------------------ + Error + MakeJIT (lldb::addr_t &func_addr, + ExecutionContext &exe_ctx); + + //------------------------------------------------------------------ + /// 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. + /// + /// @param[in] func_name + /// The name of the function to be disassembled. By default, the + /// function wrapped by ParseExpression(). + /// + /// @return + /// The error generated. If .Success() is true, disassembly succeeded. + //------------------------------------------------------------------ + Error + DisassembleFunction (Stream &stream, ExecutionContext &exc_context); + +private: + //---------------------------------------------------------------------- + /// @class JittedFunction ClangExpressionParser.h "lldb/Expression/ClangExpressionParser.h" + /// @brief Encapsulates a single function that has been generated by the JIT. + /// + /// Functions that have been generated by the JIT are first resident in the + /// local process, and then placed in the target process. JittedFunction + /// represents a function possibly resident in both. + //---------------------------------------------------------------------- + struct JittedFunction { + std::string m_name; ///< The function's name + lldb::addr_t m_local_addr; ///< The address of the function in LLDB's memory + lldb::addr_t m_remote_addr; ///< The address of the function in the target's memory + + //------------------------------------------------------------------ + /// Constructor + /// + /// Initializes class variabes. + /// + /// @param[in] name + /// The name of the function. + /// + /// @param[in] local_addr + /// The address of the function in LLDB, or LLDB_INVALID_ADDRESS if + /// it is not present in LLDB's memory. + /// + /// @param[in] remote_addr + /// The address of the function in the target, or LLDB_INVALID_ADDRESS + /// if it is not present in the target's memory. + //------------------------------------------------------------------ + JittedFunction (const char *name, + lldb::addr_t local_addr = LLDB_INVALID_ADDRESS, + lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) : + m_name (name), + m_local_addr (local_addr), + m_remote_addr (remote_addr) + { + } + }; + + ClangExpression &m_expr; ///< The expression to be parsed + + std::string m_target_triple; ///< The target triple used to initialize LLVM + std::auto_ptr<clang::TextDiagnosticBuffer> m_diagnostic_buffer; ///< The container for errors produced by the compiler + std::auto_ptr<clang::CompilerInstance> m_compiler; ///< The Clang compiler used to parse expressions into IR + std::auto_ptr<clang::Builtin::Context> m_builtin_context; ///< Context for Clang built-ins + std::auto_ptr<clang::ASTContext> m_ast_context; ///< The AST context used to hold types and names for the parser + std::auto_ptr<clang::CodeGenerator> m_code_generator; ///< [owned by the Execution Engine] The Clang object that generates IR + RecordingMemoryManager *m_jit_mm; ///< The memory manager for the LLVM JIT + std::auto_ptr<llvm::ExecutionEngine> m_execution_engine; ///< The LLVM JIT + std::vector<JittedFunction> m_jitted_functions; ///< A vector of all functions that have been JITted into machine code (just one, if ParseExpression() was called) +}; + +} + +#endif // liblldb_ClangExpressionParser_h_ diff --git a/lldb/include/lldb/Expression/ClangFunction.h b/lldb/include/lldb/Expression/ClangFunction.h index 1ee55a79c81..b49a7b411b1 100644 --- a/lldb/include/lldb/Expression/ClangFunction.h +++ b/lldb/include/lldb/Expression/ClangFunction.h @@ -20,7 +20,6 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectList.h" - #include "lldb/Expression/ClangExpression.h" // Right now, this is just a toy. It calls a set function, with fixed @@ -28,11 +27,47 @@ namespace lldb_private { + +class ASTStructExtractor; +class ClangExpressionParser; -class ClangFunction : private ClangExpression +//---------------------------------------------------------------------- +/// @class ClangFunction ClangFunction.h "lldb/Expression/ClangFunction.h" +/// @brief Encapsulates a function that can be called. +/// +/// A given ClangFunction 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 ClangFunction 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 ClangFunction : public ClangExpression { + friend class ASTStructExtractor; public: - enum ExecutionResults { eExecutionSetupError, @@ -43,56 +78,200 @@ public: }; //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - // Usage Note: - - // A given ClangFunction object can handle any function with a common signature. It can also be used to - // set up any number of concurrent functions calls once it has been constructed. - // When you construct it you pass in a particular function, information sufficient to determine the function signature - // and value list. - // The simplest use of the ClangFunction is to construct the function, then call ExecuteFunction (context, errors, results). The function - // will be called using the initial arguments, and the results determined for you, and all cleanup done. - // - // However, if you need to use the function caller in Thread Plans, you need to call the function on the plan stack. - // In that case, you call GetThreadPlanToCallFunction, args_addr will be the location of the args struct, and after you are - // done running this thread plan you can recover the results using FetchFunctionResults passing in the same value. - // You are required to call InsertFunction before calling GetThreadPlanToCallFunction. - // - // You can also reuse the struct if you want, by calling ExecuteFunction but passing in args_addr_ptr primed to this value. - // - // You can also reuse the ClangFunction for the same signature but different function or argument values by rewriting the - // Functions arguments with WriteFunctionArguments, and then calling ExecuteFunction passing in the same args_addr. - // - // Note, any of the functions below 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 functions below that take arg_addr_ptr can be passed NULL, and the argument space will be managed for you. - - ClangFunction(const char *target_triple, Function &function_ptr, ClangASTContext *ast_context, const ValueList &arg_value_list); - // This constructor takes its return type as a Clang QualType opaque pointer, and the ast_context it comes from. - // FIXME: We really should be able to easily make a Type from the qualtype, and then just pass that in. - ClangFunction(const char *target_triple, ClangASTContext *ast_context, void *return_qualtype, const Address& functionAddress, const ValueList &arg_value_list); + /// Constructor + /// + /// @param[in] target_triple + /// The LLVM-style target triple for the target in which the + /// function is to be executed. + /// + /// @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(const char *target_triple, + Function &function_ptr, + ClangASTContext *ast_context, + const ValueList &arg_value_list); + + //------------------------------------------------------------------ + /// Constructor + /// + /// @param[in] target_triple + /// The LLVM-style target triple for the target in which the + /// function is to be executed. + /// + /// @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(). + //------------------------------------------------------------------ + ClangFunction(const char *target_triple, + ClangASTContext *ast_context, + void *return_qualtype, + const Address& function_address, + const ValueList &arg_value_list); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ virtual ~ClangFunction(); + //------------------------------------------------------------------ + /// Compile the wrapper function + /// + /// @param[in] errors + /// The stream to print parser errors to. + /// + /// @return + /// The number of errors. + //------------------------------------------------------------------ unsigned CompileFunction (Stream &errors); - // args_addr is a pointer to the address the addr will be filled with. If the value on - // input is LLDB_INVALID_ADDRESS then a new address will be allocated, and returned in args_addr. - // If args_addr is a value already returned from a previous call to InsertFunction, then - // the args structure at that address is overwritten. - // If any other value is returned, then we return false, and do nothing. - bool InsertFunction (ExecutionContext &context, lldb::addr_t &args_addr_ref, Stream &errors); + //------------------------------------------------------------------ + /// Insert the default function wrapper and its default argument struct + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @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] errors + /// The stream to write errors to. + /// + /// @return + /// True on success; false otherwise. + //------------------------------------------------------------------ + bool InsertFunction (ExecutionContext &exe_ctx, + lldb::addr_t &args_addr_ref, + Stream &errors); - bool WriteFunctionWrapper (ExecutionContext &exec_ctx, Stream &errors); + //------------------------------------------------------------------ + /// Insert the default function wrapper (using the JIT) + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @param[in] errors + /// The stream to write errors to. + /// + /// @return + /// True on success; false otherwise. + //------------------------------------------------------------------ + bool WriteFunctionWrapper (ExecutionContext &exe_ctx, + Stream &errors); - // This variant writes down the original function address and values to args_addr. - bool WriteFunctionArguments (ExecutionContext &exec_ctx, lldb::addr_t &args_addr_ref, Stream &errors); + //------------------------------------------------------------------ + /// Insert the default function argument struct + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @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] errors + /// The stream to write errors to. + /// + /// @return + /// True on success; false otherwise. + //------------------------------------------------------------------ + bool WriteFunctionArguments (ExecutionContext &exe_ctx, + lldb::addr_t &args_addr_ref, + Stream &errors); - // This variant writes down function_address and arg_value. - bool WriteFunctionArguments (ExecutionContext &exc_context, lldb::addr_t &args_addr_ref, Address function_address, ValueList &arg_values, Stream &errors); + //------------------------------------------------------------------ + /// Insert an argument struct with a non-default function address and + /// non-default argument values + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @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. + /// + /// @param[in] arg_values + /// The values of the function's arguments. + /// + /// @param[in] errors + /// The stream to write errors to. + /// + /// @return + /// True on success; false otherwise. + //------------------------------------------------------------------ + bool WriteFunctionArguments (ExecutionContext &exe_ctx, + lldb::addr_t &args_addr_ref, + Address function_address, + ValueList &arg_values, + Stream &errors); - // Run a function at a particular address, with a given address passed on the stack. - static ExecutionResults ExecuteFunction (ExecutionContext &exe_ctx, lldb::addr_t function_address, lldb::addr_t &void_arg, bool stop_others, bool try_all_threads, uint32_t single_thread_timeout_usec, Stream &errors); + //------------------------------------------------------------------ + /// [Static] Execute a function, passing it a single void* parameter. + /// ClangFunction uses this to call the wrapper function. + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @param[in] function_address + /// The address of the function in the target process. + /// + /// @param[in] void_arg + /// The value of the void* parameter. + /// + /// @param[in] stop_others + /// True if other threads should pause during execution. + /// + /// @param[in] try_all_threads + /// If the timeout expires, true if other threads should run. If + /// the function may try to take locks, this is useful. + /// + /// @param[in] single_thread_timeout_usec + /// If stop_others is true, the length of time to wait before + /// concluding that the system is deadlocked. + /// + /// @param[in] errors + /// The stream to write errors to. + /// + /// @return + /// Returns one of the ExecutionResults enum indicating function call status. + //------------------------------------------------------------------ + static ExecutionResults ExecuteFunction (ExecutionContext &exe_ctx, + lldb::addr_t function_address, + lldb::addr_t &void_arg, + bool stop_others, + bool try_all_threads, + uint32_t single_thread_timeout_usec, + Stream &errors); //------------------------------------------------------------------ /// Run the function this ClangFunction was created with. @@ -101,7 +280,7 @@ public: /// for a fixed timeout period (1000 usec) and if it does not complete, /// we halt the process and try with all threads running. /// - /// @param[in] context + /// @param[in] exe_ctx /// The thread & process in which this function will run. /// /// @param[in] errors @@ -113,7 +292,9 @@ public: /// @return /// Returns one of the ExecutionResults enum indicating function call status. //------------------------------------------------------------------ - ExecutionResults ExecuteFunction(ExecutionContext &context, Stream &errors, Value &results); + ExecutionResults ExecuteFunction(ExecutionContext &exe_ctx, + Stream &errors, + Value &results); //------------------------------------------------------------------ /// Run the function this ClangFunction was created with. @@ -121,7 +302,7 @@ public: /// This simple version will run the function obeying the stop_others /// argument. There is no timeout. /// - /// @param[in] context + /// @param[in] exe_ctx /// The thread & process in which this function will run. /// /// @param[in] errors @@ -136,7 +317,9 @@ public: /// @return /// Returns one of the ExecutionResults enum indicating function call status. //------------------------------------------------------------------ - ExecutionResults ExecuteFunction(ExecutionContext &exc_context, Stream &errors, bool stop_others, Value &results); + ExecutionResults ExecuteFunction(ExecutionContext &exe_ctx, + Stream &errors, bool stop_others, + Value &results); //------------------------------------------------------------------ /// Run the function this ClangFunction was created with. @@ -145,7 +328,7 @@ public: /// is not zero, we time out after that timeout. If \a try_all_threads is true, then we will /// resume with all threads on, otherwise we halt the process, and eExecutionInterrupted will be returned. /// - /// @param[in] context + /// @param[in] exe_ctx /// The thread & process in which this function will run. /// /// @param[in] errors @@ -163,14 +346,18 @@ public: /// @return /// Returns one of the ExecutionResults enum indicating function call status. //------------------------------------------------------------------ - ExecutionResults ExecuteFunction(ExecutionContext &context, Stream &errors, uint32_t single_thread_timeout_usec, bool try_all_threads, Value &results); + ExecutionResults ExecuteFunction(ExecutionContext &exe_ctx, + Stream &errors, + uint32_t single_thread_timeout_usec, + bool try_all_threads, + Value &results); //------------------------------------------------------------------ /// Run the function this ClangFunction was created with. /// /// This is the full version. /// - /// @param[in] context + /// @param[in] exe_ctx /// The thread & process in which this function will run. /// /// @param[in] args_addr_ptr @@ -198,48 +385,220 @@ public: /// @return /// Returns one of the ExecutionResults enum indicating function call status. //------------------------------------------------------------------ - ExecutionResults ExecuteFunction(ExecutionContext &context, lldb::addr_t *args_addr_ptr, Stream &errors, bool stop_others, uint32_t single_thread_timeout_usec, bool try_all_threads, Value &results); - ExecutionResults ExecuteFunctionWithABI(ExecutionContext &context, Stream &errors, Value &results); - + ExecutionResults ExecuteFunction(ExecutionContext &exe_ctx, + lldb::addr_t *args_addr_ptr, + Stream &errors, + bool stop_others, + uint32_t single_thread_timeout_usec, + bool try_all_threads, + Value &results); + + //------------------------------------------------------------------ + /// [static] Get a thread plan to run a function. + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @param[in] func_addr + /// The address of the function in the target process. + /// + /// @param[in] args_addr_ref + /// The value of the void* parameter. + /// + /// @param[in] errors + /// The stream to write errors to. + /// + /// @param[in] stop_others + /// True if other threads should pause during execution. + /// + /// @param[in] discard_on_error + /// True if the thread plan may simply be discarded if an error occurs. + /// + /// @return + /// A ThreadPlan for executing the function. + //------------------------------------------------------------------ static ThreadPlan * - GetThreadPlanToCallFunction (ExecutionContext &exc_context, lldb::addr_t func_addr, lldb::addr_t &args_addr_ref, Stream &errors, bool stop_others, bool discard_on_error = true); + GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, + lldb::addr_t func_addr, + lldb::addr_t &args_addr_ref, + Stream &errors, + bool stop_others, + bool discard_on_error = true); + //------------------------------------------------------------------ + /// Get a thread plan to run the function this ClangFunction was created with. + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @param[in] func_addr + /// The address of the function in the target process. + /// + /// @param[in] args_addr_ref + /// The value of the void* parameter. + /// + /// @param[in] errors + /// The stream to write errors to. + /// + /// @param[in] stop_others + /// True if other threads should pause during execution. + /// + /// @param[in] discard_on_error + /// True if the thread plan may simply be discarded if an error occurs. + /// + /// @return + /// A ThreadPlan for executing the function. + //------------------------------------------------------------------ ThreadPlan * - GetThreadPlanToCallFunction (ExecutionContext &exc_context, lldb::addr_t &args_addr_ref, Stream &errors, bool stop_others, bool discard_on_error = true) + GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, + lldb::addr_t &args_addr_ref, + Stream &errors, + bool stop_others, + bool discard_on_error = true) { - return ClangFunction::GetThreadPlanToCallFunction (exc_context, m_wrapper_function_addr, args_addr_ref, errors, stop_others, discard_on_error); + return ClangFunction::GetThreadPlanToCallFunction (exe_ctx, + m_wrapper_function_addr, + args_addr_ref, + errors, + stop_others, + discard_on_error); } - bool FetchFunctionResults (ExecutionContext &exc_context, lldb::addr_t args_addr, Value &ret_value); - void DeallocateFunctionResults (ExecutionContext &exc_context, lldb::addr_t args_addr); - -protected: + //------------------------------------------------------------------ - // Classes that inherit from ClangFunction can see and modify these + /// Get the result of the function from its struct + /// + /// @param[in] exe_ctx + /// The execution context to retrieve the result from. + /// + /// @param[in] args_addr + /// The address of the argument struct. + /// + /// @param[in] ret_value + /// The value returned by the function. + /// + /// @return + /// True on success; false otherwise. + //------------------------------------------------------------------ + bool FetchFunctionResults (ExecutionContext &exe_ctx, + lldb::addr_t args_addr, + Value &ret_value); + //------------------------------------------------------------------ - + /// Deallocate the arguments structure + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @param[in] args_addr + /// The address of the argument struct. + //------------------------------------------------------------------ + void DeallocateFunctionResults (ExecutionContext &exe_ctx, + lldb::addr_t args_addr); + + //------------------------------------------------------------------ + /// Interface for ClangExpression + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Return the string that the parser should parse. Must be a full + /// translation unit. + //------------------------------------------------------------------ + const char * + Text () + { + return m_wrapper_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 () + { + return m_wrapper_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 () + { + return NULL; + } + + //------------------------------------------------------------------ + /// Return the object that the parser should use when registering + /// local variables. May be NULL if the Expression doesn't care. + //------------------------------------------------------------------ + ClangExpressionVariableStore * + 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); + + //------------------------------------------------------------------ + /// Return the stream that the parser should use to write DWARF + /// opcodes. + //------------------------------------------------------------------ + StreamString & + DwarfOpcodeStream () + { + return *((StreamString*)0); + } + private: //------------------------------------------------------------------ // For ClangFunction only //------------------------------------------------------------------ + + std::auto_ptr<ClangExpressionParser> m_parser; ///< The parser responsible for compiling the function. - Function *m_function_ptr; // The function we're going to call. May be NULL if we don't have debug info for the function. - Address m_function_addr; // If we don't have the FunctionSP, we at least need the address & return type. - void *m_function_return_qual_type; // The opaque clang qual type for the function return type. - ClangASTContext *m_clang_ast_context; // This is the clang_ast_context that we're getting types from the and value, and the function return the function pointer is NULL. + Function *m_function_ptr; ///< The function we're going to call. May be NULL if we don't have debug info for the function. + Address m_function_addr; ///< If we don't have the FunctionSP, we at least need the address & return type. + void *m_function_return_qual_type; ///< The opaque clang qual type for the function return type. + ClangASTContext *m_clang_ast_context; ///< This is the clang_ast_context that we're getting types from the and value, and the function return the function pointer is NULL. + std::string m_target_triple; ///< The target triple to compile the wrapper function for. - std::string m_wrapper_function_name; - std::string m_wrapper_struct_name; - lldb::addr_t m_wrapper_function_addr; - std::list<lldb::addr_t> m_wrapper_args_addrs; - const clang::ASTRecordLayout *m_struct_layout; - ValueList m_arg_values; - - size_t m_value_struct_size; - size_t m_return_offset; - uint64_t m_return_size; // Not strictly necessary, could get it from the Function... - bool m_compiled; - bool m_JITted; + std::string m_wrapper_function_name; ///< The name of the wrapper function. + std::string m_wrapper_function_text; ///< The contents of the wrapper function. + std::string m_wrapper_struct_name; ///< The name of the struct that contains the target function address, arguments, and result. + lldb::addr_t m_wrapper_function_addr; ///< The address of the wrapper function. + std::list<lldb::addr_t> m_wrapper_args_addrs; ///< The addresses of the arguments to the wrapper function. + + bool m_struct_valid; ///< True if the ASTStructExtractor has populated the variables below. + + //------------------------------------------------------------------ + /// These values are populated by the ASTStructExtractor + size_t m_struct_size; ///< The size of the argument struct, in bytes. + std::vector<uint64_t> m_member_offsets; ///< The offset of each member in the struct, in bytes. + uint64_t m_return_size; ///< The size of the result variable, in bytes. + uint64_t m_return_offset; ///< The offset of the result variable in the struct, in bytes. + //------------------------------------------------------------------ + + ValueList m_arg_values; ///< The default values of the arguments. + + bool m_compiled; ///< True if the wrapper function has already been parsed. + bool m_JITted; ///< True if the wrapper function has already been JIT-compiled. }; } // Namespace lldb_private + #endif // lldb_ClangFunction_h_ diff --git a/lldb/include/lldb/Expression/ClangUserExpression.h b/lldb/include/lldb/Expression/ClangUserExpression.h new file mode 100644 index 00000000000..9dfeb5f9a68 --- /dev/null +++ b/lldb/include/lldb/Expression/ClangUserExpression.h @@ -0,0 +1,160 @@ +//===-- ClangUserExpression.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_ClangUserExpression_h_ +#define liblldb_ClangUserExpression_h_ + +// C Includes +// C++ Includes +#include <string> +#include <map> +#include <memory> +#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/ClangExpression.h" + +#include "llvm/ExecutionEngine/JITMemoryManager.h" + +namespace lldb_private +{ + +//---------------------------------------------------------------------- +/// @class ClangUserExpression ClangUserExpression.h "lldb/Expression/ClangUserExpression.h" +/// @brief Encapsulates a single expression for use with Clang +/// +/// LLDB uses expressions for various purposes, notably to call functions +/// and as a backend for the expr command. ClangUserExpression encapsulates +/// 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 +{ +public: + //------------------------------------------------------------------ + /// Constructor + //------------------------------------------------------------------ + ClangUserExpression (const char *expr); + + //------------------------------------------------------------------ + /// 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.) + /// + /// @return + /// True on success (no errors); false otherwise. + //------------------------------------------------------------------ + bool + Parse (Stream &error_stream, 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] result + /// A pointer to direct at the persistent variable in which the + /// expression's result is stored. + /// + /// @return + /// True on success; false otherwise. + //------------------------------------------------------------------ + bool + Execute (Stream &error_stream, + ExecutionContext &exe_ctx, + ClangExpressionVariable *& result); + + //------------------------------------------------------------------ + /// Return the string that the parser should parse. Must be a full + /// translation unit. + //------------------------------------------------------------------ + const char * + Text () + { + return m_transformed_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 () + { + return "___clang_expr"; + } + + //------------------------------------------------------------------ + /// Return the object that the parser should use when resolving external + /// values. May be NULL if everything should be self-contained. + //------------------------------------------------------------------ + ClangExpressionDeclMap * + DeclMap () + { + return m_expr_decl_map.get(); + } + + //------------------------------------------------------------------ + /// Return the object that the parser should use when registering + /// local variables. May be NULL if the Expression doesn't care. + //------------------------------------------------------------------ + ClangExpressionVariableStore * + LocalVariables () + { + return m_local_variables.get(); + } + + //------------------------------------------------------------------ + /// 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); + + //------------------------------------------------------------------ + /// Return the stream that the parser should use to write DWARF + /// opcodes. + //------------------------------------------------------------------ + StreamString & + DwarfOpcodeStream (); + +private: + std::string m_expr_text; ///< The text of the expression, as typed by the user + std::string m_transformed_text; ///< The text of the expression, as send to the parser + + std::auto_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression. + std::auto_ptr<ClangExpressionVariableStore> m_local_variables; ///< The local expression variables, if the expression is DWARF. + std::auto_ptr<StreamString> m_dwarf_opcodes; ///< The DWARF opcodes for the expression. May be NULL. + lldb::addr_t m_jit_addr; ///< The address of the JITted code. LLDB_INVALID_ADDRESS if invalid. +}; + +} // namespace lldb_private + +#endif // liblldb_ClangUserExpression_h_ diff --git a/lldb/include/lldb/Expression/IRForTarget.h b/lldb/include/lldb/Expression/IRForTarget.h index 57158b92a79..be4cd580d6f 100644 --- a/lldb/include/lldb/Expression/IRForTarget.h +++ b/lldb/include/lldb/Expression/IRForTarget.h @@ -60,9 +60,13 @@ public: /// The data layout information for the target. This information is /// used to determine the sizes of types that have been lowered into /// IR types. + /// + /// @param[in] func_name + /// The name of the function to prepare for execution in the target. //------------------------------------------------------------------ IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map, - const llvm::TargetData *target_data); + const llvm::TargetData *target_data, + const char* func_name = "___clang_expr"); //------------------------------------------------------------------ /// Destructor @@ -96,7 +100,7 @@ private: //------------------------------------------------------------------ /// A function-level pass to take the generated global value /// ___clang_expr_result and make it into a persistent variable. - /// Also see ClangResultSynthesizer. + /// Also see ASTResultSynthesizer. //------------------------------------------------------------------ //------------------------------------------------------------------ @@ -294,6 +298,7 @@ private: bool replaceVariables(llvm::Module &M, llvm::Function &F); + std::string m_func_name; ///< The name of the function to translate lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls const llvm::TargetData *m_target_data; ///< The TargetData for use in determining type sizes llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type diff --git a/lldb/include/lldb/Expression/IRToDWARF.h b/lldb/include/lldb/Expression/IRToDWARF.h index d57ff1bf785..2415abcdf87 100644 --- a/lldb/include/lldb/Expression/IRToDWARF.h +++ b/lldb/include/lldb/Expression/IRToDWARF.h @@ -19,7 +19,7 @@ namespace llvm { } namespace lldb_private { - class ClangExpressionVariableList; + class ClangExpressionVariableStore; class ClangExpressionDeclMap; class StreamString; } @@ -50,7 +50,7 @@ public: //------------------------------------------------------------------ /// Constructor /// - /// @param[in] variable_list + /// @param[in] local_vars /// A list of variables to populate with the local variables this /// expression uses. /// @@ -60,10 +60,14 @@ public: /// /// @param[in] stream /// The stream to dump DWARF bytecode onto. + /// + /// @param[in] func_name + /// The name of the function to translate to DWARF. //------------------------------------------------------------------ - IRToDWARF(lldb_private::ClangExpressionVariableList &variable_list, + IRToDWARF(lldb_private::ClangExpressionVariableStore &local_vars, lldb_private::ClangExpressionDeclMap *decl_map, - lldb_private::StreamString &strm); + lldb_private::StreamString &strm, + const char* func_name = "___clang_expr"); //------------------------------------------------------------------ /// Destructor @@ -108,7 +112,8 @@ private: //------------------------------------------------------------------ bool runOnBasicBlock(llvm::BasicBlock &BB, Relocator &Relocator); - lldb_private::ClangExpressionVariableList &m_variable_list; ///< The list of local variables to populate while transforming + std::string m_func_name; ///< The name of the function to translate + lldb_private::ClangExpressionVariableStore &m_local_vars; ///< The list of local variables to populate while transforming lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The list of external variables lldb_private::StreamString &m_strm; ///< The stream to write bytecode to }; diff --git a/lldb/include/lldb/Expression/RecordingMemoryManager.h b/lldb/include/lldb/Expression/RecordingMemoryManager.h index 06aab9bd746..50756ee828a 100644 --- a/lldb/include/lldb/Expression/RecordingMemoryManager.h +++ b/lldb/include/lldb/Expression/RecordingMemoryManager.h @@ -24,6 +24,7 @@ #include "lldb/Core/Log.h" #include "llvm/ExecutionEngine/JITMemoryManager.h" #include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/ClangExpressionParser.h" namespace lldb_private { @@ -51,7 +52,7 @@ namespace lldb_private { //---------------------------------------------------------------------- class RecordingMemoryManager : public llvm::JITMemoryManager { -friend bool ClangExpression::WriteJITCode (const ExecutionContext &exc_context); +friend Error ClangExpressionParser::MakeJIT (uint64_t &, ExecutionContext &); public: //------------------------------------------------------------------ diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index fb4377a49bc..01a94178942 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -41,6 +41,7 @@ class ClangASTContext; class ClangExpression; class ClangExpressionDeclMap; class ClangExpressionVariableList; +class ClangExpressionVariableStore; class Debugger; class CommandInterpreter; class CommandObject; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 4da4e3a69dc..a52197d7c3c 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -152,7 +152,7 @@ 26D5B0BA11B07550009A862E /* ValueObjectList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */; }; 26D5B0BB11B07550009A862E /* ValueObjectVariable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */; }; 26D5B0BC11B07550009A862E /* VMRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9E10F1B85900F91463 /* VMRange.cpp */; }; - 26D5B0BD11B07550009A862E /* ClangExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7ED510F1B86700F91463 /* ClangExpression.cpp */; }; + 26D5B0BD11B07550009A862E /* ClangUserExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7ED510F1B86700F91463 /* ClangUserExpression.cpp */; }; 26D5B0BE11B07550009A862E /* ClangExpressionVariable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7ED610F1B86700F91463 /* ClangExpressionVariable.cpp */; }; 26D5B0C111B07550009A862E /* Condition.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7EE710F1B88F00F91463 /* Condition.cpp */; }; 26D5B0C211B07550009A862E /* Host.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7EE810F1B88F00F91463 /* Host.mm */; }; @@ -287,7 +287,6 @@ 26D5B14711B07550009A862E /* ThreadPlanCallFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49EC3E98118F90AC00B1265E /* ThreadPlanCallFunction.cpp */; }; 26D5B14811B07550009A862E /* ClangFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */; }; 26D5B14911B07550009A862E /* RecordingMemoryManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */; settings = {COMPILER_FLAGS = "-fno-rtti"; }; }; - 26D5B14A11B07550009A862E /* CommandObjectCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3E4118FB9B100E575D0 /* CommandObjectCall.cpp */; }; 26D5B14B11B07550009A862E /* CommandObjectTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 269416AD119A024800FF2715 /* CommandObjectTarget.cpp */; }; 26D5B14C11B07550009A862E /* PathMappingList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 495BBACB119A0DBE00418BEA /* PathMappingList.cpp */; }; 26D5B14D11B07550009A862E /* StringExtractorGDBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2676A093119C93C8008A98EF /* StringExtractorGDBRemote.cpp */; }; @@ -330,10 +329,15 @@ 26F5C32D10F3DFDD009D5894 /* libtermcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C32B10F3DFDD009D5894 /* libtermcap.dylib */; }; 26F5C37510F3F61B009D5894 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C37410F3F61B009D5894 /* libobjc.dylib */; }; 26F5C39110F3FA26009D5894 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C39010F3FA26009D5894 /* CoreFoundation.framework */; }; + 4911934C1226383D00578B7F /* ASTStructExtractor.h in Headers */ = {isa = PBXBuildFile; fileRef = 4911934B1226383D00578B7F /* ASTStructExtractor.h */; }; + 491193521226386000578B7F /* ASTStructExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491193501226386000578B7F /* ASTStructExtractor.cpp */; }; 49307AAE11DEA4D90081F992 /* IRForTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49307AAD11DEA4D90081F992 /* IRForTarget.cpp */; }; 49307AB211DEA4F20081F992 /* IRForTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 49307AB111DEA4F20081F992 /* IRForTarget.h */; }; - 49A8A3A011D568A300AD3B68 /* ClangResultSynthesizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49A8A39F11D568A300AD3B68 /* ClangResultSynthesizer.cpp */; }; - 49A8A3A411D568BF00AD3B68 /* ClangResultSynthesizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49A8A3A311D568BF00AD3B68 /* ClangResultSynthesizer.h */; }; + 49445C2612245E3600C11A81 /* ClangExpressionParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49445C2512245E3600C11A81 /* ClangExpressionParser.cpp */; }; + 49445C2A12245E5500C11A81 /* ClangExpressionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 49445C2912245E5500C11A81 /* ClangExpressionParser.h */; }; + 49445E351225AB6A00C11A81 /* ClangUserExpression.h in Headers */ = {isa = PBXBuildFile; fileRef = 49445E341225AB6A00C11A81 /* ClangUserExpression.h */; }; + 49A8A3A011D568A300AD3B68 /* ASTResultSynthesizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49A8A39F11D568A300AD3B68 /* ASTResultSynthesizer.cpp */; }; + 49A8A3A411D568BF00AD3B68 /* ASTResultSynthesizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49A8A3A311D568BF00AD3B68 /* ASTResultSynthesizer.h */; }; 49BB309611F79450001A4197 /* TaggedASTType.h in Headers */ = {isa = PBXBuildFile; fileRef = 49BB309511F79450001A4197 /* TaggedASTType.h */; }; 49D4FE831210B5FB00CDB854 /* ClangPersistentVariables.h in Headers */ = {isa = PBXBuildFile; fileRef = 49D4FE821210B5FB00CDB854 /* ClangPersistentVariables.h */; }; 49D4FE891210B61C00CDB854 /* ClangPersistentVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49D4FE871210B61C00CDB854 /* ClangPersistentVariables.cpp */; }; @@ -792,7 +796,7 @@ 26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectList.cpp; path = source/Core/ValueObjectList.cpp; sourceTree = "<group>"; }; 26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectVariable.cpp; path = source/Core/ValueObjectVariable.cpp; sourceTree = "<group>"; }; 26BC7E9E10F1B85900F91463 /* VMRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VMRange.cpp; path = source/Core/VMRange.cpp; sourceTree = "<group>"; }; - 26BC7ED510F1B86700F91463 /* ClangExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangExpression.cpp; path = source/Expression/ClangExpression.cpp; sourceTree = "<group>"; }; + 26BC7ED510F1B86700F91463 /* ClangUserExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangUserExpression.cpp; path = source/Expression/ClangUserExpression.cpp; sourceTree = "<group>"; }; 26BC7ED610F1B86700F91463 /* ClangExpressionVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangExpressionVariable.cpp; path = source/Expression/ClangExpressionVariable.cpp; sourceTree = "<group>"; }; 26BC7ED810F1B86700F91463 /* DWARFExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DWARFExpression.cpp; path = source/Expression/DWARFExpression.cpp; sourceTree = "<group>"; }; 26BC7EE710F1B88F00F91463 /* Condition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Condition.cpp; path = source/Host/posix/Condition.cpp; sourceTree = "<group>"; }; @@ -902,10 +906,15 @@ 26F996A8119B79C300412154 /* ARM_GCC_Registers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ARM_GCC_Registers.h; path = source/Utility/ARM_GCC_Registers.h; sourceTree = "<group>"; }; 26FE25221146CADE00F4085A /* GDBRemoteCommunication.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GDBRemoteCommunication.cpp; path = "source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp"; sourceTree = "<group>"; }; 26FE25231146CADE00F4085A /* GDBRemoteCommunication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GDBRemoteCommunication.h; path = "source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h"; sourceTree = "<group>"; }; + 4911934B1226383D00578B7F /* ASTStructExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTStructExtractor.h; path = include/lldb/Expression/ASTStructExtractor.h; sourceTree = "<group>"; }; + 491193501226386000578B7F /* ASTStructExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTStructExtractor.cpp; path = source/Expression/ASTStructExtractor.cpp; sourceTree = "<group>"; }; 49307AAD11DEA4D90081F992 /* IRForTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRForTarget.cpp; path = source/Expression/IRForTarget.cpp; sourceTree = "<group>"; }; 49307AB111DEA4F20081F992 /* IRForTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRForTarget.h; path = include/lldb/Expression/IRForTarget.h; sourceTree = "<group>"; }; 493C63F01189203300914D5E /* ABISysV_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ABISysV_x86_64.h; path = "ABI/SysV-x86_64/ABISysV_x86_64.h"; sourceTree = "<group>"; }; 493C63F11189203300914D5E /* ABISysV_x86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ABISysV_x86_64.cpp; path = "ABI/SysV-x86_64/ABISysV_x86_64.cpp"; sourceTree = "<group>"; }; + 49445C2512245E3600C11A81 /* ClangExpressionParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangExpressionParser.cpp; path = source/Expression/ClangExpressionParser.cpp; sourceTree = "<group>"; }; + 49445C2912245E5500C11A81 /* ClangExpressionParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangExpressionParser.h; path = include/lldb/Expression/ClangExpressionParser.h; sourceTree = "<group>"; }; + 49445E341225AB6A00C11A81 /* ClangUserExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangUserExpression.h; path = include/lldb/Expression/ClangUserExpression.h; sourceTree = "<group>"; }; 495BBACB119A0DBE00418BEA /* PathMappingList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PathMappingList.cpp; path = source/Target/PathMappingList.cpp; sourceTree = "<group>"; }; 495BBACF119A0DE700418BEA /* PathMappingList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PathMappingList.h; path = include/lldb/Target/PathMappingList.h; sourceTree = "<group>"; }; 497650CE11A21BEE008DDB57 /* ABIMacOSX_i386.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ABIMacOSX_i386.cpp; path = "ABI/MacOSX-i386/ABIMacOSX_i386.cpp"; sourceTree = "<group>"; }; @@ -914,8 +923,8 @@ 497E7B9D1188F6690065CCA1 /* ABI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ABI.cpp; path = source/Target/ABI.cpp; sourceTree = "<group>"; }; 499F381E11A5B3F300F5CE02 /* CommandObjectArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectArgs.h; path = source/Commands/CommandObjectArgs.h; sourceTree = "<group>"; }; 499F381F11A5B3F300F5CE02 /* CommandObjectArgs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectArgs.cpp; path = source/Commands/CommandObjectArgs.cpp; sourceTree = "<group>"; }; - 49A8A39F11D568A300AD3B68 /* ClangResultSynthesizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangResultSynthesizer.cpp; path = source/Expression/ClangResultSynthesizer.cpp; sourceTree = "<group>"; }; - 49A8A3A311D568BF00AD3B68 /* ClangResultSynthesizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangResultSynthesizer.h; path = include/lldb/Expression/ClangResultSynthesizer.h; sourceTree = "<group>"; }; + 49A8A39F11D568A300AD3B68 /* ASTResultSynthesizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTResultSynthesizer.cpp; path = source/Expression/ASTResultSynthesizer.cpp; sourceTree = "<group>"; }; + 49A8A3A311D568BF00AD3B68 /* ASTResultSynthesizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTResultSynthesizer.h; path = include/lldb/Expression/ASTResultSynthesizer.h; sourceTree = "<group>"; }; 49BB309511F79450001A4197 /* TaggedASTType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TaggedASTType.h; path = include/lldb/Symbol/TaggedASTType.h; sourceTree = "<group>"; }; 49BF48DC11ADF356008863BD /* ObjCObjectPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ObjCObjectPrinter.cpp; path = source/Target/ObjCObjectPrinter.cpp; sourceTree = "<group>"; }; 49BF48E011ADF37D008863BD /* ObjCObjectPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjCObjectPrinter.h; path = include/lldb/Target/ObjCObjectPrinter.h; sourceTree = "<group>"; }; @@ -1845,19 +1854,24 @@ 49D7072611B5AD03001AD875 /* ClangASTSource.h */, 49D7072811B5AD11001AD875 /* ClangASTSource.cpp */, 26BC7DC010F1B79500F91463 /* ClangExpression.h */, - 26BC7ED510F1B86700F91463 /* ClangExpression.cpp */, + 49445E341225AB6A00C11A81 /* ClangUserExpression.h */, + 26BC7ED510F1B86700F91463 /* ClangUserExpression.cpp */, 4C98D3E0118FB98F00E575D0 /* ClangFunction.h */, 4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */, 49F1A74911B338AE003ED505 /* ClangExpressionDeclMap.h */, 49F1A74511B3388F003ED505 /* ClangExpressionDeclMap.cpp */, + 49445C2912245E5500C11A81 /* ClangExpressionParser.h */, + 49445C2512245E3600C11A81 /* ClangExpressionParser.cpp */, 26BC7DC110F1B79500F91463 /* ClangExpressionVariable.h */, 26BC7ED610F1B86700F91463 /* ClangExpressionVariable.cpp */, 49D4FE821210B5FB00CDB854 /* ClangPersistentVariables.h */, 49D4FE871210B61C00CDB854 /* ClangPersistentVariables.cpp */, - 49A8A3A311D568BF00AD3B68 /* ClangResultSynthesizer.h */, - 49A8A39F11D568A300AD3B68 /* ClangResultSynthesizer.cpp */, 26BC7DC310F1B79500F91463 /* DWARFExpression.h */, 26BC7ED810F1B86700F91463 /* DWARFExpression.cpp */, + 49A8A3A311D568BF00AD3B68 /* ASTResultSynthesizer.h */, + 49A8A39F11D568A300AD3B68 /* ASTResultSynthesizer.cpp */, + 4911934B1226383D00578B7F /* ASTStructExtractor.h */, + 491193501226386000578B7F /* ASTStructExtractor.cpp */, 49307AB111DEA4F20081F992 /* IRForTarget.h */, 49307AAD11DEA4D90081F992 /* IRForTarget.cpp */, 49DA743411DE6BB2006AEF7E /* IRToDWARF.h */, @@ -2215,7 +2229,7 @@ 49D7072711B5AD03001AD875 /* ClangASTSource.h in Headers */, 261B5A5511C3F2AD00AABD0A /* SharingPtr.h in Headers */, 4C08CDEC11C81F1E001610A8 /* ThreadSpec.h in Headers */, - 49A8A3A411D568BF00AD3B68 /* ClangResultSynthesizer.h in Headers */, + 49A8A3A411D568BF00AD3B68 /* ASTResultSynthesizer.h in Headers */, 49DA743511DE6BB2006AEF7E /* IRToDWARF.h in Headers */, 49307AB211DEA4F20081F992 /* IRForTarget.h in Headers */, 4C5DBBC911E3FEC60035160F /* CommandObjectCommands.h in Headers */, @@ -2226,6 +2240,9 @@ 2615DB851208A9C90021781D /* StopInfo.h in Headers */, 2615DBCB1208B5FC0021781D /* StopInfoMachException.h in Headers */, 49D4FE831210B5FB00CDB854 /* ClangPersistentVariables.h in Headers */, + 49445C2A12245E5500C11A81 /* ClangExpressionParser.h in Headers */, + 49445E351225AB6A00C11A81 /* ClangUserExpression.h in Headers */, + 4911934C1226383D00578B7F /* ASTStructExtractor.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2480,7 +2497,7 @@ 26D5B0BA11B07550009A862E /* ValueObjectList.cpp in Sources */, 26D5B0BB11B07550009A862E /* ValueObjectVariable.cpp in Sources */, 26D5B0BC11B07550009A862E /* VMRange.cpp in Sources */, - 26D5B0BD11B07550009A862E /* ClangExpression.cpp in Sources */, + 26D5B0BD11B07550009A862E /* ClangUserExpression.cpp in Sources */, 26D5B0BE11B07550009A862E /* ClangExpressionVariable.cpp in Sources */, 26D5B0C111B07550009A862E /* Condition.cpp in Sources */, 26D5B0C211B07550009A862E /* Host.mm in Sources */, @@ -2615,7 +2632,6 @@ 26D5B14711B07550009A862E /* ThreadPlanCallFunction.cpp in Sources */, 26D5B14811B07550009A862E /* ClangFunction.cpp in Sources */, 26D5B14911B07550009A862E /* RecordingMemoryManager.cpp in Sources */, - 26D5B14A11B07550009A862E /* CommandObjectCall.cpp in Sources */, 26D5B14B11B07550009A862E /* CommandObjectTarget.cpp in Sources */, 26D5B14C11B07550009A862E /* PathMappingList.cpp in Sources */, 26D5B14D11B07550009A862E /* StringExtractorGDBRemote.cpp in Sources */, @@ -2672,7 +2688,7 @@ AF94005911C03F6500085DB9 /* SymbolVendor.cpp in Sources */, 261B5A5411C3F2AD00AABD0A /* SharingPtr.cpp in Sources */, 4C08CDE811C81EF8001610A8 /* ThreadSpec.cpp in Sources */, - 49A8A3A011D568A300AD3B68 /* ClangResultSynthesizer.cpp in Sources */, + 49A8A3A011D568A300AD3B68 /* ASTResultSynthesizer.cpp in Sources */, 49DA743011DE6A5A006AEF7E /* IRToDWARF.cpp in Sources */, 49307AAE11DEA4D90081F992 /* IRForTarget.cpp in Sources */, 4C5DBBC811E3FEC60035160F /* CommandObjectCommands.cpp in Sources */, @@ -2682,6 +2698,8 @@ 2615DBCA1208B5FC0021781D /* StopInfoMachException.cpp in Sources */, 49D4FE891210B61C00CDB854 /* ClangPersistentVariables.cpp in Sources */, 49FB515E121481B000DF8983 /* DWARFExpression.cpp in Sources */, + 49445C2612245E3600C11A81 /* ClangExpressionParser.cpp in Sources */, + 491193521226386000578B7F /* ASTStructExtractor.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/lldb/source/Commands/CommandObjectCall.cpp b/lldb/source/Commands/CommandObjectCall.cpp index b3dfc533b16..fe0ee534437 100644 --- a/lldb/source/Commands/CommandObjectCall.cpp +++ b/lldb/source/Commands/CommandObjectCall.cpp @@ -263,15 +263,8 @@ CommandObjectCall::Execute ClangFunction::ExecutionResults return_status; Value return_value; - if (m_options.use_abi) - { - return_status = clang_fun.ExecuteFunctionWithABI(exe_ctx, errors, return_value); - } - else - { - bool stop_others = true; - return_status = clang_fun.ExecuteFunction(exe_ctx, errors, stop_others, NULL, return_value); - } + bool stop_others = true; + return_status = clang_fun.ExecuteFunction(exe_ctx, errors, stop_others, NULL, return_value); // Now figure out what to do with the return value. if (return_status == ClangFunction::eExecutionSetupError) diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index af1041002b6..b29c0c7777d 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -16,10 +16,8 @@ #include "lldb/Interpreter/Args.h" #include "lldb/Core/Value.h" #include "lldb/Core/InputReader.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangExpressionDeclMap.h" #include "lldb/Expression/ClangExpressionVariable.h" -#include "lldb/Expression/ClangPersistentVariables.h" +#include "lldb/Expression/ClangUserExpression.h" #include "lldb/Expression/ClangFunction.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Host/Host.h" @@ -192,192 +190,22 @@ bool CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream &output_stream, Stream &error_stream, CommandReturnObject *result) { - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - //////////////////////////////////// - // Set up the target and compiler - // - - Target *target = m_exe_ctx.target; - - if (!target) - { - error_stream.PutCString ("error: invalid target\n"); - return false; - } + ClangUserExpression user_expression (expr); - ConstString target_triple; - - target->GetTargetTriple (target_triple); - - if (!target_triple) - target_triple = Host::GetTargetTriple (); - - if (!target_triple) + if (!user_expression.Parse (error_stream, m_exe_ctx)) { - error_stream.PutCString ("error: invalid target triple\n"); + error_stream.Printf ("Couldn't parse the expresssion"); return false; } - ClangExpressionDeclMap expr_decl_map (&m_exe_ctx); - ClangExpression clang_expr (target_triple.AsCString (), &expr_decl_map); - - ////////////////////////// - // Parse the expression - // - - unsigned num_errors; - - if (bare) - num_errors = clang_expr.ParseBareExpression (llvm::StringRef (expr), error_stream); - else - num_errors = clang_expr.ParseExpression (expr, error_stream, true); - - if (num_errors) - { - error_stream.Printf ("error: %d errors parsing expression\n", num_errors); - return false; - } - - /////////////////////////////////////////////// - // Convert the output of the parser to DWARF - // - - StreamString dwarf_opcodes; - dwarf_opcodes.SetByteOrder (eByteOrderHost); - dwarf_opcodes.GetFlags ().Set (Stream::eBinary); - - ClangExpressionVariableList expr_local_vars; - - bool success; - bool canInterpret = false; - - ClangExpressionVariable *expr_result = 0; - Error expr_error; - - canInterpret = clang_expr.ConvertIRToDWARF (expr_local_vars, dwarf_opcodes); - - if (canInterpret) - { - if (log) - log->Printf("Code can be interpreted."); - success = true; - } - else - { - if (log) - log->Printf("Code cannot be interpreted and must be run in the target."); - success = clang_expr.PrepareIRForTarget (); - } - - if (!success) - { - error_stream.PutCString ("error: expression couldn't be converted to IR\n"); - return false; - } + ClangExpressionVariable *expr_result; - if (canInterpret) + if (!user_expression.Execute (error_stream, m_exe_ctx, expr_result)) { - // TODO interpret IR + error_stream.Printf ("Couldn't execute the expresssion"); return false; } - else - { - if (!clang_expr.JITFunction ()) - { - error_stream.PutCString ("error: IR could not be JIT compiled\n"); - return false; - } - if (!clang_expr.WriteJITCode (m_exe_ctx)) - { - error_stream.PutCString ("error: JIT code could not be written to the target\n"); - return false; - } - - lldb::addr_t function_address(clang_expr.GetFunctionAddress ()); - - if (function_address == LLDB_INVALID_ADDRESS) - { - error_stream.PutCString ("JIT compiled code's address couldn't be found\n"); - return false; - } - - lldb::addr_t struct_address; - - if (!expr_decl_map.Materialize(&m_exe_ctx, struct_address, expr_error)) - { - error_stream.Printf ("Couldn't materialize struct: %s\n", expr_error.AsCString("unknown error")); - return false; - } - - if (log) - { - log->Printf("Function address : 0x%llx", (uint64_t)function_address); - log->Printf("Structure address : 0x%llx", (uint64_t)struct_address); - - StreamString insns; - - Error err = clang_expr.DisassembleFunction(insns, m_exe_ctx); - - if (!err.Success()) - { - log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error")); - } - else - { - log->Printf("Function disassembly:\n%s", insns.GetData()); - } - - StreamString args; - - if (!expr_decl_map.DumpMaterializedStruct(&m_exe_ctx, args, err)) - { - log->Printf("Couldn't extract variable values : %s", err.AsCString("unknown error")); - } - else - { - log->Printf("Structure contents:\n%s", args.GetData()); - } - } - - ClangFunction::ExecutionResults execution_result = - ClangFunction::ExecuteFunction (m_exe_ctx, function_address, struct_address, true, true, 10000, error_stream); - - if (execution_result != ClangFunction::eExecutionCompleted) - { - const char *result_name; - - switch (execution_result) - { - case ClangFunction::eExecutionCompleted: - result_name = "eExecutionCompleted"; - break; - case ClangFunction::eExecutionDiscarded: - result_name = "eExecutionDiscarded"; - break; - case ClangFunction::eExecutionInterrupted: - result_name = "eExecutionInterrupted"; - break; - case ClangFunction::eExecutionSetupError: - result_name = "eExecutionSetupError"; - break; - case ClangFunction::eExecutionTimedOut: - result_name = "eExecutionTimedOut"; - break; - } - - error_stream.Printf ("Couldn't execute function; result was %s\n", result_name); - return false; - } - - if (!expr_decl_map.Dematerialize(&m_exe_ctx, expr_result, expr_error)) - { - error_stream.Printf ("Couldn't dematerialize struct : %s\n", expr_error.AsCString("unknown error")); - return false; - } - } - if (expr_result) { StreamString ss; diff --git a/lldb/source/Expression/ClangResultSynthesizer.cpp b/lldb/source/Expression/ASTResultSynthesizer.cpp index b3922ee5ce4..b3790f2cae5 100644 --- a/lldb/source/Expression/ClangResultSynthesizer.cpp +++ b/lldb/source/Expression/ASTResultSynthesizer.cpp @@ -1,4 +1,4 @@ -//===-- ClangResultSynthesizer.cpp ------------------------------*- C++ -*-===// +//===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -20,13 +20,13 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" #include "lldb/Core/Log.h" -#include "lldb/Expression/ClangResultSynthesizer.h" +#include "lldb/Expression/ASTResultSynthesizer.h" using namespace llvm; using namespace clang; using namespace lldb_private; -ClangResultSynthesizer::ClangResultSynthesizer(ASTConsumer *passthrough) : +ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough) : m_ast_context (NULL), m_passthrough (passthrough), m_passthrough_sema (NULL), @@ -39,12 +39,12 @@ ClangResultSynthesizer::ClangResultSynthesizer(ASTConsumer *passthrough) : m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough); } -ClangResultSynthesizer::~ClangResultSynthesizer() +ASTResultSynthesizer::~ASTResultSynthesizer() { } void -ClangResultSynthesizer::Initialize(ASTContext &Context) +ASTResultSynthesizer::Initialize(ASTContext &Context) { m_ast_context = &Context; @@ -53,7 +53,7 @@ ClangResultSynthesizer::Initialize(ASTContext &Context) } void -ClangResultSynthesizer::TransformTopLevelDecl(Decl* D) +ASTResultSynthesizer::TransformTopLevelDecl(Decl* D) { LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D); @@ -81,7 +81,7 @@ ClangResultSynthesizer::TransformTopLevelDecl(Decl* D) } void -ClangResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D) +ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D) { DeclGroupRef::iterator decl_iterator; @@ -99,7 +99,7 @@ ClangResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D) } bool -ClangResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl) +ASTResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl) { ASTContext &Ctx(*m_ast_context); @@ -210,42 +210,42 @@ ClangResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl) } void -ClangResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx) +ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx) { if (m_passthrough) m_passthrough->HandleTranslationUnit(Ctx); } void -ClangResultSynthesizer::HandleTagDeclDefinition(TagDecl *D) +ASTResultSynthesizer::HandleTagDeclDefinition(TagDecl *D) { if (m_passthrough) m_passthrough->HandleTagDeclDefinition(D); } void -ClangResultSynthesizer::CompleteTentativeDefinition(VarDecl *D) +ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D) { if (m_passthrough) m_passthrough->CompleteTentativeDefinition(D); } void -ClangResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) +ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) { if (m_passthrough) m_passthrough->HandleVTable(RD, DefinitionRequired); } void -ClangResultSynthesizer::PrintStats() +ASTResultSynthesizer::PrintStats() { if (m_passthrough) m_passthrough->PrintStats(); } void -ClangResultSynthesizer::InitializeSema(Sema &S) +ASTResultSynthesizer::InitializeSema(Sema &S) { m_sema = &S; m_action = reinterpret_cast<Action*>(m_sema); @@ -255,7 +255,7 @@ ClangResultSynthesizer::InitializeSema(Sema &S) } void -ClangResultSynthesizer::ForgetSema() +ASTResultSynthesizer::ForgetSema() { m_sema = NULL; m_action = NULL; diff --git a/lldb/source/Expression/ASTStructExtractor.cpp b/lldb/source/Expression/ASTStructExtractor.cpp new file mode 100644 index 00000000000..84a97c8e5df --- /dev/null +++ b/lldb/source/Expression/ASTStructExtractor.cpp @@ -0,0 +1,191 @@ +//===-- ASTStructExtractor.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "stdlib.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclGroup.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Stmt.h" +#include "clang/Parse/Action.h" +#include "clang/Parse/Parser.h" +#include "clang/Parse/Scope.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" +#include "lldb/Core/Log.h" +#include "lldb/Expression/ASTStructExtractor.h" + +using namespace llvm; +using namespace clang; +using namespace lldb_private; + +ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough, + const char *struct_name, + ClangFunction &function) : + m_ast_context (NULL), + m_passthrough (passthrough), + m_passthrough_sema (NULL), + m_sema (NULL), + m_action (NULL), + m_struct_name (struct_name), + m_function (function) +{ + if (!m_passthrough) + return; + + m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough); +} + +ASTStructExtractor::~ASTStructExtractor() +{ +} + +void +ASTStructExtractor::Initialize(ASTContext &Context) +{ + m_ast_context = &Context; + + if (m_passthrough) + m_passthrough->Initialize(Context); +} + +void +ASTStructExtractor::ExtractFromFunctionDecl(FunctionDecl *F) +{ + DeclarationName struct_name(&m_ast_context->Idents.get(m_struct_name.c_str())); + RecordDecl::lookup_result struct_lookup = F->lookup(struct_name); + + if (struct_lookup.first == struct_lookup.second) + return; + + RecordDecl *struct_decl = dyn_cast<RecordDecl>(*(struct_lookup.first)); + + if (!struct_decl) + return; + + const ASTRecordLayout* struct_layout(&m_ast_context->getASTRecordLayout (struct_decl)); + + if (!struct_layout) + return; + + m_function.m_struct_size = struct_layout->getSize() / 8; // Clang returns sizes in bits. + m_function.m_return_offset = struct_layout->getFieldOffset(struct_layout->getFieldCount() - 1) / 8; + m_function.m_return_size = (struct_layout->getDataSize() / 8) - m_function.m_return_offset; + + for (unsigned field_index = 0, num_fields = struct_layout->getFieldCount(); + field_index < num_fields; + ++field_index) + { + m_function.m_member_offsets.push_back(struct_layout->getFieldOffset(field_index) / 8); + } + + m_function.m_struct_valid = true; +} + +void +ASTStructExtractor::ExtractFromTopLevelDecl(Decl* D) +{ + LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D); + + if (linkage_spec_decl) + { + RecordDecl::decl_iterator decl_iterator; + + for (decl_iterator = linkage_spec_decl->decls_begin(); + decl_iterator != linkage_spec_decl->decls_end(); + ++decl_iterator) + { + ExtractFromTopLevelDecl(*decl_iterator); + } + } + + FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D); + + if (m_ast_context && + function_decl && + !m_function.m_wrapper_function_name.compare(function_decl->getNameAsCString())) + { + ExtractFromFunctionDecl(function_decl); + } +} + +void +ASTStructExtractor::HandleTopLevelDecl(DeclGroupRef D) +{ + DeclGroupRef::iterator decl_iterator; + + for (decl_iterator = D.begin(); + decl_iterator != D.end(); + ++decl_iterator) + { + Decl *decl = *decl_iterator; + + ExtractFromTopLevelDecl(decl); + } + + if (m_passthrough) + m_passthrough->HandleTopLevelDecl(D); +} + +void +ASTStructExtractor::HandleTranslationUnit(ASTContext &Ctx) +{ + if (m_passthrough) + m_passthrough->HandleTranslationUnit(Ctx); +} + +void +ASTStructExtractor::HandleTagDeclDefinition(TagDecl *D) +{ + if (m_passthrough) + m_passthrough->HandleTagDeclDefinition(D); +} + +void +ASTStructExtractor::CompleteTentativeDefinition(VarDecl *D) +{ + if (m_passthrough) + m_passthrough->CompleteTentativeDefinition(D); +} + +void +ASTStructExtractor::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) +{ + if (m_passthrough) + m_passthrough->HandleVTable(RD, DefinitionRequired); +} + +void +ASTStructExtractor::PrintStats() +{ + if (m_passthrough) + m_passthrough->PrintStats(); +} + +void +ASTStructExtractor::InitializeSema(Sema &S) +{ + m_sema = &S; + m_action = reinterpret_cast<Action*>(m_sema); + + if (m_passthrough_sema) + m_passthrough_sema->InitializeSema(S); +} + +void +ASTStructExtractor::ForgetSema() +{ + m_sema = NULL; + m_action = NULL; + + if (m_passthrough_sema) + m_passthrough_sema->ForgetSema(); +} diff --git a/lldb/source/Expression/ClangExpression.cpp b/lldb/source/Expression/ClangExpression.cpp deleted file mode 100644 index 416bd3e3733..00000000000 --- a/lldb/source/Expression/ClangExpression.cpp +++ /dev/null @@ -1,748 +0,0 @@ -//===-- ClangExpression.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 <cstdlib> -#include <string> -#include <map> - -// Other libraries and framework includes -#include "clang/AST/ASTContext.h" -#include "clang/AST/ExternalASTSource.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/Version.h" -#include "clang/Checker/FrontendActions.h" -#include "clang/CodeGen/CodeGenAction.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "clang/Driver/CC1Options.h" -#include "clang/Driver/OptTable.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/CompilerInvocation.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Frontend/FrontendPluginRegistry.h" -#include "clang/Frontend/TextDiagnosticBuffer.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Frontend/VerifyDiagnosticsClient.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Rewrite/FrontendActions.h" -#include "clang/Sema/ParseAST.h" -#include "clang/Sema/SemaConsumer.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/JIT.h" -#include "llvm/Module.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/LLVMContext.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/System/DynamicLibrary.h" -#include "llvm/System/Host.h" -#include "llvm/System/Signals.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Target/TargetSelect.h" - -// Project includes -#include "lldb/Core/Log.h" -#include "lldb/Core/ClangForward.h" -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Disassembler.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangASTSource.h" -#include "lldb/Expression/ClangResultSynthesizer.h" -#include "lldb/Expression/IRForTarget.h" -#include "lldb/Expression/IRToDWARF.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Expression/RecordingMemoryManager.h" -#include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/Target.h" - -#include "lldb/Core/StreamString.h" -#include "lldb/Host/Mutex.h" - - -using namespace lldb_private; -using namespace clang; -using namespace llvm; - - -//===----------------------------------------------------------------------===// -// Utility Methods -//===----------------------------------------------------------------------===// - -std::string GetBuiltinIncludePath(const char *Argv0) { - llvm::sys::Path P = - llvm::sys::Path::GetMainExecutable(Argv0, - (void*)(intptr_t) GetBuiltinIncludePath); - - if (!P.isEmpty()) { - P.eraseComponent(); // Remove /clang from foo/bin/clang - P.eraseComponent(); // Remove /bin from foo/bin - - // Get foo/lib/clang/<version>/include - P.appendComponent("lib"); - P.appendComponent("clang"); - P.appendComponent(CLANG_VERSION_STRING); - P.appendComponent("include"); - } - - return P.str(); -} - - -//===----------------------------------------------------------------------===// -// Main driver -//===----------------------------------------------------------------------===// - -static void LLVMErrorHandler(void *UserData, const std::string &Message) { - Diagnostic &Diags = *static_cast<Diagnostic*>(UserData); - - Diags.Report(diag::err_fe_error_backend) << Message; - - // We cannot recover from llvm errors. - exit(1); -} - -static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { - using namespace clang::frontend; - - switch (CI.getFrontendOpts().ProgramAction) { - default: - llvm_unreachable("Invalid program action!"); - - case ASTDump: return new ASTDumpAction(); - case ASTPrint: return new ASTPrintAction(); - case ASTPrintXML: return new ASTPrintXMLAction(); - case ASTView: return new ASTViewAction(); - case BoostCon: return new BoostConAction(); - case DumpRawTokens: return new DumpRawTokensAction(); - case DumpTokens: return new DumpTokensAction(); - case EmitAssembly: return new EmitAssemblyAction(); - case EmitBC: return new EmitBCAction(); - case EmitHTML: return new HTMLPrintAction(); - case EmitLLVM: return new EmitLLVMAction(); - case EmitLLVMOnly: return new EmitLLVMOnlyAction(); - case EmitCodeGenOnly: return new EmitCodeGenOnlyAction(); - case EmitObj: return new EmitObjAction(); - case FixIt: return new FixItAction(); - case GeneratePCH: return new GeneratePCHAction(); - case GeneratePTH: return new GeneratePTHAction(); - case InheritanceView: return new InheritanceViewAction(); - case InitOnly: return new InitOnlyAction(); - case ParseSyntaxOnly: return new SyntaxOnlyAction(); - - case PluginAction: { - for (FrontendPluginRegistry::iterator it = - FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); - it != ie; ++it) { - if (it->getName() == CI.getFrontendOpts().ActionName) { - llvm::OwningPtr<PluginASTAction> P(it->instantiate()); - if (!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs)) - return 0; - return P.take(); - } - } - - CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) - << CI.getFrontendOpts().ActionName; - return 0; - } - - case PrintDeclContext: return new DeclContextPrintAction(); - case PrintPreamble: return new PrintPreambleAction(); - case PrintPreprocessedInput: return new PrintPreprocessedAction(); - case RewriteMacros: return new RewriteMacrosAction(); - case RewriteObjC: return new RewriteObjCAction(); - case RewriteTest: return new RewriteTestAction(); - case RunAnalysis: return new AnalysisAction(); - case RunPreprocessorOnly: return new PreprocessOnlyAction(); - } -} - -static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { - // Create the underlying action. - FrontendAction *Act = CreateFrontendBaseAction(CI); - if (!Act) - return 0; - - // If there are any AST files to merge, create a frontend action - // adaptor to perform the merge. - if (!CI.getFrontendOpts().ASTMergeFiles.empty()) - Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0], - CI.getFrontendOpts().ASTMergeFiles.size()); - - return Act; -} - -//---------------------------------------------------------------------- -// ClangExpression constructor -//---------------------------------------------------------------------- -ClangExpression::ClangExpression(const char *target_triple, - ClangExpressionDeclMap *decl_map) : - m_target_triple (), - m_decl_map (decl_map), - m_clang_ap (), - m_code_generator_ptr (NULL), - m_jit_mm_ptr (NULL), - m_execution_engine (), - m_jitted_functions () -{ - if (target_triple && target_triple[0]) - m_target_triple = target_triple; - else - m_target_triple = llvm::sys::getHostTriple(); -} - - -//---------------------------------------------------------------------- -// Destructor -//---------------------------------------------------------------------- -ClangExpression::~ClangExpression() -{ - if (m_code_generator_ptr && !m_execution_engine.get()) - delete m_code_generator_ptr; -} - -bool -ClangExpression::CreateCompilerInstance () -{ - // Initialize targets first, so that --version shows registered targets. - static struct InitializeLLVM { - InitializeLLVM() { - llvm::InitializeAllTargets(); - llvm::InitializeAllAsmPrinters(); - } - } InitializeLLVM; - - // 1. Create a new compiler instance. - m_clang_ap.reset(new CompilerInstance()); - m_clang_ap->setLLVMContext(new LLVMContext()); - - // 2. Set options. - - // Parse expressions as Objective C++ regardless of context. - // Our hook into Clang's lookup mechanism only works in C++. - m_clang_ap->getLangOpts().CPlusPlus = true; - m_clang_ap->getLangOpts().ObjC1 = true; - m_clang_ap->getLangOpts().ThreadsafeStatics = false; - m_clang_ap->getLangOpts().AccessControl = false; // Debuggers get universal access - m_clang_ap->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name - - // Set CodeGen options - m_clang_ap->getCodeGenOpts().EmitDeclMetadata = true; - m_clang_ap->getCodeGenOpts().InstrumentFunctions = false; - - // Disable some warnings. - m_clang_ap->getDiagnosticOpts().Warnings.push_back("no-unused-value"); - - // Set the target triple. - m_clang_ap->getTargetOpts().Triple = m_target_triple; - - // 3. Set up various important bits of infrastructure. - - m_clang_ap->createDiagnostics(0, 0); - - // Create the target instance. - m_clang_ap->setTarget(TargetInfo::CreateTargetInfo(m_clang_ap->getDiagnostics(), - m_clang_ap->getTargetOpts())); - if (!m_clang_ap->hasTarget()) - { - m_clang_ap.reset(); - return false; - } - - // Inform the target of the language options - // - // FIXME: We shouldn't need to do this, the target should be immutable once - // created. This complexity should be lifted elsewhere. - m_clang_ap->getTarget().setForcedLangOptions(m_clang_ap->getLangOpts()); - - return m_clang_ap.get(); -} - -Mutex & -ClangExpression::GetClangMutex () -{ - static Mutex g_clang_mutex(Mutex::eMutexTypeRecursive); // Control access to the clang compiler - return g_clang_mutex; -} - - -clang::ASTContext * -ClangExpression::GetASTContext () -{ - CompilerInstance *compiler_instance = GetCompilerInstance(); - if (compiler_instance) - return &compiler_instance->getASTContext(); - return NULL; -} - -unsigned -ClangExpression::ParseExpression (const char *expr_text, - Stream &stream, - bool add_result_var) -{ - // HACK: for now we have to make a function body around our expression - // since there is no way to parse a single expression line in LLVM/Clang. - std::string func_expr("extern \"C\" void ___clang_expr(void *___clang_arg)\n{\n\t"); - func_expr.append(expr_text); - func_expr.append(";\n}"); - return ParseBareExpression (func_expr, stream, add_result_var); - -} - -unsigned -ClangExpression::ParseBareExpression (llvm::StringRef expr_text, - Stream &stream, - bool add_result_var) -{ - Mutex::Locker locker(GetClangMutex ()); - - TextDiagnosticBuffer text_diagnostic_buffer; - - if (!CreateCompilerInstance ()) - { - stream.Printf("error: couldn't create compiler instance\n"); - return 1; - } - - // This code is matched below by a setClient to NULL. - // We cannot return out of this code without doing that. - m_clang_ap->getDiagnostics().setClient(&text_diagnostic_buffer); - text_diagnostic_buffer.FlushDiagnostics (m_clang_ap->getDiagnostics()); - - MemoryBuffer *memory_buffer = MemoryBuffer::getMemBufferCopy(expr_text, __FUNCTION__); - - if (!m_clang_ap->hasSourceManager()) - m_clang_ap->createSourceManager(); - - m_clang_ap->createFileManager(); - m_clang_ap->createPreprocessor(); - - // Build the ASTContext. Most of this we inherit from the - // CompilerInstance, but we also want to give the context - // an ExternalASTSource. - SelectorTable selector_table; - std::auto_ptr<Builtin::Context> builtin_ap(new Builtin::Context(m_clang_ap->getTarget())); - ASTContext *Context = new ASTContext(m_clang_ap->getLangOpts(), - m_clang_ap->getSourceManager(), - m_clang_ap->getTarget(), - m_clang_ap->getPreprocessor().getIdentifierTable(), - selector_table, - *builtin_ap.get(), - 0); - - llvm::OwningPtr<ExternalASTSource> ASTSource(new ClangASTSource(*Context, *m_decl_map)); - - if (m_decl_map) - { - Context->setExternalSource(ASTSource); - } - - m_clang_ap->setASTContext(Context); - - FileID memory_buffer_file_id = m_clang_ap->getSourceManager().createMainFileIDForMemBuffer (memory_buffer); - std::string module_name("test_func"); - text_diagnostic_buffer.BeginSourceFile(m_clang_ap->getLangOpts(), &m_clang_ap->getPreprocessor()); - - if (m_code_generator_ptr) - delete m_code_generator_ptr; - - m_code_generator_ptr = CreateLLVMCodeGen(m_clang_ap->getDiagnostics(), - module_name, - m_clang_ap->getCodeGenOpts(), - m_clang_ap->getLLVMContext()); - - - // - CodeGeneration ASTConsumer (include/clang/ModuleBuilder.h), which will be passed in when you call... - // - Call clang::ParseAST (in lib/Sema/ParseAST.cpp) to parse the buffer. The CodeGenerator will generate code for __dbg_expr. - // - Once ParseAST completes, you can grab the llvm::Module from the CodeGenerator, which will have an llvm::Function you can hand off to the JIT. - - if (add_result_var) - { - ClangResultSynthesizer result_synthesizer(m_code_generator_ptr); - ParseAST(m_clang_ap->getPreprocessor(), &result_synthesizer, m_clang_ap->getASTContext()); - } - else - { - ParseAST(m_clang_ap->getPreprocessor(), m_code_generator_ptr, m_clang_ap->getASTContext()); - } - - - text_diagnostic_buffer.EndSourceFile(); - - //compiler_instance->getASTContext().getTranslationUnitDecl()->dump(); - - //if (compiler_instance->getFrontendOpts().ShowStats) { - // compiler_instance->getFileManager().PrintStats(); - // fprintf(stderr, "\n"); - //} - - // This code resolves the setClient above. - m_clang_ap->getDiagnostics().setClient(0); - - TextDiagnosticBuffer::const_iterator diag_iterator; - - int num_errors = 0; - -#ifdef COUNT_WARNINGS_AND_ERRORS - int num_warnings = 0; - - for (diag_iterator = text_diagnostic_buffer.warn_begin(); - diag_iterator != text_diagnostic_buffer.warn_end(); - ++diag_iterator) - num_warnings++; - - for (diag_iterator = text_diagnostic_buffer.err_begin(); - diag_iterator != text_diagnostic_buffer.err_end(); - ++diag_iterator) - num_errors++; - - if (num_warnings || num_errors) - { - if (num_warnings) - stream.Printf("%u warning%s%s", num_warnings, (num_warnings == 1 ? "" : "s"), (num_errors ? " and " : "")); - if (num_errors) - stream.Printf("%u error%s", num_errors, (num_errors == 1 ? "" : "s")); - stream.Printf("\n"); - } -#endif - - for (diag_iterator = text_diagnostic_buffer.warn_begin(); - diag_iterator != text_diagnostic_buffer.warn_end(); - ++diag_iterator) - stream.Printf("warning: %s\n", (*diag_iterator).second.c_str()); - - num_errors = 0; - - for (diag_iterator = text_diagnostic_buffer.err_begin(); - diag_iterator != text_diagnostic_buffer.err_end(); - ++diag_iterator) - { - num_errors++; - stream.Printf("error: %s\n", (*diag_iterator).second.c_str()); - } - - return num_errors; -} - -bool -ClangExpression::ConvertIRToDWARF (ClangExpressionVariableList &expr_local_variable_list, - StreamString &dwarf_opcode_strm) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - llvm::Module *module = m_code_generator_ptr->GetModule(); - - if (!module) - { - if (log) - log->Printf("IR doesn't contain a module"); - - return 1; - } - - IRToDWARF ir_to_dwarf(expr_local_variable_list, m_decl_map, dwarf_opcode_strm); - - return ir_to_dwarf.runOnModule(*module); -} - -bool -ClangExpression::PrepareIRForTarget () -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - llvm::Module *module = m_code_generator_ptr->GetModule(); - - if (!module) - { - if (log) - log->Printf("IR doesn't contain a module"); - - return 1; - } - - llvm::Triple target_triple = m_clang_ap->getTarget().getTriple(); - - std::string err; - - const llvm::Target *target = llvm::TargetRegistry::lookupTarget(m_target_triple, err); - - if (!target) - { - if (log) - log->Printf("Couldn't find a target for %s", m_target_triple.c_str()); - - return 1; - } - - std::auto_ptr<llvm::TargetMachine> target_machine(target->createTargetMachine(m_target_triple, "")); - - IRForTarget ir_for_target(m_decl_map, target_machine->getTargetData()); - - return ir_for_target.runOnModule(*module); -} - -bool -ClangExpression::JITFunction (const char *name) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - llvm::Module *module = m_code_generator_ptr->GetModule(); - - if (module) - { - std::string error; - - if (m_jit_mm_ptr == NULL) - m_jit_mm_ptr = new RecordingMemoryManager(); - - //llvm::InitializeNativeTarget(); - - if (log) - { - const char *relocation_model_string; - - switch (llvm::TargetMachine::getRelocationModel()) - { - case llvm::Reloc::Default: - relocation_model_string = "Default"; - break; - case llvm::Reloc::Static: - relocation_model_string = "Static"; - break; - case llvm::Reloc::PIC_: - relocation_model_string = "PIC_"; - break; - case llvm::Reloc::DynamicNoPIC: - relocation_model_string = "DynamicNoPIC"; - break; - } - - log->Printf("Target machine's relocation model: %s", relocation_model_string); - } - - if (m_execution_engine.get() == 0) - m_execution_engine.reset(llvm::ExecutionEngine::createJIT (module, - &error, - m_jit_mm_ptr, - CodeGenOpt::Default, - true, - CodeModel::Small)); // set to small so RIP-relative relocations work in PIC - - m_execution_engine->DisableLazyCompilation(); - llvm::Function *function = module->getFunction (llvm::StringRef (name)); - - // We don't actually need the function pointer here, this just forces it to get resolved. - void *fun_ptr = m_execution_engine->getPointerToFunction(function); - // Note, you probably won't get here on error, since the LLVM JIT tends to just - // exit on error at present... So be careful. - if (fun_ptr == 0) - return false; - m_jitted_functions.push_back(ClangExpression::JittedFunction(name, (lldb::addr_t) fun_ptr)); - - } - return true; -} - -bool -ClangExpression::WriteJITCode (const ExecutionContext &exc_context) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - if (m_jit_mm_ptr == NULL) - return false; - - if (exc_context.process == NULL) - return false; - - // Look over the regions allocated for the function compiled. The JIT - // tries to allocate the functions & stubs close together, so we should try to - // write them that way too... - // For now I only write functions with no stubs, globals, exception tables, - // etc. So I only need to write the functions. - - size_t alloc_size = 0; - std::map<uint8_t *, uint8_t *>::iterator fun_pos, fun_end = m_jit_mm_ptr->m_functions.end(); - for (fun_pos = m_jit_mm_ptr->m_functions.begin(); fun_pos != fun_end; fun_pos++) - { - alloc_size += (*fun_pos).second - (*fun_pos).first; - } - - Error error; - lldb::addr_t target_addr = exc_context.process->AllocateMemory (alloc_size, lldb::ePermissionsReadable|lldb::ePermissionsExecutable, error); - - if (target_addr == LLDB_INVALID_ADDRESS) - return false; - - lldb::addr_t cursor = target_addr; - for (fun_pos = m_jit_mm_ptr->m_functions.begin(); fun_pos != fun_end; fun_pos++) - { - if (log) - log->Printf("Reading [%p-%p] from m_functions", fun_pos->first, fun_pos->second); - - lldb::addr_t lstart = (lldb::addr_t) (*fun_pos).first; - lldb::addr_t lend = (lldb::addr_t) (*fun_pos).second; - size_t size = lend - lstart; - exc_context.process->WriteMemory(cursor, (void *) lstart, size, error); - m_jit_mm_ptr->AddToLocalToRemoteMap (lstart, size, cursor); - cursor += size; - } - - std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); - - for (pos = m_jitted_functions.begin(); pos != end; pos++) - { - (*pos).m_remote_addr = m_jit_mm_ptr->GetRemoteAddressForLocal ((*pos).m_local_addr); - } - return true; -} - -lldb::addr_t -ClangExpression::GetFunctionAddress (const char *name) -{ - std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); - - for (pos = m_jitted_functions.begin(); pos < end; pos++) - { - if (strcmp ((*pos).m_name.c_str(), name) == 0) - return (*pos).m_remote_addr; - } - return LLDB_INVALID_ADDRESS; -} - -Error -ClangExpression::DisassembleFunction (Stream &stream, ExecutionContext &exe_ctx, const char *name) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - Error ret; - - ret.Clear(); - - lldb::addr_t func_local_addr = LLDB_INVALID_ADDRESS; - lldb::addr_t func_remote_addr = LLDB_INVALID_ADDRESS; - - std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); - - for (pos = m_jitted_functions.begin(); pos < end; pos++) - { - if (strcmp(pos->m_name.c_str(), name) == 0) - { - func_local_addr = pos->m_local_addr; - func_remote_addr = pos->m_remote_addr; - } - } - - if (func_local_addr == LLDB_INVALID_ADDRESS) - { - ret.SetErrorToGenericError(); - ret.SetErrorStringWithFormat("Couldn't find function %s for disassembly", name); - return ret; - } - - if(log) - log->Printf("Found function, has local address 0x%llx and remote address 0x%llx", (uint64_t)func_local_addr, (uint64_t)func_remote_addr); - - std::pair <lldb::addr_t, lldb::addr_t> func_range; - - func_range = m_jit_mm_ptr->GetRemoteRangeForLocal(func_local_addr); - - if (func_range.first == 0 && func_range.second == 0) - { - ret.SetErrorToGenericError(); - ret.SetErrorStringWithFormat("Couldn't find code range for function %s", name); - return ret; - } - - if(log) - log->Printf("Function's code range is [0x%llx-0x%llx]", func_range.first, func_range.second); - - if (!exe_ctx.target) - { - ret.SetErrorToGenericError(); - ret.SetErrorString("Couldn't find the target"); - } - - lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second - func_remote_addr, 0)); - - Error err; - exe_ctx.process->ReadMemory(func_remote_addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), err); - - if (!err.Success()) - { - ret.SetErrorToGenericError(); - ret.SetErrorStringWithFormat("Couldn't read from process: %s", err.AsCString("unknown error")); - return ret; - } - - ArchSpec arch(exe_ctx.target->GetArchitecture()); - - Disassembler *disassembler = Disassembler::FindPlugin(arch); - - if (disassembler == NULL) - { - ret.SetErrorToGenericError(); - ret.SetErrorStringWithFormat("Unable to find disassembler plug-in for %s architecture.", arch.AsCString()); - return ret; - } - - if (!exe_ctx.process) - { - ret.SetErrorToGenericError(); - ret.SetErrorString("Couldn't find the process"); - return ret; - } - - DataExtractor extractor(buffer_sp, - exe_ctx.process->GetByteOrder(), - exe_ctx.target->GetArchitecture().GetAddressByteSize()); - - if(log) - { - log->Printf("Function data has contents:"); - extractor.PutToLog (log, - 0, - extractor.GetByteSize(), - func_remote_addr, - 16, - DataExtractor::TypeUInt8); - } - - disassembler->DecodeInstructions(extractor, 0, UINT32_MAX); - - Disassembler::InstructionList &instruction_list = disassembler->GetInstructionList(); - - uint32_t bytes_offset = 0; - - for (uint32_t instruction_index = 0, num_instructions = instruction_list.GetSize(); - instruction_index < num_instructions; - ++instruction_index) - { - Disassembler::Instruction *instruction = instruction_list.GetInstructionAtIndex(instruction_index); - Address addr(NULL, func_remote_addr + bytes_offset); - instruction->Dump (&stream, - &addr, - &extractor, - bytes_offset, - exe_ctx, - true); - stream.PutChar('\n'); - bytes_offset += instruction->GetByteSize(); - } - - return ret; -} diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp new file mode 100644 index 00000000000..05c237afdb9 --- /dev/null +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -0,0 +1,640 @@ +//===-- ClangExpressionParser.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Expression/ClangExpressionParser.h" + +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Stream.h" +#include "lldb/Expression/ClangASTSource.h" +#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/IRForTarget.h" +#include "lldb/Expression/IRToDWARF.h" +#include "lldb/Expression/RecordingMemoryManager.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Version.h" +#include "clang/Checker/FrontendActions.h" +#include "clang/CodeGen/CodeGenAction.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Driver/CC1Options.h" +#include "clang/Driver/OptTable.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendPluginRegistry.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Rewrite/FrontendActions.h" +#include "clang/Sema/ParseAST.h" +#include "clang/Sema/SemaConsumer.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/JIT.h" +#include "llvm/Module.h" +#include "llvm/LLVMContext.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/DynamicLibrary.h" +#include "llvm/System/Host.h" +#include "llvm/System/Signals.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetSelect.h" + +using namespace clang; +using namespace llvm; +using namespace lldb_private; + +//===----------------------------------------------------------------------===// +// Utility Methods for Clang +//===----------------------------------------------------------------------===// + +std::string GetBuiltinIncludePath(const char *Argv0) { + llvm::sys::Path P = + llvm::sys::Path::GetMainExecutable(Argv0, + (void*)(intptr_t) GetBuiltinIncludePath); + + if (!P.isEmpty()) { + P.eraseComponent(); // Remove /clang from foo/bin/clang + P.eraseComponent(); // Remove /bin from foo/bin + + // Get foo/lib/clang/<version>/include + P.appendComponent("lib"); + P.appendComponent("clang"); + P.appendComponent(CLANG_VERSION_STRING); + P.appendComponent("include"); + } + + return P.str(); +} + + +//===----------------------------------------------------------------------===// +// Main driver for Clang +//===----------------------------------------------------------------------===// + +static void LLVMErrorHandler(void *UserData, const std::string &Message) { + Diagnostic &Diags = *static_cast<Diagnostic*>(UserData); + + Diags.Report(diag::err_fe_error_backend) << Message; + + // We cannot recover from llvm errors. + exit(1); +} + +static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { + using namespace clang::frontend; + + switch (CI.getFrontendOpts().ProgramAction) { + default: + llvm_unreachable("Invalid program action!"); + + case ASTDump: return new ASTDumpAction(); + case ASTPrint: return new ASTPrintAction(); + case ASTPrintXML: return new ASTPrintXMLAction(); + case ASTView: return new ASTViewAction(); + case BoostCon: return new BoostConAction(); + case DumpRawTokens: return new DumpRawTokensAction(); + case DumpTokens: return new DumpTokensAction(); + case EmitAssembly: return new EmitAssemblyAction(); + case EmitBC: return new EmitBCAction(); + case EmitHTML: return new HTMLPrintAction(); + case EmitLLVM: return new EmitLLVMAction(); + case EmitLLVMOnly: return new EmitLLVMOnlyAction(); + case EmitCodeGenOnly: return new EmitCodeGenOnlyAction(); + case EmitObj: return new EmitObjAction(); + case FixIt: return new FixItAction(); + case GeneratePCH: return new GeneratePCHAction(); + case GeneratePTH: return new GeneratePTHAction(); + case InheritanceView: return new InheritanceViewAction(); + case InitOnly: return new InitOnlyAction(); + case ParseSyntaxOnly: return new SyntaxOnlyAction(); + + case PluginAction: { + for (FrontendPluginRegistry::iterator it = + FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); + it != ie; ++it) { + if (it->getName() == CI.getFrontendOpts().ActionName) { + llvm::OwningPtr<PluginASTAction> P(it->instantiate()); + if (!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs)) + return 0; + return P.take(); + } + } + + CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) + << CI.getFrontendOpts().ActionName; + return 0; + } + + case PrintDeclContext: return new DeclContextPrintAction(); + case PrintPreamble: return new PrintPreambleAction(); + case PrintPreprocessedInput: return new PrintPreprocessedAction(); + case RewriteMacros: return new RewriteMacrosAction(); + case RewriteObjC: return new RewriteObjCAction(); + case RewriteTest: return new RewriteTestAction(); + case RunAnalysis: return new AnalysisAction(); + case RunPreprocessorOnly: return new PreprocessOnlyAction(); + } +} + +static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { + // Create the underlying action. + FrontendAction *Act = CreateFrontendBaseAction(CI); + if (!Act) + return 0; + + // If there are any AST files to merge, create a frontend action + // adaptor to perform the merge. + if (!CI.getFrontendOpts().ASTMergeFiles.empty()) + Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0], + CI.getFrontendOpts().ASTMergeFiles.size()); + + return Act; +} + +//===----------------------------------------------------------------------===// +// Implementation of ClangExpressionParser +//===----------------------------------------------------------------------===// + +ClangExpressionParser::ClangExpressionParser(const char *target_triple, + ClangExpression &expr) : + m_expr(expr), + m_target_triple (), + m_compiler (), + m_code_generator (NULL), + m_execution_engine (), + m_jitted_functions () +{ + // Initialize targets first, so that --version shows registered targets. + static struct InitializeLLVM { + InitializeLLVM() { + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + } + } InitializeLLVM; + + if (target_triple && target_triple[0]) + m_target_triple = target_triple; + else + m_target_triple = llvm::sys::getHostTriple(); + + // 1. Create a new compiler instance. + m_compiler.reset(new CompilerInstance()); + m_compiler->setLLVMContext(new LLVMContext()); + + // 2. Set options. + + // Parse expressions as Objective C++ regardless of context. + // Our hook into Clang's lookup mechanism only works in C++. + m_compiler->getLangOpts().CPlusPlus = true; + m_compiler->getLangOpts().ObjC1 = true; + m_compiler->getLangOpts().ThreadsafeStatics = false; + m_compiler->getLangOpts().AccessControl = false; // Debuggers get universal access + m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name + + // Set CodeGen options + m_compiler->getCodeGenOpts().EmitDeclMetadata = true; + m_compiler->getCodeGenOpts().InstrumentFunctions = false; + + // Disable some warnings. + m_compiler->getDiagnosticOpts().Warnings.push_back("no-unused-value"); + + // Set the target triple. + m_compiler->getTargetOpts().Triple = m_target_triple; + + // 3. Set up various important bits of infrastructure. + m_compiler->createDiagnostics(0, 0); + + // Create the target instance. + m_compiler->setTarget(TargetInfo::CreateTargetInfo(m_compiler->getDiagnostics(), + m_compiler->getTargetOpts())); + + assert (m_compiler->hasTarget()); + + // Inform the target of the language options + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + m_compiler->getTarget().setForcedLangOptions(m_compiler->getLangOpts()); + + // 4. Set up the diagnostic buffer for reporting errors + + m_diagnostic_buffer.reset(new clang::TextDiagnosticBuffer); + m_compiler->getDiagnostics().setClient(m_diagnostic_buffer.get()); + + // 5. Set up the source management objects inside the compiler + + if (!m_compiler->hasSourceManager()) + m_compiler->createSourceManager(); + + m_compiler->createFileManager(); + m_compiler->createPreprocessor(); + + // 6. Most of this we get from the CompilerInstance, but we + // also want to give the context an ExternalASTSource. + SelectorTable selector_table; + m_builtin_context.reset(new Builtin::Context(m_compiler->getTarget())); + + std::auto_ptr<clang::ASTContext> ast_context(new ASTContext(m_compiler->getLangOpts(), + m_compiler->getSourceManager(), + m_compiler->getTarget(), + m_compiler->getPreprocessor().getIdentifierTable(), + selector_table, + *m_builtin_context.get(), + 0)); + + ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); + + if (decl_map) + { + OwningPtr<clang::ExternalASTSource> ast_source(new ClangASTSource(*ast_context, *decl_map)); + ast_context->setExternalSource(ast_source); + } + + m_compiler->setASTContext(ast_context.release()); + + std::string module_name("___clang_module"); + + m_code_generator.reset(CreateLLVMCodeGen(m_compiler->getDiagnostics(), + module_name, + m_compiler->getCodeGenOpts(), + m_compiler->getLLVMContext())); +} + +ClangExpressionParser::~ClangExpressionParser() +{ +} + +unsigned +ClangExpressionParser::Parse (Stream &stream) +{ + m_diagnostic_buffer->FlushDiagnostics (m_compiler->getDiagnostics()); + + MemoryBuffer *memory_buffer = MemoryBuffer::getMemBufferCopy(m_expr.Text(), __FUNCTION__); + FileID memory_buffer_file_id = m_compiler->getSourceManager().createMainFileIDForMemBuffer (memory_buffer); + + m_diagnostic_buffer->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor()); + + ASTConsumer *ast_transformer = m_expr.ASTTransformer(m_code_generator.get()); + + if (ast_transformer) + ParseAST(m_compiler->getPreprocessor(), ast_transformer, m_compiler->getASTContext()); + else + ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(), m_compiler->getASTContext()); + + m_diagnostic_buffer->EndSourceFile(); + + TextDiagnosticBuffer::const_iterator diag_iterator; + + int num_errors = 0; + + for (diag_iterator = m_diagnostic_buffer->warn_begin(); + diag_iterator != m_diagnostic_buffer->warn_end(); + ++diag_iterator) + stream.Printf("warning: %s\n", (*diag_iterator).second.c_str()); + + num_errors = 0; + + for (diag_iterator = m_diagnostic_buffer->err_begin(); + diag_iterator != m_diagnostic_buffer->err_end(); + ++diag_iterator) + { + num_errors++; + stream.Printf("error: %s\n", (*diag_iterator).second.c_str()); + } + + return num_errors; +} + +Error +ClangExpressionParser::MakeDWARF () +{ + Error err; + + llvm::Module *module = m_code_generator->GetModule(); + + if (!module) + { + err.SetErrorToGenericError(); + err.SetErrorString("IR doesn't contain a module"); + return err; + } + + ClangExpressionVariableStore *local_variables = m_expr.LocalVariables(); + ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); + + if (!local_variables) + { + err.SetErrorToGenericError(); + err.SetErrorString("Can't convert an expression without a VariableList to DWARF"); + return err; + } + + if (!decl_map) + { + err.SetErrorToGenericError(); + err.SetErrorString("Can't convert an expression without a DeclMap to DWARF"); + return err; + } + + IRToDWARF ir_to_dwarf(*local_variables, decl_map, m_expr.DwarfOpcodeStream()); + + if (!ir_to_dwarf.runOnModule(*module)) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't convert the expression to DWARF"); + return err; + } + + err.Clear(); + return err; +} + +Error +ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr, ExecutionContext &exe_ctx) +{ + Error err; + + llvm::Module *module = m_code_generator->ReleaseModule(); + + if (!module) + { + err.SetErrorToGenericError(); + err.SetErrorString("IR doesn't contain a module"); + return err; + } + + ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); // result can be NULL + + if (decl_map) + { + std::string target_error; + + const llvm::Target *target = llvm::TargetRegistry::lookupTarget(m_target_triple, target_error); + + if (!target) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't find a target for %s", m_target_triple.c_str()); + return err; + } + + std::auto_ptr<llvm::TargetMachine> target_machine(target->createTargetMachine(m_target_triple, "")); + + IRForTarget ir_for_target(decl_map, target_machine->getTargetData(), m_expr.FunctionName()); + + if (!ir_for_target.runOnModule(*module)) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't convert the expression to DWARF"); + return err; + } + } + + m_jit_mm = new RecordingMemoryManager(); + + std::string error_string; + + m_execution_engine.reset(llvm::ExecutionEngine::createJIT (module, + &error_string, + m_jit_mm, + CodeGenOpt::Default, + true, + CodeModel::Small)); + + if (!m_execution_engine.get()) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str()); + return err; + } + + m_execution_engine->DisableLazyCompilation(); + + llvm::Function *function = module->getFunction (m_expr.FunctionName()); + + // We don't actually need the function pointer here, this just forces it to get resolved. + + void *fun_ptr = m_execution_engine->getPointerToFunction(function); + + // Errors usually cause failures in the JIT, but if we're lucky we get here. + + if (!fun_ptr) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't JIT the function"); + return err; + } + + m_jitted_functions.push_back (ClangExpressionParser::JittedFunction(m_expr.FunctionName(), (lldb::addr_t)fun_ptr)); + + ExecutionContext &exc_context(exe_ctx); + + if (exc_context.process == NULL) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't write the JIT compiled code into the target because there is no target"); + return err; + } + + // Look over the regions allocated for the function compiled. The JIT + // tries to allocate the functions & stubs close together, so we should try to + // write them that way too... + // For now I only write functions with no stubs, globals, exception tables, + // etc. So I only need to write the functions. + + size_t alloc_size = 0; + + std::map<uint8_t *, uint8_t *>::iterator fun_pos = m_jit_mm->m_functions.begin(); + std::map<uint8_t *, uint8_t *>::iterator fun_end = m_jit_mm->m_functions.end(); + + for (; fun_pos != fun_end; ++fun_pos) + alloc_size += (*fun_pos).second - (*fun_pos).first; + + Error alloc_error; + lldb::addr_t target_addr = exc_context.process->AllocateMemory (alloc_size, lldb::ePermissionsReadable|lldb::ePermissionsExecutable, alloc_error); + + if (target_addr == LLDB_INVALID_ADDRESS) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't allocate memory for the JITted function: %s", alloc_error.AsCString("unknown error")); + return err; + } + + lldb::addr_t cursor = target_addr; + + for (fun_pos = m_jit_mm->m_functions.begin(); fun_pos != fun_end; fun_pos++) + { + lldb::addr_t lstart = (lldb::addr_t) (*fun_pos).first; + lldb::addr_t lend = (lldb::addr_t) (*fun_pos).second; + size_t size = lend - lstart; + + Error write_error; + + if (exc_context.process->WriteMemory(cursor, (void *) lstart, size, write_error) != size) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't copy JITted function into the target: %s", write_error.AsCString("unknown error")); + return err; + } + + m_jit_mm->AddToLocalToRemoteMap (lstart, size, cursor); + cursor += size; + } + + std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); + + for (pos = m_jitted_functions.begin(); pos != end; pos++) + { + (*pos).m_remote_addr = m_jit_mm->GetRemoteAddressForLocal ((*pos).m_local_addr); + + if (!(*pos).m_name.compare(m_expr.FunctionName())) + func_addr = (*pos).m_remote_addr; + } + + err.Clear(); + return err; +} + +Error +ClangExpressionParser::DisassembleFunction (Stream &stream, ExecutionContext &exe_ctx) +{ + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); + + const char *name = m_expr.FunctionName(); + + Error ret; + + ret.Clear(); + + lldb::addr_t func_local_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t func_remote_addr = LLDB_INVALID_ADDRESS; + + std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); + + for (pos = m_jitted_functions.begin(); pos < end; pos++) + { + if (strcmp(pos->m_name.c_str(), name) == 0) + { + func_local_addr = pos->m_local_addr; + func_remote_addr = pos->m_remote_addr; + } + } + + if (func_local_addr == LLDB_INVALID_ADDRESS) + { + ret.SetErrorToGenericError(); + ret.SetErrorStringWithFormat("Couldn't find function %s for disassembly", name); + return ret; + } + + if(log) + log->Printf("Found function, has local address 0x%llx and remote address 0x%llx", (uint64_t)func_local_addr, (uint64_t)func_remote_addr); + + std::pair <lldb::addr_t, lldb::addr_t> func_range; + + func_range = m_jit_mm->GetRemoteRangeForLocal(func_local_addr); + + if (func_range.first == 0 && func_range.second == 0) + { + ret.SetErrorToGenericError(); + ret.SetErrorStringWithFormat("Couldn't find code range for function %s", name); + return ret; + } + + if(log) + log->Printf("Function's code range is [0x%llx-0x%llx]", func_range.first, func_range.second); + + if (!exe_ctx.target) + { + ret.SetErrorToGenericError(); + ret.SetErrorString("Couldn't find the target"); + } + + lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second - func_remote_addr, 0)); + + Error err; + exe_ctx.process->ReadMemory(func_remote_addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), err); + + if (!err.Success()) + { + ret.SetErrorToGenericError(); + ret.SetErrorStringWithFormat("Couldn't read from process: %s", err.AsCString("unknown error")); + return ret; + } + + ArchSpec arch(exe_ctx.target->GetArchitecture()); + + Disassembler *disassembler = Disassembler::FindPlugin(arch); + + if (disassembler == NULL) + { + ret.SetErrorToGenericError(); + ret.SetErrorStringWithFormat("Unable to find disassembler plug-in for %s architecture.", arch.AsCString()); + return ret; + } + + if (!exe_ctx.process) + { + ret.SetErrorToGenericError(); + ret.SetErrorString("Couldn't find the process"); + return ret; + } + + DataExtractor extractor(buffer_sp, + exe_ctx.process->GetByteOrder(), + exe_ctx.target->GetArchitecture().GetAddressByteSize()); + + if(log) + { + log->Printf("Function data has contents:"); + extractor.PutToLog (log, + 0, + extractor.GetByteSize(), + func_remote_addr, + 16, + DataExtractor::TypeUInt8); + } + + disassembler->DecodeInstructions(extractor, 0, UINT32_MAX); + + Disassembler::InstructionList &instruction_list = disassembler->GetInstructionList(); + + uint32_t bytes_offset = 0; + + for (uint32_t instruction_index = 0, num_instructions = instruction_list.GetSize(); + instruction_index < num_instructions; + ++instruction_index) + { + Disassembler::Instruction *instruction = instruction_list.GetInstructionAtIndex(instruction_index); + Address addr(NULL, func_remote_addr + bytes_offset); + instruction->Dump (&stream, + &addr, + &extractor, + bytes_offset, + exe_ctx, + true); + stream.PutChar('\n'); + bytes_offset += instruction->GetByteSize(); + } + + return ret; +} diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index 5d3e4c8ca0d..be107ca8eb0 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -22,6 +22,8 @@ #include "llvm/Module.h" // Project includes +#include "lldb/Expression/ASTStructExtractor.h" +#include "lldb/Expression/ClangExpressionParser.h" #include "lldb/Expression/ClangFunction.h" #include "lldb/Symbol/Type.h" #include "lldb/Core/DataExtractor.h" @@ -40,11 +42,12 @@ #include "lldb/Core/Log.h" using namespace lldb_private; + //---------------------------------------------------------------------- // ClangFunction constructor //---------------------------------------------------------------------- ClangFunction::ClangFunction(const char *target_triple, ClangASTContext *ast_context, void *return_qualtype, const Address& functionAddress, const ValueList &arg_value_list) : - ClangExpression (target_triple, NULL), + m_target_triple (target_triple), m_function_ptr (NULL), m_function_addr (functionAddress), m_function_return_qual_type(return_qualtype), @@ -53,18 +56,14 @@ ClangFunction::ClangFunction(const char *target_triple, ClangASTContext *ast_con m_wrapper_struct_name ("__lldb_caller_struct"), m_wrapper_function_addr (), m_wrapper_args_addrs (), - m_struct_layout (NULL), m_arg_values (arg_value_list), - m_value_struct_size (0), - m_return_offset(0), - m_return_size (0), m_compiled (false), m_JITted (false) { } ClangFunction::ClangFunction(const char *target_triple, Function &function, ClangASTContext *ast_context, const ValueList &arg_value_list) : - ClangExpression (target_triple, NULL), + m_target_triple (target_triple), m_function_ptr (&function), m_function_addr (), m_function_return_qual_type (), @@ -73,11 +72,7 @@ ClangFunction::ClangFunction(const char *target_triple, Function &function, Clan m_wrapper_struct_name ("__lldb_caller_struct"), m_wrapper_function_addr (), m_wrapper_args_addrs (), - m_struct_layout (NULL), m_arg_values (arg_value_list), - m_value_struct_size (0), - m_return_offset (0), - m_return_size (0), m_compiled (false), m_JITted (false) { @@ -95,154 +90,125 @@ 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; - if (!m_compiled) + std::string return_type_str = ClangASTContext::GetTypeName(m_function_return_qual_type); + + // 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. + if (m_function_ptr) { - std::string return_type_str = ClangASTContext::GetTypeName(m_function_return_qual_type); - - // 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... - std::string expression; - expression.append ("extern \"C\" void "); - expression.append (m_wrapper_function_name); - expression.append (" (void *input)\n{\n struct "); - expression.append (m_wrapper_struct_name); - expression.append (" \n {\n"); - expression.append (" "); - expression.append (return_type_str); - expression.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. - if (m_function_ptr) - { - int num_func_args = m_function_ptr->GetArgumentCount(); - if (num_func_args >= 0) - trust_function = true; - else - num_args = num_func_args; - } + int num_func_args = m_function_ptr->GetArgumentCount(); + if (num_func_args >= 0) + trust_function = true; + else + num_args = num_func_args; + } - if (num_args == UINT32_MAX) - num_args = m_arg_values.GetSize(); + 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++) - { - const char *type_string; - std::string type_stdstr; + 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++) + { + const char *type_string; + std::string type_stdstr; - if (trust_function) + if (trust_function) + { + type_string = m_function_ptr->GetArgumentTypeAtIndex(i).GetName().AsCString(); + } + else + { + Value *arg_value = m_arg_values.GetValueAtIndex(i); + void *clang_qual_type = arg_value->GetOpaqueClangQualType (); + if (clang_qual_type != NULL) { - type_string = m_function_ptr->GetArgumentTypeAtIndex(i).GetName().AsCString(); + type_stdstr = ClangASTContext::GetTypeName(clang_qual_type); + type_string = type_stdstr.c_str(); } else - { - Value *arg_value = m_arg_values.GetValueAtIndex(i); - void *clang_qual_type = arg_value->GetOpaqueClangQualType (); - if (clang_qual_type != NULL) - { - type_stdstr = ClangASTContext::GetTypeName(clang_qual_type); - type_string = type_stdstr.c_str(); - } - else - { - errors.Printf("Could not determine type of input value %d.", i); - return 1; - } + { + errors.Printf("Could not determine type of input value %d.", i); + return 1; } + } + m_wrapper_function_text.append (type_string); + if (i < num_args - 1) + m_wrapper_function_text.append (", "); - expression.append (type_string); - if (i < num_args - 1) - expression.append (", "); - - char arg_buf[32]; - args_buffer.append (" "); - args_buffer.append (type_string); - snprintf(arg_buf, 31, "arg_%zd", 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 (", "); - - } - expression.append (");\n"); // Close off the function calling prototype. - - expression.append (args_buffer); - - expression.append (" "); - expression.append (return_type_str); - expression.append (" return_value;"); - expression.append ("\n };\n struct "); - expression.append (m_wrapper_struct_name); - expression.append ("* __lldb_fn_data = (struct "); - expression.append (m_wrapper_struct_name); - expression.append (" *) input;\n"); - - expression.append (" __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr ("); - expression.append (args_list_buffer); - expression.append (");\n}\n"); - - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); - if (log) - log->Printf ("Expression: \n\n%s\n\n", expression.c_str()); - - // Okay, now compile this expression: - num_errors = ParseBareExpression (expression.c_str(), errors); - m_compiled = (num_errors == 0); - - if (m_compiled) - { - using namespace clang; - CompilerInstance *compiler_instance = GetCompilerInstance(); - ASTContext &ast_context = compiler_instance->getASTContext(); + char arg_buf[32]; + args_buffer.append (" "); + args_buffer.append (type_string); + snprintf(arg_buf, 31, "arg_%zd", i); + args_buffer.push_back (' '); + args_buffer.append (arg_buf); + args_buffer.append (";\n"); - DeclarationName wrapper_func_name(&ast_context.Idents.get(m_wrapper_function_name.c_str())); - FunctionDecl::lookup_result func_lookup = ast_context.getTranslationUnitDecl()->lookup(wrapper_func_name); - if (func_lookup.first == func_lookup.second) - return false; + args_list_buffer.append ("__lldb_fn_data->"); + args_list_buffer.append (arg_buf); + if (i < num_args - 1) + args_list_buffer.append (", "); - FunctionDecl *wrapper_func = dyn_cast<FunctionDecl> (*(func_lookup.first)); - if (!wrapper_func) - return false; + } + m_wrapper_function_text.append (");\n"); // Close off the function calling prototype. - DeclarationName wrapper_struct_name(&ast_context.Idents.get(m_wrapper_struct_name.c_str())); - RecordDecl::lookup_result struct_lookup = wrapper_func->lookup(wrapper_struct_name); - if (struct_lookup.first == struct_lookup.second) - return false; + m_wrapper_function_text.append (args_buffer); - RecordDecl *wrapper_struct = dyn_cast<RecordDecl>(*(struct_lookup.first)); + 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"); - if (!wrapper_struct) - return false; + 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"); - m_struct_layout = &ast_context.getASTRecordLayout (wrapper_struct); - if (!m_struct_layout) - { - m_compiled = false; - return 1; - } - m_return_offset = m_struct_layout->getFieldOffset(m_struct_layout->getFieldCount() - 1); - m_return_size = (m_struct_layout->getDataSize() - m_return_offset)/8; - } - } + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); + if (log) + log->Printf ("Expression: \n\n%s\n\n", m_wrapper_function_text.c_str()); + + // Okay, now compile this expression + + m_parser.reset(new ClangExpressionParser(m_target_triple.c_str(), *this)); + + num_errors = m_parser->Parse (errors); + + m_compiled = (num_errors == 0); + + if (!m_compiled) + return num_errors; return num_errors; } @@ -252,24 +218,18 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) { Process *process = exe_ctx.process; - if (process == NULL) + if (!process) + return false; + + if (!m_compiled) return false; - if (!m_JITted) - { - // Next we should JIT it and insert the result into the target program. - if (!JITFunction (m_wrapper_function_name.c_str())) - return false; - - if (!WriteJITCode (exe_ctx)) - return false; - - m_JITted = true; - } - - // Next get the call address for the function: - m_wrapper_function_addr = GetFunctionAddress (m_wrapper_function_name.c_str()); - if (m_wrapper_function_addr == LLDB_INVALID_ADDRESS) + if (m_JITted) + return true; + + Error jit_error = m_parser->MakeJIT(m_wrapper_function_addr, exe_ctx); + + if (!jit_error.Success()) return false; return true; @@ -286,12 +246,14 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t & bool ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Address function_address, ValueList &arg_values, Stream &errors) { - // Otherwise, allocate space for the argument passing struct, and write it. - // We use the information in the expression parser AST to - // figure out how to do this... - // We should probably transcode this in this object so we can ditch the compiler instance - // and all its associated data, and just keep the JITTed bytes. - + // All the information to reconstruct the struct is provided by the + // StructExtractor. + if (!m_struct_valid) + { + errors.Printf("Argument information was not correctly parsed, so the function cannot be called."); + return false; + } + Error error; using namespace clang; ExecutionResults return_value = eExecutionSetupError; @@ -300,12 +262,10 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t & if (process == NULL) return return_value; - - uint64_t struct_size = m_struct_layout->getSize()/8; // Clang returns sizes in bytes. - + if (args_addr_ref == LLDB_INVALID_ADDRESS) { - args_addr_ref = process->AllocateMemory(struct_size, lldb::ePermissionsReadable|lldb::ePermissionsWritable, error); + args_addr_ref = process->AllocateMemory(m_struct_size, lldb::ePermissionsReadable|lldb::ePermissionsWritable, error); if (args_addr_ref == LLDB_INVALID_ADDRESS) return false; m_wrapper_args_addrs.push_back (args_addr_ref); @@ -323,7 +283,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t & // Make a data extractor and put the address into the right byte order & size. uint64_t fun_addr = function_address.GetLoadAddress(exe_ctx.process); - int first_offset = m_struct_layout->getFieldOffset(0)/8; + int first_offset = m_member_offsets[0]; process->WriteMemory(args_addr_ref + first_offset, &fun_addr, 8, error); // FIXME: We will need to extend this for Variadic functions. @@ -341,7 +301,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t & { // FIXME: We should sanity check sizes. - int offset = m_struct_layout->getFieldOffset(i+1)/8; // Clang sizes are in bytes. + int offset = m_member_offsets[i+1]; // Clang sizes are in bytes. Value *arg_value = arg_values.GetValueAtIndex(i); // FIXME: For now just do scalars: @@ -419,7 +379,7 @@ ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t arg data_buffer.resize(m_return_size); Process *process = exe_ctx.process; Error error; - size_t bytes_read = process->ReadMemory(args_addr + m_return_offset/8, &data_buffer.front(), m_return_size, error); + size_t bytes_read = process->ReadMemory(args_addr + m_return_offset, &data_buffer.front(), m_return_size, error); if (bytes_read == 0) { @@ -717,69 +677,8 @@ ClangFunction::ExecuteFunction( return eExecutionCompleted; } -ClangFunction::ExecutionResults -ClangFunction::ExecuteFunctionWithABI(ExecutionContext &exe_ctx, Stream &errors, Value &results) +clang::ASTConsumer * +ClangFunction::ASTTransformer (clang::ASTConsumer *passthrough) { - // FIXME: Use the errors Stream for better error reporting. - using namespace clang; - ExecutionResults return_value = eExecutionSetupError; - - Process *process = exe_ctx.process; - - if (process == NULL) - { - errors.Printf("Can't call a function without a process."); - return return_value; - } - - //unsigned int num_args = m_arg_values.GetSize(); - //unsigned int arg_index; - - //for (arg_index = 0; arg_index < num_args; ++arg_index) - // m_arg_values.GetValueAtIndex(arg_index)->ResolveValue(&exe_ctx, GetASTContext()); - - ThreadPlan *call_plan = exe_ctx.thread->QueueThreadPlanForCallFunction (false, - m_function_addr, - m_arg_values, - true); - if (call_plan == NULL) - return return_value; - - call_plan->SetPrivate(true); - - // We need to call the function synchronously, so spin waiting for it to return. - // If we get interrupted while executing, we're going to lose our context, and - // won't be able to gather the result at this point. - - process->Resume (); - - while (1) - { - lldb::EventSP event_sp; - - // Now wait for the process to stop again: - // FIXME: Probably want a time out. - lldb::StateType stop_state = process->WaitForStateChangedEvents (NULL, event_sp); - if (stop_state == lldb::eStateRunning || stop_state == lldb::eStateStepping) - continue; - - if (exe_ctx.thread->IsThreadPlanDone (call_plan)) - { - return_value = eExecutionCompleted; - break; - } - else if (exe_ctx.thread->WasThreadPlanDiscarded (call_plan)) - { - return_value = eExecutionDiscarded; - break; - } - else - { - return_value = eExecutionInterrupted; - break; - } - - } - - return eExecutionCompleted; + return new ASTStructExtractor(passthrough, m_wrapper_struct_name.c_str(), *this); } diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp new file mode 100644 index 00000000000..afd94bbd6a8 --- /dev/null +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -0,0 +1,257 @@ +//===-- 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 <cstdlib> +#include <string> +#include <map> + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Expression/ClangExpressionDeclMap.h" +#include "lldb/Expression/ClangExpressionParser.h" +#include "lldb/Expression/ClangFunction.h" +#include "lldb/Expression/ASTResultSynthesizer.h" +#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Host/Host.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" + +using namespace lldb_private; + +ClangUserExpression::ClangUserExpression (const char *expr) : + m_expr_text(expr), + m_jit_addr(LLDB_INVALID_ADDRESS) +{ + StreamString m_transformed_stream; + + m_transformed_stream.Printf("extern \"C\" void %s(void *___clang_arg) { %s; }\n", + FunctionName(), + m_expr_text.c_str()); + + m_transformed_text = m_transformed_stream.GetData(); +} + +clang::ASTConsumer * +ClangUserExpression::ASTTransformer (clang::ASTConsumer *passthrough) +{ + return new ASTResultSynthesizer(passthrough); +} + +bool +ClangUserExpression::Parse (Stream &error_stream, ExecutionContext &exe_ctx) +{ + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); + + //////////////////////////////////// + // Set up the target and compiler + // + + Target *target = exe_ctx.target; + + if (!target) + { + error_stream.PutCString ("error: invalid target\n"); + return false; + } + + ConstString target_triple; + + target->GetTargetTriple (target_triple); + + if (!target_triple) + target_triple = Host::GetTargetTriple (); + + if (!target_triple) + { + error_stream.PutCString ("error: invalid target triple\n"); + return false; + } + + ////////////////////////// + // Parse the expression + // + + m_expr_decl_map.reset(new ClangExpressionDeclMap(&exe_ctx)); + + ClangExpressionParser parser(target_triple.GetCString(), *this); + + unsigned num_errors = parser.Parse (error_stream); + + if (num_errors) + { + error_stream.Printf ("error: %d errors parsing expression\n", num_errors); + return false; + } + + /////////////////////////////////////////////// + // Convert the output of the parser to DWARF + // + + m_dwarf_opcodes.reset(new StreamString); + m_dwarf_opcodes->SetByteOrder (lldb::eByteOrderHost); + m_dwarf_opcodes->GetFlags ().Set (Stream::eBinary); + + m_local_variables.reset(new ClangExpressionVariableStore()); + + Error dwarf_error = parser.MakeDWARF (); + + if (dwarf_error.Success()) + { + if (log) + log->Printf("Code can be interpreted."); + + return true; + } + + ////////////////////////////////// + // JIT the output of the parser + // + + m_dwarf_opcodes.reset(); + + Error jit_error = parser.MakeJIT (m_jit_addr, exe_ctx); + + if (jit_error.Success()) + { + if (log) + { + log->Printf("Code can be run in the target."); + + StreamString disassembly_stream; + + Error err = parser.DisassembleFunction(disassembly_stream, exe_ctx); + + if (!err.Success()) + { + log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error")); + } + else + { + log->Printf("Function disassembly:\n%s", disassembly_stream.GetData()); + } + } + + return true; + } + else + { + error_stream.Printf ("error: expression can't be interpreted or run\n", num_errors); + return false; + } +} + +bool +ClangUserExpression::Execute (Stream &error_stream, + ExecutionContext &exe_ctx, + ClangExpressionVariable *&result) +{ + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); + + if (m_dwarf_opcodes.get()) + { + // TODO execute the JITted opcodes + + error_stream.Printf("We don't currently support executing DWARF expressions"); + + return false; + } + else if (m_jit_addr != LLDB_INVALID_ADDRESS) + { + lldb::addr_t struct_address; + + Error materialize_error; + + if (!m_expr_decl_map->Materialize(&exe_ctx, struct_address, materialize_error)) + { + error_stream.Printf("Couldn't materialize struct: %s\n", materialize_error.AsCString("unknown error")); + return false; + } + + if (log) + { + log->Printf("Function address : 0x%llx", (uint64_t)m_jit_addr); + log->Printf("Structure address : 0x%llx", (uint64_t)struct_address); + + StreamString args; + + Error dump_error; + + if (!m_expr_decl_map->DumpMaterializedStruct(&exe_ctx, args, dump_error)) + { + log->Printf("Couldn't extract variable values : %s", dump_error.AsCString("unknown error")); + } + else + { + log->Printf("Structure contents:\n%s", args.GetData()); + } + } + + ClangFunction::ExecutionResults execution_result = + ClangFunction::ExecuteFunction (exe_ctx, m_jit_addr, struct_address, true, true, 10000, error_stream); + + if (execution_result != ClangFunction::eExecutionCompleted) + { + const char *result_name; + + switch (execution_result) + { + case ClangFunction::eExecutionCompleted: + result_name = "eExecutionCompleted"; + break; + case ClangFunction::eExecutionDiscarded: + result_name = "eExecutionDiscarded"; + break; + case ClangFunction::eExecutionInterrupted: + result_name = "eExecutionInterrupted"; + break; + case ClangFunction::eExecutionSetupError: + result_name = "eExecutionSetupError"; + break; + case ClangFunction::eExecutionTimedOut: + result_name = "eExecutionTimedOut"; + break; + } + + error_stream.Printf ("Couldn't execute function; result was %s\n", result_name); + return false; + } + + Error expr_error; + + if (!m_expr_decl_map->Dematerialize(&exe_ctx, result, expr_error)) + { + error_stream.Printf ("Couldn't dematerialize struct : %s\n", expr_error.AsCString("unknown error")); + return false; + } + + return true; + } + else + { + error_stream.Printf("Expression can't be run; neither DWARF nor a JIT compiled function are present"); + return false; + } +} + +StreamString & +ClangUserExpression::DwarfOpcodeStream () +{ + if (!m_dwarf_opcodes.get()) + m_dwarf_opcodes.reset(new StreamString()); + + return *m_dwarf_opcodes.get(); +} diff --git a/lldb/source/Expression/IRForTarget.cpp b/lldb/source/Expression/IRForTarget.cpp index c14891b160c..d74302c7299 100644 --- a/lldb/source/Expression/IRForTarget.cpp +++ b/lldb/source/Expression/IRForTarget.cpp @@ -31,11 +31,13 @@ using namespace llvm; static char ID; IRForTarget::IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map, - const TargetData *target_data) : + const TargetData *target_data, + const char *func_name) : ModulePass(&ID), m_decl_map(decl_map), m_target_data(target_data), - m_sel_registerName(NULL) + m_sel_registerName(NULL), + m_func_name(func_name) { } @@ -910,12 +912,12 @@ IRForTarget::runOnModule(Module &M) { lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - Function* function = M.getFunction(StringRef("___clang_expr")); + Function* function = M.getFunction(StringRef(m_func_name.c_str())); if (!function) { if (log) - log->Printf("Couldn't find ___clang_expr() in the module"); + log->Printf("Couldn't find %s() in the module", m_func_name.c_str()); return false; } diff --git a/lldb/source/Expression/IRToDWARF.cpp b/lldb/source/Expression/IRToDWARF.cpp index 121a47c171e..b158da6c1f5 100644 --- a/lldb/source/Expression/IRToDWARF.cpp +++ b/lldb/source/Expression/IRToDWARF.cpp @@ -26,13 +26,15 @@ using namespace llvm; static char ID; -IRToDWARF::IRToDWARF(lldb_private::ClangExpressionVariableList &variable_list, +IRToDWARF::IRToDWARF(lldb_private::ClangExpressionVariableStore &local_vars, lldb_private::ClangExpressionDeclMap *decl_map, - lldb_private::StreamString &strm) : + lldb_private::StreamString &strm, + const char *func_name) : ModulePass(&ID), - m_variable_list(variable_list), + m_local_vars(local_vars), m_decl_map(decl_map), - m_strm(strm) + m_strm(strm), + m_func_name(func_name) { } @@ -171,14 +173,14 @@ IRToDWARF::runOnModule(Module &M) { lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - llvm::Function* function = M.getFunction(StringRef("___clang_expr")); + llvm::Function* function = M.getFunction(StringRef(m_func_name.c_str())); if (!function) { if (log) - log->Printf("Couldn't find ___clang_expr() in the module"); + log->Printf("Couldn't find %s() in the module", m_func_name.c_str()); - return 1; + return false; } Relocator relocator; diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index db5cb65f42e..eaf886f76ad 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -16,7 +16,7 @@ #include "../Commands/CommandObjectApropos.h" #include "../Commands/CommandObjectArgs.h" #include "../Commands/CommandObjectBreakpoint.h" -#include "../Commands/CommandObjectCall.h" +//#include "../Commands/CommandObjectCall.h" #include "../Commands/CommandObjectDelete.h" #include "../Commands/CommandObjectDisassemble.h" #include "../Commands/CommandObjectExpression.h" @@ -207,7 +207,7 @@ CommandInterpreter::LoadCommandDictionary () m_command_dict["append"] = CommandObjectSP (new CommandObjectAppend ()); m_command_dict["apropos"] = CommandObjectSP (new CommandObjectApropos ()); m_command_dict["breakpoint"]= CommandObjectSP (new CommandObjectMultiwordBreakpoint (*this)); - m_command_dict["call"] = CommandObjectSP (new CommandObjectCall ()); + //m_command_dict["call"] = CommandObjectSP (new CommandObjectCall ()); m_command_dict["commands"] = CommandObjectSP (new CommandObjectMultiwordCommands (*this)); m_command_dict["disassemble"] = CommandObjectSP (new CommandObjectDisassemble ()); m_command_dict["expression"]= CommandObjectSP (new CommandObjectExpression ()); |