Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Crashpad Authors. All rights reserved. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 | |
| 15 #include "snapshot/win/system_snapshot_win.h" | |
| 16 | |
| 17 #include <immintrin.h> | |
| 18 #include <powrprof.h> | |
| 19 #include <windows.h> | |
| 20 | |
| 21 #include <vector> | |
| 22 | |
| 23 #include "base/numerics/safe_conversions.h" | |
| 24 #include "base/strings/stringprintf.h" | |
| 25 #include "base/strings/utf_string_conversions.h" | |
| 26 | |
| 27 namespace crashpad { | |
| 28 | |
| 29 namespace internal { | |
| 30 | |
| 31 SystemSnapshotWin::SystemSnapshotWin() | |
| 32 : SystemSnapshot(), | |
| 33 os_version_full_(), | |
| 34 os_version_build_(), | |
| 35 process_reader_(nullptr), | |
| 36 os_version_major_(0), | |
| 37 os_version_minor_(0), | |
| 38 os_version_bugfix_(0), | |
| 39 os_server_(false), | |
| 40 initialized_() { | |
| 41 } | |
| 42 | |
| 43 SystemSnapshotWin::~SystemSnapshotWin() { | |
| 44 } | |
| 45 | |
| 46 void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) { | |
| 47 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | |
| 48 | |
| 49 process_reader_ = process_reader; | |
| 50 | |
| 51 OSVERSIONINFOEX version_info = {sizeof(version_info)}; | |
| 52 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
| |
| 53 PLOG(WARNING) << "GetVersionEx"; | |
| 54 } | |
| 55 os_version_major_ = version_info.dwMajorVersion; | |
| 56 os_version_minor_ = version_info.dwMinorVersion; | |
| 57 os_version_bugfix_ = version_info.dwBuildNumber; | |
| 58 os_version_build_ = | |
| 59 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.
| |
| 60 if (version_info.wServicePackMinor != 0) { | |
| 61 os_version_build_ += | |
| 62 base::StringPrintf(".%d", version_info.wServicePackMinor); | |
| 63 } | |
| 64 os_server_ = version_info.wProductType != VER_NT_WORKSTATION; | |
| 65 // TODO(scottmg): Is there something more we can retrieve here? | |
| 66 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
| |
| 67 os_version_major_, | |
| 68 os_version_minor_, | |
| 69 os_version_bugfix_, | |
| 70 os_version_build_.c_str()); | |
| 71 | |
| 72 INITIALIZATION_STATE_SET_VALID(initialized_); | |
| 73 } | |
| 74 | |
| 75 CPUArchitecture SystemSnapshotWin::GetCPUArchitecture() const { | |
| 76 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 77 | |
| 78 return process_reader_->Is64Bit() ? kCPUArchitectureX86_64 | |
| 79 : kCPUArchitectureX86; | |
| 80 } | |
| 81 | |
| 82 uint32_t SystemSnapshotWin::CPURevision() const { | |
| 83 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 84 | |
| 85 // 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.
| |
| 86 CHECK(false) << "TODO: family << 16 | model << 8 | stepping"; | |
| 87 return 0; | |
| 88 } | |
| 89 | |
| 90 uint8_t SystemSnapshotWin::CPUCount() const { | |
| 91 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 92 | |
| 93 SYSTEM_INFO system_info; | |
| 94 GetSystemInfo(&system_info); | |
| 95 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.
| |
| 96 } | |
| 97 | |
| 98 std::string SystemSnapshotWin::CPUVendor() const { | |
| 99 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 100 | |
| 101 int cpu_info[4]; | |
| 102 __cpuid(cpu_info, 0); | |
| 103 char vendor[13] = {0}; | |
| 104 *reinterpret_cast<int*>(vendor) = cpu_info[1]; | |
| 105 *reinterpret_cast<int*>(vendor + 4) = cpu_info[3]; | |
| 106 *reinterpret_cast<int*>(vendor + 8) = cpu_info[2]; | |
| 107 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.
| |
| 108 } | |
| 109 | |
| 110 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa373184.aspx: | |
| 111 // "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.
| |
| 112 struct PROCESSOR_POWER_INFORMATION { | |
| 113 ULONG Number; | |
| 114 ULONG MaxMhz; | |
| 115 ULONG CurrentMhz; | |
| 116 ULONG MhzLimit; | |
| 117 ULONG MaxIdleState; | |
| 118 ULONG CurrentIdleState; | |
| 119 }; | |
| 120 | |
| 121 void SystemSnapshotWin::CPUFrequency(uint64_t* current_hz, | |
| 122 uint64_t* max_hz) const { | |
| 123 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 124 | |
| 125 int num_cpus = CPUCount(); | |
| 126 std::vector<PROCESSOR_POWER_INFORMATION> info(num_cpus); | |
| 127 if (CallNtPowerInformation(ProcessorInformation, | |
| 128 nullptr, | |
| 129 0, | |
| 130 &info[0], | |
| 131 sizeof(PROCESSOR_POWER_INFORMATION) * num_cpus) != | |
| 132 0) { | |
| 133 *current_hz = 0; | |
| 134 *max_hz = 0; | |
| 135 return; | |
| 136 } | |
| 137 // 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.
| |
| 138 const uint64_t kMhzToHz = 1000000; | |
|
Mark Mentovai
2015/02/20 18:58:52
1E6
scottmg
2015/02/20 22:00:45
Done.
| |
| 139 *current_hz = info[0].CurrentMhz * kMhzToHz; | |
| 140 *max_hz = info[0].MaxMhz * kMhzToHz; | |
| 141 } | |
| 142 | |
| 143 uint32_t SystemSnapshotWin::CPUX86Signature() const { | |
| 144 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 145 | |
| 146 int cpu_info[4]; | |
| 147 // We will never run on any processors that don't support at least function 1. | |
| 148 __cpuid(cpu_info, 1); | |
| 149 return cpu_info[0]; | |
| 150 } | |
| 151 | |
| 152 uint64_t SystemSnapshotWin::CPUX86Features() const { | |
| 153 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 154 | |
| 155 int cpu_info[4]; | |
| 156 // We will never run on any processors that don't support at least function 1. | |
| 157 __cpuid(cpu_info, 1); | |
| 158 return (static_cast<uint64_t>(cpu_info[2]) << 32) | | |
| 159 static_cast<uint64_t>(cpu_info[3]); | |
| 160 } | |
| 161 | |
| 162 uint64_t SystemSnapshotWin::CPUX86ExtendedFeatures() const { | |
| 163 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 164 | |
| 165 int cpu_info[4]; | |
| 166 // We will never run on any processors that don't support at least extended | |
| 167 // function 1. | |
| 168 __cpuid(cpu_info, 0x80000001); | |
| 169 return (static_cast<uint64_t>(cpu_info[2]) << 32) | | |
| 170 static_cast<uint64_t>(cpu_info[3]); | |
| 171 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
| |
| 172 static_cast<uint64_t>(cpu_info[3]); | |
| 173 } | |
| 174 | |
| 175 uint32_t SystemSnapshotWin::CPUX86Leaf7Features() const { | |
| 176 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 177 | |
| 178 int cpu_info[4]; | |
| 179 | |
| 180 // Make sure leaf 7 can be called. | |
| 181 __cpuid(cpu_info, 0); | |
| 182 if (cpu_info[0] < 7) | |
| 183 return 0; | |
| 184 | |
| 185 __cpuidex(cpu_info, 7, 0); | |
| 186 return cpu_info[1]; | |
| 187 } | |
| 188 | |
| 189 bool SystemSnapshotWin::CPUX86SupportsDAZ() const { | |
| 190 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 191 | |
| 192 // The correct way to check for denormals-as-zeros (DAZ) support is to examine | |
| 193 // mxcsr mask, which can be done with fxsave. See Intel Software Developer's | |
| 194 // Manual, Volume 1: Basic Architecture (253665-051), 11.6.3 "Checking for the | |
| 195 // DAZ Flag in the MXCSR Register". Note that since this function tests for | |
| 196 // DAZ support in the CPU, it checks the mxcsr mask. Testing mxcsr would | |
| 197 // indicate whether DAZ is actually enabled, which is a per-thread context | |
| 198 // concern. | |
| 199 | |
| 200 // Test for fxsave support. | |
| 201 uint64_t features = CPUX86Features(); | |
| 202 if (!(features & (UINT64_C(1) << 24))) { | |
| 203 return false; | |
| 204 } | |
| 205 | |
| 206 // Call fxsave. | |
| 207 __declspec(align(16)) uint32_t extended_registers[128]; | |
| 208 _fxsave(&extended_registers); | |
| 209 uint32_t mxcsr_mask = extended_registers[7]; | |
| 210 | |
| 211 // Test the DAZ bit. | |
| 212 return mxcsr_mask & (1 << 6); | |
| 213 } | |
| 214 | |
| 215 SystemSnapshot::OperatingSystem SystemSnapshotWin::GetOperatingSystem() const { | |
| 216 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 217 return kOperatingSystemWindows; | |
| 218 } | |
| 219 | |
| 220 bool SystemSnapshotWin::OSServer() const { | |
| 221 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 222 return os_server_; | |
| 223 } | |
| 224 | |
| 225 void SystemSnapshotWin::OSVersion(int* major, | |
| 226 int* minor, | |
| 227 int* bugfix, | |
| 228 std::string* build) const { | |
| 229 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 230 *major = os_version_major_; | |
| 231 *minor = os_version_minor_; | |
| 232 *bugfix = os_version_bugfix_; | |
| 233 build->assign(os_version_build_); | |
| 234 } | |
| 235 | |
| 236 std::string SystemSnapshotWin::OSVersionFull() const { | |
| 237 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 238 return os_version_full_; | |
| 239 } | |
| 240 | |
| 241 std::string SystemSnapshotWin::MachineDescription() const { | |
| 242 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 243 // TODO(scottmg): Not sure if there's anything sensible to put here. | |
| 244 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.
| |
| 245 } | |
| 246 | |
| 247 bool SystemSnapshotWin::NXEnabled() const { | |
| 248 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 249 return IsProcessorFeaturePresent(PF_NX_ENABLED); | |
| 250 } | |
| 251 | |
| 252 void SystemSnapshotWin::TimeZone(DaylightSavingTimeStatus* dst_status, | |
| 253 int* standard_offset_seconds, | |
| 254 int* daylight_offset_seconds, | |
| 255 std::string* standard_name, | |
| 256 std::string* daylight_name) const { | |
| 257 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.
| |
| 258 *dst_status = static_cast<DaylightSavingTimeStatus>( | |
| 259 GetTimeZoneInformation(&time_zone_information)); | |
| 260 *standard_offset_seconds = | |
| 261 (time_zone_information.Bias + time_zone_information.StandardBias) * -60; | |
| 262 *daylight_offset_seconds = | |
| 263 (time_zone_information.Bias + time_zone_information.DaylightBias) * -60; | |
| 264 *standard_name = base::UTF16ToUTF8(time_zone_information.StandardName); | |
| 265 *daylight_name = base::UTF16ToUTF8(time_zone_information.DaylightName); | |
| 266 } | |
| 267 | |
| 268 } // namespace internal | |
| 269 } // namespace crashpad | |
| OLD | NEW |