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

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

Issue 1400413002: win: Add Handles() to ProcessInfo (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: . Created 5 years, 2 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
« no previous file with comments | « util/win/process_info.h ('k') | util/win/process_info_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <algorithm> 19 #include <algorithm>
20 #include <limits> 20 #include <limits>
21 21
22 #include "base/logging.h" 22 #include "base/logging.h"
23 #include "base/memory/scoped_ptr.h"
23 #include "base/strings/stringprintf.h" 24 #include "base/strings/stringprintf.h"
24 #include "base/template_util.h" 25 #include "base/template_util.h"
25 #include "build/build_config.h" 26 #include "build/build_config.h"
26 #include "util/numeric/safe_assignment.h" 27 #include "util/numeric/safe_assignment.h"
28 #include "util/win/nt_internals.h"
27 #include "util/win/ntstatus_logging.h" 29 #include "util/win/ntstatus_logging.h"
28 #include "util/win/process_structs.h" 30 #include "util/win/process_structs.h"
31 #include "util/win/scoped_handle.h"
29 32
30 namespace crashpad { 33 namespace crashpad {
31 34
32 namespace { 35 namespace {
33 36
34 NTSTATUS NtQueryInformationProcess(HANDLE process_handle, 37 NTSTATUS NtQueryInformationProcess(HANDLE process_handle,
35 PROCESSINFOCLASS process_information_class, 38 PROCESSINFOCLASS process_information_class,
36 PVOID process_information, 39 PVOID process_information,
37 ULONG process_information_length, 40 ULONG process_information_length,
38 PULONG return_length) { 41 PULONG return_length) {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 mbi64.BaseAddress = reinterpret_cast<ULONGLONG>(mbi.BaseAddress); 123 mbi64.BaseAddress = reinterpret_cast<ULONGLONG>(mbi.BaseAddress);
121 mbi64.AllocationBase = reinterpret_cast<ULONGLONG>(mbi.AllocationBase); 124 mbi64.AllocationBase = reinterpret_cast<ULONGLONG>(mbi.AllocationBase);
122 mbi64.AllocationProtect = mbi.AllocationProtect; 125 mbi64.AllocationProtect = mbi.AllocationProtect;
123 mbi64.RegionSize = mbi.RegionSize; 126 mbi64.RegionSize = mbi.RegionSize;
124 mbi64.State = mbi.State; 127 mbi64.State = mbi.State;
125 mbi64.Protect = mbi.Protect; 128 mbi64.Protect = mbi.Protect;
126 mbi64.Type = mbi.Type; 129 mbi64.Type = mbi.Type;
127 return mbi64; 130 return mbi64;
128 } 131 }
129 132
133 // NtQueryObject with a retry for size mismatch as well as a minimum size to
134 // retrieve (and expect).
135 scoped_ptr<uint8_t[]> QueryObject(
136 HANDLE handle,
137 OBJECT_INFORMATION_CLASS object_information_class,
138 ULONG minimum_size) {
139 ULONG size = minimum_size;
140 ULONG return_length;
141 scoped_ptr<uint8_t[]> buffer(new uint8_t[size]);
142 NTSTATUS status = crashpad::NtQueryObject(
143 handle, object_information_class, buffer.get(), size, &return_length);
144 if (status == STATUS_INFO_LENGTH_MISMATCH) {
145 DCHECK_GT(return_length, size);
146 size = return_length;
147 buffer.reset(new uint8_t[size]);
148 status = crashpad::NtQueryObject(
149 handle, object_information_class, buffer.get(), size, &return_length);
150 }
151
152 if (!NT_SUCCESS(status)) {
153 NTSTATUS_LOG(ERROR, status) << "NtQueryObject";
154 return scoped_ptr<uint8_t[]>();
155 }
156
157 DCHECK_GE(return_length, minimum_size);
158 return buffer.Pass();
159 }
160
130 } // namespace 161 } // namespace
131 162
132 template <class Traits> 163 template <class Traits>
133 bool GetProcessBasicInformation(HANDLE process, 164 bool GetProcessBasicInformation(HANDLE process,
134 bool is_wow64, 165 bool is_wow64,
135 ProcessInfo* process_info, 166 ProcessInfo* process_info,
136 WinVMAddress* peb_address, 167 WinVMAddress* peb_address,
137 WinVMSize* peb_size) { 168 WinVMSize* peb_size) {
138 ULONG bytes_returned; 169 ULONG bytes_returned;
139 process_types::PROCESS_BASIC_INFORMATION<Traits> process_basic_information; 170 process_types::PROCESS_BASIC_INFORMATION<Traits> process_basic_information;
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 338
308 if (memory_basic_information.RegionSize == 0) { 339 if (memory_basic_information.RegionSize == 0) {
309 LOG(ERROR) << "RegionSize == 0"; 340 LOG(ERROR) << "RegionSize == 0";
310 return false; 341 return false;
311 } 342 }
312 } 343 }
313 344
314 return true; 345 return true;
315 } 346 }
316 347
348 std::vector<ProcessInfo::Handle> ProcessInfo::BuildHandleVector(
349 HANDLE process) const {
350 ULONG buffer_size = 2 * 1024 * 1024;
351 scoped_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
352
353 // Typically if the buffer were too small, STATUS_INFO_LENGTH_MISMATCH would
354 // return the correct size in the final argument, but it does not for
355 // SystemExtendedHandleInformation, so we loop and attempt larger sizes.
356 NTSTATUS status;
357 ULONG returned_length;
358 for (int tries = 0; tries < 5; ++tries) {
359 status = crashpad::NtQuerySystemInformation(
360 static_cast<SYSTEM_INFORMATION_CLASS>(SystemExtendedHandleInformation),
361 buffer.get(),
362 buffer_size,
363 &returned_length);
364 if (NT_SUCCESS(status) || status != STATUS_INFO_LENGTH_MISMATCH)
365 break;
366
367 buffer_size *= 2;
368 buffer.reset(new uint8_t[buffer_size]);
369 }
Mark Mentovai 2015/10/16 22:04:05 This is a kind of big allocation, so reset() to em
scottmg 2015/10/16 22:25:21 Done.
370
371 if (!NT_SUCCESS(status)) {
372 NTSTATUS_LOG(ERROR, status)
373 << "NtQuerySystemInformation SystemExtendedHandleInformation";
374 return std::vector<Handle>();
375 }
376
377 const auto& system_handle_information_ex =
378 *reinterpret_cast<process_types::SYSTEM_HANDLE_INFORMATION_EX*>(
379 buffer.get());
380
381 DCHECK_LE(offsetof(process_types::SYSTEM_HANDLE_INFORMATION_EX, Handles) +
382 system_handle_information_ex.NumberOfHandles *
383 sizeof(system_handle_information_ex.Handles[0]),
384 returned_length);
385
386 std::vector<Handle> handles;
387
388 for (size_t i = 0; i < system_handle_information_ex.NumberOfHandles; ++i) {
389 const auto& handle = system_handle_information_ex.Handles[i];
390 if (handle.UniqueProcessId != process_id_)
391 continue;
392
393 Handle result_handle;
394 result_handle.handle =
395 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(handle.HandleValue));
396 result_handle.attributes = handle.HandleAttributes;
397 result_handle.granted_access = handle.GrantedAccess;
398
399 // TODO(scottmg): Could special case for self.
400 HANDLE dup_handle;
401 if (DuplicateHandle(process,
402 reinterpret_cast<HANDLE>(handle.HandleValue),
403 GetCurrentProcess(),
404 &dup_handle,
405 0,
406 false,
407 DUPLICATE_SAME_ACCESS)) {
408 // Some handles cannot be duplicated, for example, handles of type
409 // EtwRegistration. If we fail to duplicate, then we can't gather any more
410 // information, but include the information that we do have already.
411 ScopedKernelHANDLE scoped_dup_handle(dup_handle);
412
413 scoped_ptr<uint8_t[]> object_basic_information_buffer =
414 QueryObject(dup_handle,
415 ObjectBasicInformation,
416 sizeof(PUBLIC_OBJECT_BASIC_INFORMATION));
417 if (object_basic_information_buffer) {
418 PUBLIC_OBJECT_BASIC_INFORMATION* object_basic_information =
419 reinterpret_cast<PUBLIC_OBJECT_BASIC_INFORMATION*>(
420 object_basic_information_buffer.get());
421 // The Attributes and GrantedAccess sometimes differ slightly between
422 // the data retrieved in SYSTEM_HANDLE_INFORMATION_EX and
423 // PUBLIC_OBJECT_TYPE_INFORMATION. We prefer the values in
424 // SYSTEM_HANDLE_INFORMATION_EX because they were retrieved from the
425 // target process, rather than on the duplicated handle, so don't use
426 // them here.
427
428 // Subtract one to account for our DuplicateHandle() and another for
429 // NtQueryObject() while the query was being executed.
430 DCHECK_GT(object_basic_information->PointerCount, 2u);
431 result_handle.pointer_count =
432 object_basic_information->PointerCount - 2;
433
434 // Subtract one to account for our DuplicateHandle().
435 DCHECK_GT(object_basic_information->HandleCount, 1u);
436 result_handle.handle_count = object_basic_information->HandleCount - 1;
437 }
438
439 scoped_ptr<uint8_t[]> object_type_information_buffer =
440 QueryObject(dup_handle,
441 ObjectTypeInformation,
442 sizeof(PUBLIC_OBJECT_TYPE_INFORMATION));
443 if (object_type_information_buffer) {
444 PUBLIC_OBJECT_TYPE_INFORMATION* object_type_information =
445 reinterpret_cast<PUBLIC_OBJECT_TYPE_INFORMATION*>(
446 object_type_information_buffer.get());
447
448 DCHECK_EQ(object_type_information->TypeName.Length %
449 sizeof(result_handle.type_name[0]),
450 0u);
451 result_handle.type_name =
452 std::wstring(object_type_information->TypeName.Buffer,
453 object_type_information->TypeName.Length /
454 sizeof(result_handle.type_name[0]));
455 }
456 }
457
458 handles.push_back(result_handle);
459 }
460 return handles;
461 }
462
317 ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() { 463 ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() {
318 } 464 }
319 465
320 ProcessInfo::Module::~Module() { 466 ProcessInfo::Module::~Module() {
321 } 467 }
322 468
469 ProcessInfo::Handle::Handle()
470 : type_name(),
471 handle(0),
472 attributes(0),
473 granted_access(0),
474 pointer_count(0),
475 handle_count(0) {
476 }
477
478 ProcessInfo::Handle::~Handle() {
479 }
480
323 ProcessInfo::ProcessInfo() 481 ProcessInfo::ProcessInfo()
324 : process_id_(), 482 : process_id_(),
325 inherited_from_process_id_(), 483 inherited_from_process_id_(),
484 process_(),
326 command_line_(), 485 command_line_(),
327 peb_address_(0), 486 peb_address_(0),
328 peb_size_(0), 487 peb_size_(0),
329 modules_(), 488 modules_(),
330 memory_info_(), 489 memory_info_(),
490 handles_(),
331 is_64_bit_(false), 491 is_64_bit_(false),
332 is_wow64_(false), 492 is_wow64_(false),
333 initialized_() { 493 initialized_() {
334 } 494 }
335 495
336 ProcessInfo::~ProcessInfo() { 496 ProcessInfo::~ProcessInfo() {
337 } 497 }
338 498
339 bool ProcessInfo::Initialize(HANDLE process) { 499 bool ProcessInfo::Initialize(HANDLE process) {
340 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); 500 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
341 501
502 process_ = process;
503
342 is_wow64_ = IsProcessWow64(process); 504 is_wow64_ = IsProcessWow64(process);
343 505
344 if (is_wow64_) { 506 if (is_wow64_) {
345 // If it's WoW64, then it's 32-on-64. 507 // If it's WoW64, then it's 32-on-64.
346 is_64_bit_ = false; 508 is_64_bit_ = false;
347 } else { 509 } else {
348 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to 510 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to
349 // distinguish between these two cases. 511 // distinguish between these two cases.
350 SYSTEM_INFO system_info; 512 SYSTEM_INFO system_info;
351 GetSystemInfo(&system_info); 513 GetSystemInfo(&system_info);
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 INITIALIZATION_STATE_DCHECK_VALID(initialized_); 594 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
433 return memory_info_; 595 return memory_info_;
434 } 596 }
435 597
436 std::vector<CheckedRange<WinVMAddress, WinVMSize>> 598 std::vector<CheckedRange<WinVMAddress, WinVMSize>>
437 ProcessInfo::GetReadableRanges( 599 ProcessInfo::GetReadableRanges(
438 const CheckedRange<WinVMAddress, WinVMSize>& range) const { 600 const CheckedRange<WinVMAddress, WinVMSize>& range) const {
439 return GetReadableRangesOfMemoryMap(range, MemoryInfo()); 601 return GetReadableRangesOfMemoryMap(range, MemoryInfo());
440 } 602 }
441 603
604 const std::vector<ProcessInfo::Handle>& ProcessInfo::Handles() {
605 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
606 if (handles_.empty())
607 handles_ = BuildHandleVector(process_);
608 return handles_;
609 }
610
442 std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRangesOfMemoryMap( 611 std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRangesOfMemoryMap(
443 const CheckedRange<WinVMAddress, WinVMSize>& range, 612 const CheckedRange<WinVMAddress, WinVMSize>& range,
444 const std::vector<MEMORY_BASIC_INFORMATION64>& memory_info) { 613 const std::vector<MEMORY_BASIC_INFORMATION64>& memory_info) {
445 using Range = CheckedRange<WinVMAddress, WinVMSize>; 614 using Range = CheckedRange<WinVMAddress, WinVMSize>;
446 615
447 // Find all the ranges that overlap the target range, maintaining their order. 616 // Find all the ranges that overlap the target range, maintaining their order.
448 std::vector<MEMORY_BASIC_INFORMATION64> overlapping; 617 std::vector<MEMORY_BASIC_INFORMATION64> overlapping;
449 for (const auto& mi : memory_info) { 618 for (const auto& mi : memory_info) {
450 static_assert(base::is_same<decltype(mi.BaseAddress), WinVMAddress>::value, 619 static_assert(base::is_same<decltype(mi.BaseAddress), WinVMAddress>::value,
451 "expected range address to be WinVMAddress"); 620 "expected range address to be WinVMAddress");
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 } else { 664 } else {
496 result.push_back(as_ranges[i]); 665 result.push_back(as_ranges[i]);
497 } 666 }
498 DCHECK(result.back().IsValid()); 667 DCHECK(result.back().IsValid());
499 } 668 }
500 669
501 return result; 670 return result;
502 } 671 }
503 672
504 } // namespace crashpad 673 } // namespace crashpad
OLDNEW
« 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