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