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 |