xref: /aosp_15_r20/external/llvm/tools/llvm-size/llvm-size.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
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.
error(std::error_code ec)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  
error(Twine Message)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.
error(llvm::Error E,StringRef FileName,const Archive::Child & C,StringRef ArchitectureName=StringRef ())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.
error(llvm::Error E,StringRef FileName,StringRef ArchitectureName=StringRef ())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.
getNumLengthAsString(uint64_t num)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.
getRadixFmt()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
considerForSize(ObjectFile * Obj,SectionRef Section)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
getCommonSize(ObjectFile * Obj)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.
printDarwinSectionSizes(MachOObjectFile * MachO)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.
printDarwinSegmentSizes(MachOObjectFile * MachO)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.
printObjectSectionSizes(ObjectFile * Obj)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.
checkMachOAndArchFlags(ObjectFile * o,StringRef file)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.
printFileSectionSizes(StringRef file)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  
main(int argc,char ** argv)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