gn build: Extract git() and git_out() functions in sync script
[llvm-complete.git] / tools / llvm-size / llvm-size.cpp
blob89b89f06275084c4d3195e1a2e2b400169b87cdb
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 /// If ec is not success, print the error and return true.
110 static bool error(std::error_code ec) {
111 if (!ec)
112 return false;
114 HadError = true;
115 errs() << ToolName << ": error reading file: " << ec.message() << ".\n";
116 errs().flush();
117 return true;
120 static bool error(Twine Message) {
121 HadError = true;
122 errs() << ToolName << ": " << Message << ".\n";
123 errs().flush();
124 return true;
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.
130 static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
131 StringRef ArchitectureName = StringRef()) {
132 HadError = true;
133 errs() << ToolName << ": " << FileName;
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() << ")";
145 if (!ArchitectureName.empty())
146 errs() << " (for architecture " << ArchitectureName << ") ";
148 std::string Buf;
149 raw_string_ostream OS(Buf);
150 logAllUnhandledErrors(std::move(E), OS);
151 OS.flush();
152 errs() << " " << Buf << "\n";
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.
158 static void error(llvm::Error E, StringRef FileName,
159 StringRef ArchitectureName = StringRef()) {
160 HadError = true;
161 errs() << ToolName << ": " << FileName;
163 if (!ArchitectureName.empty())
164 errs() << " (for architecture " << ArchitectureName << ") ";
166 std::string Buf;
167 raw_string_ostream OS(Buf);
168 logAllUnhandledErrors(std::move(E), OS);
169 OS.flush();
170 errs() << " " << Buf << "\n";
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.
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();
182 /// Return the printing format for the Radix.
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;
192 return nullptr;
195 /// Remove unneeded ELF sections from calculation
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;
207 return true;
210 /// Total size of all ELF common symbols
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;
219 /// Print the size of each Mach-O segment and section in @p MachO.
221 /// This is when used when @c OutputFormat is darwin and produces the same
222 /// output as darwin's size(1) -m output.
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;
231 uint32_t Filetype = MachO->getHeader().filetype;
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;
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;
287 if (Seg.nsects != 0)
288 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
291 outs() << "total " << format(fmt.str().c_str(), total) << "\n";
294 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
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.
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;
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;
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;
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;
358 uint64_t total = total_text + total_data + total_objc + total_others;
360 if (!BerkeleyHeaderPrinted) {
361 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
362 BerkeleyHeaderPrinted = true;
364 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
365 << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
366 << "\t";
369 /// Print the size of each section in @p Obj.
371 /// The format used is determined by @c OutputFormat and @c Radix.
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();
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;
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));
409 // Add extra padding.
410 max_name_len += 2;
411 max_size_len += 2;
412 max_addr_len += 2;
414 // Setup header format.
415 fmt << "%-" << max_name_len << "s "
416 << "%" << max_size_len << "s "
417 << "%" << max_addr_len << "s\n";
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();
425 // Setup per section format.
426 fmt << "%-" << max_name_len << "s "
427 << "%#" << max_size_len << radix_fmt << " "
428 << "%#" << max_addr_len << radix_fmt << "\n";
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;
441 outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr);
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));
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;
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;
478 if (ELFCommons)
479 total_bss += getCommonSize(Obj);
481 total = total_text + total_data + total_bss;
483 if (TotalSizes) {
484 TotalObjectText += total_text;
485 TotalObjectData += total_data;
486 TotalObjectBss += total_bss;
487 TotalObjectTotal += total;
490 if (!BerkeleyHeaderPrinted) {
491 outs() << " text\t"
492 " data\t"
493 " bss\t"
495 << (Radix == octal ? "oct" : "dec")
496 << "\t"
497 " hex\t"
498 "filename\n";
499 BerkeleyHeaderPrinted = true;
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);
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.
519 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
520 auto *MachO = dyn_cast<MachOObjectFile>(O);
522 if (!MachO || ArchAll || ArchFlags.empty())
523 return true;
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);
535 if (none_of(ArchFlags, [&](const std::string &Name) {
536 return Name == T.getArchName();
537 })) {
538 error(Filename + ": No architecture specified");
539 return false;
541 return true;
544 /// Print the section sizes for @p file. If @p file is an archive, print the
545 /// section sizes for each archive member.
546 static void printFileSectionSizes(StringRef file) {
548 // Attempt to open the binary.
549 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
550 if (!BinaryOrErr) {
551 error(BinaryOrErr.takeError(), file);
552 return;
554 Binary &Bin = *BinaryOrErr.get().getBinary();
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;
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";
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";
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";
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;
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";
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");
673 if (!ArchFound) {
674 errs() << ToolName << ": file: " << file
675 << " does not contain architecture" << ArchFlags[i] << ".\n";
676 return;
679 return;
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";
700 printObjectSectionSizes(o);
701 if (OutputFormat == berkeley) {
702 if (!MachO || MoreThanOneFile)
703 outs() << o->getFileName() << " (for architecture "
704 << I->getArchFlagName() << ")";
705 outs() << "\n";
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;
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";
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");
753 return;
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";
775 printObjectSectionSizes(o);
776 if (OutputFormat == berkeley) {
777 if (!MachO || MoreThanOneFile || MoreThanOneArch)
778 outs() << o->getFileName() << " (for architecture "
779 << I->getArchFlagName() << ")";
780 outs() << "\n";
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;
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";
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");
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";
844 } else {
845 errs() << ToolName << ": " << file << ": "
846 << "Unrecognized file type.\n";
848 // System V adds an extra newline at the end of each file.
849 if (OutputFormat == sysv)
850 outs() << "\n";
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";
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");
874 ToolName = argv[0];
875 if (OutputFormatShort.getNumOccurrences())
876 OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
877 if (RadixShort.getNumOccurrences())
878 Radix = RadixShort.getValue();
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;
892 if (InputFilenames.empty())
893 InputFilenames.push_back("a.out");
895 MoreThanOneFile = InputFilenames.size() > 1;
896 llvm::for_each(InputFilenames, printFileSectionSizes);
897 if (OutputFormat == berkeley && TotalSizes)
898 printBerkelyTotals();
900 if (HadError)
901 return 1;