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 |