Skip to content

Commit 5ac52c0

Browse files
david-salinasdsalinas
authored andcommitted
Extend llvm objdump fatbin (llvm#140286)
Utilize the new extensions to the LLVM Offloading API to extend to llvm-objdump to handle dumping fatbin offload bundles generated by HIP. This extension to llvm-objdump adds the option --offload-fatbin. Specifying this option will take the input object/executable and extract all offload fatbin bundle entries into distinct code object files with names reflecting the source file name combined with the Bundle Entry ID. Users can also use the --arch-name option to filter offload fatbin bundle entries by their target triple. --------- Co-authored-by: dsalinas <[email protected]>
1 parent 1afc1c3 commit 5ac52c0

File tree

11 files changed

+796
-1458
lines changed

11 files changed

+796
-1458
lines changed

llvm/include/llvm/Object/OffloadBinary.h

Lines changed: 0 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -51,31 +51,6 @@ enum ImageKind : uint16_t {
5151
IMG_LAST,
5252
};
5353

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-
7954
/// A simple binary serialization of an offloading file. We use this format to
8055
/// embed the offloading image into the host executable so it can be extracted
8156
/// and used by the linker.
@@ -210,160 +185,11 @@ class OffloadFile : public OwningBinary<OffloadBinary> {
210185
}
211186
};
212187

213-
/// Bundle entry in binary clang-offload-bundler format.
214-
struct OffloadBundleEntry {
215-
uint64_t Offset = 0u;
216-
uint64_t Size = 0u;
217-
uint64_t IDLength = 0u;
218-
StringRef ID;
219-
OffloadBundleEntry(uint64_t O, uint64_t S, uint64_t I, StringRef T)
220-
: Offset(O), Size(S), IDLength(I), ID(T) {}
221-
void dumpInfo(raw_ostream &OS) {
222-
OS << "Offset = " << Offset << ", Size = " << Size
223-
<< ", ID Length = " << IDLength << ", ID = " << ID;
224-
}
225-
void dumpURI(raw_ostream &OS, StringRef filePath) {
226-
OS << ID.data() << "\tfile:\/\/" << filePath << "#offset=" << Offset
227-
<< "&size=" << Size << "\n";
228-
}
229-
};
230-
231-
/// Fat binary embedded in object files in clang-offload-bundler format
232-
class OffloadBundleFatBin {
233-
234-
private:
235-
uint64_t Size = 0u;
236-
StringRef FileName;
237-
uint64_t NumberOfEntries;
238-
SmallVector<OffloadBundleEntry> Entries;
239-
240-
public:
241-
SmallVector<OffloadBundleEntry> getEntries() { return Entries; }
242-
uint64_t getSize() const { return Size; }
243-
StringRef getFileName() const { return FileName; }
244-
uint64_t getNumEntries() const { return NumberOfEntries; }
245-
246-
static Expected<std::unique_ptr<OffloadBundleFatBin>>
247-
create(MemoryBufferRef, uint64_t SectionOffset, StringRef fileName);
248-
Error extractBundle(const ObjectFile &Source);
249-
250-
Error DumpEntryToCodeObject();
251-
252-
Error ReadEntries(StringRef Section, uint64_t SectionOffset);
253-
void DumpEntries() {
254-
SmallVectorImpl<OffloadBundleEntry>::iterator it = Entries.begin();
255-
for (uint64_t I = 0; I < Entries.size(); I++) {
256-
it->dumpInfo(outs());
257-
++it;
258-
}
259-
}
260-
261-
void PrintEntriesAsURI() {
262-
SmallVectorImpl<OffloadBundleEntry>::iterator it = Entries.begin();
263-
for (uint64_t I = 0; I < NumberOfEntries; I++) {
264-
it->dumpURI(outs(), FileName);
265-
++it;
266-
}
267-
}
268-
269-
OffloadBundleFatBin(MemoryBufferRef Source, StringRef file) : FileName(file) {
270-
NumberOfEntries = 0;
271-
Entries = SmallVector<OffloadBundleEntry>();
272-
}
273-
274-
SmallVector<OffloadBundleEntry> EntryIDContains(StringRef str) {
275-
SmallVector<OffloadBundleEntry> found = SmallVector<OffloadBundleEntry>();
276-
SmallVectorImpl<OffloadBundleEntry>::iterator it = Entries.begin();
277-
for (uint64_t I = 0; I < NumberOfEntries; I++) {
278-
if (it->ID.contains(str)) {
279-
found.push_back(*it);
280-
}
281-
282-
++it;
283-
}
284-
return found;
285-
}
286-
};
287-
288-
enum uri_type_t { FILE_URI, MEMORY_URI };
289-
290-
struct OffloadBundleURI {
291-
int64_t Offset = 0;
292-
int64_t Size = 0;
293-
uint64_t ProcessID = 0;
294-
StringRef FileName;
295-
uri_type_t URIType;
296-
297-
// Constructors
298-
// TODO: add a Copy ctor ?
299-
OffloadBundleURI(StringRef file, int64_t off, int64_t size)
300-
: Offset(off), Size(size), ProcessID(0), FileName(file),
301-
URIType(FILE_URI) {}
302-
303-
OffloadBundleURI(StringRef str, uri_type_t type) {
304-
URIType = type;
305-
switch (URIType) {
306-
case FILE_URI:
307-
parseFileName(str);
308-
break;
309-
case MEMORY_URI:
310-
parseMemoryURI(str);
311-
break;
312-
default:
313-
report_fatal_error("Unrecognized URI type.");
314-
}
315-
}
316-
317-
void parseFileName(StringRef str) {
318-
ProcessID = 0;
319-
URIType = FILE_URI;
320-
if (str.consume_front("file://")) {
321-
StringRef FilePathname =
322-
str.take_until([](char c) { return (c == '#') || (c == '?'); });
323-
FileName = FilePathname;
324-
str = str.drop_front(FilePathname.size());
325-
326-
if (str.consume_front("#offset=")) {
327-
StringRef OffsetStr = str.take_until([](char c) { return c == '&'; });
328-
OffsetStr.getAsInteger(10, Offset);
329-
str = str.drop_front(OffsetStr.size());
330-
331-
if (str.consume_front("&size=")) {
332-
Size;
333-
str.getAsInteger(10, Size);
334-
} else
335-
report_fatal_error("Reading 'size' in URI.");
336-
} else
337-
report_fatal_error("Reading 'offset' in URI.");
338-
} else
339-
report_fatal_error("Reading type of URI.");
340-
}
341-
342-
void parseMemoryURI(StringRef str) {
343-
// TODO: add parseMemoryURI type
344-
}
345-
346-
StringRef getFileName() const { return FileName; }
347-
};
348-
349188
/// Extracts embedded device offloading code from a memory \p Buffer to a list
350189
/// of \p Binaries.
351190
Error extractOffloadBinaries(MemoryBufferRef Buffer,
352191
SmallVectorImpl<OffloadFile> &Binaries);
353192

354-
/// Extracts fat binary in binary clang-offload-bundler format from object \p
355-
/// Obj and return it in \p Bundles
356-
Error extractOffloadBundleFatBinary(
357-
const ObjectFile &Obj, SmallVectorImpl<OffloadBundleFatBin> &Bundles);
358-
359-
/// Extract code object memory from the given \p Source object file at \p Offset
360-
/// and of \p Size, and copy into \p OutputFileName.
361-
Error extractCodeObject(const ObjectFile &Source, int64_t Offset, int64_t Size,
362-
StringRef OutputFileName);
363-
364-
/// Extracts an Offload Bundle Entry given by URI
365-
Error extractOffloadBundleByURI(StringRef URIstr);
366-
367193
/// Convert a string \p Name to an image kind.
368194
ImageKind getImageKind(StringRef Name);
369195

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

0 commit comments

Comments
 (0)