1 | //===- ObjcopyOptions.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 "ObjcopyOptions.h" |
10 | #include "llvm/ADT/SmallVector.h" |
11 | #include "llvm/ADT/StringExtras.h" |
12 | #include "llvm/ADT/StringRef.h" |
13 | #include "llvm/ADT/StringSwitch.h" |
14 | #include "llvm/BinaryFormat/COFF.h" |
15 | #include "llvm/ObjCopy/CommonConfig.h" |
16 | #include "llvm/ObjCopy/ConfigManager.h" |
17 | #include "llvm/ObjCopy/MachO/MachOConfig.h" |
18 | #include "llvm/Object/Binary.h" |
19 | #include "llvm/Option/Arg.h" |
20 | #include "llvm/Option/ArgList.h" |
21 | #include "llvm/Support/CRC.h" |
22 | #include "llvm/Support/CommandLine.h" |
23 | #include "llvm/Support/Compression.h" |
24 | #include "llvm/Support/Errc.h" |
25 | #include "llvm/Support/Error.h" |
26 | #include "llvm/Support/MemoryBuffer.h" |
27 | |
28 | using namespace llvm; |
29 | using namespace llvm::objcopy; |
30 | using namespace llvm::object; |
31 | using namespace llvm::opt; |
32 | |
33 | namespace { |
34 | enum ObjcopyID { |
35 | OBJCOPY_INVALID = 0, // This is not an option ID. |
36 | #define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OBJCOPY_, __VA_ARGS__), |
37 | #include "ObjcopyOpts.inc" |
38 | #undef OPTION |
39 | }; |
40 | |
41 | namespace objcopy_opt { |
42 | #define PREFIX(NAME, VALUE) \ |
43 | static constexpr StringLiteral NAME##_init[] = VALUE; \ |
44 | static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ |
45 | std::size(NAME##_init) - 1); |
46 | #include "ObjcopyOpts.inc" |
47 | #undef PREFIX |
48 | |
49 | static constexpr opt::OptTable::Info ObjcopyInfoTable[] = { |
50 | #define OPTION(...) \ |
51 | LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OBJCOPY_, __VA_ARGS__), |
52 | #include "ObjcopyOpts.inc" |
53 | #undef OPTION |
54 | }; |
55 | } // namespace objcopy_opt |
56 | |
57 | class ObjcopyOptTable : public opt::GenericOptTable { |
58 | public: |
59 | ObjcopyOptTable() : opt::GenericOptTable(objcopy_opt::ObjcopyInfoTable) { |
60 | setGroupedShortOptions(true); |
61 | } |
62 | }; |
63 | |
64 | enum InstallNameToolID { |
65 | INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID. |
66 | #define OPTION(...) \ |
67 | LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(INSTALL_NAME_TOOL_, __VA_ARGS__), |
68 | #include "InstallNameToolOpts.inc" |
69 | #undef OPTION |
70 | }; |
71 | |
72 | namespace install_name_tool { |
73 | |
74 | #define PREFIX(NAME, VALUE) \ |
75 | static constexpr StringLiteral NAME##_init[] = VALUE; \ |
76 | static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ |
77 | std::size(NAME##_init) - 1); |
78 | #include "InstallNameToolOpts.inc" |
79 | #undef PREFIX |
80 | |
81 | static constexpr opt::OptTable::Info InstallNameToolInfoTable[] = { |
82 | #define OPTION(...) \ |
83 | LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(INSTALL_NAME_TOOL_, __VA_ARGS__), |
84 | #include "InstallNameToolOpts.inc" |
85 | #undef OPTION |
86 | }; |
87 | } // namespace install_name_tool |
88 | |
89 | class InstallNameToolOptTable : public opt::GenericOptTable { |
90 | public: |
91 | InstallNameToolOptTable() |
92 | : GenericOptTable(install_name_tool::InstallNameToolInfoTable) {} |
93 | }; |
94 | |
95 | enum BitcodeStripID { |
96 | BITCODE_STRIP_INVALID = 0, // This is not an option ID. |
97 | #define OPTION(...) \ |
98 | LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(BITCODE_STRIP_, __VA_ARGS__), |
99 | #include "BitcodeStripOpts.inc" |
100 | #undef OPTION |
101 | }; |
102 | |
103 | namespace bitcode_strip { |
104 | |
105 | #define PREFIX(NAME, VALUE) \ |
106 | static constexpr StringLiteral NAME##_init[] = VALUE; \ |
107 | static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ |
108 | std::size(NAME##_init) - 1); |
109 | #include "BitcodeStripOpts.inc" |
110 | #undef PREFIX |
111 | |
112 | static constexpr opt::OptTable::Info BitcodeStripInfoTable[] = { |
113 | #define OPTION(...) \ |
114 | LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(BITCODE_STRIP_, __VA_ARGS__), |
115 | #include "BitcodeStripOpts.inc" |
116 | #undef OPTION |
117 | }; |
118 | } // namespace bitcode_strip |
119 | |
120 | class BitcodeStripOptTable : public opt::GenericOptTable { |
121 | public: |
122 | BitcodeStripOptTable() |
123 | : opt::GenericOptTable(bitcode_strip::BitcodeStripInfoTable) {} |
124 | }; |
125 | |
126 | enum StripID { |
127 | STRIP_INVALID = 0, // This is not an option ID. |
128 | #define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(STRIP_, __VA_ARGS__), |
129 | #include "StripOpts.inc" |
130 | #undef OPTION |
131 | }; |
132 | |
133 | namespace strip { |
134 | #define PREFIX(NAME, VALUE) \ |
135 | static constexpr StringLiteral NAME##_init[] = VALUE; \ |
136 | static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ |
137 | std::size(NAME##_init) - 1); |
138 | #include "StripOpts.inc" |
139 | #undef PREFIX |
140 | |
141 | static constexpr opt::OptTable::Info StripInfoTable[] = { |
142 | #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(STRIP_, __VA_ARGS__), |
143 | #include "StripOpts.inc" |
144 | #undef OPTION |
145 | }; |
146 | } // namespace strip |
147 | |
148 | class StripOptTable : public opt::GenericOptTable { |
149 | public: |
150 | StripOptTable() : GenericOptTable(strip::StripInfoTable) { |
151 | setGroupedShortOptions(true); |
152 | } |
153 | }; |
154 | |
155 | } // namespace |
156 | |
157 | static SectionFlag parseSectionRenameFlag(StringRef SectionName) { |
158 | return llvm::StringSwitch<SectionFlag>(SectionName) |
159 | .CaseLower(S: "alloc" , Value: SectionFlag::SecAlloc) |
160 | .CaseLower(S: "load" , Value: SectionFlag::SecLoad) |
161 | .CaseLower(S: "noload" , Value: SectionFlag::SecNoload) |
162 | .CaseLower(S: "readonly" , Value: SectionFlag::SecReadonly) |
163 | .CaseLower(S: "debug" , Value: SectionFlag::SecDebug) |
164 | .CaseLower(S: "code" , Value: SectionFlag::SecCode) |
165 | .CaseLower(S: "data" , Value: SectionFlag::SecData) |
166 | .CaseLower(S: "rom" , Value: SectionFlag::SecRom) |
167 | .CaseLower(S: "merge" , Value: SectionFlag::SecMerge) |
168 | .CaseLower(S: "strings" , Value: SectionFlag::SecStrings) |
169 | .CaseLower(S: "contents" , Value: SectionFlag::SecContents) |
170 | .CaseLower(S: "share" , Value: SectionFlag::SecShare) |
171 | .CaseLower(S: "exclude" , Value: SectionFlag::SecExclude) |
172 | .CaseLower(S: "large" , Value: SectionFlag::SecLarge) |
173 | .Default(Value: SectionFlag::SecNone); |
174 | } |
175 | |
176 | static Expected<SectionFlag> |
177 | parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) { |
178 | SectionFlag ParsedFlags = SectionFlag::SecNone; |
179 | for (StringRef Flag : SectionFlags) { |
180 | SectionFlag ParsedFlag = parseSectionRenameFlag(SectionName: Flag); |
181 | if (ParsedFlag == SectionFlag::SecNone) |
182 | return createStringError( |
183 | EC: errc::invalid_argument, |
184 | Fmt: "unrecognized section flag '%s'. Flags supported for GNU " |
185 | "compatibility: alloc, load, noload, readonly, exclude, debug, " |
186 | "code, data, rom, share, contents, merge, strings, large" , |
187 | Vals: Flag.str().c_str()); |
188 | ParsedFlags |= ParsedFlag; |
189 | } |
190 | |
191 | return ParsedFlags; |
192 | } |
193 | |
194 | static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) { |
195 | if (!FlagValue.contains(C: '=')) |
196 | return createStringError(EC: errc::invalid_argument, |
197 | S: "bad format for --rename-section: missing '='" ); |
198 | |
199 | // Initial split: ".foo" = ".bar,f1,f2,..." |
200 | auto Old2New = FlagValue.split(Separator: '='); |
201 | SectionRename SR; |
202 | SR.OriginalName = Old2New.first; |
203 | |
204 | // Flags split: ".bar" "f1" "f2" ... |
205 | SmallVector<StringRef, 6> NameAndFlags; |
206 | Old2New.second.split(A&: NameAndFlags, Separator: ','); |
207 | SR.NewName = NameAndFlags[0]; |
208 | |
209 | if (NameAndFlags.size() > 1) { |
210 | Expected<SectionFlag> ParsedFlagSet = |
211 | parseSectionFlagSet(SectionFlags: ArrayRef(NameAndFlags).drop_front()); |
212 | if (!ParsedFlagSet) |
213 | return ParsedFlagSet.takeError(); |
214 | SR.NewFlags = *ParsedFlagSet; |
215 | } |
216 | |
217 | return SR; |
218 | } |
219 | |
220 | static Expected<std::pair<StringRef, uint64_t>> |
221 | parseSetSectionAttribute(StringRef Option, StringRef FlagValue) { |
222 | if (!FlagValue.contains(C: '=')) |
223 | return make_error<StringError>(Args: "bad format for " + Option + ": missing '='" , |
224 | Args: errc::invalid_argument); |
225 | auto Split = StringRef(FlagValue).split(Separator: '='); |
226 | if (Split.first.empty()) |
227 | return make_error<StringError>(Args: "bad format for " + Option + |
228 | ": missing section name" , |
229 | Args: errc::invalid_argument); |
230 | uint64_t Value; |
231 | if (Split.second.getAsInteger(Radix: 0, Result&: Value)) |
232 | return make_error<StringError>(Args: "invalid value for " + Option + ": '" + |
233 | Split.second + "'" , |
234 | Args: errc::invalid_argument); |
235 | return std::make_pair(x&: Split.first, y&: Value); |
236 | } |
237 | |
238 | static Expected<SectionFlagsUpdate> |
239 | parseSetSectionFlagValue(StringRef FlagValue) { |
240 | if (!StringRef(FlagValue).contains(C: '=')) |
241 | return createStringError(EC: errc::invalid_argument, |
242 | S: "bad format for --set-section-flags: missing '='" ); |
243 | |
244 | // Initial split: ".foo" = "f1,f2,..." |
245 | auto Section2Flags = StringRef(FlagValue).split(Separator: '='); |
246 | SectionFlagsUpdate SFU; |
247 | SFU.Name = Section2Flags.first; |
248 | |
249 | // Flags split: "f1" "f2" ... |
250 | SmallVector<StringRef, 6> SectionFlags; |
251 | Section2Flags.second.split(A&: SectionFlags, Separator: ','); |
252 | Expected<SectionFlag> ParsedFlagSet = parseSectionFlagSet(SectionFlags); |
253 | if (!ParsedFlagSet) |
254 | return ParsedFlagSet.takeError(); |
255 | SFU.NewFlags = *ParsedFlagSet; |
256 | |
257 | return SFU; |
258 | } |
259 | |
260 | static Expected<uint8_t> parseVisibilityType(StringRef VisType) { |
261 | const uint8_t Invalid = 0xff; |
262 | uint8_t type = StringSwitch<uint8_t>(VisType) |
263 | .Case(S: "default" , Value: ELF::STV_DEFAULT) |
264 | .Case(S: "hidden" , Value: ELF::STV_HIDDEN) |
265 | .Case(S: "internal" , Value: ELF::STV_INTERNAL) |
266 | .Case(S: "protected" , Value: ELF::STV_PROTECTED) |
267 | .Default(Value: Invalid); |
268 | if (type == Invalid) |
269 | return createStringError(EC: errc::invalid_argument, |
270 | Fmt: "'%s' is not a valid symbol visibility" , |
271 | Vals: VisType.str().c_str()); |
272 | return type; |
273 | } |
274 | |
275 | namespace { |
276 | struct TargetInfo { |
277 | FileFormat Format; |
278 | MachineInfo Machine; |
279 | }; |
280 | } // namespace |
281 | |
282 | // FIXME: consolidate with the bfd parsing used by lld. |
283 | static const StringMap<MachineInfo> TargetMap{ |
284 | // Name, {EMachine, 64bit, LittleEndian} |
285 | // x86 |
286 | {"elf32-i386" , {ELF::EM_386, false, true}}, |
287 | {"elf32-x86-64" , {ELF::EM_X86_64, false, true}}, |
288 | {"elf64-x86-64" , {ELF::EM_X86_64, true, true}}, |
289 | // Intel MCU |
290 | {"elf32-iamcu" , {ELF::EM_IAMCU, false, true}}, |
291 | // ARM |
292 | {"elf32-littlearm" , {ELF::EM_ARM, false, true}}, |
293 | // ARM AArch64 |
294 | {"elf64-aarch64" , {ELF::EM_AARCH64, true, true}}, |
295 | {"elf64-littleaarch64" , {ELF::EM_AARCH64, true, true}}, |
296 | // RISC-V |
297 | {"elf32-littleriscv" , {ELF::EM_RISCV, false, true}}, |
298 | {"elf64-littleriscv" , {ELF::EM_RISCV, true, true}}, |
299 | // PowerPC |
300 | {"elf32-powerpc" , {ELF::EM_PPC, false, false}}, |
301 | {"elf32-powerpcle" , {ELF::EM_PPC, false, true}}, |
302 | {"elf64-powerpc" , {ELF::EM_PPC64, true, false}}, |
303 | {"elf64-powerpcle" , {ELF::EM_PPC64, true, true}}, |
304 | // MIPS |
305 | {"elf32-bigmips" , {ELF::EM_MIPS, false, false}}, |
306 | {"elf32-ntradbigmips" , {ELF::EM_MIPS, false, false}}, |
307 | {"elf32-ntradlittlemips" , {ELF::EM_MIPS, false, true}}, |
308 | {"elf32-tradbigmips" , {ELF::EM_MIPS, false, false}}, |
309 | {"elf32-tradlittlemips" , {ELF::EM_MIPS, false, true}}, |
310 | {"elf64-tradbigmips" , {ELF::EM_MIPS, true, false}}, |
311 | {"elf64-tradlittlemips" , {ELF::EM_MIPS, true, true}}, |
312 | // SPARC |
313 | {"elf32-sparc" , {ELF::EM_SPARC, false, false}}, |
314 | {"elf32-sparcel" , {ELF::EM_SPARC, false, true}}, |
315 | // Hexagon |
316 | {"elf32-hexagon" , {ELF::EM_HEXAGON, false, true}}, |
317 | // LoongArch |
318 | {"elf32-loongarch" , {ELF::EM_LOONGARCH, false, true}}, |
319 | {"elf64-loongarch" , {ELF::EM_LOONGARCH, true, true}}, |
320 | // SystemZ |
321 | {"elf64-s390" , {ELF::EM_S390, true, false}}, |
322 | }; |
323 | |
324 | static Expected<TargetInfo> |
325 | getOutputTargetInfoByTargetName(StringRef TargetName) { |
326 | StringRef OriginalTargetName = TargetName; |
327 | bool IsFreeBSD = TargetName.consume_back(Suffix: "-freebsd" ); |
328 | auto Iter = TargetMap.find(Key: TargetName); |
329 | if (Iter == std::end(cont: TargetMap)) |
330 | return createStringError(EC: errc::invalid_argument, |
331 | Fmt: "invalid output format: '%s'" , |
332 | Vals: OriginalTargetName.str().c_str()); |
333 | MachineInfo MI = Iter->getValue(); |
334 | if (IsFreeBSD) |
335 | MI.OSABI = ELF::ELFOSABI_FREEBSD; |
336 | |
337 | FileFormat Format; |
338 | if (TargetName.starts_with(Prefix: "elf" )) |
339 | Format = FileFormat::ELF; |
340 | else |
341 | // This should never happen because `TargetName` is valid (it certainly |
342 | // exists in the TargetMap). |
343 | llvm_unreachable("unknown target prefix" ); |
344 | |
345 | return {TargetInfo{.Format: Format, .Machine: MI}}; |
346 | } |
347 | |
348 | static Error addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc, |
349 | StringRef Filename, MatchStyle MS, |
350 | function_ref<Error(Error)> ErrorCallback) { |
351 | StringSaver Saver(Alloc); |
352 | SmallVector<StringRef, 16> Lines; |
353 | auto BufOrErr = MemoryBuffer::getFile(Filename); |
354 | if (!BufOrErr) |
355 | return createFileError(F: Filename, EC: BufOrErr.getError()); |
356 | |
357 | BufOrErr.get()->getBuffer().split(A&: Lines, Separator: '\n'); |
358 | for (StringRef Line : Lines) { |
359 | // Ignore everything after '#', trim whitespace, and only add the symbol if |
360 | // it's not empty. |
361 | auto TrimmedLine = Line.split(Separator: '#').first.trim(); |
362 | if (!TrimmedLine.empty()) |
363 | if (Error E = Symbols.addMatcher(Matcher: NameOrPattern::create( |
364 | Pattern: Saver.save(S: TrimmedLine), MS, ErrorCallback))) |
365 | return E; |
366 | } |
367 | |
368 | return Error::success(); |
369 | } |
370 | |
371 | static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename, |
372 | BumpPtrAllocator &Alloc, |
373 | StringRef Filename) { |
374 | StringSaver Saver(Alloc); |
375 | SmallVector<StringRef, 16> Lines; |
376 | auto BufOrErr = MemoryBuffer::getFile(Filename); |
377 | if (!BufOrErr) |
378 | return createFileError(F: Filename, EC: BufOrErr.getError()); |
379 | |
380 | BufOrErr.get()->getBuffer().split(A&: Lines, Separator: '\n'); |
381 | size_t NumLines = Lines.size(); |
382 | for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) { |
383 | StringRef TrimmedLine = Lines[LineNo].split(Separator: '#').first.trim(); |
384 | if (TrimmedLine.empty()) |
385 | continue; |
386 | |
387 | std::pair<StringRef, StringRef> Pair = Saver.save(S: TrimmedLine).split(Separator: ' '); |
388 | StringRef NewName = Pair.second.trim(); |
389 | if (NewName.empty()) |
390 | return createStringError(EC: errc::invalid_argument, |
391 | Fmt: "%s:%zu: missing new symbol name" , |
392 | Vals: Filename.str().c_str(), Vals: LineNo + 1); |
393 | SymbolsToRename.insert(KV: {Pair.first, NewName}); |
394 | } |
395 | return Error::success(); |
396 | } |
397 | |
398 | template <class T> static ErrorOr<T> getAsInteger(StringRef Val) { |
399 | T Result; |
400 | if (Val.getAsInteger(0, Result)) |
401 | return errc::invalid_argument; |
402 | return Result; |
403 | } |
404 | |
405 | namespace { |
406 | |
407 | enum class ToolType { Objcopy, Strip, InstallNameTool, BitcodeStrip }; |
408 | |
409 | } // anonymous namespace |
410 | |
411 | static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS, |
412 | ToolType Tool) { |
413 | StringRef HelpText, ToolName; |
414 | switch (Tool) { |
415 | case ToolType::Objcopy: |
416 | ToolName = "llvm-objcopy" ; |
417 | HelpText = " [options] input [output]" ; |
418 | break; |
419 | case ToolType::Strip: |
420 | ToolName = "llvm-strip" ; |
421 | HelpText = " [options] inputs..." ; |
422 | break; |
423 | case ToolType::InstallNameTool: |
424 | ToolName = "llvm-install-name-tool" ; |
425 | HelpText = " [options] input" ; |
426 | break; |
427 | case ToolType::BitcodeStrip: |
428 | ToolName = "llvm-bitcode-strip" ; |
429 | HelpText = " [options] input" ; |
430 | break; |
431 | } |
432 | OptTable.printHelp(OS, Usage: (ToolName + HelpText).str().c_str(), |
433 | Title: (ToolName + " tool" ).str().c_str()); |
434 | // TODO: Replace this with libOption call once it adds extrahelp support. |
435 | // The CommandLine library has a cl::extrahelp class to support this, |
436 | // but libOption does not have that yet. |
437 | OS << "\nPass @FILE as argument to read options from FILE.\n" ; |
438 | } |
439 | |
440 | static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue) { |
441 | // Parse value given with --add-symbol option and create the |
442 | // new symbol if possible. The value format for --add-symbol is: |
443 | // |
444 | // <name>=[<section>:]<value>[,<flags>] |
445 | // |
446 | // where: |
447 | // <name> - symbol name, can be empty string |
448 | // <section> - optional section name. If not given ABS symbol is created |
449 | // <value> - symbol value, can be decimal or hexadecimal number prefixed |
450 | // with 0x. |
451 | // <flags> - optional flags affecting symbol type, binding or visibility. |
452 | NewSymbolInfo SI; |
453 | StringRef Value; |
454 | std::tie(args&: SI.SymbolName, args&: Value) = FlagValue.split(Separator: '='); |
455 | if (Value.empty()) |
456 | return createStringError( |
457 | EC: errc::invalid_argument, |
458 | Fmt: "bad format for --add-symbol, missing '=' after '%s'" , |
459 | Vals: SI.SymbolName.str().c_str()); |
460 | |
461 | if (Value.contains(C: ':')) { |
462 | std::tie(args&: SI.SectionName, args&: Value) = Value.split(Separator: ':'); |
463 | if (SI.SectionName.empty() || Value.empty()) |
464 | return createStringError( |
465 | EC: errc::invalid_argument, |
466 | S: "bad format for --add-symbol, missing section name or symbol value" ); |
467 | } |
468 | |
469 | SmallVector<StringRef, 6> Flags; |
470 | Value.split(A&: Flags, Separator: ','); |
471 | if (Flags[0].getAsInteger(Radix: 0, Result&: SI.Value)) |
472 | return createStringError(EC: errc::invalid_argument, Fmt: "bad symbol value: '%s'" , |
473 | Vals: Flags[0].str().c_str()); |
474 | |
475 | using Functor = std::function<void()>; |
476 | SmallVector<StringRef, 6> UnsupportedFlags; |
477 | for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I) |
478 | static_cast<Functor>( |
479 | StringSwitch<Functor>(Flags[I]) |
480 | .CaseLower(S: "global" , |
481 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Global); }) |
482 | .CaseLower(S: "local" , Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Local); }) |
483 | .CaseLower(S: "weak" , Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Weak); }) |
484 | .CaseLower(S: "default" , |
485 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Default); }) |
486 | .CaseLower(S: "hidden" , |
487 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Hidden); }) |
488 | .CaseLower(S: "protected" , |
489 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Protected); }) |
490 | .CaseLower(S: "file" , Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::File); }) |
491 | .CaseLower(S: "section" , |
492 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Section); }) |
493 | .CaseLower(S: "object" , |
494 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Object); }) |
495 | .CaseLower(S: "function" , |
496 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Function); }) |
497 | .CaseLower( |
498 | S: "indirect-function" , |
499 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::IndirectFunction); }) |
500 | .CaseLower(S: "debug" , Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Debug); }) |
501 | .CaseLower(S: "constructor" , |
502 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Constructor); }) |
503 | .CaseLower(S: "warning" , |
504 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Warning); }) |
505 | .CaseLower(S: "indirect" , |
506 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Indirect); }) |
507 | .CaseLower(S: "synthetic" , |
508 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::Synthetic); }) |
509 | .CaseLower(S: "unique-object" , |
510 | Value: [&] { SI.Flags.push_back(Elt: SymbolFlag::UniqueObject); }) |
511 | .StartsWithLower(S: "before=" , |
512 | Value: [&] { |
513 | StringRef SymNamePart = |
514 | Flags[I].split(Separator: '=').second; |
515 | |
516 | if (!SymNamePart.empty()) |
517 | SI.BeforeSyms.push_back(Elt: SymNamePart); |
518 | }) |
519 | .Default(Value: [&] { UnsupportedFlags.push_back(Elt: Flags[I]); }))(); |
520 | if (!UnsupportedFlags.empty()) |
521 | return createStringError(EC: errc::invalid_argument, |
522 | Fmt: "unsupported flag%s for --add-symbol: '%s'" , |
523 | Vals: UnsupportedFlags.size() > 1 ? "s" : "" , |
524 | Vals: join(R&: UnsupportedFlags, Separator: "', '" ).c_str()); |
525 | |
526 | return SI; |
527 | } |
528 | |
529 | // Parse input option \p ArgValue and load section data. This function |
530 | // extracts section name and name of the file keeping section data from |
531 | // ArgValue, loads data from the file, and stores section name and data |
532 | // into the vector of new sections \p NewSections. |
533 | static Error loadNewSectionData(StringRef ArgValue, StringRef OptionName, |
534 | SmallVector<NewSectionInfo, 0> &NewSections) { |
535 | if (!ArgValue.contains(C: '=')) |
536 | return createStringError(EC: errc::invalid_argument, |
537 | S: "bad format for " + OptionName + ": missing '='" ); |
538 | |
539 | std::pair<StringRef, StringRef> SecPair = ArgValue.split(Separator: "=" ); |
540 | if (SecPair.second.empty()) |
541 | return createStringError(EC: errc::invalid_argument, S: "bad format for " + |
542 | OptionName + |
543 | ": missing file name" ); |
544 | |
545 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = |
546 | MemoryBuffer::getFile(Filename: SecPair.second); |
547 | if (!BufOrErr) |
548 | return createFileError(F: SecPair.second, |
549 | E: errorCodeToError(EC: BufOrErr.getError())); |
550 | |
551 | NewSections.push_back(Elt: {SecPair.first, std::move(*BufOrErr)}); |
552 | return Error::success(); |
553 | } |
554 | |
555 | static Expected<int64_t> parseChangeSectionLMA(StringRef ArgValue, |
556 | StringRef OptionName) { |
557 | StringRef StringValue; |
558 | if (ArgValue.starts_with(Prefix: "*+" )) { |
559 | StringValue = ArgValue.slice(Start: 2, End: StringRef::npos); |
560 | } else if (ArgValue.starts_with(Prefix: "*-" )) { |
561 | StringValue = ArgValue.slice(Start: 1, End: StringRef::npos); |
562 | } else if (ArgValue.contains(Other: "=" )) { |
563 | return createStringError(EC: errc::invalid_argument, |
564 | S: "bad format for " + OptionName + |
565 | ": changing LMA to a specific value is not " |
566 | "supported. Use *+val or *-val instead" ); |
567 | } else if (ArgValue.contains(Other: "+" ) || ArgValue.contains(Other: "-" )) { |
568 | return createStringError(EC: errc::invalid_argument, |
569 | S: "bad format for " + OptionName + |
570 | ": changing a specific section LMA is not " |
571 | "supported. Use *+val or *-val instead" ); |
572 | } |
573 | if (StringValue.empty()) |
574 | return createStringError(EC: errc::invalid_argument, |
575 | S: "bad format for " + OptionName + |
576 | ": missing LMA offset" ); |
577 | |
578 | auto LMAValue = getAsInteger<int64_t>(Val: StringValue); |
579 | if (!LMAValue) |
580 | return createStringError(EC: LMAValue.getError(), |
581 | S: "bad format for " + OptionName + ": value after " + |
582 | ArgValue.slice(Start: 0, End: 2) + " is " + StringValue + |
583 | " when it should be an integer" ); |
584 | return *LMAValue; |
585 | } |
586 | |
587 | // parseObjcopyOptions returns the config and sets the input arguments. If a |
588 | // help flag is set then parseObjcopyOptions will print the help messege and |
589 | // exit. |
590 | Expected<DriverConfig> |
591 | objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr, |
592 | function_ref<Error(Error)> ErrorCallback) { |
593 | DriverConfig DC; |
594 | ObjcopyOptTable T; |
595 | |
596 | const char *const *DashDash = |
597 | llvm::find_if(Range&: RawArgsArr, P: [](StringRef Str) { return Str == "--" ; }); |
598 | ArrayRef<const char *> ArgsArr = ArrayRef(RawArgsArr.begin(), DashDash); |
599 | if (DashDash != RawArgsArr.end()) |
600 | DashDash = std::next(x: DashDash); |
601 | |
602 | unsigned MissingArgumentIndex, MissingArgumentCount; |
603 | llvm::opt::InputArgList InputArgs = |
604 | T.ParseArgs(Args: ArgsArr, MissingArgIndex&: MissingArgumentIndex, MissingArgCount&: MissingArgumentCount); |
605 | |
606 | if (MissingArgumentCount) |
607 | return createStringError( |
608 | EC: errc::invalid_argument, |
609 | Fmt: "argument to '%s' is missing (expected %d value(s))" , |
610 | Vals: InputArgs.getArgString(Index: MissingArgumentIndex), Vals: MissingArgumentCount); |
611 | |
612 | if (InputArgs.size() == 0 && DashDash == RawArgsArr.end()) { |
613 | printHelp(OptTable: T, OS&: errs(), Tool: ToolType::Objcopy); |
614 | exit(status: 1); |
615 | } |
616 | |
617 | if (InputArgs.hasArg(Ids: OBJCOPY_help)) { |
618 | printHelp(OptTable: T, OS&: outs(), Tool: ToolType::Objcopy); |
619 | exit(status: 0); |
620 | } |
621 | |
622 | if (InputArgs.hasArg(Ids: OBJCOPY_version)) { |
623 | outs() << "llvm-objcopy, compatible with GNU objcopy\n" ; |
624 | cl::PrintVersionMessage(); |
625 | exit(status: 0); |
626 | } |
627 | |
628 | SmallVector<const char *, 2> Positional; |
629 | |
630 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_UNKNOWN)) |
631 | return createStringError(EC: errc::invalid_argument, Fmt: "unknown argument '%s'" , |
632 | Vals: Arg->getAsString(Args: InputArgs).c_str()); |
633 | |
634 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_INPUT)) |
635 | Positional.push_back(Elt: Arg->getValue()); |
636 | std::copy(DashDash, RawArgsArr.end(), std::back_inserter(x&: Positional)); |
637 | |
638 | if (Positional.empty()) |
639 | return createStringError(EC: errc::invalid_argument, S: "no input file specified" ); |
640 | |
641 | if (Positional.size() > 2) |
642 | return createStringError(EC: errc::invalid_argument, |
643 | S: "too many positional arguments" ); |
644 | |
645 | ConfigManager ConfigMgr; |
646 | CommonConfig &Config = ConfigMgr.Common; |
647 | COFFConfig &COFFConfig = ConfigMgr.COFF; |
648 | ELFConfig &ELFConfig = ConfigMgr.ELF; |
649 | MachOConfig &MachOConfig = ConfigMgr.MachO; |
650 | Config.InputFilename = Positional[0]; |
651 | Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; |
652 | if (InputArgs.hasArg(Ids: OBJCOPY_target) && |
653 | (InputArgs.hasArg(Ids: OBJCOPY_input_target) || |
654 | InputArgs.hasArg(Ids: OBJCOPY_output_target))) |
655 | return createStringError( |
656 | EC: errc::invalid_argument, |
657 | S: "--target cannot be used with --input-target or --output-target" ); |
658 | |
659 | if (InputArgs.hasArg(Ids: OBJCOPY_regex) && InputArgs.hasArg(Ids: OBJCOPY_wildcard)) |
660 | return createStringError(EC: errc::invalid_argument, |
661 | S: "--regex and --wildcard are incompatible" ); |
662 | |
663 | MatchStyle SectionMatchStyle = InputArgs.hasArg(Ids: OBJCOPY_regex) |
664 | ? MatchStyle::Regex |
665 | : MatchStyle::Wildcard; |
666 | MatchStyle SymbolMatchStyle |
667 | = InputArgs.hasArg(Ids: OBJCOPY_regex) ? MatchStyle::Regex |
668 | : InputArgs.hasArg(Ids: OBJCOPY_wildcard) ? MatchStyle::Wildcard |
669 | : MatchStyle::Literal; |
670 | StringRef InputFormat, OutputFormat; |
671 | if (InputArgs.hasArg(Ids: OBJCOPY_target)) { |
672 | InputFormat = InputArgs.getLastArgValue(Id: OBJCOPY_target); |
673 | OutputFormat = InputArgs.getLastArgValue(Id: OBJCOPY_target); |
674 | } else { |
675 | InputFormat = InputArgs.getLastArgValue(Id: OBJCOPY_input_target); |
676 | OutputFormat = InputArgs.getLastArgValue(Id: OBJCOPY_output_target); |
677 | } |
678 | |
679 | // FIXME: Currently, we ignore the target for non-binary/ihex formats |
680 | // explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the |
681 | // format by llvm::object::createBinary regardless of the option value. |
682 | Config.InputFormat = StringSwitch<FileFormat>(InputFormat) |
683 | .Case(S: "binary" , Value: FileFormat::Binary) |
684 | .Case(S: "ihex" , Value: FileFormat::IHex) |
685 | .Default(Value: FileFormat::Unspecified); |
686 | |
687 | if (InputArgs.hasArg(Ids: OBJCOPY_new_symbol_visibility)) { |
688 | const uint8_t Invalid = 0xff; |
689 | StringRef VisibilityStr = |
690 | InputArgs.getLastArgValue(Id: OBJCOPY_new_symbol_visibility); |
691 | |
692 | ELFConfig.NewSymbolVisibility = StringSwitch<uint8_t>(VisibilityStr) |
693 | .Case(S: "default" , Value: ELF::STV_DEFAULT) |
694 | .Case(S: "hidden" , Value: ELF::STV_HIDDEN) |
695 | .Case(S: "internal" , Value: ELF::STV_INTERNAL) |
696 | .Case(S: "protected" , Value: ELF::STV_PROTECTED) |
697 | .Default(Value: Invalid); |
698 | |
699 | if (ELFConfig.NewSymbolVisibility == Invalid) |
700 | return createStringError(EC: errc::invalid_argument, |
701 | Fmt: "'%s' is not a valid symbol visibility" , |
702 | Vals: VisibilityStr.str().c_str()); |
703 | } |
704 | |
705 | for (const auto *Arg : InputArgs.filtered(Ids: OBJCOPY_subsystem)) { |
706 | StringRef Subsystem, Version; |
707 | std::tie(args&: Subsystem, args&: Version) = StringRef(Arg->getValue()).split(Separator: ':'); |
708 | COFFConfig.Subsystem = |
709 | StringSwitch<unsigned>(Subsystem.lower()) |
710 | .Case(S: "boot_application" , |
711 | Value: COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) |
712 | .Case(S: "console" , Value: COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI) |
713 | .Cases(S0: "efi_application" , S1: "efi-app" , |
714 | Value: COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION) |
715 | .Cases(S0: "efi_boot_service_driver" , S1: "efi-bsd" , |
716 | Value: COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) |
717 | .Case(S: "efi_rom" , Value: COFF::IMAGE_SUBSYSTEM_EFI_ROM) |
718 | .Cases(S0: "efi_runtime_driver" , S1: "efi-rtd" , |
719 | Value: COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) |
720 | .Case(S: "native" , Value: COFF::IMAGE_SUBSYSTEM_NATIVE) |
721 | .Case(S: "posix" , Value: COFF::IMAGE_SUBSYSTEM_POSIX_CUI) |
722 | .Case(S: "windows" , Value: COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI) |
723 | .Default(Value: COFF::IMAGE_SUBSYSTEM_UNKNOWN); |
724 | if (*COFFConfig.Subsystem == COFF::IMAGE_SUBSYSTEM_UNKNOWN) |
725 | return createStringError(EC: errc::invalid_argument, |
726 | Fmt: "'%s' is not a valid subsystem" , |
727 | Vals: Subsystem.str().c_str()); |
728 | if (!Version.empty()) { |
729 | StringRef Major, Minor; |
730 | std::tie(args&: Major, args&: Minor) = Version.split(Separator: '.'); |
731 | unsigned Number; |
732 | if (Major.getAsInteger(Radix: 10, Result&: Number)) |
733 | return createStringError(EC: errc::invalid_argument, |
734 | Fmt: "'%s' is not a valid subsystem major version" , |
735 | Vals: Major.str().c_str()); |
736 | COFFConfig.MajorSubsystemVersion = Number; |
737 | Number = 0; |
738 | if (!Minor.empty() && Minor.getAsInteger(Radix: 10, Result&: Number)) |
739 | return createStringError(EC: errc::invalid_argument, |
740 | Fmt: "'%s' is not a valid subsystem minor version" , |
741 | Vals: Minor.str().c_str()); |
742 | COFFConfig.MinorSubsystemVersion = Number; |
743 | } |
744 | } |
745 | |
746 | Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat) |
747 | .Case(S: "binary" , Value: FileFormat::Binary) |
748 | .Case(S: "ihex" , Value: FileFormat::IHex) |
749 | .Case(S: "srec" , Value: FileFormat::SREC) |
750 | .Default(Value: FileFormat::Unspecified); |
751 | if (Config.OutputFormat == FileFormat::Unspecified) { |
752 | if (OutputFormat.empty()) { |
753 | Config.OutputFormat = Config.InputFormat; |
754 | } else { |
755 | Expected<TargetInfo> Target = |
756 | getOutputTargetInfoByTargetName(TargetName: OutputFormat); |
757 | if (!Target) |
758 | return Target.takeError(); |
759 | Config.OutputFormat = Target->Format; |
760 | Config.OutputArch = Target->Machine; |
761 | } |
762 | } |
763 | |
764 | if (const auto *A = InputArgs.getLastArg(Ids: OBJCOPY_compress_debug_sections)) { |
765 | Config.CompressionType = StringSwitch<DebugCompressionType>(A->getValue()) |
766 | .Case(S: "zlib" , Value: DebugCompressionType::Zlib) |
767 | .Case(S: "zstd" , Value: DebugCompressionType::Zstd) |
768 | .Default(Value: DebugCompressionType::None); |
769 | if (Config.CompressionType == DebugCompressionType::None) { |
770 | return createStringError( |
771 | EC: errc::invalid_argument, |
772 | Fmt: "invalid or unsupported --compress-debug-sections format: %s" , |
773 | Vals: A->getValue()); |
774 | } |
775 | if (const char *Reason = compression::getReasonIfUnsupported( |
776 | F: compression::formatFor(Type: Config.CompressionType))) |
777 | return createStringError(EC: errc::invalid_argument, S: Reason); |
778 | } |
779 | |
780 | for (const auto *A : InputArgs.filtered(Ids: OBJCOPY_compress_sections)) { |
781 | SmallVector<StringRef, 0> Fields; |
782 | StringRef(A->getValue()).split(A&: Fields, Separator: '='); |
783 | if (Fields.size() != 2 || Fields[1].empty()) { |
784 | return createStringError( |
785 | EC: errc::invalid_argument, |
786 | S: A->getSpelling() + |
787 | ": parse error, not 'section-glob=[none|zlib|zstd]'" ); |
788 | } |
789 | |
790 | auto Type = StringSwitch<DebugCompressionType>(Fields[1]) |
791 | .Case(S: "zlib" , Value: DebugCompressionType::Zlib) |
792 | .Case(S: "zstd" , Value: DebugCompressionType::Zstd) |
793 | .Default(Value: DebugCompressionType::None); |
794 | if (Type == DebugCompressionType::None && Fields[1] != "none" ) { |
795 | return createStringError( |
796 | EC: errc::invalid_argument, |
797 | Fmt: "invalid or unsupported --compress-sections format: %s" , |
798 | Vals: A->getValue()); |
799 | } |
800 | |
801 | auto &P = Config.compressSections.emplace_back(); |
802 | P.second = Type; |
803 | auto Matcher = |
804 | NameOrPattern::create(Pattern: Fields[0], MS: SectionMatchStyle, ErrorCallback); |
805 | // =none allows overriding a previous =zlib or =zstd. Reject negative |
806 | // patterns, which would be confusing. |
807 | if (Matcher && !Matcher->isPositiveMatch()) { |
808 | return createStringError( |
809 | EC: errc::invalid_argument, |
810 | S: "--compress-sections: negative pattern is unsupported" ); |
811 | } |
812 | if (Error E = P.first.addMatcher(Matcher: std::move(Matcher))) |
813 | return std::move(E); |
814 | } |
815 | |
816 | Config.AddGnuDebugLink = InputArgs.getLastArgValue(Id: OBJCOPY_add_gnu_debuglink); |
817 | // The gnu_debuglink's target is expected to not change or else its CRC would |
818 | // become invalidated and get rejected. We can avoid recalculating the |
819 | // checksum for every target file inside an archive by precomputing the CRC |
820 | // here. This prevents a significant amount of I/O. |
821 | if (!Config.AddGnuDebugLink.empty()) { |
822 | auto DebugOrErr = MemoryBuffer::getFile(Filename: Config.AddGnuDebugLink); |
823 | if (!DebugOrErr) |
824 | return createFileError(F: Config.AddGnuDebugLink, EC: DebugOrErr.getError()); |
825 | auto Debug = std::move(*DebugOrErr); |
826 | Config.GnuDebugLinkCRC32 = |
827 | llvm::crc32(Data: arrayRefFromStringRef(Input: Debug->getBuffer())); |
828 | } |
829 | Config.SplitDWO = InputArgs.getLastArgValue(Id: OBJCOPY_split_dwo); |
830 | |
831 | Config.SymbolsPrefix = InputArgs.getLastArgValue(Id: OBJCOPY_prefix_symbols); |
832 | Config.SymbolsPrefixRemove = |
833 | InputArgs.getLastArgValue(Id: OBJCOPY_remove_symbol_prefix); |
834 | |
835 | Config.AllocSectionsPrefix = |
836 | InputArgs.getLastArgValue(Id: OBJCOPY_prefix_alloc_sections); |
837 | if (auto Arg = InputArgs.getLastArg(Ids: OBJCOPY_extract_partition)) |
838 | Config.ExtractPartition = Arg->getValue(); |
839 | |
840 | if (const auto *A = InputArgs.getLastArg(Ids: OBJCOPY_gap_fill)) { |
841 | if (Config.OutputFormat != FileFormat::Binary) |
842 | return createStringError( |
843 | EC: errc::invalid_argument, |
844 | S: "'--gap-fill' is only supported for binary output" ); |
845 | ErrorOr<uint64_t> Val = getAsInteger<uint64_t>(Val: A->getValue()); |
846 | if (!Val) |
847 | return createStringError(EC: Val.getError(), Fmt: "--gap-fill: bad number: %s" , |
848 | Vals: A->getValue()); |
849 | uint8_t ByteVal = Val.get(); |
850 | if (ByteVal != Val.get()) |
851 | return createStringError(EC: std::errc::value_too_large, |
852 | Fmt: "gap-fill value %s is out of range (0 to 0xff)" , |
853 | Vals: A->getValue()); |
854 | Config.GapFill = ByteVal; |
855 | } |
856 | |
857 | if (const auto *A = InputArgs.getLastArg(Ids: OBJCOPY_pad_to)) { |
858 | if (Config.OutputFormat != FileFormat::Binary) |
859 | return createStringError( |
860 | EC: errc::invalid_argument, |
861 | S: "'--pad-to' is only supported for binary output" ); |
862 | ErrorOr<uint64_t> Addr = getAsInteger<uint64_t>(Val: A->getValue()); |
863 | if (!Addr) |
864 | return createStringError(EC: Addr.getError(), Fmt: "--pad-to: bad number: %s" , |
865 | Vals: A->getValue()); |
866 | Config.PadTo = *Addr; |
867 | } |
868 | |
869 | if (const auto *Arg = InputArgs.getLastArg(Ids: OBJCOPY_change_section_lma)) { |
870 | Expected<int64_t> LMAValue = |
871 | parseChangeSectionLMA(ArgValue: Arg->getValue(), OptionName: Arg->getSpelling()); |
872 | if (!LMAValue) |
873 | return LMAValue.takeError(); |
874 | Config.ChangeSectionLMAValAll = *LMAValue; |
875 | } |
876 | |
877 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_redefine_symbol)) { |
878 | if (!StringRef(Arg->getValue()).contains(C: '=')) |
879 | return createStringError(EC: errc::invalid_argument, |
880 | S: "bad format for --redefine-sym" ); |
881 | auto Old2New = StringRef(Arg->getValue()).split(Separator: '='); |
882 | if (!Config.SymbolsToRename.insert(KV: Old2New).second) |
883 | return createStringError(EC: errc::invalid_argument, |
884 | Fmt: "multiple redefinition of symbol '%s'" , |
885 | Vals: Old2New.first.str().c_str()); |
886 | } |
887 | |
888 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_redefine_symbols)) |
889 | if (Error E = addSymbolsToRenameFromFile(SymbolsToRename&: Config.SymbolsToRename, Alloc&: DC.Alloc, |
890 | Filename: Arg->getValue())) |
891 | return std::move(E); |
892 | |
893 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_rename_section)) { |
894 | Expected<SectionRename> SR = |
895 | parseRenameSectionValue(FlagValue: StringRef(Arg->getValue())); |
896 | if (!SR) |
897 | return SR.takeError(); |
898 | if (!Config.SectionsToRename.try_emplace(Key: SR->OriginalName, Args&: *SR).second) |
899 | return createStringError(EC: errc::invalid_argument, |
900 | Fmt: "multiple renames of section '%s'" , |
901 | Vals: SR->OriginalName.str().c_str()); |
902 | } |
903 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_set_section_alignment)) { |
904 | Expected<std::pair<StringRef, uint64_t>> NameAndAlign = |
905 | parseSetSectionAttribute(Option: "--set-section-alignment" , FlagValue: Arg->getValue()); |
906 | if (!NameAndAlign) |
907 | return NameAndAlign.takeError(); |
908 | Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second; |
909 | } |
910 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_set_section_flags)) { |
911 | Expected<SectionFlagsUpdate> SFU = |
912 | parseSetSectionFlagValue(FlagValue: Arg->getValue()); |
913 | if (!SFU) |
914 | return SFU.takeError(); |
915 | if (!Config.SetSectionFlags.try_emplace(Key: SFU->Name, Args&: *SFU).second) |
916 | return createStringError( |
917 | EC: errc::invalid_argument, |
918 | Fmt: "--set-section-flags set multiple times for section '%s'" , |
919 | Vals: SFU->Name.str().c_str()); |
920 | } |
921 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_set_section_type)) { |
922 | Expected<std::pair<StringRef, uint64_t>> NameAndType = |
923 | parseSetSectionAttribute(Option: "--set-section-type" , FlagValue: Arg->getValue()); |
924 | if (!NameAndType) |
925 | return NameAndType.takeError(); |
926 | Config.SetSectionType[NameAndType->first] = NameAndType->second; |
927 | } |
928 | // Prohibit combinations of --set-section-{flags,type} when the section name |
929 | // is used as the destination of a --rename-section. |
930 | for (const auto &E : Config.SectionsToRename) { |
931 | const SectionRename &SR = E.second; |
932 | auto Err = [&](const char *Option) { |
933 | return createStringError( |
934 | EC: errc::invalid_argument, |
935 | Fmt: "--set-section-%s=%s conflicts with --rename-section=%s=%s" , Vals: Option, |
936 | Vals: SR.NewName.str().c_str(), Vals: SR.OriginalName.str().c_str(), |
937 | Vals: SR.NewName.str().c_str()); |
938 | }; |
939 | if (Config.SetSectionFlags.count(Key: SR.NewName)) |
940 | return Err("flags" ); |
941 | if (Config.SetSectionType.count(Key: SR.NewName)) |
942 | return Err("type" ); |
943 | } |
944 | |
945 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_remove_section)) |
946 | if (Error E = Config.ToRemove.addMatcher(Matcher: NameOrPattern::create( |
947 | Pattern: Arg->getValue(), MS: SectionMatchStyle, ErrorCallback))) |
948 | return std::move(E); |
949 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_keep_section)) |
950 | if (Error E = Config.KeepSection.addMatcher(Matcher: NameOrPattern::create( |
951 | Pattern: Arg->getValue(), MS: SectionMatchStyle, ErrorCallback))) |
952 | return std::move(E); |
953 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_only_section)) |
954 | if (Error E = Config.OnlySection.addMatcher(Matcher: NameOrPattern::create( |
955 | Pattern: Arg->getValue(), MS: SectionMatchStyle, ErrorCallback))) |
956 | return std::move(E); |
957 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_add_section)) { |
958 | if (Error Err = loadNewSectionData(ArgValue: Arg->getValue(), OptionName: "--add-section" , |
959 | NewSections&: Config.AddSection)) |
960 | return std::move(Err); |
961 | } |
962 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_update_section)) { |
963 | if (Error Err = loadNewSectionData(ArgValue: Arg->getValue(), OptionName: "--update-section" , |
964 | NewSections&: Config.UpdateSection)) |
965 | return std::move(Err); |
966 | } |
967 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_dump_section)) { |
968 | StringRef Value(Arg->getValue()); |
969 | if (Value.split(Separator: '=').second.empty()) |
970 | return createStringError( |
971 | EC: errc::invalid_argument, |
972 | S: "bad format for --dump-section, expected section=file" ); |
973 | Config.DumpSection.push_back(Elt: Value); |
974 | } |
975 | Config.StripAll = InputArgs.hasArg(Ids: OBJCOPY_strip_all); |
976 | Config.StripAllGNU = InputArgs.hasArg(Ids: OBJCOPY_strip_all_gnu); |
977 | Config.StripDebug = InputArgs.hasArg(Ids: OBJCOPY_strip_debug); |
978 | Config.StripDWO = InputArgs.hasArg(Ids: OBJCOPY_strip_dwo); |
979 | Config.StripSections = InputArgs.hasArg(Ids: OBJCOPY_strip_sections); |
980 | Config.StripNonAlloc = InputArgs.hasArg(Ids: OBJCOPY_strip_non_alloc); |
981 | Config.StripUnneeded = InputArgs.hasArg(Ids: OBJCOPY_strip_unneeded); |
982 | Config.ExtractDWO = InputArgs.hasArg(Ids: OBJCOPY_extract_dwo); |
983 | Config.ExtractMainPartition = |
984 | InputArgs.hasArg(Ids: OBJCOPY_extract_main_partition); |
985 | ELFConfig.LocalizeHidden = InputArgs.hasArg(Ids: OBJCOPY_localize_hidden); |
986 | Config.Weaken = InputArgs.hasArg(Ids: OBJCOPY_weaken); |
987 | if (auto *Arg = |
988 | InputArgs.getLastArg(Ids: OBJCOPY_discard_all, Ids: OBJCOPY_discard_locals)) { |
989 | Config.DiscardMode = Arg->getOption().matches(ID: OBJCOPY_discard_all) |
990 | ? DiscardType::All |
991 | : DiscardType::Locals; |
992 | } |
993 | |
994 | ELFConfig.VerifyNoteSections = InputArgs.hasFlag( |
995 | Pos: OBJCOPY_verify_note_sections, Neg: OBJCOPY_no_verify_note_sections, Default: true); |
996 | |
997 | Config.OnlyKeepDebug = InputArgs.hasArg(Ids: OBJCOPY_only_keep_debug); |
998 | ELFConfig.KeepFileSymbols = InputArgs.hasArg(Ids: OBJCOPY_keep_file_symbols); |
999 | MachOConfig.KeepUndefined = InputArgs.hasArg(Ids: OBJCOPY_keep_undefined); |
1000 | Config.DecompressDebugSections = |
1001 | InputArgs.hasArg(Ids: OBJCOPY_decompress_debug_sections); |
1002 | if (Config.DiscardMode == DiscardType::All) { |
1003 | Config.StripDebug = true; |
1004 | ELFConfig.KeepFileSymbols = true; |
1005 | } |
1006 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_localize_symbol)) |
1007 | if (Error E = Config.SymbolsToLocalize.addMatcher(Matcher: NameOrPattern::create( |
1008 | Pattern: Arg->getValue(), MS: SymbolMatchStyle, ErrorCallback))) |
1009 | return std::move(E); |
1010 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_localize_symbols)) |
1011 | if (Error E = addSymbolsFromFile(Symbols&: Config.SymbolsToLocalize, Alloc&: DC.Alloc, |
1012 | Filename: Arg->getValue(), MS: SymbolMatchStyle, |
1013 | ErrorCallback)) |
1014 | return std::move(E); |
1015 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_keep_global_symbol)) |
1016 | if (Error E = Config.SymbolsToKeepGlobal.addMatcher(Matcher: NameOrPattern::create( |
1017 | Pattern: Arg->getValue(), MS: SymbolMatchStyle, ErrorCallback))) |
1018 | return std::move(E); |
1019 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_keep_global_symbols)) |
1020 | if (Error E = addSymbolsFromFile(Symbols&: Config.SymbolsToKeepGlobal, Alloc&: DC.Alloc, |
1021 | Filename: Arg->getValue(), MS: SymbolMatchStyle, |
1022 | ErrorCallback)) |
1023 | return std::move(E); |
1024 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_globalize_symbol)) |
1025 | if (Error E = Config.SymbolsToGlobalize.addMatcher(Matcher: NameOrPattern::create( |
1026 | Pattern: Arg->getValue(), MS: SymbolMatchStyle, ErrorCallback))) |
1027 | return std::move(E); |
1028 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_globalize_symbols)) |
1029 | if (Error E = addSymbolsFromFile(Symbols&: Config.SymbolsToGlobalize, Alloc&: DC.Alloc, |
1030 | Filename: Arg->getValue(), MS: SymbolMatchStyle, |
1031 | ErrorCallback)) |
1032 | return std::move(E); |
1033 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_weaken_symbol)) |
1034 | if (Error E = Config.SymbolsToWeaken.addMatcher(Matcher: NameOrPattern::create( |
1035 | Pattern: Arg->getValue(), MS: SymbolMatchStyle, ErrorCallback))) |
1036 | return std::move(E); |
1037 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_weaken_symbols)) |
1038 | if (Error E = addSymbolsFromFile(Symbols&: Config.SymbolsToWeaken, Alloc&: DC.Alloc, |
1039 | Filename: Arg->getValue(), MS: SymbolMatchStyle, |
1040 | ErrorCallback)) |
1041 | return std::move(E); |
1042 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_strip_symbol)) |
1043 | if (Error E = Config.SymbolsToRemove.addMatcher(Matcher: NameOrPattern::create( |
1044 | Pattern: Arg->getValue(), MS: SymbolMatchStyle, ErrorCallback))) |
1045 | return std::move(E); |
1046 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_strip_symbols)) |
1047 | if (Error E = addSymbolsFromFile(Symbols&: Config.SymbolsToRemove, Alloc&: DC.Alloc, |
1048 | Filename: Arg->getValue(), MS: SymbolMatchStyle, |
1049 | ErrorCallback)) |
1050 | return std::move(E); |
1051 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_strip_unneeded_symbol)) |
1052 | if (Error E = |
1053 | Config.UnneededSymbolsToRemove.addMatcher(Matcher: NameOrPattern::create( |
1054 | Pattern: Arg->getValue(), MS: SymbolMatchStyle, ErrorCallback))) |
1055 | return std::move(E); |
1056 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_strip_unneeded_symbols)) |
1057 | if (Error E = addSymbolsFromFile(Symbols&: Config.UnneededSymbolsToRemove, Alloc&: DC.Alloc, |
1058 | Filename: Arg->getValue(), MS: SymbolMatchStyle, |
1059 | ErrorCallback)) |
1060 | return std::move(E); |
1061 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_keep_symbol)) |
1062 | if (Error E = Config.SymbolsToKeep.addMatcher(Matcher: NameOrPattern::create( |
1063 | Pattern: Arg->getValue(), MS: SymbolMatchStyle, ErrorCallback))) |
1064 | return std::move(E); |
1065 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_keep_symbols)) |
1066 | if (Error E = |
1067 | addSymbolsFromFile(Symbols&: Config.SymbolsToKeep, Alloc&: DC.Alloc, Filename: Arg->getValue(), |
1068 | MS: SymbolMatchStyle, ErrorCallback)) |
1069 | return std::move(E); |
1070 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_skip_symbol)) |
1071 | if (Error E = Config.SymbolsToSkip.addMatcher(Matcher: NameOrPattern::create( |
1072 | Pattern: Arg->getValue(), MS: SymbolMatchStyle, ErrorCallback))) |
1073 | return std::move(E); |
1074 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_skip_symbols)) |
1075 | if (Error E = |
1076 | addSymbolsFromFile(Symbols&: Config.SymbolsToSkip, Alloc&: DC.Alloc, Filename: Arg->getValue(), |
1077 | MS: SymbolMatchStyle, ErrorCallback)) |
1078 | return std::move(E); |
1079 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_add_symbol)) { |
1080 | Expected<NewSymbolInfo> SymInfo = parseNewSymbolInfo(FlagValue: Arg->getValue()); |
1081 | if (!SymInfo) |
1082 | return SymInfo.takeError(); |
1083 | |
1084 | Config.SymbolsToAdd.push_back(Elt: *SymInfo); |
1085 | } |
1086 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_set_symbol_visibility)) { |
1087 | if (!StringRef(Arg->getValue()).contains(C: '=')) |
1088 | return createStringError(EC: errc::invalid_argument, |
1089 | S: "bad format for --set-symbol-visibility" ); |
1090 | auto [Sym, Visibility] = StringRef(Arg->getValue()).split(Separator: '='); |
1091 | Expected<uint8_t> Type = parseVisibilityType(VisType: Visibility); |
1092 | if (!Type) |
1093 | return Type.takeError(); |
1094 | ELFConfig.SymbolsToSetVisibility.emplace_back(args: NameMatcher(), args&: *Type); |
1095 | if (Error E = ELFConfig.SymbolsToSetVisibility.back().first.addMatcher( |
1096 | Matcher: NameOrPattern::create(Pattern: Sym, MS: SymbolMatchStyle, ErrorCallback))) |
1097 | return std::move(E); |
1098 | } |
1099 | for (auto *Arg : InputArgs.filtered(Ids: OBJCOPY_set_symbols_visibility)) { |
1100 | if (!StringRef(Arg->getValue()).contains(C: '=')) |
1101 | return createStringError(EC: errc::invalid_argument, |
1102 | S: "bad format for --set-symbols-visibility" ); |
1103 | auto [File, Visibility] = StringRef(Arg->getValue()).split(Separator: '='); |
1104 | Expected<uint8_t> Type = parseVisibilityType(VisType: Visibility); |
1105 | if (!Type) |
1106 | return Type.takeError(); |
1107 | ELFConfig.SymbolsToSetVisibility.emplace_back(args: NameMatcher(), args&: *Type); |
1108 | if (Error E = |
1109 | addSymbolsFromFile(Symbols&: ELFConfig.SymbolsToSetVisibility.back().first, |
1110 | Alloc&: DC.Alloc, Filename: File, MS: SymbolMatchStyle, ErrorCallback)) |
1111 | return std::move(E); |
1112 | } |
1113 | |
1114 | ELFConfig.AllowBrokenLinks = InputArgs.hasArg(Ids: OBJCOPY_allow_broken_links); |
1115 | |
1116 | Config.DeterministicArchives = InputArgs.hasFlag( |
1117 | Pos: OBJCOPY_enable_deterministic_archives, |
1118 | Neg: OBJCOPY_disable_deterministic_archives, /*default=*/Default: true); |
1119 | |
1120 | Config.PreserveDates = InputArgs.hasArg(Ids: OBJCOPY_preserve_dates); |
1121 | |
1122 | if (Config.PreserveDates && |
1123 | (Config.OutputFilename == "-" || Config.InputFilename == "-" )) |
1124 | return createStringError(EC: errc::invalid_argument, |
1125 | S: "--preserve-dates requires a file" ); |
1126 | |
1127 | for (auto *Arg : InputArgs) |
1128 | if (Arg->getOption().matches(ID: OBJCOPY_set_start)) { |
1129 | auto EAddr = getAsInteger<uint64_t>(Val: Arg->getValue()); |
1130 | if (!EAddr) |
1131 | return createStringError( |
1132 | EC: EAddr.getError(), Fmt: "bad entry point address: '%s'" , Vals: Arg->getValue()); |
1133 | |
1134 | ELFConfig.EntryExpr = [EAddr](uint64_t) { return *EAddr; }; |
1135 | } else if (Arg->getOption().matches(ID: OBJCOPY_change_start)) { |
1136 | auto EIncr = getAsInteger<int64_t>(Val: Arg->getValue()); |
1137 | if (!EIncr) |
1138 | return createStringError(EC: EIncr.getError(), |
1139 | Fmt: "bad entry point increment: '%s'" , |
1140 | Vals: Arg->getValue()); |
1141 | auto Expr = ELFConfig.EntryExpr ? std::move(ELFConfig.EntryExpr) |
1142 | : [](uint64_t A) { return A; }; |
1143 | ELFConfig.EntryExpr = [Expr, EIncr](uint64_t EAddr) { |
1144 | return Expr(EAddr) + *EIncr; |
1145 | }; |
1146 | } |
1147 | |
1148 | if (Config.DecompressDebugSections && |
1149 | Config.CompressionType != DebugCompressionType::None) { |
1150 | return createStringError( |
1151 | EC: errc::invalid_argument, |
1152 | S: "cannot specify both --compress-debug-sections and " |
1153 | "--decompress-debug-sections" ); |
1154 | } |
1155 | |
1156 | if (Config.ExtractPartition && Config.ExtractMainPartition) |
1157 | return createStringError(EC: errc::invalid_argument, |
1158 | S: "cannot specify --extract-partition together with " |
1159 | "--extract-main-partition" ); |
1160 | |
1161 | DC.CopyConfigs.push_back(Elt: std::move(ConfigMgr)); |
1162 | return std::move(DC); |
1163 | } |
1164 | |
1165 | // parseInstallNameToolOptions returns the config and sets the input arguments. |
1166 | // If a help flag is set then parseInstallNameToolOptions will print the help |
1167 | // messege and exit. |
1168 | Expected<DriverConfig> |
1169 | objcopy::parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) { |
1170 | DriverConfig DC; |
1171 | ConfigManager ConfigMgr; |
1172 | CommonConfig &Config = ConfigMgr.Common; |
1173 | MachOConfig &MachOConfig = ConfigMgr.MachO; |
1174 | InstallNameToolOptTable T; |
1175 | unsigned MissingArgumentIndex, MissingArgumentCount; |
1176 | llvm::opt::InputArgList InputArgs = |
1177 | T.ParseArgs(Args: ArgsArr, MissingArgIndex&: MissingArgumentIndex, MissingArgCount&: MissingArgumentCount); |
1178 | |
1179 | if (MissingArgumentCount) |
1180 | return createStringError( |
1181 | EC: errc::invalid_argument, |
1182 | S: "missing argument to " + |
1183 | StringRef(InputArgs.getArgString(Index: MissingArgumentIndex)) + |
1184 | " option" ); |
1185 | |
1186 | if (InputArgs.size() == 0) { |
1187 | printHelp(OptTable: T, OS&: errs(), Tool: ToolType::InstallNameTool); |
1188 | exit(status: 1); |
1189 | } |
1190 | |
1191 | if (InputArgs.hasArg(Ids: INSTALL_NAME_TOOL_help)) { |
1192 | printHelp(OptTable: T, OS&: outs(), Tool: ToolType::InstallNameTool); |
1193 | exit(status: 0); |
1194 | } |
1195 | |
1196 | if (InputArgs.hasArg(Ids: INSTALL_NAME_TOOL_version)) { |
1197 | outs() << "llvm-install-name-tool, compatible with cctools " |
1198 | "install_name_tool\n" ; |
1199 | cl::PrintVersionMessage(); |
1200 | exit(status: 0); |
1201 | } |
1202 | |
1203 | for (auto *Arg : InputArgs.filtered(Ids: INSTALL_NAME_TOOL_add_rpath)) |
1204 | MachOConfig.RPathToAdd.push_back(x: Arg->getValue()); |
1205 | |
1206 | for (auto *Arg : InputArgs.filtered(Ids: INSTALL_NAME_TOOL_prepend_rpath)) |
1207 | MachOConfig.RPathToPrepend.push_back(x: Arg->getValue()); |
1208 | |
1209 | for (auto *Arg : InputArgs.filtered(Ids: INSTALL_NAME_TOOL_delete_rpath)) { |
1210 | StringRef RPath = Arg->getValue(); |
1211 | |
1212 | // Cannot add and delete the same rpath at the same time. |
1213 | if (is_contained(Range&: MachOConfig.RPathToAdd, Element: RPath)) |
1214 | return createStringError( |
1215 | EC: errc::invalid_argument, |
1216 | Fmt: "cannot specify both -add_rpath '%s' and -delete_rpath '%s'" , |
1217 | Vals: RPath.str().c_str(), Vals: RPath.str().c_str()); |
1218 | if (is_contained(Range&: MachOConfig.RPathToPrepend, Element: RPath)) |
1219 | return createStringError( |
1220 | EC: errc::invalid_argument, |
1221 | Fmt: "cannot specify both -prepend_rpath '%s' and -delete_rpath '%s'" , |
1222 | Vals: RPath.str().c_str(), Vals: RPath.str().c_str()); |
1223 | |
1224 | MachOConfig.RPathsToRemove.insert(V: RPath); |
1225 | } |
1226 | |
1227 | for (auto *Arg : InputArgs.filtered(Ids: INSTALL_NAME_TOOL_rpath)) { |
1228 | StringRef Old = Arg->getValue(N: 0); |
1229 | StringRef New = Arg->getValue(N: 1); |
1230 | |
1231 | auto Match = [=](StringRef RPath) { return RPath == Old || RPath == New; }; |
1232 | |
1233 | // Cannot specify duplicate -rpath entries |
1234 | auto It1 = find_if( |
1235 | Range&: MachOConfig.RPathsToUpdate, |
1236 | P: [&Match](const DenseMap<StringRef, StringRef>::value_type &OldNew) { |
1237 | return Match(OldNew.getFirst()) || Match(OldNew.getSecond()); |
1238 | }); |
1239 | if (It1 != MachOConfig.RPathsToUpdate.end()) |
1240 | return createStringError(EC: errc::invalid_argument, |
1241 | S: "cannot specify both -rpath '" + |
1242 | It1->getFirst() + "' '" + It1->getSecond() + |
1243 | "' and -rpath '" + Old + "' '" + New + "'" ); |
1244 | |
1245 | // Cannot specify the same rpath under both -delete_rpath and -rpath |
1246 | auto It2 = find_if(Range&: MachOConfig.RPathsToRemove, P: Match); |
1247 | if (It2 != MachOConfig.RPathsToRemove.end()) |
1248 | return createStringError(EC: errc::invalid_argument, |
1249 | S: "cannot specify both -delete_rpath '" + *It2 + |
1250 | "' and -rpath '" + Old + "' '" + New + "'" ); |
1251 | |
1252 | // Cannot specify the same rpath under both -add_rpath and -rpath |
1253 | auto It3 = find_if(Range&: MachOConfig.RPathToAdd, P: Match); |
1254 | if (It3 != MachOConfig.RPathToAdd.end()) |
1255 | return createStringError(EC: errc::invalid_argument, |
1256 | S: "cannot specify both -add_rpath '" + *It3 + |
1257 | "' and -rpath '" + Old + "' '" + New + "'" ); |
1258 | |
1259 | // Cannot specify the same rpath under both -prepend_rpath and -rpath. |
1260 | auto It4 = find_if(Range&: MachOConfig.RPathToPrepend, P: Match); |
1261 | if (It4 != MachOConfig.RPathToPrepend.end()) |
1262 | return createStringError(EC: errc::invalid_argument, |
1263 | S: "cannot specify both -prepend_rpath '" + *It4 + |
1264 | "' and -rpath '" + Old + "' '" + New + "'" ); |
1265 | |
1266 | MachOConfig.RPathsToUpdate.insert(KV: {Old, New}); |
1267 | } |
1268 | |
1269 | if (auto *Arg = InputArgs.getLastArg(Ids: INSTALL_NAME_TOOL_id)) { |
1270 | MachOConfig.SharedLibId = Arg->getValue(); |
1271 | if (MachOConfig.SharedLibId->empty()) |
1272 | return createStringError(EC: errc::invalid_argument, |
1273 | S: "cannot specify an empty id" ); |
1274 | } |
1275 | |
1276 | for (auto *Arg : InputArgs.filtered(Ids: INSTALL_NAME_TOOL_change)) |
1277 | MachOConfig.InstallNamesToUpdate.insert( |
1278 | KV: {Arg->getValue(N: 0), Arg->getValue(N: 1)}); |
1279 | |
1280 | MachOConfig.RemoveAllRpaths = |
1281 | InputArgs.hasArg(Ids: INSTALL_NAME_TOOL_delete_all_rpaths); |
1282 | |
1283 | SmallVector<StringRef, 2> Positional; |
1284 | for (auto *Arg : InputArgs.filtered(Ids: INSTALL_NAME_TOOL_UNKNOWN)) |
1285 | return createStringError(EC: errc::invalid_argument, Fmt: "unknown argument '%s'" , |
1286 | Vals: Arg->getAsString(Args: InputArgs).c_str()); |
1287 | for (auto *Arg : InputArgs.filtered(Ids: INSTALL_NAME_TOOL_INPUT)) |
1288 | Positional.push_back(Elt: Arg->getValue()); |
1289 | if (Positional.empty()) |
1290 | return createStringError(EC: errc::invalid_argument, S: "no input file specified" ); |
1291 | if (Positional.size() > 1) |
1292 | return createStringError( |
1293 | EC: errc::invalid_argument, |
1294 | S: "llvm-install-name-tool expects a single input file" ); |
1295 | Config.InputFilename = Positional[0]; |
1296 | Config.OutputFilename = Positional[0]; |
1297 | |
1298 | Expected<OwningBinary<Binary>> BinaryOrErr = |
1299 | createBinary(Path: Config.InputFilename); |
1300 | if (!BinaryOrErr) |
1301 | return createFileError(F: Config.InputFilename, E: BinaryOrErr.takeError()); |
1302 | auto *Binary = (*BinaryOrErr).getBinary(); |
1303 | if (!Binary->isMachO() && !Binary->isMachOUniversalBinary()) |
1304 | return createStringError(EC: errc::invalid_argument, |
1305 | Fmt: "input file: %s is not a Mach-O file" , |
1306 | Vals: Config.InputFilename.str().c_str()); |
1307 | |
1308 | DC.CopyConfigs.push_back(Elt: std::move(ConfigMgr)); |
1309 | return std::move(DC); |
1310 | } |
1311 | |
1312 | Expected<DriverConfig> |
1313 | objcopy::parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr, |
1314 | function_ref<Error(Error)> ErrorCallback) { |
1315 | DriverConfig DC; |
1316 | ConfigManager ConfigMgr; |
1317 | CommonConfig &Config = ConfigMgr.Common; |
1318 | MachOConfig &MachOConfig = ConfigMgr.MachO; |
1319 | BitcodeStripOptTable T; |
1320 | unsigned MissingArgumentIndex, MissingArgumentCount; |
1321 | opt::InputArgList InputArgs = |
1322 | T.ParseArgs(Args: ArgsArr, MissingArgIndex&: MissingArgumentIndex, MissingArgCount&: MissingArgumentCount); |
1323 | |
1324 | if (InputArgs.size() == 0) { |
1325 | printHelp(OptTable: T, OS&: errs(), Tool: ToolType::BitcodeStrip); |
1326 | exit(status: 1); |
1327 | } |
1328 | |
1329 | if (InputArgs.hasArg(Ids: BITCODE_STRIP_help)) { |
1330 | printHelp(OptTable: T, OS&: outs(), Tool: ToolType::BitcodeStrip); |
1331 | exit(status: 0); |
1332 | } |
1333 | |
1334 | if (InputArgs.hasArg(Ids: BITCODE_STRIP_version)) { |
1335 | outs() << "llvm-bitcode-strip, compatible with cctools " |
1336 | "bitcode_strip\n" ; |
1337 | cl::PrintVersionMessage(); |
1338 | exit(status: 0); |
1339 | } |
1340 | |
1341 | for (auto *Arg : InputArgs.filtered(Ids: BITCODE_STRIP_UNKNOWN)) |
1342 | return createStringError(EC: errc::invalid_argument, Fmt: "unknown argument '%s'" , |
1343 | Vals: Arg->getAsString(Args: InputArgs).c_str()); |
1344 | |
1345 | SmallVector<StringRef, 2> Positional; |
1346 | for (auto *Arg : InputArgs.filtered(Ids: BITCODE_STRIP_INPUT)) |
1347 | Positional.push_back(Elt: Arg->getValue()); |
1348 | if (Positional.size() > 1) |
1349 | return createStringError(EC: errc::invalid_argument, |
1350 | S: "llvm-bitcode-strip expects a single input file" ); |
1351 | assert(!Positional.empty()); |
1352 | Config.InputFilename = Positional[0]; |
1353 | |
1354 | if (!InputArgs.hasArg(Ids: BITCODE_STRIP_output)) { |
1355 | return createStringError(EC: errc::invalid_argument, |
1356 | S: "-o is a required argument" ); |
1357 | } |
1358 | Config.OutputFilename = InputArgs.getLastArgValue(Id: BITCODE_STRIP_output); |
1359 | |
1360 | if (!InputArgs.hasArg(Ids: BITCODE_STRIP_remove)) |
1361 | return createStringError(EC: errc::invalid_argument, S: "no action specified" ); |
1362 | |
1363 | // We only support -r for now, which removes all bitcode sections and |
1364 | // the __LLVM segment if it's now empty. |
1365 | cantFail(Err: Config.ToRemove.addMatcher(Matcher: NameOrPattern::create( |
1366 | Pattern: "__LLVM,__asm" , MS: MatchStyle::Literal, ErrorCallback))); |
1367 | cantFail(Err: Config.ToRemove.addMatcher(Matcher: NameOrPattern::create( |
1368 | Pattern: "__LLVM,__bitcode" , MS: MatchStyle::Literal, ErrorCallback))); |
1369 | cantFail(Err: Config.ToRemove.addMatcher(Matcher: NameOrPattern::create( |
1370 | Pattern: "__LLVM,__bundle" , MS: MatchStyle::Literal, ErrorCallback))); |
1371 | cantFail(Err: Config.ToRemove.addMatcher(Matcher: NameOrPattern::create( |
1372 | Pattern: "__LLVM,__cmdline" , MS: MatchStyle::Literal, ErrorCallback))); |
1373 | cantFail(Err: Config.ToRemove.addMatcher(Matcher: NameOrPattern::create( |
1374 | Pattern: "__LLVM,__swift_cmdline" , MS: MatchStyle::Literal, ErrorCallback))); |
1375 | MachOConfig.EmptySegmentsToRemove.insert(V: "__LLVM" ); |
1376 | |
1377 | DC.CopyConfigs.push_back(Elt: std::move(ConfigMgr)); |
1378 | return std::move(DC); |
1379 | } |
1380 | |
1381 | // parseStripOptions returns the config and sets the input arguments. If a |
1382 | // help flag is set then parseStripOptions will print the help messege and |
1383 | // exit. |
1384 | Expected<DriverConfig> |
1385 | objcopy::parseStripOptions(ArrayRef<const char *> RawArgsArr, |
1386 | function_ref<Error(Error)> ErrorCallback) { |
1387 | const char *const *DashDash = |
1388 | llvm::find_if(Range&: RawArgsArr, P: [](StringRef Str) { return Str == "--" ; }); |
1389 | ArrayRef<const char *> ArgsArr = ArrayRef(RawArgsArr.begin(), DashDash); |
1390 | if (DashDash != RawArgsArr.end()) |
1391 | DashDash = std::next(x: DashDash); |
1392 | |
1393 | StripOptTable T; |
1394 | unsigned MissingArgumentIndex, MissingArgumentCount; |
1395 | llvm::opt::InputArgList InputArgs = |
1396 | T.ParseArgs(Args: ArgsArr, MissingArgIndex&: MissingArgumentIndex, MissingArgCount&: MissingArgumentCount); |
1397 | |
1398 | if (InputArgs.size() == 0 && DashDash == RawArgsArr.end()) { |
1399 | printHelp(OptTable: T, OS&: errs(), Tool: ToolType::Strip); |
1400 | exit(status: 1); |
1401 | } |
1402 | |
1403 | if (InputArgs.hasArg(Ids: STRIP_help)) { |
1404 | printHelp(OptTable: T, OS&: outs(), Tool: ToolType::Strip); |
1405 | exit(status: 0); |
1406 | } |
1407 | |
1408 | if (InputArgs.hasArg(Ids: STRIP_version)) { |
1409 | outs() << "llvm-strip, compatible with GNU strip\n" ; |
1410 | cl::PrintVersionMessage(); |
1411 | exit(status: 0); |
1412 | } |
1413 | |
1414 | SmallVector<StringRef, 2> Positional; |
1415 | for (auto *Arg : InputArgs.filtered(Ids: STRIP_UNKNOWN)) |
1416 | return createStringError(EC: errc::invalid_argument, Fmt: "unknown argument '%s'" , |
1417 | Vals: Arg->getAsString(Args: InputArgs).c_str()); |
1418 | for (auto *Arg : InputArgs.filtered(Ids: STRIP_INPUT)) |
1419 | Positional.push_back(Elt: Arg->getValue()); |
1420 | std::copy(DashDash, RawArgsArr.end(), std::back_inserter(x&: Positional)); |
1421 | |
1422 | if (Positional.empty()) |
1423 | return createStringError(EC: errc::invalid_argument, S: "no input file specified" ); |
1424 | |
1425 | if (Positional.size() > 1 && InputArgs.hasArg(Ids: STRIP_output)) |
1426 | return createStringError( |
1427 | EC: errc::invalid_argument, |
1428 | S: "multiple input files cannot be used in combination with -o" ); |
1429 | |
1430 | ConfigManager ConfigMgr; |
1431 | CommonConfig &Config = ConfigMgr.Common; |
1432 | ELFConfig &ELFConfig = ConfigMgr.ELF; |
1433 | MachOConfig &MachOConfig = ConfigMgr.MachO; |
1434 | |
1435 | if (InputArgs.hasArg(Ids: STRIP_regex) && InputArgs.hasArg(Ids: STRIP_wildcard)) |
1436 | return createStringError(EC: errc::invalid_argument, |
1437 | S: "--regex and --wildcard are incompatible" ); |
1438 | MatchStyle SectionMatchStyle = |
1439 | InputArgs.hasArg(Ids: STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard; |
1440 | MatchStyle SymbolMatchStyle |
1441 | = InputArgs.hasArg(Ids: STRIP_regex) ? MatchStyle::Regex |
1442 | : InputArgs.hasArg(Ids: STRIP_wildcard) ? MatchStyle::Wildcard |
1443 | : MatchStyle::Literal; |
1444 | ELFConfig.AllowBrokenLinks = InputArgs.hasArg(Ids: STRIP_allow_broken_links); |
1445 | Config.StripDebug = InputArgs.hasArg(Ids: STRIP_strip_debug); |
1446 | |
1447 | if (auto *Arg = InputArgs.getLastArg(Ids: STRIP_discard_all, Ids: STRIP_discard_locals)) |
1448 | Config.DiscardMode = Arg->getOption().matches(ID: STRIP_discard_all) |
1449 | ? DiscardType::All |
1450 | : DiscardType::Locals; |
1451 | Config.StripSections = InputArgs.hasArg(Ids: STRIP_strip_sections); |
1452 | Config.StripUnneeded = InputArgs.hasArg(Ids: STRIP_strip_unneeded); |
1453 | if (auto Arg = InputArgs.getLastArg(Ids: STRIP_strip_all, Ids: STRIP_no_strip_all)) |
1454 | Config.StripAll = Arg->getOption().getID() == STRIP_strip_all; |
1455 | Config.StripAllGNU = InputArgs.hasArg(Ids: STRIP_strip_all_gnu); |
1456 | MachOConfig.StripSwiftSymbols = InputArgs.hasArg(Ids: STRIP_strip_swift_symbols); |
1457 | Config.OnlyKeepDebug = InputArgs.hasArg(Ids: STRIP_only_keep_debug); |
1458 | ELFConfig.KeepFileSymbols = InputArgs.hasArg(Ids: STRIP_keep_file_symbols); |
1459 | MachOConfig.KeepUndefined = InputArgs.hasArg(Ids: STRIP_keep_undefined); |
1460 | |
1461 | for (auto *Arg : InputArgs.filtered(Ids: STRIP_keep_section)) |
1462 | if (Error E = Config.KeepSection.addMatcher(Matcher: NameOrPattern::create( |
1463 | Pattern: Arg->getValue(), MS: SectionMatchStyle, ErrorCallback))) |
1464 | return std::move(E); |
1465 | |
1466 | for (auto *Arg : InputArgs.filtered(Ids: STRIP_remove_section)) |
1467 | if (Error E = Config.ToRemove.addMatcher(Matcher: NameOrPattern::create( |
1468 | Pattern: Arg->getValue(), MS: SectionMatchStyle, ErrorCallback))) |
1469 | return std::move(E); |
1470 | |
1471 | for (auto *Arg : InputArgs.filtered(Ids: STRIP_strip_symbol)) |
1472 | if (Error E = Config.SymbolsToRemove.addMatcher(Matcher: NameOrPattern::create( |
1473 | Pattern: Arg->getValue(), MS: SymbolMatchStyle, ErrorCallback))) |
1474 | return std::move(E); |
1475 | |
1476 | for (auto *Arg : InputArgs.filtered(Ids: STRIP_keep_symbol)) |
1477 | if (Error E = Config.SymbolsToKeep.addMatcher(Matcher: NameOrPattern::create( |
1478 | Pattern: Arg->getValue(), MS: SymbolMatchStyle, ErrorCallback))) |
1479 | return std::move(E); |
1480 | |
1481 | if (!InputArgs.hasArg(Ids: STRIP_no_strip_all) && !Config.StripDebug && |
1482 | !Config.OnlyKeepDebug && !Config.StripUnneeded && |
1483 | Config.DiscardMode == DiscardType::None && !Config.StripAllGNU && |
1484 | Config.SymbolsToRemove.empty()) |
1485 | Config.StripAll = true; |
1486 | |
1487 | if (Config.DiscardMode == DiscardType::All) { |
1488 | Config.StripDebug = true; |
1489 | ELFConfig.KeepFileSymbols = true; |
1490 | } |
1491 | |
1492 | Config.DeterministicArchives = |
1493 | InputArgs.hasFlag(Pos: STRIP_enable_deterministic_archives, |
1494 | Neg: STRIP_disable_deterministic_archives, /*default=*/Default: true); |
1495 | |
1496 | Config.PreserveDates = InputArgs.hasArg(Ids: STRIP_preserve_dates); |
1497 | Config.InputFormat = FileFormat::Unspecified; |
1498 | Config.OutputFormat = FileFormat::Unspecified; |
1499 | |
1500 | DriverConfig DC; |
1501 | if (Positional.size() == 1) { |
1502 | Config.InputFilename = Positional[0]; |
1503 | Config.OutputFilename = |
1504 | InputArgs.getLastArgValue(Id: STRIP_output, Default: Positional[0]); |
1505 | DC.CopyConfigs.push_back(Elt: std::move(ConfigMgr)); |
1506 | } else { |
1507 | StringMap<unsigned> InputFiles; |
1508 | for (StringRef Filename : Positional) { |
1509 | if (InputFiles[Filename]++ == 1) { |
1510 | if (Filename == "-" ) |
1511 | return createStringError( |
1512 | EC: errc::invalid_argument, |
1513 | S: "cannot specify '-' as an input file more than once" ); |
1514 | if (Error E = ErrorCallback(createStringError( |
1515 | EC: errc::invalid_argument, Fmt: "'%s' was already specified" , |
1516 | Vals: Filename.str().c_str()))) |
1517 | return std::move(E); |
1518 | } |
1519 | Config.InputFilename = Filename; |
1520 | Config.OutputFilename = Filename; |
1521 | DC.CopyConfigs.push_back(Elt: ConfigMgr); |
1522 | } |
1523 | } |
1524 | |
1525 | if (Config.PreserveDates && (is_contained(Range&: Positional, Element: "-" ) || |
1526 | InputArgs.getLastArgValue(Id: STRIP_output) == "-" )) |
1527 | return createStringError(EC: errc::invalid_argument, |
1528 | S: "--preserve-dates requires a file" ); |
1529 | |
1530 | return std::move(DC); |
1531 | } |
1532 | |