mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-03 01:12:53 +00:00
Object/Minidump: Add support for the ThreadList stream
Summary: The stream contains the list of threads belonging to the process described by the minidump. Its structure is the same as the ModuleList stream, and in fact, I have generalized the ModuleList reading code to handle this stream too. Reviewers: amccarth, jhenderson, clayborg Subscribers: llvm-commits, lldb-commits, markmentovai, zturner Tags: #llvm Differential Revision: https://reviews.llvm.org/D61064 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@359762 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
a65cc965db
commit
c69acccf97
@ -59,6 +59,14 @@ struct LocationDescriptor {
|
||||
};
|
||||
static_assert(sizeof(LocationDescriptor) == 8, "");
|
||||
|
||||
/// Describes a single memory range (both its VM address and where to find it in
|
||||
/// the file) of the process from which this minidump file was generated.
|
||||
struct MemoryDescriptor {
|
||||
support::ulittle64_t StartOfMemoryRange;
|
||||
LocationDescriptor Memory;
|
||||
};
|
||||
static_assert(sizeof(MemoryDescriptor) == 16, "");
|
||||
|
||||
/// 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.
|
||||
@ -159,6 +167,19 @@ struct Module {
|
||||
};
|
||||
static_assert(sizeof(Module) == 108, "");
|
||||
|
||||
/// Describes a single thread in the minidump file. Part of the ThreadList
|
||||
/// stream.
|
||||
struct Thread {
|
||||
support::ulittle32_t ThreadId;
|
||||
support::ulittle32_t SuspendCount;
|
||||
support::ulittle32_t PriorityClass;
|
||||
support::ulittle32_t Priority;
|
||||
support::ulittle64_t EnvironmentBlock;
|
||||
MemoryDescriptor Stack;
|
||||
LocationDescriptor Context;
|
||||
};
|
||||
static_assert(sizeof(Thread) == 48, "");
|
||||
|
||||
} // namespace minidump
|
||||
|
||||
template <> struct DenseMapInfo<minidump::StreamType> {
|
||||
|
@ -67,7 +67,18 @@ public:
|
||||
/// not large enough to contain the number of modules declared in the stream
|
||||
/// header. The consistency of the Module entries themselves is not checked in
|
||||
/// any way.
|
||||
Expected<ArrayRef<minidump::Module>> getModuleList() const;
|
||||
Expected<ArrayRef<minidump::Module>> getModuleList() const {
|
||||
return getListStream<minidump::Module>(minidump::StreamType::ModuleList);
|
||||
}
|
||||
|
||||
/// Returns the thread list embedded in the ThreadList stream. An error is
|
||||
/// returned if the file does not contain this stream, or if the stream is
|
||||
/// not large enough to contain the number of threads declared in the stream
|
||||
/// header. The consistency of the Thread entries themselves is not checked in
|
||||
/// any way.
|
||||
Expected<ArrayRef<minidump::Thread>> getThreadList() const {
|
||||
return getListStream<minidump::Thread>(minidump::StreamType::ThreadList);
|
||||
}
|
||||
|
||||
private:
|
||||
static Error createError(StringRef Str) {
|
||||
@ -105,6 +116,11 @@ private:
|
||||
template <typename T>
|
||||
Expected<const T &> getStream(minidump::StreamType Stream) const;
|
||||
|
||||
/// Return the contents of a stream which contains a list of fixed-size items,
|
||||
/// prefixed by the list size.
|
||||
template <typename T>
|
||||
Expected<ArrayRef<T>> getListStream(minidump::StreamType Stream) const;
|
||||
|
||||
const minidump::Header &Header;
|
||||
ArrayRef<minidump::Directory> Streams;
|
||||
DenseMap<minidump::StreamType, std::size_t> StreamMap;
|
||||
|
@ -53,8 +53,9 @@ Expected<std::string> MinidumpFile::getString(size_t Offset) const {
|
||||
return Result;
|
||||
}
|
||||
|
||||
Expected<ArrayRef<Module>> MinidumpFile::getModuleList() const {
|
||||
auto OptionalStream = getRawStream(StreamType::ModuleList);
|
||||
template <typename T>
|
||||
Expected<ArrayRef<T>> MinidumpFile::getListStream(StreamType Stream) const {
|
||||
auto OptionalStream = getRawStream(Stream);
|
||||
if (!OptionalStream)
|
||||
return createError("No such stream");
|
||||
auto ExpectedSize =
|
||||
@ -65,14 +66,18 @@ Expected<ArrayRef<Module>> MinidumpFile::getModuleList() const {
|
||||
size_t ListSize = ExpectedSize.get()[0];
|
||||
|
||||
size_t ListOffset = 4;
|
||||
// Some producers insert additional padding bytes to align the module list to
|
||||
// 8-byte boundary. Check for that by comparing the module list size with the
|
||||
// overall stream size.
|
||||
if (ListOffset + sizeof(Module) * ListSize < OptionalStream->size())
|
||||
// Some producers insert additional padding bytes to align the list to an
|
||||
// 8-byte boundary. Check for that by comparing the list size with the overall
|
||||
// stream size.
|
||||
if (ListOffset + sizeof(T) * ListSize < OptionalStream->size())
|
||||
ListOffset = 8;
|
||||
|
||||
return getDataSliceAs<Module>(*OptionalStream, ListOffset, ListSize);
|
||||
return getDataSliceAs<T>(*OptionalStream, ListOffset, ListSize);
|
||||
}
|
||||
template Expected<ArrayRef<Module>>
|
||||
MinidumpFile::getListStream(StreamType) const;
|
||||
template Expected<ArrayRef<Thread>>
|
||||
MinidumpFile::getListStream(StreamType) const;
|
||||
|
||||
Expected<ArrayRef<uint8_t>>
|
||||
MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) {
|
||||
|
@ -343,7 +343,7 @@ TEST(MinidumpFile, getModuleList) {
|
||||
5, 6, 7, 8, 9, 0, 1, 2, // Reserved1
|
||||
};
|
||||
|
||||
for (const std::vector<uint8_t> &Data : {OneModule, PaddedModule}) {
|
||||
for (ArrayRef<uint8_t> Data : {OneModule, PaddedModule}) {
|
||||
auto ExpectedFile = create(Data);
|
||||
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
||||
const MinidumpFile &File = **ExpectedFile;
|
||||
@ -396,3 +396,70 @@ TEST(MinidumpFile, getModuleList) {
|
||||
const MinidumpFile &File = **ExpectedFile;
|
||||
EXPECT_THAT_EXPECTED(File.getModuleList(), Failed<BinaryError>());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user