Home | History | Annotate | Download | only in llvm-size
      1 //===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This program is a utility that works like traditional Unix "size",
     11 // that is, it prints out the size of each section, and the total size of all
     12 // sections.
     13 //
     14 //===----------------------------------------------------------------------===//
     15 
     16 #include "llvm/ADT/APInt.h"
     17 #include "llvm/Object/Archive.h"
     18 #include "llvm/Object/ELFObjectFile.h"
     19 #include "llvm/Object/MachO.h"
     20 #include "llvm/Object/MachOUniversal.h"
     21 #include "llvm/Object/ObjectFile.h"
     22 #include "llvm/Support/Casting.h"
     23 #include "llvm/Support/CommandLine.h"
     24 #include "llvm/Support/FileSystem.h"
     25 #include "llvm/Support/Format.h"
     26 #include "llvm/Support/InitLLVM.h"
     27 #include "llvm/Support/MemoryBuffer.h"
     28 #include "llvm/Support/raw_ostream.h"
     29 #include <algorithm>
     30 #include <string>
     31 #include <system_error>
     32 
     33 using namespace llvm;
     34 using namespace object;
     35 
     36 enum OutputFormatTy { berkeley, sysv, darwin };
     37 static cl::opt<OutputFormatTy>
     38 OutputFormat("format", cl::desc("Specify output format"),
     39              cl::values(clEnumVal(sysv, "System V format"),
     40                         clEnumVal(berkeley, "Berkeley format"),
     41                         clEnumVal(darwin, "Darwin -m format")),
     42              cl::init(berkeley));
     43 
     44 static cl::opt<OutputFormatTy> OutputFormatShort(
     45     cl::desc("Specify output format"),
     46     cl::values(clEnumValN(sysv, "A", "System V format"),
     47                clEnumValN(berkeley, "B", "Berkeley format"),
     48                clEnumValN(darwin, "m", "Darwin -m format")),
     49     cl::init(berkeley));
     50 
     51 static bool BerkeleyHeaderPrinted = false;
     52 static bool MoreThanOneFile = false;
     53 static uint64_t TotalObjectText = 0;
     54 static uint64_t TotalObjectData = 0;
     55 static uint64_t TotalObjectBss = 0;
     56 static uint64_t TotalObjectTotal = 0;
     57 
     58 cl::opt<bool>
     59 DarwinLongFormat("l", cl::desc("When format is darwin, use long format "
     60                                "to include addresses and offsets."));
     61 
     62 cl::opt<bool>
     63     ELFCommons("common",
     64                cl::desc("Print common symbols in the ELF file.  When using "
     65                         "Berkely format, this is added to bss."),
     66                cl::init(false));
     67 
     68 static cl::list<std::string>
     69 ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
     70           cl::ZeroOrMore);
     71 static bool ArchAll = false;
     72 
     73 enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
     74 static cl::opt<unsigned int>
     75 Radix("radix", cl::desc("Print size in radix. Only 8, 10, and 16 are valid"),
     76       cl::init(decimal));
     77 
     78 static cl::opt<RadixTy>
     79 RadixShort(cl::desc("Print size in radix:"),
     80            cl::values(clEnumValN(octal, "o", "Print size in octal"),
     81                       clEnumValN(decimal, "d", "Print size in decimal"),
     82                       clEnumValN(hexadecimal, "x", "Print size in hexadecimal")),
     83            cl::init(decimal));
     84 
     85 static cl::opt<bool>
     86     TotalSizes("totals",
     87                cl::desc("Print totals of all objects - Berkeley format only"),
     88                cl::init(false));
     89 
     90 static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"),
     91                                  cl::aliasopt(TotalSizes));
     92 
     93 static cl::list<std::string>
     94 InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
     95 
     96 static bool HadError = false;
     97 
     98 static std::string ToolName;
     99 
    100 /// If ec is not success, print the error and return true.
    101 static bool error(std::error_code ec) {
    102   if (!ec)
    103     return false;
    104 
    105   HadError = true;
    106   errs() << ToolName << ": error reading file: " << ec.message() << ".\n";
    107   errs().flush();
    108   return true;
    109 }
    110 
    111 static bool error(Twine Message) {
    112   HadError = true;
    113   errs() << ToolName << ": " << Message << ".\n";
    114   errs().flush();
    115   return true;
    116 }
    117 
    118 // This version of error() prints the archive name and member name, for example:
    119 // "libx.a(foo.o)" after the ToolName before the error message.  It sets
    120 // HadError but returns allowing the code to move on to other archive members.
    121 static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
    122                   StringRef ArchitectureName = StringRef()) {
    123   HadError = true;
    124   errs() << ToolName << ": " << FileName;
    125 
    126   Expected<StringRef> NameOrErr = C.getName();
    127   // TODO: if we have a error getting the name then it would be nice to print
    128   // the index of which archive member this is and or its offset in the
    129   // archive instead of "???" as the name.
    130   if (!NameOrErr) {
    131     consumeError(NameOrErr.takeError());
    132     errs() << "(" << "???" << ")";
    133   } else
    134     errs() << "(" << NameOrErr.get() << ")";
    135 
    136   if (!ArchitectureName.empty())
    137     errs() << " (for architecture " << ArchitectureName << ") ";
    138 
    139   std::string Buf;
    140   raw_string_ostream OS(Buf);
    141   logAllUnhandledErrors(std::move(E), OS, "");
    142   OS.flush();
    143   errs() << " " << Buf << "\n";
    144 }
    145 
    146 // This version of error() prints the file name and which architecture slice it // is from, for example: "foo.o (for architecture i386)" after the ToolName
    147 // before the error message.  It sets HadError but returns allowing the code to
    148 // move on to other architecture slices.
    149 static void error(llvm::Error E, StringRef FileName,
    150                   StringRef ArchitectureName = StringRef()) {
    151   HadError = true;
    152   errs() << ToolName << ": " << FileName;
    153 
    154   if (!ArchitectureName.empty())
    155     errs() << " (for architecture " << ArchitectureName << ") ";
    156 
    157   std::string Buf;
    158   raw_string_ostream OS(Buf);
    159   logAllUnhandledErrors(std::move(E), OS, "");
    160   OS.flush();
    161   errs() << " " << Buf << "\n";
    162 }
    163 
    164 /// Get the length of the string that represents @p num in Radix including the
    165 /// leading 0x or 0 for hexadecimal and octal respectively.
    166 static size_t getNumLengthAsString(uint64_t num) {
    167   APInt conv(64, num);
    168   SmallString<32> result;
    169   conv.toString(result, Radix, false, true);
    170   return result.size();
    171 }
    172 
    173 /// Return the printing format for the Radix.
    174 static const char *getRadixFmt() {
    175   switch (Radix) {
    176   case octal:
    177     return PRIo64;
    178   case decimal:
    179     return PRIu64;
    180   case hexadecimal:
    181     return PRIx64;
    182   }
    183   return nullptr;
    184 }
    185 
    186 /// Remove unneeded ELF sections from calculation
    187 static bool considerForSize(ObjectFile *Obj, SectionRef Section) {
    188   if (!Obj->isELF())
    189     return true;
    190   switch (static_cast<ELFSectionRef>(Section).getType()) {
    191   case ELF::SHT_NULL:
    192   case ELF::SHT_SYMTAB:
    193   case ELF::SHT_STRTAB:
    194   case ELF::SHT_REL:
    195   case ELF::SHT_RELA:
    196     return false;
    197   }
    198   return true;
    199 }
    200 
    201 /// Total size of all ELF common symbols
    202 static uint64_t getCommonSize(ObjectFile *Obj) {
    203   uint64_t TotalCommons = 0;
    204   for (auto &Sym : Obj->symbols())
    205     if (Obj->getSymbolFlags(Sym.getRawDataRefImpl()) & SymbolRef::SF_Common)
    206       TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl());
    207   return TotalCommons;
    208 }
    209 
    210 /// Print the size of each Mach-O segment and section in @p MachO.
    211 ///
    212 /// This is when used when @c OutputFormat is darwin and produces the same
    213 /// output as darwin's size(1) -m output.
    214 static void printDarwinSectionSizes(MachOObjectFile *MachO) {
    215   std::string fmtbuf;
    216   raw_string_ostream fmt(fmtbuf);
    217   const char *radix_fmt = getRadixFmt();
    218   if (Radix == hexadecimal)
    219     fmt << "0x";
    220   fmt << "%" << radix_fmt;
    221 
    222   uint32_t Filetype = MachO->getHeader().filetype;
    223 
    224   uint64_t total = 0;
    225   for (const auto &Load : MachO->load_commands()) {
    226     if (Load.C.cmd == MachO::LC_SEGMENT_64) {
    227       MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
    228       outs() << "Segment " << Seg.segname << ": "
    229              << format(fmt.str().c_str(), Seg.vmsize);
    230       if (DarwinLongFormat)
    231         outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
    232                << Seg.fileoff << ")";
    233       outs() << "\n";
    234       total += Seg.vmsize;
    235       uint64_t sec_total = 0;
    236       for (unsigned J = 0; J < Seg.nsects; ++J) {
    237         MachO::section_64 Sec = MachO->getSection64(Load, J);
    238         if (Filetype == MachO::MH_OBJECT)
    239           outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
    240                  << format("%.16s", &Sec.sectname) << "): ";
    241         else
    242           outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
    243         outs() << format(fmt.str().c_str(), Sec.size);
    244         if (DarwinLongFormat)
    245           outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
    246                  << Sec.offset << ")";
    247         outs() << "\n";
    248         sec_total += Sec.size;
    249       }
    250       if (Seg.nsects != 0)
    251         outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
    252     } else if (Load.C.cmd == MachO::LC_SEGMENT) {
    253       MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
    254       uint64_t Seg_vmsize = Seg.vmsize;
    255       outs() << "Segment " << Seg.segname << ": "
    256              << format(fmt.str().c_str(), Seg_vmsize);
    257       if (DarwinLongFormat)
    258         outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff "
    259                << Seg.fileoff << ")";
    260       outs() << "\n";
    261       total += Seg.vmsize;
    262       uint64_t sec_total = 0;
    263       for (unsigned J = 0; J < Seg.nsects; ++J) {
    264         MachO::section Sec = MachO->getSection(Load, J);
    265         if (Filetype == MachO::MH_OBJECT)
    266           outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
    267                  << format("%.16s", &Sec.sectname) << "): ";
    268         else
    269           outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
    270         uint64_t Sec_size = Sec.size;
    271         outs() << format(fmt.str().c_str(), Sec_size);
    272         if (DarwinLongFormat)
    273           outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset "
    274                  << Sec.offset << ")";
    275         outs() << "\n";
    276         sec_total += Sec.size;
    277       }
    278       if (Seg.nsects != 0)
    279         outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
    280     }
    281   }
    282   outs() << "total " << format(fmt.str().c_str(), total) << "\n";
    283 }
    284 
    285 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
    286 ///
    287 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
    288 /// produces the same output as darwin's size(1) default output.
    289 static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
    290   uint64_t total_text = 0;
    291   uint64_t total_data = 0;
    292   uint64_t total_objc = 0;
    293   uint64_t total_others = 0;
    294   for (const auto &Load : MachO->load_commands()) {
    295     if (Load.C.cmd == MachO::LC_SEGMENT_64) {
    296       MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
    297       if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
    298         for (unsigned J = 0; J < Seg.nsects; ++J) {
    299           MachO::section_64 Sec = MachO->getSection64(Load, J);
    300           StringRef SegmentName = StringRef(Sec.segname);
    301           if (SegmentName == "__TEXT")
    302             total_text += Sec.size;
    303           else if (SegmentName == "__DATA")
    304             total_data += Sec.size;
    305           else if (SegmentName == "__OBJC")
    306             total_objc += Sec.size;
    307           else
    308             total_others += Sec.size;
    309         }
    310       } else {
    311         StringRef SegmentName = StringRef(Seg.segname);
    312         if (SegmentName == "__TEXT")
    313           total_text += Seg.vmsize;
    314         else if (SegmentName == "__DATA")
    315           total_data += Seg.vmsize;
    316         else if (SegmentName == "__OBJC")
    317           total_objc += Seg.vmsize;
    318         else
    319           total_others += Seg.vmsize;
    320       }
    321     } else if (Load.C.cmd == MachO::LC_SEGMENT) {
    322       MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
    323       if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
    324         for (unsigned J = 0; J < Seg.nsects; ++J) {
    325           MachO::section Sec = MachO->getSection(Load, J);
    326           StringRef SegmentName = StringRef(Sec.segname);
    327           if (SegmentName == "__TEXT")
    328             total_text += Sec.size;
    329           else if (SegmentName == "__DATA")
    330             total_data += Sec.size;
    331           else if (SegmentName == "__OBJC")
    332             total_objc += Sec.size;
    333           else
    334             total_others += Sec.size;
    335         }
    336       } else {
    337         StringRef SegmentName = StringRef(Seg.segname);
    338         if (SegmentName == "__TEXT")
    339           total_text += Seg.vmsize;
    340         else if (SegmentName == "__DATA")
    341           total_data += Seg.vmsize;
    342         else if (SegmentName == "__OBJC")
    343           total_objc += Seg.vmsize;
    344         else
    345           total_others += Seg.vmsize;
    346       }
    347     }
    348   }
    349   uint64_t total = total_text + total_data + total_objc + total_others;
    350 
    351   if (!BerkeleyHeaderPrinted) {
    352     outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
    353     BerkeleyHeaderPrinted = true;
    354   }
    355   outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
    356          << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
    357          << "\t";
    358 }
    359 
    360 /// Print the size of each section in @p Obj.
    361 ///
    362 /// The format used is determined by @c OutputFormat and @c Radix.
    363 static void printObjectSectionSizes(ObjectFile *Obj) {
    364   uint64_t total = 0;
    365   std::string fmtbuf;
    366   raw_string_ostream fmt(fmtbuf);
    367   const char *radix_fmt = getRadixFmt();
    368 
    369   // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
    370   // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
    371   // let it fall through to OutputFormat berkeley.
    372   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
    373   if (OutputFormat == darwin && MachO)
    374     printDarwinSectionSizes(MachO);
    375   // If we have a MachOObjectFile and the OutputFormat is berkeley print as
    376   // darwin's default berkeley format for Mach-O files.
    377   else if (MachO && OutputFormat == berkeley)
    378     printDarwinSegmentSizes(MachO);
    379   else if (OutputFormat == sysv) {
    380     // Run two passes over all sections. The first gets the lengths needed for
    381     // formatting the output. The second actually does the output.
    382     std::size_t max_name_len = strlen("section");
    383     std::size_t max_size_len = strlen("size");
    384     std::size_t max_addr_len = strlen("addr");
    385     for (const SectionRef &Section : Obj->sections()) {
    386       if (!considerForSize(Obj, Section))
    387         continue;
    388       uint64_t size = Section.getSize();
    389       total += size;
    390 
    391       StringRef name;
    392       if (error(Section.getName(name)))
    393         return;
    394       uint64_t addr = Section.getAddress();
    395       max_name_len = std::max(max_name_len, name.size());
    396       max_size_len = std::max(max_size_len, getNumLengthAsString(size));
    397       max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
    398     }
    399 
    400     // Add extra padding.
    401     max_name_len += 2;
    402     max_size_len += 2;
    403     max_addr_len += 2;
    404 
    405     // Setup header format.
    406     fmt << "%-" << max_name_len << "s "
    407         << "%" << max_size_len << "s "
    408         << "%" << max_addr_len << "s\n";
    409 
    410     // Print header
    411     outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
    412                      static_cast<const char *>("size"),
    413                      static_cast<const char *>("addr"));
    414     fmtbuf.clear();
    415 
    416     // Setup per section format.
    417     fmt << "%-" << max_name_len << "s "
    418         << "%#" << max_size_len << radix_fmt << " "
    419         << "%#" << max_addr_len << radix_fmt << "\n";
    420 
    421     // Print each section.
    422     for (const SectionRef &Section : Obj->sections()) {
    423       if (!considerForSize(Obj, Section))
    424         continue;
    425       StringRef name;
    426       if (error(Section.getName(name)))
    427         return;
    428       uint64_t size = Section.getSize();
    429       uint64_t addr = Section.getAddress();
    430       std::string namestr = name;
    431 
    432       outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr);
    433     }
    434 
    435     if (ELFCommons) {
    436       uint64_t CommonSize = getCommonSize(Obj);
    437       total += CommonSize;
    438       outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(),
    439                        CommonSize, static_cast<uint64_t>(0));
    440     }
    441 
    442     // Print total.
    443     fmtbuf.clear();
    444     fmt << "%-" << max_name_len << "s "
    445         << "%#" << max_size_len << radix_fmt << "\n";
    446     outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
    447                      total);
    448   } else {
    449     // The Berkeley format does not display individual section sizes. It
    450     // displays the cumulative size for each section type.
    451     uint64_t total_text = 0;
    452     uint64_t total_data = 0;
    453     uint64_t total_bss = 0;
    454 
    455     // Make one pass over the section table to calculate sizes.
    456     for (const SectionRef &Section : Obj->sections()) {
    457       uint64_t size = Section.getSize();
    458       bool isText = Section.isText();
    459       bool isData = Section.isData();
    460       bool isBSS = Section.isBSS();
    461       if (isText)
    462         total_text += size;
    463       else if (isData)
    464         total_data += size;
    465       else if (isBSS)
    466         total_bss += size;
    467     }
    468 
    469     if (ELFCommons)
    470       total_bss += getCommonSize(Obj);
    471 
    472     total = total_text + total_data + total_bss;
    473 
    474     if (TotalSizes) {
    475       TotalObjectText += total_text;
    476       TotalObjectData += total_data;
    477       TotalObjectBss += total_bss;
    478       TotalObjectTotal += total;
    479     }
    480 
    481     if (!BerkeleyHeaderPrinted) {
    482       outs() << "   text    data     bss     "
    483              << (Radix == octal ? "oct" : "dec") << "     hex filename\n";
    484       BerkeleyHeaderPrinted = true;
    485     }
    486 
    487     // Print result.
    488     fmt << "%#7" << radix_fmt << " "
    489         << "%#7" << radix_fmt << " "
    490         << "%#7" << radix_fmt << " ";
    491     outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
    492     fmtbuf.clear();
    493     fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " "
    494         << "%7" PRIx64 " ";
    495     outs() << format(fmt.str().c_str(), total, total);
    496   }
    497 }
    498 
    499 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
    500 /// is a list of architecture flags specified then check to make sure this
    501 /// Mach-O file is one of those architectures or all architectures was
    502 /// specificed.  If not then an error is generated and this routine returns
    503 /// false.  Else it returns true.
    504 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
    505   auto *MachO = dyn_cast<MachOObjectFile>(O);
    506 
    507   if (!MachO || ArchAll || ArchFlags.empty())
    508     return true;
    509 
    510   MachO::mach_header H;
    511   MachO::mach_header_64 H_64;
    512   Triple T;
    513   if (MachO->is64Bit()) {
    514     H_64 = MachO->MachOObjectFile::getHeader64();
    515     T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
    516   } else {
    517     H = MachO->MachOObjectFile::getHeader();
    518     T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
    519   }
    520   if (none_of(ArchFlags, [&](const std::string &Name) {
    521         return Name == T.getArchName();
    522       })) {
    523     error(Filename + ": No architecture specified");
    524     return false;
    525   }
    526   return true;
    527 }
    528 
    529 /// Print the section sizes for @p file. If @p file is an archive, print the
    530 /// section sizes for each archive member.
    531 static void printFileSectionSizes(StringRef file) {
    532 
    533   // Attempt to open the binary.
    534   Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
    535   if (!BinaryOrErr) {
    536     error(BinaryOrErr.takeError(), file);
    537     return;
    538   }
    539   Binary &Bin = *BinaryOrErr.get().getBinary();
    540 
    541   if (Archive *a = dyn_cast<Archive>(&Bin)) {
    542     // This is an archive. Iterate over each member and display its sizes.
    543     Error Err = Error::success();
    544     for (auto &C : a->children(Err)) {
    545       Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
    546       if (!ChildOrErr) {
    547         if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
    548           error(std::move(E), a->getFileName(), C);
    549         continue;
    550       }
    551       if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
    552         MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    553         if (!checkMachOAndArchFlags(o, file))
    554           return;
    555         if (OutputFormat == sysv)
    556           outs() << o->getFileName() << "   (ex " << a->getFileName() << "):\n";
    557         else if (MachO && OutputFormat == darwin)
    558           outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
    559         printObjectSectionSizes(o);
    560         if (OutputFormat == berkeley) {
    561           if (MachO)
    562             outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
    563           else
    564             outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
    565         }
    566       }
    567     }
    568     if (Err)
    569       error(std::move(Err), a->getFileName());
    570   } else if (MachOUniversalBinary *UB =
    571                  dyn_cast<MachOUniversalBinary>(&Bin)) {
    572     // If we have a list of architecture flags specified dump only those.
    573     if (!ArchAll && ArchFlags.size() != 0) {
    574       // Look for a slice in the universal binary that matches each ArchFlag.
    575       bool ArchFound;
    576       for (unsigned i = 0; i < ArchFlags.size(); ++i) {
    577         ArchFound = false;
    578         for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
    579                                                    E = UB->end_objects();
    580              I != E; ++I) {
    581           if (ArchFlags[i] == I->getArchFlagName()) {
    582             ArchFound = true;
    583             Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
    584             if (UO) {
    585               if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
    586                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    587                 if (OutputFormat == sysv)
    588                   outs() << o->getFileName() << "  :\n";
    589                 else if (MachO && OutputFormat == darwin) {
    590                   if (MoreThanOneFile || ArchFlags.size() > 1)
    591                     outs() << o->getFileName() << " (for architecture "
    592                            << I->getArchFlagName() << "): \n";
    593                 }
    594                 printObjectSectionSizes(o);
    595                 if (OutputFormat == berkeley) {
    596                   if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
    597                     outs() << o->getFileName() << " (for architecture "
    598                            << I->getArchFlagName() << ")";
    599                   outs() << "\n";
    600                 }
    601               }
    602             } else if (auto E = isNotObjectErrorInvalidFileType(
    603                        UO.takeError())) {
    604               error(std::move(E), file, ArchFlags.size() > 1 ?
    605                     StringRef(I->getArchFlagName()) : StringRef());
    606               return;
    607             } else if (Expected<std::unique_ptr<Archive>> AOrErr =
    608                            I->getAsArchive()) {
    609               std::unique_ptr<Archive> &UA = *AOrErr;
    610               // This is an archive. Iterate over each member and display its
    611               // sizes.
    612               Error Err = Error::success();
    613               for (auto &C : UA->children(Err)) {
    614                 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
    615                 if (!ChildOrErr) {
    616                   if (auto E = isNotObjectErrorInvalidFileType(
    617                                     ChildOrErr.takeError()))
    618                     error(std::move(E), UA->getFileName(), C,
    619                           ArchFlags.size() > 1 ?
    620                           StringRef(I->getArchFlagName()) : StringRef());
    621                   continue;
    622                 }
    623                 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
    624                   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    625                   if (OutputFormat == sysv)
    626                     outs() << o->getFileName() << "   (ex " << UA->getFileName()
    627                            << "):\n";
    628                   else if (MachO && OutputFormat == darwin)
    629                     outs() << UA->getFileName() << "(" << o->getFileName()
    630                            << ")"
    631                            << " (for architecture " << I->getArchFlagName()
    632                            << "):\n";
    633                   printObjectSectionSizes(o);
    634                   if (OutputFormat == berkeley) {
    635                     if (MachO) {
    636                       outs() << UA->getFileName() << "(" << o->getFileName()
    637                              << ")";
    638                       if (ArchFlags.size() > 1)
    639                         outs() << " (for architecture " << I->getArchFlagName()
    640                                << ")";
    641                       outs() << "\n";
    642                     } else
    643                       outs() << o->getFileName() << " (ex " << UA->getFileName()
    644                              << ")\n";
    645                   }
    646                 }
    647               }
    648               if (Err)
    649                 error(std::move(Err), UA->getFileName());
    650             } else {
    651               consumeError(AOrErr.takeError());
    652               error("Mach-O universal file: " + file + " for architecture " +
    653                     StringRef(I->getArchFlagName()) +
    654                     " is not a Mach-O file or an archive file");
    655             }
    656           }
    657         }
    658         if (!ArchFound) {
    659           errs() << ToolName << ": file: " << file
    660                  << " does not contain architecture" << ArchFlags[i] << ".\n";
    661           return;
    662         }
    663       }
    664       return;
    665     }
    666     // No architecture flags were specified so if this contains a slice that
    667     // matches the host architecture dump only that.
    668     if (!ArchAll) {
    669       StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
    670       for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
    671                                                  E = UB->end_objects();
    672            I != E; ++I) {
    673         if (HostArchName == I->getArchFlagName()) {
    674           Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
    675           if (UO) {
    676             if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
    677               MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    678               if (OutputFormat == sysv)
    679                 outs() << o->getFileName() << "  :\n";
    680               else if (MachO && OutputFormat == darwin) {
    681                 if (MoreThanOneFile)
    682                   outs() << o->getFileName() << " (for architecture "
    683                          << I->getArchFlagName() << "):\n";
    684               }
    685               printObjectSectionSizes(o);
    686               if (OutputFormat == berkeley) {
    687                 if (!MachO || MoreThanOneFile)
    688                   outs() << o->getFileName() << " (for architecture "
    689                          << I->getArchFlagName() << ")";
    690                 outs() << "\n";
    691               }
    692             }
    693           } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
    694             error(std::move(E), file);
    695             return;
    696           } else if (Expected<std::unique_ptr<Archive>> AOrErr =
    697                          I->getAsArchive()) {
    698             std::unique_ptr<Archive> &UA = *AOrErr;
    699             // This is an archive. Iterate over each member and display its
    700             // sizes.
    701             Error Err = Error::success();
    702             for (auto &C : UA->children(Err)) {
    703               Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
    704               if (!ChildOrErr) {
    705                 if (auto E = isNotObjectErrorInvalidFileType(
    706                                 ChildOrErr.takeError()))
    707                   error(std::move(E), UA->getFileName(), C);
    708                 continue;
    709               }
    710               if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
    711                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    712                 if (OutputFormat == sysv)
    713                   outs() << o->getFileName() << "   (ex " << UA->getFileName()
    714                          << "):\n";
    715                 else if (MachO && OutputFormat == darwin)
    716                   outs() << UA->getFileName() << "(" << o->getFileName() << ")"
    717                          << " (for architecture " << I->getArchFlagName()
    718                          << "):\n";
    719                 printObjectSectionSizes(o);
    720                 if (OutputFormat == berkeley) {
    721                   if (MachO)
    722                     outs() << UA->getFileName() << "(" << o->getFileName()
    723                            << ")\n";
    724                   else
    725                     outs() << o->getFileName() << " (ex " << UA->getFileName()
    726                            << ")\n";
    727                 }
    728               }
    729             }
    730             if (Err)
    731               error(std::move(Err), UA->getFileName());
    732           } else {
    733             consumeError(AOrErr.takeError());
    734             error("Mach-O universal file: " + file + " for architecture " +
    735                    StringRef(I->getArchFlagName()) +
    736                    " is not a Mach-O file or an archive file");
    737           }
    738           return;
    739         }
    740       }
    741     }
    742     // Either all architectures have been specified or none have been specified
    743     // and this does not contain the host architecture so dump all the slices.
    744     bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
    745     for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
    746                                                E = UB->end_objects();
    747          I != E; ++I) {
    748       Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
    749       if (UO) {
    750         if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
    751           MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    752           if (OutputFormat == sysv)
    753             outs() << o->getFileName() << "  :\n";
    754           else if (MachO && OutputFormat == darwin) {
    755             if (MoreThanOneFile || MoreThanOneArch)
    756               outs() << o->getFileName() << " (for architecture "
    757                      << I->getArchFlagName() << "):";
    758             outs() << "\n";
    759           }
    760           printObjectSectionSizes(o);
    761           if (OutputFormat == berkeley) {
    762             if (!MachO || MoreThanOneFile || MoreThanOneArch)
    763               outs() << o->getFileName() << " (for architecture "
    764                      << I->getArchFlagName() << ")";
    765             outs() << "\n";
    766           }
    767         }
    768       } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
    769         error(std::move(E), file, MoreThanOneArch ?
    770               StringRef(I->getArchFlagName()) : StringRef());
    771         return;
    772       } else if (Expected<std::unique_ptr<Archive>> AOrErr =
    773                          I->getAsArchive()) {
    774         std::unique_ptr<Archive> &UA = *AOrErr;
    775         // This is an archive. Iterate over each member and display its sizes.
    776         Error Err = Error::success();
    777         for (auto &C : UA->children(Err)) {
    778           Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
    779           if (!ChildOrErr) {
    780             if (auto E = isNotObjectErrorInvalidFileType(
    781                               ChildOrErr.takeError()))
    782               error(std::move(E), UA->getFileName(), C, MoreThanOneArch ?
    783                     StringRef(I->getArchFlagName()) : StringRef());
    784             continue;
    785           }
    786           if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
    787             MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    788             if (OutputFormat == sysv)
    789               outs() << o->getFileName() << "   (ex " << UA->getFileName()
    790                      << "):\n";
    791             else if (MachO && OutputFormat == darwin)
    792               outs() << UA->getFileName() << "(" << o->getFileName() << ")"
    793                      << " (for architecture " << I->getArchFlagName() << "):\n";
    794             printObjectSectionSizes(o);
    795             if (OutputFormat == berkeley) {
    796               if (MachO)
    797                 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
    798                        << " (for architecture " << I->getArchFlagName()
    799                        << ")\n";
    800               else
    801                 outs() << o->getFileName() << " (ex " << UA->getFileName()
    802                        << ")\n";
    803             }
    804           }
    805         }
    806         if (Err)
    807           error(std::move(Err), UA->getFileName());
    808       } else {
    809         consumeError(AOrErr.takeError());
    810         error("Mach-O universal file: " + file + " for architecture " +
    811                StringRef(I->getArchFlagName()) +
    812                " is not a Mach-O file or an archive file");
    813       }
    814     }
    815   } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
    816     if (!checkMachOAndArchFlags(o, file))
    817       return;
    818     MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    819     if (OutputFormat == sysv)
    820       outs() << o->getFileName() << "  :\n";
    821     else if (MachO && OutputFormat == darwin && MoreThanOneFile)
    822       outs() << o->getFileName() << ":\n";
    823     printObjectSectionSizes(o);
    824     if (OutputFormat == berkeley) {
    825       if (!MachO || MoreThanOneFile)
    826         outs() << o->getFileName();
    827       outs() << "\n";
    828     }
    829   } else {
    830     errs() << ToolName << ": " << file << ": "
    831            << "Unrecognized file type.\n";
    832   }
    833   // System V adds an extra newline at the end of each file.
    834   if (OutputFormat == sysv)
    835     outs() << "\n";
    836 }
    837 
    838 static void printBerkelyTotals() {
    839   std::string fmtbuf;
    840   raw_string_ostream fmt(fmtbuf);
    841   const char *radix_fmt = getRadixFmt();
    842   fmt << "%#7" << radix_fmt << " "
    843       << "%#7" << radix_fmt << " "
    844       << "%#7" << radix_fmt << " ";
    845   outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData,
    846                    TotalObjectBss);
    847   fmtbuf.clear();
    848   fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " "
    849       << "%7" PRIx64 " ";
    850   outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal)
    851          << "(TOTALS)\n";
    852 }
    853 
    854 int main(int argc, char **argv) {
    855   InitLLVM X(argc, argv);
    856   cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
    857 
    858   ToolName = argv[0];
    859   if (OutputFormatShort.getNumOccurrences())
    860     OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
    861   if (RadixShort.getNumOccurrences())
    862     Radix = RadixShort;
    863 
    864   for (unsigned i = 0; i < ArchFlags.size(); ++i) {
    865     if (ArchFlags[i] == "all") {
    866       ArchAll = true;
    867     } else {
    868       if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
    869         outs() << ToolName << ": for the -arch option: Unknown architecture "
    870                << "named '" << ArchFlags[i] << "'";
    871         return 1;
    872       }
    873     }
    874   }
    875 
    876   if (InputFilenames.size() == 0)
    877     InputFilenames.push_back("a.out");
    878 
    879   MoreThanOneFile = InputFilenames.size() > 1;
    880   llvm::for_each(InputFilenames, printFileSectionSizes);
    881   if (OutputFormat == berkeley && TotalSizes)
    882     printBerkelyTotals();
    883 
    884   if (HadError)
    885     return 1;
    886 }
    887