diff options
-rw-r--r-- | lldb/include/lldb/Expression/ClangExpression.h | 7 | ||||
-rw-r--r-- | lldb/include/lldb/Expression/ClangExpressionParser.h | 5 | ||||
-rw-r--r-- | lldb/include/lldb/Expression/ClangFunction.h | 1 | ||||
-rw-r--r-- | lldb/include/lldb/Expression/ClangUserExpression.h | 12 | ||||
-rw-r--r-- | lldb/include/lldb/Expression/ClangUtilityFunction.h | 1 | ||||
-rw-r--r-- | lldb/include/lldb/Expression/IRExecutionUnit.h | 86 | ||||
-rw-r--r-- | lldb/include/lldb/Expression/IRMemoryMap.h | 89 | ||||
-rw-r--r-- | lldb/include/lldb/lldb-forward.h | 1 | ||||
-rw-r--r-- | lldb/lldb.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | lldb/source/Expression/ClangExpressionParser.cpp | 5 | ||||
-rw-r--r-- | lldb/source/Expression/ClangFunction.cpp | 1 | ||||
-rw-r--r-- | lldb/source/Expression/ClangUserExpression.cpp | 1 | ||||
-rw-r--r-- | lldb/source/Expression/ClangUtilityFunction.cpp | 3 | ||||
-rw-r--r-- | lldb/source/Expression/IRExecutionUnit.cpp | 536 | ||||
-rw-r--r-- | lldb/source/Expression/IRMemoryMap.cpp | 410 |
15 files changed, 786 insertions, 378 deletions
diff --git a/lldb/include/lldb/Expression/ClangExpression.h b/lldb/include/lldb/Expression/ClangExpression.h index 07a9ca096f2..bf5ed23b2d9 100644 --- a/lldb/include/lldb/Expression/ClangExpression.h +++ b/lldb/include/lldb/Expression/ClangExpression.h @@ -93,13 +93,6 @@ public: DeclMap () = 0; //------------------------------------------------------------------ - /// Return the object that the parser should use when registering - /// local variables. May be NULL if the Expression doesn't care. - //------------------------------------------------------------------ - virtual ClangExpressionVariableList * - LocalVariables () = 0; - - //------------------------------------------------------------------ /// Return the object that the parser should allow to access ASTs. /// May be NULL if the ASTs do not need to be transformed. /// diff --git a/lldb/include/lldb/Expression/ClangExpressionParser.h b/lldb/include/lldb/Expression/ClangExpressionParser.h index 57172c5e3ab..57a7205a2ea 100644 --- a/lldb/include/lldb/Expression/ClangExpressionParser.h +++ b/lldb/include/lldb/Expression/ClangExpressionParser.h @@ -84,6 +84,10 @@ public: /// and func_end do not delimit an allocated region; the allocated /// region may begin before func_addr.) /// + /// @param[in] execution_unit_ap + /// After parsing, ownership of the execution unit for + /// for the expression is handed to this auto_ptr. + /// /// @param[in] exe_ctx /// The execution context to write the function into. /// @@ -108,6 +112,7 @@ public: Error PrepareForExecution (lldb::addr_t &func_addr, lldb::addr_t &func_end, + std::auto_ptr<IRExecutionUnit> &execution_unit_ap, ExecutionContext &exe_ctx, bool &evaluated_statically, lldb::ClangExpressionVariableSP &const_result, diff --git a/lldb/include/lldb/Expression/ClangFunction.h b/lldb/include/lldb/Expression/ClangFunction.h index ab7551fe540..b8663dd06d4 100644 --- a/lldb/include/lldb/Expression/ClangFunction.h +++ b/lldb/include/lldb/Expression/ClangFunction.h @@ -620,6 +620,7 @@ private: //------------------------------------------------------------------ std::auto_ptr<ClangExpressionParser> m_parser; ///< The parser responsible for compiling the function. + std::auto_ptr<IRExecutionUnit> m_execution_unit_ap; Function *m_function_ptr; ///< The function we're going to call. May be NULL if we don't have debug info for the function. Address m_function_addr; ///< If we don't have the FunctionSP, we at least need the address & return type. diff --git a/lldb/include/lldb/Expression/ClangUserExpression.h b/lldb/include/lldb/Expression/ClangUserExpression.h index aae149552cc..03cb355b760 100644 --- a/lldb/include/lldb/Expression/ClangUserExpression.h +++ b/lldb/include/lldb/Expression/ClangUserExpression.h @@ -243,16 +243,6 @@ public: } //------------------------------------------------------------------ - /// Return the object that the parser should use when registering - /// local variables. May be NULL if the Expression doesn't care. - //------------------------------------------------------------------ - ClangExpressionVariableList * - LocalVariables () - { - return m_local_variables.get(); - } - - //------------------------------------------------------------------ /// Return the object that the parser should allow to access ASTs. /// May be NULL if the ASTs do not need to be transformed. /// @@ -431,7 +421,7 @@ private: ResultType m_desired_type; ///< The type to coerce the expression's result to. If eResultTypeAny, inferred from the expression. 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<IRExecutionUnit> m_execution_unit_ap; ///< The execution unit the expression is stored in. 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 929f9238714..b89f390e21c 100644 --- a/lldb/include/lldb/Expression/ClangUtilityFunction.h +++ b/lldb/include/lldb/Expression/ClangUtilityFunction.h @@ -169,6 +169,7 @@ public: private: std::auto_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression. + std::auto_ptr<IRExecutionUnit> m_execution_unit_ap; 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 index f5db6295db9..47bdae5c5b5 100644 --- a/lldb/include/lldb/Expression/IRExecutionUnit.h +++ b/lldb/include/lldb/Expression/IRExecutionUnit.h @@ -26,6 +26,7 @@ #include "llvm/ExecutionEngine/JITMemoryManager.h" #include "lldb/Expression/ClangExpression.h" #include "lldb/Expression/ClangExpressionParser.h" +#include "lldb/Expression/IRMemoryMap.h" #include "lldb/Host/Mutex.h" namespace llvm { @@ -57,7 +58,7 @@ class Error; /// into the target process, the IRExecutionUnit knows how to copy the /// emitted code into the target process. //---------------------------------------------------------------------- -class IRExecutionUnit +class IRExecutionUnit : public IRMemoryMap { public: //------------------------------------------------------------------ @@ -415,47 +416,7 @@ private: }; //---------------------------------------------------------------------- - /// @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 - 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 - - std::unique_ptr<DataBufferHeap> m_data; ///< If non-NULL, a local data buffer containing the written bytes. Only populated by WriteNow. - - 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 (Log *log); - }; - - //---------------------------------------------------------------------- - /// @class JittedFunction ClangExpressionParser.h "lldb/Expression/ClangExpressionParser.h" + /// @class JittedFunction IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.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 @@ -492,10 +453,44 @@ private: { } }; + + static const unsigned eSectionIDInvalid = (unsigned)-1; + + //---------------------------------------------------------------------- + /// @class AllocationRecord IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.h" + /// @brief Enacpsulates a single allocation request made by the JIT. + /// + /// Allocations made by the JIT are first queued up and then applied in + /// bulk to the underlying process. + //---------------------------------------------------------------------- + struct AllocationRecord { + lldb::addr_t m_process_address; + uintptr_t m_host_address; + uint32_t m_permissions; + size_t m_size; + unsigned m_alignment; + unsigned m_section_id; + + AllocationRecord (uintptr_t host_address, + uint32_t permissions, + size_t size, + unsigned alignment, + unsigned section_id = eSectionIDInvalid) : + m_process_address(LLDB_INVALID_ADDRESS), + m_host_address(host_address), + m_permissions(permissions), + m_size(size), + m_alignment(alignment), + m_section_id(section_id) + { + } + + void dump (Log *log); + }; + + typedef std::vector<AllocationRecord> RecordVector; + RecordVector m_records; - 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 @@ -504,7 +499,6 @@ private: 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; diff --git a/lldb/include/lldb/Expression/IRMemoryMap.h b/lldb/include/lldb/Expression/IRMemoryMap.h new file mode 100644 index 00000000000..23c0de0f10c --- /dev/null +++ b/lldb/include/lldb/Expression/IRMemoryMap.h @@ -0,0 +1,89 @@ +//===-- 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_IRMemoryMap_h_ +#define lldb_IRMemoryMap_h_ + +#include "lldb/lldb-public.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/UserID.h" + +#include <map> + +namespace lldb_private +{ + +//---------------------------------------------------------------------- +/// @class IRMemoryMap IRMemoryMap.h "lldb/Expression/IRMemoryMap.h" +/// @brief Encapsulates memory that may exist in the process but must +/// also be available in the host process. +/// +/// This class encapsulates a group of memory objects that must be readable +/// or writable from the host process regardless of whether the process +/// exists. This allows the IR interpreter as well as JITted code to access +/// the same memory. +/// +/// Point queries against this group of memory objects can be made by the +/// address in the tar at which they reside. If the inferior does not +/// exist, allocations still get made-up addresses. If an inferior appears +/// at some point, then those addresses need to be re-mapped. +//---------------------------------------------------------------------- +class IRMemoryMap +{ +public: + IRMemoryMap (lldb::ProcessSP process_sp); + ~IRMemoryMap (); + + enum AllocationPolicy { + eAllocationPolicyInvalid = 0, ///< It is an error for an allocation to have this policy. + eAllocationPolicyHostOnly, ///< This allocation was created in the host and will never make it into the process. + ///< It is an error to create other types of allocations while such allocations exist. + eAllocationPolicyMirror, ///< The intent is that this allocation exist both in the host and the process and have + ///< the same content in both. + eAllocationPolicyProcessOnly ///< The intent is that this allocation exist only in the process. + }; + + lldb::addr_t Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error); + void Free (lldb::addr_t process_address, Error &error); + + void WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error); + void ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error); + +protected: + lldb::ProcessWP GetProcessWP () + { + return m_process_wp; + } + +private: + struct Allocation + { + lldb::addr_t m_process_alloc; ///< The (unaligned) base for the remote allocation + lldb::addr_t m_process_start; ///< The base address of the allocation in the process + size_t m_size; ///< The size of the requested allocation + uint32_t m_permissions; ///< The access permissions on the memory in the process. In the host, the memory is always read/write. + uint8_t m_alignment; ///< The alignment of the requested allocation + + std::unique_ptr<DataBufferHeap> m_data; + + AllocationPolicy m_policy; + }; + + lldb::ProcessWP m_process_wp; + typedef std::map<lldb::addr_t, Allocation> AllocationMap; + AllocationMap m_allocations; + + lldb::addr_t FindSpace (size_t size); + bool ContainsHostOnlyAllocations (); + AllocationMap::iterator FindAllocation (lldb::addr_t addr, size_t size); +}; + +} + +#endif diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index 872d2e9214a..4db56bbddc8 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -118,6 +118,7 @@ class InlineFunctionInfo; class InputReader; class Instruction; class InstructionList; +class IRExecutionUnit; class LanguageRuntime; class LineTable; class Listener; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index c67709a9f17..0c8cf8d6318 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -497,6 +497,7 @@ 49A71FE8141FFACF00D59478 /* DataEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 268ED0A4140FF54200DE830F /* DataEncoder.cpp */; }; 49D8FB3913B5598F00411094 /* ClangASTImporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49D8FB3513B558DE00411094 /* ClangASTImporter.cpp */; }; 49DA65031485C92A005FF180 /* AppleObjCTypeVendor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DA65021485C92A005FF180 /* AppleObjCTypeVendor.cpp */; }; + 49DCF6FE170E6B4A0092F75E /* IRMemoryMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DCF6FD170E6B4A0092F75E /* IRMemoryMap.cpp */; }; 4C6649A014EEE7F100B0316F /* StreamCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C66499F14EEE7F100B0316F /* StreamCallback.h */; }; 4C6649A314EEE81000B0316F /* StreamCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C6649A214EEE81000B0316F /* StreamCallback.cpp */; }; 4C701C1E15ABB70C00B50001 /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26D55234159A7DB100708D8D /* libxml2.dylib */; }; @@ -1449,6 +1450,7 @@ 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>"; }; + 49C66B1C17011A43004D1922 /* IRMemoryMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IRMemoryMap.h; path = include/lldb/Expression/IRMemoryMap.h; 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>"; }; @@ -1459,6 +1461,7 @@ 49D8FB3713B5594900411094 /* ClangASTImporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangASTImporter.h; path = include/lldb/Symbol/ClangASTImporter.h; sourceTree = "<group>"; }; 49DA65021485C92A005FF180 /* AppleObjCTypeVendor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppleObjCTypeVendor.cpp; sourceTree = "<group>"; }; 49DA65041485C942005FF180 /* AppleObjCTypeVendor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleObjCTypeVendor.h; sourceTree = "<group>"; }; + 49DCF6FD170E6B4A0092F75E /* IRMemoryMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRMemoryMap.cpp; path = source/Expression/IRMemoryMap.cpp; sourceTree = "<group>"; }; 49E45FA911F660DC008F7B28 /* ClangASTType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangASTType.h; path = include/lldb/Symbol/ClangASTType.h; sourceTree = "<group>"; }; 49E45FAD11F660FE008F7B28 /* ClangASTType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangASTType.cpp; path = source/Symbol/ClangASTType.cpp; sourceTree = "<group>"; }; 49EC3E98118F90AC00B1265E /* ThreadPlanCallFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanCallFunction.cpp; path = source/Target/ThreadPlanCallFunction.cpp; sourceTree = "<group>"; }; @@ -2892,6 +2895,8 @@ 491193501226386000578B7F /* ASTStructExtractor.cpp */, 49CF9833122C718B007A0B96 /* IRDynamicChecks.h */, 49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */, + 49C66B1C17011A43004D1922 /* IRMemoryMap.h */, + 49DCF6FD170E6B4A0092F75E /* IRMemoryMap.cpp */, 4C98D3E1118FB98F00E575D0 /* IRExecutionUnit.h */, 4C98D3DB118FB96F00E575D0 /* IRExecutionUnit.cpp */, 49307AB111DEA4F20081F992 /* IRForTarget.h */, @@ -4298,6 +4303,7 @@ 260CC64A15D0440D002BF2E0 /* OptionValueBoolean.cpp in Sources */, 260CC64B15D0440D002BF2E0 /* OptionValueProperties.cpp in Sources */, 260CC64C15D0440D002BF2E0 /* OptionValueDictionary.cpp in Sources */, + 49DCF6FE170E6B4A0092F75E /* IRMemoryMap.cpp in Sources */, 260CC64D15D0440D002BF2E0 /* OptionValueEnumeration.cpp in Sources */, 260CC64E15D0440D002BF2E0 /* OptionValueFileSpec.cpp in Sources */, 260CC64F15D0440D002BF2E0 /* OptionValueFileSpecLIst.cpp in Sources */, diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp index 32daaa92861..61e24101491 100644 --- a/lldb/source/Expression/ClangExpressionParser.cpp +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -461,7 +461,8 @@ static bool FindFunctionInModule (ConstString &mangled_name, Error ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, - lldb::addr_t &func_end, + lldb::addr_t &func_end, + std::auto_ptr<IRExecutionUnit> &execution_unit_ap, ExecutionContext &exe_ctx, bool &evaluated_statically, lldb::ClangExpressionVariableSP &const_result, @@ -593,6 +594,8 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, } m_execution_unit->GetRunnableInfo(err, func_addr, func_end); + + execution_unit_ap = m_execution_unit; return err; } diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index f8db5c9c798..74fb0c0e806 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -266,6 +266,7 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) Error jit_error (m_parser->PrepareForExecution (m_jit_start_addr, m_jit_end_addr, + m_execution_unit_ap, exe_ctx, evaluated_statically, const_result, diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index cff35c35e7a..b0acfa04f23 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -463,6 +463,7 @@ ClangUserExpression::Parse (Stream &error_stream, Error jit_error = parser.PrepareForExecution (m_jit_start_addr, m_jit_end_addr, + m_execution_unit_ap, exe_ctx, m_evaluated_statically, m_const_result, diff --git a/lldb/source/Expression/ClangUtilityFunction.cpp b/lldb/source/Expression/ClangUtilityFunction.cpp index af33340bd16..61b0702dfd3 100644 --- a/lldb/source/Expression/ClangUtilityFunction.cpp +++ b/lldb/source/Expression/ClangUtilityFunction.cpp @@ -130,7 +130,8 @@ ClangUtilityFunction::Install (Stream &error_stream, bool evaluated_statically = false; // should stay that way Error jit_error = parser.PrepareForExecution (m_jit_start_addr, - m_jit_end_addr, + m_jit_end_addr, + m_execution_unit_ap, exe_ctx, evaluated_statically, const_result, diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 25fb157040c..dba361bd525 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -1,4 +1,4 @@ -//===-- IRExecutionUnit.cpp ------------------------------*- C++ -*-===// +//===-- IRExecutionUnit.cpp -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -29,7 +29,7 @@ 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), + IRMemoryMap(process_sp), m_module_ap(module_ap), m_module(m_module_ap.get()), m_cpu_features(cpu_features), @@ -45,89 +45,55 @@ IRExecutionUnit::WriteNow (const uint8_t *bytes, size_t size, Error &error) { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - auto iter = m_allocations.insert(m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - allocation.m_size = size; - allocation.m_alignment = 8; - allocation.m_data.reset(new DataBufferHeap(bytes, size)); - allocation.m_local_start = (uintptr_t)allocation.m_data->GetBytes(); - 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"); - return LLDB_INVALID_ADDRESS; - } - - allocation.m_remote_allocation = process_sp->AllocateMemory(allocation_size, - (lldb::ePermissionsReadable | lldb::ePermissionsWritable), - err); + lldb::addr_t allocation_process_addr = Malloc (size, + 8, + lldb::ePermissionsWritable | lldb::ePermissionsReadable, + eAllocationPolicyMirror, + error); - if (!err.Success()) + if (!error.Success()) return LLDB_INVALID_ADDRESS; - process_sp->WriteMemory(allocation.m_remote_allocation, bytes, size, err); + WriteMemory(allocation_process_addr, bytes, size, error); - if (!err.Success()) + if (!error.Success()) { - process_sp->DeallocateMemory(allocation.m_remote_allocation); - allocation.m_remote_allocation = LLDB_INVALID_ADDRESS; + Error err; + Free (allocation_process_addr, err); + 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) + if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) { - log->Printf("IRExecutionUnit::WriteNow() wrote to 0x%llx", allocation.m_remote_start); - allocation.dump(log); - } + DataBufferHeap my_buffer(size, 0); + Error err; + ReadMemory(my_buffer.GetBytes(), allocation_process_addr, size, err); - return allocation.m_remote_start; + if (err.Success()) + { + DataExtractor my_extractor(my_buffer.GetBytes(), my_buffer.GetByteSize(), lldb::eByteOrderBig, 8); + + StreamString ss; + + my_extractor.Dump(&ss, 0, lldb::eFormatBytesWithASCII, 1, my_buffer.GetByteSize(), 32, allocation_process_addr, 0, 0); + + log->PutCString(ss.GetData()); + } + } + + return allocation_process_addr; } void IRExecutionUnit::FreeNow (lldb::addr_t allocation) { - Log *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; + Error err; - 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; - } - } + Free(allocation, err); } Error @@ -271,7 +237,7 @@ IRExecutionUnit::GetRunnableInfo(Error &error, lldb::addr_t &func_addr, lldb::addr_t &func_end) { - lldb::ProcessSP process_sp(m_process_wp.lock()); + lldb::ProcessSP process_sp(GetProcessWP().lock()); func_addr = LLDB_INVALID_ADDRESS; func_end = LLDB_INVALID_ADDRESS; @@ -289,159 +255,147 @@ IRExecutionUnit::GetRunnableInfo(Error &error, func_end = m_function_end_load_addr; return; - }; // someone else may have gotten the mutex first + }; + + m_did_jit = true; + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + std::string error_string; + if (log) { - 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 + std::string s; + llvm::raw_string_ostream oss(s); - m_did_jit = true; + m_module->print(oss, NULL); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + oss.flush(); - 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; + } + + m_module_ap->getContext().setInlineAsmDiagnosticHandler(ReportInlineAsmError, &error); + + 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); + + if (!error.Success()) + { + // We got an error through our callback! + return; + } + + 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); - 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; + for (JittedFunction &jitted_function : m_jitted_functions) + { + jitted_function.m_remote_addr = GetRemoteAddressForLocal (jitted_function.m_local_addr); - if (triple.isOSBinFormatELF()) + if (!jitted_function.m_name.compare(m_name.AsCString())) { - relocModel = llvm::Reloc::Static; - // This will be small for 32-bit and large for 64-bit. - codeModel = llvm::CodeModel::JITDefault; + 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; } - else - { - relocModel = llvm::Reloc::PIC_; - codeModel = llvm::CodeModel::Small; - } - - m_module_ap->getContext().setInlineAsmDiagnosticHandler(ReportInlineAsmError, &error); - - 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); + } + + if (log) + { + log->Printf("Code can be run in the target."); - llvm::TargetMachine *target_machine = builder.selectTarget(triple, - mArch, - mCPU, - mAttrs); + StreamString disassembly_stream; - m_execution_engine_ap.reset(builder.create(target_machine)); + Error err = DisassembleFunction(disassembly_stream, process_sp); - if (!m_execution_engine_ap.get()) + if (!err.Success()) { - error.SetErrorToGenericError(); - error.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str()); - return; + log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error")); } 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); - - if (!error.Success()) - { - // We got an error through our callback! - return; - } - - if (!function) - { - error.SetErrorToGenericError(); - error.SetErrorStringWithFormat("Couldn't find '%s' in the JITted module", m_name.AsCString()); - return; + log->Printf("Function disassembly:\n%s", disassembly_stream.GetData()); } - - 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; } + + func_addr = m_function_load_addr; + func_end = m_function_end_load_addr; + + return; } IRExecutionUnit::~IRExecutionUnit () @@ -482,20 +436,16 @@ IRExecutionUnit::MemoryManager::allocateStub(const llvm::GlobalValue* F, Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); uint8_t *return_value = m_default_mm_ap->allocateStub(F, StubSize, Alignment); - - auto iter = m_parent.m_allocations.insert(m_parent.m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - allocation.m_size = StubSize; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; + + m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + StubSize, + Alignment)); if (log) { log->Printf("IRExecutionUnit::allocateStub (F=%p, StubSize=%u, Alignment=%u) = %p", F, StubSize, Alignment, return_value); - allocation.dump(log); } return return_value; @@ -516,19 +466,15 @@ IRExecutionUnit::MemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) uint8_t *return_value = m_default_mm_ap->allocateSpace(Size, Alignment); - auto iter = m_parent.m_allocations.insert(m_parent.m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - allocation.m_size = Size; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; + m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + Size, + Alignment)); if (log) { log->Printf("IRExecutionUnit::allocateSpace(Size=%" PRIu64 ", Alignment=%u) = %p", (uint64_t)Size, Alignment, return_value); - allocation.dump(log); } return return_value; @@ -543,21 +489,16 @@ IRExecutionUnit::MemoryManager::allocateCodeSection(uintptr_t Size, uint8_t *return_value = m_default_mm_ap->allocateCodeSection(Size, Alignment, SectionID); - auto iter = m_parent.m_allocations.insert(m_parent.m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - 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; + m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value, + lldb::ePermissionsReadable | lldb::ePermissionsWritable | lldb::ePermissionsExecutable, + Size, + Alignment, + SectionID)); if (log) { log->Printf("IRExecutionUnit::allocateCodeSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p", (uint64_t)Size, Alignment, SectionID, return_value); - allocation.dump(log); } return return_value; @@ -573,20 +514,15 @@ IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size, uint8_t *return_value = m_default_mm_ap->allocateDataSection(Size, Alignment, SectionID, IsReadOnly); - auto iter = m_parent.m_allocations.insert(m_parent.m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - allocation.m_size = Size; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; - allocation.m_section_id = SectionID; - + m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + Size, + Alignment, + 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); } return return_value; @@ -600,19 +536,15 @@ IRExecutionUnit::MemoryManager::allocateGlobal(uintptr_t Size, uint8_t *return_value = m_default_mm_ap->allocateGlobal(Size, Alignment); - auto iter = m_parent.m_allocations.insert(m_parent.m_allocations.end(), Allocation()); - - Allocation &allocation(*iter); - - allocation.m_size = Size; - allocation.m_alignment = Alignment; - allocation.m_local_start = (uintptr_t)return_value; + m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + Size, + Alignment)); if (log) { log->Printf("IRExecutionUnit::allocateGlobal(Size=0x%" PRIx64 ", Alignment=%u) = %p", (uint64_t)Size, Alignment, return_value); - allocation.dump(log); } return return_value; @@ -649,11 +581,16 @@ IRExecutionUnit::MemoryManager::deallocateExceptionTable(void *ET) lldb::addr_t IRExecutionUnit::GetRemoteAddressForLocal (lldb::addr_t local_address) { - for (Allocation &allocation : m_allocations) + for (AllocationRecord &record : m_records) { - 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); + if (local_address >= record.m_host_address && + local_address < record.m_host_address + record.m_size) + { + if (record.m_process_address == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + } + + return record.m_process_address + (local_address - record.m_host_address); } return LLDB_INVALID_ADDRESS; @@ -662,11 +599,16 @@ IRExecutionUnit::GetRemoteAddressForLocal (lldb::addr_t local_address) IRExecutionUnit::AddrRange IRExecutionUnit::GetRemoteRangeForLocal (lldb::addr_t local_address) { - for (Allocation &allocation : m_allocations) + for (AllocationRecord &record : m_records) { - 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); + if (local_address >= record.m_host_address && + local_address < record.m_host_address + record.m_size) + { + if (record.m_process_address == LLDB_INVALID_ADDRESS) + return AddrRange(0, 0); + + return AddrRange(record.m_process_address, record.m_size); + } } return AddrRange (0, 0); @@ -675,53 +617,38 @@ IRExecutionUnit::GetRemoteRangeForLocal (lldb::addr_t local_address) bool IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - bool ret = true; - for (Allocation &allocation : m_allocations) + lldb_private::Error err; + + for (AllocationRecord &record : m_records) { - if (allocation.m_allocated) + if (record.m_process_address != LLDB_INVALID_ADDRESS) 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); + record.m_process_address = Malloc(record.m_size, + record.m_alignment, + record.m_permissions, + eAllocationPolicyProcessOnly, + err); 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) + for (AllocationRecord &record : m_records) { - if (allocation.m_allocated) - process_sp->DeallocateMemory(allocation.m_remote_start); + if (record.m_process_address != LLDB_INVALID_ADDRESS) + { + Free(record.m_process_address, err); + record.m_process_address = LLDB_INVALID_ADDRESS; + } } } @@ -731,16 +658,17 @@ IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp) void IRExecutionUnit::ReportAllocations (llvm::ExecutionEngine &engine) { - for (Allocation &allocation : m_allocations) + for (AllocationRecord &record : m_records) { - if (!allocation.m_allocated) + if (record.m_process_address == LLDB_INVALID_ADDRESS) continue; - if (allocation.m_section_id == Allocation::eSectionIDNone) + if (record.m_section_id == eSectionIDInvalid) continue; - engine.mapSectionAddress((void*)allocation.m_local_start, allocation.m_remote_start); + engine.mapSectionAddress((void*)record.m_host_address, record.m_process_address); } + // Trigger re-application of relocations. engine.finalizeObject(); } @@ -748,45 +676,29 @@ IRExecutionUnit::ReportAllocations (llvm::ExecutionEngine &engine) bool IRExecutionUnit::WriteData (lldb::ProcessSP &process_sp) { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - for (Allocation &allocation : m_allocations) + for (AllocationRecord &record : m_records) { - if (!allocation.m_allocated) + if (record.m_process_address == LLDB_INVALID_ADDRESS) 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); - } + + WriteMemory (record.m_process_address, (uint8_t*)record.m_host_address, record.m_size, err); } return true; } void -IRExecutionUnit::Allocation::dump (Log *log) +IRExecutionUnit::AllocationRecord::dump (Log *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_host_address, (unsigned long long)m_size, - (unsigned long long)m_remote_start, + (unsigned long long)m_process_address, (unsigned)m_alignment, (unsigned)m_section_id); } diff --git a/lldb/source/Expression/IRMemoryMap.cpp b/lldb/source/Expression/IRMemoryMap.cpp new file mode 100644 index 00000000000..aea57b25ae1 --- /dev/null +++ b/lldb/source/Expression/IRMemoryMap.cpp @@ -0,0 +1,410 @@ +//===-- IRMemoryMap.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/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Expression/IRMemoryMap.h" +#include "lldb/Target/Process.h" + +using namespace lldb_private; + +IRMemoryMap::IRMemoryMap (lldb::ProcessSP process_sp) : + m_process_wp(process_sp) +{ +} + +IRMemoryMap::~IRMemoryMap () +{ + lldb::ProcessSP process_sp = m_process_wp.lock(); + + if (process_sp) + { + for (AllocationMap::value_type &allocation : m_allocations) + { + if (allocation.second.m_policy == eAllocationPolicyMirror || + allocation.second.m_policy == eAllocationPolicyHostOnly) + process_sp->DeallocateMemory(allocation.second.m_process_alloc); + + if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) + { + log->Printf("IRMemoryMap::~IRMemoryMap deallocated [0x%llx..0x%llx)", + (uint64_t)allocation.second.m_process_start, + (uint64_t)allocation.second.m_process_start + (uint64_t)allocation.second.m_size); + } + } + } +} + +lldb::addr_t +IRMemoryMap::FindSpace (size_t size) +{ + // Yup, this is just plain O(n) insertion. We'll use a range tree if we + // start caring. + + lldb::addr_t remote_address = 0x1000; // skip first page of memory + + for (AllocationMap::value_type &allocation : m_allocations) + { + if (remote_address < allocation.second.m_process_start && + remote_address + size <= allocation.second.m_process_start) + return remote_address; + + remote_address = allocation.second.m_process_start = allocation.second.m_size; + } + + if (remote_address + size < remote_address) + return LLDB_INVALID_ADDRESS; // massively unlikely + + return remote_address; +} + +bool +IRMemoryMap::ContainsHostOnlyAllocations () +{ + for (AllocationMap::value_type &allocation : m_allocations) + { + if (allocation.second.m_policy == eAllocationPolicyHostOnly) + return true; + } + + return false; +} + +IRMemoryMap::AllocationMap::iterator +IRMemoryMap::FindAllocation (lldb::addr_t addr, size_t size) +{ + AllocationMap::iterator iter = m_allocations.lower_bound (addr); + + if (iter == m_allocations.end()) + return iter; + + if (iter->first > addr) + { + if (iter == m_allocations.begin()) + return m_allocations.end(); + iter--; + } + + if (iter->first <= addr && iter->first + iter->second.m_size >= addr + size) + return iter; + + return m_allocations.end(); +} + +lldb::addr_t +IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error) +{ + lldb::ProcessSP process_sp; + lldb::addr_t allocation_address = LLDB_INVALID_ADDRESS; + lldb::addr_t aligned_address = LLDB_INVALID_ADDRESS; + + size_t allocation_size = (size ? size : 1) + alignment - 1; + + switch (policy) + { + default: + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: invalid allocation policy"); + return LLDB_INVALID_ADDRESS; + case eAllocationPolicyHostOnly: + allocation_address = FindSpace(allocation_size); + if (allocation_address == LLDB_INVALID_ADDRESS) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: address space is full"); + return LLDB_INVALID_ADDRESS; + } + break; + case eAllocationPolicyMirror: + if (ContainsHostOnlyAllocations()) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: host-only allocations are polluting the address space"); + return LLDB_INVALID_ADDRESS; + } + process_sp = m_process_wp.lock(); + if (process_sp) + { + allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error); + if (!error.Success()) + return LLDB_INVALID_ADDRESS; + } + else + { + allocation_address = FindSpace(allocation_size); + if (allocation_address == LLDB_INVALID_ADDRESS) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: address space is full"); + return LLDB_INVALID_ADDRESS; + } + } + break; + case eAllocationPolicyProcessOnly: + if (ContainsHostOnlyAllocations()) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: host-only allocations are polluting the address space"); + return LLDB_INVALID_ADDRESS; + } + process_sp = m_process_wp.lock(); + if (process_sp) + { + allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error); + if (!error.Success()) + return LLDB_INVALID_ADDRESS; + } + else + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't malloc: process doesn't exist, and this memory must be in the process"); + return LLDB_INVALID_ADDRESS; + } + break; + } + + + lldb::addr_t mask = alignment - 1; + aligned_address = (allocation_address + mask) & (~mask); + + Allocation &allocation(m_allocations[aligned_address]); + + allocation.m_process_alloc = allocation_address; + allocation.m_process_start = aligned_address; + allocation.m_size = size; + allocation.m_permissions = permissions; + allocation.m_alignment = alignment; + allocation.m_policy = policy; + + switch (policy) + { + default: + assert (0 && "We cannot reach this!"); + case eAllocationPolicyHostOnly: + allocation.m_data.reset(new DataBufferHeap(size, 0)); + break; + case eAllocationPolicyProcessOnly: + break; + case eAllocationPolicyMirror: + allocation.m_data.reset(new DataBufferHeap(size, 0)); + break; + } + + if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) + { + const char * policy_string; + + switch (policy) + { + default: + policy_string = "<invalid policy>"; + break; + case eAllocationPolicyHostOnly: + policy_string = "eAllocationPolicyHostOnly"; + break; + case eAllocationPolicyProcessOnly: + policy_string = "eAllocationPolicyProcessOnly"; + break; + case eAllocationPolicyMirror: + policy_string = "eAllocationPolicyMirror"; + break; + } + + log->Printf("IRMemoryMap::Malloc (%llu, 0x%llx, 0x%llx, %s) -> 0x%llx", + (uint64_t)size, + (uint64_t)alignment, + (uint64_t)permissions, + policy_string, + aligned_address); + } + + return aligned_address; +} + +void +IRMemoryMap::Free (lldb::addr_t process_address, Error &error) +{ + AllocationMap::iterator iter = m_allocations.find(process_address); + + if (iter == m_allocations.end()) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't free: allocation doesn't exist"); + return; + } + + Allocation &allocation = iter->second; + + switch (allocation.m_policy) + { + default: + case eAllocationPolicyHostOnly: + break; + case eAllocationPolicyMirror: + case eAllocationPolicyProcessOnly: + lldb::ProcessSP process_sp = m_process_wp.lock(); + if (process_sp) + process_sp->DeallocateMemory(allocation.m_process_alloc); + } + + if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) + { + log->Printf("IRMemoryMap::Free (0x%llx) freed [0x%llx..0x%llx)", + (uint64_t)process_address, + iter->second.m_process_start, + iter->second.m_process_start + iter->second.m_size); + } + + m_allocations.erase(iter); +} + +void +IRMemoryMap::WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error) +{ + AllocationMap::iterator iter = FindAllocation(process_address, size); + + if (iter == m_allocations.end()) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't write: no allocation contains the target range"); + return; + } + + Allocation &allocation = iter->second; + + uint64_t offset = process_address - allocation.m_process_start; + + lldb::ProcessSP process_sp; + + switch (allocation.m_policy) + { + default: + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't write: invalid allocation policy"); + return; + case eAllocationPolicyHostOnly: + if (!allocation.m_data) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't write: data buffer is empty"); + return; + } + ::memcpy (allocation.m_data->GetBytes() + offset, bytes, size); + break; + case eAllocationPolicyMirror: + if (!allocation.m_data) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't write: data buffer is empty"); + return; + } + ::memcpy (allocation.m_data->GetBytes() + offset, bytes, size); + process_sp = m_process_wp.lock(); + if (process_sp) + { + process_sp->WriteMemory(process_address, bytes, size, error); + if (!error.Success()) + return; + } + break; + case eAllocationPolicyProcessOnly: + process_sp = m_process_wp.lock(); + if (process_sp) + { + process_sp->WriteMemory(process_address, bytes, size, error); + if (!error.Success()) + return; + } + break; + } + + if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) + { + log->Printf("IRMemoryMap::WriteMemory (0x%llx, 0x%llx, 0x%lld) went to [0x%llx..0x%llx)", + (uint64_t)process_address, + (uint64_t)bytes, + (uint64_t)size, + (uint64_t)allocation.m_process_start, + (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size); + } +} + +void +IRMemoryMap::ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error) +{ + AllocationMap::iterator iter = FindAllocation(process_address, size); + + if (iter == m_allocations.end()) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't read: no allocation contains the target range"); + return; + } + + Allocation &allocation = iter->second; + + uint64_t offset = process_address - allocation.m_process_start; + + lldb::ProcessSP process_sp; + + switch (allocation.m_policy) + { + default: + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't read: invalid allocation policy"); + return; + case eAllocationPolicyHostOnly: + if (!allocation.m_data) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't read: data buffer is empty"); + return; + } + ::memcpy (bytes, allocation.m_data->GetBytes() + offset, size); + break; + case eAllocationPolicyMirror: + process_sp = m_process_wp.lock(); + if (process_sp) + { + process_sp->ReadMemory(process_address, bytes, size, error); + if (!error.Success()) + return; + } + else + { + if (!allocation.m_data) + { + error.SetErrorToGenericError(); + error.SetErrorString("Couldn't read: data buffer is empty"); + return; + } + ::memcpy (bytes, allocation.m_data->GetBytes() + offset, size); + } + break; + case eAllocationPolicyProcessOnly: + process_sp = m_process_wp.lock(); + if (process_sp) + { + process_sp->ReadMemory(process_address, bytes, size, error); + if (!error.Success()) + return; + } + break; + } + + if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)) + { + log->Printf("IRMemoryMap::ReadMemory (0x%llx, 0x%llx, 0x%lld) came from [0x%llx..0x%llx)", + (uint64_t)process_address, + (uint64_t)bytes, + (uint64_t)size, + (uint64_t)allocation.m_process_start, + (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size); + } +} |