File: | tools/llvm-objcopy/llvm-objcopy.cpp |
Warning: | line 424, column 8 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- llvm-objcopy.cpp ---------------------------------------------------===// | |||
2 | // | |||
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 | //===----------------------------------------------------------------------===// | |||
9 | ||||
10 | #include "llvm-objcopy.h" | |||
11 | #include "Object.h" | |||
12 | #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/Archive.h" | |||
17 | #include "llvm/Object/ArchiveWriter.h" | |||
18 | #include "llvm/Object/Binary.h" | |||
19 | #include "llvm/Object/ELFObjectFile.h" | |||
20 | #include "llvm/Object/ELFTypes.h" | |||
21 | #include "llvm/Object/Error.h" | |||
22 | #include "llvm/Option/Arg.h" | |||
23 | #include "llvm/Option/ArgList.h" | |||
24 | #include "llvm/Option/Option.h" | |||
25 | #include "llvm/Support/Casting.h" | |||
26 | #include "llvm/Support/CommandLine.h" | |||
27 | #include "llvm/Support/Compiler.h" | |||
28 | #include "llvm/Support/Error.h" | |||
29 | #include "llvm/Support/ErrorHandling.h" | |||
30 | #include "llvm/Support/ErrorOr.h" | |||
31 | #include "llvm/Support/FileOutputBuffer.h" | |||
32 | #include "llvm/Support/InitLLVM.h" | |||
33 | #include "llvm/Support/Path.h" | |||
34 | #include "llvm/Support/raw_ostream.h" | |||
35 | #include <algorithm> | |||
36 | #include <cassert> | |||
37 | #include <cstdlib> | |||
38 | #include <functional> | |||
39 | #include <iterator> | |||
40 | #include <memory> | |||
41 | #include <string> | |||
42 | #include <system_error> | |||
43 | #include <utility> | |||
44 | ||||
45 | using namespace llvm; | |||
46 | using namespace llvm::objcopy; | |||
47 | using namespace object; | |||
48 | using namespace ELF; | |||
49 | ||||
50 | namespace { | |||
51 | ||||
52 | enum ObjcopyID { | |||
53 | OBJCOPY_INVALID = 0, // This is not an option ID. | |||
54 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ | |||
55 | HELPTEXT, METAVAR, VALUES) \ | |||
56 | OBJCOPY_##ID, | |||
57 | #include "ObjcopyOpts.inc" | |||
58 | #undef OPTION | |||
59 | }; | |||
60 | ||||
61 | #define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE; | |||
62 | #include "ObjcopyOpts.inc" | |||
63 | #undef PREFIX | |||
64 | ||||
65 | static const opt::OptTable::Info ObjcopyInfoTable[] = { | |||
66 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ | |||
67 | HELPTEXT, METAVAR, VALUES) \ | |||
68 | {OBJCOPY_##PREFIX, \ | |||
69 | NAME, \ | |||
70 | HELPTEXT, \ | |||
71 | METAVAR, \ | |||
72 | OBJCOPY_##ID, \ | |||
73 | opt::Option::KIND##Class, \ | |||
74 | PARAM, \ | |||
75 | FLAGS, \ | |||
76 | OBJCOPY_##GROUP, \ | |||
77 | OBJCOPY_##ALIAS, \ | |||
78 | ALIASARGS, \ | |||
79 | VALUES}, | |||
80 | #include "ObjcopyOpts.inc" | |||
81 | #undef OPTION | |||
82 | }; | |||
83 | ||||
84 | class ObjcopyOptTable : public opt::OptTable { | |||
85 | public: | |||
86 | ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {} | |||
87 | }; | |||
88 | ||||
89 | enum StripID { | |||
90 | STRIP_INVALID = 0, // This is not an option ID. | |||
91 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ | |||
92 | HELPTEXT, METAVAR, VALUES) \ | |||
93 | STRIP_##ID, | |||
94 | #include "StripOpts.inc" | |||
95 | #undef OPTION | |||
96 | }; | |||
97 | ||||
98 | #define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE; | |||
99 | #include "StripOpts.inc" | |||
100 | #undef PREFIX | |||
101 | ||||
102 | static const opt::OptTable::Info StripInfoTable[] = { | |||
103 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ | |||
104 | HELPTEXT, METAVAR, VALUES) \ | |||
105 | {STRIP_##PREFIX, NAME, HELPTEXT, \ | |||
106 | METAVAR, STRIP_##ID, opt::Option::KIND##Class, \ | |||
107 | PARAM, FLAGS, STRIP_##GROUP, \ | |||
108 | STRIP_##ALIAS, ALIASARGS, VALUES}, | |||
109 | #include "StripOpts.inc" | |||
110 | #undef OPTION | |||
111 | }; | |||
112 | ||||
113 | class StripOptTable : public opt::OptTable { | |||
114 | public: | |||
115 | StripOptTable() : OptTable(StripInfoTable, true) {} | |||
116 | }; | |||
117 | ||||
118 | struct CopyConfig { | |||
119 | StringRef OutputFilename; | |||
120 | StringRef InputFilename; | |||
121 | StringRef OutputFormat; | |||
122 | StringRef InputFormat; | |||
123 | StringRef BinaryArch; | |||
124 | ||||
125 | StringRef SplitDWO; | |||
126 | StringRef AddGnuDebugLink; | |||
127 | std::vector<StringRef> ToRemove; | |||
128 | std::vector<StringRef> Keep; | |||
129 | std::vector<StringRef> OnlyKeep; | |||
130 | std::vector<StringRef> AddSection; | |||
131 | std::vector<StringRef> SymbolsToLocalize; | |||
132 | std::vector<StringRef> SymbolsToGlobalize; | |||
133 | std::vector<StringRef> SymbolsToWeaken; | |||
134 | std::vector<StringRef> SymbolsToRemove; | |||
135 | std::vector<StringRef> SymbolsToKeep; | |||
136 | StringMap<StringRef> SectionsToRename; | |||
137 | StringMap<StringRef> SymbolsToRename; | |||
138 | bool StripAll = false; | |||
139 | bool StripAllGNU = false; | |||
140 | bool StripDebug = false; | |||
141 | bool StripSections = false; | |||
142 | bool StripNonAlloc = false; | |||
143 | bool StripDWO = false; | |||
144 | bool StripUnneeded = false; | |||
145 | bool ExtractDWO = false; | |||
146 | bool LocalizeHidden = false; | |||
147 | bool Weaken = false; | |||
148 | bool DiscardAll = false; | |||
149 | bool OnlyKeepDebug = false; | |||
150 | bool KeepFileSymbols = false; | |||
151 | }; | |||
152 | ||||
153 | using SectionPred = std::function<bool(const SectionBase &Sec)>; | |||
154 | ||||
155 | } // namespace | |||
156 | ||||
157 | namespace llvm { | |||
158 | namespace objcopy { | |||
159 | ||||
160 | // The name this program was invoked as. | |||
161 | StringRef ToolName; | |||
162 | ||||
163 | LLVM_ATTRIBUTE_NORETURN__attribute__((noreturn)) void error(Twine Message) { | |||
164 | errs() << ToolName << ": " << Message << ".\n"; | |||
165 | errs().flush(); | |||
166 | exit(1); | |||
167 | } | |||
168 | ||||
169 | LLVM_ATTRIBUTE_NORETURN__attribute__((noreturn)) void reportError(StringRef File, std::error_code EC) { | |||
170 | assert(EC)(static_cast <bool> (EC) ? void (0) : __assert_fail ("EC" , "/build/llvm-toolchain-snapshot-7~svn337957/tools/llvm-objcopy/llvm-objcopy.cpp" , 170, __extension__ __PRETTY_FUNCTION__)); | |||
171 | errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n"; | |||
172 | exit(1); | |||
173 | } | |||
174 | ||||
175 | LLVM_ATTRIBUTE_NORETURN__attribute__((noreturn)) void reportError(StringRef File, Error E) { | |||
176 | assert(E)(static_cast <bool> (E) ? void (0) : __assert_fail ("E" , "/build/llvm-toolchain-snapshot-7~svn337957/tools/llvm-objcopy/llvm-objcopy.cpp" , 176, __extension__ __PRETTY_FUNCTION__)); | |||
177 | std::string Buf; | |||
178 | raw_string_ostream OS(Buf); | |||
179 | logAllUnhandledErrors(std::move(E), OS, ""); | |||
180 | OS.flush(); | |||
181 | errs() << ToolName << ": '" << File << "': " << Buf; | |||
182 | exit(1); | |||
183 | } | |||
184 | ||||
185 | } // end namespace objcopy | |||
186 | } // end namespace llvm | |||
187 | ||||
188 | static bool IsDWOSection(const SectionBase &Sec) { | |||
189 | return Sec.Name.endswith(".dwo"); | |||
190 | } | |||
191 | ||||
192 | static bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { | |||
193 | // We can't remove the section header string table. | |||
194 | if (&Sec == Obj.SectionNames) | |||
195 | return false; | |||
196 | // Short of keeping the string table we want to keep everything that is a DWO | |||
197 | // section and remove everything else. | |||
198 | return !IsDWOSection(Sec); | |||
199 | } | |||
200 | ||||
201 | static std::unique_ptr<Writer> CreateWriter(const CopyConfig &Config, | |||
202 | Object &Obj, Buffer &Buf, | |||
203 | ElfType OutputElfType) { | |||
204 | if (Config.OutputFormat == "binary") { | |||
205 | return llvm::make_unique<BinaryWriter>(Obj, Buf); | |||
206 | } | |||
207 | // Depending on the initial ELFT and OutputFormat we need a different Writer. | |||
208 | switch (OutputElfType) { | |||
209 | case ELFT_ELF32LE: | |||
210 | return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, | |||
211 | !Config.StripSections); | |||
212 | case ELFT_ELF64LE: | |||
213 | return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, | |||
214 | !Config.StripSections); | |||
215 | case ELFT_ELF32BE: | |||
216 | return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, | |||
217 | !Config.StripSections); | |||
218 | case ELFT_ELF64BE: | |||
219 | return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, | |||
220 | !Config.StripSections); | |||
221 | } | |||
222 | llvm_unreachable("Invalid output format")::llvm::llvm_unreachable_internal("Invalid output format", "/build/llvm-toolchain-snapshot-7~svn337957/tools/llvm-objcopy/llvm-objcopy.cpp" , 222); | |||
223 | } | |||
224 | ||||
225 | static void SplitDWOToFile(const CopyConfig &Config, const Reader &Reader, | |||
226 | StringRef File, ElfType OutputElfType) { | |||
227 | auto DWOFile = Reader.create(); | |||
228 | DWOFile->removeSections( | |||
229 | [&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); }); | |||
230 | FileBuffer FB(File); | |||
231 | auto Writer = CreateWriter(Config, *DWOFile, FB, OutputElfType); | |||
232 | Writer->finalize(); | |||
233 | Writer->write(); | |||
234 | } | |||
235 | ||||
236 | // This function handles the high level operations of GNU objcopy including | |||
237 | // handling command line options. It's important to outline certain properties | |||
238 | // we expect to hold of the command line operations. Any operation that "keeps" | |||
239 | // should keep regardless of a remove. Additionally any removal should respect | |||
240 | // any previous removals. Lastly whether or not something is removed shouldn't | |||
241 | // depend a) on the order the options occur in or b) on some opaque priority | |||
242 | // system. The only priority is that keeps/copies overrule removes. | |||
243 | static void HandleArgs(const CopyConfig &Config, Object &Obj, | |||
244 | const Reader &Reader, ElfType OutputElfType) { | |||
245 | ||||
246 | if (!Config.SplitDWO.empty()) { | |||
247 | SplitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType); | |||
248 | } | |||
249 | ||||
250 | // TODO: update or remove symbols only if there is an option that affects | |||
251 | // them. | |||
252 | if (Obj.SymbolTable) { | |||
253 | Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { | |||
254 | if ((Config.LocalizeHidden && | |||
255 | (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || | |||
256 | (!Config.SymbolsToLocalize.empty() && | |||
257 | is_contained(Config.SymbolsToLocalize, Sym.Name))) | |||
258 | Sym.Binding = STB_LOCAL; | |||
259 | ||||
260 | if (!Config.SymbolsToGlobalize.empty() && | |||
261 | is_contained(Config.SymbolsToGlobalize, Sym.Name)) | |||
262 | Sym.Binding = STB_GLOBAL; | |||
263 | ||||
264 | if (!Config.SymbolsToWeaken.empty() && | |||
265 | is_contained(Config.SymbolsToWeaken, Sym.Name) && | |||
266 | Sym.Binding == STB_GLOBAL) | |||
267 | Sym.Binding = STB_WEAK; | |||
268 | ||||
269 | if (Config.Weaken && Sym.Binding == STB_GLOBAL && | |||
270 | Sym.getShndx() != SHN_UNDEF) | |||
271 | Sym.Binding = STB_WEAK; | |||
272 | ||||
273 | const auto I = Config.SymbolsToRename.find(Sym.Name); | |||
274 | if (I != Config.SymbolsToRename.end()) | |||
275 | Sym.Name = I->getValue(); | |||
276 | }); | |||
277 | ||||
278 | // The purpose of this loop is to mark symbols referenced by sections | |||
279 | // (like GroupSection or RelocationSection). This way, we know which | |||
280 | // symbols are still 'needed' and wich are not. | |||
281 | if (Config.StripUnneeded) { | |||
282 | for (auto &Section : Obj.sections()) | |||
283 | Section.markSymbols(); | |||
284 | } | |||
285 | ||||
286 | Obj.removeSymbols([&](const Symbol &Sym) { | |||
287 | if ((!Config.SymbolsToKeep.empty() && | |||
288 | is_contained(Config.SymbolsToKeep, Sym.Name)) || | |||
289 | (Config.KeepFileSymbols && Sym.Type == STT_FILE)) | |||
290 | return false; | |||
291 | ||||
292 | if (Config.DiscardAll && Sym.Binding == STB_LOCAL && | |||
293 | Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE && | |||
294 | Sym.Type != STT_SECTION) | |||
295 | return true; | |||
296 | ||||
297 | if (Config.StripAll || Config.StripAllGNU) | |||
298 | return true; | |||
299 | ||||
300 | if (!Config.SymbolsToRemove.empty() && | |||
301 | is_contained(Config.SymbolsToRemove, Sym.Name)) { | |||
302 | return true; | |||
303 | } | |||
304 | ||||
305 | if (Config.StripUnneeded && !Sym.Referenced && | |||
306 | (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) && | |||
307 | Sym.Type != STT_FILE && Sym.Type != STT_SECTION) | |||
308 | return true; | |||
309 | ||||
310 | return false; | |||
311 | }); | |||
312 | } | |||
313 | ||||
314 | SectionPred RemovePred = [](const SectionBase &) { return false; }; | |||
315 | ||||
316 | // Removes: | |||
317 | if (!Config.ToRemove.empty()) { | |||
318 | RemovePred = [&Config](const SectionBase &Sec) { | |||
319 | return std::find(std::begin(Config.ToRemove), std::end(Config.ToRemove), | |||
320 | Sec.Name) != std::end(Config.ToRemove); | |||
321 | }; | |||
322 | } | |||
323 | ||||
324 | if (Config.StripDWO || !Config.SplitDWO.empty()) | |||
325 | RemovePred = [RemovePred](const SectionBase &Sec) { | |||
326 | return IsDWOSection(Sec) || RemovePred(Sec); | |||
327 | }; | |||
328 | ||||
329 | if (Config.ExtractDWO) | |||
330 | RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { | |||
331 | return OnlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); | |||
332 | }; | |||
333 | ||||
334 | if (Config.StripAllGNU) | |||
335 | RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { | |||
336 | if (RemovePred(Sec)) | |||
337 | return true; | |||
338 | if ((Sec.Flags & SHF_ALLOC) != 0) | |||
339 | return false; | |||
340 | if (&Sec == Obj.SectionNames) | |||
341 | return false; | |||
342 | switch (Sec.Type) { | |||
343 | case SHT_SYMTAB: | |||
344 | case SHT_REL: | |||
345 | case SHT_RELA: | |||
346 | case SHT_STRTAB: | |||
347 | return true; | |||
348 | } | |||
349 | return Sec.Name.startswith(".debug"); | |||
350 | }; | |||
351 | ||||
352 | if (Config.StripSections) { | |||
353 | RemovePred = [RemovePred](const SectionBase &Sec) { | |||
354 | return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; | |||
355 | }; | |||
356 | } | |||
357 | ||||
358 | if (Config.StripDebug) { | |||
359 | RemovePred = [RemovePred](const SectionBase &Sec) { | |||
360 | return RemovePred(Sec) || Sec.Name.startswith(".debug"); | |||
361 | }; | |||
362 | } | |||
363 | ||||
364 | if (Config.StripNonAlloc) | |||
365 | RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { | |||
366 | if (RemovePred(Sec)) | |||
367 | return true; | |||
368 | if (&Sec == Obj.SectionNames) | |||
369 | return false; | |||
370 | return (Sec.Flags & SHF_ALLOC) == 0; | |||
371 | }; | |||
372 | ||||
373 | if (Config.StripAll) | |||
374 | RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { | |||
375 | if (RemovePred(Sec)) | |||
376 | return true; | |||
377 | if (&Sec == Obj.SectionNames) | |||
378 | return false; | |||
379 | if (Sec.Name.startswith(".gnu.warning")) | |||
380 | return false; | |||
381 | return (Sec.Flags & SHF_ALLOC) == 0; | |||
382 | }; | |||
383 | ||||
384 | // Explicit copies: | |||
385 | if (!Config.OnlyKeep.empty()) { | |||
386 | RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { | |||
387 | // Explicitly keep these sections regardless of previous removes. | |||
388 | if (std::find(std::begin(Config.OnlyKeep), std::end(Config.OnlyKeep), | |||
389 | Sec.Name) != std::end(Config.OnlyKeep)) | |||
390 | return false; | |||
391 | ||||
392 | // Allow all implicit removes. | |||
393 | if (RemovePred(Sec)) | |||
394 | return true; | |||
395 | ||||
396 | // Keep special sections. | |||
397 | if (Obj.SectionNames == &Sec) | |||
398 | return false; | |||
399 | if (Obj.SymbolTable == &Sec || Obj.SymbolTable->getStrTab() == &Sec) | |||
400 | return false; | |||
401 | ||||
402 | // Remove everything else. | |||
403 | return true; | |||
404 | }; | |||
405 | } | |||
406 | ||||
407 | if (!Config.Keep.empty()) { | |||
408 | RemovePred = [Config, RemovePred](const SectionBase &Sec) { | |||
409 | // Explicitly keep these sections regardless of previous removes. | |||
410 | if (std::find(std::begin(Config.Keep), std::end(Config.Keep), Sec.Name) != | |||
411 | std::end(Config.Keep)) | |||
412 | return false; | |||
413 | // Otherwise defer to RemovePred. | |||
414 | return RemovePred(Sec); | |||
415 | }; | |||
416 | } | |||
417 | ||||
418 | // This has to be the last predicate assignment. | |||
419 | // If the option --keep-symbol has been specified | |||
420 | // and at least one of those symbols is present | |||
421 | // (equivalently, the updated symbol table is not empty) | |||
422 | // the symbol table and the string table should not be removed. | |||
423 | if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) && | |||
424 | !Obj.SymbolTable->empty()) { | |||
| ||||
425 | RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { | |||
426 | if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) | |||
427 | return false; | |||
428 | return RemovePred(Sec); | |||
429 | }; | |||
430 | } | |||
431 | ||||
432 | Obj.removeSections(RemovePred); | |||
433 | ||||
434 | if (!Config.SectionsToRename.empty()) { | |||
435 | for (auto &Sec : Obj.sections()) { | |||
436 | const auto Iter = Config.SectionsToRename.find(Sec.Name); | |||
437 | if (Iter != Config.SectionsToRename.end()) | |||
438 | Sec.Name = Iter->second; | |||
439 | } | |||
440 | } | |||
441 | ||||
442 | if (!Config.AddSection.empty()) { | |||
443 | for (const auto &Flag : Config.AddSection) { | |||
444 | auto SecPair = Flag.split("="); | |||
445 | auto SecName = SecPair.first; | |||
446 | auto File = SecPair.second; | |||
447 | auto BufOrErr = MemoryBuffer::getFile(File); | |||
448 | if (!BufOrErr) | |||
449 | reportError(File, BufOrErr.getError()); | |||
450 | auto Buf = std::move(*BufOrErr); | |||
451 | auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart()); | |||
452 | auto BufSize = Buf->getBufferSize(); | |||
453 | Obj.addSection<OwnedDataSection>(SecName, | |||
454 | ArrayRef<uint8_t>(BufPtr, BufSize)); | |||
455 | } | |||
456 | } | |||
457 | ||||
458 | if (!Config.AddGnuDebugLink.empty()) | |||
459 | Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink); | |||
460 | } | |||
461 | ||||
462 | static void ExecuteElfObjcopyOnBinary(const CopyConfig &Config, Binary &Binary, | |||
463 | Buffer &Out) { | |||
464 | ELFReader Reader(&Binary); | |||
465 | std::unique_ptr<Object> Obj = Reader.create(); | |||
466 | ||||
467 | HandleArgs(Config, *Obj, Reader, Reader.getElfType()); | |||
468 | ||||
469 | std::unique_ptr<Writer> Writer = | |||
470 | CreateWriter(Config, *Obj, Out, Reader.getElfType()); | |||
471 | Writer->finalize(); | |||
472 | Writer->write(); | |||
473 | } | |||
474 | ||||
475 | // For regular archives this function simply calls llvm::writeArchive, | |||
476 | // For thin archives it writes the archive file itself as well as its members. | |||
477 | static Error deepWriteArchive(StringRef ArcName, | |||
478 | ArrayRef<NewArchiveMember> NewMembers, | |||
479 | bool WriteSymtab, object::Archive::Kind Kind, | |||
480 | bool Deterministic, bool Thin) { | |||
481 | Error E = | |||
482 | writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin); | |||
483 | if (!Thin || E) | |||
484 | return E; | |||
485 | for (const NewArchiveMember &Member : NewMembers) { | |||
486 | // Internally, FileBuffer will use the buffer created by | |||
487 | // FileOutputBuffer::create, for regular files (that is the case for | |||
488 | // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer. | |||
489 | // OnDiskBuffer uses a temporary file and then renames it. So in reality | |||
490 | // there is no inefficiency / duplicated in-memory buffers in this case. For | |||
491 | // now in-memory buffers can not be completely avoided since | |||
492 | // NewArchiveMember still requires them even though writeArchive does not | |||
493 | // write them on disk. | |||
494 | FileBuffer FB(Member.MemberName); | |||
495 | FB.allocate(Member.Buf->getBufferSize()); | |||
496 | std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(), | |||
497 | FB.getBufferStart()); | |||
498 | if (auto E = FB.commit()) | |||
499 | return E; | |||
500 | } | |||
501 | return Error::success(); | |||
502 | } | |||
503 | ||||
504 | static void ExecuteElfObjcopyOnArchive(const CopyConfig &Config, const Archive &Ar) { | |||
505 | std::vector<NewArchiveMember> NewArchiveMembers; | |||
506 | Error Err = Error::success(); | |||
507 | for (const Archive::Child &Child : Ar.children(Err)) { | |||
508 | Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); | |||
509 | if (!ChildOrErr) | |||
510 | reportError(Ar.getFileName(), ChildOrErr.takeError()); | |||
511 | Expected<StringRef> ChildNameOrErr = Child.getName(); | |||
512 | if (!ChildNameOrErr) | |||
513 | reportError(Ar.getFileName(), ChildNameOrErr.takeError()); | |||
514 | ||||
515 | MemBuffer MB(ChildNameOrErr.get()); | |||
516 | ExecuteElfObjcopyOnBinary(Config, **ChildOrErr, MB); | |||
517 | ||||
518 | Expected<NewArchiveMember> Member = | |||
519 | NewArchiveMember::getOldMember(Child, true); | |||
520 | if (!Member) | |||
521 | reportError(Ar.getFileName(), Member.takeError()); | |||
522 | Member->Buf = MB.releaseMemoryBuffer(); | |||
523 | Member->MemberName = Member->Buf->getBufferIdentifier(); | |||
524 | NewArchiveMembers.push_back(std::move(*Member)); | |||
525 | } | |||
526 | ||||
527 | if (Err) | |||
528 | reportError(Config.InputFilename, std::move(Err)); | |||
529 | if (Error E = | |||
530 | deepWriteArchive(Config.OutputFilename, NewArchiveMembers, | |||
531 | Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin())) | |||
532 | reportError(Config.OutputFilename, std::move(E)); | |||
533 | } | |||
534 | ||||
535 | static void ExecuteElfObjcopy(const CopyConfig &Config) { | |||
536 | Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr = | |||
537 | createBinary(Config.InputFilename); | |||
538 | if (!BinaryOrErr) | |||
| ||||
539 | reportError(Config.InputFilename, BinaryOrErr.takeError()); | |||
540 | ||||
541 | if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) | |||
542 | return ExecuteElfObjcopyOnArchive(Config, *Ar); | |||
543 | ||||
544 | FileBuffer FB(Config.OutputFilename); | |||
545 | ExecuteElfObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB); | |||
546 | } | |||
547 | ||||
548 | // ParseObjcopyOptions returns the config and sets the input arguments. If a | |||
549 | // help flag is set then ParseObjcopyOptions will print the help messege and | |||
550 | // exit. | |||
551 | static CopyConfig ParseObjcopyOptions(ArrayRef<const char *> ArgsArr) { | |||
552 | ObjcopyOptTable T; | |||
553 | unsigned MissingArgumentIndex, MissingArgumentCount; | |||
554 | llvm::opt::InputArgList InputArgs = | |||
555 | T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); | |||
556 | ||||
557 | if (InputArgs.size() == 0) { | |||
558 | T.PrintHelp(errs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool"); | |||
559 | exit(1); | |||
560 | } | |||
561 | ||||
562 | if (InputArgs.hasArg(OBJCOPY_help)) { | |||
563 | T.PrintHelp(outs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool"); | |||
564 | exit(0); | |||
565 | } | |||
566 | ||||
567 | SmallVector<const char *, 2> Positional; | |||
568 | ||||
569 | for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN)) | |||
570 | error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); | |||
571 | ||||
572 | for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT)) | |||
573 | Positional.push_back(Arg->getValue()); | |||
574 | ||||
575 | if (Positional.empty()) | |||
576 | error("No input file specified"); | |||
577 | ||||
578 | if (Positional.size() > 2) | |||
579 | error("Too many positional arguments"); | |||
580 | ||||
581 | CopyConfig Config; | |||
582 | Config.InputFilename = Positional[0]; | |||
583 | Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; | |||
584 | Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target); | |||
585 | Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target); | |||
586 | Config.BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture); | |||
587 | ||||
588 | Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); | |||
589 | Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); | |||
590 | ||||
591 | for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) { | |||
592 | if (!StringRef(Arg->getValue()).contains('=')) | |||
593 | error("Bad format for --redefine-sym"); | |||
594 | auto Old2New = StringRef(Arg->getValue()).split('='); | |||
595 | if (!Config.SymbolsToRename.insert(Old2New).second) | |||
596 | error("Multiple redefinition of symbol " + Old2New.first); | |||
597 | } | |||
598 | ||||
599 | for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) { | |||
600 | if (!StringRef(Arg->getValue()).contains('=')) | |||
601 | error("Bad format for --rename-section"); | |||
602 | auto Old2New = StringRef(Arg->getValue()).split('='); | |||
603 | if (!Config.SectionsToRename.insert(Old2New).second) | |||
604 | error("Already have a section rename for " + Old2New.first); | |||
605 | } | |||
606 | ||||
607 | for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section)) | |||
608 | Config.ToRemove.push_back(Arg->getValue()); | |||
609 | for (auto Arg : InputArgs.filtered(OBJCOPY_keep)) | |||
610 | Config.Keep.push_back(Arg->getValue()); | |||
611 | for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep)) | |||
612 | Config.OnlyKeep.push_back(Arg->getValue()); | |||
613 | for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) | |||
614 | Config.AddSection.push_back(Arg->getValue()); | |||
615 | Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all); | |||
616 | Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu); | |||
617 | Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug); | |||
618 | Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo); | |||
619 | Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections); | |||
620 | Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); | |||
621 | Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded); | |||
622 | Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); | |||
623 | Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); | |||
624 | Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken); | |||
625 | Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all); | |||
626 | Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug); | |||
627 | Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols); | |||
628 | for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) | |||
629 | Config.SymbolsToLocalize.push_back(Arg->getValue()); | |||
630 | for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) | |||
631 | Config.SymbolsToGlobalize.push_back(Arg->getValue()); | |||
632 | for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol)) | |||
633 | Config.SymbolsToWeaken.push_back(Arg->getValue()); | |||
634 | for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol)) | |||
635 | Config.SymbolsToRemove.push_back(Arg->getValue()); | |||
636 | for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol)) | |||
637 | Config.SymbolsToKeep.push_back(Arg->getValue()); | |||
638 | ||||
639 | return Config; | |||
640 | } | |||
641 | ||||
642 | // ParseStripOptions returns the config and sets the input arguments. If a | |||
643 | // help flag is set then ParseStripOptions will print the help messege and | |||
644 | // exit. | |||
645 | static CopyConfig ParseStripOptions(ArrayRef<const char *> ArgsArr) { | |||
646 | StripOptTable T; | |||
647 | unsigned MissingArgumentIndex, MissingArgumentCount; | |||
648 | llvm::opt::InputArgList InputArgs = | |||
649 | T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); | |||
650 | ||||
651 | if (InputArgs.size() == 0) { | |||
652 | T.PrintHelp(errs(), "llvm-strip <input> [ <output> ]", "strip tool"); | |||
653 | exit(1); | |||
654 | } | |||
655 | ||||
656 | if (InputArgs.hasArg(STRIP_help)) { | |||
657 | T.PrintHelp(outs(), "llvm-strip <input> [ <output> ]", "strip tool"); | |||
658 | exit(0); | |||
659 | } | |||
660 | ||||
661 | SmallVector<const char *, 2> Positional; | |||
662 | for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN)) | |||
663 | error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); | |||
664 | for (auto Arg : InputArgs.filtered(STRIP_INPUT)) | |||
665 | Positional.push_back(Arg->getValue()); | |||
666 | ||||
667 | if (Positional.empty()) | |||
668 | error("No input file specified"); | |||
669 | ||||
670 | if (Positional.size() > 2) | |||
671 | error("Support for multiple input files is not implemented yet"); | |||
672 | ||||
673 | CopyConfig Config; | |||
674 | Config.InputFilename = Positional[0]; | |||
675 | Config.OutputFilename = | |||
676 | InputArgs.getLastArgValue(STRIP_output, Positional[0]); | |||
677 | ||||
678 | Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); | |||
679 | ||||
680 | Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all); | |||
681 | Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded); | |||
682 | Config.StripAll = InputArgs.hasArg(STRIP_strip_all); | |||
683 | ||||
684 | if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll) | |||
685 | Config.StripAll = true; | |||
686 | ||||
687 | for (auto Arg : InputArgs.filtered(STRIP_remove_section)) | |||
688 | Config.ToRemove.push_back(Arg->getValue()); | |||
689 | ||||
690 | for (auto Arg : InputArgs.filtered(STRIP_keep_symbol)) | |||
691 | Config.SymbolsToKeep.push_back(Arg->getValue()); | |||
692 | ||||
693 | return Config; | |||
694 | } | |||
695 | ||||
696 | int main(int argc, char **argv) { | |||
697 | InitLLVM X(argc, argv); | |||
698 | ToolName = argv[0]; | |||
699 | CopyConfig Config; | |||
700 | if (sys::path::stem(ToolName).endswith_lower("strip")) | |||
701 | Config = ParseStripOptions(makeArrayRef(argv + 1, argc)); | |||
702 | else | |||
703 | Config = ParseObjcopyOptions(makeArrayRef(argv + 1, argc)); | |||
704 | ExecuteElfObjcopy(Config); | |||
705 | } |