Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(705)

Unified Diff: third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.cc

Issue 1505213004: Copy Crashpad into the Chrome tree instead of importing it via DEPS (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address review comments, update README.chromium Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.cc
diff --git a/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.cc b/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8c184c26b9ab502b49048c32d93a21a8a4b737bc
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.cc
@@ -0,0 +1,456 @@
+// 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 "snapshot/win/process_snapshot_win.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "snapshot/win/memory_snapshot_win.h"
+#include "snapshot/win/module_snapshot_win.h"
+#include "util/win/registration_protocol_win.h"
+#include "util/win/time.h"
+
+namespace crashpad {
+
+ProcessSnapshotWin::ProcessSnapshotWin()
+ : ProcessSnapshot(),
+ system_(),
+ threads_(),
+ modules_(),
+ exception_(),
+ memory_map_(),
+ process_reader_(),
+ report_id_(),
+ client_id_(),
+ annotations_simple_map_(),
+ snapshot_time_(),
+ initialized_() {
+}
+
+ProcessSnapshotWin::~ProcessSnapshotWin() {
+}
+
+bool ProcessSnapshotWin::Initialize(
+ HANDLE process,
+ ProcessSuspensionState suspension_state,
+ WinVMAddress debug_critical_section_address) {
+ INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
+
+ GetTimeOfDay(&snapshot_time_);
+
+ if (!process_reader_.Initialize(process, suspension_state))
+ return false;
+
+ system_.Initialize(&process_reader_);
+
+ 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();
+
+ for (const MEMORY_BASIC_INFORMATION64& mbi :
+ process_reader_.GetProcessInfo().MemoryInfo()) {
+ memory_map_.push_back(new internal::MemoryMapRegionSnapshotWin(mbi));
+ }
+
+ INITIALIZATION_STATE_SET_VALID(initialized_);
+ return true;
+}
+
+bool ProcessSnapshotWin::InitializeException(
+ WinVMAddress exception_information_address) {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ DCHECK(!exception_);
+
+ ExceptionInformation exception_information;
+ if (!process_reader_.ReadMemory(exception_information_address,
+ sizeof(exception_information),
+ &exception_information)) {
+ LOG(WARNING) << "ReadMemory ExceptionInformation failed";
+ return false;
+ }
+
+ exception_.reset(new internal::ExceptionSnapshotWin());
+ if (!exception_->Initialize(&process_reader_,
+ exception_information.thread_id,
+ exception_information.exception_pointers)) {
+ exception_.reset();
+ return false;
+ }
+
+ return true;
+}
+
+void ProcessSnapshotWin::GetCrashpadOptions(
+ CrashpadInfoClientOptions* options) {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
+ CrashpadInfoClientOptions local_options;
+
+ for (internal::ModuleSnapshotWin* module : modules_) {
+ CrashpadInfoClientOptions module_options;
+ module->GetCrashpadOptions(&module_options);
+
+ if (local_options.crashpad_handler_behavior == TriState::kUnset) {
+ local_options.crashpad_handler_behavior =
+ module_options.crashpad_handler_behavior;
+ }
+ if (local_options.system_crash_reporter_forwarding == TriState::kUnset) {
+ local_options.system_crash_reporter_forwarding =
+ module_options.system_crash_reporter_forwarding;
+ }
+
+ // If non-default values have been found for all options, the loop can end
+ // early.
+ if (local_options.crashpad_handler_behavior != TriState::kUnset &&
+ local_options.system_crash_reporter_forwarding != TriState::kUnset) {
+ break;
+ }
+ }
+
+ *options = local_options;
+}
+
+pid_t ProcessSnapshotWin::ProcessID() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return process_reader_.GetProcessInfo().ProcessID();
+}
+
+pid_t ProcessSnapshotWin::ParentProcessID() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return process_reader_.GetProcessInfo().ParentProcessID();
+}
+
+void ProcessSnapshotWin::SnapshotTime(timeval* snapshot_time) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ *snapshot_time = snapshot_time_;
+}
+
+void ProcessSnapshotWin::ProcessStartTime(timeval* start_time) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ process_reader_.StartTime(start_time);
+}
+
+void ProcessSnapshotWin::ProcessCPUTimes(timeval* user_time,
+ timeval* system_time) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ process_reader_.CPUTimes(user_time, system_time);
+}
+
+void ProcessSnapshotWin::ReportID(UUID* report_id) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ *report_id = report_id_;
+}
+
+void ProcessSnapshotWin::ClientID(UUID* client_id) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ *client_id = client_id_;
+}
+
+const std::map<std::string, std::string>&
+ProcessSnapshotWin::AnnotationsSimpleMap() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return annotations_simple_map_;
+}
+
+const SystemSnapshot* ProcessSnapshotWin::System() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return &system_;
+}
+
+std::vector<const ThreadSnapshot*> ProcessSnapshotWin::Threads() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ std::vector<const ThreadSnapshot*> threads;
+ for (internal::ThreadSnapshotWin* thread : threads_) {
+ threads.push_back(thread);
+ }
+ return threads;
+}
+
+std::vector<const ModuleSnapshot*> ProcessSnapshotWin::Modules() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ std::vector<const ModuleSnapshot*> modules;
+ for (internal::ModuleSnapshotWin* module : modules_) {
+ modules.push_back(module);
+ }
+ return modules;
+}
+
+const ExceptionSnapshot* ProcessSnapshotWin::Exception() const {
+ return exception_.get();
+}
+
+std::vector<const MemoryMapRegionSnapshot*> ProcessSnapshotWin::MemoryMap()
+ const {
+ std::vector<const MemoryMapRegionSnapshot*> memory_map;
+ for (const auto& item : memory_map_)
+ memory_map.push_back(item);
+ return memory_map;
+}
+
+std::vector<HandleSnapshot> ProcessSnapshotWin::Handles() const {
+ std::vector<HandleSnapshot> result;
+ for (const auto& handle : process_reader_.GetProcessInfo().Handles()) {
+ HandleSnapshot snapshot;
+ // This is probably not strictly correct, but these are not localized so we
+ // expect them all to be in ASCII range anyway. This will need to be more
+ // carefully done if the object name is added.
+ snapshot.type_name = base::UTF16ToUTF8(handle.type_name);
+ snapshot.handle = handle.handle;
+ snapshot.attributes = handle.attributes;
+ snapshot.granted_access = handle.granted_access;
+ snapshot.pointer_count = handle.pointer_count;
+ snapshot.handle_count = handle.handle_count;
+ result.push_back(snapshot);
+ }
+ return result;
+}
+
+std::vector<const MemorySnapshot*> ProcessSnapshotWin::ExtraMemory() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ std::vector<const MemorySnapshot*> extra_memory;
+ for (const auto& em : extra_memory_)
+ extra_memory.push_back(em);
+ return extra_memory;
+}
+
+void ProcessSnapshotWin::InitializeThreads() {
+ const std::vector<ProcessReaderWin::Thread>& process_reader_threads =
+ process_reader_.Threads();
+ for (const ProcessReaderWin::Thread& process_reader_thread :
+ process_reader_threads) {
+ auto thread = make_scoped_ptr(new internal::ThreadSnapshotWin());
+ if (thread->Initialize(&process_reader_, process_reader_thread)) {
+ threads_.push_back(thread.release());
+ }
+ }
+}
+
+void ProcessSnapshotWin::InitializeModules() {
+ const std::vector<ProcessInfo::Module>& process_reader_modules =
+ process_reader_.Modules();
+ for (const ProcessInfo::Module& process_reader_module :
+ process_reader_modules) {
+ auto module = make_scoped_ptr(new internal::ModuleSnapshotWin());
+ if (module->Initialize(&process_reader_, process_reader_module)) {
+ modules_.push_back(module.release());
+ }
+ }
+}
+
+template <class Traits>
+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, &extra_memory_);
+
+ process_types::PEB<Traits> peb_data;
+ if (!process_reader_.ReadMemory(peb_address, peb_size, &peb_data)) {
+ LOG(ERROR) << "ReadMemory PEB";
+ return;
+ }
+
+ process_types::PEB_LDR_DATA<Traits> peb_ldr_data;
+ 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";
+ } else {
+ // Walk the LDR structure to retrieve its pointed-to data.
+ AddMemorySnapshotForLdrLIST_ENTRY(
+ peb_ldr_data.InLoadOrderModuleList,
+ offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, InLoadOrderLinks),
+ &extra_memory_);
+ AddMemorySnapshotForLdrLIST_ENTRY(
+ peb_ldr_data.InMemoryOrderModuleList,
+ offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>,
+ InMemoryOrderLinks),
+ &extra_memory_);
+ AddMemorySnapshotForLdrLIST_ENTRY(
+ peb_ldr_data.InInitializationOrderModuleList,
+ offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>,
+ InInitializationOrderLinks),
+ &extra_memory_);
+ }
+
+ process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters;
+ if (!process_reader_.ReadMemory(peb_data.ProcessParameters,
+ sizeof(process_parameters),
+ &process_parameters)) {
+ LOG(ERROR) << "ReadMemory RTL_USER_PROCESS_PARAMETERS";
+ return;
+ }
+ AddMemorySnapshot(
+ peb_data.ProcessParameters, sizeof(process_parameters), &extra_memory_);
+
+ AddMemorySnapshotForUNICODE_STRING(
+ process_parameters.CurrentDirectory.DosPath, &extra_memory_);
+ AddMemorySnapshotForUNICODE_STRING(process_parameters.DllPath,
+ &extra_memory_);
+ AddMemorySnapshotForUNICODE_STRING(process_parameters.ImagePathName,
+ &extra_memory_);
+ AddMemorySnapshotForUNICODE_STRING(process_parameters.CommandLine,
+ &extra_memory_);
+ AddMemorySnapshotForUNICODE_STRING(process_parameters.WindowTitle,
+ &extra_memory_);
+ AddMemorySnapshotForUNICODE_STRING(process_parameters.DesktopInfo,
+ &extra_memory_);
+ AddMemorySnapshotForUNICODE_STRING(process_parameters.ShellInfo,
+ &extra_memory_);
+ AddMemorySnapshotForUNICODE_STRING(process_parameters.RuntimeData,
+ &extra_memory_);
+ AddMemorySnapshot(
+ process_parameters.Environment,
+ DetermineSizeOfEnvironmentBlock(process_parameters.Environment),
+ &extra_memory_);
+
+ // Walk the loader lock which is directly referenced by the PEB.
+ ReadLock<Traits>(peb_data.LoaderLock, &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(
+ WinVMAddress address,
+ WinVMSize size,
+ PointerVector<internal::MemorySnapshotWin>* into) {
+ if (size == 0)
+ return;
+
+ if (!process_reader_.GetProcessInfo().LoggingRangeIsFullyReadable(
+ CheckedRange<WinVMAddress, WinVMSize>(address, size))) {
+ return;
+ }
+
+ // If we have already added this exact range, don't add it again. This is
+ // useful for the LDR module lists which are a set of doubly-linked lists, all
+ // pointing to the same module name strings.
+ // TODO(scottmg): A more general version of this, handling overlapping,
+ // contained, etc. https://crashpad.chromium.org/bug/61.
+ for (const auto& memory_snapshot : *into) {
+ if (memory_snapshot->Address() == address &&
+ memory_snapshot->Size() == size) {
+ return;
+ }
+ }
+
+ internal::MemorySnapshotWin* memory_snapshot =
+ new internal::MemorySnapshotWin();
+ memory_snapshot->Initialize(&process_reader_, address, size);
+ into->push_back(memory_snapshot);
+}
+
+template <class Traits>
+void ProcessSnapshotWin::AddMemorySnapshotForUNICODE_STRING(
+ const process_types::UNICODE_STRING<Traits>& us,
+ PointerVector<internal::MemorySnapshotWin>* into) {
+ AddMemorySnapshot(us.Buffer, us.Length, into);
+}
+
+template <class Traits>
+void ProcessSnapshotWin::AddMemorySnapshotForLdrLIST_ENTRY(
+ const process_types::LIST_ENTRY<Traits>& le, size_t offset_of_member,
+ PointerVector<internal::MemorySnapshotWin>* into) {
+ // Walk the doubly-linked list of entries, adding the list memory itself, as
+ // well as pointed-to strings.
+ typename Traits::Pointer last = le.Blink;
+ process_types::LDR_DATA_TABLE_ENTRY<Traits> entry;
+ typename Traits::Pointer cur = le.Flink;
+ for (;;) {
+ // |cur| is the pointer to LIST_ENTRY embedded in the LDR_DATA_TABLE_ENTRY.
+ // So we need to offset back to the beginning of the structure.
+ if (!process_reader_.ReadMemory(
+ cur - offset_of_member, sizeof(entry), &entry)) {
+ return;
+ }
+ AddMemorySnapshot(cur - offset_of_member, sizeof(entry), into);
+ AddMemorySnapshotForUNICODE_STRING(entry.FullDllName, into);
+ AddMemorySnapshotForUNICODE_STRING(entry.BaseDllName, into);
+
+ process_types::LIST_ENTRY<Traits>* links =
+ reinterpret_cast<process_types::LIST_ENTRY<Traits>*>(
+ reinterpret_cast<unsigned char*>(&entry) + offset_of_member);
+ cur = links->Flink;
+ if (cur == last)
+ break;
+ }
+}
+
+WinVMSize ProcessSnapshotWin::DetermineSizeOfEnvironmentBlock(
+ WinVMAddress start_of_environment_block) {
+ // http://blogs.msdn.com/b/oldnewthing/archive/2010/02/03/9957320.aspx On
+ // newer OSs there's no stated limit, but in practice grabbing 32k characters
+ // should be more than enough.
+ std::wstring env_block;
+ env_block.resize(32768);
+ WinVMSize bytes_read = process_reader_.ReadAvailableMemory(
+ start_of_environment_block,
+ env_block.size() * sizeof(env_block[0]),
+ &env_block[0]);
+ env_block.resize(
+ static_cast<unsigned int>(bytes_read / sizeof(env_block[0])));
+ const wchar_t terminator[] = { 0, 0 };
+ size_t at = env_block.find(std::wstring(terminator, arraysize(terminator)));
+ if (at != std::wstring::npos)
+ env_block.resize(at + arraysize(terminator));
+
+ return env_block.size() * sizeof(env_block[0]);
+}
+
+template <class Traits>
+void ProcessSnapshotWin::ReadLock(
+ 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;
+ }
+
+ 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;
+
+ AddMemorySnapshot(critical_section.DebugInfo,
+ sizeof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>),
+ into);
+}
+
+} // namespace crashpad

Powered by Google App Engine
This is Rietveld 408576698