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/Object/ELFObjectFile.h"
17#include "llvm/Object/OffloadBinary.h"
18#include "llvm/Object/OffloadBundle.h"
19
20using namespace llvm;
21using namespace llvm::object;
22using namespace llvm::objdump;
23
24void disassembleObject(llvm::object::ObjectFile *, bool InlineRelocs);
25
26/// Get the printable name of the image kind.
27static StringRef getImageName(const OffloadBinary &OB) {
28 switch (OB.getImageKind()) {
29 case IMG_Object:
30 return "elf";
31 case IMG_Bitcode:
32 return "llvm ir";
33 case IMG_Cubin:
34 return "cubin";
35 case IMG_Fatbinary:
36 return "fatbinary";
37 case IMG_PTX:
38 return "ptx";
39 case IMG_SPIRV:
40 return "spir-v";
41 default:
42 return "<none>";
43 }
44}
45
46static void printBinary(const OffloadBinary &OB, uint64_t Index) {
47 outs() << "\nOFFLOADING IMAGE [" << Index << "]:\n";
48 outs() << left_justify(Str: "kind", Width: 16) << getImageName(OB) << "\n";
49 outs() << left_justify(Str: "arch", Width: 16) << OB.getArch() << "\n";
50 outs() << left_justify(Str: "triple", Width: 16) << OB.getTriple() << "\n";
51 outs() << left_justify(Str: "producer", Width: 16)
52 << getOffloadKindName(Name: OB.getOffloadKind()) << "\n";
53}
54
55/// Print the embedded offloading contents of an ObjectFile \p O.
56void llvm::dumpOffloadBinary(const ObjectFile &O, StringRef ArchName) {
57 if (!O.isELF() && !O.isCOFF()) {
58 reportWarning(
59 Message: "--offloading is currently only supported for COFF and ELF targets",
60 File: O.getFileName());
61 return;
62 }
63
64 SmallVector<OffloadFile> Binaries;
65 if (Error Err = extractOffloadBinaries(Buffer: O.getMemoryBufferRef(), Binaries))
66 reportError(File: O.getFileName(), Message: "while extracting offloading files: " +
67 toString(E: std::move(Err)));
68
69 // Print out all the binaries that are contained in this buffer.
70 for (uint64_t I = 0, E = Binaries.size(); I != E; ++I)
71 printBinary(OB: *Binaries[I].getBinary(), Index: I);
72
73 dumpOffloadBundleFatBinary(O, ArchName);
74}
75
76// Given an Object file, collect all Bundles of FatBin Binaries
77// and dump them into Code Object files
78// if -arch=-name is specified, only dump the Entries that match the target arch
79void llvm::dumpOffloadBundleFatBinary(const ObjectFile &O, StringRef ArchName) {
80 if (!O.isELF() && !O.isCOFF()) {
81 reportWarning(
82 Message: "--offloading is currently only supported for COFF and ELF targets",
83 File: O.getFileName());
84 return;
85 }
86
87 SmallVector<llvm::object::OffloadBundleFatBin> FoundBundles;
88
89 if (Error Err = llvm::object::extractOffloadBundleFatBinary(Obj: O, Bundles&: FoundBundles))
90 reportError(File: O.getFileName(), Message: "while extracting offload FatBin bundles: " +
91 toString(E: std::move(Err)));
92 for (const auto &[BundleNum, Bundle] : llvm::enumerate(First&: FoundBundles)) {
93 for (OffloadBundleEntry &Entry : Bundle.getEntries()) {
94 if (!ArchName.empty() && Entry.ID.find(svt: ArchName) != std::string::npos)
95 continue;
96
97 // create file name for this object file: <source-filename>.<Bundle
98 // Number>.<EntryID>
99 std::string str =
100 Bundle.getFileName().str() + "." + itostr(X: BundleNum) + "." + Entry.ID;
101
102 if (Bundle.isDecompressed()) {
103 if (Error Err = object::extractCodeObject(
104 Buffer: Bundle.DecompressedBuffer->getMemBufferRef(), Offset: Entry.Offset,
105 Size: Entry.Size, OutputFileName: StringRef(str)))
106 reportError(File: O.getFileName(),
107 Message: "while extracting offload Bundle Entries: " +
108 toString(E: std::move(Err)));
109 } else {
110 if (Error Err = object::extractCodeObject(Source: O, Offset: Entry.Offset, Size: Entry.Size,
111 OutputFileName: StringRef(str)))
112 reportError(File: O.getFileName(),
113 Message: "while extracting offload Bundle Entries: " +
114 toString(E: std::move(Err)));
115 }
116 outs() << "Extracting offload bundle: " << str << "\n";
117 }
118 }
119}
120
121/// Print the contents of an offload binary file \p OB. This may contain
122/// multiple binaries stored in the same buffer.
123void llvm::dumpOffloadSections(const OffloadBinary &OB) {
124 SmallVector<OffloadFile> Binaries;
125 if (Error Err = extractOffloadBinaries(Buffer: OB.getMemoryBufferRef(), Binaries))
126 reportError(File: OB.getFileName(), Message: "while extracting offloading files: " +
127 toString(E: std::move(Err)));
128
129 // Print out all the binaries that are contained in this buffer.
130 for (uint64_t I = 0, E = Binaries.size(); I != E; ++I)
131 printBinary(OB: *Binaries[I].getBinary(), Index: I);
132}
133