blob: 7d230390872013333bd045264a802b2b9b3ec7b6 [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
Jake Ehrlicha8c689e2018-04-12 00:40:50 +000074static cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input>"));
75static cl::opt<std::string> OutputFilename(cl::Positional, cl::desc("[ <output> ]"));
Alexander Shaposhnikovfedb0162018-02-09 23:33:31 +000076
Jake Ehrlicha8c689e2018-04-12 00:40:50 +000077static cl::opt<std::string>
78 OutputFormat("O", cl::desc("Set output format to one of the following:"
79 "\n\tbinary"));
80static cl::list<std::string> ToRemove("remove-section",
81 cl::desc("Remove <section>"),
82 cl::value_desc("section"));
83static cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"),
84 cl::aliasopt(ToRemove));
85static 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"));
92static 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));
99static cl::opt<bool> StripDebug("strip-debug",
100 cl::desc("Removes all debug information"));
101static cl::opt<bool> StripSections("strip-sections",
102 cl::desc("Remove all section headers"));
103static cl::opt<bool>
104 StripNonAlloc("strip-non-alloc",
105 cl::desc("Remove all non-allocated sections"));
106static cl::opt<bool>
107 StripDWO("strip-dwo", cl::desc("Remove all DWARF .dwo sections from file"));
108static cl::opt<bool> ExtractDWO(
109 "extract-dwo",
110 cl::desc("Remove all sections that are not DWARF .dwo sections from file"));
111static cl::opt<std::string>
112 SplitDWO("split-dwo",
113 cl::desc("Equivalent to extract-dwo on the input file to "
114 "<dwo-file>, then strip-dwo on the input file"),
115 cl::value_desc("dwo-file"));
116static 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"));
120static cl::opt<bool> LocalizeHidden(
121 "localize-hidden",
122 cl::desc(
123 "Mark all symbols that have hidden or internal visibility as local"));
124static 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 Ehrlicha8c689e2018-04-12 00:40:50 +0000142static ElfType OutputElfType;
143
144std::unique_ptr<Writer> CreateWriter(Object &Obj, StringRef File) {
145 if (OutputFormat == "binary") {
146 return llvm::make_unique<BinaryWriter>(OutputFilename, Obj);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000147 }
148 // Depending on the initial ELFT and OutputFormat we need a different Writer.
149 switch (OutputElfType) {
150 case ELFT_ELF32LE:
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000151 return llvm::make_unique<ELFWriter<ELF32LE>>(File, Obj, !StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000152 case ELFT_ELF64LE:
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000153 return llvm::make_unique<ELFWriter<ELF64LE>>(File, Obj, !StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000154 case ELFT_ELF32BE:
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000155 return llvm::make_unique<ELFWriter<ELF32BE>>(File, Obj, !StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000156 case ELFT_ELF64BE:
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000157 return llvm::make_unique<ELFWriter<ELF64BE>>(File, Obj, !StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000158 }
159 llvm_unreachable("Invalid output format");
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000160}
161
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000162void SplitDWOToFile(const Reader &Reader, StringRef File) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000163 auto DWOFile = Reader.create();
164 DWOFile->removeSections(
165 [&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); });
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000166 auto Writer = CreateWriter(*DWOFile, File);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000167 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 Ehrlicha8c689e2018-04-12 00:40:50 +0000178void HandleArgs(Object &Obj, const Reader &Reader) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000179
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000180 if (!SplitDWO.empty()) {
181 SplitDWOToFile(Reader, SplitDWO);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000182 }
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000183
Jake Ehrlich27a29b02018-01-05 19:19:09 +0000184 // Localize:
185
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000186 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 Ehrlicha8c689e2018-04-12 00:40:50 +0000196 if (!ToRemove.empty()) {
197 RemovePred = [&](const SectionBase &Sec) {
198 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 Ehrlicha8c689e2018-04-12 00:40:50 +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
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000208 if (ExtractDWO)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000209 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 Ehrlicha8c689e2018-04-12 00:40:50 +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 Ehrlicha8c689e2018-04-12 00:40:50 +0000231 if (StripSections) {
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000232 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 Ehrlicha8c689e2018-04-12 00:40:50 +0000237 if (StripDebug) {
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000238 RemovePred = [RemovePred](const SectionBase &Sec) {
239 return RemovePred(Sec) || Sec.Name.startswith(".debug");
240 };
241 }
242
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000243 if (StripNonAlloc)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000244 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 Ehrlicha8c689e2018-04-12 00:40:50 +0000252 if (StripAll)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000253 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
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000265 if (!OnlyKeep.empty()) {
266 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000267 // Explicitly keep these sections regardless of previous removes.
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000268 if (std::find(std::begin(OnlyKeep), std::end(OnlyKeep), Sec.Name) !=
269 std::end(OnlyKeep))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000270 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
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000287 if (!Keep.empty()) {
288 RemovePred = [RemovePred](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000289 // Explicitly keep these sections regardless of previous removes.
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000290 if (std::find(std::begin(Keep), std::end(Keep), Sec.Name) !=
291 std::end(Keep))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000292 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
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000300 if (!AddSection.empty()) {
301 for (const auto &Flag : AddSection) {
302 auto SecPair = StringRef(Flag).split("=");
Jake Ehrliche8437de2017-12-19 00:47:30 +0000303 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 Ehrlicha8c689e2018-04-12 00:40:50 +0000316 if (!AddGnuDebugLink.empty()) {
317 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 Ehrlicha8c689e2018-04-12 00:40:50 +0000321std::unique_ptr<Reader> CreateReader() {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000322 // Right now we can only read ELF files so there's only one reader;
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000323 auto Out = llvm::make_unique<ELFReader>(StringRef(InputFilename));
Jake Ehrlich76e91102018-01-25 22:46:17 +0000324 // 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.
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000334 cl::ParseCommandLineOptions(argc, argv, "llvm objcopy utility\n");
Petr Hosek05a04cb2017-08-01 00:33:58 +0000335 ToolName = argv[0];
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000336 if (InputFilename.empty()) {
337 cl::PrintHelpMessage();
338 return 2;
339 }
Jake Ehrlich76e91102018-01-25 22:46:17 +0000340
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000341 auto Reader = CreateReader();
342 auto Obj = Reader->create();
343 StringRef Output =
344 OutputFilename.getNumOccurrences() ? OutputFilename : InputFilename;
345 auto Writer = CreateWriter(*Obj, Output);
346 HandleArgs(*Obj, *Reader);
347 Writer->finalize();
348 Writer->write();
Petr Hosek05a04cb2017-08-01 00:33:58 +0000349}