summaryrefslogtreecommitdiffstats
path: root/lldb/source/Expression/IRMemoryMap.cpp
diff options
context:
space:
mode:
authorSean Callanan <scallanan@apple.com>2013-04-05 02:22:57 +0000
committerSean Callanan <scallanan@apple.com>2013-04-05 02:22:57 +0000
commit5a1af4e63a068efed4ab3218a63d2147404cc0fc (patch)
tree2efca166de2c880075a495d354beb12d7bcec8bc /lldb/source/Expression/IRMemoryMap.cpp
parent2f91004b64d360e80f244ab0a5e35f975c4e3c76 (diff)
downloadbcm5719-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.cpp410
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);
+ }
+}
OpenPOWER on IntegriCloud