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

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

Powered by Google App Engine
This is Rietveld 408576698