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