Skip to content

Commit

Permalink
Add the -arch flag support to llvm-nm to select the slice out of a Ma…
Browse files Browse the repository at this point in the history
…ch-O

universal file.  This also includes support for -arch all, selecting the host
architecture by default from a universal file and checking if -arch is used
with a standard Mach-O it matches that architecture.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212054 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
enderby committed Jun 30, 2014
1 parent 97fb702 commit c28eff1
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 5 deletions.
3 changes: 3 additions & 0 deletions include/llvm/Object/MachO.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ class MachOObjectFile : public ObjectFile {
StringRef &Suffix);

static Triple::ArchType getArch(uint32_t CPUType);
static Triple getArch(uint32_t CPUType, uint32_t CPUSubType);
static Triple getArch(StringRef ArchFlag);
static Triple getHostArch();

static bool classof(const Binary *v) {
return v->isMachO();
Expand Down
3 changes: 2 additions & 1 deletion include/llvm/Object/MachOUniversal.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ class MachOUniversalBinary : public Binary {
ObjectForArch getNext() const { return ObjectForArch(Parent, Index + 1); }
uint32_t getCPUType() const { return Header.cputype; }
std::string getArchTypeName() const {
return Triple::getArchTypeName(MachOObjectFile::getArch(Header.cputype));
Triple T = MachOObjectFile::getArch(Header.cputype, Header.cpusubtype);
return T.getArchName();
}

ErrorOr<std::unique_ptr<ObjectFile>> getAsObjectFile() const;
Expand Down
4 changes: 2 additions & 2 deletions include/llvm/Support/MachO.h
Original file line number Diff line number Diff line change
Expand Up @@ -1015,8 +1015,8 @@ namespace llvm {

enum : uint32_t {
// Capability bits used in the definition of cpusubtype.
CPU_SUB_TYPE_MASK = 0xff000000, // Mask for architecture bits
CPU_SUB_TYPE_LIB64 = 0x80000000, // 64 bit libraries
CPU_SUBTYPE_MASK = 0xff000000, // Mask for architecture bits
CPU_SUBTYPE_LIB64 = 0x80000000, // 64 bit libraries

// Special CPU subtype constants.
CPU_SUBTYPE_MULTIPLE = ~0u
Expand Down
102 changes: 102 additions & 0 deletions lib/Object/MachOObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1511,6 +1511,108 @@ Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) {
}
}

Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) {
switch (CPUType) {
case MachO::CPU_TYPE_I386:
switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
case MachO::CPU_SUBTYPE_I386_ALL:
return Triple("i386-apple-darwin");
default:
return Triple();
}
case MachO::CPU_TYPE_X86_64:
switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
case MachO::CPU_SUBTYPE_X86_64_ALL:
return Triple("x86_64-apple-darwin");
case MachO::CPU_SUBTYPE_X86_64_H:
return Triple("x86_64h-apple-darwin");
default:
return Triple();
}
case MachO::CPU_TYPE_ARM:
switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
case MachO::CPU_SUBTYPE_ARM_V4T:
return Triple("armv4t-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V5TEJ:
return Triple("armv5e-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V6:
return Triple("armv6-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V6M:
return Triple("armv6m-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7EM:
return Triple("armv7em-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7K:
return Triple("armv7k-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7M:
return Triple("armv7m-apple-darwin");
case MachO::CPU_SUBTYPE_ARM_V7S:
return Triple("armv7s-apple-darwin");
default:
return Triple();
}
case MachO::CPU_TYPE_ARM64:
switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
case MachO::CPU_SUBTYPE_ARM64_ALL:
return Triple("arm64-apple-darwin");
default:
return Triple();
}
case MachO::CPU_TYPE_POWERPC:
switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
case MachO::CPU_SUBTYPE_POWERPC_ALL:
return Triple("ppc-apple-darwin");
default:
return Triple();
}
case MachO::CPU_TYPE_POWERPC64:
case MachO::CPU_SUBTYPE_POWERPC_ALL:
return Triple("ppc64-apple-darwin");
switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
default:
return Triple();
}
default:
return Triple();
}
}

Triple MachOObjectFile::getHostArch() {
return Triple(sys::getDefaultTargetTriple());
}

Triple MachOObjectFile::getArch(StringRef ArchFlag) {
if (ArchFlag == "i386")
return Triple("i386-apple-darwin");
else if (ArchFlag == "x86_64")
return Triple("x86_64-apple-darwin");
else if (ArchFlag == "x86_64h")
return Triple("x86_64h-apple-darwin");
else if (ArchFlag == "armv4t" || ArchFlag == "arm")
return Triple("armv4t-apple-darwin");
else if (ArchFlag == "armv5e")
return Triple("armv5e-apple-darwin");
else if (ArchFlag == "armv6")
return Triple("armv6-apple-darwin");
else if (ArchFlag == "armv6m")
return Triple("armv6m-apple-darwin");
else if (ArchFlag == "armv7em")
return Triple("armv7em-apple-darwin");
else if (ArchFlag == "armv7k")
return Triple("armv7k-apple-darwin");
else if (ArchFlag == "armv7k")
return Triple("armv7m-apple-darwin");
else if (ArchFlag == "armv7s")
return Triple("armv7s-apple-darwin");
else if (ArchFlag == "arm64")
return Triple("arm64-apple-darwin");
else if (ArchFlag == "ppc")
return Triple("ppc-apple-darwin");
else if (ArchFlag == "ppc64")
return Triple("ppc64-apple-darwin");
else
return Triple();
}

unsigned MachOObjectFile::getArch() const {
return getArch(getCPUType(this));
}
Expand Down
16 changes: 14 additions & 2 deletions test/Object/nm-universal-binary.test
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
RUN: llvm-nm %p/Inputs/macho-universal.x86_64.i386 \
RUN: llvm-nm -arch all %p/Inputs/macho-universal.x86_64.i386 \
RUN: | FileCheck %s -check-prefix CHECK-OBJ
RUN: llvm-nm %p/Inputs/macho-universal-archive.x86_64.i386 \
RUN: llvm-nm -arch x86_64 %p/Inputs/macho-universal.x86_64.i386 \
RUN: | FileCheck %s -check-prefix CHECK-OBJ-x86_64
RUN: llvm-nm -arch all %p/Inputs/macho-universal-archive.x86_64.i386 \
RUN: | FileCheck %s -check-prefix CHECK-AR
RUN: llvm-nm -arch i386 %p/Inputs/macho-universal-archive.x86_64.i386 \
RUN: | FileCheck %s -check-prefix CHECK-AR-i386

CHECK-OBJ: macho-universal.x86_64.i386 (for architecture x86_64):
CHECK-OBJ: 0000000100000f60 T _main
CHECK-OBJ: macho-universal.x86_64.i386 (for architecture i386):
CHECK-OBJ: 00001fa0 T _main

CHECK-OBJ-x86_64: 0000000100000000 T __mh_execute_header
CHECK-OBJ-x86_64: 0000000100000f60 T _main
CHECK-OBJ-x86_64: U dyld_stub_binder

CHECK-AR: macho-universal-archive.x86_64.i386(hello.o) (for architecture x86_64):
CHECK-AR: 0000000000000068 s EH_frame0
CHECK-AR: 000000000000003b s L_.str
Expand All @@ -17,3 +25,7 @@ CHECK-AR: U _printf
CHECK-AR: macho-universal-archive.x86_64.i386(foo.o) (for architecture i386):
CHECK-AR: 00000008 D _bar
CHECK-AR: 00000000 T _foo

CHECK-AR-i386: macho-universal-archive.x86_64.i386(foo.o):
CHECK-AR-i386: 00000008 D _bar
CHECK-AR-i386: 00000000 T _foo
147 changes: 147 additions & 0 deletions tools/llvm-nm/llvm-nm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd"));
cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix"));
cl::opt<bool> DarwinFormat("m", cl::desc("Alias for --format=darwin"));

static cl::list<std::string> ArchFlags("arch",
cl::desc("architecture(s) from a Mach-O file to dump"),
cl::ZeroOrMore);
bool ArchAll = false;

cl::opt<bool> PrintFileName(
"print-file-name",
cl::desc("Precede each symbol with the object file it came from"));
Expand Down Expand Up @@ -720,6 +725,40 @@ static void dumpSymbolNamesFromObject(SymbolicFile *Obj, bool printName) {
sortAndPrintSymbolList(Obj, printName);
}

// 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) {
if (isa<MachOObjectFile>(O) && !ArchAll && ArchFlags.size() != 0) {
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O);
bool ArchFound = false;
MachO::mach_header H;
MachO::mach_header_64 H_64;
Triple T;
if (MachO->is64Bit()) {
H_64 = MachO->MachOObjectFile::getHeader64();
T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype);
} else {
H = MachO->MachOObjectFile::getHeader();
T = MachOObjectFile::getArch(H.cputype, H.cpusubtype);
}
unsigned i;
for (i = 0; i < ArchFlags.size(); ++i){
if (ArchFlags[i] == T.getArchName())
ArchFound = true;
break;
}
if (!ArchFound) {
error(ArchFlags[i],
"file: " + Filename + " does not contain architecture");
return false;
}
}
return true;
}

static void dumpSymbolNamesFromFile(std::string &Filename) {
std::unique_ptr<MemoryBuffer> Buffer;
if (error(MemoryBuffer::getFileOrSTDIN(Filename, Buffer), Filename))
Expand Down Expand Up @@ -758,6 +797,8 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
if (ChildOrErr.getError())
continue;
if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
if (!checkMachOAndArchFlags(O, Filename))
return;
outs() << "\n";
if (isa<MachOObjectFile>(O)) {
outs() << Filename << "(" << O->getFileName() << ")";
Expand All @@ -770,6 +811,98 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
return;
}
if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin.get())) {
// If we have a list of architecture flags specified dump only those.
if (!ArchAll && ArchFlags.size() != 0) {
// 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->getArchTypeName()){
ArchFound = true;
ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr =
I->getAsObjectFile();
std::unique_ptr<Archive> A;
if (ObjOrErr) {
std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get());
if (ArchFlags.size() > 1) {
outs() << "\n" << Obj->getFileName()
<< " (for architecture " << I->getArchTypeName() << ")"
<< ":\n";
}
dumpSymbolNamesFromObject(Obj.get(), false);
}
else if (!I->getAsArchive(A)) {
for (Archive::child_iterator AI = A->child_begin(),
AE = A->child_end();
AI != AE; ++AI) {
ErrorOr<std::unique_ptr<Binary>> ChildOrErr =
AI->getAsBinary(&Context);
if (ChildOrErr.getError())
continue;
if (SymbolicFile *O = dyn_cast<SymbolicFile>
(&*ChildOrErr.get())) {
outs() << "\n" << A->getFileName();
outs() << "(" << O->getFileName() << ")";
if (ArchFlags.size() > 1) {
outs() << " (for architecture " << I->getArchTypeName()
<< ")";
}
outs() << ":\n";
dumpSymbolNamesFromObject(O, false);
}
}
}
}
}
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) {
StringRef HostArchName =
MachOObjectFile::getHostArch().getArchName();
for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
E = UB->end_objects();
I != E; ++I) {
if (HostArchName == I->getArchTypeName()){
ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr =
I->getAsObjectFile();
std::unique_ptr<Archive> A;
if (ObjOrErr) {
std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get());
dumpSymbolNamesFromObject(Obj.get(), false);
}
else if (!I->getAsArchive(A)) {
for (Archive::child_iterator AI = A->child_begin(),
AE = A->child_end();
AI != AE; ++AI) {
ErrorOr<std::unique_ptr<Binary>> ChildOrErr =
AI->getAsBinary(&Context);
if (ChildOrErr.getError())
continue;
if (SymbolicFile *O = dyn_cast<SymbolicFile>
(&*ChildOrErr.get())) {
outs() << "\n" << A->getFileName()
<< "(" << O->getFileName() << ")" << ":\n";
dumpSymbolNamesFromObject(O, false);
}
}
}
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 (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
E = UB->end_objects();
Expand Down Expand Up @@ -810,6 +943,8 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
return;
}
if (SymbolicFile *O = dyn_cast<SymbolicFile>(Bin.get())) {
if (!checkMachOAndArchFlags(O, Filename))
return;
dumpSymbolNamesFromObject(O, true);
return;
}
Expand Down Expand Up @@ -854,6 +989,18 @@ int main(int argc, char **argv) {
MultipleFiles = true;
}

for (unsigned i = 0; i < ArchFlags.size(); ++i){
if (ArchFlags[i] == "all") {
ArchAll = true;
}
else {
Triple T = MachOObjectFile::getArch(ArchFlags[i]);
if (T.getArch() == Triple::UnknownArch)
error("Unknown architecture named '" + ArchFlags[i] + "'",
"for the -arch option");
}
}

std::for_each(InputFilenames.begin(), InputFilenames.end(),
dumpSymbolNamesFromFile);

Expand Down

0 comments on commit c28eff1

Please sign in to comment.