OLD | NEW |
---|---|
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 #include <type_traits> | |
Mark Mentovai
2015/10/07 18:50:52
OK if this is guaranteed to be available in all of
scottmg
2015/10/07 19:22:31
Hmm, it is, but strictly speaking it's also a C++1
| |
21 | 22 |
22 #include "base/logging.h" | 23 #include "base/logging.h" |
23 #include "base/strings/stringprintf.h" | 24 #include "base/strings/stringprintf.h" |
24 #include "build/build_config.h" | 25 #include "build/build_config.h" |
25 #include "util/numeric/safe_assignment.h" | 26 #include "util/numeric/safe_assignment.h" |
26 #include "util/win/ntstatus_logging.h" | 27 #include "util/win/ntstatus_logging.h" |
27 #include "util/win/process_structs.h" | 28 #include "util/win/process_structs.h" |
28 | 29 |
29 namespace crashpad { | 30 namespace crashpad { |
30 | 31 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
100 PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__; | 101 PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__; |
101 return false; | 102 return false; |
102 } | 103 } |
103 if (bytes_read != sizeof(T)) { | 104 if (bytes_read != sizeof(T)) { |
104 LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size"; | 105 LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size"; |
105 return false; | 106 return false; |
106 } | 107 } |
107 return true; | 108 return true; |
108 } | 109 } |
109 | 110 |
110 bool RegionIsAccessible(const ProcessInfo::MemoryInfo& memory_info) { | 111 bool RegionIsAccessible(const MEMORY_BASIC_INFORMATION64& memory_info) { |
111 return memory_info.state == MEM_COMMIT && | 112 return memory_info.State == MEM_COMMIT && |
112 (memory_info.protect & PAGE_NOACCESS) == 0 && | 113 (memory_info.Protect & PAGE_NOACCESS) == 0 && |
113 (memory_info.protect & PAGE_GUARD) == 0; | 114 (memory_info.Protect & PAGE_GUARD) == 0; |
115 } | |
116 | |
117 MEMORY_BASIC_INFORMATION64 MemoryBasicInformationToMemoryBasicInformation64( | |
118 const MEMORY_BASIC_INFORMATION& mbi) { | |
119 MEMORY_BASIC_INFORMATION64 mbi64 = {0}; | |
120 mbi64.BaseAddress = reinterpret_cast<ULONGLONG>(mbi.BaseAddress); | |
121 mbi64.AllocationBase = reinterpret_cast<ULONGLONG>(mbi.AllocationBase); | |
122 mbi64.AllocationProtect = mbi.AllocationProtect; | |
123 mbi64.RegionSize = mbi.RegionSize; | |
124 mbi64.State = mbi.State; | |
125 mbi64.Protect = mbi.Protect; | |
126 mbi64.Type = mbi.Type; | |
127 return mbi64; | |
114 } | 128 } |
115 | 129 |
116 } // namespace | 130 } // namespace |
117 | 131 |
118 template <class Traits> | 132 template <class Traits> |
119 bool GetProcessBasicInformation(HANDLE process, | 133 bool GetProcessBasicInformation(HANDLE process, |
120 bool is_wow64, | 134 bool is_wow64, |
121 ProcessInfo* process_info, | 135 ProcessInfo* process_info, |
122 WinVMAddress* peb_address, | 136 WinVMAddress* peb_address, |
123 WinVMSize* peb_size) { | 137 WinVMSize* peb_size) { |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
281 &memory_basic_information, | 295 &memory_basic_information, |
282 sizeof(memory_basic_information)); | 296 sizeof(memory_basic_information)); |
283 if (result == 0) { | 297 if (result == 0) { |
284 if (GetLastError() == ERROR_INVALID_PARAMETER) | 298 if (GetLastError() == ERROR_INVALID_PARAMETER) |
285 break; | 299 break; |
286 PLOG(ERROR) << "VirtualQueryEx"; | 300 PLOG(ERROR) << "VirtualQueryEx"; |
287 return false; | 301 return false; |
288 } | 302 } |
289 | 303 |
290 process_info->memory_info_.push_back( | 304 process_info->memory_info_.push_back( |
291 ProcessInfo::MemoryInfo(memory_basic_information)); | 305 MemoryBasicInformationToMemoryBasicInformation64( |
306 memory_basic_information)); | |
292 | 307 |
293 if (memory_basic_information.RegionSize == 0) { | 308 if (memory_basic_information.RegionSize == 0) { |
294 LOG(ERROR) << "RegionSize == 0"; | 309 LOG(ERROR) << "RegionSize == 0"; |
295 return false; | 310 return false; |
296 } | 311 } |
297 } | 312 } |
298 | 313 |
299 return true; | 314 return true; |
300 } | 315 } |
301 | 316 |
302 ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() { | 317 ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() { |
303 } | 318 } |
304 | 319 |
305 ProcessInfo::Module::~Module() { | 320 ProcessInfo::Module::~Module() { |
306 } | 321 } |
307 | 322 |
308 ProcessInfo::MemoryInfo::MemoryInfo(const MEMORY_BASIC_INFORMATION& mbi) | |
309 : base_address(reinterpret_cast<WinVMAddress>(mbi.BaseAddress)), | |
310 region_size(mbi.RegionSize), | |
311 allocation_base(reinterpret_cast<WinVMAddress>(mbi.AllocationBase)), | |
312 state(mbi.State), | |
313 allocation_protect(mbi.AllocationProtect), | |
314 protect(mbi.Protect), | |
315 type(mbi.Type) { | |
316 } | |
317 | |
318 ProcessInfo::MemoryInfo::~MemoryInfo() { | |
319 } | |
320 | |
321 ProcessInfo::ProcessInfo() | 323 ProcessInfo::ProcessInfo() |
322 : process_id_(), | 324 : process_id_(), |
323 inherited_from_process_id_(), | 325 inherited_from_process_id_(), |
324 command_line_(), | 326 command_line_(), |
325 peb_address_(0), | 327 peb_address_(0), |
326 peb_size_(0), | 328 peb_size_(0), |
327 modules_(), | 329 modules_(), |
328 memory_info_(), | 330 memory_info_(), |
329 is_64_bit_(false), | 331 is_64_bit_(false), |
330 is_wow64_(false), | 332 is_wow64_(false), |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
419 *peb_address = peb_address_; | 421 *peb_address = peb_address_; |
420 *peb_size = peb_size_; | 422 *peb_size = peb_size_; |
421 } | 423 } |
422 | 424 |
423 bool ProcessInfo::Modules(std::vector<Module>* modules) const { | 425 bool ProcessInfo::Modules(std::vector<Module>* modules) const { |
424 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 426 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
425 *modules = modules_; | 427 *modules = modules_; |
426 return true; | 428 return true; |
427 } | 429 } |
428 | 430 |
429 const std::vector<ProcessInfo::MemoryInfo>& ProcessInfo::MemoryInformation() | 431 const std::vector<MEMORY_BASIC_INFORMATION64>& ProcessInfo::MemoryInfo() const { |
430 const { | |
431 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 432 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
432 return memory_info_; | 433 return memory_info_; |
433 } | 434 } |
434 | 435 |
435 std::vector<CheckedRange<WinVMAddress, WinVMSize>> | 436 std::vector<CheckedRange<WinVMAddress, WinVMSize>> |
436 ProcessInfo::GetReadableRanges( | 437 ProcessInfo::GetReadableRanges( |
437 const CheckedRange<WinVMAddress, WinVMSize>& range) const { | 438 const CheckedRange<WinVMAddress, WinVMSize>& range) const { |
438 return GetReadableRangesOfMemoryMap(range, MemoryInformation()); | 439 return GetReadableRangesOfMemoryMap(range, MemoryInfo()); |
439 } | 440 } |
440 | 441 |
441 std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRangesOfMemoryMap( | 442 std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRangesOfMemoryMap( |
442 const CheckedRange<WinVMAddress, WinVMSize>& range, | 443 const CheckedRange<WinVMAddress, WinVMSize>& range, |
443 const std::vector<ProcessInfo::MemoryInfo>& memory_info) { | 444 const std::vector<MEMORY_BASIC_INFORMATION64>& memory_info) { |
444 using Range = CheckedRange<WinVMAddress, WinVMSize>; | 445 using Range = CheckedRange<WinVMAddress, WinVMSize>; |
445 | 446 |
446 // Find all the ranges that overlap the target range, maintaining their order. | 447 // Find all the ranges that overlap the target range, maintaining their order. |
447 std::vector<ProcessInfo::MemoryInfo> overlapping; | 448 std::vector<MEMORY_BASIC_INFORMATION64> overlapping; |
448 for (const auto& mi : memory_info) { | 449 for (const auto& mi : memory_info) { |
449 if (range.OverlapsRange(Range(mi.base_address, mi.region_size))) | 450 static_assert(std::is_same<decltype(mi.BaseAddress), WinVMAddress>::value, |
451 "expected range address to be WinVMAddress"); | |
452 static_assert(std::is_same<decltype(mi.RegionSize), WinVMSize>::value, | |
453 "expected range size to be WinVMSize"); | |
454 if (range.OverlapsRange(Range(mi.BaseAddress, mi.RegionSize))) | |
450 overlapping.push_back(mi); | 455 overlapping.push_back(mi); |
451 } | 456 } |
452 if (overlapping.empty()) | 457 if (overlapping.empty()) |
453 return std::vector<Range>(); | 458 return std::vector<Range>(); |
454 | 459 |
455 // For the first and last, trim to the boundary of the incoming range. | 460 // For the first and last, trim to the boundary of the incoming range. |
456 ProcessInfo::MemoryInfo& front = overlapping.front(); | 461 MEMORY_BASIC_INFORMATION64& front = overlapping.front(); |
457 WinVMAddress original_front_base_address = front.base_address; | 462 WinVMAddress original_front_base_address = front.BaseAddress; |
458 front.base_address = std::max(front.base_address, range.base()); | 463 front.BaseAddress = std::max(front.BaseAddress, range.base()); |
459 front.region_size = | 464 front.RegionSize = |
460 (original_front_base_address + front.region_size) - front.base_address; | 465 (original_front_base_address + front.RegionSize) - front.BaseAddress; |
461 | 466 |
462 ProcessInfo::MemoryInfo& back = overlapping.back(); | 467 MEMORY_BASIC_INFORMATION64& back = overlapping.back(); |
463 WinVMAddress back_end = back.base_address + back.region_size; | 468 WinVMAddress back_end = back.BaseAddress + back.RegionSize; |
464 back.region_size = std::min(range.end(), back_end) - back.base_address; | 469 back.RegionSize = std::min(range.end(), back_end) - back.BaseAddress; |
465 | 470 |
466 // Discard all non-accessible. | 471 // Discard all non-accessible. |
467 overlapping.erase(std::remove_if(overlapping.begin(), | 472 overlapping.erase(std::remove_if(overlapping.begin(), |
468 overlapping.end(), | 473 overlapping.end(), |
469 [](const ProcessInfo::MemoryInfo& mi) { | 474 [](const MEMORY_BASIC_INFORMATION64& mbi) { |
470 return !RegionIsAccessible(mi); | 475 return !RegionIsAccessible(mbi); |
471 }), | 476 }), |
472 overlapping.end()); | 477 overlapping.end()); |
473 if (overlapping.empty()) | 478 if (overlapping.empty()) |
474 return std::vector<Range>(); | 479 return std::vector<Range>(); |
475 | 480 |
476 // Convert to return type. | 481 // Convert to return type. |
477 std::vector<Range> as_ranges; | 482 std::vector<Range> as_ranges; |
478 for (const auto& mi : overlapping) { | 483 for (const auto& mi : overlapping) { |
479 as_ranges.push_back(Range(mi.base_address, mi.region_size)); | 484 as_ranges.push_back(Range(mi.BaseAddress, mi.RegionSize)); |
480 DCHECK(as_ranges.back().IsValid()); | 485 DCHECK(as_ranges.back().IsValid()); |
481 } | 486 } |
482 | 487 |
483 // Coalesce remaining regions. | 488 // Coalesce remaining regions. |
484 std::vector<Range> result; | 489 std::vector<Range> result; |
485 result.push_back(as_ranges[0]); | 490 result.push_back(as_ranges[0]); |
486 for (size_t i = 1; i < as_ranges.size(); ++i) { | 491 for (size_t i = 1; i < as_ranges.size(); ++i) { |
487 if (result.back().end() == as_ranges[i].base()) { | 492 if (result.back().end() == as_ranges[i].base()) { |
488 result.back().SetRange(result.back().base(), | 493 result.back().SetRange(result.back().base(), |
489 result.back().size() + as_ranges[i].size()); | 494 result.back().size() + as_ranges[i].size()); |
490 } else { | 495 } else { |
491 result.push_back(as_ranges[i]); | 496 result.push_back(as_ranges[i]); |
492 } | 497 } |
493 DCHECK(result.back().IsValid()); | 498 DCHECK(result.back().IsValid()); |
494 } | 499 } |
495 | 500 |
496 return result; | 501 return result; |
497 } | 502 } |
498 | 503 |
499 } // namespace crashpad | 504 } // namespace crashpad |
OLD | NEW |