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