forked from OSchip/llvm-project
For stepping performance I added the ability to outlaw all memory accesseses
to the __PAGEZERO segment on darwin. The dynamic loader now correctly doesn't slide __PAGEZERO and it also registers it as an invalid region of memory. This allows us to not make any memory requests from the local or remote debug session for any addresses in this region. Stepping performance can improve when uninitialized local variables that point to locations in __PAGEZERO are attempted to be read from memory as we won't even make the memory read or write request. llvm-svn: 151128
This commit is contained in:
parent
337cfaf757
commit
a9f40ad80a
|
@ -188,6 +188,17 @@ namespace lldb_private {
|
|||
m_entries.push_back (entry);
|
||||
}
|
||||
|
||||
bool
|
||||
RemoveEntrtAtIndex (uint32_t idx)
|
||||
{
|
||||
if (idx < m_entries.size())
|
||||
{
|
||||
m_entries.erase (m_entries.begin() + idx);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Sort ()
|
||||
{
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
#include <vector>
|
||||
|
||||
// Other libraries and framework includes
|
||||
//#include "llvm/ADT/BitVector.h"
|
||||
|
||||
// Project includes
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Core/RangeMap.h"
|
||||
#include "lldb/Host/Mutex.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
@ -54,16 +54,24 @@ namespace lldb_private {
|
|||
{
|
||||
return m_cache_line_byte_size ;
|
||||
}
|
||||
|
||||
void
|
||||
AddInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size);
|
||||
|
||||
bool
|
||||
RemoveInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size);
|
||||
|
||||
protected:
|
||||
typedef std::map<lldb::addr_t, lldb::DataBufferSP> collection;
|
||||
typedef std::map<lldb::addr_t, lldb::DataBufferSP> BlockMap;
|
||||
typedef RangeArray<lldb::addr_t, lldb::addr_t, 4> InvalidRanges;
|
||||
//------------------------------------------------------------------
|
||||
// Classes that inherit from MemoryCache can see and modify these
|
||||
//------------------------------------------------------------------
|
||||
Process &m_process;
|
||||
uint32_t m_cache_line_byte_size;
|
||||
Mutex m_cache_mutex;
|
||||
collection m_cache;
|
||||
|
||||
Mutex m_mutex;
|
||||
BlockMap m_cache;
|
||||
InvalidRanges m_invalid_ranges;
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN (MemoryCache);
|
||||
};
|
||||
|
@ -132,7 +140,6 @@ namespace lldb_private {
|
|||
const uint32_t m_chunk_size; // The size of chunks that the memory at m_addr is divied up into
|
||||
typedef std::map<uint32_t, uint32_t> OffsetToChunkSize;
|
||||
OffsetToChunkSize m_offset_to_chunk_size;
|
||||
//llvm::BitVector m_allocated;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1297,6 +1297,8 @@ public:
|
|||
eBroadcastInternalStateControlResume = (1<<2)
|
||||
};
|
||||
|
||||
typedef Range<lldb::addr_t, lldb::addr_t> LoadRange;
|
||||
|
||||
// These two functions fill out the Broadcaster interface:
|
||||
|
||||
static ConstString &GetStaticBroadcasterClass ();
|
||||
|
@ -3091,6 +3093,23 @@ public:
|
|||
void
|
||||
SetSTDIOFileDescriptor (int file_descriptor);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Add a permanent region of memory that should never be read or
|
||||
// written to. This can be used to ensure that memory reads or writes
|
||||
// to certain areas of memory never end up being sent to the
|
||||
// DoReadMemory or DoWriteMemory functions which can improve
|
||||
// performance.
|
||||
//------------------------------------------------------------------
|
||||
void
|
||||
AddInvalidMemoryRegion (const LoadRange ®ion);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Remove a permanent region of memory that should never be read or
|
||||
// written to that was previously added with AddInvalidMemoryRegion.
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
RemoveInvalidMemoryRange (const LoadRange ®ion);
|
||||
|
||||
protected:
|
||||
//------------------------------------------------------------------
|
||||
// NextEventAction provides a way to register an action on the next
|
||||
|
|
|
@ -100,12 +100,6 @@
|
|||
ReferencedContainer = "container:lldb.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "/private/tmp/a.out"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "LLDB_LAUNCH_FLAG_DISABLE_ASLR"
|
||||
|
|
|
@ -433,39 +433,80 @@ DynamicLoaderMacOSXDYLD::UpdateImageLoadAddress (Module *module, DYLDImageInfo&
|
|||
SectionList *section_list = image_object_file->GetSectionList ();
|
||||
if (section_list)
|
||||
{
|
||||
std::vector<uint32_t> inaccessible_segment_indexes;
|
||||
// We now know the slide amount, so go through all sections
|
||||
// and update the load addresses with the correct values.
|
||||
uint32_t num_segments = info.segments.size();
|
||||
for (uint32_t i=0; i<num_segments; ++i)
|
||||
{
|
||||
// Only load a segment if it has protections. Things like
|
||||
// __PAGEZERO don't have any protections, and they shouldn't
|
||||
// be slid
|
||||
SectionSP section_sp(section_list->FindSectionByName(info.segments[i].name));
|
||||
const addr_t new_section_load_addr = info.segments[i].vmaddr + info.slide;
|
||||
static ConstString g_section_name_LINKEDIT ("__LINKEDIT");
|
||||
|
||||
if (section_sp)
|
||||
if (info.segments[i].maxprot == 0)
|
||||
{
|
||||
// Don't ever load any __LINKEDIT sections since the ones in the shared
|
||||
// cached will be coalesced into a single section and we will get warnings
|
||||
// about multiple sections mapping to the same address.
|
||||
if (section_sp->GetName() != g_section_name_LINKEDIT)
|
||||
{
|
||||
const addr_t old_section_load_addr = m_process->GetTarget().GetSectionLoadList().GetSectionLoadAddress (section_sp.get());
|
||||
if (old_section_load_addr == LLDB_INVALID_ADDRESS ||
|
||||
old_section_load_addr != new_section_load_addr)
|
||||
{
|
||||
if (m_process->GetTarget().GetSectionLoadList().SetSectionLoadAddress (section_sp.get(), new_section_load_addr))
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
inaccessible_segment_indexes.push_back(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::SystemLog (Host::eSystemLogWarning,
|
||||
"warning: unable to find and load segment named '%s' at 0x%llx in '%s/%s' in macosx dynamic loader plug-in.\n",
|
||||
info.segments[i].name.AsCString("<invalid>"),
|
||||
(uint64_t)new_section_load_addr,
|
||||
image_object_file->GetFileSpec().GetDirectory().AsCString(),
|
||||
image_object_file->GetFileSpec().GetFilename().AsCString());
|
||||
const addr_t new_section_load_addr = info.segments[i].vmaddr + info.slide;
|
||||
static ConstString g_section_name_LINKEDIT ("__LINKEDIT");
|
||||
|
||||
if (section_sp)
|
||||
{
|
||||
// Don't ever load any __LINKEDIT sections since the ones in the shared
|
||||
// cached will be coalesced into a single section and we will get warnings
|
||||
// about multiple sections mapping to the same address.
|
||||
if (section_sp->GetName() != g_section_name_LINKEDIT)
|
||||
{
|
||||
const addr_t old_section_load_addr = m_process->GetTarget().GetSectionLoadList().GetSectionLoadAddress (section_sp.get());
|
||||
if (old_section_load_addr == LLDB_INVALID_ADDRESS ||
|
||||
old_section_load_addr != new_section_load_addr)
|
||||
{
|
||||
if (m_process->GetTarget().GetSectionLoadList().SetSectionLoadAddress (section_sp.get(), new_section_load_addr))
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::SystemLog (Host::eSystemLogWarning,
|
||||
"warning: unable to find and load segment named '%s' at 0x%llx in '%s/%s' in macosx dynamic loader plug-in.\n",
|
||||
info.segments[i].name.AsCString("<invalid>"),
|
||||
(uint64_t)new_section_load_addr,
|
||||
image_object_file->GetFileSpec().GetDirectory().AsCString(),
|
||||
image_object_file->GetFileSpec().GetFilename().AsCString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the loaded the file (it changed) and we have segments that
|
||||
// are not readable or writeable, add them to the invalid memory
|
||||
// region cache for the process. This will typically only be
|
||||
// the __PAGEZERO segment in the main executable. We might be able
|
||||
// to apply this more generally to more sections that have no
|
||||
// protections in the future, but for now we are going to just
|
||||
// do __PAGEZERO.
|
||||
if (changed && !inaccessible_segment_indexes.empty())
|
||||
{
|
||||
for (uint32_t i=0; i<inaccessible_segment_indexes.size(); ++i)
|
||||
{
|
||||
const uint32_t seg_idx = inaccessible_segment_indexes[i];
|
||||
SectionSP section_sp(section_list->FindSectionByName(info.segments[seg_idx].name));
|
||||
|
||||
if (section_sp)
|
||||
{
|
||||
static ConstString g_pagezero_section_name("__PAGEZERO");
|
||||
if (g_pagezero_section_name == section_sp->GetName())
|
||||
{
|
||||
// __PAGEZERO never slides...
|
||||
const lldb::addr_t vmaddr = info.segments[seg_idx].vmaddr;
|
||||
const lldb::addr_t vmsize = info.segments[seg_idx].vmsize;
|
||||
Process::LoadRange pagezero_range (vmaddr, vmsize);
|
||||
m_process->AddInvalidMemoryRegion(pagezero_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,9 @@ using namespace lldb_private;
|
|||
MemoryCache::MemoryCache(Process &process) :
|
||||
m_process (process),
|
||||
m_cache_line_byte_size (512),
|
||||
m_cache_mutex (Mutex::eMutexTypeRecursive),
|
||||
m_cache ()
|
||||
m_mutex (Mutex::eMutexTypeRecursive),
|
||||
m_cache (),
|
||||
m_invalid_ranges ()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -41,7 +42,7 @@ MemoryCache::~MemoryCache()
|
|||
void
|
||||
MemoryCache::Clear()
|
||||
{
|
||||
Mutex::Locker locker (m_cache_mutex);
|
||||
Mutex::Locker locker (m_mutex);
|
||||
m_cache.clear();
|
||||
}
|
||||
|
||||
|
@ -56,7 +57,7 @@ MemoryCache::Flush (addr_t addr, size_t size)
|
|||
const addr_t flush_start_addr = addr - (addr % cache_line_byte_size);
|
||||
const addr_t flush_end_addr = end_addr - (end_addr % cache_line_byte_size);
|
||||
|
||||
Mutex::Locker locker (m_cache_mutex);
|
||||
Mutex::Locker locker (m_mutex);
|
||||
if (m_cache.empty())
|
||||
return;
|
||||
|
||||
|
@ -64,12 +65,43 @@ MemoryCache::Flush (addr_t addr, size_t size)
|
|||
|
||||
for (addr_t curr_addr = flush_start_addr; curr_addr <= flush_end_addr; curr_addr += cache_line_byte_size)
|
||||
{
|
||||
collection::iterator pos = m_cache.find (curr_addr);
|
||||
BlockMap::iterator pos = m_cache.find (curr_addr);
|
||||
if (pos != m_cache.end())
|
||||
m_cache.erase(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MemoryCache::AddInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size)
|
||||
{
|
||||
if (byte_size > 0)
|
||||
{
|
||||
Mutex::Locker locker (m_mutex);
|
||||
InvalidRanges::Entry range (base_addr, byte_size);
|
||||
m_invalid_ranges.Append(range);
|
||||
m_invalid_ranges.Sort();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MemoryCache::RemoveInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size)
|
||||
{
|
||||
if (byte_size > 0)
|
||||
{
|
||||
Mutex::Locker locker (m_mutex);
|
||||
const uint32_t idx = m_invalid_ranges.FindEntryIndexThatContains(base_addr);
|
||||
if (idx != UINT32_MAX)
|
||||
{
|
||||
const InvalidRanges::Entry *entry = m_invalid_ranges.GetEntryAtIndex (idx);
|
||||
if (entry->GetRangeBase() == base_addr && entry->GetByteSize() == byte_size)
|
||||
return m_invalid_ranges.RemoveEntrtAtIndex (idx);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t
|
||||
MemoryCache::Read (addr_t addr,
|
||||
void *dst,
|
||||
|
@ -83,12 +115,15 @@ MemoryCache::Read (addr_t addr,
|
|||
uint8_t *dst_buf = (uint8_t *)dst;
|
||||
addr_t curr_addr = addr - (addr % cache_line_byte_size);
|
||||
addr_t cache_offset = addr - curr_addr;
|
||||
Mutex::Locker locker (m_cache_mutex);
|
||||
Mutex::Locker locker (m_mutex);
|
||||
|
||||
while (bytes_left > 0)
|
||||
{
|
||||
collection::const_iterator pos = m_cache.find (curr_addr);
|
||||
collection::const_iterator end = m_cache.end ();
|
||||
if (m_invalid_ranges.FindEntryThatContains(curr_addr))
|
||||
return dst_len - bytes_left;
|
||||
|
||||
BlockMap::const_iterator pos = m_cache.find (curr_addr);
|
||||
BlockMap::const_iterator end = m_cache.end ();
|
||||
|
||||
if (pos != end)
|
||||
{
|
||||
|
|
|
@ -4451,6 +4451,19 @@ Process::GetThreadStatus (Stream &strm,
|
|||
return num_thread_infos_dumped;
|
||||
}
|
||||
|
||||
void
|
||||
Process::AddInvalidMemoryRegion (const LoadRange ®ion)
|
||||
{
|
||||
m_memory_cache.AddInvalidRange(region.GetRangeBase(), region.GetByteSize());
|
||||
}
|
||||
|
||||
bool
|
||||
Process::RemoveInvalidMemoryRange (const LoadRange ®ion)
|
||||
{
|
||||
return m_memory_cache.RemoveInvalidRange(region.GetRangeBase(), region.GetByteSize());
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// class Process::SettingsController
|
||||
//--------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue