mirror of
https://github.com/chromium/crashpad.git
synced 2025-01-15 01:57:58 +08:00
032f1aecc2
Add direct includes for things provided transitively by logging.h (or by other headers including logging.h). This is in preparation for cleaning up unnecessary includes of logging.h in header files (so if something depends on logging.h, it needs include it explicitly), and for when Chromium's logging.h no longer includes check.h, check_op.h, and notreached.h. DEPS is also updated to roll mini_chromium to ae14a14ab4 which includes these new header files. Bug: chromium:1031540 Change-Id: I36f646d0a93854989dc602d0dc7139dd7a7b8621 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2250251 Commit-Queue: Hans Wennborg <hans@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
417 lines
13 KiB
C++
417 lines
13 KiB
C++
// 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 <windows.h>
|
|
#include <intrin.h>
|
|
#include <powrprof.h>
|
|
#include <winnt.h>
|
|
|
|
#include <algorithm>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "base/logging.h"
|
|
#include "base/numerics/safe_conversions.h"
|
|
#include "base/strings/stringprintf.h"
|
|
#include "base/strings/utf_string_conversions.h"
|
|
#include "build/build_config.h"
|
|
#include "util/win/module_version.h"
|
|
#include "util/win/scoped_registry_key.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 GetModuleVersionAndType() (which uses
|
|
// VerQueryValue() internally). 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 {
|
|
os_server_ = version_info.wProductType != VER_NT_WORKSTATION;
|
|
}
|
|
|
|
static constexpr wchar_t kSystemDll[] = L"kernel32.dll";
|
|
VS_FIXEDFILEINFO ffi;
|
|
if (GetModuleVersionAndType(base::FilePath(kSystemDll), &ffi)) {
|
|
std::string flags_string = GetStringForFileFlags(ffi.dwFileFlags);
|
|
std::string os_name = GetStringForFileOS(ffi.dwFileOS);
|
|
os_version_major_ = ffi.dwFileVersionMS >> 16;
|
|
os_version_minor_ = ffi.dwFileVersionMS & 0xffff;
|
|
os_version_bugfix_ = ffi.dwFileVersionLS >> 16;
|
|
os_version_build_ = base::StringPrintf("%lu", ffi.dwFileVersionLS & 0xffff);
|
|
os_version_full_ = base::StringPrintf(
|
|
"%s %u.%u.%u.%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_);
|
|
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
return process_reader_->Is64Bit() ? kCPUArchitectureX86_64
|
|
: kCPUArchitectureX86;
|
|
#elif defined(ARCH_CPU_ARM64)
|
|
return kCPUArchitectureARM64;
|
|
#else
|
|
#error Unsupported Windows Arch
|
|
#endif
|
|
}
|
|
|
|
uint32_t SystemSnapshotWin::CPURevision() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
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;
|
|
#elif defined(ARCH_CPU_ARM64)
|
|
SYSTEM_INFO system_info;
|
|
GetSystemInfo(&system_info);
|
|
|
|
return system_info.wProcessorRevision;
|
|
#else
|
|
#error Unsupported Windows Arch
|
|
#endif
|
|
}
|
|
|
|
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_);
|
|
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
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));
|
|
#elif defined(ARCH_CPU_ARM64)
|
|
HKEY key;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&key) != ERROR_SUCCESS) {
|
|
return std::string();
|
|
}
|
|
|
|
crashpad::ScopedRegistryKey scoped_key(key);
|
|
DWORD type;
|
|
wchar_t vendor_identifier[1024];
|
|
DWORD vendor_identifier_size = sizeof(vendor_identifier);
|
|
|
|
if (RegQueryValueEx(key,
|
|
L"VendorIdentifier",
|
|
nullptr,
|
|
&type,
|
|
reinterpret_cast<BYTE*>(vendor_identifier),
|
|
&vendor_identifier_size) != ERROR_SUCCESS ||
|
|
type != REG_SZ) {
|
|
return std::string();
|
|
}
|
|
|
|
std::string return_value;
|
|
DCHECK_EQ(vendor_identifier_size % sizeof(wchar_t), 0u);
|
|
base::UTF16ToUTF8(vendor_identifier,
|
|
vendor_identifier_size / sizeof(wchar_t),
|
|
&return_value);
|
|
|
|
return return_value.c_str();
|
|
#else
|
|
#error Unsupported Windows Arch
|
|
#endif
|
|
}
|
|
|
|
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;
|
|
}
|
|
constexpr 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_);
|
|
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
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];
|
|
#else
|
|
NOTREACHED();
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
uint64_t SystemSnapshotWin::CPUX86Features() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
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]);
|
|
#else
|
|
NOTREACHED();
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
uint64_t SystemSnapshotWin::CPUX86ExtendedFeatures() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
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]);
|
|
#else
|
|
NOTREACHED();
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
uint32_t SystemSnapshotWin::CPUX86Leaf7Features() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
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];
|
|
#else
|
|
NOTREACHED();
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
bool SystemSnapshotWin::CPUX86SupportsDAZ() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
// 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)) != 0;
|
|
#else
|
|
NOTREACHED();
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
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
|