blob: b7e2361cc013b5a3f13a8ba02cf81cbf25fa6034 [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
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000056namespace llvm {
57namespace objcopy {
58
59// The name this program was invoked as.
60StringRef ToolName;
61
62LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +000063 WithColor::error(errs(), ToolName) << Message << ".\n";
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000064 errs().flush();
65 exit(1);
66}
67
68LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
69 assert(EC);
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +000070 WithColor::error(errs(), ToolName)
71 << "'" << File << "': " << EC.message() << ".\n";
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000072 exit(1);
73}
74
75LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
76 assert(E);
77 std::string Buf;
78 raw_string_ostream OS(Buf);
79 logAllUnhandledErrors(std::move(E), OS, "");
80 OS.flush();
Jordan Rupprecht88ed5e52018-08-09 22:52:03 +000081 WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
Puyan Lotfi0f5d5fa2018-07-18 00:10:51 +000082 exit(1);
83}
84
85} // end namespace objcopy
Puyan Lotfic4846a52018-07-16 22:17:05 +000086} // end namespace llvm
Jake Ehrlich5de70d92017-11-03 18:58:41 +000087
Alexander Shaposhnikov654d3a92018-10-24 22:49:06 +000088// TODO: move everything enclosed in the namespace llvm::objcopy::elf
89// into separate header+cpp files.
90namespace llvm {
91namespace objcopy {
92namespace elf {
93
94using namespace object;
95using namespace ELF;
96using SectionPred = std::function<bool(const SectionBase &Sec)>;
97
Jordan Rupprecht6b575392018-08-13 21:30:27 +000098static bool isDebugSection(const SectionBase &Sec) {
Puyan Lotfi99124cc2018-09-07 08:10:22 +000099 return StringRef(Sec.Name).startswith(".debug") ||
100 StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index";
Fangrui Songfdfe2a92018-07-27 22:51:36 +0000101}
102
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000103static bool isDWOSection(const SectionBase &Sec) {
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000104 return StringRef(Sec.Name).endswith(".dwo");
Puyan Lotfic4846a52018-07-16 22:17:05 +0000105}
106
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000107static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000108 // We can't remove the section header string table.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000109 if (&Sec == Obj.SectionNames)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000110 return false;
111 // Short of keeping the string table we want to keep everything that is a DWO
112 // section and remove everything else.
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000113 return !isDWOSection(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000114}
115
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000116static ElfType getOutputElfType(const Binary &Bin) {
117 // Infer output ELF type from the input ELF object
118 if (isa<ELFObjectFile<ELF32LE>>(Bin))
119 return ELFT_ELF32LE;
120 if (isa<ELFObjectFile<ELF64LE>>(Bin))
121 return ELFT_ELF64LE;
122 if (isa<ELFObjectFile<ELF32BE>>(Bin))
123 return ELFT_ELF32BE;
124 if (isa<ELFObjectFile<ELF64BE>>(Bin))
125 return ELFT_ELF64BE;
126 llvm_unreachable("Invalid ELFType");
127}
128
129static ElfType getOutputElfType(const MachineInfo &MI) {
130 // Infer output ELF type from the binary arch specified
131 if (MI.Is64Bit)
132 return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
133 else
134 return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
135}
136
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000137static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000138 Object &Obj, Buffer &Buf,
139 ElfType OutputElfType) {
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000140 if (Config.OutputFormat == "binary") {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000141 return llvm::make_unique<BinaryWriter>(Obj, Buf);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000142 }
143 // Depending on the initial ELFT and OutputFormat we need a different Writer.
144 switch (OutputElfType) {
145 case ELFT_ELF32LE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000146 return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000147 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000148 case ELFT_ELF64LE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000149 return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000150 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000151 case ELFT_ELF32BE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000152 return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000153 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000154 case ELFT_ELF64BE:
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000155 return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf,
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000156 !Config.StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000157 }
158 llvm_unreachable("Invalid output format");
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000159}
160
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000161static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000162 StringRef File, ElfType OutputElfType) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000163 auto DWOFile = Reader.create();
164 DWOFile->removeSections(
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000165 [&](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); });
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000166 FileBuffer FB(File);
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000167 auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000168 Writer->finalize();
169 Writer->write();
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000170}
171
Paul Semela42dec72018-08-09 17:05:21 +0000172static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
173 Object &Obj) {
174 for (auto &Sec : Obj.sections()) {
175 if (Sec.Name == SecName) {
176 if (Sec.OriginalData.size() == 0)
177 return make_error<StringError>("Can't dump section \"" + SecName +
178 "\": it has no contents",
179 object_error::parse_failed);
180 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
181 FileOutputBuffer::create(Filename, Sec.OriginalData.size());
182 if (!BufferOrErr)
183 return BufferOrErr.takeError();
184 std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
185 std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
186 Buf->getBufferStart());
187 if (Error E = Buf->commit())
188 return E;
189 return Error::success();
190 }
191 }
192 return make_error<StringError>("Section not found",
193 object_error::parse_failed);
194}
195
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000196static bool isCompressed(const SectionBase &Section) {
197 const char *Magic = "ZLIB";
198 return StringRef(Section.Name).startswith(".zdebug") ||
199 (Section.OriginalData.size() > strlen(Magic) &&
200 !strncmp(reinterpret_cast<const char *>(Section.OriginalData.data()),
201 Magic, strlen(Magic))) ||
202 (Section.Flags & ELF::SHF_COMPRESSED);
203}
204
205static bool isCompressable(const SectionBase &Section) {
206 return !isCompressed(Section) && isDebugSection(Section) &&
207 Section.Name != ".gdb_index";
208}
209
Puyan Lotfiaf048642018-10-01 10:29:41 +0000210static void replaceDebugSections(
211 const CopyConfig &Config, Object &Obj, SectionPred &RemovePred,
212 function_ref<bool(const SectionBase &)> shouldReplace,
213 function_ref<SectionBase *(const SectionBase *)> addSection) {
214 SmallVector<SectionBase *, 13> ToReplace;
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000215 SmallVector<RelocationSection *, 13> RelocationSections;
216 for (auto &Sec : Obj.sections()) {
217 if (RelocationSection *R = dyn_cast<RelocationSection>(&Sec)) {
Puyan Lotfiaf048642018-10-01 10:29:41 +0000218 if (shouldReplace(*R->getSection()))
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000219 RelocationSections.push_back(R);
220 continue;
221 }
222
Puyan Lotfiaf048642018-10-01 10:29:41 +0000223 if (shouldReplace(Sec))
224 ToReplace.push_back(&Sec);
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000225 }
226
Puyan Lotfiaf048642018-10-01 10:29:41 +0000227 for (SectionBase *S : ToReplace) {
228 SectionBase *NewSection = addSection(S);
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000229
230 for (RelocationSection *RS : RelocationSections) {
231 if (RS->getSection() == S)
Puyan Lotfiaf048642018-10-01 10:29:41 +0000232 RS->setSection(NewSection);
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000233 }
234 }
235
Puyan Lotfiaf048642018-10-01 10:29:41 +0000236 RemovePred = [shouldReplace, RemovePred](const SectionBase &Sec) {
237 return shouldReplace(Sec) || RemovePred(Sec);
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000238 };
239}
240
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000241// This function handles the high level operations of GNU objcopy including
242// handling command line options. It's important to outline certain properties
243// we expect to hold of the command line operations. Any operation that "keeps"
244// should keep regardless of a remove. Additionally any removal should respect
245// any previous removals. Lastly whether or not something is removed shouldn't
246// depend a) on the order the options occur in or b) on some opaque priority
247// system. The only priority is that keeps/copies overrule removes.
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000248static void handleArgs(const CopyConfig &Config, Object &Obj,
Puyan Lotfic4846a52018-07-16 22:17:05 +0000249 const Reader &Reader, ElfType OutputElfType) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000250
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000251 if (!Config.SplitDWO.empty()) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000252 splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000253 }
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000254
255 // TODO: update or remove symbols only if there is an option that affects
256 // them.
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000257 if (Obj.SymbolTable) {
258 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
259 if ((Config.LocalizeHidden &&
260 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
261 (!Config.SymbolsToLocalize.empty() &&
262 is_contained(Config.SymbolsToLocalize, Sym.Name)))
263 Sym.Binding = STB_LOCAL;
264
Jordan Rupprechtbe8ebcc2018-08-17 22:34:48 +0000265 // Note: these two globalize flags have very similar names but different
266 // meanings:
267 //
268 // --globalize-symbol: promote a symbol to global
269 // --keep-global-symbol: all symbols except for these should be made local
270 //
271 // If --globalize-symbol is specified for a given symbol, it will be
272 // global in the output file even if it is not included via
273 // --keep-global-symbol. Because of that, make sure to check
274 // --globalize-symbol second.
275 if (!Config.SymbolsToKeepGlobal.empty() &&
276 !is_contained(Config.SymbolsToKeepGlobal, Sym.Name))
277 Sym.Binding = STB_LOCAL;
278
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000279 if (!Config.SymbolsToGlobalize.empty() &&
280 is_contained(Config.SymbolsToGlobalize, Sym.Name))
281 Sym.Binding = STB_GLOBAL;
282
283 if (!Config.SymbolsToWeaken.empty() &&
284 is_contained(Config.SymbolsToWeaken, Sym.Name) &&
285 Sym.Binding == STB_GLOBAL)
286 Sym.Binding = STB_WEAK;
287
288 if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
289 Sym.getShndx() != SHN_UNDEF)
290 Sym.Binding = STB_WEAK;
291
292 const auto I = Config.SymbolsToRename.find(Sym.Name);
293 if (I != Config.SymbolsToRename.end())
294 Sym.Name = I->getValue();
Paul Semel7a3dc2c2018-08-09 17:49:04 +0000295
296 if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
297 Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000298 });
299
Paul Semel99dda0b2018-05-25 11:01:25 +0000300 // The purpose of this loop is to mark symbols referenced by sections
301 // (like GroupSection or RelocationSection). This way, we know which
Armando Montanezfdb732b2018-10-10 21:16:57 +0000302 // symbols are still 'needed' and which are not.
Paul Semel99dda0b2018-05-25 11:01:25 +0000303 if (Config.StripUnneeded) {
304 for (auto &Section : Obj.sections())
305 Section.markSymbols();
306 }
307
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000308 Obj.removeSymbols([&](const Symbol &Sym) {
Paul Semelcf51c802018-05-26 08:10:37 +0000309 if ((!Config.SymbolsToKeep.empty() &&
310 is_contained(Config.SymbolsToKeep, Sym.Name)) ||
311 (Config.KeepFileSymbols && Sym.Type == STT_FILE))
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000312 return false;
313
314 if (Config.DiscardAll && Sym.Binding == STB_LOCAL &&
315 Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE &&
316 Sym.Type != STT_SECTION)
317 return true;
318
319 if (Config.StripAll || Config.StripAllGNU)
320 return true;
321
322 if (!Config.SymbolsToRemove.empty() &&
323 is_contained(Config.SymbolsToRemove, Sym.Name)) {
324 return true;
325 }
326
Paul Semel46201fb2018-06-01 16:19:46 +0000327 if (Config.StripUnneeded && !Sym.Referenced &&
Paul Semel99dda0b2018-05-25 11:01:25 +0000328 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
329 Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
330 return true;
331
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000332 return false;
333 });
334 }
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000335
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000336 SectionPred RemovePred = [](const SectionBase &) { return false; };
337
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000338 // Removes:
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000339 if (!Config.ToRemove.empty()) {
340 RemovePred = [&Config](const SectionBase &Sec) {
Fangrui Song0e49ef92018-08-21 00:13:52 +0000341 return is_contained(Config.ToRemove, Sec.Name);
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000342 };
Jake Ehrlich36a2eb32017-10-10 18:47:09 +0000343 }
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000344
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000345 if (Config.StripDWO || !Config.SplitDWO.empty())
David Blaikie998ff812017-11-03 20:57:09 +0000346 RemovePred = [RemovePred](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000347 return isDWOSection(Sec) || RemovePred(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000348 };
349
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000350 if (Config.ExtractDWO)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000351 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000352 return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000353 };
354
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000355 if (Config.StripAllGNU)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000356 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
357 if (RemovePred(Sec))
358 return true;
359 if ((Sec.Flags & SHF_ALLOC) != 0)
360 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000361 if (&Sec == Obj.SectionNames)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000362 return false;
Jake Ehrlich777fb002017-12-15 20:17:55 +0000363 switch (Sec.Type) {
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000364 case SHT_SYMTAB:
365 case SHT_REL:
366 case SHT_RELA:
367 case SHT_STRTAB:
368 return true;
369 }
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000370 return isDebugSection(Sec);
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000371 };
372
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000373 if (Config.StripSections) {
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000374 RemovePred = [RemovePred](const SectionBase &Sec) {
375 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
376 };
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000377 }
378
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000379 if (Config.StripDebug) {
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000380 RemovePred = [RemovePred](const SectionBase &Sec) {
Jordan Rupprecht6b575392018-08-13 21:30:27 +0000381 return RemovePred(Sec) || isDebugSection(Sec);
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000382 };
383 }
384
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000385 if (Config.StripNonAlloc)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000386 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
387 if (RemovePred(Sec))
388 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000389 if (&Sec == Obj.SectionNames)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000390 return false;
391 return (Sec.Flags & SHF_ALLOC) == 0;
392 };
393
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000394 if (Config.StripAll)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000395 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
396 if (RemovePred(Sec))
397 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000398 if (&Sec == Obj.SectionNames)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000399 return false;
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000400 if (StringRef(Sec.Name).startswith(".gnu.warning"))
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000401 return false;
402 return (Sec.Flags & SHF_ALLOC) == 0;
403 };
404
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000405 // Explicit copies:
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000406 if (!Config.OnlyKeep.empty()) {
407 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000408 // Explicitly keep these sections regardless of previous removes.
Fangrui Song0e49ef92018-08-21 00:13:52 +0000409 if (is_contained(Config.OnlyKeep, Sec.Name))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000410 return false;
411
412 // Allow all implicit removes.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000413 if (RemovePred(Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000414 return true;
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000415
416 // Keep special sections.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000417 if (Obj.SectionNames == &Sec)
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000418 return false;
Stephen Hinese6e75bf2018-07-26 20:05:31 +0000419 if (Obj.SymbolTable == &Sec ||
420 (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000421 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000422
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000423 // Remove everything else.
424 return true;
425 };
426 }
427
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000428 if (!Config.Keep.empty()) {
429 RemovePred = [Config, RemovePred](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000430 // Explicitly keep these sections regardless of previous removes.
Fangrui Song0e49ef92018-08-21 00:13:52 +0000431 if (is_contained(Config.Keep, Sec.Name))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000432 return false;
433 // Otherwise defer to RemovePred.
434 return RemovePred(Sec);
435 };
436 }
437
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000438 // This has to be the last predicate assignment.
439 // If the option --keep-symbol has been specified
Alexander Shaposhnikovc7277e62018-05-23 20:39:52 +0000440 // and at least one of those symbols is present
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000441 // (equivalently, the updated symbol table is not empty)
442 // the symbol table and the string table should not be removed.
Paul Semelcf51c802018-05-26 08:10:37 +0000443 if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
Stephen Hinese6e75bf2018-07-26 20:05:31 +0000444 Obj.SymbolTable && !Obj.SymbolTable->empty()) {
Alexander Shaposhnikov6e7814c2018-05-22 18:24:07 +0000445 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
446 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
447 return false;
448 return RemovePred(Sec);
449 };
450 }
451
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000452 if (Config.CompressionType != DebugCompressionType::None)
Puyan Lotfiaf048642018-10-01 10:29:41 +0000453 replaceDebugSections(Config, Obj, RemovePred, isCompressable,
454 [&Config, &Obj](const SectionBase *S) {
455 return &Obj.addSection<CompressedSection>(
456 *S, Config.CompressionType);
457 });
458 else if (Config.DecompressDebugSections)
459 replaceDebugSections(
460 Config, Obj, RemovePred,
461 [](const SectionBase &S) { return isa<CompressedSection>(&S); },
462 [&Obj](const SectionBase *S) {
463 auto CS = cast<CompressedSection>(S);
464 return &Obj.addSection<DecompressedSection>(*CS);
465 });
Puyan Lotfi99124cc2018-09-07 08:10:22 +0000466
Jake Ehrlich76e91102018-01-25 22:46:17 +0000467 Obj.removeSections(RemovePred);
Jake Ehrliche8437de2017-12-19 00:47:30 +0000468
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000469 if (!Config.SectionsToRename.empty()) {
470 for (auto &Sec : Obj.sections()) {
471 const auto Iter = Config.SectionsToRename.find(Sec.Name);
Jordan Rupprechtd67c1e12018-08-01 16:23:22 +0000472 if (Iter != Config.SectionsToRename.end()) {
473 const SectionRename &SR = Iter->second;
474 Sec.Name = SR.NewName;
475 if (SR.NewFlags.hasValue()) {
476 // Preserve some flags which should not be dropped when setting flags.
477 // Also, preserve anything OS/processor dependant.
478 const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
479 ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
480 ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
481 ELF::SHF_TLS | ELF::SHF_INFO_LINK;
482 Sec.Flags = (Sec.Flags & PreserveMask) |
483 (SR.NewFlags.getValue() & ~PreserveMask);
484 }
485 }
Jordan Rupprechtdb2036e2018-07-20 19:54:24 +0000486 }
487 }
488
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000489 if (!Config.AddSection.empty()) {
490 for (const auto &Flag : Config.AddSection) {
491 auto SecPair = Flag.split("=");
Jake Ehrliche8437de2017-12-19 00:47:30 +0000492 auto SecName = SecPair.first;
493 auto File = SecPair.second;
494 auto BufOrErr = MemoryBuffer::getFile(File);
495 if (!BufOrErr)
496 reportError(File, BufOrErr.getError());
497 auto Buf = std::move(*BufOrErr);
498 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
499 auto BufSize = Buf->getBufferSize();
Jake Ehrlich76e91102018-01-25 22:46:17 +0000500 Obj.addSection<OwnedDataSection>(SecName,
501 ArrayRef<uint8_t>(BufPtr, BufSize));
Jake Ehrliche8437de2017-12-19 00:47:30 +0000502 }
503 }
504
Paul Semela42dec72018-08-09 17:05:21 +0000505 if (!Config.DumpSection.empty()) {
506 for (const auto &Flag : Config.DumpSection) {
507 std::pair<StringRef, StringRef> SecPair = Flag.split("=");
508 StringRef SecName = SecPair.first;
509 StringRef File = SecPair.second;
510 if (Error E = dumpSectionToFile(SecName, File, Obj))
511 reportError(Config.InputFilename, std::move(E));
512 }
513 }
514
Alexander Shaposhnikov40e9bdf2018-04-26 18:28:17 +0000515 if (!Config.AddGnuDebugLink.empty())
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000516 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000517}
Jake Ehrlichea07d3c2018-01-25 22:15:14 +0000518
Alexander Shaposhnikov654d3a92018-10-24 22:49:06 +0000519void executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
520 Buffer &Out) {
521 BinaryReader Reader(Config.BinaryArch, &In);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000522 std::unique_ptr<Object> Obj = Reader.create();
523
Alexander Shaposhnikov654d3a92018-10-24 22:49:06 +0000524 const ElfType OutputElfType = getOutputElfType(Config.BinaryArch);
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000525 handleArgs(Config, *Obj, Reader, OutputElfType);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000526 std::unique_ptr<Writer> Writer =
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000527 createWriter(Config, *Obj, Out, OutputElfType);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000528 Writer->finalize();
529 Writer->write();
530}
531
Alexander Shaposhnikov654d3a92018-10-24 22:49:06 +0000532void executeObjcopyOnBinary(const CopyConfig &Config,
533 object::ELFObjectFileBase &In, Buffer &Out) {
534 ELFReader Reader(&In);
535 std::unique_ptr<Object> Obj = Reader.create();
536 const ElfType OutputElfType = getOutputElfType(In);
537 handleArgs(Config, *Obj, Reader, OutputElfType);
538 std::unique_ptr<Writer> Writer =
539 createWriter(Config, *Obj, Out, OutputElfType);
540 Writer->finalize();
541 Writer->write();
542}
543
544} // end namespace elf
545} // end namespace objcopy
546} // end namespace llvm
547
548using namespace llvm;
549using namespace llvm::object;
550using namespace llvm::objcopy;
551
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000552// For regular archives this function simply calls llvm::writeArchive,
553// For thin archives it writes the archive file itself as well as its members.
Puyan Lotfic4846a52018-07-16 22:17:05 +0000554static Error deepWriteArchive(StringRef ArcName,
555 ArrayRef<NewArchiveMember> NewMembers,
556 bool WriteSymtab, object::Archive::Kind Kind,
557 bool Deterministic, bool Thin) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000558 Error E =
559 writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
560 if (!Thin || E)
561 return E;
562 for (const NewArchiveMember &Member : NewMembers) {
563 // Internally, FileBuffer will use the buffer created by
564 // FileOutputBuffer::create, for regular files (that is the case for
565 // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
566 // OnDiskBuffer uses a temporary file and then renames it. So in reality
567 // there is no inefficiency / duplicated in-memory buffers in this case. For
568 // now in-memory buffers can not be completely avoided since
569 // NewArchiveMember still requires them even though writeArchive does not
570 // write them on disk.
571 FileBuffer FB(Member.MemberName);
572 FB.allocate(Member.Buf->getBufferSize());
573 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
574 FB.getBufferStart());
575 if (auto E = FB.commit())
576 return E;
577 }
578 return Error::success();
579}
580
Alexander Shaposhnikov654d3a92018-10-24 22:49:06 +0000581/// The function executeObjcopyOnRawBinary does the dispatch based on the format
582/// of the output specified by the command line options.
583static void executeObjcopyOnRawBinary(const CopyConfig &Config,
584 MemoryBuffer &In, Buffer &Out) {
585 // TODO: llvm-objcopy should parse CopyConfig.OutputFormat to recognize
586 // formats other than ELF / "binary" and invoke
587 // elf::executeObjcopyOnRawBinary, macho::executeObjcopyOnRawBinary or
588 // coff::executeObjcopyOnRawBinary accordingly.
589 return elf::executeObjcopyOnRawBinary(Config, In, Out);
590}
591
592/// The function executeObjcopyOnBinary does the dispatch based on the format
593/// of the input binary (ELF, MachO or COFF).
594static void executeObjcopyOnBinary(const CopyConfig &Config, object::Binary &In,
595 Buffer &Out) {
596 if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In))
597 return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out);
598 else
599 error("Unsupported object file format");
600}
601
602static void executeObjcopyOnArchive(const CopyConfig &Config,
603 const Archive &Ar) {
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000604 std::vector<NewArchiveMember> NewArchiveMembers;
605 Error Err = Error::success();
606 for (const Archive::Child &Child : Ar.children(Err)) {
607 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
608 if (!ChildOrErr)
609 reportError(Ar.getFileName(), ChildOrErr.takeError());
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000610 Binary *Bin = ChildOrErr->get();
611
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000612 Expected<StringRef> ChildNameOrErr = Child.getName();
613 if (!ChildNameOrErr)
614 reportError(Ar.getFileName(), ChildNameOrErr.takeError());
615
616 MemBuffer MB(ChildNameOrErr.get());
Alexander Shaposhnikov654d3a92018-10-24 22:49:06 +0000617 executeObjcopyOnBinary(Config, *Bin, MB);
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000618
619 Expected<NewArchiveMember> Member =
620 NewArchiveMember::getOldMember(Child, true);
621 if (!Member)
622 reportError(Ar.getFileName(), Member.takeError());
623 Member->Buf = MB.releaseMemoryBuffer();
624 Member->MemberName = Member->Buf->getBufferIdentifier();
625 NewArchiveMembers.push_back(std::move(*Member));
626 }
627
628 if (Err)
629 reportError(Config.InputFilename, std::move(Err));
630 if (Error E =
631 deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
632 Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin()))
633 reportError(Config.OutputFilename, std::move(E));
Petr Hosek05a04cb2017-08-01 00:33:58 +0000634}
635
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000636static void restoreDateOnFile(StringRef Filename,
637 const sys::fs::file_status &Stat) {
638 int FD;
639
Jordan Rupprecht74815402018-08-29 23:21:56 +0000640 if (auto EC =
641 sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000642 reportError(Filename, EC);
643
644 if (auto EC = sys::fs::setLastAccessAndModificationTime(
645 FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
646 reportError(Filename, EC);
647
648 if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
649 reportError(Filename, EC);
650}
651
Alexander Shaposhnikov654d3a92018-10-24 22:49:06 +0000652/// The function executeObjcopy does the higher level dispatch based on the type
653/// of input (raw binary, archive or single object file) and takes care of the
654/// format-agnostic modifications, i.e. preserving dates.
655static void executeObjcopy(const CopyConfig &Config) {
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000656 sys::fs::file_status Stat;
657 if (Config.PreserveDates)
658 if (auto EC = sys::fs::status(Config.InputFilename, Stat))
659 reportError(Config.InputFilename, EC);
660
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000661 if (Config.InputFormat == "binary") {
662 auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename);
663 if (!BufOrErr)
664 reportError(Config.InputFilename, BufOrErr.getError());
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000665 FileBuffer FB(Config.OutputFilename);
Alexander Shaposhnikov654d3a92018-10-24 22:49:06 +0000666 executeObjcopyOnRawBinary(Config, *BufOrErr->get(), FB);
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000667 } else {
668 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
669 createBinary(Config.InputFilename);
670 if (!BinaryOrErr)
671 reportError(Config.InputFilename, BinaryOrErr.takeError());
672
673 if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
Alexander Shaposhnikov654d3a92018-10-24 22:49:06 +0000674 executeObjcopyOnArchive(Config, *Ar);
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000675 } else {
676 FileBuffer FB(Config.OutputFilename);
Alexander Shaposhnikov654d3a92018-10-24 22:49:06 +0000677 executeObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB);
Jordan Rupprechtcf676332018-08-17 18:51:11 +0000678 }
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000679 }
Alexander Shaposhnikov42b5ef02018-07-06 17:51:03 +0000680
Jordan Rupprechtd1767dc2018-08-16 18:29:40 +0000681 if (Config.PreserveDates) {
682 restoreDateOnFile(Config.OutputFilename, Stat);
683 if (!Config.SplitDWO.empty())
684 restoreDateOnFile(Config.SplitDWO, Stat);
685 }
Petr Hosek05a04cb2017-08-01 00:33:58 +0000686}
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000687
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000688int main(int argc, char **argv) {
689 InitLLVM X(argc, argv);
690 ToolName = argv[0];
Jordan Rupprecht591d8892018-09-05 13:10:03 +0000691 DriverConfig DriverConfig;
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000692 if (sys::path::stem(ToolName).endswith_lower("strip"))
Jordan Rupprecht591d8892018-09-05 13:10:03 +0000693 DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc));
Alexander Shaposhnikovcca69982018-05-07 19:32:09 +0000694 else
Jordan Rupprecht591d8892018-09-05 13:10:03 +0000695 DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc));
696 for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs)
Alexander Shaposhnikov654d3a92018-10-24 22:49:06 +0000697 executeObjcopy(CopyConfig);
Alexander Shaposhnikovd6884792018-04-24 05:43:32 +0000698}