mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 22:26:06 +00:00
win: Only capture the loader lock for now
On Win 7 in a debug configuration, walking all locks was gathering hundreds of thousands of locks, causing test timeouts to be exceeded in debug. On user machines, UnhandledExceptionHandler() could have timed out too. For now, only grab the loader lock as it's the most interesting one. Unfortunately, this means that !locks won't work for now. In the future, we may want to figure out a signalling mechanism so that the client can note other interesting locks to be grabbed, and just avoid walking the list entirely. R=mark@chromium.org BUG=chromium:546288 Review URL: https://codereview.chromium.org/1475033005 .
This commit is contained in:
parent
866cffce8a
commit
1f3ced1846
@ -221,12 +221,14 @@ def RunTests(cdb_path,
|
||||
out.Check('LastStatusValue: \(NTSTATUS\) 0xc000000f - {File Not Found} The '
|
||||
'file %hs does not exist.', '!gle gets last ntstatus')
|
||||
|
||||
out = CdbRun(cdb_path, dump_path, '!locks')
|
||||
out.Check(r'CritSec crashy_program!crashpad::`anonymous namespace\'::'
|
||||
r'g_test_critical_section', 'lock was captured')
|
||||
if platform.win32_ver()[0] != '7':
|
||||
# We can't allocate CRITICAL_SECTIONs with .DebugInfo on Win 7.
|
||||
out.Check(r'\*\*\* Locked', 'lock debug info was captured, and is locked')
|
||||
if False:
|
||||
# TODO(scottmg): Re-enable when we grab ntdll!RtlCriticalSectionList.
|
||||
out = CdbRun(cdb_path, dump_path, '!locks')
|
||||
out.Check(r'CritSec crashy_program!crashpad::`anonymous namespace\'::'
|
||||
r'g_test_critical_section', 'lock was captured')
|
||||
if platform.win32_ver()[0] != '7':
|
||||
# We can't allocate CRITICAL_SECTIONs with .DebugInfo on Win 7.
|
||||
out.Check(r'\*\*\* Locked', 'lock debug info was captured, and is locked')
|
||||
|
||||
out = CdbRun(cdb_path, dump_path, '!handle')
|
||||
out.Check(r'\d+ Handles', 'captured handles')
|
||||
|
@ -326,15 +326,16 @@ void ProcessSnapshotWin::InitializePebData(
|
||||
DetermineSizeOfEnvironmentBlock(process_parameters.Environment),
|
||||
&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_);
|
||||
// Walk the loader lock which is directly referenced by the PEB.
|
||||
ReadLock<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_);
|
||||
// TODO(scottmg): Use debug_critical_section_address to walk the list of
|
||||
// locks (see history of this file for walking code). In some configurations
|
||||
// this can walk many thousands of locks, so we may want to get some
|
||||
// annotation from the client for which locks to grab. Unfortunately, without
|
||||
// walking the list, the !locks command in windbg won't work because it
|
||||
// requires the lock pointed to by ntdll!RtlCriticalSectionList, which we
|
||||
// won't have captured.
|
||||
}
|
||||
|
||||
void ProcessSnapshotWin::AddMemorySnapshot(
|
||||
@ -425,7 +426,7 @@ WinVMSize ProcessSnapshotWin::DetermineSizeOfEnvironmentBlock(
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void ProcessSnapshotWin::ReadLocks(
|
||||
void ProcessSnapshotWin::ReadLock(
|
||||
WinVMAddress start,
|
||||
PointerVector<internal::MemorySnapshotWin>* into) {
|
||||
// We're walking the RTL_CRITICAL_SECTION_DEBUG ProcessLocksList, but starting
|
||||
@ -439,82 +440,17 @@ void ProcessSnapshotWin::ReadLocks(
|
||||
return;
|
||||
}
|
||||
|
||||
AddMemorySnapshot(
|
||||
start, sizeof(process_types::RTL_CRITICAL_SECTION<Traits>), into);
|
||||
|
||||
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);
|
||||
AddMemorySnapshot(critical_section.DebugInfo,
|
||||
sizeof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>),
|
||||
into);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -168,13 +168,11 @@ 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.
|
||||
// Starting from the address of a CRITICAL_SECTION, add a lock and, if valid,
|
||||
// its .DebugInfo field to the snapshot.
|
||||
template <class Traits>
|
||||
void ReadLocks(WinVMAddress start,
|
||||
PointerVector<internal::MemorySnapshotWin>* into);
|
||||
void ReadLock(WinVMAddress start,
|
||||
PointerVector<internal::MemorySnapshotWin>* into);
|
||||
|
||||
internal::SystemSnapshotWin system_;
|
||||
PointerVector<internal::MemorySnapshotWin> extra_memory_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user