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