mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 22:26:06 +00:00
win: Capture some CRITICAL_SECTION debugging data
Capture the memory for the loader lock (can be inspected by !cs), as well as all locks that were created with .DebugInfo which can be viewed with !locks. e.g. 0:000> !cs ntdll!LdrpLoaderLock ----------------------------------------- Critical section = 0x778d6410 (ntdll!LdrpLoaderLock+0x0) DebugInfo = 0x778d6b6c NOT LOCKED LockSemaphore = 0x0 SpinCount = 0x04000000 0:000> !locks -v CritSec ntdll!RtlpProcessHeapsListLock+0 at 778d7620 LockCount NOT LOCKED RecursionCount 0 OwningThread 0 EntryCount 0 ContentionCount 0 CritSec +7a0248 at 007a0248 LockCount NOT LOCKED RecursionCount 0 OwningThread 0 EntryCount 0 ContentionCount 0 CritSec crashy_program!g_critical_section_with_debug_info+0 at 01342c48 LockCount NOT LOCKED RecursionCount 0 OwningThread 0 EntryCount 0 ContentionCount 0 CritSec crashy_program!crashpad::`anonymous namespace'::g_test_critical_section+0 at 01342be0 WaiterWoken No LockCount 0 RecursionCount 1 OwningThread 34b8 EntryCount 0 ContentionCount 0 *** Locked Scanned 4 critical sections R=mark@chromium.org BUG=crashpad:52 Review URL: https://codereview.chromium.org/1392093003 .
This commit is contained in:
parent
1f1a24cb51
commit
4893a9b76d
@ -48,6 +48,13 @@ base::Lock* g_non_crash_dump_lock;
|
||||
// dump.
|
||||
crashpad::ExceptionInformation g_non_crash_exception_information;
|
||||
|
||||
// A CRITICAL_SECTION initialized with
|
||||
// RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO to force it to be allocated with a
|
||||
// valid .DebugInfo field. The address of this critical section is given to the
|
||||
// handler. All critical sections with debug info are linked in a doubly-linked
|
||||
// list, so this allows the handler to capture all of them.
|
||||
CRITICAL_SECTION g_critical_section_with_debug_info;
|
||||
|
||||
LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
|
||||
// Tracks whether a thread has already entered UnhandledExceptionHandler.
|
||||
static base::subtle::AtomicWord have_crashed;
|
||||
@ -94,6 +101,18 @@ LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
BOOL CrashpadInitializeCriticalSectionEx(
|
||||
CRITICAL_SECTION* critical_section,
|
||||
DWORD spin_count,
|
||||
DWORD flags) {
|
||||
static decltype(InitializeCriticalSectionEx)* initialize_critical_section_ex =
|
||||
reinterpret_cast<decltype(InitializeCriticalSectionEx)*>(GetProcAddress(
|
||||
LoadLibrary(L"kernel32.dll"), "InitializeCriticalSectionEx"));
|
||||
if (!initialize_critical_section_ex)
|
||||
return false;
|
||||
return initialize_critical_section_ex(critical_section, spin_count, flags);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace crashpad {
|
||||
@ -118,6 +137,7 @@ bool CrashpadClient::SetHandler(const std::string& ipc_port) {
|
||||
DCHECK_EQ(g_signal_exception, INVALID_HANDLE_VALUE);
|
||||
DCHECK_EQ(g_signal_non_crash_dump, INVALID_HANDLE_VALUE);
|
||||
DCHECK_EQ(g_non_crash_dump_done, INVALID_HANDLE_VALUE);
|
||||
DCHECK(!g_critical_section_with_debug_info.DebugInfo);
|
||||
|
||||
ClientToServerMessage message;
|
||||
memset(&message, 0, sizeof(message));
|
||||
@ -129,6 +149,23 @@ bool CrashpadClient::SetHandler(const std::string& ipc_port) {
|
||||
message.registration.non_crash_exception_information =
|
||||
reinterpret_cast<WinVMAddress>(&g_non_crash_exception_information);
|
||||
|
||||
// We create this dummy CRITICAL_SECTION with the
|
||||
// RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO flag set to have an entry point
|
||||
// into the doubly-linked list of RTL_CRITICAL_SECTION_DEBUG objects. This
|
||||
// allows us to walk the list at crash time to gather data for !locks. A
|
||||
// debugger would instead inspect ntdll!RtlCriticalSectionList to get the head
|
||||
// of the list. But that is not an exported symbol, so on an arbitrary client
|
||||
// machine, we don't have a way of getting that pointer.
|
||||
if (CrashpadInitializeCriticalSectionEx(
|
||||
&g_critical_section_with_debug_info,
|
||||
0,
|
||||
RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO)) {
|
||||
message.registration.critical_section_address =
|
||||
reinterpret_cast<WinVMAddress>(&g_critical_section_with_debug_info);
|
||||
} else {
|
||||
PLOG(ERROR) << "InitializeCriticalSectionEx";
|
||||
}
|
||||
|
||||
ServerToClientMessage response = {0};
|
||||
|
||||
if (!SendToCrashHandlerServer(
|
||||
|
@ -42,14 +42,16 @@ void CrashReportExceptionHandler::ExceptionHandlerServerStarted() {
|
||||
|
||||
unsigned int CrashReportExceptionHandler::ExceptionHandlerServerException(
|
||||
HANDLE process,
|
||||
WinVMAddress exception_information_address) {
|
||||
WinVMAddress exception_information_address,
|
||||
WinVMAddress debug_critical_section_address) {
|
||||
const unsigned int kFailedTerminationCode = 0xffff7002;
|
||||
|
||||
ScopedProcessSuspend suspend(process);
|
||||
|
||||
ProcessSnapshotWin process_snapshot;
|
||||
if (!process_snapshot.Initialize(process,
|
||||
ProcessSuspensionState::kSuspended)) {
|
||||
ProcessSuspensionState::kSuspended,
|
||||
debug_critical_section_address)) {
|
||||
LOG(WARNING) << "ProcessSnapshotWin::Initialize failed";
|
||||
return kFailedTerminationCode;
|
||||
}
|
||||
|
@ -60,7 +60,8 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
|
||||
void ExceptionHandlerServerStarted() override;
|
||||
unsigned int ExceptionHandlerServerException(
|
||||
HANDLE process,
|
||||
WinVMAddress exception_information_address) override;
|
||||
WinVMAddress exception_information_address,
|
||||
WinVMAddress debug_critical_section_address) override;
|
||||
|
||||
private:
|
||||
CrashReportDatabase* database_; // weak
|
||||
|
@ -28,6 +28,8 @@
|
||||
namespace crashpad {
|
||||
namespace {
|
||||
|
||||
CRITICAL_SECTION g_test_critical_section;
|
||||
|
||||
ULONG RtlNtStatusToDosError(NTSTATUS status) {
|
||||
static decltype(::RtlNtStatusToDosError)* rtl_nt_status_to_dos_error =
|
||||
reinterpret_cast<decltype(::RtlNtStatusToDosError)*>(
|
||||
@ -75,6 +77,18 @@ void AllocateMemoryOfVariousProtections() {
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CrashpadInitializeCriticalSectionEx(
|
||||
CRITICAL_SECTION* critical_section,
|
||||
DWORD spin_count,
|
||||
DWORD flags) {
|
||||
static decltype(InitializeCriticalSectionEx)* initialize_critical_section_ex =
|
||||
reinterpret_cast<decltype(InitializeCriticalSectionEx)*>(GetProcAddress(
|
||||
LoadLibrary(L"kernel32.dll"), "InitializeCriticalSectionEx"));
|
||||
if (!initialize_critical_section_ex)
|
||||
return false;
|
||||
return initialize_critical_section_ex(critical_section, spin_count, flags);
|
||||
}
|
||||
|
||||
void SomeCrashyFunction() {
|
||||
// SetLastError and NTSTATUS so that we have something to view in !gle in
|
||||
// windbg. RtlNtStatusToDosError() stores STATUS_NO_SUCH_FILE into the
|
||||
@ -103,6 +117,10 @@ int CrashyMain(int argc, char* argv[]) {
|
||||
|
||||
AllocateMemoryOfVariousProtections();
|
||||
|
||||
CrashpadInitializeCriticalSectionEx(
|
||||
&g_test_critical_section, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
|
||||
EnterCriticalSection(&g_test_critical_section);
|
||||
|
||||
SomeCrashyFunction();
|
||||
|
||||
return 0;
|
||||
|
@ -75,8 +75,8 @@ TEST(CrashpadInfoClientOptions, OneModule) {
|
||||
ASSERT_TRUE(process_snapshot.Initialize(mach_task_self()));
|
||||
#elif defined(OS_WIN)
|
||||
ProcessSnapshotWin process_snapshot;
|
||||
ASSERT_TRUE(process_snapshot.Initialize(GetCurrentProcess(),
|
||||
ProcessSuspensionState::kRunning));
|
||||
ASSERT_TRUE(process_snapshot.Initialize(
|
||||
GetCurrentProcess(), ProcessSuspensionState::kRunning, 0));
|
||||
#else
|
||||
#error Port.
|
||||
#endif // OS_MACOSX
|
||||
@ -189,8 +189,8 @@ TEST(CrashpadInfoClientOptions, TwoModules) {
|
||||
ASSERT_TRUE(process_snapshot.Initialize(mach_task_self()));
|
||||
#elif defined(OS_WIN)
|
||||
ProcessSnapshotWin process_snapshot;
|
||||
ASSERT_TRUE(process_snapshot.Initialize(GetCurrentProcess(),
|
||||
ProcessSuspensionState::kRunning));
|
||||
ASSERT_TRUE(process_snapshot.Initialize(
|
||||
GetCurrentProcess(), ProcessSuspensionState::kRunning, 0));
|
||||
#else
|
||||
#error Port.
|
||||
#endif // OS_MACOSX
|
||||
|
@ -177,8 +177,6 @@ def RunTests(cdb_path, dump_path, pipe_name):
|
||||
out.Check('LastStatusValue: \(NTSTATUS\) 0xc000000f - {File Not Found} The '
|
||||
'file %hs does not exist.', '!gle gets last ntstatus')
|
||||
|
||||
# Locks.
|
||||
if False: # The code for these isn't landed yet.
|
||||
out = CdbRun(cdb_path, dump_path, '!locks')
|
||||
out.Check(r'CritSec crashy_program!crashpad::`anonymous namespace\'::'
|
||||
r'g_test_critical_section', 'lock was captured')
|
||||
|
@ -88,10 +88,13 @@ class CrashingDelegate : public ExceptionHandlerServer::Delegate {
|
||||
|
||||
unsigned int ExceptionHandlerServerException(
|
||||
HANDLE process,
|
||||
WinVMAddress exception_information_address) override {
|
||||
WinVMAddress exception_information_address,
|
||||
WinVMAddress debug_critical_section_address) override {
|
||||
ScopedProcessSuspend suspend(process);
|
||||
ProcessSnapshotWin snapshot;
|
||||
snapshot.Initialize(process, ProcessSuspensionState::kSuspended);
|
||||
snapshot.Initialize(process,
|
||||
ProcessSuspensionState::kSuspended,
|
||||
debug_critical_section_address);
|
||||
snapshot.InitializeException(exception_information_address);
|
||||
|
||||
// Confirm the exception record was read correctly.
|
||||
@ -186,10 +189,13 @@ class SimulateDelegate : public ExceptionHandlerServer::Delegate {
|
||||
|
||||
unsigned int ExceptionHandlerServerException(
|
||||
HANDLE process,
|
||||
WinVMAddress exception_information_address) override {
|
||||
WinVMAddress exception_information_address,
|
||||
WinVMAddress debug_critical_section_address) override {
|
||||
ScopedProcessSuspend suspend(process);
|
||||
ProcessSnapshotWin snapshot;
|
||||
snapshot.Initialize(process, ProcessSuspensionState::kSuspended);
|
||||
snapshot.Initialize(process,
|
||||
ProcessSuspensionState::kSuspended,
|
||||
debug_critical_section_address);
|
||||
snapshot.InitializeException(exception_information_address);
|
||||
EXPECT_TRUE(snapshot.Exception());
|
||||
EXPECT_EQ(0x517a7ed, snapshot.Exception()->Exception());
|
||||
|
@ -43,8 +43,10 @@ ProcessSnapshotWin::ProcessSnapshotWin()
|
||||
ProcessSnapshotWin::~ProcessSnapshotWin() {
|
||||
}
|
||||
|
||||
bool ProcessSnapshotWin::Initialize(HANDLE process,
|
||||
ProcessSuspensionState suspension_state) {
|
||||
bool ProcessSnapshotWin::Initialize(
|
||||
HANDLE process,
|
||||
ProcessSuspensionState suspension_state,
|
||||
WinVMAddress debug_critical_section_address) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
|
||||
GetTimeOfDay(&snapshot_time_);
|
||||
@ -54,10 +56,13 @@ bool ProcessSnapshotWin::Initialize(HANDLE process,
|
||||
|
||||
system_.Initialize(&process_reader_);
|
||||
|
||||
if (process_reader_.Is64Bit())
|
||||
InitializePebData<process_types::internal::Traits64>();
|
||||
else
|
||||
InitializePebData<process_types::internal::Traits32>();
|
||||
if (process_reader_.Is64Bit()) {
|
||||
InitializePebData<process_types::internal::Traits64>(
|
||||
debug_critical_section_address);
|
||||
} else {
|
||||
InitializePebData<process_types::internal::Traits32>(
|
||||
debug_critical_section_address);
|
||||
}
|
||||
|
||||
InitializeThreads();
|
||||
InitializeModules();
|
||||
@ -205,8 +210,8 @@ std::vector<const MemoryMapRegionSnapshot*> ProcessSnapshotWin::MemoryMap()
|
||||
std::vector<const MemorySnapshot*> ProcessSnapshotWin::ExtraMemory() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
std::vector<const MemorySnapshot*> extra_memory;
|
||||
for (const auto& peb_memory : peb_memory_)
|
||||
extra_memory.push_back(peb_memory);
|
||||
for (const auto& em : extra_memory_)
|
||||
extra_memory.push_back(em);
|
||||
return extra_memory;
|
||||
}
|
||||
|
||||
@ -235,11 +240,12 @@ void ProcessSnapshotWin::InitializeModules() {
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void ProcessSnapshotWin::InitializePebData() {
|
||||
void ProcessSnapshotWin::InitializePebData(
|
||||
WinVMAddress debug_critical_section_address) {
|
||||
WinVMAddress peb_address;
|
||||
WinVMSize peb_size;
|
||||
process_reader_.GetProcessInfo().Peb(&peb_address, &peb_size);
|
||||
AddMemorySnapshot(peb_address, peb_size, &peb_memory_);
|
||||
AddMemorySnapshot(peb_address, peb_size, &extra_memory_);
|
||||
|
||||
process_types::PEB<Traits> peb_data;
|
||||
if (!process_reader_.ReadMemory(peb_address, peb_size, &peb_data)) {
|
||||
@ -248,7 +254,7 @@ void ProcessSnapshotWin::InitializePebData() {
|
||||
}
|
||||
|
||||
process_types::PEB_LDR_DATA<Traits> peb_ldr_data;
|
||||
AddMemorySnapshot(peb_data.Ldr, sizeof(peb_ldr_data), &peb_memory_);
|
||||
AddMemorySnapshot(peb_data.Ldr, sizeof(peb_ldr_data), &extra_memory_);
|
||||
if (!process_reader_.ReadMemory(
|
||||
peb_data.Ldr, sizeof(peb_ldr_data), &peb_ldr_data)) {
|
||||
LOG(ERROR) << "ReadMemory PEB_LDR_DATA";
|
||||
@ -257,17 +263,17 @@ void ProcessSnapshotWin::InitializePebData() {
|
||||
AddMemorySnapshotForLdrLIST_ENTRY(
|
||||
peb_ldr_data.InLoadOrderModuleList,
|
||||
offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, InLoadOrderLinks),
|
||||
&peb_memory_);
|
||||
&extra_memory_);
|
||||
AddMemorySnapshotForLdrLIST_ENTRY(
|
||||
peb_ldr_data.InMemoryOrderModuleList,
|
||||
offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>,
|
||||
InMemoryOrderLinks),
|
||||
&peb_memory_);
|
||||
&extra_memory_);
|
||||
AddMemorySnapshotForLdrLIST_ENTRY(
|
||||
peb_ldr_data.InInitializationOrderModuleList,
|
||||
offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>,
|
||||
InInitializationOrderLinks),
|
||||
&peb_memory_);
|
||||
&extra_memory_);
|
||||
}
|
||||
|
||||
process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters;
|
||||
@ -278,27 +284,38 @@ void ProcessSnapshotWin::InitializePebData() {
|
||||
return;
|
||||
}
|
||||
AddMemorySnapshot(
|
||||
peb_data.ProcessParameters, sizeof(process_parameters), &peb_memory_);
|
||||
peb_data.ProcessParameters, sizeof(process_parameters), &extra_memory_);
|
||||
|
||||
AddMemorySnapshotForUNICODE_STRING(
|
||||
process_parameters.CurrentDirectory.DosPath, &peb_memory_);
|
||||
AddMemorySnapshotForUNICODE_STRING(process_parameters.DllPath, &peb_memory_);
|
||||
process_parameters.CurrentDirectory.DosPath, &extra_memory_);
|
||||
AddMemorySnapshotForUNICODE_STRING(process_parameters.DllPath,
|
||||
&extra_memory_);
|
||||
AddMemorySnapshotForUNICODE_STRING(process_parameters.ImagePathName,
|
||||
&peb_memory_);
|
||||
&extra_memory_);
|
||||
AddMemorySnapshotForUNICODE_STRING(process_parameters.CommandLine,
|
||||
&peb_memory_);
|
||||
&extra_memory_);
|
||||
AddMemorySnapshotForUNICODE_STRING(process_parameters.WindowTitle,
|
||||
&peb_memory_);
|
||||
&extra_memory_);
|
||||
AddMemorySnapshotForUNICODE_STRING(process_parameters.DesktopInfo,
|
||||
&peb_memory_);
|
||||
&extra_memory_);
|
||||
AddMemorySnapshotForUNICODE_STRING(process_parameters.ShellInfo,
|
||||
&peb_memory_);
|
||||
&extra_memory_);
|
||||
AddMemorySnapshotForUNICODE_STRING(process_parameters.RuntimeData,
|
||||
&peb_memory_);
|
||||
&extra_memory_);
|
||||
AddMemorySnapshot(
|
||||
process_parameters.Environment,
|
||||
DetermineSizeOfEnvironmentBlock(process_parameters.Environment),
|
||||
&peb_memory_);
|
||||
&extra_memory_);
|
||||
|
||||
// Walk the loader lock which is directly referenced by the PEB. It may or may
|
||||
// not have a .DebugInfo list, but doesn't on more recent OSs (it does on
|
||||
// Vista). If it does, then we may walk the lock list more than once, but
|
||||
// AddMemorySnapshot() will take care of deduplicating the added regions.
|
||||
ReadLocks<Traits>(peb_data.LoaderLock, &extra_memory_);
|
||||
|
||||
// Traverse the locks with valid .DebugInfo if a starting point was supplied.
|
||||
if (debug_critical_section_address)
|
||||
ReadLocks<Traits>(debug_critical_section_address, &extra_memory_);
|
||||
}
|
||||
|
||||
void ProcessSnapshotWin::AddMemorySnapshot(
|
||||
@ -399,4 +416,97 @@ WinVMSize ProcessSnapshotWin::DetermineSizeOfEnvironmentBlock(
|
||||
return env_block.size() * sizeof(env_block[0]);
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void ProcessSnapshotWin::ReadLocks(
|
||||
WinVMAddress start,
|
||||
PointerVector<internal::MemorySnapshotWin>* into) {
|
||||
// We're walking the RTL_CRITICAL_SECTION_DEBUG ProcessLocksList, but starting
|
||||
// from an actual RTL_CRITICAL_SECTION, so start by getting to the first
|
||||
// RTL_CRITICAL_SECTION_DEBUG.
|
||||
|
||||
process_types::RTL_CRITICAL_SECTION<Traits> critical_section;
|
||||
if (!process_reader_.ReadMemory(
|
||||
start, sizeof(critical_section), &critical_section)) {
|
||||
LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION";
|
||||
return;
|
||||
}
|
||||
|
||||
const decltype(critical_section.DebugInfo) kInvalid =
|
||||
static_cast<decltype(critical_section.DebugInfo)>(-1);
|
||||
if (critical_section.DebugInfo == kInvalid)
|
||||
return;
|
||||
|
||||
const WinVMAddress start_address_backward = critical_section.DebugInfo;
|
||||
WinVMAddress current_address = start_address_backward;
|
||||
WinVMAddress last_good_address;
|
||||
|
||||
// Typically, this seems to be a circular list, but it's not clear that it
|
||||
// always is, so follow Blink fields back to the head (or where we started)
|
||||
// before following Flink to capture memory.
|
||||
do {
|
||||
last_good_address = current_address;
|
||||
// Read the RTL_CRITICAL_SECTION_DEBUG structure to get ProcessLocksList.
|
||||
process_types::RTL_CRITICAL_SECTION_DEBUG<Traits> critical_section_debug;
|
||||
if (!process_reader_.ReadMemory(current_address,
|
||||
sizeof(critical_section_debug),
|
||||
&critical_section_debug)) {
|
||||
LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION_DEBUG";
|
||||
return;
|
||||
}
|
||||
|
||||
if (critical_section_debug.ProcessLocksList.Blink == 0) {
|
||||
// At the head of the list.
|
||||
break;
|
||||
}
|
||||
|
||||
// Move to the previous RTL_CRITICAL_SECTION_DEBUG by walking
|
||||
// ProcessLocksList.Blink.
|
||||
current_address =
|
||||
critical_section_debug.ProcessLocksList.Blink -
|
||||
offsetof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>,
|
||||
ProcessLocksList);
|
||||
} while (current_address != start_address_backward &&
|
||||
current_address != kInvalid);
|
||||
|
||||
if (current_address == kInvalid) {
|
||||
// Unexpectedly encountered a bad record, so step back one.
|
||||
current_address = last_good_address;
|
||||
}
|
||||
|
||||
const WinVMAddress start_address_forward = current_address;
|
||||
|
||||
// current_address is now the head of the list, walk Flink to add the whole
|
||||
// list.
|
||||
do {
|
||||
// Read the RTL_CRITICAL_SECTION_DEBUG structure to get ProcessLocksList.
|
||||
process_types::RTL_CRITICAL_SECTION_DEBUG<Traits> critical_section_debug;
|
||||
if (!process_reader_.ReadMemory(current_address,
|
||||
sizeof(critical_section_debug),
|
||||
&critical_section_debug)) {
|
||||
LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION_DEBUG";
|
||||
return;
|
||||
}
|
||||
|
||||
// Add both RTL_CRITICAL_SECTION_DEBUG and RTL_CRITICAL_SECTION to the extra
|
||||
// memory to be saved.
|
||||
AddMemorySnapshot(current_address,
|
||||
sizeof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>),
|
||||
into);
|
||||
AddMemorySnapshot(critical_section_debug.CriticalSection,
|
||||
sizeof(process_types::RTL_CRITICAL_SECTION<Traits>),
|
||||
into);
|
||||
|
||||
if (critical_section_debug.ProcessLocksList.Flink == 0)
|
||||
break;
|
||||
|
||||
// Move to the next RTL_CRITICAL_SECTION_DEBUG by walking
|
||||
// ProcessLocksList.Flink.
|
||||
current_address =
|
||||
critical_section_debug.ProcessLocksList.Flink -
|
||||
offsetof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>,
|
||||
ProcessLocksList);
|
||||
} while (current_address != start_address_forward &&
|
||||
current_address != kInvalid);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -59,12 +59,18 @@ class ProcessSnapshotWin final : public ProcessSnapshot {
|
||||
//! \param[in] process The handle to create a snapshot from.
|
||||
//! \param[in] suspension_state Whether \a process has been suspended by the
|
||||
//! caller.
|
||||
//! \param[in] debug_critical_section_address The address in the target
|
||||
//! process's address space of a `CRITICAL_SECTION` allocated with valid
|
||||
//! `.DebugInfo`. Used as a starting point to walk the process's locks.
|
||||
//! May be `0`.
|
||||
//!
|
||||
//! \return `true` if the snapshot could be created, `false` otherwise with
|
||||
//! an appropriate message logged.
|
||||
//!
|
||||
//! \sa ScopedProcessSuspend
|
||||
bool Initialize(HANDLE process, ProcessSuspensionState suspension_state);
|
||||
bool Initialize(HANDLE process,
|
||||
ProcessSuspensionState suspension_state,
|
||||
WinVMAddress debug_critical_section_address);
|
||||
|
||||
//! \brief Initializes the object's exception.
|
||||
//!
|
||||
@ -138,9 +144,10 @@ class ProcessSnapshotWin final : public ProcessSnapshot {
|
||||
// Initializes modules_ on behalf of Initialize().
|
||||
void InitializeModules();
|
||||
|
||||
// Initializes peb_memory_ on behalf of Initialize().
|
||||
// Initializes various memory blocks reachable from the PEB on behalf of
|
||||
// Initialize().
|
||||
template <class Traits>
|
||||
void InitializePebData();
|
||||
void InitializePebData(WinVMAddress debug_critical_section_address);
|
||||
|
||||
void AddMemorySnapshot(WinVMAddress address,
|
||||
WinVMSize size,
|
||||
@ -160,8 +167,16 @@ class ProcessSnapshotWin final : public ProcessSnapshot {
|
||||
WinVMSize DetermineSizeOfEnvironmentBlock(
|
||||
WinVMAddress start_of_environment_block);
|
||||
|
||||
// Starting from the address of a CRITICAL_SECTION, walks the doubly-linked
|
||||
// list stored in RTL_CRITICAL_SECTION.DebugInfo.ProcessLocksList adding both
|
||||
// the RTL_CRITICAL_SECTION and the RTL_CRITICAL_SECTION_DEBUG memory blocks
|
||||
// to the snapshot.
|
||||
template <class Traits>
|
||||
void ReadLocks(WinVMAddress start,
|
||||
PointerVector<internal::MemorySnapshotWin>* into);
|
||||
|
||||
internal::SystemSnapshotWin system_;
|
||||
PointerVector<internal::MemorySnapshotWin> peb_memory_;
|
||||
PointerVector<internal::MemorySnapshotWin> extra_memory_;
|
||||
PointerVector<internal::ThreadSnapshotWin> threads_;
|
||||
PointerVector<internal::ModuleSnapshotWin> modules_;
|
||||
scoped_ptr<internal::ExceptionSnapshotWin> exception_;
|
||||
|
@ -52,8 +52,8 @@ void TestImageReaderChild(const base::string16& directory_modification) {
|
||||
ScopedProcessSuspend suspend(child.process_handle());
|
||||
|
||||
ProcessSnapshotWin process_snapshot;
|
||||
ASSERT_TRUE(process_snapshot.Initialize(child.process_handle(),
|
||||
ProcessSuspensionState::kSuspended));
|
||||
ASSERT_TRUE(process_snapshot.Initialize(
|
||||
child.process_handle(), ProcessSuspensionState::kSuspended, 0));
|
||||
|
||||
ASSERT_GE(process_snapshot.Modules().size(), 2u);
|
||||
|
||||
|
@ -186,7 +186,8 @@ int GenerateDumpMain(int argc, char* argv[]) {
|
||||
if (!process_snapshot.Initialize(process.get(),
|
||||
options.suspend
|
||||
? ProcessSuspensionState::kSuspended
|
||||
: ProcessSuspensionState::kRunning)) {
|
||||
: ProcessSuspensionState::kRunning,
|
||||
0)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#endif // OS_MACOSX
|
||||
|
@ -105,6 +105,7 @@ class ClientData {
|
||||
ScopedKernelHANDLE process,
|
||||
WinVMAddress crash_exception_information_address,
|
||||
WinVMAddress non_crash_exception_information_address,
|
||||
WinVMAddress debug_critical_section_address,
|
||||
WAITORTIMERCALLBACK crash_dump_request_callback,
|
||||
WAITORTIMERCALLBACK non_crash_dump_request_callback,
|
||||
WAITORTIMERCALLBACK process_end_callback)
|
||||
@ -124,7 +125,8 @@ class ClientData {
|
||||
crash_exception_information_address_(
|
||||
crash_exception_information_address),
|
||||
non_crash_exception_information_address_(
|
||||
non_crash_exception_information_address) {
|
||||
non_crash_exception_information_address),
|
||||
debug_critical_section_address_(debug_critical_section_address) {
|
||||
RegisterThreadPoolWaits(crash_dump_request_callback,
|
||||
non_crash_dump_request_callback,
|
||||
process_end_callback);
|
||||
@ -155,6 +157,9 @@ class ClientData {
|
||||
WinVMAddress non_crash_exception_information_address() const {
|
||||
return non_crash_exception_information_address_;
|
||||
}
|
||||
WinVMAddress debug_critical_section_address() const {
|
||||
return debug_critical_section_address_;
|
||||
}
|
||||
HANDLE process() const { return process_.get(); }
|
||||
|
||||
private:
|
||||
@ -219,6 +224,7 @@ class ClientData {
|
||||
ScopedKernelHANDLE process_;
|
||||
WinVMAddress crash_exception_information_address_;
|
||||
WinVMAddress non_crash_exception_information_address_;
|
||||
WinVMAddress debug_critical_section_address_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ClientData);
|
||||
};
|
||||
@ -412,6 +418,7 @@ bool ExceptionHandlerServer::ServiceClientConnection(
|
||||
ScopedKernelHANDLE(client_process),
|
||||
message.registration.crash_exception_information,
|
||||
message.registration.non_crash_exception_information,
|
||||
message.registration.critical_section_address,
|
||||
&OnCrashDumpEvent,
|
||||
&OnNonCrashDumpEvent,
|
||||
&OnProcessEnd);
|
||||
@ -465,7 +472,9 @@ void __stdcall ExceptionHandlerServer::OnCrashDumpEvent(void* ctx, BOOLEAN) {
|
||||
|
||||
// Capture the exception.
|
||||
unsigned int exit_code = client->delegate()->ExceptionHandlerServerException(
|
||||
client->process(), client->crash_exception_information_address());
|
||||
client->process(),
|
||||
client->crash_exception_information_address(),
|
||||
client->debug_critical_section_address());
|
||||
|
||||
TerminateProcess(client->process(), exit_code);
|
||||
}
|
||||
@ -478,7 +487,9 @@ void __stdcall ExceptionHandlerServer::OnNonCrashDumpEvent(void* ctx, BOOLEAN) {
|
||||
|
||||
// Capture the exception.
|
||||
client->delegate()->ExceptionHandlerServerException(
|
||||
client->process(), client->non_crash_exception_information_address());
|
||||
client->process(),
|
||||
client->non_crash_exception_information_address(),
|
||||
client->debug_critical_section_address());
|
||||
|
||||
bool result = SetEvent(client->non_crash_dump_completed_event());
|
||||
PLOG_IF(ERROR, !result) << "SetEvent";
|
||||
|
@ -49,11 +49,15 @@ class ExceptionHandlerServer {
|
||||
//! lifetime of this handle is not passed to the delegate.
|
||||
//! \param[in] exception_information_address The address in the client's
|
||||
//! address space of an ExceptionInformation structure.
|
||||
//! \param[in] debug_critical_section_address The address in the client's
|
||||
//! address space of a `CRITICAL_SECTION` allocated with a valid
|
||||
//! `.DebugInfo` field, or `0` if unavailable.
|
||||
//! \return The exit code that should be used when terminating the client
|
||||
//! process.
|
||||
virtual unsigned int ExceptionHandlerServerException(
|
||||
HANDLE process,
|
||||
WinVMAddress exception_information_address) = 0;
|
||||
WinVMAddress exception_information_address,
|
||||
WinVMAddress debug_critical_section_address) = 0;
|
||||
};
|
||||
|
||||
//! \brief Constructs the exception handling server.
|
||||
|
@ -64,7 +64,8 @@ class TestDelegate : public ExceptionHandlerServer::Delegate {
|
||||
}
|
||||
unsigned int ExceptionHandlerServerException(
|
||||
HANDLE process,
|
||||
WinVMAddress exception_information_address) override {
|
||||
WinVMAddress exception_information_address,
|
||||
WinVMAddress debug_critical_section_address) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -232,6 +232,7 @@ struct PEB {
|
||||
typename Traits::Pointer UnicodeCaseTableData;
|
||||
DWORD NumberOfProcessors;
|
||||
DWORD NtGlobalFlag;
|
||||
DWORD alignment_for_x86;
|
||||
LARGE_INTEGER CriticalSectionTimeout;
|
||||
typename Traits::UnsignedIntegral HeapSegmentReserve;
|
||||
typename Traits::UnsignedIntegral HeapSegmentCommit;
|
||||
@ -454,6 +455,35 @@ struct EXCEPTION_POINTERS {
|
||||
using EXCEPTION_POINTERS32 = EXCEPTION_POINTERS<internal::Traits32>;
|
||||
using EXCEPTION_POINTERS64 = EXCEPTION_POINTERS<internal::Traits64>;
|
||||
|
||||
// This is defined in winnt.h, but not for cross-bitness.
|
||||
template <class Traits>
|
||||
struct RTL_CRITICAL_SECTION {
|
||||
typename Traits::Pointer DebugInfo;
|
||||
LONG LockCount;
|
||||
LONG RecursionCount;
|
||||
typename Traits::Pointer OwningThread;
|
||||
typename Traits::Pointer LockSemaphore;
|
||||
typename Traits::UnsignedIntegral SpinCount;
|
||||
};
|
||||
|
||||
template <class Traits>
|
||||
struct RTL_CRITICAL_SECTION_DEBUG {
|
||||
union {
|
||||
struct {
|
||||
WORD Type;
|
||||
WORD CreatorBackTraceIndex;
|
||||
};
|
||||
typename Traits::Pad alignment_for_x64;
|
||||
};
|
||||
typename Traits::Pointer CriticalSection;
|
||||
LIST_ENTRY<Traits> ProcessLocksList;
|
||||
DWORD EntryCount;
|
||||
DWORD ContentionCount;
|
||||
DWORD Flags;
|
||||
WORD CreatorBackTraceIndexHigh;
|
||||
WORD SpareWORD;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
//! \}
|
||||
|
@ -49,15 +49,23 @@ struct RegistrationRequest {
|
||||
//! \brief The PID of the client process.
|
||||
DWORD client_process_id;
|
||||
|
||||
//! \brief The address, in the client process address space, of an
|
||||
//! \brief The address, in the client process's address space, of an
|
||||
//! ExceptionInformation structure, used when handling a crash dump
|
||||
//! request.
|
||||
WinVMAddress crash_exception_information;
|
||||
|
||||
//! \brief The address, in the client process address space, of an
|
||||
//! \brief The address, in the client process's address space, of an
|
||||
//! ExceptionInformation structure, used when handling a non-crashing dump
|
||||
//! request.
|
||||
WinVMAddress non_crash_exception_information;
|
||||
|
||||
//! \brief The address, in the client process's address space, of a
|
||||
//! `CRITICAL_SECTION` allocated with a valid .DebugInfo field. This can
|
||||
//! be accomplished by using the
|
||||
//! `RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO` flag to
|
||||
//! `InitializeCriticalSectionEx()`. This value can be `0`, however then
|
||||
//! limited lock data will be available in minidumps.
|
||||
WinVMAddress critical_section_address;
|
||||
};
|
||||
|
||||
//! \brief A message only sent to the server by itself to trigger shutdown.
|
||||
|
Loading…
x
Reference in New Issue
Block a user