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 @@ -303,7 +303,7 @@ } static StringRef CurrentFilename; -static std::vector SymbolList; +using ObjectMemBuffVecType = std::vector; static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I); @@ -687,7 +687,7 @@ } } -static void sortSymbolList() { +static void sortSymbolList(std::vector &SymbolList) { if (NoSort) return; @@ -697,7 +697,7 @@ llvm::sort(SymbolList); } -static void printExportSymbolList() { +static void printExportSymbolList(const std::vector &SymbolList) { for (const NMSymbol &Sym : SymbolList) { outs() << Sym.Name; if (!Sym.Visibility.empty()) @@ -706,8 +706,10 @@ } } -static void printSymbolList(SymbolicFile &Obj, bool printName, - StringRef ArchiveName, StringRef ArchitectureName) { +static void printSymbolList(SymbolicFile &Obj, + const std::vector &SymbolList, + bool printName, StringRef ArchiveName, + StringRef ArchitectureName) { if (!PrintFileName) { if ((OutputFormat == bsd || OutputFormat == posix || OutputFormat == just_symbols) && @@ -842,8 +844,6 @@ << SymbolSizeStr << "| |" << S.SectionName << "\n"; } } - - SymbolList.clear(); } static char getSymbolNMTypeChar(ELFObjectFileBase &Obj, @@ -1188,7 +1188,8 @@ return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0; } -static void dumpSymbolsFromDLInfoMachO(MachOObjectFile &MachO) { +static void dumpSymbolsFromDLInfoMachO(MachOObjectFile &MachO, + std::vector &SymbolList) { size_t I = SymbolList.size(); std::string ExportsNameBuffer; raw_string_ostream EOS(ExportsNameBuffer); @@ -1667,7 +1668,8 @@ : BitMode != BitModeTy::Bit64; } -static void getXCOFFExports(XCOFFObjectFile *XCOFFObj, StringRef ArchiveName) { +static void getXCOFFExports(XCOFFObjectFile *XCOFFObj, StringRef ArchiveName, + std::vector &SymbolList) { // Skip Shared object file. if (XCOFFObj->getFlags() & XCOFF::F_SHROBJ) return; @@ -1742,7 +1744,8 @@ } } -static void getSymbolNamesFromObject(SymbolicFile &Obj) { +static void getSymbolNamesFromObject(SymbolicFile &Obj, + std::vector &SymbolList) { auto Symbols = Obj.symbols(); std::vector SymbolVersions; if (DynamicSyms) { @@ -1845,7 +1848,7 @@ // language symbols for example. The option -only-dyldinfo will fake up // all symbols from the dyld export trie as well as the bind info. if (MachO && !NoDyldInfo) - dumpSymbolsFromDLInfoMachO(*MachO); + dumpSymbolsFromDLInfoMachO(*MachO, SymbolList); } static void printObjectLabel(bool IsArchiveFile, StringRef ArchiveName, @@ -1863,34 +1866,41 @@ static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool PrintSymbolObject, bool PrintObjectLabel, - StringRef ArchiveName = {}, - StringRef ArchitectureName = {}, - StringRef ObjectName = {}, - bool IsArchiveFile = false) { - if (!shouldDump(Obj)) - return; - - if (ExportSymbols && Obj.isXCOFF()) { - XCOFFObjectFile *XCOFFObj = cast(&Obj); - getXCOFFExports(XCOFFObj, ArchiveName); - return; - } - - if (PrintObjectLabel && !ExportSymbols) - printObjectLabel(IsArchiveFile, ArchiveName, ArchitectureName, + StringRef ArchiveName, + StringRef ArchitectureName, + StringRef ObjectName, + bool isArchiveFile) { + if (PrintObjectLabel) + printObjectLabel(isArchiveFile, ArchiveName, ArchitectureName, ObjectName.empty() ? Obj.getFileName() : ObjectName); - getSymbolNamesFromObject(Obj); - if (ExportSymbols) - return; + std::vector SymbolList; + getSymbolNamesFromObject(Obj, SymbolList); CurrentFilename = Obj.getFileName(); if (Obj.symbols().empty() && SymbolList.empty() && !Quiet) { writeFileName(errs(), ArchiveName, ArchitectureName); errs() << "no symbols\n"; } - sortSymbolList(); - printSymbolList(Obj, PrintSymbolObject, ArchiveName, ArchitectureName); + sortSymbolList(SymbolList); + printSymbolList(Obj, SymbolList, PrintSymbolObject, ArchiveName, + ArchitectureName); +} + +static void dumpOrGetObject(SymbolicFile &Obj, + ObjectMemBuffVecType &ObjMemBuffs, + bool PrintSymbolObject, bool PrintObjectLabel, + StringRef ArchiveName = {}, + StringRef ArchitectureName = {}, + StringRef ObjectName = {}, bool isArchive = false) { + if (!shouldDump(Obj)) + return; + if (ExportSymbols) + ObjMemBuffs.push_back(Obj.getMemoryBufferRef()); + else + dumpSymbolNamesFromObject(Obj, PrintSymbolObject, PrintObjectLabel, + ArchiveName, ArchitectureName, ObjectName, + isArchive); } // checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file @@ -1948,8 +1958,8 @@ } } -static void dumpArchive(Archive *A, std::string &Filename, - LLVMContext *ContextPtr) { +static void dumpArchive(Archive *A, ObjectMemBuffVecType &ObjMemBuffs, + std::string &Filename, LLVMContext *ContextPtr) { if (ArchiveMap) dumpArchiveMap(A, Filename); @@ -1969,19 +1979,19 @@ } if (!checkMachOAndArchFlags(O, Filename)) return; - dumpSymbolNamesFromObject(*O, /*PrintSymbolObject=*/false, - /*PrintObjectLabel=*/!PrintFileName, Filename, - /*ArchitectureName=*/{}, O->getFileName(), - /*IsArchiveFile*/ true); + dumpOrGetObject(*O, ObjMemBuffs, /*PrintSymbolObject=*/false, + /*PrintObjectLabel=*/!PrintFileName, Filename, + /*ArchitectureName=*/{}, O->getFileName(), + /*IsArchiveFile*/ true); } } if (Err) error(std::move(Err), A->getFileName()); } -static void dumpMachOUniversalBinaryMatchArchFlags(MachOUniversalBinary *UB, - std::string &Filename, - LLVMContext *ContextPtr) { +static void dumpMachOUniversalBinaryMatchArchFlags( + MachOUniversalBinary *UB, ObjectMemBuffVecType &ObjMemBuffs, + std::string &Filename, LLVMContext *ContextPtr) { // Look for a slice in the universal binary that matches each ArchFlag. bool ArchFound; for (unsigned i = 0; i < ArchFlags.size(); ++i) { @@ -2000,10 +2010,10 @@ ObjectFile &Obj = *ObjOrErr.get(); if (ArchFlags.size() > 1) ArchitectureName = I->getArchFlagName(); - dumpSymbolNamesFromObject( - Obj, /*PrintSymbolObject=*/false, - /*PrintObjectLabel=*/(ArchFlags.size() > 1) && !PrintFileName, - ArchiveName, ArchitectureName); + dumpOrGetObject(Obj, ObjMemBuffs, /*PrintSymbolObject=*/false, + /*PrintObjectLabel=*/(ArchFlags.size() > 1) && + !PrintFileName, + ArchiveName, ArchitectureName); } else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { error(std::move(E), Filename, @@ -2030,9 +2040,9 @@ ArchiveName = std::string(A->getFileName()); if (ArchFlags.size() > 1) ArchitectureName = I->getArchFlagName(); - dumpSymbolNamesFromObject(*O, /*PrintSymbolObject=*/false, - /*PrintObjectLabel=*/!PrintFileName, - ArchiveName, ArchitectureName); + dumpOrGetObject(*O, ObjMemBuffs, /*PrintSymbolObject=*/false, + /*PrintObjectLabel=*/!PrintFileName, ArchiveName, + ArchitectureName); } } if (Err) @@ -2057,6 +2067,7 @@ // Returns true If the binary contains a slice that matches the host // architecture, or false otherwise. static bool dumpMachOUniversalBinaryMatchHost(MachOUniversalBinary *UB, + ObjectMemBuffVecType &ObjMemBuffs, std::string &Filename, LLVMContext *ContextPtr) { Triple HostTriple = MachOObjectFile::getHostArch(); @@ -2069,8 +2080,8 @@ std::string ArchiveName; if (ObjOrErr) { ObjectFile &Obj = *ObjOrErr.get(); - dumpSymbolNamesFromObject(Obj, /*PrintSymbolObject=*/false, - /*PrintObjectLabel=*/false); + dumpOrGetObject(Obj, ObjMemBuffs, /*PrintSymbolObject=*/false, + /*PrintObjectLabel=*/false); } else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) error(std::move(E), Filename); else if (Expected> AOrErr = I->getAsArchive()) { @@ -2087,9 +2098,8 @@ } if (SymbolicFile *O = dyn_cast(&*ChildOrErr.get())) { ArchiveName = std::string(A->getFileName()); - dumpSymbolNamesFromObject(*O, /*PrintSymbolObject=*/false, - /*PrintObjectLabel=*/!PrintFileName, - ArchiveName); + dumpOrGetObject(*O, ObjMemBuffs, /*PrintSymbolObject=*/false, + /*PrintObjectLabel=*/!PrintFileName, ArchiveName); } } if (Err) @@ -2108,6 +2118,7 @@ } static void dumpMachOUniversalBinaryArchAll(MachOUniversalBinary *UB, + ObjectMemBuffVecType &ObjMemBuffs, std::string &Filename, LLVMContext *ContextPtr) { bool moreThanOneArch = UB->getNumberOfObjects() > 1; @@ -2121,9 +2132,9 @@ ObjectFile &Obj = *ObjOrErr.get(); if (isa(Obj) && moreThanOneArch) ArchitectureName = O.getArchFlagName(); - dumpSymbolNamesFromObject(Obj, /*PrintSymbolObject=*/false, - /*PrintObjectLabel=*/!PrintFileName, - ArchiveName, ArchitectureName); + dumpOrGetObject(Obj, ObjMemBuffs, /*PrintSymbolObject=*/false, + /*PrintObjectLabel=*/!PrintFileName, ArchiveName, + ArchitectureName); } else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { error(std::move(E), Filename, moreThanOneArch ? StringRef(O.getArchFlagName()) : StringRef()); @@ -2144,9 +2155,9 @@ ArchiveName = std::string(A->getFileName()); if (isa(F) && moreThanOneArch) ArchitectureName = O.getArchFlagName(); - dumpSymbolNamesFromObject(*F, /*PrintSymbolObject=*/false, - /*PrintObjectLabel=*/!PrintFileName, - ArchiveName, ArchitectureName); + dumpOrGetObject(*F, ObjMemBuffs, /*PrintSymbolObject=*/false, + /*PrintObjectLabel=*/!PrintFileName, ArchiveName, + ArchitectureName); } } if (Err) @@ -2161,25 +2172,30 @@ } static void dumpMachOUniversalBinary(MachOUniversalBinary *UB, + ObjectMemBuffVecType &ObjMemBuffs, std::string &Filename, LLVMContext *ContextPtr) { // If we have a list of architecture flags specified dump only those. if (!ArchAll && !ArchFlags.empty()) { - dumpMachOUniversalBinaryMatchArchFlags(UB, Filename, ContextPtr); + dumpMachOUniversalBinaryMatchArchFlags(UB, ObjMemBuffs, Filename, + ContextPtr); return; } // No architecture flags were specified so if this contains a slice that // matches the host architecture dump only that. - if (!ArchAll && dumpMachOUniversalBinaryMatchHost(UB, Filename, ContextPtr)) + if (!ArchAll && + dumpMachOUniversalBinaryMatchHost(UB, ObjMemBuffs, Filename, ContextPtr)) return; // Either all architectures have been specified or none have been specified // and this does not contain the host architecture so dump all the slices. - dumpMachOUniversalBinaryArchAll(UB, Filename, ContextPtr); + dumpMachOUniversalBinaryArchAll(UB, ObjMemBuffs, Filename, ContextPtr); } -static void dumpTapiUniversal(TapiUniversal *TU, std::string &Filename) { +static void dumpTapiUniversal(TapiUniversal *TU, + ObjectMemBuffVecType &ObjMemBuffs, + std::string &Filename) { for (const TapiUniversal::ObjectForArch &I : TU->objects()) { StringRef ArchName = I.getArchFlagName(); const bool ShowArch = @@ -2189,17 +2205,17 @@ if (!AddInlinedInfo && !I.isTopLevelLib()) continue; if (auto ObjOrErr = I.getAsObjectFile()) - dumpSymbolNamesFromObject(*ObjOrErr.get(), /*PrintSymbolObject=*/false, - /*PrintObjectLabel=*/true, - /*ArchiveName=*/{}, ArchName, - I.getInstallName()); + dumpOrGetObject(*ObjOrErr.get(), ObjMemBuffs, /*PrintSymbolObject=*/false, + /*PrintObjectLabel=*/true, + /*ArchiveName=*/{}, ArchName, I.getInstallName()); else if (Error E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { error(std::move(E), Filename, ArchName); } } } -static void dumpSymbolicFile(SymbolicFile *O, std::string &Filename) { +static void dumpSymbolicFile(SymbolicFile *O, ObjectMemBuffVecType &ObjMemBuffs, + std::string &Filename) { if (!MachOPrintSizeWarning && PrintSize && isa(O)) { WithColor::warning(errs(), ToolName) << "sizes with --print-size for Mach-O files are always zero.\n"; @@ -2207,15 +2223,27 @@ } if (!checkMachOAndArchFlags(O, Filename)) return; - dumpSymbolNamesFromObject(*O, /*PrintSymbolObject=*/true, - /*PrintObjectLabel=*/false); + dumpOrGetObject(*O, ObjMemBuffs, + /*PrintSymbolObject=*/true, + /*PrintObjectLabel=*/false); +} + +static void exportSymbolNamesFromObject(SymbolicFile &Obj, + StringRef ArchiveName, + std::vector &SymbolList) { + if (ExportSymbols && Obj.isXCOFF()) { + XCOFFObjectFile *XCOFFObj = cast(&Obj); + return getXCOFFExports(XCOFFObj, ArchiveName, SymbolList); + } + return getSymbolNamesFromObject(Obj, SymbolList); } -static void dumpSymbolNamesFromFile(std::string &Filename) { +static std::vector dumpSymbolNamesFromFile(std::string &Filename) { + std::vector FileSymbolList; ErrorOr> BufferOrErr = MemoryBuffer::getFileOrSTDIN(Filename); if (error(BufferOrErr.getError(), Filename)) - return; + return FileSymbolList; LLVMContext Context; LLVMContext *ContextPtr = NoLLVMBitcode ? nullptr : &Context; @@ -2223,17 +2251,51 @@ createBinary(BufferOrErr.get()->getMemBufferRef(), ContextPtr); if (!BinaryOrErr) { error(BinaryOrErr.takeError(), Filename); - return; + return FileSymbolList; } + ObjectMemBuffVecType ObjMemBuffs; Binary &Bin = *BinaryOrErr.get(); if (Archive *A = dyn_cast(&Bin)) - dumpArchive(A, Filename, ContextPtr); + dumpArchive(A, ObjMemBuffs, Filename, ContextPtr); else if (MachOUniversalBinary *UB = dyn_cast(&Bin)) - dumpMachOUniversalBinary(UB, Filename, ContextPtr); + dumpMachOUniversalBinary(UB, ObjMemBuffs, Filename, ContextPtr); else if (TapiUniversal *TU = dyn_cast(&Bin)) - dumpTapiUniversal(TU, Filename); + dumpTapiUniversal(TU, ObjMemBuffs, Filename); else if (SymbolicFile *O = dyn_cast(&Bin)) - dumpSymbolicFile(O, Filename); + dumpSymbolicFile(O, ObjMemBuffs, Filename); + + if (ExportSymbols) + for (const auto &ObjMemBuff : ObjMemBuffs) { + std::unique_ptr ObjBin = + cantFail(createBinary(ObjMemBuff, ContextPtr)); + assert(dyn_cast(ObjBin.get()) && + "Can not be converted to SymbolicFile."); + exportSymbolNamesFromObject(*dyn_cast(ObjBin.get()), + dyn_cast(&Bin) ? StringRef() + : Filename, + FileSymbolList); + } + return FileSymbolList; +} + +static void +exportSymbolNamesFromFiles(const std::vector &InputFilenames) { + std::vector SymbolList; + for (auto &FileName : InputFilenames) { + const std::vector &FileSymList = + dumpSymbolNamesFromFile(const_cast(FileName)); + SymbolList.insert(SymbolList.end(), FileSymList.begin(), FileSymList.end()); + } + + // 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); + SymbolList.erase(std::unique(SymbolList.begin(), SymbolList.end()), + SymbolList.end()); + printExportSymbolList(SymbolList); } int main(int argc, char **argv) { @@ -2391,19 +2453,10 @@ if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly)) error("--no-dyldinfo can't be used with --add-dyldinfo or --dyldinfo-only"); - 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 (ExportSymbols) + exportSymbolNamesFromFiles(InputFilenames); + else + llvm::for_each(InputFilenames, dumpSymbolNamesFromFile); if (HadError) return 1;