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 #include "OffloadDump.h"
14 #include "llvm-objdump.h"
15 #include "llvm/Object/ELFObjectFile.h"
16 #include "llvm/Support/Alignment.h"
17 
18 using namespace llvm;
19 using namespace llvm::object;
20 using namespace llvm::objdump;
21 
22 /// Get the printable name of the image kind.
23 static StringRef getImageName(const OffloadBinary &OB) {
24   switch (OB.getImageKind()) {
25   case IMG_Object:
26     return "elf";
27   case IMG_Bitcode:
28     return "llvm ir";
29   case IMG_Cubin:
30     return "cubin";
31   case IMG_Fatbinary:
32     return "fatbinary";
33   case IMG_PTX:
34     return "ptx";
35   default:
36     return "<none>";
37   }
38 }
39 
40 static void printBinary(const OffloadBinary &OB, uint64_t Index) {
41   outs() << "\nOFFLOADING IMAGE [" << Index << "]:\n";
42   outs() << left_justify("kind", 16) << getImageName(OB) << "\n";
43   outs() << left_justify("arch", 16) << OB.getArch() << "\n";
44   outs() << left_justify("triple", 16) << OB.getTriple() << "\n";
45   outs() << left_justify("producer", 16)
46          << getOffloadKindName(OB.getOffloadKind()) << "\n";
47 }
48 
49 static Error visitAllBinaries(const OffloadBinary &OB) {
50   uint64_t Offset = 0;
51   uint64_t Index = 0;
52   while (Offset < OB.getMemoryBufferRef().getBufferSize()) {
53     MemoryBufferRef Buffer =
54         MemoryBufferRef(OB.getData().drop_front(Offset), OB.getFileName());
55     auto BinaryOrErr = OffloadBinary::create(Buffer);
56     if (!BinaryOrErr)
57       return BinaryOrErr.takeError();
58 
59     OffloadBinary &Binary = **BinaryOrErr;
60     printBinary(Binary, Index++);
61 
62     Offset += Binary.getSize();
63   }
64   return Error::success();
65 }
66 
67 /// Print the embedded offloading contents of an ObjectFile \p O.
68 void llvm::dumpOffloadBinary(const ObjectFile &O) {
69   if (!O.isELF()) {
70     reportWarning("--offloading is currently only supported for ELF targets",
71                   O.getFileName());
72     return;
73   }
74 
75   for (ELFSectionRef Sec : O.sections()) {
76     if (Sec.getType() != ELF::SHT_LLVM_OFFLOADING)
77       continue;
78 
79     Expected<StringRef> Contents = Sec.getContents();
80     if (!Contents)
81       reportError(Contents.takeError(), O.getFileName());
82 
83     std::unique_ptr<MemoryBuffer> Buffer =
84         MemoryBuffer::getMemBuffer(*Contents, O.getFileName(), false);
85     if (!isAddrAligned(Align(OffloadBinary::getAlignment()),
86                        Buffer->getBufferStart()))
87       Buffer = MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(),
88                                               Buffer->getBufferIdentifier());
89     auto BinaryOrErr = OffloadBinary::create(*Buffer);
90     if (!BinaryOrErr)
91       reportError(O.getFileName(), "while extracting offloading files: " +
92                                        toString(BinaryOrErr.takeError()));
93     OffloadBinary &Binary = **BinaryOrErr;
94 
95     // Print out all the binaries that are contained in this buffer. If we fail
96     // to parse a binary before reaching the end of the buffer emit a warning.
97     if (Error Err = visitAllBinaries(Binary))
98       reportWarning("while parsing offloading files: " +
99                         toString(std::move(Err)),
100                     O.getFileName());
101   }
102 }
103 
104 /// Print the contents of an offload binary file \p OB. This may contain
105 /// multiple binaries stored in the same buffer.
106 void llvm::dumpOffloadSections(const OffloadBinary &OB) {
107   // Print out all the binaries that are contained at this buffer. If we fail to
108   // parse a binary before reaching the end of the buffer emit a warning.
109   if (Error Err = visitAllBinaries(OB))
110     reportWarning("while parsing offloading files: " + toString(std::move(Err)),
111                   OB.getFileName());
112 }
113