1//===-- OffloadDump.cpp - Offloading dumper ---------------------*- 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/// \file
10/// This file implements the offloading-specific dumper for llvm-objdump.
11///
12//===----------------------------------------------------------------------===//
13
14#include "OffloadDump.h"
15#include "llvm-objdump.h"
16#include "llvm/BinaryFormat/Magic.h"
17#include "llvm/Object/ELFObjectFile.h"
18#include "llvm/Object/OffloadBinary.h"
19#include "llvm/Object/OffloadBundle.h"
20
21using namespace llvm;
22using namespace llvm::object;
23using namespace llvm::objdump;
24
25/// Get the printable name of the image kind.
26static StringRef getImageName(const OffloadBinary &OB) {
27 switch (OB.getImageKind()) {
28 case IMG_Object:
29 return "elf";
30 case IMG_Bitcode:
31 return "llvm ir";
32 case IMG_Cubin:
33 return "cubin";
34 case IMG_Fatbinary:
35 return "fatbinary";
36 case IMG_PTX:
37 return "ptx";
38 case IMG_SPIRV:
39 return "spir-v";
40 default:
41 return "<none>";
42 }
43}
44
45/// Print metadata from an OffloadBinary.
46static void printOffloadBinaryMetadata(const OffloadBinary &OB,
47 uint64_t Level) {
48 outs().indent(NumSpaces: Level * 2) << left_justify(Str: "kind", Width: 16) << getImageName(OB)
49 << "\n";
50 outs().indent(NumSpaces: Level * 2) << left_justify(Str: "arch", Width: 16) << OB.getArch() << "\n";
51 outs().indent(NumSpaces: Level * 2) << left_justify(Str: "triple", Width: 16) << OB.getTriple()
52 << "\n";
53 outs().indent(NumSpaces: Level * 2) << left_justify(Str: "producer", Width: 16)
54 << getOffloadKindName(Name: OB.getOffloadKind()) << "\n";
55
56 StringRef InnerImage = OB.getImage();
57 outs().indent(NumSpaces: Level * 2) << left_justify(Str: "image size", Width: 16)
58 << InnerImage.size() << " bytes\n";
59}
60
61static void printBinary(const OffloadBinary &OB, uint64_t Index,
62 uint64_t Level = 0, Twine ParentIndexPrefix = "") {
63 outs() << "\n";
64 outs().indent(NumSpaces: Level * 2) << "OFFLOADING IMAGE [" << ParentIndexPrefix << Index
65 << "]:\n";
66
67 printOffloadBinaryMetadata(OB, Level);
68
69 StringRef ImageData = OB.getImage();
70 if (identify_magic(magic: ImageData) != file_magic::offload_binary)
71 return;
72
73 MemoryBufferRef InnerBuffer(ImageData, "inner-offload-binary");
74 SmallVector<OffloadFile> InnerBinaries;
75 Error Err = extractOffloadBinaries(Buffer: InnerBuffer, Binaries&: InnerBinaries);
76 if (Err) {
77 reportWarning(Message: "failed to extract nested OffloadBinary: " +
78 toString(E: std::move(Err)),
79 File: OB.getFileName());
80 return;
81 }
82 assert(!InnerBinaries.empty() &&
83 "An offload binary with a magic number should contain at least one "
84 "binary");
85
86 outs().indent(NumSpaces: Level * 2) << left_justify(Str: "nested images", Width: 16)
87 << InnerBinaries.size() << "\n";
88
89 for (uint64_t I = 0, E = InnerBinaries.size(); I != E; ++I) {
90 const OffloadBinary *InnerOB = InnerBinaries[I].getBinary();
91 printBinary(OB: *InnerOB, Index: I, Level: Level + 1, ParentIndexPrefix: ParentIndexPrefix + Twine(Index) + ".");
92 }
93}
94
95/// Print the embedded offloading contents of an ObjectFile \p O.
96void llvm::dumpOffloadBinary(const ObjectFile &O, StringRef ArchName) {
97 if (!O.isELF() && !O.isCOFF()) {
98 reportWarning(
99 Message: "--offloading is currently only supported for COFF and ELF targets",
100 File: O.getFileName());
101 return;
102 }
103
104 SmallVector<OffloadFile> Binaries;
105 if (Error Err = extractOffloadBinaries(Buffer: O.getMemoryBufferRef(), Binaries))
106 reportError(File: O.getFileName(), Message: "while extracting offloading files: " +
107 toString(E: std::move(Err)));
108
109 // Print out all the binaries that are contained in this buffer.
110 for (uint64_t I = 0, E = Binaries.size(); I != E; ++I)
111 printBinary(OB: *Binaries[I].getBinary(), Index: I);
112
113 dumpOffloadBundleFatBinary(O, ArchName);
114}
115
116// Given an Object file, collect all Bundles of FatBin Binaries
117// and dump them into Code Object files
118// if -arch=-name is specified, only dump the Entries that match the target arch
119void llvm::dumpOffloadBundleFatBinary(const ObjectFile &O, StringRef ArchName) {
120 if (!O.isELF() && !O.isCOFF()) {
121 reportWarning(
122 Message: "--offloading is currently only supported for COFF and ELF targets",
123 File: O.getFileName());
124 return;
125 }
126
127 SmallVector<llvm::object::OffloadBundleFatBin> FoundBundles;
128
129 if (Error Err = llvm::object::extractOffloadBundleFatBinary(Obj: O, Bundles&: FoundBundles))
130 reportError(File: O.getFileName(), Message: "while extracting offload FatBin bundles: " +
131 toString(E: std::move(Err)));
132 for (const auto &[BundleNum, Bundle] : llvm::enumerate(First&: FoundBundles)) {
133 for (OffloadBundleEntry &Entry : Bundle.getEntries()) {
134 if (!ArchName.empty() && !StringRef(Entry.ID).contains(Other: ArchName))
135 continue;
136
137 // create file name for this object file: <source-filename>.<Bundle
138 // Number>.<EntryID>
139 std::string str =
140 Bundle.getFileName().str() + "." + itostr(X: BundleNum) + "." + Entry.ID;
141
142 if (Bundle.isDecompressed()) {
143 if (Error Err = object::extractCodeObject(
144 Buffer: Bundle.DecompressedBuffer->getMemBufferRef(), Offset: Entry.Offset,
145 Size: Entry.Size, OutputFileName: StringRef(str)))
146 reportError(File: O.getFileName(),
147 Message: "while extracting offload Bundle Entries: " +
148 toString(E: std::move(Err)));
149 } else {
150 if (Error Err = object::extractCodeObject(Source: O, Offset: Entry.Offset, Size: Entry.Size,
151 OutputFileName: StringRef(str)))
152 reportError(File: O.getFileName(),
153 Message: "while extracting offload Bundle Entries: " +
154 toString(E: std::move(Err)));
155 }
156 outs() << "Extracting offload bundle: " << str << "\n";
157 }
158 }
159}
160
161/// Print the contents of an offload binary file. This may contain multiple
162/// binaries stored in the same buffer.
163void llvm::dumpOffloadSections(MemoryBufferRef Buffer) {
164 SmallVector<OffloadFile> Binaries;
165 if (Error Err = extractOffloadBinaries(Buffer, Binaries))
166 reportError(File: Buffer.getBufferIdentifier(),
167 Message: "while extracting offloading files: " +
168 toString(E: std::move(Err)));
169
170 // Print out all the binaries that are contained in this buffer.
171 for (uint64_t I = 0, E = Binaries.size(); I != E; ++I)
172 printBinary(OB: *Binaries[I].getBinary(), Index: I);
173}
174