forked from OSchip/llvm-project
339 lines
12 KiB
C++
339 lines
12 KiB
C++
//===- MinidumpYAMLTest.cpp - Tests for Minidump<->YAML code --------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Object/Minidump.h"
|
|
#include "llvm/ObjectYAML/yaml2obj.h"
|
|
#include "llvm/Support/YAMLTraits.h"
|
|
#include "llvm/Testing/Support/Error.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::minidump;
|
|
|
|
static Expected<std::unique_ptr<object::MinidumpFile>>
|
|
toBinary(SmallVectorImpl<char> &Storage, StringRef Yaml) {
|
|
Storage.clear();
|
|
raw_svector_ostream OS(Storage);
|
|
yaml::Input YIn(Yaml);
|
|
if (!yaml::convertYAML(YIn, OS, [](const Twine &Msg) {}))
|
|
return createStringError(std::errc::invalid_argument,
|
|
"unable to convert YAML");
|
|
|
|
return object::MinidumpFile::create(MemoryBufferRef(OS.str(), "Binary"));
|
|
}
|
|
|
|
TEST(MinidumpYAML, Basic) {
|
|
SmallString<0> Storage;
|
|
auto ExpectedFile = toBinary(Storage, R"(
|
|
--- !minidump
|
|
Streams:
|
|
- Type: SystemInfo
|
|
Processor Arch: ARM64
|
|
Platform ID: Linux
|
|
CPU:
|
|
CPUID: 0x05060708
|
|
- Type: LinuxMaps
|
|
Text: |
|
|
400d9000-400db000 r-xp 00000000 b3:04 227 /system/bin/app_process
|
|
400db000-400dc000 r--p 00001000 b3:04 227 /system/bin/app_process
|
|
|
|
- Type: LinuxAuxv
|
|
Content: DEADBEEFBAADF00D)");
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
object::MinidumpFile &File = **ExpectedFile;
|
|
|
|
ASSERT_EQ(3u, File.streams().size());
|
|
|
|
EXPECT_EQ(StreamType::SystemInfo, File.streams()[0].Type);
|
|
auto ExpectedSysInfo = File.getSystemInfo();
|
|
ASSERT_THAT_EXPECTED(ExpectedSysInfo, Succeeded());
|
|
const SystemInfo &SysInfo = *ExpectedSysInfo;
|
|
EXPECT_EQ(ProcessorArchitecture::ARM64, SysInfo.ProcessorArch);
|
|
EXPECT_EQ(OSPlatform::Linux, SysInfo.PlatformId);
|
|
EXPECT_EQ(0x05060708u, SysInfo.CPU.Arm.CPUID);
|
|
|
|
EXPECT_EQ(StreamType::LinuxMaps, File.streams()[1].Type);
|
|
EXPECT_EQ("400d9000-400db000 r-xp 00000000 b3:04 227 "
|
|
"/system/bin/app_process\n"
|
|
"400db000-400dc000 r--p 00001000 b3:04 227 "
|
|
"/system/bin/app_process\n",
|
|
toStringRef(*File.getRawStream(StreamType::LinuxMaps)));
|
|
|
|
EXPECT_EQ(StreamType::LinuxAuxv, File.streams()[2].Type);
|
|
EXPECT_EQ((ArrayRef<uint8_t>{0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, 0xF0, 0x0D}),
|
|
File.getRawStream(StreamType::LinuxAuxv));
|
|
}
|
|
|
|
TEST(MinidumpYAML, RawContent) {
|
|
SmallString<0> Storage;
|
|
auto ExpectedFile = toBinary(Storage, R"(
|
|
--- !minidump
|
|
Streams:
|
|
- Type: LinuxAuxv
|
|
Size: 9
|
|
Content: DEADBEEFBAADF00D)");
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
object::MinidumpFile &File = **ExpectedFile;
|
|
|
|
EXPECT_EQ(
|
|
(ArrayRef<uint8_t>{0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, 0xF0, 0x0D, 0x00}),
|
|
File.getRawStream(StreamType::LinuxAuxv));
|
|
}
|
|
|
|
TEST(MinidumpYAML, X86SystemInfo) {
|
|
SmallString<0> Storage;
|
|
auto ExpectedFile = toBinary(Storage, R"(
|
|
--- !minidump
|
|
Streams:
|
|
- Type: SystemInfo
|
|
Processor Arch: X86
|
|
Platform ID: Linux
|
|
CPU:
|
|
Vendor ID: LLVMLLVMLLVM
|
|
Version Info: 0x01020304
|
|
Feature Info: 0x05060708
|
|
AMD Extended Features: 0x09000102)");
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
object::MinidumpFile &File = **ExpectedFile;
|
|
|
|
ASSERT_EQ(1u, File.streams().size());
|
|
|
|
auto ExpectedSysInfo = File.getSystemInfo();
|
|
ASSERT_THAT_EXPECTED(ExpectedSysInfo, Succeeded());
|
|
const SystemInfo &SysInfo = *ExpectedSysInfo;
|
|
EXPECT_EQ(ProcessorArchitecture::X86, SysInfo.ProcessorArch);
|
|
EXPECT_EQ(OSPlatform::Linux, SysInfo.PlatformId);
|
|
EXPECT_EQ("LLVMLLVMLLVM", StringRef(SysInfo.CPU.X86.VendorID,
|
|
sizeof(SysInfo.CPU.X86.VendorID)));
|
|
EXPECT_EQ(0x01020304u, SysInfo.CPU.X86.VersionInfo);
|
|
EXPECT_EQ(0x05060708u, SysInfo.CPU.X86.FeatureInfo);
|
|
EXPECT_EQ(0x09000102u, SysInfo.CPU.X86.AMDExtendedFeatures);
|
|
}
|
|
|
|
TEST(MinidumpYAML, OtherSystemInfo) {
|
|
SmallString<0> Storage;
|
|
auto ExpectedFile = toBinary(Storage, R"(
|
|
--- !minidump
|
|
Streams:
|
|
- Type: SystemInfo
|
|
Processor Arch: PPC
|
|
Platform ID: Linux
|
|
CPU:
|
|
Features: 000102030405060708090a0b0c0d0e0f)");
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
object::MinidumpFile &File = **ExpectedFile;
|
|
|
|
ASSERT_EQ(1u, File.streams().size());
|
|
|
|
auto ExpectedSysInfo = File.getSystemInfo();
|
|
ASSERT_THAT_EXPECTED(ExpectedSysInfo, Succeeded());
|
|
const SystemInfo &SysInfo = *ExpectedSysInfo;
|
|
EXPECT_EQ(ProcessorArchitecture::PPC, SysInfo.ProcessorArch);
|
|
EXPECT_EQ(OSPlatform::Linux, SysInfo.PlatformId);
|
|
EXPECT_EQ(
|
|
(ArrayRef<uint8_t>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}),
|
|
makeArrayRef(SysInfo.CPU.Other.ProcessorFeatures));
|
|
}
|
|
|
|
// Test that we can parse a normal-looking ExceptionStream.
|
|
TEST(MinidumpYAML, ExceptionStream) {
|
|
SmallString<0> Storage;
|
|
auto ExpectedFile = toBinary(Storage, R"(
|
|
--- !minidump
|
|
Streams:
|
|
- Type: Exception
|
|
Thread ID: 0x7
|
|
Exception Record:
|
|
Exception Code: 0x23
|
|
Exception Flags: 0x5
|
|
Exception Record: 0x0102030405060708
|
|
Exception Address: 0x0a0b0c0d0e0f1011
|
|
Number of Parameters: 2
|
|
Parameter 0: 0x22
|
|
Parameter 1: 0x24
|
|
Thread Context: 3DeadBeefDefacedABadCafe)");
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
object::MinidumpFile &File = **ExpectedFile;
|
|
|
|
ASSERT_EQ(1u, File.streams().size());
|
|
|
|
Expected<const minidump::ExceptionStream &> ExpectedStream =
|
|
File.getExceptionStream();
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded());
|
|
|
|
const minidump::ExceptionStream &Stream = *ExpectedStream;
|
|
EXPECT_EQ(0x7u, Stream.ThreadId);
|
|
const minidump::Exception &Exception = Stream.ExceptionRecord;
|
|
EXPECT_EQ(0x23u, Exception.ExceptionCode);
|
|
EXPECT_EQ(0x5u, Exception.ExceptionFlags);
|
|
EXPECT_EQ(0x0102030405060708u, Exception.ExceptionRecord);
|
|
EXPECT_EQ(0x0a0b0c0d0e0f1011u, Exception.ExceptionAddress);
|
|
EXPECT_EQ(2u, Exception.NumberParameters);
|
|
EXPECT_EQ(0x22u, Exception.ExceptionInformation[0]);
|
|
EXPECT_EQ(0x24u, Exception.ExceptionInformation[1]);
|
|
|
|
Expected<ArrayRef<uint8_t>> ExpectedContext =
|
|
File.getRawData(Stream.ThreadContext);
|
|
ASSERT_THAT_EXPECTED(ExpectedContext, Succeeded());
|
|
EXPECT_EQ((ArrayRef<uint8_t>{0x3d, 0xea, 0xdb, 0xee, 0xfd, 0xef, 0xac, 0xed,
|
|
0xab, 0xad, 0xca, 0xfe}),
|
|
*ExpectedContext);
|
|
}
|
|
|
|
// Test that we can parse an exception stream with no ExceptionInformation.
|
|
TEST(MinidumpYAML, ExceptionStream_NoParameters) {
|
|
SmallString<0> Storage;
|
|
auto ExpectedFile = toBinary(Storage, R"(
|
|
--- !minidump
|
|
Streams:
|
|
- Type: Exception
|
|
Thread ID: 0x7
|
|
Exception Record:
|
|
Exception Code: 0x23
|
|
Exception Flags: 0x5
|
|
Exception Record: 0x0102030405060708
|
|
Exception Address: 0x0a0b0c0d0e0f1011
|
|
Thread Context: 3DeadBeefDefacedABadCafe)");
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
object::MinidumpFile &File = **ExpectedFile;
|
|
|
|
ASSERT_EQ(1u, File.streams().size());
|
|
|
|
Expected<const minidump::ExceptionStream &> ExpectedStream =
|
|
File.getExceptionStream();
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded());
|
|
|
|
const minidump::ExceptionStream &Stream = *ExpectedStream;
|
|
EXPECT_EQ(0x7u, Stream.ThreadId);
|
|
const minidump::Exception &Exception = Stream.ExceptionRecord;
|
|
EXPECT_EQ(0x23u, Exception.ExceptionCode);
|
|
EXPECT_EQ(0x5u, Exception.ExceptionFlags);
|
|
EXPECT_EQ(0x0102030405060708u, Exception.ExceptionRecord);
|
|
EXPECT_EQ(0x0a0b0c0d0e0f1011u, Exception.ExceptionAddress);
|
|
EXPECT_EQ(0u, Exception.NumberParameters);
|
|
|
|
Expected<ArrayRef<uint8_t>> ExpectedContext =
|
|
File.getRawData(Stream.ThreadContext);
|
|
ASSERT_THAT_EXPECTED(ExpectedContext, Succeeded());
|
|
EXPECT_EQ((ArrayRef<uint8_t>{0x3d, 0xea, 0xdb, 0xee, 0xfd, 0xef, 0xac, 0xed,
|
|
0xab, 0xad, 0xca, 0xfe}),
|
|
*ExpectedContext);
|
|
}
|
|
|
|
// Test that we can parse an ExceptionStream where the stated number of
|
|
// parameters is greater than the actual size of the ExceptionInformation
|
|
// array.
|
|
TEST(MinidumpYAML, ExceptionStream_TooManyParameters) {
|
|
SmallString<0> Storage;
|
|
auto ExpectedFile = toBinary(Storage, R"(
|
|
--- !minidump
|
|
Streams:
|
|
- Type: Exception
|
|
Thread ID: 0x8
|
|
Exception Record:
|
|
Exception Code: 0
|
|
Number of Parameters: 16
|
|
Parameter 0: 0x0
|
|
Parameter 1: 0xff
|
|
Parameter 2: 0xee
|
|
Parameter 3: 0xdd
|
|
Parameter 4: 0xcc
|
|
Parameter 5: 0xbb
|
|
Parameter 6: 0xaa
|
|
Parameter 7: 0x99
|
|
Parameter 8: 0x88
|
|
Parameter 9: 0x77
|
|
Parameter 10: 0x66
|
|
Parameter 11: 0x55
|
|
Parameter 12: 0x44
|
|
Parameter 13: 0x33
|
|
Parameter 14: 0x22
|
|
Thread Context: 3DeadBeefDefacedABadCafe)");
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
object::MinidumpFile &File = **ExpectedFile;
|
|
|
|
ASSERT_EQ(1u, File.streams().size());
|
|
|
|
Expected<const minidump::ExceptionStream &> ExpectedStream =
|
|
File.getExceptionStream();
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded());
|
|
|
|
const minidump::ExceptionStream &Stream = *ExpectedStream;
|
|
EXPECT_EQ(0x8u, Stream.ThreadId);
|
|
const minidump::Exception &Exception = Stream.ExceptionRecord;
|
|
EXPECT_EQ(0x0u, Exception.ExceptionCode);
|
|
EXPECT_EQ(0x0u, Exception.ExceptionFlags);
|
|
EXPECT_EQ(0x00u, Exception.ExceptionRecord);
|
|
EXPECT_EQ(0x0u, Exception.ExceptionAddress);
|
|
EXPECT_EQ(16u, Exception.NumberParameters);
|
|
EXPECT_EQ(0x0u, Exception.ExceptionInformation[0]);
|
|
for (int Index = 1; Index < 15; ++Index) {
|
|
EXPECT_EQ(0x110u - Index * 0x11, Exception.ExceptionInformation[Index]);
|
|
}
|
|
|
|
Expected<ArrayRef<uint8_t>> ExpectedContext =
|
|
File.getRawData(Stream.ThreadContext);
|
|
ASSERT_THAT_EXPECTED(ExpectedContext, Succeeded());
|
|
EXPECT_EQ((ArrayRef<uint8_t>{0x3d, 0xea, 0xdb, 0xee, 0xfd, 0xef, 0xac, 0xed,
|
|
0xab, 0xad, 0xca, 0xfe}),
|
|
*ExpectedContext);
|
|
}
|
|
|
|
// Test that we can parse an ExceptionStream where the number of
|
|
// ExceptionInformation parameters provided is greater than the
|
|
// specified Number of Parameters.
|
|
TEST(MinidumpYAML, ExceptionStream_ExtraParameter) {
|
|
SmallString<0> Storage;
|
|
auto ExpectedFile = toBinary(Storage, R"(
|
|
--- !minidump
|
|
Streams:
|
|
- Type: Exception
|
|
Thread ID: 0x7
|
|
Exception Record:
|
|
Exception Code: 0x23
|
|
Exception Flags: 0x5
|
|
Exception Record: 0x0102030405060708
|
|
Exception Address: 0x0a0b0c0d0e0f1011
|
|
Number of Parameters: 2
|
|
Parameter 0: 0x99
|
|
Parameter 1: 0x23
|
|
Parameter 2: 0x42
|
|
Thread Context: 3DeadBeefDefacedABadCafe)");
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
object::MinidumpFile &File = **ExpectedFile;
|
|
|
|
ASSERT_EQ(1u, File.streams().size());
|
|
|
|
Expected<const minidump::ExceptionStream &> ExpectedStream =
|
|
File.getExceptionStream();
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded());
|
|
|
|
const minidump::ExceptionStream &Stream = *ExpectedStream;
|
|
EXPECT_EQ(0x7u, Stream.ThreadId);
|
|
const minidump::Exception &Exception = Stream.ExceptionRecord;
|
|
EXPECT_EQ(0x23u, Exception.ExceptionCode);
|
|
EXPECT_EQ(0x5u, Exception.ExceptionFlags);
|
|
EXPECT_EQ(0x0102030405060708u, Exception.ExceptionRecord);
|
|
EXPECT_EQ(0x0a0b0c0d0e0f1011u, Exception.ExceptionAddress);
|
|
EXPECT_EQ(2u, Exception.NumberParameters);
|
|
EXPECT_EQ(0x99u, Exception.ExceptionInformation[0]);
|
|
EXPECT_EQ(0x23u, Exception.ExceptionInformation[1]);
|
|
EXPECT_EQ(0x42u, Exception.ExceptionInformation[2]);
|
|
|
|
Expected<ArrayRef<uint8_t>> ExpectedContext =
|
|
File.getRawData(Stream.ThreadContext);
|
|
ASSERT_THAT_EXPECTED(ExpectedContext, Succeeded());
|
|
EXPECT_EQ((ArrayRef<uint8_t>{0x3d, 0xea, 0xdb, 0xee, 0xfd, 0xef, 0xac, 0xed,
|
|
0xab, 0xad, 0xca, 0xfe}),
|
|
*ExpectedContext);
|
|
}
|