| 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 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 &extra_memory_); | 319 &extra_memory_); |
| 320 AddMemorySnapshotForUNICODE_STRING(process_parameters.ShellInfo, | 320 AddMemorySnapshotForUNICODE_STRING(process_parameters.ShellInfo, |
| 321 &extra_memory_); | 321 &extra_memory_); |
| 322 AddMemorySnapshotForUNICODE_STRING(process_parameters.RuntimeData, | 322 AddMemorySnapshotForUNICODE_STRING(process_parameters.RuntimeData, |
| 323 &extra_memory_); | 323 &extra_memory_); |
| 324 AddMemorySnapshot( | 324 AddMemorySnapshot( |
| 325 process_parameters.Environment, | 325 process_parameters.Environment, |
| 326 DetermineSizeOfEnvironmentBlock(process_parameters.Environment), | 326 DetermineSizeOfEnvironmentBlock(process_parameters.Environment), |
| 327 &extra_memory_); | 327 &extra_memory_); |
| 328 | 328 |
| 329 // Walk the loader lock which is directly referenced by the PEB. It may or may | 329 // Walk the loader lock which is directly referenced by the PEB. |
| 330 // not have a .DebugInfo list, but doesn't on more recent OSs (it does on | 330 ReadLock<Traits>(peb_data.LoaderLock, &extra_memory_); |
| 331 // Vista). If it does, then we may walk the lock list more than once, but | |
| 332 // AddMemorySnapshot() will take care of deduplicating the added regions. | |
| 333 ReadLocks<Traits>(peb_data.LoaderLock, &extra_memory_); | |
| 334 | 331 |
| 335 // Traverse the locks with valid .DebugInfo if a starting point was supplied. | 332 // TODO(scottmg): Use debug_critical_section_address to walk the list of |
| 336 if (debug_critical_section_address) | 333 // locks (see history of this file for walking code). In some configurations |
| 337 ReadLocks<Traits>(debug_critical_section_address, &extra_memory_); | 334 // this can walk many thousands of locks, so we may want to get some |
| 335 // annotation from the client for which locks to grab. Unfortunately, without |
| 336 // walking the list, the !locks command in windbg won't work because it |
| 337 // requires the lock pointed to by ntdll!RtlCriticalSectionList, which we |
| 338 // won't have captured. |
| 338 } | 339 } |
| 339 | 340 |
| 340 void ProcessSnapshotWin::AddMemorySnapshot( | 341 void ProcessSnapshotWin::AddMemorySnapshot( |
| 341 WinVMAddress address, | 342 WinVMAddress address, |
| 342 WinVMSize size, | 343 WinVMSize size, |
| 343 PointerVector<internal::MemorySnapshotWin>* into) { | 344 PointerVector<internal::MemorySnapshotWin>* into) { |
| 344 if (size == 0) | 345 if (size == 0) |
| 345 return; | 346 return; |
| 346 | 347 |
| 347 if (!process_reader_.GetProcessInfo().LoggingRangeIsFullyReadable( | 348 if (!process_reader_.GetProcessInfo().LoggingRangeIsFullyReadable( |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 static_cast<unsigned int>(bytes_read / sizeof(env_block[0]))); | 419 static_cast<unsigned int>(bytes_read / sizeof(env_block[0]))); |
| 419 const wchar_t terminator[] = { 0, 0 }; | 420 const wchar_t terminator[] = { 0, 0 }; |
| 420 size_t at = env_block.find(std::wstring(terminator, arraysize(terminator))); | 421 size_t at = env_block.find(std::wstring(terminator, arraysize(terminator))); |
| 421 if (at != std::wstring::npos) | 422 if (at != std::wstring::npos) |
| 422 env_block.resize(at + arraysize(terminator)); | 423 env_block.resize(at + arraysize(terminator)); |
| 423 | 424 |
| 424 return env_block.size() * sizeof(env_block[0]); | 425 return env_block.size() * sizeof(env_block[0]); |
| 425 } | 426 } |
| 426 | 427 |
| 427 template <class Traits> | 428 template <class Traits> |
| 428 void ProcessSnapshotWin::ReadLocks( | 429 void ProcessSnapshotWin::ReadLock( |
| 429 WinVMAddress start, | 430 WinVMAddress start, |
| 430 PointerVector<internal::MemorySnapshotWin>* into) { | 431 PointerVector<internal::MemorySnapshotWin>* into) { |
| 431 // We're walking the RTL_CRITICAL_SECTION_DEBUG ProcessLocksList, but starting | 432 // We're walking the RTL_CRITICAL_SECTION_DEBUG ProcessLocksList, but starting |
| 432 // from an actual RTL_CRITICAL_SECTION, so start by getting to the first | 433 // from an actual RTL_CRITICAL_SECTION, so start by getting to the first |
| 433 // RTL_CRITICAL_SECTION_DEBUG. | 434 // RTL_CRITICAL_SECTION_DEBUG. |
| 434 | 435 |
| 435 process_types::RTL_CRITICAL_SECTION<Traits> critical_section; | 436 process_types::RTL_CRITICAL_SECTION<Traits> critical_section; |
| 436 if (!process_reader_.ReadMemory( | 437 if (!process_reader_.ReadMemory( |
| 437 start, sizeof(critical_section), &critical_section)) { | 438 start, sizeof(critical_section), &critical_section)) { |
| 438 LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION"; | 439 LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION"; |
| 439 return; | 440 return; |
| 440 } | 441 } |
| 441 | 442 |
| 443 AddMemorySnapshot( |
| 444 start, sizeof(process_types::RTL_CRITICAL_SECTION<Traits>), into); |
| 445 |
| 442 const decltype(critical_section.DebugInfo) kInvalid = | 446 const decltype(critical_section.DebugInfo) kInvalid = |
| 443 static_cast<decltype(critical_section.DebugInfo)>(-1); | 447 static_cast<decltype(critical_section.DebugInfo)>(-1); |
| 444 if (critical_section.DebugInfo == kInvalid) | 448 if (critical_section.DebugInfo == kInvalid) |
| 445 return; | 449 return; |
| 446 | 450 |
| 447 const WinVMAddress start_address_backward = critical_section.DebugInfo; | 451 AddMemorySnapshot(critical_section.DebugInfo, |
| 448 WinVMAddress current_address = start_address_backward; | 452 sizeof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>), |
| 449 WinVMAddress last_good_address; | 453 into); |
| 450 | |
| 451 // Typically, this seems to be a circular list, but it's not clear that it | |
| 452 // always is, so follow Blink fields back to the head (or where we started) | |
| 453 // before following Flink to capture memory. | |
| 454 do { | |
| 455 last_good_address = current_address; | |
| 456 // Read the RTL_CRITICAL_SECTION_DEBUG structure to get ProcessLocksList. | |
| 457 process_types::RTL_CRITICAL_SECTION_DEBUG<Traits> critical_section_debug; | |
| 458 if (!process_reader_.ReadMemory(current_address, | |
| 459 sizeof(critical_section_debug), | |
| 460 &critical_section_debug)) { | |
| 461 LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION_DEBUG"; | |
| 462 return; | |
| 463 } | |
| 464 | |
| 465 if (critical_section_debug.ProcessLocksList.Blink == 0) { | |
| 466 // At the head of the list. | |
| 467 break; | |
| 468 } | |
| 469 | |
| 470 // Move to the previous RTL_CRITICAL_SECTION_DEBUG by walking | |
| 471 // ProcessLocksList.Blink. | |
| 472 current_address = | |
| 473 critical_section_debug.ProcessLocksList.Blink - | |
| 474 offsetof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>, | |
| 475 ProcessLocksList); | |
| 476 } while (current_address != start_address_backward && | |
| 477 current_address != kInvalid); | |
| 478 | |
| 479 if (current_address == kInvalid) { | |
| 480 // Unexpectedly encountered a bad record, so step back one. | |
| 481 current_address = last_good_address; | |
| 482 } | |
| 483 | |
| 484 const WinVMAddress start_address_forward = current_address; | |
| 485 | |
| 486 // current_address is now the head of the list, walk Flink to add the whole | |
| 487 // list. | |
| 488 do { | |
| 489 // Read the RTL_CRITICAL_SECTION_DEBUG structure to get ProcessLocksList. | |
| 490 process_types::RTL_CRITICAL_SECTION_DEBUG<Traits> critical_section_debug; | |
| 491 if (!process_reader_.ReadMemory(current_address, | |
| 492 sizeof(critical_section_debug), | |
| 493 &critical_section_debug)) { | |
| 494 LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION_DEBUG"; | |
| 495 return; | |
| 496 } | |
| 497 | |
| 498 // Add both RTL_CRITICAL_SECTION_DEBUG and RTL_CRITICAL_SECTION to the extra | |
| 499 // memory to be saved. | |
| 500 AddMemorySnapshot(current_address, | |
| 501 sizeof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>), | |
| 502 into); | |
| 503 AddMemorySnapshot(critical_section_debug.CriticalSection, | |
| 504 sizeof(process_types::RTL_CRITICAL_SECTION<Traits>), | |
| 505 into); | |
| 506 | |
| 507 if (critical_section_debug.ProcessLocksList.Flink == 0) | |
| 508 break; | |
| 509 | |
| 510 // Move to the next RTL_CRITICAL_SECTION_DEBUG by walking | |
| 511 // ProcessLocksList.Flink. | |
| 512 current_address = | |
| 513 critical_section_debug.ProcessLocksList.Flink - | |
| 514 offsetof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>, | |
| 515 ProcessLocksList); | |
| 516 } while (current_address != start_address_forward && | |
| 517 current_address != kInvalid); | |
| 518 } | 454 } |
| 519 | 455 |
| 520 } // namespace crashpad | 456 } // namespace crashpad |
| OLD | NEW |