diff options
author | Sean Callanan <scallanan@apple.com> | 2013-04-05 02:22:57 +0000 |
---|---|---|
committer | Sean Callanan <scallanan@apple.com> | 2013-04-05 02:22:57 +0000 |
commit | 5a1af4e63a068efed4ab3218a63d2147404cc0fc (patch) | |
tree | 2efca166de2c880075a495d354beb12d7bcec8bc /lldb/source/Expression/IRMemoryMap.cpp | |
parent | 2f91004b64d360e80f244ab0a5e35f975c4e3c76 (diff) | |
download | bcm5719-llvm-5a1af4e63a068efed4ab3218a63d2147404cc0fc.tar.gz bcm5719-llvm-5a1af4e63a068efed4ab3218a63d2147404cc0fc.zip |
Factored out memory access into the target process
from IRExecutionUnit into a superclass called
IRMemoryMap. IRMemoryMap handles all reading and
writing, ensuring that areas are kept track of and
memory is properly cached (and deleted).
Also fixed several cases where we would simply leak
binary data in the target process over time. Now
the expression objects explicitly own their
IRExecutionUnit and delete it when they go away. This
is why I had to modify ClangUserExpression,
ClangUtilityFunction, and ClangFunction.
As a side effect of this, I am removing the JIT
mutex for an IRMemoryMap. If it turns out that we
need this mutex, I'll add it in then, but right now
it's just adding complexity.
This is part of a more general project to make
expressions fully reusable. The next step is to
make materialization and dematerialization use
the IRMemoryMap API rather than writing and
reading directly from the process's memory.
This will allow the IR interpreter to use the
same data, but in the host's memory, without having
to use a different set of pointers.
llvm-svn: 178832
Diffstat (limited to 'lldb/source/Expression/IRMemoryMap.cpp')
-rw-r--r-- | lldb/source/Expression/IRMemoryMap.cpp | 410 |
1 files changed, 410 insertions, 0 deletions
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); + } +} |