blob: 99f0264267031ceb5490e89486af0cad89c71b34 [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"
11#include "Object.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000012#include "llvm/ADT/STLExtras.h"
13#include "llvm/ADT/StringRef.h"
14#include "llvm/ADT/Twine.h"
15#include "llvm/BinaryFormat/ELF.h"
16#include "llvm/Object/Binary.h"
17#include "llvm/Object/ELFObjectFile.h"
18#include "llvm/Object/ELFTypes.h"
19#include "llvm/Object/Error.h"
20#include "llvm/Support/Casting.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000021#include "llvm/Support/CommandLine.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000022#include "llvm/Support/Compiler.h"
23#include "llvm/Support/Error.h"
24#include "llvm/Support/ErrorHandling.h"
25#include "llvm/Support/ErrorOr.h"
Petr Hosek05a04cb2017-08-01 00:33:58 +000026#include "llvm/Support/FileOutputBuffer.h"
Rui Ueyama197194b2018-04-13 18:26:06 +000027#include "llvm/Support/InitLLVM.h"
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000028#include "llvm/Support/raw_ostream.h"
29#include <algorithm>
30#include <cassert>
31#include <cstdlib>
32#include <functional>
33#include <iterator>
Petr Hosek05a04cb2017-08-01 00:33:58 +000034#include <memory>
35#include <string>
36#include <system_error>
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000037#include <utility>
Petr Hosek05a04cb2017-08-01 00:33:58 +000038
39using namespace llvm;
40using namespace object;
41using namespace ELF;
42
43// The name this program was invoked as.
44static StringRef ToolName;
45
46namespace llvm {
47
Zachary Turner41a9ee92017-10-11 23:54:34 +000048LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
Petr Hosek05a04cb2017-08-01 00:33:58 +000049 errs() << ToolName << ": " << Message << ".\n";
50 errs().flush();
51 exit(1);
52}
53
54LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
55 assert(EC);
56 errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n";
57 exit(1);
58}
59
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000060LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
Petr Hosek05a04cb2017-08-01 00:33:58 +000061 assert(E);
62 std::string Buf;
63 raw_string_ostream OS(Buf);
64 logAllUnhandledErrors(std::move(E), OS, "");
65 OS.flush();
66 errs() << ToolName << ": '" << File << "': " << Buf;
67 exit(1);
68}
Petr Hosek05a04cb2017-08-01 00:33:58 +000069
Eugene Zelenko0ad18f82017-11-01 21:16:06 +000070} // end namespace llvm
71
Jake Ehrlicha8c689e2018-04-12 00:40:50 +000072static cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input>"));
73static cl::opt<std::string> OutputFilename(cl::Positional, cl::desc("[ <output> ]"));
Alexander Shaposhnikovfedb0162018-02-09 23:33:31 +000074
Jake Ehrlicha8c689e2018-04-12 00:40:50 +000075static cl::opt<std::string>
76 OutputFormat("O", cl::desc("Set output format to one of the following:"
77 "\n\tbinary"));
78static cl::list<std::string> ToRemove("remove-section",
79 cl::desc("Remove <section>"),
80 cl::value_desc("section"));
81static cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"),
82 cl::aliasopt(ToRemove));
83static cl::opt<bool> StripAll(
84 "strip-all",
85 cl::desc(
86 "Removes non-allocated sections other than .gnu.warning* sections"));
87static cl::opt<bool>
88 StripAllGNU("strip-all-gnu",
89 cl::desc("Removes symbol, relocation, and debug information"));
90static cl::list<std::string> Keep("keep", cl::desc("Keep <section>"),
91 cl::value_desc("section"));
92static cl::list<std::string> OnlyKeep("only-keep",
93 cl::desc("Remove all but <section>"),
94 cl::value_desc("section"));
95static cl::alias OnlyKeepA("j", cl::desc("Alias for only-keep"),
96 cl::aliasopt(OnlyKeep));
97static cl::opt<bool> StripDebug("strip-debug",
98 cl::desc("Removes all debug information"));
99static cl::opt<bool> StripSections("strip-sections",
100 cl::desc("Remove all section headers"));
101static cl::opt<bool>
102 StripNonAlloc("strip-non-alloc",
103 cl::desc("Remove all non-allocated sections"));
104static cl::opt<bool>
105 StripDWO("strip-dwo", cl::desc("Remove all DWARF .dwo sections from file"));
106static cl::opt<bool> ExtractDWO(
107 "extract-dwo",
108 cl::desc("Remove all sections that are not DWARF .dwo sections from file"));
109static cl::opt<std::string>
110 SplitDWO("split-dwo",
111 cl::desc("Equivalent to extract-dwo on the input file to "
112 "<dwo-file>, then strip-dwo on the input file"),
113 cl::value_desc("dwo-file"));
114static cl::list<std::string> AddSection(
115 "add-section",
116 cl::desc("Make a section named <section> with the contents of <file>."),
117 cl::value_desc("section=file"));
118static cl::opt<bool> LocalizeHidden(
119 "localize-hidden",
120 cl::desc(
121 "Mark all symbols that have hidden or internal visibility as local"));
122static cl::opt<std::string>
123 AddGnuDebugLink("add-gnu-debuglink",
124 cl::desc("adds a .gnu_debuglink for <debug-file>"),
125 cl::value_desc("debug-file"));
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000126
Eugene Zelenko0ad18f82017-11-01 21:16:06 +0000127using SectionPred = std::function<bool(const SectionBase &Sec)>;
Petr Hosek05a04cb2017-08-01 00:33:58 +0000128
Jake Ehrlich777fb002017-12-15 20:17:55 +0000129bool IsDWOSection(const SectionBase &Sec) { return Sec.Name.endswith(".dwo"); }
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000130
Jake Ehrlich76e91102018-01-25 22:46:17 +0000131bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000132 // We can't remove the section header string table.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000133 if (&Sec == Obj.SectionNames)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000134 return false;
135 // Short of keeping the string table we want to keep everything that is a DWO
136 // section and remove everything else.
137 return !IsDWOSection(Sec);
138}
139
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000140static ElfType OutputElfType;
141
142std::unique_ptr<Writer> CreateWriter(Object &Obj, StringRef File) {
143 if (OutputFormat == "binary") {
144 return llvm::make_unique<BinaryWriter>(OutputFilename, Obj);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000145 }
146 // Depending on the initial ELFT and OutputFormat we need a different Writer.
147 switch (OutputElfType) {
148 case ELFT_ELF32LE:
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000149 return llvm::make_unique<ELFWriter<ELF32LE>>(File, Obj, !StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000150 case ELFT_ELF64LE:
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000151 return llvm::make_unique<ELFWriter<ELF64LE>>(File, Obj, !StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000152 case ELFT_ELF32BE:
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000153 return llvm::make_unique<ELFWriter<ELF32BE>>(File, Obj, !StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000154 case ELFT_ELF64BE:
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000155 return llvm::make_unique<ELFWriter<ELF64BE>>(File, Obj, !StripSections);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000156 }
157 llvm_unreachable("Invalid output format");
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000158}
159
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000160void SplitDWOToFile(const Reader &Reader, StringRef File) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000161 auto DWOFile = Reader.create();
162 DWOFile->removeSections(
163 [&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); });
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000164 auto Writer = CreateWriter(*DWOFile, File);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000165 Writer->finalize();
166 Writer->write();
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000167}
168
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000169// This function handles the high level operations of GNU objcopy including
170// handling command line options. It's important to outline certain properties
171// we expect to hold of the command line operations. Any operation that "keeps"
172// should keep regardless of a remove. Additionally any removal should respect
173// any previous removals. Lastly whether or not something is removed shouldn't
174// depend a) on the order the options occur in or b) on some opaque priority
175// system. The only priority is that keeps/copies overrule removes.
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000176void HandleArgs(Object &Obj, const Reader &Reader) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000177
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000178 if (!SplitDWO.empty()) {
179 SplitDWOToFile(Reader, SplitDWO);
Jake Ehrlich76e91102018-01-25 22:46:17 +0000180 }
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000181
Jake Ehrlich27a29b02018-01-05 19:19:09 +0000182 // Localize:
183
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000184 if (LocalizeHidden) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000185 Obj.SymbolTable->localize([](const Symbol &Sym) {
Jake Ehrlich27a29b02018-01-05 19:19:09 +0000186 return Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL;
187 });
188 }
189
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000190 SectionPred RemovePred = [](const SectionBase &) { return false; };
191
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000192 // Removes:
193
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000194 if (!ToRemove.empty()) {
195 RemovePred = [&](const SectionBase &Sec) {
196 return std::find(std::begin(ToRemove), std::end(ToRemove), Sec.Name) !=
197 std::end(ToRemove);
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000198 };
Jake Ehrlich36a2eb32017-10-10 18:47:09 +0000199 }
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000200
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000201 if (StripDWO || !SplitDWO.empty())
David Blaikie998ff812017-11-03 20:57:09 +0000202 RemovePred = [RemovePred](const SectionBase &Sec) {
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000203 return IsDWOSection(Sec) || RemovePred(Sec);
204 };
205
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000206 if (ExtractDWO)
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000207 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000208 return OnlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
Jake Ehrlich5de70d92017-11-03 18:58:41 +0000209 };
210
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000211 if (StripAllGNU)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000212 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
213 if (RemovePred(Sec))
214 return true;
215 if ((Sec.Flags & SHF_ALLOC) != 0)
216 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000217 if (&Sec == Obj.SectionNames)
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000218 return false;
Jake Ehrlich777fb002017-12-15 20:17:55 +0000219 switch (Sec.Type) {
Jake Ehrlichfabddf12017-11-13 22:02:07 +0000220 case SHT_SYMTAB:
221 case SHT_REL:
222 case SHT_RELA:
223 case SHT_STRTAB:
224 return true;
225 }
226 return Sec.Name.startswith(".debug");
227 };
228
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000229 if (StripSections) {
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000230 RemovePred = [RemovePred](const SectionBase &Sec) {
231 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
232 };
Jake Ehrlichf03384d2017-10-11 18:09:18 +0000233 }
234
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000235 if (StripDebug) {
Jake Ehrlich1bfefc12017-11-13 22:13:08 +0000236 RemovePred = [RemovePred](const SectionBase &Sec) {
237 return RemovePred(Sec) || Sec.Name.startswith(".debug");
238 };
239 }
240
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000241 if (StripNonAlloc)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000242 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
243 if (RemovePred(Sec))
244 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000245 if (&Sec == Obj.SectionNames)
Jake Ehrlichd56725a2017-11-14 18:50:24 +0000246 return false;
247 return (Sec.Flags & SHF_ALLOC) == 0;
248 };
249
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000250 if (StripAll)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000251 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
252 if (RemovePred(Sec))
253 return true;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000254 if (&Sec == Obj.SectionNames)
Jake Ehrlich6ad72d02017-11-27 18:56:01 +0000255 return false;
256 if (Sec.Name.startswith(".gnu.warning"))
257 return false;
258 return (Sec.Flags & SHF_ALLOC) == 0;
259 };
260
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000261 // Explicit copies:
262
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000263 if (!OnlyKeep.empty()) {
264 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000265 // Explicitly keep these sections regardless of previous removes.
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000266 if (std::find(std::begin(OnlyKeep), std::end(OnlyKeep), Sec.Name) !=
267 std::end(OnlyKeep))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000268 return false;
269
270 // Allow all implicit removes.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000271 if (RemovePred(Sec))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000272 return true;
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000273
274 // Keep special sections.
Jake Ehrlich76e91102018-01-25 22:46:17 +0000275 if (Obj.SectionNames == &Sec)
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000276 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000277 if (Obj.SymbolTable == &Sec || Obj.SymbolTable->getStrTab() == &Sec)
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000278 return false;
Jake Ehrlich76e91102018-01-25 22:46:17 +0000279
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000280 // Remove everything else.
281 return true;
282 };
283 }
284
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000285 if (!Keep.empty()) {
286 RemovePred = [RemovePred](const SectionBase &Sec) {
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000287 // Explicitly keep these sections regardless of previous removes.
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000288 if (std::find(std::begin(Keep), std::end(Keep), Sec.Name) !=
289 std::end(Keep))
Jake Ehrlichef3b80c2017-11-30 20:14:53 +0000290 return false;
291 // Otherwise defer to RemovePred.
292 return RemovePred(Sec);
293 };
294 }
295
Jake Ehrlich76e91102018-01-25 22:46:17 +0000296 Obj.removeSections(RemovePred);
Jake Ehrliche8437de2017-12-19 00:47:30 +0000297
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000298 if (!AddSection.empty()) {
299 for (const auto &Flag : AddSection) {
300 auto SecPair = StringRef(Flag).split("=");
Jake Ehrliche8437de2017-12-19 00:47:30 +0000301 auto SecName = SecPair.first;
302 auto File = SecPair.second;
303 auto BufOrErr = MemoryBuffer::getFile(File);
304 if (!BufOrErr)
305 reportError(File, BufOrErr.getError());
306 auto Buf = std::move(*BufOrErr);
307 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
308 auto BufSize = Buf->getBufferSize();
Jake Ehrlich76e91102018-01-25 22:46:17 +0000309 Obj.addSection<OwnedDataSection>(SecName,
310 ArrayRef<uint8_t>(BufPtr, BufSize));
Jake Ehrliche8437de2017-12-19 00:47:30 +0000311 }
312 }
313
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000314 if (!AddGnuDebugLink.empty()) {
315 Obj.addSection<GnuDebugLinkSection>(StringRef(AddGnuDebugLink));
Jake Ehrlichea07d3c2018-01-25 22:15:14 +0000316 }
Jake Ehrlich76e91102018-01-25 22:46:17 +0000317}
Jake Ehrlichea07d3c2018-01-25 22:15:14 +0000318
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000319std::unique_ptr<Reader> CreateReader() {
Jake Ehrlich76e91102018-01-25 22:46:17 +0000320 // Right now we can only read ELF files so there's only one reader;
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000321 auto Out = llvm::make_unique<ELFReader>(StringRef(InputFilename));
Jake Ehrlich76e91102018-01-25 22:46:17 +0000322 // We need to set the default ElfType for output.
323 OutputElfType = Out->getElfType();
324 return std::move(Out);
Petr Hosek05a04cb2017-08-01 00:33:58 +0000325}
326
327int main(int argc, char **argv) {
Rui Ueyama197194b2018-04-13 18:26:06 +0000328 InitLLVM X(argc, argv);
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000329 cl::ParseCommandLineOptions(argc, argv, "llvm objcopy utility\n");
Petr Hosek05a04cb2017-08-01 00:33:58 +0000330 ToolName = argv[0];
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000331 if (InputFilename.empty()) {
332 cl::PrintHelpMessage();
333 return 2;
334 }
Jake Ehrlich76e91102018-01-25 22:46:17 +0000335
Jake Ehrlicha8c689e2018-04-12 00:40:50 +0000336 auto Reader = CreateReader();
337 auto Obj = Reader->create();
338 StringRef Output =
339 OutputFilename.getNumOccurrences() ? OutputFilename : InputFilename;
340 auto Writer = CreateWriter(*Obj, Output);
341 HandleArgs(*Obj, *Reader);
342 Writer->finalize();
343 Writer->write();
Petr Hosek05a04cb2017-08-01 00:33:58 +0000344}