From 859560f70dd977d7ac9205f961134b237793a967 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Sun, 3 Aug 2014 18:47:34 -0400 Subject: [PATCH] Add MinidumpFileWriter and its test. MinidumpFileWriter writes the top-level object to a minidump file. This consists of a MINIDUMP_HEADER and a list of MINIDUMP_DIRECTORY entries that point to streams, which are second-level objects in minidump files. This change also adds the base class for stream writers, MinidumpStreamWriter. TEST=minidump_test MinidumpFileWriter* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/432863006 --- minidump/minidump.gyp | 5 + minidump/minidump_extensions.h | 2 +- minidump/minidump_file_writer.cc | 161 +++++++++++++++++ minidump/minidump_file_writer.h | 87 ++++++++++ minidump/minidump_file_writer_test.cc | 237 ++++++++++++++++++++++++++ minidump/minidump_stream_writer.cc | 46 +++++ minidump/minidump_stream_writer.h | 65 +++++++ 7 files changed, 602 insertions(+), 1 deletion(-) create mode 100644 minidump/minidump_file_writer.cc create mode 100644 minidump/minidump_file_writer.h create mode 100644 minidump/minidump_file_writer_test.cc create mode 100644 minidump/minidump_stream_writer.cc create mode 100644 minidump/minidump_stream_writer.h diff --git a/minidump/minidump.gyp b/minidump/minidump.gyp index b1b21ecb..9fe0e787 100644 --- a/minidump/minidump.gyp +++ b/minidump/minidump.gyp @@ -30,6 +30,10 @@ ], 'sources': [ 'minidump_extensions.h', + 'minidump_file_writer.cc', + 'minidump_file_writer.h', + 'minidump_stream_writer.cc', + 'minidump_stream_writer.h', 'minidump_string_writer.cc', 'minidump_string_writer.h', 'minidump_writable.cc', @@ -51,6 +55,7 @@ ], 'sources': [ '../third_party/gtest/gtest/src/gtest_main.cc', + 'minidump_file_writer_test.cc', 'minidump_string_writer_test.cc', 'minidump_writable_test.cc', ], diff --git a/minidump/minidump_extensions.h b/minidump/minidump_extensions.h index 5799e53b..26b34519 100644 --- a/minidump/minidump_extensions.h +++ b/minidump/minidump_extensions.h @@ -27,7 +27,7 @@ namespace crashpad { //! stream structure has a corresponding stream type value to identify it. //! //! \sa MINIDUMP_STREAM_TYPE -enum MinidumpStreamType { +enum MinidumpStreamType : uint32_t { //! \brief The stream type for MINIDUMP_THREAD_LIST. //! //! \sa ThreadListStream diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc new file mode 100644 index 00000000..4ee1bd07 --- /dev/null +++ b/minidump/minidump_file_writer.cc @@ -0,0 +1,161 @@ +// 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_file_writer.h" + +#include "base/logging.h" +#include "minidump/minidump_writer_util.h" +#include "util/numeric/safe_assignment.h" + +namespace crashpad { + +MinidumpFileWriter::MinidumpFileWriter() + : MinidumpWritable(), header_(), streams_(), stream_types_() { + // Don’t set the signature field right away. Leave it set to 0, so that a + // partially-written minidump file isn’t confused for a complete and valid + // one. The header will be rewritten in WriteToFile(). + header_.Signature = 0; + + header_.Version = MINIDUMP_VERSION; + header_.CheckSum = 0; + header_.Flags = MiniDumpNormal; +} + +MinidumpFileWriter::~MinidumpFileWriter() { +} + +void MinidumpFileWriter::SetTimestamp(time_t timestamp) { + DCHECK_EQ(state(), kStateMutable); + + internal::MinidumpWriterUtil::AssignTimeT(&header_.TimeDateStamp, timestamp); +} + +void MinidumpFileWriter::AddStream(internal::MinidumpStreamWriter* stream) { + DCHECK_EQ(state(), kStateMutable); + + MinidumpStreamType stream_type = stream->StreamType(); + + auto rv = stream_types_.insert(stream_type); + CHECK(rv.second) << "stream_type " << stream_type << " already present"; + + streams_.push_back(stream); + + DCHECK_EQ(streams_.size(), stream_types_.size()); +} + +bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) { + DCHECK_EQ(state(), kStateMutable); + + off_t start_offset = file_writer->Seek(0, SEEK_CUR); + if (start_offset < 0) { + return false; + } + + if (!MinidumpWritable::WriteEverything(file_writer)) { + return false; + } + + off_t end_offset = file_writer->Seek(0, SEEK_CUR); + if (end_offset < 0) { + return false; + } + + // Now that the entire minidump file has been completely written, go back to + // the beginning and rewrite the header with the correct signature to identify + // it as a valid minidump file. + header_.Signature = MINIDUMP_SIGNATURE; + + if (file_writer->Seek(start_offset, SEEK_SET) != 0) { + return false; + } + + if (!file_writer->Write(&header_, sizeof(header_))) { + return false; + } + + // Seek back to the end of the file, in case some non-minidump content will be + // written to the file after the minidump content. + return file_writer->Seek(end_offset, SEEK_SET); +} + +bool MinidumpFileWriter::Freeze() { + DCHECK_EQ(state(), kStateMutable); + + if (!MinidumpWritable::Freeze()) { + return false; + } + + size_t stream_count = streams_.size(); + CHECK_EQ(stream_count, stream_types_.size()); + + if (!AssignIfInRange(&header_.NumberOfStreams, stream_count)) { + LOG(ERROR) << "stream_count " << stream_count << " out of range"; + return false; + } + + return true; +} + +size_t MinidumpFileWriter::SizeOfObject() { + DCHECK_GE(state(), kStateFrozen); + DCHECK_EQ(streams_.size(), stream_types_.size()); + + return sizeof(header_) + streams_.size() * sizeof(MINIDUMP_DIRECTORY); +} + +std::vector MinidumpFileWriter::Children() { + DCHECK_GE(state(), kStateFrozen); + DCHECK_EQ(streams_.size(), stream_types_.size()); + + std::vector children; + for (internal::MinidumpStreamWriter* stream : streams_) { + children.push_back(stream); + } + + return children; +} + +bool MinidumpFileWriter::WillWriteAtOffsetImpl(off_t offset) { + DCHECK_EQ(state(), kStateFrozen); + DCHECK_EQ(offset, 0); + DCHECK_EQ(streams_.size(), stream_types_.size()); + + auto directory_offset = streams_.empty() ? 0 : offset + sizeof(header_); + if (!AssignIfInRange(&header_.StreamDirectoryRva, directory_offset)) { + LOG(ERROR) << "offset " << directory_offset << " out of range"; + return false; + } + + return MinidumpWritable::WillWriteAtOffsetImpl(offset); +} + +bool MinidumpFileWriter::WriteObject(FileWriterInterface* file_writer) { + DCHECK_EQ(state(), kStateWritable); + DCHECK_EQ(streams_.size(), stream_types_.size()); + + WritableIoVec iov; + iov.iov_base = &header_; + iov.iov_len = sizeof(header_); + std::vector iovecs(1, iov); + + for (internal::MinidumpStreamWriter* stream : streams_) { + iov.iov_len = sizeof(MINIDUMP_DIRECTORY); + iov.iov_base = stream->DirectoryListEntry(); + iovecs.push_back(iov); + } + + return file_writer->WriteIoVec(&iovecs); +} + +} // namespace crashpad diff --git a/minidump/minidump_file_writer.h b/minidump/minidump_file_writer.h new file mode 100644 index 00000000..bc9753d2 --- /dev/null +++ b/minidump/minidump_file_writer.h @@ -0,0 +1,87 @@ +// 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_FILE_WRITER_H_ +#define CRASHPAD_MINIDUMP_MINIDUMP_FILE_WRITER_H_ + +#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 root-level object in a minidump file. +//! +//! This object writes a MINIDUMP_HEADER and list of MINIDUMP_DIRECTORY entries +//! to a minidump file. +class MinidumpFileWriter final : public internal::MinidumpWritable { + public: + MinidumpFileWriter(); + ~MinidumpFileWriter(); + + //! \brief Sets MINIDUMP_HEADER::Timestamp. + //! + //! \note Valid in #kStateMutable. + void SetTimestamp(time_t timestamp); + + //! \brief Adds a stream to the minidump file as a child of the object, and + //! arranges for a MINIDUMP_DIRECTORY entry to point to it. + //! + //! At most one object of each stream type (as obtained from + //! internal::MinidumpStreamWriter::StreamType()) may be added to a + //! MinidumpFileWriter object. It is an error to attempt to add multiple + //! streams with the same stream type. + //! + //! \note Valid in #kStateMutable. + void AddStream(internal::MinidumpStreamWriter* stream); + + // MinidumpWritable: + + //! \copydoc internal::MinidumpWritable::WriteEverything() + //! + //! This method does not initially write the final value for + //! MINIDUMP_HEADER::Signature. After all child objects have been written, it + //! rewinds to the beginning of the file and writes the correct value for this + //! field. This prevents incompletely-written minidump files from being + //! mistaken for valid ones. + virtual bool WriteEverything(FileWriterInterface* file_writer) override; + + protected: + // MinidumpWritable: + virtual bool Freeze() override; + virtual size_t SizeOfObject() override; + virtual std::vector Children() override; + virtual bool WillWriteAtOffsetImpl(off_t offset) override; + virtual bool WriteObject(FileWriterInterface* file_writer) override; + + private: + MINIDUMP_HEADER header_; + std::vector streams_; // weak + + // Protects against multiple streams with the same ID being added. + std::set stream_types_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpFileWriter); +}; + +} // namespace crashpad + +#endif // CRASHPAD_MINIDUMP_MINIDUMP_WRITER_H_ diff --git a/minidump/minidump_file_writer_test.cc b/minidump/minidump_file_writer_test.cc new file mode 100644 index 00000000..a2aa4d04 --- /dev/null +++ b/minidump/minidump_file_writer_test.cc @@ -0,0 +1,237 @@ +// 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_file_writer.h" + +#include + +#include + +#include "base/basictypes.h" +#include "gtest/gtest.h" +#include "minidump/minidump_stream_writer.h" +#include "minidump/minidump_writable.h" +#include "util/file/file_writer.h" +#include "util/file/string_file_writer.h" + +namespace { + +using namespace crashpad; + +TEST(MinidumpFileWriter, Empty) { + MinidumpFileWriter minidump_file; + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file.WriteEverything(&file_writer)); + ASSERT_EQ(sizeof(MINIDUMP_HEADER), file_writer.string().size()); + + const MINIDUMP_HEADER* header = + reinterpret_cast(&file_writer.string()[0]); + + EXPECT_EQ(static_cast(MINIDUMP_SIGNATURE), header->Signature); + EXPECT_EQ(static_cast(MINIDUMP_VERSION), header->Version); + EXPECT_EQ(0u, header->NumberOfStreams); + EXPECT_EQ(0u, header->StreamDirectoryRva); + EXPECT_EQ(0u, header->CheckSum); + EXPECT_EQ(0u, header->TimeDateStamp); + EXPECT_EQ(MiniDumpNormal, header->Flags); +} + +class TestStream final : public internal::MinidumpStreamWriter { + public: + TestStream(MinidumpStreamType stream_type, + size_t stream_size, + uint8_t stream_value) + : stream_data_(stream_size, stream_value), stream_type_(stream_type) {} + + ~TestStream() {} + + // MinidumpStreamWriter: + virtual MinidumpStreamType StreamType() const override { + return stream_type_; + } + + protected: + // MinidumpWritable: + virtual size_t SizeOfObject() override { + EXPECT_GE(state(), kStateFrozen); + return stream_data_.size(); + } + + virtual bool WriteObject(FileWriterInterface* file_writer) override { + EXPECT_EQ(state(), kStateWritable); + return file_writer->Write(&stream_data_[0], stream_data_.size()); + } + + private: + std::string stream_data_; + MinidumpStreamType stream_type_; + + DISALLOW_COPY_AND_ASSIGN(TestStream); +}; + +TEST(MinidumpFileWriter, OneStream) { + MinidumpFileWriter minidump_file; + const time_t kTimestamp = 0x155d2fb8; + minidump_file.SetTimestamp(kTimestamp); + + const size_t kStreamSize = 5; + const MinidumpStreamType kStreamType = static_cast(0x4d); + const uint8_t kStreamValue = 0x5a; + TestStream stream(kStreamType, kStreamSize, kStreamValue); + minidump_file.AddStream(&stream); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file.WriteEverything(&file_writer)); + + const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + const size_t kStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); + const size_t kFileSize = kStreamOffset + kStreamSize; + + ASSERT_EQ(kFileSize, file_writer.string().size()); + + const MINIDUMP_HEADER* header = + reinterpret_cast(&file_writer.string()[0]); + + EXPECT_EQ(static_cast(MINIDUMP_SIGNATURE), header->Signature); + EXPECT_EQ(static_cast(MINIDUMP_VERSION), header->Version); + EXPECT_EQ(1u, header->NumberOfStreams); + EXPECT_EQ(kDirectoryOffset, header->StreamDirectoryRva); + EXPECT_EQ(0u, header->CheckSum); + EXPECT_EQ(kTimestamp, header->TimeDateStamp); + EXPECT_EQ(MiniDumpNormal, header->Flags); + + const MINIDUMP_DIRECTORY* directory = + reinterpret_cast( + &file_writer.string()[kDirectoryOffset]); + + EXPECT_EQ(kStreamType, directory->StreamType); + EXPECT_EQ(kStreamSize, directory->Location.DataSize); + EXPECT_EQ(kStreamOffset, directory->Location.Rva); + + const uint8_t* stream_data = + reinterpret_cast(&file_writer.string()[kStreamOffset]); + + std::string expected_stream(kStreamSize, kStreamValue); + EXPECT_EQ(0, memcmp(stream_data, expected_stream.c_str(), kStreamSize)); +} + +TEST(MinidumpFileWriter, ThreeStreams) { + MinidumpFileWriter minidump_file; + const time_t kTimestamp = 0x155d2fb8; + minidump_file.SetTimestamp(kTimestamp); + + const size_t kStream1Size = 5; + const MinidumpStreamType kStream1Type = static_cast(0x6d); + const uint8_t kStream1Value = 0x5a; + TestStream stream1(kStream1Type, kStream1Size, kStream1Value); + minidump_file.AddStream(&stream1); + + // Make the second stream’s type be a smaller quantity than the first stream’s + // to test that the streams show up in the order that they were added, not in + // numeric order. + const size_t kStream2Size = 3; + const MinidumpStreamType kStream2Type = static_cast(0x4d); + const uint8_t kStream2Value = 0xa5; + TestStream stream2(kStream2Type, kStream2Size, kStream2Value); + minidump_file.AddStream(&stream2); + + const size_t kStream3Size = 1; + const MinidumpStreamType kStream3Type = static_cast(0x7e); + const uint8_t kStream3Value = 0x36; + TestStream stream3(kStream3Type, kStream3Size, kStream3Value); + minidump_file.AddStream(&stream3); + + StringFileWriter file_writer; + ASSERT_TRUE(minidump_file.WriteEverything(&file_writer)); + + const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + const size_t kStream1Offset = + kDirectoryOffset + 3 * sizeof(MINIDUMP_DIRECTORY); + const size_t kStream2Padding = 3; + const size_t kStream2Offset = kStream1Offset + kStream1Size + kStream2Padding; + const size_t kStream3Padding = 1; + const size_t kStream3Offset = kStream2Offset + kStream2Size + kStream3Padding; + const size_t kFileSize = kStream3Offset + kStream3Size; + + ASSERT_EQ(kFileSize, file_writer.string().size()); + + const MINIDUMP_HEADER* header = + reinterpret_cast(&file_writer.string()[0]); + + EXPECT_EQ(static_cast(MINIDUMP_SIGNATURE), header->Signature); + EXPECT_EQ(static_cast(MINIDUMP_VERSION), header->Version); + EXPECT_EQ(3u, header->NumberOfStreams); + EXPECT_EQ(kDirectoryOffset, header->StreamDirectoryRva); + EXPECT_EQ(0u, header->CheckSum); + EXPECT_EQ(kTimestamp, header->TimeDateStamp); + EXPECT_EQ(MiniDumpNormal, header->Flags); + + const MINIDUMP_DIRECTORY* directory = + reinterpret_cast( + &file_writer.string()[kDirectoryOffset]); + + EXPECT_EQ(kStream1Type, directory[0].StreamType); + EXPECT_EQ(kStream1Size, directory[0].Location.DataSize); + EXPECT_EQ(kStream1Offset, directory[0].Location.Rva); + EXPECT_EQ(kStream2Type, directory[1].StreamType); + EXPECT_EQ(kStream2Size, directory[1].Location.DataSize); + EXPECT_EQ(kStream2Offset, directory[1].Location.Rva); + EXPECT_EQ(kStream3Type, directory[2].StreamType); + EXPECT_EQ(kStream3Size, directory[2].Location.DataSize); + EXPECT_EQ(kStream3Offset, directory[2].Location.Rva); + + const uint8_t* stream1_data = + reinterpret_cast(&file_writer.string()[kStream1Offset]); + + std::string expected_stream1(kStream1Size, kStream1Value); + EXPECT_EQ(0, memcmp(stream1_data, expected_stream1.c_str(), kStream1Size)); + + const int kZeroes[16] = {}; + ASSERT_GE(sizeof(kZeroes), kStream2Padding); + EXPECT_EQ(0, memcmp(stream1_data + kStream1Size, kZeroes, kStream2Padding)); + + const uint8_t* stream2_data = + reinterpret_cast(&file_writer.string()[kStream2Offset]); + + std::string expected_stream2(kStream2Size, kStream2Value); + EXPECT_EQ(0, memcmp(stream2_data, expected_stream2.c_str(), kStream2Size)); + + ASSERT_GE(sizeof(kZeroes), kStream3Padding); + EXPECT_EQ(0, memcmp(stream2_data + kStream2Size, kZeroes, kStream3Padding)); + + const uint8_t* stream3_data = + reinterpret_cast(&file_writer.string()[kStream3Offset]); + + std::string expected_stream3(kStream3Size, kStream3Value); + EXPECT_EQ(0, memcmp(stream3_data, expected_stream3.c_str(), kStream3Size)); +} + +TEST(MinidumpFileWriterDeathTest, SameStreamType) { + MinidumpFileWriter minidump_file; + + const size_t kStream1Size = 5; + const MinidumpStreamType kStream1Type = static_cast(0x4d); + const uint8_t kStream1Value = 0x5a; + TestStream stream1(kStream1Type, kStream1Size, kStream1Value); + minidump_file.AddStream(&stream1); + + // It is an error to add a second stream of the same type. + const size_t kStream2Size = 3; + const MinidumpStreamType kStream2Type = static_cast(0x4d); + const uint8_t kStream2Value = 0xa5; + TestStream stream2(kStream2Type, kStream2Size, kStream2Value); + ASSERT_DEATH(minidump_file.AddStream(&stream2), "already present"); +} + +} // namespace diff --git a/minidump/minidump_stream_writer.cc b/minidump/minidump_stream_writer.cc new file mode 100644 index 00000000..f0367066 --- /dev/null +++ b/minidump/minidump_stream_writer.cc @@ -0,0 +1,46 @@ +// 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_stream_writer.h" + +#include "base/logging.h" + +namespace crashpad { +namespace internal { + +MinidumpStreamWriter::MinidumpStreamWriter() + : MinidumpWritable(), directory_list_entry_() { +} + +bool MinidumpStreamWriter::Freeze() { + DCHECK_EQ(state(), kStateMutable); + + if (!MinidumpWritable::Freeze()) { + return false; + } + + directory_list_entry_.StreamType = StreamType(); + RegisterLocationDescriptor(&directory_list_entry_.Location); + + return true; +} + +const MINIDUMP_DIRECTORY* MinidumpStreamWriter::DirectoryListEntry() const { + DCHECK_EQ(state(), kStateWritable); + + return &directory_list_entry_; +} + +} // namespace internal +} // namespace crashpad diff --git a/minidump/minidump_stream_writer.h b/minidump/minidump_stream_writer.h new file mode 100644 index 00000000..a901aae2 --- /dev/null +++ b/minidump/minidump_stream_writer.h @@ -0,0 +1,65 @@ +// 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_STREAM_WRITER_H_ +#define CRASHPAD_MINIDUMP_MINIDUMP_STREAM_WRITER_H_ + +#include +#include + +#include "base/basictypes.h" +#include "minidump/minidump_extensions.h" +#include "minidump/minidump_writable.h" + +namespace crashpad { +namespace internal { + +//! \brief The base class for all second-level objects (“streams”) in a minidump +//! file. +//! +//! Instances of subclasses of this class are children of the root-level +//! MinidumpFileWriter object. +class MinidumpStreamWriter : public MinidumpWritable { + public: + //! \brief Returns an object’s stream type. + //! + //! \note Valid in any state. + virtual MinidumpStreamType StreamType() const = 0; + + //! \brief Returns a MINIDUMP_DIRECTORY entry that serves as a pointer to this + //! stream. + //! + //! This method is provided for MinidumpFileWriter, which calls it in order to + //! obtain the directory entry for a stream. + //! + //! \note Valid only in #kStateWritable. + const MINIDUMP_DIRECTORY* DirectoryListEntry() const; + + protected: + MinidumpStreamWriter(); + ~MinidumpStreamWriter() {} + + // MinidumpWritable: + virtual bool Freeze() override; + + private: + MINIDUMP_DIRECTORY directory_list_entry_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpStreamWriter); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_MINIDUMP_STREAM_WRITER_H_