Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(547)

Side by Side Diff: snapshot/system_snapshot_mac.cc

Issue 666483002: Create snapshot/mac and move some files from snapshot and util to there (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad/+/master
Patch Set: Move process_reader, process_types, and mach_o_image*_reader from util/mac to snapshot/mac Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « snapshot/system_snapshot_mac.h ('k') | snapshot/system_snapshot_mac_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 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/system_snapshot_mac.h"
16
17 #include <sys/sysctl.h>
18 #include <sys/types.h>
19 #include <sys/utsname.h>
20 #include <time.h>
21
22 #include "base/logging.h"
23 #include "base/strings/stringprintf.h"
24 #include "build/build_config.h"
25 #include "snapshot/cpu_context.h"
26 #include "util/mac/mac_util.h"
27 #include "util/mac/process_reader.h"
28 #include "util/numeric/in_range_cast.h"
29
30 namespace crashpad {
31
32 namespace {
33
34 template <typename T>
35 T ReadIntSysctlByName(const char* name, T default_value) {
36 T value;
37 size_t value_len = sizeof(value);
38 if (sysctlbyname(name, &value, &value_len, nullptr, 0) != 0) {
39 PLOG(WARNING) << "sysctlbyname " << name;
40 return default_value;
41 }
42
43 return value;
44 }
45
46 template <typename T>
47 T CastIntSysctlByName(const char* name, T default_value) {
48 int int_value = ReadIntSysctlByName<int>(name, default_value);
49 return InRangeCast<T>(int_value, default_value);
50 }
51
52 std::string ReadStringSysctlByName(const char* name) {
53 size_t buf_len;
54 if (sysctlbyname(name, nullptr, &buf_len, nullptr, 0) != 0) {
55 PLOG(WARNING) << "sysctlbyname (size) " << name;
56 return std::string();
57 }
58
59 if (buf_len == 0) {
60 return std::string();
61 }
62
63 std::string value(buf_len - 1, '\0');
64 if (sysctlbyname(name, &value[0], &buf_len, nullptr, 0) != 0) {
65 PLOG(WARNING) << "sysctlbyname " << name;
66 return std::string();
67 }
68
69 return value;
70 }
71
72 #if defined(ARCH_CPU_X86_FAMILY)
73 void CallCPUID(uint32_t leaf,
74 uint32_t* eax,
75 uint32_t* ebx,
76 uint32_t* ecx,
77 uint32_t* edx) {
78 asm("cpuid"
79 : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
80 : "a"(leaf), "b"(0), "c"(0), "d"(0));
81 }
82 #endif
83
84 } // namespace
85
86 namespace internal {
87
88 SystemSnapshotMac::SystemSnapshotMac()
89 : SystemSnapshot(),
90 os_version_full_(),
91 os_version_build_(),
92 process_reader_(nullptr),
93 snapshot_time_(nullptr),
94 os_version_major_(0),
95 os_version_minor_(0),
96 os_version_bugfix_(0),
97 os_server_(false),
98 initialized_() {
99 }
100
101 SystemSnapshotMac::~SystemSnapshotMac() {
102 }
103
104 void SystemSnapshotMac::Initialize(ProcessReader* process_reader,
105 const timeval* snapshot_time) {
106 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
107
108 process_reader_ = process_reader;
109 snapshot_time_ = snapshot_time;
110
111 // MacOSXVersion() logs its own warnings if it can’t figure anything out. It’s
112 // not fatal if this happens. The default values are reasonable.
113 std::string os_version_string;
114 MacOSXVersion(&os_version_major_,
115 &os_version_minor_,
116 &os_version_bugfix_,
117 &os_version_build_,
118 &os_server_,
119 &os_version_string);
120
121 std::string uname_string;
122 utsname uts;
123 if (uname(&uts) != 0) {
124 PLOG(WARNING) << "uname";
125 } else {
126 uname_string = base::StringPrintf(
127 "%s %s %s %s", uts.sysname, uts.release, uts.version, uts.machine);
128 }
129
130 if (!os_version_string.empty()) {
131 if (!uname_string.empty()) {
132 os_version_full_ = base::StringPrintf(
133 "%s; %s", os_version_string.c_str(), uname_string.c_str());
134 } else {
135 os_version_full_ = os_version_string;
136 }
137 } else {
138 os_version_full_ = uname_string;
139 }
140
141 INITIALIZATION_STATE_SET_VALID(initialized_);
142 }
143
144 CPUArchitecture SystemSnapshotMac::GetCPUArchitecture() const {
145 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
146
147 #if defined(ARCH_CPU_X86_FAMILY)
148 return process_reader_->Is64Bit() ? kCPUArchitectureX86_64
149 : kCPUArchitectureX86;
150 #else
151 #error port to your architecture
152 #endif
153 }
154
155 uint32_t SystemSnapshotMac::CPURevision() const {
156 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
157
158 #if defined(ARCH_CPU_X86_FAMILY)
159 // machdep.cpu.family and machdep.cpu.model already take the extended family
160 // and model IDs into account. See 10.9.2 xnu-2422.90.20/osfmk/i386/cpuid.c
161 // cpuid_set_generic_info().
162 uint16_t family = CastIntSysctlByName<uint16_t>("machdep.cpu.family", 0);
163 uint8_t model = CastIntSysctlByName<uint8_t>("machdep.cpu.model", 0);
164 uint8_t stepping = CastIntSysctlByName<uint8_t>("machdep.cpu.stepping", 0);
165
166 return (family << 16) | (model << 8) | stepping;
167 #else
168 #error port to your architecture
169 #endif
170 }
171
172 uint8_t SystemSnapshotMac::CPUCount() const {
173 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
174 return CastIntSysctlByName<uint8_t>("hw.ncpu", 1);
175 }
176
177 std::string SystemSnapshotMac::CPUVendor() const {
178 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
179
180 #if defined(ARCH_CPU_X86_FAMILY)
181 return ReadStringSysctlByName("machdep.cpu.vendor");
182 #else
183 #error port to your architecture
184 #endif
185 }
186
187 void SystemSnapshotMac::CPUFrequency(
188 uint64_t* current_hz, uint64_t* max_hz) const {
189 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
190 *current_hz = ReadIntSysctlByName<uint64_t>("hw.cpufrequency", 0);
191 *max_hz = ReadIntSysctlByName<uint64_t>("hw.cpufrequency_max", 0);
192 }
193
194 uint32_t SystemSnapshotMac::CPUX86Signature() const {
195 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
196
197 #if defined(ARCH_CPU_X86_FAMILY)
198 return ReadIntSysctlByName<uint32_t>("machdep.cpu.signature", 0);
199 #else
200 NOTREACHED();
201 return 0;
202 #endif
203 }
204
205 uint64_t SystemSnapshotMac::CPUX86Features() const {
206 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
207
208 #if defined(ARCH_CPU_X86_FAMILY)
209 return ReadIntSysctlByName<uint64_t>("machdep.cpu.feature_bits", 0);
210 #else
211 NOTREACHED();
212 return 0;
213 #endif
214 }
215
216 uint64_t SystemSnapshotMac::CPUX86ExtendedFeatures() const {
217 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
218
219 #if defined(ARCH_CPU_X86_FAMILY)
220 return ReadIntSysctlByName<uint64_t>("machdep.cpu.extfeature_bits", 0);
221 #else
222 NOTREACHED();
223 return 0;
224 #endif
225 }
226
227 uint32_t SystemSnapshotMac::CPUX86Leaf7Features() const {
228 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
229
230 #if defined(ARCH_CPU_X86_FAMILY)
231 // The machdep.cpu.leaf7_feature_bits sysctl isn’t supported prior to Mac OS X
232 // 10.7, so read this by calling cpuid directly.
233 //
234 // machdep.cpu.max_basic could be used to check whether to read the leaf, but
235 // that sysctl isn’t supported prior to Mac OS X 10.6, so read the maximum
236 // basic leaf by calling cpuid directly as well. All CPUs that Apple is known
237 // to have shipped should support a maximum basic leaf value of at least 0xa.
238 uint32_t eax, ebx, ecx, edx;
239 CallCPUID(0, &eax, &ebx, &ecx, &edx);
240 if (eax < 7) {
241 return 0;
242 }
243
244 CallCPUID(7, &eax, &ebx, &ecx, &edx);
245 return ebx;
246 #else
247 NOTREACHED();
248 return 0;
249 #endif
250 }
251
252 bool SystemSnapshotMac::CPUX86SupportsDAZ() const {
253 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
254
255 #if defined(ARCH_CPU_X86_FAMILY)
256 // The correct way to check for denormals-as-zeros (DAZ) support is to examine
257 // mxcsr mask, which can be done with fxsave. See Intel Software Developer’s
258 // Manual, Volume 1: Basic Architecture (253665-051), 11.6.3 “Checking for the
259 // DAZ Flag in the MXCSR Register”. Note that since this function tests for
260 // DAZ support in the CPU, it checks the mxcsr mask. Testing mxcsr would
261 // indicate whether DAZ is actually enabled, which is a per-thread context
262 // concern.
263 //
264 // All CPUs that Apple is known to have shipped should support DAZ.
265
266 // Test for fxsave support.
267 uint64_t features = CPUX86Features();
268 if (!(features & (UINT64_C(1) << 24))) {
269 return false;
270 }
271
272 // Call fxsave.
273 #if defined(ARCH_CPU_X86)
274 CPUContextX86::Fxsave fxsave __attribute__((aligned(16))) = {};
275 #elif defined(ARCH_CPU_X86_64)
276 CPUContextX86_64::Fxsave fxsave __attribute__((aligned(16))) = {};
277 #endif
278 static_assert(sizeof(fxsave) == 512, "fxsave size");
279 static_assert(offsetof(decltype(fxsave), mxcsr_mask) == 28,
280 "mxcsr_mask offset");
281 asm("fxsave %0" : "=m"(fxsave));
282
283 // Test the DAZ bit.
284 return fxsave.mxcsr_mask & (1 << 6);
285 #else
286 NOTREACHED();
287 return false;
288 #endif
289 }
290
291 SystemSnapshot::OperatingSystem SystemSnapshotMac::GetOperatingSystem() const {
292 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
293 return kOperatingSystemMacOSX;
294 }
295
296 bool SystemSnapshotMac::OSServer() const {
297 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
298 return os_server_;
299 }
300
301 void SystemSnapshotMac::OSVersion(int* major,
302 int* minor,
303 int* bugfix,
304 std::string* build) const {
305 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
306 *major = os_version_major_;
307 *minor = os_version_minor_;
308 *bugfix = os_version_bugfix_;
309 build->assign(os_version_build_);
310 }
311
312 std::string SystemSnapshotMac::OSVersionFull() const {
313 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
314 return os_version_full_;
315 }
316
317 std::string SystemSnapshotMac::MachineDescription() const {
318 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
319
320 std::string model;
321 std::string board_id;
322 MacModelAndBoard(&model, &board_id);
323
324 if (!model.empty()) {
325 if (!board_id.empty()) {
326 return base::StringPrintf("%s (%s)", model.c_str(), board_id.c_str());
327 }
328 return model;
329 }
330 if (!board_id.empty()) {
331 return base::StringPrintf("(%s)", board_id.c_str());
332 }
333 return std::string();
334 }
335
336 bool SystemSnapshotMac::NXEnabled() const {
337 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
338 return ReadIntSysctlByName<int>("kern.nx", 0);
339 }
340
341 void SystemSnapshotMac::TimeZone(DaylightSavingTimeStatus* dst_status,
342 int* standard_offset_seconds,
343 int* daylight_offset_seconds,
344 std::string* standard_name,
345 std::string* daylight_name) const {
346 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
347
348 tm local;
349 PCHECK(localtime_r(&snapshot_time_->tv_sec, &local)) << "localtime_r";
350
351 *standard_name = tzname[0];
352 if (daylight) {
353 // Scan forward and backward, one month at a time, looking for an instance
354 // when the observance of daylight saving time is different than it is in
355 // |local|.
356 long probe_gmtoff = local.tm_gmtoff;
357
358 const int kMonthDeltas[] =
359 { 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6,
360 7, -7, 8, -8, 9, -9, 10, -10, 11, -11, 12, -12 };
361 for (size_t index = 0; index < arraysize(kMonthDeltas); ++index) {
362 // Look at the 15th day of each month at local noon. Set tm_isdst to -1 to
363 // avoid giving mktime() any hints about whether to consider daylight
364 // saving time in effect. mktime() accepts values of tm_mon that are
365 // outside of its normal range and behaves as expected: if tm_mon is -1,
366 // it references December of the preceding year, and if it is 12, it
367 // references January of the following year.
368 tm probe_tm = {};
369 probe_tm.tm_hour = 12;
370 probe_tm.tm_mday = 15;
371 probe_tm.tm_mon = local.tm_mon + kMonthDeltas[index];
372 probe_tm.tm_year = local.tm_year;
373 probe_tm.tm_isdst = -1;
374 if (mktime(&probe_tm) != -1 && probe_tm.tm_isdst != local.tm_isdst) {
375 probe_gmtoff = probe_tm.tm_gmtoff;
376 break;
377 }
378 }
379
380 *daylight_name = tzname[1];
381 if (!local.tm_isdst) {
382 *dst_status = kObservingStandardTime;
383 *standard_offset_seconds = local.tm_gmtoff;
384 *daylight_offset_seconds = probe_gmtoff;
385 } else {
386 *dst_status = kObservingDaylightSavingTime;
387 *standard_offset_seconds = probe_gmtoff;
388 *daylight_offset_seconds = local.tm_gmtoff;
389 }
390 } else {
391 *daylight_name = tzname[0];
392 *dst_status = kDoesNotObserveDaylightSavingTime;
393 *standard_offset_seconds = local.tm_gmtoff;
394 *daylight_offset_seconds = local.tm_gmtoff;
395 }
396 }
397
398 } // namespace internal
399 } // namespace crashpad
OLDNEW
« no previous file with comments | « snapshot/system_snapshot_mac.h ('k') | snapshot/system_snapshot_mac_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698