From c73a97d4e39bcaf8ff8cb5aa9185230a82110fa1 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Mon, 11 Aug 2014 11:42:12 -0700 Subject: [PATCH] Add MinidumpMiscInfoWriter and its test. TEST=minidump_test MinidumpMiscInfoWriter R=rsesek@chromium.org Review URL: https://codereview.chromium.org/454073002 --- compat/non_win/dbghelp.h | 6 +- minidump/minidump.gyp | 3 + minidump/minidump_misc_info_writer.cc | 184 ++++++ minidump/minidump_misc_info_writer.h | 105 +++ minidump/minidump_misc_info_writer_test.cc | 659 +++++++++++++++++++ minidump/minidump_string_writer_test.cc | 1 - minidump/minidump_system_info_writer_test.cc | 12 + minidump/minidump_writable_test.cc | 1 - 8 files changed, 966 insertions(+), 5 deletions(-) create mode 100644 minidump/minidump_misc_info_writer.cc create mode 100644 minidump/minidump_misc_info_writer.h create mode 100644 minidump/minidump_misc_info_writer_test.cc diff --git a/compat/non_win/dbghelp.h b/compat/non_win/dbghelp.h index 9e73e55b..bb7b165f 100644 --- a/compat/non_win/dbghelp.h +++ b/compat/non_win/dbghelp.h @@ -636,10 +636,10 @@ struct __attribute__((packed, aligned(4))) MINIDUMP_MEMORY_LIST { //! MINIDUMP_MISC2_PROCESSOR_POWER_INFO. #define MINIDUMP_MISC1_PROCESSOR_POWER_INFO 0x00000004 -//! \brief MINIDUMP_MISC_INFO3::ProcessIntegrityLevel is valid. +//! \brief MINIDUMP_MISC_INFO_3::ProcessIntegrityLevel is valid. #define MINIDUMP_MISC3_PROCESS_INTEGRITY 0x00000010 -//! \brief MINIDUMP_MISC_INFO3::ProcessExecuteFlags is valid. +//! \brief MINIDUMP_MISC_INFO_3::ProcessExecuteFlags is valid. #define MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS 0x00000020 //! \brief The time zone-related fields in MINIDUMP_MISC_INFO_3 are valid. @@ -649,7 +649,7 @@ struct __attribute__((packed, aligned(4))) MINIDUMP_MEMORY_LIST { //! - MINIDUMP_MISC_INFO_3::TimeZone #define MINIDUMP_MISC3_TIMEZONE 0x00000040 -//! \brief MINIDUMP_MISC_INFO3::ProtectedProcess is valid. +//! \brief MINIDUMP_MISC_INFO_3::ProtectedProcess is valid. #define MINIDUMP_MISC3_PROTECTED_PROCESS 0x00000080 //! \brief The build string-related fields in MINIDUMP_MISC_INFO_4 are valid. diff --git a/minidump/minidump.gyp b/minidump/minidump.gyp index 2692aa24..50adce54 100644 --- a/minidump/minidump.gyp +++ b/minidump/minidump.gyp @@ -32,6 +32,8 @@ 'minidump_extensions.h', 'minidump_file_writer.cc', 'minidump_file_writer.h', + 'minidump_misc_info_writer.cc', + 'minidump_misc_info_writer.h', 'minidump_stream_writer.cc', 'minidump_stream_writer.h', 'minidump_string_writer.cc', @@ -58,6 +60,7 @@ 'sources': [ '../third_party/gtest/gtest/src/gtest_main.cc', 'minidump_file_writer_test.cc', + 'minidump_misc_info_writer_test.cc', 'minidump_string_writer_test.cc', 'minidump_system_info_writer_test.cc', 'minidump_writable_test.cc', diff --git a/minidump/minidump_misc_info_writer.cc b/minidump/minidump_misc_info_writer.cc new file mode 100644 index 00000000..0742ee5f --- /dev/null +++ b/minidump/minidump_misc_info_writer.cc @@ -0,0 +1,184 @@ +// 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_misc_info_writer.h" + +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "minidump/minidump_writer_util.h" +#include "util/numeric/safe_assignment.h" + +namespace crashpad { + +MinidumpMiscInfoWriter::MinidumpMiscInfoWriter() + : MinidumpStreamWriter(), misc_info_() { +} + +void MinidumpMiscInfoWriter::SetProcessId(uint32_t process_id) { + DCHECK_EQ(state(), kStateMutable); + + misc_info_.ProcessId = process_id; + misc_info_.Flags1 |= MINIDUMP_MISC1_PROCESS_ID; +} + +void MinidumpMiscInfoWriter::SetProcessTimes(time_t process_create_time, + uint32_t process_user_time, + uint32_t process_kernel_time) { + DCHECK_EQ(state(), kStateMutable); + + internal::MinidumpWriterUtil::AssignTimeT(&misc_info_.ProcessCreateTime, + process_create_time); + + misc_info_.ProcessUserTime = process_user_time; + misc_info_.ProcessKernelTime = process_kernel_time; + misc_info_.Flags1 |= MINIDUMP_MISC1_PROCESS_TIMES; +} + +void MinidumpMiscInfoWriter::SetProcessorPowerInfo( + uint32_t processor_max_mhz, + uint32_t processor_current_mhz, + uint32_t processor_mhz_limit, + uint32_t processor_max_idle_state, + uint32_t processor_current_idle_state) { + DCHECK_EQ(state(), kStateMutable); + + misc_info_.ProcessorMaxMhz = processor_max_mhz; + misc_info_.ProcessorCurrentMhz = processor_current_mhz; + misc_info_.ProcessorMhzLimit = processor_mhz_limit; + misc_info_.ProcessorMaxIdleState = processor_max_idle_state; + misc_info_.ProcessorCurrentIdleState = processor_current_idle_state; + misc_info_.Flags1 |= MINIDUMP_MISC1_PROCESSOR_POWER_INFO; +} + +void MinidumpMiscInfoWriter::SetProcessIntegrityLevel( + uint32_t process_integrity_level) { + DCHECK_EQ(state(), kStateMutable); + + misc_info_.ProcessIntegrityLevel = process_integrity_level; + misc_info_.Flags1 |= MINIDUMP_MISC3_PROCESS_INTEGRITY; +} + +void MinidumpMiscInfoWriter::SetProcessExecuteFlags( + uint32_t process_execute_flags) { + DCHECK_EQ(state(), kStateMutable); + + misc_info_.ProcessExecuteFlags = process_execute_flags; + misc_info_.Flags1 |= MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS; +} + +void MinidumpMiscInfoWriter::SetProtectedProcess(uint32_t protected_process) { + DCHECK_EQ(state(), kStateMutable); + + misc_info_.ProtectedProcess = protected_process; + misc_info_.Flags1 |= MINIDUMP_MISC3_PROTECTED_PROCESS; +} + +void MinidumpMiscInfoWriter::SetTimeZone(uint32_t time_zone_id, + int32_t bias, + const std::string& standard_name, + const SYSTEMTIME& standard_date, + int32_t standard_bias, + const std::string& daylight_name, + const SYSTEMTIME& daylight_date, + int32_t daylight_bias) { + DCHECK_EQ(state(), kStateMutable); + + misc_info_.TimeZoneId = time_zone_id; + misc_info_.TimeZone.Bias = bias; + + internal::MinidumpWriterUtil::AssignUTF8ToUTF16( + misc_info_.TimeZone.StandardName, + arraysize(misc_info_.TimeZone.StandardName), + standard_name); + + misc_info_.TimeZone.StandardDate = standard_date; + misc_info_.TimeZone.StandardBias = standard_bias; + + internal::MinidumpWriterUtil::AssignUTF8ToUTF16( + misc_info_.TimeZone.DaylightName, + arraysize(misc_info_.TimeZone.DaylightName), + daylight_name); + + misc_info_.TimeZone.DaylightDate = daylight_date; + misc_info_.TimeZone.DaylightBias = daylight_bias; + + misc_info_.Flags1 |= MINIDUMP_MISC3_TIMEZONE; +} + +void MinidumpMiscInfoWriter::SetBuildString( + const std::string& build_string, + const std::string& debug_build_string) { + DCHECK_EQ(state(), kStateMutable); + + misc_info_.Flags1 |= MINIDUMP_MISC4_BUILDSTRING; + + internal::MinidumpWriterUtil::AssignUTF8ToUTF16( + misc_info_.BuildString, arraysize(misc_info_.BuildString), build_string); + internal::MinidumpWriterUtil::AssignUTF8ToUTF16( + misc_info_.DbgBldStr, + arraysize(misc_info_.DbgBldStr), + debug_build_string); +} + +bool MinidumpMiscInfoWriter::Freeze() { + DCHECK_EQ(state(), kStateMutable); + + if (!MinidumpStreamWriter::Freeze()) { + return false; + } + + size_t size = CalculateSizeOfObjectFromFlags(); + if (!AssignIfInRange(&misc_info_.SizeOfInfo, size)) { + LOG(ERROR) << "size " << size << " out of range"; + return false; + } + + return true; +} + +size_t MinidumpMiscInfoWriter::SizeOfObject() { + DCHECK_GE(state(), kStateFrozen); + + return CalculateSizeOfObjectFromFlags(); +} + +bool MinidumpMiscInfoWriter::WriteObject(FileWriterInterface* file_writer) { + DCHECK_EQ(state(), kStateWritable); + + return file_writer->Write(&misc_info_, CalculateSizeOfObjectFromFlags()); +} + +MinidumpStreamType MinidumpMiscInfoWriter::StreamType() const { + return kMinidumpStreamTypeMiscInfo; +} + +size_t MinidumpMiscInfoWriter::CalculateSizeOfObjectFromFlags() const { + DCHECK_GE(state(), kStateFrozen); + + if (misc_info_.Flags1 & MINIDUMP_MISC4_BUILDSTRING) { + return sizeof(MINIDUMP_MISC_INFO_4); + } + if (misc_info_.Flags1 & + (MINIDUMP_MISC3_PROCESS_INTEGRITY | MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS | + MINIDUMP_MISC3_TIMEZONE | MINIDUMP_MISC3_PROTECTED_PROCESS)) { + return sizeof(MINIDUMP_MISC_INFO_3); + } + if (misc_info_.Flags1 & MINIDUMP_MISC1_PROCESSOR_POWER_INFO) { + return sizeof(MINIDUMP_MISC_INFO_2); + } + return sizeof(MINIDUMP_MISC_INFO); +} + +} // namespace crashpad diff --git a/minidump/minidump_misc_info_writer.h b/minidump/minidump_misc_info_writer.h new file mode 100644 index 00000000..f51f38c3 --- /dev/null +++ b/minidump/minidump_misc_info_writer.h @@ -0,0 +1,105 @@ +// 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. + +#ifndef CRASHPAD_MINIDUMP_MINIDUMP_MISC_INFO_WRITER_H_ +#define CRASHPAD_MINIDUMP_MINIDUMP_MISC_INFO_WRITER_H_ + +#include +#include +#include +#include + +#include + +#include "base/basictypes.h" +#include "minidump/minidump_stream_writer.h" +#include "minidump/minidump_writable.h" +#include "util/file/file_writer.h" + +namespace crashpad { + +//! \brief The writer for a stream in the MINIDUMP_MISC_INFO family in a +//! minidump file. +//! +//! The actual stream written will be a MINIDUMP_MISC_INFO, +//! MINIDUMP_MISC_INFO_2, MINIDUMP_MISC_INFO_3, or MINIDUMP_MISC_INFO_4 stream. +//! Later versions of MINIDUMP_MISC_INFO are supersets of earlier versions. The +//! earliest version that supports all of the information that an object of this +//! class contains will be used. +class MinidumpMiscInfoWriter final : public internal::MinidumpStreamWriter { + public: + MinidumpMiscInfoWriter(); + ~MinidumpMiscInfoWriter() {} + + //! \brief Sets the field referenced by #MINIDUMP_MISC1_PROCESS_ID. + void SetProcessId(uint32_t process_id); + + //! \brief Sets the fields referenced by #MINIDUMP_MISC1_PROCESS_TIMES. + void SetProcessTimes(time_t process_create_time, + uint32_t process_user_time, + uint32_t process_kernel_time); + + //! \brief Sets the fields referenced by #MINIDUMP_MISC1_PROCESSOR_POWER_INFO. + void SetProcessorPowerInfo(uint32_t processor_max_mhz, + uint32_t processor_current_mhz, + uint32_t processor_mhz_limit, + uint32_t processor_max_idle_state, + uint32_t processor_current_idle_state); + + //! \brief Sets the field referenced by #MINIDUMP_MISC3_PROCESS_INTEGRITY. + void SetProcessIntegrityLevel(uint32_t process_integrity_level); + + //! \brief Sets the field referenced by #MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS. + void SetProcessExecuteFlags(uint32_t process_execute_flags); + + //! \brief Sets the field referenced by #MINIDUMP_MISC3_PROTECTED_PROCESS. + void SetProtectedProcess(uint32_t protected_process); + + //! \brief Sets the fields referenced by #MINIDUMP_MISC3_TIMEZONE. + void SetTimeZone(uint32_t time_zone_id, + int32_t bias, + const std::string& standard_name, + const SYSTEMTIME& standard_date, + int32_t standard_bias, + const std::string& daylight_name, + const SYSTEMTIME& daylight_date, + int32_t daylight_bias); + + //! \brief Sets the fields referenced by #MINIDUMP_MISC4_BUILDSTRING. + void SetBuildString(const std::string& build_string, + const std::string& debug_build_string); + + protected: + // MinidumpWritable: + virtual bool Freeze() override; + virtual size_t SizeOfObject() override; + virtual bool WriteObject(FileWriterInterface* file_writer) override; + virtual MinidumpStreamType StreamType() const override; + + private: + //! \brief Returns the size of the object to be written based on + //! MINIDUMP_MISC_INFO_N::Flags1. + //! + //! The smallest defined structure type in the MINIDUMP_MISC_INFO family that + //! can hold all of the data that has been populated will be used. + size_t CalculateSizeOfObjectFromFlags() const; + + MINIDUMP_MISC_INFO_N misc_info_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpMiscInfoWriter); +}; + +} // namespace crashpad + +#endif // CRASHPAD_MINIDUMP_MINIDUMP_MISC_INFO_WRITER_H_ diff --git a/minidump/minidump_misc_info_writer_test.cc b/minidump/minidump_misc_info_writer_test.cc new file mode 100644 index 00000000..5ccfd8ea --- /dev/null +++ b/minidump/minidump_misc_info_writer_test.cc @@ -0,0 +1,659 @@ +// 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_misc_info_writer.h" + +#include +#include + +#include + +#include "base/basictypes.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "gtest/gtest.h" +#include "minidump/minidump_file_writer.h" +#include "util/file/string_file_writer.h" +#include "util/stdlib/strlcpy.h" + +namespace { + +using namespace crashpad; + +template +void GetMiscInfoStream(const std::string& file_contents, const T** misc_info) { + const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + const size_t kMiscInfoStreamOffset = + kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); + const size_t kMiscInfoStreamSize = sizeof(T); + const size_t kFileSize = kMiscInfoStreamOffset + kMiscInfoStreamSize; + + ASSERT_EQ(kFileSize, file_contents.size()); + + const MINIDUMP_HEADER* header = + reinterpret_cast(&file_contents[0]); + + EXPECT_EQ(static_cast(MINIDUMP_SIGNATURE), header->Signature); + EXPECT_EQ(static_cast(MINIDUMP_VERSION), header->Version); + ASSERT_EQ(1u, header->NumberOfStreams); + ASSERT_EQ(kDirectoryOffset, header->StreamDirectoryRva); + EXPECT_EQ(0u, header->CheckSum); + EXPECT_EQ(0u, header->TimeDateStamp); + EXPECT_EQ(MiniDumpNormal, header->Flags); + + const MINIDUMP_DIRECTORY* directory = + reinterpret_cast( + &file_contents[kDirectoryOffset]); + + ASSERT_EQ(kMinidumpStreamTypeMiscInfo, directory->StreamType); + ASSERT_EQ(kMiscInfoStreamSize, directory->Location.DataSize); + ASSERT_EQ(kMiscInfoStreamOffset, directory->Location.Rva); + + *misc_info = + reinterpret_cast(&file_contents[kMiscInfoStreamOffset]); + + ASSERT_EQ(kMiscInfoStreamSize, (*misc_info)->SizeOfInfo); +} + +void ExpectNULPaddedString16Equal(const char16* expected, + const char16* observed, + size_t size) { + string16 expected_string(expected, size); + string16 observed_string(observed, size); + EXPECT_EQ(expected_string, observed_string); +} + +void ExpectSystemTimeEqual(const SYSTEMTIME* expected, + const SYSTEMTIME* observed) { + EXPECT_EQ(expected->wYear, observed->wYear); + EXPECT_EQ(expected->wMonth, observed->wMonth); + EXPECT_EQ(expected->wDayOfWeek, observed->wDayOfWeek); + EXPECT_EQ(expected->wDay, observed->wDay); + EXPECT_EQ(expected->wHour, observed->wHour); + EXPECT_EQ(expected->wMinute, observed->wMinute); + EXPECT_EQ(expected->wSecond, observed->wSecond); + EXPECT_EQ(expected->wMilliseconds, observed->wMilliseconds); +} + +template +void ExpectMiscInfoEqual(const T* expected, const T* observed); + +template <> +void ExpectMiscInfoEqual( + const MINIDUMP_MISC_INFO* expected, + const MINIDUMP_MISC_INFO* observed) { + EXPECT_EQ(expected->Flags1, observed->Flags1); + EXPECT_EQ(expected->ProcessId, observed->ProcessId); + EXPECT_EQ(expected->ProcessCreateTime, observed->ProcessCreateTime); + EXPECT_EQ(expected->ProcessUserTime, observed->ProcessUserTime); + EXPECT_EQ(expected->ProcessKernelTime, observed->ProcessKernelTime); +} + +template <> +void ExpectMiscInfoEqual( + const MINIDUMP_MISC_INFO_2* expected, + const MINIDUMP_MISC_INFO_2* observed) { + ExpectMiscInfoEqual(expected, observed); + EXPECT_EQ(expected->ProcessorMaxMhz, observed->ProcessorMaxMhz); + EXPECT_EQ(expected->ProcessorCurrentMhz, observed->ProcessorCurrentMhz); + EXPECT_EQ(expected->ProcessorMhzLimit, observed->ProcessorMhzLimit); + EXPECT_EQ(expected->ProcessorMaxIdleState, observed->ProcessorMaxIdleState); + EXPECT_EQ(expected->ProcessorCurrentIdleState, + observed->ProcessorCurrentIdleState); +} + +template <> +void ExpectMiscInfoEqual( + const MINIDUMP_MISC_INFO_3* expected, + const MINIDUMP_MISC_INFO_3* observed) { + ExpectMiscInfoEqual(expected, observed); + EXPECT_EQ(expected->ProcessIntegrityLevel, observed->ProcessIntegrityLevel); + EXPECT_EQ(expected->ProcessExecuteFlags, observed->ProcessExecuteFlags); + EXPECT_EQ(expected->ProtectedProcess, observed->ProtectedProcess); + EXPECT_EQ(expected->TimeZoneId, observed->TimeZoneId); + EXPECT_EQ(expected->TimeZone.Bias, observed->TimeZone.Bias); + { + SCOPED_TRACE("Standard"); + ExpectNULPaddedString16Equal(expected->TimeZone.StandardName, + observed->TimeZone.StandardName, + arraysize(expected->TimeZone.StandardName)); + ExpectSystemTimeEqual(&expected->TimeZone.StandardDate, + &observed->TimeZone.StandardDate); + EXPECT_EQ(expected->TimeZone.StandardBias, observed->TimeZone.StandardBias); + } + { + SCOPED_TRACE("Daylight"); + ExpectNULPaddedString16Equal(expected->TimeZone.DaylightName, + observed->TimeZone.DaylightName, + arraysize(expected->TimeZone.DaylightName)); + ExpectSystemTimeEqual(&expected->TimeZone.DaylightDate, + &observed->TimeZone.DaylightDate); + EXPECT_EQ(expected->TimeZone.DaylightBias, observed->TimeZone.DaylightBias); + } +} + +template <> +void ExpectMiscInfoEqual( + const MINIDUMP_MISC_INFO_4* expected, + const MINIDUMP_MISC_INFO_4* observed) { + ExpectMiscInfoEqual(expected, observed); + { + SCOPED_TRACE("BuildString"); + ExpectNULPaddedString16Equal(expected->BuildString, + observed->BuildString, + arraysize(expected->BuildString)); + } + { + SCOPED_TRACE("DbgBldStr"); + ExpectNULPaddedString16Equal(expected->DbgBldStr, + observed->DbgBldStr, + arraysize(expected->DbgBldStr)); + } +} + +TEST(MinidumpMiscInfoWriter, Empty) { + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO expected = {}; + + ExpectMiscInfoEqual(&expected, observed); +} + +TEST(MinidumpMiscInfoWriter, ProcessId) { + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + const uint32_t kProcessId = 12345; + + misc_info_writer.SetProcessId(kProcessId); + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO expected = {}; + expected.Flags1 = MINIDUMP_MISC1_PROCESS_ID; + expected.ProcessId = kProcessId; + + ExpectMiscInfoEqual(&expected, observed); +} + +TEST(MinidumpMiscInfoWriter, ProcessTimes) { + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + const time_t kProcessCreateTime = 0x15252f00; + const uint32_t kProcessUserTime = 10; + const uint32_t kProcessKernelTime = 5; + + misc_info_writer.SetProcessTimes( + kProcessCreateTime, kProcessUserTime, kProcessKernelTime); + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO expected = {}; + expected.Flags1 = MINIDUMP_MISC1_PROCESS_TIMES; + expected.ProcessCreateTime = kProcessCreateTime; + expected.ProcessUserTime = kProcessUserTime; + expected.ProcessKernelTime = kProcessKernelTime; + + ExpectMiscInfoEqual(&expected, observed); +} + +TEST(MinidumpMiscInfoWriter, ProcessorPowerInfo) { + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + const uint32_t kProcessorMaxMhz = 2800; + const uint32_t kProcessorCurrentMhz = 2300; + const uint32_t kProcessorMhzLimit = 3300; + const uint32_t kProcessorMaxIdleState = 5; + const uint32_t kProcessorCurrentIdleState = 1; + + misc_info_writer.SetProcessorPowerInfo(kProcessorMaxMhz, + kProcessorCurrentMhz, + kProcessorMhzLimit, + kProcessorMaxIdleState, + kProcessorCurrentIdleState); + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO_2* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO_2 expected = {}; + expected.Flags1 = MINIDUMP_MISC1_PROCESSOR_POWER_INFO; + expected.ProcessorMaxMhz = kProcessorMaxMhz; + expected.ProcessorCurrentMhz = kProcessorCurrentMhz; + expected.ProcessorMhzLimit = kProcessorMhzLimit; + expected.ProcessorMaxIdleState = kProcessorMaxIdleState; + expected.ProcessorCurrentIdleState = kProcessorCurrentIdleState; + + ExpectMiscInfoEqual(&expected, observed); +} + +TEST(MinidumpMiscInfoWriter, ProcessIntegrityLevel) { + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + const uint32_t kProcessIntegrityLevel = 0x2000; + + misc_info_writer.SetProcessIntegrityLevel(kProcessIntegrityLevel); + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO_3* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO_3 expected = {}; + expected.Flags1 = MINIDUMP_MISC3_PROCESS_INTEGRITY; + expected.ProcessIntegrityLevel = kProcessIntegrityLevel; + + ExpectMiscInfoEqual(&expected, observed); +} + +TEST(MinidumpMiscInfoWriter, ProcessExecuteFlags) { + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + const uint32_t kProcessExecuteFlags = 0x13579bdf; + + misc_info_writer.SetProcessExecuteFlags(kProcessExecuteFlags); + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO_3* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO_3 expected = {}; + expected.Flags1 = MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS; + expected.ProcessExecuteFlags = kProcessExecuteFlags; + + ExpectMiscInfoEqual(&expected, observed); +} + +TEST(MinidumpMiscInfoWriter, ProtectedProcess) { + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + const uint32_t kProtectedProcess = 1; + + misc_info_writer.SetProtectedProcess(kProtectedProcess); + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO_3* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO_3 expected = {}; + expected.Flags1 = MINIDUMP_MISC3_PROTECTED_PROCESS; + expected.ProtectedProcess = kProtectedProcess; + + ExpectMiscInfoEqual(&expected, observed); +} + +TEST(MinidumpMiscInfoWriter, TimeZone) { + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + const uint32_t kTimeZoneId = 2; + const int32_t kBias = 300; + const char kStandardName[] = "EST"; + const SYSTEMTIME kStandardDate = {0, 11, 1, 0, 2, 0, 0, 0}; + const int32_t kStandardBias = 0; + const char kDaylightName[] = "EDT"; + const SYSTEMTIME kDaylightDate = {0, 3, 2, 0, 2, 0, 0, 0}; + const int32_t kDaylightBias = -60; + + misc_info_writer.SetTimeZone(kTimeZoneId, + kBias, + kStandardName, + kStandardDate, + kStandardBias, + kDaylightName, + kDaylightDate, + kDaylightBias); + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO_3* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO_3 expected = {}; + expected.Flags1 = MINIDUMP_MISC3_TIMEZONE; + expected.TimeZoneId = kTimeZoneId; + expected.TimeZone.Bias = kBias; + string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName); + c16lcpy(expected.TimeZone.StandardName, + standard_name_utf16.c_str(), + arraysize(expected.TimeZone.StandardName)); + memcpy(&expected.TimeZone.StandardDate, + &kStandardDate, + sizeof(expected.TimeZone.StandardDate)); + expected.TimeZone.StandardBias = kStandardBias; + string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName); + c16lcpy(expected.TimeZone.DaylightName, + daylight_name_utf16.c_str(), + arraysize(expected.TimeZone.DaylightName)); + memcpy(&expected.TimeZone.DaylightDate, + &kDaylightDate, + sizeof(expected.TimeZone.DaylightDate)); + expected.TimeZone.DaylightBias = kDaylightBias; + + ExpectMiscInfoEqual(&expected, observed); +} + +TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { + // This test makes sure that the time zone name strings are truncated properly + // to the widths of their fields. + + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + const uint32_t kTimeZoneId = 2; + const int32_t kBias = 300; + std::string standard_name( + arraysize(decltype(MINIDUMP_MISC_INFO_N::TimeZone)::StandardName) + 1, + 's'); + const int32_t kStandardBias = 0; + std::string daylight_name( + arraysize(decltype(MINIDUMP_MISC_INFO_N::TimeZone)::DaylightName), 'd'); + const int32_t kDaylightBias = -60; + + // Test using kSystemTimeZero, because not all platforms will be able to + // provide daylight saving time transition times. + const SYSTEMTIME kSystemTimeZero = {}; + + misc_info_writer.SetTimeZone(kTimeZoneId, + kBias, + standard_name, + kSystemTimeZero, + kStandardBias, + daylight_name, + kSystemTimeZero, + kDaylightBias); + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO_3* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO_3 expected = {}; + expected.Flags1 = MINIDUMP_MISC3_TIMEZONE; + expected.TimeZoneId = kTimeZoneId; + expected.TimeZone.Bias = kBias; + string16 standard_name_utf16 = base::UTF8ToUTF16(standard_name); + c16lcpy(expected.TimeZone.StandardName, + standard_name_utf16.c_str(), + arraysize(expected.TimeZone.StandardName)); + memcpy(&expected.TimeZone.StandardDate, + &kSystemTimeZero, + sizeof(expected.TimeZone.StandardDate)); + expected.TimeZone.StandardBias = kStandardBias; + string16 daylight_name_utf16 = base::UTF8ToUTF16(daylight_name); + c16lcpy(expected.TimeZone.DaylightName, + daylight_name_utf16.c_str(), + arraysize(expected.TimeZone.DaylightName)); + memcpy(&expected.TimeZone.DaylightDate, + &kSystemTimeZero, + sizeof(expected.TimeZone.DaylightDate)); + expected.TimeZone.DaylightBias = kDaylightBias; + + ExpectMiscInfoEqual(&expected, observed); +} + +TEST(MinidumpMiscInfoWriter, BuildStrings) { + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + const char kBuildString[] = "build string"; + const char kDebugBuildString[] = "debug build string"; + + misc_info_writer.SetBuildString(kBuildString, kDebugBuildString); + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO_4* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO_4 expected = {}; + expected.Flags1 = MINIDUMP_MISC4_BUILDSTRING; + string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString); + c16lcpy(expected.BuildString, + build_string_utf16.c_str(), + arraysize(expected.BuildString)); + string16 debug_build_string_utf16 = base::UTF8ToUTF16(kDebugBuildString); + c16lcpy(expected.DbgBldStr, + debug_build_string_utf16.c_str(), + arraysize(expected.DbgBldStr)); + + ExpectMiscInfoEqual(&expected, observed); +} + +TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) { + // This test makes sure that the build strings are truncated properly to the + // widths of their fields. + + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + std::string build_string(arraysize(MINIDUMP_MISC_INFO_N::BuildString) + 1, + 'B'); + std::string debug_build_string(arraysize(MINIDUMP_MISC_INFO_N::DbgBldStr), + 'D'); + + misc_info_writer.SetBuildString(build_string, debug_build_string); + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO_4* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO_4 expected = {}; + expected.Flags1 = MINIDUMP_MISC4_BUILDSTRING; + string16 build_string_utf16 = base::UTF8ToUTF16(build_string); + c16lcpy(expected.BuildString, + build_string_utf16.c_str(), + arraysize(expected.BuildString)); + string16 debug_build_string_utf16 = base::UTF8ToUTF16(debug_build_string); + c16lcpy(expected.DbgBldStr, + debug_build_string_utf16.c_str(), + arraysize(expected.DbgBldStr)); + + ExpectMiscInfoEqual(&expected, observed); +} + +TEST(MinidumpMiscInfoWriter, Everything) { + MinidumpFileWriter minidump_file_writer; + MinidumpMiscInfoWriter misc_info_writer; + + const uint32_t kProcessId = 12345; + const time_t kProcessCreateTime = 0x15252f00; + const uint32_t kProcessUserTime = 10; + const uint32_t kProcessKernelTime = 5; + const uint32_t kProcessorMaxMhz = 2800; + const uint32_t kProcessorCurrentMhz = 2300; + const uint32_t kProcessorMhzLimit = 3300; + const uint32_t kProcessorMaxIdleState = 5; + const uint32_t kProcessorCurrentIdleState = 1; + const uint32_t kProcessIntegrityLevel = 0x2000; + const uint32_t kProcessExecuteFlags = 0x13579bdf; + const uint32_t kProtectedProcess = 1; + const uint32_t kTimeZoneId = 2; + const int32_t kBias = 300; + const char kStandardName[] = "EST"; + const int32_t kStandardBias = 0; + const char kDaylightName[] = "EDT"; + const int32_t kDaylightBias = -60; + const SYSTEMTIME kSystemTimeZero = {}; + const char kBuildString[] = "build string"; + const char kDebugBuildString[] = "debug build string"; + + misc_info_writer.SetProcessId(kProcessId); + misc_info_writer.SetProcessTimes( + kProcessCreateTime, kProcessUserTime, kProcessKernelTime); + misc_info_writer.SetProcessorPowerInfo(kProcessorMaxMhz, + kProcessorCurrentMhz, + kProcessorMhzLimit, + kProcessorMaxIdleState, + kProcessorCurrentIdleState); + misc_info_writer.SetProcessIntegrityLevel(kProcessIntegrityLevel); + misc_info_writer.SetProcessExecuteFlags(kProcessExecuteFlags); + misc_info_writer.SetProtectedProcess(kProtectedProcess); + misc_info_writer.SetTimeZone(kTimeZoneId, + kBias, + kStandardName, + kSystemTimeZero, + kStandardBias, + kDaylightName, + kSystemTimeZero, + kDaylightBias); + misc_info_writer.SetBuildString(kBuildString, kDebugBuildString); + + minidump_file_writer.AddStream(&misc_info_writer); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MINIDUMP_MISC_INFO_4* observed; + GetMiscInfoStream(file_writer.string(), &observed); + if (Test::HasFatalFailure()) { + return; + } + + MINIDUMP_MISC_INFO_4 expected = {}; + expected.Flags1 = + MINIDUMP_MISC1_PROCESS_ID | MINIDUMP_MISC1_PROCESS_TIMES | + MINIDUMP_MISC1_PROCESSOR_POWER_INFO | MINIDUMP_MISC3_PROCESS_INTEGRITY | + MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS | MINIDUMP_MISC3_PROTECTED_PROCESS | + MINIDUMP_MISC3_TIMEZONE | MINIDUMP_MISC4_BUILDSTRING; + expected.ProcessId = kProcessId; + expected.ProcessCreateTime = kProcessCreateTime; + expected.ProcessUserTime = kProcessUserTime; + expected.ProcessKernelTime = kProcessKernelTime; + expected.ProcessorMaxMhz = kProcessorMaxMhz; + expected.ProcessorCurrentMhz = kProcessorCurrentMhz; + expected.ProcessorMhzLimit = kProcessorMhzLimit; + expected.ProcessorMaxIdleState = kProcessorMaxIdleState; + expected.ProcessorCurrentIdleState = kProcessorCurrentIdleState; + expected.ProcessIntegrityLevel = kProcessIntegrityLevel; + expected.ProcessExecuteFlags = kProcessExecuteFlags; + expected.ProtectedProcess = kProtectedProcess; + expected.TimeZoneId = kTimeZoneId; + expected.TimeZone.Bias = kBias; + string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName); + c16lcpy(expected.TimeZone.StandardName, + standard_name_utf16.c_str(), + arraysize(expected.TimeZone.StandardName)); + memcpy(&expected.TimeZone.StandardDate, + &kSystemTimeZero, + sizeof(expected.TimeZone.StandardDate)); + expected.TimeZone.StandardBias = kStandardBias; + string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName); + c16lcpy(expected.TimeZone.DaylightName, + daylight_name_utf16.c_str(), + arraysize(expected.TimeZone.DaylightName)); + memcpy(&expected.TimeZone.DaylightDate, + &kSystemTimeZero, + sizeof(expected.TimeZone.DaylightDate)); + expected.TimeZone.DaylightBias = kDaylightBias; + string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString); + c16lcpy(expected.BuildString, + build_string_utf16.c_str(), + arraysize(expected.BuildString)); + string16 debug_build_string_utf16 = base::UTF8ToUTF16(kDebugBuildString); + c16lcpy(expected.DbgBldStr, + debug_build_string_utf16.c_str(), + arraysize(expected.DbgBldStr)); + + ExpectMiscInfoEqual(&expected, observed); +} + +} // namespace diff --git a/minidump/minidump_string_writer_test.cc b/minidump/minidump_string_writer_test.cc index 3d114f9f..682da831 100644 --- a/minidump/minidump_string_writer_test.cc +++ b/minidump/minidump_string_writer_test.cc @@ -27,7 +27,6 @@ namespace { using namespace crashpad; -using namespace testing; const MINIDUMP_STRING* MinidumpStringCast(const StringFileWriter& file_writer) { return reinterpret_cast(&file_writer.string()[0]); diff --git a/minidump/minidump_system_info_writer_test.cc b/minidump/minidump_system_info_writer_test.cc index 27963a20..41fdc67c 100644 --- a/minidump/minidump_system_info_writer_test.cc +++ b/minidump/minidump_system_info_writer_test.cc @@ -92,6 +92,9 @@ TEST(MinidumpSystemInfoWriter, Empty) { const MINIDUMP_STRING* csd_version; GetSystemInfoStream(file_writer.string(), 0, &system_info, &csd_version); + if (Test::HasFatalFailure()) { + return; + } EXPECT_EQ(kMinidumpCPUArchitectureUnknown, system_info->ProcessorArchitecture); @@ -163,6 +166,9 @@ TEST(MinidumpSystemInfoWriter, X86_Win) { GetSystemInfoStream( file_writer.string(), strlen(kCSDVersion), &system_info, &csd_version); + if (Test::HasFatalFailure()) { + return; + } EXPECT_EQ(kCPUArchitecture, system_info->ProcessorArchitecture); EXPECT_EQ(kCPULevel, system_info->ProcessorLevel); @@ -223,6 +229,9 @@ TEST(MinidumpSystemInfoWriter, X86_64_Mac) { GetSystemInfoStream( file_writer.string(), strlen(kCSDVersion), &system_info, &csd_version); + if (Test::HasFatalFailure()) { + return; + } EXPECT_EQ(kCPUArchitecture, system_info->ProcessorArchitecture); EXPECT_EQ(kCPULevel, system_info->ProcessorLevel); @@ -264,6 +273,9 @@ TEST(MinidumpSystemInfoWriter, X86_CPUVendorFromRegisters) { const MINIDUMP_STRING* csd_version; GetSystemInfoStream(file_writer.string(), 0, &system_info, &csd_version); + if (Test::HasFatalFailure()) { + return; + } EXPECT_EQ(kCPUArchitecture, system_info->ProcessorArchitecture); EXPECT_EQ(0u, system_info->ProcessorLevel); diff --git a/minidump/minidump_writable_test.cc b/minidump/minidump_writable_test.cc index 6adad968..616f8cd8 100644 --- a/minidump/minidump_writable_test.cc +++ b/minidump/minidump_writable_test.cc @@ -24,7 +24,6 @@ namespace { using namespace crashpad; -using namespace testing; class BaseTestMinidumpWritable : public crashpad::internal::MinidumpWritable { public: