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