Index: source/Plugins/Process/Windows/Common/NtStructures.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/Common/NtStructures.h @@ -0,0 +1,32 @@ +//===-- NtStructures.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Plugins_Process_Windows_Common_NtStructures_h_ +#define liblldb_Plugins_Process_Windows_Common_NtStructures_h_ + +#include "lldb/Host/windows/windows.h" + +// This describes the layout of a TEB (Thread Environment Block) for a 64-bit +// process. It's adapted from the 32-bit TEB in winternl.h. Currently, we care +// only about the position of the TlsSlots. +struct TEB64 +{ + ULONG64 Reserved1[12]; + ULONG64 ProcessEnvironmentBlock; + ULONG64 Reserved2[399]; + BYTE Reserved3[1952]; + ULONG64 TlsSlots[64]; + BYTE Reserved4[8]; + ULONG64 Reserved5[26]; + ULONG64 ReservedForOle; // Windows 2000 only + ULONG64 Reserved6[4]; + ULONG64 TlsExpansionSlots; +}; + +#endif Index: source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp =================================================================== --- source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp +++ source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp @@ -35,6 +35,9 @@ #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include "Plugins/Process/Windows/Common/NtStructures.h" +#include "Plugins/Process/Windows/Common/ProcessWindowsLog.h" + #include "ExceptionRecord.h" #include "ThreadWinMiniDump.h" @@ -83,6 +86,7 @@ HANDLE m_mapping; // handle to the file mapping for the minidump file void * m_base_addr; // base memory address of the minidump std::shared_ptr m_exception_sp; + bool m_is_wow64; // minidump is of a 32-bit process captured with a 64-bit debugger }; ConstString @@ -195,7 +199,47 @@ auto thread_sp = std::make_shared(*this, mini_dump_thread.ThreadId); if (mini_dump_thread.ThreadContext.DataSize >= sizeof(CONTEXT)) { - const CONTEXT *context = reinterpret_cast(static_cast(m_data_up->m_base_addr) + mini_dump_thread.ThreadContext.Rva); + const CONTEXT *context = reinterpret_cast( + static_cast(m_data_up->m_base_addr) + mini_dump_thread.ThreadContext.Rva); + + if (m_data_up->m_is_wow64) + { + // On Windows, a 32-bit process can run on a 64-bit machine under WOW64. + // If the minidump was captured with a 64-bit debugger, then the CONTEXT + // we just grabbed from the mini_dump_thread is the one for the 64-bit + // "native" process rather than the 32-bit "guest" process we care about. + // In this case, we can get the 32-bit CONTEXT from the TEB (Thread + // Environment Block) of the 64-bit process. + Error error; + TEB64 wow64teb = {0}; + ReadMemory(mini_dump_thread.Teb, &wow64teb, sizeof(wow64teb), error); + if (error.Success()) + { + // Slot 1 of the thread-local storage in the 64-bit TEB points to a structure + // that includes the 32-bit CONTEXT (after a ULONG). + // See: https://msdn.microsoft.com/en-us/library/ms681670.aspx + const size_t addr = wow64teb.TlsSlots[1]; + Range range = {0}; + if (FindMemoryRange(addr, &range)) + { + lldbassert(range.start <= addr); + const size_t offset = addr - range.start + sizeof(ULONG); + if (offset < range.size) + { + const size_t overlap = range.size - offset; + if (overlap >= sizeof(CONTEXT)) + { + context = reinterpret_cast(range.ptr + offset); + } + } + } + } + + // NOTE: We don't currently use the TEB for anything else. If we need it in + // the future, the 32-bit TEB is located according to the address stored in the + // first slot of the 64-bit TEB (wow64teb.Reserved1[0]). + } + thread_sp->SetContext(context); } new_thread_list.AddThread(thread_sp); @@ -347,11 +391,8 @@ return ArchSpec(); } - -ProcessWinMiniDump::Data::Data() : - m_dump_file(INVALID_HANDLE_VALUE), - m_mapping(NULL), - m_base_addr(nullptr) +ProcessWinMiniDump::Data::Data() + : m_dump_file(INVALID_HANDLE_VALUE), m_mapping(NULL), m_base_addr(nullptr), m_is_wow64(false) { } @@ -381,7 +422,8 @@ auto mem_list_stream = static_cast(FindDumpStream(MemoryListStream, &stream_size)); if (mem_list_stream) { - for (ULONG32 i = 0; i < mem_list_stream->NumberOfMemoryRanges; ++i) { + for (ULONG32 i = 0; i < mem_list_stream->NumberOfMemoryRanges; ++i) + { const MINIDUMP_MEMORY_DESCRIPTOR &mem_desc = mem_list_stream->MemoryRanges[i]; const MINIDUMP_LOCATION_DESCRIPTOR &loc_desc = mem_desc.Memory; const lldb::addr_t range_start = mem_desc.StartOfMemoryRange; @@ -516,7 +558,13 @@ { const auto &module = module_list_ptr->Modules[i]; const auto file_name = GetMiniDumpString(m_data_up->m_base_addr, module.ModuleNameRva); - ModuleSpec module_spec = FileSpec(file_name, true); + const auto file_spec = FileSpec(file_name, true); + if (FileSpec::Compare(file_spec, FileSpec("wow64.dll", false), false) == 0) + { + WINLOG_IFALL(WINDOWS_LOG_PROCESS, "Minidump is for a WOW64 process."); + m_data_up->m_is_wow64 = true; + } + ModuleSpec module_spec = file_spec; lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec); if (!module_sp)