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
This commit is contained in:
Kevin Enderby 2014-06-05 21:21:57 +00:00
parent 542fdf5fba
commit ecbc72405e
9 changed files with 486 additions and 7 deletions

View File

@ -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;

View File

@ -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)
};

View File

@ -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 {

View File

@ -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<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);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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)

View File

@ -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);
}