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