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