mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
win: Add implementation of system_snapshot for Windows
ProcessReaderWin only a stub for now. R=mark@chromium.org BUG=crashpad:1 Review URL: https://codereview.chromium.org/936333004
This commit is contained in:
parent
40b931bd8e
commit
bcc580e561
@ -31,6 +31,7 @@
|
||||
'non_win/windows.h',
|
||||
'non_win/winnt.h',
|
||||
'win/sys/types.h',
|
||||
'win/winnt.h',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="mac"', {
|
||||
|
32
compat/win/winnt.h
Normal file
32
compat/win/winnt.h
Normal file
@ -0,0 +1,32 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CRASHPAD_COMPAT_WIN_WINNT_H_
|
||||
#define CRASHPAD_COMPAT_WIN_WINNT_H_
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa373184.aspx:
|
||||
// "Note that this structure definition was accidentally omitted from WinNT.h."
|
||||
struct PROCESSOR_POWER_INFORMATION {
|
||||
ULONG Number;
|
||||
ULONG MaxMhz;
|
||||
ULONG CurrentMhz;
|
||||
ULONG MhzLimit;
|
||||
ULONG MaxIdleState;
|
||||
ULONG CurrentIdleState;
|
||||
};
|
||||
|
||||
// include_next <winnt.h>
|
||||
#include <../um/winnt.h>
|
||||
|
||||
#endif // CRASHPAD_COMPAT_WIN_WINNT_H_
|
@ -78,7 +78,21 @@
|
||||
'process_snapshot.h',
|
||||
'system_snapshot.h',
|
||||
'thread_snapshot.h',
|
||||
'win/process_reader_win.cc',
|
||||
'win/process_reader_win.h',
|
||||
'win/system_snapshot_win.cc',
|
||||
'win/system_snapshot_win.h',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
'-lpowrprof.lib',
|
||||
'-lversion.lib',
|
||||
],
|
||||
},
|
||||
}],
|
||||
]
|
||||
},
|
||||
{
|
||||
'target_name': 'snapshot_test_lib',
|
||||
@ -135,6 +149,7 @@
|
||||
'mac/process_types_test.cc',
|
||||
'mac/system_snapshot_mac_test.cc',
|
||||
'minidump/process_snapshot_minidump_test.cc',
|
||||
'win/system_snapshot_win_test.cc',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -38,6 +38,9 @@ class SystemSnapshot {
|
||||
|
||||
//! \brief Mac OS X.
|
||||
kOperatingSystemMacOSX,
|
||||
|
||||
//! \brief Windows.
|
||||
kOperatingSystemWindows,
|
||||
};
|
||||
|
||||
//! \brief A system’s daylight saving time status.
|
||||
|
34
snapshot/win/process_reader_win.cc
Normal file
34
snapshot/win/process_reader_win.cc
Normal file
@ -0,0 +1,34 @@
|
||||
// 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/process_reader_win.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
ProcessReaderWin::ProcessReaderWin()
|
||||
: initialized_(),
|
||||
is_64_bit_(false) {
|
||||
}
|
||||
|
||||
ProcessReaderWin::~ProcessReaderWin() {
|
||||
}
|
||||
|
||||
bool ProcessReaderWin::Initialize(HANDLE process) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
53
snapshot/win/process_reader_win.h
Normal file
53
snapshot/win/process_reader_win.h
Normal file
@ -0,0 +1,53 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CRASHPAD_SNAPSHOT_WIN_PROCESS_READER_WIN_H_
|
||||
#define CRASHPAD_SNAPSHOT_WIN_PROCESS_READER_WIN_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief Accesses information about another process, identified by a HANDLE.
|
||||
class ProcessReaderWin {
|
||||
public:
|
||||
ProcessReaderWin();
|
||||
~ProcessReaderWin();
|
||||
|
||||
//! \brief Initializes this object. This method must be called before any
|
||||
//! other.
|
||||
//!
|
||||
//! \param[in] process Process handle, must have PROCESS_QUERY_INFORMATION,
|
||||
//! PROCESS_VM_READ, and PROCESS_DUP_HANDLE access.
|
||||
//!
|
||||
//! \return `true` on success, indicating that this object will respond
|
||||
//! validly to further method calls. `false` on failure. On failure, no
|
||||
//! further method calls should be made.
|
||||
bool Initialize(HANDLE process);
|
||||
|
||||
//! \return `true` if the target task is a 64-bit process.
|
||||
bool Is64Bit() const { return is_64_bit_; }
|
||||
|
||||
private:
|
||||
bool is_64_bit_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcessReaderWin);
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_WIN_PROCESS_READER_WIN_H_
|
356
snapshot/win/system_snapshot_win.cc
Normal file
356
snapshot/win/system_snapshot_win.cc
Normal file
@ -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
|
96
snapshot/win/system_snapshot_win.h
Normal file
96
snapshot/win/system_snapshot_win.h
Normal file
@ -0,0 +1,96 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CRASHPAD_SNAPSHOT_WIN_SYSTEM_SNAPSHOT_WIN_H_
|
||||
#define CRASHPAD_SNAPSHOT_WIN_SYSTEM_SNAPSHOT_WIN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "snapshot/system_snapshot.h"
|
||||
#include "snapshot/win/process_reader_win.h"
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
class ProcessReaderWin;
|
||||
|
||||
namespace internal {
|
||||
|
||||
//! \brief A SystemSnapshot of the running system, when the system runs Windows.
|
||||
class SystemSnapshotWin final : public SystemSnapshot {
|
||||
public:
|
||||
SystemSnapshotWin();
|
||||
~SystemSnapshotWin() override;
|
||||
|
||||
//! \brief Initializes the object.
|
||||
//!
|
||||
//! \param[in] process_reader A reader for the process being snapshotted.
|
||||
//!
|
||||
//! It seems odd that a system snapshot implementation would need a
|
||||
//! ProcessReaderWin, but some of the information reported about the
|
||||
//! system depends on the process it's being reported for. For example,
|
||||
//! the architecture returned by GetCPUArchitecture() should be the
|
||||
//! architecture of the process, which may be different than the native
|
||||
//! architecture of the system: an x86_64 system can run both x86_64 and
|
||||
//! 32-bit x86 processes.
|
||||
void Initialize(ProcessReaderWin* process_reader);
|
||||
|
||||
// SystemSnapshot:
|
||||
|
||||
CPUArchitecture GetCPUArchitecture() const override;
|
||||
uint32_t CPURevision() const override;
|
||||
uint8_t CPUCount() const override;
|
||||
std::string CPUVendor() const override;
|
||||
void CPUFrequency(uint64_t* current_hz, uint64_t* max_hz) const override;
|
||||
uint32_t CPUX86Signature() const override;
|
||||
uint64_t CPUX86Features() const override;
|
||||
uint64_t CPUX86ExtendedFeatures() const override;
|
||||
uint32_t CPUX86Leaf7Features() const override;
|
||||
bool CPUX86SupportsDAZ() const override;
|
||||
OperatingSystem GetOperatingSystem() const override;
|
||||
bool OSServer() const override;
|
||||
void OSVersion(int* major,
|
||||
int* minor,
|
||||
int* bugfix,
|
||||
std::string* build) const override;
|
||||
std::string OSVersionFull() const override;
|
||||
bool NXEnabled() const override;
|
||||
std::string MachineDescription() const override;
|
||||
void TimeZone(DaylightSavingTimeStatus* dst_status,
|
||||
int* standard_offset_seconds,
|
||||
int* daylight_offset_seconds,
|
||||
std::string* standard_name,
|
||||
std::string* daylight_name) const override;
|
||||
|
||||
private:
|
||||
std::string os_version_full_;
|
||||
std::string os_version_build_;
|
||||
ProcessReaderWin* process_reader_; // weak
|
||||
int os_version_major_;
|
||||
int os_version_minor_;
|
||||
int os_version_bugfix_;
|
||||
bool os_server_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SystemSnapshotWin);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_WIN_SYSTEM_SNAPSHOT_WIN_H_
|
156
snapshot/win/system_snapshot_win_test.cc
Normal file
156
snapshot/win/system_snapshot_win_test.cc
Normal file
@ -0,0 +1,156 @@
|
||||
// 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 <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "snapshot/win/process_reader_win.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
class SystemSnapshotWinTest : public testing::Test {
|
||||
public:
|
||||
SystemSnapshotWinTest()
|
||||
: Test(),
|
||||
process_reader_(),
|
||||
system_snapshot_() {
|
||||
}
|
||||
|
||||
const internal::SystemSnapshotWin& system_snapshot() const {
|
||||
return system_snapshot_;
|
||||
}
|
||||
|
||||
// testing::Test:
|
||||
void SetUp() override {
|
||||
ASSERT_TRUE(process_reader_.Initialize(GetCurrentProcess()));
|
||||
system_snapshot_.Initialize(&process_reader_);
|
||||
}
|
||||
|
||||
private:
|
||||
ProcessReaderWin process_reader_;
|
||||
internal::SystemSnapshotWin system_snapshot_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SystemSnapshotWinTest);
|
||||
};
|
||||
|
||||
TEST_F(SystemSnapshotWinTest, GetCPUArchitecture) {
|
||||
CPUArchitecture cpu_architecture = system_snapshot().GetCPUArchitecture();
|
||||
|
||||
#if defined(ARCH_CPU_X86)
|
||||
EXPECT_EQ(kCPUArchitectureX86, cpu_architecture);
|
||||
#elif defined(ARCH_CPU_X86_64)
|
||||
EXPECT_EQ(kCPUArchitectureX86_64, cpu_architecture);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(SystemSnapshotWinTest, CPUCount) {
|
||||
EXPECT_GE(system_snapshot().CPUCount(), 1);
|
||||
}
|
||||
|
||||
TEST_F(SystemSnapshotWinTest, CPUVendor) {
|
||||
std::string cpu_vendor = system_snapshot().CPUVendor();
|
||||
|
||||
// There are a variety of other values, but we don't expect to run our tests
|
||||
// on them.
|
||||
EXPECT_TRUE(cpu_vendor == "GenuineIntel" || cpu_vendor == "AuthenticAMD");
|
||||
}
|
||||
|
||||
TEST_F(SystemSnapshotWinTest, CPUX86SupportsDAZ) {
|
||||
// Most SSE2+ machines support Denormals-Are-Zero. This may fail if run on
|
||||
// older machines.
|
||||
EXPECT_TRUE(system_snapshot().CPUX86SupportsDAZ());
|
||||
}
|
||||
|
||||
TEST_F(SystemSnapshotWinTest, GetOperatingSystem) {
|
||||
EXPECT_EQ(SystemSnapshot::kOperatingSystemWindows,
|
||||
system_snapshot().GetOperatingSystem());
|
||||
}
|
||||
|
||||
TEST_F(SystemSnapshotWinTest, OSVersion) {
|
||||
int major;
|
||||
int minor;
|
||||
int bugfix;
|
||||
std::string build;
|
||||
system_snapshot().OSVersion(&major, &minor, &bugfix, &build);
|
||||
|
||||
EXPECT_GE(major, 5);
|
||||
if (major == 5)
|
||||
EXPECT_GE(minor, 1);
|
||||
if (major == 6)
|
||||
EXPECT_TRUE(minor >= 0 && minor <= 3);
|
||||
}
|
||||
|
||||
TEST_F(SystemSnapshotWinTest, OSVersionFull) {
|
||||
EXPECT_FALSE(system_snapshot().OSVersionFull().empty());
|
||||
}
|
||||
|
||||
TEST_F(SystemSnapshotWinTest, MachineDescription) {
|
||||
EXPECT_TRUE(system_snapshot().MachineDescription().empty());
|
||||
}
|
||||
|
||||
TEST_F(SystemSnapshotWinTest, TimeZone) {
|
||||
SystemSnapshot::DaylightSavingTimeStatus dst_status;
|
||||
int standard_offset_seconds;
|
||||
int daylight_offset_seconds;
|
||||
std::string standard_name;
|
||||
std::string daylight_name;
|
||||
|
||||
system_snapshot().TimeZone(&dst_status,
|
||||
&standard_offset_seconds,
|
||||
&daylight_offset_seconds,
|
||||
&standard_name,
|
||||
&daylight_name);
|
||||
|
||||
// |standard_offset_seconds| gives seconds east of UTC, and |timezone| gives
|
||||
// seconds west of UTC.
|
||||
EXPECT_EQ(-timezone, standard_offset_seconds);
|
||||
|
||||
// In contemporary usage, most time zones have an integer hour offset from
|
||||
// UTC, although several are at a half-hour offset, and two are at 15-minute
|
||||
// offsets. Throughout history, other variations existed. See
|
||||
// http://www.timeanddate.com/time/time-zones-interesting.html.
|
||||
EXPECT_EQ(0, standard_offset_seconds % (15 * 60))
|
||||
<< "standard_offset_seconds " << standard_offset_seconds;
|
||||
|
||||
if (dst_status == SystemSnapshot::kDoesNotObserveDaylightSavingTime) {
|
||||
EXPECT_EQ(standard_offset_seconds, daylight_offset_seconds);
|
||||
EXPECT_EQ(standard_name, daylight_name);
|
||||
} else {
|
||||
EXPECT_EQ(0, daylight_offset_seconds % (15 * 60))
|
||||
<< "daylight_offset_seconds " << daylight_offset_seconds;
|
||||
|
||||
// In contemporary usage, dst_delta_seconds will almost always be one hour,
|
||||
// except for Lord Howe Island, Australia, which uses a 30-minute
|
||||
// delta. Throughout history, other variations existed. See
|
||||
// http://www.timeanddate.com/time/dst/#brief.
|
||||
int dst_delta_seconds = daylight_offset_seconds - standard_offset_seconds;
|
||||
if (dst_delta_seconds != 60 * 60 && dst_delta_seconds != 30 * 60) {
|
||||
FAIL() << "dst_delta_seconds " << dst_delta_seconds;
|
||||
}
|
||||
|
||||
EXPECT_NE(standard_name, daylight_name);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
Loading…
x
Reference in New Issue
Block a user