crashpad/handler/win/crashy_test_program.cc
Scott Graham 4893a9b76d 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 .
2015-10-15 13:18:08 -07:00

135 lines
4.1 KiB
C++

// Copyright 2015 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <windows.h>
#include <winternl.h>
// ntstatus.h conflicts with windows.h so define this locally.
#ifndef STATUS_NO_SUCH_FILE
#define STATUS_NO_SUCH_FILE static_cast<NTSTATUS>(0xC000000F)
#endif
#include "base/basictypes.h"
#include "base/logging.h"
#include "client/crashpad_client.h"
#include "tools/tool_support.h"
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)*>(
GetProcAddress(LoadLibrary(L"ntdll.dll"), "RtlNtStatusToDosError"));
DCHECK(rtl_nt_status_to_dos_error);
return rtl_nt_status_to_dos_error(status);
}
void AllocateMemoryOfVariousProtections() {
SYSTEM_INFO system_info;
GetSystemInfo(&system_info);
const size_t kPageSize = system_info.dwPageSize;
const uint32_t kPageTypes[] = {
PAGE_NOACCESS,
PAGE_READONLY,
PAGE_READWRITE,
PAGE_EXECUTE,
PAGE_EXECUTE_READ,
PAGE_EXECUTE_READWRITE,
// PAGE_NOACCESS is invalid with PAGE_GUARD.
PAGE_READONLY | PAGE_GUARD,
PAGE_READWRITE | PAGE_GUARD,
PAGE_EXECUTE | PAGE_GUARD,
PAGE_EXECUTE_READ | PAGE_GUARD,
PAGE_EXECUTE_READWRITE | PAGE_GUARD,
};
// All of these allocations are leaked, we want to view them in windbg via
// !vprot.
void* reserve = VirtualAlloc(
nullptr, arraysize(kPageTypes) * kPageSize, MEM_RESERVE, PAGE_READWRITE);
PCHECK(reserve) << "VirtualAlloc MEM_RESERVE";
uintptr_t reserve_as_int = reinterpret_cast<uintptr_t>(reserve);
for (size_t i = 0; i < arraysize(kPageTypes); ++i) {
void* result =
VirtualAlloc(reinterpret_cast<void*>(reserve_as_int + (kPageSize * i)),
kPageSize,
MEM_COMMIT,
kPageTypes[i]);
PCHECK(result) << "VirtualAlloc MEM_COMMIT " << i;
}
}
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
// LastStatusError of the TEB as a side-effect, and we'll be setting
// ERROR_FILE_NOT_FOUND for GetLastError().
SetLastError(RtlNtStatusToDosError(STATUS_NO_SUCH_FILE));
volatile int* foo = reinterpret_cast<volatile int*>(7);
*foo = 42;
}
int CrashyMain(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <server_pipe_name>\n", argv[0]);
return 1;
}
CrashpadClient client;
if (!client.SetHandler(argv[1])) {
LOG(ERROR) << "SetHandler";
return 1;
}
if (!client.UseHandler()) {
LOG(ERROR) << "UseHandler";
return 1;
}
AllocateMemoryOfVariousProtections();
CrashpadInitializeCriticalSectionEx(
&g_test_critical_section, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
EnterCriticalSection(&g_test_critical_section);
SomeCrashyFunction();
return 0;
}
} // namespace
} // namespace crashpad
int wmain(int argc, wchar_t* argv[]) {
return crashpad::ToolSupport::Wmain(argc, argv, crashpad::CrashyMain);
}