[Object] Add basic minidump support
Summary:
This patch adds basic support for reading minidump files. It contains
the definitions of various important minidump data structures (header,
stream directory), and of one minidump stream (SystemInfo). The ability
to read other streams will be added in follow-up patches. However, all
streams can be read even now as raw data, which means lldb's minidump
support (where this code is taken from) can be immediately rebased on
top of this patch as soon as it lands.
As we don't have any support for generating minidump files (yet), this
tests the code via unit tests with some small handcrafted binaries in
the form of c char arrays.
Reviewers: Bigcheese, jhenderson, zturner
Subscribers: srhines, dschuff, mgorny, fedor.sergeev, lemo, clayborg, JDevlieghere, aprantl, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59291
llvm-svn: 356652
2019-03-21 10:18:59 +01:00
|
|
|
//===- MinidumpTest.cpp - Tests for Minidump.cpp --------------------------===//
|
|
|
|
//
|
|
|
|
// 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/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Testing/Support/Error.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::object;
|
|
|
|
using namespace minidump;
|
|
|
|
|
|
|
|
static Expected<std::unique_ptr<MinidumpFile>> create(ArrayRef<uint8_t> Data) {
|
|
|
|
return MinidumpFile::create(
|
|
|
|
MemoryBufferRef(toStringRef(Data), "Test buffer"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(MinidumpFile, BasicInterface) {
|
2019-03-21 11:21:55 +01:00
|
|
|
std::vector<uint8_t> Data{ // Header
|
|
|
|
'M', 'D', 'M', 'P', // Signature
|
|
|
|
0x93, 0xa7, 0, 0, // Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
[Object] Add basic minidump support
Summary:
This patch adds basic support for reading minidump files. It contains
the definitions of various important minidump data structures (header,
stream directory), and of one minidump stream (SystemInfo). The ability
to read other streams will be added in follow-up patches. However, all
streams can be read even now as raw data, which means lldb's minidump
support (where this code is taken from) can be immediately rebased on
top of this patch as soon as it lands.
As we don't have any support for generating minidump files (yet), this
tests the code via unit tests with some small handcrafted binaries in
the form of c char arrays.
Reviewers: Bigcheese, jhenderson, zturner
Subscribers: srhines, dschuff, mgorny, fedor.sergeev, lemo, clayborg, JDevlieghere, aprantl, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59291
llvm-svn: 356652
2019-03-21 10:18:59 +01:00
|
|
|
// Stream Directory
|
2019-03-21 11:21:55 +01:00
|
|
|
3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x2c, 0, 0, 0, // RVA
|
|
|
|
// Stream
|
|
|
|
'C', 'P', 'U', 'I', 'N', 'F', 'O'};
|
|
|
|
// A very simple minidump file which contains just a single stream.
|
|
|
|
auto ExpectedFile = create(Data);
|
[Object] Add basic minidump support
Summary:
This patch adds basic support for reading minidump files. It contains
the definitions of various important minidump data structures (header,
stream directory), and of one minidump stream (SystemInfo). The ability
to read other streams will be added in follow-up patches. However, all
streams can be read even now as raw data, which means lldb's minidump
support (where this code is taken from) can be immediately rebased on
top of this patch as soon as it lands.
As we don't have any support for generating minidump files (yet), this
tests the code via unit tests with some small handcrafted binaries in
the form of c char arrays.
Reviewers: Bigcheese, jhenderson, zturner
Subscribers: srhines, dschuff, mgorny, fedor.sergeev, lemo, clayborg, JDevlieghere, aprantl, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59291
llvm-svn: 356652
2019-03-21 10:18:59 +01:00
|
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
|
|
const MinidumpFile &File = **ExpectedFile;
|
|
|
|
const Header &H = File.header();
|
|
|
|
EXPECT_EQ(Header::MagicSignature, H.Signature);
|
|
|
|
EXPECT_EQ(Header::MagicVersion, H.Version);
|
|
|
|
EXPECT_EQ(1u, H.NumberOfStreams);
|
|
|
|
EXPECT_EQ(0x20u, H.StreamDirectoryRVA);
|
|
|
|
EXPECT_EQ(0x03020100u, H.Checksum);
|
|
|
|
EXPECT_EQ(0x07060504u, H.TimeDateStamp);
|
|
|
|
EXPECT_EQ(uint64_t(0x0504030201000908), H.Flags);
|
|
|
|
|
|
|
|
ASSERT_EQ(1u, File.streams().size());
|
|
|
|
const Directory &Stream0 = File.streams()[0];
|
|
|
|
EXPECT_EQ(StreamType::LinuxCPUInfo, Stream0.Type);
|
|
|
|
EXPECT_EQ(7u, Stream0.Location.DataSize);
|
|
|
|
EXPECT_EQ(0x2cu, Stream0.Location.RVA);
|
|
|
|
|
|
|
|
EXPECT_EQ("CPUINFO", toStringRef(File.getRawStream(Stream0)));
|
|
|
|
EXPECT_EQ("CPUINFO",
|
|
|
|
toStringRef(*File.getRawStream(StreamType::LinuxCPUInfo)));
|
|
|
|
|
|
|
|
EXPECT_THAT_EXPECTED(File.getSystemInfo(), Failed<BinaryError>());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use the input from the previous test, but corrupt it in various ways
|
|
|
|
TEST(MinidumpFile, create_ErrorCases) {
|
2019-03-21 11:21:55 +01:00
|
|
|
std::vector<uint8_t> FileTooShort{'M', 'D', 'M', 'P'};
|
|
|
|
EXPECT_THAT_EXPECTED(create(FileTooShort), Failed<BinaryError>());
|
|
|
|
|
|
|
|
std::vector<uint8_t> WrongSignature{
|
|
|
|
// Header
|
|
|
|
'!', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x2c, 0, 0, 0, // RVA
|
|
|
|
// Stream
|
|
|
|
'C', 'P', 'U', 'I', 'N', 'F', 'O'};
|
|
|
|
EXPECT_THAT_EXPECTED(create(WrongSignature), Failed<BinaryError>());
|
|
|
|
|
|
|
|
std::vector<uint8_t> WrongVersion{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x39, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x2c, 0, 0, 0, // RVA
|
|
|
|
// Stream
|
|
|
|
'C', 'P', 'U', 'I', 'N', 'F', 'O'};
|
|
|
|
EXPECT_THAT_EXPECTED(create(WrongVersion), Failed<BinaryError>());
|
|
|
|
|
|
|
|
std::vector<uint8_t> DirectoryAfterEOF{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 1, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x2c, 0, 0, 0, // RVA
|
|
|
|
// Stream
|
|
|
|
'C', 'P', 'U', 'I', 'N', 'F', 'O'};
|
|
|
|
EXPECT_THAT_EXPECTED(create(DirectoryAfterEOF), Failed<BinaryError>());
|
|
|
|
|
|
|
|
std::vector<uint8_t> TruncatedDirectory{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 1, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x2c, 0, 0, 0, // RVA
|
|
|
|
// Stream
|
|
|
|
'C', 'P', 'U', 'I', 'N', 'F', 'O'};
|
|
|
|
EXPECT_THAT_EXPECTED(create(TruncatedDirectory), Failed<BinaryError>());
|
|
|
|
|
|
|
|
std::vector<uint8_t> Stream0AfterEOF{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x2c, 1, 0, 0, // RVA
|
|
|
|
// Stream
|
|
|
|
'C', 'P', 'U', 'I', 'N', 'F', 'O'};
|
|
|
|
EXPECT_THAT_EXPECTED(create(Stream0AfterEOF), Failed<BinaryError>());
|
|
|
|
|
|
|
|
std::vector<uint8_t> Stream0Truncated{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
3, 0, 0x67, 0x47, 8, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x2c, 0, 0, 0, // RVA
|
|
|
|
// Stream
|
|
|
|
'C', 'P', 'U', 'I', 'N', 'F', 'O'};
|
|
|
|
EXPECT_THAT_EXPECTED(create(Stream0Truncated), Failed<BinaryError>());
|
|
|
|
|
|
|
|
std::vector<uint8_t> DuplicateStream{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
2, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x40, 0, 0, 0, // RVA
|
|
|
|
// Stream
|
|
|
|
3, 0, 0x67, 0x47, 7, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x40, 0, 0, 0, // RVA
|
|
|
|
// Stream
|
|
|
|
'C', 'P', 'U', 'I', 'N', 'F', 'O'};
|
|
|
|
EXPECT_THAT_EXPECTED(create(DuplicateStream), Failed<BinaryError>());
|
|
|
|
|
|
|
|
std::vector<uint8_t> DenseMapInfoConflict{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
0xff, 0xff, 0xff, 0xff, 7, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x2c, 0, 0, 0, // RVA
|
|
|
|
// Stream
|
|
|
|
'C', 'P', 'U', 'I', 'N', 'F', 'O'};
|
|
|
|
EXPECT_THAT_EXPECTED(create(DenseMapInfoConflict), Failed<BinaryError>());
|
[Object] Add basic minidump support
Summary:
This patch adds basic support for reading minidump files. It contains
the definitions of various important minidump data structures (header,
stream directory), and of one minidump stream (SystemInfo). The ability
to read other streams will be added in follow-up patches. However, all
streams can be read even now as raw data, which means lldb's minidump
support (where this code is taken from) can be immediately rebased on
top of this patch as soon as it lands.
As we don't have any support for generating minidump files (yet), this
tests the code via unit tests with some small handcrafted binaries in
the form of c char arrays.
Reviewers: Bigcheese, jhenderson, zturner
Subscribers: srhines, dschuff, mgorny, fedor.sergeev, lemo, clayborg, JDevlieghere, aprantl, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59291
llvm-svn: 356652
2019-03-21 10:18:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(MinidumpFile, IngoresDummyStreams) {
|
2019-03-21 11:21:55 +01:00
|
|
|
std::vector<uint8_t> TwoDummyStreams{
|
[Object] Add basic minidump support
Summary:
This patch adds basic support for reading minidump files. It contains
the definitions of various important minidump data structures (header,
stream directory), and of one minidump stream (SystemInfo). The ability
to read other streams will be added in follow-up patches. However, all
streams can be read even now as raw data, which means lldb's minidump
support (where this code is taken from) can be immediately rebased on
top of this patch as soon as it lands.
As we don't have any support for generating minidump files (yet), this
tests the code via unit tests with some small handcrafted binaries in
the form of c char arrays.
Reviewers: Bigcheese, jhenderson, zturner
Subscribers: srhines, dschuff, mgorny, fedor.sergeev, lemo, clayborg, JDevlieghere, aprantl, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59291
llvm-svn: 356652
2019-03-21 10:18:59 +01:00
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
2, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x20, 0, 0, 0, // RVA
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x20, 0, 0, 0, // RVA
|
2019-03-21 11:21:55 +01:00
|
|
|
};
|
|
|
|
auto ExpectedFile = create(TwoDummyStreams);
|
[Object] Add basic minidump support
Summary:
This patch adds basic support for reading minidump files. It contains
the definitions of various important minidump data structures (header,
stream directory), and of one minidump stream (SystemInfo). The ability
to read other streams will be added in follow-up patches. However, all
streams can be read even now as raw data, which means lldb's minidump
support (where this code is taken from) can be immediately rebased on
top of this patch as soon as it lands.
As we don't have any support for generating minidump files (yet), this
tests the code via unit tests with some small handcrafted binaries in
the form of c char arrays.
Reviewers: Bigcheese, jhenderson, zturner
Subscribers: srhines, dschuff, mgorny, fedor.sergeev, lemo, clayborg, JDevlieghere, aprantl, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59291
llvm-svn: 356652
2019-03-21 10:18:59 +01:00
|
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
|
|
const MinidumpFile &File = **ExpectedFile;
|
|
|
|
ASSERT_EQ(2u, File.streams().size());
|
|
|
|
EXPECT_EQ(StreamType::Unused, File.streams()[0].Type);
|
|
|
|
EXPECT_EQ(StreamType::Unused, File.streams()[1].Type);
|
|
|
|
EXPECT_EQ(None, File.getRawStream(StreamType::Unused));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(MinidumpFile, getSystemInfo) {
|
2019-03-21 11:21:55 +01:00
|
|
|
std::vector<uint8_t> Data{
|
[Object] Add basic minidump support
Summary:
This patch adds basic support for reading minidump files. It contains
the definitions of various important minidump data structures (header,
stream directory), and of one minidump stream (SystemInfo). The ability
to read other streams will be added in follow-up patches. However, all
streams can be read even now as raw data, which means lldb's minidump
support (where this code is taken from) can be immediately rebased on
top of this patch as soon as it lands.
As we don't have any support for generating minidump files (yet), this
tests the code via unit tests with some small handcrafted binaries in
the form of c char arrays.
Reviewers: Bigcheese, jhenderson, zturner
Subscribers: srhines, dschuff, mgorny, fedor.sergeev, lemo, clayborg, JDevlieghere, aprantl, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59291
llvm-svn: 356652
2019-03-21 10:18:59 +01:00
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
7, 0, 0, 0, 56, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x2c, 0, 0, 0, // RVA
|
|
|
|
// SystemInfo
|
|
|
|
0, 0, 1, 2, // ProcessorArch, ProcessorLevel
|
|
|
|
3, 4, 5, 6, // ProcessorRevision, NumberOfProcessors, ProductType
|
|
|
|
7, 8, 9, 0, 1, 2, 3, 4, // MajorVersion, MinorVersion
|
|
|
|
5, 6, 7, 8, 2, 0, 0, 0, // BuildNumber, PlatformId
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // CSDVersionRVA, SuiteMask, Reserved
|
|
|
|
'L', 'L', 'V', 'M', 'L', 'L', 'V', 'M', 'L', 'L', 'V', 'M', // VendorID
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // VersionInfo, FeatureInfo
|
|
|
|
9, 0, 1, 2, // AMDExtendedFeatures
|
2019-03-21 11:21:55 +01:00
|
|
|
};
|
|
|
|
auto ExpectedFile = create(Data);
|
[Object] Add basic minidump support
Summary:
This patch adds basic support for reading minidump files. It contains
the definitions of various important minidump data structures (header,
stream directory), and of one minidump stream (SystemInfo). The ability
to read other streams will be added in follow-up patches. However, all
streams can be read even now as raw data, which means lldb's minidump
support (where this code is taken from) can be immediately rebased on
top of this patch as soon as it lands.
As we don't have any support for generating minidump files (yet), this
tests the code via unit tests with some small handcrafted binaries in
the form of c char arrays.
Reviewers: Bigcheese, jhenderson, zturner
Subscribers: srhines, dschuff, mgorny, fedor.sergeev, lemo, clayborg, JDevlieghere, aprantl, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59291
llvm-svn: 356652
2019-03-21 10:18:59 +01:00
|
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
|
|
const MinidumpFile &File = **ExpectedFile;
|
|
|
|
|
|
|
|
auto ExpectedInfo = File.getSystemInfo();
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());
|
|
|
|
const SystemInfo &Info = *ExpectedInfo;
|
|
|
|
EXPECT_EQ(ProcessorArchitecture::X86, Info.ProcessorArch);
|
|
|
|
EXPECT_EQ(0x0201, Info.ProcessorLevel);
|
|
|
|
EXPECT_EQ(0x0403, Info.ProcessorRevision);
|
|
|
|
EXPECT_EQ(5, Info.NumberOfProcessors);
|
|
|
|
EXPECT_EQ(6, Info.ProductType);
|
|
|
|
EXPECT_EQ(0x00090807u, Info.MajorVersion);
|
|
|
|
EXPECT_EQ(0x04030201u, Info.MinorVersion);
|
|
|
|
EXPECT_EQ(0x08070605u, Info.BuildNumber);
|
|
|
|
EXPECT_EQ(OSPlatform::Win32NT, Info.PlatformId);
|
|
|
|
EXPECT_EQ(0x04030201u, Info.CSDVersionRVA);
|
|
|
|
EXPECT_EQ(0x0605u, Info.SuiteMask);
|
|
|
|
EXPECT_EQ(0x0807u, Info.Reserved);
|
|
|
|
EXPECT_EQ("LLVMLLVMLLVM", llvm::StringRef(Info.CPU.X86.VendorID,
|
|
|
|
sizeof(Info.CPU.X86.VendorID)));
|
|
|
|
EXPECT_EQ(0x04030201u, Info.CPU.X86.VersionInfo);
|
|
|
|
EXPECT_EQ(0x08070605u, Info.CPU.X86.FeatureInfo);
|
|
|
|
EXPECT_EQ(0x02010009u, Info.CPU.X86.AMDExtendedFeatures);
|
|
|
|
}
|
Minidump: Add support for reading/writing strings
Summary:
Strings in minidump files are stored as a 32-bit length field, giving
the length of the string in *bytes*, which is followed by the
appropriate number of UTF16 code units. The string is also supposed to
be null-terminated, and the null-terminator is not a part of the length
field. This patch:
- adds support for reading these strings out of the minidump file (this
implementation does not depend on proper null-termination)
- adds support for writing them to a minidump file
- using the previous two pieces implements proper (de)serialization of
the CSDVersion field of the SystemInfo stream. Previously, this was
only read/written as hex, and no attempt was made to access the
referenced string -- now this string is read and written correctly.
The changes are tested via yaml2obj|obj2yaml round-trip as well as a
unit test which checks the corner cases of the string deserialization
logic.
Reviewers: jhenderson, zturner, clayborg
Subscribers: llvm-commits, aprantl, markmentovai, amccarth, lldb-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59775
llvm-svn: 357749
2019-04-05 10:06:26 +02:00
|
|
|
|
|
|
|
TEST(MinidumpFile, getString) {
|
|
|
|
std::vector<uint8_t> ManyStrings{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
2, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x20, 0, 0, 0, // RVA
|
|
|
|
1, 0, 0, 0, 0, 0, // String1 - odd length
|
|
|
|
0, 0, 1, 0, 0, 0, // String2 - too long
|
|
|
|
2, 0, 0, 0, 0, 0xd8, // String3 - invalid utf16
|
|
|
|
0, 0, 0, 0, 0, 0, // String4 - ""
|
|
|
|
2, 0, 0, 0, 'a', 0, // String5 - "a"
|
|
|
|
0, // Mis-align next string
|
|
|
|
2, 0, 0, 0, 'a', 0, // String6 - "a"
|
|
|
|
|
|
|
|
};
|
|
|
|
auto ExpectedFile = create(ManyStrings);
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
|
|
const MinidumpFile &File = **ExpectedFile;
|
|
|
|
EXPECT_THAT_EXPECTED(File.getString(44), Failed<BinaryError>());
|
|
|
|
EXPECT_THAT_EXPECTED(File.getString(50), Failed<BinaryError>());
|
|
|
|
EXPECT_THAT_EXPECTED(File.getString(56), Failed<BinaryError>());
|
|
|
|
EXPECT_THAT_EXPECTED(File.getString(62), HasValue(""));
|
|
|
|
EXPECT_THAT_EXPECTED(File.getString(68), HasValue("a"));
|
|
|
|
EXPECT_THAT_EXPECTED(File.getString(75), HasValue("a"));
|
|
|
|
|
|
|
|
// Check the case when the size field does not fit into the remaining data.
|
|
|
|
EXPECT_THAT_EXPECTED(File.getString(ManyStrings.size() - 2),
|
|
|
|
Failed<BinaryError>());
|
|
|
|
}
|
Object/Minidump: Add support for reading the ModuleList stream
Summary:
The ModuleList stream consists of an integer giving the number of
entries in the list, followed by the list itself. Each entry in the list
describes a module (dynamically loaded objects which were loaded in the
process when it crashed (or when the minidump was generated).
The code for reading the list is relatively straight-forward, with a
single gotcha. Some minidump writers are emitting padding after the
"count" field in order to align the subsequent list on 8 byte boundary
(this depends on how their ModuleList type was defined and the native
alignment of various types on their platform). Fortunately, the minidump
format contains enough redundancy (in the form of the stream length
field in the stream directory), which allows us to detect this situation
and correct it.
This patch just adds the ability to parse the stream. Code for
conversion to/from yaml will come in a follow-up patch.
Reviewers: zturner, amccarth, jhenderson, clayborg
Subscribers: jdoerfert, markmentovai, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60121
llvm-svn: 357897
2019-04-08 11:57:29 +02:00
|
|
|
|
|
|
|
TEST(MinidumpFile, getModuleList) {
|
|
|
|
std::vector<uint8_t> OneModule{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
4, 0, 0, 0, 112, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// ModuleList
|
|
|
|
1, 0, 0, 0, // NumberOfModules
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
|
|
|
|
9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
|
|
|
|
7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
|
|
|
|
0, 0, 0, 0, // FileOS
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileDate
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
|
|
|
|
9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
|
|
|
|
7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
|
|
|
|
5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
|
|
|
|
};
|
|
|
|
// Same as before, but with a padded module list.
|
|
|
|
std::vector<uint8_t> PaddedModule{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
4, 0, 0, 0, 116, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// ModuleList
|
|
|
|
1, 0, 0, 0, // NumberOfModules
|
|
|
|
0, 0, 0, 0, // Padding
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
|
|
|
|
9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
|
|
|
|
7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
|
|
|
|
0, 0, 0, 0, // FileOS
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileDate
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
|
|
|
|
9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
|
|
|
|
7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
|
|
|
|
5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
|
|
|
|
};
|
|
|
|
|
2019-05-02 09:45:42 +02:00
|
|
|
for (ArrayRef<uint8_t> Data : {OneModule, PaddedModule}) {
|
Object/Minidump: Add support for reading the ModuleList stream
Summary:
The ModuleList stream consists of an integer giving the number of
entries in the list, followed by the list itself. Each entry in the list
describes a module (dynamically loaded objects which were loaded in the
process when it crashed (or when the minidump was generated).
The code for reading the list is relatively straight-forward, with a
single gotcha. Some minidump writers are emitting padding after the
"count" field in order to align the subsequent list on 8 byte boundary
(this depends on how their ModuleList type was defined and the native
alignment of various types on their platform). Fortunately, the minidump
format contains enough redundancy (in the form of the stream length
field in the stream directory), which allows us to detect this situation
and correct it.
This patch just adds the ability to parse the stream. Code for
conversion to/from yaml will come in a follow-up patch.
Reviewers: zturner, amccarth, jhenderson, clayborg
Subscribers: jdoerfert, markmentovai, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60121
llvm-svn: 357897
2019-04-08 11:57:29 +02:00
|
|
|
auto ExpectedFile = create(Data);
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
|
|
const MinidumpFile &File = **ExpectedFile;
|
|
|
|
Expected<ArrayRef<Module>> ExpectedModule = File.getModuleList();
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedModule, Succeeded());
|
|
|
|
ASSERT_EQ(1u, ExpectedModule->size());
|
|
|
|
const Module &M = ExpectedModule.get()[0];
|
|
|
|
EXPECT_EQ(0x0807060504030201u, M.BaseOfImage);
|
|
|
|
EXPECT_EQ(0x02010009u, M.SizeOfImage);
|
|
|
|
EXPECT_EQ(0x06050403u, M.Checksum);
|
|
|
|
EXPECT_EQ(0x00090807u, M.TimeDateStamp);
|
|
|
|
EXPECT_EQ(0x04030201u, M.ModuleNameRVA);
|
|
|
|
EXPECT_EQ(0x04030201u, M.CvRecord.DataSize);
|
|
|
|
EXPECT_EQ(0x08070605u, M.CvRecord.RVA);
|
|
|
|
EXPECT_EQ(0x02010009u, M.MiscRecord.DataSize);
|
|
|
|
EXPECT_EQ(0x06050403u, M.MiscRecord.RVA);
|
|
|
|
EXPECT_EQ(0x0403020100090807u, M.Reserved0);
|
|
|
|
EXPECT_EQ(0x0201000908070605u, M.Reserved1);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<uint8_t> StreamTooShort{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
4, 0, 0, 0, 111, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// ModuleList
|
|
|
|
1, 0, 0, 0, // NumberOfModules
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage
|
|
|
|
9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum
|
|
|
|
7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileVersion
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags
|
|
|
|
0, 0, 0, 0, // FileOS
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // FileDate
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // CvRecord
|
|
|
|
9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord
|
|
|
|
7, 8, 9, 0, 1, 2, 3, 4, // Reserved0
|
|
|
|
5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
|
|
|
|
};
|
|
|
|
auto ExpectedFile = create(StreamTooShort);
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
|
|
const MinidumpFile &File = **ExpectedFile;
|
|
|
|
EXPECT_THAT_EXPECTED(File.getModuleList(), Failed<BinaryError>());
|
|
|
|
}
|
2019-05-02 09:45:42 +02:00
|
|
|
|
|
|
|
TEST(MinidumpFile, getThreadList) {
|
|
|
|
std::vector<uint8_t> OneThread{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
3, 0, 0, 0, 52, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// ThreadList
|
|
|
|
1, 0, 0, 0, // NumberOfThreads
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // ThreadId, SuspendCount
|
|
|
|
9, 0, 1, 2, 3, 4, 5, 6, // PriorityClass, Priority
|
|
|
|
7, 8, 9, 0, 1, 2, 3, 4, // EnvironmentBlock
|
|
|
|
// Stack
|
|
|
|
5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
|
|
|
|
3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
|
|
|
|
// Context
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // DataSize, RVA
|
|
|
|
};
|
|
|
|
// Same as before, but with a padded thread list.
|
|
|
|
std::vector<uint8_t> PaddedThread{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
3, 0, 0, 0, 56, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// ThreadList
|
|
|
|
1, 0, 0, 0, // NumberOfThreads
|
|
|
|
0, 0, 0, 0, // Padding
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // ThreadId, SuspendCount
|
|
|
|
9, 0, 1, 2, 3, 4, 5, 6, // PriorityClass, Priority
|
|
|
|
7, 8, 9, 0, 1, 2, 3, 4, // EnvironmentBlock
|
|
|
|
// Stack
|
|
|
|
5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
|
|
|
|
3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
|
|
|
|
// Context
|
|
|
|
1, 2, 3, 4, 5, 6, 7, 8, // DataSize, RVA
|
|
|
|
};
|
|
|
|
|
|
|
|
for (ArrayRef<uint8_t> Data : {OneThread, PaddedThread}) {
|
|
|
|
auto ExpectedFile = create(Data);
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
|
|
const MinidumpFile &File = **ExpectedFile;
|
|
|
|
Expected<ArrayRef<Thread>> ExpectedThread = File.getThreadList();
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedThread, Succeeded());
|
|
|
|
ASSERT_EQ(1u, ExpectedThread->size());
|
|
|
|
const Thread &T = ExpectedThread.get()[0];
|
|
|
|
EXPECT_EQ(0x04030201u, T.ThreadId);
|
|
|
|
EXPECT_EQ(0x08070605u, T.SuspendCount);
|
|
|
|
EXPECT_EQ(0x02010009u, T.PriorityClass);
|
|
|
|
EXPECT_EQ(0x06050403u, T.Priority);
|
|
|
|
EXPECT_EQ(0x0403020100090807u, T.EnvironmentBlock);
|
|
|
|
EXPECT_EQ(0x0201000908070605u, T.Stack.StartOfMemoryRange);
|
|
|
|
EXPECT_EQ(0x06050403u, T.Stack.Memory.DataSize);
|
|
|
|
EXPECT_EQ(0x00090807u, T.Stack.Memory.RVA);
|
|
|
|
EXPECT_EQ(0x04030201u, T.Context.DataSize);
|
|
|
|
EXPECT_EQ(0x08070605u, T.Context.RVA);
|
|
|
|
}
|
|
|
|
}
|
2019-05-16 17:17:30 +02:00
|
|
|
|
|
|
|
TEST(MinidumpFile, getMemoryList) {
|
|
|
|
std::vector<uint8_t> OneRange{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
5, 0, 0, 0, 20, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// MemoryDescriptor
|
|
|
|
1, 0, 0, 0, // NumberOfMemoryRanges
|
|
|
|
5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
|
|
|
|
3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
|
|
|
|
};
|
|
|
|
// Same as before, but with a padded memory list.
|
|
|
|
std::vector<uint8_t> PaddedRange{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
5, 0, 0, 0, 24, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// MemoryDescriptor
|
|
|
|
1, 0, 0, 0, // NumberOfMemoryRanges
|
|
|
|
0, 0, 0, 0, // Padding
|
|
|
|
5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
|
|
|
|
3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
|
|
|
|
};
|
|
|
|
|
|
|
|
for (ArrayRef<uint8_t> Data : {OneRange, PaddedRange}) {
|
|
|
|
auto ExpectedFile = create(Data);
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
|
|
const MinidumpFile &File = **ExpectedFile;
|
|
|
|
Expected<ArrayRef<MemoryDescriptor>> ExpectedRanges = File.getMemoryList();
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedRanges, Succeeded());
|
|
|
|
ASSERT_EQ(1u, ExpectedRanges->size());
|
|
|
|
const MemoryDescriptor &MD = ExpectedRanges.get()[0];
|
|
|
|
EXPECT_EQ(0x0201000908070605u, MD.StartOfMemoryRange);
|
|
|
|
EXPECT_EQ(0x06050403u, MD.Memory.DataSize);
|
|
|
|
EXPECT_EQ(0x00090807u, MD.Memory.RVA);
|
|
|
|
}
|
|
|
|
}
|
Object/minidump: Add support for the MemoryInfoList stream
Summary:
This patch adds the definitions of the constants and structures
necessary to interpret the MemoryInfoList minidump stream, as well as
the object::MinidumpFile interface to access the stream.
While the code is fairly simple, there is one important deviation from
the other minidump streams, which is worth calling out explicitly.
Unlike other "List" streams, the size of the records inside
MemoryInfoList stream is not known statically. Instead it is described
in the stream header. This makes it impossible to return
ArrayRef<MemoryInfo> from the accessor method, as it is done with other
streams. Instead, I create an iterator class, which can be parameterized
by the runtime size of the structure, and return
iterator_range<iterator> instead.
Reviewers: amccarth, jhenderson, clayborg
Subscribers: JosephTremoulet, zturner, markmentovai, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68210
llvm-svn: 374051
2019-10-08 16:15:32 +02:00
|
|
|
|
|
|
|
TEST(MinidumpFile, getMemoryInfoList) {
|
|
|
|
std::vector<uint8_t> OneEntry{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
16, 0, 0, 0, 64, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// MemoryInfoListHeader
|
|
|
|
16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries
|
|
|
|
// MemoryInfo
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase
|
|
|
|
16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // RegionSize
|
|
|
|
0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
|
|
|
|
0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1
|
|
|
|
};
|
|
|
|
|
|
|
|
// Same as before, but the list header is larger.
|
|
|
|
std::vector<uint8_t> BiggerHeader{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
16, 0, 0, 0, 68, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// MemoryInfoListHeader
|
|
|
|
20, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries
|
|
|
|
0, 0, 0, 0, // ???
|
|
|
|
// MemoryInfo
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase
|
|
|
|
16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // RegionSize
|
|
|
|
0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
|
|
|
|
0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1
|
|
|
|
};
|
|
|
|
|
|
|
|
// Same as before, but the entry is larger.
|
|
|
|
std::vector<uint8_t> BiggerEntry{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
16, 0, 0, 0, 68, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// MemoryInfoListHeader
|
|
|
|
16, 0, 0, 0, 52, 0, 0, 0, // SizeOfHeader, SizeOfEntry
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries
|
|
|
|
// MemoryInfo
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase
|
|
|
|
16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // RegionSize
|
|
|
|
0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
|
|
|
|
0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1
|
|
|
|
0, 0, 0, 0, // ???
|
|
|
|
};
|
|
|
|
|
|
|
|
for (ArrayRef<uint8_t> Data : {OneEntry, BiggerHeader, BiggerEntry}) {
|
|
|
|
auto ExpectedFile = create(Data);
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
|
|
const MinidumpFile &File = **ExpectedFile;
|
|
|
|
auto ExpectedInfo = File.getMemoryInfoList();
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());
|
2020-01-13 19:27:03 +01:00
|
|
|
ASSERT_EQ(1, std::distance(ExpectedInfo->begin(), ExpectedInfo->end()));
|
Object/minidump: Add support for the MemoryInfoList stream
Summary:
This patch adds the definitions of the constants and structures
necessary to interpret the MemoryInfoList minidump stream, as well as
the object::MinidumpFile interface to access the stream.
While the code is fairly simple, there is one important deviation from
the other minidump streams, which is worth calling out explicitly.
Unlike other "List" streams, the size of the records inside
MemoryInfoList stream is not known statically. Instead it is described
in the stream header. This makes it impossible to return
ArrayRef<MemoryInfo> from the accessor method, as it is done with other
streams. Instead, I create an iterator class, which can be parameterized
by the runtime size of the structure, and return
iterator_range<iterator> instead.
Reviewers: amccarth, jhenderson, clayborg
Subscribers: JosephTremoulet, zturner, markmentovai, lldb-commits, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68210
llvm-svn: 374051
2019-10-08 16:15:32 +02:00
|
|
|
const MemoryInfo &Info = *ExpectedInfo.get().begin();
|
|
|
|
EXPECT_EQ(0x0706050403020100u, Info.BaseAddress);
|
|
|
|
EXPECT_EQ(0x0504030201000908u, Info.AllocationBase);
|
|
|
|
EXPECT_EQ(MemoryProtection::Execute, Info.AllocationProtect);
|
|
|
|
EXPECT_EQ(0x09080706u, Info.Reserved0);
|
|
|
|
EXPECT_EQ(0x0706050403020100u, Info.RegionSize);
|
|
|
|
EXPECT_EQ(MemoryState::Commit, Info.State);
|
|
|
|
EXPECT_EQ(MemoryProtection::ExecuteRead, Info.Protect);
|
|
|
|
EXPECT_EQ(MemoryType::Private, Info.Type);
|
|
|
|
EXPECT_EQ(0x01000908u, Info.Reserved1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Header does not fit into the stream.
|
|
|
|
std::vector<uint8_t> HeaderTooBig{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
16, 0, 0, 0, 15, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// MemoryInfoListHeader
|
|
|
|
16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
|
|
|
|
1, 0, 0, 0, 0, 0, 0, // ???
|
|
|
|
};
|
|
|
|
Expected<std::unique_ptr<MinidumpFile>> File = create(HeaderTooBig);
|
|
|
|
ASSERT_THAT_EXPECTED(File, Succeeded());
|
|
|
|
EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
|
|
|
|
|
|
|
|
// Header fits into the stream, but it is too small to contain the required
|
|
|
|
// entries.
|
|
|
|
std::vector<uint8_t> HeaderTooSmall{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
16, 0, 0, 0, 15, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// MemoryInfoListHeader
|
|
|
|
15, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
|
|
|
|
1, 0, 0, 0, 0, 0, 0, // ???
|
|
|
|
};
|
|
|
|
File = create(HeaderTooSmall);
|
|
|
|
ASSERT_THAT_EXPECTED(File, Succeeded());
|
|
|
|
EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
|
|
|
|
|
|
|
|
std::vector<uint8_t> EntryTooBig{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
16, 0, 0, 0, 64, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// MemoryInfoListHeader
|
|
|
|
16, 0, 0, 0, 49, 0, 0, 0, // SizeOfHeader, SizeOfEntry
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries
|
|
|
|
// MemoryInfo
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // BaseAddress
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // AllocationBase
|
|
|
|
16, 0, 0, 0, 6, 7, 8, 9, // AllocationProtect, Reserved0
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // RegionSize
|
|
|
|
0, 16, 0, 0, 32, 0, 0, 0, // State, Protect
|
|
|
|
0, 0, 2, 0, 8, 9, 0, 1, // Type, Reserved1
|
|
|
|
};
|
|
|
|
File = create(EntryTooBig);
|
|
|
|
ASSERT_THAT_EXPECTED(File, Succeeded());
|
|
|
|
EXPECT_THAT_EXPECTED(File.get()->getMemoryInfoList(), Failed<BinaryError>());
|
|
|
|
|
|
|
|
std::vector<uint8_t> ThreeEntries{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
32, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
16, 0, 0, 0, 160, 0, 0, 0, // Type, DataSize,
|
|
|
|
44, 0, 0, 0, // RVA
|
|
|
|
// MemoryInfoListHeader
|
|
|
|
16, 0, 0, 0, 48, 0, 0, 0, // SizeOfHeader, SizeOfEntry
|
|
|
|
3, 0, 0, 0, 0, 0, 0, 0, // NumberOfEntries
|
|
|
|
// MemoryInfo
|
|
|
|
0, 1, 2, 3, 0, 0, 0, 0, // BaseAddress
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
|
|
|
|
0, 0, 4, 5, 6, 7, 0, 0, // BaseAddress
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
|
|
|
|
0, 0, 0, 8, 9, 0, 1, 0, // BaseAddress
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // AllocationBase
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // AllocationProtect, Reserved0
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // RegionSize
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // State, Protect
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, // Type, Reserved1
|
|
|
|
};
|
|
|
|
File = create(ThreeEntries);
|
|
|
|
ASSERT_THAT_EXPECTED(File, Succeeded());
|
|
|
|
auto ExpectedInfo = File.get()->getMemoryInfoList();
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedInfo, Succeeded());
|
|
|
|
EXPECT_THAT(to_vector<3>(map_range(*ExpectedInfo,
|
|
|
|
[](const MemoryInfo &Info) -> uint64_t {
|
|
|
|
return Info.BaseAddress;
|
|
|
|
})),
|
|
|
|
testing::ElementsAre(0x0000000003020100u, 0x0000070605040000u,
|
|
|
|
0x0001000908000000u));
|
|
|
|
}
|
2019-10-18 16:43:15 +02:00
|
|
|
|
|
|
|
TEST(MinidumpFile, getExceptionStream) {
|
|
|
|
std::vector<uint8_t> Data{
|
|
|
|
// Header
|
|
|
|
'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
|
|
|
|
1, 0, 0, 0, // NumberOfStreams,
|
|
|
|
0x20, 0, 0, 0, // StreamDirectoryRVA
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
|
|
|
|
8, 9, 0, 1, 2, 3, 4, 5, // Flags
|
|
|
|
// Stream Directory
|
|
|
|
6, 0, 0, 0, 168, 0, 0, 0, // Type, DataSize,
|
|
|
|
0x2c, 0, 0, 0, // RVA
|
|
|
|
// Exception Stream
|
|
|
|
1, 2, 3, 4, // Thread ID
|
|
|
|
0, 0, 0, 0, // Padding
|
|
|
|
// Exception Record
|
|
|
|
2, 3, 4, 2, 7, 8, 8, 9, // Code, Flags
|
|
|
|
3, 4, 5, 6, 7, 8, 9, 10, // Inner exception record address
|
|
|
|
8, 7, 6, 5, 4, 3, 2, 1, // Exception address
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, // Parameter count, padding
|
|
|
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, // Parameter 0
|
|
|
|
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, // Parameter 1
|
|
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // Parameter 2
|
|
|
|
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, // Parameter 3
|
|
|
|
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // Parameter 4
|
|
|
|
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // Parameter 5
|
|
|
|
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // Parameter 6
|
|
|
|
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, // Parameter 7
|
|
|
|
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, // Parameter 8
|
|
|
|
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, // Parameter 9
|
|
|
|
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, // Parameter 10
|
|
|
|
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, // Parameter 11
|
|
|
|
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, // Parameter 12
|
|
|
|
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, // Parameter 13
|
|
|
|
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, // Parameter 14
|
|
|
|
// Thread Context
|
|
|
|
0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, // DataSize, RVA
|
|
|
|
};
|
|
|
|
auto ExpectedFile = create(Data);
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
|
|
|
const MinidumpFile &File = **ExpectedFile;
|
|
|
|
Expected<const minidump::ExceptionStream &> ExpectedStream =
|
|
|
|
File.getExceptionStream();
|
|
|
|
ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded());
|
|
|
|
EXPECT_EQ(0x04030201u, ExpectedStream->ThreadId);
|
|
|
|
const minidump::Exception &Exception = ExpectedStream->ExceptionRecord;
|
|
|
|
EXPECT_EQ(0x02040302u, Exception.ExceptionCode);
|
|
|
|
EXPECT_EQ(0x09080807u, Exception.ExceptionFlags);
|
|
|
|
EXPECT_EQ(0x0a09080706050403u, Exception.ExceptionRecord);
|
|
|
|
EXPECT_EQ(0x0102030405060708u, Exception.ExceptionAddress);
|
|
|
|
EXPECT_EQ(4u, Exception.NumberParameters);
|
|
|
|
for (uint64_t index = 0; index < Exception.MaxParameters; ++index) {
|
|
|
|
EXPECT_EQ(0x1716151413121110u + index * 0x1010101010101010u,
|
|
|
|
Exception.ExceptionInformation[index]);
|
|
|
|
}
|
|
|
|
EXPECT_EQ(0x84838281, ExpectedStream->ThreadContext.DataSize);
|
|
|
|
EXPECT_EQ(0x88878685, ExpectedStream->ThreadContext.RVA);
|
|
|
|
}
|