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>
33using namespace llvm;
34using namespace object;
35
36enum OutputFormatTy { berkeley, sysv, darwin };
37static cl::opt<OutputFormatTy>
38OutputFormat("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
44static 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
51static bool berkeleyHeaderPrinted = false;
52static bool moreThanOneFile = false;
53
54cl::opt<bool>
55DarwinLongFormat("l", cl::desc("When format is darwin, use long format "
56                               "to include addresses and offsets."));
57
58static cl::list<std::string>
59ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
60          cl::ZeroOrMore);
61bool ArchAll = false;
62
63enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
64static cl::opt<unsigned int>
65Radix("-radix", cl::desc("Print size in radix. Only 8, 10, and 16 are valid"),
66      cl::init(decimal));
67
68static cl::opt<RadixTy>
69RadixShort(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
76static cl::list<std::string>
77InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
78
79static std::string ToolName;
80
81///  @brief If ec is not success, print the error and return true.
82static 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.
93static 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.
101static 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.
117static 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.
196static 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.
277static 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.
413static 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.
444static 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
716int 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