blob: b7dbf6c66b3a08c5072f8fd1cb52a9be8bf51de5 [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"
Alexander Shaposhnikov3d4c4ac2018-10-16 05:40:18 +000011#include "Buffer.h"
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +000012#include "CopyConfig.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000013#include "Object.h"
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +000014
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +000015#include "llvm/ADT/BitmaskEnum.h"
16#include "llvm/ADT/Optional.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000017#include "llvm/ADT/STLExtras.h"
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +000018#include "llvm/ADT/SmallVector.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000019#include "llvm/ADT/StringRef.h"
20#include "llvm/ADT/Twine.h"
21#include "llvm/BinaryFormat/ELF.h"
Puyan Lotfi99124cc2018-09-07 08:10:22 +000022#include "llvm/MC/MCTargetOptions.h"
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +000023#include "llvm/Object/Archive.h"
24#include "llvm/Object/ArchiveWriter.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000025#include "llvm/Object/Binary.h"
26#include "llvm/Object/ELFObjectFile.h"
27#include "llvm/Object/ELFTypes.h"
28#include "llvm/Object/Error.h"
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +000029#include "llvm/Option/Arg.h"
30#include "llvm/Option/ArgList.h"
31#include "llvm/Option/Option.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000032#include "llvm/Support/Casting.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000033#include "llvm/Support/CommandLine.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000034#include "llvm/Support/Compiler.h"
Puyan Lotfi99124cc2018-09-07 08:10:22 +000035#include "llvm/Support/Compression.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000036#include "llvm/Support/Error.h"
37#include "llvm/Support/ErrorHandling.h"
38#include "llvm/Support/ErrorOr.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000039#include "llvm/Support/FileOutputBuffer.h"
Rui Ueyama197194b2018-04-13 18:26:06 +000040#include "llvm/Support/InitLLVM.h"
Jordan Rupprechtcf676332018-08-17 18:51:11 +000041#include "llvm/Support/Memory.h"
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +000042#include "llvm/Support/Path.h"
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +000043#include "llvm/Support/Process.h"
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +000044#include "llvm/Support/WithColor.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000045#include "llvm/Support/raw_ostream.h"
46#include <algorithm>
47#include <cassert>
48#include <cstdlib>
49#include <functional>
50#include <iterator>
Petr Hosek05a04cb2017-08-01 00:33:58 +000051#include <memory>
52#include <string>
53#include <system_error>
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000054#include <utility>
Petr Hosek05a04cb2017-08-01 00:33:58 +000055
56using namespace llvm;
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000057using namespace llvm::objcopy;
Petr Hosek05a04cb2017-08-01 00:33:58 +000058using namespace object;
59using namespace ELF;
60
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000061using SectionPred = std::function<bool(const SectionBase &Sec)>;
Petr Hosek05a04cb2017-08-01 00:33:58 +000062
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000063namespace llvm {
64namespace objcopy {
65
66// The name this program was invoked as.
67StringRef ToolName;
68
69LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +000070 WithColor::error(errs(), ToolName) << Message << ".\n";
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000071 errs().flush();
72 exit(1);
73}
74
75LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
76 assert(EC);
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +000077 WithColor::error(errs(), ToolName)
78 << "'" << File << "': " << EC.message() << ".\n";
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000079 exit(1);
80}
81
82LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
83 assert(E);
84 std::string Buf;
85 raw_string_ostream OS(Buf);
86 logAllUnhandledErrors(std::move(E), OS, "");
87 OS.flush();
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +000088 WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000089 exit(1);
90}
91
92} // end namespace objcopy
Puyan Lotfic4846a52018-07-16 22:17:05 +000093} // end namespace llvm
Jake Ehrlich5de70d92017-11-03 18:58:41 +000094
Jordan Rupprecht6b575392018-08-13 21:30:27 +000095static bool isDebugSection(const SectionBase &Sec) {
Puyan Lotfi99124cc2018-09-07 08:10:22 +000096 return StringRef(Sec.Name).startswith(".debug") ||
97 StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index";
Fangrui Songfdfe2a92018-07-27 22:51:36 +000098}
99
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000100static bool isDWOSection(const SectionBase &Sec) {
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000101 return StringRef(Sec.Name).endswith(".dwo");
Puyan Lotfic4846a52018-07-16 22:17:05 +0000102}
103
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000104static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000105 // We can't remove the section header string table.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000106 if (&Sec == Obj.SectionNames)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000107 return false;
108 // Short of keeping the string table we want to keep everything that is a DWO
109 // section and remove everything else.
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000110 return !isDWOSection(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000111}
112
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000113static ElfType getOutputElfType(const Binary &Bin) {
114 // Infer output ELF type from the input ELF object
115 if (isa<ELFObjectFile<ELF32LE>>(Bin))
116 return ELFT_ELF32LE;
117 if (isa<ELFObjectFile<ELF64LE>>(Bin))
118 return ELFT_ELF64LE;
119 if (isa<ELFObjectFile<ELF32BE>>(Bin))
120 return ELFT_ELF32BE;
121 if (isa<ELFObjectFile<ELF64BE>>(Bin))
122 return ELFT_ELF64BE;
123 llvm_unreachable("Invalid ELFType");
124}
125
126static ElfType getOutputElfType(const MachineInfo &MI) {
127 // Infer output ELF type from the binary arch specified
128 if (MI.Is64Bit)
129 return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
130 else
131 return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
132}
133
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000134static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000135 Object &Obj, Buffer &Buf,
136 ElfType OutputElfType) {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000137 if (Config.OutputFormat == "binary") {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000138 return llvm::make_unique<BinaryWriter>(Obj, Buf);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000139 }
140 // Depending on the initial ELFT and OutputFormat we need a different Writer.
141 switch (OutputElfType) {
142 case ELFT_ELF32LE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000143 return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000144 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000145 case ELFT_ELF64LE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000146 return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000147 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000148 case ELFT_ELF32BE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000149 return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000150 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000151 case ELFT_ELF64BE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000152 return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000153 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000154 }
155 llvm_unreachable("Invalid output format");
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000156}
157
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000158static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000159 StringRef File, ElfType OutputElfType) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000160 auto DWOFile = Reader.create();
161 DWOFile->removeSections(
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000162 [&](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); });
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000163 FileBuffer FB(File);
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000164 auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000165 Writer->finalize();
166 Writer->write();
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000167}
168
Paul Semela42dec72018-08-09 17:05:21 +0000169static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
170 Object &Obj) {
171 for (auto &Sec : Obj.sections()) {
172 if (Sec.Name == SecName) {
173 if (Sec.OriginalData.size() == 0)
174 return make_error<StringError>("Can't dump section \"" + SecName +
175 "\": it has no contents",
176 object_error::parse_failed);
177 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
178 FileOutputBuffer::create(Filename, Sec.OriginalData.size());
179 if (!BufferOrErr)
180 return BufferOrErr.takeError();
181 std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
182 std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
183 Buf->getBufferStart());
184 if (Error E = Buf->commit())
185 return E;
186 return Error::success();
187 }
188 }
189 return make_error<StringError>("Section not found",
190 object_error::parse_failed);
191}
192
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000193static bool isCompressed(const SectionBase &Section) {
194 const char *Magic = "ZLIB";
195 return StringRef(Section.Name).startswith(".zdebug") ||
196 (Section.OriginalData.size() > strlen(Magic) &&
197 !strncmp(reinterpret_cast<const char *>(Section.OriginalData.data()),
198 Magic, strlen(Magic))) ||
199 (Section.Flags & ELF::SHF_COMPRESSED);
200}
201
202static bool isCompressable(const SectionBase &Section) {
203 return !isCompressed(Section) && isDebugSection(Section) &&
204 Section.Name != ".gdb_index";
205}
206
Puyan Lotfiaf048642018-10-01 10:29:41 +0000207static void replaceDebugSections(
208 const CopyConfig &Config, Object &Obj, SectionPred &RemovePred,
209 function_ref<bool(const SectionBase &)> shouldReplace,
210 function_ref<SectionBase *(const SectionBase *)> addSection) {
211 SmallVector<SectionBase *, 13> ToReplace;
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000212 SmallVector<RelocationSection *, 13> RelocationSections;
213 for (auto &Sec : Obj.sections()) {
214 if (RelocationSection *R = dyn_cast<RelocationSection>(&Sec)) {
Puyan Lotfiaf048642018-10-01 10:29:41 +0000215 if (shouldReplace(*R->getSection()))
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000216 RelocationSections.push_back(R);
217 continue;
218 }
219
Puyan Lotfiaf048642018-10-01 10:29:41 +0000220 if (shouldReplace(Sec))
221 ToReplace.push_back(&Sec);
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000222 }
223
Puyan Lotfiaf048642018-10-01 10:29:41 +0000224 for (SectionBase *S : ToReplace) {
225 SectionBase *NewSection = addSection(S);
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000226
227 for (RelocationSection *RS : RelocationSections) {
228 if (RS->getSection() == S)
Puyan Lotfiaf048642018-10-01 10:29:41 +0000229 RS->setSection(NewSection);
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000230 }
231 }
232
Puyan Lotfiaf048642018-10-01 10:29:41 +0000233 RemovePred = [shouldReplace, RemovePred](const SectionBase &Sec) {
234 return shouldReplace(Sec) || RemovePred(Sec);
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000235 };
236}
237
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000238// This function handles the high level operations of GNU objcopy including
239// handling command line options. It's important to outline certain properties
240// we expect to hold of the command line operations. Any operation that "keeps"
241// should keep regardless of a remove. Additionally any removal should respect
242// any previous removals. Lastly whether or not something is removed shouldn't
243// depend a) on the order the options occur in or b) on some opaque priority
244// system. The only priority is that keeps/copies overrule removes.
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000245static void handleArgs(const CopyConfig &Config, Object &Obj,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000246 const Reader &Reader, ElfType OutputElfType) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000247
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000248 if (!Config.SplitDWO.empty()) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000249 splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000250 }
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000251
252 // TODO: update or remove symbols only if there is an option that affects
253 // them.
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000254 if (Obj.SymbolTable) {
255 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
256 if ((Config.LocalizeHidden &&
257 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
258 (!Config.SymbolsToLocalize.empty() &&
259 is_contained(Config.SymbolsToLocalize, Sym.Name)))
260 Sym.Binding = STB_LOCAL;
261
Jordan Rupprechtbe8ebcc2018-08-17 22:34:48 +0000262 // Note: these two globalize flags have very similar names but different
263 // meanings:
264 //
265 // --globalize-symbol: promote a symbol to global
266 // --keep-global-symbol: all symbols except for these should be made local
267 //
268 // If --globalize-symbol is specified for a given symbol, it will be
269 // global in the output file even if it is not included via
270 // --keep-global-symbol. Because of that, make sure to check
271 // --globalize-symbol second.
272 if (!Config.SymbolsToKeepGlobal.empty() &&
273 !is_contained(Config.SymbolsToKeepGlobal, Sym.Name))
274 Sym.Binding = STB_LOCAL;
275
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000276 if (!Config.SymbolsToGlobalize.empty() &&
277 is_contained(Config.SymbolsToGlobalize, Sym.Name))
278 Sym.Binding = STB_GLOBAL;
279
280 if (!Config.SymbolsToWeaken.empty() &&
281 is_contained(Config.SymbolsToWeaken, Sym.Name) &&
282 Sym.Binding == STB_GLOBAL)
283 Sym.Binding = STB_WEAK;
284
285 if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
286 Sym.getShndx() != SHN_UNDEF)
287 Sym.Binding = STB_WEAK;
288
289 const auto I = Config.SymbolsToRename.find(Sym.Name);
290 if (I != Config.SymbolsToRename.end())
291 Sym.Name = I->getValue();
Paul Semel7a3dc2c2018-08-09 17:49:04 +0000292
293 if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
294 Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000295 });
296
Paul Semel99dda0b2018-05-25 11:01:25 +0000297 // The purpose of this loop is to mark symbols referenced by sections
298 // (like GroupSection or RelocationSection). This way, we know which
Armando Montanezfdb732b2018-10-10 21:16:57 +0000299 // symbols are still 'needed' and which are not.
Paul Semel99dda0b2018-05-25 11:01:25 +0000300 if (Config.StripUnneeded) {
301 for (auto &Section : Obj.sections())
302 Section.markSymbols();
303 }
304
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000305 Obj.removeSymbols([&](const Symbol &Sym) {
Paul Semelcf51c802018-05-26 08:10:37 +0000306 if ((!Config.SymbolsToKeep.empty() &&
307 is_contained(Config.SymbolsToKeep, Sym.Name)) ||
308 (Config.KeepFileSymbols && Sym.Type == STT_FILE))
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000309 return false;
310
311 if (Config.DiscardAll && Sym.Binding == STB_LOCAL &&
312 Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE &&
313 Sym.Type != STT_SECTION)
314 return true;
315
316 if (Config.StripAll || Config.StripAllGNU)
317 return true;
318
319 if (!Config.SymbolsToRemove.empty() &&
320 is_contained(Config.SymbolsToRemove, Sym.Name)) {
321 return true;
322 }
323
Paul Semel46201fb2018-06-01 16:19:46 +0000324 if (Config.StripUnneeded && !Sym.Referenced &&
Paul Semel99dda0b2018-05-25 11:01:25 +0000325 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
326 Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
327 return true;
328
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000329 return false;
330 });
331 }
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000332
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000333 SectionPred RemovePred = [](const SectionBase &) { return false; };
334
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000335 // Removes:
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000336 if (!Config.ToRemove.empty()) {
337 RemovePred = [&Config](const SectionBase &Sec) {
Fangrui Song0e49ef92018-08-21 00:13:52 +0000338 return is_contained(Config.ToRemove, Sec.Name);
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000339 };
Jake Ehrlich36a2eb32017-10-10 18:47:09 +0000340 }
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000341
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000342 if (Config.StripDWO || !Config.SplitDWO.empty())
David Blaikie998ff812017-11-03 20:57:09 +0000343 RemovePred = [RemovePred](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000344 return isDWOSection(Sec) || RemovePred(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000345 };
346
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000347 if (Config.ExtractDWO)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000348 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000349 return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000350 };
351
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000352 if (Config.StripAllGNU)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000353 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
354 if (RemovePred(Sec))
355 return true;
356 if ((Sec.Flags & SHF_ALLOC) != 0)
357 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000358 if (&Sec == Obj.SectionNames)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000359 return false;
Jake Ehrlich777fb002017-12-15 20:17:55 +0000360 switch (Sec.Type) {
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000361 case SHT_SYMTAB:
362 case SHT_REL:
363 case SHT_RELA:
364 case SHT_STRTAB:
365 return true;
366 }
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000367 return isDebugSection(Sec);
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000368 };
369
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000370 if (Config.StripSections) {
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000371 RemovePred = [RemovePred](const SectionBase &Sec) {
372 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
373 };
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000374 }
375
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000376 if (Config.StripDebug) {
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000377 RemovePred = [RemovePred](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000378 return RemovePred(Sec) || isDebugSection(Sec);
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000379 };
380 }
381
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000382 if (Config.StripNonAlloc)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000383 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
384 if (RemovePred(Sec))
385 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000386 if (&Sec == Obj.SectionNames)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000387 return false;
388 return (Sec.Flags & SHF_ALLOC) == 0;
389 };
390
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000391 if (Config.StripAll)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000392 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
393 if (RemovePred(Sec))
394 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000395 if (&Sec == Obj.SectionNames)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000396 return false;
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000397 if (StringRef(Sec.Name).startswith(".gnu.warning"))
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000398 return false;
399 return (Sec.Flags & SHF_ALLOC) == 0;
400 };
401
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000402 // Explicit copies:
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000403 if (!Config.OnlyKeep.empty()) {
404 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000405 // Explicitly keep these sections regardless of previous removes.
Fangrui Song0e49ef92018-08-21 00:13:52 +0000406 if (is_contained(Config.OnlyKeep, Sec.Name))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000407 return false;
408
409 // Allow all implicit removes.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000410 if (RemovePred(Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000411 return true;
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000412
413 // Keep special sections.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000414 if (Obj.SectionNames == &Sec)
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000415 return false;
Stephen Hinese6e75bf2018-07-26 20:05:31 +0000416 if (Obj.SymbolTable == &Sec ||
417 (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000418 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000419
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000420 // Remove everything else.
421 return true;
422 };
423 }
424
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000425 if (!Config.Keep.empty()) {
426 RemovePred = [Config, RemovePred](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000427 // Explicitly keep these sections regardless of previous removes.
Fangrui Song0e49ef92018-08-21 00:13:52 +0000428 if (is_contained(Config.Keep, Sec.Name))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000429 return false;
430 // Otherwise defer to RemovePred.
431 return RemovePred(Sec);
432 };
433 }
434
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000435 // This has to be the last predicate assignment.
436 // If the option --keep-symbol has been specified
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000437 // and at least one of those symbols is present
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000438 // (equivalently, the updated symbol table is not empty)
439 // the symbol table and the string table should not be removed.
Paul Semelcf51c802018-05-26 08:10:37 +0000440 if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
Stephen Hinese6e75bf2018-07-26 20:05:31 +0000441 Obj.SymbolTable && !Obj.SymbolTable->empty()) {
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000442 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
443 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
444 return false;
445 return RemovePred(Sec);
446 };
447 }
448
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000449 if (Config.CompressionType != DebugCompressionType::None)
Puyan Lotfiaf048642018-10-01 10:29:41 +0000450 replaceDebugSections(Config, Obj, RemovePred, isCompressable,
451 [&Config, &Obj](const SectionBase *S) {
452 return &Obj.addSection<CompressedSection>(
453 *S, Config.CompressionType);
454 });
455 else if (Config.DecompressDebugSections)
456 replaceDebugSections(
457 Config, Obj, RemovePred,
458 [](const SectionBase &S) { return isa<CompressedSection>(&S); },
459 [&Obj](const SectionBase *S) {
460 auto CS = cast<CompressedSection>(S);
461 return &Obj.addSection<DecompressedSection>(*CS);
462 });
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000463
Jake Ehrlich76e91102018-01-25 22:46:17 +0000464 Obj.removeSections(RemovePred);
Jake Ehrliche8437de2017-12-19 00:47:30 +0000465
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000466 if (!Config.SectionsToRename.empty()) {
467 for (auto &Sec : Obj.sections()) {
468 const auto Iter = Config.SectionsToRename.find(Sec.Name);
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000469 if (Iter != Config.SectionsToRename.end()) {
470 const SectionRename &SR = Iter->second;
471 Sec.Name = SR.NewName;
472 if (SR.NewFlags.hasValue()) {
473 // Preserve some flags which should not be dropped when setting flags.
474 // Also, preserve anything OS/processor dependant.
475 const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
476 ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
477 ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
478 ELF::SHF_TLS | ELF::SHF_INFO_LINK;
479 Sec.Flags = (Sec.Flags & PreserveMask) |
480 (SR.NewFlags.getValue() & ~PreserveMask);
481 }
482 }
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000483 }
484 }
485
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000486 if (!Config.AddSection.empty()) {
487 for (const auto &Flag : Config.AddSection) {
488 auto SecPair = Flag.split("=");
Jake Ehrliche8437de2017-12-19 00:47:30 +0000489 auto SecName = SecPair.first;
490 auto File = SecPair.second;
491 auto BufOrErr = MemoryBuffer::getFile(File);
492 if (!BufOrErr)
493 reportError(File, BufOrErr.getError());
494 auto Buf = std::move(*BufOrErr);
495 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
496 auto BufSize = Buf->getBufferSize();
Jake Ehrlich76e91102018-01-25 22:46:17 +0000497 Obj.addSection<OwnedDataSection>(SecName,
498 ArrayRef<uint8_t>(BufPtr, BufSize));
Jake Ehrliche8437de2017-12-19 00:47:30 +0000499 }
500 }
501
Paul Semela42dec72018-08-09 17:05:21 +0000502 if (!Config.DumpSection.empty()) {
503 for (const auto &Flag : Config.DumpSection) {
504 std::pair<StringRef, StringRef> SecPair = Flag.split("=");
505 StringRef SecName = SecPair.first;
506 StringRef File = SecPair.second;
507 if (Error E = dumpSectionToFile(SecName, File, Obj))
508 reportError(Config.InputFilename, std::move(E));
509 }
510 }
511
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000512 if (!Config.AddGnuDebugLink.empty())
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000513 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000514}
Jake Ehrlichea07d3c2018-01-25 22:15:14 +0000515
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000516static void executeElfObjcopyOnBinary(const CopyConfig &Config, Reader &Reader,
517 Buffer &Out, ElfType OutputElfType) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000518 std::unique_ptr<Object> Obj = Reader.create();
519
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000520 handleArgs(Config, *Obj, Reader, OutputElfType);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000521
522 std::unique_ptr<Writer> Writer =
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000523 createWriter(Config, *Obj, Out, OutputElfType);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000524 Writer->finalize();
525 Writer->write();
526}
527
528// For regular archives this function simply calls llvm::writeArchive,
529// For thin archives it writes the archive file itself as well as its members.
Puyan Lotfic4846a52018-07-16 22:17:05 +0000530static Error deepWriteArchive(StringRef ArcName,
531 ArrayRef<NewArchiveMember> NewMembers,
532 bool WriteSymtab, object::Archive::Kind Kind,
533 bool Deterministic, bool Thin) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000534 Error E =
535 writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
536 if (!Thin || E)
537 return E;
538 for (const NewArchiveMember &Member : NewMembers) {
539 // Internally, FileBuffer will use the buffer created by
540 // FileOutputBuffer::create, for regular files (that is the case for
541 // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
542 // OnDiskBuffer uses a temporary file and then renames it. So in reality
543 // there is no inefficiency / duplicated in-memory buffers in this case. For
544 // now in-memory buffers can not be completely avoided since
545 // NewArchiveMember still requires them even though writeArchive does not
546 // write them on disk.
547 FileBuffer FB(Member.MemberName);
548 FB.allocate(Member.Buf->getBufferSize());
549 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
550 FB.getBufferStart());
551 if (auto E = FB.commit())
552 return E;
553 }
554 return Error::success();
555}
556
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000557static void executeElfObjcopyOnArchive(const CopyConfig &Config,
Puyan Lotfi97604b42018-08-02 18:16:52 +0000558 const Archive &Ar) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000559 std::vector<NewArchiveMember> NewArchiveMembers;
560 Error Err = Error::success();
561 for (const Archive::Child &Child : Ar.children(Err)) {
562 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
563 if (!ChildOrErr)
564 reportError(Ar.getFileName(), ChildOrErr.takeError());
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000565 Binary *Bin = ChildOrErr->get();
566
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000567 Expected<StringRef> ChildNameOrErr = Child.getName();
568 if (!ChildNameOrErr)
569 reportError(Ar.getFileName(), ChildNameOrErr.takeError());
570
571 MemBuffer MB(ChildNameOrErr.get());
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000572 ELFReader Reader(Bin);
573 executeElfObjcopyOnBinary(Config, Reader, MB, getOutputElfType(*Bin));
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000574
575 Expected<NewArchiveMember> Member =
576 NewArchiveMember::getOldMember(Child, true);
577 if (!Member)
578 reportError(Ar.getFileName(), Member.takeError());
579 Member->Buf = MB.releaseMemoryBuffer();
580 Member->MemberName = Member->Buf->getBufferIdentifier();
581 NewArchiveMembers.push_back(std::move(*Member));
582 }
583
584 if (Err)
585 reportError(Config.InputFilename, std::move(Err));
586 if (Error E =
587 deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
588 Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin()))
589 reportError(Config.OutputFilename, std::move(E));
Petr Hosek05a04cb2017-08-01 00:33:58 +0000590}
591
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000592static void restoreDateOnFile(StringRef Filename,
593 const sys::fs::file_status &Stat) {
594 int FD;
595
Jordan Rupprecht74815402018-08-29 23:21:56 +0000596 if (auto EC =
597 sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000598 reportError(Filename, EC);
599
600 if (auto EC = sys::fs::setLastAccessAndModificationTime(
601 FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
602 reportError(Filename, EC);
603
604 if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
605 reportError(Filename, EC);
606}
607
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000608static void executeElfObjcopy(const CopyConfig &Config) {
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000609 sys::fs::file_status Stat;
610 if (Config.PreserveDates)
611 if (auto EC = sys::fs::status(Config.InputFilename, Stat))
612 reportError(Config.InputFilename, EC);
613
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000614 if (Config.InputFormat == "binary") {
615 auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename);
616 if (!BufOrErr)
617 reportError(Config.InputFilename, BufOrErr.getError());
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000618
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000619 FileBuffer FB(Config.OutputFilename);
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000620 BinaryReader Reader(Config.BinaryArch, BufOrErr->get());
621 executeElfObjcopyOnBinary(Config, Reader, FB,
622 getOutputElfType(Config.BinaryArch));
623 } else {
624 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
625 createBinary(Config.InputFilename);
626 if (!BinaryOrErr)
627 reportError(Config.InputFilename, BinaryOrErr.takeError());
628
629 if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
630 executeElfObjcopyOnArchive(Config, *Ar);
631 } else {
632 FileBuffer FB(Config.OutputFilename);
633 Binary *Bin = BinaryOrErr.get().getBinary();
634 ELFReader Reader(Bin);
635 executeElfObjcopyOnBinary(Config, Reader, FB, getOutputElfType(*Bin));
636 }
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000637 }
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000638
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000639 if (Config.PreserveDates) {
640 restoreDateOnFile(Config.OutputFilename, Stat);
641 if (!Config.SplitDWO.empty())
642 restoreDateOnFile(Config.SplitDWO, Stat);
643 }
Petr Hosek05a04cb2017-08-01 00:33:58 +0000644}
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000645
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000646int main(int argc, char **argv) {
647 InitLLVM X(argc, argv);
648 ToolName = argv[0];
Jordan Rupprecht591d8892018-09-05 13:10:03 +0000649 DriverConfig DriverConfig;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000650 if (sys::path::stem(ToolName).endswith_lower("strip"))
Jordan Rupprecht591d8892018-09-05 13:10:03 +0000651 DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc));
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000652 else
Jordan Rupprecht591d8892018-09-05 13:10:03 +0000653 DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc));
654 for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs)
655 executeElfObjcopy(CopyConfig);
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000656}