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/InitLLVM.h"
27 #include "llvm/Support/MemoryBuffer.h"
28 #include "llvm/Support/raw_ostream.h"
29 #include <algorithm>
30 #include <string>
31 #include <system_error>
32 
33 using namespace llvm;
34 using namespace object;
35 
36 enum OutputFormatTy { berkeley, sysv, darwin };
37 static cl::opt<OutputFormatTy>
38 OutputFormat("format", cl::desc("Specify output format"),
39              cl::values(clEnumVal(sysv, "System V format"),
40                         clEnumVal(berkeley, "Berkeley format"),
41                         clEnumVal(darwin, "Darwin -m format")),
42              cl::init(berkeley));
43 
44 static cl::opt<OutputFormatTy> OutputFormatShort(
45     cl::desc("Specify output format"),
46     cl::values(clEnumValN(sysv, "A", "System V format"),
47                clEnumValN(berkeley, "B", "Berkeley format"),
48                clEnumValN(darwin, "m", "Darwin -m format")),
49     cl::init(berkeley));
50 
51 static bool BerkeleyHeaderPrinted = false;
52 static bool MoreThanOneFile = false;
53 static uint64_t TotalObjectText = 0;
54 static uint64_t TotalObjectData = 0;
55 static uint64_t TotalObjectBss = 0;
56 static uint64_t TotalObjectTotal = 0;
57 
58 cl::opt<bool>
59 DarwinLongFormat("l", cl::desc("When format is darwin, use long format "
60                                "to include addresses and offsets."));
61 
62 cl::opt<bool>
63     ELFCommons("common",
64                cl::desc("Print common symbols in the ELF file.  When using "
65                         "Berkely format, this is added to bss."),
66                cl::init(false));
67 
68 static cl::list<std::string>
69 ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
70           cl::ZeroOrMore);
71 static bool ArchAll = false;
72 
73 enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
74 static cl::opt<RadixTy> Radix(
75     "radix", cl::desc("Print size in radix"), cl::init(decimal),
76     cl::values(clEnumValN(octal, "8", "Print size in octal"),
77                clEnumValN(decimal, "10", "Print size in decimal"),
78                clEnumValN(hexadecimal, "16", "Print size in hexadecimal")));
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 static 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.isBerkeleyText();
461       bool isData = Section.isBerkeleyData();
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\t"
485                 "   data\t"
486                 "    bss\t"
487                 "    "
488              << (Radix == octal ? "oct" : "dec")
489              << "\t"
490                 "    hex\t"
491                 "filename\n";
492       BerkeleyHeaderPrinted = true;
493     }
494 
495     // Print result.
496     fmt << "%#7" << radix_fmt << "\t"
497         << "%#7" << radix_fmt << "\t"
498         << "%#7" << radix_fmt << "\t";
499     outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
500     fmtbuf.clear();
501     fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
502         << "%7" PRIx64 "\t";
503     outs() << format(fmt.str().c_str(), total, total);
504   }
505 }
506 
507 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
508 /// is a list of architecture flags specified then check to make sure this
509 /// Mach-O file is one of those architectures or all architectures was
510 /// specificed.  If not then an error is generated and this routine returns
511 /// false.  Else it returns true.
512 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
513   auto *MachO = dyn_cast<MachOObjectFile>(O);
514 
515   if (!MachO || ArchAll || ArchFlags.empty())
516     return true;
517 
518   MachO::mach_header H;
519   MachO::mach_header_64 H_64;
520   Triple T;
521   if (MachO->is64Bit()) {
522     H_64 = MachO->MachOObjectFile::getHeader64();
523     T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
524   } else {
525     H = MachO->MachOObjectFile::getHeader();
526     T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
527   }
528   if (none_of(ArchFlags, [&](const std::string &Name) {
529         return Name == T.getArchName();
530       })) {
531     error(Filename + ": No architecture specified");
532     return false;
533   }
534   return true;
535 }
536 
537 /// Print the section sizes for @p file. If @p file is an archive, print the
538 /// section sizes for each archive member.
539 static void printFileSectionSizes(StringRef file) {
540 
541   // Attempt to open the binary.
542   Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
543   if (!BinaryOrErr) {
544     error(BinaryOrErr.takeError(), file);
545     return;
546   }
547   Binary &Bin = *BinaryOrErr.get().getBinary();
548 
549   if (Archive *a = dyn_cast<Archive>(&Bin)) {
550     // This is an archive. Iterate over each member and display its sizes.
551     Error Err = Error::success();
552     for (auto &C : a->children(Err)) {
553       Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
554       if (!ChildOrErr) {
555         if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
556           error(std::move(E), a->getFileName(), C);
557         continue;
558       }
559       if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
560         MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
561         if (!checkMachOAndArchFlags(o, file))
562           return;
563         if (OutputFormat == sysv)
564           outs() << o->getFileName() << "   (ex " << a->getFileName() << "):\n";
565         else if (MachO && OutputFormat == darwin)
566           outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
567         printObjectSectionSizes(o);
568         if (OutputFormat == berkeley) {
569           if (MachO)
570             outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
571           else
572             outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
573         }
574       }
575     }
576     if (Err)
577       error(std::move(Err), a->getFileName());
578   } else if (MachOUniversalBinary *UB =
579                  dyn_cast<MachOUniversalBinary>(&Bin)) {
580     // If we have a list of architecture flags specified dump only those.
581     if (!ArchAll && !ArchFlags.empty()) {
582       // Look for a slice in the universal binary that matches each ArchFlag.
583       bool ArchFound;
584       for (unsigned i = 0; i < ArchFlags.size(); ++i) {
585         ArchFound = false;
586         for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
587                                                    E = UB->end_objects();
588              I != E; ++I) {
589           if (ArchFlags[i] == I->getArchFlagName()) {
590             ArchFound = true;
591             Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
592             if (UO) {
593               if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
594                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
595                 if (OutputFormat == sysv)
596                   outs() << o->getFileName() << "  :\n";
597                 else if (MachO && OutputFormat == darwin) {
598                   if (MoreThanOneFile || ArchFlags.size() > 1)
599                     outs() << o->getFileName() << " (for architecture "
600                            << I->getArchFlagName() << "): \n";
601                 }
602                 printObjectSectionSizes(o);
603                 if (OutputFormat == berkeley) {
604                   if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
605                     outs() << o->getFileName() << " (for architecture "
606                            << I->getArchFlagName() << ")";
607                   outs() << "\n";
608                 }
609               }
610             } else if (auto E = isNotObjectErrorInvalidFileType(
611                        UO.takeError())) {
612               error(std::move(E), file, ArchFlags.size() > 1 ?
613                     StringRef(I->getArchFlagName()) : StringRef());
614               return;
615             } else if (Expected<std::unique_ptr<Archive>> AOrErr =
616                            I->getAsArchive()) {
617               std::unique_ptr<Archive> &UA = *AOrErr;
618               // This is an archive. Iterate over each member and display its
619               // sizes.
620               Error Err = Error::success();
621               for (auto &C : UA->children(Err)) {
622                 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
623                 if (!ChildOrErr) {
624                   if (auto E = isNotObjectErrorInvalidFileType(
625                                     ChildOrErr.takeError()))
626                     error(std::move(E), UA->getFileName(), C,
627                           ArchFlags.size() > 1 ?
628                           StringRef(I->getArchFlagName()) : StringRef());
629                   continue;
630                 }
631                 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
632                   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
633                   if (OutputFormat == sysv)
634                     outs() << o->getFileName() << "   (ex " << UA->getFileName()
635                            << "):\n";
636                   else if (MachO && OutputFormat == darwin)
637                     outs() << UA->getFileName() << "(" << o->getFileName()
638                            << ")"
639                            << " (for architecture " << I->getArchFlagName()
640                            << "):\n";
641                   printObjectSectionSizes(o);
642                   if (OutputFormat == berkeley) {
643                     if (MachO) {
644                       outs() << UA->getFileName() << "(" << o->getFileName()
645                              << ")";
646                       if (ArchFlags.size() > 1)
647                         outs() << " (for architecture " << I->getArchFlagName()
648                                << ")";
649                       outs() << "\n";
650                     } else
651                       outs() << o->getFileName() << " (ex " << UA->getFileName()
652                              << ")\n";
653                   }
654                 }
655               }
656               if (Err)
657                 error(std::move(Err), UA->getFileName());
658             } else {
659               consumeError(AOrErr.takeError());
660               error("Mach-O universal file: " + file + " for architecture " +
661                     StringRef(I->getArchFlagName()) +
662                     " is not a Mach-O file or an archive file");
663             }
664           }
665         }
666         if (!ArchFound) {
667           errs() << ToolName << ": file: " << file
668                  << " does not contain architecture" << ArchFlags[i] << ".\n";
669           return;
670         }
671       }
672       return;
673     }
674     // No architecture flags were specified so if this contains a slice that
675     // matches the host architecture dump only that.
676     if (!ArchAll) {
677       StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
678       for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
679                                                  E = UB->end_objects();
680            I != E; ++I) {
681         if (HostArchName == I->getArchFlagName()) {
682           Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
683           if (UO) {
684             if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
685               MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
686               if (OutputFormat == sysv)
687                 outs() << o->getFileName() << "  :\n";
688               else if (MachO && OutputFormat == darwin) {
689                 if (MoreThanOneFile)
690                   outs() << o->getFileName() << " (for architecture "
691                          << I->getArchFlagName() << "):\n";
692               }
693               printObjectSectionSizes(o);
694               if (OutputFormat == berkeley) {
695                 if (!MachO || MoreThanOneFile)
696                   outs() << o->getFileName() << " (for architecture "
697                          << I->getArchFlagName() << ")";
698                 outs() << "\n";
699               }
700             }
701           } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
702             error(std::move(E), file);
703             return;
704           } else if (Expected<std::unique_ptr<Archive>> AOrErr =
705                          I->getAsArchive()) {
706             std::unique_ptr<Archive> &UA = *AOrErr;
707             // This is an archive. Iterate over each member and display its
708             // sizes.
709             Error Err = Error::success();
710             for (auto &C : UA->children(Err)) {
711               Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
712               if (!ChildOrErr) {
713                 if (auto E = isNotObjectErrorInvalidFileType(
714                                 ChildOrErr.takeError()))
715                   error(std::move(E), UA->getFileName(), C);
716                 continue;
717               }
718               if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
719                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
720                 if (OutputFormat == sysv)
721                   outs() << o->getFileName() << "   (ex " << UA->getFileName()
722                          << "):\n";
723                 else if (MachO && OutputFormat == darwin)
724                   outs() << UA->getFileName() << "(" << o->getFileName() << ")"
725                          << " (for architecture " << I->getArchFlagName()
726                          << "):\n";
727                 printObjectSectionSizes(o);
728                 if (OutputFormat == berkeley) {
729                   if (MachO)
730                     outs() << UA->getFileName() << "(" << o->getFileName()
731                            << ")\n";
732                   else
733                     outs() << o->getFileName() << " (ex " << UA->getFileName()
734                            << ")\n";
735                 }
736               }
737             }
738             if (Err)
739               error(std::move(Err), UA->getFileName());
740           } else {
741             consumeError(AOrErr.takeError());
742             error("Mach-O universal file: " + file + " for architecture " +
743                    StringRef(I->getArchFlagName()) +
744                    " is not a Mach-O file or an archive file");
745           }
746           return;
747         }
748       }
749     }
750     // Either all architectures have been specified or none have been specified
751     // and this does not contain the host architecture so dump all the slices.
752     bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
753     for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
754                                                E = UB->end_objects();
755          I != E; ++I) {
756       Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
757       if (UO) {
758         if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
759           MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
760           if (OutputFormat == sysv)
761             outs() << o->getFileName() << "  :\n";
762           else if (MachO && OutputFormat == darwin) {
763             if (MoreThanOneFile || MoreThanOneArch)
764               outs() << o->getFileName() << " (for architecture "
765                      << I->getArchFlagName() << "):";
766             outs() << "\n";
767           }
768           printObjectSectionSizes(o);
769           if (OutputFormat == berkeley) {
770             if (!MachO || MoreThanOneFile || MoreThanOneArch)
771               outs() << o->getFileName() << " (for architecture "
772                      << I->getArchFlagName() << ")";
773             outs() << "\n";
774           }
775         }
776       } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
777         error(std::move(E), file, MoreThanOneArch ?
778               StringRef(I->getArchFlagName()) : StringRef());
779         return;
780       } else if (Expected<std::unique_ptr<Archive>> AOrErr =
781                          I->getAsArchive()) {
782         std::unique_ptr<Archive> &UA = *AOrErr;
783         // This is an archive. Iterate over each member and display its sizes.
784         Error Err = Error::success();
785         for (auto &C : UA->children(Err)) {
786           Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
787           if (!ChildOrErr) {
788             if (auto E = isNotObjectErrorInvalidFileType(
789                               ChildOrErr.takeError()))
790               error(std::move(E), UA->getFileName(), C, MoreThanOneArch ?
791                     StringRef(I->getArchFlagName()) : StringRef());
792             continue;
793           }
794           if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
795             MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
796             if (OutputFormat == sysv)
797               outs() << o->getFileName() << "   (ex " << UA->getFileName()
798                      << "):\n";
799             else if (MachO && OutputFormat == darwin)
800               outs() << UA->getFileName() << "(" << o->getFileName() << ")"
801                      << " (for architecture " << I->getArchFlagName() << "):\n";
802             printObjectSectionSizes(o);
803             if (OutputFormat == berkeley) {
804               if (MachO)
805                 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
806                        << " (for architecture " << I->getArchFlagName()
807                        << ")\n";
808               else
809                 outs() << o->getFileName() << " (ex " << UA->getFileName()
810                        << ")\n";
811             }
812           }
813         }
814         if (Err)
815           error(std::move(Err), UA->getFileName());
816       } else {
817         consumeError(AOrErr.takeError());
818         error("Mach-O universal file: " + file + " for architecture " +
819                StringRef(I->getArchFlagName()) +
820                " is not a Mach-O file or an archive file");
821       }
822     }
823   } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
824     if (!checkMachOAndArchFlags(o, file))
825       return;
826     MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
827     if (OutputFormat == sysv)
828       outs() << o->getFileName() << "  :\n";
829     else if (MachO && OutputFormat == darwin && MoreThanOneFile)
830       outs() << o->getFileName() << ":\n";
831     printObjectSectionSizes(o);
832     if (OutputFormat == berkeley) {
833       if (!MachO || MoreThanOneFile)
834         outs() << o->getFileName();
835       outs() << "\n";
836     }
837   } else {
838     errs() << ToolName << ": " << file << ": "
839            << "Unrecognized file type.\n";
840   }
841   // System V adds an extra newline at the end of each file.
842   if (OutputFormat == sysv)
843     outs() << "\n";
844 }
845 
846 static void printBerkelyTotals() {
847   std::string fmtbuf;
848   raw_string_ostream fmt(fmtbuf);
849   const char *radix_fmt = getRadixFmt();
850   fmt << "%#7" << radix_fmt << "\t"
851       << "%#7" << radix_fmt << "\t"
852       << "%#7" << radix_fmt << "\t";
853   outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData,
854                    TotalObjectBss);
855   fmtbuf.clear();
856   fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
857       << "%7" PRIx64 "\t";
858   outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal)
859          << "(TOTALS)\n";
860 }
861 
862 int main(int argc, char **argv) {
863   InitLLVM X(argc, argv);
864   cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
865 
866   ToolName = argv[0];
867   if (OutputFormatShort.getNumOccurrences())
868     OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
869   if (RadixShort.getNumOccurrences())
870     Radix = RadixShort.getValue();
871 
872   for (StringRef Arch : ArchFlags) {
873     if (Arch == "all") {
874       ArchAll = true;
875     } else {
876       if (!MachOObjectFile::isValidArch(Arch)) {
877         outs() << ToolName << ": for the -arch option: Unknown architecture "
878                << "named '" << Arch << "'";
879         return 1;
880       }
881     }
882   }
883 
884   if (InputFilenames.empty())
885     InputFilenames.push_back("a.out");
886 
887   MoreThanOneFile = InputFilenames.size() > 1;
888   llvm::for_each(InputFilenames, printFileSectionSizes);
889   if (OutputFormat == berkeley && TotalSizes)
890     printBerkelyTotals();
891 
892   if (HadError)
893     return 1;
894 }
895