1 //===- MinidumpYAML.cpp - Minidump YAMLIO implementation ------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ObjectYAML/MinidumpYAML.h"
10 #include "llvm/Support/Allocator.h"
13 using namespace llvm::MinidumpYAML
;
14 using namespace llvm::minidump
;
16 /// Perform an optional yaml-mapping of an endian-aware type EndianType. The
17 /// only purpose of this function is to avoid casting the Default value to the
19 template <typename EndianType
>
20 static inline void mapOptional(yaml::IO
&IO
, const char *Key
, EndianType
&Val
,
21 typename
EndianType::value_type Default
) {
22 IO
.mapOptional(Key
, Val
, EndianType(Default
));
25 /// Yaml-map an endian-aware type EndianType as some other type MapType.
26 template <typename MapType
, typename EndianType
>
27 static inline void mapRequiredAs(yaml::IO
&IO
, const char *Key
,
29 MapType Mapped
= static_cast<typename
EndianType::value_type
>(Val
);
30 IO
.mapRequired(Key
, Mapped
);
31 Val
= static_cast<typename
EndianType::value_type
>(Mapped
);
34 /// Perform an optional yaml-mapping of an endian-aware type EndianType as some
35 /// other type MapType.
36 template <typename MapType
, typename EndianType
>
37 static inline void mapOptionalAs(yaml::IO
&IO
, const char *Key
, EndianType
&Val
,
39 MapType Mapped
= static_cast<typename
EndianType::value_type
>(Val
);
40 IO
.mapOptional(Key
, Mapped
, Default
);
41 Val
= static_cast<typename
EndianType::value_type
>(Mapped
);
45 /// Return the appropriate yaml Hex type for a given endian-aware type.
46 template <typename EndianType
> struct HexType
;
47 template <> struct HexType
<support::ulittle16_t
> { using type
= yaml::Hex16
; };
48 template <> struct HexType
<support::ulittle32_t
> { using type
= yaml::Hex32
; };
49 template <> struct HexType
<support::ulittle64_t
> { using type
= yaml::Hex64
; };
52 /// Yaml-map an endian-aware type as an appropriately-sized hex value.
53 template <typename EndianType
>
54 static inline void mapRequiredHex(yaml::IO
&IO
, const char *Key
,
56 mapRequiredAs
<typename HexType
<EndianType
>::type
>(IO
, Key
, Val
);
59 /// Perform an optional yaml-mapping of an endian-aware type as an
60 /// appropriately-sized hex value.
61 template <typename EndianType
>
62 static inline void mapOptionalHex(yaml::IO
&IO
, const char *Key
,
64 typename
EndianType::value_type Default
) {
65 mapOptionalAs
<typename HexType
<EndianType
>::type
>(IO
, Key
, Val
, Default
);
68 Stream::~Stream() = default;
70 Stream::StreamKind
Stream::getKind(StreamType Type
) {
72 case StreamType::MemoryInfoList
:
73 return StreamKind::MemoryInfoList
;
74 case StreamType::MemoryList
:
75 return StreamKind::MemoryList
;
76 case StreamType::ModuleList
:
77 return StreamKind::ModuleList
;
78 case StreamType::SystemInfo
:
79 return StreamKind::SystemInfo
;
80 case StreamType::LinuxCPUInfo
:
81 case StreamType::LinuxProcStatus
:
82 case StreamType::LinuxLSBRelease
:
83 case StreamType::LinuxCMDLine
:
84 case StreamType::LinuxMaps
:
85 case StreamType::LinuxProcStat
:
86 case StreamType::LinuxProcUptime
:
87 return StreamKind::TextContent
;
88 case StreamType::ThreadList
:
89 return StreamKind::ThreadList
;
91 return StreamKind::RawContent
;
95 std::unique_ptr
<Stream
> Stream::create(StreamType Type
) {
96 StreamKind Kind
= getKind(Type
);
98 case StreamKind::MemoryInfoList
:
99 return std::make_unique
<MemoryInfoListStream
>();
100 case StreamKind::MemoryList
:
101 return std::make_unique
<MemoryListStream
>();
102 case StreamKind::ModuleList
:
103 return std::make_unique
<ModuleListStream
>();
104 case StreamKind::RawContent
:
105 return std::make_unique
<RawContentStream
>(Type
);
106 case StreamKind::SystemInfo
:
107 return std::make_unique
<SystemInfoStream
>();
108 case StreamKind::TextContent
:
109 return std::make_unique
<TextContentStream
>(Type
);
110 case StreamKind::ThreadList
:
111 return std::make_unique
<ThreadListStream
>();
113 llvm_unreachable("Unhandled stream kind!");
116 void yaml::ScalarBitSetTraits
<MemoryProtection
>::bitset(
117 IO
&IO
, MemoryProtection
&Protect
) {
118 #define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME) \
119 IO.bitSetCase(Protect, #NATIVENAME, MemoryProtection::NAME);
120 #include "llvm/BinaryFormat/MinidumpConstants.def"
123 void yaml::ScalarBitSetTraits
<MemoryState
>::bitset(IO
&IO
, MemoryState
&State
) {
124 #define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME) \
125 IO.bitSetCase(State, #NATIVENAME, MemoryState::NAME);
126 #include "llvm/BinaryFormat/MinidumpConstants.def"
129 void yaml::ScalarBitSetTraits
<MemoryType
>::bitset(IO
&IO
, MemoryType
&Type
) {
130 #define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME) \
131 IO.bitSetCase(Type, #NATIVENAME, MemoryType::NAME);
132 #include "llvm/BinaryFormat/MinidumpConstants.def"
135 void yaml::ScalarEnumerationTraits
<ProcessorArchitecture
>::enumeration(
136 IO
&IO
, ProcessorArchitecture
&Arch
) {
137 #define HANDLE_MDMP_ARCH(CODE, NAME) \
138 IO.enumCase(Arch, #NAME, ProcessorArchitecture::NAME);
139 #include "llvm/BinaryFormat/MinidumpConstants.def"
140 IO
.enumFallback
<Hex16
>(Arch
);
143 void yaml::ScalarEnumerationTraits
<OSPlatform
>::enumeration(IO
&IO
,
145 #define HANDLE_MDMP_PLATFORM(CODE, NAME) \
146 IO.enumCase(Plat, #NAME, OSPlatform::NAME);
147 #include "llvm/BinaryFormat/MinidumpConstants.def"
148 IO
.enumFallback
<Hex32
>(Plat
);
151 void yaml::ScalarEnumerationTraits
<StreamType
>::enumeration(IO
&IO
,
153 #define HANDLE_MDMP_STREAM_TYPE(CODE, NAME) \
154 IO.enumCase(Type, #NAME, StreamType::NAME);
155 #include "llvm/BinaryFormat/MinidumpConstants.def"
156 IO
.enumFallback
<Hex32
>(Type
);
159 void yaml::MappingTraits
<CPUInfo::ArmInfo
>::mapping(IO
&IO
,
160 CPUInfo::ArmInfo
&Info
) {
161 mapRequiredHex(IO
, "CPUID", Info
.CPUID
);
162 mapOptionalHex(IO
, "ELF hwcaps", Info
.ElfHWCaps
, 0);
166 template <std::size_t N
> struct FixedSizeHex
{
167 FixedSizeHex(uint8_t (&Storage
)[N
]) : Storage(Storage
) {}
169 uint8_t (&Storage
)[N
];
175 template <std::size_t N
> struct ScalarTraits
<FixedSizeHex
<N
>> {
176 static void output(const FixedSizeHex
<N
> &Fixed
, void *, raw_ostream
&OS
) {
177 OS
<< toHex(makeArrayRef(Fixed
.Storage
));
180 static StringRef
input(StringRef Scalar
, void *, FixedSizeHex
<N
> &Fixed
) {
181 if (!all_of(Scalar
, isHexDigit
))
182 return "Invalid hex digit in input";
183 if (Scalar
.size() < 2 * N
)
184 return "String too short";
185 if (Scalar
.size() > 2 * N
)
186 return "String too long";
187 copy(fromHex(Scalar
), Fixed
.Storage
);
191 static QuotingType
mustQuote(StringRef S
) { return QuotingType::None
; }
195 void yaml::MappingTraits
<CPUInfo::OtherInfo
>::mapping(
196 IO
&IO
, CPUInfo::OtherInfo
&Info
) {
197 FixedSizeHex
<sizeof(Info
.ProcessorFeatures
)> Features(Info
.ProcessorFeatures
);
198 IO
.mapRequired("Features", Features
);
202 /// A type which only accepts strings of a fixed size for yaml conversion.
203 template <std::size_t N
> struct FixedSizeString
{
204 FixedSizeString(char (&Storage
)[N
]) : Storage(Storage
) {}
212 template <std::size_t N
> struct ScalarTraits
<FixedSizeString
<N
>> {
213 static void output(const FixedSizeString
<N
> &Fixed
, void *, raw_ostream
&OS
) {
214 OS
<< StringRef(Fixed
.Storage
, N
);
217 static StringRef
input(StringRef Scalar
, void *, FixedSizeString
<N
> &Fixed
) {
218 if (Scalar
.size() < N
)
219 return "String too short";
220 if (Scalar
.size() > N
)
221 return "String too long";
222 copy(Scalar
, Fixed
.Storage
);
226 static QuotingType
mustQuote(StringRef S
) { return needsQuotes(S
); }
231 void yaml::MappingTraits
<CPUInfo::X86Info
>::mapping(IO
&IO
,
232 CPUInfo::X86Info
&Info
) {
233 FixedSizeString
<sizeof(Info
.VendorID
)> VendorID(Info
.VendorID
);
234 IO
.mapRequired("Vendor ID", VendorID
);
236 mapRequiredHex(IO
, "Version Info", Info
.VersionInfo
);
237 mapRequiredHex(IO
, "Feature Info", Info
.FeatureInfo
);
238 mapOptionalHex(IO
, "AMD Extended Features", Info
.AMDExtendedFeatures
, 0);
241 void yaml::MappingTraits
<MemoryInfo
>::mapping(IO
&IO
, MemoryInfo
&Info
) {
242 mapRequiredHex(IO
, "Base Address", Info
.BaseAddress
);
243 mapOptionalHex(IO
, "Allocation Base", Info
.AllocationBase
, Info
.BaseAddress
);
244 mapRequiredAs
<MemoryProtection
>(IO
, "Allocation Protect",
245 Info
.AllocationProtect
);
246 mapOptionalHex(IO
, "Reserved0", Info
.Reserved0
, 0);
247 mapRequiredHex(IO
, "Region Size", Info
.RegionSize
);
248 mapRequiredAs
<MemoryState
>(IO
, "State", Info
.State
);
249 mapOptionalAs
<MemoryProtection
>(IO
, "Protect", Info
.Protect
,
250 Info
.AllocationProtect
);
251 mapRequiredAs
<MemoryType
>(IO
, "Type", Info
.Type
);
252 mapOptionalHex(IO
, "Reserved1", Info
.Reserved1
, 0);
255 void yaml::MappingTraits
<VSFixedFileInfo
>::mapping(IO
&IO
,
256 VSFixedFileInfo
&Info
) {
257 mapOptionalHex(IO
, "Signature", Info
.Signature
, 0);
258 mapOptionalHex(IO
, "Struct Version", Info
.StructVersion
, 0);
259 mapOptionalHex(IO
, "File Version High", Info
.FileVersionHigh
, 0);
260 mapOptionalHex(IO
, "File Version Low", Info
.FileVersionLow
, 0);
261 mapOptionalHex(IO
, "Product Version High", Info
.ProductVersionHigh
, 0);
262 mapOptionalHex(IO
, "Product Version Low", Info
.ProductVersionLow
, 0);
263 mapOptionalHex(IO
, "File Flags Mask", Info
.FileFlagsMask
, 0);
264 mapOptionalHex(IO
, "File Flags", Info
.FileFlags
, 0);
265 mapOptionalHex(IO
, "File OS", Info
.FileOS
, 0);
266 mapOptionalHex(IO
, "File Type", Info
.FileType
, 0);
267 mapOptionalHex(IO
, "File Subtype", Info
.FileSubtype
, 0);
268 mapOptionalHex(IO
, "File Date High", Info
.FileDateHigh
, 0);
269 mapOptionalHex(IO
, "File Date Low", Info
.FileDateLow
, 0);
272 void yaml::MappingTraits
<ModuleListStream::entry_type
>::mapping(
273 IO
&IO
, ModuleListStream::entry_type
&M
) {
274 mapRequiredHex(IO
, "Base of Image", M
.Entry
.BaseOfImage
);
275 mapRequiredHex(IO
, "Size of Image", M
.Entry
.SizeOfImage
);
276 mapOptionalHex(IO
, "Checksum", M
.Entry
.Checksum
, 0);
277 IO
.mapOptional("Time Date Stamp", M
.Entry
.TimeDateStamp
,
278 support::ulittle32_t(0));
279 IO
.mapRequired("Module Name", M
.Name
);
280 IO
.mapOptional("Version Info", M
.Entry
.VersionInfo
, VSFixedFileInfo());
281 IO
.mapRequired("CodeView Record", M
.CvRecord
);
282 IO
.mapOptional("Misc Record", M
.MiscRecord
, yaml::BinaryRef());
283 mapOptionalHex(IO
, "Reserved0", M
.Entry
.Reserved0
, 0);
284 mapOptionalHex(IO
, "Reserved1", M
.Entry
.Reserved1
, 0);
287 static void streamMapping(yaml::IO
&IO
, RawContentStream
&Stream
) {
288 IO
.mapOptional("Content", Stream
.Content
);
289 IO
.mapOptional("Size", Stream
.Size
, Stream
.Content
.binary_size());
292 static StringRef
streamValidate(RawContentStream
&Stream
) {
293 if (Stream
.Size
.value
< Stream
.Content
.binary_size())
294 return "Stream size must be greater or equal to the content size";
298 void yaml::MappingTraits
<MemoryListStream::entry_type
>::mapping(
299 IO
&IO
, MemoryListStream::entry_type
&Range
) {
300 MappingContextTraits
<MemoryDescriptor
, yaml::BinaryRef
>::mapping(
301 IO
, Range
.Entry
, Range
.Content
);
304 static void streamMapping(yaml::IO
&IO
, MemoryInfoListStream
&Stream
) {
305 IO
.mapRequired("Memory Ranges", Stream
.Infos
);
308 static void streamMapping(yaml::IO
&IO
, MemoryListStream
&Stream
) {
309 IO
.mapRequired("Memory Ranges", Stream
.Entries
);
312 static void streamMapping(yaml::IO
&IO
, ModuleListStream
&Stream
) {
313 IO
.mapRequired("Modules", Stream
.Entries
);
316 static void streamMapping(yaml::IO
&IO
, SystemInfoStream
&Stream
) {
317 SystemInfo
&Info
= Stream
.Info
;
318 IO
.mapRequired("Processor Arch", Info
.ProcessorArch
);
319 mapOptional(IO
, "Processor Level", Info
.ProcessorLevel
, 0);
320 mapOptional(IO
, "Processor Revision", Info
.ProcessorRevision
, 0);
321 IO
.mapOptional("Number of Processors", Info
.NumberOfProcessors
, 0);
322 IO
.mapOptional("Product type", Info
.ProductType
, 0);
323 mapOptional(IO
, "Major Version", Info
.MajorVersion
, 0);
324 mapOptional(IO
, "Minor Version", Info
.MinorVersion
, 0);
325 mapOptional(IO
, "Build Number", Info
.BuildNumber
, 0);
326 IO
.mapRequired("Platform ID", Info
.PlatformId
);
327 IO
.mapOptional("CSD Version", Stream
.CSDVersion
, "");
328 mapOptionalHex(IO
, "Suite Mask", Info
.SuiteMask
, 0);
329 mapOptionalHex(IO
, "Reserved", Info
.Reserved
, 0);
330 switch (static_cast<ProcessorArchitecture
>(Info
.ProcessorArch
)) {
331 case ProcessorArchitecture::X86
:
332 case ProcessorArchitecture::AMD64
:
333 IO
.mapOptional("CPU", Info
.CPU
.X86
);
335 case ProcessorArchitecture::ARM
:
336 case ProcessorArchitecture::ARM64
:
337 IO
.mapOptional("CPU", Info
.CPU
.Arm
);
340 IO
.mapOptional("CPU", Info
.CPU
.Other
);
345 static void streamMapping(yaml::IO
&IO
, TextContentStream
&Stream
) {
346 IO
.mapOptional("Text", Stream
.Text
);
349 void yaml::MappingContextTraits
<MemoryDescriptor
, yaml::BinaryRef
>::mapping(
350 IO
&IO
, MemoryDescriptor
&Memory
, BinaryRef
&Content
) {
351 mapRequiredHex(IO
, "Start of Memory Range", Memory
.StartOfMemoryRange
);
352 IO
.mapRequired("Content", Content
);
355 void yaml::MappingTraits
<ThreadListStream::entry_type
>::mapping(
356 IO
&IO
, ThreadListStream::entry_type
&T
) {
357 mapRequiredHex(IO
, "Thread Id", T
.Entry
.ThreadId
);
358 mapOptionalHex(IO
, "Suspend Count", T
.Entry
.SuspendCount
, 0);
359 mapOptionalHex(IO
, "Priority Class", T
.Entry
.PriorityClass
, 0);
360 mapOptionalHex(IO
, "Priority", T
.Entry
.Priority
, 0);
361 mapOptionalHex(IO
, "Environment Block", T
.Entry
.EnvironmentBlock
, 0);
362 IO
.mapRequired("Context", T
.Context
);
363 IO
.mapRequired("Stack", T
.Entry
.Stack
, T
.Stack
);
366 static void streamMapping(yaml::IO
&IO
, ThreadListStream
&Stream
) {
367 IO
.mapRequired("Threads", Stream
.Entries
);
370 void yaml::MappingTraits
<std::unique_ptr
<Stream
>>::mapping(
371 yaml::IO
&IO
, std::unique_ptr
<MinidumpYAML::Stream
> &S
) {
375 IO
.mapRequired("Type", Type
);
377 if (!IO
.outputting())
378 S
= MinidumpYAML::Stream::create(Type
);
380 case MinidumpYAML::Stream::StreamKind::MemoryInfoList
:
381 streamMapping(IO
, llvm::cast
<MemoryInfoListStream
>(*S
));
383 case MinidumpYAML::Stream::StreamKind::MemoryList
:
384 streamMapping(IO
, llvm::cast
<MemoryListStream
>(*S
));
386 case MinidumpYAML::Stream::StreamKind::ModuleList
:
387 streamMapping(IO
, llvm::cast
<ModuleListStream
>(*S
));
389 case MinidumpYAML::Stream::StreamKind::RawContent
:
390 streamMapping(IO
, llvm::cast
<RawContentStream
>(*S
));
392 case MinidumpYAML::Stream::StreamKind::SystemInfo
:
393 streamMapping(IO
, llvm::cast
<SystemInfoStream
>(*S
));
395 case MinidumpYAML::Stream::StreamKind::TextContent
:
396 streamMapping(IO
, llvm::cast
<TextContentStream
>(*S
));
398 case MinidumpYAML::Stream::StreamKind::ThreadList
:
399 streamMapping(IO
, llvm::cast
<ThreadListStream
>(*S
));
404 StringRef
yaml::MappingTraits
<std::unique_ptr
<Stream
>>::validate(
405 yaml::IO
&IO
, std::unique_ptr
<MinidumpYAML::Stream
> &S
) {
407 case MinidumpYAML::Stream::StreamKind::RawContent
:
408 return streamValidate(cast
<RawContentStream
>(*S
));
409 case MinidumpYAML::Stream::StreamKind::MemoryInfoList
:
410 case MinidumpYAML::Stream::StreamKind::MemoryList
:
411 case MinidumpYAML::Stream::StreamKind::ModuleList
:
412 case MinidumpYAML::Stream::StreamKind::SystemInfo
:
413 case MinidumpYAML::Stream::StreamKind::TextContent
:
414 case MinidumpYAML::Stream::StreamKind::ThreadList
:
417 llvm_unreachable("Fully covered switch above!");
420 void yaml::MappingTraits
<Object
>::mapping(IO
&IO
, Object
&O
) {
421 IO
.mapTag("!minidump", true);
422 mapOptionalHex(IO
, "Signature", O
.Header
.Signature
, Header::MagicSignature
);
423 mapOptionalHex(IO
, "Version", O
.Header
.Version
, Header::MagicVersion
);
424 mapOptionalHex(IO
, "Flags", O
.Header
.Flags
, 0);
425 IO
.mapRequired("Streams", O
.Streams
);
428 Expected
<std::unique_ptr
<Stream
>>
429 Stream::create(const Directory
&StreamDesc
, const object::MinidumpFile
&File
) {
430 StreamKind Kind
= getKind(StreamDesc
.Type
);
432 case StreamKind::MemoryInfoList
: {
433 if (auto ExpectedList
= File
.getMemoryInfoList())
434 return std::make_unique
<MemoryInfoListStream
>(*ExpectedList
);
436 return ExpectedList
.takeError();
438 case StreamKind::MemoryList
: {
439 auto ExpectedList
= File
.getMemoryList();
441 return ExpectedList
.takeError();
442 std::vector
<MemoryListStream::entry_type
> Ranges
;
443 for (const MemoryDescriptor
&MD
: *ExpectedList
) {
444 auto ExpectedContent
= File
.getRawData(MD
.Memory
);
445 if (!ExpectedContent
)
446 return ExpectedContent
.takeError();
447 Ranges
.push_back({MD
, *ExpectedContent
});
449 return std::make_unique
<MemoryListStream
>(std::move(Ranges
));
451 case StreamKind::ModuleList
: {
452 auto ExpectedList
= File
.getModuleList();
454 return ExpectedList
.takeError();
455 std::vector
<ModuleListStream::entry_type
> Modules
;
456 for (const Module
&M
: *ExpectedList
) {
457 auto ExpectedName
= File
.getString(M
.ModuleNameRVA
);
459 return ExpectedName
.takeError();
460 auto ExpectedCv
= File
.getRawData(M
.CvRecord
);
462 return ExpectedCv
.takeError();
463 auto ExpectedMisc
= File
.getRawData(M
.MiscRecord
);
465 return ExpectedMisc
.takeError();
467 {M
, std::move(*ExpectedName
), *ExpectedCv
, *ExpectedMisc
});
469 return std::make_unique
<ModuleListStream
>(std::move(Modules
));
471 case StreamKind::RawContent
:
472 return std::make_unique
<RawContentStream
>(StreamDesc
.Type
,
473 File
.getRawStream(StreamDesc
));
474 case StreamKind::SystemInfo
: {
475 auto ExpectedInfo
= File
.getSystemInfo();
477 return ExpectedInfo
.takeError();
478 auto ExpectedCSDVersion
= File
.getString(ExpectedInfo
->CSDVersionRVA
);
479 if (!ExpectedCSDVersion
)
480 return ExpectedInfo
.takeError();
481 return std::make_unique
<SystemInfoStream
>(*ExpectedInfo
,
482 std::move(*ExpectedCSDVersion
));
484 case StreamKind::TextContent
:
485 return std::make_unique
<TextContentStream
>(
486 StreamDesc
.Type
, toStringRef(File
.getRawStream(StreamDesc
)));
487 case StreamKind::ThreadList
: {
488 auto ExpectedList
= File
.getThreadList();
490 return ExpectedList
.takeError();
491 std::vector
<ThreadListStream::entry_type
> Threads
;
492 for (const Thread
&T
: *ExpectedList
) {
493 auto ExpectedStack
= File
.getRawData(T
.Stack
.Memory
);
495 return ExpectedStack
.takeError();
496 auto ExpectedContext
= File
.getRawData(T
.Context
);
497 if (!ExpectedContext
)
498 return ExpectedContext
.takeError();
499 Threads
.push_back({T
, *ExpectedStack
, *ExpectedContext
});
501 return std::make_unique
<ThreadListStream
>(std::move(Threads
));
504 llvm_unreachable("Unhandled stream kind!");
507 Expected
<Object
> Object::create(const object::MinidumpFile
&File
) {
508 std::vector
<std::unique_ptr
<Stream
>> Streams
;
509 Streams
.reserve(File
.streams().size());
510 for (const Directory
&StreamDesc
: File
.streams()) {
511 auto ExpectedStream
= Stream::create(StreamDesc
, File
);
513 return ExpectedStream
.takeError();
514 Streams
.push_back(std::move(*ExpectedStream
));
516 return Object(File
.header(), std::move(Streams
));