hhellyer updated this revision to Diff 62675.
hhellyer added a comment.
I’ve added a test in TestLinuxCore.py. It found a bug which the change in
RangeMap.h resolves.
It fills in the implementation of Process::GetMemoryRegions() and makes minor
changes to support the mapped attribute in MemoryRegionInfo to the Mac and
Linux process implementations. I also updated the documentation for
Process::GetMemoryRegionInfo.
Windows will require more changes to support the API correctly, I’m currently
getting an environment setup where I can work on those.
http://reviews.llvm.org/D21751
Files:
include/lldb/Core/RangeMap.h
include/lldb/Target/MemoryRegionInfo.h
include/lldb/Target/Process.h
packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py
source/Plugins/Process/Linux/NativeProcessLinux.cpp
source/Plugins/Process/elf-core/ProcessElfCore.cpp
source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
source/Plugins/Process/mach-core/ProcessMachCore.cpp
source/Target/Process.cpp
tools/lldb-server/lldb-gdbserver.cpp
Index: tools/lldb-server/lldb-gdbserver.cpp
===================================================================
--- tools/lldb-server/lldb-gdbserver.cpp
+++ tools/lldb-server/lldb-gdbserver.cpp
@@ -77,9 +77,28 @@
//----------------------------------------------------------------------
// Watch for signals
//----------------------------------------------------------------------
+static int g_sigpipe_received = 0;
static int g_sighup_received_count = 0;
#ifndef _WIN32
+
+static void
+signal_handler(int signo)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ fprintf (stderr, "lldb-server:%s received signal %d\n", __FUNCTION__, signo);
+ if (log)
+ log->Printf ("lldb-server:%s received signal %d", __FUNCTION__, signo);
+
+ switch (signo)
+ {
+ case SIGPIPE:
+ g_sigpipe_received = 1;
+ break;
+ }
+}
+
static void
sighup_handler(MainLoopBase &mainloop)
{
@@ -329,7 +348,7 @@
MainLoop mainloop;
#ifndef _WIN32
// Setup signal handlers first thing.
- signal(SIGPIPE, SIG_IGN);
+ signal (SIGPIPE, signal_handler);
MainLoop::SignalHandleUP sighup_handle = mainloop.RegisterSignal(SIGHUP, sighup_handler, error);
#endif
Index: source/Target/Process.cpp
===================================================================
--- source/Target/Process.cpp
+++ source/Target/Process.cpp
@@ -6609,3 +6609,36 @@
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;
+
+}
Index: source/Plugins/Process/mach-core/ProcessMachCore.cpp
===================================================================
--- source/Plugins/Process/mach-core/ProcessMachCore.cpp
+++ source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -581,19 +581,27 @@
: MemoryRegionInfo::eNo);
region_info.SetExecutable(permissions.Test(ePermissionsExecutable) ? MemoryRegionInfo::eYes
: MemoryRegionInfo::eNo);
+ region_info.SetMapped(MemoryRegionInfo::eYes);
}
else if (load_addr < permission_entry->GetRangeBase())
{
region_info.GetRange().SetRangeBase(load_addr);
region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase());
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
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -2427,13 +2427,16 @@
region_info.SetExecutable (MemoryRegionInfo::eYes);
else
region_info.SetExecutable (MemoryRegionInfo::eNo);
+
+ region_info.SetMapped(MemoryRegionInfo::eYes);
}
else
{
// The reported region does not contain this address -- we're looking at an unmapped page
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 @@
region_info.SetReadable (MemoryRegionInfo::eNo);
region_info.SetWritable (MemoryRegionInfo::eNo);
region_info.SetExecutable (MemoryRegionInfo::eNo);
+ region_info.SetMapped(MemoryRegionInfo::eNo);
}
}
else
Index: source/Plugins/Process/elf-core/ProcessElfCore.cpp
===================================================================
--- source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -345,18 +345,27 @@
: 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())
{
region_info.GetRange().SetRangeBase(load_addr);
region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase());
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
Index: source/Plugins/Process/Linux/NativeProcessLinux.cpp
===================================================================
--- source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -1883,6 +1883,9 @@
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");
@@ -2011,6 +2014,7 @@
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;
}
@@ -2028,21 +2032,11 @@
// 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;
}
Index: packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py
+++ packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py
@@ -21,20 +21,24 @@
_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 @@
# 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,60 @@
# 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 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))
+
+ # 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 a 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.assertEqual(last_region.GetRegionEnd(), end_region.GetRegionBase())
+ self.assertEqual(end_region.GetRegionEnd(), lldb.LLDB_INVALID_ADDRESS)
- def do_test(self, filename, pid):
+ 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 +155,6 @@
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)
Index: include/lldb/Target/Process.h
===================================================================
--- include/lldb/Target/Process.h
+++ include/lldb/Target/Process.h
@@ -2437,6 +2437,32 @@
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 @@
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)
Index: include/lldb/Target/MemoryRegionInfo.h
===================================================================
--- include/lldb/Target/MemoryRegionInfo.h
+++ include/lldb/Target/MemoryRegionInfo.h
@@ -30,7 +30,8 @@
m_range (),
m_read (eDontKnow),
m_write (eDontKnow),
- m_execute (eDontKnow)
+ m_execute (eDontKnow),
+ m_mapped (eDontKnow)
{
}
@@ -75,6 +76,12 @@
return m_execute;
}
+ OptionalBool
+ GetMapped () const
+ {
+ return m_mapped;
+ }
+
void
SetReadable (OptionalBool val)
{
@@ -92,6 +99,12 @@
{
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 @@
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 @@
OptionalBool m_read;
OptionalBool m_write;
OptionalBool m_execute;
+ OptionalBool m_mapped;
};
}
Index: include/lldb/Core/RangeMap.h
===================================================================
--- include/lldb/Core/RangeMap.h
+++ include/lldb/Core/RangeMap.h
@@ -1352,7 +1352,7 @@
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)
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits