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 |