blob: edc45ee36116007238a5e8b2b1c474d600470b8e [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"
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +000012#include "llvm/ADT/BitmaskEnum.h"
13#include "llvm/ADT/Optional.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000014#include "llvm/ADT/STLExtras.h"
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +000015#include "llvm/ADT/SmallVector.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000016#include "llvm/ADT/StringRef.h"
17#include "llvm/ADT/Twine.h"
18#include "llvm/BinaryFormat/ELF.h"
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +000019#include "llvm/Object/Archive.h"
20#include "llvm/Object/ArchiveWriter.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000021#include "llvm/Object/Binary.h"
22#include "llvm/Object/ELFObjectFile.h"
23#include "llvm/Object/ELFTypes.h"
24#include "llvm/Object/Error.h"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000025#include "llvm/Option/Arg.h"
26#include "llvm/Option/ArgList.h"
27#include "llvm/Option/Option.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000028#include "llvm/Support/Casting.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000029#include "llvm/Support/CommandLine.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000030#include "llvm/Support/Compiler.h"
31#include "llvm/Support/Error.h"
32#include "llvm/Support/ErrorHandling.h"
33#include "llvm/Support/ErrorOr.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000034#include "llvm/Support/FileOutputBuffer.h"
Rui Ueyama197194b2018-04-13 18:26:06 +000035#include "llvm/Support/InitLLVM.h"
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000036#include "llvm/Support/Path.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000037#include "llvm/Support/raw_ostream.h"
38#include <algorithm>
39#include <cassert>
40#include <cstdlib>
41#include <functional>
42#include <iterator>
Petr Hosek05a04cb2017-08-01 00:33:58 +000043#include <memory>
44#include <string>
45#include <system_error>
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000046#include <utility>
Petr Hosek05a04cb2017-08-01 00:33:58 +000047
48using namespace llvm;
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000049using namespace llvm::objcopy;
Petr Hosek05a04cb2017-08-01 00:33:58 +000050using namespace object;
51using namespace ELF;
52
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000053namespace {
54
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000055enum ObjcopyID {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000056 OBJCOPY_INVALID = 0, // This is not an option ID.
57#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
58 HELPTEXT, METAVAR, VALUES) \
59 OBJCOPY_##ID,
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000060#include "ObjcopyOpts.inc"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000061#undef OPTION
62};
63
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +000064#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000065#include "ObjcopyOpts.inc"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000066#undef PREFIX
67
Alexander Shaposhnikov3326e782018-04-24 06:23:22 +000068static const opt::OptTable::Info ObjcopyInfoTable[] = {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000069#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
70 HELPTEXT, METAVAR, VALUES) \
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +000071 {OBJCOPY_##PREFIX, \
72 NAME, \
73 HELPTEXT, \
74 METAVAR, \
75 OBJCOPY_##ID, \
76 opt::Option::KIND##Class, \
77 PARAM, \
78 FLAGS, \
79 OBJCOPY_##GROUP, \
80 OBJCOPY_##ALIAS, \
81 ALIASARGS, \
82 VALUES},
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000083#include "ObjcopyOpts.inc"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000084#undef OPTION
85};
86
87class ObjcopyOptTable : public opt::OptTable {
88public:
89 ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {}
90};
91
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000092enum StripID {
93 STRIP_INVALID = 0, // This is not an option ID.
94#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
95 HELPTEXT, METAVAR, VALUES) \
96 STRIP_##ID,
97#include "StripOpts.inc"
98#undef OPTION
99};
100
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000101#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
102#include "StripOpts.inc"
103#undef PREFIX
104
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000105static const opt::OptTable::Info StripInfoTable[] = {
106#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
107 HELPTEXT, METAVAR, VALUES) \
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000108 {STRIP_##PREFIX, NAME, HELPTEXT, \
109 METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
110 PARAM, FLAGS, STRIP_##GROUP, \
111 STRIP_##ALIAS, ALIASARGS, VALUES},
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000112#include "StripOpts.inc"
113#undef OPTION
114};
115
116class StripOptTable : public opt::OptTable {
117public:
118 StripOptTable() : OptTable(StripInfoTable, true) {}
119};
120
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000121struct SectionRename {
122 StringRef OriginalName;
123 StringRef NewName;
124 Optional<uint64_t> NewFlags;
125};
126
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000127struct CopyConfig {
128 StringRef OutputFilename;
129 StringRef InputFilename;
130 StringRef OutputFormat;
131 StringRef InputFormat;
132 StringRef BinaryArch;
Alexander Shaposhnikovfedb0162018-02-09 23:33:31 +0000133
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000134 StringRef SplitDWO;
135 StringRef AddGnuDebugLink;
136 std::vector<StringRef> ToRemove;
137 std::vector<StringRef> Keep;
138 std::vector<StringRef> OnlyKeep;
139 std::vector<StringRef> AddSection;
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000140 std::vector<StringRef> SymbolsToLocalize;
Paul Semelee5be792018-04-27 19:09:44 +0000141 std::vector<StringRef> SymbolsToGlobalize;
Paul Semel3a8a56b2018-04-27 19:16:27 +0000142 std::vector<StringRef> SymbolsToWeaken;
Paul Semel4246a462018-05-09 21:36:54 +0000143 std::vector<StringRef> SymbolsToRemove;
Paul Semel5d97c822018-05-15 14:09:37 +0000144 std::vector<StringRef> SymbolsToKeep;
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000145 StringMap<SectionRename> SectionsToRename;
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000146 StringMap<StringRef> SymbolsToRename;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000147 bool StripAll = false;
148 bool StripAllGNU = false;
149 bool StripDebug = false;
150 bool StripSections = false;
151 bool StripNonAlloc = false;
152 bool StripDWO = false;
Paul Semel99dda0b2018-05-25 11:01:25 +0000153 bool StripUnneeded = false;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000154 bool ExtractDWO = false;
155 bool LocalizeHidden = false;
156 bool Weaken = false;
157 bool DiscardAll = false;
Jake Ehrliche40398a2018-05-15 20:53:53 +0000158 bool OnlyKeepDebug = false;
Paul Semelcf51c802018-05-26 08:10:37 +0000159 bool KeepFileSymbols = false;
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000160};
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000161
Eugene Zelenko0ad18f82017-11-01 21:16:06 +0000162using SectionPred = std::function<bool(const SectionBase &Sec)>;
Petr Hosek05a04cb2017-08-01 00:33:58 +0000163
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000164enum SectionFlag {
165 SecNone = 0,
166 SecAlloc = 1 << 0,
167 SecLoad = 1 << 1,
168 SecNoload = 1 << 2,
169 SecReadonly = 1 << 3,
170 SecDebug = 1 << 4,
171 SecCode = 1 << 5,
172 SecData = 1 << 6,
173 SecRom = 1 << 7,
174 SecMerge = 1 << 8,
175 SecStrings = 1 << 9,
176 SecContents = 1 << 10,
177 SecShare = 1 << 11,
178 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare)
179};
180
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +0000181} // namespace
182
183namespace llvm {
184namespace objcopy {
185
186// The name this program was invoked as.
187StringRef ToolName;
188
189LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
190 errs() << ToolName << ": " << Message << ".\n";
191 errs().flush();
192 exit(1);
193}
194
195LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
196 assert(EC);
197 errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n";
198 exit(1);
199}
200
201LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
202 assert(E);
203 std::string Buf;
204 raw_string_ostream OS(Buf);
205 logAllUnhandledErrors(std::move(E), OS, "");
206 OS.flush();
207 errs() << ToolName << ": '" << File << "': " << Buf;
208 exit(1);
209}
210
211} // end namespace objcopy
Puyan Lotfic4846a52018-07-16 22:17:05 +0000212} // end namespace llvm
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000213
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000214static SectionFlag ParseSectionRenameFlag(StringRef SectionName) {
215 return llvm::StringSwitch<SectionFlag>(SectionName)
216 .Case("alloc", SectionFlag::SecAlloc)
217 .Case("load", SectionFlag::SecLoad)
218 .Case("noload", SectionFlag::SecNoload)
219 .Case("readonly", SectionFlag::SecReadonly)
220 .Case("debug", SectionFlag::SecDebug)
221 .Case("code", SectionFlag::SecCode)
222 .Case("data", SectionFlag::SecData)
223 .Case("rom", SectionFlag::SecRom)
224 .Case("merge", SectionFlag::SecMerge)
225 .Case("strings", SectionFlag::SecStrings)
226 .Case("contents", SectionFlag::SecContents)
227 .Case("share", SectionFlag::SecShare)
228 .Default(SectionFlag::SecNone);
229}
230
231static SectionRename ParseRenameSectionValue(StringRef FlagValue) {
232 if (!FlagValue.contains('='))
233 error("Bad format for --rename-section: missing '='");
234
235 // Initial split: ".foo" = ".bar,f1,f2,..."
236 auto Old2New = FlagValue.split('=');
237 SectionRename SR;
238 SR.OriginalName = Old2New.first;
239
240 // Flags split: ".bar" "f1" "f2" ...
241 SmallVector<StringRef, 6> NameAndFlags;
242 Old2New.second.split(NameAndFlags, ',');
243 SR.NewName = NameAndFlags[0];
244
245 if (NameAndFlags.size() > 1) {
246 SectionFlag Flags = SectionFlag::SecNone;
247 for (size_t I = 1, Size = NameAndFlags.size(); I < Size; ++I) {
248 SectionFlag Flag = ParseSectionRenameFlag(NameAndFlags[I]);
249 if (Flag == SectionFlag::SecNone)
250 error("Unrecognized section flag '" + NameAndFlags[I] +
251 "'. Flags supported for GNU compatibility: alloc, load, noload, "
252 "readonly, debug, code, data, rom, share, contents, merge, "
253 "strings.");
254 Flags |= Flag;
255 }
256
257 SR.NewFlags = 0;
258 if (Flags & SectionFlag::SecAlloc)
259 *SR.NewFlags |= ELF::SHF_ALLOC;
260 if (!(Flags & SectionFlag::SecReadonly))
261 *SR.NewFlags |= ELF::SHF_WRITE;
262 if (Flags & SectionFlag::SecCode)
263 *SR.NewFlags |= ELF::SHF_EXECINSTR;
264 if (Flags & SectionFlag::SecMerge)
265 *SR.NewFlags |= ELF::SHF_MERGE;
266 if (Flags & SectionFlag::SecStrings)
267 *SR.NewFlags |= ELF::SHF_STRINGS;
268 }
269
270 return SR;
271}
272
Fangrui Songfdfe2a92018-07-27 22:51:36 +0000273static bool IsDebugSection(const SectionBase &Sec) {
Fangrui Song87b4b8f2018-07-31 21:26:35 +0000274 return Sec.Name.startswith(".debug") || Sec.Name.startswith(".zdebug") ||
275 Sec.Name == ".gdb_index";
Fangrui Songfdfe2a92018-07-27 22:51:36 +0000276}
277
Puyan Lotfic4846a52018-07-16 22:17:05 +0000278static bool IsDWOSection(const SectionBase &Sec) {
279 return Sec.Name.endswith(".dwo");
280}
281
282static bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000283 // We can't remove the section header string table.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000284 if (&Sec == Obj.SectionNames)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000285 return false;
286 // Short of keeping the string table we want to keep everything that is a DWO
287 // section and remove everything else.
288 return !IsDWOSection(Sec);
289}
290
Puyan Lotfic4846a52018-07-16 22:17:05 +0000291static std::unique_ptr<Writer> CreateWriter(const CopyConfig &Config,
292 Object &Obj, Buffer &Buf,
293 ElfType OutputElfType) {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000294 if (Config.OutputFormat == "binary") {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000295 return llvm::make_unique<BinaryWriter>(Obj, Buf);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000296 }
297 // Depending on the initial ELFT and OutputFormat we need a different Writer.
298 switch (OutputElfType) {
299 case ELFT_ELF32LE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000300 return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000301 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000302 case ELFT_ELF64LE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000303 return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000304 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000305 case ELFT_ELF32BE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000306 return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000307 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000308 case ELFT_ELF64BE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000309 return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000310 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000311 }
312 llvm_unreachable("Invalid output format");
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000313}
314
Puyan Lotfic4846a52018-07-16 22:17:05 +0000315static void SplitDWOToFile(const CopyConfig &Config, const Reader &Reader,
316 StringRef File, ElfType OutputElfType) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000317 auto DWOFile = Reader.create();
318 DWOFile->removeSections(
319 [&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); });
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000320 FileBuffer FB(File);
321 auto Writer = CreateWriter(Config, *DWOFile, FB, OutputElfType);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000322 Writer->finalize();
323 Writer->write();
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000324}
325
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000326// This function handles the high level operations of GNU objcopy including
327// handling command line options. It's important to outline certain properties
328// we expect to hold of the command line operations. Any operation that "keeps"
329// should keep regardless of a remove. Additionally any removal should respect
330// any previous removals. Lastly whether or not something is removed shouldn't
331// depend a) on the order the options occur in or b) on some opaque priority
332// system. The only priority is that keeps/copies overrule removes.
Puyan Lotfic4846a52018-07-16 22:17:05 +0000333static void HandleArgs(const CopyConfig &Config, Object &Obj,
334 const Reader &Reader, ElfType OutputElfType) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000335
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000336 if (!Config.SplitDWO.empty()) {
337 SplitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000338 }
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000339
340 // TODO: update or remove symbols only if there is an option that affects
341 // them.
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000342 if (Obj.SymbolTable) {
343 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
344 if ((Config.LocalizeHidden &&
345 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
346 (!Config.SymbolsToLocalize.empty() &&
347 is_contained(Config.SymbolsToLocalize, Sym.Name)))
348 Sym.Binding = STB_LOCAL;
349
350 if (!Config.SymbolsToGlobalize.empty() &&
351 is_contained(Config.SymbolsToGlobalize, Sym.Name))
352 Sym.Binding = STB_GLOBAL;
353
354 if (!Config.SymbolsToWeaken.empty() &&
355 is_contained(Config.SymbolsToWeaken, Sym.Name) &&
356 Sym.Binding == STB_GLOBAL)
357 Sym.Binding = STB_WEAK;
358
359 if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
360 Sym.getShndx() != SHN_UNDEF)
361 Sym.Binding = STB_WEAK;
362
363 const auto I = Config.SymbolsToRename.find(Sym.Name);
364 if (I != Config.SymbolsToRename.end())
365 Sym.Name = I->getValue();
366 });
367
Paul Semel99dda0b2018-05-25 11:01:25 +0000368 // The purpose of this loop is to mark symbols referenced by sections
369 // (like GroupSection or RelocationSection). This way, we know which
370 // symbols are still 'needed' and wich are not.
371 if (Config.StripUnneeded) {
372 for (auto &Section : Obj.sections())
373 Section.markSymbols();
374 }
375
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000376 Obj.removeSymbols([&](const Symbol &Sym) {
Paul Semelcf51c802018-05-26 08:10:37 +0000377 if ((!Config.SymbolsToKeep.empty() &&
378 is_contained(Config.SymbolsToKeep, Sym.Name)) ||
379 (Config.KeepFileSymbols && Sym.Type == STT_FILE))
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000380 return false;
381
382 if (Config.DiscardAll && Sym.Binding == STB_LOCAL &&
383 Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE &&
384 Sym.Type != STT_SECTION)
385 return true;
386
387 if (Config.StripAll || Config.StripAllGNU)
388 return true;
389
390 if (!Config.SymbolsToRemove.empty() &&
391 is_contained(Config.SymbolsToRemove, Sym.Name)) {
392 return true;
393 }
394
Paul Semel46201fb2018-06-01 16:19:46 +0000395 if (Config.StripUnneeded && !Sym.Referenced &&
Paul Semel99dda0b2018-05-25 11:01:25 +0000396 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
397 Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
398 return true;
399
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000400 return false;
401 });
402 }
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000403
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000404 SectionPred RemovePred = [](const SectionBase &) { return false; };
405
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000406 // Removes:
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000407 if (!Config.ToRemove.empty()) {
408 RemovePred = [&Config](const SectionBase &Sec) {
Fangrui Songfdfe2a92018-07-27 22:51:36 +0000409 return find(Config.ToRemove, Sec.Name) != Config.ToRemove.end();
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000410 };
Jake Ehrlich36a2eb32017-10-10 18:47:09 +0000411 }
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000412
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000413 if (Config.StripDWO || !Config.SplitDWO.empty())
David Blaikie998ff812017-11-03 20:57:09 +0000414 RemovePred = [RemovePred](const SectionBase &Sec) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000415 return IsDWOSection(Sec) || RemovePred(Sec);
416 };
417
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000418 if (Config.ExtractDWO)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000419 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000420 return OnlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000421 };
422
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000423 if (Config.StripAllGNU)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000424 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
425 if (RemovePred(Sec))
426 return true;
427 if ((Sec.Flags & SHF_ALLOC) != 0)
428 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000429 if (&Sec == Obj.SectionNames)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000430 return false;
Jake Ehrlich777fb002017-12-15 20:17:55 +0000431 switch (Sec.Type) {
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000432 case SHT_SYMTAB:
433 case SHT_REL:
434 case SHT_RELA:
435 case SHT_STRTAB:
436 return true;
437 }
Fangrui Songfdfe2a92018-07-27 22:51:36 +0000438 return IsDebugSection(Sec);
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000439 };
440
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000441 if (Config.StripSections) {
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000442 RemovePred = [RemovePred](const SectionBase &Sec) {
443 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
444 };
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000445 }
446
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000447 if (Config.StripDebug) {
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000448 RemovePred = [RemovePred](const SectionBase &Sec) {
Fangrui Songfdfe2a92018-07-27 22:51:36 +0000449 return RemovePred(Sec) || IsDebugSection(Sec);
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000450 };
451 }
452
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000453 if (Config.StripNonAlloc)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000454 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
455 if (RemovePred(Sec))
456 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000457 if (&Sec == Obj.SectionNames)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000458 return false;
459 return (Sec.Flags & SHF_ALLOC) == 0;
460 };
461
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000462 if (Config.StripAll)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000463 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
464 if (RemovePred(Sec))
465 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000466 if (&Sec == Obj.SectionNames)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000467 return false;
468 if (Sec.Name.startswith(".gnu.warning"))
469 return false;
470 return (Sec.Flags & SHF_ALLOC) == 0;
471 };
472
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000473 // Explicit copies:
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000474 if (!Config.OnlyKeep.empty()) {
475 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000476 // Explicitly keep these sections regardless of previous removes.
Fangrui Songfdfe2a92018-07-27 22:51:36 +0000477 if (find(Config.OnlyKeep, Sec.Name) != Config.OnlyKeep.end())
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000478 return false;
479
480 // Allow all implicit removes.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000481 if (RemovePred(Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000482 return true;
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000483
484 // Keep special sections.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000485 if (Obj.SectionNames == &Sec)
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000486 return false;
Stephen Hinese6e75bf2018-07-26 20:05:31 +0000487 if (Obj.SymbolTable == &Sec ||
488 (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000489 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000490
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000491 // Remove everything else.
492 return true;
493 };
494 }
495
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000496 if (!Config.Keep.empty()) {
497 RemovePred = [Config, RemovePred](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000498 // Explicitly keep these sections regardless of previous removes.
Fangrui Songfdfe2a92018-07-27 22:51:36 +0000499 if (find(Config.Keep, Sec.Name) != Config.Keep.end())
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000500 return false;
501 // Otherwise defer to RemovePred.
502 return RemovePred(Sec);
503 };
504 }
505
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000506 // This has to be the last predicate assignment.
507 // If the option --keep-symbol has been specified
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000508 // and at least one of those symbols is present
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000509 // (equivalently, the updated symbol table is not empty)
510 // the symbol table and the string table should not be removed.
Paul Semelcf51c802018-05-26 08:10:37 +0000511 if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
Stephen Hinese6e75bf2018-07-26 20:05:31 +0000512 Obj.SymbolTable && !Obj.SymbolTable->empty()) {
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000513 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
514 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
515 return false;
516 return RemovePred(Sec);
517 };
518 }
519
Jake Ehrlich76e91102018-01-25 22:46:17 +0000520 Obj.removeSections(RemovePred);
Jake Ehrliche8437de2017-12-19 00:47:30 +0000521
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000522 if (!Config.SectionsToRename.empty()) {
523 for (auto &Sec : Obj.sections()) {
524 const auto Iter = Config.SectionsToRename.find(Sec.Name);
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000525 if (Iter != Config.SectionsToRename.end()) {
526 const SectionRename &SR = Iter->second;
527 Sec.Name = SR.NewName;
528 if (SR.NewFlags.hasValue()) {
529 // Preserve some flags which should not be dropped when setting flags.
530 // Also, preserve anything OS/processor dependant.
531 const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
532 ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
533 ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
534 ELF::SHF_TLS | ELF::SHF_INFO_LINK;
535 Sec.Flags = (Sec.Flags & PreserveMask) |
536 (SR.NewFlags.getValue() & ~PreserveMask);
537 }
538 }
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000539 }
540 }
541
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000542 if (!Config.AddSection.empty()) {
543 for (const auto &Flag : Config.AddSection) {
544 auto SecPair = Flag.split("=");
Jake Ehrliche8437de2017-12-19 00:47:30 +0000545 auto SecName = SecPair.first;
546 auto File = SecPair.second;
547 auto BufOrErr = MemoryBuffer::getFile(File);
548 if (!BufOrErr)
549 reportError(File, BufOrErr.getError());
550 auto Buf = std::move(*BufOrErr);
551 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
552 auto BufSize = Buf->getBufferSize();
Jake Ehrlich76e91102018-01-25 22:46:17 +0000553 Obj.addSection<OwnedDataSection>(SecName,
554 ArrayRef<uint8_t>(BufPtr, BufSize));
Jake Ehrliche8437de2017-12-19 00:47:30 +0000555 }
556 }
557
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000558 if (!Config.AddGnuDebugLink.empty())
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000559 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000560}
Jake Ehrlichea07d3c2018-01-25 22:15:14 +0000561
Puyan Lotfic4846a52018-07-16 22:17:05 +0000562static void ExecuteElfObjcopyOnBinary(const CopyConfig &Config, Binary &Binary,
563 Buffer &Out) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000564 ELFReader Reader(&Binary);
565 std::unique_ptr<Object> Obj = Reader.create();
566
567 HandleArgs(Config, *Obj, Reader, Reader.getElfType());
568
569 std::unique_ptr<Writer> Writer =
570 CreateWriter(Config, *Obj, Out, Reader.getElfType());
571 Writer->finalize();
572 Writer->write();
573}
574
575// For regular archives this function simply calls llvm::writeArchive,
576// For thin archives it writes the archive file itself as well as its members.
Puyan Lotfic4846a52018-07-16 22:17:05 +0000577static Error deepWriteArchive(StringRef ArcName,
578 ArrayRef<NewArchiveMember> NewMembers,
579 bool WriteSymtab, object::Archive::Kind Kind,
580 bool Deterministic, bool Thin) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000581 Error E =
582 writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
583 if (!Thin || E)
584 return E;
585 for (const NewArchiveMember &Member : NewMembers) {
586 // Internally, FileBuffer will use the buffer created by
587 // FileOutputBuffer::create, for regular files (that is the case for
588 // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
589 // OnDiskBuffer uses a temporary file and then renames it. So in reality
590 // there is no inefficiency / duplicated in-memory buffers in this case. For
591 // now in-memory buffers can not be completely avoided since
592 // NewArchiveMember still requires them even though writeArchive does not
593 // write them on disk.
594 FileBuffer FB(Member.MemberName);
595 FB.allocate(Member.Buf->getBufferSize());
596 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
597 FB.getBufferStart());
598 if (auto E = FB.commit())
599 return E;
600 }
601 return Error::success();
602}
603
Puyan Lotfi97604b42018-08-02 18:16:52 +0000604static void ExecuteElfObjcopyOnArchive(const CopyConfig &Config,
605 const Archive &Ar) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000606 std::vector<NewArchiveMember> NewArchiveMembers;
607 Error Err = Error::success();
608 for (const Archive::Child &Child : Ar.children(Err)) {
609 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
610 if (!ChildOrErr)
611 reportError(Ar.getFileName(), ChildOrErr.takeError());
612 Expected<StringRef> ChildNameOrErr = Child.getName();
613 if (!ChildNameOrErr)
614 reportError(Ar.getFileName(), ChildNameOrErr.takeError());
615
616 MemBuffer MB(ChildNameOrErr.get());
617 ExecuteElfObjcopyOnBinary(Config, **ChildOrErr, MB);
618
619 Expected<NewArchiveMember> Member =
620 NewArchiveMember::getOldMember(Child, true);
621 if (!Member)
622 reportError(Ar.getFileName(), Member.takeError());
623 Member->Buf = MB.releaseMemoryBuffer();
624 Member->MemberName = Member->Buf->getBufferIdentifier();
625 NewArchiveMembers.push_back(std::move(*Member));
626 }
627
628 if (Err)
629 reportError(Config.InputFilename, std::move(Err));
630 if (Error E =
631 deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
632 Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin()))
633 reportError(Config.OutputFilename, std::move(E));
Petr Hosek05a04cb2017-08-01 00:33:58 +0000634}
635
Puyan Lotfic4846a52018-07-16 22:17:05 +0000636static void ExecuteElfObjcopy(const CopyConfig &Config) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000637 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
638 createBinary(Config.InputFilename);
639 if (!BinaryOrErr)
640 reportError(Config.InputFilename, BinaryOrErr.takeError());
641
642 if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary()))
643 return ExecuteElfObjcopyOnArchive(Config, *Ar);
644
645 FileBuffer FB(Config.OutputFilename);
646 ExecuteElfObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB);
Petr Hosek05a04cb2017-08-01 00:33:58 +0000647}
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000648
649// ParseObjcopyOptions returns the config and sets the input arguments. If a
650// help flag is set then ParseObjcopyOptions will print the help messege and
651// exit.
Puyan Lotfic4846a52018-07-16 22:17:05 +0000652static CopyConfig ParseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000653 ObjcopyOptTable T;
654 unsigned MissingArgumentIndex, MissingArgumentCount;
655 llvm::opt::InputArgList InputArgs =
656 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +0000657
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +0000658 if (InputArgs.size() == 0) {
659 T.PrintHelp(errs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
660 exit(1);
661 }
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +0000662
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +0000663 if (InputArgs.hasArg(OBJCOPY_help)) {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000664 T.PrintHelp(outs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
665 exit(0);
666 }
667
668 SmallVector<const char *, 2> Positional;
669
670 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
671 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
672
673 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
674 Positional.push_back(Arg->getValue());
675
676 if (Positional.empty())
677 error("No input file specified");
678
679 if (Positional.size() > 2)
680 error("Too many positional arguments");
681
682 CopyConfig Config;
683 Config.InputFilename = Positional[0];
684 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
685 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
686 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
687 Config.BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
688
689 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
690 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000691
692 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
693 if (!StringRef(Arg->getValue()).contains('='))
694 error("Bad format for --redefine-sym");
695 auto Old2New = StringRef(Arg->getValue()).split('=');
696 if (!Config.SymbolsToRename.insert(Old2New).second)
697 error("Multiple redefinition of symbol " + Old2New.first);
698 }
699
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000700 for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000701 SectionRename SR = ParseRenameSectionValue(StringRef(Arg->getValue()));
702 if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
703 error("Multiple renames of section " + SR.OriginalName);
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000704 }
705
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000706 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
707 Config.ToRemove.push_back(Arg->getValue());
708 for (auto Arg : InputArgs.filtered(OBJCOPY_keep))
709 Config.Keep.push_back(Arg->getValue());
710 for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep))
711 Config.OnlyKeep.push_back(Arg->getValue());
712 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
713 Config.AddSection.push_back(Arg->getValue());
714 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
715 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
716 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
717 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
718 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
719 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
Paul Semel99dda0b2018-05-25 11:01:25 +0000720 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000721 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
722 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
Paul Semel2c0510f2018-05-02 20:14:49 +0000723 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
Paul Semel41695f82018-05-02 20:19:22 +0000724 Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
Jake Ehrliche40398a2018-05-15 20:53:53 +0000725 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
Paul Semelcf51c802018-05-26 08:10:37 +0000726 Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
Paul Semelb4924942018-04-26 17:44:43 +0000727 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000728 Config.SymbolsToLocalize.push_back(Arg->getValue());
Paul Semelee5be792018-04-27 19:09:44 +0000729 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
730 Config.SymbolsToGlobalize.push_back(Arg->getValue());
Paul Semel3a8a56b2018-04-27 19:16:27 +0000731 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
732 Config.SymbolsToWeaken.push_back(Arg->getValue());
Paul Semel4246a462018-05-09 21:36:54 +0000733 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
734 Config.SymbolsToRemove.push_back(Arg->getValue());
Paul Semel5d97c822018-05-15 14:09:37 +0000735 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
736 Config.SymbolsToKeep.push_back(Arg->getValue());
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000737
738 return Config;
739}
740
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000741// ParseStripOptions returns the config and sets the input arguments. If a
742// help flag is set then ParseStripOptions will print the help messege and
743// exit.
Puyan Lotfic4846a52018-07-16 22:17:05 +0000744static CopyConfig ParseStripOptions(ArrayRef<const char *> ArgsArr) {
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000745 StripOptTable T;
746 unsigned MissingArgumentIndex, MissingArgumentCount;
747 llvm::opt::InputArgList InputArgs =
748 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
749
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +0000750 if (InputArgs.size() == 0) {
751 T.PrintHelp(errs(), "llvm-strip <input> [ <output> ]", "strip tool");
752 exit(1);
753 }
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +0000754
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +0000755 if (InputArgs.hasArg(STRIP_help)) {
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000756 T.PrintHelp(outs(), "llvm-strip <input> [ <output> ]", "strip tool");
757 exit(0);
758 }
759
760 SmallVector<const char *, 2> Positional;
761 for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
762 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
763 for (auto Arg : InputArgs.filtered(STRIP_INPUT))
764 Positional.push_back(Arg->getValue());
765
766 if (Positional.empty())
767 error("No input file specified");
768
769 if (Positional.size() > 2)
770 error("Support for multiple input files is not implemented yet");
771
772 CopyConfig Config;
773 Config.InputFilename = Positional[0];
Alexander Shaposhnikovecc84832018-05-31 20:42:13 +0000774 Config.OutputFilename =
775 InputArgs.getLastArgValue(STRIP_output, Positional[0]);
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000776
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000777 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000778
Alexander Shaposhnikov29407f32018-06-06 21:23:19 +0000779 Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
Paul Semele57bc782018-06-07 10:05:25 +0000780 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
Stephen Hinese8c3c5f2018-07-12 17:42:17 +0000781 Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
Paul Semele57bc782018-06-07 10:05:25 +0000782
783 if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll)
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000784 Config.StripAll = true;
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +0000785
Alexander Shaposhnikov18b5fb72018-05-11 05:27:06 +0000786 for (auto Arg : InputArgs.filtered(STRIP_remove_section))
787 Config.ToRemove.push_back(Arg->getValue());
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000788
Alexander Shaposhnikov35bee3e2018-05-23 19:44:19 +0000789 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
790 Config.SymbolsToKeep.push_back(Arg->getValue());
Alexander Shaposhnikov18b5fb72018-05-11 05:27:06 +0000791
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000792 return Config;
793}
794
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000795int main(int argc, char **argv) {
796 InitLLVM X(argc, argv);
797 ToolName = argv[0];
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000798 CopyConfig Config;
799 if (sys::path::stem(ToolName).endswith_lower("strip"))
800 Config = ParseStripOptions(makeArrayRef(argv + 1, argc));
801 else
802 Config = ParseObjcopyOptions(makeArrayRef(argv + 1, argc));
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000803 ExecuteElfObjcopy(Config);
804}