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/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>
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 = Section.getSize();
301      total += size;
302
303      StringRef name;
304      if (error(Section.getName(name)))
305        return;
306      uint64_t addr = Section.getAddress();
307      max_name_len = std::max(max_name_len, name.size());
308      max_size_len = std::max(max_size_len, getNumLengthAsString(size));
309      max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
310    }
311
312    // Add extra padding.
313    max_name_len += 2;
314    max_size_len += 2;
315    max_addr_len += 2;
316
317    // Setup header format.
318    fmt << "%-" << max_name_len << "s "
319        << "%" << max_size_len << "s "
320        << "%" << max_addr_len << "s\n";
321
322    // Print header
323    outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
324                     static_cast<const char *>("size"),
325                     static_cast<const char *>("addr"));
326    fmtbuf.clear();
327
328    // Setup per section format.
329    fmt << "%-" << max_name_len << "s "
330        << "%#" << max_size_len << radix_fmt << " "
331        << "%#" << max_addr_len << radix_fmt << "\n";
332
333    // Print each section.
334    for (const SectionRef &Section : Obj->sections()) {
335      StringRef name;
336      if (error(Section.getName(name)))
337        return;
338      uint64_t size = Section.getSize();
339      uint64_t addr = Section.getAddress();
340      std::string namestr = name;
341
342      outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr);
343    }
344
345    // Print total.
346    fmtbuf.clear();
347    fmt << "%-" << max_name_len << "s "
348        << "%#" << max_size_len << radix_fmt << "\n";
349    outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
350                     total);
351  } else {
352    // The Berkeley format does not display individual section sizes. It
353    // displays the cumulative size for each section type.
354    uint64_t total_text = 0;
355    uint64_t total_data = 0;
356    uint64_t total_bss = 0;
357
358    // Make one pass over the section table to calculate sizes.
359    for (const SectionRef &Section : Obj->sections()) {
360      uint64_t size = Section.getSize();
361      bool isText = Section.isText();
362      bool isData = Section.isData();
363      bool isBSS = Section.isBSS();
364      if (isText)
365        total_text += size;
366      else if (isData)
367        total_data += size;
368      else if (isBSS)
369        total_bss += size;
370    }
371
372    total = total_text + total_data + total_bss;
373
374    if (!berkeleyHeaderPrinted) {
375      outs() << "   text    data     bss     "
376             << (Radix == octal ? "oct" : "dec") << "     hex filename\n";
377      berkeleyHeaderPrinted = true;
378    }
379
380    // Print result.
381    fmt << "%#7" << radix_fmt << " "
382        << "%#7" << radix_fmt << " "
383        << "%#7" << radix_fmt << " ";
384    outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
385    fmtbuf.clear();
386    fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " "
387        << "%7" PRIx64 " ";
388    outs() << format(fmt.str().c_str(), total, total);
389  }
390}
391
392/// @brief Checks to see if the @p o ObjectFile is a Mach-O file and if it is
393///        and there is a list of architecture flags specified then check to
394///        make sure this Mach-O file is one of those architectures or all
395///        architectures was specificed.  If not then an error is generated and
396///        this routine returns false.  Else it returns true.
397static bool checkMachOAndArchFlags(ObjectFile *o, StringRef file) {
398  if (isa<MachOObjectFile>(o) && !ArchAll && ArchFlags.size() != 0) {
399    MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
400    bool ArchFound = false;
401    MachO::mach_header H;
402    MachO::mach_header_64 H_64;
403    Triple T;
404    if (MachO->is64Bit()) {
405      H_64 = MachO->MachOObjectFile::getHeader64();
406      T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype);
407    } else {
408      H = MachO->MachOObjectFile::getHeader();
409      T = MachOObjectFile::getArch(H.cputype, H.cpusubtype);
410    }
411    unsigned i;
412    for (i = 0; i < ArchFlags.size(); ++i) {
413      if (ArchFlags[i] == T.getArchName())
414        ArchFound = true;
415      break;
416    }
417    if (!ArchFound) {
418      errs() << ToolName << ": file: " << file
419             << " does not contain architecture: " << ArchFlags[i] << ".\n";
420      return false;
421    }
422  }
423  return true;
424}
425
426/// @brief Print the section sizes for @p file. If @p file is an archive, print
427///        the section sizes for each archive member.
428static void PrintFileSectionSizes(StringRef file) {
429  // If file is not stdin, check that it exists.
430  if (file != "-") {
431    if (!sys::fs::exists(file)) {
432      errs() << ToolName << ": '" << file << "': "
433             << "No such file\n";
434      return;
435    }
436  }
437
438  // Attempt to open the binary.
439  ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
440  if (std::error_code EC = BinaryOrErr.getError()) {
441    errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
442    return;
443  }
444  Binary &Bin = *BinaryOrErr.get().getBinary();
445
446  if (Archive *a = dyn_cast<Archive>(&Bin)) {
447    // This is an archive. Iterate over each member and display its sizes.
448    for (object::Archive::child_iterator i = a->child_begin(),
449                                         e = a->child_end();
450         i != e; ++i) {
451      ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
452      if (std::error_code EC = ChildOrErr.getError()) {
453        errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
454        continue;
455      }
456      if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
457        MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
458        if (!checkMachOAndArchFlags(o, file))
459          return;
460        if (OutputFormat == sysv)
461          outs() << o->getFileName() << "   (ex " << a->getFileName() << "):\n";
462        else if (MachO && OutputFormat == darwin)
463          outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
464        PrintObjectSectionSizes(o);
465        if (OutputFormat == berkeley) {
466          if (MachO)
467            outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
468          else
469            outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
470        }
471      }
472    }
473  } else if (MachOUniversalBinary *UB =
474                 dyn_cast<MachOUniversalBinary>(&Bin)) {
475    // If we have a list of architecture flags specified dump only those.
476    if (!ArchAll && ArchFlags.size() != 0) {
477      // Look for a slice in the universal binary that matches each ArchFlag.
478      bool ArchFound;
479      for (unsigned i = 0; i < ArchFlags.size(); ++i) {
480        ArchFound = false;
481        for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
482                                                   E = UB->end_objects();
483             I != E; ++I) {
484          if (ArchFlags[i] == I->getArchTypeName()) {
485            ArchFound = true;
486            ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
487            if (UO) {
488              if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
489                MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
490                if (OutputFormat == sysv)
491                  outs() << o->getFileName() << "  :\n";
492                else if (MachO && OutputFormat == darwin) {
493                  if (moreThanOneFile || ArchFlags.size() > 1)
494                    outs() << o->getFileName() << " (for architecture "
495                           << I->getArchTypeName() << "): \n";
496                }
497                PrintObjectSectionSizes(o);
498                if (OutputFormat == berkeley) {
499                  if (!MachO || moreThanOneFile || ArchFlags.size() > 1)
500                    outs() << o->getFileName() << " (for architecture "
501                           << I->getArchTypeName() << ")";
502                  outs() << "\n";
503                }
504              }
505            } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
506                           I->getAsArchive()) {
507              std::unique_ptr<Archive> &UA = *AOrErr;
508              // This is an archive. Iterate over each member and display its
509              // sizes.
510              for (object::Archive::child_iterator i = UA->child_begin(),
511                                                   e = UA->child_end();
512                   i != e; ++i) {
513                ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
514                if (std::error_code EC = ChildOrErr.getError()) {
515                  errs() << ToolName << ": " << file << ": " << EC.message()
516                         << ".\n";
517                  continue;
518                }
519                if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
520                  MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
521                  if (OutputFormat == sysv)
522                    outs() << o->getFileName() << "   (ex " << UA->getFileName()
523                           << "):\n";
524                  else if (MachO && OutputFormat == darwin)
525                    outs() << UA->getFileName() << "(" << o->getFileName()
526                           << ")"
527                           << " (for architecture " << I->getArchTypeName()
528                           << "):\n";
529                  PrintObjectSectionSizes(o);
530                  if (OutputFormat == berkeley) {
531                    if (MachO) {
532                      outs() << UA->getFileName() << "(" << o->getFileName()
533                             << ")";
534                      if (ArchFlags.size() > 1)
535                        outs() << " (for architecture " << I->getArchTypeName()
536                               << ")";
537                      outs() << "\n";
538                    } else
539                      outs() << o->getFileName() << " (ex " << UA->getFileName()
540                             << ")\n";
541                  }
542                }
543              }
544            }
545          }
546        }
547        if (!ArchFound) {
548          errs() << ToolName << ": file: " << file
549                 << " does not contain architecture" << ArchFlags[i] << ".\n";
550          return;
551        }
552      }
553      return;
554    }
555    // No architecture flags were specified so if this contains a slice that
556    // matches the host architecture dump only that.
557    if (!ArchAll) {
558      StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
559      for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
560                                                 E = UB->end_objects();
561           I != E; ++I) {
562        if (HostArchName == I->getArchTypeName()) {
563          ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
564          if (UO) {
565            if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
566              MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
567              if (OutputFormat == sysv)
568                outs() << o->getFileName() << "  :\n";
569              else if (MachO && OutputFormat == darwin) {
570                if (moreThanOneFile)
571                  outs() << o->getFileName() << " (for architecture "
572                         << I->getArchTypeName() << "):\n";
573              }
574              PrintObjectSectionSizes(o);
575              if (OutputFormat == berkeley) {
576                if (!MachO || moreThanOneFile)
577                  outs() << o->getFileName() << " (for architecture "
578                         << I->getArchTypeName() << ")";
579                outs() << "\n";
580              }
581            }
582          } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
583                         I->getAsArchive()) {
584            std::unique_ptr<Archive> &UA = *AOrErr;
585            // This is an archive. Iterate over each member and display its
586            // sizes.
587            for (object::Archive::child_iterator i = UA->child_begin(),
588                                                 e = UA->child_end();
589                 i != e; ++i) {
590              ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
591              if (std::error_code EC = ChildOrErr.getError()) {
592                errs() << ToolName << ": " << file << ": " << EC.message()
593                       << ".\n";
594                continue;
595              }
596              if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
597                MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
598                if (OutputFormat == sysv)
599                  outs() << o->getFileName() << "   (ex " << UA->getFileName()
600                         << "):\n";
601                else if (MachO && OutputFormat == darwin)
602                  outs() << UA->getFileName() << "(" << o->getFileName() << ")"
603                         << " (for architecture " << I->getArchTypeName()
604                         << "):\n";
605                PrintObjectSectionSizes(o);
606                if (OutputFormat == berkeley) {
607                  if (MachO)
608                    outs() << UA->getFileName() << "(" << o->getFileName()
609                           << ")\n";
610                  else
611                    outs() << o->getFileName() << " (ex " << UA->getFileName()
612                           << ")\n";
613                }
614              }
615            }
616          }
617          return;
618        }
619      }
620    }
621    // Either all architectures have been specified or none have been specified
622    // and this does not contain the host architecture so dump all the slices.
623    bool moreThanOneArch = UB->getNumberOfObjects() > 1;
624    for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
625                                               E = UB->end_objects();
626         I != E; ++I) {
627      ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
628      if (UO) {
629        if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
630          MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
631          if (OutputFormat == sysv)
632            outs() << o->getFileName() << "  :\n";
633          else if (MachO && OutputFormat == darwin) {
634            if (moreThanOneFile || moreThanOneArch)
635              outs() << o->getFileName() << " (for architecture "
636                     << I->getArchTypeName() << "):";
637            outs() << "\n";
638          }
639          PrintObjectSectionSizes(o);
640          if (OutputFormat == berkeley) {
641            if (!MachO || moreThanOneFile || moreThanOneArch)
642              outs() << o->getFileName() << " (for architecture "
643                     << I->getArchTypeName() << ")";
644            outs() << "\n";
645          }
646        }
647      } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
648                         I->getAsArchive()) {
649        std::unique_ptr<Archive> &UA = *AOrErr;
650        // This is an archive. Iterate over each member and display its sizes.
651        for (object::Archive::child_iterator i = UA->child_begin(),
652                                             e = UA->child_end();
653             i != e; ++i) {
654          ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
655          if (std::error_code EC = ChildOrErr.getError()) {
656            errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
657            continue;
658          }
659          if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
660            MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
661            if (OutputFormat == sysv)
662              outs() << o->getFileName() << "   (ex " << UA->getFileName()
663                     << "):\n";
664            else if (MachO && OutputFormat == darwin)
665              outs() << UA->getFileName() << "(" << o->getFileName() << ")"
666                     << " (for architecture " << I->getArchTypeName() << "):\n";
667            PrintObjectSectionSizes(o);
668            if (OutputFormat == berkeley) {
669              if (MachO)
670                outs() << UA->getFileName() << "(" << o->getFileName() << ")"
671                       << " (for architecture " << I->getArchTypeName()
672                       << ")\n";
673              else
674                outs() << o->getFileName() << " (ex " << UA->getFileName()
675                       << ")\n";
676            }
677          }
678        }
679      }
680    }
681  } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
682    if (!checkMachOAndArchFlags(o, file))
683      return;
684    if (OutputFormat == sysv)
685      outs() << o->getFileName() << "  :\n";
686    PrintObjectSectionSizes(o);
687    if (OutputFormat == berkeley) {
688      MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
689      if (!MachO || moreThanOneFile)
690        outs() << o->getFileName();
691      outs() << "\n";
692    }
693  } else {
694    errs() << ToolName << ": " << file << ": "
695           << "Unrecognized file type.\n";
696  }
697  // System V adds an extra newline at the end of each file.
698  if (OutputFormat == sysv)
699    outs() << "\n";
700}
701
702int main(int argc, char **argv) {
703  // Print a stack trace if we signal out.
704  sys::PrintStackTraceOnErrorSignal();
705  PrettyStackTraceProgram X(argc, argv);
706
707  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
708  cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
709
710  ToolName = argv[0];
711  if (OutputFormatShort.getNumOccurrences())
712    OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
713  if (RadixShort.getNumOccurrences())
714    Radix = RadixShort;
715
716  for (unsigned i = 0; i < ArchFlags.size(); ++i) {
717    if (ArchFlags[i] == "all") {
718      ArchAll = true;
719    } else {
720      if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
721        outs() << ToolName << ": for the -arch option: Unknown architecture "
722               << "named '" << ArchFlags[i] << "'";
723        return 1;
724      }
725    }
726  }
727
728  if (InputFilenames.size() == 0)
729    InputFilenames.push_back("a.out");
730
731  moreThanOneFile = InputFilenames.size() > 1;
732  std::for_each(InputFilenames.begin(), InputFilenames.end(),
733                PrintFileSectionSizes);
734
735  return 0;
736}
737