|
21 | 21 | #include "llvm/ADT/SmallString.h"
|
22 | 22 | #include "llvm/ADT/StringRef.h"
|
23 | 23 | #include "llvm/Object/Binary.h"
|
| 24 | +#include "llvm/Object/ObjectFile.h" |
| 25 | +#include "llvm/Support/Compression.h" |
24 | 26 | #include "llvm/Support/Error.h"
|
25 | 27 | #include "llvm/Support/MemoryBuffer.h"
|
26 | 28 | #include <memory>
|
@@ -49,6 +51,31 @@ enum ImageKind : uint16_t {
|
49 | 51 | IMG_LAST,
|
50 | 52 | };
|
51 | 53 |
|
| 54 | +class CompressedOffloadBundle { |
| 55 | +private: |
| 56 | + static inline const size_t MagicSize = 4; |
| 57 | + static inline const size_t VersionFieldSize = sizeof(uint16_t); |
| 58 | + static inline const size_t MethodFieldSize = sizeof(uint16_t); |
| 59 | + static inline const size_t FileSizeFieldSize = sizeof(uint32_t); |
| 60 | + static inline const size_t UncompressedSizeFieldSize = sizeof(uint32_t); |
| 61 | + static inline const size_t HashFieldSize = sizeof(uint64_t); |
| 62 | + static inline const size_t V1HeaderSize = |
| 63 | + MagicSize + VersionFieldSize + MethodFieldSize + |
| 64 | + UncompressedSizeFieldSize + HashFieldSize; |
| 65 | + static inline const size_t V2HeaderSize = |
| 66 | + MagicSize + VersionFieldSize + FileSizeFieldSize + MethodFieldSize + |
| 67 | + UncompressedSizeFieldSize + HashFieldSize; |
| 68 | + static inline const llvm::StringRef MagicNumber = "CCOB"; |
| 69 | + static inline const uint16_t Version = 2; |
| 70 | + |
| 71 | +public: |
| 72 | + static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> |
| 73 | + compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input, |
| 74 | + bool Verbose = false); |
| 75 | + static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> |
| 76 | + decompress(llvm::MemoryBufferRef &Input, bool Verbose = false); |
| 77 | +}; |
| 78 | + |
52 | 79 | /// A simple binary serialization of an offloading file. We use this format to
|
53 | 80 | /// embed the offloading image into the host executable so it can be extracted
|
54 | 81 | /// and used by the linker.
|
@@ -182,11 +209,160 @@ class OffloadFile : public OwningBinary<OffloadBinary> {
|
182 | 209 | }
|
183 | 210 | };
|
184 | 211 |
|
| 212 | +/// Bundle entry in binary clang-offload-bundler format. |
| 213 | +struct OffloadBundleEntry { |
| 214 | + uint64_t Offset = 0u; |
| 215 | + uint64_t Size = 0u; |
| 216 | + uint64_t IDLength = 0u; |
| 217 | + StringRef ID; |
| 218 | + OffloadBundleEntry(uint64_t O, uint64_t S, uint64_t I, StringRef T) |
| 219 | + : Offset(O), Size(S), IDLength(I), ID(T) {} |
| 220 | + void dumpInfo(raw_ostream &OS) { |
| 221 | + OS << "Offset = " << Offset << ", Size = " << Size |
| 222 | + << ", ID Length = " << IDLength << ", ID = " << ID; |
| 223 | + } |
| 224 | + void dumpURI(raw_ostream &OS, StringRef filePath) { |
| 225 | + OS << ID.data() << "\tfile:\/\/" << filePath << "#offset=" << Offset |
| 226 | + << "&size=" << Size << "\n"; |
| 227 | + } |
| 228 | +}; |
| 229 | + |
| 230 | +/// Fat binary embedded in object files in clang-offload-bundler format |
| 231 | +class OffloadBundleFatBin { |
| 232 | + |
| 233 | +private: |
| 234 | + uint64_t Size = 0u; |
| 235 | + StringRef FileName; |
| 236 | + uint64_t NumberOfEntries; |
| 237 | + SmallVector<OffloadBundleEntry> Entries; |
| 238 | + |
| 239 | +public: |
| 240 | + SmallVector<OffloadBundleEntry> getEntries() { return Entries; } |
| 241 | + uint64_t getSize() const { return Size; } |
| 242 | + StringRef getFileName() const { return FileName; } |
| 243 | + uint64_t getNumEntries() const { return NumberOfEntries; } |
| 244 | + |
| 245 | + static Expected<std::unique_ptr<OffloadBundleFatBin>> |
| 246 | + create(MemoryBufferRef, uint64_t SectionOffset, StringRef fileName); |
| 247 | + Error extractBundle(const ObjectFile &Source); |
| 248 | + |
| 249 | + Error DumpEntryToCodeObject(); |
| 250 | + |
| 251 | + Error ReadEntries(StringRef Section, uint64_t SectionOffset); |
| 252 | + void DumpEntries() { |
| 253 | + SmallVectorImpl<OffloadBundleEntry>::iterator it = Entries.begin(); |
| 254 | + for (uint64_t I = 0; I < Entries.size(); I++) { |
| 255 | + it->dumpInfo(outs()); |
| 256 | + ++it; |
| 257 | + } |
| 258 | + } |
| 259 | + |
| 260 | + void PrintEntriesAsURI() { |
| 261 | + SmallVectorImpl<OffloadBundleEntry>::iterator it = Entries.begin(); |
| 262 | + for (uint64_t I = 0; I < NumberOfEntries; I++) { |
| 263 | + it->dumpURI(outs(), FileName); |
| 264 | + ++it; |
| 265 | + } |
| 266 | + } |
| 267 | + |
| 268 | + OffloadBundleFatBin(MemoryBufferRef Source, StringRef file) : FileName(file) { |
| 269 | + NumberOfEntries = 0; |
| 270 | + Entries = SmallVector<OffloadBundleEntry>(); |
| 271 | + } |
| 272 | + |
| 273 | + SmallVector<OffloadBundleEntry> EntryIDContains(StringRef str) { |
| 274 | + SmallVector<OffloadBundleEntry> found = SmallVector<OffloadBundleEntry>(); |
| 275 | + SmallVectorImpl<OffloadBundleEntry>::iterator it = Entries.begin(); |
| 276 | + for (uint64_t I = 0; I < NumberOfEntries; I++) { |
| 277 | + if (it->ID.contains(str)) { |
| 278 | + found.push_back(*it); |
| 279 | + } |
| 280 | + |
| 281 | + ++it; |
| 282 | + } |
| 283 | + return found; |
| 284 | + } |
| 285 | +}; |
| 286 | + |
| 287 | +enum uri_type_t { FILE_URI, MEMORY_URI }; |
| 288 | + |
| 289 | +struct OffloadBundleURI { |
| 290 | + int64_t Offset = 0; |
| 291 | + int64_t Size = 0; |
| 292 | + uint64_t ProcessID = 0; |
| 293 | + StringRef FileName; |
| 294 | + uri_type_t URIType; |
| 295 | + |
| 296 | + // Constructors |
| 297 | + // TODO: add a Copy ctor ? |
| 298 | + OffloadBundleURI(StringRef file, int64_t off, int64_t size) |
| 299 | + : Offset(off), Size(size), ProcessID(0), FileName(file), |
| 300 | + URIType(FILE_URI) {} |
| 301 | + |
| 302 | + OffloadBundleURI(StringRef str, uri_type_t type) { |
| 303 | + URIType = type; |
| 304 | + switch (URIType) { |
| 305 | + case FILE_URI: |
| 306 | + parseFileName(str); |
| 307 | + break; |
| 308 | + case MEMORY_URI: |
| 309 | + parseMemoryURI(str); |
| 310 | + break; |
| 311 | + default: |
| 312 | + report_fatal_error("Unrecognized URI type."); |
| 313 | + } |
| 314 | + } |
| 315 | + |
| 316 | + void parseFileName(StringRef str) { |
| 317 | + ProcessID = 0; |
| 318 | + URIType = FILE_URI; |
| 319 | + if (str.consume_front("file://")) { |
| 320 | + StringRef FilePathname = |
| 321 | + str.take_until([](char c) { return (c == '#') || (c == '?'); }); |
| 322 | + FileName = FilePathname; |
| 323 | + str = str.drop_front(FilePathname.size()); |
| 324 | + |
| 325 | + if (str.consume_front("#offset=")) { |
| 326 | + StringRef OffsetStr = str.take_until([](char c) { return c == '&'; }); |
| 327 | + OffsetStr.getAsInteger(10, Offset); |
| 328 | + str = str.drop_front(OffsetStr.size()); |
| 329 | + |
| 330 | + if (str.consume_front("&size=")) { |
| 331 | + Size; |
| 332 | + str.getAsInteger(10, Size); |
| 333 | + } else |
| 334 | + report_fatal_error("Reading 'size' in URI."); |
| 335 | + } else |
| 336 | + report_fatal_error("Reading 'offset' in URI."); |
| 337 | + } else |
| 338 | + report_fatal_error("Reading type of URI."); |
| 339 | + } |
| 340 | + |
| 341 | + void parseMemoryURI(StringRef str) { |
| 342 | + // TODO: add parseMemoryURI type |
| 343 | + } |
| 344 | + |
| 345 | + StringRef getFileName() const { return FileName; } |
| 346 | +}; |
| 347 | + |
185 | 348 | /// Extracts embedded device offloading code from a memory \p Buffer to a list
|
186 | 349 | /// of \p Binaries.
|
187 | 350 | Error extractOffloadBinaries(MemoryBufferRef Buffer,
|
188 | 351 | SmallVectorImpl<OffloadFile> &Binaries);
|
189 | 352 |
|
| 353 | +/// Extracts fat binary in binary clang-offload-bundler format from object \p |
| 354 | +/// Obj and return it in \p Bundles |
| 355 | +Error extractOffloadBundleFatBinary( |
| 356 | + const ObjectFile &Obj, SmallVectorImpl<OffloadBundleFatBin> &Bundles); |
| 357 | + |
| 358 | +/// Extract code object memory from the given \p Source object file at \p Offset |
| 359 | +/// and of \p Size, and copy into \p OutputFileName. |
| 360 | +Error extractCodeObject(const ObjectFile &Source, int64_t Offset, int64_t Size, |
| 361 | + StringRef OutputFileName); |
| 362 | + |
| 363 | +/// Extracts an Offload Bundle Entry given by URI |
| 364 | +Error extractOffloadBundleByURI(StringRef URIstr); |
| 365 | + |
190 | 366 | /// Convert a string \p Name to an image kind.
|
191 | 367 | ImageKind getImageKind(StringRef Name);
|
192 | 368 |
|
|
0 commit comments