summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Core/ClangForward.h2
-rw-r--r--lldb/include/lldb/Expression/ASTResultSynthesizer.h (renamed from lldb/include/lldb/Expression/ClangResultSynthesizer.h)16
-rw-r--r--lldb/include/lldb/Expression/ASTStructExtractor.h156
-rw-r--r--lldb/include/lldb/Expression/ClangExpression.h258
-rw-r--r--lldb/include/lldb/Expression/ClangExpressionParser.h182
-rw-r--r--lldb/include/lldb/Expression/ClangFunction.h519
-rw-r--r--lldb/include/lldb/Expression/ClangUserExpression.h160
-rw-r--r--lldb/include/lldb/Expression/IRForTarget.h9
-rw-r--r--lldb/include/lldb/Expression/IRToDWARF.h15
-rw-r--r--lldb/include/lldb/Expression/RecordingMemoryManager.h3
-rw-r--r--lldb/include/lldb/lldb-forward.h1
-rw-r--r--lldb/lldb.xcodeproj/project.pbxproj46
-rw-r--r--lldb/source/Commands/CommandObjectCall.cpp11
-rw-r--r--lldb/source/Commands/CommandObjectExpression.cpp186
-rw-r--r--lldb/source/Expression/ASTResultSynthesizer.cpp (renamed from lldb/source/Expression/ClangResultSynthesizer.cpp)30
-rw-r--r--lldb/source/Expression/ASTStructExtractor.cpp191
-rw-r--r--lldb/source/Expression/ClangExpression.cpp748
-rw-r--r--lldb/source/Expression/ClangExpressionParser.cpp640
-rw-r--r--lldb/source/Expression/ClangFunction.cpp363
-rw-r--r--lldb/source/Expression/ClangUserExpression.cpp257
-rw-r--r--lldb/source/Expression/IRForTarget.cpp10
-rw-r--r--lldb/source/Expression/IRToDWARF.cpp16
-rw-r--r--lldb/source/Interpreter/CommandInterpreter.cpp4
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 ());
OpenPOWER on IntegriCloud