Chromium Code Reviews| Index: snapshot/win/system_snapshot_win.cc |
| diff --git a/snapshot/win/system_snapshot_win.cc b/snapshot/win/system_snapshot_win.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a6541be82e8e6293bbec81dc258670cfe44754ca |
| --- /dev/null |
| +++ b/snapshot/win/system_snapshot_win.cc |
| @@ -0,0 +1,269 @@ |
| +// Copyright 2015 The Crashpad Authors. All rights reserved. |
| +// |
| +// Licensed under the Apache License, Version 2.0 (the "License"); |
| +// you may not use this file except in compliance with the License. |
| +// You may obtain a copy of the License at |
| +// |
| +// http://www.apache.org/licenses/LICENSE-2.0 |
| +// |
| +// Unless required by applicable law or agreed to in writing, software |
| +// distributed under the License is distributed on an "AS IS" BASIS, |
| +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| +// See the License for the specific language governing permissions and |
| +// limitations under the License. |
| + |
| +#include "snapshot/win/system_snapshot_win.h" |
| + |
| +#include <immintrin.h> |
| +#include <powrprof.h> |
| +#include <windows.h> |
| + |
| +#include <vector> |
| + |
| +#include "base/numerics/safe_conversions.h" |
| +#include "base/strings/stringprintf.h" |
| +#include "base/strings/utf_string_conversions.h" |
| + |
| +namespace crashpad { |
| + |
| +namespace internal { |
| + |
| +SystemSnapshotWin::SystemSnapshotWin() |
| + : SystemSnapshot(), |
| + os_version_full_(), |
| + os_version_build_(), |
| + process_reader_(nullptr), |
| + os_version_major_(0), |
| + os_version_minor_(0), |
| + os_version_bugfix_(0), |
| + os_server_(false), |
| + initialized_() { |
| +} |
| + |
| +SystemSnapshotWin::~SystemSnapshotWin() { |
| +} |
| + |
| +void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) { |
| + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
| + |
| + process_reader_ = process_reader; |
| + |
| + OSVERSIONINFOEX version_info = {sizeof(version_info)}; |
| + if (!GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info))) { |
|
Mark Mentovai
2015/02/20 18:58:52
Looking at the docs for GetVersionEx(), I’m learni
scottmg
2015/02/20 22:00:44
GetVersionEx works as long as the manifest is set
|
| + PLOG(WARNING) << "GetVersionEx"; |
| + } |
| + os_version_major_ = version_info.dwMajorVersion; |
| + os_version_minor_ = version_info.dwMinorVersion; |
| + os_version_bugfix_ = version_info.dwBuildNumber; |
| + os_version_build_ = |
| + base::StringPrintf("Service Pack %d", version_info.wServicePackMajor); |
|
Mark Mentovai
2015/02/20 18:58:52
If GetVersionEx() failed, you shouldn’t do this.
scottmg
2015/02/20 22:00:45
Done.
|
| + if (version_info.wServicePackMinor != 0) { |
| + os_version_build_ += |
| + base::StringPrintf(".%d", version_info.wServicePackMinor); |
| + } |
| + os_server_ = version_info.wProductType != VER_NT_WORKSTATION; |
| + // TODO(scottmg): Is there something more we can retrieve here? |
| + os_version_full_ = base::StringPrintf("Windows %d.%d.%d %s", |
|
Mark Mentovai
2015/02/20 18:58:52
Should this be Windows NT instead of Windows? Avoi
scottmg
2015/02/20 22:00:45
Changed in Service Pack, but not here. They're pri
|
| + os_version_major_, |
| + os_version_minor_, |
| + os_version_bugfix_, |
| + os_version_build_.c_str()); |
| + |
| + INITIALIZATION_STATE_SET_VALID(initialized_); |
| +} |
| + |
| +CPUArchitecture SystemSnapshotWin::GetCPUArchitecture() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + |
| + return process_reader_->Is64Bit() ? kCPUArchitectureX86_64 |
| + : kCPUArchitectureX86; |
| +} |
| + |
| +uint32_t SystemSnapshotWin::CPURevision() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + |
| + // TODO(scottmg): How does this differ from CPUX86Signature below? |
|
Mark Mentovai
2015/02/20 18:58:52
CPURevision() is not CPU architecture-specific, bu
scottmg
2015/02/20 22:00:45
Thanks for the explanation. Done.
|
| + CHECK(false) << "TODO: family << 16 | model << 8 | stepping"; |
| + return 0; |
| +} |
| + |
| +uint8_t SystemSnapshotWin::CPUCount() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + |
| + SYSTEM_INFO system_info; |
| + GetSystemInfo(&system_info); |
| + return base::saturated_cast<uint8_t>(system_info.dwNumberOfProcessors); |
|
Mark Mentovai
2015/02/20 18:58:52
Log a warning if this saturates.
scottmg
2015/02/20 22:00:45
Done.
|
| +} |
| + |
| +std::string SystemSnapshotWin::CPUVendor() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + |
| + int cpu_info[4]; |
| + __cpuid(cpu_info, 0); |
| + char vendor[13] = {0}; |
| + *reinterpret_cast<int*>(vendor) = cpu_info[1]; |
| + *reinterpret_cast<int*>(vendor + 4) = cpu_info[3]; |
| + *reinterpret_cast<int*>(vendor + 8) = cpu_info[2]; |
| + return vendor; |
|
Mark Mentovai
2015/02/20 18:58:52
std::string(vendor, 12)
or make vendor be size 12
scottmg
2015/02/20 22:00:45
Done.
|
| +} |
| + |
| +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa373184.aspx: |
| +// "Note that this structure definition was accidentally omitted from WinNT.h." |
|
Mark Mentovai
2015/02/20 18:58:52
Belongs in compat then?
scottmg
2015/02/20 22:00:45
Done.
|
| +struct PROCESSOR_POWER_INFORMATION { |
| + ULONG Number; |
| + ULONG MaxMhz; |
| + ULONG CurrentMhz; |
| + ULONG MhzLimit; |
| + ULONG MaxIdleState; |
| + ULONG CurrentIdleState; |
| +}; |
| + |
| +void SystemSnapshotWin::CPUFrequency(uint64_t* current_hz, |
| + uint64_t* max_hz) const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + |
| + int num_cpus = CPUCount(); |
| + std::vector<PROCESSOR_POWER_INFORMATION> info(num_cpus); |
| + if (CallNtPowerInformation(ProcessorInformation, |
| + nullptr, |
| + 0, |
| + &info[0], |
| + sizeof(PROCESSOR_POWER_INFORMATION) * num_cpus) != |
| + 0) { |
| + *current_hz = 0; |
| + *max_hz = 0; |
| + return; |
| + } |
| + // TODO(scottmg): Return all? Average? Current? |
|
Mark Mentovai
2015/02/20 18:58:52
Good question. Max of current and max of max?
scottmg
2015/02/20 22:00:45
Done.
|
| + const uint64_t kMhzToHz = 1000000; |
|
Mark Mentovai
2015/02/20 18:58:52
1E6
scottmg
2015/02/20 22:00:45
Done.
|
| + *current_hz = info[0].CurrentMhz * kMhzToHz; |
| + *max_hz = info[0].MaxMhz * kMhzToHz; |
| +} |
| + |
| +uint32_t SystemSnapshotWin::CPUX86Signature() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + |
| + int cpu_info[4]; |
| + // We will never run on any processors that don't support at least function 1. |
| + __cpuid(cpu_info, 1); |
| + return cpu_info[0]; |
| +} |
| + |
| +uint64_t SystemSnapshotWin::CPUX86Features() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + |
| + int cpu_info[4]; |
| + // We will never run on any processors that don't support at least function 1. |
| + __cpuid(cpu_info, 1); |
| + return (static_cast<uint64_t>(cpu_info[2]) << 32) | |
| + static_cast<uint64_t>(cpu_info[3]); |
| +} |
| + |
| +uint64_t SystemSnapshotWin::CPUX86ExtendedFeatures() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + |
| + int cpu_info[4]; |
| + // We will never run on any processors that don't support at least extended |
| + // function 1. |
| + __cpuid(cpu_info, 0x80000001); |
| + return (static_cast<uint64_t>(cpu_info[2]) << 32) | |
| + static_cast<uint64_t>(cpu_info[3]); |
| + return (static_cast<uint64_t>(cpu_info[2]) << 32) | |
|
Mark Mentovai
2015/02/20 18:58:52
You already returned this.
scottmg
2015/02/20 22:00:45
Hm, maybe I should look into enabling the unreacha
|
| + static_cast<uint64_t>(cpu_info[3]); |
| +} |
| + |
| +uint32_t SystemSnapshotWin::CPUX86Leaf7Features() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + |
| + int cpu_info[4]; |
| + |
| + // Make sure leaf 7 can be called. |
| + __cpuid(cpu_info, 0); |
| + if (cpu_info[0] < 7) |
| + return 0; |
| + |
| + __cpuidex(cpu_info, 7, 0); |
| + return cpu_info[1]; |
| +} |
| + |
| +bool SystemSnapshotWin::CPUX86SupportsDAZ() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + |
| + // The correct way to check for denormals-as-zeros (DAZ) support is to examine |
| + // mxcsr mask, which can be done with fxsave. See Intel Software Developer's |
| + // Manual, Volume 1: Basic Architecture (253665-051), 11.6.3 "Checking for the |
| + // DAZ Flag in the MXCSR Register". Note that since this function tests for |
| + // DAZ support in the CPU, it checks the mxcsr mask. Testing mxcsr would |
| + // indicate whether DAZ is actually enabled, which is a per-thread context |
| + // concern. |
| + |
| + // Test for fxsave support. |
| + uint64_t features = CPUX86Features(); |
| + if (!(features & (UINT64_C(1) << 24))) { |
| + return false; |
| + } |
| + |
| + // Call fxsave. |
| + __declspec(align(16)) uint32_t extended_registers[128]; |
| + _fxsave(&extended_registers); |
| + uint32_t mxcsr_mask = extended_registers[7]; |
| + |
| + // Test the DAZ bit. |
| + return mxcsr_mask & (1 << 6); |
| +} |
| + |
| +SystemSnapshot::OperatingSystem SystemSnapshotWin::GetOperatingSystem() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return kOperatingSystemWindows; |
| +} |
| + |
| +bool SystemSnapshotWin::OSServer() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return os_server_; |
| +} |
| + |
| +void SystemSnapshotWin::OSVersion(int* major, |
| + int* minor, |
| + int* bugfix, |
| + std::string* build) const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + *major = os_version_major_; |
| + *minor = os_version_minor_; |
| + *bugfix = os_version_bugfix_; |
| + build->assign(os_version_build_); |
| +} |
| + |
| +std::string SystemSnapshotWin::OSVersionFull() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return os_version_full_; |
| +} |
| + |
| +std::string SystemSnapshotWin::MachineDescription() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + // TODO(scottmg): Not sure if there's anything sensible to put here. |
| + return ""; |
|
Mark Mentovai
2015/02/20 18:58:52
std::string() (I was reminded of this during the r
scottmg
2015/02/20 22:00:45
Done.
|
| +} |
| + |
| +bool SystemSnapshotWin::NXEnabled() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return IsProcessorFeaturePresent(PF_NX_ENABLED); |
| +} |
| + |
| +void SystemSnapshotWin::TimeZone(DaylightSavingTimeStatus* dst_status, |
| + int* standard_offset_seconds, |
| + int* daylight_offset_seconds, |
| + std::string* standard_name, |
| + std::string* daylight_name) const { |
| + TIME_ZONE_INFORMATION time_zone_information; |
|
Mark Mentovai
2015/02/20 18:58:52
Comment that this returns the current time zone st
scottmg
2015/02/20 22:00:45
Done.
|
| + *dst_status = static_cast<DaylightSavingTimeStatus>( |
| + GetTimeZoneInformation(&time_zone_information)); |
| + *standard_offset_seconds = |
| + (time_zone_information.Bias + time_zone_information.StandardBias) * -60; |
| + *daylight_offset_seconds = |
| + (time_zone_information.Bias + time_zone_information.DaylightBias) * -60; |
| + *standard_name = base::UTF16ToUTF8(time_zone_information.StandardName); |
| + *daylight_name = base::UTF16ToUTF8(time_zone_information.DaylightName); |
| +} |
| + |
| +} // namespace internal |
| +} // namespace crashpad |