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

Unified Diff: util/win/process_info.cc

Issue 977003003: win: Add implementation of ProcessInfo (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: fixes3 Created 5 years, 10 months 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
« no previous file with comments | « util/win/process_info.h ('k') | util/win/process_info_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: util/win/process_info.cc
diff --git a/util/win/process_info.cc b/util/win/process_info.cc
new file mode 100644
index 0000000000000000000000000000000000000000..66157aa482c1efccecb849014a3444851c161cdf
--- /dev/null
+++ b/util/win/process_info.cc
@@ -0,0 +1,287 @@
+// 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 "util/win/process_info.h"
+
+#include "base/logging.h"
+
+namespace crashpad {
+
+namespace {
+
+NTSTATUS NtQueryInformationProcess(HANDLE process_handle,
+ PROCESSINFOCLASS process_information_class,
+ PVOID process_information,
+ ULONG process_information_length,
+ PULONG return_length) {
+ static decltype(::NtQueryInformationProcess)* nt_query_information_process =
+ reinterpret_cast<decltype(::NtQueryInformationProcess)*>(GetProcAddress(
+ LoadLibrary(L"ntdll.dll"), "NtQueryInformationProcess"));
+ DCHECK(nt_query_information_process);
+ return nt_query_information_process(process_handle,
+ process_information_class,
+ process_information,
+ process_information_length,
+ return_length);
+}
+
+bool IsProcessWow64(HANDLE process_handle) {
+ static decltype(IsWow64Process)* is_wow64_process =
+ reinterpret_cast<decltype(IsWow64Process)*>(
+ GetProcAddress(LoadLibrary(L"kernel32.dll"), "IsWow64Process"));
+ if (!is_wow64_process)
+ return false;
+ BOOL is_wow64;
+ if (!is_wow64_process(process_handle, &is_wow64)) {
+ PLOG(ERROR) << "IsWow64Process";
+ return false;
+ }
+ return is_wow64;
+}
+
+bool ReadUnicodeString(HANDLE process,
+ const UNICODE_STRING& us,
+ std::wstring* result) {
+ if (us.Length == 0) {
+ result->clear();
+ return true;
+ }
+ DCHECK_EQ(us.Length % sizeof(wchar_t), 0u);
+ result->resize(us.Length / sizeof(wchar_t));
+ SIZE_T bytes_read;
+ if (!ReadProcessMemory(
+ process, us.Buffer, &result->operator[](0), us.Length, &bytes_read)) {
+ PLOG(ERROR) << "ReadProcessMemory UNICODE_STRING";
+ return false;
+ }
+ if (bytes_read != us.Length) {
+ LOG(ERROR) << "ReadProcessMemory UNICODE_STRING incorrect size";
+ return false;
+ }
+ return true;
+}
+
+template <class T> bool ReadStruct(HANDLE process, uintptr_t at, T* into) {
+ SIZE_T bytes_read;
+ if (!ReadProcessMemory(process,
+ reinterpret_cast<const void*>(at),
+ into,
+ sizeof(T),
+ &bytes_read)) {
+ // We don't have a name for the type we're reading, so include the signature
+ // to get the type of T.
+ PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__;
+ return false;
+ }
+ if (bytes_read != sizeof(T)) {
+ LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size";
+ return false;
+ }
+ return true;
+}
+
+// PEB_LDR_DATA in winternl.h doesn't document the trailing
+// InInitializationOrderModuleList field. See `dt ntdll!PEB_LDR_DATA`.
+struct FULL_PEB_LDR_DATA : public PEB_LDR_DATA {
+ LIST_ENTRY InInitializationOrderModuleList;
+};
+
+// LDR_DATA_TABLE_ENTRY doesn't include InInitializationOrderLinks, define a
+// complete version here. See `dt ntdll!_LDR_DATA_TABLE_ENTRY`.
+struct FULL_LDR_DATA_TABLE_ENTRY {
+ LIST_ENTRY InLoadOrderLinks;
+ LIST_ENTRY InMemoryOrderLinks;
+ LIST_ENTRY InInitializationOrderLinks;
+ PVOID DllBase;
+ PVOID EntryPoint;
+ ULONG SizeOfImage;
+ UNICODE_STRING FullDllName;
+ UNICODE_STRING BaseDllName;
+ ULONG Flags;
+ WORD LoadCount;
+ WORD TlsIndex;
+ LIST_ENTRY HashLinks;
+ ULONG TimeDateStamp;
+ _ACTIVATION_CONTEXT* EntryPointActivationContext;
+};
+
+} // namespace
+
+ProcessInfo::ProcessInfo()
+ : process_basic_information_(),
+ command_line_(),
+ modules_(),
+ is_64_bit_(false),
+ is_wow64_(false),
+ initialized_() {
+}
+
+ProcessInfo::~ProcessInfo() {
+}
+
+bool ProcessInfo::Initialize(HANDLE process) {
+ INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
+
+ is_wow64_ = IsProcessWow64(process);
+
+ if (is_wow64_) {
+ // If it's WoW64, then it's 32-on-64.
+ is_64_bit_ = false;
+ } else {
+ // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to
+ // distinguish between these two cases.
+ SYSTEM_INFO system_info;
+ GetSystemInfo(&system_info);
+ is_64_bit_ =
+ system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
+ }
+
+#if ARCH_CPU_64_BITS
+ if (!is_64_bit_) {
+ LOG(ERROR) << "Reading different bitness not yet supported";
+ return false;
+ }
+#else
+ if (is_64_bit_) {
+ LOG(ERROR) << "Reading x64 process from x86 process not supported";
+ return false;
+ }
+#endif
+
+ ULONG bytes_returned;
+ NTSTATUS status =
+ crashpad::NtQueryInformationProcess(process,
+ ProcessBasicInformation,
+ &process_basic_information_,
+ sizeof(process_basic_information_),
+ &bytes_returned);
+ if (status < 0) {
+ LOG(ERROR) << "NtQueryInformationProcess: status=" << status;
+ return false;
+ }
+ if (bytes_returned != sizeof(process_basic_information_)) {
+ LOG(ERROR) << "NtQueryInformationProcess incorrect size";
+ return false;
+ }
+
+ // Try to read the process environment block.
+ PEB peb;
+ if (!ReadStruct(process,
+ reinterpret_cast<uintptr_t>(
+ process_basic_information_.PebBaseAddress),
+ &peb)) {
+ return false;
+ }
+
+ RTL_USER_PROCESS_PARAMETERS process_parameters;
+ if (!ReadStruct(process,
+ reinterpret_cast<uintptr_t>(peb.ProcessParameters),
+ &process_parameters)) {
+ return false;
+ }
+
+ if (!ReadUnicodeString(
+ process, process_parameters.CommandLine, &command_line_)) {
+ return false;
+ }
+
+ FULL_PEB_LDR_DATA peb_ldr_data;
+ if (!ReadStruct(process, reinterpret_cast<uintptr_t>(peb.Ldr), &peb_ldr_data))
+ return false;
+
+ // Include the first module in the memory order list to get our own name as
+ // it's not included in initialization order below.
+ std::wstring self_module;
+ FULL_LDR_DATA_TABLE_ENTRY self_ldr_data_table_entry;
+ if (!ReadStruct(process,
+ reinterpret_cast<uintptr_t>(
+ reinterpret_cast<const char*>(
+ peb_ldr_data.InMemoryOrderModuleList.Flink) -
+ offsetof(FULL_LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks)),
+ &self_ldr_data_table_entry)) {
+ return false;
+ }
+ if (!ReadUnicodeString(
+ process, self_ldr_data_table_entry.FullDllName, &self_module)) {
+ return false;
+ }
+ modules_.push_back(self_module);
+
+ // Walk the PEB LDR structure (doubly-linked list) to get the list of loaded
+ // modules. We use this method rather than EnumProcessModules to get the
+ // modules in initialization order rather than memory order.
+ const LIST_ENTRY* last = peb_ldr_data.InInitializationOrderModuleList.Blink;
+ FULL_LDR_DATA_TABLE_ENTRY ldr_data_table_entry;
+ for (const LIST_ENTRY* cur =
+ peb_ldr_data.InInitializationOrderModuleList.Flink;
+ ;
+ cur = ldr_data_table_entry.InInitializationOrderLinks.Flink) {
+ // |cur| is the pointer to the LIST_ENTRY embedded in the
+ // FULL_LDR_DATA_TABLE_ENTRY, in the target process's address space. So we
+ // need to read from the target, and also offset back to the beginning of
+ // the structure.
+ if (!ReadStruct(
+ process,
+ reinterpret_cast<uintptr_t>(reinterpret_cast<const char*>(cur) -
+ offsetof(FULL_LDR_DATA_TABLE_ENTRY,
+ InInitializationOrderLinks)),
+ &ldr_data_table_entry)) {
+ break;
+ }
+ // TODO(scottmg): Capture TimeDateStamp, Checksum, etc. too?
+ std::wstring module;
+ if (!ReadUnicodeString(process, ldr_data_table_entry.FullDllName, &module))
+ break;
+ modules_.push_back(module);
+ if (cur == last)
+ break;
+ }
+
+ INITIALIZATION_STATE_SET_VALID(initialized_);
+ return true;
+}
+
+bool ProcessInfo::Is64Bit() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return is_64_bit_;
+}
+
+bool ProcessInfo::IsWow64() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return is_wow64_;
+}
+
+pid_t ProcessInfo::ProcessID() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return process_basic_information_.UniqueProcessId;
+}
+
+pid_t ProcessInfo::ParentProcessID() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return process_basic_information_.InheritedFromUniqueProcessId;
+}
+
+bool ProcessInfo::CommandLine(std::wstring* command_line) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ *command_line = command_line_;
+ return true;
+}
+
+bool ProcessInfo::Modules(std::vector<std::wstring>* modules) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ *modules = modules_;
+ return true;
+}
+
+} // namespace crashpad
« no previous file with comments | « util/win/process_info.h ('k') | util/win/process_info_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698