summaryrefslogtreecommitdiffstats
path: root/tools/llvm-size/llvm-size.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-size/llvm-size.cpp')
-rw-r--r--tools/llvm-size/llvm-size.cpp599
1 files changed, 524 insertions, 75 deletions
diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp
index 58eafd4..50b5220 100644
--- a/tools/llvm-size/llvm-size.cpp
+++ b/tools/llvm-size/llvm-size.cpp
@@ -16,6 +16,8 @@
#include "llvm/ADT/APInt.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/MachOUniversal.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
@@ -25,51 +27,61 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
#include <algorithm>
#include <string>
+#include <system_error>
using namespace llvm;
using namespace object;
-enum OutputFormatTy {berkeley, sysv};
+enum OutputFormatTy { berkeley, sysv, darwin };
static cl::opt<OutputFormatTy>
- OutputFormat("format",
- cl::desc("Specify output format"),
- cl::values(clEnumVal(sysv, "System V format"),
- clEnumVal(berkeley, "Berkeley format"),
- clEnumValEnd),
- cl::init(berkeley));
+OutputFormat("format", cl::desc("Specify output format"),
+ cl::values(clEnumVal(sysv, "System V format"),
+ clEnumVal(berkeley, "Berkeley format"),
+ clEnumVal(darwin, "Darwin -m format"), clEnumValEnd),
+ cl::init(berkeley));
+
+static cl::opt<OutputFormatTy> OutputFormatShort(
+ cl::desc("Specify output format"),
+ cl::values(clEnumValN(sysv, "A", "System V format"),
+ clEnumValN(berkeley, "B", "Berkeley format"),
+ clEnumValN(darwin, "m", "Darwin -m format"), clEnumValEnd),
+ cl::init(berkeley));
+
+static bool berkeleyHeaderPrinted = false;
+static bool moreThanOneFile = false;
+
+cl::opt<bool>
+DarwinLongFormat("l", cl::desc("When format is darwin, use long format "
+ "to include addresses and offsets."));
-static cl::opt<OutputFormatTy>
- OutputFormatShort(cl::desc("Specify output format"),
- cl::values(clEnumValN(sysv, "A", "System V format"),
- clEnumValN(berkeley, "B", "Berkeley format"),
- clEnumValEnd),
- cl::init(berkeley));
+static cl::list<std::string>
+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};
+enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
static cl::opt<unsigned int>
- Radix("-radix",
- cl::desc("Print size in radix. Only 8, 10, and 16 are valid"),
- cl::init(decimal));
+Radix("-radix", cl::desc("Print size in radix. Only 8, 10, and 16 are valid"),
+ cl::init(decimal));
static cl::opt<RadixTy>
- RadixShort(cl::desc("Print size in radix:"),
- cl::values(clEnumValN(octal, "o", "Print size in octal"),
- clEnumValN(decimal, "d", "Print size in decimal"),
- clEnumValN(hexadecimal, "x", "Print size in hexadecimal"),
- clEnumValEnd),
- cl::init(decimal));
+RadixShort(cl::desc("Print size in radix:"),
+ cl::values(clEnumValN(octal, "o", "Print size in octal"),
+ clEnumValN(decimal, "d", "Print size in decimal"),
+ clEnumValN(hexadecimal, "x", "Print size in hexadecimal"),
+ clEnumValEnd),
+ cl::init(decimal));
static cl::list<std::string>
- InputFilenames(cl::Positional, cl::desc("<input files>"),
- cl::ZeroOrMore);
+InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
static std::string ToolName;
/// @brief If ec is not success, print the error and return true.
-static bool error(error_code ec) {
- if (!ec) return false;
+static bool error(std::error_code ec) {
+ if (!ec)
+ return false;
outs() << ToolName << ": error reading file: " << ec.message() << ".\n";
outs().flush();
@@ -85,6 +97,180 @@ static size_t getNumLengthAsString(uint64_t num) {
return result.size();
}
+/// @brief Return the the printing format for the Radix.
+static const char *getRadixFmt(void) {
+ switch (Radix) {
+ case octal:
+ return PRIo64;
+ case decimal:
+ return PRIu64;
+ case hexadecimal:
+ return PRIx64;
+ }
+ return nullptr;
+}
+
+/// @brief Print the size of each Mach-O segment and section in @p MachO.
+///
+/// This is when used when @c OutputFormat is darwin and produces the same
+/// output as darwin's size(1) -m output.
+static void PrintDarwinSectionSizes(MachOObjectFile *MachO) {
+ std::string fmtbuf;
+ raw_string_ostream fmt(fmtbuf);
+ const char *radix_fmt = getRadixFmt();
+ if (Radix == hexadecimal)
+ fmt << "0x";
+ fmt << "%" << radix_fmt;
+
+ uint32_t LoadCommandCount = MachO->getHeader().ncmds;
+ uint32_t Filetype = MachO->getHeader().filetype;
+ MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
+
+ uint64_t total = 0;
+ for (unsigned I = 0;; ++I) {
+ if (Load.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
+ outs() << "Segment " << Seg.segname << ": "
+ << format(fmt.str().c_str(), Seg.vmsize);
+ if (DarwinLongFormat)
+ outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
+ << Seg.fileoff << ")";
+ outs() << "\n";
+ total += Seg.vmsize;
+ uint64_t sec_total = 0;
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section_64 Sec = MachO->getSection64(Load, J);
+ if (Filetype == MachO::MH_OBJECT)
+ outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
+ << format("%.16s", &Sec.sectname) << "): ";
+ else
+ outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
+ outs() << format(fmt.str().c_str(), Sec.size);
+ if (DarwinLongFormat)
+ outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
+ << Sec.offset << ")";
+ outs() << "\n";
+ sec_total += Sec.size;
+ }
+ if (Seg.nsects != 0)
+ outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
+ } else if (Load.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
+ outs() << "Segment " << Seg.segname << ": "
+ << format(fmt.str().c_str(), Seg.vmsize);
+ if (DarwinLongFormat)
+ outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
+ << Seg.fileoff << ")";
+ outs() << "\n";
+ total += Seg.vmsize;
+ uint64_t sec_total = 0;
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section Sec = MachO->getSection(Load, J);
+ if (Filetype == MachO::MH_OBJECT)
+ outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
+ << format("%.16s", &Sec.sectname) << "): ";
+ else
+ outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
+ outs() << format(fmt.str().c_str(), Sec.size);
+ if (DarwinLongFormat)
+ outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
+ << Sec.offset << ")";
+ outs() << "\n";
+ sec_total += Sec.size;
+ }
+ if (Seg.nsects != 0)
+ outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
+ }
+ if (I == LoadCommandCount - 1)
+ break;
+ else
+ Load = MachO->getNextLoadCommandInfo(Load);
+ }
+ outs() << "total " << format(fmt.str().c_str(), total) << "\n";
+}
+
+/// @brief Print the summary sizes of the standard Mach-O segments in @p MachO.
+///
+/// This is when used when @c OutputFormat is berkeley with a Mach-O file and
+/// produces the same output as darwin's size(1) default output.
+static void PrintDarwinSegmentSizes(MachOObjectFile *MachO) {
+ uint32_t LoadCommandCount = MachO->getHeader().ncmds;
+ MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
+
+ uint64_t total_text = 0;
+ uint64_t total_data = 0;
+ uint64_t total_objc = 0;
+ uint64_t total_others = 0;
+ for (unsigned I = 0;; ++I) {
+ if (Load.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
+ if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section_64 Sec = MachO->getSection64(Load, J);
+ StringRef SegmentName = StringRef(Sec.segname);
+ if (SegmentName == "__TEXT")
+ total_text += Sec.size;
+ else if (SegmentName == "__DATA")
+ total_data += Sec.size;
+ else if (SegmentName == "__OBJC")
+ total_objc += Sec.size;
+ else
+ total_others += Sec.size;
+ }
+ } else {
+ StringRef SegmentName = StringRef(Seg.segname);
+ if (SegmentName == "__TEXT")
+ total_text += Seg.vmsize;
+ else if (SegmentName == "__DATA")
+ total_data += Seg.vmsize;
+ else if (SegmentName == "__OBJC")
+ total_objc += Seg.vmsize;
+ else
+ total_others += Seg.vmsize;
+ }
+ } else if (Load.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
+ if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section Sec = MachO->getSection(Load, J);
+ StringRef SegmentName = StringRef(Sec.segname);
+ if (SegmentName == "__TEXT")
+ total_text += Sec.size;
+ else if (SegmentName == "__DATA")
+ total_data += Sec.size;
+ else if (SegmentName == "__OBJC")
+ total_objc += Sec.size;
+ else
+ total_others += Sec.size;
+ }
+ } else {
+ StringRef SegmentName = StringRef(Seg.segname);
+ if (SegmentName == "__TEXT")
+ total_text += Seg.vmsize;
+ else if (SegmentName == "__DATA")
+ total_data += Seg.vmsize;
+ else if (SegmentName == "__OBJC")
+ total_objc += Seg.vmsize;
+ else
+ total_others += Seg.vmsize;
+ }
+ }
+ if (I == LoadCommandCount - 1)
+ break;
+ else
+ Load = MachO->getNextLoadCommandInfo(Load);
+ }
+ uint64_t total = total_text + total_data + total_objc + total_others;
+
+ if (!berkeleyHeaderPrinted) {
+ outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
+ berkeleyHeaderPrinted = true;
+ }
+ outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
+ << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
+ << "\t";
+}
+
/// @brief Print the size of each section in @p Obj.
///
/// The format used is determined by @c OutputFormat and @c Radix.
@@ -92,20 +278,19 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) {
uint64_t total = 0;
std::string fmtbuf;
raw_string_ostream fmt(fmtbuf);
-
- const char *radix_fmt = nullptr;
- switch (Radix) {
- case octal:
- radix_fmt = PRIo64;
- break;
- case decimal:
- radix_fmt = PRIu64;
- break;
- case hexadecimal:
- radix_fmt = PRIx64;
- break;
- }
- if (OutputFormat == sysv) {
+ const char *radix_fmt = getRadixFmt();
+
+ // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
+ // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
+ // let it fall through to OutputFormat berkeley.
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
+ if (OutputFormat == darwin && MachO)
+ PrintDarwinSectionSizes(MachO);
+ // If we have a MachOObjectFile and the OutputFormat is berkeley print as
+ // darwin's default berkeley format for Mach-O files.
+ else if (MachO && OutputFormat == berkeley)
+ PrintDarwinSegmentSizes(MachO);
+ else if (OutputFormat == sysv) {
// Run two passes over all sections. The first gets the lengths needed for
// formatting the output. The second actually does the output.
std::size_t max_name_len = strlen("section");
@@ -139,10 +324,9 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) {
<< "%" << max_addr_len << "s\n";
// Print header
- outs() << format(fmt.str().c_str(),
- static_cast<const char*>("section"),
- static_cast<const char*>("size"),
- static_cast<const char*>("addr"));
+ outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
+ static_cast<const char *>("size"),
+ static_cast<const char *>("addr"));
fmtbuf.clear();
// Setup per section format.
@@ -170,8 +354,7 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) {
fmtbuf.clear();
fmt << "%-" << max_name_len << "s "
<< "%#" << max_size_len << radix_fmt << "\n";
- outs() << format(fmt.str().c_str(),
- static_cast<const char*>("Total"),
+ outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
total);
} else {
// The Berkeley format does not display individual section sizes. It
@@ -204,21 +387,56 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) {
total = total_text + total_data + total_bss;
+ if (!berkeleyHeaderPrinted) {
+ outs() << " text data bss "
+ << (Radix == octal ? "oct" : "dec") << " hex filename\n";
+ berkeleyHeaderPrinted = true;
+ }
+
// Print result.
fmt << "%#7" << radix_fmt << " "
<< "%#7" << radix_fmt << " "
<< "%#7" << radix_fmt << " ";
- outs() << format(fmt.str().c_str(),
- total_text,
- total_data,
- total_bss);
+ outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
fmtbuf.clear();
fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " "
<< "%7" PRIx64 " ";
- outs() << format(fmt.str().c_str(),
- total,
- total);
+ outs() << format(fmt.str().c_str(), total, total);
+ }
+}
+
+/// @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<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) {
+ 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
@@ -228,14 +446,15 @@ static void PrintFileSectionSizes(StringRef file) {
if (file != "-") {
bool exists;
if (sys::fs::exists(file, exists) || !exists) {
- errs() << ToolName << ": '" << file << "': " << "No such file\n";
+ errs() << ToolName << ": '" << file << "': "
+ << "No such file\n";
return;
}
}
// Attempt to open the binary.
ErrorOr<Binary *> BinaryOrErr = createBinary(file);
- if (error_code EC = BinaryOrErr.getError()) {
+ if (std::error_code EC = BinaryOrErr.getError()) {
errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
return;
}
@@ -244,29 +463,250 @@ static void PrintFileSectionSizes(StringRef file) {
if (Archive *a = dyn_cast<Archive>(binary.get())) {
// This is an archive. Iterate over each member and display its sizes.
for (object::Archive::child_iterator i = a->child_begin(),
- e = a->child_end(); i != e; ++i) {
- std::unique_ptr<Binary> child;
- if (error_code ec = i->getAsBinary(child)) {
- errs() << ToolName << ": " << file << ": " << ec.message() << ".\n";
+ e = a->child_end();
+ i != e; ++i) {
+ ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
+ if (std::error_code EC = ChildOrErr.getError()) {
+ errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
continue;
}
- if (ObjectFile *o = dyn_cast<ObjectFile>(child.get())) {
+ if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
+ if (!checkMachOAndArchFlags(o, file))
+ return;
if (OutputFormat == sysv)
- outs() << o->getFileName() << " (ex " << a->getFileName()
- << "):\n";
+ outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n";
+ else if (MachO && OutputFormat == darwin)
+ outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
PrintObjectSectionSizes(o);
- if (OutputFormat == berkeley)
- outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
+ if (OutputFormat == berkeley) {
+ if (MachO)
+ outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
+ else
+ outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
+ }
+ }
+ }
+ } else if (MachOUniversalBinary *UB =
+ dyn_cast<MachOUniversalBinary>(binary.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>> UO = I->getAsObjectFile();
+ std::unique_ptr<Archive> UA;
+ if (UO) {
+ if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(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<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
+ if (std::error_code EC = ChildOrErr.getError()) {
+ errs() << ToolName << ": " << file << ": " << EC.message()
+ << ".\n";
+ continue;
+ }
+ if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(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<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
+ std::unique_ptr<Archive> UA;
+ if (UO) {
+ if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(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<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
+ if (std::error_code EC = ChildOrErr.getError()) {
+ errs() << ToolName << ": " << file << ": " << EC.message()
+ << ".\n";
+ continue;
+ }
+ if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(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();
+ I != E; ++I) {
+ ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
+ std::unique_ptr<Archive> UA;
+ if (UO) {
+ if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
+ if (OutputFormat == sysv)
+ outs() << o->getFileName() << " :\n";
+ else if (MachO && OutputFormat == darwin) {
+ if (moreThanOneFile || moreThanOneArch)
+ outs() << o->getFileName() << " (for architecture "
+ << I->getArchTypeName() << "):";
+ outs() << "\n";
+ }
+ PrintObjectSectionSizes(o);
+ if (OutputFormat == berkeley) {
+ if (!MachO || moreThanOneFile || moreThanOneArch)
+ 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<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
+ if (std::error_code EC = ChildOrErr.getError()) {
+ errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
+ continue;
+ }
+ if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(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() << ")"
+ << " (for architecture " << I->getArchTypeName()
+ << ")\n";
+ else
+ outs() << o->getFileName() << " (ex " << UA->getFileName()
+ << ")\n";
+ }
+ }
+ }
}
}
} else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) {
+ if (!checkMachOAndArchFlags(o, file))
+ return;
if (OutputFormat == sysv)
outs() << o->getFileName() << " :\n";
PrintObjectSectionSizes(o);
- if (OutputFormat == berkeley)
- outs() << o->getFileName() << "\n";
+ if (OutputFormat == berkeley) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
+ if (!MachO || moreThanOneFile)
+ outs() << o->getFileName();
+ outs() << "\n";
+ }
} else {
- errs() << ToolName << ": " << file << ": " << "Unrecognized file type.\n";
+ errs() << ToolName << ": " << file << ": "
+ << "Unrecognized file type.\n";
}
// System V adds an extra newline at the end of each file.
if (OutputFormat == sysv)
@@ -278,7 +718,7 @@ int main(int argc, char **argv) {
sys::PrintStackTraceOnErrorSignal();
PrettyStackTraceProgram X(argc, argv);
- llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
ToolName = argv[0];
@@ -287,14 +727,23 @@ 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");
- if (OutputFormat == berkeley)
- outs() << " text data bss "
- << (Radix == octal ? "oct" : "dec")
- << " hex filename\n";
-
+ moreThanOneFile = InputFilenames.size() > 1;
std::for_each(InputFilenames.begin(), InputFilenames.end(),
PrintFileSectionSizes);