blob: 8f5243cefa04c7766e3f100de3b970e118d28a41 [file] [log] [blame]
Eugene Zelenko0ad18f82017-11-01 21:16:06 +00001//===- llvm-objcopy.cpp ---------------------------------------------------===//
Petr Hosek05a04cb2017-08-01 00:33:58 +00002//
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//===----------------------------------------------------------------------===//
Eugene Zelenko0ad18f82017-11-01 21:16:06 +00009
Petr Hosek05a04cb2017-08-01 00:33:58 +000010#include "llvm-objcopy.h"
11#include "Object.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000012#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"
Petr Hosek05a04cb2017-08-01 00:33:58 +000021#include "llvm/Support/CommandLine.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000022#include "llvm/Support/Compiler.h"
23#include "llvm/Support/Error.h"
24#include "llvm/Support/ErrorHandling.h"
25#include "llvm/Support/ErrorOr.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000026#include "llvm/Support/FileOutputBuffer.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000027#include "llvm/Support/ManagedStatic.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000028#include "llvm/Support/PrettyStackTrace.h"
29#include "llvm/Support/Signals.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000030#include "llvm/Support/raw_ostream.h"
31#include <algorithm>
32#include <cassert>
33#include <cstdlib>
34#include <functional>
35#include <iterator>
Petr Hosek05a04cb2017-08-01 00:33:58 +000036#include <memory>
37#include <string>
38#include <system_error>
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000039#include <utility>
Petr Hosek05a04cb2017-08-01 00:33:58 +000040
41using namespace llvm;
42using namespace object;
43using namespace ELF;
44
45// The name this program was invoked as.
46static StringRef ToolName;
47
48namespace llvm {
49
Zachary Turner41a9ee92017-10-11 23:54:34 +000050LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
Petr Hosek05a04cb2017-08-01 00:33:58 +000051 errs() << ToolName << ": " << Message << ".\n";
52 errs().flush();
53 exit(1);
54}
55
56LLVM_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
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000062LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
Petr Hosek05a04cb2017-08-01 00:33:58 +000063 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}
Petr Hosek05a04cb2017-08-01 00:33:58 +000071
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000072} // end namespace llvm
73
74static cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input>"));
75static cl::opt<std::string> OutputFilename(cl::Positional, cl::desc("<output>"),
Jake Ehrlich777fb002017-12-15 20:17:55 +000076 cl::init("-"));
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000077static cl::opt<std::string>
Jake Ehrlich11216622017-11-14 20:36:04 +000078 OutputFormat("O", cl::desc("Set output format to one of the following:"
Petr Hosekc4df10e2017-08-04 21:09:26 +000079 "\n\tbinary"));
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000080static cl::list<std::string> ToRemove("remove-section",
Jake Ehrlich11216622017-11-14 20:36:04 +000081 cl::desc("Remove <section>"),
82 cl::value_desc("section"));
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000083static cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"),
84 cl::aliasopt(ToRemove));
Jake Ehrlich6ad72d02017-11-27 18:56:01 +000085static cl::opt<bool> StripAll(
86 "strip-all",
87 cl::desc(
88 "Removes non-allocated sections other than .gnu.warning* sections"));
89static cl::opt<bool>
90 StripAllGNU("strip-all-gnu",
91 cl::desc("Removes symbol, relocation, and debug information"));
Jake Ehrlichef3b80c2017-11-30 20:14:53 +000092static cl::list<std::string> Keep("keep", cl::desc("Keep <section>"),
93 cl::value_desc("section"));
94static cl::list<std::string> OnlyKeep("only-keep",
95 cl::desc("Remove all but <section>"),
96 cl::value_desc("section"));
97static cl::alias OnlyKeepA("j", cl::desc("Alias for only-keep"),
98 cl::aliasopt(OnlyKeep));
Jake Ehrlich1bfefc12017-11-13 22:13:08 +000099static cl::opt<bool> StripDebug("strip-debug",
100 cl::desc("Removes all debug information"));
Eugene Zelenko0ad18f82017-11-01 21:16:06 +0000101static cl::opt<bool> StripSections("strip-sections",
102 cl::desc("Remove all section headers"));
Jake Ehrlich777fb002017-12-15 20:17:55 +0000103static cl::opt<bool>
104 StripNonAlloc("strip-non-alloc",
105 cl::desc("Remove all non-allocated sections"));
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000106static cl::opt<bool>
Jake Ehrlich11216622017-11-14 20:36:04 +0000107 StripDWO("strip-dwo", cl::desc("Remove all DWARF .dwo sections from file"));
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000108static cl::opt<bool> ExtractDWO(
109 "extract-dwo",
Jake Ehrlich11216622017-11-14 20:36:04 +0000110 cl::desc("Remove all sections that are not DWARF .dwo sections from file"));
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000111static cl::opt<std::string>
112 SplitDWO("split-dwo",
Jake Ehrlich11216622017-11-14 20:36:04 +0000113 cl::desc("Equivalent to extract-dwo on the input file to "
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000114 "<dwo-file>, then strip-dwo on the input file"),
115 cl::value_desc("dwo-file"));
Jake Ehrliche8437de2017-12-19 00:47:30 +0000116static cl::list<std::string> AddSection(
117 "add-section",
118 cl::desc("Make a section named <section> with the contents of <file>."),
119 cl::value_desc("section=file"));
Jake Ehrlich27a29b02018-01-05 19:19:09 +0000120static cl::opt<bool> LocalizeHidden(
121 "localize-hidden",
122 cl::desc(
123 "Mark all symbols that have hidden or internal visibility as local"));
Jake Ehrlichea07d3c2018-01-25 22:15:14 +0000124static cl::opt<std::string>
125 AddGnuDebugLink("add-gnu-debuglink",
126 cl::desc("adds a .gnu_debuglink for <debug-file>"),
127 cl::value_desc("debug-file"));
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000128
Eugene Zelenko0ad18f82017-11-01 21:16:06 +0000129using SectionPred = std::function<bool(const SectionBase &Sec)>;
Petr Hosek05a04cb2017-08-01 00:33:58 +0000130
Jake Ehrlich777fb002017-12-15 20:17:55 +0000131bool IsDWOSection(const SectionBase &Sec) { return Sec.Name.endswith(".dwo"); }
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000132
Jake Ehrlich76e91102018-01-25 22:46:17 +0000133bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000134 // We can't remove the section header string table.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000135 if (&Sec == Obj.SectionNames)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000136 return false;
137 // Short of keeping the string table we want to keep everything that is a DWO
138 // section and remove everything else.
139 return !IsDWOSection(Sec);
140}
141
Jake Ehrlich76e91102018-01-25 22:46:17 +0000142static ElfType OutputElfType;
Rafael Espindola85593c22017-11-08 21:15:21 +0000143
Jake Ehrlich76e91102018-01-25 22:46:17 +0000144std::unique_ptr<Writer> CreateWriter(Object &Obj, StringRef File) {
145 if (OutputFormat == "binary") {
146 return llvm::make_unique<BinaryWriter>(OutputFilename, Obj);
147 }
148 // Depending on the initial ELFT and OutputFormat we need a different Writer.
149 switch (OutputElfType) {
150 case ELFT_ELF32LE:
151 return llvm::make_unique<ELFWriter<ELF32LE>>(File, Obj, !StripSections);
152 case ELFT_ELF64LE:
153 return llvm::make_unique<ELFWriter<ELF64LE>>(File, Obj, !StripSections);
154 case ELFT_ELF32BE:
155 return llvm::make_unique<ELFWriter<ELF32BE>>(File, Obj, !StripSections);
156 case ELFT_ELF64BE:
157 return llvm::make_unique<ELFWriter<ELF64BE>>(File, Obj, !StripSections);
158 }
159 llvm_unreachable("Invalid output format");
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000160}
161
Jake Ehrlich76e91102018-01-25 22:46:17 +0000162void SplitDWOToFile(const Reader &Reader, StringRef File) {
163 auto DWOFile = Reader.create();
164 DWOFile->removeSections(
165 [&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); });
166 auto Writer = CreateWriter(*DWOFile, File);
167 Writer->finalize();
168 Writer->write();
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000169}
170
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000171// This function handles the high level operations of GNU objcopy including
172// handling command line options. It's important to outline certain properties
173// we expect to hold of the command line operations. Any operation that "keeps"
174// should keep regardless of a remove. Additionally any removal should respect
175// any previous removals. Lastly whether or not something is removed shouldn't
176// depend a) on the order the options occur in or b) on some opaque priority
177// system. The only priority is that keeps/copies overrule removes.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000178void HandleArgs(Object &Obj, const Reader &Reader) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000179
Jake Ehrlich76e91102018-01-25 22:46:17 +0000180 if (!SplitDWO.empty()) {
181 SplitDWOToFile(Reader, SplitDWO);
182 }
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000183
Jake Ehrlich27a29b02018-01-05 19:19:09 +0000184 // Localize:
185
186 if (LocalizeHidden) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000187 Obj.SymbolTable->localize([](const Symbol &Sym) {
Jake Ehrlich27a29b02018-01-05 19:19:09 +0000188 return Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL;
189 });
190 }
191
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000192 SectionPred RemovePred = [](const SectionBase &) { return false; };
193
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000194 // Removes:
195
Jake Ehrlich36a2eb32017-10-10 18:47:09 +0000196 if (!ToRemove.empty()) {
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000197 RemovePred = [&](const SectionBase &Sec) {
Jake Ehrlichfcc05622017-10-10 23:02:43 +0000198 return std::find(std::begin(ToRemove), std::end(ToRemove), Sec.Name) !=
199 std::end(ToRemove);
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000200 };
Jake Ehrlich36a2eb32017-10-10 18:47:09 +0000201 }
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000202
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000203 if (StripDWO || !SplitDWO.empty())
David Blaikie998ff812017-11-03 20:57:09 +0000204 RemovePred = [RemovePred](const SectionBase &Sec) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000205 return IsDWOSection(Sec) || RemovePred(Sec);
206 };
207
208 if (ExtractDWO)
209 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000210 return OnlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000211 };
212
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000213 if (StripAllGNU)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000214 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
215 if (RemovePred(Sec))
216 return true;
217 if ((Sec.Flags & SHF_ALLOC) != 0)
218 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000219 if (&Sec == Obj.SectionNames)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000220 return false;
Jake Ehrlich777fb002017-12-15 20:17:55 +0000221 switch (Sec.Type) {
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000222 case SHT_SYMTAB:
223 case SHT_REL:
224 case SHT_RELA:
225 case SHT_STRTAB:
226 return true;
227 }
228 return Sec.Name.startswith(".debug");
229 };
230
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000231 if (StripSections) {
232 RemovePred = [RemovePred](const SectionBase &Sec) {
233 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
234 };
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000235 }
236
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000237 if (StripDebug) {
238 RemovePred = [RemovePred](const SectionBase &Sec) {
239 return RemovePred(Sec) || Sec.Name.startswith(".debug");
240 };
241 }
242
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000243 if (StripNonAlloc)
244 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
245 if (RemovePred(Sec))
246 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000247 if (&Sec == Obj.SectionNames)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000248 return false;
249 return (Sec.Flags & SHF_ALLOC) == 0;
250 };
251
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000252 if (StripAll)
253 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
254 if (RemovePred(Sec))
255 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000256 if (&Sec == Obj.SectionNames)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000257 return false;
258 if (Sec.Name.startswith(".gnu.warning"))
259 return false;
260 return (Sec.Flags & SHF_ALLOC) == 0;
261 };
262
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000263 // Explicit copies:
264
265 if (!OnlyKeep.empty()) {
266 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
267 // Explicitly keep these sections regardless of previous removes.
268 if (std::find(std::begin(OnlyKeep), std::end(OnlyKeep), Sec.Name) !=
269 std::end(OnlyKeep))
270 return false;
271
272 // Allow all implicit removes.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000273 if (RemovePred(Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000274 return true;
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000275
276 // Keep special sections.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000277 if (Obj.SectionNames == &Sec)
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000278 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000279 if (Obj.SymbolTable == &Sec || Obj.SymbolTable->getStrTab() == &Sec)
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000280 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000281
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000282 // Remove everything else.
283 return true;
284 };
285 }
286
287 if (!Keep.empty()) {
288 RemovePred = [RemovePred](const SectionBase &Sec) {
289 // Explicitly keep these sections regardless of previous removes.
290 if (std::find(std::begin(Keep), std::end(Keep), Sec.Name) !=
291 std::end(Keep))
292 return false;
293 // Otherwise defer to RemovePred.
294 return RemovePred(Sec);
295 };
296 }
297
Jake Ehrlich76e91102018-01-25 22:46:17 +0000298 Obj.removeSections(RemovePred);
Jake Ehrliche8437de2017-12-19 00:47:30 +0000299
300 if (!AddSection.empty()) {
301 for (const auto &Flag : AddSection) {
302 auto SecPair = StringRef(Flag).split("=");
303 auto SecName = SecPair.first;
304 auto File = SecPair.second;
305 auto BufOrErr = MemoryBuffer::getFile(File);
306 if (!BufOrErr)
307 reportError(File, BufOrErr.getError());
308 auto Buf = std::move(*BufOrErr);
309 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
310 auto BufSize = Buf->getBufferSize();
Jake Ehrlich76e91102018-01-25 22:46:17 +0000311 Obj.addSection<OwnedDataSection>(SecName,
312 ArrayRef<uint8_t>(BufPtr, BufSize));
Jake Ehrliche8437de2017-12-19 00:47:30 +0000313 }
314 }
315
Jake Ehrlichea07d3c2018-01-25 22:15:14 +0000316 if (!AddGnuDebugLink.empty()) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000317 Obj.addSection<GnuDebugLinkSection>(StringRef(AddGnuDebugLink));
Jake Ehrlichea07d3c2018-01-25 22:15:14 +0000318 }
Jake Ehrlich76e91102018-01-25 22:46:17 +0000319}
Jake Ehrlichea07d3c2018-01-25 22:15:14 +0000320
Jake Ehrlich76e91102018-01-25 22:46:17 +0000321std::unique_ptr<Reader> CreateReader() {
322 // Right now we can only read ELF files so there's only one reader;
323 auto Out = llvm::make_unique<ELFReader>(StringRef(InputFilename));
324 // We need to set the default ElfType for output.
325 OutputElfType = Out->getElfType();
326 return std::move(Out);
Petr Hosek05a04cb2017-08-01 00:33:58 +0000327}
328
329int main(int argc, char **argv) {
330 // Print a stack trace if we signal out.
331 sys::PrintStackTraceOnErrorSignal(argv[0]);
332 PrettyStackTraceProgram X(argc, argv);
333 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
334 cl::ParseCommandLineOptions(argc, argv, "llvm objcopy utility\n");
335 ToolName = argv[0];
336 if (InputFilename.empty()) {
337 cl::PrintHelpMessage();
338 return 2;
339 }
Jake Ehrlich76e91102018-01-25 22:46:17 +0000340
341 auto Reader = CreateReader();
342 auto Obj = Reader->create();
343 auto Writer = CreateWriter(*Obj, OutputFilename);
344 HandleArgs(*Obj, *Reader);
345 Writer->finalize();
346 Writer->write();
Petr Hosek05a04cb2017-08-01 00:33:58 +0000347}