crashpad/minidump/minidump_system_info_writer.cc
Mark Mentovai 6278690abe Update copyright boilerplate, 2022 edition (Crashpad)
sed -i '' -E -e 's/Copyright (.+) The Crashpad Authors\. All rights reserved\.$/Copyright \1 The Crashpad Authors/' $(git grep -El 'Copyright (.+) The Crashpad Authors\. All rights reserved\.$')

Bug: chromium:1098010
Change-Id: I8d6138469ddbe3d281a5d83f64cf918ec2491611
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3878262
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-09-06 23:54:07 +00:00

324 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2014 The Crashpad Authors
//
// 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 "minidump/minidump_system_info_writer.h"
#include <string.h>
#include <iterator>
#include "base/check_op.h"
#include "base/notreached.h"
#include "minidump/minidump_string_writer.h"
#include "snapshot/system_snapshot.h"
#include "util/file/file_writer.h"
#include "util/misc/arraysize.h"
#include "util/misc/implicit_cast.h"
namespace crashpad {
namespace {
uint64_t AMD64FeaturesFromSystemSnapshot(
const SystemSnapshot* system_snapshot) {
#define ADD_FEATURE(minidump_bit) (UINT64_C(1) << (minidump_bit))
// Features for which no cpuid bits are present, but that always exist on
// x86_64. cmpxchg is supported on 486 and later.
uint64_t minidump_features = ADD_FEATURE(PF_COMPARE_EXCHANGE_DOUBLE);
#define MAP_FEATURE(features, cpuid_bit, minidump_bit) \
do { \
if ((features) & (implicit_cast<decltype(features)>(1) << (cpuid_bit))) { \
minidump_features |= ADD_FEATURE(minidump_bit); \
} \
} while (false)
#define F_TSC 4
#define F_PAE 6
#define F_MMX 23
#define F_SSE 25
#define F_SSE2 26
#define F_SSE3 32
#define F_CX16 45
#define F_XSAVE 58
#define F_RDRAND 62
uint64_t cpuid_features = system_snapshot->CPUX86Features();
MAP_FEATURE(cpuid_features, F_TSC, PF_RDTSC_INSTRUCTION_AVAILABLE);
MAP_FEATURE(cpuid_features, F_PAE, PF_PAE_ENABLED);
MAP_FEATURE(cpuid_features, F_MMX, PF_MMX_INSTRUCTIONS_AVAILABLE);
MAP_FEATURE(cpuid_features, F_SSE, PF_XMMI_INSTRUCTIONS_AVAILABLE);
MAP_FEATURE(cpuid_features, F_SSE2, PF_XMMI64_INSTRUCTIONS_AVAILABLE);
MAP_FEATURE(cpuid_features, F_SSE3, PF_SSE3_INSTRUCTIONS_AVAILABLE);
MAP_FEATURE(cpuid_features, F_CX16, PF_COMPARE_EXCHANGE128);
MAP_FEATURE(cpuid_features, F_XSAVE, PF_XSAVE_ENABLED);
MAP_FEATURE(cpuid_features, F_RDRAND, PF_RDRAND_INSTRUCTION_AVAILABLE);
#define FX_XD 20
#define FX_RDTSCP 27
#define FX_3DNOW 31
uint64_t extended_features = system_snapshot->CPUX86ExtendedFeatures();
MAP_FEATURE(extended_features, FX_RDTSCP, PF_RDTSCP_INSTRUCTION_AVAILABLE);
MAP_FEATURE(extended_features, FX_3DNOW, PF_3DNOW_INSTRUCTIONS_AVAILABLE);
#define F7_FSGSBASE 0
uint32_t leaf7_features = system_snapshot->CPUX86Leaf7Features();
MAP_FEATURE(leaf7_features, F7_FSGSBASE, PF_RDWRFSGSBASE_AVAILABLE);
// This feature bit should be set if NX (XD, DEP) is enabled, not just if its
// available on the CPU as indicated by the FX_XD bit.
if (system_snapshot->NXEnabled()) {
minidump_features |= ADD_FEATURE(PF_NX_ENABLED);
}
if (system_snapshot->CPUX86SupportsDAZ()) {
minidump_features |= ADD_FEATURE(PF_SSE_DAZ_MODE_AVAILABLE);
}
// PF_SECOND_LEVEL_ADDRESS_TRANSLATION cant be determined without consulting
// model-specific registers, a privileged operation. The exact use of
// PF_VIRT_FIRMWARE_ENABLED is unknown. PF_FASTFAIL_AVAILABLE is irrelevant
// outside of Windows.
#undef MAP_FEATURE
#undef ADD_FEATURE
return minidump_features;
}
} // namespace
MinidumpSystemInfoWriter::MinidumpSystemInfoWriter()
: MinidumpStreamWriter(), system_info_(), csd_version_() {
system_info_.ProcessorArchitecture = kMinidumpCPUArchitectureUnknown;
}
MinidumpSystemInfoWriter::~MinidumpSystemInfoWriter() {
}
void MinidumpSystemInfoWriter::InitializeFromSnapshot(
const SystemSnapshot* system_snapshot) {
DCHECK_EQ(state(), kStateMutable);
DCHECK(!csd_version_);
MinidumpCPUArchitecture cpu_architecture;
switch (system_snapshot->GetCPUArchitecture()) {
case kCPUArchitectureX86:
cpu_architecture = kMinidumpCPUArchitectureX86;
break;
case kCPUArchitectureX86_64:
cpu_architecture = kMinidumpCPUArchitectureAMD64;
break;
case kCPUArchitectureARM:
cpu_architecture = kMinidumpCPUArchitectureARM;
break;
case kCPUArchitectureARM64:
cpu_architecture = kMinidumpCPUArchitectureARM64;
break;
default:
NOTREACHED();
cpu_architecture = kMinidumpCPUArchitectureUnknown;
break;
}
SetCPUArchitecture(cpu_architecture);
uint32_t cpu_revision = system_snapshot->CPURevision();
SetCPULevelAndRevision((cpu_revision & 0xffff0000) >> 16,
cpu_revision & 0x0000ffff);
SetCPUCount(system_snapshot->CPUCount());
if (cpu_architecture == kMinidumpCPUArchitectureX86) {
std::string cpu_vendor = system_snapshot->CPUVendor();
SetCPUX86VendorString(cpu_vendor);
// The minidump file format only has room for the bottom 32 bits of CPU
// features and extended CPU features.
SetCPUX86VersionAndFeatures(system_snapshot->CPUX86Signature(),
system_snapshot->CPUX86Features() & 0xffffffff);
if (cpu_vendor == "AuthenticAMD" || cpu_vendor == "HygonGenuine") {
SetCPUX86AMDExtendedFeatures(
system_snapshot->CPUX86ExtendedFeatures() & 0xffffffff);
}
} else if (cpu_architecture == kMinidumpCPUArchitectureAMD64) {
SetCPUOtherFeatures(AMD64FeaturesFromSystemSnapshot(system_snapshot), 0);
}
MinidumpOS operating_system;
switch (system_snapshot->GetOperatingSystem()) {
case SystemSnapshot::kOperatingSystemMacOSX:
operating_system = kMinidumpOSMacOSX;
break;
case SystemSnapshot::kOperatingSystemWindows:
operating_system = kMinidumpOSWin32NT;
break;
case SystemSnapshot::kOperatingSystemLinux:
operating_system = kMinidumpOSLinux;
break;
case SystemSnapshot::kOperatingSystemAndroid:
operating_system = kMinidumpOSAndroid;
break;
case SystemSnapshot::kOperatingSystemFuchsia:
operating_system = kMinidumpOSFuchsia;
break;
case SystemSnapshot::kOperatingSystemIOS:
operating_system = kMinidumpOSIOS;
break;
default:
NOTREACHED();
operating_system = kMinidumpOSUnknown;
break;
}
SetOS(operating_system);
SetOSType(system_snapshot->OSServer() ? kMinidumpOSTypeServer
: kMinidumpOSTypeWorkstation);
int major;
int minor;
int bugfix;
std::string build;
system_snapshot->OSVersion(&major, &minor, &bugfix, &build);
SetOSVersion(major, minor, bugfix);
SetCSDVersion(build);
}
void MinidumpSystemInfoWriter::SetCSDVersion(const std::string& csd_version) {
DCHECK_EQ(state(), kStateMutable);
if (!csd_version_) {
csd_version_.reset(new internal::MinidumpUTF16StringWriter());
}
csd_version_->SetUTF8(csd_version);
}
void MinidumpSystemInfoWriter::SetCPUX86Vendor(uint32_t ebx,
uint32_t edx,
uint32_t ecx) {
DCHECK_EQ(state(), kStateMutable);
DCHECK(system_info_.ProcessorArchitecture == kMinidumpCPUArchitectureX86 ||
system_info_.ProcessorArchitecture ==
kMinidumpCPUArchitectureX86Win64);
static_assert(ArraySize(system_info_.Cpu.X86CpuInfo.VendorId) == 3,
"VendorId must have 3 elements");
system_info_.Cpu.X86CpuInfo.VendorId[0] = ebx;
system_info_.Cpu.X86CpuInfo.VendorId[1] = edx;
system_info_.Cpu.X86CpuInfo.VendorId[2] = ecx;
}
void MinidumpSystemInfoWriter::SetCPUX86VendorString(
const std::string& vendor) {
DCHECK_EQ(state(), kStateMutable);
CHECK_EQ(vendor.size(), sizeof(system_info_.Cpu.X86CpuInfo.VendorId));
uint32_t registers[3];
static_assert(
sizeof(registers) == sizeof(system_info_.Cpu.X86CpuInfo.VendorId),
"VendorId sizes must be equal");
for (size_t index = 0; index < std::size(registers); ++index) {
memcpy(&registers[index],
&vendor[index * sizeof(*registers)],
sizeof(*registers));
}
SetCPUX86Vendor(registers[0], registers[1], registers[2]);
}
void MinidumpSystemInfoWriter::SetCPUX86VersionAndFeatures(uint32_t version,
uint32_t features) {
DCHECK_EQ(state(), kStateMutable);
DCHECK(system_info_.ProcessorArchitecture == kMinidumpCPUArchitectureX86 ||
system_info_.ProcessorArchitecture ==
kMinidumpCPUArchitectureX86Win64);
system_info_.Cpu.X86CpuInfo.VersionInformation = version;
system_info_.Cpu.X86CpuInfo.FeatureInformation = features;
}
void MinidumpSystemInfoWriter::SetCPUX86AMDExtendedFeatures(
uint32_t extended_features) {
DCHECK_EQ(state(), kStateMutable);
DCHECK(system_info_.ProcessorArchitecture == kMinidumpCPUArchitectureX86 ||
system_info_.ProcessorArchitecture ==
kMinidumpCPUArchitectureX86Win64);
DCHECK(system_info_.Cpu.X86CpuInfo.VendorId[0] == 'htuA' &&
system_info_.Cpu.X86CpuInfo.VendorId[1] == 'itne' &&
system_info_.Cpu.X86CpuInfo.VendorId[2] == 'DMAc');
system_info_.Cpu.X86CpuInfo.AMDExtendedCpuFeatures = extended_features;
}
void MinidumpSystemInfoWriter::SetCPUOtherFeatures(uint64_t features_0,
uint64_t features_1) {
DCHECK_EQ(state(), kStateMutable);
DCHECK(system_info_.ProcessorArchitecture != kMinidumpCPUArchitectureX86 &&
system_info_.ProcessorArchitecture !=
kMinidumpCPUArchitectureX86Win64);
static_assert(ArraySize(system_info_.Cpu.OtherCpuInfo.ProcessorFeatures) == 2,
"ProcessorFeatures must have 2 elements");
system_info_.Cpu.OtherCpuInfo.ProcessorFeatures[0] = features_0;
system_info_.Cpu.OtherCpuInfo.ProcessorFeatures[1] = features_1;
}
bool MinidumpSystemInfoWriter::Freeze() {
DCHECK_EQ(state(), kStateMutable);
CHECK(csd_version_);
if (!MinidumpStreamWriter::Freeze()) {
return false;
}
csd_version_->RegisterRVA(&system_info_.CSDVersionRva);
return true;
}
size_t MinidumpSystemInfoWriter::SizeOfObject() {
DCHECK_GE(state(), kStateFrozen);
return sizeof(system_info_);
}
std::vector<internal::MinidumpWritable*> MinidumpSystemInfoWriter::Children() {
DCHECK_GE(state(), kStateFrozen);
DCHECK(csd_version_);
std::vector<MinidumpWritable*> children(1, csd_version_.get());
return children;
}
bool MinidumpSystemInfoWriter::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
return file_writer->Write(&system_info_, sizeof(system_info_));
}
MinidumpStreamType MinidumpSystemInfoWriter::StreamType() const {
return kMinidumpStreamTypeSystemInfo;
}
} // namespace crashpad