hhellyer created this revision.
hhellyer added a reviewer: clayborg.
hhellyer added a subscriber: lldb-commits.

This patch fills in the implementation of GetMemoryRegions() on the Windows 
live process and minidump implementations of lldb_private::Process 
(ProcessWindowsLive::GetMemoryRegionInfo and 
ProcessWinMiniDump::Impl::GetMemoryRegionInfo.) The GetMemoryRegions API was 
added under: http://reviews.llvm.org/D20565

The existing Windows implementations didn’t fill in the start and end addresses 
within MemoryRegionInfo. This patch fixes that and adds support for the new 
mapped flag on MemoryRegionInfo that says whether a memory range is mapped into 
the process address space or not.

The behaviour of both live and core implementations should match the behaviour 
documented on Process::GetMemoryRegionInfo (in Process.h) which in turn should 
match the behaviour of the qMemoryRegionInfo query documented in 
lldb-gdb-remote.txt.

https://reviews.llvm.org/D22352

Files:
  .arcconfig
  source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp
  source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp

Index: source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp
===================================================================
--- source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp
+++ source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp
@@ -277,6 +277,7 @@
 {
     Error error;
     size_t size;
+    info.Clear();
     const auto list = reinterpret_cast<const MINIDUMP_MEMORY_INFO_LIST *>(FindDumpStream(MemoryInfoListStream, &size));
     if (list == nullptr || size < sizeof(MINIDUMP_MEMORY_INFO_LIST))
     {
@@ -296,24 +297,44 @@
         return error;
     }
 
+    const MINIDUMP_MEMORY_INFO *next_entry = nullptr;
+
     for (int i = 0; i < list->NumberOfEntries; ++i)
     {
         const auto entry = reinterpret_cast<const MINIDUMP_MEMORY_INFO *>(reinterpret_cast<const char *>(list) +
                                                                           list->SizeOfHeader + i * list->SizeOfEntry);
         const auto head = entry->BaseAddress;
         const auto tail = head + entry->RegionSize;
         if (head <= load_addr && load_addr < tail)
         {
+            info.GetRange().SetRangeBase((entry->State != MEM_FREE) ? head : load_addr);
+            info.GetRange().SetRangeEnd(tail);
             info.SetReadable(IsPageReadable(entry->Protect) ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
             info.SetWritable(IsPageWritable(entry->Protect) ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
             info.SetExecutable(IsPageExecutable(entry->Protect) ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+            info.SetMapped((entry->State != MEM_FREE) ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
             return error;
         }
+        else if (head > load_addr && (next_entry == nullptr || head < next_entry->BaseAddress) )
+        {
+            // In case there is no region containing load_addr keep track of the nearest region
+            // after load_addr so we can return the distance to it.
+            next_entry = entry;
+        }
     }
+
+    // No containing region found. Create an unmapped region that extends to the next region
+    // or LLDB_INVALID_ADDRESS
+    info.GetRange().SetRangeBase(load_addr);
+    info.GetRange().SetRangeEnd((next_entry != nullptr)?next_entry->BaseAddress:LLDB_INVALID_ADDRESS);
+    info.SetReadable(MemoryRegionInfo::eNo);
+    info.SetWritable(MemoryRegionInfo::eNo);
+    info.SetExecutable(MemoryRegionInfo::eNo);
+    info.SetMapped(MemoryRegionInfo::eNo);
+
     // Note that the memory info list doesn't seem to contain ranges in kernel space,
     // so if you're walking a stack that has kernel frames, the stack may appear
     // truncated.
-    error.SetErrorString("address is not in a known range");
     return error;
 }
 
Index: source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp
===================================================================
--- source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp
+++ source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp
@@ -748,14 +748,14 @@
 {
     Error error;
     llvm::sys::ScopedLock lock(m_mutex);
+    info.Clear();
 
     if (!m_session_data)
     {
         error.SetErrorString("GetMemoryRegionInfo called with no debugging session.");
         WINERR_IFALL(WINDOWS_LOG_MEMORY, error.AsCString());
         return error;
     }
-
     HostProcess process = m_session_data->m_debugger->GetProcess();
     lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
     if (handle == nullptr || handle == LLDB_INVALID_PROCESS)
@@ -772,22 +772,67 @@
     SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info));
     if (result == 0)
     {
-        error.SetError(::GetLastError(), eErrorTypeWin32);
-        WINERR_IFALL(WINDOWS_LOG_MEMORY,
-                     "VirtualQueryEx returned error %u while getting memory region info for address 0x%I64x",
-                     error.GetError(), vm_addr);
-        return error;
+        if (::GetLastError() == ERROR_INVALID_PARAMETER)
+        {
+            // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with an address
+            // past the highest accessible address. We should return a range from the vm_addr
+            // to LLDB_INVALID_ADDRESS
+            info.GetRange().SetRangeBase(vm_addr);
+            info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
+            info.SetReadable(MemoryRegionInfo::eNo);
+            info.SetExecutable(MemoryRegionInfo::eNo);
+            info.SetWritable(MemoryRegionInfo::eNo);
+            info.SetMapped(MemoryRegionInfo::eNo);
+            return error;
+        }
+        else
+        {
+            error.SetError(::GetLastError(), eErrorTypeWin32);
+            WINERR_IFALL(WINDOWS_LOG_MEMORY,
+                    "VirtualQueryEx returned error %u while getting memory region info for address 0x%I64x",
+                    error.GetError(), vm_addr);
+            return error;
+        }
+    }
+
+    // Protect bits are only valid for MEM_COMMIT regions.
+    if (mem_info.State == MEM_COMMIT) {
+        const bool readable = IsPageReadable(mem_info.Protect);
+        const bool executable = IsPageExecutable(mem_info.Protect);
+        const bool writable = IsPageWritable(mem_info.Protect);
+        info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+        info.SetExecutable(executable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+        info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+    }
+    else
+    {
+        info.SetReadable(MemoryRegionInfo::eNo);
+        info.SetExecutable(MemoryRegionInfo::eNo);
+        info.SetWritable(MemoryRegionInfo::eNo);
+    }
+
+    // AllocationBase is defined for MEM_COMMIT and MEM_RESERVE but not MEM_FREE.
+    if (mem_info.State != MEM_FREE) {
+        info.GetRange().SetRangeBase(reinterpret_cast<addr_t>(mem_info.AllocationBase));
+        info.GetRange().SetRangeEnd(reinterpret_cast<addr_t>(mem_info.BaseAddress) + mem_info.RegionSize);
+        info.SetMapped(MemoryRegionInfo::eYes);
+    }
+    else
+    {
+        // In the unmapped case we need to return the distance to the next block of memory.
+        // VirtualQueryEx nearly does that except that it gives the distance from the start
+        // of the page containing vm_addr.
+        SYSTEM_INFO data;
+        GetSystemInfo(&data);
+        DWORD page_offset = vm_addr % data.dwPageSize;
+        info.GetRange().SetRangeBase(vm_addr);
+        info.GetRange().SetByteSize(mem_info.RegionSize - page_offset);
+        info.SetMapped(MemoryRegionInfo::eNo);
     }
-    const bool readable = IsPageReadable(mem_info.Protect);
-    const bool executable = IsPageExecutable(mem_info.Protect);
-    const bool writable = IsPageWritable(mem_info.Protect);
-    info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
-    info.SetExecutable(executable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
-    info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
 
     error.SetError(::GetLastError(), eErrorTypeWin32);
     WINLOGV_IFALL(WINDOWS_LOG_MEMORY, "Memory region info for address 0x%I64u: readable=%s, executable=%s, writable=%s",
-                  BOOL_STR(readable), BOOL_STR(executable), BOOL_STR(writable));
+                  BOOL_STR(info.GetReadable()), BOOL_STR(info.GetExecutable()), BOOL_STR(info.GetWritable()));
     return error;
 }
 
Index: .arcconfig
===================================================================
--- .arcconfig
+++ .arcconfig
@@ -1,4 +1,4 @@
 {
   "project_id" : "lldb",
-  "conduit_uri" : "http://reviews.llvm.org/";
+  "conduit_uri" : "https://reviews.llvm.org/";
 }
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to