// 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/compiler_specific.h" #include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.h" #include "minidump/minidump_file_writer.h" #include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_writable_test_util.h" #include "snapshot/test/test_process_snapshot.h" #include "snapshot/test/test_system_snapshot.h" #include "util/file/string_file.h" #include "util/stdlib/strlcpy.h" namespace crashpad { namespace test { namespace { template void GetMiscInfoStream(const std::string& file_contents, const T** misc_info) { constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); constexpr size_t kMiscInfoStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); constexpr size_t kMiscInfoStreamSize = sizeof(T); constexpr size_t kFileSize = kMiscInfoStreamOffset + kMiscInfoStreamSize; ASSERT_EQ(file_contents.size(), kFileSize); const MINIDUMP_DIRECTORY* directory; const MINIDUMP_HEADER* header = MinidumpHeaderAtStart(file_contents, &directory); ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0)); ASSERT_TRUE(directory); ASSERT_EQ(directory[0].StreamType, kMinidumpStreamTypeMiscInfo); EXPECT_EQ(directory[0].Location.Rva, kMiscInfoStreamOffset); *misc_info = MinidumpWritableAtLocationDescriptor(file_contents, directory[0].Location); ASSERT_TRUE(misc_info); } void ExpectNULPaddedString16Equal(const char16_t* expected, const char16_t* observed, size_t size) { std::u16string expected_string(expected, size); std::u16string observed_string(observed, size); EXPECT_EQ(observed_string, expected_string); } void ExpectSystemTimeEqual(const SYSTEMTIME* expected, const SYSTEMTIME* observed) { EXPECT_EQ(observed->wYear, expected->wYear); EXPECT_EQ(observed->wMonth, expected->wMonth); EXPECT_EQ(observed->wDayOfWeek, expected->wDayOfWeek); EXPECT_EQ(observed->wDay, expected->wDay); EXPECT_EQ(observed->wHour, expected->wHour); EXPECT_EQ(observed->wMinute, expected->wMinute); EXPECT_EQ(observed->wSecond, expected->wSecond); EXPECT_EQ(observed->wMilliseconds, expected->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(observed->Flags1, expected->Flags1); EXPECT_EQ(observed->ProcessId, expected->ProcessId); EXPECT_EQ(observed->ProcessCreateTime, expected->ProcessCreateTime); EXPECT_EQ(observed->ProcessUserTime, expected->ProcessUserTime); EXPECT_EQ(observed->ProcessKernelTime, expected->ProcessKernelTime); } template <> void ExpectMiscInfoEqual( const MINIDUMP_MISC_INFO_2* expected, const MINIDUMP_MISC_INFO_2* observed) { ExpectMiscInfoEqual( reinterpret_cast(expected), reinterpret_cast(observed)); EXPECT_EQ(observed->ProcessorMaxMhz, expected->ProcessorMaxMhz); EXPECT_EQ(observed->ProcessorCurrentMhz, expected->ProcessorCurrentMhz); EXPECT_EQ(observed->ProcessorMhzLimit, expected->ProcessorMhzLimit); EXPECT_EQ(observed->ProcessorMaxIdleState, expected->ProcessorMaxIdleState); EXPECT_EQ(observed->ProcessorCurrentIdleState, expected->ProcessorCurrentIdleState); } template <> void ExpectMiscInfoEqual( const MINIDUMP_MISC_INFO_3* expected, const MINIDUMP_MISC_INFO_3* observed) { ExpectMiscInfoEqual( reinterpret_cast(expected), reinterpret_cast(observed)); EXPECT_EQ(observed->ProcessIntegrityLevel, expected->ProcessIntegrityLevel); EXPECT_EQ(observed->ProcessExecuteFlags, expected->ProcessExecuteFlags); EXPECT_EQ(observed->ProtectedProcess, expected->ProtectedProcess); EXPECT_EQ(observed->TimeZoneId, expected->TimeZoneId); EXPECT_EQ(observed->TimeZone.Bias, expected->TimeZone.Bias); { SCOPED_TRACE("Standard"); ExpectNULPaddedString16Equal(AsU16CStr(expected->TimeZone.StandardName), AsU16CStr(observed->TimeZone.StandardName), base::size(expected->TimeZone.StandardName)); ExpectSystemTimeEqual(&expected->TimeZone.StandardDate, &observed->TimeZone.StandardDate); EXPECT_EQ(observed->TimeZone.StandardBias, expected->TimeZone.StandardBias); } { SCOPED_TRACE("Daylight"); ExpectNULPaddedString16Equal(AsU16CStr(expected->TimeZone.DaylightName), AsU16CStr(observed->TimeZone.DaylightName), base::size(expected->TimeZone.DaylightName)); ExpectSystemTimeEqual(&expected->TimeZone.DaylightDate, &observed->TimeZone.DaylightDate); EXPECT_EQ(observed->TimeZone.DaylightBias, expected->TimeZone.DaylightBias); } } template <> void ExpectMiscInfoEqual( const MINIDUMP_MISC_INFO_4* expected, const MINIDUMP_MISC_INFO_4* observed) { ExpectMiscInfoEqual( reinterpret_cast(expected), reinterpret_cast(observed)); { SCOPED_TRACE("BuildString"); ExpectNULPaddedString16Equal(AsU16CStr(expected->BuildString), AsU16CStr(observed->BuildString), base::size(expected->BuildString)); } { SCOPED_TRACE("DbgBldStr"); ExpectNULPaddedString16Equal(AsU16CStr(expected->DbgBldStr), AsU16CStr(observed->DbgBldStr), base::size(expected->DbgBldStr)); } } template <> void ExpectMiscInfoEqual( const MINIDUMP_MISC_INFO_5* expected, const MINIDUMP_MISC_INFO_5* observed) { ExpectMiscInfoEqual( reinterpret_cast(expected), reinterpret_cast(observed)); MINIDUMP_MISC_INFO_5 expected_misc_info, observed_misc_info; memcpy(&expected_misc_info, expected, sizeof(expected_misc_info)); memcpy(&observed_misc_info, observed, sizeof(observed_misc_info)); EXPECT_EQ(observed_misc_info.XStateData.SizeOfInfo, expected_misc_info.XStateData.SizeOfInfo); EXPECT_EQ(observed_misc_info.XStateData.ContextSize, expected_misc_info.XStateData.ContextSize); EXPECT_EQ(observed_misc_info.XStateData.EnabledFeatures, expected_misc_info.XStateData.EnabledFeatures); for (size_t feature_index = 0; feature_index < base::size(observed_misc_info.XStateData.Features); ++feature_index) { SCOPED_TRACE(base::StringPrintf("feature_index %" PRIuS, feature_index)); EXPECT_EQ(observed_misc_info.XStateData.Features[feature_index].Offset, expected_misc_info.XStateData.Features[feature_index].Offset); EXPECT_EQ(observed_misc_info.XStateData.Features[feature_index].Size, expected_misc_info.XStateData.Features[feature_index].Size); } EXPECT_EQ(observed_misc_info.ProcessCookie, expected_misc_info.ProcessCookie); } // Bypass restrictions on conversion of compile-time constants (added for // https://crbug.com/1189439). const char* Crbug1189439Cast(const char str[]) { return str; } TEST(MinidumpMiscInfoWriter, Empty) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = std::make_unique(); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); MINIDUMP_MISC_INFO expected = {}; ExpectMiscInfoEqual(&expected, observed); } TEST(MinidumpMiscInfoWriter, ProcessId) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = std::make_unique(); constexpr uint32_t kProcessId = 12345; misc_info_writer->SetProcessID(kProcessId); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); MINIDUMP_MISC_INFO expected = {}; expected.Flags1 = MINIDUMP_MISC1_PROCESS_ID; expected.ProcessId = kProcessId; ExpectMiscInfoEqual(&expected, observed); } TEST(MinidumpMiscInfoWriter, ProcessTimes) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = std::make_unique(); constexpr time_t kProcessCreateTime = 0x15252f00; constexpr uint32_t kProcessUserTime = 10; constexpr uint32_t kProcessKernelTime = 5; misc_info_writer->SetProcessTimes( kProcessCreateTime, kProcessUserTime, kProcessKernelTime); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); 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; auto misc_info_writer = std::make_unique(); constexpr uint32_t kProcessorMaxMhz = 2800; constexpr uint32_t kProcessorCurrentMhz = 2300; constexpr uint32_t kProcessorMhzLimit = 3300; constexpr uint32_t kProcessorMaxIdleState = 5; constexpr uint32_t kProcessorCurrentIdleState = 1; misc_info_writer->SetProcessorPowerInfo(kProcessorMaxMhz, kProcessorCurrentMhz, kProcessorMhzLimit, kProcessorMaxIdleState, kProcessorCurrentIdleState); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_2* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); 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; auto misc_info_writer = std::make_unique(); constexpr uint32_t kProcessIntegrityLevel = 0x2000; misc_info_writer->SetProcessIntegrityLevel(kProcessIntegrityLevel); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_3* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); MINIDUMP_MISC_INFO_3 expected = {}; expected.Flags1 = MINIDUMP_MISC3_PROCESS_INTEGRITY; expected.ProcessIntegrityLevel = kProcessIntegrityLevel; ExpectMiscInfoEqual(&expected, observed); } TEST(MinidumpMiscInfoWriter, ProcessExecuteFlags) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = std::make_unique(); constexpr uint32_t kProcessExecuteFlags = 0x13579bdf; misc_info_writer->SetProcessExecuteFlags(kProcessExecuteFlags); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_3* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); 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; auto misc_info_writer = std::make_unique(); constexpr uint32_t kProtectedProcess = 1; misc_info_writer->SetProtectedProcess(kProtectedProcess); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_3* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); MINIDUMP_MISC_INFO_3 expected = {}; expected.Flags1 = MINIDUMP_MISC3_PROTECTED_PROCESS; expected.ProtectedProcess = kProtectedProcess; ExpectMiscInfoEqual(&expected, observed); } TEST(MinidumpMiscInfoWriter, TimeZone) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = std::make_unique(); constexpr uint32_t kTimeZoneId = 2; constexpr int32_t kBias = 300; static constexpr char kStandardName[] = "EST"; constexpr SYSTEMTIME kStandardDate = {0, 11, 1, 0, 2, 0, 0, 0}; constexpr int32_t kStandardBias = 0; static constexpr char kDaylightName[] = "EDT"; constexpr SYSTEMTIME kDaylightDate = {0, 3, 2, 0, 2, 0, 0, 0}; constexpr int32_t kDaylightBias = -60; misc_info_writer->SetTimeZone(kTimeZoneId, kBias, kStandardName, kStandardDate, kStandardBias, kDaylightName, kDaylightDate, kDaylightBias); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_3* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); MINIDUMP_MISC_INFO_3 expected = {}; expected.Flags1 = MINIDUMP_MISC3_TIMEZONE; expected.TimeZoneId = kTimeZoneId; expected.TimeZone.Bias = kBias; std::u16string standard_name_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kStandardName)); c16lcpy(AsU16CStr(expected.TimeZone.StandardName), standard_name_utf16.c_str(), base::size(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kStandardDate, sizeof(expected.TimeZone.StandardDate)); expected.TimeZone.StandardBias = kStandardBias; std::u16string daylight_name_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kDaylightName)); c16lcpy(AsU16CStr(expected.TimeZone.DaylightName), daylight_name_utf16.c_str(), base::size(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; auto misc_info_writer = std::make_unique(); constexpr uint32_t kTimeZoneId = 2; constexpr int32_t kBias = 300; MINIDUMP_MISC_INFO_N tmp; ALLOW_UNUSED_LOCAL(tmp); std::string standard_name(base::size(tmp.TimeZone.StandardName) + 1, 's'); constexpr int32_t kStandardBias = 0; std::string daylight_name(base::size(tmp.TimeZone.DaylightName), 'd'); constexpr int32_t kDaylightBias = -60; // Test using kSystemTimeZero, because not all platforms will be able to // provide daylight saving time transition times. constexpr SYSTEMTIME kSystemTimeZero = {}; misc_info_writer->SetTimeZone(kTimeZoneId, kBias, standard_name, kSystemTimeZero, kStandardBias, daylight_name, kSystemTimeZero, kDaylightBias); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_3* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); MINIDUMP_MISC_INFO_3 expected = {}; expected.Flags1 = MINIDUMP_MISC3_TIMEZONE; expected.TimeZoneId = kTimeZoneId; expected.TimeZone.Bias = kBias; std::u16string standard_name_utf16 = base::UTF8ToUTF16(standard_name); c16lcpy(AsU16CStr(expected.TimeZone.StandardName), standard_name_utf16.c_str(), base::size(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kSystemTimeZero, sizeof(expected.TimeZone.StandardDate)); expected.TimeZone.StandardBias = kStandardBias; std::u16string daylight_name_utf16 = base::UTF8ToUTF16(daylight_name); c16lcpy(AsU16CStr(expected.TimeZone.DaylightName), daylight_name_utf16.c_str(), base::size(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; auto misc_info_writer = std::make_unique(); static constexpr char kBuildString[] = "build string"; static constexpr char kDebugBuildString[] = "debug build string"; misc_info_writer->SetBuildString(kBuildString, kDebugBuildString); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_4* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); MINIDUMP_MISC_INFO_4 expected = {}; expected.Flags1 = MINIDUMP_MISC4_BUILDSTRING; std::u16string build_string_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kBuildString)); c16lcpy(AsU16CStr(expected.BuildString), build_string_utf16.c_str(), base::size(expected.BuildString)); std::u16string debug_build_string_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kDebugBuildString)); c16lcpy(AsU16CStr(expected.DbgBldStr), debug_build_string_utf16.c_str(), base::size(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; auto misc_info_writer = std::make_unique(); MINIDUMP_MISC_INFO_N tmp; ALLOW_UNUSED_LOCAL(tmp); std::string build_string(base::size(tmp.BuildString) + 1, 'B'); std::string debug_build_string(base::size(tmp.DbgBldStr), 'D'); misc_info_writer->SetBuildString(build_string, debug_build_string); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_4* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); MINIDUMP_MISC_INFO_4 expected = {}; expected.Flags1 = MINIDUMP_MISC4_BUILDSTRING; std::u16string build_string_utf16 = base::UTF8ToUTF16(build_string); c16lcpy(AsU16CStr(expected.BuildString), build_string_utf16.c_str(), base::size(expected.BuildString)); std::u16string debug_build_string_utf16 = base::UTF8ToUTF16(debug_build_string); c16lcpy(AsU16CStr(expected.DbgBldStr), debug_build_string_utf16.c_str(), base::size(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } TEST(MinidumpMiscInfoWriter, XStateData) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = std::make_unique(); constexpr XSTATE_CONFIG_FEATURE_MSC_INFO kXStateData = { sizeof(XSTATE_CONFIG_FEATURE_MSC_INFO), 1024, 0x000000000000005f, { {0, 512}, {512, 256}, {768, 128}, {896, 64}, {960, 32}, {0, 0}, {992, 32}, }}; misc_info_writer->SetXStateData(kXStateData); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_5* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); MINIDUMP_MISC_INFO_5 expected = {}; expected.XStateData = kXStateData; ExpectMiscInfoEqual(&expected, observed); } TEST(MinidumpMiscInfoWriter, ProcessCookie) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = std::make_unique(); constexpr uint32_t kProcessCookie = 0x12345678; misc_info_writer->SetProcessCookie(kProcessCookie); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_5* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); MINIDUMP_MISC_INFO_5 expected = {}; expected.Flags1 = MINIDUMP_MISC5_PROCESS_COOKIE; expected.ProcessCookie = kProcessCookie; ExpectMiscInfoEqual(&expected, observed); } TEST(MinidumpMiscInfoWriter, Everything) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = std::make_unique(); constexpr uint32_t kProcessId = 12345; constexpr time_t kProcessCreateTime = 0x15252f00; constexpr uint32_t kProcessUserTime = 10; constexpr uint32_t kProcessKernelTime = 5; constexpr uint32_t kProcessorMaxMhz = 2800; constexpr uint32_t kProcessorCurrentMhz = 2300; constexpr uint32_t kProcessorMhzLimit = 3300; constexpr uint32_t kProcessorMaxIdleState = 5; constexpr uint32_t kProcessorCurrentIdleState = 1; constexpr uint32_t kProcessIntegrityLevel = 0x2000; constexpr uint32_t kProcessExecuteFlags = 0x13579bdf; constexpr uint32_t kProtectedProcess = 1; constexpr uint32_t kTimeZoneId = 2; constexpr int32_t kBias = 300; static constexpr char kStandardName[] = "EST"; constexpr int32_t kStandardBias = 0; static constexpr char kDaylightName[] = "EDT"; constexpr int32_t kDaylightBias = -60; constexpr SYSTEMTIME kSystemTimeZero = {}; static constexpr char kBuildString[] = "build string"; static constexpr 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); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_4* observed = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed)); 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; std::u16string standard_name_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kStandardName)); c16lcpy(AsU16CStr(expected.TimeZone.StandardName), standard_name_utf16.c_str(), base::size(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kSystemTimeZero, sizeof(expected.TimeZone.StandardDate)); expected.TimeZone.StandardBias = kStandardBias; std::u16string daylight_name_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kDaylightName)); c16lcpy(AsU16CStr(expected.TimeZone.DaylightName), daylight_name_utf16.c_str(), base::size(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kSystemTimeZero, sizeof(expected.TimeZone.DaylightDate)); expected.TimeZone.DaylightBias = kDaylightBias; std::u16string build_string_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kBuildString)); c16lcpy(AsU16CStr(expected.BuildString), build_string_utf16.c_str(), base::size(expected.BuildString)); std::u16string debug_build_string_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kDebugBuildString)); c16lcpy(AsU16CStr(expected.DbgBldStr), debug_build_string_utf16.c_str(), base::size(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) { MINIDUMP_MISC_INFO_4 expect_misc_info = {}; static constexpr char kStandardTimeName[] = "EST"; static constexpr char kDaylightTimeName[] = "EDT"; static constexpr char kOSVersionFull[] = "Mac OS X 10.9.5 (13F34); " "Darwin 13.4.0 Darwin Kernel Version 13.4.0: " "Sun Aug 17 19:50:11 PDT 2014; " "root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64"; static constexpr char kMachineDescription[] = "MacBookPro11,3 (Mac-2BD1B31983FE1663)"; std::u16string standard_time_name_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kStandardTimeName)); std::u16string daylight_time_name_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kDaylightTimeName)); std::u16string build_string_utf16 = base::UTF8ToUTF16( std::string(kOSVersionFull) + "; " + kMachineDescription); std::string debug_build_string = internal::MinidumpMiscInfoDebugBuildString(); EXPECT_FALSE(debug_build_string.empty()); std::u16string debug_build_string_utf16 = base::UTF8ToUTF16(debug_build_string); expect_misc_info.SizeOfInfo = sizeof(expect_misc_info); expect_misc_info.Flags1 = MINIDUMP_MISC1_PROCESS_ID | MINIDUMP_MISC1_PROCESS_TIMES | MINIDUMP_MISC1_PROCESSOR_POWER_INFO | MINIDUMP_MISC3_TIMEZONE | MINIDUMP_MISC4_BUILDSTRING; expect_misc_info.ProcessId = 12345; expect_misc_info.ProcessCreateTime = 0x555c7740; expect_misc_info.ProcessUserTime = 60; expect_misc_info.ProcessKernelTime = 15; expect_misc_info.ProcessorCurrentMhz = 2800; expect_misc_info.ProcessorMaxMhz = 2800; expect_misc_info.TimeZoneId = 1; expect_misc_info.TimeZone.Bias = 300; c16lcpy(AsU16CStr(expect_misc_info.TimeZone.StandardName), standard_time_name_utf16.c_str(), base::size(expect_misc_info.TimeZone.StandardName)); expect_misc_info.TimeZone.StandardBias = 0; c16lcpy(AsU16CStr(expect_misc_info.TimeZone.DaylightName), daylight_time_name_utf16.c_str(), base::size(expect_misc_info.TimeZone.DaylightName)); expect_misc_info.TimeZone.DaylightBias = -60; c16lcpy(AsU16CStr(expect_misc_info.BuildString), build_string_utf16.c_str(), base::size(expect_misc_info.BuildString)); c16lcpy(AsU16CStr(expect_misc_info.DbgBldStr), debug_build_string_utf16.c_str(), base::size(expect_misc_info.DbgBldStr)); const timeval kStartTime = { static_cast(expect_misc_info.ProcessCreateTime), 0}; const timeval kUserCPUTime = { static_cast(expect_misc_info.ProcessUserTime), 0}; const timeval kSystemCPUTime = { static_cast(expect_misc_info.ProcessKernelTime), 0}; TestProcessSnapshot process_snapshot; process_snapshot.SetProcessID(expect_misc_info.ProcessId); process_snapshot.SetProcessStartTime(kStartTime); process_snapshot.SetProcessCPUTimes(kUserCPUTime, kSystemCPUTime); auto system_snapshot = std::make_unique(); constexpr uint64_t kHzPerMHz = static_cast(1E6); system_snapshot->SetCPUFrequency( expect_misc_info.ProcessorCurrentMhz * kHzPerMHz, expect_misc_info.ProcessorMaxMhz * kHzPerMHz); system_snapshot->SetTimeZone(SystemSnapshot::kObservingStandardTime, expect_misc_info.TimeZone.Bias * -60, (expect_misc_info.TimeZone.Bias + expect_misc_info.TimeZone.DaylightBias) * -60, kStandardTimeName, kDaylightTimeName); system_snapshot->SetOSVersionFull(kOSVersionFull); system_snapshot->SetMachineDescription(kMachineDescription); process_snapshot.SetSystem(std::move(system_snapshot)); auto misc_info_writer = std::make_unique(); misc_info_writer->InitializeFromSnapshot(&process_snapshot); MinidumpFileWriter minidump_file_writer; ASSERT_TRUE(minidump_file_writer.AddStream(std::move(misc_info_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); const MINIDUMP_MISC_INFO_4* misc_info = nullptr; ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &misc_info)); ExpectMiscInfoEqual(&expect_misc_info, misc_info); } } // namespace } // namespace test } // namespace crashpad