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> | |
|
Mark Mentovai
2015/02/27 22:27:42
Just <intrin.h>? I don’t see you using any multime
scottmg
2015/02/28 00:37:32
Done.
| |
| 18 #include <powrprof.h> | |
| 19 #include <windows.h> | |
| 20 | |
| 21 #include <algorithm> | |
| 22 #include <vector> | |
| 23 | |
| 24 #include "base/numerics/safe_conversions.h" | |
| 25 #include "base/strings/stringprintf.h" | |
| 26 #include "base/strings/utf_string_conversions.h" | |
| 27 #include "compat/win/processor_power_information.h" | |
|
Mark Mentovai
2015/02/27 22:27:42
Things in compat should be treated as system heade
scottmg
2015/02/28 00:37:32
Done.
| |
| 28 | |
| 29 namespace crashpad { | |
| 30 | |
| 31 namespace internal { | |
| 32 | |
| 33 SystemSnapshotWin::SystemSnapshotWin() | |
| 34 : SystemSnapshot(), | |
| 35 os_version_full_(), | |
| 36 os_version_build_(), | |
| 37 process_reader_(nullptr), | |
| 38 os_version_major_(0), | |
| 39 os_version_minor_(0), | |
| 40 os_version_bugfix_(0), | |
| 41 os_server_(false), | |
| 42 initialized_() { | |
| 43 } | |
| 44 | |
| 45 SystemSnapshotWin::~SystemSnapshotWin() { | |
| 46 } | |
| 47 | |
| 48 void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) { | |
| 49 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | |
| 50 | |
| 51 process_reader_ = process_reader; | |
| 52 | |
| 53 OSVERSIONINFOEX version_info = {sizeof(version_info)}; | |
| 54 if (!GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info))) { | |
|
Mark Mentovai
2015/02/27 22:27:42
The only concern here is that if the manifest does
scottmg
2015/02/28 00:37:32
Understood.
I hunted a bit more and it seems the
| |
| 55 PLOG(WARNING) << "GetVersionEx"; | |
| 56 } else { | |
| 57 os_version_major_ = version_info.dwMajorVersion; | |
| 58 os_version_minor_ = version_info.dwMinorVersion; | |
| 59 os_version_bugfix_ = version_info.dwBuildNumber; | |
| 60 if (version_info.wServicePackMajor != 0) { | |
| 61 os_version_build_ = | |
| 62 base::StringPrintf("Service Pack %u", version_info.wServicePackMajor); | |
| 63 if (version_info.wServicePackMinor != 0) { | |
| 64 os_version_build_ += | |
| 65 base::StringPrintf(".%u", version_info.wServicePackMinor); | |
| 66 } | |
| 67 } | |
| 68 os_server_ = version_info.wProductType != VER_NT_WORKSTATION; | |
| 69 // TODO(scottmg): Is there something more we can retrieve here? | |
| 70 os_version_full_ = base::StringPrintf("Windows %d.%d.%d", | |
|
Mark Mentovai
2015/02/27 22:27:42
I asked if this should be Windows NT or if there w
scottmg
2015/02/28 00:37:32
Switched to using the dwFileOS field.
| |
| 71 os_version_major_, | |
| 72 os_version_minor_, | |
| 73 os_version_bugfix_); | |
| 74 if (!os_version_build_.empty()) | |
| 75 os_version_full_ += std::string(" ") + os_version_build_; | |
| 76 } | |
| 77 | |
| 78 INITIALIZATION_STATE_SET_VALID(initialized_); | |
| 79 } | |
| 80 | |
| 81 CPUArchitecture SystemSnapshotWin::GetCPUArchitecture() const { | |
| 82 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 83 | |
| 84 return process_reader_->Is64Bit() ? kCPUArchitectureX86_64 | |
| 85 : kCPUArchitectureX86; | |
| 86 } | |
| 87 | |
| 88 uint32_t SystemSnapshotWin::CPURevision() const { | |
| 89 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 90 | |
| 91 uint32_t raw = CPUX86Signature(); | |
| 92 uint32_t stepping = raw & 0xf; | |
|
Mark Mentovai
2015/02/27 22:27:42
If you can stick this into a uint8_t…
Same with 8
scottmg
2015/02/28 00:37:32
Done.
| |
| 93 uint32_t model = (raw & 0xf0) >> 4; | |
| 94 uint32_t family = (raw & 0xf00) >> 8; | |
| 95 uint32_t extended_model = (raw & 0xf0000) >> 16; | |
| 96 uint32_t extended_family = (raw & 0xff00000) >> 20; | |
| 97 | |
| 98 if (family < 15) { | |
| 99 // For families before 15, these are simply reserved bits so ignore them. | |
| 100 extended_model = 0; | |
|
Mark Mentovai
2015/02/27 22:27:42
extended_model is valid when family is 15 or 6.
scottmg
2015/02/28 00:37:32
Done.
| |
| 101 extended_family = 0; | |
|
Mark Mentovai
2015/02/27 22:27:42
but this is correct for extended_family.
See Inte
scottmg
2015/02/28 00:37:32
Oops, that'll teach me to use Wikipedia! http://en
| |
| 102 } | |
| 103 | |
| 104 uint32_t adjusted_family = family + extended_family; | |
| 105 uint32_t adjusted_model = model + (extended_model << 4); | |
| 106 return (adjusted_family << 16) | (adjusted_model << 8) | stepping; | |
| 107 } | |
| 108 | |
| 109 uint8_t SystemSnapshotWin::CPUCount() const { | |
| 110 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 111 | |
| 112 SYSTEM_INFO system_info; | |
| 113 GetSystemInfo(&system_info); | |
| 114 if (!base::IsValueInRangeForNumericType<uint8_t>( | |
| 115 system_info.dwNumberOfProcessors)) { | |
| 116 LOG(WARNING) << "dwNumberOfProcessors exceeds uint8_t storage"; | |
| 117 } | |
| 118 return base::saturated_cast<uint8_t>(system_info.dwNumberOfProcessors); | |
| 119 } | |
| 120 | |
| 121 std::string SystemSnapshotWin::CPUVendor() const { | |
| 122 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 123 | |
| 124 int cpu_info[4]; | |
| 125 __cpuid(cpu_info, 0); | |
| 126 char vendor[12]; | |
| 127 *reinterpret_cast<int*>(vendor) = cpu_info[1]; | |
| 128 *reinterpret_cast<int*>(vendor + 4) = cpu_info[3]; | |
| 129 *reinterpret_cast<int*>(vendor + 8) = cpu_info[2]; | |
| 130 return std::string(vendor, sizeof(vendor)); | |
| 131 } | |
| 132 | |
| 133 void SystemSnapshotWin::CPUFrequency(uint64_t* current_hz, | |
| 134 uint64_t* max_hz) const { | |
| 135 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 136 | |
| 137 int num_cpus = CPUCount(); | |
| 138 DCHECK_GT(num_cpus, 0); | |
| 139 std::vector<PROCESSOR_POWER_INFORMATION> info(num_cpus); | |
| 140 if (CallNtPowerInformation(ProcessorInformation, | |
| 141 nullptr, | |
| 142 0, | |
| 143 &info[0], | |
| 144 sizeof(PROCESSOR_POWER_INFORMATION) * num_cpus) != | |
| 145 0) { | |
| 146 *current_hz = 0; | |
| 147 *max_hz = 0; | |
| 148 return; | |
| 149 } | |
| 150 const uint64_t kMhzToHz = static_cast<uint64_t>(1E6); | |
| 151 *current_hz = std::max_element(info.begin(), | |
|
Mark Mentovai
2015/02/27 22:27:42
#include <utility>
scottmg
2015/02/28 00:37:32
Done.
| |
| 152 info.end(), | |
| 153 [](const PROCESSOR_POWER_INFORMATION& a, | |
| 154 const PROCESSOR_POWER_INFORMATION& b) { | |
| 155 return a.CurrentMhz < b.CurrentMhz; | |
| 156 })->CurrentMhz * | |
| 157 kMhzToHz; | |
| 158 *max_hz = std::max_element(info.begin(), | |
| 159 info.end(), | |
| 160 [](const PROCESSOR_POWER_INFORMATION& a, | |
| 161 const PROCESSOR_POWER_INFORMATION& b) { | |
| 162 return a.MaxMhz < b.MaxMhz; | |
| 163 })->MaxMhz * | |
| 164 kMhzToHz; | |
| 165 } | |
| 166 | |
| 167 uint32_t SystemSnapshotWin::CPUX86Signature() const { | |
| 168 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 169 | |
| 170 int cpu_info[4]; | |
| 171 // We will never run on any processors that don't support at least function 1. | |
| 172 __cpuid(cpu_info, 1); | |
| 173 return cpu_info[0]; | |
| 174 } | |
| 175 | |
| 176 uint64_t SystemSnapshotWin::CPUX86Features() const { | |
| 177 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 178 | |
| 179 int cpu_info[4]; | |
| 180 // We will never run on any processors that don't support at least function 1. | |
| 181 __cpuid(cpu_info, 1); | |
| 182 return (static_cast<uint64_t>(cpu_info[2]) << 32) | | |
| 183 static_cast<uint64_t>(cpu_info[3]); | |
| 184 } | |
| 185 | |
| 186 uint64_t SystemSnapshotWin::CPUX86ExtendedFeatures() const { | |
| 187 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 188 | |
| 189 int cpu_info[4]; | |
| 190 // We will never run on any processors that don't support at least extended | |
| 191 // function 1. | |
| 192 __cpuid(cpu_info, 0x80000001); | |
| 193 return (static_cast<uint64_t>(cpu_info[2]) << 32) | | |
| 194 static_cast<uint64_t>(cpu_info[3]); | |
| 195 } | |
| 196 | |
| 197 uint32_t SystemSnapshotWin::CPUX86Leaf7Features() const { | |
| 198 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 199 | |
| 200 int cpu_info[4]; | |
| 201 | |
| 202 // Make sure leaf 7 can be called. | |
| 203 __cpuid(cpu_info, 0); | |
| 204 if (cpu_info[0] < 7) | |
| 205 return 0; | |
| 206 | |
| 207 __cpuidex(cpu_info, 7, 0); | |
| 208 return cpu_info[1]; | |
| 209 } | |
| 210 | |
| 211 bool SystemSnapshotWin::CPUX86SupportsDAZ() const { | |
| 212 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 213 | |
| 214 // The correct way to check for denormals-as-zeros (DAZ) support is to examine | |
| 215 // mxcsr mask, which can be done with fxsave. See Intel Software Developer's | |
| 216 // Manual, Volume 1: Basic Architecture (253665-051), 11.6.3 "Checking for the | |
| 217 // DAZ Flag in the MXCSR Register". Note that since this function tests for | |
| 218 // DAZ support in the CPU, it checks the mxcsr mask. Testing mxcsr would | |
| 219 // indicate whether DAZ is actually enabled, which is a per-thread context | |
| 220 // concern. | |
| 221 | |
| 222 // Test for fxsave support. | |
| 223 uint64_t features = CPUX86Features(); | |
| 224 if (!(features & (UINT64_C(1) << 24))) { | |
| 225 return false; | |
| 226 } | |
| 227 | |
| 228 // Call fxsave. | |
| 229 __declspec(align(16)) uint32_t extended_registers[128]; | |
| 230 _fxsave(&extended_registers); | |
| 231 uint32_t mxcsr_mask = extended_registers[7]; | |
| 232 | |
| 233 // Test the DAZ bit. | |
| 234 return mxcsr_mask & (1 << 6); | |
| 235 } | |
| 236 | |
| 237 SystemSnapshot::OperatingSystem SystemSnapshotWin::GetOperatingSystem() const { | |
| 238 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 239 return kOperatingSystemWindows; | |
| 240 } | |
| 241 | |
| 242 bool SystemSnapshotWin::OSServer() const { | |
| 243 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 244 return os_server_; | |
| 245 } | |
| 246 | |
| 247 void SystemSnapshotWin::OSVersion(int* major, | |
| 248 int* minor, | |
| 249 int* bugfix, | |
| 250 std::string* build) const { | |
| 251 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 252 *major = os_version_major_; | |
| 253 *minor = os_version_minor_; | |
| 254 *bugfix = os_version_bugfix_; | |
| 255 build->assign(os_version_build_); | |
| 256 } | |
| 257 | |
| 258 std::string SystemSnapshotWin::OSVersionFull() const { | |
| 259 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 260 return os_version_full_; | |
| 261 } | |
| 262 | |
| 263 std::string SystemSnapshotWin::MachineDescription() const { | |
| 264 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 265 // TODO(scottmg): Not sure if there's anything sensible to put here. | |
| 266 return std::string(); | |
| 267 } | |
| 268 | |
| 269 bool SystemSnapshotWin::NXEnabled() const { | |
| 270 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 271 return IsProcessorFeaturePresent(PF_NX_ENABLED); | |
| 272 } | |
| 273 | |
| 274 void SystemSnapshotWin::TimeZone(DaylightSavingTimeStatus* dst_status, | |
| 275 int* standard_offset_seconds, | |
| 276 int* daylight_offset_seconds, | |
| 277 std::string* standard_name, | |
| 278 std::string* daylight_name) const { | |
| 279 // This returns the current time zone status rather than the status at the | |
| 280 // time of the snapshot. This differs from the Mac implementation. | |
| 281 TIME_ZONE_INFORMATION time_zone_information; | |
| 282 *dst_status = static_cast<DaylightSavingTimeStatus>( | |
| 283 GetTimeZoneInformation(&time_zone_information)); | |
| 284 *standard_offset_seconds = | |
| 285 (time_zone_information.Bias + time_zone_information.StandardBias) * -60; | |
| 286 *daylight_offset_seconds = | |
| 287 (time_zone_information.Bias + time_zone_information.DaylightBias) * -60; | |
| 288 *standard_name = base::UTF16ToUTF8(time_zone_information.StandardName); | |
| 289 *daylight_name = base::UTF16ToUTF8(time_zone_information.DaylightName); | |
| 290 } | |
| 291 | |
| 292 } // namespace internal | |
| 293 } // namespace crashpad | |
| OLD | NEW |