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