blob: 775c5ae42b657e64ee3eb344b3a94d17410200b3 [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
30LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
31 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 Ehrlich36a2eb32017-10-10 18:47:09 +000059// TODO: make this a cl::list to support removing multiple sections
60cl::opt<std::string> ToRemove("remove-section",
61 cl::desc("Remove a specific section"));
62cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"), cl::aliasopt(ToRemove));
Petr Hosek05a04cb2017-08-01 00:33:58 +000063
64void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) {
65 std::unique_ptr<FileOutputBuffer> Buffer;
Petr Hosekc4df10e2017-08-04 21:09:26 +000066 std::unique_ptr<Object<ELF64LE>> Obj;
67 if (!OutputFormat.empty() && OutputFormat != "binary")
68 error("invalid output format '" + OutputFormat + "'");
Petr Hosekc4df10e2017-08-04 21:09:26 +000069 if (!OutputFormat.empty() && OutputFormat == "binary")
70 Obj = llvm::make_unique<BinaryObject<ELF64LE>>(ObjFile);
71 else
72 Obj = llvm::make_unique<ELFObject<ELF64LE>>(ObjFile);
Jake Ehrlich36a2eb32017-10-10 18:47:09 +000073 if (!ToRemove.empty()) {
74 Obj->removeSections(
75 [&](const SectionBase &Sec) { return ToRemove == Sec.Name; });
76 }
Petr Hosekc4df10e2017-08-04 21:09:26 +000077 Obj->finalize();
Petr Hosek05a04cb2017-08-01 00:33:58 +000078 ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
Petr Hosekc4df10e2017-08-04 21:09:26 +000079 FileOutputBuffer::create(OutputFilename, Obj->totalSize(),
Petr Hosek05a04cb2017-08-01 00:33:58 +000080 FileOutputBuffer::F_executable);
81 if (BufferOrErr.getError())
82 error("failed to open " + OutputFilename);
83 else
84 Buffer = std::move(*BufferOrErr);
85 std::error_code EC;
86 if (EC)
87 report_fatal_error(EC.message());
Petr Hosekc4df10e2017-08-04 21:09:26 +000088 Obj->write(*Buffer);
Petr Hosek05a04cb2017-08-01 00:33:58 +000089 if (auto EC = Buffer->commit())
90 reportError(OutputFilename, EC);
91}
92
93int main(int argc, char **argv) {
94 // Print a stack trace if we signal out.
95 sys::PrintStackTraceOnErrorSignal(argv[0]);
96 PrettyStackTraceProgram X(argc, argv);
97 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
98 cl::ParseCommandLineOptions(argc, argv, "llvm objcopy utility\n");
99 ToolName = argv[0];
100 if (InputFilename.empty()) {
101 cl::PrintHelpMessage();
102 return 2;
103 }
104 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(InputFilename);
105 if (!BinaryOrErr)
106 reportError(InputFilename, BinaryOrErr.takeError());
107 Binary &Binary = *BinaryOrErr.get().getBinary();
108 if (ELFObjectFile<ELF64LE> *o = dyn_cast<ELFObjectFile<ELF64LE>>(&Binary)) {
109 CopyBinary(*o);
110 return 0;
111 }
112 reportError(InputFilename, object_error::invalid_file_type);
113}