2023-01-28 04:54:20 +00:00
|
|
|
// Copyright 2017 The Crashpad Authors
|
2022-04-02 01:21:55 +00:00
|
|
|
//
|
|
|
|
// 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_annotation_writer.h"
|
|
|
|
|
2022-08-16 00:48:53 +00:00
|
|
|
#include <iterator>
|
2022-04-02 01:21:55 +00:00
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "minidump/minidump_extensions.h"
|
|
|
|
#include "minidump/test/minidump_byte_array_writer_test_util.h"
|
|
|
|
#include "minidump/test/minidump_string_writer_test_util.h"
|
|
|
|
#include "minidump/test/minidump_writable_test_util.h"
|
|
|
|
#include "util/file/string_file.h"
|
|
|
|
|
|
|
|
namespace crashpad {
|
|
|
|
namespace test {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
const MinidumpAnnotationList* MinidumpAnnotationListAtStart(
|
|
|
|
const std::string& file_contents,
|
|
|
|
uint32_t count) {
|
|
|
|
MINIDUMP_LOCATION_DESCRIPTOR location_descriptor;
|
|
|
|
location_descriptor.DataSize = static_cast<uint32_t>(
|
|
|
|
sizeof(MinidumpAnnotationList) + count * sizeof(MinidumpAnnotation));
|
|
|
|
location_descriptor.Rva = 0;
|
|
|
|
return MinidumpWritableAtLocationDescriptor<MinidumpAnnotationList>(
|
|
|
|
file_contents, location_descriptor);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(MinidumpAnnotationWriter, EmptyList) {
|
|
|
|
StringFile string_file;
|
|
|
|
|
|
|
|
MinidumpAnnotationListWriter list_writer;
|
|
|
|
|
|
|
|
EXPECT_FALSE(list_writer.IsUseful());
|
|
|
|
|
|
|
|
EXPECT_TRUE(list_writer.WriteEverything(&string_file));
|
|
|
|
|
|
|
|
ASSERT_EQ(string_file.string().size(), sizeof(MinidumpAnnotationList));
|
|
|
|
|
|
|
|
auto* list = MinidumpAnnotationListAtStart(string_file.string(), 0);
|
|
|
|
ASSERT_TRUE(list);
|
|
|
|
EXPECT_EQ(list->count, 0u);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(MinidumpAnnotationWriter, OneItem) {
|
|
|
|
StringFile string_file;
|
|
|
|
|
|
|
|
const char kName[] = "name";
|
|
|
|
const uint16_t kType = 0xFFFF;
|
|
|
|
const std::vector<uint8_t> kValue{'v', 'a', 'l', 'u', 'e', '\0'};
|
|
|
|
|
|
|
|
auto annotation_writer = std::make_unique<MinidumpAnnotationWriter>();
|
|
|
|
annotation_writer->InitializeWithData(kName, kType, kValue);
|
|
|
|
|
|
|
|
MinidumpAnnotationListWriter list_writer;
|
|
|
|
list_writer.AddObject(std::move(annotation_writer));
|
|
|
|
|
|
|
|
EXPECT_TRUE(list_writer.IsUseful());
|
|
|
|
|
|
|
|
EXPECT_TRUE(list_writer.WriteEverything(&string_file));
|
|
|
|
|
|
|
|
ASSERT_EQ(string_file.string().size(),
|
|
|
|
sizeof(MinidumpAnnotationList) + sizeof(MinidumpAnnotation) +
|
|
|
|
sizeof(MinidumpUTF8String) + sizeof(kName) +
|
|
|
|
sizeof(MinidumpByteArray) + kValue.size() +
|
|
|
|
3); // 3 for padding.
|
|
|
|
|
|
|
|
auto* list = MinidumpAnnotationListAtStart(string_file.string(), 1);
|
|
|
|
ASSERT_TRUE(list);
|
|
|
|
EXPECT_EQ(list->count, 1u);
|
|
|
|
EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(),
|
|
|
|
list->objects[0].name),
|
|
|
|
kName);
|
|
|
|
EXPECT_EQ(list->objects[0].type, kType);
|
|
|
|
EXPECT_EQ(list->objects[0].reserved, 0u);
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
|
|
|
MinidumpByteArrayAtRVA(string_file.string(), list->objects[0].value),
|
|
|
|
kValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(MinidumpAnnotationWriter, ThreeItems) {
|
|
|
|
StringFile string_file;
|
|
|
|
|
|
|
|
const char* kNames[] = {
|
|
|
|
"~~FIRST~~", " second + ", "3",
|
|
|
|
};
|
|
|
|
const uint16_t kTypes[] = {
|
|
|
|
0x1, 0xABCD, 0x42,
|
|
|
|
};
|
|
|
|
const std::vector<uint8_t> kValues[] = {
|
|
|
|
{'\0'}, {0xB0, 0xA0, 0xD0, 0xD0, 0xD0}, {'T'},
|
|
|
|
};
|
|
|
|
|
|
|
|
MinidumpAnnotationListWriter list_writer;
|
|
|
|
|
2022-08-16 00:48:53 +00:00
|
|
|
for (size_t i = 0; i < std::size(kNames); ++i) {
|
2022-04-02 01:21:55 +00:00
|
|
|
auto annotation = std::make_unique<MinidumpAnnotationWriter>();
|
|
|
|
annotation->InitializeWithData(kNames[i], kTypes[i], kValues[i]);
|
|
|
|
list_writer.AddObject(std::move(annotation));
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_TRUE(list_writer.WriteEverything(&string_file));
|
|
|
|
|
|
|
|
ASSERT_EQ(string_file.string().size(),
|
|
|
|
sizeof(MinidumpAnnotationList) + 3 * sizeof(MinidumpAnnotation) +
|
|
|
|
3 * sizeof(MinidumpUTF8String) + 3 * sizeof(MinidumpByteArray) +
|
|
|
|
strlen(kNames[0]) + 1 + kValues[0].size() + 2 +
|
|
|
|
strlen(kNames[1]) + 1 + 3 + kValues[1].size() + 1 +
|
|
|
|
strlen(kNames[2]) + 1 + 3 + kValues[2].size() + 2);
|
|
|
|
|
|
|
|
auto* list = MinidumpAnnotationListAtStart(string_file.string(), 3);
|
|
|
|
ASSERT_TRUE(list);
|
|
|
|
EXPECT_EQ(list->count, 3u);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < 3; ++i) {
|
|
|
|
EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(),
|
|
|
|
list->objects[i].name),
|
|
|
|
kNames[i]);
|
|
|
|
EXPECT_EQ(list->objects[i].type, kTypes[i]);
|
|
|
|
EXPECT_EQ(list->objects[i].reserved, 0u);
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
|
|
|
MinidumpByteArrayAtRVA(string_file.string(), list->objects[i].value),
|
|
|
|
kValues[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(MinidumpAnnotationWriter, DuplicateNames) {
|
|
|
|
StringFile string_file;
|
|
|
|
|
|
|
|
const char kName[] = "@@name!";
|
|
|
|
const uint16_t kType = 0x1;
|
|
|
|
const std::vector<uint8_t> kValue1{'r', 'e', 'd', '\0'};
|
|
|
|
const std::vector<uint8_t> kValue2{'m', 'a', 'g', 'e', 'n', 't', 'a', '\0'};
|
|
|
|
|
|
|
|
MinidumpAnnotationListWriter list_writer;
|
|
|
|
|
|
|
|
auto annotation = std::make_unique<MinidumpAnnotationWriter>();
|
|
|
|
annotation->InitializeWithData(kName, kType, kValue1);
|
|
|
|
list_writer.AddObject(std::move(annotation));
|
|
|
|
|
|
|
|
annotation = std::make_unique<MinidumpAnnotationWriter>();
|
|
|
|
annotation->InitializeWithData(kName, kType, kValue2);
|
|
|
|
list_writer.AddObject(std::move(annotation));
|
|
|
|
|
|
|
|
EXPECT_TRUE(list_writer.WriteEverything(&string_file));
|
|
|
|
|
|
|
|
ASSERT_EQ(string_file.string().size(),
|
|
|
|
sizeof(MinidumpAnnotationList) + 2 * sizeof(MinidumpAnnotation) +
|
|
|
|
2 * sizeof(MinidumpUTF8String) + 2 * sizeof(MinidumpByteArray) +
|
|
|
|
2 * sizeof(kName) + kValue1.size() + kValue2.size());
|
|
|
|
|
|
|
|
auto* list = MinidumpAnnotationListAtStart(string_file.string(), 2);
|
|
|
|
ASSERT_TRUE(list);
|
|
|
|
EXPECT_EQ(list->count, 2u);
|
|
|
|
|
|
|
|
EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(),
|
|
|
|
list->objects[0].name),
|
|
|
|
kName);
|
|
|
|
EXPECT_EQ(list->objects[0].type, kType);
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
|
|
|
MinidumpByteArrayAtRVA(string_file.string(), list->objects[0].value),
|
|
|
|
kValue1);
|
|
|
|
|
|
|
|
EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(),
|
|
|
|
list->objects[1].name),
|
|
|
|
kName);
|
|
|
|
EXPECT_EQ(list->objects[1].type, kType);
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
|
|
|
MinidumpByteArrayAtRVA(string_file.string(), list->objects[1].value),
|
|
|
|
kValue2);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
} // namespace test
|
|
|
|
} // namespace crashpad
|