diff --git a/llvm/docs/CommandGuide/llvm-nm.rst b/llvm/docs/CommandGuide/llvm-nm.rst --- a/llvm/docs/CommandGuide/llvm-nm.rst +++ b/llvm/docs/CommandGuide/llvm-nm.rst @@ -157,6 +157,11 @@ Display dynamic symbols instead of normal symbols. +.. option:: --export-symbols + + Print sorted symbols with their visibility (if applicable), with duplicates + removed. + .. option:: --extern-only, -g Print only symbols whose definitions are external; that is, accessible from @@ -282,6 +287,13 @@ Print symbol entry in hex. +XCOFF SPECIFIC OPTIONS +---------------------- + +.. option:: --no-rsrc + + Exclude resource file symbols (``__rsrc``) from export symbol list. + BUGS ---- diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -54,6 +54,34 @@ ///< future use and should be set to 0. }; +enum XCOFFInterpret : uint16_t { + OLD_XCOFF_INTERPRET = 1, + NEW_XCOFF_INTERPRET = 2 +}; + +enum FileFlag : uint16_t { + F_RELFLG = 0x0001, ///< relocation info stripped from file + F_EXEC = 0x0002, ///< file is executable (i.e., it + ///< has a loader section) + F_LNNO = 0x0004, ///< line numbers stripped from file + F_LSYMS = 0x0008, ///< local symbols stripped from file + F_FDPR_PROF = 0x0010, ///< file was profiled with FDPR + F_FDPR_OPTI = 0x0020, ///< file was reordered with FDPR + F_DSA = 0x0040, ///< file uses Dynamic Segment Allocation (32-bit + ///< only) + F_DEP_1 = 0x0080, ///< Data Execution Protection bit 1 + F_VARPG = 0x0100, ///< executable requests using variable size pages + F_LPTEXT = 0x0400, ///< executable requires large pages for text + F_LPDATA = 0x0800, ///< executable requires large pages for data + F_DYNLOAD = 0x1000, ///< file is dynamically loadable and + ///< executable (equivalent to F_EXEC on AIX) + F_SHROBJ = 0x2000, ///< file is a shared object + F_LOADONLY = + 0x4000, ///< file can be loaded by the system loader, but it is + ///< ignored by the linker if it is a member of an archive. + F_DEP_2 = 0x8000 ///< Data Execution Protection bit 2 +}; + // x_smclas field of x_csect from system header: /usr/include/syms.h /// Storage Mapping Class definitions. enum StorageMappingClass : uint8_t { @@ -212,6 +240,8 @@ SYM_V_EXPORTED = 0x4000 }; +constexpr uint16_t VISIBILITY_MASK = 0x7000; + // Relocation types, defined in `/usr/include/reloc.h`. enum RelocationType : uint8_t { R_POS = 0x00, ///< Positive relocation. Provides the address of the referenced diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -60,10 +60,13 @@ return static_cast(this)->FlagAndTDataAlignment & AuxiHeaderFlagMask; } + uint8_t getTDataAlignment() const { return static_cast(this)->FlagAndTDataAlignment & AuxiHeaderTDataAlignmentMask; } + + uint16_t getVersion() const { return static_cast(this)->Version; } }; struct XCOFFAuxiliaryHeader32 : XCOFFAuxiliaryHeader { diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -615,6 +615,16 @@ if (XCOFFSym.getSectionNumber() == XCOFF::N_UNDEF) Result |= SymbolRef::SF_Undefined; + // There is no visibility in old 32 bit XCOFF object file interpret. + if (is64Bit() || (auxiliaryHeader32() && (auxiliaryHeader32()->getVersion() == + NEW_XCOFF_INTERPRET))) { + uint16_t SymType = XCOFFSym.getSymbolType(); + if ((SymType & VISIBILITY_MASK) == SYM_V_HIDDEN) + Result |= SymbolRef::SF_Hidden; + + if ((SymType & VISIBILITY_MASK) == SYM_V_EXPORTED) + Result |= SymbolRef::SF_Exported; + } return Result; } diff --git a/llvm/test/tools/llvm-nm/XCOFF/export-symbols.test b/llvm/test/tools/llvm-nm/XCOFF/export-symbols.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-nm/XCOFF/export-symbols.test @@ -0,0 +1,340 @@ +## Test the "--export-symbols" option. +## The option merges all the output of input files, sorts and prints out unique symbols from the input files. + +# RUN: yaml2obj --docnum=1 -DFLAG=0x0002 %s -o %t1.o +# RUN: yaml2obj --docnum=2 -DFLAG=0x0002 %s -o %t2.o +# RUN: yaml2obj --docnum=2 -DFLAG=0x0002 -DSECT=26 %s -o %t2_invalid.o + +## Test the following cases: +## Do not export global symbols beginning with "__sinit" , "__sterm" , "." , "(". or regular expression "^__[0-9]+__". +## Do not export hidden and internal symbols. +## Remove name prefixes of global symbols beginning with "__tf1" and "__tf9". +# RUN: llvm-nm --export-symbols %t1.o | FileCheck %s --check-prefixes=COMMON,WEAK,RSRC --implicit-check-not={{.}} + +## Show that weak symbols are not exported when using the "--no-weak" option. +# RUN: llvm-nm --export-symbols --no-weak %t1.o | FileCheck --check-prefixes=COMMON,RSRC %s --implicit-check-not={{.}} + +## Show that only unique symbols (with a different name or visibility) are exported. +## RUN: llvm-nm --export-symbols %t1.o %t2.o | FileCheck --check-prefixes=COMMON,WEAK,OBJ2,RSRC %s --implicit-check-not={{.}} + +## Show that __rsrc symbols are not exported when using the "--no-rsrc" option. +# RUN: llvm-nm --export-symbols --no-rsrc %t1.o | FileCheck --check-prefixes=COMMON,WEAK %s --implicit-check-not={{.}} + +# COMMON: 023__ +# COMMON-NEXT: __023 +# COMMON-NEXT: __02er02__ +# COMMON-NEXT: ____ +# RSRC-NEXT: __rsrc +# COMMON-NEXT: __rsrc export +# COMMON-NEXT: __tf2value +# COMMON-NEXT: export_protected_var export +# COMMON-NEXT: export_protected_var protected +# OBJ2-NEXT: export_var_in_sec_obj export +# COMMON-NEXT: protected_var protected +# OBJ2-NEXT: protected_var_in_sec_obj protected +# COMMON-NEXT: tf1value +# COMMON-NEXT: tf9value +# OBJ2-NEXT: var1_in_sec_obj +# WEAK-NEXT: weak_func + +## Test the behavior of the symbol reference section. +# RUN: llvm-nm --export-symbols --no-rsrc %t2_invalid.o 2>&1 | \ +# RUN: FileCheck -DFILE=%t2_invalid.o --check-prefixes=INVALID %s + +# INVALID: llvm-nm{{(\.exe)?}}: warning: [[FILE]]: for symbol with index 8: the section index (26) is invalid +# INVALID-NEXT: export_protected_var export +# INVALID-NEXT: export_protected_var protected +# INVALID-NEXT: protected_var_in_sec_obj protected +# INVALID-NEXT: var1_in_sec_obj + +## Show that symbols in shared object files are not exported. +## Generate XCOFF shared object file. +# RUN: yaml2obj -DFLAG=0x2000 --docnum=2 %s -o %t_shared.o +# RUN: llvm-nm --export-symbols %t_shared.o | count 0 + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF + Flags: [[FLAG]] +AuxiliaryHeader: + Magic: 0x10B + Version: 0x2 +Sections: + - Name: .text + Flags: [ STYP_TEXT ] + - Name: .data + Flags: [ STYP_DATA ] + - Name: .bss + Flags: [ STYP_DATA ] + - Name: .debug + Flags: [ STYP_DEBUG ] +Symbols: + - Name: export_protected_var + Section: .data +## Exported visibility. + Type: 0x4000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: export_protected_var + Section: .data +## Protected visibility. + Type: 0x3000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: __rsrc + Section: .data +## No visibility. + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + SectionOrLength: 0x4 + - Name: __sinit + Section: .data + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x9 + StorageMappingClass: XMC_RW + SectionOrLength: 0xC + - Name: __sterm + Section: .data + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + SectionOrLength: 0xC + - Name: .func + Section: .text + Type: 0x20 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x02 + StorageMappingClass: XMC_PR + - Name: (func) + Section: .data + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + SectionOrLength: 0xC + - Name: __023__ + Section: .data + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + SectionOrLength: 0x4 + - Name: __tf1_tf1value + Section: .text + Type: 0x00 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RO + - Name: __tf9_12345678tf9value + Section: .data + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: __tf2value + Section: .data + Type: 0x0 + StorageClass: C_HIDEXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x21 + StorageMappingClass: XMC_TC + - Name: __tf2value + Section: .data + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: weak_func + Section: .data + Type: 0x0 + StorageClass: C_WEAKEXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: protected_var + Section: .bss + Type: 0x3000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x02 + StorageMappingClass: XMC_RW + - Name: hidden_var + Section: .data +## Hidden visibility. + Type: 0x2000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: internal_var + Section: .data +## Internal visibility. + Type: 0x1000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW +## A symbol that is neither text, nor data, nor bss. + - Name: debug + Section: .debug +## Empty symbol name. + - Name: "" + Section: .data + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_TC + - Name: undef_var + SectionIndex: 0 + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x20 + StorageMappingClass: XMC_UA +## Do not export not global symbol. + - Name: hidext_var + Section: .data +## Protected visibility. + Type: 0x3000 + StorageClass: C_HIDEXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW +## Symbol should not be filtered out by option --no-rsrc. + - Name: __tf1___rsrc + Section: .data + Type: 0x4000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + SectionOrLength: 0x4 +## Following symbols should not be filtered out by regular expression "^__[0-9]+__". + - Name: __023 + Section: .data + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + SectionOrLength: 0x4 + - Name: 023__ + Section: .data + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + SectionOrLength: 0x4 + - Name: ____ + Section: .data + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + SectionOrLength: 0x4 + - Name: __02er02__ + Section: .data + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + SectionOrLength: 0x4 + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF + Flags: [[FLAG]] +AuxiliaryHeader: + Magic: 0x10B + Version: 0x2 + TextSectionSize: 0x280 + DataSectionSize: 0x90 +Sections: + - Name: .text + Flags: [ STYP_TEXT ] + - Name: .data + Flags: [ STYP_DATA ] +Symbols: + - Name: export_protected_var + Section: .data + Type: 0x4000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: export_protected_var + Section: .data + Type: 0x3000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: var1_in_sec_obj + Section: .data + Type: 0x0 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + SectionOrLength: 0x4 + - Name: protected_var_in_sec_obj + Section: .data + Type: 0x3000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: export_var_in_sec_obj + SectionIndex: [[SECT=2]] + Type: 0x4000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW diff --git a/llvm/test/tools/llvm-nm/bitcode-export-sym.test b/llvm/test/tools/llvm-nm/bitcode-export-sym.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-nm/bitcode-export-sym.test @@ -0,0 +1,12 @@ +# REQUIRES: powerpc-registered-target +## Test the "--export-symbols" option with bitcode input files. + +# RUN: llvm-as -o %t32.bc %p/Inputs/bitcode-sym32.ll +# RUN: llvm-as -o %t64.bc %p/Inputs/bitcode-sym64.ll + +# RUN: llvm-nm --export-symbols %t32.bc %t64.bc | FileCheck %s --check-prefixes=CHECK --implicit-check-not={{.}} + +# CHECK: C32 +# CHECK-NEXT: C64 +# CHECK-NEXT: bar64 +# CHECK-NEXT: foo32 diff --git a/llvm/tools/llvm-nm/Opts.td b/llvm/tools/llvm-nm/Opts.td --- a/llvm/tools/llvm-nm/Opts.td +++ b/llvm/tools/llvm-nm/Opts.td @@ -18,6 +18,7 @@ def defined_only : FF<"defined-only", "Show only defined symbols">; defm demangle : BB<"demangle", "Demangle C++ symbol names", "Don't demangle symbol names">; def dynamic : FF<"dynamic", "Display dynamic symbols instead of normal symbols">; +def export_symbols : FF<"export-symbols", "Export symbol list for all inputs">; def extern_only : FF<"extern-only", "Show only external symbols">; defm format : Eq<"format", "Specify output format: bsd (default), posix, sysv, darwin, just-symbols">, MetaVarName<"">; def help : FF<"help", "Display this help">; @@ -49,6 +50,11 @@ def s : F<"s", "Dump only symbols from this segment and section name">, Group; def x : F<"x", "Print symbol entry in hex">, Group; +// XCOFF specific options. +def grp_xcoff_o : OptionGroup<"kind">, HelpText<"llvm-nm XCOFF Specific Options">; + +def no_rsrc : FF<"no-rsrc", "Exclude resource file symbols (__rsrc) from the export symbol list.">, Group; + def : FF<"just-symbol-name", "Alias for --format=just-symbols">, Alias, AliasArgs<["just-symbols"]>, Flags<[HelpHidden]>; def : FF<"portability", "Alias for --format=posix">, Alias, AliasArgs<["posix"]>; diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp --- a/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/llvm/tools/llvm-nm/llvm-nm.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/Demangle/Demangle.h" #include "llvm/IR/Function.h" #include "llvm/IR/LLVMContext.h" @@ -92,6 +93,7 @@ static bool DefinedOnly; static bool Demangle; static bool DynamicSyms; +static bool ExportSymbols; static bool ExternalOnly; static OutputFormatTy OutputFormat; static bool NoLLVMBitcode; @@ -107,6 +109,9 @@ static bool UndefinedOnly; static bool WithoutAliases; +// XCOFF-specific options. +static bool NoRsrc; + namespace { enum Radix { d, o, x }; } // namespace @@ -130,7 +135,8 @@ static StringRef ToolName; -static void warn(Error Err, Twine FileName, Twine Context = Twine()) { +static void warn(Error Err, Twine FileName, Twine Context = Twine(), + Twine Archive = Twine()) { assert(Err); // Flush the standard output so that the warning isn't interleaved with other @@ -139,8 +145,9 @@ handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) { WithColor::warning(errs(), ToolName) - << FileName << ": " << (Context.str().empty() ? "" : Context + ": ") - << EI.message() << "\n"; + << (Archive.str().empty() ? FileName : Archive + "(" + FileName + ")") + << ": " << (Context.str().empty() ? "" : Context + ": ") << EI.message() + << "\n"; }); } @@ -213,6 +220,8 @@ StringRef SectionName; StringRef TypeName; BasicSymbolRef Sym; + StringRef Visibility; + // The Sym field above points to the native symbol in the object file, // for Mach-O when we are creating symbols from the dyld info the above // pointer is null as there is no native symbol. In these cases the fields @@ -232,6 +241,29 @@ } return TypeChar != 'U'; } + + bool initializeFlags(const SymbolicFile &Obj) { + Expected SymFlagsOrErr = Sym.getFlags(); + if (!SymFlagsOrErr) { + // TODO: Test this error. + error(SymFlagsOrErr.takeError(), Obj.getFileName()); + return false; + } + SymFlags = *SymFlagsOrErr; + return true; + } + + bool shouldPrint() const { + bool Undefined = SymFlags & SymbolRef::SF_Undefined; + bool Global = SymFlags & SymbolRef::SF_Global; + bool Weak = SymFlags & SymbolRef::SF_Weak; + bool FormatSpecific = SymFlags & SymbolRef::SF_FormatSpecific; + if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) || + (!Global && ExternalOnly) || (Weak && NoWeakSymbols) || + (FormatSpecific && !(SpecialSyms || DebugSyms))) + return false; + return true; + } }; bool operator<(const NMSymbol &A, const NMSymbol &B) { @@ -241,11 +273,17 @@ if (SizeSort) return std::make_tuple(A.Size, A.Name, A.Address) < std::make_tuple(B.Size, B.Name, B.Address); + if (ExportSymbols) + return std::make_tuple(A.Name, A.Visibility) < + std::make_tuple(B.Name, B.Visibility); return std::make_tuple(A.Name, A.Size, A.Address) < std::make_tuple(B.Name, B.Size, B.Address); } bool operator>(const NMSymbol &A, const NMSymbol &B) { return B < A; } +bool operator==(const NMSymbol &A, const NMSymbol &B) { + return !(A < B) && !(B < A); +} } // anonymous namespace static char isSymbolList64Bit(SymbolicFile &Obj) { @@ -659,6 +697,15 @@ llvm::sort(SymbolList); } +static void printExportSymbolList() { + for (const NMSymbol &Sym : SymbolList) { + outs() << Sym.Name; + if (!Sym.Visibility.empty()) + outs() << ' ' << Sym.Visibility; + outs() << '\n'; + } +} + static void printSymbolList(SymbolicFile &Obj, bool printName, StringRef ArchiveName, StringRef ArchitectureName) { if (!PrintFileName) { @@ -707,25 +754,7 @@ } for (const NMSymbol &S : SymbolList) { - uint32_t SymFlags; - if (S.Sym.getRawDataRefImpl().p) { - Expected SymFlagsOrErr = S.Sym.getFlags(); - if (!SymFlagsOrErr) { - // TODO: Test this error. - error(SymFlagsOrErr.takeError(), Obj.getFileName()); - return; - } - SymFlags = *SymFlagsOrErr; - } else - SymFlags = S.SymFlags; - - bool Undefined = SymFlags & SymbolRef::SF_Undefined; - bool Global = SymFlags & SymbolRef::SF_Global; - bool Weak = SymFlags & SymbolRef::SF_Weak; - bool FormatSpecific = SymFlags & SymbolRef::SF_FormatSpecific; - if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) || - (!Global && ExternalOnly) || (Weak && NoWeakSymbols) || - (FormatSpecific && !(SpecialSyms || DebugSyms))) + if (!S.shouldPrint()) continue; std::string Name = S.Name; @@ -1638,11 +1667,93 @@ : BitMode != BitModeTy::Bit64; } +static void getXCOFFExports(XCOFFObjectFile *XCOFFObj, StringRef ArchiveName) { + // Skip Shared object file. + if (XCOFFObj->getFlags() & XCOFF::F_SHROBJ) + return; + + for (SymbolRef Sym : XCOFFObj->symbols()) { + // There is no visibility in old 32 bit XCOFF object file interpret. + bool HasVisibilityAttr = + XCOFFObj->is64Bit() || (XCOFFObj->auxiliaryHeader32() && + (XCOFFObj->auxiliaryHeader32()->getVersion() == + XCOFF::NEW_XCOFF_INTERPRET)); + + if (HasVisibilityAttr) { + XCOFFSymbolRef XCOFFSym = XCOFFObj->toSymbolRef(Sym.getRawDataRefImpl()); + uint16_t SymType = XCOFFSym.getSymbolType(); + if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_INTERNAL) + continue; + if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_HIDDEN) + continue; + } + + Expected SymSecOrErr = Sym.getSection(); + if (!SymSecOrErr) { + warn(SymSecOrErr.takeError(), XCOFFObj->getFileName(), + "for symbol with index " + + Twine(XCOFFObj->getSymbolIndex(Sym.getRawDataRefImpl().p)), + ArchiveName); + continue; + } + section_iterator SecIter = *SymSecOrErr; + // If the symbol is not in a text or data section, it is not exported. + if (SecIter == XCOFFObj->section_end()) + continue; + if (!(SecIter->isText() || SecIter->isData() || SecIter->isBSS())) + continue; + + StringRef SymName = cantFail(Sym.getName()); + if (SymName.empty()) + continue; + if (SymName.startswith("__sinit") || SymName.startswith("__sterm") || + SymName.front() == '.' || SymName.front() == '(') + continue; + + // Check the SymName regex matching with "^__[0-9]+__". + if (SymName.size() > 4 && SymName.startswith("__") && + SymName.endswith("__")) { + if (std::all_of(SymName.begin() + 2, SymName.end() - 2, isDigit)) + continue; + } + + if (SymName == "__rsrc" && NoRsrc) + continue; + + if (SymName.startswith("__tf1")) + SymName = SymName.substr(6); + else if (SymName.startswith("__tf9")) + SymName = SymName.substr(14); + + NMSymbol S = {}; + S.Name = SymName.str(); + S.Sym = Sym; + + if (HasVisibilityAttr) { + XCOFFSymbolRef XCOFFSym = XCOFFObj->toSymbolRef(Sym.getRawDataRefImpl()); + uint16_t SymType = XCOFFSym.getSymbolType(); + if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_PROTECTED) + S.Visibility = "protected"; + else if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_EXPORTED) + S.Visibility = "export"; + } + if (S.initializeFlags(*XCOFFObj)) + SymbolList.push_back(S); + } +} + static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName, StringRef ArchiveName = {}, StringRef ArchitectureName = {}) { if (!shouldDump(Obj)) return; + + if (ExportSymbols && Obj.isXCOFF()) { + XCOFFObjectFile *XCOFFObj = cast(&Obj); + getXCOFFExports(XCOFFObj, ArchiveName); + return; + } + auto Symbols = Obj.symbols(); std::vector SymbolVersions; if (DynamicSyms) { @@ -1672,6 +1783,7 @@ if (Nsect == 0) return; } + if (!(MachO && DyldInfoOnly)) { size_t I = -1; for (BasicSymbolRef Sym : Symbols) { @@ -1732,7 +1844,8 @@ (SymbolVersions[I].IsVerDef ? "@@" : "@") + SymbolVersions[I].Name; S.Sym = Sym; - SymbolList.push_back(S); + if (S.initializeFlags(Obj)) + SymbolList.push_back(S); } } @@ -1745,6 +1858,9 @@ if (MachO && !NoDyldInfo) dumpSymbolsFromDLInfoMachO(*MachO); + if (ExportSymbols) + return; + CurrentFilename = Obj.getFileName(); if (Symbols.empty() && SymbolList.empty() && !Quiet) { @@ -1846,7 +1962,7 @@ } if (!checkMachOAndArchFlags(O, Filename)) return; - if (!PrintFileName && shouldDump(*O)) { + if (!PrintFileName && shouldDump(*O) && !ExportSymbols) { outs() << "\n"; if (isa(O)) { outs() << Filename << "(" << O->getFileName() << ")"; @@ -2168,6 +2284,12 @@ PrintFileName = Args.hasArg(OPT_print_file_name); PrintSize = Args.hasArg(OPT_print_size); ReverseSort = Args.hasArg(OPT_reverse_sort); + ExportSymbols = Args.hasArg(OPT_export_symbols); + if (ExportSymbols) { + ExternalOnly = true; + DefinedOnly = true; + } + Quiet = Args.hasArg(OPT_quiet); V = Args.getLastArgValue(OPT_radix_EQ, "x"); if (V == "o") @@ -2203,6 +2325,9 @@ DyldInfoOnly = Args.hasArg(OPT_dyldinfo_only); NoDyldInfo = Args.hasArg(OPT_no_dyldinfo); + // XCOFF specific options. + NoRsrc = Args.hasArg(OPT_no_rsrc); + // llvm-nm only reads binary files. if (error(sys::ChangeStdinToBinary())) return 1; @@ -2262,6 +2387,18 @@ llvm::for_each(InputFilenames, dumpSymbolNamesFromFile); + if (ExportSymbols) { + // Delete symbols which should not be printed from SymolList. + SymbolList.erase( + std::remove_if(SymbolList.begin(), SymbolList.end(), + [](const NMSymbol &s) { return !s.shouldPrint(); }), + SymbolList.end()); + sortSymbolList(); + SymbolList.erase(std::unique(SymbolList.begin(), SymbolList.end()), + SymbolList.end()); + printExportSymbolList(); + } + if (HadError) return 1; }