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