| Index: client/crashpad_client_win.cc
|
| diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc
|
| index 195916004198e2a517ff7b8fe30aa4f244552da9..7a1e547a4c8bfdbda64af09d36aee477e0b777ac 100644
|
| --- a/client/crashpad_client_win.cc
|
| +++ b/client/crashpad_client_win.cc
|
| @@ -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(
|
|
|