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 @@ -226,6 +226,11 @@ Print only undefined symbols. +.. option:: --export-symbols + + Export sorted and unique symbol list for object files or archives. Sort and + unique symbol are based on the symbol name and visibility(if there is). + .. option:: --version, -V Display the version of the :program:`llvm-nm` executable, then exit. Does not @@ -267,6 +272,13 @@ Print symbol entry in hex. +XCOFF SPECIFIC OPTIONS +---------------------- + +.. option:: --no-rsrc + + Exclude the rsrc symbol from export symbol list for XCOFF object file. + 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 }; +static 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/BinaryFormat/Magic.cpp b/llvm/lib/BinaryFormat/Magic.cpp --- a/llvm/lib/BinaryFormat/Magic.cpp +++ b/llvm/lib/BinaryFormat/Magic.cpp @@ -88,6 +88,10 @@ if (startswith(Magic, "!\n") || startswith(Magic, "!\n")) return file_magic::archive; break; + case '<': + if (startswith(Magic, "\n")) + return file_magic::archive; + break; case '\177': if (startswith(Magic, "\177ELF") && Magic.size() >= 18) { bool Data2MSB = Magic[5] == 2; 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/Inputs/big_ar_lib.a b/llvm/test/tools/llvm-nm/XCOFF/Inputs/big_ar_lib.a new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@&1 | FileCheck %s + +# CHECK: llvm-nm{{(\.exe)?}}: warning: {{.*}}big_ar_lib.a(export_invalid.o): for symbol with index 26: csect symbol "invalid_var" with index 26 contains no auxiliary entry +# CHECK-NEXT: __rsrc +# CHECK-NEXT: export_var export +# CHECK-NEXT: protected_var protected +# CHECK-NEXT: tf1value +# CHECK-NEXT: tf9value +# CHECK-NEXT: weak_func diff --git a/llvm/test/tools/llvm-nm/XCOFF/export_sym_list_obj.test b/llvm/test/tools/llvm-nm/XCOFF/export_sym_list_obj.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-nm/XCOFF/export_sym_list_obj.test @@ -0,0 +1,173 @@ +## Test the option "--export-symbols" of llvm-nm. +## The option merge all the output of input files,sort and print out unique symbols from xcoff object file. + +# RUN: yaml2obj -DFLAG=0x0002 %s -o %t.o + +## Test the following cases: +## Do not export global symbols begin with "__sinit" , "__sterm" , "." , "(". +## Do not export global symbols begin with regular expression "^__[0-9]+__". +## Do not export hidden symbols and internal symbols. +## Export substring of the global symbol name beginning with "__tf1" and "__tf9". +# RUN: llvm-nm --export-symbols %t.o | FileCheck %s --implicit-check-not={{.}} + +## Show that only unique symbols(with the same name and visibility) are exported. +# RUN: llvm-nm --export-symbols %t.o %t.o | FileCheck %s --implicit-check-not={{.}} + +# CHECK: __rsrc +# CHECK-NEXT: export_protested_var export +# CHECK-NEXT: export_protested_var protected +# CHECK-NEXT: protected_var protected +# CHECK-NEXT: tf1value +# CHECK-NEXT: tf9value +# CHECK-NEXT: weak_func + +## Show that __rsrc symbols are not exported when using the "--no-rsrc" option. +# RUN: llvm-nm --export-symbols --no-rsrc %t.o | FileCheck --check-prefixes=NO_RSRC %s --implicit-check-not={{.}} +# NO_RSRC: export_protested_var export +# NO_RSRC: export_protested_var protected +# NO_RSRC-NEXT: protected_var protected +# NO_RSRC-NEXT: tf1value +# NO_RSRC-NEXT: tf9value +# NO_RSRC-NEXT: weak_func + +## Show that weak symbols are not exported when using the "--no-weak" option. +# RUN: llvm-nm --export-symbols --no-weak %t.o | FileCheck --check-prefixes=NO-WEAK %s --implicit-check-not={{.}} +# NO-WEAK: __rsrc +# NO-WEAK-NEXT: export_protested_var export +# NO-WEAK-NEXT: export_protested_var protected +# NO-WEAK-NEXT: protected_var protected +# NO-WEAK-NEXT: tf1value +# NO-WEAK-NEXT: tf9value + +--- !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_protested_var + Section: .data + Type: 0x4000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: export_protested_var + Section: .data + Type: 0x3000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: __rsrc + Section: .data + 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: .data + Type: 0x00 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: __tf9_12345678tf9value + 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: .data + Type: 0x3000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x02 + StorageMappingClass: XMC_RW + - Name: hidden_var + Section: .data + Type: 0x2000 + StorageClass: C_HIDEXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: internal_var + Section: .data + Type: 0x1000 + StorageClass: C_HIDEXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW diff --git a/llvm/test/tools/llvm-nm/XCOFF/not_export_shared_obj.test b/llvm/test/tools/llvm-nm/XCOFF/not_export_shared_obj.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-nm/XCOFF/not_export_shared_obj.test @@ -0,0 +1,27 @@ +## Show that symbols in shared object files are not exported. +## Generate XCOFF shared object file. +# RUN: yaml2obj -DFLAG=0x2000 %s -o %t_shared.o + +# RUN: llvm-nm --export-symbols %t_shared.o | FileCheck %s --implicit-check-not={{.*}}} --allow-empty + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF + Flags: [[FLAG]] +AuxiliaryHeader: + Magic: 0x10B + Version: 0x2 + TextSectionSize: 0x280 + DataSectionSize: 0x90 +Sections: + - Name: .data + Flags: [ STYP_DATA ] +Symbols: + - Name: export_var + Section: .data + Type: 0x4000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW 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 @@ -33,6 +33,7 @@ def size_sort : FF<"size-sort", "Sort symbols by size">; def special_syms : FF<"special-syms", "Do not filter special symbols from the output">; def undefined_only : FF<"undefined-only", "Show only undefined symbols">; +def export_symbols : FF<"export-symbols", "Export symbol list for object files or archives.">; def version : FF<"version", "Display the version">; def without_aliases : FF<"without-aliases", "Exclude aliases from output">, Flags<[HelpHidden]>; @@ -48,6 +49,12 @@ 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 the rsrc symbol from export symbol list" + "for xcoff (requires --export-symbols)">, 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" @@ -41,6 +42,7 @@ #include "llvm/Support/InitLLVM.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Program.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/WithColor.h" @@ -104,6 +106,9 @@ static bool SizeSort; static bool UndefinedOnly; static bool WithoutAliases; +static bool ExportSymbols; +// XCOFF-specific options. +static bool NoRsrc; namespace { enum Radix { d, o, x }; @@ -128,7 +133,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 @@ -137,8 +143,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"; }); } @@ -211,6 +218,7 @@ 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 @@ -256,6 +264,11 @@ std::make_tuple(B.Name, B.Size, B.Address); } +static bool compareSymbolNameVisibility(const NMSymbol &A, const NMSymbol &B) { + return std::make_tuple(A.Name, A.Visibility) < + std::make_tuple(B.Name, B.Visibility); +} + static char isSymbolList64Bit(SymbolicFile &Obj) { if (auto *IRObj = dyn_cast(&Obj)) return Triple(IRObj->getTargetTriple()).isArch64Bit(); @@ -263,7 +276,6 @@ return false; if (XCOFFObjectFile *XCOFFObj = dyn_cast(&Obj)) return XCOFFObj->is64Bit(); - if (isa(Obj)) return false; if (TapiFile *Tapi = dyn_cast(&Obj)) @@ -646,27 +658,59 @@ } } -static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, - StringRef ArchiveName, - StringRef ArchitectureName) { - if (!NoSort) { - using Comparator = bool (*)(const NMSymbol &, const NMSymbol &); - Comparator Cmp; - if (NumericSort) - Cmp = &compareSymbolAddress; - else if (SizeSort) - Cmp = &compareSymbolSize; - else - Cmp = &compareSymbolName; +using Comparator = bool (*)(const NMSymbol &, const NMSymbol &); - if (ReverseSort) - llvm::sort(SymbolList, [=](const NMSymbol &A, const NMSymbol &B) -> bool { - return Cmp(B, A); - }); +static Comparator getSymbolComparator() { + if (NumericSort) + return &compareSymbolAddress; + else if (SizeSort) + return &compareSymbolSize; + else if (ExportSymbols) + return &compareSymbolNameVisibility; + else + return &compareSymbolName; +} + +// The function only work for a sorted SymbolList. +static void removeDuplicateSortedSymbolList() { + if (SymbolList.size() == 0) + return; + + Comparator lessThan = getSymbolComparator(); + std::vector::const_iterator Iter = SymbolList.begin(); + std::vector::const_iterator PreIter = Iter; + + while (++Iter < SymbolList.end()) { + if (!lessThan(*PreIter, *Iter) && !lessThan(*Iter, *PreIter)) { + SymbolList.erase(Iter); + Iter = PreIter; + } else + PreIter = Iter; + } +} + +static void sortSymbolList() { + if (ReverseSort) + llvm::sort(SymbolList, [=](const NMSymbol &A, const NMSymbol &B) -> bool { + return getSymbolComparator()(B, A); + }); + else + llvm::sort(SymbolList, getSymbolComparator()); +} + +static void printMergedSymbolList() { + for (const auto &Sym : SymbolList) { + outs() << Sym.Name; + if (!Sym.Visibility.empty()) + outs() << " " << Sym.Visibility << "\n"; else - llvm::sort(SymbolList, Cmp); + outs() << "\n"; } + SymbolList.clear(); +} +static void printSymbolList(SymbolicFile &Obj, bool printName, + StringRef ArchiveName, StringRef ArchitectureName) { if (!PrintFileName) { if ((OutputFormat == bsd || OutputFormat == posix || OutputFormat == just_symbols) && @@ -1625,6 +1669,103 @@ } } +static void exportSymbolsForXCOFF(XCOFFObjectFile *Obj, StringRef ArchiveName) { + + // Skip Shared object file. + if (Obj->getFlags() & XCOFF::F_SHROBJ) + return; + + for (const SymbolRef &Sym : Obj->symbols()) { + Expected NameOrErr = Sym.getName(); + + if (!NameOrErr) { + warn(NameOrErr.takeError(), Obj->getFileName(), + "for symbol with index " + + Twine(Obj->getSymbolIndex(Sym.getRawDataRefImpl().p)), + ArchiveName); + return; + } + + Expected SymFlagsOrErr = Sym.getFlags(); + if (!SymFlagsOrErr) { + warn(SymFlagsOrErr.takeError(), Obj->getFileName(), + "for symbol with index " + + Twine(Obj->getSymbolIndex(Sym.getRawDataRefImpl().p)), + ArchiveName); + return; + } + + uint32_t Flags = *SymFlagsOrErr; + StringRef SymName = *NameOrErr; + + if (!(Flags & SymbolRef::SF_Global)) + continue; + if ((Flags & SymbolRef::SF_Weak) && NoWeakSymbols) + continue; + if (Flags & SymbolRef::SF_Hidden) + continue; + + XCOFFObjectFile *XCOFFObj = dyn_cast(Obj); + assert(XCOFFObj && "Not a XCOFFObjectFile in exportSymbolsForXCOFF()."); + // 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; + } + + Expected SymSecOrErr = Sym.getSection(); + if (!SymSecOrErr) { + warn(SymSecOrErr.takeError(), Obj->getFileName(), + "for symbol with index " + + Twine(Obj->getSymbolIndex(Sym.getRawDataRefImpl().p)), + ArchiveName); + continue; + } + + section_iterator SecIter = *SymSecOrErr; + + // if the symbol is not in text or data section, not be exported. + if (SecIter == Obj->section_end()) + continue; + if (!(SecIter->isText() || SecIter->isData() || SecIter->isBSS())) + continue; + + Regex r("^__[0-9]+__"); + if (SymName.startswith("__sinit") || SymName.startswith("__sterm") || + SymName.front() == '.' || SymName.front() == '(' || r.match(SymName)) + continue; + + if (SymName.startswith("__tf1")) { + SymName = SymName.substr(6); + } else if (SymName.startswith("__tf9")) { + SymName = SymName.substr(14); + } + + if (SymName == "__rsrc" && NoRsrc) + continue; + + NMSymbol S = {}; + S.Name = SymName.str(); + + 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"; + if ((SymType & XCOFF::VISIBILITY_MASK) == XCOFF::SYM_V_EXPORTED) + S.Visibility = "export"; + } + SymbolList.push_back(S); + } +} + static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName, StringRef ArchiveName = {}, StringRef ArchitectureName = {}) { @@ -1658,6 +1799,14 @@ return; } if (!(MachO && DyldInfoOnly)) { + + if (ExportSymbols && Obj.isXCOFF()) { + XCOFFObjectFile *XCOFFObj = dyn_cast(&Obj); + assert(XCOFFObj && "Not a XCOFF Object file."); + exportSymbolsForXCOFF(XCOFFObj, ArchiveName); + return; + } + size_t I = -1; for (BasicSymbolRef Sym : Symbols) { ++I; @@ -1732,7 +1881,10 @@ errs() << "no symbols\n"; } - sortAndPrintSymbolList(Obj, printName, ArchiveName, ArchitectureName); + if (!NoSort) + sortSymbolList(); + + printSymbolList(Obj, printName, ArchiveName, ArchitectureName); } // checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file @@ -2147,6 +2299,7 @@ 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); Quiet = Args.hasArg(OPT_quiet); V = Args.getLastArgValue(OPT_radix_EQ, "x"); if (V == "o") @@ -2170,6 +2323,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; @@ -2229,6 +2385,12 @@ llvm::for_each(InputFilenames, dumpSymbolNamesFromFile); + if (ExportSymbols) { + sortSymbolList(); + removeDuplicateSortedSymbolList(); + printMergedSymbolList(); + } + if (HadError) return 1; }