Home | History | Annotate | Download | only in llvm-size
      1 //===-- llvm-size.cpp - Print the size of each object section -------------===//
      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/ObjectFile.h"
     19 #include "llvm/Object/MachO.h"
     20 #include "llvm/Object/MachOUniversal.h"
     21 #include "llvm/Support/Casting.h"
     22 #include "llvm/Support/CommandLine.h"
     23 #include "llvm/Support/FileSystem.h"
     24 #include "llvm/Support/Format.h"
     25 #include "llvm/Support/ManagedStatic.h"
     26 #include "llvm/Support/MemoryBuffer.h"
     27 #include "llvm/Support/PrettyStackTrace.h"
     28 #include "llvm/Support/Signals.h"
     29 #include "llvm/Support/raw_ostream.h"
     30 #include <algorithm>
     31 #include <string>
     32 #include <system_error>
     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"), clEnumValEnd),
     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"), clEnumValEnd),
     49     cl::init(berkeley));
     50 
     51 static bool berkeleyHeaderPrinted = false;
     52 static bool moreThanOneFile = false;
     53 
     54 cl::opt<bool>
     55 DarwinLongFormat("l", cl::desc("When format is darwin, use long format "
     56                                "to include addresses and offsets."));
     57 
     58 static cl::list<std::string>
     59 ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
     60           cl::ZeroOrMore);
     61 bool ArchAll = false;
     62 
     63 enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
     64 static cl::opt<unsigned int>
     65 Radix("-radix", cl::desc("Print size in radix. Only 8, 10, and 16 are valid"),
     66       cl::init(decimal));
     67 
     68 static cl::opt<RadixTy>
     69 RadixShort(cl::desc("Print size in radix:"),
     70            cl::values(clEnumValN(octal, "o", "Print size in octal"),
     71                       clEnumValN(decimal, "d", "Print size in decimal"),
     72                       clEnumValN(hexadecimal, "x", "Print size in hexadecimal"),
     73                       clEnumValEnd),
     74            cl::init(decimal));
     75 
     76 static cl::list<std::string>
     77 InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
     78 
     79 static std::string ToolName;
     80 
     81 ///  @brief If ec is not success, print the error and return true.
     82 static bool error(std::error_code ec) {
     83   if (!ec)
     84     return false;
     85 
     86   outs() << ToolName << ": error reading file: " << ec.message() << ".\n";
     87   outs().flush();
     88   return true;
     89 }
     90 
     91 /// @brief Get the length of the string that represents @p num in Radix
     92 ///        including the leading 0x or 0 for hexadecimal and octal respectively.
     93 static size_t getNumLengthAsString(uint64_t num) {
     94   APInt conv(64, num);
     95   SmallString<32> result;
     96   conv.toString(result, Radix, false, true);
     97   return result.size();
     98 }
     99 
    100 /// @brief Return the the printing format for the Radix.
    101 static const char *getRadixFmt(void) {
    102   switch (Radix) {
    103   case octal:
    104     return PRIo64;
    105   case decimal:
    106     return PRIu64;
    107   case hexadecimal:
    108     return PRIx64;
    109   }
    110   return nullptr;
    111 }
    112 
    113 /// @brief Print the size of each Mach-O segment and section in @p MachO.
    114 ///
    115 /// This is when used when @c OutputFormat is darwin and produces the same
    116 /// output as darwin's size(1) -m output.
    117 static void PrintDarwinSectionSizes(MachOObjectFile *MachO) {
    118   std::string fmtbuf;
    119   raw_string_ostream fmt(fmtbuf);
    120   const char *radix_fmt = getRadixFmt();
    121   if (Radix == hexadecimal)
    122     fmt << "0x";
    123   fmt << "%" << radix_fmt;
    124 
    125   uint32_t LoadCommandCount = MachO->getHeader().ncmds;
    126   uint32_t Filetype = MachO->getHeader().filetype;
    127   MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
    128 
    129   uint64_t total = 0;
    130   for (unsigned I = 0;; ++I) {
    131     if (Load.C.cmd == MachO::LC_SEGMENT_64) {
    132       MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
    133       outs() << "Segment " << Seg.segname << ": "
    134              << format(fmt.str().c_str(), Seg.vmsize);
    135       if (DarwinLongFormat)
    136         outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
    137                << Seg.fileoff << ")";
    138       outs() << "\n";
    139       total += Seg.vmsize;
    140       uint64_t sec_total = 0;
    141       for (unsigned J = 0; J < Seg.nsects; ++J) {
    142         MachO::section_64 Sec = MachO->getSection64(Load, J);
    143         if (Filetype == MachO::MH_OBJECT)
    144           outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
    145                  << format("%.16s", &Sec.sectname) << "): ";
    146         else
    147           outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
    148         outs() << format(fmt.str().c_str(), Sec.size);
    149         if (DarwinLongFormat)
    150           outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
    151                  << Sec.offset << ")";
    152         outs() << "\n";
    153         sec_total += Sec.size;
    154       }
    155       if (Seg.nsects != 0)
    156         outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
    157     } else if (Load.C.cmd == MachO::LC_SEGMENT) {
    158       MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
    159       outs() << "Segment " << Seg.segname << ": "
    160              << format(fmt.str().c_str(), Seg.vmsize);
    161       if (DarwinLongFormat)
    162         outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
    163                << Seg.fileoff << ")";
    164       outs() << "\n";
    165       total += Seg.vmsize;
    166       uint64_t sec_total = 0;
    167       for (unsigned J = 0; J < Seg.nsects; ++J) {
    168         MachO::section Sec = MachO->getSection(Load, J);
    169         if (Filetype == MachO::MH_OBJECT)
    170           outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
    171                  << format("%.16s", &Sec.sectname) << "): ";
    172         else
    173           outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
    174         outs() << format(fmt.str().c_str(), Sec.size);
    175         if (DarwinLongFormat)
    176           outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
    177                  << Sec.offset << ")";
    178         outs() << "\n";
    179         sec_total += Sec.size;
    180       }
    181       if (Seg.nsects != 0)
    182         outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
    183     }
    184     if (I == LoadCommandCount - 1)
    185       break;
    186     else
    187       Load = MachO->getNextLoadCommandInfo(Load);
    188   }
    189   outs() << "total " << format(fmt.str().c_str(), total) << "\n";
    190 }
    191 
    192 /// @brief Print the summary sizes of the standard Mach-O segments in @p MachO.
    193 ///
    194 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
    195 /// produces the same output as darwin's size(1) default output.
    196 static void PrintDarwinSegmentSizes(MachOObjectFile *MachO) {
    197   uint32_t LoadCommandCount = MachO->getHeader().ncmds;
    198   MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
    199 
    200   uint64_t total_text = 0;
    201   uint64_t total_data = 0;
    202   uint64_t total_objc = 0;
    203   uint64_t total_others = 0;
    204   for (unsigned I = 0;; ++I) {
    205     if (Load.C.cmd == MachO::LC_SEGMENT_64) {
    206       MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
    207       if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
    208         for (unsigned J = 0; J < Seg.nsects; ++J) {
    209           MachO::section_64 Sec = MachO->getSection64(Load, J);
    210           StringRef SegmentName = StringRef(Sec.segname);
    211           if (SegmentName == "__TEXT")
    212             total_text += Sec.size;
    213           else if (SegmentName == "__DATA")
    214             total_data += Sec.size;
    215           else if (SegmentName == "__OBJC")
    216             total_objc += Sec.size;
    217           else
    218             total_others += Sec.size;
    219         }
    220       } else {
    221         StringRef SegmentName = StringRef(Seg.segname);
    222         if (SegmentName == "__TEXT")
    223           total_text += Seg.vmsize;
    224         else if (SegmentName == "__DATA")
    225           total_data += Seg.vmsize;
    226         else if (SegmentName == "__OBJC")
    227           total_objc += Seg.vmsize;
    228         else
    229           total_others += Seg.vmsize;
    230       }
    231     } else if (Load.C.cmd == MachO::LC_SEGMENT) {
    232       MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
    233       if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
    234         for (unsigned J = 0; J < Seg.nsects; ++J) {
    235           MachO::section Sec = MachO->getSection(Load, J);
    236           StringRef SegmentName = StringRef(Sec.segname);
    237           if (SegmentName == "__TEXT")
    238             total_text += Sec.size;
    239           else if (SegmentName == "__DATA")
    240             total_data += Sec.size;
    241           else if (SegmentName == "__OBJC")
    242             total_objc += Sec.size;
    243           else
    244             total_others += Sec.size;
    245         }
    246       } else {
    247         StringRef SegmentName = StringRef(Seg.segname);
    248         if (SegmentName == "__TEXT")
    249           total_text += Seg.vmsize;
    250         else if (SegmentName == "__DATA")
    251           total_data += Seg.vmsize;
    252         else if (SegmentName == "__OBJC")
    253           total_objc += Seg.vmsize;
    254         else
    255           total_others += Seg.vmsize;
    256       }
    257     }
    258     if (I == LoadCommandCount - 1)
    259       break;
    260     else
    261       Load = MachO->getNextLoadCommandInfo(Load);
    262   }
    263   uint64_t total = total_text + total_data + total_objc + total_others;
    264 
    265   if (!berkeleyHeaderPrinted) {
    266     outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
    267     berkeleyHeaderPrinted = true;
    268   }
    269   outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
    270          << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
    271          << "\t";
    272 }
    273 
    274 /// @brief Print the size of each section in @p Obj.
    275 ///
    276 /// The format used is determined by @c OutputFormat and @c Radix.
    277 static void PrintObjectSectionSizes(ObjectFile *Obj) {
    278   uint64_t total = 0;
    279   std::string fmtbuf;
    280   raw_string_ostream fmt(fmtbuf);
    281   const char *radix_fmt = getRadixFmt();
    282 
    283   // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
    284   // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
    285   // let it fall through to OutputFormat berkeley.
    286   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
    287   if (OutputFormat == darwin && MachO)
    288     PrintDarwinSectionSizes(MachO);
    289   // If we have a MachOObjectFile and the OutputFormat is berkeley print as
    290   // darwin's default berkeley format for Mach-O files.
    291   else if (MachO && OutputFormat == berkeley)
    292     PrintDarwinSegmentSizes(MachO);
    293   else if (OutputFormat == sysv) {
    294     // Run two passes over all sections. The first gets the lengths needed for
    295     // formatting the output. The second actually does the output.
    296     std::size_t max_name_len = strlen("section");
    297     std::size_t max_size_len = strlen("size");
    298     std::size_t max_addr_len = strlen("addr");
    299     for (const SectionRef &Section : Obj->sections()) {
    300       uint64_t size = 0;
    301       if (error(Section.getSize(size)))
    302         return;
    303       total += size;
    304 
    305       StringRef name;
    306       uint64_t addr = 0;
    307       if (error(Section.getName(name)))
    308         return;
    309       if (error(Section.getAddress(addr)))
    310         return;
    311       max_name_len = std::max(max_name_len, name.size());
    312       max_size_len = std::max(max_size_len, getNumLengthAsString(size));
    313       max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
    314     }
    315 
    316     // Add extra padding.
    317     max_name_len += 2;
    318     max_size_len += 2;
    319     max_addr_len += 2;
    320 
    321     // Setup header format.
    322     fmt << "%-" << max_name_len << "s "
    323         << "%" << max_size_len << "s "
    324         << "%" << max_addr_len << "s\n";
    325 
    326     // Print header
    327     outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
    328                      static_cast<const char *>("size"),
    329                      static_cast<const char *>("addr"));
    330     fmtbuf.clear();
    331 
    332     // Setup per section format.
    333     fmt << "%-" << max_name_len << "s "
    334         << "%#" << max_size_len << radix_fmt << " "
    335         << "%#" << max_addr_len << radix_fmt << "\n";
    336 
    337     // Print each section.
    338     for (const SectionRef &Section : Obj->sections()) {
    339       StringRef name;
    340       uint64_t size = 0;
    341       uint64_t addr = 0;
    342       if (error(Section.getName(name)))
    343         return;
    344       if (error(Section.getSize(size)))
    345         return;
    346       if (error(Section.getAddress(addr)))
    347         return;
    348       std::string namestr = name;
    349 
    350       outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr);
    351     }
    352 
    353     // Print total.
    354     fmtbuf.clear();
    355     fmt << "%-" << max_name_len << "s "
    356         << "%#" << max_size_len << radix_fmt << "\n";
    357     outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
    358                      total);
    359   } else {
    360     // The Berkeley format does not display individual section sizes. It
    361     // displays the cumulative size for each section type.
    362     uint64_t total_text = 0;
    363     uint64_t total_data = 0;
    364     uint64_t total_bss = 0;
    365 
    366     // Make one pass over the section table to calculate sizes.
    367     for (const SectionRef &Section : Obj->sections()) {
    368       uint64_t size = 0;
    369       bool isText = false;
    370       bool isData = false;
    371       bool isBSS = false;
    372       if (error(Section.getSize(size)))
    373         return;
    374       if (error(Section.isText(isText)))
    375         return;
    376       if (error(Section.isData(isData)))
    377         return;
    378       if (error(Section.isBSS(isBSS)))
    379         return;
    380       if (isText)
    381         total_text += size;
    382       else if (isData)
    383         total_data += size;
    384       else if (isBSS)
    385         total_bss += size;
    386     }
    387 
    388     total = total_text + total_data + total_bss;
    389 
    390     if (!berkeleyHeaderPrinted) {
    391       outs() << "   text    data     bss     "
    392              << (Radix == octal ? "oct" : "dec") << "     hex filename\n";
    393       berkeleyHeaderPrinted = true;
    394     }
    395 
    396     // Print result.
    397     fmt << "%#7" << radix_fmt << " "
    398         << "%#7" << radix_fmt << " "
    399         << "%#7" << radix_fmt << " ";
    400     outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
    401     fmtbuf.clear();
    402     fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " "
    403         << "%7" PRIx64 " ";
    404     outs() << format(fmt.str().c_str(), total, total);
    405   }
    406 }
    407 
    408 /// @brief Checks to see if the @p o ObjectFile is a Mach-O file and if it is
    409 ///        and there is a list of architecture flags specified then check to
    410 ///        make sure this Mach-O file is one of those architectures or all
    411 ///        architectures was specificed.  If not then an error is generated and
    412 ///        this routine returns false.  Else it returns true.
    413 static bool checkMachOAndArchFlags(ObjectFile *o, StringRef file) {
    414   if (isa<MachOObjectFile>(o) && !ArchAll && ArchFlags.size() != 0) {
    415     MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    416     bool ArchFound = false;
    417     MachO::mach_header H;
    418     MachO::mach_header_64 H_64;
    419     Triple T;
    420     if (MachO->is64Bit()) {
    421       H_64 = MachO->MachOObjectFile::getHeader64();
    422       T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype);
    423     } else {
    424       H = MachO->MachOObjectFile::getHeader();
    425       T = MachOObjectFile::getArch(H.cputype, H.cpusubtype);
    426     }
    427     unsigned i;
    428     for (i = 0; i < ArchFlags.size(); ++i) {
    429       if (ArchFlags[i] == T.getArchName())
    430         ArchFound = true;
    431       break;
    432     }
    433     if (!ArchFound) {
    434       errs() << ToolName << ": file: " << file
    435              << " does not contain architecture: " << ArchFlags[i] << ".\n";
    436       return false;
    437     }
    438   }
    439   return true;
    440 }
    441 
    442 /// @brief Print the section sizes for @p file. If @p file is an archive, print
    443 ///        the section sizes for each archive member.
    444 static void PrintFileSectionSizes(StringRef file) {
    445   // If file is not stdin, check that it exists.
    446   if (file != "-") {
    447     bool exists;
    448     if (sys::fs::exists(file, exists) || !exists) {
    449       errs() << ToolName << ": '" << file << "': "
    450              << "No such file\n";
    451       return;
    452     }
    453   }
    454 
    455   // Attempt to open the binary.
    456   ErrorOr<Binary *> BinaryOrErr = createBinary(file);
    457   if (std::error_code EC = BinaryOrErr.getError()) {
    458     errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
    459     return;
    460   }
    461   std::unique_ptr<Binary> binary(BinaryOrErr.get());
    462 
    463   if (Archive *a = dyn_cast<Archive>(binary.get())) {
    464     // This is an archive. Iterate over each member and display its sizes.
    465     for (object::Archive::child_iterator i = a->child_begin(),
    466                                          e = a->child_end();
    467          i != e; ++i) {
    468       ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
    469       if (std::error_code EC = ChildOrErr.getError()) {
    470         errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
    471         continue;
    472       }
    473       if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
    474         MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    475         if (!checkMachOAndArchFlags(o, file))
    476           return;
    477         if (OutputFormat == sysv)
    478           outs() << o->getFileName() << "   (ex " << a->getFileName() << "):\n";
    479         else if (MachO && OutputFormat == darwin)
    480           outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
    481         PrintObjectSectionSizes(o);
    482         if (OutputFormat == berkeley) {
    483           if (MachO)
    484             outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
    485           else
    486             outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
    487         }
    488       }
    489     }
    490   } else if (MachOUniversalBinary *UB =
    491                  dyn_cast<MachOUniversalBinary>(binary.get())) {
    492     // If we have a list of architecture flags specified dump only those.
    493     if (!ArchAll && ArchFlags.size() != 0) {
    494       // Look for a slice in the universal binary that matches each ArchFlag.
    495       bool ArchFound;
    496       for (unsigned i = 0; i < ArchFlags.size(); ++i) {
    497         ArchFound = false;
    498         for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
    499                                                    E = UB->end_objects();
    500              I != E; ++I) {
    501           if (ArchFlags[i] == I->getArchTypeName()) {
    502             ArchFound = true;
    503             ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
    504             std::unique_ptr<Archive> UA;
    505             if (UO) {
    506               if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
    507                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    508                 if (OutputFormat == sysv)
    509                   outs() << o->getFileName() << "  :\n";
    510                 else if (MachO && OutputFormat == darwin) {
    511                   if (moreThanOneFile || ArchFlags.size() > 1)
    512                     outs() << o->getFileName() << " (for architecture "
    513                            << I->getArchTypeName() << "): \n";
    514                 }
    515                 PrintObjectSectionSizes(o);
    516                 if (OutputFormat == berkeley) {
    517                   if (!MachO || moreThanOneFile || ArchFlags.size() > 1)
    518                     outs() << o->getFileName() << " (for architecture "
    519                            << I->getArchTypeName() << ")";
    520                   outs() << "\n";
    521                 }
    522               }
    523             } else if (!I->getAsArchive(UA)) {
    524               // This is an archive. Iterate over each member and display its
    525               // sizes.
    526               for (object::Archive::child_iterator i = UA->child_begin(),
    527                                                    e = UA->child_end();
    528                    i != e; ++i) {
    529                 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
    530                 if (std::error_code EC = ChildOrErr.getError()) {
    531                   errs() << ToolName << ": " << file << ": " << EC.message()
    532                          << ".\n";
    533                   continue;
    534                 }
    535                 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
    536                   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    537                   if (OutputFormat == sysv)
    538                     outs() << o->getFileName() << "   (ex " << UA->getFileName()
    539                            << "):\n";
    540                   else if (MachO && OutputFormat == darwin)
    541                     outs() << UA->getFileName() << "(" << o->getFileName()
    542                            << ")"
    543                            << " (for architecture " << I->getArchTypeName()
    544                            << "):\n";
    545                   PrintObjectSectionSizes(o);
    546                   if (OutputFormat == berkeley) {
    547                     if (MachO) {
    548                       outs() << UA->getFileName() << "(" << o->getFileName()
    549                              << ")";
    550                       if (ArchFlags.size() > 1)
    551                         outs() << " (for architecture " << I->getArchTypeName()
    552                                << ")";
    553                       outs() << "\n";
    554                     } else
    555                       outs() << o->getFileName() << " (ex " << UA->getFileName()
    556                              << ")\n";
    557                   }
    558                 }
    559               }
    560             }
    561           }
    562         }
    563         if (!ArchFound) {
    564           errs() << ToolName << ": file: " << file
    565                  << " does not contain architecture" << ArchFlags[i] << ".\n";
    566           return;
    567         }
    568       }
    569       return;
    570     }
    571     // No architecture flags were specified so if this contains a slice that
    572     // matches the host architecture dump only that.
    573     if (!ArchAll) {
    574       StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
    575       for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
    576                                                  E = UB->end_objects();
    577            I != E; ++I) {
    578         if (HostArchName == I->getArchTypeName()) {
    579           ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
    580           std::unique_ptr<Archive> UA;
    581           if (UO) {
    582             if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
    583               MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    584               if (OutputFormat == sysv)
    585                 outs() << o->getFileName() << "  :\n";
    586               else if (MachO && OutputFormat == darwin) {
    587                 if (moreThanOneFile)
    588                   outs() << o->getFileName() << " (for architecture "
    589                          << I->getArchTypeName() << "):\n";
    590               }
    591               PrintObjectSectionSizes(o);
    592               if (OutputFormat == berkeley) {
    593                 if (!MachO || moreThanOneFile)
    594                   outs() << o->getFileName() << " (for architecture "
    595                          << I->getArchTypeName() << ")";
    596                 outs() << "\n";
    597               }
    598             }
    599           } else if (!I->getAsArchive(UA)) {
    600             // This is an archive. Iterate over each member and display its
    601             // sizes.
    602             for (object::Archive::child_iterator i = UA->child_begin(),
    603                                                  e = UA->child_end();
    604                  i != e; ++i) {
    605               ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
    606               if (std::error_code EC = ChildOrErr.getError()) {
    607                 errs() << ToolName << ": " << file << ": " << EC.message()
    608                        << ".\n";
    609                 continue;
    610               }
    611               if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
    612                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    613                 if (OutputFormat == sysv)
    614                   outs() << o->getFileName() << "   (ex " << UA->getFileName()
    615                          << "):\n";
    616                 else if (MachO && OutputFormat == darwin)
    617                   outs() << UA->getFileName() << "(" << o->getFileName() << ")"
    618                          << " (for architecture " << I->getArchTypeName()
    619                          << "):\n";
    620                 PrintObjectSectionSizes(o);
    621                 if (OutputFormat == berkeley) {
    622                   if (MachO)
    623                     outs() << UA->getFileName() << "(" << o->getFileName()
    624                            << ")\n";
    625                   else
    626                     outs() << o->getFileName() << " (ex " << UA->getFileName()
    627                            << ")\n";
    628                 }
    629               }
    630             }
    631           }
    632           return;
    633         }
    634       }
    635     }
    636     // Either all architectures have been specified or none have been specified
    637     // and this does not contain the host architecture so dump all the slices.
    638     bool moreThanOneArch = UB->getNumberOfObjects() > 1;
    639     for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
    640                                                E = UB->end_objects();
    641          I != E; ++I) {
    642       ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
    643       std::unique_ptr<Archive> UA;
    644       if (UO) {
    645         if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
    646           MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    647           if (OutputFormat == sysv)
    648             outs() << o->getFileName() << "  :\n";
    649           else if (MachO && OutputFormat == darwin) {
    650             if (moreThanOneFile || moreThanOneArch)
    651               outs() << o->getFileName() << " (for architecture "
    652                      << I->getArchTypeName() << "):";
    653             outs() << "\n";
    654           }
    655           PrintObjectSectionSizes(o);
    656           if (OutputFormat == berkeley) {
    657             if (!MachO || moreThanOneFile || moreThanOneArch)
    658               outs() << o->getFileName() << " (for architecture "
    659                      << I->getArchTypeName() << ")";
    660             outs() << "\n";
    661           }
    662         }
    663       } else if (!I->getAsArchive(UA)) {
    664         // This is an archive. Iterate over each member and display its sizes.
    665         for (object::Archive::child_iterator i = UA->child_begin(),
    666                                              e = UA->child_end();
    667              i != e; ++i) {
    668           ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
    669           if (std::error_code EC = ChildOrErr.getError()) {
    670             errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
    671             continue;
    672           }
    673           if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
    674             MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    675             if (OutputFormat == sysv)
    676               outs() << o->getFileName() << "   (ex " << UA->getFileName()
    677                      << "):\n";
    678             else if (MachO && OutputFormat == darwin)
    679               outs() << UA->getFileName() << "(" << o->getFileName() << ")"
    680                      << " (for architecture " << I->getArchTypeName() << "):\n";
    681             PrintObjectSectionSizes(o);
    682             if (OutputFormat == berkeley) {
    683               if (MachO)
    684                 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
    685                        << " (for architecture " << I->getArchTypeName()
    686                        << ")\n";
    687               else
    688                 outs() << o->getFileName() << " (ex " << UA->getFileName()
    689                        << ")\n";
    690             }
    691           }
    692         }
    693       }
    694     }
    695   } else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) {
    696     if (!checkMachOAndArchFlags(o, file))
    697       return;
    698     if (OutputFormat == sysv)
    699       outs() << o->getFileName() << "  :\n";
    700     PrintObjectSectionSizes(o);
    701     if (OutputFormat == berkeley) {
    702       MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
    703       if (!MachO || moreThanOneFile)
    704         outs() << o->getFileName();
    705       outs() << "\n";
    706     }
    707   } else {
    708     errs() << ToolName << ": " << file << ": "
    709            << "Unrecognized file type.\n";
    710   }
    711   // System V adds an extra newline at the end of each file.
    712   if (OutputFormat == sysv)
    713     outs() << "\n";
    714 }
    715 
    716 int main(int argc, char **argv) {
    717   // Print a stack trace if we signal out.
    718   sys::PrintStackTraceOnErrorSignal();
    719   PrettyStackTraceProgram X(argc, argv);
    720 
    721   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
    722   cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
    723 
    724   ToolName = argv[0];
    725   if (OutputFormatShort.getNumOccurrences())
    726     OutputFormat = OutputFormatShort;
    727   if (RadixShort.getNumOccurrences())
    728     Radix = RadixShort;
    729 
    730   for (unsigned i = 0; i < ArchFlags.size(); ++i) {
    731     if (ArchFlags[i] == "all") {
    732       ArchAll = true;
    733     } else {
    734       Triple T = MachOObjectFile::getArch(ArchFlags[i]);
    735       if (T.getArch() == Triple::UnknownArch) {
    736         outs() << ToolName << ": for the -arch option: Unknown architecture "
    737                << "named '" << ArchFlags[i] << "'";
    738         return 1;
    739       }
    740     }
    741   }
    742 
    743   if (InputFilenames.size() == 0)
    744     InputFilenames.push_back("a.out");
    745 
    746   moreThanOneFile = InputFilenames.size() > 1;
    747   std::for_each(InputFilenames.begin(), InputFilenames.end(),
    748                 PrintFileSectionSizes);
    749 
    750   return 0;
    751 }
    752