Chromium Code Reviews| 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 |