15 changes: 15 additions & 0 deletions llvm/test/ObjectYAML/Offload/malformed-entry-size.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s
!Offload
EntrySize: 999999999
Members:
- ImageKind: IMG_Cubin
OffloadKind: OFK_OpenMP
Flags: 0
String:
- Key: "triple"
Value: "nvptx64-nvidia-cuda"
- Key: "arch"
Value: "sm_70"
Content: "deadbeef"

# CHECK: Error reading file: <stdin>: The end of the file was unexpectedly encountered
15 changes: 15 additions & 0 deletions llvm/test/ObjectYAML/Offload/malformed-offset.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s
!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"

# CHECK: Error reading file: <stdin>: The end of the file was unexpectedly encountered
15 changes: 15 additions & 0 deletions llvm/test/ObjectYAML/Offload/malformed-size.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s
!Offload
Size: 999999999
Members:
- ImageKind: IMG_Cubin
OffloadKind: OFK_OpenMP
Flags: 0
String:
- Key: "triple"
Value: "nvptx64-nvidia-cuda"
- Key: "arch"
Value: "sm_70"
Content: "deadbeef"

# CHECK: Error reading file: <stdin>: The end of the file was unexpectedly encountered
15 changes: 15 additions & 0 deletions llvm/test/ObjectYAML/Offload/malformed-version.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# RUN: yaml2obj %s | not obj2yaml 2>&1 | FileCheck %s
!Offload
Version: 2
Members:
- ImageKind: IMG_Cubin
OffloadKind: OFK_OpenMP
Flags: 0
String:
- Key: "triple"
Value: "nvptx64-nvidia-cuda"
- Key: "arch"
Value: "sm_70"
Content: "deadbeef"

# CHECK: Error reading file: <stdin>: Invalid data was encountered while parsing the file
43 changes: 43 additions & 0 deletions llvm/test/ObjectYAML/Offload/multiple_members.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# RUN: yaml2obj %s | obj2yaml | FileCheck %s
!Offload
Members:
- ImageKind: IMG_Cubin
OffloadKind: OFK_OpenMP
Flags: 0
String:
- Key: "triple"
Value: "nvptx64-nvidia-cuda"
- Key: "arch"
Value: "sm_70"
Content: "deadbeef"
- ImageKind: IMG_Bitcode
OffloadKind: OFK_OpenMP
Flags: 0
String:
- Key: "triple"
Value: "amdgcn-amd-amdhsa"
- Key: "arch"
Value: "gfx908"
Content: "cafefeed"

# CHECK: --- !Offload
# CHECK-NEXT: Members:
# CHECK-NEXT: - ImageKind: IMG_Cubin
# CHECK-NEXT: OffloadKind: OFK_OpenMP
# CHECK-NEXT: Flags: 0
# CHECK-NEXT: String:
# CHECK-NEXT: - Key: triple
# CHECK-NEXT: Value: nvptx64-nvidia-cuda
# CHECK-NEXT: - Key: arch
# CHECK-NEXT: Value: sm_70
# CHECK-NEXT: Content: DEADBEEF
# CHECK-NEXT: - ImageKind: IMG_Bitcode
# CHECK-NEXT: OffloadKind: OFK_OpenMP
# CHECK-NEXT: Flags: 0
# CHECK-NEXT: String:
# CHECK-NEXT: - Key: triple
# CHECK-NEXT: Value: amdgcn-amd-amdhsa
# CHECK-NEXT: - Key: arch
# CHECK-NEXT: Value: gfx908
# CHECK-NEXT: Content: CAFEFEED
# CHECK-NEXT: ...
30 changes: 30 additions & 0 deletions llvm/test/tools/llvm-objdump/Offloading/Inputs/binary.yaml
Original file line number Diff line number Diff line change
@@ -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"
12 changes: 12 additions & 0 deletions llvm/test/tools/llvm-objdump/Offloading/Inputs/malformed.yaml
Original file line number Diff line number Diff line change
@@ -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"
40 changes: 40 additions & 0 deletions llvm/test/tools/llvm-objdump/Offloading/binary.test
Original file line number Diff line number Diff line change
@@ -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
18 changes: 18 additions & 0 deletions llvm/test/tools/llvm-objdump/Offloading/content-failure.test
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions llvm/test/tools/llvm-objdump/Offloading/failure.test
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions llvm/test/tools/llvm-objdump/Offloading/warning.test
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions llvm/tools/llvm-objdump/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ add_llvm_tool(llvm-objdump
COFFDump.cpp
ELFDump.cpp
MachODump.cpp
OffloadDump.cpp
WasmDump.cpp
XCOFFDump.cpp
DEPENDS
Expand Down
3 changes: 3 additions & 0 deletions llvm/tools/llvm-objdump/ObjdumpOpts.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
102 changes: 102 additions & 0 deletions llvm/tools/llvm-objdump/OffloadDump.cpp
Original file line number Diff line number Diff line change
@@ -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());
}
22 changes: 22 additions & 0 deletions llvm/tools/llvm-objdump/OffloadDump.h
Original file line number Diff line number Diff line change
@@ -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
10 changes: 9 additions & 1 deletion llvm/tools/llvm-objdump/llvm-objdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 ||
Expand Down
1 change: 1 addition & 0 deletions llvm/tools/obj2yaml/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ add_llvm_utility(obj2yaml
elf2yaml.cpp
macho2yaml.cpp
minidump2yaml.cpp
offload2yaml.cpp
xcoff2yaml.cpp
wasm2yaml.cpp
)
2 changes: 2 additions & 0 deletions llvm/tools/obj2yaml/obj2yaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ static Error dumpInput(StringRef File) {
return archive2yaml(outs(), MemBuf);
case file_magic::dxcontainer_object:
return dxcontainer2yaml(outs(), MemBuf);
case file_magic::offload_binary:
return offload2yaml(outs(), MemBuf);
default:
break;
}
Expand Down
7 changes: 4 additions & 3 deletions llvm/tools/obj2yaml/obj2yaml.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
#include "llvm/Object/Minidump.h"
#include "llvm/Object/Wasm.h"
#include "llvm/Object/XCOFFObjectFile.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>

enum RawSegments : unsigned { none = 0, data = 1, linkedit = 1 << 1 };
std::error_code coff2yaml(llvm::raw_ostream &Out,
const llvm::object::COFFObjectFile &Obj);
llvm::Error elf2yaml(llvm::raw_ostream &Out,
const llvm::object::ObjectFile &Obj);
const llvm::object::ObjectFile &Obj);
llvm::Error macho2yaml(llvm::raw_ostream &Out, const llvm::object::Binary &Obj,
unsigned RawSegments);
llvm::Error minidump2yaml(llvm::raw_ostream &Out,
Expand All @@ -34,6 +34,7 @@ llvm::Error xcoff2yaml(llvm::raw_ostream &Out,
std::error_code wasm2yaml(llvm::raw_ostream &Out,
const llvm::object::WasmObjectFile &Obj);
llvm::Error archive2yaml(llvm::raw_ostream &Out, llvm::MemoryBufferRef Source);
llvm::Error offload2yaml(llvm::raw_ostream &Out, llvm::MemoryBufferRef Source);
llvm::Error dxcontainer2yaml(llvm::raw_ostream &Out,
llvm::MemoryBufferRef Source);

Expand All @@ -43,7 +44,7 @@ class DWARFContext;
namespace DWARFYAML {
struct Data;
}
}
} // namespace llvm

void dumpDebugAbbrev(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
llvm::Error dumpDebugAddr(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
Expand Down
82 changes: 82 additions & 0 deletions llvm/tools/obj2yaml/offload2yaml.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//===------ offload2yaml.cpp - obj2yaml conversion tool ---*- 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
//
//===----------------------------------------------------------------------===//

#include "obj2yaml.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Object/OffloadBinary.h"
#include "llvm/ObjectYAML/OffloadYAML.h"
#include "llvm/Support/StringSaver.h"

using namespace llvm;

namespace {

void populateYAML(OffloadYAML::Binary &YAMLBinary, object::OffloadBinary &OB,
UniqueStringSaver Saver) {
YAMLBinary.Members.emplace_back();
auto &Member = YAMLBinary.Members.back();
Member.ImageKind = OB.getImageKind();
Member.OffloadKind = OB.getOffloadKind();
Member.Flags = OB.getFlags();
if (!OB.strings().empty()) {
Member.StringEntries = std::vector<OffloadYAML::Binary::StringEntry>();
for (const auto &Entry : OB.strings())
Member.StringEntries->emplace_back(OffloadYAML::Binary::StringEntry(
{Saver.save(Entry.getKey()), Saver.save(Entry.getValue())}));
}

if (!OB.getImage().empty())
Member.Content = arrayRefFromStringRef(OB.getImage());
}

Expected<OffloadYAML::Binary *> dump(MemoryBufferRef Source,
UniqueStringSaver Saver) {
Expected<std::unique_ptr<object::OffloadBinary>> OB =
object::OffloadBinary::create(Source);
if (!OB)
return OB.takeError();

std::unique_ptr<OffloadYAML::Binary> YAMLBinary =
std::make_unique<OffloadYAML::Binary>();

YAMLBinary->Members = std::vector<OffloadYAML::Binary::Member>();

uint64_t Offset = 0;
while (Offset < (*OB)->getMemoryBufferRef().getBufferSize()) {
MemoryBufferRef Buffer = MemoryBufferRef(
(*OB)->getData().drop_front(Offset), (*OB)->getFileName());
auto BinaryOrErr = object::OffloadBinary::create(Buffer);
if (!BinaryOrErr)
return BinaryOrErr.takeError();

object::OffloadBinary &Binary = **BinaryOrErr;

populateYAML(*YAMLBinary, Binary, Saver);

Offset += Binary.getSize();
}

return YAMLBinary.release();
}

} // namespace

Error offload2yaml(raw_ostream &Out, MemoryBufferRef Source) {
BumpPtrAllocator Alloc;
UniqueStringSaver Saver(Alloc);

Expected<OffloadYAML::Binary *> YAMLOrErr = dump(Source, Saver);
if (!YAMLOrErr)
return YAMLOrErr.takeError();

std::unique_ptr<OffloadYAML::Binary> YAML(YAMLOrErr.get());
yaml::Output Yout(Out);
Yout << *YAML;

return Error::success();
}