crashpad/snapshot/linux/system_snapshot_linux.cc
Hans Wennborg 032f1aecc2 Include-what-you-use related to logging.h
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>
2020-06-18 13:51:20 +00:00

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