Add MinidumpByteArray extension and its Writer.

The MinidumpByteArray can be used to carry arbitrary blob payloads in a
minidump file.

Bug: crashpad:192
Change-Id: I1a0710b856375213cdd97eafa9247830aa9a9291
Reviewed-on: https://chromium-review.googlesource.com/716462
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Robert Sesek <rsesek@chromium.org>
This commit is contained in:
Robert Sesek 2017-10-31 14:28:20 -04:00 committed by Commit Bot
parent b88fde0b56
commit 38c8f51ae8
8 changed files with 313 additions and 0 deletions

View File

@ -33,6 +33,8 @@
'..',
],
'sources': [
'minidump_byte_array_writer.cc',
'minidump_byte_array_writer.h',
'minidump_context.h',
'minidump_context_writer.cc',
'minidump_context_writer.h',

View File

@ -0,0 +1,73 @@
// Copyright 2017 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_byte_array_writer.h"
#include "base/logging.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"
namespace crashpad {
MinidumpByteArrayWriter::MinidumpByteArrayWriter()
: minidump_array_(new MinidumpByteArray()) {}
MinidumpByteArrayWriter::~MinidumpByteArrayWriter() = default;
void MinidumpByteArrayWriter::set_data(const uint8_t* data, size_t size) {
data_.clear();
data_.insert(data_.begin(), data, data + size);
}
bool MinidumpByteArrayWriter::Freeze() {
DCHECK_EQ(state(), kStateMutable);
if (!MinidumpWritable::Freeze()) {
return false;
}
size_t size = data_.size();
if (!AssignIfInRange(&minidump_array_->length, size)) {
LOG(ERROR) << "data size " << size << " is out of range";
return false;
}
return true;
}
size_t MinidumpByteArrayWriter::SizeOfObject() {
DCHECK_EQ(state(), kStateFrozen);
return sizeof(*minidump_array_) + data_.size();
}
bool MinidumpByteArrayWriter::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
WritableIoVec iov;
iov.iov_base = minidump_array_.get();
iov.iov_len = sizeof(*minidump_array_);
std::vector<WritableIoVec> iovecs(1, iov);
if (!data_.empty()) {
iov.iov_base = data_.data();
iov.iov_len = data_.size();
iovecs.push_back(iov);
}
return file_writer->WriteIoVec(&iovecs);
}
} // namespace crashpad

View File

@ -0,0 +1,65 @@
// Copyright 2017 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_BYTE_ARRAY_WRITER_H_
#define CRASHPAD_MINIDUMP_MINIDUMP_BYTE_ARRAY_WRITER_H_
#include <memory>
#include <vector>
#include "base/macros.h"
#include "minidump/minidump_extensions.h"
#include "minidump/minidump_writable.h"
namespace crashpad {
//! \brief Writes a variable-length byte array for a minidump into a
//! \sa MinidumpByteArray.
class MinidumpByteArrayWriter final : public internal::MinidumpWritable {
public:
MinidumpByteArrayWriter();
~MinidumpByteArrayWriter() override;
//! \brief Sets the data to be written.
//!
//! \note Valid in #kStateMutable.
void set_data(const std::vector<uint8_t>& data) { data_ = data; }
//! \brief Sets the data to be written.
//!
//! \note Valid in #kStateMutable.
void set_data(const uint8_t* data, size_t size);
//! \brief Gets the data to be written.
//!
//! \note Valid in any state.
const std::vector<uint8_t>& data() const { return data_; }
protected:
// MinidumpWritable:
bool Freeze() override;
size_t SizeOfObject() override;
bool WriteObject(FileWriterInterface* file_writer) override;
private:
std::unique_ptr<MinidumpByteArray> minidump_array_;
std::vector<uint8_t> data_;
DISALLOW_COPY_AND_ASSIGN(MinidumpByteArrayWriter);
};
} // namespace crashpad
#endif // CRASHPAD_MINIDUMP_MINIDUMP_BYTE_ARRAY_WRITER_H_

View File

@ -0,0 +1,80 @@
// Copyright 2017 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_byte_array_writer.h"
#include <memory>
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
#include "gtest/gtest.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file.h"
namespace crashpad {
namespace test {
namespace {
TEST(MinidumpByteArrayWriter, Write) {
const std::vector<uint8_t> kTests[] = {
{'h', 'e', 'l', 'l', 'o'},
{0x42, 0x99, 0x00, 0xbe},
{0x00},
{},
};
for (size_t i = 0; i < arraysize(kTests); ++i) {
SCOPED_TRACE(base::StringPrintf("index %" PRIuS, i));
StringFile string_file;
crashpad::MinidumpByteArrayWriter writer;
writer.set_data(kTests[i]);
EXPECT_TRUE(writer.WriteEverything(&string_file));
ASSERT_EQ(string_file.string().size(),
sizeof(MinidumpByteArray) + kTests[i].size());
auto byte_array = std::make_unique<MinidumpByteArray>();
EXPECT_EQ(string_file.Seek(0, SEEK_SET), 0);
string_file.Read(byte_array.get(), sizeof(*byte_array));
EXPECT_EQ(byte_array->length, kTests[i].size());
std::vector<uint8_t> data(byte_array->length);
string_file.Read(data.data(), byte_array->length);
EXPECT_EQ(data, kTests[i]);
}
}
TEST(MinidumpByteArrayWriter, SetData) {
const std::vector<uint8_t> kTests[] = {
{1, 2, 3, 4, 5},
{0x0},
{},
};
for (size_t i = 0; i < arraysize(kTests); ++i) {
SCOPED_TRACE(base::StringPrintf("index %" PRIuS, i));
crashpad::MinidumpByteArrayWriter writer;
writer.set_data(kTests[i].data(), kTests[i].size());
EXPECT_EQ(writer.data(), kTests[i]);
}
}
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -118,6 +118,17 @@ struct ALIGNAS(4) PACKED MinidumpUTF8String {
uint8_t Buffer[0];
};
//! \brief A variable-length array of bytes carried within a minidump file.
//! The data have no intrinsic type and should be interpreted according
//! to their referencing context.
struct ALIGNAS(4) PACKED MinidumpByteArray {
//! \brief The length of the #data field.
uint32_t length;
//! \brief The bytes of data.
uint8_t data[0];
};
//! \brief CPU type values for MINIDUMP_SYSTEM_INFO::ProcessorArchitecture.
//!
//! \sa \ref PROCESSOR_ARCHITECTURE_x "PROCESSOR_ARCHITECTURE_*"

View File

@ -29,6 +29,8 @@
'..',
],
'sources': [
'test/minidump_byte_array_writer_test_util.cc',
'test/minidump_byte_array_writer_test_util.h',
'test/minidump_context_test_util.cc',
'test/minidump_context_test_util.h',
'test/minidump_file_writer_test_util.cc',
@ -62,6 +64,7 @@
'..',
],
'sources': [
'minidump_byte_array_writer_test.cc',
'minidump_context_writer_test.cc',
'minidump_crashpad_info_writer_test.cc',
'minidump_exception_writer_test.cc',

View File

@ -0,0 +1,36 @@
// Copyright 2017 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_byte_array_writer_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
namespace crashpad {
namespace test {
std::vector<uint8_t> MinidumpByteArrayAtRVA(const std::string& file_contents,
RVA rva) {
auto* minidump_byte_array =
MinidumpWritableAtRVA<MinidumpByteArray>(file_contents, rva);
if (!minidump_byte_array) {
return {};
}
auto* data = static_cast<const uint8_t*>(minidump_byte_array->data);
const uint8_t* data_end = data + minidump_byte_array->length;
return std::vector<uint8_t>(data, data_end);
}
} // namespace test
} // namespace crashpad

View File

@ -0,0 +1,43 @@
// Copyright 2017 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 MINIDUMP_TEST_MINIDUMP_BYTE_ARRAY_WRITER_TEST_UTIL_H_
#define MINIDUMP_TEST_MINIDUMP_BYTE_ARRAY_WRITER_TEST_UTIL_H_
#include <windows.h>
#include <dbghelp.h>
#include <stdint.h>
#include <string>
#include <vector>
namespace crashpad {
namespace test {
//! \brief Returns the bytes referenced by a MinidumpByteArray object located
//! in a minidump file at the specified RVA.
//!
//! \param[in] file_contents The contents of the minidump file.
//! \param[in] rva The offset in the minidump file of the MinidumpByteArray.
//!
//! \return The MinidumpByteArray::data referenced by the \a rva. Note that
//! this function does not check that the data are within the bounds of
//! the \a file_contents.
std::vector<uint8_t> MinidumpByteArrayAtRVA(const std::string& file_contents,
RVA rva);
} // namespace test
} // namespace crashpad
#endif // MINIDUMP_TEST_MINIDUMP_BYTE_ARRAY_WRITER_TEST_UTIL_H_