diff --git a/llvm/test/ObjectYAML/Offload/default.yaml b/llvm/test/ObjectYAML/Offload/default.yaml --- a/llvm/test/ObjectYAML/Offload/default.yaml +++ b/llvm/test/ObjectYAML/Offload/default.yaml @@ -1,4 +1,8 @@ -# RUN: yaml2obj %s | obj2yaml | FileCheck %s +# RUN: yaml2obj %s -o %t +# RUN: obj2yaml %t > %t.stdout.yaml +# RUN: obj2yaml %t -o %t.file.yaml 2>&1 | count 0 +# RUN: FileCheck --input-file=%t.stdout.yaml %s +# RUN: diff %t.stdout.yaml %t.file.yaml !Offload Members: - diff --git a/llvm/test/ObjectYAML/wasm/header.yaml b/llvm/test/ObjectYAML/wasm/header.yaml --- a/llvm/test/ObjectYAML/wasm/header.yaml +++ b/llvm/test/ObjectYAML/wasm/header.yaml @@ -1,4 +1,8 @@ -# RUN: yaml2obj %s | obj2yaml | FileCheck %s +# RUN: yaml2obj %s -o %t +# RUN: obj2yaml %t > %t.stdout.yaml +# RUN: obj2yaml %t -o %t.file.yaml 2>&1 | count 0 +# RUN: FileCheck --input-file=%t.stdout.yaml %s +# RUN: diff %t.stdout.yaml %t.file.yaml --- !WASM FileHeader: Version: 0x00000001 diff --git a/llvm/test/tools/obj2yaml/Archives/regular.yaml b/llvm/test/tools/obj2yaml/Archives/regular.yaml --- a/llvm/test/tools/obj2yaml/Archives/regular.yaml +++ b/llvm/test/tools/obj2yaml/Archives/regular.yaml @@ -3,7 +3,10 @@ ## Check how we dump an empty archive. # RUN: yaml2obj %s --docnum=1 -o %t.empty.a -# RUN: obj2yaml %t.empty.a | FileCheck %s --check-prefix=EMPTY +# RUN: obj2yaml %t.empty.a > %t.stdout.yaml +# RUN: obj2yaml %t.empty.a -o %t.file.yaml 2>&1 | count 0 +# RUN: FileCheck --input-file=%t.stdout.yaml %s --check-prefix=EMPTY +# RUN: diff %t.stdout.yaml %t.file.yaml # EMPTY: --- !Arch # EMPTY-NEXT: Members: [] diff --git a/llvm/test/tools/obj2yaml/COFF/test-1.test b/llvm/test/tools/obj2yaml/COFF/test-1.test --- a/llvm/test/tools/obj2yaml/COFF/test-1.test +++ b/llvm/test/tools/obj2yaml/COFF/test-1.test @@ -1,4 +1,7 @@ -# RUN: obj2yaml %S/Inputs/test-1.o | yaml2obj -o %t.o +# RUN: obj2yaml %S/Inputs/test-1.o > %t.stdout.yaml +# RUN: obj2yaml %S/Inputs/test-1.o -o %t.file.yaml 2>&1 | count 0 +# RUN: yaml2obj %t.stdout.yaml -o %t.o # RUN: llvm-pdbutil dump --types %t.o | FileCheck %s -check-prefix=ALL +# RUN: diff %t.stdout.yaml %t.file.yaml # ALL: {{.*}} guid = {00C903AB-0968-4639-84F8-7D3E719A1BE1} diff --git a/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml b/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml --- a/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml +++ b/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml @@ -1,4 +1,8 @@ -# RUN: yaml2obj %s | obj2yaml | FileCheck %s +# RUN: yaml2obj %s -o %t +# RUN: obj2yaml %t > %t.stdout.yaml +# RUN: obj2yaml %t -o %t.file.yaml 2>&1 | count 0 +# RUN: FileCheck --input-file=%t.stdout.yaml %s +# RUN: diff %t.stdout.yaml %t.file.yaml --- !dxcontainer Header: diff --git a/llvm/test/tools/obj2yaml/Minidump/basic.yaml b/llvm/test/tools/obj2yaml/Minidump/basic.yaml --- a/llvm/test/tools/obj2yaml/Minidump/basic.yaml +++ b/llvm/test/tools/obj2yaml/Minidump/basic.yaml @@ -1,4 +1,8 @@ -# RUN: yaml2obj %s | obj2yaml - | FileCheck %s +# RUN: yaml2obj %s -o %t +# RUN: obj2yaml %t > %t.stdout.yaml +# RUN: obj2yaml %t -o %t.file.yaml 2>&1 | count 0 +# RUN: FileCheck --input-file=%t.stdout.yaml %s +# RUN: diff %t.stdout.yaml %t.file.yaml --- !minidump Streams: diff --git a/llvm/test/tools/obj2yaml/XCOFF/aix.yaml b/llvm/test/tools/obj2yaml/XCOFF/aix.yaml --- a/llvm/test/tools/obj2yaml/XCOFF/aix.yaml +++ b/llvm/test/tools/obj2yaml/XCOFF/aix.yaml @@ -2,7 +2,8 @@ # RUN: yaml2obj %s -DMAGIC=0x01DF -o %t-32 # RUN: obj2yaml %t-32 | FileCheck %s --check-prefix=CHECK32 # RUN: yaml2obj %s -DMAGIC=0x01F7 -o %t-64 -# RUN: obj2yaml %t-64 | FileCheck %s --check-prefix=CHECK64 +# RUN: obj2yaml %t-64 -o %t-64.yaml 2>&1 | count 0 +# RUN: FileCheck --input-file %t-64.yaml %s --check-prefix=CHECK64 # CHECK32: --- !XCOFF # CHECK32-NEXT: FileHeader: diff --git a/llvm/test/tools/obj2yaml/output-file.yaml b/llvm/test/tools/obj2yaml/output-file.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/obj2yaml/output-file.yaml @@ -0,0 +1,23 @@ +## Test that -o sets the output file name. + +# RUN: yaml2obj %s -o %t +# RUN: rm -f %t.yaml && obj2yaml %t -o %t.yaml +# RUN: ls %t.yaml +# RUN: rm -f %t.yaml && cat %t | obj2yaml -o%t.yaml +# RUN: ls %t.yaml + +## In case of an error, don't create the output file. +# RUN: rm -f %t.yaml +# RUN: echo | not obj2yaml -o %t.yaml +# RUN: not ls %t.yaml + +# RUN: not obj2yaml %t -o %p/path/does/not/exist 2>&1 | FileCheck -DMSG=%errc_ENOENT %s + +# CHECK: obj2yaml: error: failed to open '{{.*}}/path/does/not/exist': [[MSG]] + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_NONE diff --git a/llvm/tools/obj2yaml/obj2yaml.cpp b/llvm/tools/obj2yaml/obj2yaml.cpp --- a/llvm/tools/obj2yaml/obj2yaml.cpp +++ b/llvm/tools/obj2yaml/obj2yaml.cpp @@ -14,35 +14,40 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Errc.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/WithColor.h" using namespace llvm; using namespace llvm::object; static cl::opt InputFilename(cl::Positional, cl::desc(""), cl::init("-")); +static cl::opt OutputFilename("o", cl::desc("Output filename"), + cl::value_desc("filename"), + cl::init("-"), cl::Prefix); static cl::bits RawSegment( "raw-segment", cl::desc("Mach-O: dump the raw contents of the listed segments instead of " "parsing them:"), cl::values(clEnumVal(data, "__DATA"), clEnumVal(linkedit, "__LINKEDIT"))); -static Error dumpObject(const ObjectFile &Obj) { +static Error dumpObject(const ObjectFile &Obj, raw_ostream &OS) { if (Obj.isCOFF()) - return errorCodeToError(coff2yaml(outs(), cast(Obj))); + return errorCodeToError(coff2yaml(OS, cast(Obj))); if (Obj.isXCOFF()) - return xcoff2yaml(outs(), cast(Obj)); + return xcoff2yaml(OS, cast(Obj)); if (Obj.isELF()) - return elf2yaml(outs(), Obj); + return elf2yaml(OS, Obj); if (Obj.isWasm()) - return errorCodeToError(wasm2yaml(outs(), cast(Obj))); + return errorCodeToError(wasm2yaml(OS, cast(Obj))); llvm_unreachable("unexpected object file format"); } -static Error dumpInput(StringRef File) { +static Error dumpInput(StringRef File, raw_ostream &OS) { ErrorOr> FileOrErr = MemoryBuffer::getFileOrSTDIN(File, /*IsText=*/false, /*RequiresNullTerminator=*/false); @@ -52,11 +57,11 @@ MemoryBufferRef MemBuf = Buffer->getMemBufferRef(); switch (identify_magic(MemBuf.getBuffer())) { case file_magic::archive: - return archive2yaml(outs(), MemBuf); + return archive2yaml(OS, MemBuf); case file_magic::dxcontainer_object: - return dxcontainer2yaml(outs(), MemBuf); + return dxcontainer2yaml(OS, MemBuf); case file_magic::offload_binary: - return offload2yaml(outs(), MemBuf); + return offload2yaml(OS, MemBuf); default: break; } @@ -70,11 +75,11 @@ // Universal MachO is not a subclass of ObjectFile, so it needs to be handled // here with the other binary types. if (Binary.isMachO() || Binary.isMachOUniversalBinary()) - return macho2yaml(outs(), Binary, RawSegment.getBits()); + return macho2yaml(OS, Binary, RawSegment.getBits()); if (ObjectFile *Obj = dyn_cast(&Binary)) - return dumpObject(*Obj); + return dumpObject(*Obj, OS); if (MinidumpFile *Minidump = dyn_cast(&Binary)) - return minidump2yaml(outs(), *Minidump); + return minidump2yaml(OS, *Minidump); return Error::success(); } @@ -94,10 +99,19 @@ InitLLVM X(argc, argv); cl::ParseCommandLineOptions(argc, argv); - if (Error Err = dumpInput(InputFilename)) { + std::error_code EC; + std::unique_ptr Out( + new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None)); + if (EC) { + WithColor::error(errs(), "obj2yaml") + << "failed to open '" + OutputFilename + "': " + EC.message() << '\n'; + return 1; + } + if (Error Err = dumpInput(InputFilename, Out->os())) { reportError(InputFilename, std::move(Err)); return 1; } + Out->keep(); return 0; }