llvm.org GIT mirror llvm / 001e6f8
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@360908 91177308-0d34-0410-b5e6-96231b3b80d8 Pavel Labath 3 months ago
6 changed file(s) with 128 addition(s) and 8 deletion(s). Raw diff Collapse all Expand all
7979 return getListStream(minidump::StreamType::ThreadList);
8080 }
8181
82 /// Returns the list of memory ranges embedded in the MemoryList stream. An
83 /// error is returned if the file does not contain this stream, or if the
84 /// stream is not large enough to contain the number of memory descriptors
85 /// declared in the stream header. The consistency of the MemoryDescriptor
86 /// entries themselves is not checked in any way.
87 Expected> getMemoryList() const {
88 return getListStream(
89 minidump::StreamType::MemoryList);
90 }
91
8292 private:
8393 static Error createError(StringRef Str) {
8494 return make_error(Str, object_error::parse_failed);
2525 /// from Types to Kinds is fixed and given by the static getKind function.
2626 struct Stream {
2727 enum class StreamKind {
28 MemoryList,
2829 ModuleList,
2930 RawContent,
3031 SystemInfo,
8586 yaml::BinaryRef Stack;
8687 yaml::BinaryRef Context;
8788 };
89
90 /// A structure containing all data describing a single memory region.
91 struct ParsedMemoryDescriptor {
92 static constexpr Stream::StreamKind Kind = Stream::StreamKind::MemoryList;
93 static constexpr minidump::StreamType Type = minidump::StreamType::MemoryList;
94
95 minidump::MemoryDescriptor Entry;
96 yaml::BinaryRef Content;
97 };
8898 } // namespace detail
8999
90100 using ModuleListStream = detail::ListStream;
91101 using ThreadListStream = detail::ListStream;
102 using MemoryListStream = detail::ListStream;
92103
93104 /// A minidump stream represented as a sequence of hex bytes. This is used as a
94105 /// fallback when no other stream kind is suitable.
211222 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo)
212223
213224 LLVM_YAML_DECLARE_MAPPING_TRAITS(
225 llvm::MinidumpYAML::MemoryListStream::entry_type)
226 LLVM_YAML_DECLARE_MAPPING_TRAITS(
214227 llvm::MinidumpYAML::ModuleListStream::entry_type)
215228 LLVM_YAML_DECLARE_MAPPING_TRAITS(
216229 llvm::MinidumpYAML::ThreadListStream::entry_type)
217230
218231 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr)
232 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::MemoryListStream::entry_type)
219233 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ModuleListStream::entry_type)
220234 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ThreadListStream::entry_type)
221235
7777 MinidumpFile::getListStream(StreamType) const;
7878 template Expected>
7979 MinidumpFile::getListStream(StreamType) const;
80 template Expected>
81 MinidumpFile::getListStream(StreamType) const;
8082
8183 Expected>
8284 MinidumpFile::getDataSlice(ArrayRef Data, size_t Offset, size_t Size) {
167167
168168 Stream::StreamKind Stream::getKind(StreamType Type) {
169169 switch (Type) {
170 case StreamType::MemoryList:
171 return StreamKind::MemoryList;
170172 case StreamType::ModuleList:
171173 return StreamKind::ModuleList;
172174 case StreamType::SystemInfo:
189191 std::unique_ptr Stream::create(StreamType Type) {
190192 StreamKind Kind = getKind(Type);
191193 switch (Kind) {
194 case StreamKind::MemoryList:
195 return llvm::make_unique();
192196 case StreamKind::ModuleList:
193197 return llvm::make_unique();
194198 case StreamKind::RawContent:
350354 if (Stream.Size.value < Stream.Content.binary_size())
351355 return "Stream size must be greater or equal to the content size";
352356 return "";
357 }
358
359 void yaml::MappingTraits::mapping(
360 IO &IO, MemoryListStream::entry_type &Range) {
361 MappingContextTraits::mapping(
362 IO, Range.Entry, Range.Content);
363 }
364
365 static void streamMapping(yaml::IO &IO, MemoryListStream &Stream) {
366 IO.mapRequired("Memory Ranges", Stream.Entries);
353367 }
354368
355369 static void streamMapping(yaml::IO &IO, ModuleListStream &Stream) {
420434 if (!IO.outputting())
421435 S = MinidumpYAML::Stream::create(Type);
422436 switch (S->Kind) {
437 case MinidumpYAML::Stream::StreamKind::MemoryList:
438 streamMapping(IO, llvm::cast(*S));
439 break;
423440 case MinidumpYAML::Stream::StreamKind::ModuleList:
424441 streamMapping(IO, llvm::cast(*S));
425442 break;
443460 switch (S->Kind) {
444461 case MinidumpYAML::Stream::StreamKind::RawContent:
445462 return streamValidate(cast(*S));
463 case MinidumpYAML::Stream::StreamKind::MemoryList:
446464 case MinidumpYAML::Stream::StreamKind::ModuleList:
447465 case MinidumpYAML::Stream::StreamKind::SystemInfo:
448466 case MinidumpYAML::Stream::StreamKind::TextContent:
465483 support::ulittle32_t(File.allocateBytes(Data))};
466484 }
467485
486 static void layout(BlobAllocator &File, MemoryListStream::entry_type &Range) {
487 Range.Entry.Memory = layout(File, Range.Content);
488 }
489
468490 static void layout(BlobAllocator &File, ModuleListStream::entry_type &M) {
469491 M.Entry.ModuleNameRVA = File.allocateString(M.Name);
470492
501523 Result.Location.RVA = File.tell();
502524 Optional DataEnd;
503525 switch (S.Kind) {
526 case Stream::StreamKind::MemoryList:
527 DataEnd = layout(File, cast(S));
528 break;
504529 case Stream::StreamKind::ModuleList:
505530 DataEnd = layout(File, cast(S));
506531 break;
565590 Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) {
566591 StreamKind Kind = getKind(StreamDesc.Type);
567592 switch (Kind) {
593 case StreamKind::MemoryList: {
594 auto ExpectedList = File.getMemoryList();
595 if (!ExpectedList)
596 return ExpectedList.takeError();
597 std::vector Ranges;
598 for (const MemoryDescriptor &MD : *ExpectedList) {
599 auto ExpectedContent = File.getRawData(MD.Memory);
600 if (!ExpectedContent)
601 return ExpectedContent.takeError();
602 Ranges.push_back({MD, *ExpectedContent});
603 }
604 return llvm::make_unique(std::move(Ranges));
605 }
568606 case StreamKind::ModuleList: {
569607 auto ExpectedList = File.getModuleList();
570608 if (!ExpectedList)
3636 File Date High: 0x3C3D3E3F
3737 File Date Low: 0x40414243
3838 CodeView Record: '44454647'
39 Misc Record: 48494A4B
39 Misc Record: '48494A4B'
4040 - Base of Image: 0x4C4D4E4F50515253
4141 Size of Image: 0x54555657
4242 Module Name: libb.so
43 CodeView Record: 58595A5B
43 CodeView Record: '58595A5B'
4444 - Type: ThreadList
4545 Threads:
4646 - Thread Id: 0x5C5D5E5F
4747 Priority Class: 0x60616263
4848 Environment Block: 0x6465666768696A6B
49 Context: 7C7D7E7F80818283
49 Context: '7C7D7E7F80818283'
5050 Stack:
5151 Start of Memory Range: 0x6C6D6E6F70717273
52 Content: 7475767778797A7B
52 Content: '7475767778797A7B'
53 - Type: MemoryList
54 Memory Ranges:
55 - Start of Memory Range: 0x7C7D7E7F80818283
56 Content: '8485868788'
5357 ...
5458
5559 # CHECK: --- !minidump
96100 # CHECK-NEXT: CodeView Record: 58595A5B
97101 # CHECK-NEXT: - Type: ThreadList
98102 # CHECK-NEXT: Threads:
99 # CHECK-NEXT: - Thread Id: 0x5C5D5E5F
100 # CHECK-NEXT: Priority Class: 0x60616263
103 # CHECK-NEXT: - Thread Id: 0x5C5D5E5F
104 # CHECK-NEXT: Priority Class: 0x60616263
101105 # CHECK-NEXT: Environment Block: 0x6465666768696A6B
102 # CHECK-NEXT: Context: 7C7D7E7F80818283
106 # CHECK-NEXT: Context: 7C7D7E7F80818283
103107 # CHECK-NEXT: Stack:
104108 # CHECK-NEXT: Start of Memory Range: 0x6C6D6E6F70717273
105 # CHECK-NEXT: Content: 7475767778797A7B
109 # CHECK-NEXT: Content: 7475767778797A7B
110 # CHECK-NEXT: - Type: MemoryList
111 # CHECK-NEXT: Memory Ranges:
112 # CHECK-NEXT: - Start of Memory Range: 0x7C7D7E7F80818283
113 # CHECK-NEXT: Content: '8485868788'
106114 # CHECK-NEXT: ...
462462 EXPECT_EQ(0x08070605u, T.Context.RVA);
463463 }
464464 }
465
466 TEST(MinidumpFile, getMemoryList) {
467 std::vector OneRange{
468 // Header
469 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
470 1, 0, 0, 0, // NumberOfStreams,
471 32, 0, 0, 0, // StreamDirectoryRVA
472 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
473 0, 0, 0, 0, 0, 0, 0, 0, // Flags
474 // Stream Directory
475 5, 0, 0, 0, 20, 0, 0, 0, // Type, DataSize,
476 44, 0, 0, 0, // RVA
477 // MemoryDescriptor
478 1, 0, 0, 0, // NumberOfMemoryRanges
479 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
480 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
481 };
482 // Same as before, but with a padded memory list.
483 std::vector PaddedRange{
484 // Header
485 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version
486 1, 0, 0, 0, // NumberOfStreams,
487 32, 0, 0, 0, // StreamDirectoryRVA
488 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp
489 0, 0, 0, 0, 0, 0, 0, 0, // Flags
490 // Stream Directory
491 5, 0, 0, 0, 24, 0, 0, 0, // Type, DataSize,
492 44, 0, 0, 0, // RVA
493 // MemoryDescriptor
494 1, 0, 0, 0, // NumberOfMemoryRanges
495 0, 0, 0, 0, // Padding
496 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange
497 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA
498 };
499
500 for (ArrayRef Data : {OneRange, PaddedRange}) {
501 auto ExpectedFile = create(Data);
502 ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
503 const MinidumpFile &File = **ExpectedFile;
504 Expected> ExpectedRanges = File.getMemoryList();
505 ASSERT_THAT_EXPECTED(ExpectedRanges, Succeeded());
506 ASSERT_EQ(1u, ExpectedRanges->size());
507 const MemoryDescriptor &MD = ExpectedRanges.get()[0];
508 EXPECT_EQ(0x0201000908070605u, MD.StartOfMemoryRange);
509 EXPECT_EQ(0x06050403u, MD.Memory.DataSize);
510 EXPECT_EQ(0x00090807u, MD.Memory.RVA);
511 }
512 }