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

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