1 //===------ utils/obj2yaml.cpp - obj2yaml conversion tool -----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "obj2yaml.h" 10 #include "llvm/BinaryFormat/Magic.h" 11 #include "llvm/Object/Archive.h" 12 #include "llvm/Object/COFF.h" 13 #include "llvm/Object/Minidump.h" 14 #include "llvm/Support/CommandLine.h" 15 #include "llvm/Support/Errc.h" 16 #include "llvm/Support/InitLLVM.h" 17 #include "llvm/Support/ToolOutputFile.h" 18 #include "llvm/Support/WithColor.h" 19 20 using namespace llvm; 21 using namespace llvm::object; 22 23 static cl::opt<std::string> 24 InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-")); 25 static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), 26 cl::value_desc("filename"), 27 cl::init("-"), cl::Prefix); 28 static cl::bits<RawSegments> RawSegment( 29 "raw-segment", 30 cl::desc("Mach-O: dump the raw contents of the listed segments instead of " 31 "parsing them:"), 32 cl::values(clEnumVal(data, "__DATA"), clEnumVal(linkedit, "__LINKEDIT"))); 33 34 static Error dumpObject(const ObjectFile &Obj, raw_ostream &OS) { 35 if (Obj.isCOFF()) 36 return errorCodeToError(coff2yaml(OS, cast<COFFObjectFile>(Obj))); 37 38 if (Obj.isXCOFF()) 39 return xcoff2yaml(OS, cast<XCOFFObjectFile>(Obj)); 40 41 if (Obj.isELF()) 42 return elf2yaml(OS, Obj); 43 44 if (Obj.isWasm()) 45 return errorCodeToError(wasm2yaml(OS, cast<WasmObjectFile>(Obj))); 46 47 llvm_unreachable("unexpected object file format"); 48 } 49 50 static Error dumpInput(StringRef File, raw_ostream &OS) { 51 ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = 52 MemoryBuffer::getFileOrSTDIN(File, /*IsText=*/false, 53 /*RequiresNullTerminator=*/false); 54 if (std::error_code EC = FileOrErr.getError()) 55 return errorCodeToError(EC); 56 std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get(); 57 MemoryBufferRef MemBuf = Buffer->getMemBufferRef(); 58 switch (identify_magic(MemBuf.getBuffer())) { 59 case file_magic::archive: 60 return archive2yaml(OS, MemBuf); 61 case file_magic::dxcontainer_object: 62 return dxcontainer2yaml(OS, MemBuf); 63 case file_magic::offload_binary: 64 return offload2yaml(OS, MemBuf); 65 default: 66 break; 67 } 68 69 Expected<std::unique_ptr<Binary>> BinOrErr = 70 createBinary(MemBuf, /*Context=*/nullptr); 71 if (!BinOrErr) 72 return BinOrErr.takeError(); 73 74 Binary &Binary = *BinOrErr->get(); 75 // Universal MachO is not a subclass of ObjectFile, so it needs to be handled 76 // here with the other binary types. 77 if (Binary.isMachO() || Binary.isMachOUniversalBinary()) 78 return macho2yaml(OS, Binary, RawSegment.getBits()); 79 if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary)) 80 return dumpObject(*Obj, OS); 81 if (MinidumpFile *Minidump = dyn_cast<MinidumpFile>(&Binary)) 82 return minidump2yaml(OS, *Minidump); 83 84 return Error::success(); 85 } 86 87 static void reportError(StringRef Input, Error Err) { 88 if (Input == "-") 89 Input = "<stdin>"; 90 std::string ErrMsg; 91 raw_string_ostream OS(ErrMsg); 92 logAllUnhandledErrors(std::move(Err), OS); 93 OS.flush(); 94 errs() << "Error reading file: " << Input << ": " << ErrMsg; 95 errs().flush(); 96 } 97 98 int main(int argc, char *argv[]) { 99 InitLLVM X(argc, argv); 100 cl::ParseCommandLineOptions(argc, argv); 101 102 std::error_code EC; 103 std::unique_ptr<ToolOutputFile> Out( 104 new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None)); 105 if (EC) { 106 WithColor::error(errs(), "obj2yaml") 107 << "failed to open '" + OutputFilename + "': " + EC.message() << '\n'; 108 return 1; 109 } 110 if (Error Err = dumpInput(InputFilename, Out->os())) { 111 reportError(InputFilename, std::move(Err)); 112 return 1; 113 } 114 Out->keep(); 115 116 return 0; 117 } 118