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