Recommit r368812 "[llvm/Object] - Convert SectionRef::getName() to return Expected<>"
[llvm-complete.git] / tools / llvm-size / llvm-size.cpp
blob87df1264fbca2dac46ce93283a35be0b4b0fe5c3
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.
13 //===----------------------------------------------------------------------===//
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>
32 using namespace llvm;
33 using namespace object;
35 cl::OptionCategory SizeCat("llvm-size Options");
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));
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));
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;
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));
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));
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;
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));
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));
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));
96 static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"),
97 cl::aliasopt(TotalSizes));
99 static cl::list<std::string>
100 InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
102 static cl::extrahelp
103 HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
105 static bool HadError = false;
107 static std::string ToolName;
109 static bool error(Twine Message) {
110 HadError = true;
111 errs() << ToolName << ": " << Message << ".\n";
112 errs().flush();
113 return true;
116 // This version of error() prints the archive name and member name, for example:
117 // "libx.a(foo.o)" after the ToolName before the error message. It sets
118 // HadError but returns allowing the code to move on to other archive members.
119 static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
120 StringRef ArchitectureName = StringRef()) {
121 HadError = true;
122 errs() << ToolName << ": " << FileName;
124 Expected<StringRef> NameOrErr = C.getName();
125 // TODO: if we have a error getting the name then it would be nice to print
126 // the index of which archive member this is and or its offset in the
127 // archive instead of "???" as the name.
128 if (!NameOrErr) {
129 consumeError(NameOrErr.takeError());
130 errs() << "(" << "???" << ")";
131 } else
132 errs() << "(" << NameOrErr.get() << ")";
134 if (!ArchitectureName.empty())
135 errs() << " (for architecture " << ArchitectureName << ") ";
137 std::string Buf;
138 raw_string_ostream OS(Buf);
139 logAllUnhandledErrors(std::move(E), OS);
140 OS.flush();
141 errs() << " " << Buf << "\n";
144 // 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
145 // before the error message. It sets HadError but returns allowing the code to
146 // move on to other architecture slices.
147 static void error(llvm::Error E, StringRef FileName,
148 StringRef ArchitectureName = StringRef()) {
149 HadError = true;
150 errs() << ToolName << ": " << FileName;
152 if (!ArchitectureName.empty())
153 errs() << " (for architecture " << ArchitectureName << ") ";
155 std::string Buf;
156 raw_string_ostream OS(Buf);
157 logAllUnhandledErrors(std::move(E), OS);
158 OS.flush();
159 errs() << " " << Buf << "\n";
162 /// Get the length of the string that represents @p num in Radix including the
163 /// leading 0x or 0 for hexadecimal and octal respectively.
164 static size_t getNumLengthAsString(uint64_t num) {
165 APInt conv(64, num);
166 SmallString<32> result;
167 conv.toString(result, Radix, false, true);
168 return result.size();
171 /// Return the printing format for the Radix.
172 static const char *getRadixFmt() {
173 switch (Radix) {
174 case octal:
175 return PRIo64;
176 case decimal:
177 return PRIu64;
178 case hexadecimal:
179 return PRIx64;
181 return nullptr;
184 /// Remove unneeded ELF sections from calculation
185 static bool considerForSize(ObjectFile *Obj, SectionRef Section) {
186 if (!Obj->isELF())
187 return true;
188 switch (static_cast<ELFSectionRef>(Section).getType()) {
189 case ELF::SHT_NULL:
190 case ELF::SHT_SYMTAB:
191 case ELF::SHT_STRTAB:
192 case ELF::SHT_REL:
193 case ELF::SHT_RELA:
194 return false;
196 return true;
199 /// Total size of all ELF common symbols
200 static uint64_t getCommonSize(ObjectFile *Obj) {
201 uint64_t TotalCommons = 0;
202 for (auto &Sym : Obj->symbols())
203 if (Obj->getSymbolFlags(Sym.getRawDataRefImpl()) & SymbolRef::SF_Common)
204 TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl());
205 return TotalCommons;
208 /// Print the size of each Mach-O segment and section in @p MachO.
210 /// This is when used when @c OutputFormat is darwin and produces the same
211 /// output as darwin's size(1) -m output.
212 static void printDarwinSectionSizes(MachOObjectFile *MachO) {
213 std::string fmtbuf;
214 raw_string_ostream fmt(fmtbuf);
215 const char *radix_fmt = getRadixFmt();
216 if (Radix == hexadecimal)
217 fmt << "0x";
218 fmt << "%" << radix_fmt;
220 uint32_t Filetype = MachO->getHeader().filetype;
222 uint64_t total = 0;
223 for (const auto &Load : MachO->load_commands()) {
224 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
225 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
226 outs() << "Segment " << Seg.segname << ": "
227 << format(fmt.str().c_str(), Seg.vmsize);
228 if (DarwinLongFormat)
229 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
230 << Seg.fileoff << ")";
231 outs() << "\n";
232 total += Seg.vmsize;
233 uint64_t sec_total = 0;
234 for (unsigned J = 0; J < Seg.nsects; ++J) {
235 MachO::section_64 Sec = MachO->getSection64(Load, J);
236 if (Filetype == MachO::MH_OBJECT)
237 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
238 << format("%.16s", &Sec.sectname) << "): ";
239 else
240 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
241 outs() << format(fmt.str().c_str(), Sec.size);
242 if (DarwinLongFormat)
243 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
244 << Sec.offset << ")";
245 outs() << "\n";
246 sec_total += Sec.size;
248 if (Seg.nsects != 0)
249 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
250 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
251 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
252 uint64_t Seg_vmsize = Seg.vmsize;
253 outs() << "Segment " << Seg.segname << ": "
254 << format(fmt.str().c_str(), Seg_vmsize);
255 if (DarwinLongFormat)
256 outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff "
257 << Seg.fileoff << ")";
258 outs() << "\n";
259 total += Seg.vmsize;
260 uint64_t sec_total = 0;
261 for (unsigned J = 0; J < Seg.nsects; ++J) {
262 MachO::section Sec = MachO->getSection(Load, J);
263 if (Filetype == MachO::MH_OBJECT)
264 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
265 << format("%.16s", &Sec.sectname) << "): ";
266 else
267 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
268 uint64_t Sec_size = Sec.size;
269 outs() << format(fmt.str().c_str(), Sec_size);
270 if (DarwinLongFormat)
271 outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset "
272 << Sec.offset << ")";
273 outs() << "\n";
274 sec_total += Sec.size;
276 if (Seg.nsects != 0)
277 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
280 outs() << "total " << format(fmt.str().c_str(), total) << "\n";
283 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
285 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
286 /// produces the same output as darwin's size(1) default output.
287 static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
288 uint64_t total_text = 0;
289 uint64_t total_data = 0;
290 uint64_t total_objc = 0;
291 uint64_t total_others = 0;
292 for (const auto &Load : MachO->load_commands()) {
293 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
294 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
295 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
296 for (unsigned J = 0; J < Seg.nsects; ++J) {
297 MachO::section_64 Sec = MachO->getSection64(Load, J);
298 StringRef SegmentName = StringRef(Sec.segname);
299 if (SegmentName == "__TEXT")
300 total_text += Sec.size;
301 else if (SegmentName == "__DATA")
302 total_data += Sec.size;
303 else if (SegmentName == "__OBJC")
304 total_objc += Sec.size;
305 else
306 total_others += Sec.size;
308 } else {
309 StringRef SegmentName = StringRef(Seg.segname);
310 if (SegmentName == "__TEXT")
311 total_text += Seg.vmsize;
312 else if (SegmentName == "__DATA")
313 total_data += Seg.vmsize;
314 else if (SegmentName == "__OBJC")
315 total_objc += Seg.vmsize;
316 else
317 total_others += Seg.vmsize;
319 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
320 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
321 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
322 for (unsigned J = 0; J < Seg.nsects; ++J) {
323 MachO::section Sec = MachO->getSection(Load, J);
324 StringRef SegmentName = StringRef(Sec.segname);
325 if (SegmentName == "__TEXT")
326 total_text += Sec.size;
327 else if (SegmentName == "__DATA")
328 total_data += Sec.size;
329 else if (SegmentName == "__OBJC")
330 total_objc += Sec.size;
331 else
332 total_others += Sec.size;
334 } else {
335 StringRef SegmentName = StringRef(Seg.segname);
336 if (SegmentName == "__TEXT")
337 total_text += Seg.vmsize;
338 else if (SegmentName == "__DATA")
339 total_data += Seg.vmsize;
340 else if (SegmentName == "__OBJC")
341 total_objc += Seg.vmsize;
342 else
343 total_others += Seg.vmsize;
347 uint64_t total = total_text + total_data + total_objc + total_others;
349 if (!BerkeleyHeaderPrinted) {
350 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
351 BerkeleyHeaderPrinted = true;
353 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
354 << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
355 << "\t";
358 /// Print the size of each section in @p Obj.
360 /// The format used is determined by @c OutputFormat and @c Radix.
361 static void printObjectSectionSizes(ObjectFile *Obj) {
362 uint64_t total = 0;
363 std::string fmtbuf;
364 raw_string_ostream fmt(fmtbuf);
365 const char *radix_fmt = getRadixFmt();
367 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
368 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
369 // let it fall through to OutputFormat berkeley.
370 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
371 if (OutputFormat == darwin && MachO)
372 printDarwinSectionSizes(MachO);
373 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
374 // darwin's default berkeley format for Mach-O files.
375 else if (MachO && OutputFormat == berkeley)
376 printDarwinSegmentSizes(MachO);
377 else if (OutputFormat == sysv) {
378 // Run two passes over all sections. The first gets the lengths needed for
379 // formatting the output. The second actually does the output.
380 std::size_t max_name_len = strlen("section");
381 std::size_t max_size_len = strlen("size");
382 std::size_t max_addr_len = strlen("addr");
383 for (const SectionRef &Section : Obj->sections()) {
384 if (!considerForSize(Obj, Section))
385 continue;
386 uint64_t size = Section.getSize();
387 total += size;
389 Expected<StringRef> name_or_err = Section.getName();
390 if (!name_or_err) {
391 error(name_or_err.takeError(), Obj->getFileName());
392 return;
395 uint64_t addr = Section.getAddress();
396 max_name_len = std::max(max_name_len, name_or_err->size());
397 max_size_len = std::max(max_size_len, getNumLengthAsString(size));
398 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
401 // Add extra padding.
402 max_name_len += 2;
403 max_size_len += 2;
404 max_addr_len += 2;
406 // Setup header format.
407 fmt << "%-" << max_name_len << "s "
408 << "%" << max_size_len << "s "
409 << "%" << max_addr_len << "s\n";
411 // Print header
412 outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
413 static_cast<const char *>("size"),
414 static_cast<const char *>("addr"));
415 fmtbuf.clear();
417 // Setup per section format.
418 fmt << "%-" << max_name_len << "s "
419 << "%#" << max_size_len << radix_fmt << " "
420 << "%#" << max_addr_len << radix_fmt << "\n";
422 // Print each section.
423 for (const SectionRef &Section : Obj->sections()) {
424 if (!considerForSize(Obj, Section))
425 continue;
427 Expected<StringRef> name_or_err = Section.getName();
428 if (!name_or_err) {
429 error(name_or_err.takeError(), Obj->getFileName());
430 return;
433 uint64_t size = Section.getSize();
434 uint64_t addr = Section.getAddress();
435 outs() << format(fmt.str().c_str(), name_or_err->str().c_str(), size, addr);
438 if (ELFCommons) {
439 uint64_t CommonSize = getCommonSize(Obj);
440 total += CommonSize;
441 outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(),
442 CommonSize, static_cast<uint64_t>(0));
445 // Print total.
446 fmtbuf.clear();
447 fmt << "%-" << max_name_len << "s "
448 << "%#" << max_size_len << radix_fmt << "\n";
449 outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
450 total);
451 } else {
452 // The Berkeley format does not display individual section sizes. It
453 // displays the cumulative size for each section type.
454 uint64_t total_text = 0;
455 uint64_t total_data = 0;
456 uint64_t total_bss = 0;
458 // Make one pass over the section table to calculate sizes.
459 for (const SectionRef &Section : Obj->sections()) {
460 uint64_t size = Section.getSize();
461 bool isText = Section.isBerkeleyText();
462 bool isData = Section.isBerkeleyData();
463 bool isBSS = Section.isBSS();
464 if (isText)
465 total_text += size;
466 else if (isData)
467 total_data += size;
468 else if (isBSS)
469 total_bss += size;
472 if (ELFCommons)
473 total_bss += getCommonSize(Obj);
475 total = total_text + total_data + total_bss;
477 if (TotalSizes) {
478 TotalObjectText += total_text;
479 TotalObjectData += total_data;
480 TotalObjectBss += total_bss;
481 TotalObjectTotal += total;
484 if (!BerkeleyHeaderPrinted) {
485 outs() << " text\t"
486 " data\t"
487 " bss\t"
489 << (Radix == octal ? "oct" : "dec")
490 << "\t"
491 " hex\t"
492 "filename\n";
493 BerkeleyHeaderPrinted = true;
496 // Print result.
497 fmt << "%#7" << radix_fmt << "\t"
498 << "%#7" << radix_fmt << "\t"
499 << "%#7" << radix_fmt << "\t";
500 outs() << format(fmt.str().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(fmt.str().c_str(), total, total);
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);
516 if (!MachO || ArchAll || ArchFlags.empty())
517 return true;
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);
529 if (none_of(ArchFlags, [&](const std::string &Name) {
530 return Name == T.getArchName();
531 })) {
532 error(Filename + ": No architecture specified");
533 return false;
535 return true;
538 /// Print the section sizes for @p file. If @p file is an archive, print the
539 /// section sizes for each archive member.
540 static void printFileSectionSizes(StringRef file) {
542 // Attempt to open the binary.
543 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
544 if (!BinaryOrErr) {
545 error(BinaryOrErr.takeError(), file);
546 return;
548 Binary &Bin = *BinaryOrErr.get().getBinary();
550 if (Archive *a = dyn_cast<Archive>(&Bin)) {
551 // This is an archive. Iterate over each member and display its sizes.
552 Error Err = Error::success();
553 for (auto &C : a->children(Err)) {
554 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
555 if (!ChildOrErr) {
556 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
557 error(std::move(E), a->getFileName(), C);
558 continue;
560 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
561 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
562 if (!checkMachOAndArchFlags(o, file))
563 return;
564 if (OutputFormat == sysv)
565 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n";
566 else if (MachO && OutputFormat == darwin)
567 outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
568 printObjectSectionSizes(o);
569 if (OutputFormat == berkeley) {
570 if (MachO)
571 outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
572 else
573 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
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";
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";
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;
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";
657 if (Err)
658 error(std::move(Err), UA->getFileName());
659 } else {
660 consumeError(AOrErr.takeError());
661 error("Mach-O universal file: " + file + " for architecture " +
662 StringRef(I->getArchFlagName()) +
663 " is not a Mach-O file or an archive file");
667 if (!ArchFound) {
668 errs() << ToolName << ": file: " << file
669 << " does not contain architecture" << ArchFlags[i] << ".\n";
670 return;
673 return;
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";
694 printObjectSectionSizes(o);
695 if (OutputFormat == berkeley) {
696 if (!MachO || MoreThanOneFile)
697 outs() << o->getFileName() << " (for architecture "
698 << I->getArchFlagName() << ")";
699 outs() << "\n";
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;
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";
739 if (Err)
740 error(std::move(Err), UA->getFileName());
741 } else {
742 consumeError(AOrErr.takeError());
743 error("Mach-O universal file: " + file + " for architecture " +
744 StringRef(I->getArchFlagName()) +
745 " is not a Mach-O file or an archive file");
747 return;
751 // Either all architectures have been specified or none have been specified
752 // and this does not contain the host architecture so dump all the slices.
753 bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
754 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
755 E = UB->end_objects();
756 I != E; ++I) {
757 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
758 if (UO) {
759 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
760 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
761 if (OutputFormat == sysv)
762 outs() << o->getFileName() << " :\n";
763 else if (MachO && OutputFormat == darwin) {
764 if (MoreThanOneFile || MoreThanOneArch)
765 outs() << o->getFileName() << " (for architecture "
766 << I->getArchFlagName() << "):";
767 outs() << "\n";
769 printObjectSectionSizes(o);
770 if (OutputFormat == berkeley) {
771 if (!MachO || MoreThanOneFile || MoreThanOneArch)
772 outs() << o->getFileName() << " (for architecture "
773 << I->getArchFlagName() << ")";
774 outs() << "\n";
777 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
778 error(std::move(E), file, MoreThanOneArch ?
779 StringRef(I->getArchFlagName()) : StringRef());
780 return;
781 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
782 I->getAsArchive()) {
783 std::unique_ptr<Archive> &UA = *AOrErr;
784 // This is an archive. Iterate over each member and display its sizes.
785 Error Err = Error::success();
786 for (auto &C : UA->children(Err)) {
787 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
788 if (!ChildOrErr) {
789 if (auto E = isNotObjectErrorInvalidFileType(
790 ChildOrErr.takeError()))
791 error(std::move(E), UA->getFileName(), C, MoreThanOneArch ?
792 StringRef(I->getArchFlagName()) : StringRef());
793 continue;
795 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
796 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
797 if (OutputFormat == sysv)
798 outs() << o->getFileName() << " (ex " << UA->getFileName()
799 << "):\n";
800 else if (MachO && OutputFormat == darwin)
801 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
802 << " (for architecture " << I->getArchFlagName() << "):\n";
803 printObjectSectionSizes(o);
804 if (OutputFormat == berkeley) {
805 if (MachO)
806 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
807 << " (for architecture " << I->getArchFlagName()
808 << ")\n";
809 else
810 outs() << o->getFileName() << " (ex " << UA->getFileName()
811 << ")\n";
815 if (Err)
816 error(std::move(Err), UA->getFileName());
817 } else {
818 consumeError(AOrErr.takeError());
819 error("Mach-O universal file: " + file + " for architecture " +
820 StringRef(I->getArchFlagName()) +
821 " is not a Mach-O file or an archive file");
824 } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
825 if (!checkMachOAndArchFlags(o, file))
826 return;
827 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
828 if (OutputFormat == sysv)
829 outs() << o->getFileName() << " :\n";
830 else if (MachO && OutputFormat == darwin && MoreThanOneFile)
831 outs() << o->getFileName() << ":\n";
832 printObjectSectionSizes(o);
833 if (OutputFormat == berkeley) {
834 if (!MachO || MoreThanOneFile)
835 outs() << o->getFileName();
836 outs() << "\n";
838 } else {
839 errs() << ToolName << ": " << file << ": "
840 << "Unrecognized file type.\n";
842 // System V adds an extra newline at the end of each file.
843 if (OutputFormat == sysv)
844 outs() << "\n";
847 static void printBerkelyTotals() {
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(fmt.str().c_str(), TotalObjectText, TotalObjectData,
855 TotalObjectBss);
856 fmtbuf.clear();
857 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
858 << "%7" PRIx64 "\t";
859 outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal)
860 << "(TOTALS)\n";
863 int main(int argc, char **argv) {
864 InitLLVM X(argc, argv);
865 cl::HideUnrelatedOptions(SizeCat);
866 cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
868 ToolName = argv[0];
869 if (OutputFormatShort.getNumOccurrences())
870 OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
871 if (RadixShort.getNumOccurrences())
872 Radix = RadixShort.getValue();
874 for (StringRef Arch : ArchFlags) {
875 if (Arch == "all") {
876 ArchAll = true;
877 } else {
878 if (!MachOObjectFile::isValidArch(Arch)) {
879 outs() << ToolName << ": for the -arch option: Unknown architecture "
880 << "named '" << Arch << "'";
881 return 1;
886 if (InputFilenames.empty())
887 InputFilenames.push_back("a.out");
889 MoreThanOneFile = InputFilenames.size() > 1;
890 llvm::for_each(InputFilenames, printFileSectionSizes);
891 if (OutputFormat == berkeley && TotalSizes)
892 printBerkelyTotals();
894 if (HadError)
895 return 1;