| Index: snapshot/win/process_snapshot_win.cc
|
| diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc
|
| index 98e955c0e3d139e208f22c951b6d53e53f4f5445..e3f4baadaf2d0b621dc78424e65b2f6521e7a95a 100644
|
| --- a/snapshot/win/process_snapshot_win.cc
|
| +++ b/snapshot/win/process_snapshot_win.cc
|
| @@ -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
|
|
|