diff --git a/minidump/minidump_crashpad_info_writer.cc b/minidump/minidump_crashpad_info_writer.cc index 22be5977..b77796ea 100644 --- a/minidump/minidump_crashpad_info_writer.cc +++ b/minidump/minidump_crashpad_info_writer.cc @@ -16,6 +16,7 @@ #include "base/logging.h" #include "minidump/minidump_module_crashpad_info_writer.h" +#include "snapshot/process_snapshot.h" #include "util/file/file_writer.h" namespace crashpad { @@ -28,6 +29,19 @@ MinidumpCrashpadInfoWriter::MinidumpCrashpadInfoWriter() MinidumpCrashpadInfoWriter::~MinidumpCrashpadInfoWriter() { } +void MinidumpCrashpadInfoWriter::InitializeFromSnapshot( + const ProcessSnapshot* process_snapshot) { + DCHECK_EQ(state(), kStateMutable); + DCHECK(!module_list_); + + auto modules = make_scoped_ptr(new MinidumpModuleCrashpadInfoListWriter()); + modules->InitializeFromSnapshot(process_snapshot->Modules()); + + if (modules->IsUseful()) { + SetModuleList(modules.Pass()); + } +} + void MinidumpCrashpadInfoWriter::SetModuleList( scoped_ptr module_list) { DCHECK_EQ(state(), kStateMutable); @@ -77,4 +91,8 @@ MinidumpStreamType MinidumpCrashpadInfoWriter::StreamType() const { return kMinidumpStreamTypeCrashpadInfo; } +bool MinidumpCrashpadInfoWriter::IsUseful() const { + return module_list_; +} + } // namespace crashpad diff --git a/minidump/minidump_crashpad_info_writer.h b/minidump/minidump_crashpad_info_writer.h index 43f6d551..22c60747 100644 --- a/minidump/minidump_crashpad_info_writer.h +++ b/minidump/minidump_crashpad_info_writer.h @@ -25,6 +25,7 @@ namespace crashpad { class MinidumpModuleCrashpadInfoListWriter; +class ProcessSnapshot; //! \brief The writer for a MinidumpCrashpadInfo stream in a minidump file. class MinidumpCrashpadInfoWriter final : public internal::MinidumpStreamWriter { @@ -32,6 +33,23 @@ class MinidumpCrashpadInfoWriter final : public internal::MinidumpStreamWriter { MinidumpCrashpadInfoWriter(); ~MinidumpCrashpadInfoWriter() override; + //! \brief Initializes MinidumpCrashpadInfo based on \a process_snapshot. + //! + //! This method may add additional structures to the minidump file as children + //! of the MinidumpCrashpadInfo stream. To do so, it may obtain other + //! snapshot information from \a process_snapshot, such as a list of + //! ModuleSnapshot objects used to initialize + //! MinidumpCrashpadInfo::module_list. Only data that is considered useful + //! will be included. For module information, usefulness is determined by + //! MinidumpModuleCrashpadInfoListWriter::IsUseful(). + //! + //! \param[in] process_snapshot The process snapshot to use as source data. + //! + //! \note Valid in #kStateMutable. No mutator methods may be called before + //! this method, and it is not normally necessary to call any mutator + //! methods after this method. + void InitializeFromSnapshot(const ProcessSnapshot* process_snapshot); + //! \brief Arranges for MinidumpCrashpadInfo::module_list to point to the //! MinidumpModuleCrashpadInfoList object to be written by \a //! module_list. @@ -43,6 +61,15 @@ class MinidumpCrashpadInfoWriter final : public internal::MinidumpStreamWriter { void SetModuleList( scoped_ptr module_list); + //! \brief Determines whether the object is useful. + //! + //! A useful object is one that carries data that makes a meaningful + //! contribution to a minidump file. An object carrying children would be + //! considered useful. + //! + //! \return `true` if the object is useful, `false` otherwise. + bool IsUseful() const; + protected: // MinidumpWritable: bool Freeze() override; diff --git a/minidump/minidump_crashpad_info_writer_test.cc b/minidump/minidump_crashpad_info_writer_test.cc index 2840d348..27907965 100644 --- a/minidump/minidump_crashpad_info_writer_test.cc +++ b/minidump/minidump_crashpad_info_writer_test.cc @@ -21,7 +21,10 @@ #include "minidump/minidump_file_writer.h" #include "minidump/minidump_module_crashpad_info_writer.h" #include "minidump/test/minidump_file_writer_test_util.h" +#include "minidump/test/minidump_string_writer_test_util.h" #include "minidump/test/minidump_writable_test_util.h" +#include "snapshot/test/test_module_snapshot.h" +#include "snapshot/test/test_process_snapshot.h" #include "util/file/string_file_writer.h" namespace crashpad { @@ -51,6 +54,7 @@ void GetCrashpadInfoStream(const std::string& file_contents, TEST(MinidumpCrashpadInfoWriter, Empty) { MinidumpFileWriter minidump_file_writer; auto crashpad_info_writer = make_scoped_ptr(new MinidumpCrashpadInfoWriter()); + EXPECT_FALSE(crashpad_info_writer->IsUseful()); minidump_file_writer.AddStream(crashpad_info_writer.Pass()); @@ -80,6 +84,8 @@ TEST(MinidumpCrashpadInfoWriter, CrashpadModuleList) { module_list_writer->AddModule(module_writer.Pass()); crashpad_info_writer->SetModuleList(module_list_writer.Pass()); + EXPECT_TRUE(crashpad_info_writer->IsUseful()); + minidump_file_writer.AddStream(crashpad_info_writer.Pass()); StringFileWriter file_writer; @@ -102,10 +108,77 @@ TEST(MinidumpCrashpadInfoWriter, CrashpadModuleList) { EXPECT_EQ(MinidumpModuleCrashpadInfo::kVersion, module->version); EXPECT_EQ(kMinidumpModuleListIndex, module->minidump_module_list_index); + EXPECT_EQ(0u, module->list_annotations.DataSize); + EXPECT_EQ(0u, module->list_annotations.Rva); EXPECT_EQ(0u, module->simple_annotations.DataSize); EXPECT_EQ(0u, module->simple_annotations.Rva); } +TEST(MinidumpCrashpadInfoWriter, InitializeFromSnapshot) { + const char kEntry[] = "This is a simple annotation in a list."; + + // Test with a useless module, one that doesn’t carry anything that would + // require MinidumpCrashpadInfo or any child object. + auto process_snapshot = make_scoped_ptr(new TestProcessSnapshot()); + + auto module_snapshot = make_scoped_ptr(new TestModuleSnapshot()); + process_snapshot->AddModule(module_snapshot.Pass()); + + auto info_writer = make_scoped_ptr(new MinidumpCrashpadInfoWriter()); + info_writer->InitializeFromSnapshot(process_snapshot.get()); + EXPECT_FALSE(info_writer->IsUseful()); + + // Try again with a useful module. + process_snapshot.reset(new TestProcessSnapshot()); + + module_snapshot.reset(new TestModuleSnapshot()); + std::vector annotations_list(1, std::string(kEntry)); + module_snapshot->SetAnnotationsVector(annotations_list); + process_snapshot->AddModule(module_snapshot.Pass()); + + info_writer.reset(new MinidumpCrashpadInfoWriter()); + info_writer->InitializeFromSnapshot(process_snapshot.get()); + EXPECT_TRUE(info_writer->IsUseful()); + + MinidumpFileWriter minidump_file_writer; + minidump_file_writer.AddStream(info_writer.Pass()); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); + + const MinidumpCrashpadInfo* info; + const MinidumpModuleCrashpadInfoList* module_list; + ASSERT_NO_FATAL_FAILURE(GetCrashpadInfoStream( + file_writer.string(), &info, &module_list)); + + EXPECT_EQ(MinidumpCrashpadInfo::kVersion, info->version); + ASSERT_TRUE(module_list); + ASSERT_EQ(1u, module_list->count); + + const MinidumpModuleCrashpadInfo* module = + MinidumpWritableAtLocationDescriptor( + file_writer.string(), module_list->children[0]); + ASSERT_TRUE(module); + + EXPECT_EQ(MinidumpModuleCrashpadInfo::kVersion, module->version); + EXPECT_EQ(0u, module->minidump_module_list_index); + + const MinidumpRVAList* list_annotations = + MinidumpWritableAtLocationDescriptor( + file_writer.string(), module->list_annotations); + ASSERT_TRUE(list_annotations); + + ASSERT_EQ(1u, list_annotations->count); + EXPECT_EQ(kEntry, + MinidumpUTF8StringAtRVAAsString( + file_writer.string(), list_annotations->children[0])); + + const MinidumpSimpleStringDictionary* simple_annotations = + MinidumpWritableAtLocationDescriptor( + file_writer.string(), module->simple_annotations); + EXPECT_FALSE(simple_annotations); +} + } // namespace } // namespace test } // namespace crashpad diff --git a/minidump/minidump_module_crashpad_info_writer.cc b/minidump/minidump_module_crashpad_info_writer.cc index 93da6f0f..d8568583 100644 --- a/minidump/minidump_module_crashpad_info_writer.cc +++ b/minidump/minidump_module_crashpad_info_writer.cc @@ -161,4 +161,8 @@ void MinidumpModuleCrashpadInfoListWriter::AddModule( AddChild(module.Pass()); } +bool MinidumpModuleCrashpadInfoListWriter::IsUseful() const { + return !IsEmpty(); +} + } // namespace crashpad diff --git a/minidump/minidump_module_crashpad_info_writer.h b/minidump/minidump_module_crashpad_info_writer.h index 030755e5..b2c54c76 100644 --- a/minidump/minidump_module_crashpad_info_writer.h +++ b/minidump/minidump_module_crashpad_info_writer.h @@ -41,8 +41,7 @@ class MinidumpModuleCrashpadInfoWriter final MinidumpModuleCrashpadInfoWriter(); ~MinidumpModuleCrashpadInfoWriter() override; - //! \brief Initializes the MinidumpModuleCrashpadInfo based on \a - //! module_snapshot. + //! \brief Initializes MinidumpModuleCrashpadInfo based on \a module_snapshot. //! //! Only data in \a module_snapshot that is considered useful will be //! included. For simple annotations, usefulness is determined by @@ -142,6 +141,15 @@ class MinidumpModuleCrashpadInfoListWriter final //! \note Valid in #kStateMutable. void AddModule(scoped_ptr module); + //! \brief Determines whether the object is useful. + //! + //! A useful object is one that carries data that makes a meaningful + //! contribution to a minidump file. An object carrying children would be + //! considered useful. + //! + //! \return `true` if the object is useful, `false` otherwise. + bool IsUseful() const; + private: DISALLOW_COPY_AND_ASSIGN(MinidumpModuleCrashpadInfoListWriter); }; diff --git a/minidump/minidump_module_crashpad_info_writer_test.cc b/minidump/minidump_module_crashpad_info_writer_test.cc index 47aa7601..a798f03f 100644 --- a/minidump/minidump_module_crashpad_info_writer_test.cc +++ b/minidump/minidump_module_crashpad_info_writer_test.cc @@ -34,6 +34,7 @@ TEST(MinidumpModuleCrashpadInfoWriter, EmptyList) { StringFileWriter file_writer; MinidumpModuleCrashpadInfoListWriter module_list_writer; + EXPECT_FALSE(module_list_writer.IsUseful()); EXPECT_TRUE(module_list_writer.WriteEverything(&file_writer)); ASSERT_EQ(sizeof(MinidumpModuleCrashpadInfoList), @@ -53,6 +54,8 @@ TEST(MinidumpModuleCrashpadInfoWriter, EmptyModule) { EXPECT_FALSE(module_writer->IsUseful()); module_list_writer.AddModule(module_writer.Pass()); + EXPECT_TRUE(module_list_writer.IsUseful()); + EXPECT_TRUE(module_list_writer.WriteEverything(&file_writer)); ASSERT_EQ(sizeof(MinidumpModuleCrashpadInfoList) + sizeof(MINIDUMP_LOCATION_DESCRIPTOR) + @@ -105,6 +108,8 @@ TEST(MinidumpModuleCrashpadInfoWriter, FullModule) { EXPECT_TRUE(module_writer->IsUseful()); module_list_writer.AddModule(module_writer.Pass()); + EXPECT_TRUE(module_list_writer.IsUseful()); + EXPECT_TRUE(module_list_writer.WriteEverything(&file_writer)); ASSERT_EQ(sizeof(MinidumpModuleCrashpadInfoList) + sizeof(MINIDUMP_LOCATION_DESCRIPTOR) + @@ -213,6 +218,8 @@ TEST(MinidumpModuleCrashpadInfoWriter, ThreeModules) { EXPECT_TRUE(module_writer_2->IsUseful()); module_list_writer.AddModule(module_writer_2.Pass()); + EXPECT_TRUE(module_list_writer.IsUseful()); + EXPECT_TRUE(module_list_writer.WriteEverything(&file_writer)); const MinidumpModuleCrashpadInfoList* module_list = @@ -335,6 +342,7 @@ TEST(MinidumpModuleCrashpadInfoWriter, InitializeFromSnapshot) { MinidumpModuleCrashpadInfoListWriter module_list_writer; module_list_writer.InitializeFromSnapshot(module_snapshots); + EXPECT_TRUE(module_list_writer.IsUseful()); StringFileWriter file_writer; ASSERT_TRUE(module_list_writer.WriteEverything(&file_writer));