crashpad/minidump/minidump_system_info_writer.cc
Mark Mentovai 48b1964d1b Use implicit_cast<> instead of static_cast<> whenever possible.
implicit_cast<> only performs a cast in cases where an implicit
conversion would be possible. It’s even safer than static_cast<> It’s an
“explicit implicit” cast, which is not normally necsesary, but is
frequently required when working with the ?: operator, functions like
std::min() and std::max(), and logging and testing macros.

The public style guide does not mention implicit_cast<> only because it
is not part of the standard library, but would otherwise require it in
these situations. Since base does provide implicit_cast<>, it should be
used whenever possible.

The only uses of static_cast<> not converted to implicit_cast<> are
those that require static_cast<>, such as those that assign an integer
constant to a variable of an enum type.

R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/700383007
2014-11-06 16:44:38 -05:00

297 lines
9.9 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. 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 "minidump/minidump_system_info_writer.h"
#include <string.h>
#include <sys/types.h>
#include "base/logging.h"
#include "minidump/minidump_string_writer.h"
#include "snapshot/system_snapshot.h"
#include "util/file/file_writer.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_3DNOW 31
uint64_t extended_features = system_snapshot->CPUX86ExtendedFeatures();
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 XF_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;
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") {
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;
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 < arraysize(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