blob: 36ed77a8063394b46acdd18e4b868adc8e7de152 [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 Lotfi99124cc2018-09-07 08:10:22 +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"
Puyan Lotfi99124cc2018-09-07 08:10:22 +000033#include "llvm/Support/Compression.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000034#include "llvm/Support/Error.h"
35#include "llvm/Support/ErrorHandling.h"
36#include "llvm/Support/ErrorOr.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000037#include "llvm/Support/FileOutputBuffer.h"
Rui Ueyama197194b2018-04-13 18:26:06 +000038#include "llvm/Support/InitLLVM.h"
Jordan Rupprechtcf676332018-08-17 18:51:11 +000039#include "llvm/Support/Memory.h"
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000040#include "llvm/Support/Path.h"
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +000041#include "llvm/Support/Process.h"
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +000042#include "llvm/Support/WithColor.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000043#include "llvm/Support/raw_ostream.h"
44#include <algorithm>
45#include <cassert>
46#include <cstdlib>
47#include <functional>
48#include <iterator>
Petr Hosek05a04cb2017-08-01 00:33:58 +000049#include <memory>
50#include <string>
51#include <system_error>
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000052#include <utility>
Petr Hosek05a04cb2017-08-01 00:33:58 +000053
54using namespace llvm;
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000055using namespace llvm::objcopy;
Petr Hosek05a04cb2017-08-01 00:33:58 +000056using namespace object;
57using namespace ELF;
58
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000059namespace {
60
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000061enum ObjcopyID {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000062 OBJCOPY_INVALID = 0, // This is not an option ID.
63#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
64 HELPTEXT, METAVAR, VALUES) \
65 OBJCOPY_##ID,
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000066#include "ObjcopyOpts.inc"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000067#undef OPTION
68};
69
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +000070#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000071#include "ObjcopyOpts.inc"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000072#undef PREFIX
73
Alexander Shaposhnikov3326e782018-04-24 06:23:22 +000074static const opt::OptTable::Info ObjcopyInfoTable[] = {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000075#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
76 HELPTEXT, METAVAR, VALUES) \
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +000077 {OBJCOPY_##PREFIX, \
78 NAME, \
79 HELPTEXT, \
80 METAVAR, \
81 OBJCOPY_##ID, \
82 opt::Option::KIND##Class, \
83 PARAM, \
84 FLAGS, \
85 OBJCOPY_##GROUP, \
86 OBJCOPY_##ALIAS, \
87 ALIASARGS, \
88 VALUES},
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000089#include "ObjcopyOpts.inc"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000090#undef OPTION
91};
92
93class ObjcopyOptTable : public opt::OptTable {
94public:
95 ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {}
96};
97
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000098enum StripID {
99 STRIP_INVALID = 0, // This is not an option ID.
100#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
101 HELPTEXT, METAVAR, VALUES) \
102 STRIP_##ID,
103#include "StripOpts.inc"
104#undef OPTION
105};
106
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000107#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
108#include "StripOpts.inc"
109#undef PREFIX
110
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000111static const opt::OptTable::Info StripInfoTable[] = {
112#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
113 HELPTEXT, METAVAR, VALUES) \
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000114 {STRIP_##PREFIX, NAME, HELPTEXT, \
115 METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
116 PARAM, FLAGS, STRIP_##GROUP, \
117 STRIP_##ALIAS, ALIASARGS, VALUES},
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000118#include "StripOpts.inc"
119#undef OPTION
120};
121
122class StripOptTable : public opt::OptTable {
123public:
124 StripOptTable() : OptTable(StripInfoTable, true) {}
125};
126
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000127struct SectionRename {
128 StringRef OriginalName;
129 StringRef NewName;
130 Optional<uint64_t> NewFlags;
131};
132
Jordan Rupprecht591d8892018-09-05 13:10:03 +0000133// Configuration for copying/stripping a single file.
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000134struct CopyConfig {
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000135 // Main input/output options
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000136 StringRef InputFilename;
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000137 StringRef InputFormat;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000138 StringRef OutputFilename;
139 StringRef OutputFormat;
Alexander Shaposhnikovfedb0162018-02-09 23:33:31 +0000140
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000141 // Only applicable for --input-format=Binary
142 MachineInfo BinaryArch;
143
144 // Advanced options
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000145 StringRef AddGnuDebugLink;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000146 StringRef SplitDWO;
Paul Semel7a3dc2c2018-08-09 17:49:04 +0000147 StringRef SymbolsPrefix;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000148
149 // Repeated options
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000150 std::vector<StringRef> AddSection;
Paul Semela42dec72018-08-09 17:05:21 +0000151 std::vector<StringRef> DumpSection;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000152 std::vector<StringRef> Keep;
153 std::vector<StringRef> OnlyKeep;
Paul Semelee5be792018-04-27 19:09:44 +0000154 std::vector<StringRef> SymbolsToGlobalize;
Paul Semel5d97c822018-05-15 14:09:37 +0000155 std::vector<StringRef> SymbolsToKeep;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000156 std::vector<StringRef> SymbolsToLocalize;
157 std::vector<StringRef> SymbolsToRemove;
158 std::vector<StringRef> SymbolsToWeaken;
159 std::vector<StringRef> ToRemove;
Jordan Rupprechtbe8ebcc2018-08-17 22:34:48 +0000160 std::vector<std::string> SymbolsToKeepGlobal;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000161
162 // Map options
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000163 StringMap<SectionRename> SectionsToRename;
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000164 StringMap<StringRef> SymbolsToRename;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000165
166 // Boolean options
167 bool DiscardAll = false;
168 bool ExtractDWO = false;
169 bool KeepFileSymbols = false;
170 bool LocalizeHidden = false;
171 bool OnlyKeepDebug = false;
172 bool PreserveDates = false;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000173 bool StripAll = false;
174 bool StripAllGNU = false;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000175 bool StripDWO = false;
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000176 bool StripDebug = false;
177 bool StripNonAlloc = false;
178 bool StripSections = false;
Paul Semel99dda0b2018-05-25 11:01:25 +0000179 bool StripUnneeded = false;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000180 bool Weaken = false;
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000181 DebugCompressionType CompressionType = DebugCompressionType::None;
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000182};
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000183
Jordan Rupprecht591d8892018-09-05 13:10:03 +0000184// Configuration for the overall invocation of this tool. When invoked as
185// objcopy, will always contain exactly one CopyConfig. When invoked as strip,
186// will contain one or more CopyConfigs.
187struct DriverConfig {
188 SmallVector<CopyConfig, 1> CopyConfigs;
189};
190
Eugene Zelenko0ad18f82017-11-01 21:16:06 +0000191using SectionPred = std::function<bool(const SectionBase &Sec)>;
Petr Hosek05a04cb2017-08-01 00:33:58 +0000192
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000193enum SectionFlag {
194 SecNone = 0,
195 SecAlloc = 1 << 0,
196 SecLoad = 1 << 1,
197 SecNoload = 1 << 2,
198 SecReadonly = 1 << 3,
199 SecDebug = 1 << 4,
200 SecCode = 1 << 5,
201 SecData = 1 << 6,
202 SecRom = 1 << 7,
203 SecMerge = 1 << 8,
204 SecStrings = 1 << 9,
205 SecContents = 1 << 10,
206 SecShare = 1 << 11,
207 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare)
208};
209
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +0000210} // namespace
211
212namespace llvm {
213namespace objcopy {
214
215// The name this program was invoked as.
216StringRef ToolName;
217
218LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +0000219 WithColor::error(errs(), ToolName) << Message << ".\n";
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +0000220 errs().flush();
221 exit(1);
222}
223
224LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
225 assert(EC);
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +0000226 WithColor::error(errs(), ToolName)
227 << "'" << File << "': " << EC.message() << ".\n";
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +0000228 exit(1);
229}
230
231LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
232 assert(E);
233 std::string Buf;
234 raw_string_ostream OS(Buf);
235 logAllUnhandledErrors(std::move(E), OS, "");
236 OS.flush();
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +0000237 WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +0000238 exit(1);
239}
240
241} // end namespace objcopy
Puyan Lotfic4846a52018-07-16 22:17:05 +0000242} // end namespace llvm
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000243
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000244static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000245 return llvm::StringSwitch<SectionFlag>(SectionName)
246 .Case("alloc", SectionFlag::SecAlloc)
247 .Case("load", SectionFlag::SecLoad)
248 .Case("noload", SectionFlag::SecNoload)
249 .Case("readonly", SectionFlag::SecReadonly)
250 .Case("debug", SectionFlag::SecDebug)
251 .Case("code", SectionFlag::SecCode)
252 .Case("data", SectionFlag::SecData)
253 .Case("rom", SectionFlag::SecRom)
254 .Case("merge", SectionFlag::SecMerge)
255 .Case("strings", SectionFlag::SecStrings)
256 .Case("contents", SectionFlag::SecContents)
257 .Case("share", SectionFlag::SecShare)
258 .Default(SectionFlag::SecNone);
259}
260
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000261static SectionRename parseRenameSectionValue(StringRef FlagValue) {
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000262 if (!FlagValue.contains('='))
263 error("Bad format for --rename-section: missing '='");
264
265 // Initial split: ".foo" = ".bar,f1,f2,..."
266 auto Old2New = FlagValue.split('=');
267 SectionRename SR;
268 SR.OriginalName = Old2New.first;
269
270 // Flags split: ".bar" "f1" "f2" ...
271 SmallVector<StringRef, 6> NameAndFlags;
272 Old2New.second.split(NameAndFlags, ',');
273 SR.NewName = NameAndFlags[0];
274
275 if (NameAndFlags.size() > 1) {
276 SectionFlag Flags = SectionFlag::SecNone;
277 for (size_t I = 1, Size = NameAndFlags.size(); I < Size; ++I) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000278 SectionFlag Flag = parseSectionRenameFlag(NameAndFlags[I]);
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000279 if (Flag == SectionFlag::SecNone)
280 error("Unrecognized section flag '" + NameAndFlags[I] +
281 "'. Flags supported for GNU compatibility: alloc, load, noload, "
282 "readonly, debug, code, data, rom, share, contents, merge, "
283 "strings.");
284 Flags |= Flag;
285 }
286
287 SR.NewFlags = 0;
288 if (Flags & SectionFlag::SecAlloc)
289 *SR.NewFlags |= ELF::SHF_ALLOC;
290 if (!(Flags & SectionFlag::SecReadonly))
291 *SR.NewFlags |= ELF::SHF_WRITE;
292 if (Flags & SectionFlag::SecCode)
293 *SR.NewFlags |= ELF::SHF_EXECINSTR;
294 if (Flags & SectionFlag::SecMerge)
295 *SR.NewFlags |= ELF::SHF_MERGE;
296 if (Flags & SectionFlag::SecStrings)
297 *SR.NewFlags |= ELF::SHF_STRINGS;
298 }
299
300 return SR;
301}
302
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000303static bool isDebugSection(const SectionBase &Sec) {
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000304 return StringRef(Sec.Name).startswith(".debug") ||
305 StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index";
Fangrui Songfdfe2a92018-07-27 22:51:36 +0000306}
307
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000308static bool isDWOSection(const SectionBase &Sec) {
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000309 return StringRef(Sec.Name).endswith(".dwo");
Puyan Lotfic4846a52018-07-16 22:17:05 +0000310}
311
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000312static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000313 // We can't remove the section header string table.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000314 if (&Sec == Obj.SectionNames)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000315 return false;
316 // Short of keeping the string table we want to keep everything that is a DWO
317 // section and remove everything else.
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000318 return !isDWOSection(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000319}
320
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000321static const StringMap<MachineInfo> ArchMap{
322 // Name, {EMachine, 64bit, LittleEndian}
323 {"aarch64", {EM_AARCH64, true, true}},
324 {"arm", {EM_ARM, false, true}},
325 {"i386", {EM_386, false, true}},
326 {"i386:x86-64", {EM_X86_64, true, true}},
327 {"powerpc:common64", {EM_PPC64, true, true}},
328 {"sparc", {EM_SPARC, false, true}},
329 {"x86-64", {EM_X86_64, true, true}},
330};
331
332static const MachineInfo &getMachineInfo(StringRef Arch) {
333 auto Iter = ArchMap.find(Arch);
334 if (Iter == std::end(ArchMap))
335 error("Invalid architecture: '" + Arch + "'");
336 return Iter->getValue();
337}
338
339static ElfType getOutputElfType(const Binary &Bin) {
340 // Infer output ELF type from the input ELF object
341 if (isa<ELFObjectFile<ELF32LE>>(Bin))
342 return ELFT_ELF32LE;
343 if (isa<ELFObjectFile<ELF64LE>>(Bin))
344 return ELFT_ELF64LE;
345 if (isa<ELFObjectFile<ELF32BE>>(Bin))
346 return ELFT_ELF32BE;
347 if (isa<ELFObjectFile<ELF64BE>>(Bin))
348 return ELFT_ELF64BE;
349 llvm_unreachable("Invalid ELFType");
350}
351
352static ElfType getOutputElfType(const MachineInfo &MI) {
353 // Infer output ELF type from the binary arch specified
354 if (MI.Is64Bit)
355 return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
356 else
357 return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
358}
359
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000360static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000361 Object &Obj, Buffer &Buf,
362 ElfType OutputElfType) {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000363 if (Config.OutputFormat == "binary") {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000364 return llvm::make_unique<BinaryWriter>(Obj, Buf);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000365 }
366 // Depending on the initial ELFT and OutputFormat we need a different Writer.
367 switch (OutputElfType) {
368 case ELFT_ELF32LE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000369 return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000370 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000371 case ELFT_ELF64LE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000372 return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000373 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000374 case ELFT_ELF32BE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000375 return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000376 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000377 case ELFT_ELF64BE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000378 return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000379 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000380 }
381 llvm_unreachable("Invalid output format");
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000382}
383
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000384static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000385 StringRef File, ElfType OutputElfType) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000386 auto DWOFile = Reader.create();
387 DWOFile->removeSections(
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000388 [&](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); });
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000389 FileBuffer FB(File);
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000390 auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000391 Writer->finalize();
392 Writer->write();
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000393}
394
Paul Semela42dec72018-08-09 17:05:21 +0000395static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
396 Object &Obj) {
397 for (auto &Sec : Obj.sections()) {
398 if (Sec.Name == SecName) {
399 if (Sec.OriginalData.size() == 0)
400 return make_error<StringError>("Can't dump section \"" + SecName +
401 "\": it has no contents",
402 object_error::parse_failed);
403 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
404 FileOutputBuffer::create(Filename, Sec.OriginalData.size());
405 if (!BufferOrErr)
406 return BufferOrErr.takeError();
407 std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
408 std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
409 Buf->getBufferStart());
410 if (Error E = Buf->commit())
411 return E;
412 return Error::success();
413 }
414 }
415 return make_error<StringError>("Section not found",
416 object_error::parse_failed);
417}
418
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000419static bool isCompressed(const SectionBase &Section) {
420 const char *Magic = "ZLIB";
421 return StringRef(Section.Name).startswith(".zdebug") ||
422 (Section.OriginalData.size() > strlen(Magic) &&
423 !strncmp(reinterpret_cast<const char *>(Section.OriginalData.data()),
424 Magic, strlen(Magic))) ||
425 (Section.Flags & ELF::SHF_COMPRESSED);
426}
427
428static bool isCompressable(const SectionBase &Section) {
429 return !isCompressed(Section) && isDebugSection(Section) &&
430 Section.Name != ".gdb_index";
431}
432
433static void compressSections(const CopyConfig &Config, Object &Obj,
434 SectionPred &RemovePred) {
435 SmallVector<SectionBase *, 13> ToCompress;
436 SmallVector<RelocationSection *, 13> RelocationSections;
437 for (auto &Sec : Obj.sections()) {
438 if (RelocationSection *R = dyn_cast<RelocationSection>(&Sec)) {
439 if (isCompressable(*R->getSection()))
440 RelocationSections.push_back(R);
441 continue;
442 }
443
444 if (isCompressable(Sec))
445 ToCompress.push_back(&Sec);
446 }
447
448 for (SectionBase *S : ToCompress) {
449 CompressedSection &CS =
450 Obj.addSection<CompressedSection>(*S, Config.CompressionType);
451
452 for (RelocationSection *RS : RelocationSections) {
453 if (RS->getSection() == S)
454 RS->setSection(&CS);
455 }
456 }
457
458 RemovePred = [RemovePred](const SectionBase &Sec) {
459 return isCompressable(Sec) || RemovePred(Sec);
460 };
461}
462
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000463// This function handles the high level operations of GNU objcopy including
464// handling command line options. It's important to outline certain properties
465// we expect to hold of the command line operations. Any operation that "keeps"
466// should keep regardless of a remove. Additionally any removal should respect
467// any previous removals. Lastly whether or not something is removed shouldn't
468// depend a) on the order the options occur in or b) on some opaque priority
469// system. The only priority is that keeps/copies overrule removes.
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000470static void handleArgs(const CopyConfig &Config, Object &Obj,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000471 const Reader &Reader, ElfType OutputElfType) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000472
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000473 if (!Config.SplitDWO.empty()) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000474 splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000475 }
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000476
477 // TODO: update or remove symbols only if there is an option that affects
478 // them.
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000479 if (Obj.SymbolTable) {
480 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
481 if ((Config.LocalizeHidden &&
482 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
483 (!Config.SymbolsToLocalize.empty() &&
484 is_contained(Config.SymbolsToLocalize, Sym.Name)))
485 Sym.Binding = STB_LOCAL;
486
Jordan Rupprechtbe8ebcc2018-08-17 22:34:48 +0000487 // Note: these two globalize flags have very similar names but different
488 // meanings:
489 //
490 // --globalize-symbol: promote a symbol to global
491 // --keep-global-symbol: all symbols except for these should be made local
492 //
493 // If --globalize-symbol is specified for a given symbol, it will be
494 // global in the output file even if it is not included via
495 // --keep-global-symbol. Because of that, make sure to check
496 // --globalize-symbol second.
497 if (!Config.SymbolsToKeepGlobal.empty() &&
498 !is_contained(Config.SymbolsToKeepGlobal, Sym.Name))
499 Sym.Binding = STB_LOCAL;
500
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000501 if (!Config.SymbolsToGlobalize.empty() &&
502 is_contained(Config.SymbolsToGlobalize, Sym.Name))
503 Sym.Binding = STB_GLOBAL;
504
505 if (!Config.SymbolsToWeaken.empty() &&
506 is_contained(Config.SymbolsToWeaken, Sym.Name) &&
507 Sym.Binding == STB_GLOBAL)
508 Sym.Binding = STB_WEAK;
509
510 if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
511 Sym.getShndx() != SHN_UNDEF)
512 Sym.Binding = STB_WEAK;
513
514 const auto I = Config.SymbolsToRename.find(Sym.Name);
515 if (I != Config.SymbolsToRename.end())
516 Sym.Name = I->getValue();
Paul Semel7a3dc2c2018-08-09 17:49:04 +0000517
518 if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
519 Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000520 });
521
Paul Semel99dda0b2018-05-25 11:01:25 +0000522 // The purpose of this loop is to mark symbols referenced by sections
523 // (like GroupSection or RelocationSection). This way, we know which
524 // symbols are still 'needed' and wich are not.
525 if (Config.StripUnneeded) {
526 for (auto &Section : Obj.sections())
527 Section.markSymbols();
528 }
529
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000530 Obj.removeSymbols([&](const Symbol &Sym) {
Paul Semelcf51c802018-05-26 08:10:37 +0000531 if ((!Config.SymbolsToKeep.empty() &&
532 is_contained(Config.SymbolsToKeep, Sym.Name)) ||
533 (Config.KeepFileSymbols && Sym.Type == STT_FILE))
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000534 return false;
535
536 if (Config.DiscardAll && Sym.Binding == STB_LOCAL &&
537 Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE &&
538 Sym.Type != STT_SECTION)
539 return true;
540
541 if (Config.StripAll || Config.StripAllGNU)
542 return true;
543
544 if (!Config.SymbolsToRemove.empty() &&
545 is_contained(Config.SymbolsToRemove, Sym.Name)) {
546 return true;
547 }
548
Paul Semel46201fb2018-06-01 16:19:46 +0000549 if (Config.StripUnneeded && !Sym.Referenced &&
Paul Semel99dda0b2018-05-25 11:01:25 +0000550 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
551 Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
552 return true;
553
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000554 return false;
555 });
556 }
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000557
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000558 SectionPred RemovePred = [](const SectionBase &) { return false; };
559
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000560 // Removes:
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000561 if (!Config.ToRemove.empty()) {
562 RemovePred = [&Config](const SectionBase &Sec) {
Fangrui Song0e49ef92018-08-21 00:13:52 +0000563 return is_contained(Config.ToRemove, Sec.Name);
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000564 };
Jake Ehrlich36a2eb32017-10-10 18:47:09 +0000565 }
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000566
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000567 if (Config.StripDWO || !Config.SplitDWO.empty())
David Blaikie998ff812017-11-03 20:57:09 +0000568 RemovePred = [RemovePred](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000569 return isDWOSection(Sec) || RemovePred(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000570 };
571
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000572 if (Config.ExtractDWO)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000573 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000574 return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000575 };
576
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000577 if (Config.StripAllGNU)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000578 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
579 if (RemovePred(Sec))
580 return true;
581 if ((Sec.Flags & SHF_ALLOC) != 0)
582 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000583 if (&Sec == Obj.SectionNames)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000584 return false;
Jake Ehrlich777fb002017-12-15 20:17:55 +0000585 switch (Sec.Type) {
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000586 case SHT_SYMTAB:
587 case SHT_REL:
588 case SHT_RELA:
589 case SHT_STRTAB:
590 return true;
591 }
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000592 return isDebugSection(Sec);
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000593 };
594
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000595 if (Config.StripSections) {
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000596 RemovePred = [RemovePred](const SectionBase &Sec) {
597 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
598 };
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000599 }
600
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000601 if (Config.StripDebug) {
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000602 RemovePred = [RemovePred](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000603 return RemovePred(Sec) || isDebugSection(Sec);
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000604 };
605 }
606
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000607 if (Config.StripNonAlloc)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000608 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
609 if (RemovePred(Sec))
610 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000611 if (&Sec == Obj.SectionNames)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000612 return false;
613 return (Sec.Flags & SHF_ALLOC) == 0;
614 };
615
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000616 if (Config.StripAll)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000617 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
618 if (RemovePred(Sec))
619 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000620 if (&Sec == Obj.SectionNames)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000621 return false;
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000622 if (StringRef(Sec.Name).startswith(".gnu.warning"))
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000623 return false;
624 return (Sec.Flags & SHF_ALLOC) == 0;
625 };
626
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000627 // Explicit copies:
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000628 if (!Config.OnlyKeep.empty()) {
629 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000630 // Explicitly keep these sections regardless of previous removes.
Fangrui Song0e49ef92018-08-21 00:13:52 +0000631 if (is_contained(Config.OnlyKeep, Sec.Name))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000632 return false;
633
634 // Allow all implicit removes.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000635 if (RemovePred(Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000636 return true;
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000637
638 // Keep special sections.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000639 if (Obj.SectionNames == &Sec)
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000640 return false;
Stephen Hinese6e75bf2018-07-26 20:05:31 +0000641 if (Obj.SymbolTable == &Sec ||
642 (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000643 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000644
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000645 // Remove everything else.
646 return true;
647 };
648 }
649
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000650 if (!Config.Keep.empty()) {
651 RemovePred = [Config, RemovePred](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000652 // Explicitly keep these sections regardless of previous removes.
Fangrui Song0e49ef92018-08-21 00:13:52 +0000653 if (is_contained(Config.Keep, Sec.Name))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000654 return false;
655 // Otherwise defer to RemovePred.
656 return RemovePred(Sec);
657 };
658 }
659
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000660 // This has to be the last predicate assignment.
661 // If the option --keep-symbol has been specified
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000662 // and at least one of those symbols is present
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000663 // (equivalently, the updated symbol table is not empty)
664 // the symbol table and the string table should not be removed.
Paul Semelcf51c802018-05-26 08:10:37 +0000665 if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
Stephen Hinese6e75bf2018-07-26 20:05:31 +0000666 Obj.SymbolTable && !Obj.SymbolTable->empty()) {
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000667 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
668 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
669 return false;
670 return RemovePred(Sec);
671 };
672 }
673
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000674 if (Config.CompressionType != DebugCompressionType::None)
675 compressSections(Config, Obj, RemovePred);
676
Jake Ehrlich76e91102018-01-25 22:46:17 +0000677 Obj.removeSections(RemovePred);
Jake Ehrliche8437de2017-12-19 00:47:30 +0000678
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000679 if (!Config.SectionsToRename.empty()) {
680 for (auto &Sec : Obj.sections()) {
681 const auto Iter = Config.SectionsToRename.find(Sec.Name);
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000682 if (Iter != Config.SectionsToRename.end()) {
683 const SectionRename &SR = Iter->second;
684 Sec.Name = SR.NewName;
685 if (SR.NewFlags.hasValue()) {
686 // Preserve some flags which should not be dropped when setting flags.
687 // Also, preserve anything OS/processor dependant.
688 const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
689 ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
690 ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
691 ELF::SHF_TLS | ELF::SHF_INFO_LINK;
692 Sec.Flags = (Sec.Flags & PreserveMask) |
693 (SR.NewFlags.getValue() & ~PreserveMask);
694 }
695 }
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000696 }
697 }
698
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000699 if (!Config.AddSection.empty()) {
700 for (const auto &Flag : Config.AddSection) {
701 auto SecPair = Flag.split("=");
Jake Ehrliche8437de2017-12-19 00:47:30 +0000702 auto SecName = SecPair.first;
703 auto File = SecPair.second;
704 auto BufOrErr = MemoryBuffer::getFile(File);
705 if (!BufOrErr)
706 reportError(File, BufOrErr.getError());
707 auto Buf = std::move(*BufOrErr);
708 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
709 auto BufSize = Buf->getBufferSize();
Jake Ehrlich76e91102018-01-25 22:46:17 +0000710 Obj.addSection<OwnedDataSection>(SecName,
711 ArrayRef<uint8_t>(BufPtr, BufSize));
Jake Ehrliche8437de2017-12-19 00:47:30 +0000712 }
713 }
714
Paul Semela42dec72018-08-09 17:05:21 +0000715 if (!Config.DumpSection.empty()) {
716 for (const auto &Flag : Config.DumpSection) {
717 std::pair<StringRef, StringRef> SecPair = Flag.split("=");
718 StringRef SecName = SecPair.first;
719 StringRef File = SecPair.second;
720 if (Error E = dumpSectionToFile(SecName, File, Obj))
721 reportError(Config.InputFilename, std::move(E));
722 }
723 }
724
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000725 if (!Config.AddGnuDebugLink.empty())
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000726 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000727}
Jake Ehrlichea07d3c2018-01-25 22:15:14 +0000728
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000729static void executeElfObjcopyOnBinary(const CopyConfig &Config, Reader &Reader,
730 Buffer &Out, ElfType OutputElfType) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000731 std::unique_ptr<Object> Obj = Reader.create();
732
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000733 handleArgs(Config, *Obj, Reader, OutputElfType);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000734
735 std::unique_ptr<Writer> Writer =
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000736 createWriter(Config, *Obj, Out, OutputElfType);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000737 Writer->finalize();
738 Writer->write();
739}
740
741// For regular archives this function simply calls llvm::writeArchive,
742// For thin archives it writes the archive file itself as well as its members.
Puyan Lotfic4846a52018-07-16 22:17:05 +0000743static Error deepWriteArchive(StringRef ArcName,
744 ArrayRef<NewArchiveMember> NewMembers,
745 bool WriteSymtab, object::Archive::Kind Kind,
746 bool Deterministic, bool Thin) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000747 Error E =
748 writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
749 if (!Thin || E)
750 return E;
751 for (const NewArchiveMember &Member : NewMembers) {
752 // Internally, FileBuffer will use the buffer created by
753 // FileOutputBuffer::create, for regular files (that is the case for
754 // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
755 // OnDiskBuffer uses a temporary file and then renames it. So in reality
756 // there is no inefficiency / duplicated in-memory buffers in this case. For
757 // now in-memory buffers can not be completely avoided since
758 // NewArchiveMember still requires them even though writeArchive does not
759 // write them on disk.
760 FileBuffer FB(Member.MemberName);
761 FB.allocate(Member.Buf->getBufferSize());
762 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
763 FB.getBufferStart());
764 if (auto E = FB.commit())
765 return E;
766 }
767 return Error::success();
768}
769
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000770static void executeElfObjcopyOnArchive(const CopyConfig &Config,
Puyan Lotfi97604b42018-08-02 18:16:52 +0000771 const Archive &Ar) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000772 std::vector<NewArchiveMember> NewArchiveMembers;
773 Error Err = Error::success();
774 for (const Archive::Child &Child : Ar.children(Err)) {
775 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
776 if (!ChildOrErr)
777 reportError(Ar.getFileName(), ChildOrErr.takeError());
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000778 Binary *Bin = ChildOrErr->get();
779
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000780 Expected<StringRef> ChildNameOrErr = Child.getName();
781 if (!ChildNameOrErr)
782 reportError(Ar.getFileName(), ChildNameOrErr.takeError());
783
784 MemBuffer MB(ChildNameOrErr.get());
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000785 ELFReader Reader(Bin);
786 executeElfObjcopyOnBinary(Config, Reader, MB, getOutputElfType(*Bin));
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000787
788 Expected<NewArchiveMember> Member =
789 NewArchiveMember::getOldMember(Child, true);
790 if (!Member)
791 reportError(Ar.getFileName(), Member.takeError());
792 Member->Buf = MB.releaseMemoryBuffer();
793 Member->MemberName = Member->Buf->getBufferIdentifier();
794 NewArchiveMembers.push_back(std::move(*Member));
795 }
796
797 if (Err)
798 reportError(Config.InputFilename, std::move(Err));
799 if (Error E =
800 deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
801 Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin()))
802 reportError(Config.OutputFilename, std::move(E));
Petr Hosek05a04cb2017-08-01 00:33:58 +0000803}
804
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000805static void restoreDateOnFile(StringRef Filename,
806 const sys::fs::file_status &Stat) {
807 int FD;
808
Jordan Rupprecht74815402018-08-29 23:21:56 +0000809 if (auto EC =
810 sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000811 reportError(Filename, EC);
812
813 if (auto EC = sys::fs::setLastAccessAndModificationTime(
814 FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
815 reportError(Filename, EC);
816
817 if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
818 reportError(Filename, EC);
819}
820
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000821static void executeElfObjcopy(const CopyConfig &Config) {
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000822 sys::fs::file_status Stat;
823 if (Config.PreserveDates)
824 if (auto EC = sys::fs::status(Config.InputFilename, Stat))
825 reportError(Config.InputFilename, EC);
826
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000827 if (Config.InputFormat == "binary") {
828 auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename);
829 if (!BufOrErr)
830 reportError(Config.InputFilename, BufOrErr.getError());
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000831
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000832 FileBuffer FB(Config.OutputFilename);
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000833 BinaryReader Reader(Config.BinaryArch, BufOrErr->get());
834 executeElfObjcopyOnBinary(Config, Reader, FB,
835 getOutputElfType(Config.BinaryArch));
836 } else {
837 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
838 createBinary(Config.InputFilename);
839 if (!BinaryOrErr)
840 reportError(Config.InputFilename, BinaryOrErr.takeError());
841
842 if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
843 executeElfObjcopyOnArchive(Config, *Ar);
844 } else {
845 FileBuffer FB(Config.OutputFilename);
846 Binary *Bin = BinaryOrErr.get().getBinary();
847 ELFReader Reader(Bin);
848 executeElfObjcopyOnBinary(Config, Reader, FB, getOutputElfType(*Bin));
849 }
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000850 }
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000851
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000852 if (Config.PreserveDates) {
853 restoreDateOnFile(Config.OutputFilename, Stat);
854 if (!Config.SplitDWO.empty())
855 restoreDateOnFile(Config.SplitDWO, Stat);
856 }
Petr Hosek05a04cb2017-08-01 00:33:58 +0000857}
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000858
Jordan Rupprechtbe8ebcc2018-08-17 22:34:48 +0000859static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
860 StringRef Filename) {
861 SmallVector<StringRef, 16> Lines;
862 auto BufOrErr = MemoryBuffer::getFile(Filename);
863 if (!BufOrErr)
864 reportError(Filename, BufOrErr.getError());
865
866 BufOrErr.get()->getBuffer().split(Lines, '\n');
867 for (StringRef Line : Lines) {
868 // Ignore everything after '#', trim whitespace, and only add the symbol if
869 // it's not empty.
870 auto TrimmedLine = Line.split('#').first.trim();
871 if (!TrimmedLine.empty())
872 Symbols.push_back(TrimmedLine.str());
873 }
874}
875
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000876// ParseObjcopyOptions returns the config and sets the input arguments. If a
877// help flag is set then ParseObjcopyOptions will print the help messege and
878// exit.
Jordan Rupprecht591d8892018-09-05 13:10:03 +0000879static DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000880 ObjcopyOptTable T;
881 unsigned MissingArgumentIndex, MissingArgumentCount;
882 llvm::opt::InputArgList InputArgs =
883 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +0000884
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +0000885 if (InputArgs.size() == 0) {
886 T.PrintHelp(errs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
887 exit(1);
888 }
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +0000889
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +0000890 if (InputArgs.hasArg(OBJCOPY_help)) {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000891 T.PrintHelp(outs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
892 exit(0);
893 }
894
895 SmallVector<const char *, 2> Positional;
896
897 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
898 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
899
900 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
901 Positional.push_back(Arg->getValue());
902
903 if (Positional.empty())
904 error("No input file specified");
905
906 if (Positional.size() > 2)
907 error("Too many positional arguments");
908
909 CopyConfig Config;
910 Config.InputFilename = Positional[0];
911 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
912 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
913 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000914 if (Config.InputFormat == "binary") {
915 auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
916 if (BinaryArch.empty())
917 error("Specified binary input without specifiying an architecture");
918 Config.BinaryArch = getMachineInfo(BinaryArch);
919 }
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000920
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000921 if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
922 OBJCOPY_compress_debug_sections_eq)) {
923 Config.CompressionType = DebugCompressionType::Z;
924
925 if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
926 Config.CompressionType =
927 StringSwitch<DebugCompressionType>(
928 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
929 .Case("zlib-gnu", DebugCompressionType::GNU)
930 .Case("zlib", DebugCompressionType::Z)
931 .Default(DebugCompressionType::None);
932 if (Config.CompressionType == DebugCompressionType::None)
933 error("Invalid or unsupported --compress-debug-sections format: " +
934 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq));
935 if (!zlib::isAvailable())
936 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
937 }
938 }
939
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000940 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
941 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
Paul Semel7a3dc2c2018-08-09 17:49:04 +0000942 Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000943
944 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
945 if (!StringRef(Arg->getValue()).contains('='))
946 error("Bad format for --redefine-sym");
947 auto Old2New = StringRef(Arg->getValue()).split('=');
948 if (!Config.SymbolsToRename.insert(Old2New).second)
949 error("Multiple redefinition of symbol " + Old2New.first);
950 }
951
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000952 for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000953 SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue()));
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000954 if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
955 error("Multiple renames of section " + SR.OriginalName);
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000956 }
957
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000958 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
959 Config.ToRemove.push_back(Arg->getValue());
960 for (auto Arg : InputArgs.filtered(OBJCOPY_keep))
961 Config.Keep.push_back(Arg->getValue());
962 for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep))
963 Config.OnlyKeep.push_back(Arg->getValue());
964 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
965 Config.AddSection.push_back(Arg->getValue());
Paul Semela42dec72018-08-09 17:05:21 +0000966 for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
967 Config.DumpSection.push_back(Arg->getValue());
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000968 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
969 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
970 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
971 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
972 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
973 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
Paul Semel99dda0b2018-05-25 11:01:25 +0000974 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000975 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
976 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
Paul Semel2c0510f2018-05-02 20:14:49 +0000977 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
Paul Semel41695f82018-05-02 20:19:22 +0000978 Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
Jake Ehrliche40398a2018-05-15 20:53:53 +0000979 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
Paul Semelcf51c802018-05-26 08:10:37 +0000980 Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
Paul Semelb4924942018-04-26 17:44:43 +0000981 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000982 Config.SymbolsToLocalize.push_back(Arg->getValue());
Jordan Rupprechtbe8ebcc2018-08-17 22:34:48 +0000983 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
984 Config.SymbolsToKeepGlobal.push_back(Arg->getValue());
985 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
986 addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue());
Paul Semelee5be792018-04-27 19:09:44 +0000987 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
988 Config.SymbolsToGlobalize.push_back(Arg->getValue());
Paul Semel3a8a56b2018-04-27 19:16:27 +0000989 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
990 Config.SymbolsToWeaken.push_back(Arg->getValue());
Paul Semel4246a462018-05-09 21:36:54 +0000991 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
992 Config.SymbolsToRemove.push_back(Arg->getValue());
Paul Semel5d97c822018-05-15 14:09:37 +0000993 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
994 Config.SymbolsToKeep.push_back(Arg->getValue());
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000995
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000996 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
997
Jordan Rupprecht591d8892018-09-05 13:10:03 +0000998 DriverConfig DC;
999 DC.CopyConfigs.push_back(std::move(Config));
1000 return DC;
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +00001001}
1002
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001003// ParseStripOptions returns the config and sets the input arguments. If a
1004// help flag is set then ParseStripOptions will print the help messege and
1005// exit.
Jordan Rupprecht591d8892018-09-05 13:10:03 +00001006static DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001007 StripOptTable T;
1008 unsigned MissingArgumentIndex, MissingArgumentCount;
1009 llvm::opt::InputArgList InputArgs =
1010 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
1011
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +00001012 if (InputArgs.size() == 0) {
Fangrui Songffbc3e22018-08-20 23:01:57 +00001013 T.PrintHelp(errs(), "llvm-strip", "strip tool");
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +00001014 exit(1);
1015 }
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +00001016
Alexander Shaposhnikovb07c22b2018-05-08 17:12:54 +00001017 if (InputArgs.hasArg(STRIP_help)) {
Fangrui Songffbc3e22018-08-20 23:01:57 +00001018 T.PrintHelp(outs(), "llvm-strip", "strip tool");
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001019 exit(0);
1020 }
1021
1022 SmallVector<const char *, 2> Positional;
1023 for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
1024 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
1025 for (auto Arg : InputArgs.filtered(STRIP_INPUT))
1026 Positional.push_back(Arg->getValue());
1027
1028 if (Positional.empty())
1029 error("No input file specified");
1030
Jordan Rupprecht591d8892018-09-05 13:10:03 +00001031 if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
1032 error("Multiple input files cannot be used in combination with -o");
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001033
1034 CopyConfig Config;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001035 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +00001036
Alexander Shaposhnikov29407f32018-06-06 21:23:19 +00001037 Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
Paul Semele57bc782018-06-07 10:05:25 +00001038 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
Stephen Hinese8c3c5f2018-07-12 17:42:17 +00001039 Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
Paul Semele57bc782018-06-07 10:05:25 +00001040
1041 if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll)
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001042 Config.StripAll = true;
Alexander Shaposhnikovd29bf4c2018-05-18 04:18:41 +00001043
Alexander Shaposhnikov18b5fb72018-05-11 05:27:06 +00001044 for (auto Arg : InputArgs.filtered(STRIP_remove_section))
1045 Config.ToRemove.push_back(Arg->getValue());
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +00001046
Alexander Shaposhnikov35bee3e2018-05-23 19:44:19 +00001047 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
1048 Config.SymbolsToKeep.push_back(Arg->getValue());
Alexander Shaposhnikov18b5fb72018-05-11 05:27:06 +00001049
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +00001050 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
1051
Jordan Rupprecht591d8892018-09-05 13:10:03 +00001052 DriverConfig DC;
1053 if (Positional.size() == 1) {
1054 Config.InputFilename = Positional[0];
1055 Config.OutputFilename =
1056 InputArgs.getLastArgValue(STRIP_output, Positional[0]);
1057 DC.CopyConfigs.push_back(std::move(Config));
1058 } else {
1059 for (const char *Filename : Positional) {
1060 Config.InputFilename = Filename;
1061 Config.OutputFilename = Filename;
1062 DC.CopyConfigs.push_back(Config);
1063 }
1064 }
1065
1066 return DC;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001067}
1068
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +00001069int main(int argc, char **argv) {
1070 InitLLVM X(argc, argv);
1071 ToolName = argv[0];
Jordan Rupprecht591d8892018-09-05 13:10:03 +00001072 DriverConfig DriverConfig;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001073 if (sys::path::stem(ToolName).endswith_lower("strip"))
Jordan Rupprecht591d8892018-09-05 13:10:03 +00001074 DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc));
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +00001075 else
Jordan Rupprecht591d8892018-09-05 13:10:03 +00001076 DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc));
1077 for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs)
1078 executeElfObjcopy(CopyConfig);
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +00001079}