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

Side by Side 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: . Created 5 years, 9 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/win/process_info.h"
16
17 namespace crashpad {
18
19 namespace {
20
21 std::wstring ReadUnicodeString(HANDLE process, const UNICODE_STRING& us) {
Mark Mentovai 2015/03/05 17:32:22 In returning, this should have a way to distinguis
scottmg 2015/03/05 20:31:06 Done.
22 std::wstring str;
23 if (us.Length > 0) {
24 str.resize(us.Length / sizeof(wchar_t));
Mark Mentovai 2015/03/05 17:32:22 DCHECK_EQ(us.Length % sizeof(wchar_t), 0)
scottmg 2015/03/05 20:31:06 Done.
25 SIZE_T bytes_read;
26 if (!ReadProcessMemory(
Mark Mentovai 2015/03/05 17:32:22 If I’m reading this correctly, for cross-bitted op
scottmg 2015/03/05 20:31:06 I haven't tested it yet, but yes, I believe that's
27 process, us.Buffer, &str[0], us.Length, &bytes_read) ||
28 bytes_read != us.Length) {
29 PLOG(ERROR) << "ReadProcessMemory UNICODE_STRING";
Mark Mentovai 2015/03/05 17:32:22 #include "base/logging.h". Also, PLOG is incorrect
scottmg 2015/03/05 20:31:06 Done.
30 return std::wstring();
31 }
32 }
33 return str;
34 }
35
36 template <class T> bool ReadStruct(HANDLE process, void* at, T* into) {
Mark Mentovai 2015/03/05 17:32:22 const void* at, but Using pointer types to refer
scottmg 2015/03/05 20:31:06 Switched to uintptr_t. ReadProcessMemory just uses
37 SIZE_T bytes_read;
38 if (!ReadProcessMemory(process, at, into, sizeof(T), &bytes_read) ||
39 bytes_read != sizeof(T)) {
40 // We don't have a name for the type we're reading, so include the signature
41 // to get the type of T.
42 PLOG(ERROR) << "ReadProcessMemory: " << __FUNCSIG__;
43 return false;
44 }
45 return true;
46 }
47
48 // This is similar to PEB_LDR_DATA in winternl.h, but includes the
49 // InInitializationOrderModuleList field.
50 struct FULL_PEB_LDR_DATA {
Mark Mentovai 2015/03/05 17:32:22 Since you don’t need Length or Initialized, you ca
scottmg 2015/03/05 20:31:06 Done.
51 ULONG Length;
52 BOOLEAN Initialized;
53 PVOID Reserved;
54 LIST_ENTRY InLoadOrderModuleList;
Mark Mentovai 2015/03/05 17:32:22 What’s the difference between load order and initi
scottmg 2015/03/05 20:31:07 Load and Memory order seem to always be the same (
55 LIST_ENTRY InMemoryOrderModuleList;
56 LIST_ENTRY InInitializationOrderModuleList;
57 };
58
59 } // namespace
60
61 ProcessInfo::ProcessInfo()
62 : process_basic_information_(),
63 command_line_(),
64 is64bit_(false),
65 iswow64_(FALSE) {
66 }
67
68 ProcessInfo::~ProcessInfo() {
69 }
70
71 bool ProcessInfo::Initialize(HANDLE process) {
72 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
73
74 decltype(NtQueryInformationProcess)* nt_query_information_process =
Mark Mentovai 2015/03/05 17:32:22 I like to wrap these kinds of things in their own
scottmg 2015/03/05 20:31:06 Done.
75 reinterpret_cast<decltype(NtQueryInformationProcess)*>(GetProcAddress(
76 LoadLibrary(L"ntdll.dll"), "NtQueryInformationProcess"));
77 if (!nt_query_information_process) {
78 PLOG(ERROR) << "GetProcAddress NtQueryInformationProcess failed";
79 return false;
80 }
81
82 ULONG bytes_returned;
83 NTSTATUS status =
84 nt_query_information_process(process,
85 ProcessBasicInformation,
86 &process_basic_information_,
87 sizeof(process_basic_information_),
88 &bytes_returned);
89 if (status < 0 || bytes_returned != sizeof(process_basic_information_)) {
90 LOG(ERROR) << "NtQueryInformationProcess";
Mark Mentovai 2015/03/05 17:32:22 If status < 0, the value of status might be a good
scottmg 2015/03/05 20:31:07 Done.
91 return false;
92 }
93
94 // Try to read the process environment block.
95 PEB peb;
96 if (!ReadStruct(process, process_basic_information_.PebBaseAddress, &peb))
Mark Mentovai 2015/03/05 17:32:22 This looks like the first point where cross-bitted
scottmg 2015/03/05 20:31:06 Right, good point. For now I've moved the 32/64 c
97 return false;
98
99 RTL_USER_PROCESS_PARAMETERS process_parameters;
100 if (!ReadStruct(process, peb.ProcessParameters, &process_parameters))
101 return false;
102
103 command_line_ =
104 ReadUnicodeString(process, process_parameters.CommandLine);
105 if (command_line_.empty())
106 return false;
107
108 FULL_PEB_LDR_DATA peb_ldr_data;
109 if (!ReadStruct(process, peb.Ldr, &peb_ldr_data))
110 return false;
111
112 // Walk the PEB LDR structure (doubly-linked list) to get the list of loaded
113 // modules. We awkwardly use the Reserved fields of LDR_DATA_TABLE_ENTRY to
114 // get the modules in InitializationOrder rather than MemoryOrder.
115 LIST_ENTRY* cur = peb_ldr_data.InInitializationOrderModuleList.Flink;
116 LIST_ENTRY* last = peb_ldr_data.InInitializationOrderModuleList.Blink;
117 for (;;) {
Mark Mentovai 2015/03/05 17:32:21 You could hoist some stuff into the for construct
scottmg 2015/03/05 20:31:06 Some hoisted. Unfortunately, it's a "back" pointer
118 // |cur| is the pointer to the LIST_ENTRY embedded in the
119 // LDR_DATA_TABLE_ENTRY, in the target process's address space. So we need
120 // to read from the target, and also offset back to the beginning of the
121 // structure.
122 LDR_DATA_TABLE_ENTRY ldr_data_table_entry;
123 if (!ReadStruct(process,
Mark Mentovai 2015/03/05 17:32:22 Your CL description had me geared up for a truly h
scottmg 2015/03/05 20:31:07 All in the eye of the beholder, I suppose. :)
124 reinterpret_cast<char*>(cur) -
125 offsetof(LDR_DATA_TABLE_ENTRY, Reserved2),
Mark Mentovai 2015/03/05 17:32:22 I see. Presumably, LDR_DATA_TABLE_ENTRY really st
scottmg 2015/03/05 20:31:07 That's right.
126 &ldr_data_table_entry))
127 return false;
Mark Mentovai 2015/03/05 17:32:22 {} around this, its controlling condition is so lo
scottmg 2015/03/05 20:31:06 Done.
128 // TODO(scottmg): Capture TimeDateStamp, Checksum, etc. too?
129 std::wstring module =
130 ReadUnicodeString(process, ldr_data_table_entry.FullDllName);
131 if (module.empty())
132 return false;
Mark Mentovai 2015/03/05 17:32:22 A bad module should probably invalidate that modul
scottmg 2015/03/05 20:31:06 Done. I was concerned that a bad PEB meant the wor
133 modules_.push_back(module);
134 if (cur == last)
135 break;
136 cur = reinterpret_cast<LIST_ENTRY*>(&ldr_data_table_entry.Reserved2)->Flink;
137 }
138
139 decltype(IsWow64Process)* is_wow64_process =
Mark Mentovai 2015/03/05 17:32:22 If you break this one into its own function, you c
scottmg 2015/03/05 20:31:07 Done.
140 reinterpret_cast<decltype(IsWow64Process)*>(
141 GetProcAddress(LoadLibrary(L"kernel32.dll"), "IsWow64Process"));
142 if (!is_wow64_process) {
143 // This means kernel32 doesn't implement this function, so there's no such
144 // thing as WoW64 on this OS.
145 iswow64_ = FALSE;
146 } else if (!is_wow64_process(process, &iswow64_)) {
147 PLOG(ERROR) << "IsWow64Process";
148 return false;
149 }
150
151 if (iswow64_) {
152 // If it's WoW64, then it's 32-on-64.
153 is64bit_ = false;
154 } else {
155 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to
156 // distinguish between these two cases.
157 SYSTEM_INFO system_info;
158 GetSystemInfo(&system_info);
159 is64bit_ =
160 system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
161 }
162
163 INITIALIZATION_STATE_SET_VALID(initialized_);
164 return true;
165 }
166
167 bool ProcessInfo::Is64Bit() const {
168 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
169 return is64bit_;
170 }
171
172 bool ProcessInfo::IsWow64() const {
173 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
174 return iswow64_;
175 }
176
177 pid_t ProcessInfo::ProcessID() const {
178 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
179 return process_basic_information_.UniqueProcessId;
180 }
181
182 pid_t ProcessInfo::ParentProcessID() const {
183 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
184 return reinterpret_cast<ULONG_PTR>(process_basic_information_.Reserved3);
Mark Mentovai 2015/03/05 17:32:22 Can process_basic_information_ be a union type tha
scottmg 2015/03/05 20:31:06 Added FULL_... for this type too.
185 }
186
187 bool ProcessInfo::CommandLine(std::wstring* command_line) const {
188 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
189 *command_line = command_line_;
190 return true;
191 }
192
193 bool ProcessInfo::Modules(std::vector<std::wstring>* modules) const {
194 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
195 *modules = modules_;
196 return true;
197 }
198
199 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698