aboutsummaryrefslogtreecommitdiff
path: root/source/Expression/IRMemoryMap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Expression/IRMemoryMap.cpp')
-rw-r--r--source/Expression/IRMemoryMap.cpp127
1 files changed, 118 insertions, 9 deletions
diff --git a/source/Expression/IRMemoryMap.cpp b/source/Expression/IRMemoryMap.cpp
index e96bddde7cbb..aa165722c437 100644
--- a/source/Expression/IRMemoryMap.cpp
+++ b/source/Expression/IRMemoryMap.cpp
@@ -13,8 +13,10 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Expression/IRMemoryMap.h"
+#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/LLDBAssert.h"
using namespace lldb_private;
@@ -47,37 +49,136 @@ IRMemoryMap::~IRMemoryMap ()
}
lldb::addr_t
-IRMemoryMap::FindSpace (size_t size, bool zero_memory)
+IRMemoryMap::FindSpace (size_t size)
{
+ // The FindSpace algorithm's job is to find a region of memory that the
+ // underlying process is unlikely to be using.
+ //
+ // The memory returned by this function will never be written to. The only
+ // point is that it should not shadow process memory if possible, so that
+ // expressions processing real values from the process do not use the
+ // wrong data.
+ //
+ // If the process can in fact allocate memory (CanJIT() lets us know this)
+ // then this can be accomplished just be allocating memory in the inferior.
+ // Then no guessing is required.
+
lldb::TargetSP target_sp = m_target_wp.lock();
lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ const bool process_is_alive = process_sp && process_sp->IsAlive();
lldb::addr_t ret = LLDB_INVALID_ADDRESS;
if (size == 0)
return ret;
- if (process_sp && process_sp->CanJIT() && process_sp->IsAlive())
+ if (process_is_alive && process_sp->CanJIT())
{
Error alloc_error;
- if (!zero_memory)
- ret = process_sp->AllocateMemory(size, lldb::ePermissionsReadable | lldb::ePermissionsWritable, alloc_error);
- else
- ret = process_sp->CallocateMemory(size, lldb::ePermissionsReadable | lldb::ePermissionsWritable, alloc_error);
+ ret = process_sp->AllocateMemory(size, lldb::ePermissionsReadable | lldb::ePermissionsWritable, alloc_error);
if (!alloc_error.Success())
return LLDB_INVALID_ADDRESS;
else
return ret;
}
+
+ // At this point we know that we need to hunt.
+ //
+ // First, go to the end of the existing allocations we've made if there are
+ // any allocations. Otherwise start at the beginning of memory.
- ret = 0;
- if (!m_allocations.empty())
+ if (m_allocations.empty())
+ {
+ ret = 0x0;
+ }
+ else
+ {
+ auto back = m_allocations.rbegin();
+ lldb::addr_t addr = back->first;
+ size_t alloc_size = back->second.m_size;
+ ret = llvm::alignTo(addr+alloc_size, 4096);
+ }
+
+ // Now, if it's possible to use the GetMemoryRegionInfo API to detect mapped
+ // regions, walk forward through memory until a region is found that
+ // has adequate space for our allocation.
+ if (process_is_alive)
+ {
+ const uint64_t end_of_memory = process_sp->GetAddressByteSize() == 8 ?
+ 0xffffffffffffffffull : 0xffffffffull;
+
+ lldbassert(process_sp->GetAddressByteSize() == 4 || end_of_memory != 0xffffffffull);
+
+ MemoryRegionInfo region_info;
+ Error err = process_sp->GetMemoryRegionInfo(ret, region_info);
+ if (err.Success())
+ {
+ while (true)
+ {
+ if (region_info.GetReadable() != MemoryRegionInfo::OptionalBool::eNo ||
+ region_info.GetWritable() != MemoryRegionInfo::OptionalBool::eNo ||
+ region_info.GetExecutable() != MemoryRegionInfo::OptionalBool::eNo)
+ {
+ if (region_info.GetRange().GetRangeEnd() - 1 >= end_of_memory)
+ {
+ ret = LLDB_INVALID_ADDRESS;
+ break;
+ }
+ else
+ {
+ ret = region_info.GetRange().GetRangeEnd();
+ }
+ }
+ else if (ret + size < region_info.GetRange().GetRangeEnd())
+ {
+ return ret;
+ }
+ else
+ {
+ // ret stays the same. We just need to walk a bit further.
+ }
+
+ err = process_sp->GetMemoryRegionInfo(region_info.GetRange().GetRangeEnd(), region_info);
+ if (err.Fail())
+ {
+ lldbassert(!"GetMemoryRegionInfo() succeeded, then failed");
+ ret = LLDB_INVALID_ADDRESS;
+ break;
+ }
+ }
+ }
+ }
+
+ // We've tried our algorithm, and it didn't work. Now we have to reset back
+ // to the end of the allocations we've already reported, or use a 'sensible'
+ // default if this is our first allocation.
+
+ if (m_allocations.empty())
+ {
+ uint32_t address_byte_size = GetAddressByteSize();
+ if (address_byte_size != UINT32_MAX)
+ {
+ switch (address_byte_size)
+ {
+ case 8:
+ ret = 0xffffffff00000000ull;
+ break;
+ case 4:
+ ret = 0xee000000ull;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
{
auto back = m_allocations.rbegin();
lldb::addr_t addr = back->first;
size_t alloc_size = back->second.m_size;
- ret = llvm::RoundUpToAlignment(addr+alloc_size, 4096);
+ ret = llvm::alignTo(addr+alloc_size, 4096);
}
return ret;
@@ -329,6 +430,13 @@ IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, Alloc
alignment,
policy);
+ if (zero_memory)
+ {
+ Error write_error;
+ std::vector<uint8_t> zero_buf(size, 0);
+ WriteMemory(aligned_address, zero_buf.data(), size, write_error);
+ }
+
if (log)
{
const char * policy_string;
@@ -784,6 +892,7 @@ IRMemoryMap::GetMemoryData (DataExtractor &extractor, lldb::addr_t process_addre
return;
}
}
+ break;
case eAllocationPolicyHostOnly:
if (!allocation.m_data.GetByteSize())
{