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