mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-29 00:32:35 +08:00
032f1aecc2
Add direct includes for things provided transitively by logging.h (or by other headers including logging.h). This is in preparation for cleaning up unnecessary includes of logging.h in header files (so if something depends on logging.h, it needs include it explicitly), and for when Chromium's logging.h no longer includes check.h, check_op.h, and notreached.h. DEPS is also updated to roll mini_chromium to ae14a14ab4 which includes these new header files. Bug: chromium:1031540 Change-Id: I36f646d0a93854989dc602d0dc7139dd7a7b8621 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2250251 Commit-Queue: Hans Wennborg <hans@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
432 lines
12 KiB
C++
432 lines
12 KiB
C++
// Copyright 2017 The Crashpad Authors. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "snapshot/linux/system_snapshot_linux.h"
|
|
|
|
#include <stddef.h>
|
|
#include <sys/types.h>
|
|
#include <sys/utsname.h>
|
|
|
|
#include <algorithm>
|
|
|
|
#include "base/files/file_path.h"
|
|
#include "base/logging.h"
|
|
#include "base/notreached.h"
|
|
#include "base/strings/string_number_conversions.h"
|
|
#include "base/strings/string_piece.h"
|
|
#include "base/strings/stringprintf.h"
|
|
#include "snapshot/cpu_context.h"
|
|
#include "snapshot/posix/timezone.h"
|
|
#include "util/file/file_io.h"
|
|
#include "util/numeric/in_range_cast.h"
|
|
#include "util/string/split_string.h"
|
|
|
|
#if defined(OS_ANDROID)
|
|
#include <sys/system_properties.h>
|
|
#endif
|
|
|
|
namespace crashpad {
|
|
namespace internal {
|
|
|
|
namespace {
|
|
|
|
bool ReadCPUsOnline(uint32_t* first_cpu, uint8_t* cpu_count) {
|
|
std::string contents;
|
|
if (!LoggingReadEntireFile(base::FilePath("/sys/devices/system/cpu/online"),
|
|
&contents)) {
|
|
return false;
|
|
}
|
|
if (contents.back() != '\n') {
|
|
LOG(ERROR) << "format error";
|
|
return false;
|
|
}
|
|
contents.pop_back();
|
|
|
|
unsigned int count = 0;
|
|
unsigned int first = 0;
|
|
bool have_first = false;
|
|
std::vector<std::string> ranges = SplitString(contents, ',');
|
|
for (const auto& range : ranges) {
|
|
std::string left, right;
|
|
if (SplitStringFirst(range, '-', &left, &right)) {
|
|
unsigned int start, end;
|
|
if (!StringToUint(base::StringPiece(left), &start) ||
|
|
!StringToUint(base::StringPiece(right), &end) || end <= start) {
|
|
LOG(ERROR) << "format error: " << range;
|
|
return false;
|
|
}
|
|
if (end <= start) {
|
|
LOG(ERROR) << "format error";
|
|
return false;
|
|
}
|
|
count += end - start + 1;
|
|
if (!have_first) {
|
|
first = start;
|
|
have_first = true;
|
|
}
|
|
} else {
|
|
unsigned int cpuno;
|
|
if (!StringToUint(base::StringPiece(range), &cpuno)) {
|
|
LOG(ERROR) << "format error";
|
|
return false;
|
|
}
|
|
if (!have_first) {
|
|
first = cpuno;
|
|
have_first = true;
|
|
}
|
|
++count;
|
|
}
|
|
}
|
|
if (!have_first) {
|
|
LOG(ERROR) << "no cpus online";
|
|
return false;
|
|
}
|
|
*cpu_count = InRangeCast<uint8_t>(count, std::numeric_limits<uint8_t>::max());
|
|
*first_cpu = first;
|
|
return true;
|
|
}
|
|
|
|
bool ReadFreqFile(const std::string& filename, uint64_t* hz) {
|
|
std::string contents;
|
|
if (!LoggingReadEntireFile(base::FilePath(filename), &contents)) {
|
|
return false;
|
|
}
|
|
if (contents.back() != '\n') {
|
|
LOG(ERROR) << "format error";
|
|
return false;
|
|
}
|
|
contents.pop_back();
|
|
|
|
uint64_t khz;
|
|
if (!base::StringToUint64(base::StringPiece(contents), &khz)) {
|
|
LOG(ERROR) << "format error";
|
|
return false;
|
|
}
|
|
|
|
*hz = khz * 1000;
|
|
return true;
|
|
}
|
|
|
|
#if defined(OS_ANDROID)
|
|
bool ReadProperty(const char* property, std::string* value) {
|
|
char value_buffer[PROP_VALUE_MAX];
|
|
int length = __system_property_get(property, value_buffer);
|
|
if (length <= 0) {
|
|
LOG(ERROR) << "Couldn't read property " << property;
|
|
return false;
|
|
}
|
|
*value = value_buffer;
|
|
return true;
|
|
}
|
|
#endif // OS_ANDROID
|
|
|
|
} // namespace
|
|
|
|
SystemSnapshotLinux::SystemSnapshotLinux()
|
|
: SystemSnapshot(),
|
|
os_version_full_(),
|
|
os_version_build_(),
|
|
process_reader_(nullptr),
|
|
snapshot_time_(nullptr),
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
cpuid_(),
|
|
#endif // ARCH_CPU_X86_FAMILY
|
|
os_version_major_(-1),
|
|
os_version_minor_(-1),
|
|
os_version_bugfix_(-1),
|
|
target_cpu_(0),
|
|
cpu_count_(0),
|
|
initialized_() {
|
|
}
|
|
|
|
SystemSnapshotLinux::~SystemSnapshotLinux() {}
|
|
|
|
void SystemSnapshotLinux::Initialize(ProcessReaderLinux* process_reader,
|
|
const timeval* snapshot_time) {
|
|
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
|
process_reader_ = process_reader;
|
|
snapshot_time_ = snapshot_time;
|
|
|
|
#if defined(OS_ANDROID)
|
|
std::string build_string;
|
|
if (ReadProperty("ro.build.fingerprint", &build_string)) {
|
|
os_version_build_ = build_string;
|
|
os_version_full_ = build_string;
|
|
}
|
|
#endif // OS_ANDROID
|
|
|
|
utsname uts;
|
|
if (uname(&uts) != 0) {
|
|
PLOG(WARNING) << "uname";
|
|
} else {
|
|
if (!os_version_full_.empty()) {
|
|
os_version_full_.push_back(' ');
|
|
}
|
|
os_version_full_ += base::StringPrintf(
|
|
"%s %s %s %s", uts.sysname, uts.release, uts.version, uts.machine);
|
|
}
|
|
ReadKernelVersion(uts.release);
|
|
|
|
if (!os_version_build_.empty()) {
|
|
os_version_build_.push_back(' ');
|
|
}
|
|
os_version_build_ += uts.version;
|
|
os_version_build_.push_back(' ');
|
|
os_version_build_ += uts.machine;
|
|
|
|
if (!ReadCPUsOnline(&target_cpu_, &cpu_count_)) {
|
|
target_cpu_ = 0;
|
|
cpu_count_ = 0;
|
|
}
|
|
|
|
INITIALIZATION_STATE_SET_VALID(initialized_);
|
|
}
|
|
|
|
CPUArchitecture SystemSnapshotLinux::GetCPUArchitecture() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
return process_reader_->Is64Bit() ? kCPUArchitectureX86_64
|
|
: kCPUArchitectureX86;
|
|
#elif defined(ARCH_CPU_ARM_FAMILY)
|
|
return process_reader_->Is64Bit() ? kCPUArchitectureARM64
|
|
: kCPUArchitectureARM;
|
|
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
|
return process_reader_->Is64Bit() ? kCPUArchitectureMIPS64EL
|
|
: kCPUArchitectureMIPSEL;
|
|
#else
|
|
#error port to your architecture
|
|
#endif
|
|
}
|
|
|
|
uint32_t SystemSnapshotLinux::CPURevision() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
return cpuid_.Revision();
|
|
#elif defined(ARCH_CPU_ARM_FAMILY)
|
|
// TODO(jperaza): do this. https://crashpad.chromium.org/bug/30
|
|
return 0;
|
|
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
|
// Not implementable on MIPS
|
|
return 0;
|
|
#else
|
|
#error port to your architecture
|
|
#endif
|
|
}
|
|
|
|
uint8_t SystemSnapshotLinux::CPUCount() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
return cpu_count_;
|
|
}
|
|
|
|
std::string SystemSnapshotLinux::CPUVendor() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
return cpuid_.Vendor();
|
|
#elif defined(ARCH_CPU_ARM_FAMILY)
|
|
// TODO(jperaza): do this. https://crashpad.chromium.org/bug/30
|
|
return std::string();
|
|
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
|
// Not implementable on MIPS
|
|
return std::string();
|
|
#else
|
|
#error port to your architecture
|
|
#endif
|
|
}
|
|
|
|
void SystemSnapshotLinux::CPUFrequency(uint64_t* current_hz,
|
|
uint64_t* max_hz) const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
*current_hz = 0;
|
|
*max_hz = 0;
|
|
|
|
ReadFreqFile(base::StringPrintf(
|
|
"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq",
|
|
target_cpu_),
|
|
current_hz);
|
|
|
|
ReadFreqFile(base::StringPrintf(
|
|
"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq",
|
|
target_cpu_),
|
|
max_hz);
|
|
}
|
|
|
|
uint32_t SystemSnapshotLinux::CPUX86Signature() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
return cpuid_.Signature();
|
|
#else
|
|
NOTREACHED();
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
uint64_t SystemSnapshotLinux::CPUX86Features() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
return cpuid_.Features();
|
|
#else
|
|
NOTREACHED();
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
uint64_t SystemSnapshotLinux::CPUX86ExtendedFeatures() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
return cpuid_.ExtendedFeatures();
|
|
#else
|
|
NOTREACHED();
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
uint32_t SystemSnapshotLinux::CPUX86Leaf7Features() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
return cpuid_.Leaf7Features();
|
|
#else
|
|
NOTREACHED();
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
bool SystemSnapshotLinux::CPUX86SupportsDAZ() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
return cpuid_.SupportsDAZ();
|
|
#else
|
|
NOTREACHED();
|
|
return false;
|
|
#endif // ARCH_CPU_X86_FMAILY
|
|
}
|
|
|
|
SystemSnapshot::OperatingSystem SystemSnapshotLinux::GetOperatingSystem()
|
|
const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
#if defined(OS_ANDROID)
|
|
return kOperatingSystemAndroid;
|
|
#else
|
|
return kOperatingSystemLinux;
|
|
#endif // OS_ANDROID
|
|
}
|
|
|
|
bool SystemSnapshotLinux::OSServer() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
return false;
|
|
}
|
|
|
|
void SystemSnapshotLinux::OSVersion(int* major,
|
|
int* minor,
|
|
int* bugfix,
|
|
std::string* build) const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
*major = os_version_major_;
|
|
*minor = os_version_minor_;
|
|
*bugfix = os_version_bugfix_;
|
|
build->assign(os_version_build_);
|
|
}
|
|
|
|
std::string SystemSnapshotLinux::OSVersionFull() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
return os_version_full_;
|
|
}
|
|
|
|
std::string SystemSnapshotLinux::MachineDescription() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
#if defined(OS_ANDROID)
|
|
std::string description;
|
|
std::string prop;
|
|
if (ReadProperty("ro.product.model", &prop)) {
|
|
description += prop;
|
|
}
|
|
if (ReadProperty("ro.product.board", &prop)) {
|
|
if (!description.empty()) {
|
|
description.push_back(' ');
|
|
}
|
|
description += prop;
|
|
}
|
|
return description;
|
|
#else
|
|
return std::string();
|
|
#endif // OS_ANDROID
|
|
}
|
|
|
|
bool SystemSnapshotLinux::NXEnabled() const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
#if defined(ARCH_CPU_X86_FAMILY)
|
|
return cpuid_.NXEnabled();
|
|
#elif defined(ARCH_CPU_ARM_FAMILY)
|
|
// TODO(jperaza): do this. https://crashpad.chromium.org/bug/30
|
|
return false;
|
|
#elif defined(ARCH_CPU_MIPS_FAMILY)
|
|
// Not implementable on MIPS
|
|
return false;
|
|
#else
|
|
#error Port.
|
|
#endif // ARCH_CPU_X86_FAMILY
|
|
}
|
|
|
|
void SystemSnapshotLinux::TimeZone(DaylightSavingTimeStatus* dst_status,
|
|
int* standard_offset_seconds,
|
|
int* daylight_offset_seconds,
|
|
std::string* standard_name,
|
|
std::string* daylight_name) const {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
internal::TimeZone(*snapshot_time_,
|
|
dst_status,
|
|
standard_offset_seconds,
|
|
daylight_offset_seconds,
|
|
standard_name,
|
|
daylight_name);
|
|
}
|
|
|
|
void SystemSnapshotLinux::ReadKernelVersion(const std::string& version_string) {
|
|
std::vector<std::string> versions = SplitString(version_string, '.');
|
|
if (versions.size() < 3) {
|
|
LOG(WARNING) << "format error";
|
|
return;
|
|
}
|
|
|
|
if (!StringToInt(base::StringPiece(versions[0]), &os_version_major_)) {
|
|
LOG(WARNING) << "no kernel version";
|
|
return;
|
|
}
|
|
DCHECK_GE(os_version_major_, 3);
|
|
|
|
if (!StringToInt(base::StringPiece(versions[1]), &os_version_minor_)) {
|
|
LOG(WARNING) << "no major revision";
|
|
return;
|
|
}
|
|
DCHECK_GE(os_version_minor_, 0);
|
|
|
|
size_t minor_rev_end = versions[2].find_first_not_of("0123456789");
|
|
if (minor_rev_end == std::string::npos) {
|
|
minor_rev_end = versions[2].size();
|
|
}
|
|
if (!StringToInt(base::StringPiece(versions[2].c_str(), minor_rev_end),
|
|
&os_version_bugfix_)) {
|
|
LOG(WARNING) << "no minor revision";
|
|
return;
|
|
}
|
|
DCHECK_GE(os_version_bugfix_, 0);
|
|
|
|
if (!os_version_build_.empty()) {
|
|
os_version_build_.push_back(' ');
|
|
}
|
|
os_version_build_ += versions[2].substr(minor_rev_end);
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace crashpad
|