mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-21 18:22:53 +01:00
[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
This commit is contained in:
parent
5bc40f99c0
commit
6587b1348f
@ -39,6 +39,7 @@ struct file_magic {
|
||||
macho_dsym_companion, ///< Mach-O dSYM companion file
|
||||
macho_kext_bundle, ///< Mach-O kext bundle file
|
||||
macho_universal_binary, ///< Mach-O universal binary
|
||||
minidump, ///< Windows minidump file
|
||||
coff_cl_gl_object, ///< Microsoft cl.exe's intermediate code file
|
||||
coff_object, ///< COFF object file
|
||||
coff_import_library, ///< COFF import library
|
||||
|
147
include/llvm/BinaryFormat/Minidump.h
Normal file
147
include/llvm/BinaryFormat/Minidump.h
Normal file
@ -0,0 +1,147 @@
|
||||
//===- Minidump.h - Minidump constants and structures -----------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header constants and data structures pertaining to the Windows Minidump
|
||||
// core file format.
|
||||
//
|
||||
// Reference:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms679293(v=vs.85).aspx
|
||||
// https://chromium.googlesource.com/breakpad/breakpad/
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_BINARYFORMAT_MINIDUMP_H
|
||||
#define LLVM_BINARYFORMAT_MINIDUMP_H
|
||||
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace minidump {
|
||||
|
||||
/// The minidump header is the first part of a minidump file. It identifies the
|
||||
/// file as a minidump file, and gives the location of the stream directory.
|
||||
struct Header {
|
||||
static constexpr uint32_t MagicSignature = 0x504d444d; // PMDM
|
||||
static constexpr uint16_t MagicVersion = 0xa793;
|
||||
|
||||
support::ulittle32_t Signature;
|
||||
// The high 16 bits of version field are implementation specific. The low 16
|
||||
// bits should be MagicVersion.
|
||||
support::ulittle32_t Version;
|
||||
support::ulittle32_t NumberOfStreams;
|
||||
support::ulittle32_t StreamDirectoryRVA;
|
||||
support::ulittle32_t Checksum;
|
||||
support::ulittle32_t TimeDateStamp;
|
||||
support::ulittle64_t Flags;
|
||||
};
|
||||
static_assert(sizeof(Header) == 32, "");
|
||||
|
||||
/// The type of a minidump stream identifies its contents. Streams numbers after
|
||||
/// LastReserved are for application-defined data streams.
|
||||
enum class StreamType : uint32_t {
|
||||
#define HANDLE_MDMP_STREAM_TYPE(CODE, NAME) NAME = CODE,
|
||||
#include "llvm/BinaryFormat/MinidumpConstants.def"
|
||||
Unused = 0,
|
||||
LastReserved = 0x0000ffff,
|
||||
};
|
||||
|
||||
/// Specifies the location (and size) of various objects in the minidump file.
|
||||
/// The location is relative to the start of the file.
|
||||
struct LocationDescriptor {
|
||||
support::ulittle32_t DataSize;
|
||||
support::ulittle32_t RVA;
|
||||
};
|
||||
static_assert(sizeof(LocationDescriptor) == 8, "");
|
||||
|
||||
/// Specifies the location and type of a single stream in the minidump file. The
|
||||
/// minidump stream directory is an array of entries of this type, with its size
|
||||
/// given by Header.NumberOfStreams.
|
||||
struct Directory {
|
||||
support::little_t<StreamType> Type;
|
||||
LocationDescriptor Location;
|
||||
};
|
||||
static_assert(sizeof(Directory) == 12, "");
|
||||
|
||||
/// The processor architecture of the system that generated this minidump. Used
|
||||
/// in the ProcessorArch field of the SystemInfo stream.
|
||||
enum class ProcessorArchitecture : uint16_t {
|
||||
#define HANDLE_MDMP_ARCH(CODE, NAME) NAME = CODE,
|
||||
#include "llvm/BinaryFormat/MinidumpConstants.def"
|
||||
};
|
||||
|
||||
/// The OS Platform of the system that generated this minidump. Used in the
|
||||
/// PlatformId field of the SystemInfo stream.
|
||||
enum class OSPlatform : uint32_t {
|
||||
#define HANDLE_MDMP_PLATFORM(CODE, NAME) NAME = CODE,
|
||||
#include "llvm/BinaryFormat/MinidumpConstants.def"
|
||||
};
|
||||
|
||||
/// Detailed information about the processor of the system that generated this
|
||||
/// minidump. Its interpretation depends on the ProcessorArchitecture enum.
|
||||
union CPUInfo {
|
||||
struct X86Info {
|
||||
char VendorID[12]; // cpuid 0: ebx, edx, ecx
|
||||
support::ulittle32_t VersionInfo; // cpuid 1: eax
|
||||
support::ulittle32_t FeatureInfo; // cpuid 1: edx
|
||||
support::ulittle32_t AMDExtendedFeatures; // cpuid 0x80000001, ebx
|
||||
} X86;
|
||||
struct ArmInfo {
|
||||
support::ulittle32_t CPUID;
|
||||
support::ulittle32_t ElfHWCaps; // linux specific, 0 otherwise
|
||||
} Arm;
|
||||
struct OtherInfo {
|
||||
uint8_t ProcessorFeatures[16];
|
||||
} Other;
|
||||
};
|
||||
static_assert(sizeof(CPUInfo) == 24, "");
|
||||
|
||||
/// The SystemInfo stream, containing various information about the system where
|
||||
/// this minidump was generated.
|
||||
struct SystemInfo {
|
||||
support::little_t<ProcessorArchitecture> ProcessorArch;
|
||||
support::ulittle16_t ProcessorLevel;
|
||||
support::ulittle16_t ProcessorRevision;
|
||||
|
||||
uint8_t NumberOfProcessors;
|
||||
uint8_t ProductType;
|
||||
|
||||
support::ulittle32_t MajorVersion;
|
||||
support::ulittle32_t MinorVersion;
|
||||
support::ulittle32_t BuildNumber;
|
||||
support::little_t<OSPlatform> PlatformId;
|
||||
support::ulittle32_t CSDVersionRVA;
|
||||
|
||||
support::ulittle16_t SuiteMask;
|
||||
support::ulittle16_t Reserved;
|
||||
|
||||
CPUInfo CPU;
|
||||
};
|
||||
static_assert(sizeof(SystemInfo) == 56, "");
|
||||
|
||||
} // namespace minidump
|
||||
|
||||
template <> struct DenseMapInfo<minidump::StreamType> {
|
||||
static minidump::StreamType getEmptyKey() { return minidump::StreamType(-1); }
|
||||
|
||||
static minidump::StreamType getTombstoneKey() {
|
||||
return minidump::StreamType(-2);
|
||||
}
|
||||
|
||||
static unsigned getHashValue(minidump::StreamType Val) {
|
||||
return DenseMapInfo<uint32_t>::getHashValue(static_cast<uint32_t>(Val));
|
||||
}
|
||||
|
||||
static bool isEqual(minidump::StreamType LHS, minidump::StreamType RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_BINARYFORMAT_MINIDUMP_H
|
107
include/llvm/BinaryFormat/MinidumpConstants.def
Normal file
107
include/llvm/BinaryFormat/MinidumpConstants.def
Normal file
@ -0,0 +1,107 @@
|
||||
//===- MinidumpConstants.def - Iteration over minidump constants-*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if !(defined HANDLE_MDMP_STREAM_TYPE || defined HANDLE_MDMP_ARCH || \
|
||||
defined HANDLE_MDMP_PLATFORM)
|
||||
#error "Missing HANDLE_MDMP definition"
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MDMP_STREAM_TYPE
|
||||
#define HANDLE_MDMP_STREAM_TYPE(CODE, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MDMP_ARCH
|
||||
#define HANDLE_MDMP_ARCH(CODE, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MDMP_PLATFORM
|
||||
#define HANDLE_MDMP_PLATFORM(CODE, NAME)
|
||||
#endif
|
||||
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0003, ThreadList)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0004, ModuleList)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0005, MemoryList)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0006, Exception)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0007, SystemInfo)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0008, ThreadExList)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0009, Memory64List)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x000a, CommentA)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x000b, CommentW)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x000c, HandleData)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x000d, FunctionTable)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x000e, UnloadedModuleList)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x000f, MiscInfo)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0010, MemoryInfoList)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0011, ThreadInfoList)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0012, HandleOperationList)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0013, Token)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0014, JavascriptData)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0015, SystemMemoryInfo)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0016, ProcessVMCounters)
|
||||
// Breakpad extension types. 0x4767 = "Gg"
|
||||
HANDLE_MDMP_STREAM_TYPE(0x47670001, BreakpadInfo)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x47670002, AssertionInfo)
|
||||
// These are additional minidump stream values which are specific to the linux
|
||||
// breakpad implementation.
|
||||
HANDLE_MDMP_STREAM_TYPE(0x47670003, LinuxCPUInfo) // /proc/cpuinfo
|
||||
HANDLE_MDMP_STREAM_TYPE(0x47670004, LinuxProcStatus) // /proc/$x/status
|
||||
HANDLE_MDMP_STREAM_TYPE(0x47670005, LinuxLSBRelease) // /etc/lsb-release
|
||||
HANDLE_MDMP_STREAM_TYPE(0x47670006, LinuxCMDLine) // /proc/$x/cmdline
|
||||
HANDLE_MDMP_STREAM_TYPE(0x47670007, LinuxEnviron) // /proc/$x/environ
|
||||
HANDLE_MDMP_STREAM_TYPE(0x47670008, LinuxAuxv) // /proc/$x/auxv
|
||||
HANDLE_MDMP_STREAM_TYPE(0x47670009, LinuxMaps) // /proc/$x/maps
|
||||
HANDLE_MDMP_STREAM_TYPE(0x4767000A, LinuxDSODebug)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x4767000B, LinuxProcStat) // /proc/$x/stat
|
||||
HANDLE_MDMP_STREAM_TYPE(0x4767000C, LinuxProcUptime) // uptime
|
||||
HANDLE_MDMP_STREAM_TYPE(0x4767000D, LinuxProcFD) // /proc/$x/fd
|
||||
// Facebook-defined stream types
|
||||
HANDLE_MDMP_STREAM_TYPE(0xFACE1CA7, FacebookLogcat)
|
||||
HANDLE_MDMP_STREAM_TYPE(0xFACECAFA, FacebookAppCustomData)
|
||||
HANDLE_MDMP_STREAM_TYPE(0xFACECAFB, FacebookBuildID)
|
||||
HANDLE_MDMP_STREAM_TYPE(0xFACECAFC, FacebookAppVersionName)
|
||||
HANDLE_MDMP_STREAM_TYPE(0xFACECAFD, FacebookJavaStack)
|
||||
HANDLE_MDMP_STREAM_TYPE(0xFACECAFE, FacebookDalvikInfo)
|
||||
HANDLE_MDMP_STREAM_TYPE(0xFACECAFF, FacebookUnwindSymbols)
|
||||
HANDLE_MDMP_STREAM_TYPE(0xFACECB00, FacebookDumpErrorLog)
|
||||
HANDLE_MDMP_STREAM_TYPE(0xFACECCCC, FacebookAppStateLog)
|
||||
HANDLE_MDMP_STREAM_TYPE(0xFACEDEAD, FacebookAbortReason)
|
||||
HANDLE_MDMP_STREAM_TYPE(0xFACEE000, FacebookThreadName)
|
||||
|
||||
HANDLE_MDMP_ARCH(0x0000, X86) // PROCESSOR_ARCHITECTURE_INTEL
|
||||
HANDLE_MDMP_ARCH(0x0001, MIPS) // PROCESSOR_ARCHITECTURE_MIPS
|
||||
HANDLE_MDMP_ARCH(0x0002, Alpha) // PROCESSOR_ARCHITECTURE_ALPHA
|
||||
HANDLE_MDMP_ARCH(0x0003, PPC) // PROCESSOR_ARCHITECTURE_PPC
|
||||
HANDLE_MDMP_ARCH(0x0004, SHX) // PROCESSOR_ARCHITECTURE_SHX (Super-H)
|
||||
HANDLE_MDMP_ARCH(0x0005, ARM) // PROCESSOR_ARCHITECTURE_ARM
|
||||
HANDLE_MDMP_ARCH(0x0006, IA64) // PROCESSOR_ARCHITECTURE_IA64
|
||||
HANDLE_MDMP_ARCH(0x0007, Alpha64) // PROCESSOR_ARCHITECTURE_ALPHA64
|
||||
HANDLE_MDMP_ARCH(0x0008, MSIL) // PROCESSOR_ARCHITECTURE_MSIL
|
||||
HANDLE_MDMP_ARCH(0x0009, AMD64) // PROCESSOR_ARCHITECTURE_AMD64
|
||||
HANDLE_MDMP_ARCH(0x000a, X86Win64) // PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
|
||||
HANDLE_MDMP_ARCH(0x8001, SPARC) // Breakpad-defined value for SPARC
|
||||
HANDLE_MDMP_ARCH(0x8002, PPC64) // Breakpad-defined value for PPC64
|
||||
HANDLE_MDMP_ARCH(0x8003, ARM64) // Breakpad-defined value for ARM64
|
||||
HANDLE_MDMP_ARCH(0x8004, MIPS64) // Breakpad-defined value for MIPS64
|
||||
|
||||
HANDLE_MDMP_PLATFORM(0x0000, Win32S) // Win32 on Windows 3.1
|
||||
HANDLE_MDMP_PLATFORM(0x0001, Win32Windows) // Windows 95-98-Me
|
||||
HANDLE_MDMP_PLATFORM(0x0002, Win32NT) // Windows NT, 2000+
|
||||
HANDLE_MDMP_PLATFORM(0x0003, Win32CE) // Windows CE, Windows Mobile, "Handheld"
|
||||
// Breakpad-defined values.
|
||||
HANDLE_MDMP_PLATFORM(0x8000, Unix) // Generic Unix-ish
|
||||
HANDLE_MDMP_PLATFORM(0x8101, MacOSX) // Mac OS X/Darwin
|
||||
HANDLE_MDMP_PLATFORM(0x8102, IOS) // iOS
|
||||
HANDLE_MDMP_PLATFORM(0x8201, Linux) // Linux
|
||||
HANDLE_MDMP_PLATFORM(0x8202, Solaris) // Solaris
|
||||
HANDLE_MDMP_PLATFORM(0x8203, Android) // Android
|
||||
HANDLE_MDMP_PLATFORM(0x8204, PS3) // PS3
|
||||
HANDLE_MDMP_PLATFORM(0x8205, NaCl) // Native Client (NaCl)
|
||||
|
||||
#undef HANDLE_MDMP_STREAM_TYPE
|
||||
#undef HANDLE_MDMP_ARCH
|
||||
#undef HANDLE_MDMP_PLATFORM
|
@ -41,7 +41,9 @@ protected:
|
||||
ID_Archive,
|
||||
ID_MachOUniversalBinary,
|
||||
ID_COFFImportFile,
|
||||
ID_IR, // LLVM IR
|
||||
ID_IR, // LLVM IR
|
||||
|
||||
ID_Minidump,
|
||||
|
||||
ID_WinRes, // Windows resource (.res) file.
|
||||
|
||||
@ -127,6 +129,8 @@ public:
|
||||
return TypeID == ID_IR;
|
||||
}
|
||||
|
||||
bool isMinidump() const { return TypeID == ID_Minidump; }
|
||||
|
||||
bool isLittleEndian() const {
|
||||
return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B ||
|
||||
TypeID == ID_MachO32B || TypeID == ID_MachO64B);
|
||||
|
121
include/llvm/Object/Minidump.h
Normal file
121
include/llvm/Object/Minidump.h
Normal file
@ -0,0 +1,121 @@
|
||||
//===- Minidump.h - Minidump object file implementation ---------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_OBJECT_MINIDUMP_H
|
||||
#define LLVM_OBJECT_MINIDUMP_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/BinaryFormat/Minidump.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace object {
|
||||
|
||||
/// A class providing access to the contents of a minidump file.
|
||||
class MinidumpFile : public Binary {
|
||||
public:
|
||||
/// Construct a new MinidumpFile object from the given memory buffer. Returns
|
||||
/// an error if this file cannot be identified as a minidump file, or if its
|
||||
/// contents are badly corrupted (i.e. we cannot read the stream directory).
|
||||
static Expected<std::unique_ptr<MinidumpFile>> create(MemoryBufferRef Source);
|
||||
|
||||
static bool classof(const Binary *B) { return B->isMinidump(); }
|
||||
|
||||
/// Returns the contents of the minidump header.
|
||||
const minidump::Header &header() const { return Header; }
|
||||
|
||||
/// Returns the list of streams (stream directory entries) in this file.
|
||||
ArrayRef<minidump::Directory> streams() const { return Streams; }
|
||||
|
||||
/// Returns the raw contents of the stream given by the directory entry.
|
||||
ArrayRef<uint8_t> getRawStream(const minidump::Directory &Stream) const {
|
||||
return getData().slice(Stream.Location.RVA, Stream.Location.DataSize);
|
||||
}
|
||||
|
||||
/// Returns the raw contents of the stream of the given type, or None if the
|
||||
/// file does not contain a stream of this type.
|
||||
Optional<ArrayRef<uint8_t>> getRawStream(minidump::StreamType Type) const;
|
||||
|
||||
/// Returns the contents of the SystemInfo stream, cast to the appropriate
|
||||
/// type. An error is returned if the file does not contain this stream, or
|
||||
/// the stream is smaller than the size of the SystemInfo structure. The
|
||||
/// internal consistency of the stream is not checked in any way.
|
||||
Expected<const minidump::SystemInfo &> getSystemInfo() const {
|
||||
return getStream<minidump::SystemInfo>(minidump::StreamType::SystemInfo);
|
||||
}
|
||||
|
||||
private:
|
||||
static Error createError(StringRef Str,
|
||||
object_error Err = object_error::parse_failed) {
|
||||
return make_error<GenericBinaryError>(Str, Err);
|
||||
}
|
||||
|
||||
static Error createEOFError() {
|
||||
return createError("Unexpected EOF", object_error::unexpected_eof);
|
||||
}
|
||||
|
||||
/// Return a slice of the given data array, with bounds checking.
|
||||
static Expected<ArrayRef<uint8_t>> getDataSlice(ArrayRef<uint8_t> Data,
|
||||
size_t Offset, size_t Size);
|
||||
|
||||
/// Return the slice of the given data array as an array of objects of the
|
||||
/// given type. The function checks that the input array is large enough to
|
||||
/// contain the correct number of objects of the given type.
|
||||
template <typename T>
|
||||
static Expected<ArrayRef<T>> getDataSliceAs(ArrayRef<uint8_t> Data,
|
||||
size_t Offset, size_t Count);
|
||||
|
||||
MinidumpFile(MemoryBufferRef Source, const minidump::Header &Header,
|
||||
ArrayRef<minidump::Directory> Streams,
|
||||
DenseMap<minidump::StreamType, std::size_t> StreamMap)
|
||||
: Binary(ID_Minidump, Source), Header(Header), Streams(Streams),
|
||||
StreamMap(std::move(StreamMap)) {}
|
||||
|
||||
ArrayRef<uint8_t> getData() const {
|
||||
return arrayRefFromStringRef(Data.getBuffer());
|
||||
}
|
||||
|
||||
/// Return the stream of the given type, cast to the appropriate type. Checks
|
||||
/// that the stream is large enough to hold an object of this type.
|
||||
template <typename T>
|
||||
Expected<const T &> getStream(minidump::StreamType Stream) const;
|
||||
|
||||
const minidump::Header &Header;
|
||||
ArrayRef<minidump::Directory> Streams;
|
||||
DenseMap<minidump::StreamType, std::size_t> StreamMap;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Expected<const T &> MinidumpFile::getStream(minidump::StreamType Stream) const {
|
||||
if (auto OptionalStream = getRawStream(Stream)) {
|
||||
if (OptionalStream->size() >= sizeof(T))
|
||||
return *reinterpret_cast<const T *>(OptionalStream->data());
|
||||
return createError("Malformed stream", object_error::unexpected_eof);
|
||||
}
|
||||
return createError("No such stream", object_error::invalid_section_index);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Expected<ArrayRef<T>> MinidumpFile::getDataSliceAs(ArrayRef<uint8_t> Data,
|
||||
size_t Offset,
|
||||
size_t Count) {
|
||||
// Check for overflow.
|
||||
if (Count > std::numeric_limits<size_t>::max() / sizeof(T))
|
||||
return createEOFError();
|
||||
auto ExpectedArray = getDataSlice(Data, Offset, sizeof(T) * Count);
|
||||
if (!ExpectedArray)
|
||||
return ExpectedArray.takeError();
|
||||
return ArrayRef<T>(reinterpret_cast<const T *>(ExpectedArray->data()), Count);
|
||||
}
|
||||
|
||||
} // end namespace object
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_OBJECT_MINIDUMP_H
|
@ -2,6 +2,7 @@ add_llvm_library(LLVMBinaryFormat
|
||||
AMDGPUMetadataVerifier.cpp
|
||||
Dwarf.cpp
|
||||
Magic.cpp
|
||||
Minidump.cpp
|
||||
MsgPackDocument.cpp
|
||||
MsgPackDocumentYAML.cpp
|
||||
MsgPackReader.cpp
|
||||
|
@ -181,7 +181,8 @@ file_magic llvm::identify_magic(StringRef Magic) {
|
||||
return file_magic::coff_object;
|
||||
break;
|
||||
|
||||
case 'M': // Possible MS-DOS stub on Windows PE file or MSF/PDB file.
|
||||
case 'M': // Possible MS-DOS stub on Windows PE file, MSF/PDB file or a
|
||||
// Minidump file.
|
||||
if (startswith(Magic, "MZ") && Magic.size() >= 0x3c + 4) {
|
||||
uint32_t off = read32le(Magic.data() + 0x3c);
|
||||
// PE/COFF file, either EXE or DLL.
|
||||
@ -191,6 +192,8 @@ file_magic llvm::identify_magic(StringRef Magic) {
|
||||
}
|
||||
if (Magic.startswith("Microsoft C/C++ MSF 7.00\r\n"))
|
||||
return file_magic::pdb;
|
||||
if (startswith(Magic, "MDMP"))
|
||||
return file_magic::minidump;
|
||||
break;
|
||||
|
||||
case 0x64: // x86-64 or ARM64 Windows.
|
||||
|
14
lib/BinaryFormat/Minidump.cpp
Normal file
14
lib/BinaryFormat/Minidump.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
//===-- Minidump.cpp - Minidump constants and structures ---------*- C++-*-===//
|
||||
//
|
||||
// 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/BinaryFormat/Minidump.h"
|
||||
|
||||
using namespace llvm::minidump;
|
||||
|
||||
constexpr uint32_t Header::MagicSignature;
|
||||
constexpr uint16_t Header::MagicVersion;
|
@ -16,6 +16,7 @@
|
||||
#include "llvm/Object/Archive.h"
|
||||
#include "llvm/Object/Error.h"
|
||||
#include "llvm/Object/MachOUniversal.h"
|
||||
#include "llvm/Object/Minidump.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Object/WindowsResource.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
@ -81,6 +82,8 @@ Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer,
|
||||
case file_magic::coff_cl_gl_object:
|
||||
// Unrecognized object file format.
|
||||
return errorCodeToError(object_error::invalid_file_type);
|
||||
case file_magic::minidump:
|
||||
return MinidumpFile::create(Buffer);
|
||||
}
|
||||
llvm_unreachable("Unexpected Binary File Type");
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ add_llvm_library(LLVMObject
|
||||
IRSymtab.cpp
|
||||
MachOObjectFile.cpp
|
||||
MachOUniversal.cpp
|
||||
Minidump.cpp
|
||||
ModuleSymbolTable.cpp
|
||||
Object.cpp
|
||||
ObjectFile.cpp
|
||||
|
77
lib/Object/Minidump.cpp
Normal file
77
lib/Object/Minidump.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
//===- Minidump.cpp - Minidump object file implementation -----------------===//
|
||||
//
|
||||
// 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/Object/Error.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
using namespace llvm::minidump;
|
||||
|
||||
Optional<ArrayRef<uint8_t>>
|
||||
MinidumpFile::getRawStream(minidump::StreamType Type) const {
|
||||
auto It = StreamMap.find(Type);
|
||||
if (It != StreamMap.end())
|
||||
return getRawStream(Streams[It->second]);
|
||||
return None;
|
||||
}
|
||||
|
||||
Expected<ArrayRef<uint8_t>>
|
||||
MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) {
|
||||
// Check for overflow.
|
||||
if (Offset + Size < Offset || Offset + Size < Size ||
|
||||
Offset + Size > Data.size())
|
||||
return createEOFError();
|
||||
return Data.slice(Offset, Size);
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<MinidumpFile>>
|
||||
MinidumpFile::create(MemoryBufferRef Source) {
|
||||
ArrayRef<uint8_t> Data = arrayRefFromStringRef(Source.getBuffer());
|
||||
auto ExpectedHeader = getDataSliceAs<minidump::Header>(Data, 0, 1);
|
||||
if (!ExpectedHeader)
|
||||
return ExpectedHeader.takeError();
|
||||
|
||||
const minidump::Header &Hdr = (*ExpectedHeader)[0];
|
||||
if (Hdr.Signature != Header::MagicSignature)
|
||||
return createError("Invalid signature");
|
||||
if ((Hdr.Version & 0xffff) != Header::MagicVersion)
|
||||
return createError("Invalid version");
|
||||
|
||||
auto ExpectedStreams = getDataSliceAs<Directory>(Data, Hdr.StreamDirectoryRVA,
|
||||
Hdr.NumberOfStreams);
|
||||
if (!ExpectedStreams)
|
||||
return ExpectedStreams.takeError();
|
||||
|
||||
DenseMap<StreamType, std::size_t> StreamMap;
|
||||
for (const auto &Stream : llvm::enumerate(*ExpectedStreams)) {
|
||||
StreamType Type = Stream.value().Type;
|
||||
const LocationDescriptor &Loc = Stream.value().Location;
|
||||
|
||||
auto ExpectedStream = getDataSlice(Data, Loc.RVA, Loc.DataSize);
|
||||
if (!ExpectedStream)
|
||||
return ExpectedStream.takeError();
|
||||
|
||||
if (Type == StreamType::Unused && Loc.DataSize == 0) {
|
||||
// Ignore dummy streams. This is technically ill-formed, but a number of
|
||||
// existing minidumps seem to contain such streams.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Type == DenseMapInfo<StreamType>::getEmptyKey() ||
|
||||
Type == DenseMapInfo<StreamType>::getTombstoneKey())
|
||||
return createError("Cannot handle one of the minidump streams");
|
||||
|
||||
// Update the directory map, checking for duplicate stream types.
|
||||
if (!StreamMap.try_emplace(Type, Stream.index()).second)
|
||||
return createError("Duplicate stream type");
|
||||
}
|
||||
|
||||
return std::unique_ptr<MinidumpFile>(
|
||||
new MinidumpFile(Source, Hdr, *ExpectedStreams, std::move(StreamMap)));
|
||||
}
|
@ -127,6 +127,7 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type) {
|
||||
case file_magic::macho_universal_binary:
|
||||
case file_magic::windows_resource:
|
||||
case file_magic::pdb:
|
||||
case file_magic::minidump:
|
||||
return errorCodeToError(object_error::invalid_file_type);
|
||||
case file_magic::elf:
|
||||
case file_magic::elf_relocatable:
|
||||
|
@ -52,6 +52,7 @@ SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type,
|
||||
case file_magic::macho_universal_binary:
|
||||
case file_magic::windows_resource:
|
||||
case file_magic::pdb:
|
||||
case file_magic::minidump:
|
||||
return errorCodeToError(object_error::invalid_file_type);
|
||||
case file_magic::elf:
|
||||
case file_magic::elf_executable:
|
||||
|
@ -3,7 +3,9 @@ set(LLVM_LINK_COMPONENTS
|
||||
)
|
||||
|
||||
add_llvm_unittest(ObjectTests
|
||||
MinidumpTest.cpp
|
||||
SymbolSizeTest.cpp
|
||||
SymbolicFileTest.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(ObjectTests PRIVATE LLVMTestingSupport)
|
||||
|
256
unittests/Object/MinidumpTest.cpp
Normal file
256
unittests/Object/MinidumpTest.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
//===- 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) {
|
||||
// A very simple minidump file which contains just a single stream.
|
||||
auto ExpectedFile =
|
||||
create({ // 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, 0, 0, 0, // RVA
|
||||
// Stream
|
||||
'C', 'P', 'U', 'I', 'N', 'F', 'O'});
|
||||
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) {
|
||||
// File too short
|
||||
EXPECT_THAT_EXPECTED(create({'M', 'D', 'M', 'P'}), Failed<BinaryError>());
|
||||
|
||||
// Wrong Signature
|
||||
EXPECT_THAT_EXPECTED(
|
||||
create({ // 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'}),
|
||||
Failed<BinaryError>());
|
||||
|
||||
// Wrong Version
|
||||
EXPECT_THAT_EXPECTED(
|
||||
create({ // 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'}),
|
||||
Failed<BinaryError>());
|
||||
|
||||
// Stream directory after EOF
|
||||
EXPECT_THAT_EXPECTED(
|
||||
create({ // 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'}),
|
||||
Failed<BinaryError>());
|
||||
|
||||
// Truncated stream directory
|
||||
EXPECT_THAT_EXPECTED(
|
||||
create({ // 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'}),
|
||||
Failed<BinaryError>());
|
||||
|
||||
// Stream0 after EOF
|
||||
EXPECT_THAT_EXPECTED(
|
||||
create({ // 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'}),
|
||||
Failed<BinaryError>());
|
||||
|
||||
// Truncated Stream0
|
||||
EXPECT_THAT_EXPECTED(
|
||||
create({ // 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'}),
|
||||
Failed<BinaryError>());
|
||||
|
||||
// Duplicate Stream
|
||||
EXPECT_THAT_EXPECTED(
|
||||
create({ // 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'}),
|
||||
Failed<BinaryError>());
|
||||
|
||||
// Stream matching one of the DenseMapInfo magic values
|
||||
EXPECT_THAT_EXPECTED(
|
||||
create({ // 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'}),
|
||||
Failed<BinaryError>());
|
||||
}
|
||||
|
||||
TEST(MinidumpFile, IngoresDummyStreams) {
|
||||
auto ExpectedFile = create({
|
||||
// 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
|
||||
});
|
||||
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) {
|
||||
auto ExpectedFile = create({
|
||||
// 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
|
||||
});
|
||||
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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user