[llvm] d2d8b0a - [llvm-objdump] Add support for dumping embedded offloading data
Joseph Huber via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 1 18:13:44 PDT 2022
Author: Joseph Huber
Date: 2022-07-01T21:13:28-04:00
New Revision: d2d8b0aa4f80752722321d1e74e2d98761caaa61
URL: https://github.com/llvm/llvm-project/commit/d2d8b0aa4f80752722321d1e74e2d98761caaa61
DIFF: https://github.com/llvm/llvm-project/commit/d2d8b0aa4f80752722321d1e74e2d98761caaa61.diff
LOG: [llvm-objdump] Add support for dumping embedded offloading data
In Clang/LLVM we are moving towards a new binary format to store many
embedded object files to create a fatbinary. This patch adds support for
dumping these embedded images in the `llvm-objdump` tool. This will
allow users to query information about what is stored inside the binary.
This has very similar functionality to the `cuobjdump` tool for thoe familiar
with the Nvidia utilities. The proposed use is as follows:
```
$ clang input.c -fopenmp --offload-arch=sm_70 --offload-arch=sm_52 -c
$ llvm-objdump -O input.o
input.o: file format elf64-x86-64
OFFLOADIND IMAGE [0]:
kind cubin
arch sm_52
triple nvptx64-nvidia-cuda
producer openmp
OFFLOADIND IMAGE [1]:
kind cubin
arch sm_70
triple nvptx64-nvidia-cuda
producer openmp
```
This will be expanded further once we start embedding more information
into these offloading images. Right now we are planning on adding
flags and entries for debug level, optimization, LTO usage, target
features, among others.
This patch only supports printing these sections, later we will want to
support dumping files the user may be interested in via another flag. I
am unsure if this should go here in `llvm-objdump` or `llvm-objcopy`.
Reviewed By: MaskRay, tra, jhenderson, JonChesterfield
Differential Revision: https://reviews.llvm.org/D126904
Added:
llvm/test/tools/llvm-objdump/Offloading/Inputs/binary.yaml
llvm/test/tools/llvm-objdump/Offloading/Inputs/malformed.yaml
llvm/test/tools/llvm-objdump/Offloading/binary.test
llvm/test/tools/llvm-objdump/Offloading/content-failure.test
llvm/test/tools/llvm-objdump/Offloading/failure.test
llvm/test/tools/llvm-objdump/Offloading/warning.test
llvm/tools/llvm-objdump/OffloadDump.cpp
llvm/tools/llvm-objdump/OffloadDump.h
Modified:
llvm/tools/llvm-objdump/CMakeLists.txt
llvm/tools/llvm-objdump/ObjdumpOpts.td
llvm/tools/llvm-objdump/llvm-objdump.cpp
Removed:
################################################################################
diff --git a/llvm/test/tools/llvm-objdump/Offloading/Inputs/binary.yaml b/llvm/test/tools/llvm-objdump/Offloading/Inputs/binary.yaml
new file mode 100644
index 0000000000000..703c93b24dcc0
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/Offloading/Inputs/binary.yaml
@@ -0,0 +1,30 @@
+!Offload
+Members:
+ - ImageKind: IMG_Bitcode
+ OffloadKind: OFK_OpenMP
+ String:
+ - Key: "triple"
+ Value: "amdgcn-amd-amdhsa"
+ - Key: "arch"
+ Value: "gfx908"
+ - ImageKind: IMG_Bitcode
+ OffloadKind: OFK_OpenMP
+ String:
+ - Key: "triple"
+ Value: "amdgcn-amd-amdhsa"
+ - Key: "arch"
+ Value: "gfx90a"
+ - ImageKind: IMG_Cubin
+ OffloadKind: OFK_OpenMP
+ String:
+ - Key: "triple"
+ Value: "nvptx64-nvidia-cuda"
+ - Key: "arch"
+ Value: "sm_52"
+ - ImageKind: IMG_None
+ OffloadKind: OFK_None
+ String:
+ - Key: "triple"
+ Value: "nvptx64-nvidia-cuda"
+ - Key: "arch"
+ Value: "sm_70"
diff --git a/llvm/test/tools/llvm-objdump/Offloading/Inputs/malformed.yaml b/llvm/test/tools/llvm-objdump/Offloading/Inputs/malformed.yaml
new file mode 100644
index 0000000000000..016917831fe04
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/Offloading/Inputs/malformed.yaml
@@ -0,0 +1,12 @@
+!Offload
+EntryOffset: 999999999
+Members:
+ - ImageKind: IMG_Cubin
+ OffloadKind: OFK_OpenMP
+ Flags: 0
+ String:
+ - Key: "triple"
+ Value: "nvptx64-nvidia-cuda"
+ - Key: "arch"
+ Value: "sm_70"
+ Content: "deadbeef"
diff --git a/llvm/test/tools/llvm-objdump/Offloading/binary.test b/llvm/test/tools/llvm-objdump/Offloading/binary.test
new file mode 100644
index 0000000000000..3e2b711057b8c
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/Offloading/binary.test
@@ -0,0 +1,40 @@
+## Check that we can dump an offloading binary directly.
+# RUN: yaml2obj %S/Inputs/binary.yaml -o %t.bin
+# RUN: llvm-objdump --offloading %t.bin | FileCheck %s --match-full-lines --strict-whitespace --implicit-check-not={{.}}
+
+## Check that we can dump an offloading binary inside of an ELF section.
+# RUN: yaml2obj %s -o %t.elf
+# RUN: llvm-objcopy --add-section .llvm.offloading=%t.bin %t.elf
+# RUN: llvm-objdump --offloading %t.elf | FileCheck %s --check-prefixes=CHECK,ELF --match-full-lines --strict-whitespace --implicit-check-not={{.}}
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+
+# ELF:{{.*}}file format elf64-unknown
+# ELF-EMPTY:
+# CHECK:OFFLOADING IMAGE [0]:
+# CHECK-NEXT:kind llvm ir
+# CHECK-NEXT:arch gfx908
+# CHECK-NEXT:triple amdgcn-amd-amdhsa
+# CHECK-NEXT:producer openmp
+# CHECK-EMPTY:
+# CHECK-NEXT:OFFLOADING IMAGE [1]:
+# CHECK-NEXT:kind llvm ir
+# CHECK-NEXT:arch gfx90a
+# CHECK-NEXT:triple amdgcn-amd-amdhsa
+# CHECK-NEXT:producer openmp
+# CHECK-EMPTY:
+# CHECK-NEXT:OFFLOADING IMAGE [2]:
+# CHECK-NEXT:kind cubin
+# CHECK-NEXT:arch sm_52
+# CHECK-NEXT:triple nvptx64-nvidia-cuda
+# CHECK-NEXT:producer openmp
+# CHECK-EMPTY:
+# CHECK-NEXT:OFFLOADING IMAGE [3]:
+# CHECK-NEXT:kind <none>
+# CHECK-NEXT:arch sm_70
+# CHECK-NEXT:triple nvptx64-nvidia-cuda
+# CHECK-NEXT:producer none
diff --git a/llvm/test/tools/llvm-objdump/Offloading/content-failure.test b/llvm/test/tools/llvm-objdump/Offloading/content-failure.test
new file mode 100644
index 0000000000000..d445226ce5166
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/Offloading/content-failure.test
@@ -0,0 +1,18 @@
+# Test to check if we fail to get the section contents.
+# RUN: yaml2obj %s -o %t
+# RUN: not llvm-objdump --offloading %t 2>&1 | FileCheck -DFILENAME=%t %s
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+Sections:
+ - Name: .llvm.offloading
+ Type: SHT_PROGBITS
+ Flags: [ SHF_EXCLUDE ]
+ Address: 0x0
+ ShOffset: 0x99999
+ AddressAlign: 0x0000000000000008
+
+# CHECK: error: '[[FILENAME]]': The end of the file was unexpectedly encountered
diff --git a/llvm/test/tools/llvm-objdump/Offloading/failure.test b/llvm/test/tools/llvm-objdump/Offloading/failure.test
new file mode 100644
index 0000000000000..854d8e00f3fa8
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/Offloading/failure.test
@@ -0,0 +1,17 @@
+# RUN: yaml2obj %s -o %t
+# RUN: not llvm-objdump --offloading %t 2>&1 | FileCheck -DFILENAME=%t %s
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+Sections:
+ - Name: .llvm.offloading
+ Type: SHT_PROGBITS
+ Flags: [ SHF_EXCLUDE ]
+ Address: 0x0
+ AddressAlign: 0x0000000000000008
+ Content: "10ffb0ad"
+
+# CHECK: error: '[[FILENAME]]': while extracting offloading files: Invalid data was encountered while parsing the file
diff --git a/llvm/test/tools/llvm-objdump/Offloading/warning.test b/llvm/test/tools/llvm-objdump/Offloading/warning.test
new file mode 100644
index 0000000000000..a7ce7db3d7f96
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/Offloading/warning.test
@@ -0,0 +1,16 @@
+## Ensure we give a warning on bad input following good input.
+# RUN: yaml2obj %S/Inputs/binary.yaml -o %t-good.bin
+# RUN: yaml2obj %S/Inputs/malformed.yaml -o %t-bad.bin
+# RUN: cat %t-bad.bin >> %t-good.bin
+# RUN: yaml2obj %s -o %t.elf
+# RUN: llvm-objcopy --add-section .llvm.offloading=%t-good.bin %t.elf
+# RUN: llvm-objdump --offloading %t.elf 2>&1 | FileCheck %s -DFILENAME=%t.elf
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+
+# CHECK: OFFLOADING IMAGE [0]:
+# CHECK: warning: '[[FILENAME]]': while parsing offloading files: The end of the file was unexpectedly encountered
diff --git a/llvm/tools/llvm-objdump/CMakeLists.txt b/llvm/tools/llvm-objdump/CMakeLists.txt
index 051c7f5d3454c..2179728e4a8c2 100644
--- a/llvm/tools/llvm-objdump/CMakeLists.txt
+++ b/llvm/tools/llvm-objdump/CMakeLists.txt
@@ -28,6 +28,7 @@ add_llvm_tool(llvm-objdump
COFFDump.cpp
ELFDump.cpp
MachODump.cpp
+ OffloadDump.cpp
WasmDump.cpp
XCOFFDump.cpp
DEPENDS
diff --git a/llvm/tools/llvm-objdump/ObjdumpOpts.td b/llvm/tools/llvm-objdump/ObjdumpOpts.td
index 5b35ada6e124a..00d7d8ccff171 100644
--- a/llvm/tools/llvm-objdump/ObjdumpOpts.td
+++ b/llvm/tools/llvm-objdump/ObjdumpOpts.td
@@ -81,6 +81,9 @@ def dwarf_EQ : Joined<["--"], "dwarf=">,
def fault_map_section : Flag<["--"], "fault-map-section">,
HelpText<"Display the content of the fault map section">;
+def offloading : Flag<["--"], "offloading">,
+ HelpText<"Display the content of the offloading section">;
+
def file_headers : Flag<["--"], "file-headers">,
HelpText<"Display the contents of the overall file header">;
def : Flag<["-"], "f">, Alias<file_headers>,
diff --git a/llvm/tools/llvm-objdump/OffloadDump.cpp b/llvm/tools/llvm-objdump/OffloadDump.cpp
new file mode 100644
index 0000000000000..7d4461f0a70ec
--- /dev/null
+++ b/llvm/tools/llvm-objdump/OffloadDump.cpp
@@ -0,0 +1,102 @@
+//===-- OffloadDump.cpp - Offloading dumper ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the offloading-specific dumper for llvm-objdump.
+///
+//===----------------------------------------------------------------------===//
+#include "OffloadDump.h"
+#include "llvm-objdump.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::objdump;
+
+constexpr const char OffloadSectionString[] = ".llvm.offloading";
+
+/// Get the printable name of the image kind.
+static StringRef getImageName(const OffloadBinary &OB) {
+ switch (OB.getImageKind()) {
+ case IMG_Object:
+ return "elf";
+ case IMG_Bitcode:
+ return "llvm ir";
+ case IMG_Cubin:
+ return "cubin";
+ case IMG_Fatbinary:
+ return "fatbinary";
+ case IMG_PTX:
+ return "ptx";
+ default:
+ return "<none>";
+ }
+}
+
+static void printBinary(const OffloadBinary &OB, uint64_t Index) {
+ outs() << "\nOFFLOADING IMAGE [" << Index << "]:\n";
+ outs() << left_justify("kind", 16) << getImageName(OB) << "\n";
+ outs() << left_justify("arch", 16) << OB.getArch() << "\n";
+ outs() << left_justify("triple", 16) << OB.getTriple() << "\n";
+ outs() << left_justify("producer", 16)
+ << getOffloadKindName(OB.getOffloadKind()) << "\n";
+}
+
+static Error visitAllBinaries(const OffloadBinary &OB) {
+ uint64_t Offset = 0;
+ uint64_t Index = 0;
+ while (Offset < OB.getMemoryBufferRef().getBufferSize()) {
+ MemoryBufferRef Buffer =
+ MemoryBufferRef(OB.getData().drop_front(Offset), OB.getFileName());
+ auto BinaryOrErr = OffloadBinary::create(Buffer);
+ if (!BinaryOrErr)
+ return BinaryOrErr.takeError();
+
+ OffloadBinary &Binary = **BinaryOrErr;
+ printBinary(Binary, Index++);
+
+ Offset += Binary.getSize();
+ }
+ return Error::success();
+}
+
+/// Print the embedded offloading contents of an ObjectFile \p O.
+void llvm::dumpOffloadBinary(const ObjectFile &O) {
+ for (SectionRef Sec : O.sections()) {
+ Expected<StringRef> Name = Sec.getName();
+ if (!Name || !Name->startswith(OffloadSectionString))
+ continue;
+
+ Expected<StringRef> Contents = Sec.getContents();
+ if (!Contents)
+ reportError(Contents.takeError(), O.getFileName());
+
+ MemoryBufferRef Buffer = MemoryBufferRef(*Contents, O.getFileName());
+ auto BinaryOrErr = OffloadBinary::create(Buffer);
+ if (!BinaryOrErr)
+ reportError(O.getFileName(), "while extracting offloading files: " +
+ toString(BinaryOrErr.takeError()));
+ OffloadBinary &Binary = **BinaryOrErr;
+
+ // Print out all the binaries that are contained in this buffer. If we fail
+ // to parse a binary before reaching the end of the buffer emit a warning.
+ if (Error Err = visitAllBinaries(Binary))
+ reportWarning("while parsing offloading files: " +
+ toString(std::move(Err)),
+ O.getFileName());
+ }
+}
+
+/// Print the contents of an offload binary file \p OB. This may contain
+/// multiple binaries stored in the same buffer.
+void llvm::dumpOffloadSections(const OffloadBinary &OB) {
+ // Print out all the binaries that are contained at this buffer. If we fail to
+ // parse a binary before reaching the end of the buffer emit a warning.
+ if (Error Err = visitAllBinaries(OB))
+ reportWarning("while parsing offloading files: " + toString(std::move(Err)),
+ OB.getFileName());
+}
diff --git a/llvm/tools/llvm-objdump/OffloadDump.h b/llvm/tools/llvm-objdump/OffloadDump.h
new file mode 100644
index 0000000000000..75f188e9d5065
--- /dev/null
+++ b/llvm/tools/llvm-objdump/OffloadDump.h
@@ -0,0 +1,22 @@
+//===-- OffloadDump.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_OBJDUMP_OFFLOADDUMP_H
+#define LLVM_TOOLS_LLVM_OBJDUMP_OFFLOADDUMP_H
+
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/OffloadBinary.h"
+
+namespace llvm {
+
+void dumpOffloadSections(const object::OffloadBinary &OB);
+void dumpOffloadBinary(const object::ObjectFile &O);
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index dc7083b70eb7e..7cd47da9efd97 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -20,6 +20,7 @@
#include "ELFDump.h"
#include "MachODump.h"
#include "ObjdumpOptID.h"
+#include "OffloadDump.h"
#include "SourcePrinter.h"
#include "WasmDump.h"
#include "XCOFFDump.h"
@@ -58,6 +59,7 @@
#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/OffloadBinary.h"
#include "llvm/Object/Wasm.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
@@ -198,6 +200,7 @@ std::string objdump::MCPU;
std::vector<std::string> objdump::MAttrs;
bool objdump::ShowRawInsn;
bool objdump::LeadingAddr;
+static bool Offloading;
static bool RawClangAST;
bool objdump::Relocations;
bool objdump::PrintImmHex;
@@ -2480,6 +2483,8 @@ static void dumpObject(ObjectFile *O, const Archive *A = nullptr,
printRawClangAST(O);
if (FaultMapSection)
printFaultMaps(O);
+ if (Offloading)
+ dumpOffloadBinary(*O);
}
static void dumpObject(const COFFImportFile *I, const Archive *A,
@@ -2543,6 +2548,8 @@ static void dumpInput(StringRef file) {
dumpObject(O);
else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Binary))
parseInputMachO(UB);
+ else if (OffloadBinary *OB = dyn_cast<OffloadBinary>(&Binary))
+ dumpOffloadSections(*OB);
else
reportError(errorCodeToError(object_error::invalid_file_type), file);
}
@@ -2646,6 +2653,7 @@ static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) {
}
DynamicRelocations = InputArgs.hasArg(OBJDUMP_dynamic_reloc);
FaultMapSection = InputArgs.hasArg(OBJDUMP_fault_map_section);
+ Offloading = InputArgs.hasArg(OBJDUMP_offloading);
FileHeaders = InputArgs.hasArg(OBJDUMP_file_headers);
SectionContents = InputArgs.hasArg(OBJDUMP_full_contents);
PrintLines = InputArgs.hasArg(OBJDUMP_line_numbers);
@@ -2813,7 +2821,7 @@ int main(int argc, char **argv) {
if (!ArchiveHeaders && !Disassemble && DwarfDumpType == DIDT_Null &&
!DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST &&
!Relocations && !SectionHeaders && !SectionContents && !SymbolTable &&
- !DynamicSymbolTable && !UnwindInfo && !FaultMapSection &&
+ !DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !Offloading &&
!(MachOOpt && (Bind || DataInCode || DyldInfo || DylibId || DylibsUsed ||
ExportsTrie || FirstPrivateHeader || FunctionStarts ||
IndirectSymbols || InfoPlist || LazyBind || LinkOptHints ||
More information about the llvm-commits
mailing list