| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ExceptionRecord.h" |
| #include "lldb/Host/windows/windows.h" |
| #include "lldb/lldb-forward.h" |
| #include "lldb/lldb-types.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/Support/Format.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| #include <dbghelp.h> |
| #include <memory> |
| #include <vector> |
| |
| using namespace lldb_private; |
| |
| ExceptionRecord::ExceptionRecord(const EXCEPTION_RECORD &record, |
| lldb::tid_t thread_id) { |
| // Notes about the `record.ExceptionRecord` field: |
| // In the past, some code tried to parse the nested exception with it, but |
| // in practice, that code just causes Access Violation. I suspect |
| // `ExceptionRecord` here actually points to the address space of the |
| // debuggee process. However, I did not manage to find any official or |
| // unofficial reference that clarifies this point. If anyone would like to |
| // reimplement this, please also keep in mind to check how this behaves when |
| // debugging a WOW64 process. I suspect you may have to use the explicit |
| // `EXCEPTION_RECORD32` and `EXCEPTION_RECORD64` structs. |
| m_code = record.ExceptionCode; |
| m_continuable = (record.ExceptionFlags == 0); |
| m_exception_addr = reinterpret_cast<lldb::addr_t>(record.ExceptionAddress); |
| m_thread_id = thread_id; |
| m_arguments.assign(record.ExceptionInformation, |
| record.ExceptionInformation + record.NumberParameters); |
| } |
| |
| lldb_private::ExceptionRecord::ExceptionRecord(const MINIDUMP_EXCEPTION &record, |
| lldb::tid_t thread_id) |
| : m_code(record.ExceptionCode), m_continuable(record.ExceptionFlags == 0), |
| m_exception_addr(static_cast<lldb::addr_t>(record.ExceptionAddress)), |
| m_thread_id(thread_id), |
| m_arguments(record.ExceptionInformation, |
| record.ExceptionInformation + record.NumberParameters) {} |
| |
| void lldb_private::ExceptionRecord::Dump(llvm::raw_ostream &stream) const { |
| // Decode additional exception information for specific exception types based |
| // on |
| // https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_exception_record |
| // Mirrors ProcessWindows::DumpAdditionalExceptionInformation so that |
| // lldb-server stop descriptions match the in-process debugger. |
| |
| const int addr_min_width = 2 + 8; // "0x" + 4 address bytes |
| |
| const llvm::ArrayRef<uint64_t> args = GetExceptionArguments(); |
| switch (GetExceptionValue()) { |
| case EXCEPTION_ACCESS_VIOLATION: { |
| if (args.size() < 2) |
| break; |
| |
| stream << ": "; |
| const int access_violation_code = args[0]; |
| const lldb::addr_t access_violation_address = args[1]; |
| switch (access_violation_code) { |
| case 0: |
| stream << "Access violation reading"; |
| break; |
| case 1: |
| stream << "Access violation writing"; |
| break; |
| case 8: |
| stream << "User-mode data execution prevention (DEP) violation at"; |
| break; |
| default: |
| stream << "Unknown access violation (code " << access_violation_code |
| << ") at"; |
| break; |
| } |
| stream << " location " |
| << llvm::format_hex(access_violation_address, addr_min_width); |
| break; |
| } |
| case EXCEPTION_IN_PAGE_ERROR: { |
| if (args.size() < 3) |
| break; |
| |
| stream << ": "; |
| const int page_load_error_code = args[0]; |
| const lldb::addr_t page_load_error_address = args[1]; |
| const DWORD underlying_code = args[2]; |
| switch (page_load_error_code) { |
| case 0: |
| stream << "In page error reading"; |
| break; |
| case 1: |
| stream << "In page error writing"; |
| break; |
| case 8: |
| stream << "User-mode data execution prevention (DEP) violation at"; |
| break; |
| default: |
| stream << "Unknown page loading error (code " << page_load_error_code |
| << ") at"; |
| break; |
| } |
| stream << " location " |
| << llvm::format_hex(page_load_error_address, addr_min_width) |
| << " (status code " << llvm::format_hex(underlying_code, 8) << ")"; |
| break; |
| } |
| } |
| } |