diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index 710ad7ef156..ab5b462e01e 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -61,6 +61,10 @@ public: void moveSymbolNext(DataRefImpl &Symb) const override; error_code getSymbolName(DataRefImpl Symb, StringRef &Res) const override; + + // MachO specific. + error_code getIndirectName(DataRefImpl Symb, StringRef &Res) const; + error_code getSymbolAddress(DataRefImpl Symb, uint64_t &Res) const override; error_code getSymbolAlignment(DataRefImpl Symb, uint32_t &Res) const override; error_code getSymbolSize(DataRefImpl Symb, uint64_t &Res) const override; @@ -105,6 +109,9 @@ public: LibraryRef &Res) const override; error_code getLibraryPath(DataRefImpl LibData, StringRef &Res) const override; + // MachO specific. + error_code getLibraryShortNameByIndex(unsigned Index, StringRef &Res); + // TODO: Would be useful to have an iterator based version // of the load command interface too. @@ -198,6 +205,9 @@ public: bool is64Bit() const; void ReadULEB128s(uint64_t Index, SmallVectorImpl &Out) const; + static StringRef guessLibraryShortName(StringRef Name, bool &isFramework, + StringRef &Suffix); + static Triple::ArchType getArch(uint32_t CPUType); static bool classof(const Binary *v) { @@ -207,6 +217,10 @@ public: private: typedef SmallVector SectionList; SectionList Sections; + typedef SmallVector LibraryList; + LibraryList Libraries; + typedef SmallVector LibraryShortName; + LibraryShortName LibrariesShortNames; const char *SymtabLoadCmd; const char *DysymtabLoadCmd; const char *DataInCodeLoadCmd; diff --git a/include/llvm/Object/SymbolicFile.h b/include/llvm/Object/SymbolicFile.h index 7b900487171..0801f46d560 100644 --- a/include/llvm/Object/SymbolicFile.h +++ b/include/llvm/Object/SymbolicFile.h @@ -86,8 +86,8 @@ public: SF_Weak = 1U << 2, // Weak symbol SF_Absolute = 1U << 3, // Absolute symbol SF_Common = 1U << 4, // Symbol has common linkage - SF_Indirect = 1U << 5, - SF_FormatSpecific = 1U << 5 // Specific to the object file format + SF_Indirect = 1U << 5, // Symbol is an alias to another symbol + SF_FormatSpecific = 1U << 6 // Specific to the object file format // (e.g. section symbols) }; diff --git a/include/llvm/Support/MachO.h b/include/llvm/Support/MachO.h index 2a0fc7bfe06..60f7918ae72 100644 --- a/include/llvm/Support/MachO.h +++ b/include/llvm/Support/MachO.h @@ -360,11 +360,28 @@ namespace llvm { enum { // Constant masks for the "n_desc" field in llvm::MachO::nlist and // llvm::MachO::nlist_64 + // The low 3 bits are the for the REFERENCE_TYPE. + REFERENCE_TYPE = 0x7, + REFERENCE_FLAG_UNDEFINED_NON_LAZY = 0, + REFERENCE_FLAG_UNDEFINED_LAZY = 1, + REFERENCE_FLAG_DEFINED = 2, + REFERENCE_FLAG_PRIVATE_DEFINED = 3, + REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY = 4, + REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY = 5, + // Flag bits (some overlap with the library ordinal bits). N_ARM_THUMB_DEF = 0x0008u, + REFERENCED_DYNAMICALLY = 0x0010u, N_NO_DEAD_STRIP = 0x0020u, N_WEAK_REF = 0x0040u, N_WEAK_DEF = 0x0080u, - N_SYMBOL_RESOLVER = 0x0100u + N_SYMBOL_RESOLVER = 0x0100u, + N_ALT_ENTRY = 0x0200u, + // For undefined symbols coming from libraries, see GET_LIBRARY_ORDINAL() + // as these are in the top 8 bits. + SELF_LIBRARY_ORDINAL = 0x0, + MAX_LIBRARY_ORDINAL = 0xfd, + DYNAMIC_LOOKUP_ORDINAL = 0xfe, + EXECUTABLE_ORDINAL = 0xff }; enum StabType { diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 6dca9750c16..1fb0c134073 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -222,6 +222,16 @@ void SwapStruct(MachO::version_min_command&C) { SwapValue(C.reserved); } +template<> +void SwapStruct(MachO::dylib_command&C) { + SwapValue(C.cmd); + SwapValue(C.cmdsize); + SwapValue(C.dylib.name); + SwapValue(C.dylib.timestamp); + SwapValue(C.dylib.current_version); + SwapValue(C.dylib.compatibility_version); +} + template<> void SwapStruct(MachO::data_in_code_entry &C) { SwapValue(C.offset); @@ -443,6 +453,12 @@ MachOObjectFile::MachOObjectFile(MemoryBuffer *Object, bool IsLittleEndian, const char *Sec = getSectionPtr(this, Load, J); Sections.push_back(Sec); } + } else if (Load.C.cmd == MachO::LC_LOAD_DYLIB || + Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB || + Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB || + Load.C.cmd == MachO::LC_REEXPORT_DYLIB || + Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) { + Libraries.push_back(Load.Ptr); } if (I == LoadCommandCount - 1) @@ -468,6 +484,30 @@ error_code MachOObjectFile::getSymbolName(DataRefImpl Symb, return object_error::success; } +// getIndirectName() returns the name of the alias'ed symbol who's string table +// index is in the n_value field. +error_code MachOObjectFile::getIndirectName(DataRefImpl Symb, + StringRef &Res) const { + StringRef StringTable = getStringTableData(); + uint64_t NValue; + if (is64Bit()) { + MachO::nlist_64 Entry = getSymbol64TableEntry(Symb); + NValue = Entry.n_value; + if ((Entry.n_type & MachO::N_TYPE) != MachO::N_INDR) + return object_error::parse_failed; + } else { + MachO::nlist Entry = getSymbolTableEntry(Symb); + NValue = Entry.n_value; + if ((Entry.n_type & MachO::N_TYPE) != MachO::N_INDR) + return object_error::parse_failed; + } + if (NValue >= StringTable.size()) + return object_error::parse_failed; + const char *Start = &StringTable.data()[NValue]; + Res = StringRef(Start); + return object_error::success; +} + error_code MachOObjectFile::getSymbolAddress(DataRefImpl Symb, uint64_t &Res) const { if (is64Bit()) { @@ -1180,6 +1220,189 @@ error_code MachOObjectFile::getLibraryPath(DataRefImpl LibData, report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); } +// +// guessLibraryShortName() is passed a name of a dynamic library and returns a +// guess on what the short name is. Then name is returned as a substring of the +// StringRef Name passed in. The name of the dynamic library is recognized as +// a framework if it has one of the two following forms: +// Foo.framework/Versions/A/Foo +// Foo.framework/Foo +// Where A and Foo can be any string. And may contain a trailing suffix +// starting with an underbar. If the Name is recognized as a framework then +// isFramework is set to true else it is set to false. If the Name has a +// suffix then Suffix is set to the substring in Name that contains the suffix +// else it is set to a NULL StringRef. +// +// The Name of the dynamic library is recognized as a library name if it has +// one of the two following forms: +// libFoo.A.dylib +// libFoo.dylib +// The library may have a suffix trailing the name Foo of the form: +// libFoo_profile.A.dylib +// libFoo_profile.dylib +// +// The Name of the dynamic library is also recognized as a library name if it +// has the following form: +// Foo.qtx +// +// If the Name of the dynamic library is none of the forms above then a NULL +// StringRef is returned. +// +StringRef MachOObjectFile::guessLibraryShortName(StringRef Name, + bool &isFramework, + StringRef &Suffix) { + StringRef Foo, F, DotFramework, V, Dylib, Lib, Dot, Qtx; + size_t a, b, c, d, Idx; + + isFramework = false; + Suffix = StringRef(); + + // Pull off the last component and make Foo point to it + a = Name.rfind('/'); + if (a == Name.npos || a == 0) + goto guess_library; + Foo = Name.slice(a+1, Name.npos); + + // Look for a suffix starting with a '_' + Idx = Foo.rfind('_'); + if (Idx != Foo.npos && Foo.size() >= 2) { + Suffix = Foo.slice(Idx, Foo.npos); + Foo = Foo.slice(0, Idx); + } + + // First look for the form Foo.framework/Foo + b = Name.rfind('/', a); + if (b == Name.npos) + Idx = 0; + else + Idx = b+1; + F = Name.slice(Idx, Idx + Foo.size()); + DotFramework = Name.slice(Idx + Foo.size(), + Idx + Foo.size() + sizeof(".framework/")-1); + if (F == Foo && DotFramework == ".framework/") { + isFramework = true; + return Foo; + } + + // Next look for the form Foo.framework/Versions/A/Foo + if (b == Name.npos) + goto guess_library; + c = Name.rfind('/', b); + if (c == Name.npos || c == 0) + goto guess_library; + V = Name.slice(c+1, Name.npos); + if (!V.startswith("Versions/")) + goto guess_library; + d = Name.rfind('/', c); + if (d == Name.npos) + Idx = 0; + else + Idx = d+1; + F = Name.slice(Idx, Idx + Foo.size()); + DotFramework = Name.slice(Idx + Foo.size(), + Idx + Foo.size() + sizeof(".framework/")-1); + if (F == Foo && DotFramework == ".framework/") { + isFramework = true; + return Foo; + } + +guess_library: + // pull off the suffix after the "." and make a point to it + a = Name.rfind('.'); + if (a == Name.npos || a == 0) + return StringRef(); + Dylib = Name.slice(a, Name.npos); + if (Dylib != ".dylib") + goto guess_qtx; + + // First pull off the version letter for the form Foo.A.dylib if any. + if (a >= 3) { + Dot = Name.slice(a-2, a-1); + if (Dot == ".") + a = a - 2; + } + + b = Name.rfind('/', a); + if (b == Name.npos) + b = 0; + else + b = b+1; + // ignore any suffix after an underbar like Foo_profile.A.dylib + Idx = Name.find('_', b); + if (Idx != Name.npos && Idx != b) { + Lib = Name.slice(b, Idx); + Suffix = Name.slice(Idx, a); + } + else + Lib = Name.slice(b, a); + // There are incorrect library names of the form: + // libATS.A_profile.dylib so check for these. + if (Lib.size() >= 3) { + Dot = Lib.slice(Lib.size()-2, Lib.size()-1); + if (Dot == ".") + Lib = Lib.slice(0, Lib.size()-2); + } + return Lib; + +guess_qtx: + Qtx = Name.slice(a, Name.npos); + if (Qtx != ".qtx") + return StringRef(); + b = Name.rfind('/', a); + if (b == Name.npos) + Lib = Name.slice(0, a); + else + Lib = Name.slice(b+1, a); + // There are library names of the form: QT.A.qtx so check for these. + if (Lib.size() >= 3) { + Dot = Lib.slice(Lib.size()-2, Lib.size()-1); + if (Dot == ".") + Lib = Lib.slice(0, Lib.size()-2); + } + return Lib; +} + +// getLibraryShortNameByIndex() is used to get the short name of the library +// for an undefined symbol in a linked Mach-O binary that was linked with the +// normal two-level namespace default (that is MH_TWOLEVEL in the header). +// It is passed the index (0 - based) of the library as translated from +// GET_LIBRARY_ORDINAL (1 - based). +error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index, + StringRef &Res) { + if (Index >= Libraries.size()) + return object_error::parse_failed; + + MachO::dylib_command D = + getStruct(this, Libraries[Index]); + if (D.dylib.name >= D.cmdsize) + return object_error::parse_failed; + + // If the cache of LibrariesShortNames is not built up do that first for + // all the Libraries. + if (LibrariesShortNames.size() == 0) { + for (unsigned i = 0; i < Libraries.size(); i++) { + MachO::dylib_command D = + getStruct(this, Libraries[i]); + if (D.dylib.name >= D.cmdsize) { + LibrariesShortNames.push_back(StringRef()); + continue; + } + char *P = (char *)(Libraries[i]) + D.dylib.name; + StringRef Name = StringRef(P); + StringRef Suffix; + bool isFramework; + StringRef shortName = guessLibraryShortName(Name, isFramework, Suffix); + if (shortName == StringRef()) + LibrariesShortNames.push_back(Name); + else + LibrariesShortNames.push_back(shortName); + } + } + + Res = LibrariesShortNames[Index]; + return object_error::success; +} + basic_symbol_iterator MachOObjectFile::symbol_begin_impl() const { return getSymbolByIndex(0); } diff --git a/test/Object/Inputs/darwin-m-test1.mach0-armv7 b/test/Object/Inputs/darwin-m-test1.mach0-armv7 new file mode 100644 index 00000000000..2ce3a18cfa7 Binary files /dev/null and b/test/Object/Inputs/darwin-m-test1.mach0-armv7 differ diff --git a/test/Object/Inputs/darwin-m-test2.macho-i386 b/test/Object/Inputs/darwin-m-test2.macho-i386 new file mode 100644 index 00000000000..dc0e86525f4 Binary files /dev/null and b/test/Object/Inputs/darwin-m-test2.macho-i386 differ diff --git a/test/Object/Inputs/darwin-m-test3.macho-x86-64 b/test/Object/Inputs/darwin-m-test3.macho-x86-64 new file mode 100755 index 00000000000..18960c4f6aa Binary files /dev/null and b/test/Object/Inputs/darwin-m-test3.macho-x86-64 differ diff --git a/test/Object/nm-darwin-m.test b/test/Object/nm-darwin-m.test new file mode 100644 index 00000000000..6c718128aa6 --- /dev/null +++ b/test/Object/nm-darwin-m.test @@ -0,0 +1,53 @@ +RUN: llvm-nm -format darwin %p/Inputs/darwin-m-test1.mach0-armv7 \ +RUN: | FileCheck %s -check-prefix test1 +RUN: llvm-nm -format darwin %p/Inputs/darwin-m-test2.macho-i386 \ +RUN: | FileCheck %s -check-prefix test2 +RUN: llvm-nm -format darwin %p/Inputs/darwin-m-test3.macho-x86-64 \ +RUN: | FileCheck %s -check-prefix test3 + +# This is testing that the various bits in the n_desc feild are correct +test1: 00000001 (absolute) non-external _a +test1: 00000008 (common) (alignment 2^2) external _c +test1: 0000000a (__DATA,__data) non-external [no dead strip] _d +test1: 00000004 (__TEXT,__text) non-external [alt entry] _e +test1: 00000000 (__TEXT,__text) non-external [symbol resolver] _r +test1: 00000008 (__TEXT,__text) non-external [Thumb] _t + +# This is testing that an N_INDR symbol gets its alias name, the "(for ...)" +test2: (undefined) external __i +test2: (indirect) external _i (for __i) + +# This is testing is using darwin-m-test3.macho-x86-64 that is linked with +# dylibs that have the follow set of -install_names: +# Foo.framework/Foo +# /System/Library/Frameworks/FooPath.framework/FooPath +# FooSuffix.framework/FooSuffix_debug +# /System/Library/Frameworks/FooPathSuffix.framework/FooPathSuffix_profile +# FooVers.framework/Versions/A/FooVers +# /System/Library/Frameworks/FooPathVers.framework/Versions/B/FooPathVers +# libx.dylib +# libxSuffix_profile.dylib +# /usr/local/lib/libxPathSuffix_debug.dylib +# libATS.A_profile.dylib +# /usr/lib/libPathATS.A_profile.dylib +# QT.A.qtx +# /lib/QTPath.qtx +# /usr/lib/libSystem.B.dylib +# to test that MachOObjectFile::guessLibraryShortName() is correctly parsing +# them into their short names. +test3: 0000000100000000 (__TEXT,__text) [referenced dynamically] external __mh_execute_header +test3: (undefined) external _atsPathVersSuffix (from libPathATS) +test3: (undefined) external _atsVersSuffix (from libATS) +test3: (undefined) external _foo (from Foo) +test3: (undefined) external _fooPath (from FooPath) +test3: (undefined) external _fooPathSuffix (from FooPathSuffix) +test3: (undefined) external _fooPathVers (from FooPathVers) +test3: (undefined) external _fooSuffix (from FooSuffix) +test3: (undefined) external _fooVers (from FooVers) +test3: 0000000100000e60 (__TEXT,__text) external _main +test3: (undefined) external _qt (from QT) +test3: (undefined) external _qtPath (from QTPath) +test3: (undefined) external _x (from libx) +test3: (undefined) external _xPathSuffix (from libxPathSuffix) +test3: (undefined) external _xSuffix (from libxSuffix) +test3: (undefined) external dyld_stub_binder (from libSystem) diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 476b49486ae..0fd43532ed1 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -47,11 +47,12 @@ using namespace llvm; using namespace object; namespace { -enum OutputFormatTy { bsd, sysv, posix }; +enum OutputFormatTy { bsd, sysv, posix, darwin }; cl::opt OutputFormat( "format", cl::desc("Specify output format"), cl::values(clEnumVal(bsd, "BSD format"), clEnumVal(sysv, "System V format"), - clEnumVal(posix, "POSIX.2 format"), clEnumValEnd), + clEnumVal(posix, "POSIX.2 format"), + clEnumVal(darwin, "Darwin -m format"), clEnumValEnd), cl::init(bsd)); cl::alias OutputFormat2("f", cl::desc("Alias for --format"), cl::aliasopt(OutputFormat)); @@ -145,6 +146,7 @@ struct NMSymbol { uint64_t Size; char TypeChar; StringRef Name; + DataRefImpl Symb; }; } @@ -204,6 +206,169 @@ static StringRef CurrentFilename; typedef std::vector SymbolListT; static SymbolListT SymbolList; +// darwinPrintSymbol() is used to print a symbol from a Mach-O file when the +// the OutputFormat is darwin. It produces the same output as darwin's nm(1) -m +// output. +static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I, + char *SymbolAddrStr, const char *printBlanks) { + MachO::mach_header H; + MachO::mach_header_64 H_64; + uint32_t Filetype, Flags; + MachO::nlist_64 STE_64; + MachO::nlist STE; + uint8_t NType; + uint16_t NDesc; + uint64_t NValue; + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + Filetype = H_64.filetype; + Flags = H_64.flags; + STE_64 = MachO->getSymbol64TableEntry(I->Symb); + NType = STE_64.n_type; + NDesc = STE_64.n_desc; + NValue = STE_64.n_value; + } else { + H = MachO->MachOObjectFile::getHeader(); + Filetype = H.filetype; + Flags = H.flags; + STE = MachO->getSymbolTableEntry(I->Symb); + NType = STE.n_type; + NDesc = STE.n_desc; + NValue = STE.n_value; + } + + if (PrintAddress) { + if ((NType & MachO::N_TYPE) == MachO::N_INDR) + strcpy(SymbolAddrStr, printBlanks); + 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_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: { + section_iterator Sec = MachO->section_end(); + MachO->getSymbolSection(I->Symb, Sec); + DataRefImpl Ref = Sec->getRawDataRefImpl(); + StringRef SectionName; + MachO->getSectionName(Ref, SectionName); + 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 && + (NDesc & MachO::N_NO_DEAD_STRIP) == MachO::N_NO_DEAD_STRIP) + outs() << "[no dead strip] "; + + if (Filetype == MachO::MH_OBJECT && + ((NType & MachO::N_TYPE) != MachO::N_UNDF) && + (NDesc & MachO::N_SYMBOL_RESOLVER) == MachO::N_SYMBOL_RESOLVER) + outs() << "[symbol resolver] "; + + if (Filetype == MachO::MH_OBJECT && + ((NType & MachO::N_TYPE) != MachO::N_UNDF) && + (NDesc & MachO::N_ALT_ENTRY) == MachO::N_ALT_ENTRY) + outs() << "[alt entry] "; + + if ((NDesc & MachO::N_ARM_THUMB_DEF) == MachO::N_ARM_THUMB_DEF) + outs() << "[Thumb] "; + + if ((NType & MachO::N_TYPE) == MachO::N_INDR) { + outs() << I->Name << " (for "; + StringRef IndirectName; + if (MachO->getIndirectName(I->Symb, IndirectName)) + outs() << "?)"; + else + outs() << IndirectName << ")"; + } + else + outs() << I->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->getLibraryShortNameByIndex(LibraryOrdinal - 1, + LibraryName)) + outs() << " (from bad library ordinal " << + LibraryOrdinal << ")"; + else + outs() << " (from " << LibraryName << ")"; + } + } + } + + outs() << "\n"; +} + static void sortAndPrintSymbolList(SymbolicFile *Obj) { if (!NoSort) { if (NumericSort) @@ -256,10 +421,16 @@ static void sortAndPrintSymbolList(SymbolicFile *Obj) { if (I->Size != UnknownAddressOrSize) format(printFormat, I->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr)); - if (OutputFormat == posix) { + // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's + // nm(1) -m output, else if OutputFormat is darwin and not a Mach-O object + // fall back to OutputFormat bsd (see below). + MachOObjectFile *MachO = dyn_cast(Obj); + if (OutputFormat == darwin && MachO) { + darwinPrintSymbol(MachO, I, SymbolAddrStr, printBlanks); + } else if (OutputFormat == posix) { outs() << I->Name << " " << I->TypeChar << " " << SymbolAddrStr << SymbolSizeStr << "\n"; - } else if (OutputFormat == bsd) { + } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) { if (PrintAddress) outs() << SymbolAddrStr << ' '; if (PrintSize) { @@ -529,6 +700,7 @@ static void dumpSymbolNamesFromObject(SymbolicFile *Obj) { if (error(I->printName(OS))) break; OS << '\0'; + S.Symb = I->getRawDataRefImpl(); SymbolList.push_back(S); }