File: | build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/tools/llvm-nm/llvm-nm.cpp |
Warning: | line 352, column 9 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- llvm-nm.cpp - Symbol table dumping utility for llvm ---------------===// | |||
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 | // This program is a utility that works like traditional Unix "nm", that is, it | |||
10 | // prints out the names of symbols in a bitcode or object file, along with some | |||
11 | // information about each symbol. | |||
12 | // | |||
13 | // This "nm" supports many of the features of GNU "nm", including its different | |||
14 | // output formats. | |||
15 | // | |||
16 | //===----------------------------------------------------------------------===// | |||
17 | ||||
18 | #include "llvm/ADT/StringSwitch.h" | |||
19 | #include "llvm/BinaryFormat/COFF.h" | |||
20 | #include "llvm/BinaryFormat/XCOFF.h" | |||
21 | #include "llvm/Demangle/Demangle.h" | |||
22 | #include "llvm/IR/Function.h" | |||
23 | #include "llvm/IR/LLVMContext.h" | |||
24 | #include "llvm/Object/Archive.h" | |||
25 | #include "llvm/Object/COFF.h" | |||
26 | #include "llvm/Object/COFFImportFile.h" | |||
27 | #include "llvm/Object/ELFObjectFile.h" | |||
28 | #include "llvm/Object/IRObjectFile.h" | |||
29 | #include "llvm/Object/MachO.h" | |||
30 | #include "llvm/Object/MachOUniversal.h" | |||
31 | #include "llvm/Object/ObjectFile.h" | |||
32 | #include "llvm/Object/TapiFile.h" | |||
33 | #include "llvm/Object/TapiUniversal.h" | |||
34 | #include "llvm/Object/Wasm.h" | |||
35 | #include "llvm/Object/XCOFFObjectFile.h" | |||
36 | #include "llvm/Option/Arg.h" | |||
37 | #include "llvm/Option/ArgList.h" | |||
38 | #include "llvm/Option/Option.h" | |||
39 | #include "llvm/Support/CommandLine.h" | |||
40 | #include "llvm/Support/FileSystem.h" | |||
41 | #include "llvm/Support/Format.h" | |||
42 | #include "llvm/Support/InitLLVM.h" | |||
43 | #include "llvm/Support/MemoryBuffer.h" | |||
44 | #include "llvm/Support/Program.h" | |||
45 | #include "llvm/Support/Signals.h" | |||
46 | #include "llvm/Support/TargetSelect.h" | |||
47 | #include "llvm/Support/WithColor.h" | |||
48 | #include "llvm/Support/raw_ostream.h" | |||
49 | #include <vector> | |||
50 | ||||
51 | using namespace llvm; | |||
52 | using namespace object; | |||
53 | ||||
54 | namespace { | |||
55 | using namespace llvm::opt; // for HelpHidden in Opts.inc | |||
56 | enum ID { | |||
57 | OPT_INVALID = 0, // This is not an option ID. | |||
58 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ | |||
59 | HELPTEXT, METAVAR, VALUES) \ | |||
60 | OPT_##ID, | |||
61 | #include "Opts.inc" | |||
62 | #undef OPTION | |||
63 | }; | |||
64 | ||||
65 | #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; | |||
66 | #include "Opts.inc" | |||
67 | #undef PREFIX | |||
68 | ||||
69 | const opt::OptTable::Info InfoTable[] = { | |||
70 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ | |||
71 | HELPTEXT, METAVAR, VALUES) \ | |||
72 | { \ | |||
73 | PREFIX, NAME, HELPTEXT, \ | |||
74 | METAVAR, OPT_##ID, opt::Option::KIND##Class, \ | |||
75 | PARAM, FLAGS, OPT_##GROUP, \ | |||
76 | OPT_##ALIAS, ALIASARGS, VALUES}, | |||
77 | #include "Opts.inc" | |||
78 | #undef OPTION | |||
79 | }; | |||
80 | ||||
81 | class NmOptTable : public opt::OptTable { | |||
82 | public: | |||
83 | NmOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); } | |||
84 | }; | |||
85 | ||||
86 | enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols }; | |||
87 | enum class BitModeTy { Bit32, Bit64, Bit32_64, Any }; | |||
88 | } // namespace | |||
89 | ||||
90 | static bool ArchiveMap; | |||
91 | static BitModeTy BitMode; | |||
92 | static bool DebugSyms; | |||
93 | static bool DefinedOnly; | |||
94 | static bool Demangle; | |||
95 | static bool DynamicSyms; | |||
96 | static bool ExportSymbols; | |||
97 | static bool ExternalOnly; | |||
98 | static OutputFormatTy OutputFormat; | |||
99 | static bool NoLLVMBitcode; | |||
100 | static bool NoSort; | |||
101 | static bool NoWeakSymbols; | |||
102 | static bool NumericSort; | |||
103 | static bool PrintFileName; | |||
104 | static bool PrintSize; | |||
105 | static bool Quiet; | |||
106 | static bool ReverseSort; | |||
107 | static bool SpecialSyms; | |||
108 | static bool SizeSort; | |||
109 | static bool UndefinedOnly; | |||
110 | static bool WithoutAliases; | |||
111 | ||||
112 | // XCOFF-specific options. | |||
113 | static bool NoRsrc; | |||
114 | ||||
115 | namespace { | |||
116 | enum Radix { d, o, x }; | |||
117 | } // namespace | |||
118 | static Radix AddressRadix; | |||
119 | ||||
120 | // Mach-O specific options. | |||
121 | static bool ArchAll = false; | |||
122 | static std::vector<StringRef> ArchFlags; | |||
123 | static bool AddDyldInfo; | |||
124 | static bool AddInlinedInfo; | |||
125 | static bool DyldInfoOnly; | |||
126 | static bool FormatMachOasHex; | |||
127 | static bool NoDyldInfo; | |||
128 | static std::vector<StringRef> SegSect; | |||
129 | static bool MachOPrintSizeWarning = false; | |||
130 | ||||
131 | // Miscellaneous states. | |||
132 | static bool PrintAddress = true; | |||
133 | static bool MultipleFiles = false; | |||
134 | static bool HadError = false; | |||
135 | ||||
136 | static StringRef ToolName; | |||
137 | ||||
138 | static void warn(Error Err, Twine FileName, Twine Context = Twine(), | |||
139 | Twine Archive = Twine()) { | |||
140 | assert(Err)(static_cast <bool> (Err) ? void (0) : __assert_fail ("Err" , "llvm/tools/llvm-nm/llvm-nm.cpp", 140, __extension__ __PRETTY_FUNCTION__ )); | |||
141 | ||||
142 | // Flush the standard output so that the warning isn't interleaved with other | |||
143 | // output if stdout and stderr are writing to the same place. | |||
144 | outs().flush(); | |||
145 | ||||
146 | handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) { | |||
147 | WithColor::warning(errs(), ToolName) | |||
148 | << (Archive.str().empty() ? FileName : Archive + "(" + FileName + ")") | |||
149 | << ": " << (Context.str().empty() ? "" : Context + ": ") << EI.message() | |||
150 | << "\n"; | |||
151 | }); | |||
152 | } | |||
153 | ||||
154 | static void error(Twine Message, Twine Path = Twine()) { | |||
155 | HadError = true; | |||
156 | WithColor::error(errs(), ToolName) << Path << ": " << Message << "\n"; | |||
157 | } | |||
158 | ||||
159 | static bool error(std::error_code EC, Twine Path = Twine()) { | |||
160 | if (EC) { | |||
161 | error(EC.message(), Path); | |||
162 | return true; | |||
163 | } | |||
164 | return false; | |||
165 | } | |||
166 | ||||
167 | // This version of error() prints the archive name and member name, for example: | |||
168 | // "libx.a(foo.o)" after the ToolName before the error message. It sets | |||
169 | // HadError but returns allowing the code to move on to other archive members. | |||
170 | static void error(llvm::Error E, StringRef FileName, const Archive::Child &C, | |||
171 | StringRef ArchitectureName = StringRef()) { | |||
172 | HadError = true; | |||
173 | WithColor::error(errs(), ToolName) << FileName; | |||
174 | ||||
175 | Expected<StringRef> NameOrErr = C.getName(); | |||
176 | // TODO: if we have a error getting the name then it would be nice to print | |||
177 | // the index of which archive member this is and or its offset in the | |||
178 | // archive instead of "???" as the name. | |||
179 | if (!NameOrErr) { | |||
180 | consumeError(NameOrErr.takeError()); | |||
181 | errs() << "(" << "???" << ")"; | |||
182 | } else | |||
183 | errs() << "(" << NameOrErr.get() << ")"; | |||
184 | ||||
185 | if (!ArchitectureName.empty()) | |||
186 | errs() << " (for architecture " << ArchitectureName << ")"; | |||
187 | ||||
188 | std::string Buf; | |||
189 | raw_string_ostream OS(Buf); | |||
190 | logAllUnhandledErrors(std::move(E), OS); | |||
191 | OS.flush(); | |||
192 | errs() << ": " << Buf << "\n"; | |||
193 | } | |||
194 | ||||
195 | // This version of error() prints the file name and which architecture slice it | |||
196 | // is from, for example: "foo.o (for architecture i386)" after the ToolName | |||
197 | // before the error message. It sets HadError but returns allowing the code to | |||
198 | // move on to other architecture slices. | |||
199 | static void error(llvm::Error E, StringRef FileName, | |||
200 | StringRef ArchitectureName = StringRef()) { | |||
201 | HadError = true; | |||
202 | WithColor::error(errs(), ToolName) << FileName; | |||
203 | ||||
204 | if (!ArchitectureName.empty()) | |||
205 | errs() << " (for architecture " << ArchitectureName << ")"; | |||
206 | ||||
207 | std::string Buf; | |||
208 | raw_string_ostream OS(Buf); | |||
209 | logAllUnhandledErrors(std::move(E), OS); | |||
210 | OS.flush(); | |||
211 | errs() << ": " << Buf << "\n"; | |||
212 | } | |||
213 | ||||
214 | namespace { | |||
215 | struct NMSymbol { | |||
216 | uint64_t Address; | |||
217 | uint64_t Size; | |||
218 | char TypeChar; | |||
219 | std::string Name; | |||
220 | StringRef SectionName; | |||
221 | StringRef TypeName; | |||
222 | BasicSymbolRef Sym; | |||
223 | StringRef Visibility; | |||
224 | ||||
225 | // The Sym field above points to the native symbol in the object file, | |||
226 | // for Mach-O when we are creating symbols from the dyld info the above | |||
227 | // pointer is null as there is no native symbol. In these cases the fields | |||
228 | // below are filled in to represent what would have been a Mach-O nlist | |||
229 | // native symbol. | |||
230 | uint32_t SymFlags; | |||
231 | SectionRef Section; | |||
232 | uint8_t NType; | |||
233 | uint8_t NSect; | |||
234 | uint16_t NDesc; | |||
235 | std::string IndirectName; | |||
236 | ||||
237 | bool isDefined() const { | |||
238 | if (Sym.getRawDataRefImpl().p) { | |||
239 | uint32_t Flags = cantFail(Sym.getFlags()); | |||
240 | return !(Flags & SymbolRef::SF_Undefined); | |||
241 | } | |||
242 | return TypeChar != 'U'; | |||
243 | } | |||
244 | ||||
245 | bool initializeFlags(const SymbolicFile &Obj) { | |||
246 | Expected<uint32_t> SymFlagsOrErr = Sym.getFlags(); | |||
247 | if (!SymFlagsOrErr) { | |||
248 | // TODO: Test this error. | |||
249 | error(SymFlagsOrErr.takeError(), Obj.getFileName()); | |||
250 | return false; | |||
251 | } | |||
252 | SymFlags = *SymFlagsOrErr; | |||
253 | return true; | |||
254 | } | |||
255 | ||||
256 | bool shouldPrint() const { | |||
257 | bool Undefined = SymFlags & SymbolRef::SF_Undefined; | |||
258 | bool Global = SymFlags & SymbolRef::SF_Global; | |||
259 | bool Weak = SymFlags & SymbolRef::SF_Weak; | |||
260 | bool FormatSpecific = SymFlags & SymbolRef::SF_FormatSpecific; | |||
261 | if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) || | |||
262 | (!Global && ExternalOnly) || (Weak && NoWeakSymbols) || | |||
263 | (FormatSpecific && !(SpecialSyms || DebugSyms))) | |||
264 | return false; | |||
265 | return true; | |||
266 | } | |||
267 | }; | |||
268 | ||||
269 | bool operator<(const NMSymbol &A, const NMSymbol &B) { | |||
270 | if (NumericSort) | |||
271 | return std::make_tuple(A.isDefined(), A.Address, A.Name, A.Size) < | |||
272 | std::make_tuple(B.isDefined(), B.Address, B.Name, B.Size); | |||
273 | if (SizeSort) | |||
274 | return std::make_tuple(A.Size, A.Name, A.Address) < | |||
275 | std::make_tuple(B.Size, B.Name, B.Address); | |||
276 | if (ExportSymbols) | |||
277 | return std::make_tuple(A.Name, A.Visibility) < | |||
278 | std::make_tuple(B.Name, B.Visibility); | |||
279 | return std::make_tuple(A.Name, A.Size, A.Address) < | |||
280 | std::make_tuple(B.Name, B.Size, B.Address); | |||
281 | } | |||
282 | ||||
283 | bool operator>(const NMSymbol &A, const NMSymbol &B) { return B < A; } | |||
284 | bool operator==(const NMSymbol &A, const NMSymbol &B) { | |||
285 | return !(A < B) && !(B < A); | |||
286 | } | |||
287 | } // anonymous namespace | |||
288 | ||||
289 | static char isSymbolList64Bit(SymbolicFile &Obj) { | |||
290 | if (auto *IRObj = dyn_cast<IRObjectFile>(&Obj)) | |||
291 | return Triple(IRObj->getTargetTriple()).isArch64Bit(); | |||
292 | if (isa<COFFObjectFile>(Obj) || isa<COFFImportFile>(Obj)) | |||
293 | return false; | |||
294 | if (XCOFFObjectFile *XCOFFObj = dyn_cast<XCOFFObjectFile>(&Obj)) | |||
295 | return XCOFFObj->is64Bit(); | |||
296 | if (isa<WasmObjectFile>(Obj)) | |||
297 | return false; | |||
298 | if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj)) | |||
299 | return Tapi->is64Bit(); | |||
300 | if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj)) | |||
301 | return MachO->is64Bit(); | |||
302 | return cast<ELFObjectFileBase>(Obj).getBytesInAddress() == 8; | |||
303 | } | |||
304 | ||||
305 | static StringRef CurrentFilename; | |||
306 | ||||
307 | static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I); | |||
308 | ||||
309 | // darwinPrintSymbol() is used to print a symbol from a Mach-O file when the | |||
310 | // the OutputFormat is darwin or we are printing Mach-O symbols in hex. For | |||
311 | // the darwin format it produces the same output as darwin's nm(1) -m output | |||
312 | // and when printing Mach-O symbols in hex it produces the same output as | |||
313 | // darwin's nm(1) -x format. | |||
314 | static void darwinPrintSymbol(SymbolicFile &Obj, const NMSymbol &S, | |||
315 | char *SymbolAddrStr, const char *printBlanks, | |||
316 | const char *printDashes, | |||
317 | const char *printFormat) { | |||
318 | MachO::mach_header H; | |||
319 | MachO::mach_header_64 H_64; | |||
320 | uint32_t Filetype = MachO::MH_OBJECT; | |||
321 | uint32_t Flags = 0; | |||
322 | uint8_t NType = 0; | |||
323 | uint8_t NSect = 0; | |||
324 | uint16_t NDesc = 0; | |||
325 | uint32_t NStrx = 0; | |||
326 | uint64_t NValue = 0; | |||
327 | MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj); | |||
| ||||
328 | if (Obj.isIR()) { | |||
329 | uint32_t SymFlags = cantFail(S.Sym.getFlags()); | |||
330 | if (SymFlags & SymbolRef::SF_Global) | |||
331 | NType |= MachO::N_EXT; | |||
332 | if (SymFlags & SymbolRef::SF_Hidden) | |||
333 | NType |= MachO::N_PEXT; | |||
334 | if (SymFlags & SymbolRef::SF_Undefined) | |||
335 | NType |= MachO::N_EXT | MachO::N_UNDF; | |||
336 | else { | |||
337 | // Here we have a symbol definition. So to fake out a section name we | |||
338 | // use 1, 2 and 3 for section numbers. See below where they are used to | |||
339 | // print out fake section names. | |||
340 | NType |= MachO::N_SECT; | |||
341 | if (SymFlags & SymbolRef::SF_Const) | |||
342 | NSect = 3; | |||
343 | else if (SymFlags & SymbolRef::SF_Executable) | |||
344 | NSect = 1; | |||
345 | else | |||
346 | NSect = 2; | |||
347 | } | |||
348 | if (SymFlags & SymbolRef::SF_Weak) | |||
349 | NDesc |= MachO::N_WEAK_DEF; | |||
350 | } else { | |||
351 | DataRefImpl SymDRI = S.Sym.getRawDataRefImpl(); | |||
352 | if (MachO->is64Bit()) { | |||
| ||||
353 | H_64 = MachO->MachOObjectFile::getHeader64(); | |||
354 | Filetype = H_64.filetype; | |||
355 | Flags = H_64.flags; | |||
356 | if (SymDRI.p){ | |||
357 | MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI); | |||
358 | NType = STE_64.n_type; | |||
359 | NSect = STE_64.n_sect; | |||
360 | NDesc = STE_64.n_desc; | |||
361 | NStrx = STE_64.n_strx; | |||
362 | NValue = STE_64.n_value; | |||
363 | } else { | |||
364 | NType = S.NType; | |||
365 | NSect = S.NSect; | |||
366 | NDesc = S.NDesc; | |||
367 | NStrx = 0; | |||
368 | NValue = S.Address; | |||
369 | } | |||
370 | } else { | |||
371 | H = MachO->MachOObjectFile::getHeader(); | |||
372 | Filetype = H.filetype; | |||
373 | Flags = H.flags; | |||
374 | if (SymDRI.p){ | |||
375 | MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI); | |||
376 | NType = STE.n_type; | |||
377 | NSect = STE.n_sect; | |||
378 | NDesc = STE.n_desc; | |||
379 | NStrx = STE.n_strx; | |||
380 | NValue = STE.n_value; | |||
381 | } else { | |||
382 | NType = S.NType; | |||
383 | NSect = S.NSect; | |||
384 | NDesc = S.NDesc; | |||
385 | NStrx = 0; | |||
386 | NValue = S.Address; | |||
387 | } | |||
388 | } | |||
389 | } | |||
390 | ||||
391 | // If we are printing Mach-O symbols in hex do that and return. | |||
392 | if (FormatMachOasHex) { | |||
393 | outs() << format(printFormat, NValue) << ' ' | |||
394 | << format("%02x %02x %04x %08x", NType, NSect, NDesc, NStrx) << ' ' | |||
395 | << S.Name; | |||
396 | if ((NType & MachO::N_TYPE) == MachO::N_INDR) { | |||
397 | outs() << " (indirect for "; | |||
398 | outs() << format(printFormat, NValue) << ' '; | |||
399 | StringRef IndirectName; | |||
400 | if (S.Sym.getRawDataRefImpl().p) { | |||
401 | if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName)) | |||
402 | outs() << "?)"; | |||
403 | else | |||
404 | outs() << IndirectName << ")"; | |||
405 | } else | |||
406 | outs() << S.IndirectName << ")"; | |||
407 | } | |||
408 | outs() << "\n"; | |||
409 | return; | |||
410 | } | |||
411 | ||||
412 | if (PrintAddress) { | |||
413 | if ((NType & MachO::N_TYPE) == MachO::N_INDR) | |||
414 | strcpy(SymbolAddrStr, printBlanks); | |||
415 | if (Obj.isIR() && (NType & MachO::N_TYPE) == MachO::N_TYPE) | |||
416 | strcpy(SymbolAddrStr, printDashes); | |||
417 | outs() << SymbolAddrStr << ' '; | |||
418 | } | |||
419 | ||||
420 | switch (NType & MachO::N_TYPE) { | |||
421 | case MachO::N_UNDF: | |||
422 | if (NValue != 0) { | |||
423 | outs() << "(common) "; | |||
424 | if (MachO::GET_COMM_ALIGN(NDesc) != 0) | |||
425 | outs() << "(alignment 2^" << (int)MachO::GET_COMM_ALIGN(NDesc) << ") "; | |||
426 | } else { | |||
427 | if ((NType & MachO::N_TYPE) == MachO::N_PBUD) | |||
428 | outs() << "(prebound "; | |||
429 | else | |||
430 | outs() << "("; | |||
431 | if ((NDesc & MachO::REFERENCE_TYPE) == | |||
432 | MachO::REFERENCE_FLAG_UNDEFINED_LAZY) | |||
433 | outs() << "undefined [lazy bound]) "; | |||
434 | else if ((NDesc & MachO::REFERENCE_TYPE) == | |||
435 | MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY) | |||
436 | outs() << "undefined [private lazy bound]) "; | |||
437 | else if ((NDesc & MachO::REFERENCE_TYPE) == | |||
438 | MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY) | |||
439 | outs() << "undefined [private]) "; | |||
440 | else | |||
441 | outs() << "undefined) "; | |||
442 | } | |||
443 | break; | |||
444 | case MachO::N_ABS: | |||
445 | outs() << "(absolute) "; | |||
446 | break; | |||
447 | case MachO::N_INDR: | |||
448 | outs() << "(indirect) "; | |||
449 | break; | |||
450 | case MachO::N_SECT: { | |||
451 | if (Obj.isIR()) { | |||
452 | // For llvm bitcode files print out a fake section name using the values | |||
453 | // use 1, 2 and 3 for section numbers as set above. | |||
454 | if (NSect == 1) | |||
455 | outs() << "(LTO,CODE) "; | |||
456 | else if (NSect == 2) | |||
457 | outs() << "(LTO,DATA) "; | |||
458 | else if (NSect == 3) | |||
459 | outs() << "(LTO,RODATA) "; | |||
460 | else | |||
461 | outs() << "(?,?) "; | |||
462 | break; | |||
463 | } | |||
464 | section_iterator Sec = SectionRef(); | |||
465 | if (S.Sym.getRawDataRefImpl().p) { | |||
466 | Expected<section_iterator> SecOrErr = | |||
467 | MachO->getSymbolSection(S.Sym.getRawDataRefImpl()); | |||
468 | if (!SecOrErr) { | |||
469 | consumeError(SecOrErr.takeError()); | |||
470 | outs() << "(?,?) "; | |||
471 | break; | |||
472 | } | |||
473 | Sec = *SecOrErr; | |||
474 | if (Sec == MachO->section_end()) { | |||
475 | outs() << "(?,?) "; | |||
476 | break; | |||
477 | } | |||
478 | } else { | |||
479 | Sec = S.Section; | |||
480 | } | |||
481 | DataRefImpl Ref = Sec->getRawDataRefImpl(); | |||
482 | StringRef SectionName; | |||
483 | if (Expected<StringRef> NameOrErr = MachO->getSectionName(Ref)) | |||
484 | SectionName = *NameOrErr; | |||
485 | StringRef SegmentName = MachO->getSectionFinalSegmentName(Ref); | |||
486 | outs() << "(" << SegmentName << "," << SectionName << ") "; | |||
487 | break; | |||
488 | } | |||
489 | default: | |||
490 | outs() << "(?) "; | |||
491 | break; | |||
492 | } | |||
493 | ||||
494 | if (NType & MachO::N_EXT) { | |||
495 | if (NDesc & MachO::REFERENCED_DYNAMICALLY) | |||
496 | outs() << "[referenced dynamically] "; | |||
497 | if (NType & MachO::N_PEXT) { | |||
498 | if ((NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF) | |||
499 | outs() << "weak private external "; | |||
500 | else | |||
501 | outs() << "private external "; | |||
502 | } else { | |||
503 | if ((NDesc & MachO::N_WEAK_REF) == MachO::N_WEAK_REF || | |||
504 | (NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF) { | |||
505 | if ((NDesc & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) == | |||
506 | (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) | |||
507 | outs() << "weak external automatically hidden "; | |||
508 | else | |||
509 | outs() << "weak external "; | |||
510 | } else | |||
511 | outs() << "external "; | |||
512 | } | |||
513 | } else { | |||
514 | if (NType & MachO::N_PEXT) | |||
515 | outs() << "non-external (was a private external) "; | |||
516 | else | |||
517 | outs() << "non-external "; | |||
518 | } | |||
519 | ||||
520 | if (Filetype == MachO::MH_OBJECT) { | |||
521 | if (NDesc & MachO::N_NO_DEAD_STRIP) | |||
522 | outs() << "[no dead strip] "; | |||
523 | if ((NType & MachO::N_TYPE) != MachO::N_UNDF && | |||
524 | NDesc & MachO::N_SYMBOL_RESOLVER) | |||
525 | outs() << "[symbol resolver] "; | |||
526 | if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_ALT_ENTRY) | |||
527 | outs() << "[alt entry] "; | |||
528 | if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_COLD_FUNC) | |||
529 | outs() << "[cold func] "; | |||
530 | } | |||
531 | ||||
532 | if ((NDesc & MachO::N_ARM_THUMB_DEF) == MachO::N_ARM_THUMB_DEF) | |||
533 | outs() << "[Thumb] "; | |||
534 | ||||
535 | if ((NType & MachO::N_TYPE) == MachO::N_INDR) { | |||
536 | outs() << S.Name << " (for "; | |||
537 | StringRef IndirectName; | |||
538 | if (MachO) { | |||
539 | if (S.Sym.getRawDataRefImpl().p) { | |||
540 | if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName)) | |||
541 | outs() << "?)"; | |||
542 | else | |||
543 | outs() << IndirectName << ")"; | |||
544 | } else | |||
545 | outs() << S.IndirectName << ")"; | |||
546 | } else | |||
547 | outs() << "?)"; | |||
548 | } else | |||
549 | outs() << S.Name; | |||
550 | ||||
551 | if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL && | |||
552 | (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) || | |||
553 | (NType & MachO::N_TYPE) == MachO::N_PBUD)) { | |||
554 | uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc); | |||
555 | if (LibraryOrdinal != 0) { | |||
556 | if (LibraryOrdinal == MachO::EXECUTABLE_ORDINAL) | |||
557 | outs() << " (from executable)"; | |||
558 | else if (LibraryOrdinal == MachO::DYNAMIC_LOOKUP_ORDINAL) | |||
559 | outs() << " (dynamically looked up)"; | |||
560 | else { | |||
561 | StringRef LibraryName; | |||
562 | if (!MachO || | |||
563 | MachO->getLibraryShortNameByIndex(LibraryOrdinal - 1, LibraryName)) | |||
564 | outs() << " (from bad library ordinal " << LibraryOrdinal << ")"; | |||
565 | else | |||
566 | outs() << " (from " << LibraryName << ")"; | |||
567 | } | |||
568 | } | |||
569 | } | |||
570 | ||||
571 | outs() << "\n"; | |||
572 | } | |||
573 | ||||
574 | // Table that maps Darwin's Mach-O stab constants to strings to allow printing. | |||
575 | struct DarwinStabName { | |||
576 | uint8_t NType; | |||
577 | const char *Name; | |||
578 | }; | |||
579 | const struct DarwinStabName DarwinStabNames[] = { | |||
580 | {MachO::N_GSYM, "GSYM"}, | |||
581 | {MachO::N_FNAME, "FNAME"}, | |||
582 | {MachO::N_FUN, "FUN"}, | |||
583 | {MachO::N_STSYM, "STSYM"}, | |||
584 | {MachO::N_LCSYM, "LCSYM"}, | |||
585 | {MachO::N_BNSYM, "BNSYM"}, | |||
586 | {MachO::N_PC, "PC"}, | |||
587 | {MachO::N_AST, "AST"}, | |||
588 | {MachO::N_OPT, "OPT"}, | |||
589 | {MachO::N_RSYM, "RSYM"}, | |||
590 | {MachO::N_SLINE, "SLINE"}, | |||
591 | {MachO::N_ENSYM, "ENSYM"}, | |||
592 | {MachO::N_SSYM, "SSYM"}, | |||
593 | {MachO::N_SO, "SO"}, | |||
594 | {MachO::N_OSO, "OSO"}, | |||
595 | {MachO::N_LSYM, "LSYM"}, | |||
596 | {MachO::N_BINCL, "BINCL"}, | |||
597 | {MachO::N_SOL, "SOL"}, | |||
598 | {MachO::N_PARAMS, "PARAM"}, | |||
599 | {MachO::N_VERSION, "VERS"}, | |||
600 | {MachO::N_OLEVEL, "OLEV"}, | |||
601 | {MachO::N_PSYM, "PSYM"}, | |||
602 | {MachO::N_EINCL, "EINCL"}, | |||
603 | {MachO::N_ENTRY, "ENTRY"}, | |||
604 | {MachO::N_LBRAC, "LBRAC"}, | |||
605 | {MachO::N_EXCL, "EXCL"}, | |||
606 | {MachO::N_RBRAC, "RBRAC"}, | |||
607 | {MachO::N_BCOMM, "BCOMM"}, | |||
608 | {MachO::N_ECOMM, "ECOMM"}, | |||
609 | {MachO::N_ECOML, "ECOML"}, | |||
610 | {MachO::N_LENG, "LENG"}, | |||
611 | }; | |||
612 | ||||
613 | static const char *getDarwinStabString(uint8_t NType) { | |||
614 | for (auto I : makeArrayRef(DarwinStabNames)) | |||
615 | if (I.NType == NType) | |||
616 | return I.Name; | |||
617 | return nullptr; | |||
618 | } | |||
619 | ||||
620 | // darwinPrintStab() prints the n_sect, n_desc along with a symbolic name of | |||
621 | // a stab n_type value in a Mach-O file. | |||
622 | static void darwinPrintStab(MachOObjectFile *MachO, const NMSymbol &S) { | |||
623 | MachO::nlist_64 STE_64; | |||
624 | MachO::nlist STE; | |||
625 | uint8_t NType; | |||
626 | uint8_t NSect; | |||
627 | uint16_t NDesc; | |||
628 | DataRefImpl SymDRI = S.Sym.getRawDataRefImpl(); | |||
629 | if (MachO->is64Bit()) { | |||
630 | STE_64 = MachO->getSymbol64TableEntry(SymDRI); | |||
631 | NType = STE_64.n_type; | |||
632 | NSect = STE_64.n_sect; | |||
633 | NDesc = STE_64.n_desc; | |||
634 | } else { | |||
635 | STE = MachO->getSymbolTableEntry(SymDRI); | |||
636 | NType = STE.n_type; | |||
637 | NSect = STE.n_sect; | |||
638 | NDesc = STE.n_desc; | |||
639 | } | |||
640 | ||||
641 | outs() << format(" %02x %04x ", NSect, NDesc); | |||
642 | if (const char *stabString = getDarwinStabString(NType)) | |||
643 | outs() << format("%5.5s", stabString); | |||
644 | else | |||
645 | outs() << format(" %02x", NType); | |||
646 | } | |||
647 | ||||
648 | static Optional<std::string> demangle(StringRef Name) { | |||
649 | std::string Demangled; | |||
650 | if (nonMicrosoftDemangle(Name.str().c_str(), Demangled)) | |||
651 | return Demangled; | |||
652 | return None; | |||
653 | } | |||
654 | ||||
655 | static Optional<std::string> demangleXCOFF(StringRef Name) { | |||
656 | if (Name.empty() || Name[0] != '.') | |||
657 | return demangle(Name); | |||
658 | ||||
659 | Name = Name.drop_front(); | |||
660 | Optional<std::string> DemangledName = demangle(Name); | |||
661 | if (DemangledName) | |||
662 | return "." + *DemangledName; | |||
663 | return None; | |||
664 | } | |||
665 | ||||
666 | static Optional<std::string> demangleMachO(StringRef Name) { | |||
667 | if (!Name.empty() && Name[0] == '_') | |||
668 | Name = Name.drop_front(); | |||
669 | return demangle(Name); | |||
670 | } | |||
671 | ||||
672 | static bool symbolIsDefined(const NMSymbol &Sym) { | |||
673 | return Sym.TypeChar != 'U' && Sym.TypeChar != 'w' && Sym.TypeChar != 'v'; | |||
674 | } | |||
675 | ||||
676 | static void writeFileName(raw_ostream &S, StringRef ArchiveName, | |||
677 | StringRef ArchitectureName) { | |||
678 | if (!ArchitectureName.empty()) | |||
679 | S << "(for architecture " << ArchitectureName << "):"; | |||
680 | if (OutputFormat == posix && !ArchiveName.empty()) | |||
681 | S << ArchiveName << "[" << CurrentFilename << "]: "; | |||
682 | else { | |||
683 | if (!ArchiveName.empty()) | |||
684 | S << ArchiveName << ":"; | |||
685 | S << CurrentFilename << ": "; | |||
686 | } | |||
687 | } | |||
688 | ||||
689 | static void sortSymbolList(std::vector<NMSymbol> &SymbolList) { | |||
690 | if (NoSort) | |||
691 | return; | |||
692 | ||||
693 | if (ReverseSort) | |||
694 | llvm::sort(SymbolList, std::greater<>()); | |||
695 | else | |||
696 | llvm::sort(SymbolList); | |||
697 | } | |||
698 | ||||
699 | static void printExportSymbolList(const std::vector<NMSymbol> &SymbolList) { | |||
700 | for (const NMSymbol &Sym : SymbolList) { | |||
701 | outs() << Sym.Name; | |||
702 | if (!Sym.Visibility.empty()) | |||
703 | outs() << ' ' << Sym.Visibility; | |||
704 | outs() << '\n'; | |||
705 | } | |||
706 | } | |||
707 | ||||
708 | static void printSymbolList(SymbolicFile &Obj, | |||
709 | std::vector<NMSymbol> &SymbolList, bool printName, | |||
710 | StringRef ArchiveName, StringRef ArchitectureName) { | |||
711 | if (!PrintFileName) { | |||
712 | if ((OutputFormat == bsd || OutputFormat == posix || | |||
713 | OutputFormat == just_symbols) && | |||
714 | MultipleFiles && printName) { | |||
715 | outs() << '\n' << CurrentFilename << ":\n"; | |||
716 | } else if (OutputFormat == sysv) { | |||
717 | outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n"; | |||
718 | if (isSymbolList64Bit(Obj)) | |||
719 | outs() << "Name Value Class Type" | |||
720 | << " Size Line Section\n"; | |||
721 | else | |||
722 | outs() << "Name Value Class Type" | |||
723 | << " Size Line Section\n"; | |||
724 | } | |||
725 | } | |||
726 | ||||
727 | const char *printBlanks, *printDashes, *printFormat; | |||
728 | if (isSymbolList64Bit(Obj)) { | |||
729 | printBlanks = " "; | |||
730 | printDashes = "----------------"; | |||
731 | switch (AddressRadix) { | |||
732 | case Radix::o: | |||
733 | printFormat = OutputFormat == posix ? "%" PRIo64"l" "o" : "%016" PRIo64"l" "o"; | |||
734 | break; | |||
735 | case Radix::x: | |||
736 | printFormat = OutputFormat == posix ? "%" PRIx64"l" "x" : "%016" PRIx64"l" "x"; | |||
737 | break; | |||
738 | default: | |||
739 | printFormat = OutputFormat == posix ? "%" PRId64"l" "d" : "%016" PRId64"l" "d"; | |||
740 | } | |||
741 | } else { | |||
742 | printBlanks = " "; | |||
743 | printDashes = "--------"; | |||
744 | switch (AddressRadix) { | |||
745 | case Radix::o: | |||
746 | printFormat = OutputFormat == posix ? "%" PRIo64"l" "o" : "%08" PRIo64"l" "o"; | |||
747 | break; | |||
748 | case Radix::x: | |||
749 | printFormat = OutputFormat == posix ? "%" PRIx64"l" "x" : "%08" PRIx64"l" "x"; | |||
750 | break; | |||
751 | default: | |||
752 | printFormat = OutputFormat == posix ? "%" PRId64"l" "d" : "%08" PRId64"l" "d"; | |||
753 | } | |||
754 | } | |||
755 | ||||
756 | for (const NMSymbol &S : SymbolList) { | |||
757 | if (!S.shouldPrint()) | |||
758 | continue; | |||
759 | ||||
760 | std::string Name = S.Name; | |||
761 | MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj); | |||
762 | if (Demangle) { | |||
763 | function_ref<Optional<std::string>(StringRef)> Fn = ::demangle; | |||
764 | if (Obj.isXCOFF()) | |||
765 | Fn = demangleXCOFF; | |||
766 | if (Obj.isMachO()) | |||
767 | Fn = demangleMachO; | |||
768 | if (Optional<std::string> Opt = Fn(S.Name)) | |||
769 | Name = *Opt; | |||
770 | } | |||
771 | ||||
772 | if (PrintFileName) | |||
773 | writeFileName(outs(), ArchiveName, ArchitectureName); | |||
774 | if ((OutputFormat == just_symbols || | |||
775 | (UndefinedOnly && MachO && OutputFormat != darwin)) && | |||
776 | OutputFormat != posix) { | |||
777 | outs() << Name << "\n"; | |||
778 | continue; | |||
779 | } | |||
780 | ||||
781 | char SymbolAddrStr[23], SymbolSizeStr[23]; | |||
782 | ||||
783 | // If the format is SysV or the symbol isn't defined, then print spaces. | |||
784 | if (OutputFormat == sysv || !symbolIsDefined(S)) { | |||
785 | if (OutputFormat == posix) { | |||
786 | format(printFormat, S.Address) | |||
787 | .print(SymbolAddrStr, sizeof(SymbolAddrStr)); | |||
788 | format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr)); | |||
789 | } else { | |||
790 | strcpy(SymbolAddrStr, printBlanks); | |||
791 | strcpy(SymbolSizeStr, printBlanks); | |||
792 | } | |||
793 | } | |||
794 | ||||
795 | if (symbolIsDefined(S)) { | |||
796 | // Otherwise, print the symbol address and size. | |||
797 | if (Obj.isIR()) | |||
798 | strcpy(SymbolAddrStr, printDashes); | |||
799 | else if (MachO && S.TypeChar == 'I') | |||
800 | strcpy(SymbolAddrStr, printBlanks); | |||
801 | else | |||
802 | format(printFormat, S.Address) | |||
803 | .print(SymbolAddrStr, sizeof(SymbolAddrStr)); | |||
804 | format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr)); | |||
805 | } | |||
806 | ||||
807 | // If OutputFormat is darwin or we are printing Mach-O symbols in hex and | |||
808 | // we have a MachOObjectFile, call darwinPrintSymbol to print as darwin's | |||
809 | // nm(1) -m output or hex, else if OutputFormat is darwin or we are | |||
810 | // printing Mach-O symbols in hex and not a Mach-O object fall back to | |||
811 | // OutputFormat bsd (see below). | |||
812 | if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) { | |||
813 | darwinPrintSymbol(Obj, S, SymbolAddrStr, printBlanks, printDashes, | |||
814 | printFormat); | |||
815 | } else if (OutputFormat == posix) { | |||
816 | outs() << Name << " " << S.TypeChar << " " << SymbolAddrStr << " " | |||
817 | << (MachO ? "0" : SymbolSizeStr) << "\n"; | |||
818 | } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) { | |||
819 | if (PrintAddress) | |||
820 | outs() << SymbolAddrStr << ' '; | |||
821 | if (PrintSize) | |||
822 | outs() << SymbolSizeStr << ' '; | |||
823 | outs() << S.TypeChar; | |||
824 | if (S.TypeChar == '-' && MachO) | |||
825 | darwinPrintStab(MachO, S); | |||
826 | outs() << " " << Name; | |||
827 | if (S.TypeChar == 'I' && MachO) { | |||
828 | outs() << " (indirect for "; | |||
829 | if (S.Sym.getRawDataRefImpl().p) { | |||
830 | StringRef IndirectName; | |||
831 | if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName)) | |||
832 | outs() << "?)"; | |||
833 | else | |||
834 | outs() << IndirectName << ")"; | |||
835 | } else | |||
836 | outs() << S.IndirectName << ")"; | |||
837 | } | |||
838 | outs() << "\n"; | |||
839 | } else if (OutputFormat == sysv) { | |||
840 | outs() << left_justify(Name, 20) << "|" << SymbolAddrStr << "| " | |||
841 | << S.TypeChar << " |" << right_justify(S.TypeName, 18) << "|" | |||
842 | << SymbolSizeStr << "| |" << S.SectionName << "\n"; | |||
843 | } | |||
844 | } | |||
845 | ||||
846 | SymbolList.clear(); | |||
847 | } | |||
848 | ||||
849 | static char getSymbolNMTypeChar(ELFObjectFileBase &Obj, | |||
850 | basic_symbol_iterator I) { | |||
851 | // OK, this is ELF | |||
852 | elf_symbol_iterator SymI(I); | |||
853 | ||||
854 | Expected<elf_section_iterator> SecIOrErr = SymI->getSection(); | |||
855 | if (!SecIOrErr) { | |||
856 | consumeError(SecIOrErr.takeError()); | |||
857 | return '?'; | |||
858 | } | |||
859 | ||||
860 | uint8_t Binding = SymI->getBinding(); | |||
861 | if (Binding == ELF::STB_GNU_UNIQUE) | |||
862 | return 'u'; | |||
863 | ||||
864 | assert(Binding != ELF::STB_WEAK && "STB_WEAK not tested in calling function")(static_cast <bool> (Binding != ELF::STB_WEAK && "STB_WEAK not tested in calling function") ? void (0) : __assert_fail ("Binding != ELF::STB_WEAK && \"STB_WEAK not tested in calling function\"" , "llvm/tools/llvm-nm/llvm-nm.cpp", 864, __extension__ __PRETTY_FUNCTION__ )); | |||
865 | if (Binding != ELF::STB_GLOBAL && Binding != ELF::STB_LOCAL) | |||
866 | return '?'; | |||
867 | ||||
868 | elf_section_iterator SecI = *SecIOrErr; | |||
869 | if (SecI != Obj.section_end()) { | |||
870 | uint32_t Type = SecI->getType(); | |||
871 | uint64_t Flags = SecI->getFlags(); | |||
872 | if (Flags & ELF::SHF_EXECINSTR) | |||
873 | return 't'; | |||
874 | if (Type == ELF::SHT_NOBITS) | |||
875 | return 'b'; | |||
876 | if (Flags & ELF::SHF_ALLOC) | |||
877 | return Flags & ELF::SHF_WRITE ? 'd' : 'r'; | |||
878 | ||||
879 | auto NameOrErr = SecI->getName(); | |||
880 | if (!NameOrErr) { | |||
881 | consumeError(NameOrErr.takeError()); | |||
882 | return '?'; | |||
883 | } | |||
884 | if ((*NameOrErr).startswith(".debug")) | |||
885 | return 'N'; | |||
886 | if (!(Flags & ELF::SHF_WRITE)) | |||
887 | return 'n'; | |||
888 | } | |||
889 | ||||
890 | return '?'; | |||
891 | } | |||
892 | ||||
893 | static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) { | |||
894 | COFFSymbolRef Symb = Obj.getCOFFSymbol(*I); | |||
895 | // OK, this is COFF. | |||
896 | symbol_iterator SymI(I); | |||
897 | ||||
898 | Expected<StringRef> Name = SymI->getName(); | |||
899 | if (!Name) { | |||
900 | consumeError(Name.takeError()); | |||
901 | return '?'; | |||
902 | } | |||
903 | ||||
904 | char Ret = StringSwitch<char>(*Name) | |||
905 | .StartsWith(".debug", 'N') | |||
906 | .StartsWith(".sxdata", 'N') | |||
907 | .Default('?'); | |||
908 | ||||
909 | if (Ret != '?') | |||
910 | return Ret; | |||
911 | ||||
912 | uint32_t Characteristics = 0; | |||
913 | if (!COFF::isReservedSectionNumber(Symb.getSectionNumber())) { | |||
914 | Expected<section_iterator> SecIOrErr = SymI->getSection(); | |||
915 | if (!SecIOrErr) { | |||
916 | consumeError(SecIOrErr.takeError()); | |||
917 | return '?'; | |||
918 | } | |||
919 | section_iterator SecI = *SecIOrErr; | |||
920 | const coff_section *Section = Obj.getCOFFSection(*SecI); | |||
921 | Characteristics = Section->Characteristics; | |||
922 | if (Expected<StringRef> NameOrErr = Obj.getSectionName(Section)) | |||
923 | if (NameOrErr->startswith(".idata")) | |||
924 | return 'i'; | |||
925 | } | |||
926 | ||||
927 | switch (Symb.getSectionNumber()) { | |||
928 | case COFF::IMAGE_SYM_DEBUG: | |||
929 | return 'n'; | |||
930 | default: | |||
931 | // Check section type. | |||
932 | if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) | |||
933 | return 't'; | |||
934 | if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) | |||
935 | return Characteristics & COFF::IMAGE_SCN_MEM_WRITE ? 'd' : 'r'; | |||
936 | if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) | |||
937 | return 'b'; | |||
938 | if (Characteristics & COFF::IMAGE_SCN_LNK_INFO) | |||
939 | return 'i'; | |||
940 | // Check for section symbol. | |||
941 | if (Symb.isSectionDefinition()) | |||
942 | return 's'; | |||
943 | } | |||
944 | ||||
945 | return '?'; | |||
946 | } | |||
947 | ||||
948 | static char getSymbolNMTypeChar(XCOFFObjectFile &Obj, symbol_iterator I) { | |||
949 | Expected<uint32_t> TypeOrErr = I->getType(); | |||
950 | if (!TypeOrErr) { | |||
951 | warn(TypeOrErr.takeError(), Obj.getFileName(), | |||
952 | "for symbol with index " + | |||
953 | Twine(Obj.getSymbolIndex(I->getRawDataRefImpl().p))); | |||
954 | return '?'; | |||
955 | } | |||
956 | ||||
957 | uint32_t SymType = *TypeOrErr; | |||
958 | ||||
959 | if (SymType == SymbolRef::ST_File) | |||
960 | return 'f'; | |||
961 | ||||
962 | // If the I->getSection() call would return an error, the earlier I->getType() | |||
963 | // call will already have returned the same error first. | |||
964 | section_iterator SecIter = cantFail(I->getSection()); | |||
965 | ||||
966 | if (SecIter == Obj.section_end()) | |||
967 | return '?'; | |||
968 | ||||
969 | if (Obj.isDebugSection(SecIter->getRawDataRefImpl())) | |||
970 | return 'N'; | |||
971 | ||||
972 | if (SecIter->isText()) | |||
973 | return 't'; | |||
974 | ||||
975 | if (SecIter->isData()) | |||
976 | return 'd'; | |||
977 | ||||
978 | if (SecIter->isBSS()) | |||
979 | return 'b'; | |||
980 | ||||
981 | return '?'; | |||
982 | } | |||
983 | ||||
984 | static char getSymbolNMTypeChar(COFFImportFile &Obj) { | |||
985 | switch (Obj.getCOFFImportHeader()->getType()) { | |||
986 | case COFF::IMPORT_CODE: | |||
987 | return 't'; | |||
988 | case COFF::IMPORT_DATA: | |||
989 | return 'd'; | |||
990 | case COFF::IMPORT_CONST: | |||
991 | return 'r'; | |||
992 | } | |||
993 | return '?'; | |||
994 | } | |||
995 | ||||
996 | static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) { | |||
997 | DataRefImpl Symb = I->getRawDataRefImpl(); | |||
998 | uint8_t NType = Obj.is64Bit() ? Obj.getSymbol64TableEntry(Symb).n_type | |||
999 | : Obj.getSymbolTableEntry(Symb).n_type; | |||
1000 | ||||
1001 | if (NType & MachO::N_STAB) | |||
1002 | return '-'; | |||
1003 | ||||
1004 | switch (NType & MachO::N_TYPE) { | |||
1005 | case MachO::N_ABS: | |||
1006 | return 's'; | |||
1007 | case MachO::N_INDR: | |||
1008 | return 'i'; | |||
1009 | case MachO::N_SECT: { | |||
1010 | Expected<section_iterator> SecOrErr = Obj.getSymbolSection(Symb); | |||
1011 | if (!SecOrErr) { | |||
1012 | consumeError(SecOrErr.takeError()); | |||
1013 | return 's'; | |||
1014 | } | |||
1015 | section_iterator Sec = *SecOrErr; | |||
1016 | if (Sec == Obj.section_end()) | |||
1017 | return 's'; | |||
1018 | DataRefImpl Ref = Sec->getRawDataRefImpl(); | |||
1019 | StringRef SectionName; | |||
1020 | if (Expected<StringRef> NameOrErr = Obj.getSectionName(Ref)) | |||
1021 | SectionName = *NameOrErr; | |||
1022 | StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref); | |||
1023 | if (Obj.is64Bit() && Obj.getHeader64().filetype == MachO::MH_KEXT_BUNDLE && | |||
1024 | SegmentName == "__TEXT_EXEC" && SectionName == "__text") | |||
1025 | return 't'; | |||
1026 | if (SegmentName == "__TEXT" && SectionName == "__text") | |||
1027 | return 't'; | |||
1028 | if (SegmentName == "__DATA" && SectionName == "__data") | |||
1029 | return 'd'; | |||
1030 | if (SegmentName == "__DATA" && SectionName == "__bss") | |||
1031 | return 'b'; | |||
1032 | return 's'; | |||
1033 | } | |||
1034 | } | |||
1035 | ||||
1036 | return '?'; | |||
1037 | } | |||
1038 | ||||
1039 | static char getSymbolNMTypeChar(TapiFile &Obj, basic_symbol_iterator I) { | |||
1040 | return 's'; | |||
1041 | } | |||
1042 | ||||
1043 | static char getSymbolNMTypeChar(WasmObjectFile &Obj, basic_symbol_iterator I) { | |||
1044 | uint32_t Flags = cantFail(I->getFlags()); | |||
1045 | if (Flags & SymbolRef::SF_Executable) | |||
1046 | return 't'; | |||
1047 | return 'd'; | |||
1048 | } | |||
1049 | ||||
1050 | static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) { | |||
1051 | uint32_t Flags = cantFail(I->getFlags()); | |||
1052 | // FIXME: should we print 'b'? At the IR level we cannot be sure if this | |||
1053 | // will be in bss or not, but we could approximate. | |||
1054 | if (Flags & SymbolRef::SF_Executable) | |||
1055 | return 't'; | |||
1056 | else if (Triple(Obj.getTargetTriple()).isOSDarwin() && | |||
1057 | (Flags & SymbolRef::SF_Const)) | |||
1058 | return 's'; | |||
1059 | else | |||
1060 | return 'd'; | |||
1061 | } | |||
1062 | ||||
1063 | static bool isObject(SymbolicFile &Obj, basic_symbol_iterator I) { | |||
1064 | return isa<ELFObjectFileBase>(&Obj) && | |||
1065 | elf_symbol_iterator(I)->getELFType() == ELF::STT_OBJECT; | |||
1066 | } | |||
1067 | ||||
1068 | // For ELF object files, Set TypeName to the symbol typename, to be printed | |||
1069 | // in the 'Type' column of the SYSV format output. | |||
1070 | static StringRef getNMTypeName(SymbolicFile &Obj, basic_symbol_iterator I) { | |||
1071 | if (isa<ELFObjectFileBase>(&Obj)) { | |||
1072 | elf_symbol_iterator SymI(I); | |||
1073 | return SymI->getELFTypeName(); | |||
1074 | } | |||
1075 | return ""; | |||
1076 | } | |||
1077 | ||||
1078 | // Return Posix nm class type tag (single letter), but also set SecName and | |||
1079 | // section and name, to be used in format=sysv output. | |||
1080 | static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I, | |||
1081 | StringRef &SecName) { | |||
1082 | // Symbol Flags have been checked in the caller. | |||
1083 | uint32_t Symflags = cantFail(I->getFlags()); | |||
1084 | if (ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj)) { | |||
1085 | if (Symflags & object::SymbolRef::SF_Absolute) | |||
1086 | SecName = "*ABS*"; | |||
1087 | else if (Symflags & object::SymbolRef::SF_Common) | |||
1088 | SecName = "*COM*"; | |||
1089 | else if (Symflags & object::SymbolRef::SF_Undefined) | |||
1090 | SecName = "*UND*"; | |||
1091 | else { | |||
1092 | elf_symbol_iterator SymI(I); | |||
1093 | Expected<elf_section_iterator> SecIOrErr = SymI->getSection(); | |||
1094 | if (!SecIOrErr) { | |||
1095 | consumeError(SecIOrErr.takeError()); | |||
1096 | return '?'; | |||
1097 | } | |||
1098 | ||||
1099 | if (*SecIOrErr == ELFObj->section_end()) | |||
1100 | return '?'; | |||
1101 | ||||
1102 | Expected<StringRef> NameOrErr = (*SecIOrErr)->getName(); | |||
1103 | if (!NameOrErr) { | |||
1104 | consumeError(NameOrErr.takeError()); | |||
1105 | return '?'; | |||
1106 | } | |||
1107 | SecName = *NameOrErr; | |||
1108 | } | |||
1109 | } | |||
1110 | ||||
1111 | if (Symflags & object::SymbolRef::SF_Undefined) { | |||
1112 | if (isa<MachOObjectFile>(Obj) || !(Symflags & object::SymbolRef::SF_Weak)) | |||
1113 | return 'U'; | |||
1114 | return isObject(Obj, I) ? 'v' : 'w'; | |||
1115 | } | |||
1116 | if (isa<ELFObjectFileBase>(&Obj)) | |||
1117 | if (ELFSymbolRef(*I).getELFType() == ELF::STT_GNU_IFUNC) | |||
1118 | return 'i'; | |||
1119 | if (!isa<MachOObjectFile>(Obj) && (Symflags & object::SymbolRef::SF_Weak)) | |||
1120 | return isObject(Obj, I) ? 'V' : 'W'; | |||
1121 | ||||
1122 | if (Symflags & object::SymbolRef::SF_Common) | |||
1123 | return 'C'; | |||
1124 | ||||
1125 | char Ret = '?'; | |||
1126 | if (Symflags & object::SymbolRef::SF_Absolute) | |||
1127 | Ret = 'a'; | |||
1128 | else if (IRObjectFile *IR = dyn_cast<IRObjectFile>(&Obj)) | |||
1129 | Ret = getSymbolNMTypeChar(*IR, I); | |||
1130 | else if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(&Obj)) | |||
1131 | Ret = getSymbolNMTypeChar(*COFF, I); | |||
1132 | else if (XCOFFObjectFile *XCOFF = dyn_cast<XCOFFObjectFile>(&Obj)) | |||
1133 | Ret = getSymbolNMTypeChar(*XCOFF, I); | |||
1134 | else if (COFFImportFile *COFFImport = dyn_cast<COFFImportFile>(&Obj)) | |||
1135 | Ret = getSymbolNMTypeChar(*COFFImport); | |||
1136 | else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj)) | |||
1137 | Ret = getSymbolNMTypeChar(*MachO, I); | |||
1138 | else if (WasmObjectFile *Wasm = dyn_cast<WasmObjectFile>(&Obj)) | |||
1139 | Ret = getSymbolNMTypeChar(*Wasm, I); | |||
1140 | else if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj)) | |||
1141 | Ret = getSymbolNMTypeChar(*Tapi, I); | |||
1142 | else if (ELFObjectFileBase *ELF = dyn_cast<ELFObjectFileBase>(&Obj)) { | |||
1143 | Ret = getSymbolNMTypeChar(*ELF, I); | |||
1144 | if (ELFSymbolRef(*I).getBinding() == ELF::STB_GNU_UNIQUE) | |||
1145 | return Ret; | |||
1146 | } else | |||
1147 | llvm_unreachable("unknown binary format")::llvm::llvm_unreachable_internal("unknown binary format", "llvm/tools/llvm-nm/llvm-nm.cpp" , 1147); | |||
1148 | ||||
1149 | if (!(Symflags & object::SymbolRef::SF_Global)) | |||
1150 | return Ret; | |||
1151 | ||||
1152 | return toupper(Ret); | |||
1153 | } | |||
1154 | ||||
1155 | // getNsectForSegSect() is used to implement the Mach-O "-s segname sectname" | |||
1156 | // option to dump only those symbols from that section in a Mach-O file. | |||
1157 | // It is called once for each Mach-O file from getSymbolNamesFromObject() | |||
1158 | // to get the section number for that named section from the command line | |||
1159 | // arguments. It returns the section number for that section in the Mach-O | |||
1160 | // file or zero it is not present. | |||
1161 | static unsigned getNsectForSegSect(MachOObjectFile *Obj) { | |||
1162 | unsigned Nsect = 1; | |||
1163 | for (auto &S : Obj->sections()) { | |||
1164 | DataRefImpl Ref = S.getRawDataRefImpl(); | |||
1165 | StringRef SectionName; | |||
1166 | if (Expected<StringRef> NameOrErr = Obj->getSectionName(Ref)) | |||
1167 | SectionName = *NameOrErr; | |||
1168 | StringRef SegmentName = Obj->getSectionFinalSegmentName(Ref); | |||
1169 | if (SegmentName == SegSect[0] && SectionName == SegSect[1]) | |||
1170 | return Nsect; | |||
1171 | Nsect++; | |||
1172 | } | |||
1173 | return 0; | |||
1174 | } | |||
1175 | ||||
1176 | // getNsectInMachO() is used to implement the Mach-O "-s segname sectname" | |||
1177 | // option to dump only those symbols from that section in a Mach-O file. | |||
1178 | // It is called once for each symbol in a Mach-O file from | |||
1179 | // getSymbolNamesFromObject() and returns the section number for that symbol | |||
1180 | // if it is in a section, else it returns 0. | |||
1181 | static unsigned getNsectInMachO(MachOObjectFile &Obj, BasicSymbolRef Sym) { | |||
1182 | DataRefImpl Symb = Sym.getRawDataRefImpl(); | |||
1183 | if (Obj.is64Bit()) { | |||
1184 | MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb); | |||
1185 | return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0; | |||
1186 | } | |||
1187 | MachO::nlist STE = Obj.getSymbolTableEntry(Symb); | |||
1188 | return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0; | |||
1189 | } | |||
1190 | ||||
1191 | static void dumpSymbolsFromDLInfoMachO(MachOObjectFile &MachO, | |||
1192 | std::vector<NMSymbol> &SymbolList) { | |||
1193 | size_t I = SymbolList.size(); | |||
1194 | std::string ExportsNameBuffer; | |||
1195 | raw_string_ostream EOS(ExportsNameBuffer); | |||
1196 | std::string BindsNameBuffer; | |||
1197 | raw_string_ostream BOS(BindsNameBuffer); | |||
1198 | std::string LazysNameBuffer; | |||
1199 | raw_string_ostream LOS(LazysNameBuffer); | |||
1200 | std::string WeaksNameBuffer; | |||
1201 | raw_string_ostream WOS(WeaksNameBuffer); | |||
1202 | std::string FunctionStartsNameBuffer; | |||
1203 | raw_string_ostream FOS(FunctionStartsNameBuffer); | |||
1204 | ||||
1205 | MachO::mach_header H; | |||
1206 | MachO::mach_header_64 H_64; | |||
1207 | uint32_t HFlags = 0; | |||
1208 | if (MachO.is64Bit()) { | |||
1209 | H_64 = MachO.MachOObjectFile::getHeader64(); | |||
1210 | HFlags = H_64.flags; | |||
1211 | } else { | |||
1212 | H = MachO.MachOObjectFile::getHeader(); | |||
1213 | HFlags = H.flags; | |||
1214 | } | |||
1215 | uint64_t BaseSegmentAddress = 0; | |||
1216 | for (const auto &Command : MachO.load_commands()) { | |||
1217 | if (Command.C.cmd == MachO::LC_SEGMENT) { | |||
1218 | MachO::segment_command Seg = MachO.getSegmentLoadCommand(Command); | |||
1219 | if (Seg.fileoff == 0 && Seg.filesize != 0) { | |||
1220 | BaseSegmentAddress = Seg.vmaddr; | |||
1221 | break; | |||
1222 | } | |||
1223 | } else if (Command.C.cmd == MachO::LC_SEGMENT_64) { | |||
1224 | MachO::segment_command_64 Seg = MachO.getSegment64LoadCommand(Command); | |||
1225 | if (Seg.fileoff == 0 && Seg.filesize != 0) { | |||
1226 | BaseSegmentAddress = Seg.vmaddr; | |||
1227 | break; | |||
1228 | } | |||
1229 | } | |||
1230 | } | |||
1231 | if (DyldInfoOnly || AddDyldInfo || | |||
1232 | HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) { | |||
1233 | unsigned ExportsAdded = 0; | |||
1234 | Error Err = Error::success(); | |||
1235 | for (const llvm::object::ExportEntry &Entry : MachO.exports(Err)) { | |||
1236 | bool found = false; | |||
1237 | bool ReExport = false; | |||
1238 | if (!DyldInfoOnly) { | |||
1239 | for (const NMSymbol &S : SymbolList) | |||
1240 | if (S.Address == Entry.address() + BaseSegmentAddress && | |||
1241 | S.Name == Entry.name()) { | |||
1242 | found = true; | |||
1243 | break; | |||
1244 | } | |||
1245 | } | |||
1246 | if (!found) { | |||
1247 | NMSymbol S = {}; | |||
1248 | S.Address = Entry.address() + BaseSegmentAddress; | |||
1249 | S.Size = 0; | |||
1250 | S.TypeChar = '\0'; | |||
1251 | S.Name = Entry.name().str(); | |||
1252 | // There is no symbol in the nlist symbol table for this so we set | |||
1253 | // Sym effectivly to null and the rest of code in here must test for | |||
1254 | // it and not do things like Sym.getFlags() for it. | |||
1255 | S.Sym = BasicSymbolRef(); | |||
1256 | S.SymFlags = SymbolRef::SF_Global; | |||
1257 | S.Section = SectionRef(); | |||
1258 | S.NType = 0; | |||
1259 | S.NSect = 0; | |||
1260 | S.NDesc = 0; | |||
1261 | ||||
1262 | uint64_t EFlags = Entry.flags(); | |||
1263 | bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) == | |||
1264 | MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE); | |||
1265 | bool Resolver = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER); | |||
1266 | ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT); | |||
1267 | bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION); | |||
1268 | if (WeakDef) | |||
1269 | S.NDesc |= MachO::N_WEAK_DEF; | |||
1270 | if (Abs) { | |||
1271 | S.NType = MachO::N_EXT | MachO::N_ABS; | |||
1272 | S.TypeChar = 'A'; | |||
1273 | } else if (ReExport) { | |||
1274 | S.NType = MachO::N_EXT | MachO::N_INDR; | |||
1275 | S.TypeChar = 'I'; | |||
1276 | } else { | |||
1277 | S.NType = MachO::N_EXT | MachO::N_SECT; | |||
1278 | if (Resolver) { | |||
1279 | S.Address = Entry.other() + BaseSegmentAddress; | |||
1280 | if ((S.Address & 1) != 0 && !MachO.is64Bit() && | |||
1281 | H.cputype == MachO::CPU_TYPE_ARM) { | |||
1282 | S.Address &= ~1LL; | |||
1283 | S.NDesc |= MachO::N_ARM_THUMB_DEF; | |||
1284 | } | |||
1285 | } else { | |||
1286 | S.Address = Entry.address() + BaseSegmentAddress; | |||
1287 | } | |||
1288 | StringRef SegmentName = StringRef(); | |||
1289 | StringRef SectionName = StringRef(); | |||
1290 | for (const SectionRef &Section : MachO.sections()) { | |||
1291 | S.NSect++; | |||
1292 | ||||
1293 | if (Expected<StringRef> NameOrErr = Section.getName()) | |||
1294 | SectionName = *NameOrErr; | |||
1295 | else | |||
1296 | consumeError(NameOrErr.takeError()); | |||
1297 | ||||
1298 | SegmentName = | |||
1299 | MachO.getSectionFinalSegmentName(Section.getRawDataRefImpl()); | |||
1300 | if (S.Address >= Section.getAddress() && | |||
1301 | S.Address < Section.getAddress() + Section.getSize()) { | |||
1302 | S.Section = Section; | |||
1303 | break; | |||
1304 | } else if (Entry.name() == "__mh_execute_header" && | |||
1305 | SegmentName == "__TEXT" && SectionName == "__text") { | |||
1306 | S.Section = Section; | |||
1307 | S.NDesc |= MachO::REFERENCED_DYNAMICALLY; | |||
1308 | break; | |||
1309 | } | |||
1310 | } | |||
1311 | if (SegmentName == "__TEXT" && SectionName == "__text") | |||
1312 | S.TypeChar = 'T'; | |||
1313 | else if (SegmentName == "__DATA" && SectionName == "__data") | |||
1314 | S.TypeChar = 'D'; | |||
1315 | else if (SegmentName == "__DATA" && SectionName == "__bss") | |||
1316 | S.TypeChar = 'B'; | |||
1317 | else | |||
1318 | S.TypeChar = 'S'; | |||
1319 | } | |||
1320 | SymbolList.push_back(S); | |||
1321 | ||||
1322 | EOS << Entry.name(); | |||
1323 | EOS << '\0'; | |||
1324 | ExportsAdded++; | |||
1325 | ||||
1326 | // For ReExports there are a two more things to do, first add the | |||
1327 | // indirect name and second create the undefined symbol using the | |||
1328 | // referened dynamic library. | |||
1329 | if (ReExport) { | |||
1330 | ||||
1331 | // Add the indirect name. | |||
1332 | if (Entry.otherName().empty()) | |||
1333 | EOS << Entry.name(); | |||
1334 | else | |||
1335 | EOS << Entry.otherName(); | |||
1336 | EOS << '\0'; | |||
1337 | ||||
1338 | // Now create the undefined symbol using the referened dynamic | |||
1339 | // library. | |||
1340 | NMSymbol U = {}; | |||
1341 | U.Address = 0; | |||
1342 | U.Size = 0; | |||
1343 | U.TypeChar = 'U'; | |||
1344 | if (Entry.otherName().empty()) | |||
1345 | U.Name = Entry.name().str(); | |||
1346 | else | |||
1347 | U.Name = Entry.otherName().str(); | |||
1348 | // Again there is no symbol in the nlist symbol table for this so | |||
1349 | // we set Sym effectivly to null and the rest of code in here must | |||
1350 | // test for it and not do things like Sym.getFlags() for it. | |||
1351 | U.Sym = BasicSymbolRef(); | |||
1352 | U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined; | |||
1353 | U.Section = SectionRef(); | |||
1354 | U.NType = MachO::N_EXT | MachO::N_UNDF; | |||
1355 | U.NSect = 0; | |||
1356 | U.NDesc = 0; | |||
1357 | // The library ordinal for this undefined symbol is in the export | |||
1358 | // trie Entry.other(). | |||
1359 | MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other()); | |||
1360 | SymbolList.push_back(U); | |||
1361 | ||||
1362 | // Finally add the undefined symbol's name. | |||
1363 | if (Entry.otherName().empty()) | |||
1364 | EOS << Entry.name(); | |||
1365 | else | |||
1366 | EOS << Entry.otherName(); | |||
1367 | EOS << '\0'; | |||
1368 | ExportsAdded++; | |||
1369 | } | |||
1370 | } | |||
1371 | } | |||
1372 | if (Err) | |||
1373 | error(std::move(Err), MachO.getFileName()); | |||
1374 | // Set the symbol names and indirect names for the added symbols. | |||
1375 | if (ExportsAdded) { | |||
1376 | EOS.flush(); | |||
1377 | const char *Q = ExportsNameBuffer.c_str(); | |||
1378 | for (unsigned K = 0; K < ExportsAdded; K++) { | |||
1379 | SymbolList[I].Name = Q; | |||
1380 | Q += strlen(Q) + 1; | |||
1381 | if (SymbolList[I].TypeChar == 'I') { | |||
1382 | SymbolList[I].IndirectName = Q; | |||
1383 | Q += strlen(Q) + 1; | |||
1384 | } | |||
1385 | I++; | |||
1386 | } | |||
1387 | } | |||
1388 | ||||
1389 | // Add the undefined symbols from the bind entries. | |||
1390 | unsigned BindsAdded = 0; | |||
1391 | Error BErr = Error::success(); | |||
1392 | StringRef LastSymbolName = StringRef(); | |||
1393 | for (const llvm::object::MachOBindEntry &Entry : MachO.bindTable(BErr)) { | |||
1394 | bool found = false; | |||
1395 | if (LastSymbolName == Entry.symbolName()) | |||
1396 | found = true; | |||
1397 | else if (!DyldInfoOnly) { | |||
1398 | for (unsigned J = 0; J < SymbolList.size() && !found; ++J) { | |||
1399 | if (SymbolList[J].Name == Entry.symbolName()) | |||
1400 | found = true; | |||
1401 | } | |||
1402 | } | |||
1403 | if (!found) { | |||
1404 | LastSymbolName = Entry.symbolName(); | |||
1405 | NMSymbol B = {}; | |||
1406 | B.Address = 0; | |||
1407 | B.Size = 0; | |||
1408 | B.TypeChar = 'U'; | |||
1409 | // There is no symbol in the nlist symbol table for this so we set | |||
1410 | // Sym effectivly to null and the rest of code in here must test for | |||
1411 | // it and not do things like Sym.getFlags() for it. | |||
1412 | B.Sym = BasicSymbolRef(); | |||
1413 | B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined; | |||
1414 | B.NType = MachO::N_EXT | MachO::N_UNDF; | |||
1415 | B.NSect = 0; | |||
1416 | B.NDesc = 0; | |||
1417 | MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal()); | |||
1418 | B.Name = Entry.symbolName().str(); | |||
1419 | SymbolList.push_back(B); | |||
1420 | BOS << Entry.symbolName(); | |||
1421 | BOS << '\0'; | |||
1422 | BindsAdded++; | |||
1423 | } | |||
1424 | } | |||
1425 | if (BErr) | |||
1426 | error(std::move(BErr), MachO.getFileName()); | |||
1427 | // Set the symbol names and indirect names for the added symbols. | |||
1428 | if (BindsAdded) { | |||
1429 | BOS.flush(); | |||
1430 | const char *Q = BindsNameBuffer.c_str(); | |||
1431 | for (unsigned K = 0; K < BindsAdded; K++) { | |||
1432 | SymbolList[I].Name = Q; | |||
1433 | Q += strlen(Q) + 1; | |||
1434 | if (SymbolList[I].TypeChar == 'I') { | |||
1435 | SymbolList[I].IndirectName = Q; | |||
1436 | Q += strlen(Q) + 1; | |||
1437 | } | |||
1438 | I++; | |||
1439 | } | |||
1440 | } | |||
1441 | ||||
1442 | // Add the undefined symbols from the lazy bind entries. | |||
1443 | unsigned LazysAdded = 0; | |||
1444 | Error LErr = Error::success(); | |||
1445 | LastSymbolName = StringRef(); | |||
1446 | for (const llvm::object::MachOBindEntry &Entry : | |||
1447 | MachO.lazyBindTable(LErr)) { | |||
1448 | bool found = false; | |||
1449 | if (LastSymbolName == Entry.symbolName()) | |||
1450 | found = true; | |||
1451 | else { | |||
1452 | // Here we must check to see it this symbol is already in the | |||
1453 | // SymbolList as it might have already have been added above via a | |||
1454 | // non-lazy (bind) entry. | |||
1455 | for (unsigned J = 0; J < SymbolList.size() && !found; ++J) { | |||
1456 | if (SymbolList[J].Name == Entry.symbolName()) | |||
1457 | found = true; | |||
1458 | } | |||
1459 | } | |||
1460 | if (!found) { | |||
1461 | LastSymbolName = Entry.symbolName(); | |||
1462 | NMSymbol L = {}; | |||
1463 | L.Name = Entry.symbolName().str(); | |||
1464 | L.Address = 0; | |||
1465 | L.Size = 0; | |||
1466 | L.TypeChar = 'U'; | |||
1467 | // There is no symbol in the nlist symbol table for this so we set | |||
1468 | // Sym effectivly to null and the rest of code in here must test for | |||
1469 | // it and not do things like Sym.getFlags() for it. | |||
1470 | L.Sym = BasicSymbolRef(); | |||
1471 | L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined; | |||
1472 | L.NType = MachO::N_EXT | MachO::N_UNDF; | |||
1473 | L.NSect = 0; | |||
1474 | // The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it | |||
1475 | // makes sence since we are creating this from a lazy bind entry. | |||
1476 | L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY; | |||
1477 | MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal()); | |||
1478 | SymbolList.push_back(L); | |||
1479 | LOS << Entry.symbolName(); | |||
1480 | LOS << '\0'; | |||
1481 | LazysAdded++; | |||
1482 | } | |||
1483 | } | |||
1484 | if (LErr) | |||
1485 | error(std::move(LErr), MachO.getFileName()); | |||
1486 | // Set the symbol names and indirect names for the added symbols. | |||
1487 | if (LazysAdded) { | |||
1488 | LOS.flush(); | |||
1489 | const char *Q = LazysNameBuffer.c_str(); | |||
1490 | for (unsigned K = 0; K < LazysAdded; K++) { | |||
1491 | SymbolList[I].Name = Q; | |||
1492 | Q += strlen(Q) + 1; | |||
1493 | if (SymbolList[I].TypeChar == 'I') { | |||
1494 | SymbolList[I].IndirectName = Q; | |||
1495 | Q += strlen(Q) + 1; | |||
1496 | } | |||
1497 | I++; | |||
1498 | } | |||
1499 | } | |||
1500 | ||||
1501 | // Add the undefineds symbol from the weak bind entries which are not | |||
1502 | // strong symbols. | |||
1503 | unsigned WeaksAdded = 0; | |||
1504 | Error WErr = Error::success(); | |||
1505 | LastSymbolName = StringRef(); | |||
1506 | for (const llvm::object::MachOBindEntry &Entry : | |||
1507 | MachO.weakBindTable(WErr)) { | |||
1508 | bool found = false; | |||
1509 | unsigned J = 0; | |||
1510 | if (LastSymbolName == Entry.symbolName() || | |||
1511 | Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) { | |||
1512 | found = true; | |||
1513 | } else { | |||
1514 | for (J = 0; J < SymbolList.size() && !found; ++J) { | |||
1515 | if (SymbolList[J].Name == Entry.symbolName()) { | |||
1516 | found = true; | |||
1517 | break; | |||
1518 | } | |||
1519 | } | |||
1520 | } | |||
1521 | if (!found) { | |||
1522 | LastSymbolName = Entry.symbolName(); | |||
1523 | NMSymbol W = {}; | |||
1524 | W.Name = Entry.symbolName().str(); | |||
1525 | W.Address = 0; | |||
1526 | W.Size = 0; | |||
1527 | W.TypeChar = 'U'; | |||
1528 | // There is no symbol in the nlist symbol table for this so we set | |||
1529 | // Sym effectivly to null and the rest of code in here must test for | |||
1530 | // it and not do things like Sym.getFlags() for it. | |||
1531 | W.Sym = BasicSymbolRef(); | |||
1532 | W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined; | |||
1533 | W.NType = MachO::N_EXT | MachO::N_UNDF; | |||
1534 | W.NSect = 0; | |||
1535 | // Odd that we are using N_WEAK_DEF on an undefined symbol but that is | |||
1536 | // what is created in this case by the linker when there are real | |||
1537 | // symbols in the nlist structs. | |||
1538 | W.NDesc = MachO::N_WEAK_DEF; | |||
1539 | SymbolList.push_back(W); | |||
1540 | WOS << Entry.symbolName(); | |||
1541 | WOS << '\0'; | |||
1542 | WeaksAdded++; | |||
1543 | } else { | |||
1544 | // This is the case the symbol was previously been found and it could | |||
1545 | // have been added from a bind or lazy bind symbol. If so and not | |||
1546 | // a definition also mark it as weak. | |||
1547 | if (SymbolList[J].TypeChar == 'U') | |||
1548 | // See comment above about N_WEAK_DEF. | |||
1549 | SymbolList[J].NDesc |= MachO::N_WEAK_DEF; | |||
1550 | } | |||
1551 | } | |||
1552 | if (WErr) | |||
1553 | error(std::move(WErr), MachO.getFileName()); | |||
1554 | // Set the symbol names and indirect names for the added symbols. | |||
1555 | if (WeaksAdded) { | |||
1556 | WOS.flush(); | |||
1557 | const char *Q = WeaksNameBuffer.c_str(); | |||
1558 | for (unsigned K = 0; K < WeaksAdded; K++) { | |||
1559 | SymbolList[I].Name = Q; | |||
1560 | Q += strlen(Q) + 1; | |||
1561 | if (SymbolList[I].TypeChar == 'I') { | |||
1562 | SymbolList[I].IndirectName = Q; | |||
1563 | Q += strlen(Q) + 1; | |||
1564 | } | |||
1565 | I++; | |||
1566 | } | |||
1567 | } | |||
1568 | ||||
1569 | // Trying adding symbol from the function starts table and LC_MAIN entry | |||
1570 | // point. | |||
1571 | SmallVector<uint64_t, 8> FoundFns; | |||
1572 | uint64_t lc_main_offset = UINT64_MAX(18446744073709551615UL); | |||
1573 | for (const auto &Command : MachO.load_commands()) { | |||
1574 | if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) { | |||
1575 | // We found a function starts segment, parse the addresses for | |||
1576 | // consumption. | |||
1577 | MachO::linkedit_data_command LLC = | |||
1578 | MachO.getLinkeditDataLoadCommand(Command); | |||
1579 | ||||
1580 | MachO.ReadULEB128s(LLC.dataoff, FoundFns); | |||
1581 | } else if (Command.C.cmd == MachO::LC_MAIN) { | |||
1582 | MachO::entry_point_command LCmain = MachO.getEntryPointCommand(Command); | |||
1583 | lc_main_offset = LCmain.entryoff; | |||
1584 | } | |||
1585 | } | |||
1586 | // See if these addresses are already in the symbol table. | |||
1587 | unsigned FunctionStartsAdded = 0; | |||
1588 | for (uint64_t f = 0; f < FoundFns.size(); f++) { | |||
1589 | bool found = false; | |||
1590 | for (unsigned J = 0; J < SymbolList.size() && !found; ++J) { | |||
1591 | if (SymbolList[J].Address == FoundFns[f] + BaseSegmentAddress) | |||
1592 | found = true; | |||
1593 | } | |||
1594 | // See this address is not already in the symbol table fake up an | |||
1595 | // nlist for it. | |||
1596 | if (!found) { | |||
1597 | NMSymbol F = {}; | |||
1598 | F.Name = "<redacted function X>"; | |||
1599 | F.Address = FoundFns[f] + BaseSegmentAddress; | |||
1600 | F.Size = 0; | |||
1601 | // There is no symbol in the nlist symbol table for this so we set | |||
1602 | // Sym effectivly to null and the rest of code in here must test for | |||
1603 | // it and not do things like Sym.getFlags() for it. | |||
1604 | F.Sym = BasicSymbolRef(); | |||
1605 | F.SymFlags = 0; | |||
1606 | F.NType = MachO::N_SECT; | |||
1607 | F.NSect = 0; | |||
1608 | StringRef SegmentName = StringRef(); | |||
1609 | StringRef SectionName = StringRef(); | |||
1610 | for (const SectionRef &Section : MachO.sections()) { | |||
1611 | if (Expected<StringRef> NameOrErr = Section.getName()) | |||
1612 | SectionName = *NameOrErr; | |||
1613 | else | |||
1614 | consumeError(NameOrErr.takeError()); | |||
1615 | ||||
1616 | SegmentName = | |||
1617 | MachO.getSectionFinalSegmentName(Section.getRawDataRefImpl()); | |||
1618 | F.NSect++; | |||
1619 | if (F.Address >= Section.getAddress() && | |||
1620 | F.Address < Section.getAddress() + Section.getSize()) { | |||
1621 | F.Section = Section; | |||
1622 | break; | |||
1623 | } | |||
1624 | } | |||
1625 | if (SegmentName == "__TEXT" && SectionName == "__text") | |||
1626 | F.TypeChar = 't'; | |||
1627 | else if (SegmentName == "__DATA" && SectionName == "__data") | |||
1628 | F.TypeChar = 'd'; | |||
1629 | else if (SegmentName == "__DATA" && SectionName == "__bss") | |||
1630 | F.TypeChar = 'b'; | |||
1631 | else | |||
1632 | F.TypeChar = 's'; | |||
1633 | F.NDesc = 0; | |||
1634 | SymbolList.push_back(F); | |||
1635 | if (FoundFns[f] == lc_main_offset) | |||
1636 | FOS << "<redacted LC_MAIN>"; | |||
1637 | else | |||
1638 | FOS << "<redacted function " << f << ">"; | |||
1639 | FOS << '\0'; | |||
1640 | FunctionStartsAdded++; | |||
1641 | } | |||
1642 | } | |||
1643 | if (FunctionStartsAdded) { | |||
1644 | FOS.flush(); | |||
1645 | const char *Q = FunctionStartsNameBuffer.c_str(); | |||
1646 | for (unsigned K = 0; K < FunctionStartsAdded; K++) { | |||
1647 | SymbolList[I].Name = Q; | |||
1648 | Q += strlen(Q) + 1; | |||
1649 | if (SymbolList[I].TypeChar == 'I') { | |||
1650 | SymbolList[I].IndirectName = Q; | |||
1651 | Q += strlen(Q) + 1; | |||
1652 | } | |||
1653 | I++; | |||
1654 | } | |||
1655 | } | |||
1656 | } | |||
1657 | } | |||
1658 | ||||
1659 | static bool shouldDump(SymbolicFile &Obj) { | |||
1660 | // The -X option is currently only implemented for XCOFF, ELF, and IR object | |||
1661 | // files. The option isn't fundamentally impossible with other formats, just | |||
1662 | // isn't implemented. | |||
1663 | if (!isa<XCOFFObjectFile>(Obj) && !isa<ELFObjectFileBase>(Obj) && | |||
1664 | !isa<IRObjectFile>(Obj)) | |||
1665 | return true; | |||
1666 | ||||
1667 | return isSymbolList64Bit(Obj) ? BitMode != BitModeTy::Bit32 | |||
1668 | : BitMode != BitModeTy::Bit64; | |||
1669 | } | |||
1670 | ||||
1671 | static void getXCOFFExports(XCOFFObjectFile *XCOFFObj, | |||
1672 | std::vector<NMSymbol> &SymbolList, | |||
1673 | StringRef ArchiveName) { | |||
1674 | // Skip Shared object file. | |||
1675 | if (XCOFFObj->getFlags() & XCOFF::F_SHROBJ) | |||
1676 | return; | |||
1677 | ||||
1678 | for (SymbolRef Sym : XCOFFObj->symbols()) { | |||
1679 | // There is no visibility in old 32 bit XCOFF object file interpret. | |||
1680 | bool HasVisibilityAttr = | |||
1681 | XCOFFObj->is64Bit() || (XCOFFObj->auxiliaryHeader32() && | |||
1682 | (XCOFFObj->auxiliaryHeader32()->getVersion() == | |||
1683 | XCOFF::NEW_XCOFF_INTERPRET)); | |||
1684 | ||||
1685 | if (HasVisibilityAttr) { | |||
1686 | XCOFFSymbolRef XCOFFSym = XCOFFObj->toSymbolRef(Sym.getRawDataRefImpl()); | |||
1687 | uint16_t SymType = XCOFFSym.getSymbolType(); | |||
1688 | if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_INTERNAL) | |||
1689 | continue; | |||
1690 | if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_HIDDEN) | |||
1691 | continue; | |||
1692 | } | |||
1693 | ||||
1694 | Expected<section_iterator> SymSecOrErr = Sym.getSection(); | |||
1695 | if (!SymSecOrErr) { | |||
1696 | warn(SymSecOrErr.takeError(), XCOFFObj->getFileName(), | |||
1697 | "for symbol with index " + | |||
1698 | Twine(XCOFFObj->getSymbolIndex(Sym.getRawDataRefImpl().p)), | |||
1699 | ArchiveName); | |||
1700 | continue; | |||
1701 | } | |||
1702 | section_iterator SecIter = *SymSecOrErr; | |||
1703 | // If the symbol is not in a text or data section, it is not exported. | |||
1704 | if (SecIter == XCOFFObj->section_end()) | |||
1705 | continue; | |||
1706 | if (!(SecIter->isText() || SecIter->isData() || SecIter->isBSS())) | |||
1707 | continue; | |||
1708 | ||||
1709 | StringRef SymName = cantFail(Sym.getName()); | |||
1710 | if (SymName.empty()) | |||
1711 | continue; | |||
1712 | if (SymName.startswith("__sinit") || SymName.startswith("__sterm") || | |||
1713 | SymName.front() == '.' || SymName.front() == '(') | |||
1714 | continue; | |||
1715 | ||||
1716 | // Check the SymName regex matching with "^__[0-9]+__". | |||
1717 | if (SymName.size() > 4 && SymName.startswith("__") && | |||
1718 | SymName.endswith("__")) { | |||
1719 | if (std::all_of(SymName.begin() + 2, SymName.end() - 2, isDigit)) | |||
1720 | continue; | |||
1721 | } | |||
1722 | ||||
1723 | if (SymName == "__rsrc" && NoRsrc) | |||
1724 | continue; | |||
1725 | ||||
1726 | if (SymName.startswith("__tf1")) | |||
1727 | SymName = SymName.substr(6); | |||
1728 | else if (SymName.startswith("__tf9")) | |||
1729 | SymName = SymName.substr(14); | |||
1730 | ||||
1731 | NMSymbol S = {}; | |||
1732 | S.Name = SymName.str(); | |||
1733 | S.Sym = Sym; | |||
1734 | ||||
1735 | if (HasVisibilityAttr) { | |||
1736 | XCOFFSymbolRef XCOFFSym = XCOFFObj->toSymbolRef(Sym.getRawDataRefImpl()); | |||
1737 | uint16_t SymType = XCOFFSym.getSymbolType(); | |||
1738 | if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_PROTECTED) | |||
1739 | S.Visibility = "protected"; | |||
1740 | else if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_EXPORTED) | |||
1741 | S.Visibility = "export"; | |||
1742 | } | |||
1743 | if (S.initializeFlags(*XCOFFObj)) | |||
1744 | SymbolList.push_back(S); | |||
1745 | } | |||
1746 | } | |||
1747 | ||||
1748 | static Expected<SymbolicFile::basic_symbol_iterator_range> | |||
1749 | getDynamicSyms(SymbolicFile &Obj) { | |||
1750 | const auto *E = dyn_cast<ELFObjectFileBase>(&Obj); | |||
1751 | if (!E) | |||
1752 | return createError("File format has no dynamic symbol table"); | |||
1753 | return E->getDynamicSymbolIterators(); | |||
1754 | } | |||
1755 | ||||
1756 | // Returns false if there is error found or true otherwise. | |||
1757 | static bool getSymbolNamesFromObject(SymbolicFile &Obj, | |||
1758 | std::vector<NMSymbol> &SymbolList) { | |||
1759 | auto Symbols = Obj.symbols(); | |||
1760 | std::vector<VersionEntry> SymbolVersions; | |||
1761 | ||||
1762 | if (DynamicSyms) { | |||
1763 | Expected<SymbolicFile::basic_symbol_iterator_range> SymbolsOrErr = | |||
1764 | getDynamicSyms(Obj); | |||
1765 | if (!SymbolsOrErr) { | |||
1766 | error(SymbolsOrErr.takeError(), Obj.getFileName()); | |||
1767 | return false; | |||
1768 | } | |||
1769 | Symbols = *SymbolsOrErr; | |||
1770 | if (const auto *E = dyn_cast<ELFObjectFileBase>(&Obj)) { | |||
1771 | if (Expected<std::vector<VersionEntry>> VersionsOrErr = | |||
1772 | E->readDynsymVersions()) | |||
1773 | SymbolVersions = std::move(*VersionsOrErr); | |||
1774 | else | |||
1775 | WithColor::warning(errs(), ToolName) | |||
1776 | << "unable to read symbol versions: " | |||
1777 | << toString(VersionsOrErr.takeError()) << "\n"; | |||
1778 | } | |||
1779 | } | |||
1780 | // If a "-s segname sectname" option was specified and this is a Mach-O | |||
1781 | // file get the section number for that section in this object file. | |||
1782 | unsigned int Nsect = 0; | |||
1783 | MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj); | |||
1784 | if (!SegSect.empty() && MachO) { | |||
1785 | Nsect = getNsectForSegSect(MachO); | |||
1786 | // If this section is not in the object file no symbols are printed. | |||
1787 | if (Nsect == 0) | |||
1788 | return false; | |||
1789 | } | |||
1790 | ||||
1791 | if (!(MachO && DyldInfoOnly)) { | |||
1792 | size_t I = -1; | |||
1793 | for (BasicSymbolRef Sym : Symbols) { | |||
1794 | ++I; | |||
1795 | Expected<uint32_t> SymFlagsOrErr = Sym.getFlags(); | |||
1796 | if (!SymFlagsOrErr) { | |||
1797 | error(SymFlagsOrErr.takeError(), Obj.getFileName()); | |||
1798 | return false; | |||
1799 | } | |||
1800 | ||||
1801 | // Don't drop format specifc symbols for ARM and AArch64 ELF targets, they | |||
1802 | // are used to repesent mapping symbols and needed to honor the | |||
1803 | // --special-syms option. | |||
1804 | auto *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj); | |||
1805 | if ((!ELFObj || (ELFObj->getEMachine() != ELF::EM_ARM && | |||
1806 | ELFObj->getEMachine() != ELF::EM_AARCH64)) && | |||
1807 | !DebugSyms && (*SymFlagsOrErr & SymbolRef::SF_FormatSpecific)) | |||
1808 | continue; | |||
1809 | if (WithoutAliases && (*SymFlagsOrErr & SymbolRef::SF_Indirect)) | |||
1810 | continue; | |||
1811 | // If a "-s segname sectname" option was specified and this is a Mach-O | |||
1812 | // file and this section appears in this file, Nsect will be non-zero then | |||
1813 | // see if this symbol is a symbol from that section and if not skip it. | |||
1814 | if (Nsect && Nsect != getNsectInMachO(*MachO, Sym)) | |||
1815 | continue; | |||
1816 | NMSymbol S = {}; | |||
1817 | S.Size = 0; | |||
1818 | S.Address = 0; | |||
1819 | if (isa<ELFObjectFileBase>(&Obj)) | |||
1820 | S.Size = ELFSymbolRef(Sym).getSize(); | |||
1821 | ||||
1822 | if (const XCOFFObjectFile *XCOFFObj = | |||
1823 | dyn_cast<const XCOFFObjectFile>(&Obj)) | |||
1824 | S.Size = XCOFFObj->getSymbolSize(Sym.getRawDataRefImpl()); | |||
1825 | ||||
1826 | if (PrintAddress && isa<ObjectFile>(Obj)) { | |||
1827 | SymbolRef SymRef(Sym); | |||
1828 | Expected<uint64_t> AddressOrErr = SymRef.getAddress(); | |||
1829 | if (!AddressOrErr) { | |||
1830 | consumeError(AddressOrErr.takeError()); | |||
1831 | break; | |||
1832 | } | |||
1833 | S.Address = *AddressOrErr; | |||
1834 | } | |||
1835 | S.TypeName = getNMTypeName(Obj, Sym); | |||
1836 | S.TypeChar = getNMSectionTagAndName(Obj, Sym, S.SectionName); | |||
1837 | ||||
1838 | raw_string_ostream OS(S.Name); | |||
1839 | if (Error E = Sym.printName(OS)) { | |||
1840 | if (MachO) { | |||
1841 | OS << "bad string index"; | |||
1842 | consumeError(std::move(E)); | |||
1843 | } else | |||
1844 | error(std::move(E), Obj.getFileName()); | |||
1845 | } | |||
1846 | if (!SymbolVersions.empty() && !SymbolVersions[I].Name.empty()) | |||
1847 | S.Name += | |||
1848 | (SymbolVersions[I].IsVerDef ? "@@" : "@") + SymbolVersions[I].Name; | |||
1849 | ||||
1850 | S.Sym = Sym; | |||
1851 | if (S.initializeFlags(Obj)) | |||
1852 | SymbolList.push_back(S); | |||
1853 | } | |||
1854 | } | |||
1855 | ||||
1856 | // If this is a Mach-O file where the nlist symbol table is out of sync | |||
1857 | // with the dyld export trie then look through exports and fake up symbols | |||
1858 | // for the ones that are missing (also done with the -add-dyldinfo flag). | |||
1859 | // This is needed if strip(1) -T is run on a binary containing swift | |||
1860 | // language symbols for example. The option -only-dyldinfo will fake up | |||
1861 | // all symbols from the dyld export trie as well as the bind info. | |||
1862 | if (MachO && !NoDyldInfo) | |||
1863 | dumpSymbolsFromDLInfoMachO(*MachO, SymbolList); | |||
1864 | ||||
1865 | return true; | |||
1866 | } | |||
1867 | ||||
1868 | static void printObjectLabel(bool PrintArchiveName, StringRef ArchiveName, | |||
1869 | StringRef ArchitectureName, | |||
1870 | StringRef ObjectFileName) { | |||
1871 | outs() << "\n"; | |||
1872 | if (ArchiveName.empty() || !PrintArchiveName) | |||
1873 | outs() << ObjectFileName; | |||
1874 | else | |||
1875 | outs() << ArchiveName << "(" << ObjectFileName << ")"; | |||
1876 | if (!ArchitectureName.empty()) | |||
1877 | outs() << " (for architecture " << ArchitectureName << ")"; | |||
1878 | outs() << ":\n"; | |||
1879 | } | |||
1880 | ||||
1881 | static Expected<bool> hasSymbols(SymbolicFile &Obj) { | |||
1882 | if (DynamicSyms) { | |||
1883 | Expected<SymbolicFile::basic_symbol_iterator_range> DynamicSymsOrErr = | |||
1884 | getDynamicSyms(Obj); | |||
1885 | if (!DynamicSymsOrErr) | |||
1886 | return DynamicSymsOrErr.takeError(); | |||
1887 | return !DynamicSymsOrErr->empty(); | |||
1888 | } | |||
1889 | return !Obj.symbols().empty(); | |||
1890 | } | |||
1891 | ||||
1892 | static void dumpSymbolNamesFromObject( | |||
1893 | SymbolicFile &Obj, std::vector<NMSymbol> &SymbolList, | |||
1894 | bool PrintSymbolObject, bool PrintObjectLabel, StringRef ArchiveName = {}, | |||
1895 | StringRef ArchitectureName = {}, StringRef ObjectName = {}, | |||
1896 | bool PrintArchiveName = true) { | |||
1897 | if (!shouldDump(Obj)) | |||
1898 | return; | |||
1899 | ||||
1900 | if (ExportSymbols && Obj.isXCOFF()) { | |||
1901 | XCOFFObjectFile *XCOFFObj = cast<XCOFFObjectFile>(&Obj); | |||
1902 | getXCOFFExports(XCOFFObj, SymbolList, ArchiveName); | |||
1903 | return; | |||
1904 | } | |||
1905 | ||||
1906 | if (PrintObjectLabel && !ExportSymbols) | |||
1907 | printObjectLabel(PrintArchiveName, ArchiveName, ArchitectureName, | |||
1908 | ObjectName.empty() ? Obj.getFileName() : ObjectName); | |||
1909 | if (!getSymbolNamesFromObject(Obj, SymbolList) || ExportSymbols) | |||
1910 | return; | |||
1911 | CurrentFilename = Obj.getFileName(); | |||
1912 | ||||
1913 | // If there is an error in hasSymbols(), the error should be encountered in | |||
1914 | // function getSymbolNamesFromObject first. | |||
1915 | if (!cantFail(hasSymbols(Obj)) && SymbolList.empty() && !Quiet) { | |||
1916 | writeFileName(errs(), ArchiveName, ArchitectureName); | |||
1917 | errs() << "no symbols\n"; | |||
1918 | } | |||
1919 | ||||
1920 | sortSymbolList(SymbolList); | |||
1921 | printSymbolList(Obj, SymbolList, PrintSymbolObject, ArchiveName, | |||
1922 | ArchitectureName); | |||
1923 | } | |||
1924 | ||||
1925 | // checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file | |||
1926 | // and if it is and there is a list of architecture flags is specified then | |||
1927 | // check to make sure this Mach-O file is one of those architectures or all | |||
1928 | // architectures was specificed. If not then an error is generated and this | |||
1929 | // routine returns false. Else it returns true. | |||
1930 | static bool checkMachOAndArchFlags(SymbolicFile *O, StringRef Filename) { | |||
1931 | auto *MachO = dyn_cast<MachOObjectFile>(O); | |||
1932 | ||||
1933 | if (!MachO || ArchAll || ArchFlags.empty()) | |||
1934 | return true; | |||
1935 | ||||
1936 | MachO::mach_header H; | |||
1937 | MachO::mach_header_64 H_64; | |||
1938 | Triple T; | |||
1939 | const char *McpuDefault, *ArchFlag; | |||
1940 | if (MachO->is64Bit()) { | |||
1941 | H_64 = MachO->MachOObjectFile::getHeader64(); | |||
1942 | T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype, | |||
1943 | &McpuDefault, &ArchFlag); | |||
1944 | } else { | |||
1945 | H = MachO->MachOObjectFile::getHeader(); | |||
1946 | T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype, | |||
1947 | &McpuDefault, &ArchFlag); | |||
1948 | } | |||
1949 | const std::string ArchFlagName(ArchFlag); | |||
1950 | if (!llvm::is_contained(ArchFlags, ArchFlagName)) { | |||
1951 | error("No architecture specified", Filename); | |||
1952 | return false; | |||
1953 | } | |||
1954 | return true; | |||
1955 | } | |||
1956 | ||||
1957 | static void dumpArchiveMap(Archive *A, StringRef Filename) { | |||
1958 | Archive::symbol_iterator I = A->symbol_begin(); | |||
1959 | Archive::symbol_iterator E = A->symbol_end(); | |||
1960 | if (I != E) { | |||
1961 | outs() << "Archive map\n"; | |||
1962 | for (; I != E; ++I) { | |||
1963 | Expected<Archive::Child> C = I->getMember(); | |||
1964 | if (!C) { | |||
1965 | error(C.takeError(), Filename); | |||
1966 | break; | |||
1967 | } | |||
1968 | Expected<StringRef> FileNameOrErr = C->getName(); | |||
1969 | if (!FileNameOrErr) { | |||
1970 | error(FileNameOrErr.takeError(), Filename); | |||
1971 | break; | |||
1972 | } | |||
1973 | StringRef SymName = I->getName(); | |||
1974 | outs() << SymName << " in " << FileNameOrErr.get() << "\n"; | |||
1975 | } | |||
1976 | outs() << "\n"; | |||
1977 | } | |||
1978 | } | |||
1979 | ||||
1980 | static void dumpArchive(Archive *A, std::vector<NMSymbol> &SymbolList, | |||
1981 | StringRef Filename, LLVMContext *ContextPtr) { | |||
1982 | if (ArchiveMap) | |||
1983 | dumpArchiveMap(A, Filename); | |||
1984 | ||||
1985 | Error Err = Error::success(); | |||
1986 | for (auto &C : A->children(Err)) { | |||
1987 | Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(ContextPtr); | |||
1988 | if (!ChildOrErr) { | |||
1989 | if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) | |||
1990 | error(std::move(E), Filename, C); | |||
1991 | continue; | |||
1992 | } | |||
1993 | if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { | |||
1994 | if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) { | |||
1995 | WithColor::warning(errs(), ToolName) | |||
1996 | << "sizes with -print-size for Mach-O files are always zero.\n"; | |||
1997 | MachOPrintSizeWarning = true; | |||
1998 | } | |||
1999 | if (!checkMachOAndArchFlags(O, Filename)) | |||
2000 | return; | |||
2001 | dumpSymbolNamesFromObject(*O, SymbolList, /*PrintSymbolObject=*/false, | |||
2002 | !PrintFileName, Filename, | |||
2003 | /*ArchitectureName=*/{}, O->getFileName(), | |||
2004 | /*PrintArchiveName=*/false); | |||
2005 | } | |||
2006 | } | |||
2007 | if (Err) | |||
2008 | error(std::move(Err), A->getFileName()); | |||
2009 | } | |||
2010 | ||||
2011 | static void dumpMachOUniversalBinaryMatchArchFlags( | |||
2012 | MachOUniversalBinary *UB, std::vector<NMSymbol> &SymbolList, | |||
2013 | StringRef Filename, LLVMContext *ContextPtr) { | |||
2014 | // Look for a slice in the universal binary that matches each ArchFlag. | |||
2015 | bool ArchFound; | |||
2016 | for (unsigned i = 0; i < ArchFlags.size(); ++i) { | |||
2017 | ArchFound = false; | |||
2018 | for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), | |||
2019 | E = UB->end_objects(); | |||
2020 | I != E; ++I) { | |||
2021 | if (ArchFlags[i] == I->getArchFlagName()) { | |||
2022 | ArchFound = true; | |||
2023 | Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile(); | |||
2024 | std::string ArchiveName; | |||
2025 | std::string ArchitectureName; | |||
2026 | ArchiveName.clear(); | |||
2027 | ArchitectureName.clear(); | |||
2028 | if (ObjOrErr) { | |||
2029 | ObjectFile &Obj = *ObjOrErr.get(); | |||
2030 | if (ArchFlags.size() > 1) | |||
2031 | ArchitectureName = I->getArchFlagName(); | |||
2032 | dumpSymbolNamesFromObject(Obj, SymbolList, | |||
2033 | /*PrintSymbolObject=*/false, | |||
2034 | (ArchFlags.size() > 1) && !PrintFileName, | |||
2035 | ArchiveName, ArchitectureName); | |||
2036 | } else if (auto E = | |||
2037 | isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { | |||
2038 | error(std::move(E), Filename, | |||
2039 | ArchFlags.size() > 1 ? StringRef(I->getArchFlagName()) | |||
2040 | : StringRef()); | |||
2041 | continue; | |||
2042 | } else if (Expected<std::unique_ptr<Archive>> AOrErr = | |||
2043 | I->getAsArchive()) { | |||
2044 | std::unique_ptr<Archive> &A = *AOrErr; | |||
2045 | Error Err = Error::success(); | |||
2046 | for (auto &C : A->children(Err)) { | |||
2047 | Expected<std::unique_ptr<Binary>> ChildOrErr = | |||
2048 | C.getAsBinary(ContextPtr); | |||
2049 | if (!ChildOrErr) { | |||
2050 | if (auto E = | |||
2051 | isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) { | |||
2052 | error(std::move(E), Filename, C, | |||
2053 | ArchFlags.size() > 1 ? StringRef(I->getArchFlagName()) | |||
2054 | : StringRef()); | |||
2055 | } | |||
2056 | continue; | |||
2057 | } | |||
2058 | if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { | |||
2059 | ArchiveName = std::string(A->getFileName()); | |||
2060 | if (ArchFlags.size() > 1) | |||
2061 | ArchitectureName = I->getArchFlagName(); | |||
2062 | dumpSymbolNamesFromObject( | |||
2063 | *O, SymbolList, /*PrintSymbolObject=*/false, !PrintFileName, | |||
2064 | ArchiveName, ArchitectureName); | |||
2065 | } | |||
2066 | } | |||
2067 | if (Err) | |||
2068 | error(std::move(Err), A->getFileName()); | |||
2069 | } else { | |||
2070 | consumeError(AOrErr.takeError()); | |||
2071 | error(Filename + " for architecture " + | |||
2072 | StringRef(I->getArchFlagName()) + | |||
2073 | " is not a Mach-O file or an archive file", | |||
2074 | "Mach-O universal file"); | |||
2075 | } | |||
2076 | } | |||
2077 | } | |||
2078 | if (!ArchFound) { | |||
2079 | error(ArchFlags[i], | |||
2080 | "file: " + Filename + " does not contain architecture"); | |||
2081 | return; | |||
2082 | } | |||
2083 | } | |||
2084 | } | |||
2085 | ||||
2086 | // Returns true If the binary contains a slice that matches the host | |||
2087 | // architecture, or false otherwise. | |||
2088 | static bool dumpMachOUniversalBinaryMatchHost(MachOUniversalBinary *UB, | |||
2089 | std::vector<NMSymbol> &SymbolList, | |||
2090 | StringRef Filename, | |||
2091 | LLVMContext *ContextPtr) { | |||
2092 | Triple HostTriple = MachOObjectFile::getHostArch(); | |||
2093 | StringRef HostArchName = HostTriple.getArchName(); | |||
2094 | for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), | |||
2095 | E = UB->end_objects(); | |||
2096 | I != E; ++I) { | |||
2097 | if (HostArchName == I->getArchFlagName()) { | |||
2098 | Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile(); | |||
2099 | std::string ArchiveName; | |||
2100 | if (ObjOrErr) { | |||
2101 | ObjectFile &Obj = *ObjOrErr.get(); | |||
2102 | dumpSymbolNamesFromObject(Obj, SymbolList, /*PrintSymbolObject=*/false, | |||
2103 | /*PrintObjectLabel=*/false); | |||
2104 | } else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) | |||
2105 | error(std::move(E), Filename); | |||
2106 | else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) { | |||
2107 | std::unique_ptr<Archive> &A = *AOrErr; | |||
2108 | Error Err = Error::success(); | |||
2109 | for (auto &C : A->children(Err)) { | |||
2110 | Expected<std::unique_ptr<Binary>> ChildOrErr = | |||
2111 | C.getAsBinary(ContextPtr); | |||
2112 | if (!ChildOrErr) { | |||
2113 | if (auto E = | |||
2114 | isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) | |||
2115 | error(std::move(E), Filename, C); | |||
2116 | continue; | |||
2117 | } | |||
2118 | if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { | |||
2119 | ArchiveName = std::string(A->getFileName()); | |||
2120 | dumpSymbolNamesFromObject(*O, SymbolList, | |||
2121 | /*PrintSymbolObject=*/false, | |||
2122 | !PrintFileName, ArchiveName); | |||
2123 | } | |||
2124 | } | |||
2125 | if (Err) | |||
2126 | error(std::move(Err), A->getFileName()); | |||
2127 | } else { | |||
2128 | consumeError(AOrErr.takeError()); | |||
2129 | error(Filename + " for architecture " + | |||
2130 | StringRef(I->getArchFlagName()) + | |||
2131 | " is not a Mach-O file or an archive file", | |||
2132 | "Mach-O universal file"); | |||
2133 | } | |||
2134 | return true; | |||
2135 | } | |||
2136 | } | |||
2137 | return false; | |||
2138 | } | |||
2139 | ||||
2140 | static void dumpMachOUniversalBinaryArchAll(MachOUniversalBinary *UB, | |||
2141 | std::vector<NMSymbol> &SymbolList, | |||
2142 | StringRef Filename, | |||
2143 | LLVMContext *ContextPtr) { | |||
2144 | bool moreThanOneArch = UB->getNumberOfObjects() > 1; | |||
2145 | for (const MachOUniversalBinary::ObjectForArch &O : UB->objects()) { | |||
2146 | Expected<std::unique_ptr<ObjectFile>> ObjOrErr = O.getAsObjectFile(); | |||
2147 | std::string ArchiveName; | |||
2148 | std::string ArchitectureName; | |||
2149 | ArchiveName.clear(); | |||
2150 | ArchitectureName.clear(); | |||
2151 | if (ObjOrErr) { | |||
2152 | ObjectFile &Obj = *ObjOrErr.get(); | |||
2153 | if (isa<MachOObjectFile>(Obj) && moreThanOneArch) | |||
2154 | ArchitectureName = O.getArchFlagName(); | |||
2155 | dumpSymbolNamesFromObject(Obj, SymbolList, /*PrintSymbolObject=*/false, | |||
2156 | !PrintFileName, ArchiveName, ArchitectureName); | |||
2157 | } else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { | |||
2158 | error(std::move(E), Filename, | |||
2159 | moreThanOneArch ? StringRef(O.getArchFlagName()) : StringRef()); | |||
2160 | continue; | |||
2161 | } else if (Expected<std::unique_ptr<Archive>> AOrErr = O.getAsArchive()) { | |||
2162 | std::unique_ptr<Archive> &A = *AOrErr; | |||
2163 | Error Err = Error::success(); | |||
2164 | for (auto &C : A->children(Err)) { | |||
2165 | Expected<std::unique_ptr<Binary>> ChildOrErr = | |||
2166 | C.getAsBinary(ContextPtr); | |||
2167 | if (!ChildOrErr) { | |||
2168 | if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) | |||
2169 | error(std::move(E), Filename, C, | |||
2170 | moreThanOneArch ? StringRef(ArchitectureName) : StringRef()); | |||
2171 | continue; | |||
2172 | } | |||
2173 | if (SymbolicFile *F = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { | |||
2174 | ArchiveName = std::string(A->getFileName()); | |||
2175 | if (isa<MachOObjectFile>(F) && moreThanOneArch) | |||
2176 | ArchitectureName = O.getArchFlagName(); | |||
2177 | dumpSymbolNamesFromObject(*F, SymbolList, /*PrintSymbolObject=*/false, | |||
2178 | !PrintFileName, ArchiveName, | |||
2179 | ArchitectureName); | |||
2180 | } | |||
2181 | } | |||
2182 | if (Err) | |||
2183 | error(std::move(Err), A->getFileName()); | |||
2184 | } else { | |||
2185 | consumeError(AOrErr.takeError()); | |||
2186 | error(Filename + " for architecture " + StringRef(O.getArchFlagName()) + | |||
2187 | " is not a Mach-O file or an archive file", | |||
2188 | "Mach-O universal file"); | |||
2189 | } | |||
2190 | } | |||
2191 | } | |||
2192 | ||||
2193 | static void dumpMachOUniversalBinary(MachOUniversalBinary *UB, | |||
2194 | std::vector<NMSymbol> &SymbolList, | |||
2195 | StringRef Filename, | |||
2196 | LLVMContext *ContextPtr) { | |||
2197 | // If we have a list of architecture flags specified dump only those. | |||
2198 | if (!ArchAll && !ArchFlags.empty()) { | |||
2199 | dumpMachOUniversalBinaryMatchArchFlags(UB, SymbolList, Filename, | |||
2200 | ContextPtr); | |||
2201 | return; | |||
2202 | } | |||
2203 | ||||
2204 | // No architecture flags were specified so if this contains a slice that | |||
2205 | // matches the host architecture dump only that. | |||
2206 | if (!ArchAll && | |||
2207 | dumpMachOUniversalBinaryMatchHost(UB, SymbolList, Filename, ContextPtr)) | |||
2208 | return; | |||
2209 | ||||
2210 | // Either all architectures have been specified or none have been specified | |||
2211 | // and this does not contain the host architecture so dump all the slices. | |||
2212 | dumpMachOUniversalBinaryArchAll(UB, SymbolList, Filename, ContextPtr); | |||
2213 | } | |||
2214 | ||||
2215 | static void dumpTapiUniversal(TapiUniversal *TU, | |||
2216 | std::vector<NMSymbol> &SymbolList, | |||
2217 | StringRef Filename) { | |||
2218 | for (const TapiUniversal::ObjectForArch &I : TU->objects()) { | |||
2219 | StringRef ArchName = I.getArchFlagName(); | |||
2220 | const bool ShowArch = | |||
2221 | ArchFlags.empty() || llvm::is_contained(ArchFlags, ArchName); | |||
2222 | if (!ShowArch) | |||
2223 | continue; | |||
2224 | if (!AddInlinedInfo && !I.isTopLevelLib()) | |||
2225 | continue; | |||
2226 | if (auto ObjOrErr = I.getAsObjectFile()) | |||
2227 | dumpSymbolNamesFromObject( | |||
2228 | *ObjOrErr.get(), SymbolList, /*PrintSymbolObject=*/false, | |||
2229 | /*PrintObjectLabel=*/true, | |||
2230 | /*ArchiveName=*/{}, ArchName, I.getInstallName()); | |||
2231 | else if (Error E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { | |||
2232 | error(std::move(E), Filename, ArchName); | |||
2233 | } | |||
2234 | } | |||
2235 | } | |||
2236 | ||||
2237 | static void dumpSymbolicFile(SymbolicFile *O, std::vector<NMSymbol> &SymbolList, | |||
2238 | StringRef Filename) { | |||
2239 | if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) { | |||
2240 | WithColor::warning(errs(), ToolName) | |||
2241 | << "sizes with --print-size for Mach-O files are always zero.\n"; | |||
2242 | MachOPrintSizeWarning = true; | |||
2243 | } | |||
2244 | if (!checkMachOAndArchFlags(O, Filename)) | |||
2245 | return; | |||
2246 | dumpSymbolNamesFromObject(*O, SymbolList, /*PrintSymbolObject=*/true, | |||
2247 | /*PrintObjectLabel=*/false); | |||
2248 | } | |||
2249 | ||||
2250 | static std::vector<NMSymbol> dumpSymbolNamesFromFile(StringRef Filename) { | |||
2251 | std::vector<NMSymbol> SymbolList; | |||
2252 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = | |||
2253 | MemoryBuffer::getFileOrSTDIN(Filename); | |||
2254 | if (error(BufferOrErr.getError(), Filename)) | |||
2255 | return SymbolList; | |||
2256 | ||||
2257 | LLVMContext Context; | |||
2258 | LLVMContext *ContextPtr = NoLLVMBitcode ? nullptr : &Context; | |||
2259 | Expected<std::unique_ptr<Binary>> BinaryOrErr = | |||
2260 | createBinary(BufferOrErr.get()->getMemBufferRef(), ContextPtr); | |||
2261 | if (!BinaryOrErr) { | |||
2262 | error(BinaryOrErr.takeError(), Filename); | |||
2263 | return SymbolList; | |||
2264 | } | |||
2265 | Binary &Bin = *BinaryOrErr.get(); | |||
2266 | if (Archive *A = dyn_cast<Archive>(&Bin)) | |||
2267 | dumpArchive(A, SymbolList, Filename, ContextPtr); | |||
2268 | else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) | |||
2269 | dumpMachOUniversalBinary(UB, SymbolList, Filename, ContextPtr); | |||
2270 | else if (TapiUniversal *TU = dyn_cast<TapiUniversal>(&Bin)) | |||
2271 | dumpTapiUniversal(TU, SymbolList, Filename); | |||
2272 | else if (SymbolicFile *O = dyn_cast<SymbolicFile>(&Bin)) | |||
2273 | dumpSymbolicFile(O, SymbolList, Filename); | |||
2274 | return SymbolList; | |||
2275 | } | |||
2276 | ||||
2277 | static void | |||
2278 | exportSymbolNamesFromFiles(const std::vector<std::string> &InputFilenames) { | |||
2279 | std::vector<NMSymbol> SymbolList; | |||
2280 | for (const auto &FileName : InputFilenames) { | |||
2281 | std::vector<NMSymbol> FileSymList = dumpSymbolNamesFromFile(FileName); | |||
2282 | SymbolList.insert(SymbolList.end(), FileSymList.begin(), FileSymList.end()); | |||
2283 | } | |||
2284 | ||||
2285 | // Delete symbols which should not be printed from SymolList. | |||
2286 | SymbolList.erase( | |||
2287 | llvm::remove_if(SymbolList, | |||
2288 | [](const NMSymbol &s) { return !s.shouldPrint(); }), | |||
2289 | SymbolList.end()); | |||
2290 | sortSymbolList(SymbolList); | |||
2291 | SymbolList.erase(std::unique(SymbolList.begin(), SymbolList.end()), | |||
2292 | SymbolList.end()); | |||
2293 | printExportSymbolList(SymbolList); | |||
2294 | } | |||
2295 | ||||
2296 | int main(int argc, char **argv) { | |||
2297 | InitLLVM X(argc, argv); | |||
2298 | BumpPtrAllocator A; | |||
2299 | StringSaver Saver(A); | |||
2300 | NmOptTable Tbl; | |||
2301 | ToolName = argv[0]; | |||
2302 | opt::InputArgList Args = | |||
2303 | Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { | |||
2304 | error(Msg); | |||
2305 | exit(1); | |||
2306 | }); | |||
2307 | if (Args.hasArg(OPT_help)) { | |||
2308 | Tbl.printHelp( | |||
2309 | outs(), | |||
2310 | (Twine(ToolName) + " [options] <input object files>").str().c_str(), | |||
2311 | "LLVM symbol table dumper"); | |||
2312 | // TODO Replace this with OptTable API once it adds extrahelp support. | |||
2313 | outs() << "\nPass @FILE as argument to read options from FILE.\n"; | |||
2314 | return 0; | |||
2315 | } | |||
2316 | if (Args.hasArg(OPT_version)) { | |||
2317 | // This needs to contain the word "GNU", libtool looks for that string. | |||
2318 | outs() << "llvm-nm, compatible with GNU nm" << '\n'; | |||
2319 | cl::PrintVersionMessage(); | |||
2320 | return 0; | |||
2321 | } | |||
2322 | ||||
2323 | DebugSyms = Args.hasArg(OPT_debug_syms); | |||
2324 | DefinedOnly = Args.hasArg(OPT_defined_only); | |||
2325 | Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false); | |||
2326 | DynamicSyms = Args.hasArg(OPT_dynamic); | |||
2327 | ExternalOnly = Args.hasArg(OPT_extern_only); | |||
2328 | StringRef V = Args.getLastArgValue(OPT_format_EQ, "bsd"); | |||
2329 | if (V == "bsd") | |||
2330 | OutputFormat = bsd; | |||
2331 | else if (V == "posix") | |||
2332 | OutputFormat = posix; | |||
2333 | else if (V == "sysv") | |||
2334 | OutputFormat = sysv; | |||
2335 | else if (V == "darwin") | |||
2336 | OutputFormat = darwin; | |||
2337 | else if (V == "just-symbols") | |||
2338 | OutputFormat = just_symbols; | |||
2339 | else | |||
2340 | error("--format value should be one of: bsd, posix, sysv, darwin, " | |||
2341 | "just-symbols"); | |||
2342 | NoLLVMBitcode = Args.hasArg(OPT_no_llvm_bc); | |||
2343 | NoSort = Args.hasArg(OPT_no_sort); | |||
2344 | NoWeakSymbols = Args.hasArg(OPT_no_weak); | |||
2345 | NumericSort = Args.hasArg(OPT_numeric_sort); | |||
2346 | ArchiveMap = Args.hasArg(OPT_print_armap); | |||
2347 | PrintFileName = Args.hasArg(OPT_print_file_name); | |||
2348 | PrintSize = Args.hasArg(OPT_print_size); | |||
2349 | ReverseSort = Args.hasArg(OPT_reverse_sort); | |||
2350 | ExportSymbols = Args.hasArg(OPT_export_symbols); | |||
2351 | if (ExportSymbols) { | |||
2352 | ExternalOnly = true; | |||
2353 | DefinedOnly = true; | |||
2354 | } | |||
2355 | ||||
2356 | Quiet = Args.hasArg(OPT_quiet); | |||
2357 | V = Args.getLastArgValue(OPT_radix_EQ, "x"); | |||
2358 | if (V == "o") | |||
2359 | AddressRadix = Radix::o; | |||
2360 | else if (V == "d") | |||
2361 | AddressRadix = Radix::d; | |||
2362 | else if (V == "x") | |||
2363 | AddressRadix = Radix::x; | |||
2364 | else | |||
2365 | error("--radix value should be one of: 'o' (octal), 'd' (decimal), 'x' " | |||
2366 | "(hexadecimal)"); | |||
2367 | SizeSort = Args.hasArg(OPT_size_sort); | |||
2368 | SpecialSyms = Args.hasArg(OPT_special_syms); | |||
2369 | UndefinedOnly = Args.hasArg(OPT_undefined_only); | |||
2370 | WithoutAliases = Args.hasArg(OPT_without_aliases); | |||
2371 | ||||
2372 | StringRef Mode = Args.getLastArgValue(OPT_X, "any"); | |||
2373 | if (Mode == "32") | |||
2374 | BitMode = BitModeTy::Bit32; | |||
2375 | else if (Mode == "64") | |||
2376 | BitMode = BitModeTy::Bit64; | |||
2377 | else if (Mode == "32_64") | |||
2378 | BitMode = BitModeTy::Bit32_64; | |||
2379 | else if (Mode == "any") | |||
2380 | BitMode = BitModeTy::Any; | |||
2381 | else | |||
2382 | error("-X value should be one of: 32, 64, 32_64, (default) any"); | |||
2383 | ||||
2384 | // Mach-O specific options. | |||
2385 | FormatMachOasHex = Args.hasArg(OPT_x); | |||
2386 | AddDyldInfo = Args.hasArg(OPT_add_dyldinfo); | |||
2387 | AddInlinedInfo = Args.hasArg(OPT_add_inlinedinfo); | |||
2388 | DyldInfoOnly = Args.hasArg(OPT_dyldinfo_only); | |||
2389 | NoDyldInfo = Args.hasArg(OPT_no_dyldinfo); | |||
2390 | ||||
2391 | // XCOFF specific options. | |||
2392 | NoRsrc = Args.hasArg(OPT_no_rsrc); | |||
2393 | ||||
2394 | // llvm-nm only reads binary files. | |||
2395 | if (error(sys::ChangeStdinToBinary())) | |||
2396 | return 1; | |||
2397 | ||||
2398 | // These calls are needed so that we can read bitcode correctly. | |||
2399 | llvm::InitializeAllTargetInfos(); | |||
2400 | llvm::InitializeAllTargetMCs(); | |||
2401 | llvm::InitializeAllAsmParsers(); | |||
2402 | ||||
2403 | // The relative order of these is important. If you pass --size-sort it should | |||
2404 | // only print out the size. However, if you pass -S --size-sort, it should | |||
2405 | // print out both the size and address. | |||
2406 | if (SizeSort && !PrintSize) | |||
2407 | PrintAddress = false; | |||
2408 | if (OutputFormat == sysv || SizeSort) | |||
2409 | PrintSize = true; | |||
2410 | ||||
2411 | for (const auto *A : Args.filtered(OPT_arch_EQ)) { | |||
2412 | SmallVector<StringRef, 2> Values; | |||
2413 | llvm::SplitString(A->getValue(), Values, ","); | |||
2414 | for (StringRef V : Values) { | |||
2415 | if (V == "all") | |||
2416 | ArchAll = true; | |||
2417 | else if (MachOObjectFile::isValidArch(V)) | |||
2418 | ArchFlags.push_back(V); | |||
2419 | else | |||
2420 | error("Unknown architecture named '" + V + "'", | |||
2421 | "for the --arch option"); | |||
2422 | } | |||
2423 | } | |||
2424 | ||||
2425 | // Mach-O takes -s to accept two arguments. We emulate this by iterating over | |||
2426 | // both OPT_s and OPT_INPUT. | |||
2427 | std::vector<std::string> InputFilenames; | |||
2428 | int SegSectArgs = 0; | |||
2429 | for (opt::Arg *A : Args.filtered(OPT_s, OPT_INPUT)) { | |||
2430 | if (SegSectArgs > 0) { | |||
2431 | --SegSectArgs; | |||
2432 | SegSect.push_back(A->getValue()); | |||
2433 | } else if (A->getOption().matches(OPT_s)) { | |||
2434 | SegSectArgs = 2; | |||
2435 | } else { | |||
2436 | InputFilenames.push_back(A->getValue()); | |||
2437 | } | |||
2438 | } | |||
2439 | if (!SegSect.empty() && SegSect.size() != 2) | |||
2440 | error("bad number of arguments (must be two arguments)", | |||
2441 | "for the -s option"); | |||
2442 | ||||
2443 | if (InputFilenames.empty()) | |||
2444 | InputFilenames.push_back("a.out"); | |||
2445 | if (InputFilenames.size() > 1) | |||
2446 | MultipleFiles = true; | |||
2447 | ||||
2448 | if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly)) | |||
2449 | error("--no-dyldinfo can't be used with --add-dyldinfo or --dyldinfo-only"); | |||
2450 | ||||
2451 | if (ExportSymbols) | |||
2452 | exportSymbolNamesFromFiles(InputFilenames); | |||
2453 | else | |||
2454 | llvm::for_each(InputFilenames, dumpSymbolNamesFromFile); | |||
2455 | ||||
2456 | if (HadError) | |||
2457 | return 1; | |||
2458 | } |