forked from OSchip/llvm-project
Implement GetMemoryRegions() for Linux and Mac OSX core files.
Summary: This patch fills in the implementation of GetMemoryRegions() on the Linux and Mac OS core file implementations of lldb_private::Process (ProcessElfCore::GetMemoryRegions and ProcessMachCore::GetMemoryRegions.) The GetMemoryRegions API was added under: http://reviews.llvm.org/D20565 The patch re-uses the m_core_range_infos list that was recently added to implement GetMemoryRegionInfo in both ProcessElfCore and ProcessMachCore to ensure the returned regions match the regions returned by Process::GetMemoryRegionInfo(addr_t load_addr, MemoryRegionInfo ®ion_info). Reviewers: clayborg Subscribers: labath, lldb-commits Differential Revision: http://reviews.llvm.org/D21751 llvm-svn: 274741
This commit is contained in:
parent
168800c97d
commit
ad00756301
|
@ -76,6 +76,16 @@ public:
|
|||
bool
|
||||
IsExecutable ();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Check if this memory address is mapped into the process address
|
||||
/// space.
|
||||
///
|
||||
/// @return
|
||||
/// true if this memory address is in the process address space.
|
||||
//------------------------------------------------------------------
|
||||
bool
|
||||
IsMapped ();
|
||||
|
||||
bool
|
||||
operator == (const lldb::SBMemoryRegionInfo &rhs) const;
|
||||
|
||||
|
|
|
@ -1352,7 +1352,7 @@ namespace lldb_private {
|
|||
typename Collection::const_iterator end = m_entries.end();
|
||||
typename Collection::const_iterator pos =
|
||||
std::lower_bound(m_entries.begin(), end, addr, [](const Entry &lhs, B rhs_base) -> bool {
|
||||
return lhs.GetRangeBase() < rhs_base;
|
||||
return lhs.GetRangeEnd() <= rhs_base;
|
||||
});
|
||||
|
||||
if (pos != end)
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace lldb_private
|
|||
m_range (),
|
||||
m_read (eDontKnow),
|
||||
m_write (eDontKnow),
|
||||
m_execute (eDontKnow)
|
||||
m_execute (eDontKnow),
|
||||
m_mapped (eDontKnow)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -75,6 +76,12 @@ namespace lldb_private
|
|||
return m_execute;
|
||||
}
|
||||
|
||||
OptionalBool
|
||||
GetMapped () const
|
||||
{
|
||||
return m_mapped;
|
||||
}
|
||||
|
||||
void
|
||||
SetReadable (OptionalBool val)
|
||||
{
|
||||
|
@ -92,6 +99,12 @@ namespace lldb_private
|
|||
{
|
||||
m_execute = val;
|
||||
}
|
||||
|
||||
void
|
||||
SetMapped (OptionalBool val)
|
||||
{
|
||||
m_mapped = val;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Get permissions as a uint32_t that is a mask of one or more bits from
|
||||
|
@ -128,7 +141,8 @@ namespace lldb_private
|
|||
return m_range == rhs.m_range &&
|
||||
m_read == rhs.m_read &&
|
||||
m_write == rhs.m_write &&
|
||||
m_execute == rhs.m_execute;
|
||||
m_execute == rhs.m_execute &&
|
||||
m_mapped == rhs.m_mapped;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -142,6 +156,7 @@ namespace lldb_private
|
|||
OptionalBool m_read;
|
||||
OptionalBool m_write;
|
||||
OptionalBool m_execute;
|
||||
OptionalBool m_mapped;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2437,6 +2437,32 @@ public:
|
|||
virtual lldb::addr_t
|
||||
ResolveIndirectFunction(const Address *address, Error &error);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Locate the memory region that contains load_addr.
|
||||
///
|
||||
/// If load_addr is within the address space the process has mapped
|
||||
/// range_info will be filled in with the start and end of that range
|
||||
/// as well as the permissions for that range and range_info.GetMapped
|
||||
/// will return true.
|
||||
///
|
||||
/// If load_addr is outside any mapped region then range_info will
|
||||
/// have its start address set to load_addr and the end of the
|
||||
/// range will indicate the start of the next mapped range or be
|
||||
/// set to LLDB_INVALID_ADDRESS if there are no valid mapped ranges
|
||||
/// between load_addr and the end of the process address space.
|
||||
///
|
||||
/// GetMemoryRegionInfo will only return an error if it is
|
||||
/// unimplemented for the current process.
|
||||
///
|
||||
/// @param[in] load_addr
|
||||
/// The load address to query the range_info for.
|
||||
///
|
||||
/// @param[out] range_info
|
||||
/// An range_info value containing the details of the range.
|
||||
///
|
||||
/// @return
|
||||
/// An error value.
|
||||
//------------------------------------------------------------------
|
||||
virtual Error
|
||||
GetMemoryRegionInfo (lldb::addr_t load_addr,
|
||||
MemoryRegionInfo &range_info)
|
||||
|
@ -2446,13 +2472,18 @@ public:
|
|||
return error;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Obtain all the mapped memory regions within this process.
|
||||
///
|
||||
/// @param[out] region_list
|
||||
/// A vector to contain MemoryRegionInfo objects for all mapped
|
||||
/// ranges.
|
||||
///
|
||||
/// @return
|
||||
/// An error value.
|
||||
//------------------------------------------------------------------
|
||||
virtual Error
|
||||
GetMemoryRegions (std::vector<lldb::MemoryRegionInfoSP>&)
|
||||
{
|
||||
Error error;
|
||||
error.SetErrorString ("Process::GetMemoryRegions() not supported");
|
||||
return error;
|
||||
}
|
||||
GetMemoryRegions (std::vector<lldb::MemoryRegionInfoSP>& region_list);
|
||||
|
||||
virtual Error
|
||||
GetWatchpointSupportInfo (uint32_t &num)
|
||||
|
|
|
@ -21,20 +21,24 @@ class LinuxCoreTestCase(TestBase):
|
|||
_x86_64_pid = 32259
|
||||
_s390x_pid = 1045
|
||||
|
||||
_i386_regions = 4
|
||||
_x86_64_regions = 5
|
||||
_s390x_regions = 2
|
||||
|
||||
@skipIf(bugnumber="llvm.org/pr26947")
|
||||
def test_i386(self):
|
||||
"""Test that lldb can read the process information from an i386 linux core file."""
|
||||
self.do_test("i386", self._i386_pid)
|
||||
self.do_test("i386", self._i386_pid, self._i386_regions)
|
||||
|
||||
def test_x86_64(self):
|
||||
"""Test that lldb can read the process information from an x86_64 linux core file."""
|
||||
self.do_test("x86_64", self._x86_64_pid)
|
||||
self.do_test("x86_64", self._x86_64_pid, self._x86_64_regions)
|
||||
|
||||
# This seems to hang on non-s390x platforms for some reason. Disabling for now.
|
||||
@skipIf(archs=no_match(['s390x']))
|
||||
def test_s390x(self):
|
||||
"""Test that lldb can read the process information from an s390x linux core file."""
|
||||
self.do_test("s390x", self._s390x_pid)
|
||||
self.do_test("s390x", self._s390x_pid, self._s390x_regions)
|
||||
|
||||
def test_same_pid_running(self):
|
||||
"""Test that we read the information from the core correctly even if we have a running
|
||||
|
@ -53,7 +57,7 @@ class LinuxCoreTestCase(TestBase):
|
|||
# We insert our own pid, and make sure the test still works.
|
||||
f.seek(pid_offset)
|
||||
f.write(struct.pack("<I", os.getpid()))
|
||||
self.do_test("x86_64-pid", os.getpid())
|
||||
self.do_test("x86_64-pid", os.getpid(), self._x86_64_regions)
|
||||
finally:
|
||||
self.RemoveTempFile("x86_64-pid.out")
|
||||
self.RemoveTempFile("x86_64-pid.core")
|
||||
|
@ -78,9 +82,64 @@ class LinuxCoreTestCase(TestBase):
|
|||
|
||||
# without destroying this process, run the test which opens another core file with the
|
||||
# same pid
|
||||
self.do_test("x86_64", self._x86_64_pid)
|
||||
self.do_test("x86_64", self._x86_64_pid, self._x86_64_regions)
|
||||
|
||||
def do_test(self, filename, pid):
|
||||
def check_memory_regions(self, process, region_count):
|
||||
region_list = process.GetMemoryRegions()
|
||||
self.assertEqual(region_list.GetSize(), region_count)
|
||||
|
||||
region = lldb.SBMemoryRegionInfo()
|
||||
|
||||
# Check we have the right number of regions.
|
||||
self.assertEqual(region_list.GetSize(), region_count);
|
||||
|
||||
# Check that getting a region beyond the last in the list fails.
|
||||
self.assertFalse(region_list.GetMemoryRegionAtIndex(region_count, region));
|
||||
|
||||
# Check each region is valid.
|
||||
for i in range(region_list.GetSize()):
|
||||
# Check we can actually get this region.
|
||||
self.assertTrue(region_list.GetMemoryRegionAtIndex(i, region))
|
||||
|
||||
#Every region in the list should be mapped.
|
||||
self.assertTrue(region.IsMapped())
|
||||
|
||||
# Test the address at the start of a region returns it's enclosing region.
|
||||
begin_address = region.GetRegionBase()
|
||||
region_at_begin = lldb.SBMemoryRegionInfo()
|
||||
error = process.GetMemoryRegionInfo(begin_address, region_at_begin)
|
||||
self.assertEqual(region, region_at_begin)
|
||||
|
||||
# Test an address in the middle of a region returns it's enclosing region.
|
||||
middle_address = (region.GetRegionBase() + region.GetRegionEnd()) / 2l
|
||||
region_at_middle = lldb.SBMemoryRegionInfo()
|
||||
error = process.GetMemoryRegionInfo(middle_address, region_at_middle)
|
||||
self.assertEqual(region, region_at_middle)
|
||||
|
||||
# Test the address at the end of a region returns it's enclosing region.
|
||||
end_address = region.GetRegionEnd() - 1l
|
||||
region_at_end = lldb.SBMemoryRegionInfo()
|
||||
error = process.GetMemoryRegionInfo(end_address, region_at_end)
|
||||
self.assertEqual(region, region_at_end)
|
||||
|
||||
# Check that quering the end address does not return this region but
|
||||
# the next one.
|
||||
next_region = lldb.SBMemoryRegionInfo()
|
||||
error = process.GetMemoryRegionInfo(region.GetRegionEnd(), next_region)
|
||||
self.assertNotEqual(region, next_region)
|
||||
self.assertEqual(region.GetRegionEnd(), next_region.GetRegionBase())
|
||||
|
||||
# Check that query beyond the last region returns an unmapped region
|
||||
# that ends at LLDB_INVALID_ADDRESS
|
||||
last_region = lldb.SBMemoryRegionInfo()
|
||||
region_list.GetMemoryRegionAtIndex(region_count - 1, last_region)
|
||||
end_region = lldb.SBMemoryRegionInfo()
|
||||
error = process.GetMemoryRegionInfo(last_region.GetRegionEnd(), end_region)
|
||||
self.assertFalse(end_region.IsMapped())
|
||||
self.assertEqual(last_region.GetRegionEnd(), end_region.GetRegionBase())
|
||||
self.assertEqual(end_region.GetRegionEnd(), lldb.LLDB_INVALID_ADDRESS)
|
||||
|
||||
def do_test(self, filename, pid, region_count):
|
||||
target = self.dbg.CreateTarget(filename + ".out")
|
||||
process = target.LoadCore(filename + ".core")
|
||||
self.assertTrue(process, PROCESS_IS_VALID)
|
||||
|
@ -100,4 +159,6 @@ class LinuxCoreTestCase(TestBase):
|
|||
line_number("main.c", "Frame " + backtrace[i]))
|
||||
self.assertEqual(frame.FindVariable("F").GetValueAsUnsigned(), ord(backtrace[i][0]))
|
||||
|
||||
self.check_memory_regions(process, region_count)
|
||||
|
||||
self.dbg.DeleteTarget(target)
|
||||
|
|
|
@ -41,6 +41,9 @@ public:
|
|||
bool
|
||||
IsExecutable ();
|
||||
|
||||
bool
|
||||
IsMapped ();
|
||||
|
||||
bool
|
||||
operator == (const lldb::SBMemoryRegionInfo &rhs) const;
|
||||
|
||||
|
|
|
@ -105,6 +105,11 @@ SBMemoryRegionInfo::IsExecutable () {
|
|||
return m_opaque_ap->GetExecutable() == MemoryRegionInfo::eYes;
|
||||
}
|
||||
|
||||
bool
|
||||
SBMemoryRegionInfo::IsMapped () {
|
||||
return m_opaque_ap->GetMapped() == MemoryRegionInfo::eYes;
|
||||
}
|
||||
|
||||
bool
|
||||
SBMemoryRegionInfo::GetDescription (SBStream &description)
|
||||
{
|
||||
|
|
|
@ -1896,6 +1896,9 @@ ParseMemoryRegionInfoFromProcMapsLine (const std::string &maps_line, MemoryRegio
|
|||
memory_region_info.GetRange ().SetRangeBase (start_address);
|
||||
memory_region_info.GetRange ().SetRangeEnd (end_address);
|
||||
|
||||
// Any memory region in /proc/{pid}/maps is by definition mapped into the process.
|
||||
memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
|
||||
|
||||
// Parse out each permission entry.
|
||||
if (line_extractor.GetBytesLeft () < 4)
|
||||
return Error ("malformed /proc/{pid}/maps entry, missing some portion of permissions");
|
||||
|
@ -2024,6 +2027,7 @@ NativeProcessLinux::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInf
|
|||
range_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo);
|
||||
range_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo);
|
||||
range_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo);
|
||||
range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -2041,21 +2045,11 @@ NativeProcessLinux::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInf
|
|||
// load_addr as start and the amount of bytes betwwen load address and the end of the memory as
|
||||
// size.
|
||||
range_info.GetRange ().SetRangeBase (load_addr);
|
||||
switch (m_arch.GetAddressByteSize())
|
||||
{
|
||||
case 4:
|
||||
range_info.GetRange ().SetByteSize (0x100000000ull - load_addr);
|
||||
break;
|
||||
case 8:
|
||||
range_info.GetRange ().SetByteSize (0ull - load_addr);
|
||||
break;
|
||||
default:
|
||||
assert(false && "Unrecognized data byte size");
|
||||
break;
|
||||
}
|
||||
range_info.GetRange ().SetRangeEnd(LLDB_INVALID_ADDRESS);
|
||||
range_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo);
|
||||
range_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo);
|
||||
range_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo);
|
||||
range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -345,6 +345,7 @@ ProcessElfCore::GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &re
|
|||
: MemoryRegionInfo::eNo);
|
||||
region_info.SetExecutable(permissions.Test(lldb::ePermissionsExecutable) ? MemoryRegionInfo::eYes
|
||||
: MemoryRegionInfo::eNo);
|
||||
region_info.SetMapped(MemoryRegionInfo::eYes);
|
||||
}
|
||||
else if (load_addr < permission_entry->GetRangeBase())
|
||||
{
|
||||
|
@ -353,10 +354,18 @@ ProcessElfCore::GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &re
|
|||
region_info.SetReadable(MemoryRegionInfo::eNo);
|
||||
region_info.SetWritable(MemoryRegionInfo::eNo);
|
||||
region_info.SetExecutable(MemoryRegionInfo::eNo);
|
||||
region_info.SetMapped(MemoryRegionInfo::eNo);
|
||||
}
|
||||
return Error();
|
||||
}
|
||||
return Error("invalid address");
|
||||
|
||||
region_info.GetRange().SetRangeBase(load_addr);
|
||||
region_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
|
||||
region_info.SetReadable(MemoryRegionInfo::eNo);
|
||||
region_info.SetWritable(MemoryRegionInfo::eNo);
|
||||
region_info.SetExecutable(MemoryRegionInfo::eNo);
|
||||
region_info.SetMapped(MemoryRegionInfo::eNo);
|
||||
return Error();
|
||||
}
|
||||
|
||||
size_t
|
||||
|
|
|
@ -2427,6 +2427,8 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
|
|||
region_info.SetExecutable (MemoryRegionInfo::eYes);
|
||||
else
|
||||
region_info.SetExecutable (MemoryRegionInfo::eNo);
|
||||
|
||||
region_info.SetMapped(MemoryRegionInfo::eYes);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2434,6 +2436,7 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
|
|||
region_info.SetReadable (MemoryRegionInfo::eNo);
|
||||
region_info.SetWritable (MemoryRegionInfo::eNo);
|
||||
region_info.SetExecutable (MemoryRegionInfo::eNo);
|
||||
region_info.SetMapped(MemoryRegionInfo::eNo);
|
||||
}
|
||||
}
|
||||
else if (name.compare ("error") == 0)
|
||||
|
@ -2453,6 +2456,7 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
|
|||
region_info.SetReadable (MemoryRegionInfo::eNo);
|
||||
region_info.SetWritable (MemoryRegionInfo::eNo);
|
||||
region_info.SetExecutable (MemoryRegionInfo::eNo);
|
||||
region_info.SetMapped(MemoryRegionInfo::eNo);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -581,6 +581,7 @@ ProcessMachCore::GetMemoryRegionInfo(addr_t load_addr, MemoryRegionInfo ®ion_
|
|||
: MemoryRegionInfo::eNo);
|
||||
region_info.SetExecutable(permissions.Test(ePermissionsExecutable) ? MemoryRegionInfo::eYes
|
||||
: MemoryRegionInfo::eNo);
|
||||
region_info.SetMapped(MemoryRegionInfo::eYes);
|
||||
}
|
||||
else if (load_addr < permission_entry->GetRangeBase())
|
||||
{
|
||||
|
@ -589,11 +590,18 @@ ProcessMachCore::GetMemoryRegionInfo(addr_t load_addr, MemoryRegionInfo ®ion_
|
|||
region_info.SetReadable(MemoryRegionInfo::eNo);
|
||||
region_info.SetWritable(MemoryRegionInfo::eNo);
|
||||
region_info.SetExecutable(MemoryRegionInfo::eNo);
|
||||
region_info.SetMapped(MemoryRegionInfo::eNo);
|
||||
}
|
||||
return Error();
|
||||
}
|
||||
|
||||
return Error("invalid address");
|
||||
region_info.GetRange().SetRangeBase(load_addr);
|
||||
region_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
|
||||
region_info.SetReadable(MemoryRegionInfo::eNo);
|
||||
region_info.SetWritable(MemoryRegionInfo::eNo);
|
||||
region_info.SetExecutable(MemoryRegionInfo::eNo);
|
||||
region_info.SetMapped(MemoryRegionInfo::eNo);
|
||||
return Error();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -6609,3 +6609,36 @@ Process::AdvanceAddressToNextBranchInstruction (Address default_stop_addr, Addre
|
|||
|
||||
return retval;
|
||||
}
|
||||
|
||||
Error
|
||||
Process::GetMemoryRegions (std::vector<lldb::MemoryRegionInfoSP>& region_list)
|
||||
{
|
||||
|
||||
Error error;
|
||||
|
||||
lldb::addr_t range_base = 0;
|
||||
lldb::addr_t range_end = 0;
|
||||
|
||||
region_list.clear();
|
||||
do
|
||||
{
|
||||
lldb::MemoryRegionInfoSP region_info( new lldb_private::MemoryRegionInfo() );
|
||||
error = GetMemoryRegionInfo (range_end, *region_info);
|
||||
// GetMemoryRegionInfo should only return an error if it is unimplemented.
|
||||
if (error.Fail())
|
||||
{
|
||||
region_list.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
range_base = region_info->GetRange().GetRangeBase();
|
||||
range_end = region_info->GetRange().GetRangeEnd();
|
||||
if( region_info->GetMapped() == MemoryRegionInfo::eYes )
|
||||
{
|
||||
region_list.push_back(region_info);
|
||||
}
|
||||
} while (range_end != LLDB_INVALID_ADDRESS);
|
||||
|
||||
return error;
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue