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