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