1//===- DXContainer.cpp - DXContainer object file implementation -----------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/Object/DXContainer.h"
10#include "llvm/ADT/Sequence.h"
11#include "llvm/BinaryFormat/DXContainer.h"
12#include "llvm/Object/Error.h"
13#include "llvm/Support/Compression.h"
14#include "llvm/Support/Endian.h"
15#include "llvm/Support/FormatVariadic.h"
16#include "llvm/TargetParser/SubtargetFeature.h"
17
18using namespace llvm;
19using namespace llvm::object;
20
21static Error parseFailed(const Twine &Msg) {
22 return make_error<GenericBinaryError>(Args: Msg.str(), Args: object_error::parse_failed);
23}
24
25static bool readIsOutOfBounds(StringRef Buffer, const char *Src, size_t Size) {
26 return !Src || Size > static_cast<size_t>(Buffer.end() - Src);
27}
28
29template <typename T, bool FixEndianness = true>
30static Error readStruct(StringRef Buffer, const char *Src, T &Struct) {
31 // Don't read before the beginning or past the end of the file
32 if (readIsOutOfBounds(Buffer, Src, Size: sizeof(T)))
33 return parseFailed(Msg: "Reading structure out of file bounds");
34
35 memcpy(&Struct, Src, sizeof(T));
36 // DXContainer is always little endian
37 if constexpr (FixEndianness)
38 if (sys::IsBigEndianHost)
39 Struct.swapBytes();
40 return Error::success();
41}
42
43template <typename T>
44static Error readInteger(StringRef Buffer, const char *Src, T &Val,
45 Twine Str = "structure") {
46 static_assert(std::is_integral_v<T>,
47 "Cannot call readInteger on non-integral type.");
48 // Don't read before the beginning or past the end of the file
49 if (readIsOutOfBounds(Buffer, Src, Size: sizeof(T)))
50 return parseFailed(Msg: Twine("Reading ") + Str + " out of file bounds");
51
52 // The DXContainer offset table is comprised of uint32_t values but not padded
53 // to a 64-bit boundary. So Parts may start unaligned if there is an odd
54 // number of parts and part data itself is not required to be padded.
55 if (reinterpret_cast<uintptr_t>(Src) % alignof(T) != 0)
56 memcpy(dest: reinterpret_cast<char *>(&Val), src: Src, n: sizeof(T));
57 else
58 Val = *reinterpret_cast<const T *>(Src);
59 // DXContainer is always little endian
60 if (sys::IsBigEndianHost)
61 sys::swapByteOrder(Val);
62 return Error::success();
63}
64
65/// Read a null-terminated string at the position Src from Buffer, with maximum
66/// byte size of MaxSize (including the null-terminator). Advance Src by the
67/// number of bytes read.
68static Error readString(StringRef Buffer, const char *&Src, size_t MaxSize,
69 StringRef &Val, Twine Desc) {
70 if (readIsOutOfBounds(Buffer, Src, Size: MaxSize))
71 return parseFailed(Msg: Desc + " is out of file bounds");
72
73 // Ensure that the null-terminator is somewhere within MaxSize bytes.
74 Buffer = Buffer.substr(Start: Src - Buffer.data(), N: MaxSize);
75 size_t Length = Buffer.find(C: '\0');
76 if (Length == Buffer.npos)
77 return parseFailed(Msg: Desc + " does not end with null-terminator");
78
79 Val = StringRef(Buffer.data(), Length);
80 Src += Length + 1;
81 return Error::success();
82}
83
84DXContainer::DXContainer(MemoryBufferRef O) : Data(O) {}
85
86Error DXContainer::parseHeader() {
87 if (Error Err = readStruct(Buffer: Data.getBuffer(), Src: Data.getBuffer().data(), Struct&: Header))
88 return Err;
89 if (StringRef(reinterpret_cast<char *>(Header.Magic), 4) != "DXBC")
90 return parseFailed(Msg: "Missing DXBC header magic");
91 return Error::success();
92}
93
94Error DXContainer::parseDXILHeader(dxbc::PartType PT, StringRef Part) {
95 bool IsDebug = dxbc::isDebugProgramPart(PT);
96 std::optional<DXILData> &DXIL = IsDebug ? this->DebugDXIL : this->DXIL;
97
98 if (DXIL)
99 return parseFailed(Msg: formatv(Fmt: "more than one {0} part is present in the file",
100 Vals: dxbc::getProgramPartName(IsDebug)));
101 const char *Current = Part.begin();
102 dxbc::ProgramHeader Header;
103 if (Error Err = readStruct(Buffer: Part, Src: Current, Struct&: Header))
104 return Err;
105 Current += offsetof(dxbc::ProgramHeader, Bitcode) + Header.Bitcode.Offset;
106 DXIL.emplace(args: std::make_pair(x&: Header, y&: Current));
107 return Error::success();
108}
109
110Error DXContainer::parseDebugName(StringRef Part) {
111 if (DebugName)
112 return parseFailed(Msg: "more than one ILDN part is present in the file");
113 const char *Current = Part.begin();
114 dxbc::DebugNameHeader Header;
115 if (Error Err = readStruct(Buffer: Part, Src: Current, Struct&: Header))
116 return Err;
117 Current += sizeof(Header);
118
119 StringRef Name;
120 if (Error Err = readString(Buffer: Part, Src&: Current, MaxSize: Header.NameLength + 1, Val&: Name,
121 Desc: "debug file name"))
122 return Err;
123 if (Name.size() != Header.NameLength)
124 return parseFailed(Msg: "debug file name length mismatch");
125 DebugName.emplace(args&: Header, args: Name.data());
126
127 return Error::success();
128}
129
130Error DXContainer::parsePrivateData(StringRef Part) {
131 if (PrivateData)
132 return parseFailed(Msg: "more than one PRIV part is present in the file");
133 PrivateData.emplace(args&: Part);
134 return Error::success();
135}
136
137Error DXContainer::parseShaderFeatureFlags(StringRef Part) {
138 if (ShaderFeatureFlags)
139 return parseFailed(Msg: "More than one SFI0 part is present in the file");
140 uint64_t FlagValue = 0;
141 if (Error Err = readInteger(Buffer: Part, Src: Part.begin(), Val&: FlagValue))
142 return Err;
143 ShaderFeatureFlags = FlagValue;
144 return Error::success();
145}
146
147Error DXContainer::parseHash(StringRef Part) {
148 if (Hash)
149 return parseFailed(Msg: "More than one HASH part is present in the file");
150 dxbc::ShaderHash ReadHash;
151 if (Error Err = readStruct(Buffer: Part, Src: Part.begin(), Struct&: ReadHash))
152 return Err;
153 Hash = ReadHash;
154 return Error::success();
155}
156
157Error DXContainer::parseRootSignature(StringRef Part) {
158 if (RootSignature)
159 return parseFailed(Msg: "More than one RTS0 part is present in the file");
160 RootSignature = DirectX::RootSignature(Part);
161 if (Error Err = RootSignature->parse())
162 return Err;
163 return Error::success();
164}
165
166Error DXContainer::parsePSVInfo(StringRef Part) {
167 if (PSVInfo)
168 return parseFailed(Msg: "More than one PSV0 part is present in the file");
169 PSVInfo = DirectX::PSVRuntimeInfo(Part);
170 // Parsing the PSVRuntime info occurs late because we need to read data from
171 // other parts first.
172 return Error::success();
173}
174
175Error DirectX::Signature::initialize(StringRef Part) {
176 dxbc::ProgramSignatureHeader SigHeader;
177 if (Error Err = readStruct(Buffer: Part, Src: Part.begin(), Struct&: SigHeader))
178 return Err;
179 size_t Size = sizeof(dxbc::ProgramSignatureElement) * SigHeader.ParamCount;
180
181 if (Part.size() < Size + SigHeader.FirstParamOffset)
182 return parseFailed(Msg: "Signature parameters extend beyond the part boundary");
183
184 Parameters.Data = Part.substr(Start: SigHeader.FirstParamOffset, N: Size);
185
186 StringTableOffset = SigHeader.FirstParamOffset + static_cast<uint32_t>(Size);
187 StringTable = Part.substr(Start: SigHeader.FirstParamOffset + Size);
188
189 for (const auto &Param : Parameters) {
190 if (Param.NameOffset < StringTableOffset)
191 return parseFailed(Msg: "Invalid parameter name offset: name starts before "
192 "the first name offset");
193 if (Param.NameOffset - StringTableOffset > StringTable.size())
194 return parseFailed(Msg: "Invalid parameter name offset: name starts after the "
195 "end of the part data");
196 }
197 return Error::success();
198}
199
200Error DXContainer::parseCompilerVersionInfo(StringRef Part) {
201 if (VersionInfo)
202 return parseFailed(Msg: "more than one VERS part is present in the file");
203 const char *Current = Part.begin();
204 dxbc::CompilerVersionHeader Header;
205 if (Error Err = readStruct(Buffer: Part, Src: Current, Struct&: Header))
206 return Err;
207 Current += sizeof(Header);
208
209 if (!dxbc::isValidCompilerVersionFlags(V: to_underlying(E: Header.Flags)))
210 return parseFailed(Msg: "Incorrect shader compiler version flags combination");
211
212 StringRef CommitSha;
213 const char *Prev = Current;
214 if (Error Err = readString(Buffer: Part, Src&: Current, MaxSize: Header.ContentSizeInBytes,
215 Val&: CommitSha, Desc: "CommitSha"))
216 return Err;
217 StringRef CustomVersionString;
218 if (Error Err = readString(Buffer: Part, Src&: Current,
219 MaxSize: Header.ContentSizeInBytes - (Current - Prev),
220 Val&: CustomVersionString, Desc: "CustomVersionString"))
221 return Err;
222
223 VersionInfo.emplace();
224 VersionInfo->Parameters = Header;
225 VersionInfo->CommitSha = CommitSha;
226 VersionInfo->CustomVersionString = CustomVersionString;
227 return Error::success();
228}
229
230static Expected<size_t> parseNames(StringRef Section,
231 mcdxbc::SourceInfo::SourceNames &Names) {
232 const char *Current = Section.begin();
233 dxbc::SourceInfo::Names::HeaderOnDisk HeaderOnDisk;
234 if (Error Err = readStruct<decltype(HeaderOnDisk), false>(Buffer: Section, Src: Current,
235 Struct&: HeaderOnDisk))
236 return Err;
237 Names.Parameters = HeaderOnDisk;
238 Current += sizeof(HeaderOnDisk);
239
240 if (Names.Parameters.Flags)
241 return parseFailed(Msg: "SRCI Names header flags must be zero");
242 if (Current + Names.Parameters.EntriesSizeInBytes > Section.end())
243 return parseFailed(
244 Msg: "SRCI Names section content ends beyond the section boundary");
245
246 Names.Entries.reserve(N: Names.Parameters.Count);
247 for (size_t I : llvm::seq(Size: Names.Parameters.Count)) {
248 auto &Entry = Names.Entries.emplace_back();
249 if (Error Err = readStruct(Buffer: Section, Src: Current, Struct&: Entry.Parameters))
250 return Err;
251
252 const char *Next = Current + Entry.Parameters.AlignedSizeInBytes;
253 if (Next > Section.end())
254 return parseFailed(
255 Msg: formatv(Fmt: "SRCI Names entry {0} ends beyond the section boundary", Vals&: I));
256 if (Entry.Parameters.Flags)
257 return parseFailed(Msg: formatv(Fmt: "SRCI Names entry {0} flags must be zero", Vals&: I));
258
259 const char *FileName = Current + sizeof(Entry.Parameters);
260 if (Error Err = readString(
261 Buffer: Section, Src&: FileName, MaxSize: Entry.Parameters.NameSizeInBytes, Val&: Entry.FileName,
262 Desc: Twine("SRCI Names entry ") + Twine(I) + Twine(" file name")))
263 return Err;
264 if (FileName > Next)
265 return parseFailed(Msg: formatv(
266 Fmt: "SRCI Names entry {0} file name ends beyond the entry boundary", Vals&: I));
267 Current = Next;
268 }
269
270 return Current - Section.begin();
271}
272
273static Expected<size_t>
274parseUncompressedContentsEntries(StringRef Entries,
275 mcdxbc::SourceInfo::SourceContents &Contents) {
276 const char *Current = Entries.begin();
277
278 Contents.Entries.reserve(N: Contents.Parameters.Count);
279 for (size_t I : llvm::seq(Size: Contents.Parameters.Count)) {
280 auto &Entry = Contents.Entries.emplace_back();
281 if (Error Err = readStruct(Buffer: Entries, Src: Current, Struct&: Entry.Parameters))
282 return Err;
283
284 const char *Next = Current + Entry.Parameters.AlignedSizeInBytes;
285 if (Next > Entries.end())
286 return parseFailed(Msg: formatv(
287 Fmt: "SRCI Contents entry {0} ends beyond the section boundary", Vals&: I));
288 if (Entry.Parameters.Flags)
289 return parseFailed(
290 Msg: formatv(Fmt: "SRCI Contents entry {0} flags must be zero", Vals&: I));
291
292 const char *FileContentPtr = Current + sizeof(Entry.Parameters);
293 const char *FileContentEndPtr = FileContentPtr;
294 StringRef FileContent;
295 if (Error Err = readString(Buffer: Entries, Src&: FileContentEndPtr,
296 MaxSize: Entry.Parameters.ContentSizeInBytes, Val&: FileContent,
297 Desc: Twine("SRCI Contents entry ") + Twine(I) +
298 Twine(" file content")))
299 return Err;
300 if (FileContentEndPtr - FileContentPtr !=
301 Entry.Parameters.ContentSizeInBytes)
302 return parseFailed(
303 Msg: formatv(Fmt: "file size from header ({0} bytes) does not match content "
304 "size in SRCI Contents entry {1} ({2} bytes)",
305 Vals: FileContentEndPtr - FileContentPtr, Vals&: I,
306 Vals&: Entry.Parameters.ContentSizeInBytes));
307 if (FileContentEndPtr > Next)
308 return parseFailed(Msg: formatv(
309 Fmt: "SRCI Contents entry {0} file content ends beyond the entry boundary",
310 Vals&: I));
311
312 Entry.FileContent = std::string(FileContent.data(),
313 Entry.Parameters.ContentSizeInBytes - 1);
314
315 Current = Next;
316 }
317
318 return Current - Entries.begin();
319}
320
321static Expected<size_t>
322parseContentsEntries(StringRef Entries,
323 mcdxbc::SourceInfo::SourceContents &Contents) {
324 using dxbc::SourceInfo::Contents::CompressionType;
325
326 if (!dxbc::SourceInfo::Contents::isValidCompressionType(
327 V: to_underlying(E: Contents.Parameters.Type)))
328 return parseFailed(Msg: "SRCI Contents section uses unknown compression type");
329
330 SmallVector<uint8_t> UncompressedEntriesData;
331 switch (Contents.Parameters.Type) {
332 case CompressionType::None: {
333 if (Contents.Parameters.EntriesSizeInBytes !=
334 Contents.Parameters.UncompressedEntriesSizeInBytes)
335 return parseFailed(Msg: formatv(
336 Fmt: "SRCI Contents is not compressed, but compressed size ({0} bytes) "
337 "doesn't match uncompressed size ({1} bytes) in section header",
338 Vals&: Contents.Parameters.EntriesSizeInBytes,
339 Vals&: Contents.Parameters.UncompressedEntriesSizeInBytes));
340
341 return parseUncompressedContentsEntries(Entries, Contents);
342 }
343 case CompressionType::Zlib: {
344 if (!compression::zlib::isAvailable())
345 return parseFailed(Msg: formatv(
346 Fmt: "SRCI Contents is compressed with Zlib, but {0}",
347 Vals: compression::getReasonIfUnsupported(F: compression::Format::Zlib)));
348 if (Error Err = compression::zlib::decompress(
349 Input: ArrayRef(reinterpret_cast<const uint8_t *>(Entries.begin()),
350 Contents.Parameters.EntriesSizeInBytes),
351 Output&: UncompressedEntriesData,
352 UncompressedSize: Contents.Parameters.UncompressedEntriesSizeInBytes))
353 return Err;
354
355 if (UncompressedEntriesData.size() !=
356 Contents.Parameters.UncompressedEntriesSizeInBytes)
357 return parseFailed(Msg: "SRCI Contents uncompressed size from header does not "
358 "match with actual content size");
359
360 if (Error Err = parseUncompressedContentsEntries(
361 Entries: StringRef(reinterpret_cast<const char *>(
362 UncompressedEntriesData.data()),
363 UncompressedEntriesData.size()),
364 Contents)
365 .takeError())
366 return Err;
367
368 return Contents.Parameters.EntriesSizeInBytes;
369 }
370 }
371 llvm_unreachable("unhandled compression type");
372}
373
374static Expected<size_t>
375parseContents(StringRef Section, mcdxbc::SourceInfo::SourceContents &Contents) {
376 const char *Current = Section.begin();
377 if (Error Err = readStruct(Buffer: Section, Src: Current, Struct&: Contents.Parameters))
378 return Err;
379 size_t BytesRead = sizeof(Contents.Parameters);
380 Current += BytesRead;
381
382 if (Section.begin() + Contents.Parameters.EntriesSizeInBytes > Section.end())
383 return parseFailed(
384 Msg: formatv(Fmt: "SRCI Contents section ends beyond the section boundary"));
385 if (Contents.Parameters.Flags)
386 return parseFailed(Msg: "SRCI Contents header flags must be zero");
387 if (Current + Contents.Parameters.EntriesSizeInBytes > Section.end())
388 return parseFailed(
389 Msg: formatv(Fmt: "SRCI Contents entries end beyond the section boundary"));
390
391 size_t BodyBytesRead = 0;
392 if (Error Err = parseContentsEntries(Entries: Section.substr(Start: BytesRead), Contents)
393 .moveInto(Value&: BodyBytesRead))
394 return Err;
395 return BytesRead + BodyBytesRead;
396}
397
398static Expected<size_t> parseArgs(StringRef Section,
399 mcdxbc::SourceInfo::ProgramArgs &Args) {
400 const char *Current = Section.begin();
401 if (Error Err = readStruct(Buffer: Section, Src: Current, Struct&: Args.Parameters))
402 return Err;
403 Current += sizeof(Args.Parameters);
404
405 if (Args.Parameters.Flags)
406 return parseFailed(Msg: "SRCI Args header flags must be zero");
407 if (Current + Args.Parameters.SizeInBytes > Section.end())
408 return parseFailed(
409 Msg: formatv(Fmt: "SRCI Args entries end beyond the section boundary", Vals&: Section));
410
411 Args.Args.reserve(N: Args.Parameters.Count);
412 for (size_t I : llvm::seq(Size: Args.Parameters.Count)) {
413 auto &Entry = Args.Args.emplace_back();
414 if (Error Err =
415 readString(Buffer: Section, Src&: Current, MaxSize: Section.end() - Current, Val&: Entry.first,
416 Desc: Twine("SRCI Args entry ") + Twine(I) + Twine(" name")))
417 return Err;
418 if (Error Err =
419 readString(Buffer: Section, Src&: Current, MaxSize: Section.end() - Current, Val&: Entry.second,
420 Desc: Twine("SRCI Args entry ") + Twine(I) + Twine(" value")))
421 return Err;
422 }
423
424 return Current - Section.begin();
425}
426
427static Expected<size_t>
428parseSourceInfoSection(const dxbc::SourceInfo::SectionHeader &Header,
429 StringRef SectionData, mcdxbc::SourceInfo &SourceInfo) {
430 using dxbc::SourceInfo::SectionType;
431 switch (Header.Type) {
432 case SectionType::SourceNames: {
433 SourceInfo.Names.GenericHeader = Header;
434 return parseNames(Section: SectionData, Names&: SourceInfo.Names);
435 }
436 case SectionType::SourceContents: {
437 SourceInfo.Contents.GenericHeader = Header;
438 return parseContents(Section: SectionData, Contents&: SourceInfo.Contents);
439 }
440 case SectionType::Args: {
441 SourceInfo.Args.GenericHeader = Header;
442 return parseArgs(Section: SectionData, Args&: SourceInfo.Args);
443 }
444 }
445
446 llvm_unreachable("Unknown source info section type");
447}
448
449Error DXContainer::parseSourceInfo(StringRef Part) {
450 using dxbc::SourceInfo::SectionType;
451
452 if (SourceInfo)
453 return parseFailed(Msg: "more than one SRCI part is present in the file");
454 SourceInfo.emplace();
455
456 const char *Current = Part.begin();
457 if (Error Err = readStruct(Buffer: Part, Src: Current, Struct&: SourceInfo->Parameters))
458 return Err;
459 Current += sizeof(SourceInfo->Parameters);
460
461 if (SourceInfo->Parameters.AlignedSizeInBytes > Part.size())
462 return parseFailed(Msg: formatv(Fmt: "size field in SRCI header ({0} bytes) is "
463 "greater than SRCI part size ({1} bytes)",
464 Vals&: SourceInfo->Parameters.AlignedSizeInBytes,
465 Vals: Part.size()));
466 if (SourceInfo->Parameters.Flags)
467 return parseFailed(Msg: "SRCI header flags must be zero");
468 if (SourceInfo->Parameters.SectionCount != 3)
469 return parseFailed(Msg: "SRCI part must contain 3 sections");
470
471 bool IsSectionPresent[to_underlying(
472 E: SectionType::LLVM_BITMASK_LARGEST_ENUMERATOR) +
473 1];
474 std::fill(first: IsSectionPresent,
475 last: IsSectionPresent +
476 sizeof(IsSectionPresent) / sizeof(*IsSectionPresent),
477 value: false);
478 for (uint32_t Section = 0; Section < SourceInfo->Parameters.SectionCount;
479 ++Section) {
480 dxbc::SourceInfo::SectionHeader SectionHeader;
481 if (Error Err = readStruct(Buffer: Part, Src: Current, Struct&: SectionHeader))
482 return Err;
483 size_t BytesRead = sizeof(SectionHeader);
484
485 StringRef SectionName =
486 dxbc::SourceInfo::getSectionName(Type: SectionHeader.Type);
487 if (Current + SectionHeader.AlignedSizeInBytes > Part.end())
488 return parseFailed(
489 Msg: formatv(Fmt: "SRCI section {0} (#{1}) extends beyond the part boundary",
490 Vals&: SectionName, Vals&: Section));
491 if (SectionHeader.Flags)
492 return parseFailed(
493 Msg: formatv(Fmt: "SRCI section {0} (#{1}) header flags must be zero",
494 Vals&: SectionName, Vals&: Section));
495
496 size_t SectionTypeIdx = to_underlying(E: SectionHeader.Type);
497 if (!dxbc::SourceInfo::isValidSectionType(V: SectionTypeIdx))
498 return parseFailed(
499 Msg: formatv(Fmt: "unknown SRCI section type {0}", Vals&: SectionTypeIdx));
500 if (IsSectionPresent[SectionTypeIdx])
501 return parseFailed(Msg: formatv(
502 Fmt: "more than one {0} section is present in SRCI part", Vals&: SectionName));
503 IsSectionPresent[SectionTypeIdx] = true;
504
505 size_t SectionBytesRead = 0;
506 if (Error Err = parseSourceInfoSection(
507 Header: SectionHeader,
508 SectionData: Part.substr(Start: Current + BytesRead - Part.begin(),
509 N: SectionHeader.AlignedSizeInBytes),
510 SourceInfo&: *SourceInfo)
511 .moveInto(Value&: SectionBytesRead))
512 return Err;
513 BytesRead += SectionBytesRead;
514 BytesRead = alignTo<dxbc::DXCONTAINER_STRUCT_ALIGNMENT>(Value: BytesRead);
515
516 if (BytesRead != SectionHeader.AlignedSizeInBytes)
517 return parseFailed(Msg: formatv(
518 Fmt: "size of SRCI section {0} (#{1} - {2} bytes) does not match size "
519 "specified in generic header ({3} bytes)",
520 Vals&: SectionName, Vals&: Section, Vals&: BytesRead, Vals&: SectionHeader.AlignedSizeInBytes));
521 Current += SectionHeader.AlignedSizeInBytes;
522 }
523
524 if (SourceInfo->Contents.Parameters.Count !=
525 SourceInfo->Names.Parameters.Count)
526 return parseFailed(
527 Msg: "SRCI Contents entries count is not equal to SRCI Names entries count");
528
529 for (size_t I : llvm::seq(Size: SourceInfo->Contents.Parameters.Count))
530 if (SourceInfo->Contents.Entries[I].Parameters.ContentSizeInBytes !=
531 SourceInfo->Names.Entries[I].Parameters.ContentSizeInBytes)
532 return parseFailed(Msg: formatv(
533 Fmt: "content size for entry {0} ({1} bytes) in SRCI Contents section "
534 "does not match with size in SRCI Names section ({2} bytes)",
535 Vals&: I, Vals&: SourceInfo->Contents.Entries[I].Parameters.ContentSizeInBytes,
536 Vals&: SourceInfo->Names.Entries[I].Parameters.ContentSizeInBytes));
537
538 return Error::success();
539}
540
541Error DXContainer::parsePartOffsets() {
542 uint32_t LastOffset =
543 sizeof(dxbc::Header) + (Header.PartCount * sizeof(uint32_t));
544 const char *Current = Data.getBuffer().data() + sizeof(dxbc::Header);
545 for (uint32_t Part = 0; Part < Header.PartCount; ++Part) {
546 uint32_t PartOffset;
547 if (Error Err = readInteger(Buffer: Data.getBuffer(), Src: Current, Val&: PartOffset))
548 return Err;
549 if (PartOffset < LastOffset)
550 return parseFailed(
551 Msg: formatv(
552 Fmt: "Part offset for part {0} begins before the previous part ends",
553 Vals&: Part)
554 .str());
555 Current += sizeof(uint32_t);
556 if (PartOffset >= Data.getBufferSize())
557 return parseFailed(Msg: "Part offset points beyond boundary of the file");
558 // To prevent overflow when reading the part name, we subtract the part name
559 // size from the buffer size, rather than adding to the offset. Since the
560 // file header is larger than the part header we can't reach this code
561 // unless the buffer is at least as large as a part header, so this
562 // subtraction can't underflow.
563 if (PartOffset >= Data.getBufferSize() - sizeof(dxbc::PartHeader::Name))
564 return parseFailed(Msg: "File not large enough to read part name");
565 PartOffsets.push_back(Elt: PartOffset);
566
567 dxbc::PartType PT =
568 dxbc::parsePartType(S: Data.getBuffer().substr(Start: PartOffset, N: 4));
569 uint32_t PartDataStart = PartOffset + sizeof(dxbc::PartHeader);
570 uint32_t PartSize;
571 if (Error Err = readInteger(Buffer: Data.getBuffer(),
572 Src: Data.getBufferStart() + PartOffset + 4,
573 Val&: PartSize, Str: "part size"))
574 return Err;
575 StringRef PartData = Data.getBuffer().substr(Start: PartDataStart, N: PartSize);
576 LastOffset = PartOffset + PartSize;
577 switch (PT) {
578 case dxbc::PartType::DXIL:
579 case dxbc::PartType::ILDB:
580 if (Error Err = parseDXILHeader(PT, Part: PartData))
581 return Err;
582 break;
583 case dxbc::PartType::ILDN:
584 if (Error Err = parseDebugName(Part: PartData))
585 return Err;
586 break;
587 case dxbc::PartType::PRIV:
588 if (Error Err = parsePrivateData(Part: PartData))
589 return Err;
590 break;
591 case dxbc::PartType::SFI0:
592 if (Error Err = parseShaderFeatureFlags(Part: PartData))
593 return Err;
594 break;
595 case dxbc::PartType::HASH:
596 if (Error Err = parseHash(Part: PartData))
597 return Err;
598 break;
599 case dxbc::PartType::PSV0:
600 if (Error Err = parsePSVInfo(Part: PartData))
601 return Err;
602 break;
603 case dxbc::PartType::ISG1:
604 if (Error Err = InputSignature.initialize(Part: PartData))
605 return Err;
606 break;
607 case dxbc::PartType::OSG1:
608 if (Error Err = OutputSignature.initialize(Part: PartData))
609 return Err;
610 break;
611 case dxbc::PartType::PSG1:
612 if (Error Err = PatchConstantSignature.initialize(Part: PartData))
613 return Err;
614 break;
615 case dxbc::PartType::Unknown:
616 break;
617 case dxbc::PartType::RTS0:
618 if (Error Err = parseRootSignature(Part: PartData))
619 return Err;
620 break;
621 case dxbc::PartType::SRCI:
622 if (Error Err = parseSourceInfo(Part: PartData))
623 return Err;
624 break;
625 case dxbc::PartType::VERS:
626 if (Error Err = parseCompilerVersionInfo(Part: PartData))
627 return Err;
628 break;
629 }
630 }
631
632 if (DXIL && DebugDXIL &&
633 DXIL->first.ShaderKind != DebugDXIL->first.ShaderKind)
634 return parseFailed(
635 Msg: "ILDB part shader kind does not match DXIL part shader kind");
636
637 // Fully parsing the PSVInfo requires knowing the shader kind which we read
638 // out of the program header in the DXIL part.
639 if (PSVInfo) {
640 std::optional<uint16_t> ShaderKind = getShaderKind();
641 if (!ShaderKind)
642 return parseFailed(Msg: "cannot fully parse pipeline state validation "
643 "information without DXIL or ILDB part");
644 if (Error Err = PSVInfo->parse(ShaderKind: *ShaderKind))
645 return Err;
646 }
647 return Error::success();
648}
649
650Expected<DXContainer> DXContainer::create(MemoryBufferRef Object) {
651 DXContainer Container(Object);
652 if (Error Err = Container.parseHeader())
653 return std::move(Err);
654 if (Error Err = Container.parsePartOffsets())
655 return std::move(Err);
656 return Container;
657}
658
659void DXContainer::PartIterator::updateIteratorImpl(const uint32_t Offset) {
660 StringRef Buffer = Container.Data.getBuffer();
661 const char *Current = Buffer.data() + Offset;
662 // Offsets are validated during parsing, so all offsets in the container are
663 // valid and contain enough readable data to read a header.
664 cantFail(Err: readStruct(Buffer, Src: Current, Struct&: IteratorState.Part));
665 IteratorState.Data =
666 StringRef(Current + sizeof(dxbc::PartHeader), IteratorState.Part.Size);
667 IteratorState.Offset = Offset;
668}
669
670Error DirectX::RootSignature::parse() {
671 const char *Current = PartData.begin();
672
673 // Root Signature headers expects 6 integers to be present.
674 if (PartData.size() < 6 * sizeof(uint32_t))
675 return parseFailed(
676 Msg: "Invalid root signature, insufficient space for header.");
677
678 Version = support::endian::read<uint32_t, llvm::endianness::little>(P: Current);
679 Current += sizeof(uint32_t);
680
681 NumParameters =
682 support::endian::read<uint32_t, llvm::endianness::little>(P: Current);
683 Current += sizeof(uint32_t);
684
685 RootParametersOffset =
686 support::endian::read<uint32_t, llvm::endianness::little>(P: Current);
687 Current += sizeof(uint32_t);
688
689 NumStaticSamplers =
690 support::endian::read<uint32_t, llvm::endianness::little>(P: Current);
691 Current += sizeof(uint32_t);
692
693 StaticSamplersOffset =
694 support::endian::read<uint32_t, llvm::endianness::little>(P: Current);
695 Current += sizeof(uint32_t);
696
697 Flags = support::endian::read<uint32_t, llvm::endianness::little>(P: Current);
698 Current += sizeof(uint32_t);
699
700 ParametersHeaders.Data = PartData.substr(
701 Start: RootParametersOffset,
702 N: NumParameters * sizeof(dxbc::RTS0::v1::RootParameterHeader));
703
704 StaticSamplers.Stride = (Version <= 2)
705 ? sizeof(dxbc::RTS0::v1::StaticSampler)
706 : sizeof(dxbc::RTS0::v3::StaticSampler);
707
708 StaticSamplers.Data = PartData.substr(Start: StaticSamplersOffset,
709 N: static_cast<size_t>(NumStaticSamplers) *
710 StaticSamplers.Stride);
711
712 return Error::success();
713}
714
715Error DirectX::PSVRuntimeInfo::parse(uint16_t ShaderKind) {
716 Triple::EnvironmentType ShaderStage = dxbc::getShaderStage(Kind: ShaderKind);
717
718 const char *Current = Data.begin();
719 if (Error Err = readInteger(Buffer: Data, Src: Current, Val&: Size))
720 return Err;
721 Current += sizeof(uint32_t);
722
723 StringRef PSVInfoData = Data.substr(Start: sizeof(uint32_t), N: Size);
724
725 if (PSVInfoData.size() < Size)
726 return parseFailed(
727 Msg: "Pipeline state data extends beyond the bounds of the part");
728
729 using namespace dxbc::PSV;
730
731 const uint32_t PSVVersion = getVersion();
732
733 // Detect the PSVVersion by looking at the size field.
734 if (PSVVersion == 3) {
735 v3::RuntimeInfo Info;
736 if (Error Err = readStruct(Buffer: PSVInfoData, Src: Current, Struct&: Info))
737 return Err;
738 if (sys::IsBigEndianHost)
739 Info.swapBytes(Stage: ShaderStage);
740 BasicInfo = Info;
741 } else if (PSVVersion == 2) {
742 v2::RuntimeInfo Info;
743 if (Error Err = readStruct(Buffer: PSVInfoData, Src: Current, Struct&: Info))
744 return Err;
745 if (sys::IsBigEndianHost)
746 Info.swapBytes(Stage: ShaderStage);
747 BasicInfo = Info;
748 } else if (PSVVersion == 1) {
749 v1::RuntimeInfo Info;
750 if (Error Err = readStruct(Buffer: PSVInfoData, Src: Current, Struct&: Info))
751 return Err;
752 if (sys::IsBigEndianHost)
753 Info.swapBytes(Stage: ShaderStage);
754 BasicInfo = Info;
755 } else if (PSVVersion == 0) {
756 v0::RuntimeInfo Info;
757 if (Error Err = readStruct(Buffer: PSVInfoData, Src: Current, Struct&: Info))
758 return Err;
759 if (sys::IsBigEndianHost)
760 Info.swapBytes(Stage: ShaderStage);
761 BasicInfo = Info;
762 } else
763 return parseFailed(
764 Msg: "Cannot read PSV Runtime Info, unsupported PSV version.");
765
766 Current += Size;
767
768 uint32_t ResourceCount = 0;
769 if (Error Err = readInteger(Buffer: Data, Src: Current, Val&: ResourceCount))
770 return Err;
771 Current += sizeof(uint32_t);
772
773 if (ResourceCount > 0) {
774 if (Error Err = readInteger(Buffer: Data, Src: Current, Val&: Resources.Stride))
775 return Err;
776 Current += sizeof(uint32_t);
777
778 size_t BindingDataSize = Resources.Stride * ResourceCount;
779 Resources.Data = Data.substr(Start: Current - Data.begin(), N: BindingDataSize);
780
781 if (Resources.Data.size() < BindingDataSize)
782 return parseFailed(
783 Msg: "Resource binding data extends beyond the bounds of the part");
784
785 Current += BindingDataSize;
786 } else
787 Resources.Stride = sizeof(v2::ResourceBindInfo);
788
789 // PSV version 0 ends after the resource bindings.
790 if (PSVVersion == 0)
791 return Error::success();
792
793 // String table starts at a 4-byte offset.
794 Current = reinterpret_cast<const char *>(
795 alignTo<dxbc::DXCONTAINER_STRUCT_ALIGNMENT>(
796 Value: reinterpret_cast<uintptr_t>(Current)));
797
798 uint32_t StringTableSize = 0;
799 if (Error Err = readInteger(Buffer: Data, Src: Current, Val&: StringTableSize))
800 return Err;
801 if (StringTableSize % 4 != 0)
802 return parseFailed(Msg: "String table misaligned");
803 Current += sizeof(uint32_t);
804 StringTable = StringRef(Current, StringTableSize);
805
806 Current += StringTableSize;
807
808 uint32_t SemanticIndexTableSize = 0;
809 if (Error Err = readInteger(Buffer: Data, Src: Current, Val&: SemanticIndexTableSize))
810 return Err;
811 Current += sizeof(uint32_t);
812
813 SemanticIndexTable.reserve(N: SemanticIndexTableSize);
814 for (uint32_t I = 0; I < SemanticIndexTableSize; ++I) {
815 uint32_t Index = 0;
816 if (Error Err = readInteger(Buffer: Data, Src: Current, Val&: Index))
817 return Err;
818 Current += sizeof(uint32_t);
819 SemanticIndexTable.push_back(Elt: Index);
820 }
821
822 uint8_t InputCount = getSigInputCount();
823 uint8_t OutputCount = getSigOutputCount();
824 uint8_t PatchOrPrimCount = getSigPatchOrPrimCount();
825
826 uint32_t ElementCount = InputCount + OutputCount + PatchOrPrimCount;
827
828 if (ElementCount > 0) {
829 if (Error Err = readInteger(Buffer: Data, Src: Current, Val&: SigInputElements.Stride))
830 return Err;
831 Current += sizeof(uint32_t);
832 // Assign the stride to all the arrays.
833 SigOutputElements.Stride = SigPatchOrPrimElements.Stride =
834 SigInputElements.Stride;
835
836 if (Data.end() - Current <
837 (ptrdiff_t)(ElementCount * SigInputElements.Stride))
838 return parseFailed(
839 Msg: "Signature elements extend beyond the size of the part");
840
841 size_t InputSize = SigInputElements.Stride * InputCount;
842 SigInputElements.Data = Data.substr(Start: Current - Data.begin(), N: InputSize);
843 Current += InputSize;
844
845 size_t OutputSize = SigOutputElements.Stride * OutputCount;
846 SigOutputElements.Data = Data.substr(Start: Current - Data.begin(), N: OutputSize);
847 Current += OutputSize;
848
849 size_t PSize = SigPatchOrPrimElements.Stride * PatchOrPrimCount;
850 SigPatchOrPrimElements.Data = Data.substr(Start: Current - Data.begin(), N: PSize);
851 Current += PSize;
852 }
853
854 ArrayRef<uint8_t> OutputVectorCounts = getOutputVectorCounts();
855 uint8_t PatchConstOrPrimVectorCount = getPatchConstOrPrimVectorCount();
856 uint8_t InputVectorCount = getInputVectorCount();
857
858 auto maskDwordSize = [](uint8_t Vector) {
859 return (static_cast<uint32_t>(Vector) + 7) >> 3;
860 };
861
862 auto mapTableSize = [maskDwordSize](uint8_t X, uint8_t Y) {
863 return maskDwordSize(Y) * X * 4;
864 };
865
866 if (usesViewID()) {
867 for (uint32_t I = 0; I < OutputVectorCounts.size(); ++I) {
868 // The vector mask is one bit per component and 4 components per vector.
869 // We can compute the number of dwords required by rounding up to the next
870 // multiple of 8.
871 uint32_t NumDwords =
872 maskDwordSize(static_cast<uint32_t>(OutputVectorCounts[I]));
873 size_t NumBytes = NumDwords * sizeof(uint32_t);
874 OutputVectorMasks[I].Data = Data.substr(Start: Current - Data.begin(), N: NumBytes);
875 Current += NumBytes;
876 }
877
878 if (ShaderStage == Triple::Hull && PatchConstOrPrimVectorCount > 0) {
879 uint32_t NumDwords = maskDwordSize(PatchConstOrPrimVectorCount);
880 size_t NumBytes = NumDwords * sizeof(uint32_t);
881 PatchOrPrimMasks.Data = Data.substr(Start: Current - Data.begin(), N: NumBytes);
882 Current += NumBytes;
883 }
884 }
885
886 // Input/Output mapping table
887 for (uint32_t I = 0; I < OutputVectorCounts.size(); ++I) {
888 if (InputVectorCount == 0 || OutputVectorCounts[I] == 0)
889 continue;
890 uint32_t NumDwords = mapTableSize(InputVectorCount, OutputVectorCounts[I]);
891 size_t NumBytes = NumDwords * sizeof(uint32_t);
892 InputOutputMap[I].Data = Data.substr(Start: Current - Data.begin(), N: NumBytes);
893 Current += NumBytes;
894 }
895
896 // Hull shader: Input/Patch mapping table
897 if (ShaderStage == Triple::Hull && PatchConstOrPrimVectorCount > 0 &&
898 InputVectorCount > 0) {
899 uint32_t NumDwords =
900 mapTableSize(InputVectorCount, PatchConstOrPrimVectorCount);
901 size_t NumBytes = NumDwords * sizeof(uint32_t);
902 InputPatchMap.Data = Data.substr(Start: Current - Data.begin(), N: NumBytes);
903 Current += NumBytes;
904 }
905
906 // Domain Shader: Patch/Output mapping table
907 if (ShaderStage == Triple::Domain && PatchConstOrPrimVectorCount > 0 &&
908 OutputVectorCounts[0] > 0) {
909 uint32_t NumDwords =
910 mapTableSize(PatchConstOrPrimVectorCount, OutputVectorCounts[0]);
911 size_t NumBytes = NumDwords * sizeof(uint32_t);
912 PatchOutputMap.Data = Data.substr(Start: Current - Data.begin(), N: NumBytes);
913 Current += NumBytes;
914 }
915
916 return Error::success();
917}
918
919uint8_t DirectX::PSVRuntimeInfo::getSigInputCount() const {
920 if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(ptr: &BasicInfo))
921 return P->SigInputElements;
922 if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(ptr: &BasicInfo))
923 return P->SigInputElements;
924 if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(ptr: &BasicInfo))
925 return P->SigInputElements;
926 return 0;
927}
928
929uint8_t DirectX::PSVRuntimeInfo::getSigOutputCount() const {
930 if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(ptr: &BasicInfo))
931 return P->SigOutputElements;
932 if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(ptr: &BasicInfo))
933 return P->SigOutputElements;
934 if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(ptr: &BasicInfo))
935 return P->SigOutputElements;
936 return 0;
937}
938
939uint8_t DirectX::PSVRuntimeInfo::getSigPatchOrPrimCount() const {
940 if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(ptr: &BasicInfo))
941 return P->SigPatchOrPrimElements;
942 if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(ptr: &BasicInfo))
943 return P->SigPatchOrPrimElements;
944 if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(ptr: &BasicInfo))
945 return P->SigPatchOrPrimElements;
946 return 0;
947}
948
949class DXNotSupportedError : public ErrorInfo<DXNotSupportedError> {
950public:
951 static char ID;
952
953 DXNotSupportedError(StringRef S) : FeatureString(S) {}
954
955 void log(raw_ostream &OS) const override {
956 OS << "DXContainer does not support " << FeatureString;
957 }
958
959 std::error_code convertToErrorCode() const override {
960 return inconvertibleErrorCode();
961 }
962
963private:
964 StringRef FeatureString;
965};
966
967char DXNotSupportedError::ID = 0;
968
969Expected<section_iterator>
970DXContainerObjectFile::getSymbolSection(DataRefImpl Symb) const {
971 return make_error<DXNotSupportedError>(Args: "Symbol sections");
972}
973
974Expected<StringRef> DXContainerObjectFile::getSymbolName(DataRefImpl) const {
975 return make_error<DXNotSupportedError>(Args: "Symbol names");
976}
977
978Expected<uint64_t>
979DXContainerObjectFile::getSymbolAddress(DataRefImpl Symb) const {
980 return make_error<DXNotSupportedError>(Args: "Symbol addresses");
981}
982
983uint64_t DXContainerObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
984 llvm_unreachable("DXContainer does not support symbols");
985}
986uint64_t
987DXContainerObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
988 llvm_unreachable("DXContainer does not support symbols");
989}
990
991Expected<SymbolRef::Type>
992DXContainerObjectFile::getSymbolType(DataRefImpl Symb) const {
993 return make_error<DXNotSupportedError>(Args: "Symbol types");
994}
995
996void DXContainerObjectFile::moveSectionNext(DataRefImpl &Sec) const {
997 PartIterator It = reinterpret_cast<PartIterator>(Sec.p);
998 if (It == Parts.end())
999 return;
1000
1001 ++It;
1002 Sec.p = reinterpret_cast<uintptr_t>(It);
1003}
1004
1005Expected<StringRef>
1006DXContainerObjectFile::getSectionName(DataRefImpl Sec) const {
1007 PartIterator It = reinterpret_cast<PartIterator>(Sec.p);
1008 return StringRef(It->Part.getName());
1009}
1010
1011uint64_t DXContainerObjectFile::getSectionAddress(DataRefImpl Sec) const {
1012 PartIterator It = reinterpret_cast<PartIterator>(Sec.p);
1013 return It->Offset;
1014}
1015
1016uint64_t DXContainerObjectFile::getSectionIndex(DataRefImpl Sec) const {
1017 return (Sec.p - reinterpret_cast<uintptr_t>(Parts.begin())) /
1018 sizeof(PartIterator);
1019}
1020
1021uint64_t DXContainerObjectFile::getSectionSize(DataRefImpl Sec) const {
1022 PartIterator It = reinterpret_cast<PartIterator>(Sec.p);
1023 return It->Data.size();
1024}
1025Expected<ArrayRef<uint8_t>>
1026DXContainerObjectFile::getSectionContents(DataRefImpl Sec) const {
1027 PartIterator It = reinterpret_cast<PartIterator>(Sec.p);
1028 return ArrayRef<uint8_t>(It->Data.bytes_begin(), It->Data.size());
1029}
1030
1031uint64_t DXContainerObjectFile::getSectionAlignment(DataRefImpl Sec) const {
1032 return 1;
1033}
1034
1035bool DXContainerObjectFile::isSectionCompressed(DataRefImpl Sec) const {
1036 return false;
1037}
1038
1039bool DXContainerObjectFile::isSectionText(DataRefImpl Sec) const {
1040 return false;
1041}
1042
1043bool DXContainerObjectFile::isSectionData(DataRefImpl Sec) const {
1044 return false;
1045}
1046
1047bool DXContainerObjectFile::isSectionBSS(DataRefImpl Sec) const {
1048 return false;
1049}
1050
1051bool DXContainerObjectFile::isSectionVirtual(DataRefImpl Sec) const {
1052 return false;
1053}
1054
1055relocation_iterator
1056DXContainerObjectFile::section_rel_begin(DataRefImpl Sec) const {
1057 return relocation_iterator(RelocationRef());
1058}
1059
1060relocation_iterator
1061DXContainerObjectFile::section_rel_end(DataRefImpl Sec) const {
1062 return relocation_iterator(RelocationRef());
1063}
1064
1065void DXContainerObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
1066 llvm_unreachable("DXContainer does not support relocations");
1067}
1068
1069uint64_t DXContainerObjectFile::getRelocationOffset(DataRefImpl Rel) const {
1070 llvm_unreachable("DXContainer does not support relocations");
1071}
1072
1073symbol_iterator
1074DXContainerObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
1075 return symbol_iterator(SymbolRef());
1076}
1077
1078uint64_t DXContainerObjectFile::getRelocationType(DataRefImpl Rel) const {
1079 llvm_unreachable("DXContainer does not support relocations");
1080}
1081
1082void DXContainerObjectFile::getRelocationTypeName(
1083 DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
1084 llvm_unreachable("DXContainer does not support relocations");
1085}
1086
1087section_iterator DXContainerObjectFile::section_begin() const {
1088 DataRefImpl Sec;
1089 Sec.p = reinterpret_cast<uintptr_t>(Parts.begin());
1090 return section_iterator(SectionRef(Sec, this));
1091}
1092section_iterator DXContainerObjectFile::section_end() const {
1093 DataRefImpl Sec;
1094 Sec.p = reinterpret_cast<uintptr_t>(Parts.end());
1095 return section_iterator(SectionRef(Sec, this));
1096}
1097
1098uint8_t DXContainerObjectFile::getBytesInAddress() const { return 4; }
1099
1100StringRef DXContainerObjectFile::getFileFormatName() const {
1101 return "DirectX Container";
1102}
1103
1104Triple::ArchType DXContainerObjectFile::getArch() const { return Triple::dxil; }
1105
1106Expected<SubtargetFeatures> DXContainerObjectFile::getFeatures() const {
1107 return SubtargetFeatures();
1108}
1109
1110Error DXContainerObjectFile::printSymbolName(raw_ostream &OS,
1111 DataRefImpl Symb) const {
1112 return make_error<DXNotSupportedError>(Args: "Symbol names");
1113}
1114
1115Expected<uint32_t>
1116DXContainerObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1117 return make_error<DXNotSupportedError>(Args: "Symbol flags");
1118}
1119
1120Expected<std::unique_ptr<DXContainerObjectFile>>
1121ObjectFile::createDXContainerObjectFile(MemoryBufferRef Object) {
1122 auto ExC = DXContainer::create(Object);
1123 if (!ExC)
1124 return ExC.takeError();
1125 std::unique_ptr<DXContainerObjectFile> Obj(new DXContainerObjectFile(*ExC));
1126 return std::move(Obj);
1127}
1128