[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