1 //===- OffloadBundle.h - Utilities for offload bundles---*- 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 contains the binary format used for budingling device metadata with 10 // an associated device image. The data can then be stored inside a host object 11 // file to create a fat binary and read by the linker. This is intended to be a 12 // thin wrapper around the image itself. If this format becomes sufficiently 13 // complex it should be moved to a standard binary format like msgpack or ELF. 14 // 15 //===-------------------------------------------------------------------------===// 16 17 #ifndef LLVM_OBJECT_OFFLOADBUNDLE_H 18 #define LLVM_OBJECT_OFFLOADBUNDLE_H 19 20 #include "llvm/ADT/MapVector.h" 21 #include "llvm/ADT/SmallString.h" 22 #include "llvm/ADT/StringRef.h" 23 #include "llvm/Object/Binary.h" 24 #include "llvm/Object/ObjectFile.h" 25 #include "llvm/Support/Compiler.h" 26 #include "llvm/Support/Compression.h" 27 #include "llvm/Support/Error.h" 28 #include "llvm/Support/MemoryBuffer.h" 29 #include <memory> 30 31 namespace llvm { 32 33 namespace object { 34 35 class CompressedOffloadBundle { 36 private: 37 static inline const size_t MagicSize = 4; 38 static inline const size_t VersionFieldSize = sizeof(uint16_t); 39 static inline const size_t MethodFieldSize = sizeof(uint16_t); 40 static inline const size_t FileSizeFieldSize = sizeof(uint32_t); 41 static inline const size_t UncompressedSizeFieldSize = sizeof(uint32_t); 42 static inline const size_t HashFieldSize = sizeof(uint64_t); 43 static inline const size_t V1HeaderSize = 44 MagicSize + VersionFieldSize + MethodFieldSize + 45 UncompressedSizeFieldSize + HashFieldSize; 46 static inline const size_t V2HeaderSize = 47 MagicSize + VersionFieldSize + FileSizeFieldSize + MethodFieldSize + 48 UncompressedSizeFieldSize + HashFieldSize; 49 static inline const llvm::StringRef MagicNumber = "CCOB"; 50 static inline const uint16_t Version = 2; 51 52 public: 53 LLVM_ABI static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> 54 compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input, 55 bool Verbose = false); 56 LLVM_ABI static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> 57 decompress(llvm::MemoryBufferRef &Input, bool Verbose = false); 58 }; 59 60 /// Bundle entry in binary clang-offload-bundler format. 61 struct OffloadBundleEntry { 62 uint64_t Offset = 0u; 63 uint64_t Size = 0u; 64 uint64_t IDLength = 0u; 65 StringRef ID; OffloadBundleEntryOffloadBundleEntry66 OffloadBundleEntry(uint64_t O, uint64_t S, uint64_t I, StringRef T) 67 : Offset(O), Size(S), IDLength(I), ID(T) {} dumpInfoOffloadBundleEntry68 void dumpInfo(raw_ostream &OS) { 69 OS << "Offset = " << Offset << ", Size = " << Size 70 << ", ID Length = " << IDLength << ", ID = " << ID; 71 } dumpURIOffloadBundleEntry72 void dumpURI(raw_ostream &OS, StringRef FilePath) { 73 OS << ID.data() << "\tfile://" << FilePath << "#offset=" << Offset 74 << "&size=" << Size << "\n"; 75 } 76 }; 77 78 /// Fat binary embedded in object files in clang-offload-bundler format 79 class OffloadBundleFatBin { 80 81 uint64_t Size = 0u; 82 StringRef FileName; 83 uint64_t NumberOfEntries; 84 SmallVector<OffloadBundleEntry> Entries; 85 86 public: getEntries()87 SmallVector<OffloadBundleEntry> getEntries() { return Entries; } getSize()88 uint64_t getSize() const { return Size; } getFileName()89 StringRef getFileName() const { return FileName; } getNumEntries()90 uint64_t getNumEntries() const { return NumberOfEntries; } 91 92 LLVM_ABI static Expected<std::unique_ptr<OffloadBundleFatBin>> 93 create(MemoryBufferRef, uint64_t SectionOffset, StringRef FileName); 94 LLVM_ABI Error extractBundle(const ObjectFile &Source); 95 96 LLVM_ABI Error dumpEntryToCodeObject(); 97 98 LLVM_ABI Error readEntries(StringRef Section, uint64_t SectionOffset); dumpEntries()99 void dumpEntries() { 100 for (OffloadBundleEntry &Entry : Entries) 101 Entry.dumpInfo(outs()); 102 } 103 printEntriesAsURI()104 void printEntriesAsURI() { 105 for (OffloadBundleEntry &Entry : Entries) 106 Entry.dumpURI(outs(), FileName); 107 } 108 OffloadBundleFatBin(MemoryBufferRef Source,StringRef File)109 OffloadBundleFatBin(MemoryBufferRef Source, StringRef File) 110 : FileName(File), NumberOfEntries(0), 111 Entries(SmallVector<OffloadBundleEntry>()) {} 112 }; 113 114 enum UriTypeT { FILE_URI, MEMORY_URI }; 115 116 struct OffloadBundleURI { 117 int64_t Offset = 0; 118 int64_t Size = 0; 119 uint64_t ProcessID = 0; 120 StringRef FileName; 121 UriTypeT URIType; 122 123 // Constructors 124 // TODO: add a Copy ctor ? OffloadBundleURIOffloadBundleURI125 OffloadBundleURI(StringRef File, int64_t Off, int64_t Size) 126 : Offset(Off), Size(Size), ProcessID(0), FileName(File), 127 URIType(FILE_URI) {} 128 129 public: 130 static Expected<std::unique_ptr<OffloadBundleURI>> createOffloadBundleURIOffloadBundleURI131 createOffloadBundleURI(StringRef Str, UriTypeT Type) { 132 switch (Type) { 133 case FILE_URI: 134 return createFileURI(Str); 135 break; 136 case MEMORY_URI: 137 return createMemoryURI(Str); 138 break; 139 } 140 llvm_unreachable("Unknown UriTypeT enum"); 141 } 142 143 static Expected<std::unique_ptr<OffloadBundleURI>> createFileURIOffloadBundleURI144 createFileURI(StringRef Str) { 145 int64_t O = 0; 146 int64_t S = 0; 147 148 if (!Str.consume_front("file://")) 149 return createStringError(object_error::parse_failed, 150 "Reading type of URI"); 151 152 StringRef FilePathname = 153 Str.take_until([](char C) { return (C == '#') || (C == '?'); }); 154 Str = Str.drop_front(FilePathname.size()); 155 156 if (!Str.consume_front("#offset=")) 157 return createStringError(object_error::parse_failed, 158 "Reading 'offset' in URI"); 159 160 StringRef OffsetStr = Str.take_until([](char C) { return C == '&'; }); 161 OffsetStr.getAsInteger(10, O); 162 Str = Str.drop_front(OffsetStr.size()); 163 164 if (Str.consume_front("&size=")) 165 return createStringError(object_error::parse_failed, 166 "Reading 'size' in URI"); 167 168 Str.getAsInteger(10, S); 169 std::unique_ptr<OffloadBundleURI> OffloadingURI( 170 new OffloadBundleURI(FilePathname, O, S)); 171 return std::move(OffloadingURI); 172 } 173 174 static Expected<std::unique_ptr<OffloadBundleURI>> createMemoryURIOffloadBundleURI175 createMemoryURI(StringRef Str) { 176 // TODO: add parseMemoryURI type 177 return createStringError(object_error::parse_failed, 178 "Memory Type URI is not currently supported."); 179 } 180 getFileNameOffloadBundleURI181 StringRef getFileName() const { return FileName; } 182 }; 183 184 /// Extracts fat binary in binary clang-offload-bundler format from object \p 185 /// Obj and return it in \p Bundles 186 LLVM_ABI Error extractOffloadBundleFatBinary( 187 const ObjectFile &Obj, SmallVectorImpl<OffloadBundleFatBin> &Bundles); 188 189 /// Extract code object memory from the given \p Source object file at \p Offset 190 /// and of \p Size, and copy into \p OutputFileName. 191 LLVM_ABI Error extractCodeObject(const ObjectFile &Source, int64_t Offset, 192 int64_t Size, StringRef OutputFileName); 193 194 /// Extracts an Offload Bundle Entry given by URI 195 LLVM_ABI Error extractOffloadBundleByURI(StringRef URIstr); 196 197 } // namespace object 198 199 } // namespace llvm 200 #endif 201