[minidump] Extend minidump string writer support for RVA64 strings

To support MINIDUMP_THREAD_NAME_LIST (which uses 64-bit RVAs for the
thread name MINIDUMP_STRING), this adds minidump string writing and
reading support for the new 64-bit RVA64 and
MINIDUMP_LOCATION_DESCRIPTOR64 types.

Bug: crashpad:327
Change-Id: Iffefffef358517dfc6deac02051dff9dbb8eb214
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3673779
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
Commit-Queue: Ben Hamilton <benhamilton@google.com>
This commit is contained in:
Ben Hamilton 2022-06-02 12:27:37 -06:00 committed by Crashpad LUCI CQ
parent fc0b157a8e
commit 91cec09d93
8 changed files with 325 additions and 80 deletions

View File

@ -16,6 +16,10 @@
#include <stdint.h>
#include <string>
#include <type_traits>
#include "base/notreached.h"
#include "gtest/gtest.h"
#include "minidump/minidump_context.h"
#include "minidump/test/minidump_context_test_util.h"
@ -28,7 +32,7 @@ namespace crashpad {
namespace test {
namespace {
template <typename Writer, typename Context>
template <typename Writer, typename Context, typename RVAType>
void EmptyContextTest(void (*expect_context)(uint32_t, const Context*, bool)) {
Writer context_writer;
StringFile string_file;
@ -36,13 +40,34 @@ void EmptyContextTest(void (*expect_context)(uint32_t, const Context*, bool)) {
ASSERT_EQ(string_file.string().size(), sizeof(Context));
const Context* observed =
MinidumpWritableAtRVA<Context>(string_file.string(), 0);
MinidumpWritableAtRVA<Context>(string_file.string(), RVAType(0));
ASSERT_TRUE(observed);
expect_context(0, observed, false);
}
TEST(MinidumpContextWriter, MinidumpContextX86Writer) {
class TestTypeNames {
public:
template <typename T>
static std::string GetName(int) {
if (std::is_same<T, RVA>()) {
return "RVA";
}
if (std::is_same<T, RVA64>()) {
return "RVA64";
}
NOTREACHED();
return "";
}
};
template <typename RVAType>
class MinidumpContextWriter : public ::testing::Test {};
using RVATypes = ::testing::Types<RVA, RVA64>;
TYPED_TEST_SUITE(MinidumpContextWriter, RVATypes, TestTypeNames);
TYPED_TEST(MinidumpContextWriter, MinidumpContextX86Writer) {
StringFile string_file;
{
@ -50,7 +75,7 @@ TEST(MinidumpContextWriter, MinidumpContextX86Writer) {
// context.
SCOPED_TRACE("zero");
EmptyContextTest<MinidumpContextX86Writer, MinidumpContextX86>(
EmptyContextTest<MinidumpContextX86Writer, MinidumpContextX86, TypeParam>(
ExpectMinidumpContextX86);
}
@ -67,14 +92,15 @@ TEST(MinidumpContextWriter, MinidumpContextX86Writer) {
ASSERT_EQ(string_file.string().size(), sizeof(MinidumpContextX86));
const MinidumpContextX86* observed =
MinidumpWritableAtRVA<MinidumpContextX86>(string_file.string(), 0);
MinidumpWritableAtRVA<MinidumpContextX86>(string_file.string(),
TypeParam(0));
ASSERT_TRUE(observed);
ExpectMinidumpContextX86(kSeed, observed, false);
}
}
TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
TYPED_TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
{
// Make sure that a heap-allocated context writer has the proper alignment,
// because it may be nonstandard.
@ -91,8 +117,9 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
// context.
SCOPED_TRACE("zero");
EmptyContextTest<MinidumpContextAMD64Writer, MinidumpContextAMD64>(
ExpectMinidumpContextAMD64);
EmptyContextTest<MinidumpContextAMD64Writer,
MinidumpContextAMD64,
TypeParam>(ExpectMinidumpContextAMD64);
}
{
@ -108,52 +135,53 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
ASSERT_EQ(string_file.string().size(), sizeof(MinidumpContextAMD64));
const MinidumpContextAMD64* observed =
MinidumpWritableAtRVA<MinidumpContextAMD64>(string_file.string(), 0);
MinidumpWritableAtRVA<MinidumpContextAMD64>(string_file.string(),
TypeParam(0));
ASSERT_TRUE(observed);
ExpectMinidumpContextAMD64(kSeed, observed, false);
}
}
template <typename Writer, typename Context>
template <typename Writer, typename Context, typename RVAType>
void FromSnapshotTest(const CPUContext& snapshot_context,
void (*expect_context)(uint32_t, const Context*, bool),
uint32_t seed) {
std::unique_ptr<MinidumpContextWriter> context_writer =
MinidumpContextWriter::CreateFromSnapshot(&snapshot_context);
std::unique_ptr<::crashpad::MinidumpContextWriter> context_writer =
::crashpad::MinidumpContextWriter::CreateFromSnapshot(&snapshot_context);
ASSERT_TRUE(context_writer);
StringFile string_file;
ASSERT_TRUE(context_writer->WriteEverything(&string_file));
const Context* observed =
MinidumpWritableAtRVA<Context>(string_file.string(), 0);
MinidumpWritableAtRVA<Context>(string_file.string(), RVAType(0));
ASSERT_TRUE(observed);
expect_context(seed, observed, true);
}
TEST(MinidumpContextWriter, X86_FromSnapshot) {
TYPED_TEST(MinidumpContextWriter, X86_FromSnapshot) {
constexpr uint32_t kSeed = 32;
CPUContextX86 context_x86;
CPUContext context;
context.x86 = &context_x86;
InitializeCPUContextX86(&context, kSeed);
FromSnapshotTest<MinidumpContextX86Writer, MinidumpContextX86>(
FromSnapshotTest<MinidumpContextX86Writer, MinidumpContextX86, TypeParam>(
context, ExpectMinidumpContextX86, kSeed);
}
TEST(MinidumpContextWriter, AMD64_FromSnapshot) {
TYPED_TEST(MinidumpContextWriter, AMD64_FromSnapshot) {
constexpr uint32_t kSeed = 64;
CPUContextX86_64 context_x86_64;
CPUContext context;
context.x86_64 = &context_x86_64;
InitializeCPUContextX86_64(&context, kSeed);
FromSnapshotTest<MinidumpContextAMD64Writer, MinidumpContextAMD64>(
FromSnapshotTest<MinidumpContextAMD64Writer, MinidumpContextAMD64, TypeParam>(
context, ExpectMinidumpContextAMD64, kSeed);
}
TEST(MinidumpContextWriter, AMD64_CetFromSnapshot) {
TYPED_TEST(MinidumpContextWriter, AMD64_CetFromSnapshot) {
constexpr uint32_t kSeed = 77;
CPUContextX86_64 context_x86_64;
CPUContext context;
@ -163,78 +191,81 @@ TEST(MinidumpContextWriter, AMD64_CetFromSnapshot) {
context_x86_64.xstate.cet_u.cetmsr = 1;
context_x86_64.xstate.cet_u.ssp = kSeed * kSeed;
// We cannot use FromSnapshotTest as we write more than the fixed context.
std::unique_ptr<MinidumpContextWriter> context_writer =
MinidumpContextWriter::CreateFromSnapshot(&context);
std::unique_ptr<::crashpad::MinidumpContextWriter> context_writer =
::crashpad::MinidumpContextWriter::CreateFromSnapshot(&context);
ASSERT_TRUE(context_writer);
StringFile string_file;
ASSERT_TRUE(context_writer->WriteEverything(&string_file));
const MinidumpContextAMD64* observed =
MinidumpWritableAtRVA<MinidumpContextAMD64>(string_file.string(), 0);
MinidumpWritableAtRVA<MinidumpContextAMD64>(string_file.string(),
TypeParam(0));
ASSERT_TRUE(observed);
ExpectMinidumpContextAMD64(kSeed, observed, true);
}
TEST(MinidumpContextWriter, ARM_Zeros) {
EmptyContextTest<MinidumpContextARMWriter, MinidumpContextARM>(
TYPED_TEST(MinidumpContextWriter, ARM_Zeros) {
EmptyContextTest<MinidumpContextARMWriter, MinidumpContextARM, TypeParam>(
ExpectMinidumpContextARM);
}
TEST(MinidumpContextWRiter, ARM64_Zeros) {
EmptyContextTest<MinidumpContextARM64Writer, MinidumpContextARM64>(
TYPED_TEST(MinidumpContextWriter, ARM64_Zeros) {
EmptyContextTest<MinidumpContextARM64Writer, MinidumpContextARM64, TypeParam>(
ExpectMinidumpContextARM64);
}
TEST(MinidumpContextWriter, ARM_FromSnapshot) {
TYPED_TEST(MinidumpContextWriter, ARM_FromSnapshot) {
constexpr uint32_t kSeed = 32;
CPUContextARM context_arm;
CPUContext context;
context.arm = &context_arm;
InitializeCPUContextARM(&context, kSeed);
FromSnapshotTest<MinidumpContextARMWriter, MinidumpContextARM>(
FromSnapshotTest<MinidumpContextARMWriter, MinidumpContextARM, TypeParam>(
context, ExpectMinidumpContextARM, kSeed);
}
TEST(MinidumpContextWriter, ARM64_FromSnapshot) {
TYPED_TEST(MinidumpContextWriter, ARM64_FromSnapshot) {
constexpr uint32_t kSeed = 64;
CPUContextARM64 context_arm64;
CPUContext context;
context.arm64 = &context_arm64;
InitializeCPUContextARM64(&context, kSeed);
FromSnapshotTest<MinidumpContextARM64Writer, MinidumpContextARM64>(
FromSnapshotTest<MinidumpContextARM64Writer, MinidumpContextARM64, TypeParam>(
context, ExpectMinidumpContextARM64, kSeed);
}
TEST(MinidumpContextWriter, MIPS_Zeros) {
EmptyContextTest<MinidumpContextMIPSWriter, MinidumpContextMIPS>(
TYPED_TEST(MinidumpContextWriter, MIPS_Zeros) {
EmptyContextTest<MinidumpContextMIPSWriter, MinidumpContextMIPS, TypeParam>(
ExpectMinidumpContextMIPS);
}
TEST(MinidumpContextWriter, MIPS64_Zeros) {
EmptyContextTest<MinidumpContextMIPS64Writer, MinidumpContextMIPS64>(
ExpectMinidumpContextMIPS64);
TYPED_TEST(MinidumpContextWriter, MIPS64_Zeros) {
EmptyContextTest<MinidumpContextMIPS64Writer,
MinidumpContextMIPS64,
TypeParam>(ExpectMinidumpContextMIPS64);
}
TEST(MinidumpContextWriter, MIPS_FromSnapshot) {
TYPED_TEST(MinidumpContextWriter, MIPS_FromSnapshot) {
constexpr uint32_t kSeed = 32;
CPUContextMIPS context_mips;
CPUContext context;
context.mipsel = &context_mips;
InitializeCPUContextMIPS(&context, kSeed);
FromSnapshotTest<MinidumpContextMIPSWriter, MinidumpContextMIPS>(
FromSnapshotTest<MinidumpContextMIPSWriter, MinidumpContextMIPS, TypeParam>(
context, ExpectMinidumpContextMIPS, kSeed);
}
TEST(MinidumpContextWriter, MIPS64_FromSnapshot) {
TYPED_TEST(MinidumpContextWriter, MIPS64_FromSnapshot) {
constexpr uint32_t kSeed = 64;
CPUContextMIPS64 context_mips;
CPUContext context;
context.mips64 = &context_mips;
InitializeCPUContextMIPS64(&context, kSeed);
FromSnapshotTest<MinidumpContextMIPS64Writer, MinidumpContextMIPS64>(
context, ExpectMinidumpContextMIPS64, kSeed);
FromSnapshotTest<MinidumpContextMIPS64Writer,
MinidumpContextMIPS64,
TypeParam>(context, ExpectMinidumpContextMIPS64, kSeed);
}
} // namespace

View File

@ -16,8 +16,10 @@
#include <iterator>
#include <string>
#include <type_traits>
#include "base/format_macros.h"
#include "base/notreached.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "gtest/gtest.h"
@ -30,7 +32,28 @@ namespace crashpad {
namespace test {
namespace {
TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) {
class TestTypeNames {
public:
template <typename T>
static std::string GetName(int) {
if (std::is_same<T, RVA>()) {
return "RVA";
}
if (std::is_same<T, RVA64>()) {
return "RVA64";
}
NOTREACHED();
return "";
}
};
template <typename RVAType>
class MinidumpStringWriter : public ::testing::Test {};
using RVATypes = ::testing::Types<RVA, RVA64>;
TYPED_TEST_SUITE(MinidumpStringWriter, RVATypes, TestTypeNames);
TYPED_TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) {
StringFile string_file;
{
@ -41,9 +64,9 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) {
ASSERT_EQ(string_file.string().size(), 6u);
const MINIDUMP_STRING* minidump_string =
MinidumpStringAtRVA(string_file.string(), 0);
MinidumpStringAtRVA(string_file.string(), TypeParam(0));
EXPECT_TRUE(minidump_string);
EXPECT_EQ(MinidumpStringAtRVAAsString(string_file.string(), 0),
EXPECT_EQ(MinidumpStringAtRVAAsString(string_file.string(), TypeParam(0)),
std::u16string());
}
@ -90,16 +113,16 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) {
ASSERT_EQ(string_file.string().size(), sizeof(*tmp) + expected_utf16_bytes);
const MINIDUMP_STRING* minidump_string =
MinidumpStringAtRVA(string_file.string(), 0);
MinidumpStringAtRVA(string_file.string(), TypeParam(0));
EXPECT_TRUE(minidump_string);
std::u16string expect_string = std::u16string(
kTestData[index].output_string, kTestData[index].output_length);
EXPECT_EQ(MinidumpStringAtRVAAsString(string_file.string(), 0),
EXPECT_EQ(MinidumpStringAtRVAAsString(string_file.string(), TypeParam(0)),
expect_string);
}
}
TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) {
TYPED_TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) {
StringFile string_file;
static constexpr const char* kTestData[] = {
@ -125,20 +148,20 @@ TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) {
// data written, and make sure that at least one U+FFFD replacement
// character was written.
const MINIDUMP_STRING* minidump_string =
MinidumpStringAtRVA(string_file.string(), 0);
MinidumpStringAtRVA(string_file.string(), TypeParam(0));
EXPECT_TRUE(minidump_string);
[[maybe_unused]] MINIDUMP_STRING* tmp;
EXPECT_EQ(
minidump_string->Length,
string_file.string().size() - sizeof(*tmp) - sizeof(tmp->Buffer[0]));
std::u16string output_string =
MinidumpStringAtRVAAsString(string_file.string(), 0);
MinidumpStringAtRVAAsString(string_file.string(), TypeParam(0));
EXPECT_FALSE(output_string.empty());
EXPECT_NE(output_string.find(0xfffd), std::u16string::npos);
}
}
TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) {
TYPED_TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) {
StringFile string_file;
{
@ -149,10 +172,11 @@ TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) {
ASSERT_EQ(string_file.string().size(), 5u);
const MinidumpUTF8String* minidump_string =
MinidumpUTF8StringAtRVA(string_file.string(), 0);
MinidumpUTF8StringAtRVA(string_file.string(), TypeParam(0));
EXPECT_TRUE(minidump_string);
EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(), 0),
std::string());
EXPECT_EQ(
MinidumpUTF8StringAtRVAAsString(string_file.string(), TypeParam(0)),
std::string());
}
static constexpr struct {
@ -188,10 +212,11 @@ TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) {
sizeof(MinidumpUTF8String) + expected_utf8_bytes_with_nul);
const MinidumpUTF8String* minidump_string =
MinidumpUTF8StringAtRVA(string_file.string(), 0);
MinidumpUTF8StringAtRVA(string_file.string(), TypeParam(0));
EXPECT_TRUE(minidump_string);
EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(), 0),
test_string);
EXPECT_EQ(
MinidumpUTF8StringAtRVAAsString(string_file.string(), TypeParam(0)),
test_string);
}
}
@ -245,11 +270,11 @@ void MinidumpStringListTest() {
}
}
TEST(MinidumpStringWriter, MinidumpUTF16StringList) {
TYPED_TEST(MinidumpStringWriter, MinidumpUTF16StringList) {
MinidumpStringListTest<MinidumpUTF16StringListWriterTraits>();
}
TEST(MinidumpStringWriter, MinidumpUTF8StringList) {
TYPED_TEST(MinidumpStringWriter, MinidumpUTF8StringList) {
MinidumpStringListTest<MinidumpUTF8StringListWriterTraits>();
}

View File

@ -25,8 +25,11 @@ namespace test {
namespace {
template <typename T>
const T* TMinidumpStringAtRVA(const std::string& file_contents, RVA rva) {
template <
typename T,
typename RVAType = RVA,
typename MinidumpLocationDescriptorType = MINIDUMP_LOCATION_DESCRIPTOR>
const T* TMinidumpStringAtRVA(const std::string& file_contents, RVAType rva) {
const T* string_base = MinidumpWritableAtRVA<T>(file_contents, rva);
if (!string_base) {
return nullptr;
@ -41,7 +44,7 @@ const T* TMinidumpStringAtRVA(const std::string& file_contents, RVA rva) {
}
// |Length| does not include space for the required NUL terminator.
MINIDUMP_LOCATION_DESCRIPTOR location;
MinidumpLocationDescriptorType location;
location.DataSize =
sizeof(*string_base) + string_base->Length + kCodeUnitSize;
location.Rva = rva;
@ -62,11 +65,16 @@ const T* TMinidumpStringAtRVA(const std::string& file_contents, RVA rva) {
return string;
}
template <typename StringType, typename MinidumpStringType>
template <typename StringType,
typename MinidumpStringType,
typename RVAType,
typename MinidumpLocationDescriptorType>
StringType TMinidumpStringAtRVAAsString(const std::string& file_contents,
RVA rva) {
RVAType rva) {
const MinidumpStringType* minidump_string =
TMinidumpStringAtRVA<MinidumpStringType>(file_contents, rva);
TMinidumpStringAtRVA<MinidumpStringType,
RVAType,
MinidumpLocationDescriptorType>(file_contents, rva);
if (!minidump_string) {
return StringType();
}
@ -82,24 +90,69 @@ StringType TMinidumpStringAtRVAAsString(const std::string& file_contents,
const MINIDUMP_STRING* MinidumpStringAtRVA(const std::string& file_contents,
RVA rva) {
return TMinidumpStringAtRVA<MINIDUMP_STRING>(file_contents, rva);
return TMinidumpStringAtRVA<MINIDUMP_STRING,
RVA,
MINIDUMP_LOCATION_DESCRIPTOR>(file_contents, rva);
}
const MINIDUMP_STRING* MinidumpStringAtRVA(const std::string& file_contents,
RVA64 rva) {
return TMinidumpStringAtRVA<MINIDUMP_STRING,
RVA64,
MINIDUMP_LOCATION_DESCRIPTOR64>(file_contents,
rva);
}
const MinidumpUTF8String* MinidumpUTF8StringAtRVA(
const std::string& file_contents,
RVA rva) {
return TMinidumpStringAtRVA<MinidumpUTF8String>(file_contents, rva);
return TMinidumpStringAtRVA<MinidumpUTF8String,
RVA,
MINIDUMP_LOCATION_DESCRIPTOR>(file_contents, rva);
}
const MinidumpUTF8String* MinidumpUTF8StringAtRVA(
const std::string& file_contents,
RVA64 rva) {
return TMinidumpStringAtRVA<MinidumpUTF8String,
RVA64,
MINIDUMP_LOCATION_DESCRIPTOR64>(file_contents,
rva);
}
std::u16string MinidumpStringAtRVAAsString(const std::string& file_contents,
RVA rva) {
return TMinidumpStringAtRVAAsString<std::u16string, MINIDUMP_STRING>(
return TMinidumpStringAtRVAAsString<std::u16string,
MINIDUMP_STRING,
RVA,
MINIDUMP_LOCATION_DESCRIPTOR>(
file_contents, rva);
}
std::u16string MinidumpStringAtRVAAsString(const std::string& file_contents,
RVA64 rva) {
return TMinidumpStringAtRVAAsString<std::u16string,
MINIDUMP_STRING,
RVA64,
MINIDUMP_LOCATION_DESCRIPTOR64>(
file_contents, rva);
}
std::string MinidumpUTF8StringAtRVAAsString(const std::string& file_contents,
RVA rva) {
return TMinidumpStringAtRVAAsString<std::string, MinidumpUTF8String>(
return TMinidumpStringAtRVAAsString<std::string,
MinidumpUTF8String,
RVA,
MINIDUMP_LOCATION_DESCRIPTOR>(
file_contents, rva);
}
std::string MinidumpUTF8StringAtRVAAsString(const std::string& file_contents,
RVA64 rva) {
return TMinidumpStringAtRVAAsString<std::string,
MinidumpUTF8String,
RVA64,
MINIDUMP_LOCATION_DESCRIPTOR64>(
file_contents, rva);
}

View File

@ -20,6 +20,11 @@
#include <string>
#include "minidump/minidump_extensions.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "gtest/gtest.h"
namespace crashpad {
struct MinidumpUTF8String;
@ -44,6 +49,10 @@ namespace test {
const MINIDUMP_STRING* MinidumpStringAtRVA(const std::string& file_contents,
RVA rva);
//! \brief 64-bit specialization of MinidumpStringAtRVA.
const MINIDUMP_STRING* MinidumpStringAtRVA(const std::string& file_contents,
RVA64 rva);
//! \brief Returns a MinidumpUTF8String located within a minidump files
//! contents.
//!
@ -64,6 +73,11 @@ const MinidumpUTF8String* MinidumpUTF8StringAtRVA(
const std::string& file_contents,
RVA rva);
//! \brief 64-bit specialization of MinidumpUTF8StringAtRVA.
const MinidumpUTF8String* MinidumpUTF8StringAtRVA(
const std::string& file_contents,
RVA64 rva);
//! \brief Returns the contents of a MINIDUMP_STRING as a `std::u16string`.
//!
//! This function uses MinidumpStringAtRVA() to obtain a MINIDUMP_STRING, and
@ -80,6 +94,10 @@ const MinidumpUTF8String* MinidumpUTF8StringAtRVA(
std::u16string MinidumpStringAtRVAAsString(const std::string& file_contents,
RVA rva);
//! \brief 64-bit specialization of MinidumpStringAtRVAAsString.
std::u16string MinidumpStringAtRVAAsString(const std::string& file_contents,
RVA64 rva);
//! \brief Returns the contents of a MinidumpUTF8String as a `std::string`.
//!
//! This function uses MinidumpUTF8StringAtRVA() to obtain a MinidumpUTF8String,
@ -96,6 +114,10 @@ std::u16string MinidumpStringAtRVAAsString(const std::string& file_contents,
std::string MinidumpUTF8StringAtRVAAsString(const std::string& file_contents,
RVA rva);
//! \brief 64-bit specialization of MinidumpUTF8StringAtRVAAsString.
std::string MinidumpUTF8StringAtRVAAsString(const std::string& file_contents,
RVA64 rva);
} // namespace test
} // namespace crashpad

View File

@ -21,6 +21,7 @@
#include "gtest/gtest.h"
#include "util/file/file_writer.h"
#include "util/misc/implicit_cast.h"
#include "util/numeric/in_range_cast.h"
namespace crashpad {
namespace test {
@ -39,25 +40,26 @@ namespace {
//!
//! Do not call this function. Use the typed version, MinidumpWritableAtRVA<>(),
//! or another type-specific function.
template <typename RVAType>
const void* MinidumpWritableAtRVAInternal(const std::string& file_contents,
RVA rva) {
if (rva >= file_contents.size()) {
EXPECT_LT(rva, file_contents.size());
RVAType rva) {
const auto rva_offset = crashpad::InRangeCast(rva, file_contents.size());
if (rva_offset >= file_contents.size()) {
EXPECT_LT(rva_offset, file_contents.size());
return nullptr;
}
return &file_contents[rva];
return &file_contents[rva_offset];
}
} // namespace
const void* MinidumpWritableAtLocationDescriptorInternal(
template <typename RVAType, typename MinidumpLocationDescriptorType>
const void* TMinidumpWritableAtLocationDescriptorInternal(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location,
const MinidumpLocationDescriptorType& location,
size_t expected_size,
bool allow_oversized_data) {
if (location.DataSize == 0) {
EXPECT_EQ(location.Rva, 0u);
EXPECT_EQ(location.Rva, RVAType(0));
return nullptr;
}
@ -71,17 +73,42 @@ const void* MinidumpWritableAtLocationDescriptorInternal(
return nullptr;
}
RVA end = location.Rva + location.DataSize;
RVAType end = location.Rva + location.DataSize;
if (end > file_contents.size()) {
EXPECT_LE(end, file_contents.size());
return nullptr;
}
const void* rv = MinidumpWritableAtRVAInternal(file_contents, location.Rva);
const void* rv =
MinidumpWritableAtRVAInternal<RVAType>(file_contents, location.Rva);
return rv;
}
} // namespace
const void* MinidumpWritableAtLocationDescriptorInternal(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location,
size_t expected_size,
bool allow_oversized_data) {
return TMinidumpWritableAtLocationDescriptorInternal<
RVA,
MINIDUMP_LOCATION_DESCRIPTOR>(
file_contents, location, expected_size, allow_oversized_data);
}
const void* MinidumpWritableAtLocationDescriptorInternal(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR64& location,
size_t expected_size,
bool allow_oversized_data) {
return TMinidumpWritableAtLocationDescriptorInternal<
RVA64,
MINIDUMP_LOCATION_DESCRIPTOR64>(
file_contents, location, expected_size, allow_oversized_data);
}
template <>
const IMAGE_DEBUG_MISC* MinidumpWritableAtLocationDescriptor<IMAGE_DEBUG_MISC>(
const std::string& file_contents,

View File

@ -59,6 +59,17 @@ const void* MinidumpWritableAtLocationDescriptorInternal(
size_t expected_size,
bool allow_oversized_data);
//! \brief 64-bit specialization of
//! MinidumpWritableAtLocationDescriptorInternal.
//!
//! Do not call this function. Use the typed version,
//! MinidumpWritableAtLocationDescriptor<>(), or another type-specific function.
const void* MinidumpWritableAtLocationDescriptorInternal(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR64& location,
size_t expected_size,
bool allow_oversized_data);
//! \brief A traits class defining whether a minidump object type is required to
//! appear only as a fixed-size object or if it is variable-sized.
//!
@ -134,6 +145,22 @@ const T* TMinidumpWritableAtLocationDescriptor(
MinidumpWritableTraits<T>::kAllowOversizedData));
}
//! \brief 64-bit specialization of TMinidumpWritableAtLocationDescriptor.
//!
//! Do not call this function directly. Use
//! MinidumpWritableAtLocationDescriptor<>() instead.
template <typename T>
const T* TMinidumpWritableAtLocationDescriptor(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR64& location) {
return reinterpret_cast<const T*>(
MinidumpWritableAtLocationDescriptorInternal(
file_contents,
location,
sizeof(T),
MinidumpWritableTraits<T>::kAllowOversizedData));
}
//! \brief Returns a typed minidump object located within a minidump files
//! contents, where the offset and size of the object are known.
//!
@ -168,6 +195,14 @@ const T* MinidumpWritableAtLocationDescriptor(
return TMinidumpWritableAtLocationDescriptor<T>(file_contents, location);
}
//! \brief 64-bit specialization of MinidumpWritableAtLocationDescriptor.
template <typename T>
const T* MinidumpWritableAtLocationDescriptor(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR64& location) {
return TMinidumpWritableAtLocationDescriptor<T>(file_contents, location);
}
template <>
const IMAGE_DEBUG_MISC* MinidumpWritableAtLocationDescriptor<IMAGE_DEBUG_MISC>(
const std::string& file_contents,
@ -270,6 +305,15 @@ const T* MinidumpWritableAtRVA(const std::string& file_contents, RVA rva) {
return MinidumpWritableAtLocationDescriptor<T>(file_contents, location);
}
//! \brief 64-bit specialization of MinidumpWritableAtRVA.
template <typename T>
const T* MinidumpWritableAtRVA(const std::string& file_contents, RVA64 rva) {
MINIDUMP_LOCATION_DESCRIPTOR64 location;
location.DataSize = sizeof(T);
location.Rva = rva;
return MinidumpWritableAtLocationDescriptor<T>(file_contents, location);
}
//! \brief An internal::MinidumpWritable that carries a `uint32_t` for testing.
class TestUInt32MinidumpWritable final : public internal::MinidumpWritable {
public:

View File

@ -24,10 +24,10 @@ namespace internal {
namespace {
template<typename StringType>
template<typename StringType, typename RVAType>
bool ReadMinidumpString(FileReaderInterface* file_reader,
RVA rva,
StringType* string) {
RVAType rva,
StringType* string) {
if (rva == 0) {
string->clear();
return true;
@ -59,12 +59,24 @@ bool ReadMinidumpUTF8String(FileReaderInterface* file_reader,
return ReadMinidumpString(file_reader, rva, string);
}
bool ReadMinidumpUTF8String(FileReaderInterface* file_reader,
RVA64 rva,
std::string* string) {
return ReadMinidumpString(file_reader, rva, string);
}
bool ReadMinidumpUTF16String(FileReaderInterface* file_reader,
RVA rva,
std::u16string* string) {
return ReadMinidumpString(file_reader, rva, string);
}
bool ReadMinidumpUTF16String(FileReaderInterface* file_reader,
RVA64 rva,
std::u16string* string) {
return ReadMinidumpString(file_reader, rva, string);
}
bool ReadMinidumpUTF16String(FileReaderInterface* file_reader,
RVA rva,
std::string* string) {
@ -79,5 +91,19 @@ bool ReadMinidumpUTF16String(FileReaderInterface* file_reader,
return true;
}
bool ReadMinidumpUTF16String(FileReaderInterface* file_reader,
RVA64 rva,
std::string* string) {
std::u16string string_raw;
if (!ReadMinidumpString(file_reader, rva, &string_raw)) {
return false;
}
base::UTF16ToUTF8(string_raw.data(), string_raw.size(), string);
return true;
}
} // namespace internal
} // namespace crashpad

View File

@ -20,6 +20,8 @@
#include <string>
#include "base/strings/utf_string_conversions.h"
#include "minidump/minidump_extensions.h"
#include "util/file/file_reader.h"
namespace crashpad {
@ -34,6 +36,11 @@ bool ReadMinidumpUTF8String(FileReaderInterface* file_reader,
RVA rva,
std::string* string);
//! \brief 64-bit specialization of ReadMinidumpUTF8String.
bool ReadMinidumpUTF8String(FileReaderInterface* file_reader,
RVA64 rva,
std::string* string);
//! \brief Reads a MinidumpUTF16String from a minidump file at offset \a rva in
//! \a file_reader, and returns it in \a string.
//!
@ -43,6 +50,11 @@ bool ReadMinidumpUTF16String(FileReaderInterface* file_reader,
RVA rva,
std::u16string* string);
//! \brief 64-bit specialization of ReadMinidumpUTF16String.
bool ReadMinidumpUTF16String(FileReaderInterface* file_reader,
RVA64 rva,
std::u16string* string);
//! \brief Reads a MinidumpUTF16String from a minidump file at offset \a rva in
//! \a file_reader, and returns it in \a string.
//!
@ -52,6 +64,11 @@ bool ReadMinidumpUTF16String(FileReaderInterface* file_reader,
RVA rva,
std::string* string);
//! \brief 64-bit specialization of ReadMinidumpUTF16String.
bool ReadMinidumpUTF16String(FileReaderInterface* file_reader,
RVA64 rva,
std::string* string);
} // namespace internal
} // namespace crashpad