From adaa88ecc571c6ae3ed68be894348fff3e88d647 Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Tue, 1 Jul 2014 17:19:10 +0000 Subject: [PATCH] Add the -arch flag support to llvm-size like what was done to llvm-nm to select the slice out of a Mach-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@212108 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/Object/size-trivial-macho.test | 14 +- tools/llvm-size/llvm-size.cpp | 209 +++++++++++++++++++++++++++- 2 files changed, 219 insertions(+), 4 deletions(-) diff --git a/test/Object/size-trivial-macho.test b/test/Object/size-trivial-macho.test index 1642790c2c7..a6d3d1c4330 100644 --- a/test/Object/size-trivial-macho.test +++ b/test/Object/size-trivial-macho.test @@ -10,10 +10,14 @@ RUN: llvm-size -format darwin %p/Inputs/macho-archive-x86_64.a \ RUN: | FileCheck %s -check-prefix mAR RUN: llvm-size -m -x -l %p/Inputs/hello-world.macho-x86_64 \ RUN: | FileCheck %s -check-prefix mxl -RUN: llvm-size %p/Inputs/macho-universal.x86_64.i386 \ +RUN: llvm-size -arch all %p/Inputs/macho-universal.x86_64.i386 \ RUN: | FileCheck %s -check-prefix u -RUN: llvm-size %p/Inputs/macho-universal-archive.x86_64.i386 \ +RUN: llvm-size -arch i386 %p/Inputs/macho-universal.x86_64.i386 \ +RUN: | FileCheck %s -check-prefix u-i386 +RUN: llvm-size -arch all %p/Inputs/macho-universal-archive.x86_64.i386 \ RUN: | FileCheck %s -check-prefix uAR +RUN: llvm-size -arch x86_64 %p/Inputs/macho-universal-archive.x86_64.i386 \ +RUN: | FileCheck %s -check-prefix uAR-x86_64 A: section size addr A: __text 12 0 @@ -74,6 +78,12 @@ u: __TEXT __DATA __OBJC others dec hex u: 4096 0 0 4294971392 4294975488 100002000 {{.*}}/macho-universal.x86_64.i386 (for architecture x86_64) u: 4096 0 0 8192 12288 3000 {{.*}}/macho-universal.x86_64.i386 (for architecture i386) +u-i386: __TEXT __DATA __OBJC others dec hex +u-i386: 4096 0 0 8192 12288 3000 + uAR: __TEXT __DATA __OBJC others dec hex uAR: 136 0 0 32 168 a8 {{.*}}/macho-universal-archive.x86_64.i386(hello.o) (for architecture x86_64) uAR: 5 4 0 0 9 9 {{.*}}/macho-universal-archive.x86_64.i386(foo.o) (for architecture i386) + +uAR-x86_64: __TEXT __DATA __OBJC others dec hex +uAR-x86_64: 136 0 0 32 168 a8 {{.*}}/macho-universal-archive.x86_64.i386(hello.o) diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp index 48614d8176b..bc4d0d41228 100644 --- a/tools/llvm-size/llvm-size.cpp +++ b/tools/llvm-size/llvm-size.cpp @@ -57,6 +57,12 @@ cl::opt DarwinLongFormat("l", cl::desc("When format is darwin, use long format " "to include addresses and offsets.")); +static cl::list + ArchFlags("arch", + cl::desc("architecture(s) from a Mach-O file to dump"), + cl::ZeroOrMore); +bool ArchAll = false; + enum RadixTy {octal = 8, decimal = 10, hexadecimal = 16}; static cl::opt Radix("-radix", @@ -413,6 +419,40 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) { } } +/// @brief Checks to see if the @p o ObjectFile is a Mach-O file and if it is +/// and there is a list of architecture flags 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(ObjectFile *o, StringRef file) { + if (isa(o) && !ArchAll && ArchFlags.size() != 0) { + MachOObjectFile *MachO = dyn_cast(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) { + errs() << ToolName << ": file: " << file + << " does not contain architecture: " << ArchFlags[i] << ".\n"; + return false; + } + } + return true; +} + /// @brief Print the section sizes for @p file. If @p file is an archive, print /// the section sizes for each archive member. static void PrintFileSectionSizes(StringRef file) { @@ -444,6 +484,8 @@ static void PrintFileSectionSizes(StringRef file) { } if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { MachOObjectFile *MachO = dyn_cast(o); + if (!checkMachOAndArchFlags(o, file)) + return; if (OutputFormat == sysv) outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n"; @@ -460,8 +502,155 @@ static void PrintFileSectionSizes(StringRef file) { } } else if (MachOUniversalBinary *UB = dyn_cast(binary.get())) { - // This is a Mach-O universal binary. Iterate over each object and - // display its sizes. + // 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> UO = I->getAsObjectFile(); + std::unique_ptr UA; + if (UO) { + if (ObjectFile *o = dyn_cast(&*UO.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if(MachO && OutputFormat == darwin) { + if (moreThanOneFile || ArchFlags.size() > 1) + outs() << o->getFileName() << " (for architecture " + << I->getArchTypeName() << "): \n"; + } + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || moreThanOneFile || ArchFlags.size() > 1) + outs() << o->getFileName() << " (for architecture " + << I->getArchTypeName() << ")"; + outs() << "\n"; + } + } + } + else if (!I->getAsArchive(UA)) { + // This is an archive. Iterate over each member and display its + //sizes. + for (object::Archive::child_iterator i = UA->child_begin(), + e = UA->child_end(); + i != e; ++i) { + ErrorOr> ChildOrErr = i->getAsBinary(); + if (std::error_code EC = ChildOrErr.getError()) { + errs() << ToolName << ": " << file << ": " << EC.message() + << ".\n"; + continue; + } + if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << UA->getFileName() + << "):\n"; + else if(MachO && OutputFormat == darwin) + outs() << UA->getFileName() << "(" << o->getFileName() + << ")" << " (for architecture " + << I->getArchTypeName() << "):\n"; + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) { + outs() << UA->getFileName() << "(" << o->getFileName() + << ")"; + if (ArchFlags.size() > 1) + outs() << " (for architecture " + << I->getArchTypeName() << ")"; + outs() << "\n"; + } + else + outs() << o->getFileName() << " (ex " << UA->getFileName() + << ")\n"; + } + } + } + } + } + } + if (!ArchFound) { + errs() << ToolName << ": file: " << file + << " does not contain architecture" << ArchFlags[i] << ".\n"; + 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> UO = I->getAsObjectFile(); + std::unique_ptr UA; + if (UO) { + if (ObjectFile *o = dyn_cast(&*UO.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if(MachO && OutputFormat == darwin) { + if (moreThanOneFile) + outs() << o->getFileName() << " (for architecture " + << I->getArchTypeName() << "):\n"; + } + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || moreThanOneFile) + outs() << o->getFileName() << " (for architecture " + << I->getArchTypeName() << ")"; + outs() << "\n"; + } + } + } + else if (!I->getAsArchive(UA)) { + // This is an archive. Iterate over each member and display its + // sizes. + for (object::Archive::child_iterator i = UA->child_begin(), + e = UA->child_end(); + i != e; ++i) { + ErrorOr> ChildOrErr = i->getAsBinary(); + if (std::error_code EC = ChildOrErr.getError()) { + errs() << ToolName << ": " << file << ": " << EC.message() + << ".\n"; + continue; + } + if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << UA->getFileName() + << "):\n"; + else if(MachO && OutputFormat == darwin) + outs() << UA->getFileName() << "(" << o->getFileName() << ")" + << " (for architecture " << I->getArchTypeName() + << "):\n"; + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) + outs() << UA->getFileName() << "(" << o->getFileName() + << ")\n"; + else + outs() << o->getFileName() << " (ex " << UA->getFileName() + << ")\n"; + } + } + } + } + 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(); @@ -521,6 +710,8 @@ static void PrintFileSectionSizes(StringRef file) { } } } else if (ObjectFile *o = dyn_cast(binary.get())) { + if (!checkMachOAndArchFlags(o, file)) + return; if (OutputFormat == sysv) outs() << o->getFileName() << " :\n"; PrintObjectSectionSizes(o); @@ -552,6 +743,20 @@ int main(int argc, char **argv) { if (RadixShort.getNumOccurrences()) Radix = RadixShort; + 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){ + outs() << ToolName << ": for the -arch option: Unknown architecture " + << "named '" << ArchFlags[i] << "'"; + return 1; + } + } + } + if (InputFilenames.size() == 0) InputFilenames.push_back("a.out"); -- 2.34.1