summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Enderby <enderby@apple.com>2014-06-05 21:21:57 +0000
committerKevin Enderby <enderby@apple.com>2014-06-05 21:21:57 +0000
commitecbc72405ea7257f726511e4f4409f8ecc0eb426 (patch)
treeba47fa33e261bba2c6ebdd6aa0d1dc75dcc42ba0
parent542fdf5fba28c7325d901f5af16bb10b5bfe2190 (diff)
downloadllvm-ecbc72405ea7257f726511e4f4409f8ecc0eb426.tar.gz
llvm-ecbc72405ea7257f726511e4f4409f8ecc0eb426.tar.bz2
llvm-ecbc72405ea7257f726511e4f4409f8ecc0eb426.tar.xz
Add "-format darwin" to llvm-nm to be like darwin's nm(1) -m output.
This is a first step in seeing if it is possible to make llvm-nm produce the same output as darwin's nm(1). Darwin's default format is bsd but its -m output prints the longer Mach-O specific details. For now I added the "-format darwin" to do this (whos name may need to change in the future). As there are other Mach-O specific flags to nm(1) which I'm hoping to add some how in the future. But I wanted to see if I could get the correct output for -m flag using llvm-nm and the libObject interfaces. I got this working but would love to hear what others think about this approach to getting object/format specific details printed with llvm-nm. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@210285 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Object/MachO.h14
-rw-r--r--include/llvm/Object/SymbolicFile.h4
-rw-r--r--include/llvm/Support/MachO.h19
-rw-r--r--lib/Object/MachOObjectFile.cpp223
-rw-r--r--test/Object/Inputs/darwin-m-test1.mach0-armv7bin0 -> 432 bytes
-rw-r--r--test/Object/Inputs/darwin-m-test2.macho-i386bin0 -> 88 bytes
-rwxr-xr-xtest/Object/Inputs/darwin-m-test3.macho-x86-64bin0 -> 9216 bytes
-rw-r--r--test/Object/nm-darwin-m.test53
-rw-r--r--tools/llvm-nm/llvm-nm.cpp180
9 files changed, 486 insertions, 7 deletions
diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h
index 710ad7ef15..ab5b462e01 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<uint64_t> &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<const char*, 1> SectionList;
SectionList Sections;
+ typedef SmallVector<const char*, 1> LibraryList;
+ LibraryList Libraries;
+ typedef SmallVector<StringRef, 1> 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 7b90048717..0801f46d56 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 2a0fc7bfe0..60f7918ae7 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 6dca9750c1..1fb0c13407 100644
--- a/lib/Object/MachOObjectFile.cpp
+++ b/lib/Object/MachOObjectFile.cpp
@@ -223,6 +223,16 @@ void SwapStruct(MachO::version_min_command&C) {
}
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);
SwapValue(C.length);
@@ -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<MachO::dylib_command>(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<MachO::dylib_command>(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 0000000000..2ce3a18cfa
--- /dev/null
+++ b/test/Object/Inputs/darwin-m-test1.mach0-armv7
Binary files 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 0000000000..dc0e86525f
--- /dev/null
+++ b/test/Object/Inputs/darwin-m-test2.macho-i386
Binary files 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 0000000000..18960c4f6a
--- /dev/null
+++ b/test/Object/Inputs/darwin-m-test3.macho-x86-64
Binary files differ
diff --git a/test/Object/nm-darwin-m.test b/test/Object/nm-darwin-m.test
new file mode 100644
index 0000000000..6c718128aa
--- /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 476b49486a..0fd43532ed 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<OutputFormatTy> 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<NMSymbol> 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<MachOObjectFile>(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);
}