blob: bd9273385037e9476c8544c9b09c65f86be2c203 [file] [log] [blame]
// 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 <string.h>
#include <string>
#include <utility>
#include "base/compiler_specific.h"
#include "base/format_macros.h"
#include "base/stl_util.h"
#include "base/strings/string16.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 <typename T>
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<T>(file_contents,
directory[0].Location);
ASSERT_TRUE(misc_info);
}
void ExpectNULPaddedString16Equal(const base::char16* expected,
const base::char16* observed,
size_t size) {
base::string16 expected_string(expected, size);
base::string16 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 <typename T>
void ExpectMiscInfoEqual(const T* expected, const T* observed);
template <>
void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO>(
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<MINIDUMP_MISC_INFO_2>(
const MINIDUMP_MISC_INFO_2* expected,
const MINIDUMP_MISC_INFO_2* observed) {
ExpectMiscInfoEqual<MINIDUMP_MISC_INFO>(
reinterpret_cast<const MINIDUMP_MISC_INFO*>(expected),
reinterpret_cast<const MINIDUMP_MISC_INFO*>(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<MINIDUMP_MISC_INFO_3>(
const MINIDUMP_MISC_INFO_3* expected,
const MINIDUMP_MISC_INFO_3* observed) {
ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_2>(
reinterpret_cast<const MINIDUMP_MISC_INFO_2*>(expected),
reinterpret_cast<const MINIDUMP_MISC_INFO_2*>(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(expected->TimeZone.StandardName,
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(expected->TimeZone.DaylightName,
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<MINIDUMP_MISC_INFO_4>(
const MINIDUMP_MISC_INFO_4* expected,
const MINIDUMP_MISC_INFO_4* observed) {
ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_3>(
reinterpret_cast<const MINIDUMP_MISC_INFO_3*>(expected),
reinterpret_cast<const MINIDUMP_MISC_INFO_3*>(observed));
{
SCOPED_TRACE("BuildString");
ExpectNULPaddedString16Equal(expected->BuildString,
observed->BuildString,
base::size(expected->BuildString));
}
{
SCOPED_TRACE("DbgBldStr");
ExpectNULPaddedString16Equal(expected->DbgBldStr,
observed->DbgBldStr,
base::size(expected->DbgBldStr));
}
}
template <>
void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_5>(
const MINIDUMP_MISC_INFO_5* expected,
const MINIDUMP_MISC_INFO_5* observed) {
ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_4>(
reinterpret_cast<const MINIDUMP_MISC_INFO_4*>(expected),
reinterpret_cast<const MINIDUMP_MISC_INFO_4*>(observed));
EXPECT_EQ(observed->XStateData.SizeOfInfo, expected->XStateData.SizeOfInfo);
EXPECT_EQ(observed->XStateData.ContextSize, expected->XStateData.ContextSize);
EXPECT_EQ(observed->XStateData.EnabledFeatures,
expected->XStateData.EnabledFeatures);
for (size_t feature_index = 0;
feature_index < base::size(observed->XStateData.Features);
++feature_index) {
SCOPED_TRACE(base::StringPrintf("feature_index %" PRIuS, feature_index));
EXPECT_EQ(observed->XStateData.Features[feature_index].Offset,
expected->XStateData.Features[feature_index].Offset);
EXPECT_EQ(observed->XStateData.Features[feature_index].Size,
expected->XStateData.Features[feature_index].Size);
}
EXPECT_EQ(observed->ProcessCookie, expected->ProcessCookie);
}
TEST(MinidumpMiscInfoWriter, Empty) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = std::make_unique<MinidumpMiscInfoWriter>();
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<MinidumpMiscInfoWriter>();
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<MinidumpMiscInfoWriter>();
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<MinidumpMiscInfoWriter>();
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<MinidumpMiscInfoWriter>();
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<MinidumpMiscInfoWriter>();
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<MinidumpMiscInfoWriter>();
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<MinidumpMiscInfoWriter>();
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;
base::string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName);
c16lcpy(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;
base::string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName);
c16lcpy(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<MinidumpMiscInfoWriter>();
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;
base::string16 standard_name_utf16 = base::UTF8ToUTF16(standard_name);
c16lcpy(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;
base::string16 daylight_name_utf16 = base::UTF8ToUTF16(daylight_name);
c16lcpy(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<MinidumpMiscInfoWriter>();
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;
base::string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString);
c16lcpy(expected.BuildString,
build_string_utf16.c_str(),
base::size(expected.BuildString));
base::string16 debug_build_string_utf16 =
base::UTF8ToUTF16(kDebugBuildString);
c16lcpy(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<MinidumpMiscInfoWriter>();
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;
base::string16 build_string_utf16 = base::UTF8ToUTF16(build_string);
c16lcpy(expected.BuildString,
build_string_utf16.c_str(),
base::size(expected.BuildString));
base::string16 debug_build_string_utf16 =
base::UTF8ToUTF16(debug_build_string);
c16lcpy(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<MinidumpMiscInfoWriter>();
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<MinidumpMiscInfoWriter>();
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<MinidumpMiscInfoWriter>();
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;
base::string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName);
c16lcpy(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;
base::string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName);
c16lcpy(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;
base::string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString);
c16lcpy(expected.BuildString,
build_string_utf16.c_str(),
base::size(expected.BuildString));
base::string16 debug_build_string_utf16 =
base::UTF8ToUTF16(kDebugBuildString);
c16lcpy(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)";
base::string16 standard_time_name_utf16 =
base::UTF8ToUTF16(kStandardTimeName);
base::string16 daylight_time_name_utf16 =
base::UTF8ToUTF16(kDaylightTimeName);
base::string16 build_string_utf16 = base::UTF8ToUTF16(
std::string(kOSVersionFull) + "; " + kMachineDescription);
std::string debug_build_string = internal::MinidumpMiscInfoDebugBuildString();
EXPECT_FALSE(debug_build_string.empty());
base::string16 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(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(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(expect_misc_info.BuildString,
build_string_utf16.c_str(),
base::size(expect_misc_info.BuildString));
c16lcpy(expect_misc_info.DbgBldStr,
debug_build_string_utf16.c_str(),
base::size(expect_misc_info.DbgBldStr));
const timeval kStartTime =
{ static_cast<time_t>(expect_misc_info.ProcessCreateTime), 0 };
const timeval kUserCPUTime =
{ static_cast<time_t>(expect_misc_info.ProcessUserTime), 0 };
const timeval kSystemCPUTime =
{ static_cast<time_t>(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<TestSystemSnapshot>();
constexpr uint64_t kHzPerMHz = static_cast<uint64_t>(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<MinidumpMiscInfoWriter>();
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