Index: source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp =================================================================== --- source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp +++ source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp @@ -39,7 +39,8 @@ return false; } HANDLE file_handle = ::CreateFileW(wide_name.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - const auto result = ::MiniDumpWriteDump(process_handle, process_sp->GetID(), file_handle, MiniDumpNormal, NULL, NULL, NULL); + const auto result = ::MiniDumpWriteDump(process_handle, process_sp->GetID(), file_handle, + MiniDumpWithFullMemoryInfo, NULL, NULL, NULL); ::CloseHandle(file_handle); ::CloseHandle(process_handle); if (!result) Index: source/Plugins/Process/Windows/Common/ProcessWindows.h =================================================================== --- source/Plugins/Process/Windows/Common/ProcessWindows.h +++ source/Plugins/Process/Windows/Common/ProcessWindows.h @@ -34,6 +34,17 @@ size_t PutSTDIN(const char *buf, size_t buf_size, lldb_private::Error &error) override; lldb::addr_t GetImageInfoAddress() override; + +protected: + // These decode the page protection bits. + static bool + IsPageReadable(uint32_t protect); + + static bool + IsPageWritable(uint32_t protect); + + static bool + IsPageExecutable(uint32_t protect); }; } Index: source/Plugins/Process/Windows/Common/ProcessWindows.cpp =================================================================== --- source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -15,6 +15,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Core/State.h" +#include "lldb/Host/windows/windows.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/Target.h" @@ -74,4 +75,26 @@ return LLDB_INVALID_ADDRESS; } +// The Windows page protection bits are NOT independent masks that can be bitwise-ORed +// together. For example, PAGE_EXECUTE_READ is not (PAGE_EXECUTE | PAGE_READ). +// To test for an access type, it's necessary to test for any of the bits that provide +// that access type. +bool +ProcessWindows::IsPageReadable(uint32_t protect) +{ + return (protect & PAGE_NOACCESS) == 0; +} + +bool +ProcessWindows::IsPageWritable(uint32_t protect) +{ + return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_READWRITE | PAGE_WRITECOPY)) != 0; +} + +bool +ProcessWindows::IsPageExecutable(uint32_t protect) +{ + return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0; +} + } Index: source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp =================================================================== --- source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp +++ source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp @@ -743,12 +743,13 @@ error.GetError(), vm_addr); return error; } - bool readable = !(mem_info.Protect & PAGE_NOACCESS); - bool executable = mem_info.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); - bool writable = mem_info.Protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | PAGE_READWRITE | PAGE_WRITECOPY); + 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)); Index: source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h =================================================================== --- source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h +++ source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h @@ -23,7 +23,7 @@ class ProcessWinMiniDump : public lldb_private::ProcessWindows { -public: + public: static lldb::ProcessSP CreateInstance (lldb::TargetSP target_sp, lldb_private::Listener &listener, @@ -84,7 +84,10 @@ lldb_private::ArchSpec GetArchitecture(); -protected: + lldb_private::Error + GetMemoryRegionInfo(lldb::addr_t load_addr, lldb_private::MemoryRegionInfo &range_info) override; + + protected: void Clear(); @@ -92,7 +95,7 @@ UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list) override; -private: + private: // Describes a range of memory captured in the mini dump. struct Range { lldb::addr_t start; // virtual address of the beginning of the range Index: source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp =================================================================== --- source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp +++ source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp @@ -17,21 +17,22 @@ #include #include -#include "lldb/Core/PluginManager.h" +#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Core/State.h" -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Log.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" -#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/UnixSignals.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/ConvertUTF.h" -#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h" #include "ExceptionRecord.h" #include "ThreadWinMiniDump.h" @@ -272,6 +273,51 @@ return overlap; } +Error +ProcessWinMiniDump::GetMemoryRegionInfo(lldb::addr_t load_addr, lldb_private::MemoryRegionInfo &info) +{ + Error error; + size_t size; + const auto list = reinterpret_cast(FindDumpStream(MemoryInfoListStream, &size)); + if (list == nullptr || size < sizeof(MINIDUMP_MEMORY_INFO_LIST)) + { + error.SetErrorString("the mini dump contains no memory range information"); + return error; + } + + if (list->SizeOfEntry < sizeof(MINIDUMP_MEMORY_INFO)) + { + error.SetErrorString("the entries in the mini dump memory info list are smaller than expected"); + return error; + } + + if (size < list->SizeOfHeader + list->SizeOfEntry * list->NumberOfEntries) + { + error.SetErrorString("the mini dump memory info list is incomplete"); + return error; + } + + for (int i = 0; i < list->NumberOfEntries; ++i) + { + const auto entry = reinterpret_cast(reinterpret_cast(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.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); + return error; + } + } + // 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; +} + void ProcessWinMiniDump::Clear() {