blob: f0d6b4416cf20c04bcd449957c4cc48012996c2a [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"
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +000011
Petr Hosek05a04cb2017-08-01 00:33:58 +000012#include "Object.h"
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +000013#include "llvm/ADT/BitmaskEnum.h"
14#include "llvm/ADT/Optional.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000015#include "llvm/ADT/STLExtras.h"
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +000016#include "llvm/ADT/SmallVector.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000017#include "llvm/ADT/StringRef.h"
18#include "llvm/ADT/Twine.h"
19#include "llvm/BinaryFormat/ELF.h"
Puyan Lotfi5a40cd52018-09-03 22:25:56 +000020#include "llvm/MC/MCTargetOptions.h"
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +000021#include "llvm/Object/Archive.h"
22#include "llvm/Object/ArchiveWriter.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000023#include "llvm/Object/Binary.h"
24#include "llvm/Object/ELFObjectFile.h"
25#include "llvm/Object/ELFTypes.h"
26#include "llvm/Object/Error.h"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000027#include "llvm/Option/Arg.h"
28#include "llvm/Option/ArgList.h"
29#include "llvm/Option/Option.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000030#include "llvm/Support/Casting.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000031#include "llvm/Support/CommandLine.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000032#include "llvm/Support/Compiler.h"
33#include "llvm/Support/Error.h"
34#include "llvm/Support/ErrorHandling.h"
35#include "llvm/Support/ErrorOr.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000036#include "llvm/Support/FileOutputBuffer.h"
Rui Ueyama197194b2018-04-13 18:26:06 +000037#include "llvm/Support/InitLLVM.h"
Jordan Rupprechtcf676332018-08-17 18:51:11 +000038#include "llvm/Support/Memory.h"
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000039#include "llvm/Support/Path.h"
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +000040#include "llvm/Support/Process.h"
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +000041#include "llvm/Support/WithColor.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000042#include "llvm/Support/raw_ostream.h"
43#include <algorithm>
44#include <cassert>
45#include <cstdlib>
46#include <functional>
47#include <iterator>
Petr Hosek05a04cb2017-08-01 00:33:58 +000048#include <memory>
49#include <string>
50#include <system_error>
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000051#include <utility>
Petr Hosek05a04cb2017-08-01 00:33:58 +000052
53using namespace llvm;
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000054using namespace llvm::objcopy;
Petr Hosek05a04cb2017-08-01 00:33:58 +000055using namespace object;
56using namespace ELF;
57
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000058namespace {
59
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000060enum ObjcopyID {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000061 OBJCOPY_INVALID = 0, // This is not an option ID.
62#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
63 HELPTEXT, METAVAR, VALUES) \
64 OBJCOPY_##ID,
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000065#include "ObjcopyOpts.inc"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000066#undef OPTION
67};
68
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +000069#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000070#include "ObjcopyOpts.inc"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000071#undef PREFIX
72
Alexander Shaposhnikov3326e782018-04-24 06:23:22 +000073static const opt::OptTable::Info ObjcopyInfoTable[] = {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000074#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
75 HELPTEXT, METAVAR, VALUES) \
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +000076 {OBJCOPY_##PREFIX, \
77 NAME, \
78 HELPTEXT, \
79 METAVAR, \
80 OBJCOPY_##ID, \
81 opt::Option::KIND##Class, \
82 PARAM, \
83 FLAGS, \
84 OBJCOPY_##GROUP, \
85 OBJCOPY_##ALIAS, \
86 ALIASARGS, \
87 VALUES},
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000088#include "ObjcopyOpts.inc"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000089#undef OPTION
90};
91
92class ObjcopyOptTable : public opt::OptTable {
93public:
94 ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {}
95};
96
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000097enum StripID {
98 STRIP_INVALID = 0, // This is not an option ID.
99#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
100 HELPTEXT, METAVAR, VALUES) \
101 STRIP_##ID,
102#include "StripOpts.inc"
103#undef OPTION
104};
105
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000106#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
107#include "StripOpts.inc"
108#undef PREFIX
109
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000110static const opt::OptTable::Info StripInfoTable[] = {
111#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
112 HELPTEXT, METAVAR, VALUES) \
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000113 {STRIP_##PREFIX, NAME, HELPTEXT, \
114 METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
115 PARAM, FLAGS, STRIP_##GROUP, \
116 STRIP_##ALIAS, ALIASARGS, VALUES},
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000117#include "StripOpts.inc"
118#undef OPTION
119};
120
121class StripOptTable : public opt::OptTable {
122public:
123 StripOptTable() : OptTable(StripInfoTable, true) {}
124};
125
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000126struct SectionRename {
127 StringRef OriginalName;
128 StringRef NewName;
129 Optional<uint64_t> NewFlags;
130};
131
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000132struct CopyConfig {
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000133 // Main input/output options
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000134 StringRef InputFilename;
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000135 StringRef InputFormat;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000136 StringRef OutputFilename;
137 StringRef OutputFormat;
Alexander Shaposhnikovfedb0162018-02-09 23:33:31 +0000138
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000139 // Only applicable for --input-format=Binary
140 MachineInfo BinaryArch;
141
142 // Advanced options
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000143 StringRef AddGnuDebugLink;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000144 StringRef SplitDWO;
Paul Semel7a3dc2c2018-08-09 17:49:04 +0000145 StringRef SymbolsPrefix;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000146
147 // Repeated options
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000148 std::vector<StringRef> AddSection;
Paul Semela42dec72018-08-09 17:05:21 +0000149 std::vector<StringRef> DumpSection;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000150 std::vector<StringRef> Keep;
151 std::vector<StringRef> OnlyKeep;
Paul Semelee5be792018-04-27 19:09:44 +0000152 std::vector<StringRef> SymbolsToGlobalize;
Paul Semel5d97c822018-05-15 14:09:37 +0000153 std::vector<StringRef> SymbolsToKeep;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000154 std::vector<StringRef> SymbolsToLocalize;
155 std::vector<StringRef> SymbolsToRemove;
156 std::vector<StringRef> SymbolsToWeaken;
157 std::vector<StringRef> ToRemove;
Jordan Rupprechtbe8ebcc2018-08-17 22:34:48 +0000158 std::vector<std::string> SymbolsToKeepGlobal;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000159
160 // Map options
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000161 StringMap<SectionRename> SectionsToRename;
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000162 StringMap<StringRef> SymbolsToRename;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000163
164 // Boolean options
165 bool DiscardAll = false;
166 bool ExtractDWO = false;
167 bool KeepFileSymbols = false;
168 bool LocalizeHidden = false;
169 bool OnlyKeepDebug = false;
170 bool PreserveDates = false;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000171 bool StripAll = false;
172 bool StripAllGNU = false;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000173 bool StripDWO = false;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000174 bool StripDebug = false;
175 bool StripNonAlloc = false;
176 bool StripSections = false;
Paul Semel99dda0b2018-05-25 11:01:25 +0000177 bool StripUnneeded = false;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000178 bool Weaken = false;
Puyan Lotfi5a40cd52018-09-03 22:25:56 +0000179 DebugCompressionType CompressionType = DebugCompressionType::None;
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000180};
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000181
Eugene Zelenko0ad18f82017-11-01 21:16:06 +0000182using SectionPred = std::function<bool(const SectionBase &Sec)>;
Petr Hosek05a04cb2017-08-01 00:33:58 +0000183
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000184enum SectionFlag {
185 SecNone = 0,
186 SecAlloc = 1 << 0,
187 SecLoad = 1 << 1,
188 SecNoload = 1 << 2,
189 SecReadonly = 1 << 3,
190 SecDebug = 1 << 4,
191 SecCode = 1 << 5,
192 SecData = 1 << 6,
193 SecRom = 1 << 7,
194 SecMerge = 1 << 8,
195 SecStrings = 1 << 9,
196 SecContents = 1 << 10,
197 SecShare = 1 << 11,
198 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare)
199};
200
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +0000201} // namespace
202
203namespace llvm {
204namespace objcopy {
205
206// The name this program was invoked as.
207StringRef ToolName;
208
209LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +0000210 WithColor::error(errs(), ToolName) << Message << ".\n";
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +0000211 errs().flush();
212 exit(1);
213}
214
215LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
216 assert(EC);
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +0000217 WithColor::error(errs(), ToolName)
218 << "'" << File << "': " << EC.message() << ".\n";
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +0000219 exit(1);
220}
221
222LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
223 assert(E);
224 std::string Buf;
225 raw_string_ostream OS(Buf);
226 logAllUnhandledErrors(std::move(E), OS, "");
227 OS.flush();
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +0000228 WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +0000229 exit(1);
230}
231
232} // end namespace objcopy
Puyan Lotfic4846a52018-07-16 22:17:05 +0000233} // end namespace llvm
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000234
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000235static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000236 return llvm::StringSwitch<SectionFlag>(SectionName)
237 .Case("alloc", SectionFlag::SecAlloc)
238 .Case("load", SectionFlag::SecLoad)
239 .Case("noload", SectionFlag::SecNoload)
240 .Case("readonly", SectionFlag::SecReadonly)
241 .Case("debug", SectionFlag::SecDebug)
242 .Case("code", SectionFlag::SecCode)
243 .Case("data", SectionFlag::SecData)
244 .Case("rom", SectionFlag::SecRom)
245 .Case("merge", SectionFlag::SecMerge)
246 .Case("strings", SectionFlag::SecStrings)
247 .Case("contents", SectionFlag::SecContents)
248 .Case("share", SectionFlag::SecShare)
249 .Default(SectionFlag::SecNone);
250}
251
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000252static SectionRename parseRenameSectionValue(StringRef FlagValue) {
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000253 if (!FlagValue.contains('='))
254 error("Bad format for --rename-section: missing '='");
255
256 // Initial split: ".foo" = ".bar,f1,f2,..."
257 auto Old2New = FlagValue.split('=');
258 SectionRename SR;
259 SR.OriginalName = Old2New.first;
260
261 // Flags split: ".bar" "f1" "f2" ...
262 SmallVector<StringRef, 6> NameAndFlags;
263 Old2New.second.split(NameAndFlags, ',');
264 SR.NewName = NameAndFlags[0];
265
266 if (NameAndFlags.size() > 1) {
267 SectionFlag Flags = SectionFlag::SecNone;
268 for (size_t I = 1, Size = NameAndFlags.size(); I < Size; ++I) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000269 SectionFlag Flag = parseSectionRenameFlag(NameAndFlags[I]);
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000270 if (Flag == SectionFlag::SecNone)
271 error("Unrecognized section flag '" + NameAndFlags[I] +
272 "'. Flags supported for GNU compatibility: alloc, load, noload, "
273 "readonly, debug, code, data, rom, share, contents, merge, "
274 "strings.");
275 Flags |= Flag;
276 }
277
278 SR.NewFlags = 0;
279 if (Flags & SectionFlag::SecAlloc)
280 *SR.NewFlags |= ELF::SHF_ALLOC;
281 if (!(Flags & SectionFlag::SecReadonly))
282 *SR.NewFlags |= ELF::SHF_WRITE;
283 if (Flags & SectionFlag::SecCode)
284 *SR.NewFlags |= ELF::SHF_EXECINSTR;
285 if (Flags & SectionFlag::SecMerge)
286 *SR.NewFlags |= ELF::SHF_MERGE;
287 if (Flags & SectionFlag::SecStrings)
288 *SR.NewFlags |= ELF::SHF_STRINGS;
289 }
290
291 return SR;
292}
293
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000294static bool isDebugSection(const SectionBase &Sec) {
Puyan Lotfi5a40cd52018-09-03 22:25:56 +0000295 return StringRef(Sec.Name).startswith(".debug") ||
296 StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index";
Fangrui Songfdfe2a92018-07-27 22:51:36 +0000297}
298
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000299static bool isDWOSection(const SectionBase &Sec) {
Puyan Lotfi5a40cd52018-09-03 22:25:56 +0000300 return StringRef(Sec.Name).endswith(".dwo");
Puyan Lotfic4846a52018-07-16 22:17:05 +0000301}
302
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000303static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000304 // We can't remove the section header string table.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000305 if (&Sec == Obj.SectionNames)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000306 return false;
307 // Short of keeping the string table we want to keep everything that is a DWO
308 // section and remove everything else.
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000309 return !isDWOSection(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000310}
311
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000312static const StringMap<MachineInfo> ArchMap{
313 // Name, {EMachine, 64bit, LittleEndian}
314 {"aarch64", {EM_AARCH64, true, true}},
315 {"arm", {EM_ARM, false, true}},
316 {"i386", {EM_386, false, true}},
317 {"i386:x86-64", {EM_X86_64, true, true}},
318 {"powerpc:common64", {EM_PPC64, true, true}},
319 {"sparc", {EM_SPARC, false, true}},
320 {"x86-64", {EM_X86_64, true, true}},
321};
322
323static const MachineInfo &getMachineInfo(StringRef Arch) {
324 auto Iter = ArchMap.find(Arch);
325 if (Iter == std::end(ArchMap))
326 error("Invalid architecture: '" + Arch + "'");
327 return Iter->getValue();
328}
329
330static ElfType getOutputElfType(const Binary &Bin) {
331 // Infer output ELF type from the input ELF object
332 if (isa<ELFObjectFile<ELF32LE>>(Bin))
333 return ELFT_ELF32LE;
334 if (isa<ELFObjectFile<ELF64LE>>(Bin))
335 return ELFT_ELF64LE;
336 if (isa<ELFObjectFile<ELF32BE>>(Bin))
337 return ELFT_ELF32BE;
338 if (isa<ELFObjectFile<ELF64BE>>(Bin))
339 return ELFT_ELF64BE;
340 llvm_unreachable("Invalid ELFType");
341}
342
343static ElfType getOutputElfType(const MachineInfo &MI) {
344 // Infer output ELF type from the binary arch specified
345 if (MI.Is64Bit)
346 return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
347 else
348 return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
349}
350
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000351static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000352 Object &Obj, Buffer &Buf,
353 ElfType OutputElfType) {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000354 if (Config.OutputFormat == "binary") {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000355 return llvm::make_unique<BinaryWriter>(Obj, Buf);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000356 }
357 // Depending on the initial ELFT and OutputFormat we need a different Writer.
358 switch (OutputElfType) {
359 case ELFT_ELF32LE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000360 return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000361 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000362 case ELFT_ELF64LE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000363 return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000364 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000365 case ELFT_ELF32BE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000366 return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000367 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000368 case ELFT_ELF64BE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000369 return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000370 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000371 }
372 llvm_unreachable("Invalid output format");
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000373}
374
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000375static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000376 StringRef File, ElfType OutputElfType) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000377 auto DWOFile = Reader.create();
378 DWOFile->removeSections(
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000379 [&](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); });
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000380 FileBuffer FB(File);
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000381 auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000382 Writer->finalize();
383 Writer->write();
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000384}
385
Paul Semela42dec72018-08-09 17:05:21 +0000386static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
387 Object &Obj) {
388 for (auto &Sec : Obj.sections()) {
389 if (Sec.Name == SecName) {
390 if (Sec.OriginalData.size() == 0)
391 return make_error<StringError>("Can't dump section \"" + SecName +
392 "\": it has no contents",
393 object_error::parse_failed);
394 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
395 FileOutputBuffer::create(Filename, Sec.OriginalData.size());
396 if (!BufferOrErr)
397 return BufferOrErr.takeError();
398 std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
399 std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
400 Buf->getBufferStart());
401 if (Error E = Buf->commit())
402 return E;
403 return Error::success();
404 }
405 }
406 return make_error<StringError>("Section not found",
407 object_error::parse_failed);
408}
409
Puyan Lotfi5a40cd52018-09-03 22:25:56 +0000410static bool isCompressed(const SectionBase &Section) {
411 ArrayRef<uint8_t> GnuPrefix = {'Z', 'L', 'I', 'B'};
412 return StringRef(Section.Name).startswith(".zdebug") ||
413 (Section.OriginalData.size() > strlen("ZLIB") &&
414 std::equal(GnuPrefix.begin(), GnuPrefix.end(),
415 Section.OriginalData.data())) ||
416 (Section.Flags & ELF::SHF_COMPRESSED);
417}
418
419static bool isCompressable(const SectionBase &Section) {
420 return !isCompressed(Section) && isDebugSection(Section) &&
421 Section.Name != ".gdb_index";
422}
423
424static void compressSections(const CopyConfig &Config, Object &Obj,
425 SectionPred &RemovePred) {
426 SmallVector<SectionBase *, 13> ToCompress;
427 SmallVector<RelocationSection *, 13> RelocationSections;
428 for (auto &Sec : Obj.sections()) {
429 if (RelocationSection *R = dyn_cast<RelocationSection>(&Sec)) {
430 if (isCompressable(*R->getSection()))
431 RelocationSections.push_back(R);
432 continue;
433 }
434
435 if (isCompressable(Sec))
436 ToCompress.push_back(&Sec);
437 }
438
439 for (SectionBase *S : ToCompress) {
440 CompressedSection &CS =
441 Obj.addSection<CompressedSection>(*S, Config.CompressionType);
442
443 for (RelocationSection *RS : RelocationSections) {
444 if (RS->getSection() == S)
445 RS->setSection(&CS);
446 }
447 }
448
449 RemovePred = [RemovePred](const SectionBase &Sec) {
450 return isCompressable(Sec) || RemovePred(Sec);
451 };
452}
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000453// This function handles the high level operations of GNU objcopy including
454// handling command line options. It's important to outline certain properties
455// we expect to hold of the command line operations. Any operation that "keeps"
456// should keep regardless of a remove. Additionally any removal should respect
457// any previous removals. Lastly whether or not something is removed shouldn't
458// depend a) on the order the options occur in or b) on some opaque priority
459// system. The only priority is that keeps/copies overrule removes.
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000460static void handleArgs(const CopyConfig &Config, Object &Obj,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000461 const Reader &Reader, ElfType OutputElfType) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000462
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000463 if (!Config.SplitDWO.empty()) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000464 splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000465 }
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000466
467 // TODO: update or remove symbols only if there is an option that affects
468 // them.
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000469 if (Obj.SymbolTable) {
470 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
471 if ((Config.LocalizeHidden &&
472 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
473 (!Config.SymbolsToLocalize.empty() &&
474 is_contained(Config.SymbolsToLocalize, Sym.Name)))
475 Sym.Binding = STB_LOCAL;
476
Jordan Rupprechtbe8ebcc2018-08-17 22:34:48 +0000477 // Note: these two globalize flags have very similar names but different
478 // meanings:
479 //
480 // --globalize-symbol: promote a symbol to global
481 // --keep-global-symbol: all symbols except for these should be made local
482 //
483 // If --globalize-symbol is specified for a given symbol, it will be
484 // global in the output file even if it is not included via
485 // --keep-global-symbol. Because of that, make sure to check
486 // --globalize-symbol second.
487 if (!Config.SymbolsToKeepGlobal.empty() &&
488 !is_contained(Config.SymbolsToKeepGlobal, Sym.Name))
489 Sym.Binding = STB_LOCAL;
490
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000491 if (!Config.SymbolsToGlobalize.empty() &&
492 is_contained(Config.SymbolsToGlobalize, Sym.Name))
493 Sym.Binding = STB_GLOBAL;
494
495 if (!Config.SymbolsToWeaken.empty() &&
496 is_contained(Config.SymbolsToWeaken, Sym.Name) &&
497 Sym.Binding == STB_GLOBAL)
498 Sym.Binding = STB_WEAK;
499
500 if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
501 Sym.getShndx() != SHN_UNDEF)
502 Sym.Binding = STB_WEAK;
503
504 const auto I = Config.SymbolsToRename.find(Sym.Name);
505 if (I != Config.SymbolsToRename.end())
506 Sym.Name = I->getValue();
Paul Semel7a3dc2c2018-08-09 17:49:04 +0000507
508 if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
509 Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000510 });
511
Paul Semel99dda0b2018-05-25 11:01:25 +0000512 // The purpose of this loop is to mark symbols referenced by sections
513 // (like GroupSection or RelocationSection). This way, we know which
514 // symbols are still 'needed' and wich are not.
515 if (Config.StripUnneeded) {
516 for (auto &Section : Obj.sections())
517 Section.markSymbols();
518 }
519
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000520 Obj.removeSymbols([&](const Symbol &Sym) {
Paul Semelcf51c802018-05-26 08:10:37 +0000521 if ((!Config.SymbolsToKeep.empty() &&
522 is_contained(Config.SymbolsToKeep, Sym.Name)) ||
523 (Config.KeepFileSymbols && Sym.Type == STT_FILE))
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000524 return false;
525
526 if (Config.DiscardAll && Sym.Binding == STB_LOCAL &&
527 Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE &&
528 Sym.Type != STT_SECTION)
529 return true;
530
531 if (Config.StripAll || Config.StripAllGNU)
532 return true;
533
534 if (!Config.SymbolsToRemove.empty() &&
535 is_contained(Config.SymbolsToRemove, Sym.Name)) {
536 return true;
537 }
538
Paul Semel46201fb2018-06-01 16:19:46 +0000539 if (Config.StripUnneeded && !Sym.Referenced &&
Paul Semel99dda0b2018-05-25 11:01:25 +0000540 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
541 Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
542 return true;
543
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000544 return false;
545 });
546 }
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000547
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000548 SectionPred RemovePred = [](const SectionBase &) { return false; };
549
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000550 // Removes:
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000551 if (!Config.ToRemove.empty()) {
552 RemovePred = [&Config](const SectionBase &Sec) {
Fangrui Song0e49ef92018-08-21 00:13:52 +0000553 return is_contained(Config.ToRemove, Sec.Name);
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000554 };
Jake Ehrlich36a2eb32017-10-10 18:47:09 +0000555 }
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000556
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000557 if (Config.StripDWO || !Config.SplitDWO.empty())
David Blaikie998ff812017-11-03 20:57:09 +0000558 RemovePred = [RemovePred](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000559 return isDWOSection(Sec) || RemovePred(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000560 };
561
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000562 if (Config.ExtractDWO)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000563 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000564 return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000565 };
566
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000567 if (Config.StripAllGNU)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000568 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
569 if (RemovePred(Sec))
570 return true;
571 if ((Sec.Flags & SHF_ALLOC) != 0)
572 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000573 if (&Sec == Obj.SectionNames)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000574 return false;
Jake Ehrlich777fb002017-12-15 20:17:55 +0000575 switch (Sec.Type) {
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000576 case SHT_SYMTAB:
577 case SHT_REL:
578 case SHT_RELA:
579 case SHT_STRTAB:
580 return true;
581 }
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000582 return isDebugSection(Sec);
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000583 };
584
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000585 if (Config.StripSections) {
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000586 RemovePred = [RemovePred](const SectionBase &Sec) {
587 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
588 };
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000589 }
590
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000591 if (Config.StripDebug) {
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000592 RemovePred = [RemovePred](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000593 return RemovePred(Sec) || isDebugSection(Sec);
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000594 };
595 }
596
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000597 if (Config.StripNonAlloc)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000598 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
599 if (RemovePred(Sec))
600 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000601 if (&Sec == Obj.SectionNames)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000602 return false;
603 return (Sec.Flags & SHF_ALLOC) == 0;
604 };
605
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000606 if (Config.StripAll)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000607 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
608 if (RemovePred(Sec))
609 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000610 if (&Sec == Obj.SectionNames)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000611 return false;
Puyan Lotfi5a40cd52018-09-03 22:25:56 +0000612 if (StringRef(Sec.Name).startswith(".gnu.warning"))
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000613 return false;
614 return (Sec.Flags & SHF_ALLOC) == 0;
615 };
616
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000617 // Explicit copies:
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000618 if (!Config.OnlyKeep.empty()) {
619 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000620 // Explicitly keep these sections regardless of previous removes.
Fangrui Song0e49ef92018-08-21 00:13:52 +0000621 if (is_contained(Config.OnlyKeep, Sec.Name))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000622 return false;
623
624 // Allow all implicit removes.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000625 if (RemovePred(Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000626 return true;
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000627
628 // Keep special sections.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000629 if (Obj.SectionNames == &Sec)
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000630 return false;
Stephen Hinese6e75bf2018-07-26 20:05:31 +0000631 if (Obj.SymbolTable == &Sec ||
632 (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000633 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000634
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000635 // Remove everything else.
636 return true;
637 };
638 }
639
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000640 if (!Config.Keep.empty()) {
641 RemovePred = [Config, RemovePred](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000642 // Explicitly keep these sections regardless of previous removes.
Fangrui Song0e49ef92018-08-21 00:13:52 +0000643 if (is_contained(Config.Keep, Sec.Name))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000644 return false;
645 // Otherwise defer to RemovePred.
646 return RemovePred(Sec);
647 };
648 }
649
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000650 // This has to be the last predicate assignment.
651 // If the option --keep-symbol has been specified
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000652 // and at least one of those symbols is present
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000653 // (equivalently, the updated symbol table is not empty)
654 // the symbol table and the string table should not be removed.
Paul Semelcf51c802018-05-26 08:10:37 +0000655 if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
Stephen Hinese6e75bf2018-07-26 20:05:31 +0000656 Obj.SymbolTable && !Obj.SymbolTable->empty()) {
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000657 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
658 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
659 return false;
660 return RemovePred(Sec);
661 };
662 }
663
Puyan Lotfi5a40cd52018-09-03 22:25:56 +0000664 if (Config.CompressionType != DebugCompressionType::None)
665 compressSections(Config, Obj, RemovePred);
666
Jake Ehrlich76e91102018-01-25 22:46:17 +0000667 Obj.removeSections(RemovePred);
Jake Ehrliche8437de2017-12-19 00:47:30 +0000668
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000669 if (!Config.SectionsToRename.empty()) {
670 for (auto &Sec : Obj.sections()) {
671 const auto Iter = Config.SectionsToRename.find(Sec.Name);
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000672 if (Iter != Config.SectionsToRename.end()) {
673 const SectionRename &SR = Iter->second;
674 Sec.Name = SR.NewName;
675 if (SR.NewFlags.hasValue()) {
676 // Preserve some flags which should not be dropped when setting flags.
677 // Also, preserve anything OS/processor dependant.
678 const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
679 ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
680 ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
681 ELF::SHF_TLS | ELF::SHF_INFO_LINK;
682 Sec.Flags = (Sec.Flags & PreserveMask) |
683 (SR.NewFlags.getValue() & ~PreserveMask);
684 }
685 }
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000686 }
687 }
688
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000689 if (!Config.AddSection.empty()) {
690 for (const auto &Flag : Config.AddSection) {
691 auto SecPair = Flag.split("=");
Jake Ehrliche8437de2017-12-19 00:47:30 +0000692 auto SecName = SecPair.first;
693 auto File = SecPair.second;
694 auto BufOrErr = MemoryBuffer::getFile(File);
695 if (!BufOrErr)
696 reportError(File, BufOrErr.getError());
697 auto Buf = std::move(*BufOrErr);
698 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
699 auto BufSize = Buf->getBufferSize();
Jake Ehrlich76e91102018-01-25 22:46:17 +0000700 Obj.addSection<OwnedDataSection>(SecName,
701 ArrayRef<uint8_t>(BufPtr, BufSize));
Jake Ehrliche8437de2017-12-19 00:47:30 +0000702 }
703 }
704
Paul Semela42dec72018-08-09 17:05:21 +0000705 if (!Config.DumpSection.empty()) {
706 for (const auto &Flag : Config.DumpSection) {
707 std::pair<StringRef, StringRef> SecPair = Flag.split("=");
708 StringRef SecName = SecPair.first;
709 StringRef File = SecPair.second;
710 if (Error E = dumpSectionToFile(SecName, File, Obj))
711 reportError(Config.InputFilename, std::move(E));
712 }
713 }
714
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000715 if (!Config.AddGnuDebugLink.empty())
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000716 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000717}
Jake Ehrlichea07d3c2018-01-25 22:15:14 +0000718
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000719static void executeElfObjcopyOnBinary(const CopyConfig &Config, Reader &Reader,
720 Buffer &Out, ElfType OutputElfType) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000721 std::unique_ptr<Object> Obj = Reader.create();
722
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000723 handleArgs(Config, *Obj, Reader, OutputElfType);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000724
725 std::unique_ptr<Writer> Writer =
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000726 createWriter(Config, *Obj, Out, OutputElfType);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000727 Writer->finalize();
728 Writer->write();
729}
730
731// For regular archives this function simply calls llvm::writeArchive,
732// For thin archives it writes the archive file itself as well as its members.
Puyan Lotfic4846a52018-07-16 22:17:05 +0000733static Error deepWriteArchive(StringRef ArcName,
734 ArrayRef<NewArchiveMember> NewMembers,
735 bool WriteSymtab, object::Archive::Kind Kind,
736 bool Deterministic, bool Thin) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000737 Error E =
738 writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
739 if (!Thin || E)
740 return E;
741 for (const NewArchiveMember &Member : NewMembers) {
742 // Internally, FileBuffer will use the buffer created by
743 // FileOutputBuffer::create, for regular files (that is the case for
744 // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
745 // OnDiskBuffer uses a temporary file and then renames it. So in reality
746 // there is no inefficiency / duplicated in-memory buffers in this case. For
747 // now in-memory buffers can not be completely avoided since
748 // NewArchiveMember still requires them even though writeArchive does not
749 // write them on disk.
750 FileBuffer FB(Member.MemberName);
751 FB.allocate(Member.Buf->getBufferSize());
752 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
753 FB.getBufferStart());
754 if (auto E = FB.commit())
755 return E;
756 }
757 return Error::success();
758}
759
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000760static void executeElfObjcopyOnArchive(const CopyConfig &Config,
Puyan Lotfi97604b42018-08-02 18:16:52 +0000761 const Archive &Ar) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000762 std::vector<NewArchiveMember> NewArchiveMembers;
763 Error Err = Error::success();
764 for (const Archive::Child &Child : Ar.children(Err)) {
765 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
766 if (!ChildOrErr)
767 reportError(Ar.getFileName(), ChildOrErr.takeError());
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000768 Binary *Bin = ChildOrErr->get();
769
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000770 Expected<StringRef> ChildNameOrErr = Child.getName();
771 if (!ChildNameOrErr)
772 reportError(Ar.getFileName(), ChildNameOrErr.takeError());
773
774 MemBuffer MB(ChildNameOrErr.get());
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000775 ELFReader Reader(Bin);
776 executeElfObjcopyOnBinary(Config, Reader, MB, getOutputElfType(*Bin));
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000777
778 Expected<NewArchiveMember> Member =
779 NewArchiveMember::getOldMember(Child, true);
780 if (!Member)
781 reportError(Ar.getFileName(), Member.takeError());
782 Member->Buf = MB.releaseMemoryBuffer();
783 Member->MemberName = Member->Buf->getBufferIdentifier();
784 NewArchiveMembers.push_back(std::move(*Member));
785 }
786
787 if (Err)
788 reportError(Config.InputFilename, std::move(Err));
789 if (Error E =
790 deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
791 Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin()))
792 reportError(Config.OutputFilename, std::move(E));
Petr Hosek05a04cb2017-08-01 00:33:58 +0000793}
794
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000795static void restoreDateOnFile(StringRef Filename,
796 const sys::fs::file_status &Stat) {
797 int FD;
798
Jordan Rupprecht74815402018-08-29 23:21:56 +0000799 if (auto EC =
800 sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000801 reportError(Filename, EC);
802
803 if (auto EC = sys::fs::setLastAccessAndModificationTime(
804 FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
805 reportError(Filename, EC);
806
807 if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
808 reportError(Filename, EC);
809}
810
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000811static void executeElfObjcopy(const CopyConfig &Config) {
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000812 sys::fs::file_status Stat;
813 if (Config.PreserveDates)
814 if (auto EC = sys::fs::status(Config.InputFilename, Stat))
815 reportError(Config.InputFilename, EC);
816
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000817 if (Config.InputFormat == "binary") {
818 auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename);
819 if (!BufOrErr)
820 reportError(Config.InputFilename, BufOrErr.getError());
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000821
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000822 FileBuffer FB(Config.OutputFilename);
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000823 BinaryReader Reader(Config.BinaryArch, BufOrErr->get());
824 executeElfObjcopyOnBinary(Config, Reader, FB,
825 getOutputElfType(Config.BinaryArch));
826 } else {
827 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
828 createBinary(Config.InputFilename);
829 if (!BinaryOrErr)
830 reportError(Config.InputFilename, BinaryOrErr.takeError());
831
832 if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
833 executeElfObjcopyOnArchive(Config, *Ar);
834 } else {
835 FileBuffer FB(Config.OutputFilename);
836 Binary *Bin = BinaryOrErr.get().getBinary();
837 ELFReader Reader(Bin);
838 executeElfObjcopyOnBinary(Config, Reader, FB, getOutputElfType(*Bin));
839 }
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000840 }
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000841
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000842 if (Config.PreserveDates) {
843 restoreDateOnFile(Config.OutputFilename, Stat);
844 if (!Config.SplitDWO.empty())
845 restoreDateOnFile(Config.SplitDWO, Stat);
846 }
Petr Hosek05a04cb2017-08-01 00:33:58 +0000847}
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000848
Jordan Rupprechtbe8ebcc2018-08-17 22:34:48 +0000849static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
850 StringRef Filename) {
851 SmallVector<StringRef, 16> Lines;
852 auto BufOrErr = MemoryBuffer::getFile(Filename);
853 if (!BufOrErr)
854 reportError(Filename, BufOrErr.getError());
855
856 BufOrErr.get()->getBuffer().split(Lines, '\n');
857 for (StringRef Line : Lines) {
858 // Ignore everything after '#', trim whitespace, and only add the symbol if
859 // it's not empty.
860 auto TrimmedLine = Line.split('#').first.trim();
861 if (!TrimmedLine.empty())
862 Symbols.push_back(TrimmedLine.str());
863 }
864}
865
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000866// ParseObjcopyOptions returns the config and sets the input arguments. If a
867// help flag is set then ParseObjcopyOptions will print the help messege and
868// exit.
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000869static CopyConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000870 ObjcopyOptTable T;
871 unsigned MissingArgumentIndex, MissingArgumentCount;
872 llvm::opt::InputArgList InputArgs =
873 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +0000874
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +0000875 if (InputArgs.size() == 0) {
876 T.PrintHelp(errs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
877 exit(1);
878 }
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +0000879
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +0000880 if (InputArgs.hasArg(OBJCOPY_help)) {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000881 T.PrintHelp(outs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
882 exit(0);
883 }
884
885 SmallVector<const char *, 2> Positional;
886
887 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
888 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
889
890 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
891 Positional.push_back(Arg->getValue());
892
893 if (Positional.empty())
894 error("No input file specified");
895
896 if (Positional.size() > 2)
897 error("Too many positional arguments");
898
899 CopyConfig Config;
900 Config.InputFilename = Positional[0];
901 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
902 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
903 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000904 if (Config.InputFormat == "binary") {
905 auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
906 if (BinaryArch.empty())
907 error("Specified binary input without specifiying an architecture");
908 Config.BinaryArch = getMachineInfo(BinaryArch);
909 }
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000910
Puyan Lotfi5a40cd52018-09-03 22:25:56 +0000911 if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
912 OBJCOPY_compress_debug_sections_eq)) {
913 Config.CompressionType = DebugCompressionType::Z;
914
915 if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
916 Config.CompressionType =
917 StringSwitch<DebugCompressionType>(
918 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
919 .Case("zlib-gnu", DebugCompressionType::GNU)
920 .Case("zlib", DebugCompressionType::Z)
921 .Default(DebugCompressionType::None);
922 if (Config.CompressionType == DebugCompressionType::None)
923 error("Invalid or unsupported --compress-debug-sections format: " +
924 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq));
925 }
926 }
927
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000928 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
929 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
Paul Semel7a3dc2c2018-08-09 17:49:04 +0000930 Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000931
932 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
933 if (!StringRef(Arg->getValue()).contains('='))
934 error("Bad format for --redefine-sym");
935 auto Old2New = StringRef(Arg->getValue()).split('=');
936 if (!Config.SymbolsToRename.insert(Old2New).second)
937 error("Multiple redefinition of symbol " + Old2New.first);
938 }
939
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000940 for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000941 SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue()));
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000942 if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
943 error("Multiple renames of section " + SR.OriginalName);
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000944 }
945
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000946 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
947 Config.ToRemove.push_back(Arg->getValue());
948 for (auto Arg : InputArgs.filtered(OBJCOPY_keep))
949 Config.Keep.push_back(Arg->getValue());
950 for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep))
951 Config.OnlyKeep.push_back(Arg->getValue());
952 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
953 Config.AddSection.push_back(Arg->getValue());
Paul Semela42dec72018-08-09 17:05:21 +0000954 for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
955 Config.DumpSection.push_back(Arg->getValue());
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000956 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
957 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
958 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
959 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
960 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
961 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
Paul Semel99dda0b2018-05-25 11:01:25 +0000962 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000963 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
964 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
Paul Semel2c0510f2018-05-02 20:14:49 +0000965 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
Paul Semel41695f82018-05-02 20:19:22 +0000966 Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
Jake Ehrliche40398a2018-05-15 20:53:53 +0000967 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
Paul Semelcf51c802018-05-26 08:10:37 +0000968 Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
Paul Semelb4924942018-04-26 17:44:43 +0000969 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000970 Config.SymbolsToLocalize.push_back(Arg->getValue());
Jordan Rupprechtbe8ebcc2018-08-17 22:34:48 +0000971 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
972 Config.SymbolsToKeepGlobal.push_back(Arg->getValue());
973 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
974 addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue());
Paul Semelee5be792018-04-27 19:09:44 +0000975 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
976 Config.SymbolsToGlobalize.push_back(Arg->getValue());
Paul Semel3a8a56b2018-04-27 19:16:27 +0000977 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
978 Config.SymbolsToWeaken.push_back(Arg->getValue());
Paul Semel4246a462018-05-09 21:36:54 +0000979 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
980 Config.SymbolsToRemove.push_back(Arg->getValue());
Paul Semel5d97c822018-05-15 14:09:37 +0000981 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
982 Config.SymbolsToKeep.push_back(Arg->getValue());
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000983
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000984 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
985
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000986 return Config;
987}
988
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000989// ParseStripOptions returns the config and sets the input arguments. If a
990// help flag is set then ParseStripOptions will print the help messege and
991// exit.
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000992static CopyConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000993 StripOptTable T;
994 unsigned MissingArgumentIndex, MissingArgumentCount;
995 llvm::opt::InputArgList InputArgs =
996 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
997
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +0000998 if (InputArgs.size() == 0) {
Fangrui Songffbc3e22018-08-20 23:01:57 +0000999 T.PrintHelp(errs(), "llvm-strip", "strip tool");
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +00001000 exit(1);
1001 }
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +00001002
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +00001003 if (InputArgs.hasArg(STRIP_help)) {
Fangrui Songffbc3e22018-08-20 23:01:57 +00001004 T.PrintHelp(outs(), "llvm-strip", "strip tool");
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001005 exit(0);
1006 }
1007
1008 SmallVector<const char *, 2> Positional;
1009 for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
1010 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
1011 for (auto Arg : InputArgs.filtered(STRIP_INPUT))
1012 Positional.push_back(Arg->getValue());
1013
1014 if (Positional.empty())
1015 error("No input file specified");
1016
Fangrui Songffbc3e22018-08-20 23:01:57 +00001017 if (Positional.size() > 1)
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001018 error("Support for multiple input files is not implemented yet");
1019
1020 CopyConfig Config;
1021 Config.InputFilename = Positional[0];
Alexander Shaposhnikovecc84832018-05-31 20:42:13 +00001022 Config.OutputFilename =
1023 InputArgs.getLastArgValue(STRIP_output, Positional[0]);
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001024
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001025 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +00001026
Alexander Shaposhnikov29407f32018-06-06 21:23:19 +00001027 Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
Paul Semele57bc782018-06-07 10:05:25 +00001028 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
Stephen Hinese8c3c5f2018-07-12 17:42:17 +00001029 Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
Paul Semele57bc782018-06-07 10:05:25 +00001030
1031 if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll)
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001032 Config.StripAll = true;
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +00001033
Alexander Shaposhnikov18b5fb72018-05-11 05:27:06 +00001034 for (auto Arg : InputArgs.filtered(STRIP_remove_section))
1035 Config.ToRemove.push_back(Arg->getValue());
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +00001036
Alexander Shaposhnikov35bee3e2018-05-23 19:44:19 +00001037 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
1038 Config.SymbolsToKeep.push_back(Arg->getValue());
Alexander Shaposhnikov18b5fb72018-05-11 05:27:06 +00001039
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +00001040 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
1041
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001042 return Config;
1043}
1044
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +00001045int main(int argc, char **argv) {
1046 InitLLVM X(argc, argv);
1047 ToolName = argv[0];
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001048 CopyConfig Config;
1049 if (sys::path::stem(ToolName).endswith_lower("strip"))
Jordan Rupprecht6b575392018-08-13 21:30:27 +00001050 Config = parseStripOptions(makeArrayRef(argv + 1, argc));
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001051 else
Jordan Rupprecht6b575392018-08-13 21:30:27 +00001052 Config = parseObjcopyOptions(makeArrayRef(argv + 1, argc));
1053 executeElfObjcopy(Config);
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +00001054}