Skip to content

Commit 6fa91a9

Browse files
dsalinasDavid Salinas
authored andcommitted
Extend llvm-objdump to support clang offload fat bins
extend option --offloading Change-Id: Ibc865f80e30aa1a6e5495ecfe617be68a5e15fcf
1 parent c148185 commit 6fa91a9

File tree

8 files changed

+185
-50
lines changed

8 files changed

+185
-50
lines changed

llvm/docs/CommandGuide/llvm-objdump.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ OPTIONS
217217

218218
.. option:: --offloading
219219

220-
Display the content of the LLVM offloading section.
220+
Display the content of the LLVM offloading sections and HIP offload bundles.
221221

222222
.. option:: --prefix=<prefix>
223223

llvm/include/llvm/Object/OffloadBundle.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
//===--- OffloadBundle.h - Utilities for handling offloading code -*- C++
2-
//-*-===//
1+
//===- OffloadBundle.h - Utilities for handling offloading code -----*- C++ -*-===//
32
//
43
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
54
// See https://llvm.org/LICENSE.txt for license information.
65
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
76
//
8-
//===------------------------------------------------------------------------===//
7+
//===-------------------------------------------------------------------------===//
98
//
109
// This file contains the binary format used for budingling device metadata with
1110
// an associated device image. The data can then be stored inside a host object
1211
// file to create a fat binary and read by the linker. This is intended to be a
1312
// thin wrapper around the image itself. If this format becomes sufficiently
1413
// complex it should be moved to a standard binary format like msgpack or ELF.
1514
//
16-
//===------------------------------------------------------------------------===//
15+
//===-------------------------------------------------------------------------===//
1716

1817
#ifndef LLVM_OBJECT_OFFLOADBUNDLE_H
1918
#define LLVM_OBJECT_OFFLOADBUNDLE_H

llvm/lib/Object/OffloadBundle.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
//===- OffloadBundle.cpp - Utilities for handling offloading code -*- C++
2-
//-*-===//
1+
//===- OffloadBundle.cpp - Utilities for offload bundles---*- C++ -*-===//
32
//
43
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
54
// See https://llvm.org/LICENSE.txt for license information.
65
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
76
//
8-
//===----------------------------------------------------------------------===//
7+
//===----------------------------------------------------------------===//
98

109
#include "llvm/Object/OffloadBundle.h"
1110
#include "llvm/ADT/StringSwitch.h"
@@ -79,9 +78,8 @@ Error OffloadBundleFatBin::readEntries(StringRef Buffer,
7978

8079
// Read the Magic String first.
8180
StringRef Magic;
82-
if (auto EC = Reader.readFixedString(Magic, 24)) {
81+
if (auto EC = Reader.readFixedString(Magic, 24))
8382
return errorCodeToError(object_error::parse_failed);
84-
}
8583

8684
// Read the number of Code Objects (Entries) in the current Bundle.
8785
if (auto EC = Reader.readInteger(NumOfEntries))
@@ -108,8 +106,10 @@ Error OffloadBundleFatBin::readEntries(StringRef Buffer,
108106
if (auto EC = Reader.readFixedString(EntryID, EntryIDSize))
109107
return errorCodeToError(object_error::parse_failed);
110108

111-
// create a Bundle Entry object:
112-
auto Entry = new OffloadBundleEntry(EntryOffset + SectionOffset, EntrySize,
109+
// Create a Bundle Entry object:
110+
// auto Entry = new OffloadBundleEntry(EntryOffset + SectionOffset, EntrySize,
111+
// EntryIDSize, EntryID);
112+
auto Entry = std::make_unique<OffloadBundleEntry>(EntryOffset + SectionOffset, EntrySize,
113113
EntryIDSize, EntryID);
114114

115115
Entries.push_back(*Entry);
@@ -142,15 +142,16 @@ Error OffloadBundleFatBin::extractBundle(const ObjectFile &Source) {
142142
// This will extract all entries in the Bundle
143143
for (OffloadBundleEntry &Entry : Entries) {
144144

145-
if (Entry.Size > 0) {
146-
// create output file name. Which should be
147-
// <fileName>-offset<Offset>-size<Size>.co"
148-
std::string Str = getFileName().str() + "-offset" + itostr(Entry.Offset) +
149-
"-size" + itostr(Entry.Size) + ".co";
150-
if (Error Err = object::extractCodeObject(Source, Entry.Offset,
151-
Entry.Size, StringRef(Str)))
152-
return Err;
153-
}
145+
if (Entry.Size == 0)
146+
continue;
147+
148+
// create output file name. Which should be
149+
// <fileName>-offset<Offset>-size<Size>.co"
150+
std::string Str = getFileName().str() + "-offset" + itostr(Entry.Offset) +
151+
"-size" + itostr(Entry.Size) + ".co";
152+
if (Error Err = object::extractCodeObject(Source, Entry.Offset, Entry.Size,
153+
StringRef(Str)))
154+
return Err;
154155
}
155156

156157
return Error::success();
@@ -160,7 +161,7 @@ Error object::extractOffloadBundleFatBinary(
160161
const ObjectFile &Obj, SmallVectorImpl<OffloadBundleFatBin> &Bundles) {
161162
assert((Obj.isELF() || Obj.isCOFF()) && "Invalid file type");
162163

163-
// iterate through Sections until we find an offload_bundle section.
164+
// Iterate through Sections until we find an offload_bundle section.
164165
for (SectionRef Sec : Obj.sections()) {
165166
Expected<StringRef> Buffer = Sec.getContents();
166167
if (!Buffer)
@@ -175,9 +176,8 @@ Error object::extractOffloadBundleFatBinary(
175176
if (Obj.isELF()) {
176177
SectionOffset = ELFSectionRef(Sec).getOffset();
177178
} else if (Obj.isCOFF()) {
178-
if (const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(&Obj)) {
179+
if (const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(&Obj))
179180
const coff_section *CoffSection = COFFObj->getCOFFSection(Sec);
180-
}
181181
}
182182

183183
MemoryBufferRef Contents(*Buffer, Obj.getFileName());
@@ -341,7 +341,7 @@ CompressedOffloadBundle::decompress(llvm::MemoryBufferRef &Input,
341341
double DecompressionTimeSeconds =
342342
DecompressTimer.getTotalTime().getWallTime();
343343

344-
// Recalculate MD5 hash for integrity check
344+
// Recalculate MD5 hash for integrity check.
345345
llvm::Timer HashRecalcTimer("Hash Recalculation Timer",
346346
"Hash recalculation time",
347347
OffloadBundlerTimerGroup);

llvm/test/tools/llvm-objdump/Offloading/fatbin.test

Lines changed: 60 additions & 0 deletions
Large diffs are not rendered by default.

llvm/tools/llvm-objdump/OffloadDump.cpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@
1414
#include "OffloadDump.h"
1515
#include "llvm-objdump.h"
1616
#include "llvm/Object/ELFObjectFile.h"
17+
#include "llvm/Object/OffloadBinary.h"
18+
#include "llvm/Object/OffloadBundle.h"
1719
#include "llvm/Support/Alignment.h"
1820

1921
using namespace llvm;
2022
using namespace llvm::object;
2123
using namespace llvm::objdump;
2224

25+
void disassembleObject(llvm::object::ObjectFile *, bool InlineRelocs);
26+
2327
/// Get the printable name of the image kind.
2428
static StringRef getImageName(const OffloadBinary &OB) {
2529
switch (OB.getImageKind()) {
@@ -48,7 +52,7 @@ static void printBinary(const OffloadBinary &OB, uint64_t Index) {
4852
}
4953

5054
/// Print the embedded offloading contents of an ObjectFile \p O.
51-
void llvm::dumpOffloadBinary(const ObjectFile &O) {
55+
void llvm::dumpOffloadBinary(const ObjectFile &O, StringRef ArchName) {
5256
if (!O.isELF() && !O.isCOFF()) {
5357
reportWarning(
5458
"--offloading is currently only supported for COFF and ELF targets",
@@ -64,6 +68,46 @@ void llvm::dumpOffloadBinary(const ObjectFile &O) {
6468
// Print out all the binaries that are contained in this buffer.
6569
for (uint64_t I = 0, E = Binaries.size(); I != E; ++I)
6670
printBinary(*Binaries[I].getBinary(), I);
71+
72+
dumpOffloadBundleFatBinary(O, ArchName);
73+
}
74+
75+
// Given an Object file, collect all Bundles of FatBin Binaries
76+
// and dump them into Code Object files
77+
// if -arch=-name is specified, only dump the Entries that match the target arch
78+
void llvm::dumpOffloadBundleFatBinary(const ObjectFile &O, StringRef ArchName) {
79+
if (!O.isELF() && !O.isCOFF()) {
80+
reportWarning(
81+
"--offloading is currently only supported for COFF and ELF targets",
82+
O.getFileName());
83+
return;
84+
}
85+
86+
SmallVector<llvm::object::OffloadBundleFatBin> FoundBundles;
87+
SmallVector<llvm::object::OffloadBundleEntry> FoundEntries;
88+
89+
if (Error Err = llvm::object::extractOffloadBundleFatBinary(O, FoundBundles))
90+
reportError(O.getFileName(), "while extracting offload FatBin bundles: " +
91+
toString(std::move(Err)));
92+
93+
for (const auto &[BundleNum, Bundle] : llvm::enumerate(FoundBundles)) {
94+
if (!ArchName.empty())
95+
FoundEntries = Bundle.entryIDContains(ArchName);
96+
else
97+
FoundEntries = Bundle.getEntries();
98+
99+
for (OffloadBundleEntry &Entry : FoundEntries) {
100+
// create file name for this object file: <source-filename>:<Bundle
101+
// Number>.<EntryID>
102+
std::string str = Bundle.getFileName().str() + ":" + itostr(BundleNum) +
103+
"." + Entry.ID.str();
104+
if (Error Err = object::extractCodeObject(O, Entry.Offset, Entry.Size,
105+
StringRef(str)))
106+
reportError(O.getFileName(),
107+
"while extracting offload Bundle Entries: " +
108+
toString(std::move(Err)));
109+
}
110+
}
67111
}
68112

69113
/// Print the contents of an offload binary file \p OB. This may contain

llvm/tools/llvm-objdump/OffloadDump.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@
1111

1212
#include "llvm/Object/ObjectFile.h"
1313
#include "llvm/Object/OffloadBinary.h"
14+
#include "llvm/Object/OffloadBundle.h"
1415

1516
namespace llvm {
1617

1718
void dumpOffloadSections(const object::OffloadBinary &OB);
18-
void dumpOffloadBinary(const object::ObjectFile &O);
19+
void dumpOffloadBinary(const object::ObjectFile &O, StringRef ArchName);
1920

21+
/// Dump fat binary in binary clang-offload-bundler format
22+
void dumpOffloadBundleFatBinary(const object::ObjectFile &O,
23+
StringRef ArchName);
2024
} // namespace llvm
2125

2226
#endif

llvm/tools/llvm-objdump/llvm-objdump.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#include "llvm/Object/MachO.h"
5757
#include "llvm/Object/MachOUniversal.h"
5858
#include "llvm/Object/OffloadBinary.h"
59+
#include "llvm/Object/OffloadBundle.h"
5960
#include "llvm/Object/Wasm.h"
6061
#include "llvm/Option/Arg.h"
6162
#include "llvm/Option/ArgList.h"
@@ -3338,7 +3339,7 @@ static void dumpObject(ObjectFile *O, const Archive *A = nullptr,
33383339
if (FaultMapSection)
33393340
printFaultMaps(O);
33403341
if (Offloading)
3341-
dumpOffloadBinary(*O);
3342+
dumpOffloadBinary(*O, StringRef(ArchName));
33423343
}
33433344

33443345
static void dumpObject(const COFFImportFile *I, const Archive *A,
Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
// Skip running on Windows.
2+
#if !defined(_WIN32)
3+
14
#include "llvm/Object/ELFObjectFile.h"
25
#include "llvm/Object/OffloadBinary.h"
36
#include "llvm/Object/OffloadBundle.h"
47
#include "llvm/ObjectYAML/yaml2obj.h"
8+
#include "llvm/Support/FileOutputBuffer.h"
59
#include "llvm/Support/MemoryBuffer.h"
610
#include "llvm/Support/YAMLTraits.h"
711
#include "llvm/Testing/Support/Error.h"
@@ -11,27 +15,7 @@
1115
using namespace llvm;
1216
using namespace llvm::object;
1317

14-
// ELF Object creation
15-
static Expected<std::unique_ptr<ObjectFile>>
16-
toBinary(SmallVectorImpl<char> &Storage, StringRef Yaml) {
17-
raw_svector_ostream OS(Storage);
18-
yaml::Input YIn(Yaml);
19-
if (!yaml::convertYAML(YIn, OS, [](const Twine &Msg) {}))
20-
return createStringError(std::errc::invalid_argument,
21-
"unable to convert YAML");
22-
return object::ObjectFile::createELFObjectFile(
23-
MemoryBufferRef(OS.str(), "dummyELF"));
24-
}
25-
26-
TEST(OffloadingBundleTest, checkOffloadingFatBinary) {
27-
28-
// create a Memory Buffer with a fatbin offloading section
29-
MemoryBufferRef mbuf;
30-
StringRef FileName;
31-
SmallVector<OffloadBundleEntry>();
32-
SmallString<0> Storage;
33-
// Expected<ELFObjectFile<ELF64LE>> ObjOrErr = toBinary<ELF64LE>(Storage, R"(
34-
Expected<std::unique_ptr<ObjectFile>> ObjOrErr = toBinary(Storage, R"(
18+
StringRef simpleAdd = R"(
3519
--- !ELF
3620
FileHeader:
3721
Class: ELFCLASS64
@@ -52,11 +36,54 @@ TEST(OffloadingBundleTest, checkOffloadingFatBinary) {
5236
Address: 0x202FD0
5337
AddressAlign: 0x8
5438
Content: '465049480100000000102000000000000000000000000000'
55-
)");
39+
)";
40+
41+
// ELF Object creation
42+
static Expected<std::unique_ptr<ObjectFile>>
43+
toBinary(SmallVectorImpl<char> &Storage, StringRef Yaml) {
44+
raw_svector_ostream OS(Storage);
45+
yaml::Input YIn(Yaml);
46+
if (!yaml::convertYAML(YIn, OS, [](const Twine &Msg) {}))
47+
return createStringError(std::errc::invalid_argument,
48+
"unable to convert YAML");
49+
return object::ObjectFile::createELFObjectFile(
50+
MemoryBufferRef(OS.str(), "dummyELF"));
51+
}
52+
53+
TEST(OffloadingBundleTest, checkExtractOffloadBundleFatBinary) {
54+
55+
// create a Memory Buffer with a fatbin offloading section
56+
MemoryBufferRef mbuf;
57+
StringRef FileName;
58+
SmallVector<OffloadBundleEntry>();
59+
SmallString<0> Storage;
60+
// Expected<ELFObjectFile<ELF64LE>> ObjOrErr = toBinary<ELF64LE>(Storage, R"(
61+
Expected<std::unique_ptr<ObjectFile>> ObjOrErr = toBinary(Storage, simpleAdd);
5662

5763
ASSERT_THAT_EXPECTED(ObjOrErr, Succeeded());
5864

5965
SmallVector<llvm::object::OffloadBundleFatBin> Bundles;
6066
Error Err = extractOffloadBundleFatBinary(**ObjOrErr, Bundles);
6167
EXPECT_FALSE(errorToBool(std::move(Err)));
6268
}
69+
70+
TEST(OffloadingBundleTest, checkExtractCodeObject) {
71+
// create a Memory Buffer with a fatbin offloading section
72+
MemoryBufferRef mbuf;
73+
StringRef FileName;
74+
SmallVector<OffloadBundleEntry>();
75+
SmallString<0> Storage;
76+
// Expected<ELFObjectFile<ELF64LE>> ObjOrErr = toBinary<ELF64LE>(Storage, R"(
77+
Expected<std::unique_ptr<ObjectFile>> ObjOrErr = toBinary(Storage, simpleAdd);
78+
79+
ASSERT_THAT_EXPECTED(ObjOrErr, Succeeded());
80+
81+
int64_t Offset = 8192;
82+
int64_t Size = 4048;
83+
84+
Error Err = extractCodeObject(**ObjOrErr, Offset, Size,
85+
StringRef("checkExtractCodeObject.co"));
86+
EXPECT_FALSE(errorToBool(std::move(Err)));
87+
}
88+
89+
#endif

0 commit comments

Comments
 (0)