Index: source/Plugins/Process/Windows/ExceptionRecord.h =================================================================== --- source/Plugins/Process/Windows/ExceptionRecord.h +++ source/Plugins/Process/Windows/ExceptionRecord.h @@ -14,6 +14,7 @@ #include "lldb/lldb-forward.h" #include "lldb/Host/windows/windows.h" +#include #include #include @@ -40,6 +41,24 @@ m_thread_id = thread_id; m_arguments.assign(record.ExceptionInformation, record.ExceptionInformation + record.NumberParameters); } + + // MINIDUMP_EXCEPTIONs are almost identical to EXCEPTION_RECORDs. + ExceptionRecord(const MINIDUMP_EXCEPTION &record, lldb::tid_t thread_id) : + m_code(record.ExceptionCode), + m_continuable(record.ExceptionFlags == 0), + m_next_exception(nullptr), + m_exception_addr(static_cast(record.ExceptionAddress)), + m_thread_id(thread_id), + m_arguments(record.ExceptionInformation, record.ExceptionInformation + record.NumberParameters) + { + // Set up link to nested exception. + if (record.ExceptionRecord) + { + m_next_exception.reset(new ExceptionRecord(*reinterpret_cast(record.ExceptionRecord), + thread_id)); + } + } + virtual ~ExceptionRecord() {} DWORD Index: source/Plugins/Process/win-minidump/ProcessWinMiniDump.h =================================================================== --- source/Plugins/Process/win-minidump/ProcessWinMiniDump.h +++ source/Plugins/Process/win-minidump/ProcessWinMiniDump.h @@ -97,6 +97,15 @@ lldb_private::ArchSpec DetermineArchitecture(); + void + ReadExceptionRecord(); + + // A thin wrapper around WinAPI's MiniDumpReadDumpStream to avoid redundant + // checks. If there's a failure (e.g., if the requested stream doesn't exist), + // the function returns nullptr and sets *size_out to 0. + void * + FindDumpStream(unsigned stream_number, size_t *size_out); + // Isolate the data to keep Windows-specific types out of this header. Can't // use the typical pimpl idiom because the implementation of this class also // needs access to public and protected members of the base class. Index: source/Plugins/Process/win-minidump/ProcessWinMiniDump.cpp =================================================================== --- source/Plugins/Process/win-minidump/ProcessWinMiniDump.cpp +++ source/Plugins/Process/win-minidump/ProcessWinMiniDump.cpp @@ -24,11 +24,15 @@ #include "lldb/Core/State.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Log.h" +#include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/UnixSignals.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" #include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h" +#include "../windows/ExceptionRecord.h" // TODO(amccarth): move this file to a common location #include "ThreadWinMiniDump.h" using namespace lldb_private; @@ -45,6 +49,7 @@ HANDLE m_dump_file; // handle to the open minidump file 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; }; ConstString @@ -129,7 +134,8 @@ m_target.SetArchitecture(DetermineArchitecture()); // TODO(amccarth): Build the module list. - // TODO(amccarth): Read the exeception record. + + ReadExceptionRecord(); return error; @@ -146,21 +152,12 @@ bool ProcessWinMiniDump::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) { - assert(m_data_up != nullptr); - assert(m_data_up->m_base_addr != 0); - - MINIDUMP_DIRECTORY *dir = nullptr; - void *ptr = nullptr; - ULONG size = 0; - if (::MiniDumpReadDumpStream(m_data_up->m_base_addr, ThreadListStream, &dir, &ptr, &size)) + size_t size = 0; + auto thread_list_ptr = static_cast(FindDumpStream(ThreadListStream, &size)); + if (thread_list_ptr) { - assert(dir->StreamType == ThreadListStream); - assert(size == dir->Location.DataSize); - assert(ptr == static_cast(static_cast(m_data_up->m_base_addr) + dir->Location.Rva)); - auto thread_list_ptr = static_cast(ptr); const ULONG32 thread_count = thread_list_ptr->NumberOfThreads; - assert(thread_count < std::numeric_limits::max()); - for (int i = 0; i < thread_count; ++i) { + for (ULONG32 i = 0; i < thread_count; ++i) { std::shared_ptr thread_sp(new ThreadWinMiniDump(*this, thread_list_ptr->Threads[i].ThreadId)); new_thread_list.AddThread(thread_sp); } @@ -172,6 +169,20 @@ void ProcessWinMiniDump::RefreshStateAfterStop() { + if (m_data_up) return; + if (m_data_up->m_exception_sp) return; + + auto active_exception = m_data_up->m_exception_sp; + std::string desc; + llvm::raw_string_ostream desc_stream(desc); + desc_stream << "Exception " + << llvm::format_hex(active_exception->GetExceptionCode(), 8) + << " encountered at address " + << llvm::format_hex(active_exception->GetExceptionAddress(), 8); + m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID()); + auto stop_thread = m_thread_list.GetSelectedThread(); + auto stop_info = StopInfo::CreateStopReasonWithException(*stop_thread, desc_stream.str().c_str()); + stop_thread->SetStopInfo(stop_info); } Error @@ -302,18 +313,10 @@ ArchSpec ProcessWinMiniDump::DetermineArchitecture() { - assert(m_data_up != nullptr); - assert(m_data_up->m_base_addr != 0); - - MINIDUMP_DIRECTORY *dir = nullptr; - void *ptr = nullptr; - ULONG size = 0; - if (::MiniDumpReadDumpStream(m_data_up->m_base_addr, SystemInfoStream, &dir, &ptr, &size)) + size_t size = 0; + auto system_info_ptr = static_cast(FindDumpStream(SystemInfoStream, &size)); + if (system_info_ptr) { - assert(dir->StreamType == SystemInfoStream); - assert(size == dir->Location.DataSize); - assert(ptr == static_cast(static_cast(m_data_up->m_base_addr) + dir->Location.Rva)); - auto system_info_ptr = static_cast(ptr); switch (system_info_ptr->ProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL: @@ -327,3 +330,33 @@ return ArchSpec(); // invalid or unknown } + +void +ProcessWinMiniDump::ReadExceptionRecord() { + size_t size = 0; + auto exception_stream_ptr = static_cast(FindDumpStream(ExceptionStream, &size)); + if (exception_stream_ptr) + { + m_data_up->m_exception_sp.reset(new ExceptionRecord(exception_stream_ptr->ExceptionRecord, exception_stream_ptr->ThreadId)); + } +} + +void * +ProcessWinMiniDump::FindDumpStream(unsigned stream_number, size_t *size_out) { + void *stream = nullptr; + *size_out = 0; + + assert(m_data_up != nullptr); + assert(m_data_up->m_base_addr != 0); + + MINIDUMP_DIRECTORY *dir = nullptr; + if (::MiniDumpReadDumpStream(m_data_up->m_base_addr, stream_number, &dir, nullptr, nullptr) && + dir != nullptr && dir->Location.DataSize > 0) + { + assert(dir->StreamType == stream_number); + *size_out = dir->Location.DataSize; + stream = static_cast(static_cast(m_data_up->m_base_addr) + dir->Location.Rva); + } + + return stream; +}