123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- // 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 "build/build_config.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 BUILDFLAG(IS_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 BUILDFLAG(IS_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 // BUILDFLAG(IS_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 BUILDFLAG(IS_ANDROID)
- std::string build_string;
- if (ReadProperty("ro.build.fingerprint", &build_string)) {
- os_version_build_ = build_string;
- os_version_full_ = build_string;
- }
- #endif // BUILDFLAG(IS_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;
- #elif defined(ARCH_CPU_RISCV_FAMILY)
- return process_reader_->Is64Bit() ? kCPUArchitectureRISCV64
- : kCPUArchitectureRISCV;
- #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;
- #elif defined(ARCH_CPU_RISCV_FAMILY)
- // Not implementable on RISCV
- 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();
- #elif defined(ARCH_CPU_RISCV_FAMILY)
- // Not implementable on RISCV
- 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 BUILDFLAG(IS_ANDROID)
- return kOperatingSystemAndroid;
- #else
- return kOperatingSystemLinux;
- #endif // BUILDFLAG(IS_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 BUILDFLAG(IS_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 // BUILDFLAG(IS_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;
- #elif defined(ARCH_CPU_RISCV_FAMILY)
- // Not implementable on RISCV
- 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
|