diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 85a2a500..768697db 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -48,6 +48,8 @@ static_library("snapshot") { "minidump/module_snapshot_minidump.h", "minidump/process_snapshot_minidump.cc", "minidump/process_snapshot_minidump.h", + "minidump/system_snapshot_minidump.cc", + "minidump/system_snapshot_minidump.h", "minidump/thread_snapshot_minidump.cc", "minidump/thread_snapshot_minidump.h", "module_snapshot.h", diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index 97db3bdb..f50c6520 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -29,6 +29,7 @@ ProcessSnapshotMinidump::ProcessSnapshotMinidump() modules_(), unloaded_modules_(), crashpad_info_(), + system_snapshot_(), annotations_simple_map_(), file_reader_(nullptr), process_id_(static_cast(-1)), @@ -87,7 +88,8 @@ bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { if (!InitializeCrashpadInfo() || !InitializeMiscInfo() || !InitializeModules() || - !InitializeThreads()) { + !InitializeThreads() || + !InitializeSystemSnapshot()) { return false; } @@ -154,8 +156,7 @@ ProcessSnapshotMinidump::AnnotationsSimpleMap() const { const SystemSnapshot* ProcessSnapshotMinidump::System() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return nullptr; + return &system_snapshot_; } std::vector ProcessSnapshotMinidump::Threads() const { @@ -435,4 +436,18 @@ bool ProcessSnapshotMinidump::InitializeThreads() { return true; } +bool ProcessSnapshotMinidump::InitializeSystemSnapshot() { + const auto& stream_it = stream_map_.find(kMinidumpStreamTypeSystemInfo); + if (stream_it == stream_map_.end()) { + return true; + } + + if (stream_it->second->DataSize < sizeof(MINIDUMP_SYSTEM_INFO)) { + LOG(ERROR) << "system info size mismatch"; + return false; + } + + return system_snapshot_.Initialize(file_reader_, stream_it->second->Rva); +} + } // namespace crashpad diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index d15ea2fb..105c5d27 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -30,6 +30,7 @@ #include "snapshot/exception_snapshot.h" #include "snapshot/memory_snapshot.h" #include "snapshot/minidump/module_snapshot_minidump.h" +#include "snapshot/minidump/system_snapshot_minidump.h" #include "snapshot/minidump/thread_snapshot_minidump.h" #include "snapshot/module_snapshot.h" #include "snapshot/process_snapshot.h" @@ -90,6 +91,10 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { // Initialize(). bool InitializeThreads(); + // Initializes data carried in a MINIDUMP_SYSTEM_INFO stream on behalf of + // Initialize(). + bool InitializeSystemSnapshot(); + // Initializes data carried in a MinidumpModuleCrashpadInfoList structure on // behalf of InitializeModules(). This makes use of MinidumpCrashpadInfo as // well, so it must be called after InitializeCrashpadInfo(). @@ -108,6 +113,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector> threads_; std::vector unloaded_modules_; MinidumpCrashpadInfo crashpad_info_; + internal::SystemSnapshotMinidump system_snapshot_; std::map annotations_simple_map_; FileReaderInterface* file_reader_; // weak pid_t process_id_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index a08fbe47..9212dacb 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -506,6 +506,71 @@ TEST(ProcessSnapshotMinidump, Threads) { } } +TEST(ProcessSnapshotMinidump, System) { + const char* cpu_info = "GenuineIntel"; + const uint32_t* cpu_info_bytes = reinterpret_cast(cpu_info); + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + MINIDUMP_SYSTEM_INFO minidump_system_info = {}; + + minidump_system_info.ProcessorArchitecture = kMinidumpCPUArchitectureX86; + minidump_system_info.ProcessorLevel = 3; + minidump_system_info.ProcessorRevision = 3; + minidump_system_info.NumberOfProcessors = 8; + minidump_system_info.ProductType = kMinidumpOSTypeServer; + minidump_system_info.PlatformId = kMinidumpOSFuchsia; + minidump_system_info.MajorVersion = 3; + minidump_system_info.MinorVersion = 4; + minidump_system_info.BuildNumber = 56; + minidump_system_info.CSDVersionRva = WriteString(&string_file, "Snazzle"); + minidump_system_info.Cpu.X86CpuInfo.VendorId[0] = cpu_info_bytes[0]; + minidump_system_info.Cpu.X86CpuInfo.VendorId[1] = cpu_info_bytes[1]; + minidump_system_info.Cpu.X86CpuInfo.VendorId[2] = cpu_info_bytes[2]; + + MINIDUMP_DIRECTORY minidump_system_info_directory = {}; + minidump_system_info_directory.StreamType = kMinidumpStreamTypeSystemInfo; + minidump_system_info_directory.Location.DataSize = + sizeof(MINIDUMP_SYSTEM_INFO); + minidump_system_info_directory.Location.Rva = + static_cast(string_file.SeekGet()); + + ASSERT_TRUE(string_file.Write(&minidump_system_info, + sizeof(minidump_system_info))); + + header.StreamDirectoryRva = static_cast(string_file.SeekGet()); + ASSERT_TRUE(string_file.Write(&minidump_system_info_directory, + sizeof(minidump_system_info_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 1; + EXPECT_TRUE(string_file.SeekSet(0)); + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + EXPECT_TRUE(process_snapshot.Initialize(&string_file)); + + const SystemSnapshot* s = process_snapshot.System(); + + EXPECT_EQ(s->GetCPUArchitecture(), kCPUArchitectureX86); + EXPECT_EQ(s->CPURevision(), 3UL); + EXPECT_EQ(s->CPUVendor(), "GenuineIntel"); + EXPECT_EQ(s->GetOperatingSystem(), + SystemSnapshot::OperatingSystem::kOperatingSystemFuchsia); + + int major, minor, bugfix; + std::string build; + s->OSVersion(&major, &minor, &bugfix, &build); + + EXPECT_EQ(major, 3); + EXPECT_EQ(minor, 4); + EXPECT_EQ(bugfix, 56); + EXPECT_EQ(build, "Snazzle"); +} + } // namespace } // namespace test } // namespace crashpad diff --git a/snapshot/minidump/system_snapshot_minidump.cc b/snapshot/minidump/system_snapshot_minidump.cc new file mode 100644 index 00000000..356bd16c --- /dev/null +++ b/snapshot/minidump/system_snapshot_minidump.cc @@ -0,0 +1,199 @@ +// Copyright 2018 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/minidump/system_snapshot_minidump.h" + +#include "snapshot/minidump/minidump_string_reader.h" + +namespace crashpad { +namespace internal { + +SystemSnapshotMinidump::SystemSnapshotMinidump() + : SystemSnapshot(), + minidump_system_info_(), + initialized_() { +} + +SystemSnapshotMinidump::~SystemSnapshotMinidump() { +} + +bool SystemSnapshotMinidump::Initialize(FileReaderInterface* file_reader, + RVA minidump_system_info_rva) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + if (!file_reader->SeekSet(minidump_system_info_rva)) { + return false; + } + + if (!file_reader->ReadExactly(&minidump_system_info_, + sizeof(minidump_system_info_))) { + return false; + } + + if (!ReadMinidumpUTF8String(file_reader, minidump_system_info_.CSDVersionRva, + &minidump_build_name_)) { + return false; + } + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +CPUArchitecture SystemSnapshotMinidump::GetCPUArchitecture() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + switch (minidump_system_info_.ProcessorArchitecture) { + case kMinidumpCPUArchitectureAMD64: + return kCPUArchitectureX86_64; + case kMinidumpCPUArchitectureX86: + case kMinidumpCPUArchitectureX86Win64: + return kCPUArchitectureX86; + case kMinidumpCPUArchitectureARM: + case kMinidumpCPUArchitectureARM32Win64: + return kCPUArchitectureARM; + case kMinidumpCPUArchitectureARM64: + case kMinidumpCPUArchitectureARM64Breakpad: + return kCPUArchitectureARM64; + case kMinidumpCPUArchitectureMIPS: + return kCPUArchitectureMIPSEL; + // No word on how MIPS64 is signalled + + default: + return CPUArchitecture::kCPUArchitectureUnknown; + } +} + +uint32_t SystemSnapshotMinidump::CPURevision() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return minidump_system_info_.ProcessorRevision; +} + +uint8_t SystemSnapshotMinidump::CPUCount() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return minidump_system_info_.NumberOfProcessors; +} + +std::string SystemSnapshotMinidump::CPUVendor() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (GetCPUArchitecture() == kCPUArchitectureX86) { + const char* ptr = + reinterpret_cast(minidump_system_info_.Cpu.X86CpuInfo. + VendorId); + return std::string(ptr, ptr + (3 * sizeof(uint32_t))); + } else { + return std::string(); + } +} + +void SystemSnapshotMinidump::CPUFrequency(uint64_t* current_hz, + uint64_t* max_hz) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 +} + +uint32_t SystemSnapshotMinidump::CPUX86Signature() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return 0; +} + +uint64_t SystemSnapshotMinidump::CPUX86Features() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return 0; +} + +uint64_t SystemSnapshotMinidump::CPUX86ExtendedFeatures() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return 0; +} + +uint32_t SystemSnapshotMinidump::CPUX86Leaf7Features() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return 0; +} + +bool SystemSnapshotMinidump::CPUX86SupportsDAZ() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return false; +} + +SystemSnapshot::OperatingSystem + SystemSnapshotMinidump::GetOperatingSystem() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + switch (minidump_system_info_.PlatformId) { + case kMinidumpOSMacOSX: + return OperatingSystem::kOperatingSystemMacOSX; + case kMinidumpOSWin32s: + case kMinidumpOSWin32Windows: + case kMinidumpOSWin32NT: + return OperatingSystem::kOperatingSystemWindows; + case kMinidumpOSLinux: + return OperatingSystem::kOperatingSystemLinux; + case kMinidumpOSAndroid: + return OperatingSystem::kOperatingSystemAndroid; + case kMinidumpOSFuchsia: + return OperatingSystem::kOperatingSystemFuchsia; + default: + return OperatingSystem::kOperatingSystemUnknown; + } +} + +bool SystemSnapshotMinidump::OSServer() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return minidump_system_info_.ProductType == kMinidumpOSTypeServer; +} + +void SystemSnapshotMinidump::OSVersion(int* major, + int* minor, + int* bugfix, + std::string* build) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + *major = minidump_system_info_.MajorVersion; + *minor = minidump_system_info_.MinorVersion; + *bugfix = minidump_system_info_.BuildNumber; + *build = minidump_build_name_; +} + +std::string SystemSnapshotMinidump::OSVersionFull() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return std::string(); +} + +std::string SystemSnapshotMinidump::MachineDescription() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return std::string(); +} + +bool SystemSnapshotMinidump::NXEnabled() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return false; +} + +void SystemSnapshotMinidump::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_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/minidump/system_snapshot_minidump.h b/snapshot/minidump/system_snapshot_minidump.h new file mode 100644 index 00000000..71e57891 --- /dev/null +++ b/snapshot/minidump/system_snapshot_minidump.h @@ -0,0 +1,82 @@ +// Copyright 2018 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. + +#ifndef CRASHPAD_SNAPSHOT_MINIDUMP_SYSTEM_SNAPSHOT_MINIDUMP_H_ +#define CRASHPAD_SNAPSHOT_MINIDUMP_SYSTEM_SNAPSHOT_MINIDUMP_H_ + +#include + +#include "base/macros.h" +#include "minidump/minidump_extensions.h" +#include "snapshot/system_snapshot.h" +#include "util/file/file_reader.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { +namespace internal { + +//! \brief A SystemSnapshot based on a minidump file. +class SystemSnapshotMinidump : public SystemSnapshot { + public: + SystemSnapshotMinidump(); + ~SystemSnapshotMinidump() override; + + //! \brief Initializes the object. + //! + //! \param[in] file_reader A file reader corresponding to a minidump file. + //! The file reader must support seeking. + //! \param[in] minidump_system_info_rva The file offset in \a file_reader at + //! which the thread’s MINIDUMP_SYSTEM_INFO structure is located. + //! + //! \return `true` if the snapshot could be created, `false` otherwise with + //! an appropriate message logged. + bool Initialize(FileReaderInterface* file_reader, + RVA minidump_system_info_rva); + + CPUArchitecture GetCPUArchitecture() const override; + uint32_t CPURevision() const override; + uint8_t CPUCount() const override; + std::string CPUVendor() const override; + void CPUFrequency(uint64_t* current_hz, uint64_t* max_hz) const override; + uint32_t CPUX86Signature() const override; + uint64_t CPUX86Features() const override; + uint64_t CPUX86ExtendedFeatures() const override; + uint32_t CPUX86Leaf7Features() const override; + bool CPUX86SupportsDAZ() const override; + OperatingSystem GetOperatingSystem() const override; + bool OSServer() const override; + void OSVersion(int* major, + int* minor, + int* bugfix, + std::string* build) const override; + std::string OSVersionFull() const override; + std::string MachineDescription() const override; + bool NXEnabled() const override; + void TimeZone(DaylightSavingTimeStatus* dst_status, + int* standard_offset_seconds, + int* daylight_offset_seconds, + std::string* standard_name, + std::string* daylight_name) const override; + private: + MINIDUMP_SYSTEM_INFO minidump_system_info_; + std::string minidump_build_name_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(SystemSnapshotMinidump); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MINIDUMP_SYSTEM_SNAPSHOT_MINIDUMP_H_ diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 7fb4ba82..4c8a5cbf 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -119,6 +119,8 @@ 'minidump/module_snapshot_minidump.h', 'minidump/process_snapshot_minidump.cc', 'minidump/process_snapshot_minidump.h', + 'minidump/system_snapshot_minidump.cc', + 'minidump/system_snapshot_minidump.h', 'minidump/thread_snapshot_minidump.cc', 'minidump/thread_snapshot_minidump.h', 'module_snapshot.h',