123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256 |
- //===-- llvm-nm.cpp - Symbol table dumping utility for llvm ---------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This program is a utility that works like traditional Unix "nm", that is, it
- // prints out the names of symbols in a bitcode or object file, along with some
- // information about each symbol.
- //
- // This "nm" supports many of the features of GNU "nm", including its different
- // output formats.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ADT/StringSwitch.h"
- #include "llvm/BinaryFormat/COFF.h"
- #include "llvm/Demangle/Demangle.h"
- #include "llvm/IR/Function.h"
- #include "llvm/IR/LLVMContext.h"
- #include "llvm/Object/Archive.h"
- #include "llvm/Object/COFF.h"
- #include "llvm/Object/COFFImportFile.h"
- #include "llvm/Object/ELFObjectFile.h"
- #include "llvm/Object/IRObjectFile.h"
- #include "llvm/Object/MachO.h"
- #include "llvm/Object/MachOUniversal.h"
- #include "llvm/Object/ObjectFile.h"
- #include "llvm/Object/TapiFile.h"
- #include "llvm/Object/TapiUniversal.h"
- #include "llvm/Object/Wasm.h"
- #include "llvm/Object/XCOFFObjectFile.h"
- #include "llvm/Option/Arg.h"
- #include "llvm/Option/ArgList.h"
- #include "llvm/Option/Option.h"
- #include "llvm/Support/CommandLine.h"
- #include "llvm/Support/FileSystem.h"
- #include "llvm/Support/Format.h"
- #include "llvm/Support/InitLLVM.h"
- #include "llvm/Support/MemoryBuffer.h"
- #include "llvm/Support/Program.h"
- #include "llvm/Support/Signals.h"
- #include "llvm/Support/TargetSelect.h"
- #include "llvm/Support/WithColor.h"
- #include "llvm/Support/raw_ostream.h"
- #include <vector>
- using namespace llvm;
- using namespace object;
- namespace {
- using namespace llvm::opt; // for HelpHidden in Opts.inc
- enum ID {
- OPT_INVALID = 0, // This is not an option ID.
- #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OPT_##ID,
- #include "Opts.inc"
- #undef OPTION
- };
- #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
- #include "Opts.inc"
- #undef PREFIX
- const opt::OptTable::Info InfoTable[] = {
- #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- { \
- PREFIX, NAME, HELPTEXT, \
- METAVAR, OPT_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, \
- OPT_##ALIAS, ALIASARGS, VALUES},
- #include "Opts.inc"
- #undef OPTION
- };
- class NmOptTable : public opt::OptTable {
- public:
- NmOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
- };
- enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };
- } // namespace
- static bool ArchiveMap;
- static bool DebugSyms;
- static bool DefinedOnly;
- static bool Demangle;
- static bool DynamicSyms;
- static bool ExternalOnly;
- static OutputFormatTy OutputFormat;
- static bool NoLLVMBitcode;
- static bool NoSort;
- static bool NoWeakSymbols;
- static bool NumericSort;
- static bool PrintFileName;
- static bool PrintSize;
- static bool Quiet;
- static bool ReverseSort;
- static bool SpecialSyms;
- static bool SizeSort;
- static bool UndefinedOnly;
- static bool WithoutAliases;
- namespace {
- enum Radix { d, o, x };
- } // namespace
- static Radix AddressRadix;
- // Mach-O specific options.
- static bool ArchAll = false;
- static std::vector<StringRef> ArchFlags;
- static bool AddDyldInfo;
- static bool AddInlinedInfo;
- static bool DyldInfoOnly;
- static bool FormatMachOasHex;
- static bool NoDyldInfo;
- static std::vector<StringRef> SegSect;
- static bool MachOPrintSizeWarning = false;
- // Miscellaneous states.
- static bool PrintAddress = true;
- static bool MultipleFiles = false;
- static bool HadError = false;
- static StringRef ToolName;
- static void warn(Error Err, Twine FileName, Twine Context = Twine()) {
- assert(Err);
- // Flush the standard output so that the warning isn't interleaved with other
- // output if stdout and stderr are writing to the same place.
- outs().flush();
- handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
- WithColor::warning(errs(), ToolName)
- << FileName << ": " << (Context.str().empty() ? "" : Context + ": ")
- << EI.message() << "\n";
- });
- }
- static void error(Twine Message, Twine Path = Twine()) {
- HadError = true;
- WithColor::error(errs(), ToolName) << Path << ": " << Message << "\n";
- }
- static bool error(std::error_code EC, Twine Path = Twine()) {
- if (EC) {
- error(EC.message(), Path);
- return true;
- }
- return false;
- }
- // This version of error() prints the archive name and member name, for example:
- // "libx.a(foo.o)" after the ToolName before the error message. It sets
- // HadError but returns allowing the code to move on to other archive members.
- static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
- StringRef ArchitectureName = StringRef()) {
- HadError = true;
- WithColor::error(errs(), ToolName) << FileName;
- Expected<StringRef> NameOrErr = C.getName();
- // TODO: if we have a error getting the name then it would be nice to print
- // the index of which archive member this is and or its offset in the
- // archive instead of "???" as the name.
- if (!NameOrErr) {
- consumeError(NameOrErr.takeError());
- errs() << "(" << "???" << ")";
- } else
- errs() << "(" << NameOrErr.get() << ")";
- if (!ArchitectureName.empty())
- errs() << " (for architecture " << ArchitectureName << ")";
- std::string Buf;
- raw_string_ostream OS(Buf);
- logAllUnhandledErrors(std::move(E), OS);
- OS.flush();
- errs() << ": " << Buf << "\n";
- }
- // This version of error() prints the file name and which architecture slice it
- // is from, for example: "foo.o (for architecture i386)" after the ToolName
- // before the error message. It sets HadError but returns allowing the code to
- // move on to other architecture slices.
- static void error(llvm::Error E, StringRef FileName,
- StringRef ArchitectureName = StringRef()) {
- HadError = true;
- WithColor::error(errs(), ToolName) << FileName;
- if (!ArchitectureName.empty())
- errs() << " (for architecture " << ArchitectureName << ")";
- std::string Buf;
- raw_string_ostream OS(Buf);
- logAllUnhandledErrors(std::move(E), OS);
- OS.flush();
- errs() << ": " << Buf << "\n";
- }
- namespace {
- struct NMSymbol {
- uint64_t Address;
- uint64_t Size;
- char TypeChar;
- std::string Name;
- StringRef SectionName;
- StringRef TypeName;
- BasicSymbolRef Sym;
- // 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
- // below are filled in to represent what would have been a Mach-O nlist
- // native symbol.
- uint32_t SymFlags;
- SectionRef Section;
- uint8_t NType;
- uint8_t NSect;
- uint16_t NDesc;
- std::string IndirectName;
- };
- } // anonymous namespace
- static bool compareSymbolAddress(const NMSymbol &A, const NMSymbol &B) {
- bool ADefined;
- // Symbol flags have been checked in the caller.
- if (A.Sym.getRawDataRefImpl().p) {
- uint32_t AFlags = cantFail(A.Sym.getFlags());
- ADefined = !(AFlags & SymbolRef::SF_Undefined);
- } else {
- ADefined = A.TypeChar != 'U';
- }
- bool BDefined;
- // Symbol flags have been checked in the caller.
- if (B.Sym.getRawDataRefImpl().p) {
- uint32_t BFlags = cantFail(B.Sym.getFlags());
- BDefined = !(BFlags & SymbolRef::SF_Undefined);
- } else {
- BDefined = B.TypeChar != 'U';
- }
- return std::make_tuple(ADefined, A.Address, A.Name, A.Size) <
- std::make_tuple(BDefined, B.Address, B.Name, B.Size);
- }
- static bool compareSymbolSize(const NMSymbol &A, const NMSymbol &B) {
- return std::make_tuple(A.Size, A.Name, A.Address) <
- std::make_tuple(B.Size, B.Name, B.Address);
- }
- static bool compareSymbolName(const NMSymbol &A, const NMSymbol &B) {
- return std::make_tuple(A.Name, A.Size, A.Address) <
- std::make_tuple(B.Name, B.Size, B.Address);
- }
- static char isSymbolList64Bit(SymbolicFile &Obj) {
- if (auto *IRObj = dyn_cast<IRObjectFile>(&Obj))
- return Triple(IRObj->getTargetTriple()).isArch64Bit();
- if (isa<COFFObjectFile>(Obj) || isa<COFFImportFile>(Obj))
- return false;
- if (XCOFFObjectFile *XCOFFObj = dyn_cast<XCOFFObjectFile>(&Obj))
- return XCOFFObj->is64Bit();
- if (isa<WasmObjectFile>(Obj))
- return false;
- if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj))
- return Tapi->is64Bit();
- if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
- return MachO->is64Bit();
- return cast<ELFObjectFileBase>(Obj).getBytesInAddress() == 8;
- }
- static StringRef CurrentFilename;
- static std::vector<NMSymbol> SymbolList;
- static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I);
- // darwinPrintSymbol() is used to print a symbol from a Mach-O file when the
- // the OutputFormat is darwin or we are printing Mach-O symbols in hex. For
- // the darwin format it produces the same output as darwin's nm(1) -m output
- // and when printing Mach-O symbols in hex it produces the same output as
- // darwin's nm(1) -x format.
- static void darwinPrintSymbol(SymbolicFile &Obj, const NMSymbol &S,
- char *SymbolAddrStr, const char *printBlanks,
- const char *printDashes,
- const char *printFormat) {
- MachO::mach_header H;
- MachO::mach_header_64 H_64;
- uint32_t Filetype = MachO::MH_OBJECT;
- uint32_t Flags = 0;
- uint8_t NType = 0;
- uint8_t NSect = 0;
- uint16_t NDesc = 0;
- uint32_t NStrx = 0;
- uint64_t NValue = 0;
- MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
- if (Obj.isIR()) {
- uint32_t SymFlags = cantFail(S.Sym.getFlags());
- if (SymFlags & SymbolRef::SF_Global)
- NType |= MachO::N_EXT;
- if (SymFlags & SymbolRef::SF_Hidden)
- NType |= MachO::N_PEXT;
- if (SymFlags & SymbolRef::SF_Undefined)
- NType |= MachO::N_EXT | MachO::N_UNDF;
- else {
- // Here we have a symbol definition. So to fake out a section name we
- // use 1, 2 and 3 for section numbers. See below where they are used to
- // print out fake section names.
- NType |= MachO::N_SECT;
- if (SymFlags & SymbolRef::SF_Const)
- NSect = 3;
- else if (SymFlags & SymbolRef::SF_Executable)
- NSect = 1;
- else
- NSect = 2;
- }
- if (SymFlags & SymbolRef::SF_Weak)
- NDesc |= MachO::N_WEAK_DEF;
- } else {
- DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
- if (MachO->is64Bit()) {
- H_64 = MachO->MachOObjectFile::getHeader64();
- Filetype = H_64.filetype;
- Flags = H_64.flags;
- if (SymDRI.p){
- MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI);
- NType = STE_64.n_type;
- NSect = STE_64.n_sect;
- NDesc = STE_64.n_desc;
- NStrx = STE_64.n_strx;
- NValue = STE_64.n_value;
- } else {
- NType = S.NType;
- NSect = S.NSect;
- NDesc = S.NDesc;
- NStrx = 0;
- NValue = S.Address;
- }
- } else {
- H = MachO->MachOObjectFile::getHeader();
- Filetype = H.filetype;
- Flags = H.flags;
- if (SymDRI.p){
- MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI);
- NType = STE.n_type;
- NSect = STE.n_sect;
- NDesc = STE.n_desc;
- NStrx = STE.n_strx;
- NValue = STE.n_value;
- } else {
- NType = S.NType;
- NSect = S.NSect;
- NDesc = S.NDesc;
- NStrx = 0;
- NValue = S.Address;
- }
- }
- }
- // If we are printing Mach-O symbols in hex do that and return.
- if (FormatMachOasHex) {
- outs() << format(printFormat, NValue) << ' '
- << format("%02x %02x %04x %08x", NType, NSect, NDesc, NStrx) << ' '
- << S.Name;
- if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
- outs() << " (indirect for ";
- outs() << format(printFormat, NValue) << ' ';
- StringRef IndirectName;
- if (S.Sym.getRawDataRefImpl().p) {
- if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
- outs() << "?)";
- else
- outs() << IndirectName << ")";
- } else
- outs() << S.IndirectName << ")";
- }
- outs() << "\n";
- return;
- }
- if (PrintAddress) {
- if ((NType & MachO::N_TYPE) == MachO::N_INDR)
- strcpy(SymbolAddrStr, printBlanks);
- if (Obj.isIR() && (NType & MachO::N_TYPE) == MachO::N_TYPE)
- strcpy(SymbolAddrStr, printDashes);
- outs() << SymbolAddrStr << ' ';
- }
- switch (NType & MachO::N_TYPE) {
- case MachO::N_UNDF:
- if (NValue != 0) {
- outs() << "(common) ";
- if (MachO::GET_COMM_ALIGN(NDesc) != 0)
- outs() << "(alignment 2^" << (int)MachO::GET_COMM_ALIGN(NDesc) << ") ";
- } else {
- if ((NType & MachO::N_TYPE) == MachO::N_PBUD)
- outs() << "(prebound ";
- else
- outs() << "(";
- if ((NDesc & MachO::REFERENCE_TYPE) ==
- MachO::REFERENCE_FLAG_UNDEFINED_LAZY)
- outs() << "undefined [lazy bound]) ";
- else if ((NDesc & MachO::REFERENCE_TYPE) ==
- MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY)
- outs() << "undefined [private lazy bound]) ";
- else if ((NDesc & MachO::REFERENCE_TYPE) ==
- MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY)
- outs() << "undefined [private]) ";
- else
- outs() << "undefined) ";
- }
- break;
- case MachO::N_ABS:
- outs() << "(absolute) ";
- break;
- case MachO::N_INDR:
- outs() << "(indirect) ";
- break;
- case MachO::N_SECT: {
- if (Obj.isIR()) {
- // For llvm bitcode files print out a fake section name using the values
- // use 1, 2 and 3 for section numbers as set above.
- if (NSect == 1)
- outs() << "(LTO,CODE) ";
- else if (NSect == 2)
- outs() << "(LTO,DATA) ";
- else if (NSect == 3)
- outs() << "(LTO,RODATA) ";
- else
- outs() << "(?,?) ";
- break;
- }
- section_iterator Sec = SectionRef();
- if (S.Sym.getRawDataRefImpl().p) {
- Expected<section_iterator> SecOrErr =
- MachO->getSymbolSection(S.Sym.getRawDataRefImpl());
- if (!SecOrErr) {
- consumeError(SecOrErr.takeError());
- outs() << "(?,?) ";
- break;
- }
- Sec = *SecOrErr;
- if (Sec == MachO->section_end()) {
- outs() << "(?,?) ";
- break;
- }
- } else {
- Sec = S.Section;
- }
- DataRefImpl Ref = Sec->getRawDataRefImpl();
- StringRef SectionName;
- if (Expected<StringRef> NameOrErr = MachO->getSectionName(Ref))
- SectionName = *NameOrErr;
- StringRef SegmentName = MachO->getSectionFinalSegmentName(Ref);
- outs() << "(" << SegmentName << "," << SectionName << ") ";
- break;
- }
- default:
- outs() << "(?) ";
- break;
- }
- if (NType & MachO::N_EXT) {
- if (NDesc & MachO::REFERENCED_DYNAMICALLY)
- outs() << "[referenced dynamically] ";
- if (NType & MachO::N_PEXT) {
- if ((NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF)
- outs() << "weak private external ";
- else
- outs() << "private external ";
- } else {
- if ((NDesc & MachO::N_WEAK_REF) == MachO::N_WEAK_REF ||
- (NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF) {
- if ((NDesc & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) ==
- (MachO::N_WEAK_REF | MachO::N_WEAK_DEF))
- outs() << "weak external automatically hidden ";
- else
- outs() << "weak external ";
- } else
- outs() << "external ";
- }
- } else {
- if (NType & MachO::N_PEXT)
- outs() << "non-external (was a private external) ";
- else
- outs() << "non-external ";
- }
- if (Filetype == MachO::MH_OBJECT) {
- if (NDesc & MachO::N_NO_DEAD_STRIP)
- outs() << "[no dead strip] ";
- if ((NType & MachO::N_TYPE) != MachO::N_UNDF &&
- NDesc & MachO::N_SYMBOL_RESOLVER)
- outs() << "[symbol resolver] ";
- if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_ALT_ENTRY)
- outs() << "[alt entry] ";
- if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_COLD_FUNC)
- outs() << "[cold func] ";
- }
- if ((NDesc & MachO::N_ARM_THUMB_DEF) == MachO::N_ARM_THUMB_DEF)
- outs() << "[Thumb] ";
- if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
- outs() << S.Name << " (for ";
- StringRef IndirectName;
- if (MachO) {
- if (S.Sym.getRawDataRefImpl().p) {
- if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
- outs() << "?)";
- else
- outs() << IndirectName << ")";
- } else
- outs() << S.IndirectName << ")";
- } else
- outs() << "?)";
- } else
- outs() << S.Name;
- if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL &&
- (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) ||
- (NType & MachO::N_TYPE) == MachO::N_PBUD)) {
- uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc);
- if (LibraryOrdinal != 0) {
- if (LibraryOrdinal == MachO::EXECUTABLE_ORDINAL)
- outs() << " (from executable)";
- else if (LibraryOrdinal == MachO::DYNAMIC_LOOKUP_ORDINAL)
- outs() << " (dynamically looked up)";
- else {
- StringRef LibraryName;
- if (!MachO ||
- MachO->getLibraryShortNameByIndex(LibraryOrdinal - 1, LibraryName))
- outs() << " (from bad library ordinal " << LibraryOrdinal << ")";
- else
- outs() << " (from " << LibraryName << ")";
- }
- }
- }
- outs() << "\n";
- }
- // Table that maps Darwin's Mach-O stab constants to strings to allow printing.
- struct DarwinStabName {
- uint8_t NType;
- const char *Name;
- };
- const struct DarwinStabName DarwinStabNames[] = {
- {MachO::N_GSYM, "GSYM"},
- {MachO::N_FNAME, "FNAME"},
- {MachO::N_FUN, "FUN"},
- {MachO::N_STSYM, "STSYM"},
- {MachO::N_LCSYM, "LCSYM"},
- {MachO::N_BNSYM, "BNSYM"},
- {MachO::N_PC, "PC"},
- {MachO::N_AST, "AST"},
- {MachO::N_OPT, "OPT"},
- {MachO::N_RSYM, "RSYM"},
- {MachO::N_SLINE, "SLINE"},
- {MachO::N_ENSYM, "ENSYM"},
- {MachO::N_SSYM, "SSYM"},
- {MachO::N_SO, "SO"},
- {MachO::N_OSO, "OSO"},
- {MachO::N_LSYM, "LSYM"},
- {MachO::N_BINCL, "BINCL"},
- {MachO::N_SOL, "SOL"},
- {MachO::N_PARAMS, "PARAM"},
- {MachO::N_VERSION, "VERS"},
- {MachO::N_OLEVEL, "OLEV"},
- {MachO::N_PSYM, "PSYM"},
- {MachO::N_EINCL, "EINCL"},
- {MachO::N_ENTRY, "ENTRY"},
- {MachO::N_LBRAC, "LBRAC"},
- {MachO::N_EXCL, "EXCL"},
- {MachO::N_RBRAC, "RBRAC"},
- {MachO::N_BCOMM, "BCOMM"},
- {MachO::N_ECOMM, "ECOMM"},
- {MachO::N_ECOML, "ECOML"},
- {MachO::N_LENG, "LENG"},
- };
- static const char *getDarwinStabString(uint8_t NType) {
- for (auto I : makeArrayRef(DarwinStabNames))
- if (I.NType == NType)
- return I.Name;
- return nullptr;
- }
- // darwinPrintStab() prints the n_sect, n_desc along with a symbolic name of
- // a stab n_type value in a Mach-O file.
- static void darwinPrintStab(MachOObjectFile *MachO, const NMSymbol &S) {
- MachO::nlist_64 STE_64;
- MachO::nlist STE;
- uint8_t NType;
- uint8_t NSect;
- uint16_t NDesc;
- DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
- if (MachO->is64Bit()) {
- STE_64 = MachO->getSymbol64TableEntry(SymDRI);
- NType = STE_64.n_type;
- NSect = STE_64.n_sect;
- NDesc = STE_64.n_desc;
- } else {
- STE = MachO->getSymbolTableEntry(SymDRI);
- NType = STE.n_type;
- NSect = STE.n_sect;
- NDesc = STE.n_desc;
- }
- outs() << format(" %02x %04x ", NSect, NDesc);
- if (const char *stabString = getDarwinStabString(NType))
- outs() << format("%5.5s", stabString);
- else
- outs() << format(" %02x", NType);
- }
- static Optional<std::string> demangle(StringRef Name) {
- std::string Demangled;
- if (nonMicrosoftDemangle(Name.str().c_str(), Demangled))
- return Demangled;
- return None;
- }
- static Optional<std::string> demangleXCOFF(StringRef Name) {
- if (Name.empty() || Name[0] != '.')
- return demangle(Name);
- Name = Name.drop_front();
- Optional<std::string> DemangledName = demangle(Name);
- if (DemangledName)
- return "." + *DemangledName;
- return None;
- }
- static Optional<std::string> demangleMachO(StringRef Name) {
- if (!Name.empty() && Name[0] == '_')
- Name = Name.drop_front();
- return demangle(Name);
- }
- static bool symbolIsDefined(const NMSymbol &Sym) {
- return Sym.TypeChar != 'U' && Sym.TypeChar != 'w' && Sym.TypeChar != 'v';
- }
- static void writeFileName(raw_ostream &S, StringRef ArchiveName,
- StringRef ArchitectureName) {
- if (!ArchitectureName.empty())
- S << "(for architecture " << ArchitectureName << "):";
- if (OutputFormat == posix && !ArchiveName.empty())
- S << ArchiveName << "[" << CurrentFilename << "]: ";
- else {
- if (!ArchiveName.empty())
- S << ArchiveName << ":";
- S << CurrentFilename << ": ";
- }
- }
- 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;
- if (ReverseSort)
- llvm::sort(SymbolList, [=](const NMSymbol &A, const NMSymbol &B) -> bool {
- return Cmp(B, A);
- });
- else
- llvm::sort(SymbolList, Cmp);
- }
- if (!PrintFileName) {
- if ((OutputFormat == bsd || OutputFormat == posix ||
- OutputFormat == just_symbols) &&
- MultipleFiles && printName) {
- outs() << '\n' << CurrentFilename << ":\n";
- } else if (OutputFormat == sysv) {
- outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n";
- if (isSymbolList64Bit(Obj))
- outs() << "Name Value Class Type"
- << " Size Line Section\n";
- else
- outs() << "Name Value Class Type"
- << " Size Line Section\n";
- }
- }
- const char *printBlanks, *printDashes, *printFormat;
- if (isSymbolList64Bit(Obj)) {
- printBlanks = " ";
- printDashes = "----------------";
- switch (AddressRadix) {
- case Radix::o:
- printFormat = OutputFormat == posix ? "%" PRIo64 : "%016" PRIo64;
- break;
- case Radix::x:
- printFormat = OutputFormat == posix ? "%" PRIx64 : "%016" PRIx64;
- break;
- default:
- printFormat = OutputFormat == posix ? "%" PRId64 : "%016" PRId64;
- }
- } else {
- printBlanks = " ";
- printDashes = "--------";
- switch (AddressRadix) {
- case Radix::o:
- printFormat = OutputFormat == posix ? "%" PRIo64 : "%08" PRIo64;
- break;
- case Radix::x:
- printFormat = OutputFormat == posix ? "%" PRIx64 : "%08" PRIx64;
- break;
- default:
- printFormat = OutputFormat == posix ? "%" PRId64 : "%08" PRId64;
- }
- }
- for (const NMSymbol &S : SymbolList) {
- uint32_t SymFlags;
- std::string Name = S.Name;
- MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
- if (Demangle) {
- function_ref<Optional<std::string>(StringRef)> Fn = ::demangle;
- if (Obj.isXCOFF())
- Fn = demangleXCOFF;
- if (Obj.isMachO())
- Fn = demangleMachO;
- if (Optional<std::string> Opt = Fn(S.Name))
- Name = *Opt;
- }
- if (S.Sym.getRawDataRefImpl().p) {
- Expected<uint32_t> 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)))
- continue;
- if (PrintFileName)
- writeFileName(outs(), ArchiveName, ArchitectureName);
- if ((OutputFormat == just_symbols ||
- (UndefinedOnly && MachO && OutputFormat != darwin)) &&
- OutputFormat != posix) {
- outs() << Name << "\n";
- continue;
- }
- char SymbolAddrStr[23], SymbolSizeStr[23];
- // If the format is SysV or the symbol isn't defined, then print spaces.
- if (OutputFormat == sysv || !symbolIsDefined(S)) {
- if (OutputFormat == posix) {
- format(printFormat, S.Address)
- .print(SymbolAddrStr, sizeof(SymbolAddrStr));
- format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
- } else {
- strcpy(SymbolAddrStr, printBlanks);
- strcpy(SymbolSizeStr, printBlanks);
- }
- }
- if (symbolIsDefined(S)) {
- // Otherwise, print the symbol address and size.
- if (Obj.isIR())
- strcpy(SymbolAddrStr, printDashes);
- else if (MachO && S.TypeChar == 'I')
- strcpy(SymbolAddrStr, printBlanks);
- else
- format(printFormat, S.Address)
- .print(SymbolAddrStr, sizeof(SymbolAddrStr));
- format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
- }
- // If OutputFormat is darwin or we are printing Mach-O symbols in hex and
- // we have a MachOObjectFile, call darwinPrintSymbol to print as darwin's
- // nm(1) -m output or hex, else if OutputFormat is darwin or we are
- // printing Mach-O symbols in hex and not a Mach-O object fall back to
- // OutputFormat bsd (see below).
- if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) {
- darwinPrintSymbol(Obj, S, SymbolAddrStr, printBlanks, printDashes,
- printFormat);
- } else if (OutputFormat == posix) {
- outs() << Name << " " << S.TypeChar << " " << SymbolAddrStr << " "
- << (MachO ? "0" : SymbolSizeStr) << "\n";
- } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) {
- if (PrintAddress)
- outs() << SymbolAddrStr << ' ';
- if (PrintSize)
- outs() << SymbolSizeStr << ' ';
- outs() << S.TypeChar;
- if (S.TypeChar == '-' && MachO)
- darwinPrintStab(MachO, S);
- outs() << " " << Name;
- if (S.TypeChar == 'I' && MachO) {
- outs() << " (indirect for ";
- if (S.Sym.getRawDataRefImpl().p) {
- StringRef IndirectName;
- if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
- outs() << "?)";
- else
- outs() << IndirectName << ")";
- } else
- outs() << S.IndirectName << ")";
- }
- outs() << "\n";
- } else if (OutputFormat == sysv) {
- outs() << left_justify(Name, 20) << "|" << SymbolAddrStr << "| "
- << S.TypeChar << " |" << right_justify(S.TypeName, 18) << "|"
- << SymbolSizeStr << "| |" << S.SectionName << "\n";
- }
- }
- SymbolList.clear();
- }
- static char getSymbolNMTypeChar(ELFObjectFileBase &Obj,
- basic_symbol_iterator I) {
- // OK, this is ELF
- elf_symbol_iterator SymI(I);
- Expected<elf_section_iterator> SecIOrErr = SymI->getSection();
- if (!SecIOrErr) {
- consumeError(SecIOrErr.takeError());
- return '?';
- }
- uint8_t Binding = SymI->getBinding();
- if (Binding == ELF::STB_GNU_UNIQUE)
- return 'u';
- assert(Binding != ELF::STB_WEAK && "STB_WEAK not tested in calling function");
- if (Binding != ELF::STB_GLOBAL && Binding != ELF::STB_LOCAL)
- return '?';
- elf_section_iterator SecI = *SecIOrErr;
- if (SecI != Obj.section_end()) {
- uint32_t Type = SecI->getType();
- uint64_t Flags = SecI->getFlags();
- if (Flags & ELF::SHF_EXECINSTR)
- return 't';
- if (Type == ELF::SHT_NOBITS)
- return 'b';
- if (Flags & ELF::SHF_ALLOC)
- return Flags & ELF::SHF_WRITE ? 'd' : 'r';
- auto NameOrErr = SecI->getName();
- if (!NameOrErr) {
- consumeError(NameOrErr.takeError());
- return '?';
- }
- if ((*NameOrErr).startswith(".debug"))
- return 'N';
- if (!(Flags & ELF::SHF_WRITE))
- return 'n';
- }
- return '?';
- }
- static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
- COFFSymbolRef Symb = Obj.getCOFFSymbol(*I);
- // OK, this is COFF.
- symbol_iterator SymI(I);
- Expected<StringRef> Name = SymI->getName();
- if (!Name) {
- consumeError(Name.takeError());
- return '?';
- }
- char Ret = StringSwitch<char>(*Name)
- .StartsWith(".debug", 'N')
- .StartsWith(".sxdata", 'N')
- .Default('?');
- if (Ret != '?')
- return Ret;
- uint32_t Characteristics = 0;
- if (!COFF::isReservedSectionNumber(Symb.getSectionNumber())) {
- Expected<section_iterator> SecIOrErr = SymI->getSection();
- if (!SecIOrErr) {
- consumeError(SecIOrErr.takeError());
- return '?';
- }
- section_iterator SecI = *SecIOrErr;
- const coff_section *Section = Obj.getCOFFSection(*SecI);
- Characteristics = Section->Characteristics;
- if (Expected<StringRef> NameOrErr = Obj.getSectionName(Section))
- if (NameOrErr->startswith(".idata"))
- return 'i';
- }
- switch (Symb.getSectionNumber()) {
- case COFF::IMAGE_SYM_DEBUG:
- return 'n';
- default:
- // Check section type.
- if (Characteristics & COFF::IMAGE_SCN_CNT_CODE)
- return 't';
- if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
- return Characteristics & COFF::IMAGE_SCN_MEM_WRITE ? 'd' : 'r';
- if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
- return 'b';
- if (Characteristics & COFF::IMAGE_SCN_LNK_INFO)
- return 'i';
- // Check for section symbol.
- if (Symb.isSectionDefinition())
- return 's';
- }
- return '?';
- }
- static char getSymbolNMTypeChar(XCOFFObjectFile &Obj, symbol_iterator I) {
- Expected<uint32_t> TypeOrErr = I->getType();
- if (!TypeOrErr) {
- warn(TypeOrErr.takeError(), Obj.getFileName(),
- "for symbol with index " +
- Twine(Obj.getSymbolIndex(I->getRawDataRefImpl().p)));
- return '?';
- }
- uint32_t SymType = *TypeOrErr;
- if (SymType == SymbolRef::ST_File)
- return 'f';
- // If the I->getSection() call would return an error, the earlier I->getType()
- // call will already have returned the same error first.
- section_iterator SecIter = cantFail(I->getSection());
- if (SecIter == Obj.section_end())
- return '?';
- if (Obj.isDebugSection(SecIter->getRawDataRefImpl()))
- return 'N';
- if (SecIter->isText())
- return 't';
- if (SecIter->isData())
- return 'd';
- if (SecIter->isBSS())
- return 'b';
- return '?';
- }
- static char getSymbolNMTypeChar(COFFImportFile &Obj) {
- switch (Obj.getCOFFImportHeader()->getType()) {
- case COFF::IMPORT_CODE:
- return 't';
- case COFF::IMPORT_DATA:
- return 'd';
- case COFF::IMPORT_CONST:
- return 'r';
- }
- return '?';
- }
- static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
- DataRefImpl Symb = I->getRawDataRefImpl();
- uint8_t NType = Obj.is64Bit() ? Obj.getSymbol64TableEntry(Symb).n_type
- : Obj.getSymbolTableEntry(Symb).n_type;
- if (NType & MachO::N_STAB)
- return '-';
- switch (NType & MachO::N_TYPE) {
- case MachO::N_ABS:
- return 's';
- case MachO::N_INDR:
- return 'i';
- case MachO::N_SECT: {
- Expected<section_iterator> SecOrErr = Obj.getSymbolSection(Symb);
- if (!SecOrErr) {
- consumeError(SecOrErr.takeError());
- return 's';
- }
- section_iterator Sec = *SecOrErr;
- if (Sec == Obj.section_end())
- return 's';
- DataRefImpl Ref = Sec->getRawDataRefImpl();
- StringRef SectionName;
- if (Expected<StringRef> NameOrErr = Obj.getSectionName(Ref))
- SectionName = *NameOrErr;
- StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref);
- if (Obj.is64Bit() && Obj.getHeader64().filetype == MachO::MH_KEXT_BUNDLE &&
- SegmentName == "__TEXT_EXEC" && SectionName == "__text")
- return 't';
- if (SegmentName == "__TEXT" && SectionName == "__text")
- return 't';
- if (SegmentName == "__DATA" && SectionName == "__data")
- return 'd';
- if (SegmentName == "__DATA" && SectionName == "__bss")
- return 'b';
- return 's';
- }
- }
- return '?';
- }
- static char getSymbolNMTypeChar(TapiFile &Obj, basic_symbol_iterator I) {
- return 's';
- }
- static char getSymbolNMTypeChar(WasmObjectFile &Obj, basic_symbol_iterator I) {
- uint32_t Flags = cantFail(I->getFlags());
- if (Flags & SymbolRef::SF_Executable)
- return 't';
- return 'd';
- }
- static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) {
- uint32_t Flags = cantFail(I->getFlags());
- // FIXME: should we print 'b'? At the IR level we cannot be sure if this
- // will be in bss or not, but we could approximate.
- if (Flags & SymbolRef::SF_Executable)
- return 't';
- else if (Triple(Obj.getTargetTriple()).isOSDarwin() &&
- (Flags & SymbolRef::SF_Const))
- return 's';
- else
- return 'd';
- }
- static bool isObject(SymbolicFile &Obj, basic_symbol_iterator I) {
- return isa<ELFObjectFileBase>(&Obj) &&
- elf_symbol_iterator(I)->getELFType() == ELF::STT_OBJECT;
- }
- // For ELF object files, Set TypeName to the symbol typename, to be printed
- // in the 'Type' column of the SYSV format output.
- static StringRef getNMTypeName(SymbolicFile &Obj, basic_symbol_iterator I) {
- if (isa<ELFObjectFileBase>(&Obj)) {
- elf_symbol_iterator SymI(I);
- return SymI->getELFTypeName();
- }
- return "";
- }
- // Return Posix nm class type tag (single letter), but also set SecName and
- // section and name, to be used in format=sysv output.
- static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I,
- StringRef &SecName) {
- // Symbol Flags have been checked in the caller.
- uint32_t Symflags = cantFail(I->getFlags());
- if (ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj)) {
- if (Symflags & object::SymbolRef::SF_Absolute)
- SecName = "*ABS*";
- else if (Symflags & object::SymbolRef::SF_Common)
- SecName = "*COM*";
- else if (Symflags & object::SymbolRef::SF_Undefined)
- SecName = "*UND*";
- else {
- elf_symbol_iterator SymI(I);
- Expected<elf_section_iterator> SecIOrErr = SymI->getSection();
- if (!SecIOrErr) {
- consumeError(SecIOrErr.takeError());
- return '?';
- }
- if (*SecIOrErr == ELFObj->section_end())
- return '?';
- Expected<StringRef> NameOrErr = (*SecIOrErr)->getName();
- if (!NameOrErr) {
- consumeError(NameOrErr.takeError());
- return '?';
- }
- SecName = *NameOrErr;
- }
- }
- if (Symflags & object::SymbolRef::SF_Undefined) {
- if (isa<MachOObjectFile>(Obj) || !(Symflags & object::SymbolRef::SF_Weak))
- return 'U';
- return isObject(Obj, I) ? 'v' : 'w';
- }
- if (isa<ELFObjectFileBase>(&Obj))
- if (ELFSymbolRef(*I).getELFType() == ELF::STT_GNU_IFUNC)
- return 'i';
- if (!isa<MachOObjectFile>(Obj) && (Symflags & object::SymbolRef::SF_Weak))
- return isObject(Obj, I) ? 'V' : 'W';
- if (Symflags & object::SymbolRef::SF_Common)
- return 'C';
- char Ret = '?';
- if (Symflags & object::SymbolRef::SF_Absolute)
- Ret = 'a';
- else if (IRObjectFile *IR = dyn_cast<IRObjectFile>(&Obj))
- Ret = getSymbolNMTypeChar(*IR, I);
- else if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(&Obj))
- Ret = getSymbolNMTypeChar(*COFF, I);
- else if (XCOFFObjectFile *XCOFF = dyn_cast<XCOFFObjectFile>(&Obj))
- Ret = getSymbolNMTypeChar(*XCOFF, I);
- else if (COFFImportFile *COFFImport = dyn_cast<COFFImportFile>(&Obj))
- Ret = getSymbolNMTypeChar(*COFFImport);
- else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
- Ret = getSymbolNMTypeChar(*MachO, I);
- else if (WasmObjectFile *Wasm = dyn_cast<WasmObjectFile>(&Obj))
- Ret = getSymbolNMTypeChar(*Wasm, I);
- else if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj))
- Ret = getSymbolNMTypeChar(*Tapi, I);
- else if (ELFObjectFileBase *ELF = dyn_cast<ELFObjectFileBase>(&Obj)) {
- Ret = getSymbolNMTypeChar(*ELF, I);
- if (ELFSymbolRef(*I).getBinding() == ELF::STB_GNU_UNIQUE)
- return Ret;
- } else
- llvm_unreachable("unknown binary format");
- if (!(Symflags & object::SymbolRef::SF_Global))
- return Ret;
- return toupper(Ret);
- }
- // getNsectForSegSect() is used to implement the Mach-O "-s segname sectname"
- // option to dump only those symbols from that section in a Mach-O file.
- // It is called once for each Mach-O file from dumpSymbolNamesFromObject()
- // to get the section number for that named section from the command line
- // arguments. It returns the section number for that section in the Mach-O
- // file or zero it is not present.
- static unsigned getNsectForSegSect(MachOObjectFile *Obj) {
- unsigned Nsect = 1;
- for (auto &S : Obj->sections()) {
- DataRefImpl Ref = S.getRawDataRefImpl();
- StringRef SectionName;
- if (Expected<StringRef> NameOrErr = Obj->getSectionName(Ref))
- SectionName = *NameOrErr;
- StringRef SegmentName = Obj->getSectionFinalSegmentName(Ref);
- if (SegmentName == SegSect[0] && SectionName == SegSect[1])
- return Nsect;
- Nsect++;
- }
- return 0;
- }
- // getNsectInMachO() is used to implement the Mach-O "-s segname sectname"
- // option to dump only those symbols from that section in a Mach-O file.
- // It is called once for each symbol in a Mach-O file from
- // dumpSymbolNamesFromObject() and returns the section number for that symbol
- // if it is in a section, else it returns 0.
- static unsigned getNsectInMachO(MachOObjectFile &Obj, BasicSymbolRef Sym) {
- DataRefImpl Symb = Sym.getRawDataRefImpl();
- if (Obj.is64Bit()) {
- MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb);
- return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0;
- }
- MachO::nlist STE = Obj.getSymbolTableEntry(Symb);
- return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0;
- }
- static void dumpSymbolsFromDLInfoMachO(MachOObjectFile &MachO) {
- size_t I = SymbolList.size();
- std::string ExportsNameBuffer;
- raw_string_ostream EOS(ExportsNameBuffer);
- std::string BindsNameBuffer;
- raw_string_ostream BOS(BindsNameBuffer);
- std::string LazysNameBuffer;
- raw_string_ostream LOS(LazysNameBuffer);
- std::string WeaksNameBuffer;
- raw_string_ostream WOS(WeaksNameBuffer);
- std::string FunctionStartsNameBuffer;
- raw_string_ostream FOS(FunctionStartsNameBuffer);
- MachO::mach_header H;
- MachO::mach_header_64 H_64;
- uint32_t HFlags = 0;
- if (MachO.is64Bit()) {
- H_64 = MachO.MachOObjectFile::getHeader64();
- HFlags = H_64.flags;
- } else {
- H = MachO.MachOObjectFile::getHeader();
- HFlags = H.flags;
- }
- uint64_t BaseSegmentAddress = 0;
- for (const auto &Command : MachO.load_commands()) {
- if (Command.C.cmd == MachO::LC_SEGMENT) {
- MachO::segment_command Seg = MachO.getSegmentLoadCommand(Command);
- if (Seg.fileoff == 0 && Seg.filesize != 0) {
- BaseSegmentAddress = Seg.vmaddr;
- break;
- }
- } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
- MachO::segment_command_64 Seg = MachO.getSegment64LoadCommand(Command);
- if (Seg.fileoff == 0 && Seg.filesize != 0) {
- BaseSegmentAddress = Seg.vmaddr;
- break;
- }
- }
- }
- if (DyldInfoOnly || AddDyldInfo ||
- HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
- unsigned ExportsAdded = 0;
- Error Err = Error::success();
- for (const llvm::object::ExportEntry &Entry : MachO.exports(Err)) {
- bool found = false;
- bool ReExport = false;
- if (!DyldInfoOnly) {
- for (const NMSymbol &S : SymbolList)
- if (S.Address == Entry.address() + BaseSegmentAddress &&
- S.Name == Entry.name()) {
- found = true;
- break;
- }
- }
- if (!found) {
- NMSymbol S = {};
- S.Address = Entry.address() + BaseSegmentAddress;
- S.Size = 0;
- S.TypeChar = '\0';
- S.Name = Entry.name().str();
- // There is no symbol in the nlist symbol table for this so we set
- // Sym effectivly to null and the rest of code in here must test for
- // it and not do things like Sym.getFlags() for it.
- S.Sym = BasicSymbolRef();
- S.SymFlags = SymbolRef::SF_Global;
- S.Section = SectionRef();
- S.NType = 0;
- S.NSect = 0;
- S.NDesc = 0;
- uint64_t EFlags = Entry.flags();
- bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
- MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
- bool Resolver = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
- ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
- bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
- if (WeakDef)
- S.NDesc |= MachO::N_WEAK_DEF;
- if (Abs) {
- S.NType = MachO::N_EXT | MachO::N_ABS;
- S.TypeChar = 'A';
- } else if (ReExport) {
- S.NType = MachO::N_EXT | MachO::N_INDR;
- S.TypeChar = 'I';
- } else {
- S.NType = MachO::N_EXT | MachO::N_SECT;
- if (Resolver) {
- S.Address = Entry.other() + BaseSegmentAddress;
- if ((S.Address & 1) != 0 && !MachO.is64Bit() &&
- H.cputype == MachO::CPU_TYPE_ARM) {
- S.Address &= ~1LL;
- S.NDesc |= MachO::N_ARM_THUMB_DEF;
- }
- } else {
- S.Address = Entry.address() + BaseSegmentAddress;
- }
- StringRef SegmentName = StringRef();
- StringRef SectionName = StringRef();
- for (const SectionRef &Section : MachO.sections()) {
- S.NSect++;
- if (Expected<StringRef> NameOrErr = Section.getName())
- SectionName = *NameOrErr;
- else
- consumeError(NameOrErr.takeError());
- SegmentName =
- MachO.getSectionFinalSegmentName(Section.getRawDataRefImpl());
- if (S.Address >= Section.getAddress() &&
- S.Address < Section.getAddress() + Section.getSize()) {
- S.Section = Section;
- break;
- } else if (Entry.name() == "__mh_execute_header" &&
- SegmentName == "__TEXT" && SectionName == "__text") {
- S.Section = Section;
- S.NDesc |= MachO::REFERENCED_DYNAMICALLY;
- break;
- }
- }
- if (SegmentName == "__TEXT" && SectionName == "__text")
- S.TypeChar = 'T';
- else if (SegmentName == "__DATA" && SectionName == "__data")
- S.TypeChar = 'D';
- else if (SegmentName == "__DATA" && SectionName == "__bss")
- S.TypeChar = 'B';
- else
- S.TypeChar = 'S';
- }
- SymbolList.push_back(S);
- EOS << Entry.name();
- EOS << '\0';
- ExportsAdded++;
- // For ReExports there are a two more things to do, first add the
- // indirect name and second create the undefined symbol using the
- // referened dynamic library.
- if (ReExport) {
- // Add the indirect name.
- if (Entry.otherName().empty())
- EOS << Entry.name();
- else
- EOS << Entry.otherName();
- EOS << '\0';
- // Now create the undefined symbol using the referened dynamic
- // library.
- NMSymbol U = {};
- U.Address = 0;
- U.Size = 0;
- U.TypeChar = 'U';
- if (Entry.otherName().empty())
- U.Name = Entry.name().str();
- else
- U.Name = Entry.otherName().str();
- // Again there is no symbol in the nlist symbol table for this so
- // we set Sym effectivly to null and the rest of code in here must
- // test for it and not do things like Sym.getFlags() for it.
- U.Sym = BasicSymbolRef();
- U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
- U.Section = SectionRef();
- U.NType = MachO::N_EXT | MachO::N_UNDF;
- U.NSect = 0;
- U.NDesc = 0;
- // The library ordinal for this undefined symbol is in the export
- // trie Entry.other().
- MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other());
- SymbolList.push_back(U);
- // Finally add the undefined symbol's name.
- if (Entry.otherName().empty())
- EOS << Entry.name();
- else
- EOS << Entry.otherName();
- EOS << '\0';
- ExportsAdded++;
- }
- }
- }
- if (Err)
- error(std::move(Err), MachO.getFileName());
- // Set the symbol names and indirect names for the added symbols.
- if (ExportsAdded) {
- EOS.flush();
- const char *Q = ExportsNameBuffer.c_str();
- for (unsigned K = 0; K < ExportsAdded; K++) {
- SymbolList[I].Name = Q;
- Q += strlen(Q) + 1;
- if (SymbolList[I].TypeChar == 'I') {
- SymbolList[I].IndirectName = Q;
- Q += strlen(Q) + 1;
- }
- I++;
- }
- }
- // Add the undefined symbols from the bind entries.
- unsigned BindsAdded = 0;
- Error BErr = Error::success();
- StringRef LastSymbolName = StringRef();
- for (const llvm::object::MachOBindEntry &Entry : MachO.bindTable(BErr)) {
- bool found = false;
- if (LastSymbolName == Entry.symbolName())
- found = true;
- else if (!DyldInfoOnly) {
- for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
- if (SymbolList[J].Name == Entry.symbolName())
- found = true;
- }
- }
- if (!found) {
- LastSymbolName = Entry.symbolName();
- NMSymbol B = {};
- B.Address = 0;
- B.Size = 0;
- B.TypeChar = 'U';
- // There is no symbol in the nlist symbol table for this so we set
- // Sym effectivly to null and the rest of code in here must test for
- // it and not do things like Sym.getFlags() for it.
- B.Sym = BasicSymbolRef();
- B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
- B.NType = MachO::N_EXT | MachO::N_UNDF;
- B.NSect = 0;
- B.NDesc = 0;
- MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
- B.Name = Entry.symbolName().str();
- SymbolList.push_back(B);
- BOS << Entry.symbolName();
- BOS << '\0';
- BindsAdded++;
- }
- }
- if (BErr)
- error(std::move(BErr), MachO.getFileName());
- // Set the symbol names and indirect names for the added symbols.
- if (BindsAdded) {
- BOS.flush();
- const char *Q = BindsNameBuffer.c_str();
- for (unsigned K = 0; K < BindsAdded; K++) {
- SymbolList[I].Name = Q;
- Q += strlen(Q) + 1;
- if (SymbolList[I].TypeChar == 'I') {
- SymbolList[I].IndirectName = Q;
- Q += strlen(Q) + 1;
- }
- I++;
- }
- }
- // Add the undefined symbols from the lazy bind entries.
- unsigned LazysAdded = 0;
- Error LErr = Error::success();
- LastSymbolName = StringRef();
- for (const llvm::object::MachOBindEntry &Entry :
- MachO.lazyBindTable(LErr)) {
- bool found = false;
- if (LastSymbolName == Entry.symbolName())
- found = true;
- else {
- // Here we must check to see it this symbol is already in the
- // SymbolList as it might have already have been added above via a
- // non-lazy (bind) entry.
- for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
- if (SymbolList[J].Name == Entry.symbolName())
- found = true;
- }
- }
- if (!found) {
- LastSymbolName = Entry.symbolName();
- NMSymbol L = {};
- L.Name = Entry.symbolName().str();
- L.Address = 0;
- L.Size = 0;
- L.TypeChar = 'U';
- // There is no symbol in the nlist symbol table for this so we set
- // Sym effectivly to null and the rest of code in here must test for
- // it and not do things like Sym.getFlags() for it.
- L.Sym = BasicSymbolRef();
- L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
- L.NType = MachO::N_EXT | MachO::N_UNDF;
- L.NSect = 0;
- // The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it
- // makes sence since we are creating this from a lazy bind entry.
- L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY;
- MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal());
- SymbolList.push_back(L);
- LOS << Entry.symbolName();
- LOS << '\0';
- LazysAdded++;
- }
- }
- if (LErr)
- error(std::move(LErr), MachO.getFileName());
- // Set the symbol names and indirect names for the added symbols.
- if (LazysAdded) {
- LOS.flush();
- const char *Q = LazysNameBuffer.c_str();
- for (unsigned K = 0; K < LazysAdded; K++) {
- SymbolList[I].Name = Q;
- Q += strlen(Q) + 1;
- if (SymbolList[I].TypeChar == 'I') {
- SymbolList[I].IndirectName = Q;
- Q += strlen(Q) + 1;
- }
- I++;
- }
- }
- // Add the undefineds symbol from the weak bind entries which are not
- // strong symbols.
- unsigned WeaksAdded = 0;
- Error WErr = Error::success();
- LastSymbolName = StringRef();
- for (const llvm::object::MachOBindEntry &Entry :
- MachO.weakBindTable(WErr)) {
- bool found = false;
- unsigned J = 0;
- if (LastSymbolName == Entry.symbolName() ||
- Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
- found = true;
- } else {
- for (J = 0; J < SymbolList.size() && !found; ++J) {
- if (SymbolList[J].Name == Entry.symbolName()) {
- found = true;
- break;
- }
- }
- }
- if (!found) {
- LastSymbolName = Entry.symbolName();
- NMSymbol W = {};
- W.Name = Entry.symbolName().str();
- W.Address = 0;
- W.Size = 0;
- W.TypeChar = 'U';
- // There is no symbol in the nlist symbol table for this so we set
- // Sym effectivly to null and the rest of code in here must test for
- // it and not do things like Sym.getFlags() for it.
- W.Sym = BasicSymbolRef();
- W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
- W.NType = MachO::N_EXT | MachO::N_UNDF;
- W.NSect = 0;
- // Odd that we are using N_WEAK_DEF on an undefined symbol but that is
- // what is created in this case by the linker when there are real
- // symbols in the nlist structs.
- W.NDesc = MachO::N_WEAK_DEF;
- SymbolList.push_back(W);
- WOS << Entry.symbolName();
- WOS << '\0';
- WeaksAdded++;
- } else {
- // This is the case the symbol was previously been found and it could
- // have been added from a bind or lazy bind symbol. If so and not
- // a definition also mark it as weak.
- if (SymbolList[J].TypeChar == 'U')
- // See comment above about N_WEAK_DEF.
- SymbolList[J].NDesc |= MachO::N_WEAK_DEF;
- }
- }
- if (WErr)
- error(std::move(WErr), MachO.getFileName());
- // Set the symbol names and indirect names for the added symbols.
- if (WeaksAdded) {
- WOS.flush();
- const char *Q = WeaksNameBuffer.c_str();
- for (unsigned K = 0; K < WeaksAdded; K++) {
- SymbolList[I].Name = Q;
- Q += strlen(Q) + 1;
- if (SymbolList[I].TypeChar == 'I') {
- SymbolList[I].IndirectName = Q;
- Q += strlen(Q) + 1;
- }
- I++;
- }
- }
- // Trying adding symbol from the function starts table and LC_MAIN entry
- // point.
- SmallVector<uint64_t, 8> FoundFns;
- uint64_t lc_main_offset = UINT64_MAX;
- for (const auto &Command : MachO.load_commands()) {
- if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
- // We found a function starts segment, parse the addresses for
- // consumption.
- MachO::linkedit_data_command LLC =
- MachO.getLinkeditDataLoadCommand(Command);
- MachO.ReadULEB128s(LLC.dataoff, FoundFns);
- } else if (Command.C.cmd == MachO::LC_MAIN) {
- MachO::entry_point_command LCmain = MachO.getEntryPointCommand(Command);
- lc_main_offset = LCmain.entryoff;
- }
- }
- // See if these addresses are already in the symbol table.
- unsigned FunctionStartsAdded = 0;
- for (uint64_t f = 0; f < FoundFns.size(); f++) {
- bool found = false;
- for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
- if (SymbolList[J].Address == FoundFns[f] + BaseSegmentAddress)
- found = true;
- }
- // See this address is not already in the symbol table fake up an
- // nlist for it.
- if (!found) {
- NMSymbol F = {};
- F.Name = "<redacted function X>";
- F.Address = FoundFns[f] + BaseSegmentAddress;
- F.Size = 0;
- // There is no symbol in the nlist symbol table for this so we set
- // Sym effectivly to null and the rest of code in here must test for
- // it and not do things like Sym.getFlags() for it.
- F.Sym = BasicSymbolRef();
- F.SymFlags = 0;
- F.NType = MachO::N_SECT;
- F.NSect = 0;
- StringRef SegmentName = StringRef();
- StringRef SectionName = StringRef();
- for (const SectionRef &Section : MachO.sections()) {
- if (Expected<StringRef> NameOrErr = Section.getName())
- SectionName = *NameOrErr;
- else
- consumeError(NameOrErr.takeError());
- SegmentName =
- MachO.getSectionFinalSegmentName(Section.getRawDataRefImpl());
- F.NSect++;
- if (F.Address >= Section.getAddress() &&
- F.Address < Section.getAddress() + Section.getSize()) {
- F.Section = Section;
- break;
- }
- }
- if (SegmentName == "__TEXT" && SectionName == "__text")
- F.TypeChar = 't';
- else if (SegmentName == "__DATA" && SectionName == "__data")
- F.TypeChar = 'd';
- else if (SegmentName == "__DATA" && SectionName == "__bss")
- F.TypeChar = 'b';
- else
- F.TypeChar = 's';
- F.NDesc = 0;
- SymbolList.push_back(F);
- if (FoundFns[f] == lc_main_offset)
- FOS << "<redacted LC_MAIN>";
- else
- FOS << "<redacted function " << f << ">";
- FOS << '\0';
- FunctionStartsAdded++;
- }
- }
- if (FunctionStartsAdded) {
- FOS.flush();
- const char *Q = FunctionStartsNameBuffer.c_str();
- for (unsigned K = 0; K < FunctionStartsAdded; K++) {
- SymbolList[I].Name = Q;
- Q += strlen(Q) + 1;
- if (SymbolList[I].TypeChar == 'I') {
- SymbolList[I].IndirectName = Q;
- Q += strlen(Q) + 1;
- }
- I++;
- }
- }
- }
- }
- static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
- StringRef ArchiveName = {},
- StringRef ArchitectureName = {}) {
- auto Symbols = Obj.symbols();
- std::vector<VersionEntry> SymbolVersions;
- if (DynamicSyms) {
- const auto *E = dyn_cast<ELFObjectFileBase>(&Obj);
- if (!E) {
- error("File format has no dynamic symbol table", Obj.getFileName());
- return;
- }
- Symbols = E->getDynamicSymbolIterators();
- if (Expected<std::vector<VersionEntry>> VersionsOrErr =
- E->readDynsymVersions())
- SymbolVersions = std::move(*VersionsOrErr);
- else
- WithColor::warning(errs(), ToolName)
- << "unable to read symbol versions: "
- << toString(VersionsOrErr.takeError()) << "\n";
- }
- // If a "-s segname sectname" option was specified and this is a Mach-O
- // file get the section number for that section in this object file.
- unsigned int Nsect = 0;
- MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
- if (!SegSect.empty() && MachO) {
- Nsect = getNsectForSegSect(MachO);
- // If this section is not in the object file no symbols are printed.
- if (Nsect == 0)
- return;
- }
- if (!(MachO && DyldInfoOnly)) {
- size_t I = -1;
- for (BasicSymbolRef Sym : Symbols) {
- ++I;
- Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
- if (!SymFlagsOrErr) {
- error(SymFlagsOrErr.takeError(), Obj.getFileName());
- return;
- }
- // Don't drop format specifc symbols for ARM and AArch64 ELF targets, they
- // are used to repesent mapping symbols and needed to honor the
- // --special-syms option.
- auto *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj);
- if ((!ELFObj || (ELFObj->getEMachine() != ELF::EM_ARM &&
- ELFObj->getEMachine() != ELF::EM_AARCH64)) &&
- !DebugSyms && (*SymFlagsOrErr & SymbolRef::SF_FormatSpecific))
- continue;
- if (WithoutAliases && (*SymFlagsOrErr & SymbolRef::SF_Indirect))
- continue;
- // If a "-s segname sectname" option was specified and this is a Mach-O
- // file and this section appears in this file, Nsect will be non-zero then
- // see if this symbol is a symbol from that section and if not skip it.
- if (Nsect && Nsect != getNsectInMachO(*MachO, Sym))
- continue;
- NMSymbol S = {};
- S.Size = 0;
- S.Address = 0;
- if (isa<ELFObjectFileBase>(&Obj))
- S.Size = ELFSymbolRef(Sym).getSize();
- if (const XCOFFObjectFile *XCOFFObj =
- dyn_cast<const XCOFFObjectFile>(&Obj))
- S.Size = XCOFFObj->getSymbolSize(Sym.getRawDataRefImpl());
- if (PrintAddress && isa<ObjectFile>(Obj)) {
- SymbolRef SymRef(Sym);
- Expected<uint64_t> AddressOrErr = SymRef.getAddress();
- if (!AddressOrErr) {
- consumeError(AddressOrErr.takeError());
- break;
- }
- S.Address = *AddressOrErr;
- }
- S.TypeName = getNMTypeName(Obj, Sym);
- S.TypeChar = getNMSectionTagAndName(Obj, Sym, S.SectionName);
- raw_string_ostream OS(S.Name);
- if (Error E = Sym.printName(OS)) {
- if (MachO) {
- OS << "bad string index";
- consumeError(std::move(E));
- } else
- error(std::move(E), Obj.getFileName());
- }
- if (!SymbolVersions.empty() && !SymbolVersions[I].Name.empty())
- S.Name +=
- (SymbolVersions[I].IsVerDef ? "@@" : "@") + SymbolVersions[I].Name;
- S.Sym = Sym;
- SymbolList.push_back(S);
- }
- }
- // If this is a Mach-O file where the nlist symbol table is out of sync
- // with the dyld export trie then look through exports and fake up symbols
- // for the ones that are missing (also done with the -add-dyldinfo flag).
- // This is needed if strip(1) -T is run on a binary containing swift
- // 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);
- CurrentFilename = Obj.getFileName();
- if (Symbols.empty() && SymbolList.empty() && !Quiet) {
- writeFileName(errs(), ArchiveName, ArchitectureName);
- errs() << "no symbols\n";
- }
- sortAndPrintSymbolList(Obj, printName, ArchiveName, ArchitectureName);
- }
- // checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file
- // and if it is and there is a list of architecture flags is specified then
- // check to make sure this Mach-O file is one of those architectures or all
- // architectures was specificed. If not then an error is generated and this
- // routine returns false. Else it returns true.
- static bool checkMachOAndArchFlags(SymbolicFile *O, std::string &Filename) {
- auto *MachO = dyn_cast<MachOObjectFile>(O);
- if (!MachO || ArchAll || ArchFlags.empty())
- return true;
- MachO::mach_header H;
- MachO::mach_header_64 H_64;
- Triple T;
- const char *McpuDefault, *ArchFlag;
- if (MachO->is64Bit()) {
- H_64 = MachO->MachOObjectFile::getHeader64();
- T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,
- &McpuDefault, &ArchFlag);
- } else {
- H = MachO->MachOObjectFile::getHeader();
- T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,
- &McpuDefault, &ArchFlag);
- }
- const std::string ArchFlagName(ArchFlag);
- if (!llvm::is_contained(ArchFlags, ArchFlagName)) {
- error("No architecture specified", Filename);
- return false;
- }
- return true;
- }
- static void dumpSymbolNamesFromFile(std::string &Filename) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
- MemoryBuffer::getFileOrSTDIN(Filename);
- if (error(BufferOrErr.getError(), Filename))
- return;
- LLVMContext Context;
- LLVMContext *ContextPtr = NoLLVMBitcode ? nullptr : &Context;
- Expected<std::unique_ptr<Binary>> BinaryOrErr =
- createBinary(BufferOrErr.get()->getMemBufferRef(), ContextPtr);
- if (!BinaryOrErr) {
- error(BinaryOrErr.takeError(), Filename);
- return;
- }
- Binary &Bin = *BinaryOrErr.get();
- if (Archive *A = dyn_cast<Archive>(&Bin)) {
- if (ArchiveMap) {
- Archive::symbol_iterator I = A->symbol_begin();
- Archive::symbol_iterator E = A->symbol_end();
- if (I != E) {
- outs() << "Archive map\n";
- for (; I != E; ++I) {
- Expected<Archive::Child> C = I->getMember();
- if (!C) {
- error(C.takeError(), Filename);
- break;
- }
- Expected<StringRef> FileNameOrErr = C->getName();
- if (!FileNameOrErr) {
- error(FileNameOrErr.takeError(), Filename);
- break;
- }
- StringRef SymName = I->getName();
- outs() << SymName << " in " << FileNameOrErr.get() << "\n";
- }
- outs() << "\n";
- }
- }
- {
- Error Err = Error::success();
- for (auto &C : A->children(Err)) {
- Expected<std::unique_ptr<Binary>> ChildOrErr =
- C.getAsBinary(ContextPtr);
- if (!ChildOrErr) {
- if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
- error(std::move(E), Filename, C);
- continue;
- }
- if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
- if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
- WithColor::warning(errs(), ToolName)
- << "sizes with -print-size for Mach-O files are always zero.\n";
- MachOPrintSizeWarning = true;
- }
- if (!checkMachOAndArchFlags(O, Filename))
- return;
- if (!PrintFileName) {
- outs() << "\n";
- if (isa<MachOObjectFile>(O)) {
- outs() << Filename << "(" << O->getFileName() << ")";
- } else
- outs() << O->getFileName();
- outs() << ":\n";
- }
- dumpSymbolNamesFromObject(*O, false, Filename);
- }
- }
- if (Err)
- error(std::move(Err), A->getFileName());
- }
- return;
- }
- if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
- // If we have a list of architecture flags specified dump only those.
- if (!ArchAll && !ArchFlags.empty()) {
- // Look for a slice in the universal binary that matches each ArchFlag.
- bool ArchFound;
- for (unsigned i = 0; i < ArchFlags.size(); ++i) {
- ArchFound = false;
- for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
- E = UB->end_objects();
- I != E; ++I) {
- if (ArchFlags[i] == I->getArchFlagName()) {
- ArchFound = true;
- Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
- I->getAsObjectFile();
- std::string ArchiveName;
- std::string ArchitectureName;
- ArchiveName.clear();
- ArchitectureName.clear();
- if (ObjOrErr) {
- ObjectFile &Obj = *ObjOrErr.get();
- if (ArchFlags.size() > 1) {
- if (PrintFileName)
- ArchitectureName = I->getArchFlagName();
- else
- outs() << "\n" << Obj.getFileName() << " (for architecture "
- << I->getArchFlagName() << ")"
- << ":\n";
- }
- dumpSymbolNamesFromObject(Obj, false, ArchiveName,
- ArchitectureName);
- } else if (auto E = isNotObjectErrorInvalidFileType(
- ObjOrErr.takeError())) {
- error(std::move(E), Filename, ArchFlags.size() > 1 ?
- StringRef(I->getArchFlagName()) : StringRef());
- continue;
- } else if (Expected<std::unique_ptr<Archive>> AOrErr =
- I->getAsArchive()) {
- std::unique_ptr<Archive> &A = *AOrErr;
- Error Err = Error::success();
- for (auto &C : A->children(Err)) {
- Expected<std::unique_ptr<Binary>> ChildOrErr =
- C.getAsBinary(ContextPtr);
- if (!ChildOrErr) {
- if (auto E = isNotObjectErrorInvalidFileType(
- ChildOrErr.takeError())) {
- error(std::move(E), Filename, C, ArchFlags.size() > 1 ?
- StringRef(I->getArchFlagName()) : StringRef());
- }
- continue;
- }
- if (SymbolicFile *O =
- dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
- if (PrintFileName) {
- ArchiveName = std::string(A->getFileName());
- if (ArchFlags.size() > 1)
- ArchitectureName = I->getArchFlagName();
- } else {
- outs() << "\n" << A->getFileName();
- outs() << "(" << O->getFileName() << ")";
- if (ArchFlags.size() > 1) {
- outs() << " (for architecture " << I->getArchFlagName()
- << ")";
- }
- outs() << ":\n";
- }
- dumpSymbolNamesFromObject(*O, false, ArchiveName,
- ArchitectureName);
- }
- }
- if (Err)
- error(std::move(Err), A->getFileName());
- } else {
- consumeError(AOrErr.takeError());
- error(Filename + " for architecture " +
- StringRef(I->getArchFlagName()) +
- " is not a Mach-O file or an archive file",
- "Mach-O universal file");
- }
- }
- }
- if (!ArchFound) {
- error(ArchFlags[i],
- "file: " + Filename + " does not contain architecture");
- return;
- }
- }
- return;
- }
- // No architecture flags were specified so if this contains a slice that
- // matches the host architecture dump only that.
- if (!ArchAll) {
- Triple HostTriple = MachOObjectFile::getHostArch();
- StringRef HostArchName = HostTriple.getArchName();
- for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
- E = UB->end_objects();
- I != E; ++I) {
- if (HostArchName == I->getArchFlagName()) {
- Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
- std::string ArchiveName;
- if (ObjOrErr) {
- ObjectFile &Obj = *ObjOrErr.get();
- dumpSymbolNamesFromObject(Obj, false);
- } else if (auto E = isNotObjectErrorInvalidFileType(
- ObjOrErr.takeError())) {
- error(std::move(E), Filename);
- return;
- } else if (Expected<std::unique_ptr<Archive>> AOrErr =
- I->getAsArchive()) {
- std::unique_ptr<Archive> &A = *AOrErr;
- Error Err = Error::success();
- for (auto &C : A->children(Err)) {
- Expected<std::unique_ptr<Binary>> ChildOrErr =
- C.getAsBinary(ContextPtr);
- if (!ChildOrErr) {
- if (auto E = isNotObjectErrorInvalidFileType(
- ChildOrErr.takeError()))
- error(std::move(E), Filename, C);
- continue;
- }
- if (SymbolicFile *O =
- dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
- if (PrintFileName)
- ArchiveName = std::string(A->getFileName());
- else
- outs() << "\n" << A->getFileName() << "(" << O->getFileName()
- << ")"
- << ":\n";
- dumpSymbolNamesFromObject(*O, false, ArchiveName);
- }
- }
- if (Err)
- error(std::move(Err), A->getFileName());
- } else {
- consumeError(AOrErr.takeError());
- error(Filename + " for architecture " +
- StringRef(I->getArchFlagName()) +
- " is not a Mach-O file or an archive file",
- "Mach-O universal file");
- }
- 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.
- bool moreThanOneArch = UB->getNumberOfObjects() > 1;
- for (const MachOUniversalBinary::ObjectForArch &O : UB->objects()) {
- Expected<std::unique_ptr<ObjectFile>> ObjOrErr = O.getAsObjectFile();
- std::string ArchiveName;
- std::string ArchitectureName;
- ArchiveName.clear();
- ArchitectureName.clear();
- if (ObjOrErr) {
- ObjectFile &Obj = *ObjOrErr.get();
- if (PrintFileName) {
- if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
- ArchitectureName = O.getArchFlagName();
- } else {
- if (moreThanOneArch)
- outs() << "\n";
- outs() << Obj.getFileName();
- if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
- outs() << " (for architecture " << O.getArchFlagName() << ")";
- outs() << ":\n";
- }
- dumpSymbolNamesFromObject(Obj, false, ArchiveName, ArchitectureName);
- } else if (auto E = isNotObjectErrorInvalidFileType(
- ObjOrErr.takeError())) {
- error(std::move(E), Filename, moreThanOneArch ?
- StringRef(O.getArchFlagName()) : StringRef());
- continue;
- } else if (Expected<std::unique_ptr<Archive>> AOrErr =
- O.getAsArchive()) {
- std::unique_ptr<Archive> &A = *AOrErr;
- Error Err = Error::success();
- for (auto &C : A->children(Err)) {
- Expected<std::unique_ptr<Binary>> ChildOrErr =
- C.getAsBinary(ContextPtr);
- if (!ChildOrErr) {
- if (auto E = isNotObjectErrorInvalidFileType(
- ChildOrErr.takeError()))
- error(std::move(E), Filename, C, moreThanOneArch ?
- StringRef(ArchitectureName) : StringRef());
- continue;
- }
- if (SymbolicFile *F = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
- if (PrintFileName) {
- ArchiveName = std::string(A->getFileName());
- if (isa<MachOObjectFile>(F) && moreThanOneArch)
- ArchitectureName = O.getArchFlagName();
- } else {
- outs() << "\n" << A->getFileName();
- if (isa<MachOObjectFile>(F)) {
- outs() << "(" << F->getFileName() << ")";
- if (moreThanOneArch)
- outs() << " (for architecture " << O.getArchFlagName()
- << ")";
- } else
- outs() << ":" << F->getFileName();
- outs() << ":\n";
- }
- dumpSymbolNamesFromObject(*F, false, ArchiveName, ArchitectureName);
- }
- }
- if (Err)
- error(std::move(Err), A->getFileName());
- } else {
- consumeError(AOrErr.takeError());
- error(Filename + " for architecture " +
- StringRef(O.getArchFlagName()) +
- " is not a Mach-O file or an archive file",
- "Mach-O universal file");
- }
- }
- return;
- }
- if (TapiUniversal *TU = dyn_cast<TapiUniversal>(&Bin)) {
- for (const TapiUniversal::ObjectForArch &I : TU->objects()) {
- StringRef ArchName = I.getArchFlagName();
- const bool ShowArch =
- ArchFlags.empty() || llvm::is_contained(ArchFlags, ArchName);
- if (!ShowArch)
- continue;
- if (!AddInlinedInfo && !I.isTopLevelLib())
- continue;
- if (auto ObjOrErr = I.getAsObjectFile()) {
- outs() << "\n"
- << I.getInstallName() << " (for architecture " << ArchName << ")"
- << ":\n";
- dumpSymbolNamesFromObject(*ObjOrErr.get(), false, {}, ArchName);
- } else if (Error E =
- isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
- error(std::move(E), Filename, ArchName);
- }
- }
- return;
- }
- if (SymbolicFile *O = dyn_cast<SymbolicFile>(&Bin)) {
- if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
- WithColor::warning(errs(), ToolName)
- << "sizes with --print-size for Mach-O files are always zero.\n";
- MachOPrintSizeWarning = true;
- }
- if (!checkMachOAndArchFlags(O, Filename))
- return;
- dumpSymbolNamesFromObject(*O, true);
- }
- }
- int main(int argc, char **argv) {
- InitLLVM X(argc, argv);
- BumpPtrAllocator A;
- StringSaver Saver(A);
- NmOptTable Tbl;
- ToolName = argv[0];
- opt::InputArgList Args =
- Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
- error(Msg);
- exit(1);
- });
- if (Args.hasArg(OPT_help)) {
- Tbl.printHelp(
- outs(),
- (Twine(ToolName) + " [options] <input object files>").str().c_str(),
- "LLVM symbol table dumper");
- // TODO Replace this with OptTable API once it adds extrahelp support.
- outs() << "\nPass @FILE as argument to read options from FILE.\n";
- return 0;
- }
- if (Args.hasArg(OPT_version)) {
- // This needs to contain the word "GNU", libtool looks for that string.
- outs() << "llvm-nm, compatible with GNU nm" << '\n';
- cl::PrintVersionMessage();
- return 0;
- }
- DebugSyms = Args.hasArg(OPT_debug_syms);
- DefinedOnly = Args.hasArg(OPT_defined_only);
- Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false);
- DynamicSyms = Args.hasArg(OPT_dynamic);
- ExternalOnly = Args.hasArg(OPT_extern_only);
- StringRef V = Args.getLastArgValue(OPT_format_EQ, "bsd");
- if (V == "bsd")
- OutputFormat = bsd;
- else if (V == "posix")
- OutputFormat = posix;
- else if (V == "sysv")
- OutputFormat = sysv;
- else if (V == "darwin")
- OutputFormat = darwin;
- else if (V == "just-symbols")
- OutputFormat = just_symbols;
- else
- error("--format value should be one of: bsd, posix, sysv, darwin, "
- "just-symbols");
- NoLLVMBitcode = Args.hasArg(OPT_no_llvm_bc);
- NoSort = Args.hasArg(OPT_no_sort);
- NoWeakSymbols = Args.hasArg(OPT_no_weak);
- NumericSort = Args.hasArg(OPT_numeric_sort);
- ArchiveMap = Args.hasArg(OPT_print_armap);
- PrintFileName = Args.hasArg(OPT_print_file_name);
- PrintSize = Args.hasArg(OPT_print_size);
- ReverseSort = Args.hasArg(OPT_reverse_sort);
- Quiet = Args.hasArg(OPT_quiet);
- V = Args.getLastArgValue(OPT_radix_EQ, "x");
- if (V == "o")
- AddressRadix = Radix::o;
- else if (V == "d")
- AddressRadix = Radix::d;
- else if (V == "x")
- AddressRadix = Radix::x;
- else
- error("--radix value should be one of: 'o' (octal), 'd' (decimal), 'x' "
- "(hexadecimal)");
- SizeSort = Args.hasArg(OPT_size_sort);
- SpecialSyms = Args.hasArg(OPT_special_syms);
- UndefinedOnly = Args.hasArg(OPT_undefined_only);
- WithoutAliases = Args.hasArg(OPT_without_aliases);
- // Mach-O specific options.
- FormatMachOasHex = Args.hasArg(OPT_x);
- AddDyldInfo = Args.hasArg(OPT_add_dyldinfo);
- AddInlinedInfo = Args.hasArg(OPT_add_inlinedinfo);
- DyldInfoOnly = Args.hasArg(OPT_dyldinfo_only);
- NoDyldInfo = Args.hasArg(OPT_no_dyldinfo);
- // llvm-nm only reads binary files.
- if (error(sys::ChangeStdinToBinary()))
- return 1;
- // These calls are needed so that we can read bitcode correctly.
- llvm::InitializeAllTargetInfos();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllAsmParsers();
- // The relative order of these is important. If you pass --size-sort it should
- // only print out the size. However, if you pass -S --size-sort, it should
- // print out both the size and address.
- if (SizeSort && !PrintSize)
- PrintAddress = false;
- if (OutputFormat == sysv || SizeSort)
- PrintSize = true;
- for (const auto *A : Args.filtered(OPT_arch_EQ)) {
- SmallVector<StringRef, 2> Values;
- llvm::SplitString(A->getValue(), Values, ",");
- for (StringRef V : Values) {
- if (V == "all")
- ArchAll = true;
- else if (MachOObjectFile::isValidArch(V))
- ArchFlags.push_back(V);
- else
- error("Unknown architecture named '" + V + "'",
- "for the --arch option");
- }
- }
- // Mach-O takes -s to accept two arguments. We emulate this by iterating over
- // both OPT_s and OPT_INPUT.
- std::vector<std::string> InputFilenames;
- int SegSectArgs = 0;
- for (opt::Arg *A : Args.filtered(OPT_s, OPT_INPUT)) {
- if (SegSectArgs > 0) {
- --SegSectArgs;
- SegSect.push_back(A->getValue());
- } else if (A->getOption().matches(OPT_s)) {
- SegSectArgs = 2;
- } else {
- InputFilenames.push_back(A->getValue());
- }
- }
- if (!SegSect.empty() && SegSect.size() != 2)
- error("bad number of arguments (must be two arguments)",
- "for the -s option");
- if (InputFilenames.empty())
- InputFilenames.push_back("a.out");
- if (InputFilenames.size() > 1)
- MultipleFiles = true;
- if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly))
- error("--no-dyldinfo can't be used with --add-dyldinfo or --dyldinfo-only");
- llvm::for_each(InputFilenames, dumpSymbolNamesFromFile);
- if (HadError)
- return 1;
- }
|