1 //===- DXContainer.h - DXContainer file implementation ----------*- C++ -*-===//
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 // This file declares the DXContainerFile class, which implements the ObjectFile
10 // interface for DXContainer files.
11 //
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_OBJECT_DXCONTAINER_H
16 #define LLVM_OBJECT_DXCONTAINER_H
17 
18 #include "llvm/ADT/Optional.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/BinaryFormat/DXContainer.h"
22 #include "llvm/Support/Error.h"
23 #include "llvm/Support/MemoryBufferRef.h"
24 
25 namespace llvm {
26 namespace object {
27 class DXContainer {
28 public:
29   using DXILData = std::pair<dxbc::ProgramHeader, const char *>;
30 
31 private:
32   DXContainer(MemoryBufferRef O);
33 
34   MemoryBufferRef Data;
35   dxbc::Header Header;
36   SmallVector<uint32_t, 4> PartOffsets;
37   Optional<DXILData> DXIL;
38 
39   Error parseHeader();
40   Error parsePartOffsets();
41   Error parseDXILHeader(uint32_t Offset);
42   friend class PartIterator;
43 
44 public:
45   // The PartIterator is a wrapper around the iterator for the PartOffsets
46   // member of the DXContainer. It contains a refernce to the container, and the
47   // current iterator value, as well as storage for a parsed part header.
48   class PartIterator {
49     const DXContainer &Container;
50     SmallVectorImpl<uint32_t>::const_iterator OffsetIt;
51     struct PartData {
52       dxbc::PartHeader Part;
53       uint32_t Offset;
54       StringRef Data;
55     } IteratorState;
56 
57     friend class DXContainer;
58 
59     PartIterator(const DXContainer &C,
60                  SmallVectorImpl<uint32_t>::const_iterator It)
61         : Container(C), OffsetIt(It) {
62       if (OffsetIt == Container.PartOffsets.end())
63         updateIteratorImpl(Container.PartOffsets.back());
64       else
65         updateIterator();
66     }
67 
68     // Updates the iterator's state data. This results in copying the part
69     // header into the iterator and handling any required byte swapping. This is
70     // called when incrementing or decrementing the iterator.
71     void updateIterator() {
72       if (OffsetIt != Container.PartOffsets.end())
73         updateIteratorImpl(*OffsetIt);
74     }
75 
76     // Implementation for updating the iterator state based on a specified
77     // offest.
78     void updateIteratorImpl(const uint32_t Offset);
79 
80   public:
81     PartIterator &operator++() {
82       if (OffsetIt == Container.PartOffsets.end())
83         return *this;
84       ++OffsetIt;
85       updateIterator();
86       return *this;
87     }
88 
89     PartIterator operator++(int) {
90       PartIterator Tmp = *this;
91       ++(*this);
92       return Tmp;
93     }
94 
95     bool operator==(const PartIterator &RHS) const {
96       return OffsetIt == RHS.OffsetIt;
97     }
98 
99     bool operator!=(const PartIterator &RHS) const {
100       return OffsetIt != RHS.OffsetIt;
101     }
102 
103     const PartData &operator*() { return IteratorState; }
104     const PartData *operator->() { return &IteratorState; }
105   };
106 
107   PartIterator begin() const {
108     return PartIterator(*this, PartOffsets.begin());
109   }
110 
111   PartIterator end() const { return PartIterator(*this, PartOffsets.end()); }
112 
113   StringRef getData() const { return Data.getBuffer(); }
114   static Expected<DXContainer> create(MemoryBufferRef Object);
115 
116   const dxbc::Header &getHeader() const { return Header; }
117 
118   Optional<DXILData> getDXIL() const { return DXIL; }
119 };
120 
121 } // namespace object
122 } // namespace llvm
123 
124 #endif // LLVM_OBJECT_DXCONTAINER_H
125