| OLD | NEW |
| 1 // Copyright 2015 The Crashpad Authors. All rights reserved. | 1 // Copyright 2015 The Crashpad Authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 report_id_(), | 36 report_id_(), |
| 37 client_id_(), | 37 client_id_(), |
| 38 annotations_simple_map_(), | 38 annotations_simple_map_(), |
| 39 snapshot_time_(), | 39 snapshot_time_(), |
| 40 initialized_() { | 40 initialized_() { |
| 41 } | 41 } |
| 42 | 42 |
| 43 ProcessSnapshotWin::~ProcessSnapshotWin() { | 43 ProcessSnapshotWin::~ProcessSnapshotWin() { |
| 44 } | 44 } |
| 45 | 45 |
| 46 bool ProcessSnapshotWin::Initialize(HANDLE process, | 46 bool ProcessSnapshotWin::Initialize( |
| 47 ProcessSuspensionState suspension_state) { | 47 HANDLE process, |
| 48 ProcessSuspensionState suspension_state, |
| 49 WinVMAddress debug_critical_section_address) { |
| 48 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | 50 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
| 49 | 51 |
| 50 GetTimeOfDay(&snapshot_time_); | 52 GetTimeOfDay(&snapshot_time_); |
| 51 | 53 |
| 52 if (!process_reader_.Initialize(process, suspension_state)) | 54 if (!process_reader_.Initialize(process, suspension_state)) |
| 53 return false; | 55 return false; |
| 54 | 56 |
| 55 system_.Initialize(&process_reader_); | 57 system_.Initialize(&process_reader_); |
| 56 | 58 |
| 57 if (process_reader_.Is64Bit()) | 59 if (process_reader_.Is64Bit()) { |
| 58 InitializePebData<process_types::internal::Traits64>(); | 60 InitializePebData<process_types::internal::Traits64>( |
| 59 else | 61 debug_critical_section_address); |
| 60 InitializePebData<process_types::internal::Traits32>(); | 62 } else { |
| 63 InitializePebData<process_types::internal::Traits32>( |
| 64 debug_critical_section_address); |
| 65 } |
| 61 | 66 |
| 62 InitializeThreads(); | 67 InitializeThreads(); |
| 63 InitializeModules(); | 68 InitializeModules(); |
| 64 | 69 |
| 65 for (const MEMORY_BASIC_INFORMATION64& mbi : | 70 for (const MEMORY_BASIC_INFORMATION64& mbi : |
| 66 process_reader_.GetProcessInfo().MemoryInfo()) { | 71 process_reader_.GetProcessInfo().MemoryInfo()) { |
| 67 memory_map_.push_back(new internal::MemoryMapRegionSnapshotWin(mbi)); | 72 memory_map_.push_back(new internal::MemoryMapRegionSnapshotWin(mbi)); |
| 68 } | 73 } |
| 69 | 74 |
| 70 INITIALIZATION_STATE_SET_VALID(initialized_); | 75 INITIALIZATION_STATE_SET_VALID(initialized_); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 const { | 203 const { |
| 199 std::vector<const MemoryMapRegionSnapshot*> memory_map; | 204 std::vector<const MemoryMapRegionSnapshot*> memory_map; |
| 200 for (const auto& item : memory_map_) | 205 for (const auto& item : memory_map_) |
| 201 memory_map.push_back(item); | 206 memory_map.push_back(item); |
| 202 return memory_map; | 207 return memory_map; |
| 203 } | 208 } |
| 204 | 209 |
| 205 std::vector<const MemorySnapshot*> ProcessSnapshotWin::ExtraMemory() const { | 210 std::vector<const MemorySnapshot*> ProcessSnapshotWin::ExtraMemory() const { |
| 206 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 211 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 207 std::vector<const MemorySnapshot*> extra_memory; | 212 std::vector<const MemorySnapshot*> extra_memory; |
| 208 for (const auto& peb_memory : peb_memory_) | 213 for (const auto& em : extra_memory_) |
| 209 extra_memory.push_back(peb_memory); | 214 extra_memory.push_back(em); |
| 210 return extra_memory; | 215 return extra_memory; |
| 211 } | 216 } |
| 212 | 217 |
| 213 void ProcessSnapshotWin::InitializeThreads() { | 218 void ProcessSnapshotWin::InitializeThreads() { |
| 214 const std::vector<ProcessReaderWin::Thread>& process_reader_threads = | 219 const std::vector<ProcessReaderWin::Thread>& process_reader_threads = |
| 215 process_reader_.Threads(); | 220 process_reader_.Threads(); |
| 216 for (const ProcessReaderWin::Thread& process_reader_thread : | 221 for (const ProcessReaderWin::Thread& process_reader_thread : |
| 217 process_reader_threads) { | 222 process_reader_threads) { |
| 218 auto thread = make_scoped_ptr(new internal::ThreadSnapshotWin()); | 223 auto thread = make_scoped_ptr(new internal::ThreadSnapshotWin()); |
| 219 if (thread->Initialize(&process_reader_, process_reader_thread)) { | 224 if (thread->Initialize(&process_reader_, process_reader_thread)) { |
| 220 threads_.push_back(thread.release()); | 225 threads_.push_back(thread.release()); |
| 221 } | 226 } |
| 222 } | 227 } |
| 223 } | 228 } |
| 224 | 229 |
| 225 void ProcessSnapshotWin::InitializeModules() { | 230 void ProcessSnapshotWin::InitializeModules() { |
| 226 const std::vector<ProcessInfo::Module>& process_reader_modules = | 231 const std::vector<ProcessInfo::Module>& process_reader_modules = |
| 227 process_reader_.Modules(); | 232 process_reader_.Modules(); |
| 228 for (const ProcessInfo::Module& process_reader_module : | 233 for (const ProcessInfo::Module& process_reader_module : |
| 229 process_reader_modules) { | 234 process_reader_modules) { |
| 230 auto module = make_scoped_ptr(new internal::ModuleSnapshotWin()); | 235 auto module = make_scoped_ptr(new internal::ModuleSnapshotWin()); |
| 231 if (module->Initialize(&process_reader_, process_reader_module)) { | 236 if (module->Initialize(&process_reader_, process_reader_module)) { |
| 232 modules_.push_back(module.release()); | 237 modules_.push_back(module.release()); |
| 233 } | 238 } |
| 234 } | 239 } |
| 235 } | 240 } |
| 236 | 241 |
| 237 template <class Traits> | 242 template <class Traits> |
| 238 void ProcessSnapshotWin::InitializePebData() { | 243 void ProcessSnapshotWin::InitializePebData( |
| 244 WinVMAddress debug_critical_section_address) { |
| 239 WinVMAddress peb_address; | 245 WinVMAddress peb_address; |
| 240 WinVMSize peb_size; | 246 WinVMSize peb_size; |
| 241 process_reader_.GetProcessInfo().Peb(&peb_address, &peb_size); | 247 process_reader_.GetProcessInfo().Peb(&peb_address, &peb_size); |
| 242 AddMemorySnapshot(peb_address, peb_size, &peb_memory_); | 248 AddMemorySnapshot(peb_address, peb_size, &extra_memory_); |
| 243 | 249 |
| 244 process_types::PEB<Traits> peb_data; | 250 process_types::PEB<Traits> peb_data; |
| 245 if (!process_reader_.ReadMemory(peb_address, peb_size, &peb_data)) { | 251 if (!process_reader_.ReadMemory(peb_address, peb_size, &peb_data)) { |
| 246 LOG(ERROR) << "ReadMemory PEB"; | 252 LOG(ERROR) << "ReadMemory PEB"; |
| 247 return; | 253 return; |
| 248 } | 254 } |
| 249 | 255 |
| 250 process_types::PEB_LDR_DATA<Traits> peb_ldr_data; | 256 process_types::PEB_LDR_DATA<Traits> peb_ldr_data; |
| 251 AddMemorySnapshot(peb_data.Ldr, sizeof(peb_ldr_data), &peb_memory_); | 257 AddMemorySnapshot(peb_data.Ldr, sizeof(peb_ldr_data), &extra_memory_); |
| 252 if (!process_reader_.ReadMemory( | 258 if (!process_reader_.ReadMemory( |
| 253 peb_data.Ldr, sizeof(peb_ldr_data), &peb_ldr_data)) { | 259 peb_data.Ldr, sizeof(peb_ldr_data), &peb_ldr_data)) { |
| 254 LOG(ERROR) << "ReadMemory PEB_LDR_DATA"; | 260 LOG(ERROR) << "ReadMemory PEB_LDR_DATA"; |
| 255 } else { | 261 } else { |
| 256 // Walk the LDR structure to retrieve its pointed-to data. | 262 // Walk the LDR structure to retrieve its pointed-to data. |
| 257 AddMemorySnapshotForLdrLIST_ENTRY( | 263 AddMemorySnapshotForLdrLIST_ENTRY( |
| 258 peb_ldr_data.InLoadOrderModuleList, | 264 peb_ldr_data.InLoadOrderModuleList, |
| 259 offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, InLoadOrderLinks), | 265 offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, InLoadOrderLinks), |
| 260 &peb_memory_); | 266 &extra_memory_); |
| 261 AddMemorySnapshotForLdrLIST_ENTRY( | 267 AddMemorySnapshotForLdrLIST_ENTRY( |
| 262 peb_ldr_data.InMemoryOrderModuleList, | 268 peb_ldr_data.InMemoryOrderModuleList, |
| 263 offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, | 269 offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, |
| 264 InMemoryOrderLinks), | 270 InMemoryOrderLinks), |
| 265 &peb_memory_); | 271 &extra_memory_); |
| 266 AddMemorySnapshotForLdrLIST_ENTRY( | 272 AddMemorySnapshotForLdrLIST_ENTRY( |
| 267 peb_ldr_data.InInitializationOrderModuleList, | 273 peb_ldr_data.InInitializationOrderModuleList, |
| 268 offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, | 274 offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, |
| 269 InInitializationOrderLinks), | 275 InInitializationOrderLinks), |
| 270 &peb_memory_); | 276 &extra_memory_); |
| 271 } | 277 } |
| 272 | 278 |
| 273 process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters; | 279 process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters; |
| 274 if (!process_reader_.ReadMemory(peb_data.ProcessParameters, | 280 if (!process_reader_.ReadMemory(peb_data.ProcessParameters, |
| 275 sizeof(process_parameters), | 281 sizeof(process_parameters), |
| 276 &process_parameters)) { | 282 &process_parameters)) { |
| 277 LOG(ERROR) << "ReadMemory RTL_USER_PROCESS_PARAMETERS"; | 283 LOG(ERROR) << "ReadMemory RTL_USER_PROCESS_PARAMETERS"; |
| 278 return; | 284 return; |
| 279 } | 285 } |
| 280 AddMemorySnapshot( | 286 AddMemorySnapshot( |
| 281 peb_data.ProcessParameters, sizeof(process_parameters), &peb_memory_); | 287 peb_data.ProcessParameters, sizeof(process_parameters), &extra_memory_); |
| 282 | 288 |
| 283 AddMemorySnapshotForUNICODE_STRING( | 289 AddMemorySnapshotForUNICODE_STRING( |
| 284 process_parameters.CurrentDirectory.DosPath, &peb_memory_); | 290 process_parameters.CurrentDirectory.DosPath, &extra_memory_); |
| 285 AddMemorySnapshotForUNICODE_STRING(process_parameters.DllPath, &peb_memory_); | 291 AddMemorySnapshotForUNICODE_STRING(process_parameters.DllPath, |
| 292 &extra_memory_); |
| 286 AddMemorySnapshotForUNICODE_STRING(process_parameters.ImagePathName, | 293 AddMemorySnapshotForUNICODE_STRING(process_parameters.ImagePathName, |
| 287 &peb_memory_); | 294 &extra_memory_); |
| 288 AddMemorySnapshotForUNICODE_STRING(process_parameters.CommandLine, | 295 AddMemorySnapshotForUNICODE_STRING(process_parameters.CommandLine, |
| 289 &peb_memory_); | 296 &extra_memory_); |
| 290 AddMemorySnapshotForUNICODE_STRING(process_parameters.WindowTitle, | 297 AddMemorySnapshotForUNICODE_STRING(process_parameters.WindowTitle, |
| 291 &peb_memory_); | 298 &extra_memory_); |
| 292 AddMemorySnapshotForUNICODE_STRING(process_parameters.DesktopInfo, | 299 AddMemorySnapshotForUNICODE_STRING(process_parameters.DesktopInfo, |
| 293 &peb_memory_); | 300 &extra_memory_); |
| 294 AddMemorySnapshotForUNICODE_STRING(process_parameters.ShellInfo, | 301 AddMemorySnapshotForUNICODE_STRING(process_parameters.ShellInfo, |
| 295 &peb_memory_); | 302 &extra_memory_); |
| 296 AddMemorySnapshotForUNICODE_STRING(process_parameters.RuntimeData, | 303 AddMemorySnapshotForUNICODE_STRING(process_parameters.RuntimeData, |
| 297 &peb_memory_); | 304 &extra_memory_); |
| 298 AddMemorySnapshot( | 305 AddMemorySnapshot( |
| 299 process_parameters.Environment, | 306 process_parameters.Environment, |
| 300 DetermineSizeOfEnvironmentBlock(process_parameters.Environment), | 307 DetermineSizeOfEnvironmentBlock(process_parameters.Environment), |
| 301 &peb_memory_); | 308 &extra_memory_); |
| 309 |
| 310 // Walk the loader lock which is directly referenced by the PEB. It may or may |
| 311 // not have a .DebugInfo list, but doesn't on more recent OSs (it does on |
| 312 // Vista). If it does, then we may walk the lock list more than once, but |
| 313 // AddMemorySnapshot() will take care of deduplicating the added regions. |
| 314 ReadLocks<Traits>(peb_data.LoaderLock, &extra_memory_); |
| 315 |
| 316 // Traverse the locks with valid .DebugInfo if a starting point was supplied. |
| 317 if (debug_critical_section_address) |
| 318 ReadLocks<Traits>(debug_critical_section_address, &extra_memory_); |
| 302 } | 319 } |
| 303 | 320 |
| 304 void ProcessSnapshotWin::AddMemorySnapshot( | 321 void ProcessSnapshotWin::AddMemorySnapshot( |
| 305 WinVMAddress address, | 322 WinVMAddress address, |
| 306 WinVMSize size, | 323 WinVMSize size, |
| 307 PointerVector<internal::MemorySnapshotWin>* into) { | 324 PointerVector<internal::MemorySnapshotWin>* into) { |
| 308 if (size == 0) | 325 if (size == 0) |
| 309 return; | 326 return; |
| 310 | 327 |
| 311 // Ensure that the entire range is readable. TODO(scottmg): Consider | 328 // Ensure that the entire range is readable. TODO(scottmg): Consider |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 env_block.resize( | 409 env_block.resize( |
| 393 static_cast<unsigned int>(bytes_read / sizeof(env_block[0]))); | 410 static_cast<unsigned int>(bytes_read / sizeof(env_block[0]))); |
| 394 const wchar_t terminator[] = { 0, 0 }; | 411 const wchar_t terminator[] = { 0, 0 }; |
| 395 size_t at = env_block.find(std::wstring(terminator, arraysize(terminator))); | 412 size_t at = env_block.find(std::wstring(terminator, arraysize(terminator))); |
| 396 if (at != std::wstring::npos) | 413 if (at != std::wstring::npos) |
| 397 env_block.resize(at + arraysize(terminator)); | 414 env_block.resize(at + arraysize(terminator)); |
| 398 | 415 |
| 399 return env_block.size() * sizeof(env_block[0]); | 416 return env_block.size() * sizeof(env_block[0]); |
| 400 } | 417 } |
| 401 | 418 |
| 419 template <class Traits> |
| 420 void ProcessSnapshotWin::ReadLocks( |
| 421 WinVMAddress start, |
| 422 PointerVector<internal::MemorySnapshotWin>* into) { |
| 423 // We're walking the RTL_CRITICAL_SECTION_DEBUG ProcessLocksList, but starting |
| 424 // from an actual RTL_CRITICAL_SECTION, so start by getting to the first |
| 425 // RTL_CRITICAL_SECTION_DEBUG. |
| 426 |
| 427 process_types::RTL_CRITICAL_SECTION<Traits> critical_section; |
| 428 if (!process_reader_.ReadMemory( |
| 429 start, sizeof(critical_section), &critical_section)) { |
| 430 LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION"; |
| 431 return; |
| 432 } |
| 433 |
| 434 const decltype(critical_section.DebugInfo) kInvalid = |
| 435 static_cast<decltype(critical_section.DebugInfo)>(-1); |
| 436 if (critical_section.DebugInfo == kInvalid) |
| 437 return; |
| 438 |
| 439 const WinVMAddress start_address_backward = critical_section.DebugInfo; |
| 440 WinVMAddress current_address = start_address_backward; |
| 441 WinVMAddress last_good_address; |
| 442 |
| 443 // Typically, this seems to be a circular list, but it's not clear that it |
| 444 // always is, so follow Blink fields back to the head (or where we started) |
| 445 // before following Flink to capture memory. |
| 446 do { |
| 447 last_good_address = current_address; |
| 448 // Read the RTL_CRITICAL_SECTION_DEBUG structure to get ProcessLocksList. |
| 449 process_types::RTL_CRITICAL_SECTION_DEBUG<Traits> critical_section_debug; |
| 450 if (!process_reader_.ReadMemory(current_address, |
| 451 sizeof(critical_section_debug), |
| 452 &critical_section_debug)) { |
| 453 LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION_DEBUG"; |
| 454 return; |
| 455 } |
| 456 |
| 457 if (critical_section_debug.ProcessLocksList.Blink == 0) { |
| 458 // At the head of the list. |
| 459 break; |
| 460 } |
| 461 |
| 462 // Move to the previous RTL_CRITICAL_SECTION_DEBUG by walking |
| 463 // ProcessLocksList.Blink. |
| 464 current_address = |
| 465 critical_section_debug.ProcessLocksList.Blink - |
| 466 offsetof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>, |
| 467 ProcessLocksList); |
| 468 } while (current_address != start_address_backward && |
| 469 current_address != kInvalid); |
| 470 |
| 471 if (current_address == kInvalid) { |
| 472 // Unexpectedly encountered a bad record, so step back one. |
| 473 current_address = last_good_address; |
| 474 } |
| 475 |
| 476 const WinVMAddress start_address_forward = current_address; |
| 477 |
| 478 // current_address is now the head of the list, walk Flink to add the whole |
| 479 // list. |
| 480 do { |
| 481 // Read the RTL_CRITICAL_SECTION_DEBUG structure to get ProcessLocksList. |
| 482 process_types::RTL_CRITICAL_SECTION_DEBUG<Traits> critical_section_debug; |
| 483 if (!process_reader_.ReadMemory(current_address, |
| 484 sizeof(critical_section_debug), |
| 485 &critical_section_debug)) { |
| 486 LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION_DEBUG"; |
| 487 return; |
| 488 } |
| 489 |
| 490 // Add both RTL_CRITICAL_SECTION_DEBUG and RTL_CRITICAL_SECTION to the extra |
| 491 // memory to be saved. |
| 492 AddMemorySnapshot(current_address, |
| 493 sizeof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>), |
| 494 into); |
| 495 AddMemorySnapshot(critical_section_debug.CriticalSection, |
| 496 sizeof(process_types::RTL_CRITICAL_SECTION<Traits>), |
| 497 into); |
| 498 |
| 499 if (critical_section_debug.ProcessLocksList.Flink == 0) |
| 500 break; |
| 501 |
| 502 // Move to the next RTL_CRITICAL_SECTION_DEBUG by walking |
| 503 // ProcessLocksList.Flink. |
| 504 current_address = |
| 505 critical_section_debug.ProcessLocksList.Flink - |
| 506 offsetof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>, |
| 507 ProcessLocksList); |
| 508 } while (current_address != start_address_forward && |
| 509 current_address != kInvalid); |
| 510 } |
| 511 |
| 402 } // namespace crashpad | 512 } // namespace crashpad |
| OLD | NEW |