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"), clEnumValEnd),
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"), clEnumValEnd),
51     cl::init(berkeley));
52 
53 static bool BerkeleyHeaderPrinted = false;
54 static bool MoreThanOneFile = false;
55 
56 cl::opt<bool>
57 DarwinLongFormat("l", cl::desc("When format is darwin, use long format "
58                                "to include addresses and offsets."));
59 
60 static cl::list<std::string>
61 ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
62           cl::ZeroOrMore);
63 bool ArchAll = false;
64 
65 enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
66 static cl::opt<unsigned int>
67 Radix("-radix", cl::desc("Print size in radix. Only 8, 10, and 16 are valid"),
68       cl::init(decimal));
69 
70 static cl::opt<RadixTy>
71 RadixShort(cl::desc("Print size in radix:"),
72            cl::values(clEnumValN(octal, "o", "Print size in octal"),
73                       clEnumValN(decimal, "d", "Print size in decimal"),
74                       clEnumValN(hexadecimal, "x", "Print size in hexadecimal"),
75                       clEnumValEnd),
76            cl::init(decimal));
77 
78 static cl::list<std::string>
79 InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
80 
81 static std::string ToolName;
82 
83 /// If ec is not success, print the error and return true.
84 static bool error(std::error_code ec) {
85   if (!ec)
86     return false;
87 
88   errs() << ToolName << ": error reading file: " << ec.message() << ".\n";
89   errs().flush();
90   return true;
91 }
92 
93 /// Get the length of the string that represents @p num in Radix including the
94 /// leading 0x or 0 for hexadecimal and octal respectively.
95 static size_t getNumLengthAsString(uint64_t num) {
96   APInt conv(64, num);
97   SmallString<32> result;
98   conv.toString(result, Radix, false, true);
99   return result.size();
100 }
101 
102 /// Return the printing format for the Radix.
103 static const char *getRadixFmt() {
104   switch (Radix) {
105   case octal:
106     return PRIo64;
107   case decimal:
108     return PRIu64;
109   case hexadecimal:
110     return PRIx64;
111   }
112   return nullptr;
113 }
114 
115 /// Remove unneeded ELF sections from calculation
116 static bool considerForSize(ObjectFile *Obj, SectionRef Section) {
117   if (!Obj->isELF())
118     return true;
119   switch (static_cast<ELFSectionRef>(Section).getType()) {
120   case ELF::SHT_NULL:
121   case ELF::SHT_SYMTAB:
122   case ELF::SHT_STRTAB:
123   case ELF::SHT_REL:
124   case ELF::SHT_RELA:
125     return false;
126   }
127   return true;
128 }
129 
130 /// Print the size of each Mach-O segment and section in @p MachO.
131 ///
132 /// This is when used when @c OutputFormat is darwin and produces the same
133 /// output as darwin's size(1) -m output.
134 static void printDarwinSectionSizes(MachOObjectFile *MachO) {
135   std::string fmtbuf;
136   raw_string_ostream fmt(fmtbuf);
137   const char *radix_fmt = getRadixFmt();
138   if (Radix == hexadecimal)
139     fmt << "0x";
140   fmt << "%" << radix_fmt;
141 
142   uint32_t Filetype = MachO->getHeader().filetype;
143 
144   uint64_t total = 0;
145   for (const auto &Load : MachO->load_commands()) {
146     if (Load.C.cmd == MachO::LC_SEGMENT_64) {
147       MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
148       outs() << "Segment " << Seg.segname << ": "
149              << format(fmt.str().c_str(), Seg.vmsize);
150       if (DarwinLongFormat)
151         outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
152                << Seg.fileoff << ")";
153       outs() << "\n";
154       total += Seg.vmsize;
155       uint64_t sec_total = 0;
156       for (unsigned J = 0; J < Seg.nsects; ++J) {
157         MachO::section_64 Sec = MachO->getSection64(Load, J);
158         if (Filetype == MachO::MH_OBJECT)
159           outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
160                  << format("%.16s", &Sec.sectname) << "): ";
161         else
162           outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
163         outs() << format(fmt.str().c_str(), Sec.size);
164         if (DarwinLongFormat)
165           outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
166                  << Sec.offset << ")";
167         outs() << "\n";
168         sec_total += Sec.size;
169       }
170       if (Seg.nsects != 0)
171         outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
172     } else if (Load.C.cmd == MachO::LC_SEGMENT) {
173       MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
174       uint64_t Seg_vmsize = Seg.vmsize;
175       outs() << "Segment " << Seg.segname << ": "
176              << format(fmt.str().c_str(), Seg_vmsize);
177       if (DarwinLongFormat)
178         outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff "
179                << Seg.fileoff << ")";
180       outs() << "\n";
181       total += Seg.vmsize;
182       uint64_t sec_total = 0;
183       for (unsigned J = 0; J < Seg.nsects; ++J) {
184         MachO::section Sec = MachO->getSection(Load, J);
185         if (Filetype == MachO::MH_OBJECT)
186           outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
187                  << format("%.16s", &Sec.sectname) << "): ";
188         else
189           outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
190         uint64_t Sec_size = Sec.size;
191         outs() << format(fmt.str().c_str(), Sec_size);
192         if (DarwinLongFormat)
193           outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset "
194                  << Sec.offset << ")";
195         outs() << "\n";
196         sec_total += Sec.size;
197       }
198       if (Seg.nsects != 0)
199         outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
200     }
201   }
202   outs() << "total " << format(fmt.str().c_str(), total) << "\n";
203 }
204 
205 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
206 ///
207 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
208 /// produces the same output as darwin's size(1) default output.
209 static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
210   uint64_t total_text = 0;
211   uint64_t total_data = 0;
212   uint64_t total_objc = 0;
213   uint64_t total_others = 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       if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
218         for (unsigned J = 0; J < Seg.nsects; ++J) {
219           MachO::section_64 Sec = MachO->getSection64(Load, J);
220           StringRef SegmentName = StringRef(Sec.segname);
221           if (SegmentName == "__TEXT")
222             total_text += Sec.size;
223           else if (SegmentName == "__DATA")
224             total_data += Sec.size;
225           else if (SegmentName == "__OBJC")
226             total_objc += Sec.size;
227           else
228             total_others += Sec.size;
229         }
230       } else {
231         StringRef SegmentName = StringRef(Seg.segname);
232         if (SegmentName == "__TEXT")
233           total_text += Seg.vmsize;
234         else if (SegmentName == "__DATA")
235           total_data += Seg.vmsize;
236         else if (SegmentName == "__OBJC")
237           total_objc += Seg.vmsize;
238         else
239           total_others += Seg.vmsize;
240       }
241     } else if (Load.C.cmd == MachO::LC_SEGMENT) {
242       MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
243       if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
244         for (unsigned J = 0; J < Seg.nsects; ++J) {
245           MachO::section Sec = MachO->getSection(Load, J);
246           StringRef SegmentName = StringRef(Sec.segname);
247           if (SegmentName == "__TEXT")
248             total_text += Sec.size;
249           else if (SegmentName == "__DATA")
250             total_data += Sec.size;
251           else if (SegmentName == "__OBJC")
252             total_objc += Sec.size;
253           else
254             total_others += Sec.size;
255         }
256       } else {
257         StringRef SegmentName = StringRef(Seg.segname);
258         if (SegmentName == "__TEXT")
259           total_text += Seg.vmsize;
260         else if (SegmentName == "__DATA")
261           total_data += Seg.vmsize;
262         else if (SegmentName == "__OBJC")
263           total_objc += Seg.vmsize;
264         else
265           total_others += Seg.vmsize;
266       }
267     }
268   }
269   uint64_t total = total_text + total_data + total_objc + total_others;
270 
271   if (!BerkeleyHeaderPrinted) {
272     outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
273     BerkeleyHeaderPrinted = true;
274   }
275   outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
276          << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
277          << "\t";
278 }
279 
280 /// Print the size of each section in @p Obj.
281 ///
282 /// The format used is determined by @c OutputFormat and @c Radix.
283 static void printObjectSectionSizes(ObjectFile *Obj) {
284   uint64_t total = 0;
285   std::string fmtbuf;
286   raw_string_ostream fmt(fmtbuf);
287   const char *radix_fmt = getRadixFmt();
288 
289   // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
290   // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
291   // let it fall through to OutputFormat berkeley.
292   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
293   if (OutputFormat == darwin && MachO)
294     printDarwinSectionSizes(MachO);
295   // If we have a MachOObjectFile and the OutputFormat is berkeley print as
296   // darwin's default berkeley format for Mach-O files.
297   else if (MachO && OutputFormat == berkeley)
298     printDarwinSegmentSizes(MachO);
299   else if (OutputFormat == sysv) {
300     // Run two passes over all sections. The first gets the lengths needed for
301     // formatting the output. The second actually does the output.
302     std::size_t max_name_len = strlen("section");
303     std::size_t max_size_len = strlen("size");
304     std::size_t max_addr_len = strlen("addr");
305     for (const SectionRef &Section : Obj->sections()) {
306       if (!considerForSize(Obj, Section))
307         continue;
308       uint64_t size = Section.getSize();
309       total += size;
310 
311       StringRef name;
312       if (error(Section.getName(name)))
313         return;
314       uint64_t addr = Section.getAddress();
315       max_name_len = std::max(max_name_len, name.size());
316       max_size_len = std::max(max_size_len, getNumLengthAsString(size));
317       max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
318     }
319 
320     // Add extra padding.
321     max_name_len += 2;
322     max_size_len += 2;
323     max_addr_len += 2;
324 
325     // Setup header format.
326     fmt << "%-" << max_name_len << "s "
327         << "%" << max_size_len << "s "
328         << "%" << max_addr_len << "s\n";
329 
330     // Print header
331     outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
332                      static_cast<const char *>("size"),
333                      static_cast<const char *>("addr"));
334     fmtbuf.clear();
335 
336     // Setup per section format.
337     fmt << "%-" << max_name_len << "s "
338         << "%#" << max_size_len << radix_fmt << " "
339         << "%#" << max_addr_len << radix_fmt << "\n";
340 
341     // Print each section.
342     for (const SectionRef &Section : Obj->sections()) {
343       if (!considerForSize(Obj, Section))
344         continue;
345       StringRef name;
346       if (error(Section.getName(name)))
347         return;
348       uint64_t size = Section.getSize();
349       uint64_t addr = Section.getAddress();
350       std::string namestr = name;
351 
352       outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr);
353     }
354 
355     // Print total.
356     fmtbuf.clear();
357     fmt << "%-" << max_name_len << "s "
358         << "%#" << max_size_len << radix_fmt << "\n";
359     outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
360                      total);
361   } else {
362     // The Berkeley format does not display individual section sizes. It
363     // displays the cumulative size for each section type.
364     uint64_t total_text = 0;
365     uint64_t total_data = 0;
366     uint64_t total_bss = 0;
367 
368     // Make one pass over the section table to calculate sizes.
369     for (const SectionRef &Section : Obj->sections()) {
370       uint64_t size = Section.getSize();
371       bool isText = Section.isText();
372       bool isData = Section.isData();
373       bool isBSS = Section.isBSS();
374       if (isText)
375         total_text += size;
376       else if (isData)
377         total_data += size;
378       else if (isBSS)
379         total_bss += size;
380     }
381 
382     total = total_text + total_data + total_bss;
383 
384     if (!BerkeleyHeaderPrinted) {
385       outs() << "   text    data     bss     "
386              << (Radix == octal ? "oct" : "dec") << "     hex filename\n";
387       BerkeleyHeaderPrinted = true;
388     }
389 
390     // Print result.
391     fmt << "%#7" << radix_fmt << " "
392         << "%#7" << radix_fmt << " "
393         << "%#7" << radix_fmt << " ";
394     outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
395     fmtbuf.clear();
396     fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " "
397         << "%7" PRIx64 " ";
398     outs() << format(fmt.str().c_str(), total, total);
399   }
400 }
401 
402 /// Checks to see if the @p o ObjectFile is a Mach-O file and if it is and there
403 /// is a list of architecture flags specified then check to make sure this
404 /// Mach-O file is one of those architectures or all architectures was
405 /// specificed.  If not then an error is generated and this routine returns
406 /// false.  Else it returns true.
407 static bool checkMachOAndArchFlags(ObjectFile *o, StringRef file) {
408   if (isa<MachOObjectFile>(o) && !ArchAll && ArchFlags.size() != 0) {
409     MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
410     bool ArchFound = false;
411     MachO::mach_header H;
412     MachO::mach_header_64 H_64;
413     Triple T;
414     if (MachO->is64Bit()) {
415       H_64 = MachO->MachOObjectFile::getHeader64();
416       T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype);
417     } else {
418       H = MachO->MachOObjectFile::getHeader();
419       T = MachOObjectFile::getArch(H.cputype, H.cpusubtype);
420     }
421     unsigned i;
422     for (i = 0; i < ArchFlags.size(); ++i) {
423       if (ArchFlags[i] == T.getArchName())
424         ArchFound = true;
425       break;
426     }
427     if (!ArchFound) {
428       errs() << ToolName << ": file: " << file
429              << " does not contain architecture: " << ArchFlags[i] << ".\n";
430       return false;
431     }
432   }
433   return true;
434 }
435 
436 /// Print the section sizes for @p file. If @p file is an archive, print the
437 /// section sizes for each archive member.
438 static void printFileSectionSizes(StringRef file) {
439 
440   // Attempt to open the binary.
441   ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
442   if (error(BinaryOrErr.getError()))
443     return;
444   Binary &Bin = *BinaryOrErr.get().getBinary();
445 
446   if (Archive *a = dyn_cast<Archive>(&Bin)) {
447     // This is an archive. Iterate over each member and display its sizes.
448     for (object::Archive::child_iterator i = a->child_begin(),
449                                          e = a->child_end();
450          i != e; ++i) {
451       if (error(i->getError()))
452         exit(1);
453       ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->get().getAsBinary();
454       if (error(ChildOrErr.getError()))
455         continue;
456       if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
457         MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
458         if (!checkMachOAndArchFlags(o, file))
459           return;
460         if (OutputFormat == sysv)
461           outs() << o->getFileName() << "   (ex " << a->getFileName() << "):\n";
462         else if (MachO && OutputFormat == darwin)
463           outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
464         printObjectSectionSizes(o);
465         if (OutputFormat == berkeley) {
466           if (MachO)
467             outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
468           else
469             outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
470         }
471       }
472     }
473   } else if (MachOUniversalBinary *UB =
474                  dyn_cast<MachOUniversalBinary>(&Bin)) {
475     // If we have a list of architecture flags specified dump only those.
476     if (!ArchAll && ArchFlags.size() != 0) {
477       // Look for a slice in the universal binary that matches each ArchFlag.
478       bool ArchFound;
479       for (unsigned i = 0; i < ArchFlags.size(); ++i) {
480         ArchFound = false;
481         for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
482                                                    E = UB->end_objects();
483              I != E; ++I) {
484           if (ArchFlags[i] == I->getArchTypeName()) {
485             ArchFound = true;
486             ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
487             if (UO) {
488               if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
489                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
490                 if (OutputFormat == sysv)
491                   outs() << o->getFileName() << "  :\n";
492                 else if (MachO && OutputFormat == darwin) {
493                   if (MoreThanOneFile || ArchFlags.size() > 1)
494                     outs() << o->getFileName() << " (for architecture "
495                            << I->getArchTypeName() << "): \n";
496                 }
497                 printObjectSectionSizes(o);
498                 if (OutputFormat == berkeley) {
499                   if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
500                     outs() << o->getFileName() << " (for architecture "
501                            << I->getArchTypeName() << ")";
502                   outs() << "\n";
503                 }
504               }
505             } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
506                            I->getAsArchive()) {
507               std::unique_ptr<Archive> &UA = *AOrErr;
508               // This is an archive. Iterate over each member and display its
509               // sizes.
510               for (object::Archive::child_iterator i = UA->child_begin(),
511                                                    e = UA->child_end();
512                    i != e; ++i) {
513                 if (error(i->getError()))
514                   exit(1);
515                 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->get().getAsBinary();
516                 if (error(ChildOrErr.getError()))
517                   continue;
518                 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
519                   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
520                   if (OutputFormat == sysv)
521                     outs() << o->getFileName() << "   (ex " << UA->getFileName()
522                            << "):\n";
523                   else if (MachO && OutputFormat == darwin)
524                     outs() << UA->getFileName() << "(" << o->getFileName()
525                            << ")"
526                            << " (for architecture " << I->getArchTypeName()
527                            << "):\n";
528                   printObjectSectionSizes(o);
529                   if (OutputFormat == berkeley) {
530                     if (MachO) {
531                       outs() << UA->getFileName() << "(" << o->getFileName()
532                              << ")";
533                       if (ArchFlags.size() > 1)
534                         outs() << " (for architecture " << I->getArchTypeName()
535                                << ")";
536                       outs() << "\n";
537                     } else
538                       outs() << o->getFileName() << " (ex " << UA->getFileName()
539                              << ")\n";
540                   }
541                 }
542               }
543             }
544           }
545         }
546         if (!ArchFound) {
547           errs() << ToolName << ": file: " << file
548                  << " does not contain architecture" << ArchFlags[i] << ".\n";
549           return;
550         }
551       }
552       return;
553     }
554     // No architecture flags were specified so if this contains a slice that
555     // matches the host architecture dump only that.
556     if (!ArchAll) {
557       StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
558       for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
559                                                  E = UB->end_objects();
560            I != E; ++I) {
561         if (HostArchName == I->getArchTypeName()) {
562           ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
563           if (UO) {
564             if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
565               MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
566               if (OutputFormat == sysv)
567                 outs() << o->getFileName() << "  :\n";
568               else if (MachO && OutputFormat == darwin) {
569                 if (MoreThanOneFile)
570                   outs() << o->getFileName() << " (for architecture "
571                          << I->getArchTypeName() << "):\n";
572               }
573               printObjectSectionSizes(o);
574               if (OutputFormat == berkeley) {
575                 if (!MachO || MoreThanOneFile)
576                   outs() << o->getFileName() << " (for architecture "
577                          << I->getArchTypeName() << ")";
578                 outs() << "\n";
579               }
580             }
581           } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
582                          I->getAsArchive()) {
583             std::unique_ptr<Archive> &UA = *AOrErr;
584             // This is an archive. Iterate over each member and display its
585             // sizes.
586             for (object::Archive::child_iterator i = UA->child_begin(),
587                                                  e = UA->child_end();
588                  i != e; ++i) {
589               if (error(i->getError()))
590                 exit(1);
591               ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->get().getAsBinary();
592               if (error(ChildOrErr.getError()))
593                 continue;
594               if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
595                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
596                 if (OutputFormat == sysv)
597                   outs() << o->getFileName() << "   (ex " << UA->getFileName()
598                          << "):\n";
599                 else if (MachO && OutputFormat == darwin)
600                   outs() << UA->getFileName() << "(" << o->getFileName() << ")"
601                          << " (for architecture " << I->getArchTypeName()
602                          << "):\n";
603                 printObjectSectionSizes(o);
604                 if (OutputFormat == berkeley) {
605                   if (MachO)
606                     outs() << UA->getFileName() << "(" << o->getFileName()
607                            << ")\n";
608                   else
609                     outs() << o->getFileName() << " (ex " << UA->getFileName()
610                            << ")\n";
611                 }
612               }
613             }
614           }
615           return;
616         }
617       }
618     }
619     // Either all architectures have been specified or none have been specified
620     // and this does not contain the host architecture so dump all the slices.
621     bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
622     for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
623                                                E = UB->end_objects();
624          I != E; ++I) {
625       ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
626       if (UO) {
627         if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
628           MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
629           if (OutputFormat == sysv)
630             outs() << o->getFileName() << "  :\n";
631           else if (MachO && OutputFormat == darwin) {
632             if (MoreThanOneFile || MoreThanOneArch)
633               outs() << o->getFileName() << " (for architecture "
634                      << I->getArchTypeName() << "):";
635             outs() << "\n";
636           }
637           printObjectSectionSizes(o);
638           if (OutputFormat == berkeley) {
639             if (!MachO || MoreThanOneFile || MoreThanOneArch)
640               outs() << o->getFileName() << " (for architecture "
641                      << I->getArchTypeName() << ")";
642             outs() << "\n";
643           }
644         }
645       } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
646                          I->getAsArchive()) {
647         std::unique_ptr<Archive> &UA = *AOrErr;
648         // This is an archive. Iterate over each member and display its sizes.
649         for (object::Archive::child_iterator i = UA->child_begin(),
650                                              e = UA->child_end();
651              i != e; ++i) {
652           if (error(i->getError()))
653             exit(1);
654           ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->get().getAsBinary();
655           if (error(ChildOrErr.getError()))
656             continue;
657           if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
658             MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
659             if (OutputFormat == sysv)
660               outs() << o->getFileName() << "   (ex " << UA->getFileName()
661                      << "):\n";
662             else if (MachO && OutputFormat == darwin)
663               outs() << UA->getFileName() << "(" << o->getFileName() << ")"
664                      << " (for architecture " << I->getArchTypeName() << "):\n";
665             printObjectSectionSizes(o);
666             if (OutputFormat == berkeley) {
667               if (MachO)
668                 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
669                        << " (for architecture " << I->getArchTypeName()
670                        << ")\n";
671               else
672                 outs() << o->getFileName() << " (ex " << UA->getFileName()
673                        << ")\n";
674             }
675           }
676         }
677       }
678     }
679   } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
680     if (!checkMachOAndArchFlags(o, file))
681       return;
682     if (OutputFormat == sysv)
683       outs() << o->getFileName() << "  :\n";
684     printObjectSectionSizes(o);
685     if (OutputFormat == berkeley) {
686       MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
687       if (!MachO || MoreThanOneFile)
688         outs() << o->getFileName();
689       outs() << "\n";
690     }
691   } else {
692     errs() << ToolName << ": " << file << ": "
693            << "Unrecognized file type.\n";
694   }
695   // System V adds an extra newline at the end of each file.
696   if (OutputFormat == sysv)
697     outs() << "\n";
698 }
699 
700 int main(int argc, char **argv) {
701   // Print a stack trace if we signal out.
702   sys::PrintStackTraceOnErrorSignal();
703   PrettyStackTraceProgram X(argc, argv);
704 
705   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
706   cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
707 
708   ToolName = argv[0];
709   if (OutputFormatShort.getNumOccurrences())
710     OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
711   if (RadixShort.getNumOccurrences())
712     Radix = RadixShort;
713 
714   for (unsigned i = 0; i < ArchFlags.size(); ++i) {
715     if (ArchFlags[i] == "all") {
716       ArchAll = true;
717     } else {
718       if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
719         outs() << ToolName << ": for the -arch option: Unknown architecture "
720                << "named '" << ArchFlags[i] << "'";
721         return 1;
722       }
723     }
724   }
725 
726   if (InputFilenames.size() == 0)
727     InputFilenames.push_back("a.out");
728 
729   MoreThanOneFile = InputFilenames.size() > 1;
730   std::for_each(InputFilenames.begin(), InputFilenames.end(),
731                 printFileSectionSizes);
732 
733   return 0;
734 }
735