diff options
17 files changed, 1371 insertions, 1314 deletions
diff --git a/lldb/include/lldb/Expression/ClangExpression.h b/lldb/include/lldb/Expression/ClangExpression.h index ac29024804e..07a9ca096f2 100644 --- a/lldb/include/lldb/Expression/ClangExpression.h +++ b/lldb/include/lldb/Expression/ClangExpression.h @@ -48,7 +48,6 @@ public: ClangExpression () : m_jit_process_wp(), - m_jit_alloc (LLDB_INVALID_ADDRESS), m_jit_start_addr (LLDB_INVALID_ADDRESS), m_jit_end_addr (LLDB_INVALID_ADDRESS) { @@ -59,7 +58,6 @@ public: //------------------------------------------------------------------ virtual ~ClangExpression () { - DeallocateJITFunction (); } //------------------------------------------------------------------ @@ -140,20 +138,6 @@ public: virtual bool NeedsVariableResolution () = 0; - void - DeallocateJITFunction () - { - lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); - if (jit_process_sp && m_jit_alloc != LLDB_INVALID_ADDRESS) - { - jit_process_sp->DeallocateMemory (m_jit_alloc); - // If this process is ever used for anything else, we can not clear it - // here. For now it is only used in order to deallocate any code if - // m_jit_alloc is a valid address. - m_jit_alloc = LLDB_INVALID_ADDRESS; - } - } - //------------------------------------------------------------------ /// Return the address of the function's JIT-compiled code, or /// LLDB_INVALID_ADDRESS if the function is not JIT compiled @@ -167,7 +151,6 @@ public: protected: lldb::ProcessWP m_jit_process_wp; - lldb::addr_t m_jit_alloc; ///< The address of the block containing JITted code. LLDB_INVALID_ADDRESS if invalid. lldb::addr_t m_jit_start_addr; ///< The address of the JITted function within the JIT allocation. LLDB_INVALID_ADDRESS if invalid. lldb::addr_t m_jit_end_addr; ///< The address of the JITted function within the JIT allocation. LLDB_INVALID_ADDRESS if invalid. diff --git a/lldb/include/lldb/Expression/ClangExpressionParser.h b/lldb/include/lldb/Expression/ClangExpressionParser.h index c3323b88e13..57172c5e3ab 100644 --- a/lldb/include/lldb/Expression/ClangExpressionParser.h +++ b/lldb/include/lldb/Expression/ClangExpressionParser.h @@ -22,7 +22,7 @@ namespace lldb_private { -class RecordingMemoryManager; +class IRExecutionUnit; //---------------------------------------------------------------------- /// @class ClangExpressionParser ClangExpressionParser.h "lldb/Expression/ClangExpressionParser.h" @@ -76,10 +76,6 @@ public: /// Ready an already-parsed expression for execution, possibly /// evaluating it statically. /// - /// @param[out] func_allocation_addr - /// The address which can be used to deallocate the code for this - /// JIT'ed function - /// /// @param[out] func_addr /// The address to which the function has been written. /// @@ -91,9 +87,6 @@ public: /// @param[in] exe_ctx /// The execution context to write the function into. /// - /// @param[in] data_allocator - /// If non-NULL, the static data allocator to use for literal strings. - /// /// @param[out] evaluated_statically /// Set to true if the expression could be interpreted statically; /// untouched otherwise. @@ -113,11 +106,9 @@ public: /// Test with Success(). //------------------------------------------------------------------ Error - PrepareForExecution (lldb::addr_t &func_allocation_addr, - lldb::addr_t &func_addr, + PrepareForExecution (lldb::addr_t &func_addr, lldb::addr_t &func_end, ExecutionContext &exe_ctx, - IRForTarget::StaticDataAllocator *data_allocator, bool &evaluated_statically, lldb::ClangExpressionVariableSP &const_result, lldb_private::ExecutionPolicy execution_policy); @@ -137,49 +128,9 @@ public: //------------------------------------------------------------------ Error DisassembleFunction (Stream &stream, - ExecutionContext &exe_ctx, - RecordingMemoryManager *jit_memory_manager); + ExecutionContext &exe_ctx); 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::auto_ptr<llvm::LLVMContext> m_llvm_context; ///< The LLVM context to generate IR into @@ -188,8 +139,8 @@ private: std::auto_ptr<clang::Builtin::Context> m_builtin_context; ///< Context for Clang built-ins std::auto_ptr<clang::SelectorTable> m_selector_table; ///< Selector table for Objective-C methods 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 - std::vector<JittedFunction> m_jitted_functions; ///< A vector of all functions that have been JITted into machine code (just one, if ParseExpression() was called) + std::auto_ptr<clang::CodeGenerator> m_code_generator; ///< The Clang object that generates IR + std::auto_ptr<IRExecutionUnit> m_execution_unit; ///< The container for the finished Module }; } diff --git a/lldb/include/lldb/Expression/ClangUserExpression.h b/lldb/include/lldb/Expression/ClangUserExpression.h index b7484fa41a4..aae149552cc 100644 --- a/lldb/include/lldb/Expression/ClangUserExpression.h +++ b/lldb/include/lldb/Expression/ClangUserExpression.h @@ -26,7 +26,6 @@ #include "lldb/Expression/ClangExpression.h" #include "lldb/Expression/ClangExpressionVariable.h" #include "lldb/Expression/IRForTarget.h" -#include "lldb/Expression/ProcessDataAllocator.h" #include "lldb/Symbol/TaggedASTType.h" #include "lldb/Target/ExecutionContext.h" @@ -433,7 +432,6 @@ private: std::auto_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression. std::auto_ptr<ClangExpressionVariableList> m_local_variables; ///< The local expression variables, if the expression is DWARF. - std::auto_ptr<ProcessDataAllocator> m_data_allocator; ///< The allocator that the parser uses to place strings for use by JIT-compiled code. std::auto_ptr<ASTResultSynthesizer> m_result_synthesizer; ///< The result synthesizer, if one is needed. diff --git a/lldb/include/lldb/Expression/ClangUtilityFunction.h b/lldb/include/lldb/Expression/ClangUtilityFunction.h index 14275c1c931..929f9238714 100644 --- a/lldb/include/lldb/Expression/ClangUtilityFunction.h +++ b/lldb/include/lldb/Expression/ClangUtilityFunction.h @@ -24,7 +24,6 @@ #include "lldb/lldb-private.h" #include "lldb/Core/ClangForward.h" #include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ProcessDataAllocator.h" namespace lldb_private { @@ -170,7 +169,6 @@ public: private: std::auto_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression. - std::auto_ptr<ProcessDataAllocator> m_data_allocator; ///< The allocator for static data used in the expression. std::string m_function_text; ///< The text of the function. Must be a well-formed translation unit. std::string m_function_name; ///< The name of the function. diff --git a/lldb/include/lldb/Expression/IRExecutionUnit.h b/lldb/include/lldb/Expression/IRExecutionUnit.h new file mode 100644 index 00000000000..4ff71ff5f00 --- /dev/null +++ b/lldb/include/lldb/Expression/IRExecutionUnit.h @@ -0,0 +1,512 @@ +//===-- IRExecutionUnit.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_IRExecutionUnit_h_ +#define lldb_IRExecutionUnit_h_ + +// C Includes +// C++ Includes +#include <atomic> +#include <string> +#include <vector> +#include <map> + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" +#include "lldb/Core/ClangForward.h" +#include "llvm/ExecutionEngine/JITMemoryManager.h" +#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/ClangExpressionParser.h" +#include "lldb/Host/Mutex.h" + +namespace llvm { + +class Module; +class ExecutionEngine; + +} + +namespace lldb_private { + +class Error; + +//---------------------------------------------------------------------- +/// @class IRExecutionUnit IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.h" +/// @brief Contains the IR and, optionally, JIT-compiled code for a module. +/// +/// This class encapsulates the compiled version of an expression, in IR +/// form (for interpretation purposes) and in raw machine code form (for +/// execution in the target). +/// +/// This object wraps an IR module that comes from the expression parser, +/// and knows how to use the JIT to make it into executable code. It can +/// then be used as input to the IR interpreter, or the address of the +/// executable code can be passed to a thread plan to run in the target. +/// +/// This class creates a subclass of LLVM's JITMemoryManager, because that is +/// how the JIT emits code. Because LLDB needs to move JIT-compiled code +/// into the target process, the IRExecutionUnit knows how to copy the +/// emitted code into the target process. +//---------------------------------------------------------------------- +class IRExecutionUnit +{ +public: + //------------------------------------------------------------------ + /// Constructor + //------------------------------------------------------------------ + IRExecutionUnit (std::auto_ptr<llvm::Module> &module_ap, + ConstString &name, + lldb::ProcessSP process_sp, + std::vector<std::string> &cpu_features); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~IRExecutionUnit(); + + llvm::Module *GetModule() + { + return m_module; + } + + void GetRunnableInfo(Error &error, + lldb::addr_t &func_addr, + lldb::addr_t &func_end); + + //------------------------------------------------------------------ + /// Accessors for IRForTarget and other clients that may want binary + /// data placed on their behalf. The binary data is owned by the + /// IRExecutionUnit unless the client explicitly chooses to free it. + //------------------------------------------------------------------ + + lldb::addr_t WriteNow(const uint8_t *bytes, + size_t size, + Error &error); + + void FreeNow(lldb::addr_t allocation); + +private: + //------------------------------------------------------------------ + /// Look up the object in m_address_map that contains a given address, + /// find where it was copied to, and return the remote address at the + /// same offset into the copied entity + /// + /// @param[in] local_address + /// The address in the debugger. + /// + /// @return + /// The address in the target process. + //------------------------------------------------------------------ + lldb::addr_t + GetRemoteAddressForLocal (lldb::addr_t local_address); + + //------------------------------------------------------------------ + /// Look up the object in m_address_map that contains a given address, + /// find where it was copied to, and return its address range in the + /// target process + /// + /// @param[in] local_address + /// The address in the debugger. + /// + /// @return + /// The range of the containing object in the target process. + //------------------------------------------------------------------ + typedef std::pair <lldb::addr_t, uintptr_t> AddrRange; + AddrRange + GetRemoteRangeForLocal (lldb::addr_t local_address); + + //------------------------------------------------------------------ + /// Commit all allocations to the process and record where they were stored. + /// + /// @param[in] process + /// The process to allocate memory in. + /// + /// @return + /// True <=> all allocations were performed successfully. + /// This method will attempt to free allocated memory if the + /// operation fails. + //------------------------------------------------------------------ + bool + CommitAllocations (lldb::ProcessSP &process_sp); + + //------------------------------------------------------------------ + /// Report all committed allocations to the execution engine. + /// + /// @param[in] engine + /// The execution engine to notify. + //------------------------------------------------------------------ + void + ReportAllocations (llvm::ExecutionEngine &engine); + + //------------------------------------------------------------------ + /// Write the contents of all allocations to the process. + /// + /// @param[in] local_address + /// The process containing the allocations. + /// + /// @return + /// True <=> all allocations were performed successfully. + //------------------------------------------------------------------ + bool + WriteData (lldb::ProcessSP &process_sp); + + Error + DisassembleFunction (Stream &stream, + lldb::ProcessSP &process_sp); + + class MemoryManager : public llvm::JITMemoryManager + { + public: + MemoryManager (IRExecutionUnit &parent); + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual void setMemoryWritable (); + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual void setMemoryExecutable (); + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual void setPoisonMemory (bool poison) + { + m_default_mm_ap->setPoisonMemory (poison); + } + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual void AllocateGOT() + { + m_default_mm_ap->AllocateGOT(); + } + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual uint8_t *getGOTBase() const + { + return m_default_mm_ap->getGOTBase(); + } + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual uint8_t *startFunctionBody(const llvm::Function *F, + uintptr_t &ActualSize); + + //------------------------------------------------------------------ + /// Allocate room for a dyld stub for a lazy-referenced function, + /// and add it to the m_stubs map + /// + /// @param[in] F + /// The function being referenced. + /// + /// @param[in] StubSize + /// The size of the stub. + /// + /// @param[in] Alignment + /// The required alignment of the stub. + /// + /// @return + /// Allocated space for the stub. + //------------------------------------------------------------------ + virtual uint8_t *allocateStub(const llvm::GlobalValue* F, + unsigned StubSize, + unsigned Alignment); + + //------------------------------------------------------------------ + /// Complete the body of a function, and add it to the m_functions map + /// + /// @param[in] F + /// The function being completed. + /// + /// @param[in] FunctionStart + /// The first instruction of the function. + /// + /// @param[in] FunctionEnd + /// The last byte of the last instruction of the function. + //------------------------------------------------------------------ + virtual void endFunctionBody(const llvm::Function *F, + uint8_t *FunctionStart, + uint8_t *FunctionEnd); + //------------------------------------------------------------------ + /// Allocate space for an unspecified purpose, and add it to the + /// m_spaceBlocks map + /// + /// @param[in] Size + /// The size of the area. + /// + /// @param[in] Alignment + /// The required alignment of the area. + /// + /// @return + /// Allocated space. + //------------------------------------------------------------------ + virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); + + //------------------------------------------------------------------ + /// Allocate space for executable code, and add it to the + /// m_spaceBlocks map + /// + /// @param[in] Size + /// The size of the area. + /// + /// @param[in] Alignment + /// The required alignment of the area. + /// + /// @param[in] SectionID + /// A unique identifier for the section. + /// + /// @return + /// Allocated space. + //------------------------------------------------------------------ + virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID); + + //------------------------------------------------------------------ + /// Allocate space for data, and add it to the m_spaceBlocks map + /// + /// @param[in] Size + /// The size of the area. + /// + /// @param[in] Alignment + /// The required alignment of the area. + /// + /// @param[in] SectionID + /// A unique identifier for the section. + /// + /// @param[in] IsReadOnly + /// Flag indicating the section is read-only. + /// + /// @return + /// Allocated space. + //------------------------------------------------------------------ + virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, bool IsReadOnly); + + //------------------------------------------------------------------ + /// Allocate space for a global variable, and add it to the + /// m_spaceBlocks map + /// + /// @param[in] Size + /// The size of the variable. + /// + /// @param[in] Alignment + /// The required alignment of the variable. + /// + /// @return + /// Allocated space for the global. + //------------------------------------------------------------------ + virtual uint8_t *allocateGlobal(uintptr_t Size, + unsigned Alignment); + + //------------------------------------------------------------------ + /// Called when object loading is complete and section page + /// permissions can be applied. Currently unimplemented for LLDB. + /// + /// @param[out] ErrMsg + /// The error that prevented the page protection from succeeding. + /// + /// @return + /// True in case of failure, false in case of success. + //------------------------------------------------------------------ + bool applyPermissions(std::string *ErrMsg) { return false; } + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual void deallocateFunctionBody(void *Body); + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual uint8_t* startExceptionTable(const llvm::Function* F, + uintptr_t &ActualSize); + + //------------------------------------------------------------------ + /// Complete the exception table for a function, and add it to the + /// m_exception_tables map + /// + /// @param[in] F + /// The function whose exception table is being written. + /// + /// @param[in] TableStart + /// The first byte of the exception table. + /// + /// @param[in] TableEnd + /// The last byte of the exception table. + /// + /// @param[in] FrameRegister + /// I don't know what this does, but it's passed through. + //------------------------------------------------------------------ + virtual void endExceptionTable(const llvm::Function *F, + uint8_t *TableStart, + uint8_t *TableEnd, + uint8_t* FrameRegister); + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual void deallocateExceptionTable(void *ET); + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual size_t GetDefaultCodeSlabSize() { + return m_default_mm_ap->GetDefaultCodeSlabSize(); + } + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual size_t GetDefaultDataSlabSize() { + return m_default_mm_ap->GetDefaultDataSlabSize(); + } + + virtual size_t GetDefaultStubSlabSize() { + return m_default_mm_ap->GetDefaultStubSlabSize(); + } + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual unsigned GetNumCodeSlabs() { + return m_default_mm_ap->GetNumCodeSlabs(); + } + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual unsigned GetNumDataSlabs() { + return m_default_mm_ap->GetNumDataSlabs(); + } + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual unsigned GetNumStubSlabs() { + return m_default_mm_ap->GetNumStubSlabs(); + } + + //------------------------------------------------------------------ + /// Passthrough interface stub + //------------------------------------------------------------------ + virtual void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure = true) { + return m_default_mm_ap->getPointerToNamedFunction(Name, AbortOnFailure); + } + private: + std::auto_ptr<JITMemoryManager> m_default_mm_ap; ///< The memory allocator to use in actually creating space. All calls are passed through to it. + IRExecutionUnit &m_parent; ///< The execution unit this is a proxy for. + }; + + //---------------------------------------------------------------------- + /// @class Allocation IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.h" + /// @brief A record of a region that has been allocated by the JIT. + /// + /// The IRExecutionUnit makes records of all regions that need copying; + /// upon requests, it allocates and + //---------------------------------------------------------------------- + struct Allocation + { + lldb::addr_t m_remote_allocation;///< The (unaligned) base for the remote allocation + lldb::addr_t m_remote_start; ///< The base address of the remote allocation + uintptr_t m_local_start; ///< The base address of the local allocation - LLDB_INVALID_ADDRESS means it was allocated with WriteNow + uintptr_t m_size; ///< The size of the allocation + unsigned m_section_id; ///< The ID of the section + unsigned m_alignment; ///< The required alignment for the allocation + bool m_executable; ///< True <=> the allocation must be executable in the target + bool m_allocated; ///< True <=> the allocation has been propagated to the target + + static const unsigned eSectionIDNone = (unsigned)-1; + + //------------------------------------------------------------------ + /// Constructor + //------------------------------------------------------------------ + Allocation () : + m_remote_allocation(0), + m_remote_start(0), + m_local_start(0), + m_size(0), + m_section_id(eSectionIDNone), + m_alignment(0), + m_executable(false), + m_allocated(false) + { + } + + void dump (lldb::LogSP log); + }; + + //---------------------------------------------------------------------- + /// @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) + { + } + }; + + lldb::ProcessWP m_process_wp; + typedef std::vector<Allocation> AllocationList; + AllocationList m_allocations; ///< The base address of the remote allocation + std::auto_ptr<llvm::ExecutionEngine> m_execution_engine_ap; + std::auto_ptr<llvm::Module> m_module_ap; ///< Holder for the module until it's been handed off + llvm::Module *m_module; ///< Owned by the execution engine + std::vector<std::string> m_cpu_features; + llvm::SmallVector<JittedFunction, 1> m_jitted_functions; ///< A vector of all functions that have been JITted into machine code + const ConstString m_name; + + std::atomic<bool> m_did_jit; + Mutex m_jit_mutex; + + lldb::addr_t m_function_load_addr; + lldb::addr_t m_function_end_load_addr; +}; + +} // namespace lldb_private + +#endif // lldb_IRExecutionUnit_h_ diff --git a/lldb/include/lldb/Expression/IRForTarget.h b/lldb/include/lldb/Expression/IRForTarget.h index 61c8deac5e0..b0a9aa8ad24 100644 --- a/lldb/include/lldb/Expression/IRForTarget.h +++ b/lldb/include/lldb/Expression/IRForTarget.h @@ -14,6 +14,7 @@ #include "lldb/Core/ConstString.h" #include "lldb/Core/Error.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/StreamString.h" #include "lldb/Symbol/TaggedASTType.h" #include "llvm/Pass.h" @@ -35,6 +36,7 @@ namespace llvm { namespace lldb_private { class ClangExpressionDeclMap; + class IRExecutionUnit; } //---------------------------------------------------------------------- @@ -54,14 +56,6 @@ namespace lldb_private { class IRForTarget : public llvm::ModulePass { public: - class StaticDataAllocator { - public: - StaticDataAllocator(); - virtual ~StaticDataAllocator(); - virtual lldb_private::StreamString &GetStream() = 0; - virtual lldb::addr_t Allocate() = 0; - }; - //------------------------------------------------------------------ /// Constructor /// @@ -84,8 +78,8 @@ public: /// of the function, if it has no side-effects and the result can /// be computed statically. /// - /// @param[in] data_allocator - /// If non-NULL, the static data allocator to use for literal strings. + /// @param[in] execution_unit + /// The holder for raw data associated with the expression. /// /// @param[in] error_stream /// If non-NULL, a stream on which errors can be printed. @@ -97,7 +91,7 @@ public: bool resolve_vars, lldb_private::ExecutionPolicy execution_policy, lldb::ClangExpressionVariableSP &const_result, - StaticDataAllocator *data_allocator, + lldb_private::IRExecutionUnit &execution_unit, lldb_private::Stream *error_stream, const char* func_name = "$__lldb_expr"); @@ -653,6 +647,20 @@ private: bool StripAllGVs (llvm::Module &llvm_module); + class StaticDataAllocator { + public: + StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit); + lldb_private::StreamString &GetStream() + { + return m_stream_string; + } + lldb::addr_t Allocate(); + private: + lldb_private::IRExecutionUnit &m_execution_unit; + lldb_private::StreamString m_stream_string; + lldb::addr_t m_allocation; + }; + /// Flags bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved lldb_private::ExecutionPolicy m_execution_policy; ///< True if the interpreter should be used to attempt to get a static result @@ -663,7 +671,7 @@ private: llvm::Module *m_module; ///< The module being processed, or NULL if that has not been determined yet. std::auto_ptr<llvm::DataLayout> m_target_data; ///< The target data for the module being processed, or NULL if there is no module. lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls - StaticDataAllocator *m_data_allocator; ///< If non-NULL, the allocator to use for constant strings + StaticDataAllocator m_data_allocator; ///< The allocator to use for constant strings llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the appropriate function pointer type llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type lldb::ClangExpressionVariableSP &m_const_result; ///< This value should be set to the return value of the expression if it is constant and the expression has no side effects diff --git a/lldb/include/lldb/Expression/ProcessDataAllocator.h b/lldb/include/lldb/Expression/ProcessDataAllocator.h deleted file mode 100644 index 56ed22404db..00000000000 --- a/lldb/include/lldb/Expression/ProcessDataAllocator.h +++ /dev/null @@ -1,72 +0,0 @@ -//===-- ProcessDataAllocator.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_ProcessDataAllocator_h_ -#define liblldb_ProcessDataAllocator_h_ - -#include "lldb/lldb-forward.h" -#include "lldb/lldb-private.h" -#include "lldb/Expression/IRForTarget.h" -#include "lldb/Target/Process.h" - -namespace lldb_private -{ - -class ProcessDataAllocator : public IRForTarget::StaticDataAllocator { -public: - ProcessDataAllocator(Process &process) : - IRForTarget::StaticDataAllocator(), - m_process(process), - m_stream_string(StreamString::eBinary, process.GetAddressByteSize(), process.GetByteOrder()), - m_allocation(0) - { - } - - ~ProcessDataAllocator() - { - if (m_allocation) - m_process.DeallocateMemory(m_allocation); - } - - lldb_private::StreamString &GetStream() - { - return m_stream_string; - } - - lldb::addr_t Allocate() - { - Error err; - - if (m_allocation) - m_process.DeallocateMemory(m_allocation); - - m_allocation = m_process.AllocateMemory(m_stream_string.GetSize(), lldb::ePermissionsReadable | lldb::ePermissionsWritable, err); - - if (!err.Success()) - return 0; - - if (m_allocation) - m_process.WriteMemory(m_allocation, m_stream_string.GetData(), m_stream_string.GetSize(), err); - - if (!err.Success()) - return 0; - - return m_allocation; - } - - void Dump(lldb_private::Stream &stream); -private: - Process &m_process; - StreamString m_stream_string; - lldb::addr_t m_allocation; -}; - -} // namespace lldb_private - -#endif diff --git a/lldb/include/lldb/Expression/RecordingMemoryManager.h b/lldb/include/lldb/Expression/RecordingMemoryManager.h deleted file mode 100644 index b9758e17614..00000000000 --- a/lldb/include/lldb/Expression/RecordingMemoryManager.h +++ /dev/null @@ -1,424 +0,0 @@ -//===-- RecordingMemoryManager.h --------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef lldb_RecordingMemoryManager_h_ -#define lldb_RecordingMemoryManager_h_ - -// C Includes -// C++ Includes -#include <string> -#include <vector> -#include <map> - -// Other libraries and framework includes -// Project includes -#include "lldb/lldb-forward.h" -#include "lldb/lldb-private.h" -#include "lldb/Core/ClangForward.h" -#include "lldb/Core/Log.h" -#include "llvm/ExecutionEngine/JITMemoryManager.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangExpressionParser.h" - -namespace lldb_private { - -//---------------------------------------------------------------------- -/// @class RecordingMemoryManager RecordingMemoryManager.h "lldb/Expression/RecordingMemoryManager.h" -/// @brief Passthrough memory manager for the JIT that records what was allocated where -/// -/// The LLVM JIT is built to compile code for execution in the current -/// process, so it needs to be able to allocate memory. Because different -/// clients have different requirements for the locations of JIT compiled -/// code, the interface for allocating memory has been abstracted out and -/// can be implemented by any client. -/// -/// LLDB, however, needs to move JIT-compiled code into the target process. -/// Because writing individual bytes of code hasn't been abstracted out of -/// the JIT, LLDB instead implements a custom memory allocator that records -/// what regions have been allocated for code. When JIT compilation is -/// complete, these regions are then copied as necessary into the target -/// process. -/// -/// Ideally the memory manager would handle this copying, but this class has -/// to be built without RTTI, which means it cannot include Process.h. As a -/// result, ClangExpression::WriteJITCode() accesses the stored mappings -/// directly. -//---------------------------------------------------------------------- -class RecordingMemoryManager : public llvm::JITMemoryManager -{ -public: - //------------------------------------------------------------------ - /// Constructor - //------------------------------------------------------------------ - RecordingMemoryManager (); - - //------------------------------------------------------------------ - /// Destructor - //------------------------------------------------------------------ - virtual ~RecordingMemoryManager(); - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual void setMemoryWritable (); - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual void setMemoryExecutable (); - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual void setPoisonMemory (bool poison) - { - m_default_mm_ap->setPoisonMemory (poison); - } - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual void AllocateGOT() - { - m_default_mm_ap->AllocateGOT(); - } - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual uint8_t *getGOTBase() const - { - return m_default_mm_ap->getGOTBase(); - } - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual uint8_t *startFunctionBody(const llvm::Function *F, - uintptr_t &ActualSize); - - //------------------------------------------------------------------ - /// Allocate room for a dyld stub for a lazy-referenced function, - /// and add it to the m_stubs map - /// - /// @param[in] F - /// The function being referenced. - /// - /// @param[in] StubSize - /// The size of the stub. - /// - /// @param[in] Alignment - /// The required alignment of the stub. - /// - /// @return - /// Allocated space for the stub. - //------------------------------------------------------------------ - virtual uint8_t *allocateStub(const llvm::GlobalValue* F, - unsigned StubSize, - unsigned Alignment); - - //------------------------------------------------------------------ - /// Complete the body of a function, and add it to the m_functions map - /// - /// @param[in] F - /// The function being completed. - /// - /// @param[in] FunctionStart - /// The first instruction of the function. - /// - /// @param[in] FunctionEnd - /// The last byte of the last instruction of the function. - //------------------------------------------------------------------ - virtual void endFunctionBody(const llvm::Function *F, - uint8_t *FunctionStart, - uint8_t *FunctionEnd); - //------------------------------------------------------------------ - /// Allocate space for an unspecified purpose, and add it to the - /// m_spaceBlocks map - /// - /// @param[in] Size - /// The size of the area. - /// - /// @param[in] Alignment - /// The required alignment of the area. - /// - /// @return - /// Allocated space. - //------------------------------------------------------------------ - virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); - - //------------------------------------------------------------------ - /// Allocate space for executable code, and add it to the - /// m_spaceBlocks map - /// - /// @param[in] Size - /// The size of the area. - /// - /// @param[in] Alignment - /// The required alignment of the area. - /// - /// @param[in] SectionID - /// A unique identifier for the section. - /// - /// @return - /// Allocated space. - //------------------------------------------------------------------ - virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID); - - //------------------------------------------------------------------ - /// Allocate space for data, and add it to the m_spaceBlocks map - /// - /// @param[in] Size - /// The size of the area. - /// - /// @param[in] Alignment - /// The required alignment of the area. - /// - /// @param[in] SectionID - /// A unique identifier for the section. - /// - /// @param[in] IsReadOnly - /// Flag indicating the section is read-only. - /// - /// @return - /// Allocated space. - //------------------------------------------------------------------ - virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, bool IsReadOnly); - - //------------------------------------------------------------------ - /// Allocate space for a global variable, and add it to the - /// m_spaceBlocks map - /// - /// @param[in] Size - /// The size of the variable. - /// - /// @param[in] Alignment - /// The required alignment of the variable. - /// - /// @return - /// Allocated space for the global. - //------------------------------------------------------------------ - virtual uint8_t *allocateGlobal(uintptr_t Size, - unsigned Alignment); - - //------------------------------------------------------------------ - /// Called when object loading is complete and section page - /// permissions can be applied. Currently unimplemented for LLDB. - /// - /// @param[out] ErrMsg - /// The error that prevented the page protection from succeeding. - /// - /// @return - /// True in case of failure, false in case of success. - //------------------------------------------------------------------ - bool applyPermissions(std::string *ErrMsg) { return false; } - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual void deallocateFunctionBody(void *Body); - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual uint8_t* startExceptionTable(const llvm::Function* F, - uintptr_t &ActualSize); - - //------------------------------------------------------------------ - /// Complete the exception table for a function, and add it to the - /// m_exception_tables map - /// - /// @param[in] F - /// The function whose exception table is being written. - /// - /// @param[in] TableStart - /// The first byte of the exception table. - /// - /// @param[in] TableEnd - /// The last byte of the exception table. - /// - /// @param[in] FrameRegister - /// I don't know what this does, but it's passed through. - //------------------------------------------------------------------ - virtual void endExceptionTable(const llvm::Function *F, - uint8_t *TableStart, - uint8_t *TableEnd, - uint8_t* FrameRegister); - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual void deallocateExceptionTable(void *ET); - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual size_t GetDefaultCodeSlabSize() { - return m_default_mm_ap->GetDefaultCodeSlabSize(); - } - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual size_t GetDefaultDataSlabSize() { - return m_default_mm_ap->GetDefaultDataSlabSize(); - } - - virtual size_t GetDefaultStubSlabSize() { - return m_default_mm_ap->GetDefaultStubSlabSize(); - } - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual unsigned GetNumCodeSlabs() { - return m_default_mm_ap->GetNumCodeSlabs(); - } - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual unsigned GetNumDataSlabs() { - return m_default_mm_ap->GetNumDataSlabs(); - } - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual unsigned GetNumStubSlabs() { - return m_default_mm_ap->GetNumStubSlabs(); - } - - //------------------------------------------------------------------ - /// Passthrough interface stub - //------------------------------------------------------------------ - virtual void *getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure = true) { - return m_default_mm_ap->getPointerToNamedFunction(Name, AbortOnFailure); - } - - //------------------------------------------------------------------ - /// [Convenience method for ClangExpressionParser] Look up the object in - /// m_address_map that contains a given address, find where it was - /// copied to, and return the remote address at the same offset into - /// the copied entity - /// - /// @param[in] local_address - /// The address in the debugger. - /// - /// @return - /// The address in the target process. - //------------------------------------------------------------------ - lldb::addr_t - GetRemoteAddressForLocal (lldb::addr_t local_address); - - //------------------------------------------------------------------ - /// [Convenience method for ClangExpressionParser] Look up the object in - /// m_address_map that contains a given address, find where it was - /// copied to, and return its address range in the target process - /// - /// @param[in] local_address - /// The address in the debugger. - /// - /// @return - /// The range of the containing object in the target process. - //------------------------------------------------------------------ - typedef std::pair <lldb::addr_t, uintptr_t> AddrRange; - AddrRange - GetRemoteRangeForLocal (lldb::addr_t local_address); - - //------------------------------------------------------------------ - /// [Convenience method for ClangExpressionParser] Commit all allocations - /// to the process and record where they were stored. - /// - /// @param[in] process - /// The process to allocate memory in. - /// - /// @return - /// True <=> all allocations were performed successfully. - /// This method will attempt to free allocated memory if the - /// operation fails. - //------------------------------------------------------------------ - bool - CommitAllocations (Process &process); - - //------------------------------------------------------------------ - /// [Convenience method for ClangExpressionParser] Report all committed - /// allocations to the execution engine. - /// - /// @param[in] engine - /// The execution engine to notify. - //------------------------------------------------------------------ - void - ReportAllocations (llvm::ExecutionEngine &engine); - - //------------------------------------------------------------------ - /// [Convenience method for ClangExpressionParser] Write the contents - /// of all allocations to the process. - /// - /// @param[in] local_address - /// The process containing the allocations. - /// - /// @return - /// True <=> all allocations were performed successfully. - //------------------------------------------------------------------ - bool - WriteData (Process &process); -private: - std::auto_ptr<JITMemoryManager> m_default_mm_ap; ///< The memory allocator to use in actually creating space. All calls are passed through to it. - - lldb::LogSP m_log; ///< The log to use when printing log messages. May be NULL. - - //---------------------------------------------------------------------- - /// @class Allocation RecordingMemoryManager.h "lldb/Expression/RecordingMemoryManager.h" - /// @brief A record of a region that has been allocated by the JIT. - /// - /// The RecordingMemoryManager makes records of all regions that need copying; - /// upon requests, it allocates and - //---------------------------------------------------------------------- - struct Allocation - { - lldb::addr_t m_remote_allocation;///< The (unaligned) base for the remote allocation - lldb::addr_t m_remote_start; ///< The base address of the remote allocation - uintptr_t m_local_start; ///< The base address of the local allocation - uintptr_t m_size; ///< The size of the allocation - unsigned m_section_id; ///< The ID of the section - unsigned m_alignment; ///< The required alignment for the allocation - bool m_executable; ///< True <=> the allocation must be executable in the target - bool m_allocated; ///< True <=> the allocation has been propagated to the target - - static const unsigned eSectionIDNone = (unsigned)-1; - - //------------------------------------------------------------------ - /// Constructor - //------------------------------------------------------------------ - Allocation () : - m_remote_allocation(0), - m_remote_start(0), - m_local_start(0), - m_size(0), - m_section_id(eSectionIDNone), - m_alignment(0), - m_executable(false), - m_allocated(false) - { - } - - void dump (lldb::LogSP log); - }; - - typedef std::vector<Allocation> AllocationList; - AllocationList m_allocations; ///< The base address of the remote allocation -}; - -} // namespace lldb_private - -#endif // lldb_RecordingMemoryManager_h_ diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index faafd94f3a0..ec10307c6f9 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -255,7 +255,7 @@ 2689006913353E0E00698AC0 /* ASTStructExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 491193501226386000578B7F /* ASTStructExtractor.cpp */; }; 2689006A13353E0E00698AC0 /* IRDynamicChecks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */; }; 2689006B13353E0E00698AC0 /* IRForTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49307AAD11DEA4D90081F992 /* IRForTarget.cpp */; }; - 2689006D13353E0E00698AC0 /* RecordingMemoryManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */; }; + 2689006D13353E0E00698AC0 /* IRExecutionUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C98D3DB118FB96F00E575D0 /* IRExecutionUnit.cpp */; }; 2689006E13353E1A00698AC0 /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C6EA213011581005E16B0 /* File.cpp */; }; 2689006F13353E1A00698AC0 /* FileSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26FA43171301048600E71120 /* FileSpec.cpp */; }; 2689007013353E1A00698AC0 /* Condition.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 69A01E1B1236C5D400C660B5 /* Condition.cpp */; }; @@ -495,7 +495,6 @@ 49A1CAC51430E8DE00306AC9 /* ExpressionSourceCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49A1CAC31430E8BD00306AC9 /* ExpressionSourceCode.cpp */; }; 49A71FE7141FFA5C00D59478 /* IRInterpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 496B01581406DE8900F830D5 /* IRInterpreter.cpp */; }; 49A71FE8141FFACF00D59478 /* DataEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 268ED0A4140FF54200DE830F /* DataEncoder.cpp */; }; - 49C8507C1384A786007DB519 /* ProcessDataAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49C850781384A0CA007DB519 /* ProcessDataAllocator.cpp */; }; 49D8FB3913B5598F00411094 /* ClangASTImporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49D8FB3513B558DE00411094 /* ClangASTImporter.cpp */; }; 49DA65031485C92A005FF180 /* AppleObjCTypeVendor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DA65021485C92A005FF180 /* AppleObjCTypeVendor.cpp */; }; 4C6649A014EEE7F100B0316F /* StreamCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C66499F14EEE7F100B0316F /* StreamCallback.h */; }; @@ -1444,8 +1443,6 @@ 49A8A3A311D568BF00AD3B68 /* ASTResultSynthesizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTResultSynthesizer.h; path = include/lldb/Expression/ASTResultSynthesizer.h; sourceTree = "<group>"; }; 49B01A2D15F67B1700666829 /* TypeVendor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TypeVendor.h; path = include/lldb/Symbol/TypeVendor.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>"; }; - 49C850761384A02F007DB519 /* ProcessDataAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcessDataAllocator.h; path = include/lldb/Expression/ProcessDataAllocator.h; sourceTree = "<group>"; }; - 49C850781384A0CA007DB519 /* ProcessDataAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProcessDataAllocator.cpp; path = source/Expression/ProcessDataAllocator.cpp; sourceTree = "<group>"; }; 49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRDynamicChecks.cpp; path = source/Expression/IRDynamicChecks.cpp; sourceTree = "<group>"; }; 49CF9833122C718B007A0B96 /* IRDynamicChecks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRDynamicChecks.h; path = include/lldb/Expression/IRDynamicChecks.h; sourceTree = "<group>"; }; 49D4FE821210B5FB00CDB854 /* ClangPersistentVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangPersistentVariables.h; path = include/lldb/Expression/ClangPersistentVariables.h; sourceTree = "<group>"; }; @@ -1484,9 +1481,9 @@ 4C7CF7E31295E10E00B4FBB5 /* ThreadPlanCallUserExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanCallUserExpression.h; path = include/lldb/Target/ThreadPlanCallUserExpression.h; sourceTree = "<group>"; }; 4C7CF7E51295E12B00B4FBB5 /* ThreadPlanCallUserExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanCallUserExpression.cpp; path = source/Target/ThreadPlanCallUserExpression.cpp; sourceTree = "<group>"; }; 4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangFunction.cpp; path = source/Expression/ClangFunction.cpp; sourceTree = "<group>"; }; - 4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecordingMemoryManager.cpp; path = source/Expression/RecordingMemoryManager.cpp; sourceTree = "<group>"; }; + 4C98D3DB118FB96F00E575D0 /* IRExecutionUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRExecutionUnit.cpp; path = source/Expression/IRExecutionUnit.cpp; sourceTree = "<group>"; }; 4C98D3E0118FB98F00E575D0 /* ClangFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangFunction.h; path = include/lldb/Expression/ClangFunction.h; sourceTree = "<group>"; }; - 4C98D3E1118FB98F00E575D0 /* RecordingMemoryManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecordingMemoryManager.h; path = include/lldb/Expression/RecordingMemoryManager.h; sourceTree = "<group>"; }; + 4C98D3E1118FB98F00E575D0 /* IRExecutionUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRExecutionUnit.h; path = include/lldb/Expression/IRExecutionUnit.h; sourceTree = "<group>"; }; 4CA9637911B6E99A00780E28 /* CommandObjectApropos.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectApropos.cpp; path = source/Commands/CommandObjectApropos.cpp; sourceTree = "<group>"; }; 4CA9637A11B6E99A00780E28 /* CommandObjectApropos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectApropos.h; path = source/Commands/CommandObjectApropos.h; sourceTree = "<group>"; }; 4CAA56121422D96A001FFA01 /* BreakpointResolverFileRegex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointResolverFileRegex.h; path = include/lldb/Breakpoint/BreakpointResolverFileRegex.h; sourceTree = "<group>"; }; @@ -2883,14 +2880,12 @@ 491193501226386000578B7F /* ASTStructExtractor.cpp */, 49CF9833122C718B007A0B96 /* IRDynamicChecks.h */, 49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */, + 4C98D3E1118FB98F00E575D0 /* IRExecutionUnit.h */, + 4C98D3DB118FB96F00E575D0 /* IRExecutionUnit.cpp */, 49307AB111DEA4F20081F992 /* IRForTarget.h */, 49307AAD11DEA4D90081F992 /* IRForTarget.cpp */, 496B015A1406DEB100F830D5 /* IRInterpreter.h */, 496B01581406DE8900F830D5 /* IRInterpreter.cpp */, - 4C98D3E1118FB98F00E575D0 /* RecordingMemoryManager.h */, - 4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */, - 49C850761384A02F007DB519 /* ProcessDataAllocator.h */, - 49C850781384A0CA007DB519 /* ProcessDataAllocator.cpp */, ); name = Expression; sourceTree = "<group>"; @@ -3938,7 +3933,6 @@ files = ( 9456F2241616671900656F91 /* DynamicLibrary.cpp in Sources */, 26D1804216CEDF0700EDFB5B /* TimeSpecTimeout.cpp in Sources */, - 49C8507C1384A786007DB519 /* ProcessDataAllocator.cpp in Sources */, 2689FFDA13353D9D00698AC0 /* lldb.cpp in Sources */, 2689FFDB13353DA300698AC0 /* lldb-log.cpp in Sources */, 2689FFEF13353DB600698AC0 /* Breakpoint.cpp in Sources */, @@ -4048,7 +4042,7 @@ 2689006913353E0E00698AC0 /* ASTStructExtractor.cpp in Sources */, 2689006A13353E0E00698AC0 /* IRDynamicChecks.cpp in Sources */, 2689006B13353E0E00698AC0 /* IRForTarget.cpp in Sources */, - 2689006D13353E0E00698AC0 /* RecordingMemoryManager.cpp in Sources */, + 2689006D13353E0E00698AC0 /* IRExecutionUnit.cpp in Sources */, 2689006E13353E1A00698AC0 /* File.cpp in Sources */, 94D6A0AB16CEB55F00833B6E /* NSDictionary.cpp in Sources */, 2689006F13353E1A00698AC0 /* FileSpec.cpp in Sources */, diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp index 58ecd13822b..4f8e3341494 100644 --- a/lldb/source/Expression/ClangExpressionParser.cpp +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -20,8 +20,8 @@ #include "lldb/Expression/ClangASTSource.h" #include "lldb/Expression/ClangExpression.h" #include "lldb/Expression/ClangExpressionDeclMap.h" +#include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRDynamicChecks.h" -#include "lldb/Expression/RecordingMemoryManager.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" @@ -188,8 +188,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, ClangExpression &expr) : m_expr (expr), m_compiler (), - m_code_generator (NULL), - m_jitted_functions () + m_code_generator (NULL) { // Initialize targets first, so that --version shows registered targets. static struct InitializeLLVM { @@ -441,7 +440,7 @@ ClangExpressionParser::Parse (Stream &stream) return num_errors; } -static bool FindFunctionInModule (std::string &mangled_name, +static bool FindFunctionInModule (ConstString &mangled_name, llvm::Module *module, const char *orig_name) { @@ -451,7 +450,7 @@ static bool FindFunctionInModule (std::string &mangled_name, { if (fi->getName().str().find(orig_name) != std::string::npos) { - mangled_name = fi->getName().str(); + mangled_name.SetCString(fi->getName().str().c_str()); return true; } } @@ -460,16 +459,13 @@ static bool FindFunctionInModule (std::string &mangled_name, } Error -ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_allocation_addr, - lldb::addr_t &func_addr, +ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, lldb::addr_t &func_end, ExecutionContext &exe_ctx, - IRForTarget::StaticDataAllocator *data_allocator, bool &evaluated_statically, lldb::ClangExpressionVariableSP &const_result, ExecutionPolicy execution_policy) { - func_allocation_addr = LLDB_INVALID_ADDRESS; func_addr = LLDB_INVALID_ADDRESS; func_end = LLDB_INVALID_ADDRESS; lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -489,7 +485,7 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_allocation_addr, // Find the actual name of the function (it's often mangled somehow) - std::string function_name; + ConstString function_name; if (!FindFunctionInModule(function_name, module_ap.get(), m_expr.FunctionName())) { @@ -500,9 +496,14 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_allocation_addr, else { if (log) - log->Printf("Found function %s for %s", function_name.c_str(), m_expr.FunctionName()); + log->Printf("Found function %s for %s", function_name.AsCString(), m_expr.FunctionName()); } + m_execution_unit.reset(new IRExecutionUnit(module_ap, // handed off here + function_name, + exe_ctx.GetProcessSP(), + m_compiler->getTargetOpts().Features)); + ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); // result can be NULL if (decl_map) @@ -516,11 +517,11 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_allocation_addr, m_expr.NeedsVariableResolution(), execution_policy, const_result, - data_allocator, + *m_execution_unit, error_stream, - function_name.c_str()); + function_name.AsCString()); - bool ir_can_run = ir_for_target.runOnModule(*module_ap); + bool ir_can_run = ir_for_target.runOnModule(*m_execution_unit->GetModule()); Error &interpreter_error(ir_for_target.getInterpreterError()); @@ -579,9 +580,9 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_allocation_addr, log->Printf("== [ClangUserExpression::Evaluate] Finished installing dynamic checkers =="); } - IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.c_str()); + IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString()); - if (!ir_dynamic_checks.runOnModule(*module_ap)) + if (!ir_dynamic_checks.runOnModule(*m_execution_unit->GetModule())) { err.SetErrorToGenericError(); err.SetErrorString("Couldn't add dynamic checks to the expression"); @@ -590,264 +591,7 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_allocation_addr, } } - // llvm will own this pointer when llvm::ExecutionEngine::createJIT is called - // below so we don't need to free it. - RecordingMemoryManager *jit_memory_manager = new RecordingMemoryManager(); - - std::string error_string; - - if (log) - { - std::string s; - raw_string_ostream oss(s); - - module_ap->print(oss, NULL); - - oss.flush(); - - log->Printf ("Module being sent to JIT: \n%s", s.c_str()); - } - llvm::Triple triple(module_ap->getTargetTriple()); - llvm::Function *function = module_ap->getFunction (function_name.c_str()); - llvm::Reloc::Model relocModel; - llvm::CodeModel::Model codeModel; - if (triple.isOSBinFormatELF()) - { - relocModel = llvm::Reloc::Static; - // This will be small for 32-bit and large for 64-bit. - codeModel = llvm::CodeModel::JITDefault; - } - else - { - relocModel = llvm::Reloc::PIC_; - codeModel = llvm::CodeModel::Small; - } - EngineBuilder builder(module_ap.release()); - builder.setEngineKind(EngineKind::JIT) - .setErrorStr(&error_string) - .setRelocationModel(relocModel) - .setJITMemoryManager(jit_memory_manager) - .setOptLevel(CodeGenOpt::Less) - .setAllocateGVsWithCode(true) - .setCodeModel(codeModel) - .setUseMCJIT(true); - - StringRef mArch; - StringRef mCPU; - SmallVector<std::string, 0> mAttrs; - - for (std::string &feature : m_compiler->getTargetOpts().Features) - mAttrs.push_back(feature); - - TargetMachine *target_machine = builder.selectTarget(triple, - mArch, - mCPU, - mAttrs); - - execution_engine_ap.reset(builder.create(target_machine)); - - if (!execution_engine_ap.get()) - { - err.SetErrorToGenericError(); - err.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str()); - return err; - } - - execution_engine_ap->DisableLazyCompilation(); - - - // We don't actually need the function pointer here, this just forces it to get resolved. - - void *fun_ptr = execution_engine_ap->getPointerToFunction(function); + m_execution_unit->GetRunnableInfo(err, func_addr, func_end); - // Errors usually cause failures in the JIT, but if we're lucky we get here. - - if (!function) - { - err.SetErrorToGenericError(); - err.SetErrorStringWithFormat("Couldn't find '%s' in the JITted module", function_name.c_str()); - return err; - } - - if (!fun_ptr) - { - err.SetErrorToGenericError(); - err.SetErrorStringWithFormat("'%s' was in the JITted module but wasn't lowered", function_name.c_str()); - return err; - } - - m_jitted_functions.push_back (ClangExpressionParser::JittedFunction(function_name.c_str(), (lldb::addr_t)fun_ptr)); - - - Process *process = exe_ctx.GetProcessPtr(); - if (process == NULL) - { - err.SetErrorToGenericError(); - err.SetErrorString("Couldn't write the JIT compiled code into the target because there is no target"); - return err; - } - - jit_memory_manager->CommitAllocations(*process); - jit_memory_manager->ReportAllocations(*execution_engine_ap); - jit_memory_manager->WriteData(*process); - - std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); - - for (pos = m_jitted_functions.begin(); pos != end; pos++) - { - (*pos).m_remote_addr = jit_memory_manager->GetRemoteAddressForLocal ((*pos).m_local_addr); - - if (!(*pos).m_name.compare(function_name.c_str())) - { - RecordingMemoryManager::AddrRange func_range = jit_memory_manager->GetRemoteRangeForLocal((*pos).m_local_addr); - func_end = func_range.first + func_range.second; - func_addr = (*pos).m_remote_addr; - } - } - - if (log) - { - log->Printf("Code can be run in the target."); - - StreamString disassembly_stream; - - Error err = DisassembleFunction(disassembly_stream, exe_ctx, jit_memory_manager); - - if (!err.Success()) - { - log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error")); - } - else - { - log->Printf("Function disassembly:\n%s", disassembly_stream.GetData()); - } - } - - err.Clear(); return err; } - -Error -ClangExpressionParser::DisassembleFunction (Stream &stream, ExecutionContext &exe_ctx, RecordingMemoryManager *jit_memory_manager) -{ - lldb::LogSP 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 (strstr(pos->m_name.c_str(), name)) - { - 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%" PRIx64 " and remote address 0x%" PRIx64, (uint64_t)func_local_addr, (uint64_t)func_remote_addr); - - std::pair <lldb::addr_t, lldb::addr_t> func_range; - - func_range = jit_memory_manager->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%" PRIx64 "+0x%" PRIx64 "]", func_range.first, func_range.second); - - Target *target = exe_ctx.GetTargetPtr(); - if (!target) - { - ret.SetErrorToGenericError(); - ret.SetErrorString("Couldn't find the target"); - return ret; - } - - lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second, 0)); - - Process *process = exe_ctx.GetProcessPtr(); - Error err; - 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(target->GetArchitecture()); - - const char *plugin_name = NULL; - const char *flavor_string = NULL; - lldb::DisassemblerSP disassembler = Disassembler::FindPlugin(arch, flavor_string, plugin_name); - - if (!disassembler) - { - ret.SetErrorToGenericError(); - ret.SetErrorStringWithFormat("Unable to find disassembler plug-in for %s architecture.", arch.GetArchitectureName()); - return ret; - } - - if (!process) - { - ret.SetErrorToGenericError(); - ret.SetErrorString("Couldn't find the process"); - return ret; - } - - DataExtractor extractor(buffer_sp, - process->GetByteOrder(), - target->GetArchitecture().GetAddressByteSize()); - - if (log) - { - log->Printf("Function data has contents:"); - extractor.PutToLog (log.get(), - 0, - extractor.GetByteSize(), - func_remote_addr, - 16, - DataExtractor::TypeUInt8); - } - - disassembler->DecodeInstructions (Address (func_remote_addr), extractor, 0, UINT32_MAX, false); - - InstructionList &instruction_list = disassembler->GetInstructionList(); - const uint32_t max_opcode_byte_size = instruction_list.GetMaxOpcocdeByteSize(); - for (size_t instruction_index = 0, num_instructions = instruction_list.GetSize(); - instruction_index < num_instructions; - ++instruction_index) - { - Instruction *instruction = instruction_list.GetInstructionAtIndex(instruction_index).get(); - instruction->Dump (&stream, - max_opcode_byte_size, - true, - true, - &exe_ctx); - stream.PutChar('\n'); - } - - return ret; -} diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index 794e035287b..95b75574101 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -264,18 +264,17 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) bool evaluated_statically = false; // should stay that way - Error jit_error (m_parser->PrepareForExecution (m_jit_alloc, - m_jit_start_addr, + Error jit_error (m_parser->PrepareForExecution (m_jit_start_addr, m_jit_end_addr, exe_ctx, - NULL, evaluated_statically, const_result, eExecutionPolicyAlways)); if (!jit_error.Success()) return false; - if (process && m_jit_alloc != LLDB_INVALID_ADDRESS) + + if (process && m_jit_start_addr) m_jit_process_wp = lldb::ProcessWP(process->shared_from_this()); m_JITted = true; diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 5a1c3aa8b6e..98b5c63efd2 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -460,30 +460,17 @@ ClangUserExpression::Parse (Stream &error_stream, ////////////////////////////////////////////////////////////////////////////////////////// // Prepare the output of the parser for execution, evaluating it statically if possible // - - if (execution_policy != eExecutionPolicyNever && process) - m_data_allocator.reset(new ProcessDataAllocator(*process)); - - Error jit_error = parser.PrepareForExecution (m_jit_alloc, - m_jit_start_addr, + + Error jit_error = parser.PrepareForExecution (m_jit_start_addr, m_jit_end_addr, exe_ctx, - m_data_allocator.get(), m_evaluated_statically, m_const_result, execution_policy); - - if (log && m_data_allocator.get()) - { - StreamString dump_string; - m_data_allocator->Dump(dump_string); - - log->Printf("Data buffer contents:\n%s", dump_string.GetString().c_str()); - } if (jit_error.Success()) { - if (process && m_jit_alloc != LLDB_INVALID_ADDRESS) + if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS) m_jit_process_wp = lldb::ProcessWP(process->shared_from_this()); return true; } diff --git a/lldb/source/Expression/ClangUtilityFunction.cpp b/lldb/source/Expression/ClangUtilityFunction.cpp index 2f41ae9a2f3..e457bb94655 100644 --- a/lldb/source/Expression/ClangUtilityFunction.cpp +++ b/lldb/source/Expression/ClangUtilityFunction.cpp @@ -104,8 +104,6 @@ ClangUtilityFunction::Install (Stream &error_stream, m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx)); - m_data_allocator.reset(new ProcessDataAllocator(*process)); - if (!m_expr_decl_map->WillParse(exe_ctx)) { error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n"); @@ -133,23 +131,13 @@ ClangUtilityFunction::Install (Stream &error_stream, bool evaluated_statically = false; // should stay that way - Error jit_error = parser.PrepareForExecution (m_jit_alloc, - m_jit_start_addr, + Error jit_error = parser.PrepareForExecution (m_jit_start_addr, m_jit_end_addr, exe_ctx, - m_data_allocator.get(), evaluated_statically, const_result, eExecutionPolicyAlways); - if (log) - { - StreamString dump_string; - m_data_allocator->Dump(dump_string); - - log->Printf("Data buffer contents:\n%s", dump_string.GetString().c_str()); - } - if (m_jit_start_addr != LLDB_INVALID_ADDRESS) m_jit_process_wp = lldb::ProcessWP(process->shared_from_this()); diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp new file mode 100644 index 00000000000..c2a86d68654 --- /dev/null +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -0,0 +1,770 @@ +//===-- IRExecutionUnit.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/IR/Module.h" +// Project includes +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Log.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" + +using namespace lldb_private; + +IRExecutionUnit::IRExecutionUnit (std::auto_ptr<llvm::Module> &module_ap, + ConstString &name, + lldb::ProcessSP process_sp, + std::vector<std::string> &cpu_features) : + m_process_wp(process_sp), + m_module_ap(module_ap), + m_module(m_module_ap.get()), + m_cpu_features(), + m_name(name), + m_did_jit(false), + m_function_load_addr(LLDB_INVALID_ADDRESS), + m_function_end_load_addr(LLDB_INVALID_ADDRESS) +{ + for (std::string &feature : cpu_features) + { + m_cpu_features.push_back(std::string(feature.c_str())); + } +} + +lldb::addr_t +IRExecutionUnit::WriteNow (const uint8_t *bytes, + size_t size, + Error &error) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + Allocation allocation; + allocation.m_size = size; + allocation.m_alignment = 8; + allocation.m_local_start = LLDB_INVALID_ADDRESS; + allocation.m_section_id = Allocation::eSectionIDNone; + + lldb_private::Error err; + + size_t allocation_size = (allocation.m_size ? allocation.m_size : 1) + allocation.m_alignment - 1; + + if (allocation_size == 0) + allocation_size = 1; + + lldb::ProcessSP process_sp = m_process_wp.lock(); + + if (!process_sp) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't find the process"); + } + + allocation.m_remote_allocation = process_sp->AllocateMemory(allocation_size, + (lldb::ePermissionsReadable | lldb::ePermissionsWritable), + err); + + if (!err.Success()) + return LLDB_INVALID_ADDRESS; + + process_sp->WriteMemory(allocation.m_remote_allocation, bytes, size, err); + + if (!err.Success()) + { + process_sp->DeallocateMemory(allocation.m_remote_allocation); + allocation.m_remote_allocation = LLDB_INVALID_ADDRESS; + return LLDB_INVALID_ADDRESS; + } + + uint64_t mask = allocation.m_alignment - 1; + + allocation.m_remote_start = (allocation.m_remote_allocation + mask) & (~mask); + + allocation.m_allocated = true; + + if (log) + { + log->Printf("IRExecutionUnit::WriteNow() wrote to 0x%llx", allocation.m_remote_start); + allocation.dump(log); + } + + m_allocations.push_back(allocation); + + return allocation.m_remote_start; +} + +void +IRExecutionUnit::FreeNow (lldb::addr_t allocation) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + if (allocation == LLDB_INVALID_ADDRESS) + return; + + lldb::ProcessSP process_sp = m_process_wp.lock(); + + if (!process_sp) + return; + + for (auto ai = m_allocations.begin(), ae = m_allocations.end(); + ai != ae; + ++ai) + { + if (ai->m_remote_allocation == allocation) + { + m_allocations.erase(ai); + log->Printf("IRExecutionUnit::FreeNow() freed 0x%llx", allocation); + return; + } + } +} + +Error +IRExecutionUnit::DisassembleFunction (Stream &stream, + lldb::ProcessSP &process_wp) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + ExecutionContext exe_ctx(process_wp); + + Error ret; + + ret.Clear(); + + lldb::addr_t func_local_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t func_remote_addr = LLDB_INVALID_ADDRESS; + + for (JittedFunction &function : m_jitted_functions) + { + if (strstr(function.m_name.c_str(), m_name.AsCString())) + { + func_local_addr = function.m_local_addr; + func_remote_addr = function.m_remote_addr; + } + } + + if (func_local_addr == LLDB_INVALID_ADDRESS) + { + ret.SetErrorToGenericError(); + ret.SetErrorStringWithFormat("Couldn't find function %s for disassembly", m_name.AsCString()); + return ret; + } + + if (log) + log->Printf("Found function, has local address 0x%" PRIx64 " and remote address 0x%" PRIx64, (uint64_t)func_local_addr, (uint64_t)func_remote_addr); + + std::pair <lldb::addr_t, lldb::addr_t> func_range; + + func_range = 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", m_name.AsCString()); + return ret; + } + + if (log) + log->Printf("Function's code range is [0x%" PRIx64 "+0x%" PRIx64 "]", func_range.first, func_range.second); + + Target *target = exe_ctx.GetTargetPtr(); + if (!target) + { + ret.SetErrorToGenericError(); + ret.SetErrorString("Couldn't find the target"); + return ret; + } + + lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second, 0)); + + Process *process = exe_ctx.GetProcessPtr(); + Error err; + 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(target->GetArchitecture()); + + const char *plugin_name = NULL; + const char *flavor_string = NULL; + lldb::DisassemblerSP disassembler = Disassembler::FindPlugin(arch, flavor_string, plugin_name); + + if (!disassembler) + { + ret.SetErrorToGenericError(); + ret.SetErrorStringWithFormat("Unable to find disassembler plug-in for %s architecture.", arch.GetArchitectureName()); + return ret; + } + + if (!process) + { + ret.SetErrorToGenericError(); + ret.SetErrorString("Couldn't find the process"); + return ret; + } + + DataExtractor extractor(buffer_sp, + process->GetByteOrder(), + target->GetArchitecture().GetAddressByteSize()); + + if (log) + { + log->Printf("Function data has contents:"); + extractor.PutToLog (log.get(), + 0, + extractor.GetByteSize(), + func_remote_addr, + 16, + DataExtractor::TypeUInt8); + } + + disassembler->DecodeInstructions (Address (func_remote_addr), extractor, 0, UINT32_MAX, false); + + InstructionList &instruction_list = disassembler->GetInstructionList(); + const uint32_t max_opcode_byte_size = instruction_list.GetMaxOpcocdeByteSize(); + + for (size_t instruction_index = 0, num_instructions = instruction_list.GetSize(); + instruction_index < num_instructions; + ++instruction_index) + { + Instruction *instruction = instruction_list.GetInstructionAtIndex(instruction_index).get(); + instruction->Dump (&stream, + max_opcode_byte_size, + true, + true, + &exe_ctx); + stream.PutChar('\n'); + } + + return ret; +} + +void +IRExecutionUnit::GetRunnableInfo(Error &error, + lldb::addr_t &func_addr, + lldb::addr_t &func_end) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + lldb::ProcessSP process_sp(m_process_wp.lock()); + + func_addr = LLDB_INVALID_ADDRESS; + func_end = LLDB_INVALID_ADDRESS; + + if (!process_sp) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't write the JIT compiled code into the process because the process is invalid"); + return; + } + + if (m_did_jit) + { + func_addr = m_function_load_addr; + func_end = m_function_end_load_addr; + + return; + }; // someone else may have gotten the mutex first + + { + Mutex::Locker jit_mutex_locker(m_jit_mutex); + + if (m_did_jit) + { + func_addr = m_function_load_addr; + func_end = m_function_end_load_addr; + + return; + }; // someone else may have gotten the mutex first + + m_did_jit = true; + + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + std::string error_string; + + if (log) + { + std::string s; + llvm::raw_string_ostream oss(s); + + m_module->print(oss, NULL); + + oss.flush(); + + log->Printf ("Module being sent to JIT: \n%s", s.c_str()); + } + + llvm::Triple triple(m_module->getTargetTriple()); + llvm::Function *function = m_module->getFunction (m_name.AsCString()); + llvm::Reloc::Model relocModel; + llvm::CodeModel::Model codeModel; + + if (triple.isOSBinFormatELF()) + { + relocModel = llvm::Reloc::Static; + // This will be small for 32-bit and large for 64-bit. + codeModel = llvm::CodeModel::JITDefault; + } + else + { + relocModel = llvm::Reloc::PIC_; + codeModel = llvm::CodeModel::Small; + } + + llvm::EngineBuilder builder(m_module_ap.get()); + + builder.setEngineKind(llvm::EngineKind::JIT) + .setErrorStr(&error_string) + .setRelocationModel(relocModel) + .setJITMemoryManager(new MemoryManager(*this)) + .setOptLevel(llvm::CodeGenOpt::Less) + .setAllocateGVsWithCode(true) + .setCodeModel(codeModel) + .setUseMCJIT(true); + + llvm::StringRef mArch; + llvm::StringRef mCPU; + llvm::SmallVector<std::string, 0> mAttrs; + + for (std::string &feature : m_cpu_features) + mAttrs.push_back(feature); + + llvm::TargetMachine *target_machine = builder.selectTarget(triple, + mArch, + mCPU, + mAttrs); + + m_execution_engine_ap.reset(builder.create(target_machine)); + + if (!m_execution_engine_ap.get()) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str()); + return; + } + else + { + m_module_ap.release(); // ownership was transferred + } + + m_execution_engine_ap->DisableLazyCompilation(); + + // We don't actually need the function pointer here, this just forces it to get resolved. + + void *fun_ptr = m_execution_engine_ap->getPointerToFunction(function); + + // Errors usually cause failures in the JIT, but if we're lucky we get here. + + if (!function) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("Couldn't find '%s' in the JITted module", m_name.AsCString()); + return; + } + + if (!fun_ptr) + { + error.SetErrorToGenericError(); + error.SetErrorStringWithFormat("'%s' was in the JITted module but wasn't lowered", m_name.AsCString()); + return; + } + + m_jitted_functions.push_back (JittedFunction(m_name.AsCString(), (lldb::addr_t)fun_ptr)); + + CommitAllocations(process_sp); + ReportAllocations(*m_execution_engine_ap); + WriteData(process_sp); + + for (JittedFunction &jitted_function : m_jitted_functions) + { + jitted_function.m_remote_addr = GetRemoteAddressForLocal (jitted_function.m_local_addr); + + if (!jitted_function.m_name.compare(m_name.AsCString())) + { + AddrRange func_range = GetRemoteRangeForLocal(jitted_function.m_local_addr); + m_function_end_load_addr = func_range.first + func_range.second; + m_function_load_addr = jitted_function.m_remote_addr; + } + } + + if (log) + { + log->Printf("Code can be run in the target."); + + StreamString disassembly_stream; + + Error err = DisassembleFunction(disassembly_stream, process_sp); + + if (!err.Success()) + { + log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error")); + } + else + { + log->Printf("Function disassembly:\n%s", disassembly_stream.GetData()); + } + } + + func_addr = m_function_load_addr; + func_end = m_function_end_load_addr; + + return; + } +} + +IRExecutionUnit::~IRExecutionUnit () +{ +} + +IRExecutionUnit::MemoryManager::MemoryManager (IRExecutionUnit &parent) : + m_default_mm_ap (llvm::JITMemoryManager::CreateDefaultMemManager()), + m_parent (parent) +{ +} + +void +IRExecutionUnit::MemoryManager::setMemoryWritable () +{ + m_default_mm_ap->setMemoryWritable(); +} + +void +IRExecutionUnit::MemoryManager::setMemoryExecutable () +{ + m_default_mm_ap->setMemoryExecutable(); +} + + +uint8_t * +IRExecutionUnit::MemoryManager::startFunctionBody(const llvm::Function *F, + uintptr_t &ActualSize) +{ + return m_default_mm_ap->startFunctionBody(F, ActualSize); +} + +uint8_t * +IRExecutionUnit::MemoryManager::allocateStub(const llvm::GlobalValue* F, + unsigned StubSize, + unsigned Alignment) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + uint8_t *return_value = m_default_mm_ap->allocateStub(F, StubSize, Alignment); + + Allocation allocation; + allocation.m_size = StubSize; + allocation.m_alignment = Alignment; + allocation.m_local_start = (uintptr_t)return_value; + + if (log) + { + log->Printf("IRExecutionUnit::allocateStub (F=%p, StubSize=%u, Alignment=%u) = %p", + F, StubSize, Alignment, return_value); + allocation.dump(log); + } + + m_parent.m_allocations.push_back(allocation); + + return return_value; +} + +void +IRExecutionUnit::MemoryManager::endFunctionBody(const llvm::Function *F, + uint8_t *FunctionStart, + uint8_t *FunctionEnd) +{ + m_default_mm_ap->endFunctionBody(F, FunctionStart, FunctionEnd); +} + +uint8_t * +IRExecutionUnit::MemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + uint8_t *return_value = m_default_mm_ap->allocateSpace(Size, Alignment); + + Allocation allocation; + allocation.m_size = Size; + allocation.m_alignment = Alignment; + allocation.m_local_start = (uintptr_t)return_value; + + if (log) + { + log->Printf("IRExecutionUnit::allocateSpace(Size=%" PRIu64 ", Alignment=%u) = %p", + (uint64_t)Size, Alignment, return_value); + allocation.dump(log); + } + + m_parent.m_allocations.push_back(allocation); + + return return_value; +} + +uint8_t * +IRExecutionUnit::MemoryManager::allocateCodeSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + uint8_t *return_value = m_default_mm_ap->allocateCodeSection(Size, Alignment, SectionID); + + Allocation allocation; + allocation.m_size = Size; + allocation.m_alignment = Alignment; + allocation.m_local_start = (uintptr_t)return_value; + allocation.m_section_id = SectionID; + allocation.m_executable = true; + + if (log) + { + log->Printf("IRExecutionUnit::allocateCodeSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p", + (uint64_t)Size, Alignment, SectionID, return_value); + allocation.dump(log); + } + + m_parent.m_allocations.push_back(allocation); + + return return_value; +} + +uint8_t * +IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID, + bool IsReadOnly) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + uint8_t *return_value = m_default_mm_ap->allocateDataSection(Size, Alignment, SectionID, IsReadOnly); + + Allocation allocation; + allocation.m_size = Size; + allocation.m_alignment = Alignment; + allocation.m_local_start = (uintptr_t)return_value; + allocation.m_section_id = SectionID; + + if (log) + { + log->Printf("IRExecutionUnit::allocateDataSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p", + (uint64_t)Size, Alignment, SectionID, return_value); + allocation.dump(log); + } + + m_parent.m_allocations.push_back(allocation); + + return return_value; +} + +uint8_t * +IRExecutionUnit::MemoryManager::allocateGlobal(uintptr_t Size, + unsigned Alignment) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + uint8_t *return_value = m_default_mm_ap->allocateGlobal(Size, Alignment); + + Allocation allocation; + allocation.m_size = Size; + allocation.m_alignment = Alignment; + allocation.m_local_start = (uintptr_t)return_value; + + if (log) + { + log->Printf("IRExecutionUnit::allocateGlobal(Size=0x%" PRIx64 ", Alignment=%u) = %p", + (uint64_t)Size, Alignment, return_value); + allocation.dump(log); + } + + m_parent.m_allocations.push_back(allocation); + + return return_value; +} + +void +IRExecutionUnit::MemoryManager::deallocateFunctionBody(void *Body) +{ + m_default_mm_ap->deallocateFunctionBody(Body); +} + +uint8_t* +IRExecutionUnit::MemoryManager::startExceptionTable(const llvm::Function* F, + uintptr_t &ActualSize) +{ + return m_default_mm_ap->startExceptionTable(F, ActualSize); +} + +void +IRExecutionUnit::MemoryManager::endExceptionTable(const llvm::Function *F, + uint8_t *TableStart, + uint8_t *TableEnd, + uint8_t* FrameRegister) +{ + m_default_mm_ap->endExceptionTable(F, TableStart, TableEnd, FrameRegister); +} + +void +IRExecutionUnit::MemoryManager::deallocateExceptionTable(void *ET) +{ + m_default_mm_ap->deallocateExceptionTable (ET); +} + +lldb::addr_t +IRExecutionUnit::GetRemoteAddressForLocal (lldb::addr_t local_address) +{ + for (Allocation &allocation : m_allocations) + { + if (local_address >= allocation.m_local_start && + local_address < allocation.m_local_start + allocation.m_size) + return allocation.m_remote_start + (local_address - allocation.m_local_start); + } + + return LLDB_INVALID_ADDRESS; +} + +IRExecutionUnit::AddrRange +IRExecutionUnit::GetRemoteRangeForLocal (lldb::addr_t local_address) +{ + for (Allocation &allocation : m_allocations) + { + if (local_address >= allocation.m_local_start && + local_address < allocation.m_local_start + allocation.m_size) + return AddrRange(allocation.m_remote_start, allocation.m_size); + } + + return AddrRange (0, 0); +} + +bool +IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + bool ret = true; + + for (Allocation &allocation : m_allocations) + { + if (allocation.m_allocated) + continue; + + lldb_private::Error err; + + size_t allocation_size = (allocation.m_size ? allocation.m_size : 1) + allocation.m_alignment - 1; + + if (allocation_size == 0) + allocation_size = 1; + + allocation.m_remote_allocation = process_sp->AllocateMemory( + allocation_size, + allocation.m_executable ? (lldb::ePermissionsReadable | lldb::ePermissionsExecutable) + : (lldb::ePermissionsReadable | lldb::ePermissionsWritable), + err); + + uint64_t mask = allocation.m_alignment - 1; + + allocation.m_remote_start = (allocation.m_remote_allocation + mask) & (~mask); + + if (!err.Success()) + { + ret = false; + break; + } + + allocation.m_allocated = true; + + if (log) + { + log->Printf("IRExecutionUnit::CommitAllocations() committed an allocation"); + allocation.dump(log); + } + } + + if (!ret) + { + for (Allocation &allocation : m_allocations) + { + if (allocation.m_allocated) + process_sp->DeallocateMemory(allocation.m_remote_start); + } + } + + return ret; +} + +void +IRExecutionUnit::ReportAllocations (llvm::ExecutionEngine &engine) +{ + for (Allocation &allocation : m_allocations) + { + if (!allocation.m_allocated) + continue; + + if (allocation.m_local_start == LLDB_INVALID_ADDRESS) + continue; + + engine.mapSectionAddress((void*)allocation.m_local_start, allocation.m_remote_start); + } + // Trigger re-application of relocations. + engine.finalizeObject(); +} + +bool +IRExecutionUnit::WriteData (lldb::ProcessSP &process_sp) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + for (Allocation &allocation : m_allocations) + { + if (!allocation.m_allocated) + return false; + + if (allocation.m_local_start == LLDB_INVALID_ADDRESS) + continue; + + lldb_private::Error err; + + if (process_sp->WriteMemory(allocation.m_remote_start, + (void*)allocation.m_local_start, + allocation.m_size, + err) != allocation.m_size || + !err.Success()) + return false; + + if (log) + { + log->Printf("IRExecutionUnit::CommitAllocations() wrote an allocation"); + allocation.dump(log); + } + } + + return true; +} + +void +IRExecutionUnit::Allocation::dump (lldb::LogSP log) +{ + if (!log) + return; + + log->Printf("[0x%llx+0x%llx]->0x%llx (alignment %d, section ID %d)", + (unsigned long long)m_local_start, + (unsigned long long)m_size, + (unsigned long long)m_remote_start, + (unsigned)m_alignment, + (unsigned)m_section_id); +} diff --git a/lldb/source/Expression/IRForTarget.cpp b/lldb/source/Expression/IRForTarget.cpp index c7c96f73fbd..279e034d832 100644 --- a/lldb/source/Expression/IRForTarget.cpp +++ b/lldb/source/Expression/IRForTarget.cpp @@ -22,12 +22,14 @@ #include "clang/AST/ASTContext.h" -#include "lldb/Core/ConstString.h" #include "lldb/Core/dwarf.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Log.h" #include "lldb/Core/Scalar.h" #include "lldb/Core/StreamString.h" #include "lldb/Expression/ClangExpressionDeclMap.h" +#include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRInterpreter.h" #include "lldb/Host/Endian.h" #include "lldb/Symbol/ClangASTContext.h" @@ -38,19 +40,32 @@ using namespace llvm; static char ID; -IRForTarget::StaticDataAllocator::StaticDataAllocator() +IRForTarget::StaticDataAllocator::StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit) : + m_execution_unit(execution_unit), + m_allocation(LLDB_INVALID_ADDRESS) { } -IRForTarget::StaticDataAllocator::~StaticDataAllocator() +lldb::addr_t IRForTarget::StaticDataAllocator::Allocate() { + lldb_private::Error err; + + if (m_allocation != LLDB_INVALID_ADDRESS) + { + m_execution_unit.FreeNow(m_allocation); + m_allocation = LLDB_INVALID_ADDRESS; + } + + m_allocation = m_execution_unit.WriteNow((const uint8_t*)m_stream_string.GetData(), m_stream_string.GetSize(), err); + + return m_allocation; } IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map, bool resolve_vars, lldb_private::ExecutionPolicy execution_policy, lldb::ClangExpressionVariableSP &const_result, - StaticDataAllocator *data_allocator, + lldb_private::IRExecutionUnit &execution_unit, lldb_private::Stream *error_stream, const char *func_name) : ModulePass(ID), @@ -60,7 +75,7 @@ IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map, m_func_name(func_name), m_module(NULL), m_decl_map(decl_map), - m_data_allocator(data_allocator), + m_data_allocator(execution_unit), m_CFStringCreateWithBytes(NULL), m_sel_registerName(NULL), m_const_result(const_result), @@ -1559,7 +1574,7 @@ IRForTarget::MaterializeInternalVariable (GlobalVariable *global_variable) if (global_variable == m_reloc_placeholder) return true; - uint64_t offset = m_data_allocator->GetStream().GetSize(); + uint64_t offset = m_data_allocator.GetStream().GetSize(); llvm::Type *variable_type = global_variable->getType(); @@ -1572,7 +1587,7 @@ IRForTarget::MaterializeInternalVariable (GlobalVariable *global_variable) const size_t mask = (align - 1); uint64_t aligned_offset = (offset + mask) & ~mask; - m_data_allocator->GetStream().PutNHex8(aligned_offset - offset, 0); + m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0); offset = aligned_offset; lldb_private::DataBufferHeap data(size, '\0'); @@ -1581,7 +1596,7 @@ IRForTarget::MaterializeInternalVariable (GlobalVariable *global_variable) if (!MaterializeInitializer(data.GetBytes(), initializer)) return false; - m_data_allocator->GetStream().Write(data.GetBytes(), data.GetByteSize()); + m_data_allocator.GetStream().Write(data.GetBytes(), data.GetByteSize()); Constant *new_pointer = BuildRelocation(variable_type, offset); @@ -1960,9 +1975,6 @@ IRForTarget::ReplaceStrings () { lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - if (!m_data_allocator) - return true; // hope for the best; some clients may not want static allocation! - typedef std::map <GlobalVariable *, size_t> OffsetsTy; OffsetsTy offsets; @@ -2014,9 +2026,9 @@ IRForTarget::ReplaceStrings () str = gc_array->getAsString(); } - offsets[gv] = m_data_allocator->GetStream().GetSize(); + offsets[gv] = m_data_allocator.GetStream().GetSize(); - m_data_allocator->GetStream().Write(str.c_str(), str.length() + 1); + m_data_allocator.GetStream().Write(str.c_str(), str.length() + 1); } Type *char_ptr_ty = Type::getInt8PtrTy(m_module->getContext()); @@ -2083,9 +2095,6 @@ bool IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block) { lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (!m_data_allocator) - return true; typedef SmallVector <Value*, 2> ConstantList; typedef SmallVector <llvm::Instruction*, 2> UserList; @@ -2156,7 +2165,7 @@ IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block) lldb_private::DataBufferHeap data(operand_data_size, 0); - if (lldb::endian::InlHostByteOrder() != m_data_allocator->GetStream().GetByteOrder()) + if (lldb::endian::InlHostByteOrder() != m_data_allocator.GetStream().GetByteOrder()) { uint8_t *data_bytes = data.GetBytes(); @@ -2172,16 +2181,16 @@ IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block) memcpy(data.GetBytes(), operand_raw_data, operand_data_size); } - uint64_t offset = m_data_allocator->GetStream().GetSize(); + uint64_t offset = m_data_allocator.GetStream().GetSize(); size_t align = m_target_data->getPrefTypeAlignment(operand_type); const size_t mask = (align - 1); uint64_t aligned_offset = (offset + mask) & ~mask; - m_data_allocator->GetStream().PutNHex8(aligned_offset - offset, 0); + m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0); offset = aligned_offset; - m_data_allocator->GetStream().Write(data.GetBytes(), operand_data_size); + m_data_allocator.GetStream().Write(data.GetBytes(), operand_data_size); llvm::Type *fp_ptr_ty = operand_constant_fp->getType()->getPointerTo(); @@ -2603,16 +2612,13 @@ IRForTarget::BuildRelocation(llvm::Type *type, bool IRForTarget::CompleteDataAllocation () -{ - if (!m_data_allocator) - return true; - +{ lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - if (!m_data_allocator->GetStream().GetSize()) + if (!m_data_allocator.GetStream().GetSize()) return true; - lldb::addr_t allocation = m_data_allocator->Allocate(); + lldb::addr_t allocation = m_data_allocator.Allocate(); if (log) { @@ -2622,7 +2628,7 @@ IRForTarget::CompleteDataAllocation () log->Printf("Failed to allocate static data"); } - if (!allocation) + if (!allocation || allocation == LLDB_INVALID_ADDRESS) return false; IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(), diff --git a/lldb/source/Expression/ProcessDataAllocator.cpp b/lldb/source/Expression/ProcessDataAllocator.cpp deleted file mode 100644 index 3ac07708e91..00000000000 --- a/lldb/source/Expression/ProcessDataAllocator.cpp +++ /dev/null @@ -1,43 +0,0 @@ -//===-- ProcessDataAllocator.cpp --------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/DataExtractor.h" -#include "lldb/Expression/ProcessDataAllocator.h" - -using namespace lldb_private; - -void -ProcessDataAllocator::Dump(Stream &stream) -{ - size_t data_size = m_stream_string.GetSize(); - - if (!m_allocation) - return; - - lldb::DataBufferSP data(new DataBufferHeap(data_size, 0)); - - Error error; - if (m_process.ReadMemory (m_allocation, data->GetBytes(), data_size, error) != data_size) - return; - - DataExtractor extractor(data, m_process.GetByteOrder(), m_process.GetAddressByteSize()); - - extractor.Dump(&stream, // stream - 0, // offset - lldb::eFormatBytesWithASCII, // format - 1, // byte size of individual entries - data_size, // number of entries - 16, // entries per line - m_allocation, // address to print - 0, // bit size (bitfields only; 0 means ignore) - 0); // bit alignment (bitfields only; 0 means ignore) - - stream.PutChar('\n'); -} diff --git a/lldb/source/Expression/RecordingMemoryManager.cpp b/lldb/source/Expression/RecordingMemoryManager.cpp deleted file mode 100644 index 2a81fc2d125..00000000000 --- a/lldb/source/Expression/RecordingMemoryManager.cpp +++ /dev/null @@ -1,342 +0,0 @@ -//===-- RecordingMemoryManager.cpp ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// C Includes -// C++ Includes -// Other libraries and framework includes -#include "llvm/ExecutionEngine/ExecutionEngine.h" -// Project includes -#include "lldb/Expression/RecordingMemoryManager.h" - -using namespace lldb_private; - -RecordingMemoryManager::RecordingMemoryManager () : - llvm::JITMemoryManager(), - m_default_mm_ap (llvm::JITMemoryManager::CreateDefaultMemManager()), - m_log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) -{ -} - -RecordingMemoryManager::~RecordingMemoryManager () -{ -} - -void -RecordingMemoryManager::setMemoryWritable () -{ - m_default_mm_ap->setMemoryWritable(); -} - -void -RecordingMemoryManager::setMemoryExecutable () -{ - m_default_mm_ap->setMemoryExecutable(); -} - - -uint8_t * -RecordingMemoryManager::startFunctionBody(const llvm::Function *F, - uintptr_t &ActualSize) -{ - return m_default_mm_ap->startFunctionBody(F, ActualSize); -} - -uint8_t * -RecordingMemoryManager::allocateStub(const llvm::GlobalValue* F, unsigned StubSize, - unsigned Alignment) -{ - uint8_t *return_value = m_default_mm_ap->allocateStub(F, StubSize, Alignment); - - Allocation allocation; - allocation.m_size = StubSize; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; - - if (m_log) - { - m_log->Printf("RecordingMemoryManager::allocateStub (F=%p, StubSize=%u, Alignment=%u) = %p", - F, StubSize, Alignment, return_value); - allocation.dump(m_log); - } - - m_allocations.push_back(allocation); - - return return_value; -} - -void -RecordingMemoryManager::endFunctionBody(const llvm::Function *F, uint8_t *FunctionStart, - uint8_t *FunctionEnd) -{ - m_default_mm_ap->endFunctionBody(F, FunctionStart, FunctionEnd); -} - -uint8_t * -RecordingMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) -{ - uint8_t *return_value = m_default_mm_ap->allocateSpace(Size, Alignment); - - Allocation allocation; - allocation.m_size = Size; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; - - if (m_log) - { - m_log->Printf("RecordingMemoryManager::allocateSpace(Size=%" PRIu64 ", Alignment=%u) = %p", - (uint64_t)Size, Alignment, return_value); - allocation.dump(m_log); - } - - m_allocations.push_back(allocation); - - return return_value; -} - -uint8_t * -RecordingMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) -{ - uint8_t *return_value = m_default_mm_ap->allocateCodeSection(Size, Alignment, SectionID); - - Allocation allocation; - allocation.m_size = Size; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; - allocation.m_section_id = SectionID; - allocation.m_executable = true; - - if (m_log) - { - m_log->Printf("RecordingMemoryManager::allocateCodeSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p", - (uint64_t)Size, Alignment, SectionID, return_value); - allocation.dump(m_log); - } - - m_allocations.push_back(allocation); - - return return_value; -} - -uint8_t * -RecordingMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, bool IsReadOnly) -{ - uint8_t *return_value = m_default_mm_ap->allocateDataSection(Size, Alignment, SectionID, IsReadOnly); - - Allocation allocation; - allocation.m_size = Size; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; - allocation.m_section_id = SectionID; - - if (m_log) - { - m_log->Printf("RecordingMemoryManager::allocateDataSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p", - (uint64_t)Size, Alignment, SectionID, return_value); - allocation.dump(m_log); - } - - m_allocations.push_back(allocation); - - return return_value; -} - -uint8_t * -RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) -{ - uint8_t *return_value = m_default_mm_ap->allocateGlobal(Size, Alignment); - - Allocation allocation; - allocation.m_size = Size; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; - - if (m_log) - { - m_log->Printf("RecordingMemoryManager::allocateGlobal(Size=0x%" PRIx64 ", Alignment=%u) = %p", - (uint64_t)Size, Alignment, return_value); - allocation.dump(m_log); - } - - m_allocations.push_back(allocation); - - return return_value; -} - -void -RecordingMemoryManager::deallocateFunctionBody(void *Body) -{ - m_default_mm_ap->deallocateFunctionBody(Body); -} - -uint8_t* -RecordingMemoryManager::startExceptionTable(const llvm::Function* F, - uintptr_t &ActualSize) -{ - return m_default_mm_ap->startExceptionTable(F, ActualSize); -} - -void -RecordingMemoryManager::endExceptionTable(const llvm::Function *F, uint8_t *TableStart, - uint8_t *TableEnd, uint8_t* FrameRegister) -{ - m_default_mm_ap->endExceptionTable(F, TableStart, TableEnd, FrameRegister); -} - -void -RecordingMemoryManager::deallocateExceptionTable(void *ET) -{ - m_default_mm_ap->deallocateExceptionTable (ET); -} - -lldb::addr_t -RecordingMemoryManager::GetRemoteAddressForLocal (lldb::addr_t local_address) -{ - for (AllocationList::iterator ai = m_allocations.begin(), ae = m_allocations.end(); - ai != ae; - ++ai) - { - if (local_address >= ai->m_local_start && - local_address < ai->m_local_start + ai->m_size) - return ai->m_remote_start + (local_address - ai->m_local_start); - } - - return LLDB_INVALID_ADDRESS; -} - -RecordingMemoryManager::AddrRange -RecordingMemoryManager::GetRemoteRangeForLocal (lldb::addr_t local_address) -{ - for (AllocationList::iterator ai = m_allocations.begin(), ae = m_allocations.end(); - ai != ae; - ++ai) - { - if (local_address >= ai->m_local_start && - local_address < ai->m_local_start + ai->m_size) - return AddrRange(ai->m_remote_start, ai->m_size); - } - - return AddrRange (0, 0); -} - -bool -RecordingMemoryManager::CommitAllocations (Process &process) -{ - bool ret = true; - - for (AllocationList::iterator ai = m_allocations.begin(), ae = m_allocations.end(); - ai != ae; - ++ai) - { - if (ai->m_allocated) - continue; - - lldb_private::Error err; - - size_t allocation_size = (ai->m_size ? ai->m_size : 1) + ai->m_alignment - 1; - - if (allocation_size == 0) - allocation_size = 1; - - ai->m_remote_allocation = process.AllocateMemory( - allocation_size, - ai->m_executable ? (lldb::ePermissionsReadable | lldb::ePermissionsExecutable) - : (lldb::ePermissionsReadable | lldb::ePermissionsWritable), - err); - - uint64_t mask = ai->m_alignment - 1; - - ai->m_remote_start = (ai->m_remote_allocation + mask) & (~mask); - - if (!err.Success()) - { - ret = false; - break; - } - - ai->m_allocated = true; - - if (m_log) - { - m_log->Printf("RecordingMemoryManager::CommitAllocations() committed an allocation"); - ai->dump(m_log); - } - } - - if (!ret) - { - for (AllocationList::iterator ai = m_allocations.end(), ae = m_allocations.end(); - ai != ae; - ++ai) - { - if (ai->m_allocated) - process.DeallocateMemory(ai->m_remote_start); - } - } - - return ret; -} - -void -RecordingMemoryManager::ReportAllocations (llvm::ExecutionEngine &engine) -{ - for (AllocationList::iterator ai = m_allocations.begin(), ae = m_allocations.end(); - ai != ae; - ++ai) - { - if (!ai->m_allocated) - continue; - - engine.mapSectionAddress((void*)ai->m_local_start, ai->m_remote_start); - } - // Trigger re-application of relocations. - engine.finalizeObject(); -} - -bool -RecordingMemoryManager::WriteData (Process &process) -{ - for (AllocationList::iterator ai = m_allocations.begin(), ae = m_allocations.end(); - ai != ae; - ++ai) - { - if (!ai->m_allocated) - return false; - - lldb_private::Error err; - - if (process.WriteMemory(ai->m_remote_start, - (void*)ai->m_local_start, - ai->m_size, - err) != ai->m_size || - !err.Success()) - return false; - - if (m_log) - { - m_log->Printf("RecordingMemoryManager::CommitAllocations() wrote an allocation"); - ai->dump(m_log); - } - } - - return true; -} - -void -RecordingMemoryManager::Allocation::dump (lldb::LogSP log) -{ - if (!log) - return; - - log->Printf("[0x%llx+0x%llx]->0x%llx (alignment %d, section ID %d)", - (unsigned long long)m_local_start, - (unsigned long long)m_size, - (unsigned long long)m_remote_start, - (unsigned)m_alignment, - (unsigned)m_section_id); -} |