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..5e24211a2ddb27cb70249dd2df0d0dca715051ed |
--- /dev/null |
+++ b/snapshot/win/system_snapshot_win.cc |
@@ -0,0 +1,356 @@ |
+// 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 <intrin.h> |
+#include <powrprof.h> |
+#include <windows.h> |
+#include <winnt.h> |
+ |
+#include <algorithm> |
+#include <utility> |
+#include <vector> |
+ |
+#include "base/memory/scoped_ptr.h" |
+#include "base/numerics/safe_conversions.h" |
+#include "base/strings/stringprintf.h" |
+#include "base/strings/utf_string_conversions.h" |
+ |
+namespace crashpad { |
+ |
+namespace { |
+ |
+//! \brief Gets a string representation for a VS_FIXEDFILEINFO.dwFileFlags |
+//! value. |
+std::string GetStringForFileFlags(uint32_t file_flags) { |
+ std::string result; |
+ DCHECK_EQ(file_flags & VS_FF_INFOINFERRED, 0u); |
+ if (file_flags & VS_FF_DEBUG) |
+ result += "Debug,"; |
+ if (file_flags & VS_FF_PATCHED) |
+ result += "Patched,"; |
+ if (file_flags & VS_FF_PRERELEASE) |
+ result += "Prerelease,"; |
+ if (file_flags & VS_FF_PRIVATEBUILD) |
+ result += "Private,"; |
+ if (file_flags & VS_FF_SPECIALBUILD) |
+ result += "Special,"; |
+ if (!result.empty()) |
+ return result.substr(0, result.size() - 1); // Remove trailing comma. |
+ return result; |
+} |
+ |
+//! \brief Gets a string representation for a VS_FIXEDFILEINFO.dwFileOS value. |
+std::string GetStringForFileOS(uint32_t file_os) { |
+ // There are a variety of ancient things this could theoretically be. In |
+ // practice, we're always going to get VOS_NT_WINDOWS32 here. |
+ if ((file_os & VOS_NT_WINDOWS32) == VOS_NT_WINDOWS32) |
+ return "Windows NT"; |
+ else |
+ return "Unknown"; |
+} |
+ |
+} // namespace |
+ |
+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; |
+ |
+ // We use both GetVersionEx and VerQueryValue. GetVersionEx is not trustworthy |
+ // after Windows 8 (depending on the application manifest) so its data is used |
+ // only to fill the os_server_ field, and the rest comes from the version |
+ // information stamped on kernel32.dll. |
+ OSVERSIONINFOEX version_info = {sizeof(version_info)}; |
+ if (!GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info))) { |
+ PLOG(WARNING) << "GetVersionEx"; |
+ } else { |
+ const wchar_t kSystemDll[] = L"kernel32.dll"; |
+ DWORD size = GetFileVersionInfoSize(kSystemDll, nullptr); |
+ if (!size) { |
+ PLOG(WARNING) << "GetFileVersionInfoSize"; |
+ } else { |
+ scoped_ptr<uint8_t[]> data(new uint8_t[size]); |
+ if (!GetFileVersionInfo(kSystemDll, 0, size, data.get())) { |
+ PLOG(WARNING) << "GetFileVersionInfo"; |
+ } else { |
+ VS_FIXEDFILEINFO* fixed_file_info; |
+ UINT size; |
+ if (!VerQueryValue(data.get(), |
+ L"\\", |
+ reinterpret_cast<void**>(&fixed_file_info), |
+ &size)) { |
+ PLOG(WARNING) << "VerQueryValue"; |
+ } else { |
+ uint32_t valid_flags = |
+ fixed_file_info->dwFileFlags & fixed_file_info->dwFileFlagsMask; |
+ std::string flags_string = GetStringForFileFlags(valid_flags); |
+ os_version_major_ = |
+ (fixed_file_info->dwFileVersionMS & 0xffff0000) >> 16; |
+ os_version_minor_ = fixed_file_info->dwFileVersionMS & 0xffff; |
+ os_version_bugfix_ = |
+ (fixed_file_info->dwFileVersionLS & 0xffff0000) >> 16; |
+ os_version_build_ = base::StringPrintf( |
+ "%d", fixed_file_info->dwFileVersionLS & 0xffff); |
+ os_server_ = version_info.wProductType != VER_NT_WORKSTATION; |
+ std::string os_name = GetStringForFileOS(fixed_file_info->dwFileOS); |
+ os_version_full_ = base::StringPrintf( |
+ "%s %d.%d.%d.%s%s", |
+ os_name.c_str(), |
+ os_version_major_, |
+ os_version_minor_, |
+ os_version_bugfix_, |
+ os_version_build_.c_str(), |
+ flags_string.empty() ? "" : (std::string(" (") + flags_string + |
+ ")").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_); |
+ |
+ uint32_t raw = CPUX86Signature(); |
+ uint8_t stepping = raw & 0xf; |
+ uint8_t model = (raw & 0xf0) >> 4; |
+ uint8_t family = (raw & 0xf00) >> 8; |
+ uint8_t extended_model = static_cast<uint8_t>((raw & 0xf0000) >> 16); |
+ uint16_t extended_family = (raw & 0xff00000) >> 20; |
+ |
+ // For families before 15, extended_family are simply reserved bits. |
+ if (family < 15) |
+ extended_family = 0; |
+ // extended_model is only used for families 6 and 15. |
+ if (family != 6 && family != 15) |
+ extended_model = 0; |
+ |
+ uint16_t adjusted_family = family + extended_family; |
+ uint8_t adjusted_model = model + (extended_model << 4); |
+ return (adjusted_family << 16) | (adjusted_model << 8) | stepping; |
+} |
+ |
+uint8_t SystemSnapshotWin::CPUCount() const { |
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
+ |
+ SYSTEM_INFO system_info; |
+ GetSystemInfo(&system_info); |
+ if (!base::IsValueInRangeForNumericType<uint8_t>( |
+ system_info.dwNumberOfProcessors)) { |
+ LOG(WARNING) << "dwNumberOfProcessors exceeds uint8_t storage"; |
+ } |
+ return base::saturated_cast<uint8_t>(system_info.dwNumberOfProcessors); |
+} |
+ |
+std::string SystemSnapshotWin::CPUVendor() const { |
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
+ |
+ int cpu_info[4]; |
+ __cpuid(cpu_info, 0); |
+ char vendor[12]; |
+ *reinterpret_cast<int*>(vendor) = cpu_info[1]; |
+ *reinterpret_cast<int*>(vendor + 4) = cpu_info[3]; |
+ *reinterpret_cast<int*>(vendor + 8) = cpu_info[2]; |
+ return std::string(vendor, sizeof(vendor)); |
+} |
+ |
+void SystemSnapshotWin::CPUFrequency(uint64_t* current_hz, |
+ uint64_t* max_hz) const { |
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
+ |
+ int num_cpus = CPUCount(); |
+ DCHECK_GT(num_cpus, 0); |
+ 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; |
+ } |
+ const uint64_t kMhzToHz = static_cast<uint64_t>(1E6); |
+ *current_hz = std::max_element(info.begin(), |
+ info.end(), |
+ [](const PROCESSOR_POWER_INFORMATION& a, |
+ const PROCESSOR_POWER_INFORMATION& b) { |
+ return a.CurrentMhz < b.CurrentMhz; |
+ })->CurrentMhz * |
+ kMhzToHz; |
+ *max_hz = std::max_element(info.begin(), |
+ info.end(), |
+ [](const PROCESSOR_POWER_INFORMATION& a, |
+ const PROCESSOR_POWER_INFORMATION& b) { |
+ return a.MaxMhz < b.MaxMhz; |
+ })->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]); |
+} |
+ |
+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 std::string(); |
+} |
+ |
+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 { |
+ // This returns the current time zone status rather than the status at the |
+ // time of the snapshot. This differs from the Mac implementation. |
+ TIME_ZONE_INFORMATION time_zone_information; |
+ *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 |