xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
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/InitLLVM.h"
29 #include "llvm/Support/LLVMDriver.h"
30 #include "llvm/Support/MemoryBuffer.h"
31 #include "llvm/Support/WithColor.h"
32 #include "llvm/Support/raw_ostream.h"
33 #include <algorithm>
34 #include <string>
35 #include <system_error>
36 
37 using namespace llvm;
38 using namespace object;
39 
40 namespace {
41 using namespace llvm::opt; // for HelpHidden in Opts.inc
42 enum ID {
43   OPT_INVALID = 0, // This is not an option ID.
44 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
45                HELPTEXT, METAVAR, VALUES)                                      \
46   OPT_##ID,
47 #include "Opts.inc"
48 #undef OPTION
49 };
50 
51 #define PREFIX(NAME, VALUE)                                                    \
52   static constexpr StringLiteral NAME##_init[] = VALUE;                        \
53   static constexpr ArrayRef<StringLiteral> NAME(NAME##_init,                   \
54                                                 std::size(NAME##_init) - 1);
55 #include "Opts.inc"
56 #undef PREFIX
57 
58 static constexpr opt::OptTable::Info InfoTable[] = {
59 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
60                HELPTEXT, METAVAR, VALUES)                                      \
61   {                                                                            \
62       PREFIX,      NAME,      HELPTEXT,                                        \
63       METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
64       PARAM,       FLAGS,     OPT_##GROUP,                                     \
65       OPT_##ALIAS, ALIASARGS, VALUES},
66 #include "Opts.inc"
67 #undef OPTION
68 };
69 
70 class SizeOptTable : public opt::GenericOptTable {
71 public:
72   SizeOptTable() : GenericOptTable(InfoTable) { setGroupedShortOptions(true); }
73 };
74 
75 enum OutputFormatTy { berkeley, sysv, darwin };
76 enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
77 } // namespace
78 
79 static bool ArchAll = false;
80 static std::vector<StringRef> ArchFlags;
81 static bool ELFCommons;
82 static OutputFormatTy OutputFormat;
83 static bool DarwinLongFormat;
84 static RadixTy Radix;
85 static bool TotalSizes;
86 
87 static std::vector<std::string> InputFilenames;
88 
89 static std::string ToolName;
90 
91 // States
92 static bool HadError = false;
93 static bool BerkeleyHeaderPrinted = false;
94 static bool MoreThanOneFile = false;
95 static uint64_t TotalObjectText = 0;
96 static uint64_t TotalObjectData = 0;
97 static uint64_t TotalObjectBss = 0;
98 static uint64_t TotalObjectTotal = 0;
99 
100 static void error(const Twine &Message, StringRef File = "") {
101   HadError = true;
102   if (File.empty())
103     WithColor::error(errs(), ToolName) << Message << '\n';
104   else
105     WithColor::error(errs(), ToolName)
106         << "'" << File << "': " << Message << '\n';
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.
112 static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
113                   StringRef ArchitectureName = StringRef()) {
114   HadError = true;
115   WithColor::error(errs(), ToolName) << "'" << FileName << "'";
116 
117   Expected<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) {
122     consumeError(NameOrErr.takeError());
123     errs() << "(" << "???" << ")";
124   } else
125     errs() << "(" << NameOrErr.get() << ")";
126 
127   if (!ArchitectureName.empty())
128     errs() << " (for architecture " << ArchitectureName << ") ";
129 
130   std::string Buf;
131   raw_string_ostream OS(Buf);
132   logAllUnhandledErrors(std::move(E), OS);
133   OS.flush();
134   errs() << ": " << Buf << "\n";
135 }
136 
137 // 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
138 // before the error message.  It sets HadError but returns allowing the code to
139 // move on to other architecture slices.
140 static void error(llvm::Error E, StringRef FileName,
141                   StringRef ArchitectureName = StringRef()) {
142   HadError = true;
143   WithColor::error(errs(), ToolName) << "'" << FileName << "'";
144 
145   if (!ArchitectureName.empty())
146     errs() << " (for architecture " << ArchitectureName << ") ";
147 
148   std::string Buf;
149   raw_string_ostream OS(Buf);
150   logAllUnhandledErrors(std::move(E), OS);
151   OS.flush();
152   errs() << ": " << Buf << "\n";
153 }
154 
155 /// Get the length of the string that represents @p num in Radix including the
156 /// leading 0x or 0 for hexadecimal and octal respectively.
157 static size_t getNumLengthAsString(uint64_t num) {
158   APInt conv(64, num);
159   SmallString<32> result;
160   conv.toString(result, Radix, false, true);
161   return result.size();
162 }
163 
164 /// Return the printing format for the Radix.
165 static const char *getRadixFmt() {
166   switch (Radix) {
167   case octal:
168     return PRIo64;
169   case decimal:
170     return PRIu64;
171   case hexadecimal:
172     return PRIx64;
173   }
174   return nullptr;
175 }
176 
177 /// Remove unneeded ELF sections from calculation
178 static bool considerForSize(ObjectFile *Obj, SectionRef Section) {
179   if (!Obj->isELF())
180     return true;
181   switch (static_cast<ELFSectionRef>(Section).getType()) {
182   case ELF::SHT_NULL:
183   case ELF::SHT_SYMTAB:
184     return false;
185   case ELF::SHT_STRTAB:
186   case ELF::SHT_REL:
187   case ELF::SHT_RELA:
188     return static_cast<ELFSectionRef>(Section).getFlags() & ELF::SHF_ALLOC;
189   }
190   return true;
191 }
192 
193 /// Total size of all ELF common symbols
194 static Expected<uint64_t> getCommonSize(ObjectFile *Obj) {
195   uint64_t TotalCommons = 0;
196   for (auto &Sym : Obj->symbols()) {
197     Expected<uint32_t> SymFlagsOrErr =
198         Obj->getSymbolFlags(Sym.getRawDataRefImpl());
199     if (!SymFlagsOrErr)
200       return SymFlagsOrErr.takeError();
201     if (*SymFlagsOrErr & SymbolRef::SF_Common)
202       TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl());
203   }
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.
211 static 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.
286 static 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.
360 static 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       if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) {
439         total += *CommonSizeOrErr;
440         outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(),
441                          *CommonSizeOrErr, static_cast<uint64_t>(0));
442       } else {
443         error(CommonSizeOrErr.takeError(), Obj->getFileName());
444         return;
445       }
446     }
447 
448     // Print total.
449     fmtbuf.clear();
450     fmt << "%-" << max_name_len << "s "
451         << "%#" << max_size_len << radix_fmt << "\n";
452     outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
453                      total)
454            << "\n\n";
455   } else {
456     // The Berkeley format does not display individual section sizes. It
457     // displays the cumulative size for each section type.
458     uint64_t total_text = 0;
459     uint64_t total_data = 0;
460     uint64_t total_bss = 0;
461 
462     // Make one pass over the section table to calculate sizes.
463     for (const SectionRef &Section : Obj->sections()) {
464       uint64_t size = Section.getSize();
465       bool isText = Section.isBerkeleyText();
466       bool isData = Section.isBerkeleyData();
467       bool isBSS = Section.isBSS();
468       if (isText)
469         total_text += size;
470       else if (isData)
471         total_data += size;
472       else if (isBSS)
473         total_bss += size;
474     }
475 
476     if (ELFCommons) {
477       if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj))
478         total_bss += *CommonSizeOrErr;
479       else {
480         error(CommonSizeOrErr.takeError(), Obj->getFileName());
481         return;
482       }
483     }
484 
485     total = total_text + total_data + total_bss;
486 
487     if (TotalSizes) {
488       TotalObjectText += total_text;
489       TotalObjectData += total_data;
490       TotalObjectBss += total_bss;
491       TotalObjectTotal += total;
492     }
493 
494     if (!BerkeleyHeaderPrinted) {
495       outs() << "   text\t"
496                 "   data\t"
497                 "    bss\t"
498                 "    "
499              << (Radix == octal ? "oct" : "dec")
500              << "\t"
501                 "    hex\t"
502                 "filename\n";
503       BerkeleyHeaderPrinted = true;
504     }
505 
506     // Print result.
507     fmt << "%#7" << radix_fmt << "\t"
508         << "%#7" << radix_fmt << "\t"
509         << "%#7" << radix_fmt << "\t";
510     outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
511     fmtbuf.clear();
512     fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
513         << "%7" PRIx64 "\t";
514     outs() << format(fmt.str().c_str(), total, total);
515   }
516 }
517 
518 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
519 /// is a list of architecture flags specified then check to make sure this
520 /// Mach-O file is one of those architectures or all architectures was
521 /// specificed.  If not then an error is generated and this routine returns
522 /// false.  Else it returns true.
523 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
524   auto *MachO = dyn_cast<MachOObjectFile>(O);
525 
526   if (!MachO || ArchAll || ArchFlags.empty())
527     return true;
528 
529   MachO::mach_header H;
530   MachO::mach_header_64 H_64;
531   Triple T;
532   if (MachO->is64Bit()) {
533     H_64 = MachO->MachOObjectFile::getHeader64();
534     T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
535   } else {
536     H = MachO->MachOObjectFile::getHeader();
537     T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
538   }
539   if (!is_contained(ArchFlags, T.getArchName())) {
540     error("no architecture specified", Filename);
541     return false;
542   }
543   return true;
544 }
545 
546 /// Print the section sizes for @p file. If @p file is an archive, print the
547 /// section sizes for each archive member.
548 static void printFileSectionSizes(StringRef file) {
549 
550   // Attempt to open the binary.
551   Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
552   if (!BinaryOrErr) {
553     error(BinaryOrErr.takeError(), file);
554     return;
555   }
556   Binary &Bin = *BinaryOrErr.get().getBinary();
557 
558   if (Archive *a = dyn_cast<Archive>(&Bin)) {
559     // This is an archive. Iterate over each member and display its sizes.
560     Error Err = Error::success();
561     for (auto &C : a->children(Err)) {
562       Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
563       if (!ChildOrErr) {
564         if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
565           error(std::move(E), a->getFileName(), C);
566         continue;
567       }
568       if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
569         MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
570         if (!checkMachOAndArchFlags(o, file))
571           return;
572         if (OutputFormat == sysv)
573           outs() << o->getFileName() << "   (ex " << a->getFileName() << "):\n";
574         else if (MachO && OutputFormat == darwin)
575           outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
576         printObjectSectionSizes(o);
577         if (!MachO && OutputFormat == darwin)
578           outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
579         if (OutputFormat == berkeley) {
580           if (MachO)
581             outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
582           else
583             outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
584         }
585       }
586     }
587     if (Err)
588       error(std::move(Err), a->getFileName());
589   } else if (MachOUniversalBinary *UB =
590                  dyn_cast<MachOUniversalBinary>(&Bin)) {
591     // If we have a list of architecture flags specified dump only those.
592     if (!ArchAll && !ArchFlags.empty()) {
593       // Look for a slice in the universal binary that matches each ArchFlag.
594       bool ArchFound;
595       for (unsigned i = 0; i < ArchFlags.size(); ++i) {
596         ArchFound = false;
597         for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
598                                                    E = UB->end_objects();
599              I != E; ++I) {
600           if (ArchFlags[i] == I->getArchFlagName()) {
601             ArchFound = true;
602             Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
603             if (UO) {
604               if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
605                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
606                 if (OutputFormat == sysv)
607                   outs() << o->getFileName() << "  :\n";
608                 else if (MachO && OutputFormat == darwin) {
609                   if (MoreThanOneFile || ArchFlags.size() > 1)
610                     outs() << o->getFileName() << " (for architecture "
611                            << I->getArchFlagName() << "): \n";
612                 }
613                 printObjectSectionSizes(o);
614                 if (OutputFormat == berkeley) {
615                   if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
616                     outs() << o->getFileName() << " (for architecture "
617                            << I->getArchFlagName() << ")";
618                   outs() << "\n";
619                 }
620               }
621             } else if (auto E = isNotObjectErrorInvalidFileType(
622                        UO.takeError())) {
623               error(std::move(E), file, ArchFlags.size() > 1 ?
624                     StringRef(I->getArchFlagName()) : StringRef());
625               return;
626             } else if (Expected<std::unique_ptr<Archive>> AOrErr =
627                            I->getAsArchive()) {
628               std::unique_ptr<Archive> &UA = *AOrErr;
629               // This is an archive. Iterate over each member and display its
630               // sizes.
631               Error Err = Error::success();
632               for (auto &C : UA->children(Err)) {
633                 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
634                 if (!ChildOrErr) {
635                   if (auto E = isNotObjectErrorInvalidFileType(
636                                     ChildOrErr.takeError()))
637                     error(std::move(E), UA->getFileName(), C,
638                           ArchFlags.size() > 1 ?
639                           StringRef(I->getArchFlagName()) : StringRef());
640                   continue;
641                 }
642                 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
643                   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
644                   if (OutputFormat == sysv)
645                     outs() << o->getFileName() << "   (ex " << UA->getFileName()
646                            << "):\n";
647                   else if (MachO && OutputFormat == darwin)
648                     outs() << UA->getFileName() << "(" << o->getFileName()
649                            << ")"
650                            << " (for architecture " << I->getArchFlagName()
651                            << "):\n";
652                   printObjectSectionSizes(o);
653                   if (OutputFormat == berkeley) {
654                     if (MachO) {
655                       outs() << UA->getFileName() << "(" << o->getFileName()
656                              << ")";
657                       if (ArchFlags.size() > 1)
658                         outs() << " (for architecture " << I->getArchFlagName()
659                                << ")";
660                       outs() << "\n";
661                     } else
662                       outs() << o->getFileName() << " (ex " << UA->getFileName()
663                              << ")\n";
664                   }
665                 }
666               }
667               if (Err)
668                 error(std::move(Err), UA->getFileName());
669             } else {
670               consumeError(AOrErr.takeError());
671               error("mach-o universal file for architecture " +
672                         StringRef(I->getArchFlagName()) +
673                         " is not a mach-o file or an archive file",
674                     file);
675             }
676           }
677         }
678         if (!ArchFound) {
679           error("file does not contain architecture " + ArchFlags[i], file);
680           return;
681         }
682       }
683       return;
684     }
685     // No architecture flags were specified so if this contains a slice that
686     // matches the host architecture dump only that.
687     if (!ArchAll) {
688       StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
689       for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
690                                                  E = UB->end_objects();
691            I != E; ++I) {
692         if (HostArchName == I->getArchFlagName()) {
693           Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
694           if (UO) {
695             if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
696               MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
697               if (OutputFormat == sysv)
698                 outs() << o->getFileName() << "  :\n";
699               else if (MachO && OutputFormat == darwin) {
700                 if (MoreThanOneFile)
701                   outs() << o->getFileName() << " (for architecture "
702                          << I->getArchFlagName() << "):\n";
703               }
704               printObjectSectionSizes(o);
705               if (OutputFormat == berkeley) {
706                 if (!MachO || MoreThanOneFile)
707                   outs() << o->getFileName() << " (for architecture "
708                          << I->getArchFlagName() << ")";
709                 outs() << "\n";
710               }
711             }
712           } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
713             error(std::move(E), file);
714             return;
715           } else if (Expected<std::unique_ptr<Archive>> AOrErr =
716                          I->getAsArchive()) {
717             std::unique_ptr<Archive> &UA = *AOrErr;
718             // This is an archive. Iterate over each member and display its
719             // sizes.
720             Error Err = Error::success();
721             for (auto &C : UA->children(Err)) {
722               Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
723               if (!ChildOrErr) {
724                 if (auto E = isNotObjectErrorInvalidFileType(
725                                 ChildOrErr.takeError()))
726                   error(std::move(E), UA->getFileName(), C);
727                 continue;
728               }
729               if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
730                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
731                 if (OutputFormat == sysv)
732                   outs() << o->getFileName() << "   (ex " << UA->getFileName()
733                          << "):\n";
734                 else if (MachO && OutputFormat == darwin)
735                   outs() << UA->getFileName() << "(" << o->getFileName() << ")"
736                          << " (for architecture " << I->getArchFlagName()
737                          << "):\n";
738                 printObjectSectionSizes(o);
739                 if (OutputFormat == berkeley) {
740                   if (MachO)
741                     outs() << UA->getFileName() << "(" << o->getFileName()
742                            << ")\n";
743                   else
744                     outs() << o->getFileName() << " (ex " << UA->getFileName()
745                            << ")\n";
746                 }
747               }
748             }
749             if (Err)
750               error(std::move(Err), UA->getFileName());
751           } else {
752             consumeError(AOrErr.takeError());
753             error("mach-o universal file for architecture " +
754                       StringRef(I->getArchFlagName()) +
755                       " is not a mach-o file or an archive file",
756                   file);
757           }
758           return;
759         }
760       }
761     }
762     // Either all architectures have been specified or none have been specified
763     // and this does not contain the host architecture so dump all the slices.
764     bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
765     for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
766                                                E = UB->end_objects();
767          I != E; ++I) {
768       Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
769       if (UO) {
770         if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
771           MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
772           if (OutputFormat == sysv)
773             outs() << o->getFileName() << "  :\n";
774           else if (MachO && OutputFormat == darwin) {
775             if (MoreThanOneFile || MoreThanOneArch)
776               outs() << o->getFileName() << " (for architecture "
777                      << I->getArchFlagName() << "):";
778             outs() << "\n";
779           }
780           printObjectSectionSizes(o);
781           if (OutputFormat == berkeley) {
782             if (!MachO || MoreThanOneFile || MoreThanOneArch)
783               outs() << o->getFileName() << " (for architecture "
784                      << I->getArchFlagName() << ")";
785             outs() << "\n";
786           }
787         }
788       } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
789         error(std::move(E), file, MoreThanOneArch ?
790               StringRef(I->getArchFlagName()) : StringRef());
791         return;
792       } else if (Expected<std::unique_ptr<Archive>> AOrErr =
793                          I->getAsArchive()) {
794         std::unique_ptr<Archive> &UA = *AOrErr;
795         // This is an archive. Iterate over each member and display its sizes.
796         Error Err = Error::success();
797         for (auto &C : UA->children(Err)) {
798           Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
799           if (!ChildOrErr) {
800             if (auto E = isNotObjectErrorInvalidFileType(
801                               ChildOrErr.takeError()))
802               error(std::move(E), UA->getFileName(), C, MoreThanOneArch ?
803                     StringRef(I->getArchFlagName()) : StringRef());
804             continue;
805           }
806           if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
807             MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
808             if (OutputFormat == sysv)
809               outs() << o->getFileName() << "   (ex " << UA->getFileName()
810                      << "):\n";
811             else if (MachO && OutputFormat == darwin)
812               outs() << UA->getFileName() << "(" << o->getFileName() << ")"
813                      << " (for architecture " << I->getArchFlagName() << "):\n";
814             printObjectSectionSizes(o);
815             if (OutputFormat == berkeley) {
816               if (MachO)
817                 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
818                        << " (for architecture " << I->getArchFlagName()
819                        << ")\n";
820               else
821                 outs() << o->getFileName() << " (ex " << UA->getFileName()
822                        << ")\n";
823             }
824           }
825         }
826         if (Err)
827           error(std::move(Err), UA->getFileName());
828       } else {
829         consumeError(AOrErr.takeError());
830         error("mach-o universal file for architecture " +
831                   StringRef(I->getArchFlagName()) +
832                   " is not a mach-o file or an archive file",
833               file);
834       }
835     }
836   } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
837     if (!checkMachOAndArchFlags(o, file))
838       return;
839     MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
840     if (OutputFormat == sysv)
841       outs() << o->getFileName() << "  :\n";
842     else if (MachO && OutputFormat == darwin && MoreThanOneFile)
843       outs() << o->getFileName() << ":\n";
844     printObjectSectionSizes(o);
845     if (!MachO && OutputFormat == darwin)
846       outs() << o->getFileName() << "\n";
847     if (OutputFormat == berkeley) {
848       if (!MachO || MoreThanOneFile)
849         outs() << o->getFileName();
850       outs() << "\n";
851     }
852   } else {
853     error("unsupported file type", file);
854   }
855 }
856 
857 static void printBerkeleyTotals() {
858   std::string fmtbuf;
859   raw_string_ostream fmt(fmtbuf);
860   const char *radix_fmt = getRadixFmt();
861   fmt << "%#7" << radix_fmt << "\t"
862       << "%#7" << radix_fmt << "\t"
863       << "%#7" << radix_fmt << "\t";
864   outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData,
865                    TotalObjectBss);
866   fmtbuf.clear();
867   fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
868       << "%7" PRIx64 "\t";
869   outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal)
870          << "(TOTALS)\n";
871 }
872 
873 int llvm_size_main(int argc, char **argv, const llvm::ToolContext &) {
874   InitLLVM X(argc, argv);
875   BumpPtrAllocator A;
876   StringSaver Saver(A);
877   SizeOptTable Tbl;
878   ToolName = argv[0];
879   opt::InputArgList Args =
880       Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
881         error(Msg);
882         exit(1);
883       });
884   if (Args.hasArg(OPT_help)) {
885     Tbl.printHelp(
886         outs(),
887         (Twine(ToolName) + " [options] <input object files>").str().c_str(),
888         "LLVM object size dumper");
889     // TODO Replace this with OptTable API once it adds extrahelp support.
890     outs() << "\nPass @FILE as argument to read options from FILE.\n";
891     return 0;
892   }
893   if (Args.hasArg(OPT_version)) {
894     outs() << ToolName << '\n';
895     cl::PrintVersionMessage();
896     return 0;
897   }
898 
899   ELFCommons = Args.hasArg(OPT_common);
900   DarwinLongFormat = Args.hasArg(OPT_l);
901   TotalSizes = Args.hasArg(OPT_totals);
902   StringRef V = Args.getLastArgValue(OPT_format_EQ, "berkeley");
903   if (V == "berkeley")
904     OutputFormat = berkeley;
905   else if (V == "darwin")
906     OutputFormat = darwin;
907   else if (V == "sysv")
908     OutputFormat = sysv;
909   else
910     error("--format value should be one of: 'berkeley', 'darwin', 'sysv'");
911   V = Args.getLastArgValue(OPT_radix_EQ, "10");
912   if (V == "8")
913     Radix = RadixTy::octal;
914   else if (V == "10")
915     Radix = RadixTy::decimal;
916   else if (V == "16")
917     Radix = RadixTy::hexadecimal;
918   else
919     error("--radix value should be one of: 8, 10, 16 ");
920 
921   for (const auto *A : Args.filtered(OPT_arch_EQ)) {
922     SmallVector<StringRef, 2> Values;
923     llvm::SplitString(A->getValue(), Values, ",");
924     for (StringRef V : Values) {
925       if (V == "all")
926         ArchAll = true;
927       else if (MachOObjectFile::isValidArch(V))
928         ArchFlags.push_back(V);
929       else {
930         outs() << ToolName << ": for the -arch option: Unknown architecture "
931                << "named '" << V << "'";
932         return 1;
933       }
934     }
935   }
936 
937   InputFilenames = Args.getAllArgValues(OPT_INPUT);
938   if (InputFilenames.empty())
939     InputFilenames.push_back("a.out");
940 
941   MoreThanOneFile = InputFilenames.size() > 1;
942   llvm::for_each(InputFilenames, printFileSectionSizes);
943   if (OutputFormat == berkeley && TotalSizes)
944     printBerkeleyTotals();
945 
946   if (HadError)
947     return 1;
948   return 0;
949 }
950