2013-04-05 10:22:57 +08:00
|
|
|
//===-- IRMemoryMap.cpp -----------------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-04-13 02:10:34 +08:00
|
|
|
#include "lldb/Core/DataBufferHeap.h"
|
|
|
|
#include "lldb/Core/DataExtractor.h"
|
2013-04-05 10:22:57 +08:00
|
|
|
#include "lldb/Core/Error.h"
|
|
|
|
#include "lldb/Core/Log.h"
|
2013-04-13 02:10:34 +08:00
|
|
|
#include "lldb/Core/Scalar.h"
|
2013-04-05 10:22:57 +08:00
|
|
|
#include "lldb/Expression/IRMemoryMap.h"
|
|
|
|
#include "lldb/Target/Process.h"
|
2013-04-13 02:10:34 +08:00
|
|
|
#include "lldb/Target/Target.h"
|
2013-04-05 10:22:57 +08:00
|
|
|
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
2013-04-13 02:10:34 +08:00
|
|
|
IRMemoryMap::IRMemoryMap (lldb::TargetSP target_sp) :
|
|
|
|
m_target_wp(target_sp)
|
2013-04-05 10:22:57 +08:00
|
|
|
{
|
2013-04-16 01:12:47 +08:00
|
|
|
if (target_sp)
|
|
|
|
m_process_wp = target_sp->GetProcessSP();
|
2013-04-05 10:22:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2013-04-17 15:50:58 +08:00
|
|
|
remote_address = allocation.second.m_process_start + allocation.second.m_size;
|
2013-04-05 10:22:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
This commit changes the way LLDB executes user
expressions.
Previously, ClangUserExpression assumed that if
there was a constant result for an expression
then it could be determined during parsing. In
particular, the IRInterpreter ran while parser
state (in particular, ClangExpressionDeclMap)
was present. This approach is flawed, because
the IRInterpreter actually is capable of using
external variables, and hence the result might
be different each run. Until now, we papered
over this flaw by re-parsing the expression each
time we ran it.
I have rewritten the IRInterpreter to be
completely independent of the ClangExpressionDeclMap.
Instead of special-casing external variable lookup,
which ties the IRInterpreter closely to LLDB,
we now interpret the exact same IR that the JIT
would see. This IR assumes that materialization
has occurred; hence the recent implementation of the
Materializer, which does not require parser state
(in the form of ClangExpressionDeclMap) to be
present.
Materialization, interpretation, and dematerialization
are now all independent of parsing. This means that
in theory we can parse expressions once and run them
many times. I have three outstanding tasks before
shutting this down:
- First, I will ensure that all of this works with
core files. Core files have a Process but do not
allow allocating memory, which currently confuses
materialization.
- Second, I will make expression breakpoint
conditions remember their ClangUserExpression and
re-use it.
- Third, I will tear out all the redundant code
(for example, materialization logic in
ClangExpressionDeclMap) that is no longer used.
While implementing this fix, I also found a bug in
IRForTarget's handling of floating-point constants.
This should be fixed.
llvm-svn: 179801
2013-04-19 06:06:33 +08:00
|
|
|
if (addr == LLDB_INVALID_ADDRESS)
|
|
|
|
return m_allocations.end();
|
|
|
|
|
2013-04-05 10:22:57 +08:00
|
|
|
AllocationMap::iterator iter = m_allocations.lower_bound (addr);
|
|
|
|
|
2013-04-17 07:25:35 +08:00
|
|
|
if (iter == m_allocations.end() ||
|
|
|
|
iter->first > addr)
|
2013-04-05 10:22:57 +08:00
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2013-04-13 02:10:34 +08:00
|
|
|
lldb::ByteOrder
|
|
|
|
IRMemoryMap::GetByteOrder()
|
|
|
|
{
|
|
|
|
lldb::ProcessSP process_sp = m_process_wp.lock();
|
|
|
|
|
|
|
|
if (process_sp)
|
|
|
|
return process_sp->GetByteOrder();
|
|
|
|
|
|
|
|
lldb::TargetSP target_sp = m_target_wp.lock();
|
|
|
|
|
|
|
|
if (target_sp)
|
2013-04-17 15:50:58 +08:00
|
|
|
return target_sp->GetArchitecture().GetByteOrder();
|
2013-04-13 02:10:34 +08:00
|
|
|
|
|
|
|
return lldb::eByteOrderInvalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
IRMemoryMap::GetAddressByteSize()
|
|
|
|
{
|
|
|
|
lldb::ProcessSP process_sp = m_process_wp.lock();
|
|
|
|
|
|
|
|
if (process_sp)
|
|
|
|
return process_sp->GetAddressByteSize();
|
|
|
|
|
|
|
|
lldb::TargetSP target_sp = m_target_wp.lock();
|
|
|
|
|
|
|
|
if (target_sp)
|
2013-04-17 15:50:58 +08:00
|
|
|
return target_sp->GetArchitecture().GetAddressByteSize();
|
2013-04-13 02:10:34 +08:00
|
|
|
|
|
|
|
return UINT32_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
ExecutionContextScope *
|
|
|
|
IRMemoryMap::GetBestExecutionContextScope()
|
|
|
|
{
|
|
|
|
lldb::ProcessSP process_sp = m_process_wp.lock();
|
|
|
|
|
|
|
|
if (process_sp)
|
|
|
|
return process_sp.get();
|
|
|
|
|
|
|
|
lldb::TargetSP target_sp = m_target_wp.lock();
|
|
|
|
|
|
|
|
if (target_sp)
|
|
|
|
return target_sp.get();
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-04-05 10:22:57 +08:00
|
|
|
lldb::addr_t
|
|
|
|
IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error)
|
|
|
|
{
|
2013-04-17 15:50:58 +08:00
|
|
|
error.Clear();
|
|
|
|
|
2013-04-05 10:22:57 +08:00
|
|
|
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);
|
|
|
|
|
2013-04-19 06:59:51 +08:00
|
|
|
Allocation allocation;
|
2013-04-05 10:22:57 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2013-04-19 06:59:51 +08:00
|
|
|
m_allocations[aligned_address] = std::move(allocation);
|
|
|
|
|
2013-04-05 10:22:57 +08:00
|
|
|
switch (policy)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
assert (0 && "We cannot reach this!");
|
|
|
|
case eAllocationPolicyHostOnly:
|
2013-04-19 06:01:06 +08:00
|
|
|
allocation.m_data_ap.reset(new DataBufferHeap(size, 0));
|
2013-04-05 10:22:57 +08:00
|
|
|
break;
|
|
|
|
case eAllocationPolicyProcessOnly:
|
|
|
|
break;
|
|
|
|
case eAllocationPolicyMirror:
|
2013-04-19 06:01:06 +08:00
|
|
|
allocation.m_data_ap.reset(new DataBufferHeap(size, 0));
|
2013-04-05 10:22:57 +08:00
|
|
|
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)
|
|
|
|
{
|
2013-04-17 15:50:58 +08:00
|
|
|
error.Clear();
|
|
|
|
|
2013-04-05 10:22:57 +08:00
|
|
|
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)
|
|
|
|
{
|
2013-04-17 15:50:58 +08:00
|
|
|
error.Clear();
|
|
|
|
|
2013-04-05 10:22:57 +08:00
|
|
|
AllocationMap::iterator iter = FindAllocation(process_address, size);
|
|
|
|
|
|
|
|
if (iter == m_allocations.end())
|
|
|
|
{
|
2013-04-16 05:35:52 +08:00
|
|
|
lldb::ProcessSP process_sp = m_process_wp.lock();
|
|
|
|
|
|
|
|
if (process_sp)
|
|
|
|
{
|
|
|
|
process_sp->WriteMemory(process_address, bytes, size, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-05 10:22:57 +08:00
|
|
|
error.SetErrorToGenericError();
|
2013-04-16 05:35:52 +08:00
|
|
|
error.SetErrorString("Couldn't write: no allocation contains the target range and the process doesn't exist");
|
2013-04-05 10:22:57 +08:00
|
|
|
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:
|
2013-04-19 06:01:06 +08:00
|
|
|
if (!allocation.m_data_ap.get())
|
2013-04-05 10:22:57 +08:00
|
|
|
{
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorString("Couldn't write: data buffer is empty");
|
|
|
|
return;
|
|
|
|
}
|
2013-04-19 06:01:06 +08:00
|
|
|
::memcpy (allocation.m_data_ap->GetBytes() + offset, bytes, size);
|
2013-04-05 10:22:57 +08:00
|
|
|
break;
|
|
|
|
case eAllocationPolicyMirror:
|
2013-04-19 06:01:06 +08:00
|
|
|
if (!allocation.m_data_ap.get())
|
2013-04-05 10:22:57 +08:00
|
|
|
{
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorString("Couldn't write: data buffer is empty");
|
|
|
|
return;
|
|
|
|
}
|
2013-04-19 06:01:06 +08:00
|
|
|
::memcpy (allocation.m_data_ap->GetBytes() + offset, bytes, size);
|
2013-04-05 10:22:57 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-13 02:10:34 +08:00
|
|
|
void
|
|
|
|
IRMemoryMap::WriteScalarToMemory (lldb::addr_t process_address, Scalar &scalar, size_t size, Error &error)
|
2013-04-17 15:50:58 +08:00
|
|
|
{
|
|
|
|
error.Clear();
|
|
|
|
|
2013-04-13 02:10:34 +08:00
|
|
|
if (size == UINT32_MAX)
|
|
|
|
size = scalar.GetByteSize();
|
|
|
|
|
|
|
|
if (size > 0)
|
|
|
|
{
|
|
|
|
uint8_t buf[32];
|
|
|
|
const size_t mem_size = scalar.GetAsMemoryData (buf, size, GetByteOrder(), error);
|
|
|
|
if (mem_size > 0)
|
|
|
|
{
|
|
|
|
return WriteMemory(process_address, buf, mem_size, error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorString ("Couldn't write scalar: failed to get scalar as memory data");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorString ("Couldn't write scalar: its size was zero");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-13 05:40:34 +08:00
|
|
|
void
|
|
|
|
IRMemoryMap::WritePointerToMemory (lldb::addr_t process_address, lldb::addr_t address, Error &error)
|
|
|
|
{
|
2013-04-17 15:50:58 +08:00
|
|
|
error.Clear();
|
|
|
|
|
2013-04-13 05:40:34 +08:00
|
|
|
Scalar scalar(address);
|
|
|
|
|
|
|
|
WriteScalarToMemory(process_address, scalar, GetAddressByteSize(), error);
|
|
|
|
}
|
|
|
|
|
2013-04-05 10:22:57 +08:00
|
|
|
void
|
|
|
|
IRMemoryMap::ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error)
|
|
|
|
{
|
2013-04-17 15:50:58 +08:00
|
|
|
error.Clear();
|
|
|
|
|
2013-04-05 10:22:57 +08:00
|
|
|
AllocationMap::iterator iter = FindAllocation(process_address, size);
|
|
|
|
|
|
|
|
if (iter == m_allocations.end())
|
|
|
|
{
|
2013-04-16 05:35:52 +08:00
|
|
|
lldb::ProcessSP process_sp = m_process_wp.lock();
|
|
|
|
|
|
|
|
if (process_sp)
|
|
|
|
{
|
|
|
|
process_sp->ReadMemory(process_address, bytes, size, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
lldb::TargetSP target_sp = m_target_wp.lock();
|
|
|
|
|
|
|
|
if (target_sp)
|
|
|
|
{
|
|
|
|
Address absolute_address(process_address);
|
|
|
|
target_sp->ReadMemory(absolute_address, false, bytes, size, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-05 10:22:57 +08:00
|
|
|
error.SetErrorToGenericError();
|
2013-04-16 05:35:52 +08:00
|
|
|
error.SetErrorString("Couldn't read: no allocation contains the target range, and neither the process nor the target exist");
|
2013-04-05 10:22:57 +08:00
|
|
|
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:
|
2013-04-19 06:01:06 +08:00
|
|
|
if (!allocation.m_data_ap.get())
|
2013-04-05 10:22:57 +08:00
|
|
|
{
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorString("Couldn't read: data buffer is empty");
|
|
|
|
return;
|
|
|
|
}
|
2013-04-19 06:01:06 +08:00
|
|
|
::memcpy (bytes, allocation.m_data_ap->GetBytes() + offset, size);
|
2013-04-05 10:22:57 +08:00
|
|
|
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
|
|
|
|
{
|
2013-04-19 06:01:06 +08:00
|
|
|
if (!allocation.m_data_ap.get())
|
2013-04-05 10:22:57 +08:00
|
|
|
{
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorString("Couldn't read: data buffer is empty");
|
|
|
|
return;
|
|
|
|
}
|
2013-04-19 06:01:06 +08:00
|
|
|
::memcpy (bytes, allocation.m_data_ap->GetBytes() + offset, size);
|
2013-04-05 10:22:57 +08:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2013-04-13 02:10:34 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
IRMemoryMap::ReadScalarFromMemory (Scalar &scalar, lldb::addr_t process_address, size_t size, Error &error)
|
2013-04-17 15:50:58 +08:00
|
|
|
{
|
|
|
|
error.Clear();
|
|
|
|
|
2013-04-13 02:10:34 +08:00
|
|
|
if (size > 0)
|
|
|
|
{
|
|
|
|
DataBufferHeap buf(size, 0);
|
|
|
|
ReadMemory(buf.GetBytes(), process_address, size, error);
|
|
|
|
|
|
|
|
if (!error.Success())
|
|
|
|
return;
|
|
|
|
|
|
|
|
DataExtractor extractor(buf.GetBytes(), buf.GetByteSize(), GetByteOrder(), GetAddressByteSize());
|
|
|
|
|
|
|
|
lldb::offset_t offset = 0;
|
|
|
|
|
|
|
|
switch (size)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorStringWithFormat("Couldn't read scalar: unsupported size %lld", (unsigned long long)size);
|
|
|
|
return;
|
|
|
|
case 1: scalar = extractor.GetU8(&offset); break;
|
|
|
|
case 2: scalar = extractor.GetU16(&offset); break;
|
|
|
|
case 4: scalar = extractor.GetU32(&offset); break;
|
|
|
|
case 8: scalar = extractor.GetU64(&offset); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error.SetErrorToGenericError();
|
2013-04-13 10:06:42 +08:00
|
|
|
error.SetErrorString ("Couldn't read scalar: its size was zero");
|
2013-04-13 02:10:34 +08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-16 06:48:23 +08:00
|
|
|
void
|
|
|
|
IRMemoryMap::ReadPointerFromMemory (lldb::addr_t *address, lldb::addr_t process_address, Error &error)
|
|
|
|
{
|
2013-04-17 15:50:58 +08:00
|
|
|
error.Clear();
|
|
|
|
|
2013-04-16 06:48:23 +08:00
|
|
|
Scalar pointer_scalar;
|
|
|
|
ReadScalarFromMemory(pointer_scalar, process_address, GetAddressByteSize(), error);
|
|
|
|
|
|
|
|
if (!error.Success())
|
|
|
|
return;
|
|
|
|
|
|
|
|
*address = pointer_scalar.ULongLong();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-13 10:06:42 +08:00
|
|
|
void
|
|
|
|
IRMemoryMap::GetMemoryData (DataExtractor &extractor, lldb::addr_t process_address, size_t size, Error &error)
|
|
|
|
{
|
2013-04-17 15:50:58 +08:00
|
|
|
error.Clear();
|
|
|
|
|
2013-04-13 10:06:42 +08:00
|
|
|
if (size > 0)
|
|
|
|
{
|
|
|
|
AllocationMap::iterator iter = FindAllocation(process_address, size);
|
|
|
|
|
|
|
|
if (iter == m_allocations.end())
|
|
|
|
{
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorStringWithFormat("Couldn't find an allocation containing [0x%llx..0x%llx)", (unsigned long long)process_address, (unsigned long long)(process_address + size));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Allocation &allocation = iter->second;
|
|
|
|
|
|
|
|
switch (allocation.m_policy)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorString("Couldn't get memory data: invalid allocation policy");
|
|
|
|
return;
|
|
|
|
case eAllocationPolicyProcessOnly:
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorString("Couldn't get memory data: memory is only in the target");
|
|
|
|
return;
|
|
|
|
case eAllocationPolicyMirror:
|
2013-04-16 05:35:52 +08:00
|
|
|
{
|
|
|
|
lldb::ProcessSP process_sp = m_process_wp.lock();
|
|
|
|
|
2013-04-19 06:01:06 +08:00
|
|
|
if (!allocation.m_data_ap.get())
|
2013-04-16 05:35:52 +08:00
|
|
|
{
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorString("Couldn't get memory data: data buffer is empty");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (process_sp)
|
|
|
|
{
|
2013-04-19 06:01:06 +08:00
|
|
|
process_sp->ReadMemory(allocation.m_process_start, allocation.m_data_ap->GetBytes(), allocation.m_data_ap->GetByteSize(), error);
|
2013-04-16 05:35:52 +08:00
|
|
|
if (!error.Success())
|
|
|
|
return;
|
|
|
|
uint64_t offset = process_address - allocation.m_process_start;
|
2013-04-19 06:01:06 +08:00
|
|
|
extractor = DataExtractor(allocation.m_data_ap->GetBytes() + offset, size, GetByteOrder(), GetAddressByteSize());
|
2013-04-16 05:35:52 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case eAllocationPolicyHostOnly:
|
2013-04-19 06:01:06 +08:00
|
|
|
if (!allocation.m_data_ap.get())
|
2013-04-13 10:06:42 +08:00
|
|
|
{
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorString("Couldn't get memory data: data buffer is empty");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
uint64_t offset = process_address - allocation.m_process_start;
|
2013-04-19 06:01:06 +08:00
|
|
|
extractor = DataExtractor(allocation.m_data_ap->GetBytes() + offset, size, GetByteOrder(), GetAddressByteSize());
|
2013-04-13 10:06:42 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error.SetErrorToGenericError();
|
|
|
|
error.SetErrorString ("Couldn't get memory data: its size was zero");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|