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