blob: 7f55a434b334423007d148b780a65889859f4e97 [file] [log] [blame]
Petr Hosek05a04cb2017-08-01 00:33:58 +00001//===- llvm-objcopy.cpp -----------------------------------------*- C++ -*-===//
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#include "llvm-objcopy.h"
10#include "Object.h"
11#include "llvm/Support/CommandLine.h"
12#include "llvm/Support/FileOutputBuffer.h"
13#include "llvm/Support/PrettyStackTrace.h"
14#include "llvm/Support/Signals.h"
15#include "llvm/Support/ToolOutputFile.h"
16
17#include <memory>
18#include <string>
19#include <system_error>
20
21using namespace llvm;
22using namespace object;
23using namespace ELF;
24
25// The name this program was invoked as.
26static StringRef ToolName;
27
28namespace llvm {
29
Zachary Turner41a9ee92017-10-11 23:54:34 +000030LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
Petr Hosek05a04cb2017-08-01 00:33:58 +000031 errs() << ToolName << ": " << Message << ".\n";
32 errs().flush();
33 exit(1);
34}
35
36LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
37 assert(EC);
38 errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n";
39 exit(1);
40}
41
42LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, llvm::Error E) {
43 assert(E);
44 std::string Buf;
45 raw_string_ostream OS(Buf);
46 logAllUnhandledErrors(std::move(E), OS, "");
47 OS.flush();
48 errs() << ToolName << ": '" << File << "': " << Buf;
49 exit(1);
50}
51}
52
53cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input>"));
54cl::opt<std::string> OutputFilename(cl::Positional, cl::desc("<output>"),
55 cl::init("-"));
Petr Hosekc4df10e2017-08-04 21:09:26 +000056cl::opt<std::string>
57 OutputFormat("O", cl::desc("set output format to one of the following:"
58 "\n\tbinary"));
Jake Ehrlichfcc05622017-10-10 23:02:43 +000059cl::list<std::string> ToRemove("remove-section",
60 cl::desc("Remove a specific section"));
61cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"),
62 cl::aliasopt(ToRemove));
Jake Ehrlichf03384d2017-10-11 18:09:18 +000063cl::opt<bool> StripSections("strip-sections",
64 cl::desc("Remove all section headers"));
65
66typedef std::function<bool(const SectionBase &Sec)> SectionPred;
Petr Hosek05a04cb2017-08-01 00:33:58 +000067
68void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) {
69 std::unique_ptr<FileOutputBuffer> Buffer;
Petr Hosekc4df10e2017-08-04 21:09:26 +000070 std::unique_ptr<Object<ELF64LE>> Obj;
71 if (!OutputFormat.empty() && OutputFormat != "binary")
72 error("invalid output format '" + OutputFormat + "'");
Petr Hosekc4df10e2017-08-04 21:09:26 +000073 if (!OutputFormat.empty() && OutputFormat == "binary")
74 Obj = llvm::make_unique<BinaryObject<ELF64LE>>(ObjFile);
75 else
76 Obj = llvm::make_unique<ELFObject<ELF64LE>>(ObjFile);
Jake Ehrlichf03384d2017-10-11 18:09:18 +000077
78 SectionPred RemovePred = [](const SectionBase &) { return false; };
79
Jake Ehrlich36a2eb32017-10-10 18:47:09 +000080 if (!ToRemove.empty()) {
Jake Ehrlichf03384d2017-10-11 18:09:18 +000081 RemovePred = [&](const SectionBase &Sec) {
Jake Ehrlichfcc05622017-10-10 23:02:43 +000082 return std::find(std::begin(ToRemove), std::end(ToRemove), Sec.Name) !=
83 std::end(ToRemove);
Jake Ehrlichf03384d2017-10-11 18:09:18 +000084 };
Jake Ehrlich36a2eb32017-10-10 18:47:09 +000085 }
Jake Ehrlichf03384d2017-10-11 18:09:18 +000086
87 if (StripSections) {
88 RemovePred = [RemovePred](const SectionBase &Sec) {
89 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
90 };
91 Obj->WriteSectionHeaders = false;
92 }
93
94 Obj->removeSections(RemovePred);
95
Petr Hosekc4df10e2017-08-04 21:09:26 +000096 Obj->finalize();
Petr Hosek05a04cb2017-08-01 00:33:58 +000097 ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
Petr Hosekc4df10e2017-08-04 21:09:26 +000098 FileOutputBuffer::create(OutputFilename, Obj->totalSize(),
Petr Hosek05a04cb2017-08-01 00:33:58 +000099 FileOutputBuffer::F_executable);
100 if (BufferOrErr.getError())
101 error("failed to open " + OutputFilename);
102 else
103 Buffer = std::move(*BufferOrErr);
104 std::error_code EC;
105 if (EC)
106 report_fatal_error(EC.message());
Petr Hosekc4df10e2017-08-04 21:09:26 +0000107 Obj->write(*Buffer);
Petr Hosek05a04cb2017-08-01 00:33:58 +0000108 if (auto EC = Buffer->commit())
109 reportError(OutputFilename, EC);
110}
111
112int main(int argc, char **argv) {
113 // Print a stack trace if we signal out.
114 sys::PrintStackTraceOnErrorSignal(argv[0]);
115 PrettyStackTraceProgram X(argc, argv);
116 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
117 cl::ParseCommandLineOptions(argc, argv, "llvm objcopy utility\n");
118 ToolName = argv[0];
119 if (InputFilename.empty()) {
120 cl::PrintHelpMessage();
121 return 2;
122 }
123 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(InputFilename);
124 if (!BinaryOrErr)
125 reportError(InputFilename, BinaryOrErr.takeError());
126 Binary &Binary = *BinaryOrErr.get().getBinary();
127 if (ELFObjectFile<ELF64LE> *o = dyn_cast<ELFObjectFile<ELF64LE>>(&Binary)) {
128 CopyBinary(*o);
129 return 0;
130 }
131 reportError(InputFilename, object_error::invalid_file_type);
132}