ELFObjcopy.cpp revision 360784
1//===- ELFObjcopy.cpp -----------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ELFObjcopy.h"
10#include "Buffer.h"
11#include "CopyConfig.h"
12#include "Object.h"
13#include "llvm-objcopy.h"
14
15#include "llvm/ADT/BitmaskEnum.h"
16#include "llvm/ADT/DenseSet.h"
17#include "llvm/ADT/Optional.h"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/ADT/Twine.h"
22#include "llvm/BinaryFormat/ELF.h"
23#include "llvm/MC/MCTargetOptions.h"
24#include "llvm/Object/Binary.h"
25#include "llvm/Object/ELFObjectFile.h"
26#include "llvm/Object/ELFTypes.h"
27#include "llvm/Object/Error.h"
28#include "llvm/Option/Option.h"
29#include "llvm/Support/Casting.h"
30#include "llvm/Support/Compression.h"
31#include "llvm/Support/Errc.h"
32#include "llvm/Support/Error.h"
33#include "llvm/Support/ErrorHandling.h"
34#include "llvm/Support/ErrorOr.h"
35#include "llvm/Support/Memory.h"
36#include "llvm/Support/Path.h"
37#include "llvm/Support/raw_ostream.h"
38#include <algorithm>
39#include <cassert>
40#include <cstdlib>
41#include <functional>
42#include <iterator>
43#include <memory>
44#include <string>
45#include <system_error>
46#include <utility>
47
48namespace llvm {
49namespace objcopy {
50namespace elf {
51
52using namespace object;
53using namespace ELF;
54using SectionPred = std::function<bool(const SectionBase &Sec)>;
55
56static bool isDebugSection(const SectionBase &Sec) {
57  return StringRef(Sec.Name).startswith(".debug") ||
58         StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index";
59}
60
61static bool isDWOSection(const SectionBase &Sec) {
62  return StringRef(Sec.Name).endswith(".dwo");
63}
64
65static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
66  // We can't remove the section header string table.
67  if (&Sec == Obj.SectionNames)
68    return false;
69  // Short of keeping the string table we want to keep everything that is a DWO
70  // section and remove everything else.
71  return !isDWOSection(Sec);
72}
73
74uint64_t getNewShfFlags(SectionFlag AllFlags) {
75  uint64_t NewFlags = 0;
76  if (AllFlags & SectionFlag::SecAlloc)
77    NewFlags |= ELF::SHF_ALLOC;
78  if (!(AllFlags & SectionFlag::SecReadonly))
79    NewFlags |= ELF::SHF_WRITE;
80  if (AllFlags & SectionFlag::SecCode)
81    NewFlags |= ELF::SHF_EXECINSTR;
82  if (AllFlags & SectionFlag::SecMerge)
83    NewFlags |= ELF::SHF_MERGE;
84  if (AllFlags & SectionFlag::SecStrings)
85    NewFlags |= ELF::SHF_STRINGS;
86  return NewFlags;
87}
88
89static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags,
90                                            uint64_t NewFlags) {
91  // Preserve some flags which should not be dropped when setting flags.
92  // Also, preserve anything OS/processor dependant.
93  const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
94                                ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
95                                ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
96                                ELF::SHF_TLS | ELF::SHF_INFO_LINK;
97  return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);
98}
99
100static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) {
101  Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, getNewShfFlags(Flags));
102
103  // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule
104  // may promote more non-ALLOC sections than GNU objcopy, but it is fine as
105  // non-ALLOC SHT_NOBITS sections do not make much sense.
106  if (Sec.Type == SHT_NOBITS &&
107      (!(Sec.Flags & ELF::SHF_ALLOC) ||
108       Flags & (SectionFlag::SecContents | SectionFlag::SecLoad)))
109    Sec.Type = SHT_PROGBITS;
110}
111
112static ElfType getOutputElfType(const Binary &Bin) {
113  // Infer output ELF type from the input ELF object
114  if (isa<ELFObjectFile<ELF32LE>>(Bin))
115    return ELFT_ELF32LE;
116  if (isa<ELFObjectFile<ELF64LE>>(Bin))
117    return ELFT_ELF64LE;
118  if (isa<ELFObjectFile<ELF32BE>>(Bin))
119    return ELFT_ELF32BE;
120  if (isa<ELFObjectFile<ELF64BE>>(Bin))
121    return ELFT_ELF64BE;
122  llvm_unreachable("Invalid ELFType");
123}
124
125static ElfType getOutputElfType(const MachineInfo &MI) {
126  // Infer output ELF type from the binary arch specified
127  if (MI.Is64Bit)
128    return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
129  else
130    return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
131}
132
133static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config,
134                                               Object &Obj, Buffer &Buf,
135                                               ElfType OutputElfType) {
136  // Depending on the initial ELFT and OutputFormat we need a different Writer.
137  switch (OutputElfType) {
138  case ELFT_ELF32LE:
139    return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, !Config.StripSections,
140                                                Config.OnlyKeepDebug);
141  case ELFT_ELF64LE:
142    return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, !Config.StripSections,
143                                                Config.OnlyKeepDebug);
144  case ELFT_ELF32BE:
145    return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, !Config.StripSections,
146                                                Config.OnlyKeepDebug);
147  case ELFT_ELF64BE:
148    return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, !Config.StripSections,
149                                                Config.OnlyKeepDebug);
150  }
151  llvm_unreachable("Invalid output format");
152}
153
154static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
155                                            Object &Obj, Buffer &Buf,
156                                            ElfType OutputElfType) {
157  switch (Config.OutputFormat) {
158  case FileFormat::Binary:
159    return std::make_unique<BinaryWriter>(Obj, Buf);
160  case FileFormat::IHex:
161    return std::make_unique<IHexWriter>(Obj, Buf);
162  default:
163    return createELFWriter(Config, Obj, Buf, OutputElfType);
164  }
165}
166
167template <class ELFT>
168static Expected<ArrayRef<uint8_t>>
169findBuildID(const CopyConfig &Config, const object::ELFFile<ELFT> &In) {
170  auto PhdrsOrErr = In.program_headers();
171  if (auto Err = PhdrsOrErr.takeError())
172    return createFileError(Config.InputFilename, std::move(Err));
173
174  for (const auto &Phdr : *PhdrsOrErr) {
175    if (Phdr.p_type != PT_NOTE)
176      continue;
177    Error Err = Error::success();
178    for (auto Note : In.notes(Phdr, Err))
179      if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU)
180        return Note.getDesc();
181    if (Err)
182      return createFileError(Config.InputFilename, std::move(Err));
183  }
184
185  return createFileError(
186      Config.InputFilename,
187      createStringError(llvm::errc::invalid_argument,
188                        "could not find build ID"));
189}
190
191static Expected<ArrayRef<uint8_t>>
192findBuildID(const CopyConfig &Config, const object::ELFObjectFileBase &In) {
193  if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In))
194    return findBuildID(Config, *O->getELFFile());
195  else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In))
196    return findBuildID(Config, *O->getELFFile());
197  else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In))
198    return findBuildID(Config, *O->getELFFile());
199  else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In))
200    return findBuildID(Config, *O->getELFFile());
201
202  llvm_unreachable("Bad file format");
203}
204
205template <class... Ts>
206static Error makeStringError(std::error_code EC, const Twine &Msg, Ts &&... Args) {
207  std::string FullMsg = (EC.message() + ": " + Msg).str();
208  return createStringError(EC, FullMsg.c_str(), std::forward<Ts>(Args)...);
209}
210
211#define MODEL_8 "%%%%%%%%"
212#define MODEL_16 MODEL_8 MODEL_8
213#define MODEL_32 (MODEL_16 MODEL_16)
214
215static Error linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink,
216                              StringRef Suffix,
217                              ArrayRef<uint8_t> BuildIdBytes) {
218  SmallString<128> Path = Config.BuildIdLinkDir;
219  sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true));
220  if (auto EC = sys::fs::create_directories(Path))
221    return createFileError(
222        Path.str(),
223        makeStringError(EC, "cannot create build ID link directory"));
224
225  sys::path::append(Path,
226                    llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true));
227  Path += Suffix;
228  SmallString<128> TmpPath;
229  // create_hard_link races so we need to link to a temporary path but
230  // we want to make sure that we choose a filename that does not exist.
231  // By using 32 model characters we get 128-bits of entropy. It is
232  // unlikely that this string has ever existed before much less exists
233  // on this disk or in the current working directory.
234  // Additionally we prepend the original Path for debugging but also
235  // because it ensures that we're linking within a directory on the same
236  // partition on the same device which is critical. It has the added
237  // win of yet further decreasing the odds of a conflict.
238  sys::fs::createUniquePath(Twine(Path) + "-" + MODEL_32 + ".tmp", TmpPath,
239                            /*MakeAbsolute*/ false);
240  if (auto EC = sys::fs::create_hard_link(ToLink, TmpPath)) {
241    Path.push_back('\0');
242    return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(),
243                           Path.data());
244  }
245  // We then atomically rename the link into place which will just move the
246  // link. If rename fails something is more seriously wrong so just return
247  // an error.
248  if (auto EC = sys::fs::rename(TmpPath, Path)) {
249    Path.push_back('\0');
250    return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(),
251                           Path.data());
252  }
253  // If `Path` was already a hard-link to the same underlying file then the
254  // temp file will be left so we need to remove it. Remove will not cause
255  // an error by default if the file is already gone so just blindly remove
256  // it rather than checking.
257  if (auto EC = sys::fs::remove(TmpPath)) {
258    TmpPath.push_back('\0');
259    return makeStringError(EC, "could not remove '%s'", TmpPath.data());
260  }
261  return Error::success();
262}
263
264static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
265                            StringRef File, ElfType OutputElfType) {
266  auto DWOFile = Reader.create(false);
267  auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) {
268    return onlyKeepDWOPred(*DWOFile, Sec);
269  };
270  if (Error E = DWOFile->removeSections(Config.AllowBrokenLinks,
271                                        OnlyKeepDWOPred))
272    return E;
273  if (Config.OutputArch) {
274    DWOFile->Machine = Config.OutputArch.getValue().EMachine;
275    DWOFile->OSABI = Config.OutputArch.getValue().OSABI;
276  }
277  FileBuffer FB(File);
278  auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType);
279  if (Error E = Writer->finalize())
280    return E;
281  return Writer->write();
282}
283
284static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
285                               Object &Obj) {
286  for (auto &Sec : Obj.sections()) {
287    if (Sec.Name == SecName) {
288      if (Sec.OriginalData.empty())
289        return createStringError(object_error::parse_failed,
290                                 "cannot dump section '%s': it has no contents",
291                                 SecName.str().c_str());
292      Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
293          FileOutputBuffer::create(Filename, Sec.OriginalData.size());
294      if (!BufferOrErr)
295        return BufferOrErr.takeError();
296      std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
297      std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
298                Buf->getBufferStart());
299      if (Error E = Buf->commit())
300        return E;
301      return Error::success();
302    }
303  }
304  return createStringError(object_error::parse_failed, "section '%s' not found",
305                           SecName.str().c_str());
306}
307
308static bool isCompressable(const SectionBase &Sec) {
309  return !(Sec.Flags & ELF::SHF_COMPRESSED) &&
310         StringRef(Sec.Name).startswith(".debug");
311}
312
313static void replaceDebugSections(
314    Object &Obj, SectionPred &RemovePred,
315    function_ref<bool(const SectionBase &)> shouldReplace,
316    function_ref<SectionBase *(const SectionBase *)> addSection) {
317  // Build a list of the debug sections we are going to replace.
318  // We can't call `addSection` while iterating over sections,
319  // because it would mutate the sections array.
320  SmallVector<SectionBase *, 13> ToReplace;
321  for (auto &Sec : Obj.sections())
322    if (shouldReplace(Sec))
323      ToReplace.push_back(&Sec);
324
325  // Build a mapping from original section to a new one.
326  DenseMap<SectionBase *, SectionBase *> FromTo;
327  for (SectionBase *S : ToReplace)
328    FromTo[S] = addSection(S);
329
330  // Now we want to update the target sections of relocation
331  // sections. Also we will update the relocations themselves
332  // to update the symbol references.
333  for (auto &Sec : Obj.sections())
334    Sec.replaceSectionReferences(FromTo);
335
336  RemovePred = [shouldReplace, RemovePred](const SectionBase &Sec) {
337    return shouldReplace(Sec) || RemovePred(Sec);
338  };
339}
340
341static bool isUnneededSymbol(const Symbol &Sym) {
342  return !Sym.Referenced &&
343         (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
344         Sym.Type != STT_SECTION;
345}
346
347static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {
348  // TODO: update or remove symbols only if there is an option that affects
349  // them.
350  if (!Obj.SymbolTable)
351    return Error::success();
352
353  Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
354    // Common and undefined symbols don't make sense as local symbols, and can
355    // even cause crashes if we localize those, so skip them.
356    if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF &&
357        ((Config.LocalizeHidden &&
358          (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
359         Config.SymbolsToLocalize.matches(Sym.Name)))
360      Sym.Binding = STB_LOCAL;
361
362    // Note: these two globalize flags have very similar names but different
363    // meanings:
364    //
365    // --globalize-symbol: promote a symbol to global
366    // --keep-global-symbol: all symbols except for these should be made local
367    //
368    // If --globalize-symbol is specified for a given symbol, it will be
369    // global in the output file even if it is not included via
370    // --keep-global-symbol. Because of that, make sure to check
371    // --globalize-symbol second.
372    if (!Config.SymbolsToKeepGlobal.empty() &&
373        !Config.SymbolsToKeepGlobal.matches(Sym.Name) &&
374        Sym.getShndx() != SHN_UNDEF)
375      Sym.Binding = STB_LOCAL;
376
377    if (Config.SymbolsToGlobalize.matches(Sym.Name) &&
378        Sym.getShndx() != SHN_UNDEF)
379      Sym.Binding = STB_GLOBAL;
380
381    if (Config.SymbolsToWeaken.matches(Sym.Name) && Sym.Binding == STB_GLOBAL)
382      Sym.Binding = STB_WEAK;
383
384    if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
385        Sym.getShndx() != SHN_UNDEF)
386      Sym.Binding = STB_WEAK;
387
388    const auto I = Config.SymbolsToRename.find(Sym.Name);
389    if (I != Config.SymbolsToRename.end())
390      Sym.Name = I->getValue();
391
392    if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
393      Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
394  });
395
396  // The purpose of this loop is to mark symbols referenced by sections
397  // (like GroupSection or RelocationSection). This way, we know which
398  // symbols are still 'needed' and which are not.
399  if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() ||
400      !Config.OnlySection.empty()) {
401    for (SectionBase &Sec : Obj.sections())
402      Sec.markSymbols();
403  }
404
405  auto RemoveSymbolsPred = [&](const Symbol &Sym) {
406    if (Config.SymbolsToKeep.matches(Sym.Name) ||
407        (Config.KeepFileSymbols && Sym.Type == STT_FILE))
408      return false;
409
410    if ((Config.DiscardMode == DiscardType::All ||
411         (Config.DiscardMode == DiscardType::Locals &&
412          StringRef(Sym.Name).startswith(".L"))) &&
413        Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF &&
414        Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
415      return true;
416
417    if (Config.StripAll || Config.StripAllGNU)
418      return true;
419
420    if (Config.SymbolsToRemove.matches(Sym.Name))
421      return true;
422
423    if ((Config.StripUnneeded ||
424         Config.UnneededSymbolsToRemove.matches(Sym.Name)) &&
425        (!Obj.isRelocatable() || isUnneededSymbol(Sym)))
426      return true;
427
428    // We want to remove undefined symbols if all references have been stripped.
429    if (!Config.OnlySection.empty() && !Sym.Referenced &&
430        Sym.getShndx() == SHN_UNDEF)
431      return true;
432
433    return false;
434  };
435
436  return Obj.removeSymbols(RemoveSymbolsPred);
437}
438
439static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {
440  SectionPred RemovePred = [](const SectionBase &) { return false; };
441
442  // Removes:
443  if (!Config.ToRemove.empty()) {
444    RemovePred = [&Config](const SectionBase &Sec) {
445      return Config.ToRemove.matches(Sec.Name);
446    };
447  }
448
449  if (Config.StripDWO || !Config.SplitDWO.empty())
450    RemovePred = [RemovePred](const SectionBase &Sec) {
451      return isDWOSection(Sec) || RemovePred(Sec);
452    };
453
454  if (Config.ExtractDWO)
455    RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
456      return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
457    };
458
459  if (Config.StripAllGNU)
460    RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
461      if (RemovePred(Sec))
462        return true;
463      if ((Sec.Flags & SHF_ALLOC) != 0)
464        return false;
465      if (&Sec == Obj.SectionNames)
466        return false;
467      switch (Sec.Type) {
468      case SHT_SYMTAB:
469      case SHT_REL:
470      case SHT_RELA:
471      case SHT_STRTAB:
472        return true;
473      }
474      return isDebugSection(Sec);
475    };
476
477  if (Config.StripSections) {
478    RemovePred = [RemovePred](const SectionBase &Sec) {
479      return RemovePred(Sec) || Sec.ParentSegment == nullptr;
480    };
481  }
482
483  if (Config.StripDebug || Config.StripUnneeded) {
484    RemovePred = [RemovePred](const SectionBase &Sec) {
485      return RemovePred(Sec) || isDebugSection(Sec);
486    };
487  }
488
489  if (Config.StripNonAlloc)
490    RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
491      if (RemovePred(Sec))
492        return true;
493      if (&Sec == Obj.SectionNames)
494        return false;
495      return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr;
496    };
497
498  if (Config.StripAll)
499    RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
500      if (RemovePred(Sec))
501        return true;
502      if (&Sec == Obj.SectionNames)
503        return false;
504      if (StringRef(Sec.Name).startswith(".gnu.warning"))
505        return false;
506      // We keep the .ARM.attribute section to maintain compatibility
507      // with Debian derived distributions. This is a bug in their
508      // patchset as documented here:
509      // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943798
510      if (Sec.Type == SHT_ARM_ATTRIBUTES)
511        return false;
512      if (Sec.ParentSegment != nullptr)
513        return false;
514      return (Sec.Flags & SHF_ALLOC) == 0;
515    };
516
517  if (Config.ExtractPartition || Config.ExtractMainPartition) {
518    RemovePred = [RemovePred](const SectionBase &Sec) {
519      if (RemovePred(Sec))
520        return true;
521      if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR)
522        return true;
523      return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment;
524    };
525  }
526
527  // Explicit copies:
528  if (!Config.OnlySection.empty()) {
529    RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
530      // Explicitly keep these sections regardless of previous removes.
531      if (Config.OnlySection.matches(Sec.Name))
532        return false;
533
534      // Allow all implicit removes.
535      if (RemovePred(Sec))
536        return true;
537
538      // Keep special sections.
539      if (Obj.SectionNames == &Sec)
540        return false;
541      if (Obj.SymbolTable == &Sec ||
542          (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
543        return false;
544
545      // Remove everything else.
546      return true;
547    };
548  }
549
550  if (!Config.KeepSection.empty()) {
551    RemovePred = [&Config, RemovePred](const SectionBase &Sec) {
552      // Explicitly keep these sections regardless of previous removes.
553      if (Config.KeepSection.matches(Sec.Name))
554        return false;
555      // Otherwise defer to RemovePred.
556      return RemovePred(Sec);
557    };
558  }
559
560  // This has to be the last predicate assignment.
561  // If the option --keep-symbol has been specified
562  // and at least one of those symbols is present
563  // (equivalently, the updated symbol table is not empty)
564  // the symbol table and the string table should not be removed.
565  if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
566      Obj.SymbolTable && !Obj.SymbolTable->empty()) {
567    RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
568      if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
569        return false;
570      return RemovePred(Sec);
571    };
572  }
573
574  if (Config.CompressionType != DebugCompressionType::None)
575    replaceDebugSections(Obj, RemovePred, isCompressable,
576                         [&Config, &Obj](const SectionBase *S) {
577                           return &Obj.addSection<CompressedSection>(
578                                *S, Config.CompressionType);
579                        });
580  else if (Config.DecompressDebugSections)
581    replaceDebugSections(
582        Obj, RemovePred,
583        [](const SectionBase &S) { return isa<CompressedSection>(&S); },
584        [&Obj](const SectionBase *S) {
585          auto CS = cast<CompressedSection>(S);
586          return &Obj.addSection<DecompressedSection>(*CS);
587        });
588
589  return Obj.removeSections(Config.AllowBrokenLinks, RemovePred);
590}
591
592// This function handles the high level operations of GNU objcopy including
593// handling command line options. It's important to outline certain properties
594// we expect to hold of the command line operations. Any operation that "keeps"
595// should keep regardless of a remove. Additionally any removal should respect
596// any previous removals. Lastly whether or not something is removed shouldn't
597// depend a) on the order the options occur in or b) on some opaque priority
598// system. The only priority is that keeps/copies overrule removes.
599static Error handleArgs(const CopyConfig &Config, Object &Obj,
600                        const Reader &Reader, ElfType OutputElfType) {
601
602  if (!Config.SplitDWO.empty())
603    if (Error E =
604            splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType))
605      return E;
606
607  if (Config.OutputArch) {
608    Obj.Machine = Config.OutputArch.getValue().EMachine;
609    Obj.OSABI = Config.OutputArch.getValue().OSABI;
610  }
611
612  // It is important to remove the sections first. For example, we want to
613  // remove the relocation sections before removing the symbols. That allows
614  // us to avoid reporting the inappropriate errors about removing symbols
615  // named in relocations.
616  if (Error E = replaceAndRemoveSections(Config, Obj))
617    return E;
618
619  if (Error E = updateAndRemoveSymbols(Config, Obj))
620    return E;
621
622  if (!Config.SectionsToRename.empty()) {
623    for (SectionBase &Sec : Obj.sections()) {
624      const auto Iter = Config.SectionsToRename.find(Sec.Name);
625      if (Iter != Config.SectionsToRename.end()) {
626        const SectionRename &SR = Iter->second;
627        Sec.Name = SR.NewName;
628        if (SR.NewFlags.hasValue())
629          setSectionFlagsAndType(Sec, SR.NewFlags.getValue());
630      }
631    }
632  }
633
634  // Add a prefix to allocated sections and their relocation sections. This
635  // should be done after renaming the section by Config.SectionToRename to
636  // imitate the GNU objcopy behavior.
637  if (!Config.AllocSectionsPrefix.empty()) {
638    DenseSet<SectionBase *> PrefixedSections;
639    for (SectionBase &Sec : Obj.sections()) {
640      if (Sec.Flags & SHF_ALLOC) {
641        Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str();
642        PrefixedSections.insert(&Sec);
643      } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) {
644        // Rename relocation sections associated to the allocated sections.
645        // For example, if we rename .text to .prefix.text, we also rename
646        // .rel.text to .rel.prefix.text.
647        //
648        // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled
649        // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not
650        // .rela.prefix.plt since GNU objcopy does so.
651        const SectionBase *TargetSec = RelocSec->getSection();
652        if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) {
653          StringRef prefix;
654          switch (Sec.Type) {
655          case SHT_REL:
656            prefix = ".rel";
657            break;
658          case SHT_RELA:
659            prefix = ".rela";
660            break;
661          default:
662            llvm_unreachable("not a relocation section");
663          }
664
665          // If the relocation section comes *after* the target section, we
666          // don't add Config.AllocSectionsPrefix because we've already added
667          // the prefix to TargetSec->Name. Otherwise, if the relocation
668          // section comes *before* the target section, we add the prefix.
669          if (PrefixedSections.count(TargetSec))
670            Sec.Name = (prefix + TargetSec->Name).str();
671          else
672            Sec.Name =
673                (prefix + Config.AllocSectionsPrefix + TargetSec->Name).str();
674        }
675      }
676    }
677  }
678
679  if (!Config.SetSectionAlignment.empty()) {
680    for (SectionBase &Sec : Obj.sections()) {
681      auto I = Config.SetSectionAlignment.find(Sec.Name);
682      if (I != Config.SetSectionAlignment.end())
683        Sec.Align = I->second;
684    }
685  }
686
687  if (!Config.SetSectionFlags.empty()) {
688    for (auto &Sec : Obj.sections()) {
689      const auto Iter = Config.SetSectionFlags.find(Sec.Name);
690      if (Iter != Config.SetSectionFlags.end()) {
691        const SectionFlagsUpdate &SFU = Iter->second;
692        setSectionFlagsAndType(Sec, SFU.NewFlags);
693      }
694    }
695  }
696
697  if (Config.OnlyKeepDebug)
698    for (auto &Sec : Obj.sections())
699      if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)
700        Sec.Type = SHT_NOBITS;
701
702  for (const auto &Flag : Config.AddSection) {
703    std::pair<StringRef, StringRef> SecPair = Flag.split("=");
704    StringRef SecName = SecPair.first;
705    StringRef File = SecPair.second;
706    ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
707        MemoryBuffer::getFile(File);
708    if (!BufOrErr)
709      return createFileError(File, errorCodeToError(BufOrErr.getError()));
710    std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
711    ArrayRef<uint8_t> Data(
712        reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
713        Buf->getBufferSize());
714    OwnedDataSection &NewSection =
715        Obj.addSection<OwnedDataSection>(SecName, Data);
716    if (SecName.startswith(".note") && SecName != ".note.GNU-stack")
717      NewSection.Type = SHT_NOTE;
718  }
719
720  for (const auto &Flag : Config.DumpSection) {
721    std::pair<StringRef, StringRef> SecPair = Flag.split("=");
722    StringRef SecName = SecPair.first;
723    StringRef File = SecPair.second;
724    if (Error E = dumpSectionToFile(SecName, File, Obj))
725      return E;
726  }
727
728  if (!Config.AddGnuDebugLink.empty())
729    Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink,
730                                        Config.GnuDebugLinkCRC32);
731
732  for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) {
733    SectionBase *Sec = Obj.findSection(SI.SectionName);
734    uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value;
735    Obj.SymbolTable->addSymbol(
736        SI.SymbolName, SI.Bind, SI.Type, Sec, Value, SI.Visibility,
737        Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0);
738  }
739
740  if (Config.EntryExpr)
741    Obj.Entry = Config.EntryExpr(Obj.Entry);
742  return Error::success();
743}
744
745static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out,
746                         ElfType OutputElfType) {
747  std::unique_ptr<Writer> Writer =
748      createWriter(Config, Obj, Out, OutputElfType);
749  if (Error E = Writer->finalize())
750    return E;
751  return Writer->write();
752}
753
754Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
755                           Buffer &Out) {
756  IHexReader Reader(&In);
757  std::unique_ptr<Object> Obj = Reader.create(true);
758  const ElfType OutputElfType =
759    getOutputElfType(Config.OutputArch.getValueOr(MachineInfo()));
760  if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))
761    return E;
762  return writeOutput(Config, *Obj, Out, OutputElfType);
763}
764
765Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
766                                Buffer &Out) {
767  uint8_t NewSymbolVisibility =
768      Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT);
769  BinaryReader Reader(&In, NewSymbolVisibility);
770  std::unique_ptr<Object> Obj = Reader.create(true);
771
772  // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
773  // (-B<arch>).
774  const ElfType OutputElfType =
775      getOutputElfType(Config.OutputArch.getValueOr(MachineInfo()));
776  if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))
777    return E;
778  return writeOutput(Config, *Obj, Out, OutputElfType);
779}
780
781Error executeObjcopyOnBinary(const CopyConfig &Config,
782                             object::ELFObjectFileBase &In, Buffer &Out) {
783  ELFReader Reader(&In, Config.ExtractPartition);
784  std::unique_ptr<Object> Obj = Reader.create(!Config.SymbolsToAdd.empty());
785  // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
786  const ElfType OutputElfType =
787      Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue())
788                        : getOutputElfType(In);
789  ArrayRef<uint8_t> BuildIdBytes;
790
791  if (!Config.BuildIdLinkDir.empty()) {
792    auto BuildIdBytesOrErr = findBuildID(Config, In);
793    if (auto E = BuildIdBytesOrErr.takeError())
794      return E;
795    BuildIdBytes = *BuildIdBytesOrErr;
796
797    if (BuildIdBytes.size() < 2)
798      return createFileError(
799          Config.InputFilename,
800          createStringError(object_error::parse_failed,
801                            "build ID is smaller than two bytes"));
802  }
803
804  if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput)
805    if (Error E =
806            linkToBuildIdDir(Config, Config.InputFilename,
807                             Config.BuildIdLinkInput.getValue(), BuildIdBytes))
808      return E;
809
810  if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))
811    return createFileError(Config.InputFilename, std::move(E));
812
813  if (Error E = writeOutput(Config, *Obj, Out, OutputElfType))
814    return createFileError(Config.InputFilename, std::move(E));
815  if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput)
816    if (Error E =
817            linkToBuildIdDir(Config, Config.OutputFilename,
818                             Config.BuildIdLinkOutput.getValue(), BuildIdBytes))
819      return createFileError(Config.OutputFilename, std::move(E));
820
821  return Error::success();
822}
823
824} // end namespace elf
825} // end namespace objcopy
826} // end namespace llvm
827