Add MinidumpCrashpadInfoWriter and its test.

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

Review URL: https://codereview.chromium.org/654573003
This commit is contained in:
Mark Mentovai 2014-10-17 18:00:41 -04:00
parent b9db7543a3
commit b8a2f41156
7 changed files with 408 additions and 32 deletions

View File

@ -32,6 +32,8 @@
'minidump_context.h', 'minidump_context.h',
'minidump_context_writer.cc', 'minidump_context_writer.cc',
'minidump_context_writer.h', 'minidump_context_writer.h',
'minidump_crashpad_info_writer.cc',
'minidump_crashpad_info_writer.h',
'minidump_exception_writer.cc', 'minidump_exception_writer.cc',
'minidump_exception_writer.h', 'minidump_exception_writer.h',
'minidump_extensions.cc', 'minidump_extensions.cc',
@ -76,6 +78,7 @@
'minidump_context_test_util.cc', 'minidump_context_test_util.cc',
'minidump_context_test_util.h', 'minidump_context_test_util.h',
'minidump_context_writer_test.cc', 'minidump_context_writer_test.cc',
'minidump_crashpad_info_writer_test.cc',
'minidump_exception_writer_test.cc', 'minidump_exception_writer_test.cc',
'minidump_file_writer_test.cc', 'minidump_file_writer_test.cc',
'minidump_file_writer_test_util.cc', 'minidump_file_writer_test_util.cc',
@ -87,6 +90,8 @@
'minidump_module_writer_test.cc', 'minidump_module_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_string_writer_test_util.cc',
'minidump_string_writer_test_util.h',
'minidump_system_info_writer_test.cc', 'minidump_system_info_writer_test.cc',
'minidump_thread_writer_test.cc', 'minidump_thread_writer_test.cc',
'minidump_writable_test.cc', 'minidump_writable_test.cc',

View File

@ -0,0 +1,80 @@
// 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_crashpad_info_writer.h"
#include "base/logging.h"
namespace crashpad {
MinidumpCrashpadInfoWriter::MinidumpCrashpadInfoWriter()
: MinidumpStreamWriter(), crashpad_info_(), simple_annotations_() {
crashpad_info_.size = sizeof(crashpad_info_);
crashpad_info_.version = 1;
}
MinidumpCrashpadInfoWriter::~MinidumpCrashpadInfoWriter() {
}
void MinidumpCrashpadInfoWriter::SetSimpleAnnotations(
MinidumpSimpleStringDictionaryWriter* simple_annotations) {
DCHECK_EQ(state(), kStateMutable);
simple_annotations_ = simple_annotations;
}
bool MinidumpCrashpadInfoWriter::Freeze() {
DCHECK_EQ(state(), kStateMutable);
if (!MinidumpStreamWriter::Freeze()) {
return false;
}
if (simple_annotations_) {
simple_annotations_->RegisterLocationDescriptor(
&crashpad_info_.simple_annotations);
}
return true;
}
size_t MinidumpCrashpadInfoWriter::SizeOfObject() {
DCHECK_GE(state(), kStateFrozen);
return sizeof(crashpad_info_);
}
std::vector<internal::MinidumpWritable*>
MinidumpCrashpadInfoWriter::Children() {
DCHECK_GE(state(), kStateFrozen);
std::vector<MinidumpWritable*> children;
if (simple_annotations_) {
children.push_back(simple_annotations_);
}
return children;
}
bool MinidumpCrashpadInfoWriter::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
return file_writer->Write(&crashpad_info_, sizeof(crashpad_info_));
}
MinidumpStreamType MinidumpCrashpadInfoWriter::StreamType() const {
return kMinidumpStreamTypeCrashpadInfo;
}
} // namespace crashpad

View File

@ -0,0 +1,69 @@
// 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_CRASHPAD_INFO_WRITER_H_
#define CRASHPAD_MINIDUMP_MINIDUMP_CRASHPAD_INFO_WRITER_H_
#include <stdint.h>
#include <sys/types.h>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "minidump/minidump_extensions.h"
#include "minidump/minidump_simple_string_dictionary_writer.h"
#include "minidump/minidump_stream_writer.h"
#include "minidump/minidump_writable.h"
#include "util/file/file_writer.h"
namespace crashpad {
//! \brief The writer for a MinidumpCrashpadInfo stream in a minidump file.
class MinidumpCrashpadInfoWriter final : public internal::MinidumpStreamWriter {
public:
MinidumpCrashpadInfoWriter();
~MinidumpCrashpadInfoWriter();
//! \brief Arranges for MinidumpCrashpadInfo::simple_annotations to point to
//! the MinidumpSimpleStringDictionaryWriter object to be written by \a
//! simple_annotations.
//!
//! \a simple_annotations will become a child of this object in the overall
//! tree of internal::MinidumpWritable objects.
//!
//! \note Valid in #kStateMutable.
void SetSimpleAnnotations(
MinidumpSimpleStringDictionaryWriter* simple_annotations);
protected:
// MinidumpWritable:
bool Freeze() override;
size_t SizeOfObject() override;
std::vector<MinidumpWritable*> Children() override;
bool WriteObject(FileWriterInterface* file_writer) override;
// MinidumpStreamWriter:
MinidumpStreamType StreamType() const override;
private:
MinidumpCrashpadInfo crashpad_info_;
MinidumpSimpleStringDictionaryWriter* simple_annotations_; // weak
DISALLOW_COPY_AND_ASSIGN(MinidumpCrashpadInfoWriter);
};
} // namespace crashpad
#endif // CRASHPAD_MINIDUMP_MINIDUMP_CRASHPAD_INFO_WRITER_H_

View File

@ -0,0 +1,155 @@
// 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_crashpad_info_writer.h"
#include <dbghelp.h>
#include "gtest/gtest.h"
#include "minidump/minidump_extensions.h"
#include "minidump/minidump_file_writer.h"
#include "minidump/minidump_file_writer_test_util.h"
#include "minidump/minidump_simple_string_dictionary_writer.h"
#include "minidump/minidump_string_writer_test_util.h"
#include "util/file/string_file_writer.h"
namespace crashpad {
namespace test {
namespace {
void GetCrashpadInfoStream(
const std::string& file_contents,
const MinidumpCrashpadInfo** crashpad_info,
const MinidumpSimpleStringDictionary** simple_annotations) {
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kCrashpadInfoStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
size_t end = kCrashpadInfoStreamOffset + sizeof(MinidumpCrashpadInfo);
const size_t kSimpleAnnotationsOffset = simple_annotations ? end : 0;
if (simple_annotations) {
end += sizeof(MinidumpSimpleStringDictionary);
}
const size_t kFileSize = end;
if (!simple_annotations) {
ASSERT_EQ(kFileSize, file_contents.size());
} else {
EXPECT_GE(file_contents.size(), kFileSize);
}
const MINIDUMP_HEADER* header =
reinterpret_cast<const MINIDUMP_HEADER*>(&file_contents[0]);
ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0));
const MINIDUMP_DIRECTORY* directory =
reinterpret_cast<const MINIDUMP_DIRECTORY*>(
&file_contents[kDirectoryOffset]);
ASSERT_EQ(kMinidumpStreamTypeCrashpadInfo, directory->StreamType);
ASSERT_EQ(sizeof(MinidumpCrashpadInfo), directory->Location.DataSize);
ASSERT_EQ(kCrashpadInfoStreamOffset, directory->Location.Rva);
*crashpad_info = reinterpret_cast<const MinidumpCrashpadInfo*>(
&file_contents[kCrashpadInfoStreamOffset]);
if (simple_annotations) {
ASSERT_GE((*crashpad_info)->simple_annotations.DataSize,
sizeof(MinidumpSimpleStringDictionary));
ASSERT_EQ(kSimpleAnnotationsOffset,
(*crashpad_info)->simple_annotations.Rva);
*simple_annotations =
reinterpret_cast<const MinidumpSimpleStringDictionary*>(
&file_contents[kSimpleAnnotationsOffset]);
} else {
ASSERT_EQ(0u, (*crashpad_info)->simple_annotations.DataSize);
ASSERT_EQ(0u, (*crashpad_info)->simple_annotations.Rva);
}
}
TEST(MinidumpCrashpadInfoWriter, Empty) {
MinidumpFileWriter minidump_file_writer;
MinidumpCrashpadInfoWriter crashpad_info_writer;
minidump_file_writer.AddStream(&crashpad_info_writer);
StringFileWriter file_writer;
ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
const MinidumpCrashpadInfo* crashpad_info;
ASSERT_NO_FATAL_FAILURE(
GetCrashpadInfoStream(file_writer.string(), &crashpad_info, nullptr));
EXPECT_EQ(sizeof(*crashpad_info), crashpad_info->size);
EXPECT_EQ(1u, crashpad_info->version);
EXPECT_EQ(0u, crashpad_info->simple_annotations.DataSize);
EXPECT_EQ(0u, crashpad_info->simple_annotations.Rva);
}
TEST(MinidumpCrashpadInfoWriter, SimpleAnnotations) {
MinidumpFileWriter minidump_file_writer;
MinidumpCrashpadInfoWriter crashpad_info_writer;
minidump_file_writer.AddStream(&crashpad_info_writer);
MinidumpSimpleStringDictionaryWriter simple_annotations_writer;
// Set a key and value before adding the simple_annotations_writer to
// crashpad_info_writer, and another one after.
const char kKey0[] = "k0";
const char kValue0[] = "v";
const char kKey1[] = "KEY1";
const char kValue1[] = "";
MinidumpSimpleStringDictionaryEntryWriter entry_0;
entry_0.SetKeyValue(kKey0, kValue0);
simple_annotations_writer.AddEntry(&entry_0);
crashpad_info_writer.SetSimpleAnnotations(&simple_annotations_writer);
MinidumpSimpleStringDictionaryEntryWriter entry_1;
entry_1.SetKeyValue(kKey1, kValue1);
simple_annotations_writer.AddEntry(&entry_1);
StringFileWriter file_writer;
ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
const MinidumpCrashpadInfo* crashpad_info;
const MinidumpSimpleStringDictionary* simple_annotations;
ASSERT_NO_FATAL_FAILURE(GetCrashpadInfoStream(
file_writer.string(), &crashpad_info, &simple_annotations));
EXPECT_EQ(sizeof(*crashpad_info), crashpad_info->size);
EXPECT_EQ(1u, crashpad_info->version);
ASSERT_EQ(2u, simple_annotations->count);
EXPECT_EQ(
kKey1,
MinidumpUTF8StringAtRVA(file_writer, simple_annotations->entries[0].key));
EXPECT_EQ(kValue1,
MinidumpUTF8StringAtRVA(file_writer,
simple_annotations->entries[0].value));
EXPECT_EQ(
kKey0,
MinidumpUTF8StringAtRVA(file_writer, simple_annotations->entries[1].key));
EXPECT_EQ(kValue0,
MinidumpUTF8StringAtRVA(file_writer,
simple_annotations->entries[1].value));
}
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -18,6 +18,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "minidump/minidump_extensions.h" #include "minidump/minidump_extensions.h"
#include "minidump/minidump_string_writer_test_util.h"
#include "util/file/string_file_writer.h" #include "util/file/string_file_writer.h"
namespace crashpad { namespace crashpad {
@ -44,38 +45,6 @@ TEST(MinidumpSimpleStringDictionaryWriter, EmptySimpleStringDictionary) {
EXPECT_EQ(0u, dictionary->count); EXPECT_EQ(0u, dictionary->count);
} }
std::string MinidumpUTF8StringAtRVA(const StringFileWriter& file_writer,
RVA rva) {
const std::string& contents = file_writer.string();
if (rva == 0) {
return std::string();
}
if (rva + sizeof(MinidumpUTF8String) > contents.size()) {
ADD_FAILURE()
<< "rva " << rva << " too large for contents " << contents.size();
return std::string();
}
const MinidumpUTF8String* minidump_string =
reinterpret_cast<const MinidumpUTF8String*>(&contents[rva]);
// Verify that the file has enough data for the strings stated length plus
// its required NUL terminator.
if (rva + sizeof(MinidumpUTF8String) + minidump_string->Length + 1 >
contents.size()) {
ADD_FAILURE()
<< "rva " << rva << ", length " << minidump_string->Length
<< " too large for contents " << contents.size();
return std::string();
}
std::string minidump_string_data(
reinterpret_cast<const char*>(&minidump_string->Buffer[0]),
minidump_string->Length);
return minidump_string_data;
}
TEST(MinidumpSimpleStringDictionaryWriter, EmptyKeyValue) { TEST(MinidumpSimpleStringDictionaryWriter, EmptyKeyValue) {
StringFileWriter file_writer; StringFileWriter file_writer;

View File

@ -0,0 +1,56 @@
// 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_string_writer_test_util.h"
#include "gtest/gtest.h"
#include "minidump/minidump_extensions.h"
namespace crashpad {
namespace test {
std::string MinidumpUTF8StringAtRVA(const StringFileWriter& file_writer,
RVA rva) {
const std::string& contents = file_writer.string();
if (rva == 0) {
return std::string();
}
if (rva + sizeof(MinidumpUTF8String) > contents.size()) {
ADD_FAILURE()
<< "rva " << rva << " too large for contents " << contents.size();
return std::string();
}
const MinidumpUTF8String* minidump_string =
reinterpret_cast<const MinidumpUTF8String*>(&contents[rva]);
// Verify that the file has enough data for the strings stated length plus
// its required NUL terminator.
if (rva + sizeof(MinidumpUTF8String) + minidump_string->Length + 1 >
contents.size()) {
ADD_FAILURE()
<< "rva " << rva << ", length " << minidump_string->Length
<< " too large for contents " << contents.size();
return std::string();
}
std::string minidump_string_data(
reinterpret_cast<const char*>(&minidump_string->Buffer[0]),
minidump_string->Length);
return minidump_string_data;
}
} // namespace test
} // namespace crashpad

View File

@ -0,0 +1,42 @@
// 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 <dbghelp.h>
#include <string>
#include "util/file/string_file_writer.h"
namespace crashpad {
namespace test {
//! \brief Returns the contents of a MinidumpUTF8String.
//!
//! If \a rva points outside of the range of \a file_writer, or if any of the
//! string data would lie outside of the range of \a file_writer, this function
//! will fail.
//!
//! \param[in] file_writer A StringFileWriter into which MinidumpWritable
//! objects have been written.
//! \param[in] rva An offset in \a file_writer at which to find the desired
//! string.
//!
//! \return On success, the string read from \a file_writer at offset \a rva. On
//! failure, returns an empty string, with a nonfatal assertion logged to
//! gtest.
std::string MinidumpUTF8StringAtRVA(const StringFileWriter& file_writer,
RVA rva);
} // namespace test
} // namespace crashpad