mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 20:09:46 +00:00
Minidump: Add support for the MemoryList stream
Summary: the stream format is exactly the same as for ThreadList and ModuleList streams, only the entry types are slightly different, so the changes in this patch are just straight-forward applications of established patterns. Reviewers: amccarth, jhenderson, clayborg Subscribers: markmentovai, lldb-commits, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D61885 llvm-svn: 360908
This commit is contained in:
parent
80ec90264f
commit
4adc6bd3dd
@ -80,6 +80,16 @@ public:
|
||||
return getListStream<minidump::Thread>(minidump::StreamType::ThreadList);
|
||||
}
|
||||
|
||||
/// Returns the list of memory ranges embedded in the MemoryList 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 memory descriptors
|
||||
/// declared in the stream header. The consistency of the MemoryDescriptor
|
||||
/// entries themselves is not checked in any way.
|
||||
Expected<ArrayRef<minidump::MemoryDescriptor>> getMemoryList() const {
|
||||
return getListStream<minidump::MemoryDescriptor>(
|
||||
minidump::StreamType::MemoryList);
|
||||
}
|
||||
|
||||
private:
|
||||
static Error createError(StringRef Str) {
|
||||
return make_error<GenericBinaryError>(Str, object_error::parse_failed);
|
||||
|
@ -26,6 +26,7 @@ namespace MinidumpYAML {
|
||||
/// from Types to Kinds is fixed and given by the static getKind function.
|
||||
struct Stream {
|
||||
enum class StreamKind {
|
||||
MemoryList,
|
||||
ModuleList,
|
||||
RawContent,
|
||||
SystemInfo,
|
||||
@ -86,10 +87,20 @@ struct ParsedThread {
|
||||
yaml::BinaryRef Stack;
|
||||
yaml::BinaryRef Context;
|
||||
};
|
||||
|
||||
/// A structure containing all data describing a single memory region.
|
||||
struct ParsedMemoryDescriptor {
|
||||
static constexpr Stream::StreamKind Kind = Stream::StreamKind::MemoryList;
|
||||
static constexpr minidump::StreamType Type = minidump::StreamType::MemoryList;
|
||||
|
||||
minidump::MemoryDescriptor Entry;
|
||||
yaml::BinaryRef Content;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
using ModuleListStream = detail::ListStream<detail::ParsedModule>;
|
||||
using ThreadListStream = detail::ListStream<detail::ParsedThread>;
|
||||
using MemoryListStream = detail::ListStream<detail::ParsedMemoryDescriptor>;
|
||||
|
||||
/// A minidump stream represented as a sequence of hex bytes. This is used as a
|
||||
/// fallback when no other stream kind is suitable.
|
||||
@ -211,12 +222,15 @@ LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::OtherInfo)
|
||||
LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info)
|
||||
LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo)
|
||||
|
||||
LLVM_YAML_DECLARE_MAPPING_TRAITS(
|
||||
llvm::MinidumpYAML::MemoryListStream::entry_type)
|
||||
LLVM_YAML_DECLARE_MAPPING_TRAITS(
|
||||
llvm::MinidumpYAML::ModuleListStream::entry_type)
|
||||
LLVM_YAML_DECLARE_MAPPING_TRAITS(
|
||||
llvm::MinidumpYAML::ThreadListStream::entry_type)
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::MinidumpYAML::Stream>)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::MemoryListStream::entry_type)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ModuleListStream::entry_type)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ThreadListStream::entry_type)
|
||||
|
||||
|
@ -78,6 +78,8 @@ template Expected<ArrayRef<Module>>
|
||||
MinidumpFile::getListStream(StreamType) const;
|
||||
template Expected<ArrayRef<Thread>>
|
||||
MinidumpFile::getListStream(StreamType) const;
|
||||
template Expected<ArrayRef<MemoryDescriptor>>
|
||||
MinidumpFile::getListStream(StreamType) const;
|
||||
|
||||
Expected<ArrayRef<uint8_t>>
|
||||
MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) {
|
||||
|
@ -168,6 +168,8 @@ Stream::~Stream() = default;
|
||||
|
||||
Stream::StreamKind Stream::getKind(StreamType Type) {
|
||||
switch (Type) {
|
||||
case StreamType::MemoryList:
|
||||
return StreamKind::MemoryList;
|
||||
case StreamType::ModuleList:
|
||||
return StreamKind::ModuleList;
|
||||
case StreamType::SystemInfo:
|
||||
@ -190,6 +192,8 @@ Stream::StreamKind Stream::getKind(StreamType Type) {
|
||||
std::unique_ptr<Stream> Stream::create(StreamType Type) {
|
||||
StreamKind Kind = getKind(Type);
|
||||
switch (Kind) {
|
||||
case StreamKind::MemoryList:
|
||||
return llvm::make_unique<MemoryListStream>();
|
||||
case StreamKind::ModuleList:
|
||||
return llvm::make_unique<ModuleListStream>();
|
||||
case StreamKind::RawContent:
|
||||
@ -353,6 +357,16 @@ static StringRef streamValidate(RawContentStream &Stream) {
|
||||
return "";
|
||||
}
|
||||
|
||||
void yaml::MappingTraits<MemoryListStream::entry_type>::mapping(
|
||||
IO &IO, MemoryListStream::entry_type &Range) {
|
||||
MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping(
|
||||
IO, Range.Entry, Range.Content);
|
||||
}
|
||||
|
||||
static void streamMapping(yaml::IO &IO, MemoryListStream &Stream) {
|
||||
IO.mapRequired("Memory Ranges", Stream.Entries);
|
||||
}
|
||||
|
||||
static void streamMapping(yaml::IO &IO, ModuleListStream &Stream) {
|
||||
IO.mapRequired("Modules", Stream.Entries);
|
||||
}
|
||||
@ -421,6 +435,9 @@ void yaml::MappingTraits<std::unique_ptr<Stream>>::mapping(
|
||||
if (!IO.outputting())
|
||||
S = MinidumpYAML::Stream::create(Type);
|
||||
switch (S->Kind) {
|
||||
case MinidumpYAML::Stream::StreamKind::MemoryList:
|
||||
streamMapping(IO, llvm::cast<MemoryListStream>(*S));
|
||||
break;
|
||||
case MinidumpYAML::Stream::StreamKind::ModuleList:
|
||||
streamMapping(IO, llvm::cast<ModuleListStream>(*S));
|
||||
break;
|
||||
@ -444,6 +461,7 @@ StringRef yaml::MappingTraits<std::unique_ptr<Stream>>::validate(
|
||||
switch (S->Kind) {
|
||||
case MinidumpYAML::Stream::StreamKind::RawContent:
|
||||
return streamValidate(cast<RawContentStream>(*S));
|
||||
case MinidumpYAML::Stream::StreamKind::MemoryList:
|
||||
case MinidumpYAML::Stream::StreamKind::ModuleList:
|
||||
case MinidumpYAML::Stream::StreamKind::SystemInfo:
|
||||
case MinidumpYAML::Stream::StreamKind::TextContent:
|
||||
@ -466,6 +484,10 @@ static LocationDescriptor layout(BlobAllocator &File, yaml::BinaryRef Data) {
|
||||
support::ulittle32_t(File.allocateBytes(Data))};
|
||||
}
|
||||
|
||||
static void layout(BlobAllocator &File, MemoryListStream::entry_type &Range) {
|
||||
Range.Entry.Memory = layout(File, Range.Content);
|
||||
}
|
||||
|
||||
static void layout(BlobAllocator &File, ModuleListStream::entry_type &M) {
|
||||
M.Entry.ModuleNameRVA = File.allocateString(M.Name);
|
||||
|
||||
@ -502,6 +524,9 @@ static Directory layout(BlobAllocator &File, Stream &S) {
|
||||
Result.Location.RVA = File.tell();
|
||||
Optional<size_t> DataEnd;
|
||||
switch (S.Kind) {
|
||||
case Stream::StreamKind::MemoryList:
|
||||
DataEnd = layout(File, cast<MemoryListStream>(S));
|
||||
break;
|
||||
case Stream::StreamKind::ModuleList:
|
||||
DataEnd = layout(File, cast<ModuleListStream>(S));
|
||||
break;
|
||||
@ -566,6 +591,19 @@ Expected<std::unique_ptr<Stream>>
|
||||
Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) {
|
||||
StreamKind Kind = getKind(StreamDesc.Type);
|
||||
switch (Kind) {
|
||||
case StreamKind::MemoryList: {
|
||||
auto ExpectedList = File.getMemoryList();
|
||||
if (!ExpectedList)
|
||||
return ExpectedList.takeError();
|
||||
std::vector<MemoryListStream::entry_type> Ranges;
|
||||
for (const MemoryDescriptor &MD : *ExpectedList) {
|
||||
auto ExpectedContent = File.getRawData(MD.Memory);
|
||||
if (!ExpectedContent)
|
||||
return ExpectedContent.takeError();
|
||||
Ranges.push_back({MD, *ExpectedContent});
|
||||
}
|
||||
return llvm::make_unique<MemoryListStream>(std::move(Ranges));
|
||||
}
|
||||
case StreamKind::ModuleList: {
|
||||
auto ExpectedList = File.getModuleList();
|
||||
if (!ExpectedList)
|
||||
|
@ -37,20 +37,24 @@ Streams:
|
||||
File Date High: 0x3C3D3E3F
|
||||
File Date Low: 0x40414243
|
||||
CodeView Record: '44454647'
|
||||
Misc Record: 48494A4B
|
||||
Misc Record: '48494A4B'
|
||||
- Base of Image: 0x4C4D4E4F50515253
|
||||
Size of Image: 0x54555657
|
||||
Module Name: libb.so
|
||||
CodeView Record: 58595A5B
|
||||
CodeView Record: '58595A5B'
|
||||
- Type: ThreadList
|
||||
Threads:
|
||||
- Thread Id: 0x5C5D5E5F
|
||||
Priority Class: 0x60616263
|
||||
Environment Block: 0x6465666768696A6B
|
||||
Context: 7C7D7E7F80818283
|
||||
Context: '7C7D7E7F80818283'
|
||||
Stack:
|
||||
Start of Memory Range: 0x6C6D6E6F70717273
|
||||
Content: 7475767778797A7B
|
||||
Content: '7475767778797A7B'
|
||||
- Type: MemoryList
|
||||
Memory Ranges:
|
||||
- Start of Memory Range: 0x7C7D7E7F80818283
|
||||
Content: '8485868788'
|
||||
...
|
||||
|
||||
# CHECK: --- !minidump
|
||||
@ -97,11 +101,15 @@ Streams:
|
||||
# CHECK-NEXT: CodeView Record: 58595A5B
|
||||
# CHECK-NEXT: - Type: ThreadList
|
||||
# CHECK-NEXT: Threads:
|
||||
# CHECK-NEXT: - Thread Id: 0x5C5D5E5F
|
||||
# CHECK-NEXT: Priority Class: 0x60616263
|
||||
# CHECK-NEXT: - Thread Id: 0x5C5D5E5F
|
||||
# CHECK-NEXT: Priority Class: 0x60616263
|
||||
# CHECK-NEXT: Environment Block: 0x6465666768696A6B
|
||||
# CHECK-NEXT: Context: 7C7D7E7F80818283
|
||||
# CHECK-NEXT: Context: 7C7D7E7F80818283
|
||||
# CHECK-NEXT: Stack:
|
||||
# CHECK-NEXT: Start of Memory Range: 0x6C6D6E6F70717273
|
||||
# CHECK-NEXT: Content: 7475767778797A7B
|
||||
# CHECK-NEXT: Content: 7475767778797A7B
|
||||
# CHECK-NEXT: - Type: MemoryList
|
||||
# CHECK-NEXT: Memory Ranges:
|
||||
# CHECK-NEXT: - Start of Memory Range: 0x7C7D7E7F80818283
|
||||
# CHECK-NEXT: Content: '8485868788'
|
||||
# CHECK-NEXT: ...
|
||||
|
@ -463,3 +463,51 @@ TEST(MinidumpFile, getThreadList) {
|
||||
EXPECT_EQ(0x08070605u, T.Context.RVA);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user