1 //===- llvm-objcopy.cpp ---------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm-objcopy.h" 11 #include "Object.h" 12 #include "llvm/ADT/STLExtras.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/ADT/Twine.h" 15 #include "llvm/BinaryFormat/ELF.h" 16 #include "llvm/Object/Binary.h" 17 #include "llvm/Object/ELFObjectFile.h" 18 #include "llvm/Object/ELFTypes.h" 19 #include "llvm/Object/Error.h" 20 #include "llvm/Support/Casting.h" 21 #include "llvm/Support/CommandLine.h" 22 #include "llvm/Support/Compiler.h" 23 #include "llvm/Support/Error.h" 24 #include "llvm/Support/ErrorHandling.h" 25 #include "llvm/Support/ErrorOr.h" 26 #include "llvm/Support/FileOutputBuffer.h" 27 #include "llvm/Support/ManagedStatic.h" 28 #include "llvm/Support/PrettyStackTrace.h" 29 #include "llvm/Support/Signals.h" 30 #include "llvm/Support/raw_ostream.h" 31 #include <algorithm> 32 #include <cassert> 33 #include <cstdlib> 34 #include <functional> 35 #include <iterator> 36 #include <memory> 37 #include <string> 38 #include <system_error> 39 #include <utility> 40 41 using namespace llvm; 42 using namespace object; 43 using namespace ELF; 44 45 // The name this program was invoked as. 46 static StringRef ToolName; 47 48 namespace llvm { 49 50 LLVM_ATTRIBUTE_NORETURN void error(Twine Message) { 51 errs() << ToolName << ": " << Message << ".\n"; 52 errs().flush(); 53 exit(1); 54 } 55 56 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) { 57 assert(EC); 58 errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n"; 59 exit(1); 60 } 61 62 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) { 63 assert(E); 64 std::string Buf; 65 raw_string_ostream OS(Buf); 66 logAllUnhandledErrors(std::move(E), OS, ""); 67 OS.flush(); 68 errs() << ToolName << ": '" << File << "': " << Buf; 69 exit(1); 70 } 71 72 } // end namespace llvm 73 74 static cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input>")); 75 static cl::opt<std::string> OutputFilename(cl::Positional, cl::desc("<output>"), 76 cl::init("-")); 77 static cl::opt<std::string> 78 OutputFormat("O", cl::desc("set output format to one of the following:" 79 "\n\tbinary")); 80 static cl::list<std::string> ToRemove("remove-section", 81 cl::desc("Remove a specific section")); 82 static cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"), 83 cl::aliasopt(ToRemove)); 84 static cl::opt<bool> StripSections("strip-sections", 85 cl::desc("Remove all section headers")); 86 87 using SectionPred = std::function<bool(const SectionBase &Sec)>; 88 89 void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) { 90 std::unique_ptr<FileOutputBuffer> Buffer; 91 std::unique_ptr<Object<ELF64LE>> Obj; 92 if (!OutputFormat.empty() && OutputFormat != "binary") 93 error("invalid output format '" + OutputFormat + "'"); 94 if (!OutputFormat.empty() && OutputFormat == "binary") 95 Obj = llvm::make_unique<BinaryObject<ELF64LE>>(ObjFile); 96 else 97 Obj = llvm::make_unique<ELFObject<ELF64LE>>(ObjFile); 98 99 SectionPred RemovePred = [](const SectionBase &) { return false; }; 100 101 if (!ToRemove.empty()) { 102 RemovePred = [&](const SectionBase &Sec) { 103 return std::find(std::begin(ToRemove), std::end(ToRemove), Sec.Name) != 104 std::end(ToRemove); 105 }; 106 } 107 108 if (StripSections) { 109 RemovePred = [RemovePred](const SectionBase &Sec) { 110 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; 111 }; 112 Obj->WriteSectionHeaders = false; 113 } 114 115 Obj->removeSections(RemovePred); 116 117 Obj->finalize(); 118 ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr = 119 FileOutputBuffer::create(OutputFilename, Obj->totalSize(), 120 FileOutputBuffer::F_executable); 121 if (BufferOrErr.getError()) 122 error("failed to open " + OutputFilename); 123 else 124 Buffer = std::move(*BufferOrErr); 125 std::error_code EC; 126 if (EC) 127 report_fatal_error(EC.message()); 128 Obj->write(*Buffer); 129 if (auto EC = Buffer->commit()) 130 reportError(OutputFilename, EC); 131 } 132 133 int main(int argc, char **argv) { 134 // Print a stack trace if we signal out. 135 sys::PrintStackTraceOnErrorSignal(argv[0]); 136 PrettyStackTraceProgram X(argc, argv); 137 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 138 cl::ParseCommandLineOptions(argc, argv, "llvm objcopy utility\n"); 139 ToolName = argv[0]; 140 if (InputFilename.empty()) { 141 cl::PrintHelpMessage(); 142 return 2; 143 } 144 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(InputFilename); 145 if (!BinaryOrErr) 146 reportError(InputFilename, BinaryOrErr.takeError()); 147 Binary &Binary = *BinaryOrErr.get().getBinary(); 148 if (ELFObjectFile<ELF64LE> *o = dyn_cast<ELFObjectFile<ELF64LE>>(&Binary)) { 149 CopyBinary(*o); 150 return 0; 151 } 152 reportError(InputFilename, object_error::invalid_file_type); 153 } 154