blob: 2842f85956d55b965c25574285f60d70f6b68d40 [file]
//===----------------------------------------------------------------------===//
//
// 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;
}
}
}