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

Side by Side Diff: util/win/process_info.cc

Issue 1336823002: win x86: Grab bag of restructuring to get tests working on x86-on-x86 (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: . Created 5 years, 3 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
1 // Copyright 2015 The Crashpad Authors. All rights reserved.
Mark Mentovai 2015/09/16 02:57:20 Pretty sure we still own this file.
scottmg 2015/09/16 18:05:07 Done.
2 // 1 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 2 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 3 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 4 // You may obtain a copy of the License at
6 // 5 //
7 // http://www.apache.org/licenses/LICENSE-2.0 6 // http://www.apache.org/licenses/LICENSE-2.0
8 // 7 //
9 // Unless required by applicable law or agreed to in writing, software 8 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 9 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 11 // See the License for the specific language governing permissions and
13 // limitations under the License. 12 // limitations under the License.
14 13
15 #include "util/win/process_info.h" 14 #include "util/win/process_info.h"
16 15
17 #include <winternl.h> 16 #include <winternl.h>
18 17
19 #include "base/logging.h" 18 #include "base/logging.h"
20 #include "util/numeric/safe_assignment.h" 19 #include "util/numeric/safe_assignment.h"
20 #include "util/win/ntstatus_logging.h"
21 #include "util/win/process_structs.h" 21 #include "util/win/process_structs.h"
22 22
23 namespace crashpad { 23 namespace crashpad {
24 24
25 namespace { 25 namespace {
26 26
27 NTSTATUS NtQueryInformationProcess(HANDLE process_handle, 27 NTSTATUS NtQueryInformationProcess(HANDLE process_handle,
28 PROCESSINFOCLASS process_information_class, 28 PROCESSINFOCLASS process_information_class,
29 PVOID process_information, 29 PVOID process_information,
30 ULONG process_information_length, 30 ULONG process_information_length,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 PLOG(ERROR) << "ReadProcessMemory UNICODE_STRING"; 73 PLOG(ERROR) << "ReadProcessMemory UNICODE_STRING";
74 return false; 74 return false;
75 } 75 }
76 if (bytes_read != us.Length) { 76 if (bytes_read != us.Length) {
77 LOG(ERROR) << "ReadProcessMemory UNICODE_STRING incorrect size"; 77 LOG(ERROR) << "ReadProcessMemory UNICODE_STRING incorrect size";
78 return false; 78 return false;
79 } 79 }
80 return true; 80 return true;
81 } 81 }
82 82
83 template <class T> bool ReadStruct(HANDLE process, WinVMAddress at, T* into) { 83 template <class T>
84 bool ReadStruct(HANDLE process, WinVMAddress at, T* into) {
84 SIZE_T bytes_read; 85 SIZE_T bytes_read;
85 if (!ReadProcessMemory(process, 86 if (!ReadProcessMemory(process,
86 reinterpret_cast<const void*>(at), 87 reinterpret_cast<const void*>(at),
87 into, 88 into,
88 sizeof(T), 89 sizeof(T),
89 &bytes_read)) { 90 &bytes_read)) {
90 // We don't have a name for the type we're reading, so include the signature 91 // We don't have a name for the type we're reading, so include the signature
91 // to get the type of T. 92 // to get the type of T.
92 PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__; 93 PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__;
93 return false; 94 return false;
94 } 95 }
95 if (bytes_read != sizeof(T)) { 96 if (bytes_read != sizeof(T)) {
96 LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size"; 97 LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size";
97 return false; 98 return false;
98 } 99 }
99 return true; 100 return true;
100 } 101 }
101 102
102 } // namespace 103 } // namespace
103 104
104 template <class Traits> 105 template <class Traits>
106 bool GetProcessBasicInformation(HANDLE process,
107 bool is_wow64,
108 ProcessInfo* process_info,
109 WinVMAddress* peb_address) {
110 ULONG bytes_returned;
111 process_types::PROCESS_BASIC_INFORMATION<Traits> process_basic_information;
112 NTSTATUS status =
113 crashpad::NtQueryInformationProcess(process,
114 ProcessBasicInformation,
115 &process_basic_information,
116 sizeof(process_basic_information),
117 &bytes_returned);
118 if (!NT_SUCCESS(status)) {
119 NTSTATUS_LOG(ERROR, status) << "NtQueryInformationProcess";
120 return false;
121 }
122 if (bytes_returned != sizeof(process_basic_information)) {
123 LOG(ERROR) << "NtQueryInformationProcess incorrect size";
124 return false;
125 }
126
127 // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203 on
128 // 32 bit being the correct size for HANDLEs for proceses, even on Windows
129 // x64. API functions (e.g. OpenProcess) take only a DWORD, so there's no
130 // sense in maintaining the top bits.
131 process_info->process_id_ =
132 static_cast<DWORD>(process_basic_information.UniqueProcessId);
133 process_info->inherited_from_process_id_ = static_cast<DWORD>(
134 process_basic_information.InheritedFromUniqueProcessId);
135
136 // We now want to read the PEB to gather the rest of our information. The
137 // PebBaseAddress as returned above is what we want for 64-on-64 and 32-on-32,
138 // but for Wow64, we want to read the 32 bit PEB (a Wow64 process has both).
139 // The address of this is found by a second call to NtQueryInformationProcess.
140 *peb_address = process_basic_information.PebBaseAddress;
Mark Mentovai 2015/09/16 02:57:20 if (!is_wow64) { // this assignment } else { /
scottmg 2015/09/16 18:05:07 Done.
141 if (is_wow64) {
142 ULONG_PTR wow64_peb_address;
143 status = crashpad::NtQueryInformationProcess(process,
144 ProcessWow64Information,
Mark Mentovai 2015/09/16 02:57:20 It’s a little weird that the thing named this way
scottmg 2015/09/16 18:05:07 Yeah, the limited bit that MSDN documented is conf
145 &wow64_peb_address,
146 sizeof(wow64_peb_address),
147 &bytes_returned);
148 if (!NT_SUCCESS(status)) {
149 NTSTATUS_LOG(ERROR, status), "NtQueryInformationProcess";
150 return false;
151 }
152 if (bytes_returned != sizeof(wow64_peb_address)) {
153 LOG(ERROR) << "NtQueryInformationProcess incorrect size";
154 return false;
155 }
156 *peb_address = wow64_peb_address;
157 }
158
159 return true;
160 }
161
162 template <class Traits>
105 bool ReadProcessData(HANDLE process, 163 bool ReadProcessData(HANDLE process,
106 WinVMAddress peb_address_vmaddr, 164 WinVMAddress peb_address_vmaddr,
107 ProcessInfo* process_info) { 165 ProcessInfo* process_info) {
166
Mark Mentovai 2015/09/16 02:57:20 Unnecessary new blank line.
scottmg 2015/09/16 18:05:06 Done.
108 Traits::Pointer peb_address; 167 Traits::Pointer peb_address;
109 if (!AssignIfInRange(&peb_address, peb_address_vmaddr)) { 168 if (!AssignIfInRange(&peb_address, peb_address_vmaddr)) {
110 LOG(ERROR) << "peb_address_vmaddr " << peb_address_vmaddr 169 LOG(ERROR) << "peb address" << peb_address_vmaddr << " out of range";
Mark Mentovai 2015/09/16 02:57:20 Need a space after the word “address”. peb_addres
scottmg 2015/09/16 18:05:06 Done.
111 << " out of range";
112 return false; 170 return false;
113 } 171 }
114 172
115 // Try to read the process environment block. 173 // Try to read the process environment block.
116 process_types::PEB<Traits> peb; 174 process_types::PEB<Traits> peb;
117 if (!ReadStruct(process, peb_address, &peb)) 175 if (!ReadStruct(process, peb_address, &peb))
118 return false; 176 return false;
119 177
120 process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters; 178 process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters;
121 if (!ReadStruct(process, peb.ProcessParameters, &process_parameters)) 179 if (!ReadStruct(process, peb.ProcessParameters, &process_parameters))
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 initialized_() { 263 initialized_() {
206 } 264 }
207 265
208 ProcessInfo::~ProcessInfo() { 266 ProcessInfo::~ProcessInfo() {
209 } 267 }
210 268
211 bool ProcessInfo::Initialize(HANDLE process) { 269 bool ProcessInfo::Initialize(HANDLE process) {
212 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); 270 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
213 271
214 is_wow64_ = IsProcessWow64(process); 272 is_wow64_ = IsProcessWow64(process);
273 bool self_is_wow64 = IsProcessWow64(GetCurrentProcess());
Mark Mentovai 2015/09/16 02:57:20 Don’t declare it ’til you need it. Since you only
scottmg 2015/09/16 18:05:07 Gone.
215 274
216 if (is_wow64_) { 275 if (is_wow64_) {
217 // If it's WoW64, then it's 32-on-64. 276 // If it's WoW64, then it's 32-on-64.
218 is_64_bit_ = false; 277 is_64_bit_ = false;
219 } else { 278 } else {
220 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to 279 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to
221 // distinguish between these two cases. 280 // distinguish between these two cases.
222 SYSTEM_INFO system_info; 281 SYSTEM_INFO system_info;
223 GetSystemInfo(&system_info); 282 GetSystemInfo(&system_info);
224 is_64_bit_ = 283 is_64_bit_ =
225 system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64; 284 system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
226 } 285 }
227 286
228 #if ARCH_CPU_32_BITS 287 #if ARCH_CPU_32_BITS
229 if (is_64_bit_) { 288 if (is_64_bit_) {
230 LOG(ERROR) << "Reading x64 process from x86 process not supported"; 289 LOG(ERROR) << "Reading x64 process from x86 process not supported";
231 return false; 290 return false;
232 } 291 }
233 #endif 292 #endif
234 293
235 ULONG bytes_returned; 294 WinVMAddress peb_address;
236 // We assume this process is not running on Wow64. The 295 bool result =
237 // PROCESS_BASIC_INFORMATION uses the OS size (that is, even Wow64 has a 64 296 (is_64_bit_ || (is_wow64_ && !self_is_wow64))
Mark Mentovai 2015/09/16 02:57:20 This condition makes my head hurt. It seems like i
scottmg 2015/09/16 18:05:07 Me too! I think what it really needed to be was ba
238 // bit one.) 297 ? GetProcessBasicInformation<process_types::internal::Traits64>(
239 // TODO(scottmg): Either support running as Wow64, or check/resolve this at a 298 process, is_wow64_, this, &peb_address)
240 // higher level. 299 : GetProcessBasicInformation<process_types::internal::Traits32>(
241 #if ARCH_CPU_32_BITS 300 process, is_wow64_, this, &peb_address);
242 process_types::PROCESS_BASIC_INFORMATION<process_types::internal::Traits32> 301 if (!result) {
243 process_basic_information; 302 LOG(ERROR) << "GetProcessBasicInformation failed";
244 #else
245 process_types::PROCESS_BASIC_INFORMATION<process_types::internal::Traits64>
246 process_basic_information;
247 #endif
248 NTSTATUS status =
249 crashpad::NtQueryInformationProcess(process,
250 ProcessBasicInformation,
251 &process_basic_information,
252 sizeof(process_basic_information),
253 &bytes_returned);
254 if (status < 0) {
255 LOG(ERROR) << "NtQueryInformationProcess: status=" << status;
256 return false;
257 }
258 if (bytes_returned != sizeof(process_basic_information)) {
259 LOG(ERROR) << "NtQueryInformationProcess incorrect size";
260 return false; 303 return false;
261 } 304 }
262 305
263 // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203 on 306 result = is_64_bit_ ? ReadProcessData<process_types::internal::Traits64>(
264 // 32 bit being the correct size for HANDLEs for proceses, even on Windows
265 // x64. API functions (e.g. OpenProcess) take only a DWORD, so there's no
266 // sense in maintaining the top bits.
267 process_id_ = static_cast<DWORD>(process_basic_information.UniqueProcessId);
268 inherited_from_process_id_ = static_cast<DWORD>(
269 process_basic_information.InheritedFromUniqueProcessId);
270
271 // We now want to read the PEB to gather the rest of our information. The
272 // PebBaseAddress as returned above is what we want for 64-on-64 and 32-on-32,
273 // but for Wow64, we want to read the 32 bit PEB (a Wow64 process has both).
274 // The address of this is found by a second call to NtQueryInformationProcess.
275 WinVMAddress peb_address = process_basic_information.PebBaseAddress;
276 if (is_wow64_) {
277 ULONG_PTR wow64_peb_address;
278 status =
279 crashpad::NtQueryInformationProcess(process,
280 ProcessWow64Information,
281 &wow64_peb_address,
282 sizeof(wow64_peb_address),
283 &bytes_returned);
284 if (status < 0) {
285 LOG(ERROR) << "NtQueryInformationProcess: status=" << status;
286 return false;
287 }
288 if (bytes_returned != sizeof(wow64_peb_address)) {
289 LOG(ERROR) << "NtQueryInformationProcess incorrect size";
290 return false;
291 }
292 peb_address = wow64_peb_address;
293 }
294
295 // Read the PEB data using the correct word size.
296 bool result = is_64_bit_ ? ReadProcessData<process_types::internal::Traits64>(
297 process, peb_address, this) 307 process, peb_address, this)
298 : ReadProcessData<process_types::internal::Traits32>( 308 : ReadProcessData<process_types::internal::Traits32>(
299 process, peb_address, this); 309 process, peb_address, this);
300 if (!result) 310 if (!result) {
311 LOG(ERROR) << "ReadProcessData failed";
301 return false; 312 return false;
313 }
302 314
303 INITIALIZATION_STATE_SET_VALID(initialized_); 315 INITIALIZATION_STATE_SET_VALID(initialized_);
304 return true; 316 return true;
305 } 317 }
306 318
307 bool ProcessInfo::Is64Bit() const { 319 bool ProcessInfo::Is64Bit() const {
308 INITIALIZATION_STATE_DCHECK_VALID(initialized_); 320 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
309 return is_64_bit_; 321 return is_64_bit_;
310 } 322 }
311 323
(...skipping 18 matching lines...) Expand all
330 return true; 342 return true;
331 } 343 }
332 344
333 bool ProcessInfo::Modules(std::vector<Module>* modules) const { 345 bool ProcessInfo::Modules(std::vector<Module>* modules) const {
334 INITIALIZATION_STATE_DCHECK_VALID(initialized_); 346 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
335 *modules = modules_; 347 *modules = modules_;
336 return true; 348 return true;
337 } 349 }
338 350
339 } // namespace crashpad 351 } // namespace crashpad
OLDNEW
« util/util_test.gyp ('K') | « util/win/process_info.h ('k') | util/win/process_structs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698