Author: hhellyer Date: Thu Jul 7 03:21:28 2016 New Revision: 274741 URL: http://llvm.org/viewvc/llvm-project?rev=274741&view=rev Log: 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 Modified: lldb/trunk/include/lldb/API/SBMemoryRegionInfo.h lldb/trunk/include/lldb/Core/RangeMap.h lldb/trunk/include/lldb/Target/MemoryRegionInfo.h lldb/trunk/include/lldb/Target/Process.h lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py lldb/trunk/scripts/interface/SBMemoryRegionInfo.i lldb/trunk/source/API/SBMemoryRegionInfo.cpp lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp lldb/trunk/source/Plugins/Process/mach-core/ProcessMachCore.cpp lldb/trunk/source/Target/Process.cpp Modified: lldb/trunk/include/lldb/API/SBMemoryRegionInfo.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBMemoryRegionInfo.h?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/include/lldb/API/SBMemoryRegionInfo.h (original) +++ lldb/trunk/include/lldb/API/SBMemoryRegionInfo.h Thu Jul 7 03:21:28 2016 @@ -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; Modified: lldb/trunk/include/lldb/Core/RangeMap.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/RangeMap.h?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/RangeMap.h (original) +++ lldb/trunk/include/lldb/Core/RangeMap.h Thu Jul 7 03:21:28 2016 @@ -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) Modified: lldb/trunk/include/lldb/Target/MemoryRegionInfo.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/MemoryRegionInfo.h?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/include/lldb/Target/MemoryRegionInfo.h (original) +++ lldb/trunk/include/lldb/Target/MemoryRegionInfo.h Thu Jul 7 03:21:28 2016 @@ -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; }; } Modified: lldb/trunk/include/lldb/Target/Process.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/include/lldb/Target/Process.h (original) +++ lldb/trunk/include/lldb/Target/Process.h Thu Jul 7 03:21:28 2016 @@ -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) Modified: lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py (original) +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/postmortem/linux-core/TestLinuxCore.py Thu Jul 7 03:21:28 2016 @@ -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 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): + 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) Modified: lldb/trunk/scripts/interface/SBMemoryRegionInfo.i URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/interface/SBMemoryRegionInfo.i?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/scripts/interface/SBMemoryRegionInfo.i (original) +++ lldb/trunk/scripts/interface/SBMemoryRegionInfo.i Thu Jul 7 03:21:28 2016 @@ -42,6 +42,9 @@ public: IsExecutable (); bool + IsMapped (); + + bool operator == (const lldb::SBMemoryRegionInfo &rhs) const; bool Modified: lldb/trunk/source/API/SBMemoryRegionInfo.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBMemoryRegionInfo.cpp?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/source/API/SBMemoryRegionInfo.cpp (original) +++ lldb/trunk/source/API/SBMemoryRegionInfo.cpp Thu Jul 7 03:21:28 2016 @@ -106,6 +106,11 @@ SBMemoryRegionInfo::IsExecutable () { } bool +SBMemoryRegionInfo::IsMapped () { + return m_opaque_ap->GetMapped() == MemoryRegionInfo::eYes; +} + +bool SBMemoryRegionInfo::GetDescription (SBStream &description) { Stream &strm = description.ref(); Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original) +++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Thu Jul 7 03:21:28 2016 @@ -1896,6 +1896,9 @@ ParseMemoryRegionInfoFromProcMapsLine (c 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 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 // 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; } Modified: lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp (original) +++ lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.cpp Thu Jul 7 03:21:28 2016 @@ -345,6 +345,7 @@ ProcessElfCore::GetMemoryRegionInfo(lldb : 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 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 Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp Thu Jul 7 03:21:28 2016 @@ -2427,6 +2427,8 @@ GDBRemoteCommunicationClient::GetMemoryR region_info.SetExecutable (MemoryRegionInfo::eYes); else region_info.SetExecutable (MemoryRegionInfo::eNo); + + region_info.SetMapped(MemoryRegionInfo::eYes); } else { @@ -2434,6 +2436,7 @@ GDBRemoteCommunicationClient::GetMemoryR 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::GetMemoryR region_info.SetReadable (MemoryRegionInfo::eNo); region_info.SetWritable (MemoryRegionInfo::eNo); region_info.SetExecutable (MemoryRegionInfo::eNo); + region_info.SetMapped(MemoryRegionInfo::eNo); } } else Modified: lldb/trunk/source/Plugins/Process/mach-core/ProcessMachCore.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/mach-core/ProcessMachCore.cpp?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/mach-core/ProcessMachCore.cpp (original) +++ lldb/trunk/source/Plugins/Process/mach-core/ProcessMachCore.cpp Thu Jul 7 03:21:28 2016 @@ -581,6 +581,7 @@ ProcessMachCore::GetMemoryRegionInfo(add : 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(add 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 Modified: lldb/trunk/source/Target/Process.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=274741&r1=274740&r2=274741&view=diff ============================================================================== --- lldb/trunk/source/Target/Process.cpp (original) +++ lldb/trunk/source/Target/Process.cpp Thu Jul 7 03:21:28 2016 @@ -6609,3 +6609,36 @@ Process::AdvanceAddressToNextBranchInstr 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; + +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits