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

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: fixes 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. 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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 #include "util/win/process_info.h" 15 #include "util/win/process_info.h"
16 16
17 #include <winternl.h> 17 #include <winternl.h>
18 18
19 #include "base/logging.h" 19 #include "base/logging.h"
20 #include "base/strings/stringprintf.h"
20 #include "util/numeric/safe_assignment.h" 21 #include "util/numeric/safe_assignment.h"
22 #include "util/win/ntstatus_logging.h"
21 #include "util/win/process_structs.h" 23 #include "util/win/process_structs.h"
22 24
23 namespace crashpad { 25 namespace crashpad {
24 26
25 namespace { 27 namespace {
26 28
27 NTSTATUS NtQueryInformationProcess(HANDLE process_handle, 29 NTSTATUS NtQueryInformationProcess(HANDLE process_handle,
28 PROCESSINFOCLASS process_information_class, 30 PROCESSINFOCLASS process_information_class,
29 PVOID process_information, 31 PVOID process_information,
30 ULONG process_information_length, 32 ULONG process_information_length,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 PLOG(ERROR) << "ReadProcessMemory UNICODE_STRING"; 75 PLOG(ERROR) << "ReadProcessMemory UNICODE_STRING";
74 return false; 76 return false;
75 } 77 }
76 if (bytes_read != us.Length) { 78 if (bytes_read != us.Length) {
77 LOG(ERROR) << "ReadProcessMemory UNICODE_STRING incorrect size"; 79 LOG(ERROR) << "ReadProcessMemory UNICODE_STRING incorrect size";
78 return false; 80 return false;
79 } 81 }
80 return true; 82 return true;
81 } 83 }
82 84
83 template <class T> bool ReadStruct(HANDLE process, WinVMAddress at, T* into) { 85 template <class T>
86 bool ReadStruct(HANDLE process, WinVMAddress at, T* into) {
84 SIZE_T bytes_read; 87 SIZE_T bytes_read;
85 if (!ReadProcessMemory(process, 88 if (!ReadProcessMemory(process,
86 reinterpret_cast<const void*>(at), 89 reinterpret_cast<const void*>(at),
87 into, 90 into,
88 sizeof(T), 91 sizeof(T),
89 &bytes_read)) { 92 &bytes_read)) {
90 // We don't have a name for the type we're reading, so include the signature 93 // We don't have a name for the type we're reading, so include the signature
91 // to get the type of T. 94 // to get the type of T.
92 PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__; 95 PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__;
93 return false; 96 return false;
94 } 97 }
95 if (bytes_read != sizeof(T)) { 98 if (bytes_read != sizeof(T)) {
96 LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size"; 99 LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size";
97 return false; 100 return false;
98 } 101 }
99 return true; 102 return true;
100 } 103 }
101 104
102 } // namespace 105 } // namespace
103 106
104 template <class Traits> 107 template <class Traits>
108 bool GetProcessBasicInformation(HANDLE process,
109 bool is_wow64,
110 ProcessInfo* process_info,
111 WinVMAddress* peb_address) {
112 ULONG bytes_returned;
113 process_types::PROCESS_BASIC_INFORMATION<Traits> process_basic_information;
114 NTSTATUS status =
115 crashpad::NtQueryInformationProcess(process,
116 ProcessBasicInformation,
117 &process_basic_information,
118 sizeof(process_basic_information),
119 &bytes_returned);
120 if (!NT_SUCCESS(status)) {
121 NTSTATUS_LOG(ERROR, status) << "NtQueryInformationProcess";
122 return false;
123 }
124 if (bytes_returned != sizeof(process_basic_information)) {
125 LOG(ERROR) << "NtQueryInformationProcess incorrect size";
126 return false;
127 }
128
129 // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203 on
130 // 32 bit being the correct size for HANDLEs for proceses, even on Windows
131 // x64. API functions (e.g. OpenProcess) take only a DWORD, so there's no
132 // sense in maintaining the top bits.
133 process_info->process_id_ =
134 static_cast<DWORD>(process_basic_information.UniqueProcessId);
135 process_info->inherited_from_process_id_ = static_cast<DWORD>(
136 process_basic_information.InheritedFromUniqueProcessId);
137
138 // We now want to read the PEB to gather the rest of our information. The
139 // PebBaseAddress as returned above is what we want for 64-on-64 and 32-on-32,
140 // but for Wow64, we want to read the 32 bit PEB (a Wow64 process has both).
141 // The address of this is found by a second call to NtQueryInformationProcess.
142 if (!is_wow64) {
143 *peb_address = process_basic_information.PebBaseAddress;
144 } else {
145 ULONG_PTR wow64_peb_address;
146 status = crashpad::NtQueryInformationProcess(process,
147 ProcessWow64Information,
148 &wow64_peb_address,
149 sizeof(wow64_peb_address),
150 &bytes_returned);
151 if (!NT_SUCCESS(status)) {
152 NTSTATUS_LOG(ERROR, status), "NtQueryInformationProcess";
153 return false;
154 }
155 if (bytes_returned != sizeof(wow64_peb_address)) {
156 LOG(ERROR) << "NtQueryInformationProcess incorrect size";
157 return false;
158 }
159 *peb_address = wow64_peb_address;
160 }
161
162 return true;
163 }
164
165 template <class Traits>
105 bool ReadProcessData(HANDLE process, 166 bool ReadProcessData(HANDLE process,
106 WinVMAddress peb_address_vmaddr, 167 WinVMAddress peb_address_vmaddr,
107 ProcessInfo* process_info) { 168 ProcessInfo* process_info) {
108 Traits::Pointer peb_address; 169 Traits::Pointer peb_address;
109 if (!AssignIfInRange(&peb_address, peb_address_vmaddr)) { 170 if (!AssignIfInRange(&peb_address, peb_address_vmaddr)) {
110 LOG(ERROR) << "peb_address_vmaddr " << peb_address_vmaddr 171 LOG(ERROR) << base::StringPrintf("peb address 0x%x out of range",
111 << " out of range"; 172 peb_address_vmaddr);
112 return false; 173 return false;
113 } 174 }
114 175
115 // Try to read the process environment block. 176 // Try to read the process environment block.
116 process_types::PEB<Traits> peb; 177 process_types::PEB<Traits> peb;
117 if (!ReadStruct(process, peb_address, &peb)) 178 if (!ReadStruct(process, peb_address, &peb))
118 return false; 179 return false;
119 180
120 process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters; 181 process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters;
121 if (!ReadStruct(process, peb.ProcessParameters, &process_parameters)) 182 if (!ReadStruct(process, peb.ProcessParameters, &process_parameters))
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64; 286 system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
226 } 287 }
227 288
228 #if ARCH_CPU_32_BITS 289 #if ARCH_CPU_32_BITS
229 if (is_64_bit_) { 290 if (is_64_bit_) {
230 LOG(ERROR) << "Reading x64 process from x86 process not supported"; 291 LOG(ERROR) << "Reading x64 process from x86 process not supported";
231 return false; 292 return false;
232 } 293 }
233 #endif 294 #endif
234 295
235 ULONG bytes_returned; 296 WinVMAddress peb_address;
236 // We assume this process is not running on Wow64. The 297 #if ARCH_CPU_64_BITS
Mark Mentovai 2015/09/16 18:56:58 Much better. #include "build/build_config.h".
scottmg 2015/09/16 19:38:21 Done.
237 // PROCESS_BASIC_INFORMATION uses the OS size (that is, even Wow64 has a 64 298 bool result = GetProcessBasicInformation<process_types::internal::Traits64>(
238 // bit one.) 299 process, is_wow64_, this, &peb_address);
239 // TODO(scottmg): Either support running as Wow64, or check/resolve this at a
240 // higher level.
241 #if ARCH_CPU_32_BITS
242 process_types::PROCESS_BASIC_INFORMATION<process_types::internal::Traits32>
243 process_basic_information;
244 #else 300 #else
245 process_types::PROCESS_BASIC_INFORMATION<process_types::internal::Traits64> 301 bool result = GetProcessBasicInformation<process_types::internal::Traits32>(
246 process_basic_information; 302 process, false, this, &peb_address);
247 #endif 303 #endif // ARCH_CPU_64_BITS
248 NTSTATUS status = 304
249 crashpad::NtQueryInformationProcess(process, 305 if (!result) {
250 ProcessBasicInformation, 306 LOG(ERROR) << "GetProcessBasicInformation failed";
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; 307 return false;
261 } 308 }
262 309
263 // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203 on 310 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) 311 process, peb_address, this)
298 : ReadProcessData<process_types::internal::Traits32>( 312 : ReadProcessData<process_types::internal::Traits32>(
299 process, peb_address, this); 313 process, peb_address, this);
300 if (!result) 314 if (!result) {
315 LOG(ERROR) << "ReadProcessData failed";
301 return false; 316 return false;
317 }
302 318
303 INITIALIZATION_STATE_SET_VALID(initialized_); 319 INITIALIZATION_STATE_SET_VALID(initialized_);
304 return true; 320 return true;
305 } 321 }
306 322
307 bool ProcessInfo::Is64Bit() const { 323 bool ProcessInfo::Is64Bit() const {
308 INITIALIZATION_STATE_DCHECK_VALID(initialized_); 324 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
309 return is_64_bit_; 325 return is_64_bit_;
310 } 326 }
311 327
(...skipping 18 matching lines...) Expand all
330 return true; 346 return true;
331 } 347 }
332 348
333 bool ProcessInfo::Modules(std::vector<Module>* modules) const { 349 bool ProcessInfo::Modules(std::vector<Module>* modules) const {
334 INITIALIZATION_STATE_DCHECK_VALID(initialized_); 350 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
335 *modules = modules_; 351 *modules = modules_;
336 return true; 352 return true;
337 } 353 }
338 354
339 } // namespace crashpad 355 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698