Add MinidumpRVAListWriter and test.

This will be used as the foundation for writing a list of
MinidumpUTF8String objects. MinidumpUTF8String (and UTF-16
MINIDUMP_STRING) objects are never referenced by
MINIDUMP_LOCATION_DESCRIPTOR because they carry their own lengths.
Instead, they are always referenced by RVA.

The list of MinidumpUTF8String objects will be used for the module
annotations vector.

TEST=minidump_test MinidumpRVAListWriter.*
R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/704333002
This commit is contained in:
Mark Mentovai 2014-11-07 09:44:09 -05:00
parent 20032b5ddf
commit a980409288
10 changed files with 426 additions and 25 deletions

View File

@ -51,6 +51,8 @@
'minidump_module_crashpad_info_writer.h', 'minidump_module_crashpad_info_writer.h',
'minidump_module_writer.cc', 'minidump_module_writer.cc',
'minidump_module_writer.h', 'minidump_module_writer.h',
'minidump_rva_list_writer.cc',
'minidump_rva_list_writer.h',
'minidump_simple_string_dictionary_writer.cc', 'minidump_simple_string_dictionary_writer.cc',
'minidump_simple_string_dictionary_writer.h', 'minidump_simple_string_dictionary_writer.h',
'minidump_stream_writer.cc', 'minidump_stream_writer.cc',
@ -92,6 +94,7 @@
'minidump_misc_info_writer_test.cc', 'minidump_misc_info_writer_test.cc',
'minidump_module_crashpad_info_writer_test.cc', 'minidump_module_crashpad_info_writer_test.cc',
'minidump_module_writer_test.cc', 'minidump_module_writer_test.cc',
'minidump_rva_list_writer_test.cc',
'minidump_simple_string_dictionary_writer_test.cc', 'minidump_simple_string_dictionary_writer_test.cc',
'minidump_string_writer_test.cc', 'minidump_string_writer_test.cc',
'minidump_system_info_writer_test.cc', 'minidump_system_info_writer_test.cc',
@ -106,6 +109,8 @@
'test/minidump_location_descriptor_list_test_util.h', 'test/minidump_location_descriptor_list_test_util.h',
'test/minidump_memory_writer_test_util.cc', 'test/minidump_memory_writer_test_util.cc',
'test/minidump_memory_writer_test_util.h', 'test/minidump_memory_writer_test_util.h',
'test/minidump_rva_list_test_util.cc',
'test/minidump_rva_list_test_util.h',
'test/minidump_string_writer_test_util.cc', 'test/minidump_string_writer_test_util.cc',
'test/minidump_string_writer_test_util.h', 'test/minidump_string_writer_test_util.h',
'test/minidump_writable_test_util.cc', 'test/minidump_writable_test_util.cc',

View File

@ -296,6 +296,15 @@ struct MinidumpModuleCodeViewRecordPDB70 {
uint8_t pdb_name[1]; uint8_t pdb_name[1];
}; };
//! \brief A list of ::RVA pointers.
struct __attribute__((packed, aligned(4))) MinidumpRVAList {
//! \brief The number of children present in the #children array.
uint32_t count;
//! \brief Pointers to other structures in the minidump file.
RVA children[0];
};
//! \brief A list of MINIDUMP_LOCATION_DESCRIPTOR objects. //! \brief A list of MINIDUMP_LOCATION_DESCRIPTOR objects.
struct __attribute__((packed, aligned(4))) MinidumpLocationDescriptorList { struct __attribute__((packed, aligned(4))) MinidumpLocationDescriptorList {
//! \brief The number of children present in the #children array. //! \brief The number of children present in the #children array.

View File

@ -24,30 +24,6 @@ namespace crashpad {
namespace test { namespace test {
namespace { namespace {
class TestMinidumpWritable final : public internal::MinidumpWritable {
public:
explicit TestMinidumpWritable(uint32_t value)
: MinidumpWritable(),
value_(value) {
}
~TestMinidumpWritable() override {}
protected:
// MinidumpWritable:
size_t SizeOfObject() override { return sizeof(value_); }
bool WriteObject(FileWriterInterface* file_writer) override {
return file_writer->Write(&value_, sizeof(value_));
}
private:
uint32_t value_;
DISALLOW_COPY_AND_ASSIGN(TestMinidumpWritable);
};
class TestMinidumpLocationDescriptorListWriter final class TestMinidumpLocationDescriptorListWriter final
: public MinidumpLocationDescriptorListWriter { : public MinidumpLocationDescriptorListWriter {
public: public:
@ -58,7 +34,7 @@ class TestMinidumpLocationDescriptorListWriter final
~TestMinidumpLocationDescriptorListWriter() override {} ~TestMinidumpLocationDescriptorListWriter() override {}
void AddChild(uint32_t value) { void AddChild(uint32_t value) {
auto child = make_scoped_ptr(new TestMinidumpWritable(value)); auto child = make_scoped_ptr(new TestUInt32MinidumpWritable(value));
MinidumpLocationDescriptorListWriter::AddChild(child.Pass()); MinidumpLocationDescriptorListWriter::AddChild(child.Pass());
} }

View File

@ -0,0 +1,97 @@
// 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_rva_list_writer.h"
#include "base/logging.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"
namespace crashpad {
MinidumpRVAListWriter::MinidumpRVAListWriter()
: MinidumpWritable(),
rva_list_base_(),
children_(),
child_rvas_() {
}
MinidumpRVAListWriter::~MinidumpRVAListWriter() {
}
void MinidumpRVAListWriter::AddChild(
scoped_ptr<internal::MinidumpWritable> child) {
DCHECK_EQ(state(), kStateMutable);
children_.push_back(child.release());
}
bool MinidumpRVAListWriter::Freeze() {
DCHECK_EQ(state(), kStateMutable);
DCHECK(child_rvas_.empty());
if (!MinidumpWritable::Freeze()) {
return false;
}
size_t child_count = children_.size();
if (!AssignIfInRange(&rva_list_base_.count, child_count)) {
LOG(ERROR) << "child_count " << child_count << " out of range";
return false;
}
child_rvas_.resize(child_count);
for (size_t index = 0; index < child_count; ++index) {
children_[index]->RegisterRVA(&child_rvas_[index]);
}
return true;
}
size_t MinidumpRVAListWriter::SizeOfObject() {
DCHECK_GE(state(), kStateFrozen);
return sizeof(rva_list_base_) + children_.size() * sizeof(RVA);
}
std::vector<internal::MinidumpWritable*> MinidumpRVAListWriter::Children() {
DCHECK_GE(state(), kStateFrozen);
std::vector<MinidumpWritable*> children;
for (MinidumpWritable* child : children_) {
children.push_back(child);
}
return children;
}
bool MinidumpRVAListWriter::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
DCHECK_EQ(children_.size(), child_rvas_.size());
WritableIoVec iov;
iov.iov_base = &rva_list_base_;
iov.iov_len = sizeof(rva_list_base_);
std::vector<WritableIoVec> iovecs(1, iov);
if (!child_rvas_.empty()) {
iov.iov_base = &child_rvas_[0];
iov.iov_len = child_rvas_.size() * sizeof(RVA);
iovecs.push_back(iov);
}
return file_writer->WriteIoVec(&iovecs);
}
} // namespace crashpad

View File

@ -0,0 +1,78 @@
// 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_RVA_LIST_WRITER_H_
#define CRASHPAD_MINIDUMP_RVA_LIST_WRITER_H_
#include <stdint.h>
#include <sys/types.h>
#include <vector>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "minidump/minidump_extensions.h"
#include "minidump/minidump_writable.h"
#include "util/stdlib/pointer_container.h"
namespace crashpad {
//! \brief The writer for a MinidumpRVAList object in a minidump file,
//! containing a list of ::RVA pointers.
class MinidumpRVAListWriter : public internal::MinidumpWritable {
protected:
MinidumpRVAListWriter();
~MinidumpRVAListWriter() override;
//! \brief Adds an ::RVA referencing an internal::MinidumpWritable to the
//! MinidumpRVAList.
//!
//! This object takes ownership of \a child and becomes its parent in the
//! overall tree of internal::MinidumpWritable objects.
//!
//! To provide type-correctness, subclasses are expected to provide a public
//! method that accepts a `scoped_ptr`-wrapped argument of the proper
//! internal::MinidumpWritable subclass, and call this method with that
//! argument.
//!
//! \note Valid in #kStateMutable.
void AddChild(scoped_ptr<MinidumpWritable> child);
//! \brief Returns `true` if no child objects have been added by AddChild(),
//! and `false` if child objects are present.
bool IsEmpty() const { return children_.empty(); }
//! \brief Returns an objects ::RVA objects referencing its children.
//!
//! \note The returned vector will be empty until the object advances to
//! #kStateFrozen or beyond.
const std::vector<RVA>& child_rvas() const { return child_rvas_; }
// MinidumpWritable:
bool Freeze() override;
size_t SizeOfObject() override;
std::vector<MinidumpWritable*> Children() override;
bool WriteObject(FileWriterInterface* file_writer) override;
private:
MinidumpRVAList rva_list_base_;
PointerVector<MinidumpWritable> children_;
std::vector<RVA> child_rvas_;
DISALLOW_COPY_AND_ASSIGN(MinidumpRVAListWriter);
};
} // namespace crashpad
#endif // CRASHPAD_MINIDUMP_RVA_LIST_WRITER_H_

View File

@ -0,0 +1,101 @@
// 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_rva_list_writer.h"
#include "base/strings/stringprintf.h"
#include "gtest/gtest.h"
#include "minidump/test/minidump_rva_list_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file_writer.h"
namespace crashpad {
namespace test {
namespace {
class TestMinidumpRVAListWriter final : public MinidumpRVAListWriter {
public:
TestMinidumpRVAListWriter() : MinidumpRVAListWriter() {}
~TestMinidumpRVAListWriter() override {}
void AddChild(uint32_t value) {
auto child = make_scoped_ptr(new TestUInt32MinidumpWritable(value));
MinidumpRVAListWriter::AddChild(child.Pass());
}
private:
DISALLOW_COPY_AND_ASSIGN(TestMinidumpRVAListWriter);
};
TEST(MinidumpRVAListWriter, Empty) {
TestMinidumpRVAListWriter list_writer;
StringFileWriter file_writer;
ASSERT_TRUE(list_writer.WriteEverything(&file_writer));
EXPECT_EQ(sizeof(MinidumpRVAList), file_writer.string().size());
const MinidumpRVAList* list = MinidumpRVAListAtStart(file_writer.string(), 0);
ASSERT_TRUE(list);
}
TEST(MinidumpRVAListWriter, OneChild) {
TestMinidumpRVAListWriter list_writer;
const uint32_t kValue = 0;
list_writer.AddChild(kValue);
StringFileWriter file_writer;
ASSERT_TRUE(list_writer.WriteEverything(&file_writer));
const MinidumpRVAList* list = MinidumpRVAListAtStart(file_writer.string(), 1);
ASSERT_TRUE(list);
const uint32_t* child = MinidumpWritableAtRVA<uint32_t>(
file_writer.string(), list->children[0]);
ASSERT_TRUE(child);
EXPECT_EQ(kValue, *child);
}
TEST(MinidumpRVAListWriter, ThreeChildren) {
TestMinidumpRVAListWriter list_writer;
const uint32_t kValues[] = { 0x80000000, 0x55555555, 0x66006600 };
list_writer.AddChild(kValues[0]);
list_writer.AddChild(kValues[1]);
list_writer.AddChild(kValues[2]);
StringFileWriter file_writer;
ASSERT_TRUE(list_writer.WriteEverything(&file_writer));
const MinidumpRVAList* list =
MinidumpRVAListAtStart(file_writer.string(), arraysize(kValues));
ASSERT_TRUE(list);
for (size_t index = 0; index < arraysize(kValues); ++index) {
SCOPED_TRACE(base::StringPrintf("index %zu", index));
const uint32_t* child = MinidumpWritableAtRVA<uint32_t>(
file_writer.string(), list->children[index]);
ASSERT_TRUE(child);
EXPECT_EQ(kValues[index], *child);
}
}
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -0,0 +1,48 @@
// 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/test/minidump_rva_list_test_util.h"
#include <dbghelp.h>
#include "minidump/minidump_extensions.h"
#include "minidump/test/minidump_writable_test_util.h"
namespace crashpad {
namespace test {
const MinidumpRVAList* MinidumpRVAListAtStart(const std::string& file_contents,
size_t count) {
MINIDUMP_LOCATION_DESCRIPTOR location_descriptor;
location_descriptor.DataSize =
sizeof(MinidumpLocationDescriptorList) + count * sizeof(RVA);
location_descriptor.Rva = 0;
const MinidumpRVAList* list =
MinidumpWritableAtLocationDescriptor<MinidumpRVAList>(
file_contents, location_descriptor);
if (!list) {
return nullptr;
}
if (list->count != count) {
EXPECT_EQ(count, list->count);
return nullptr;
}
return list;
}
} // namespace test
} // namespace crashpad

View File

@ -0,0 +1,44 @@
// 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_TEST_MINIDUMP_RVA_LIST_TEST_UTIL_H_
#define CRASHPAD_MINIDUMP_TEST_MINIDUMP_RVA_LIST_TEST_UTIL_H_
#include <sys/types.h>
#include <string>
namespace crashpad {
struct MinidumpRVAList;
namespace test {
//! \brief Returns the MinidumpRVAList at the start of a minidump file.
//!
//! \param[in] file_contents The contents of the minidump file.
//! \param[in] count The number of ::RVA objects expected in the
//! MinidumpRVAList. This function will only be successful if exactly this
//! many objects are present, and if space for them exists in \a
//! file_contents.
//!
//! \return On success, the MinidumpRVAList at the beginning of the file. On
//! failure, raises a gtest assertion and returns `nullptr`.
const MinidumpRVAList* MinidumpRVAListAtStart(const std::string& file_contents,
size_t count);
} // namespace test
} // namespace crashpad
#endif // CRASHPAD_MINIDUMP_TEST_MINIDUMP_RVA_LIST_TEST_UTIL_H_

View File

@ -19,6 +19,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "util/file/file_writer.h"
namespace crashpad { namespace crashpad {
namespace test { namespace test {
@ -306,5 +307,21 @@ MinidumpWritableAtLocationDescriptor<MinidumpModuleCodeViewRecordPDB70>(
file_contents, location); file_contents, location);
} }
TestUInt32MinidumpWritable::TestUInt32MinidumpWritable(uint32_t value)
: MinidumpWritable(),
value_(value) {
}
TestUInt32MinidumpWritable::~TestUInt32MinidumpWritable() {
}
size_t TestUInt32MinidumpWritable::SizeOfObject() {
return sizeof(value_);
}
bool TestUInt32MinidumpWritable::WriteObject(FileWriterInterface* file_writer) {
return file_writer->Write(&value_, sizeof(value_));
}
} // namespace test } // namespace test
} // namespace crashpad } // namespace crashpad

View File

@ -17,13 +17,19 @@
#include <dbghelp.h> #include <dbghelp.h>
#include <stdint.h> #include <stdint.h>
#include <sys/types.h>
#include <string> #include <string>
#include "base/basictypes.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "minidump/minidump_extensions.h" #include "minidump/minidump_extensions.h"
#include "minidump/minidump_writable.h"
namespace crashpad { namespace crashpad {
class FileWriterInterface;
namespace test { namespace test {
//! \brief Returns an untyped minidump object located within a minidump files //! \brief Returns an untyped minidump object located within a minidump files
@ -84,6 +90,7 @@ MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_MEMORY_LIST);
MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_MODULE_LIST); MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_MODULE_LIST);
MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_THREAD_LIST); MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_THREAD_LIST);
MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpLocationDescriptorList); MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpLocationDescriptorList);
MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpRVAList);
MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpSimpleStringDictionary); MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpSimpleStringDictionary);
// These types have final fields carrying variable-sized data (typically string // These types have final fields carrying variable-sized data (typically string
@ -225,6 +232,25 @@ const T* MinidumpWritableAtRVA(const std::string& file_contents, RVA rva) {
return MinidumpWritableAtLocationDescriptor<T>(file_contents, location); return MinidumpWritableAtLocationDescriptor<T>(file_contents, location);
} }
//! \brief An internal::MinidumpWritable that carries a `uint32_t` for testing.
class TestUInt32MinidumpWritable final : public internal::MinidumpWritable {
public:
//! \brief Constructs the object to write a `uint32_t` with value \a value.
explicit TestUInt32MinidumpWritable(uint32_t value);
~TestUInt32MinidumpWritable() override;
protected:
// MinidumpWritable:
size_t SizeOfObject() override;
bool WriteObject(FileWriterInterface* file_writer) override;
private:
uint32_t value_;
DISALLOW_COPY_AND_ASSIGN(TestUInt32MinidumpWritable);
};
} // namespace test } // namespace test
} // namespace crashpad } // namespace crashpad