[lit] Add argument check: --timeout must be non-negative integer
[llvm-core.git] / tools / llvm-size / llvm-size.cpp
blob7c63bc291f1b5b6afdf999a44656e8ff609e798b
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/WithColor.h"
28 #include "llvm/Support/raw_ostream.h"
29 #include <algorithm>
30 #include <string>
31 #include <system_error>
33 using namespace llvm;
34 using namespace object;
36 cl::OptionCategory SizeCat("llvm-size Options");
38 enum OutputFormatTy { berkeley, sysv, darwin };
39 static cl::opt<OutputFormatTy>
40 OutputFormat("format", cl::desc("Specify output format"),
41 cl::values(clEnumVal(sysv, "System V format"),
42 clEnumVal(berkeley, "Berkeley format"),
43 clEnumVal(darwin, "Darwin -m format")),
44 cl::init(berkeley), cl::cat(SizeCat));
46 static cl::opt<OutputFormatTy>
47 OutputFormatShort(cl::desc("Specify output format"),
48 cl::values(clEnumValN(sysv, "A", "System V format"),
49 clEnumValN(berkeley, "B", "Berkeley format"),
50 clEnumValN(darwin, "m", "Darwin -m format")),
51 cl::init(berkeley), cl::cat(SizeCat));
53 static bool BerkeleyHeaderPrinted = false;
54 static bool MoreThanOneFile = false;
55 static uint64_t TotalObjectText = 0;
56 static uint64_t TotalObjectData = 0;
57 static uint64_t TotalObjectBss = 0;
58 static uint64_t TotalObjectTotal = 0;
60 cl::opt<bool>
61 DarwinLongFormat("l",
62 cl::desc("When format is darwin, use long format "
63 "to include addresses and offsets."),
64 cl::cat(SizeCat));
66 cl::opt<bool>
67 ELFCommons("common",
68 cl::desc("Print common symbols in the ELF file. When using "
69 "Berkeley format, this is added to bss."),
70 cl::init(false), cl::cat(SizeCat));
72 static cl::list<std::string>
73 ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
74 cl::ZeroOrMore, cl::cat(SizeCat));
75 static bool ArchAll = false;
77 enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
78 static cl::opt<RadixTy> Radix(
79 "radix", cl::desc("Print size in radix"), cl::init(decimal),
80 cl::values(clEnumValN(octal, "8", "Print size in octal"),
81 clEnumValN(decimal, "10", "Print size in decimal"),
82 clEnumValN(hexadecimal, "16", "Print size in hexadecimal")),
83 cl::cat(SizeCat));
85 static cl::opt<RadixTy> RadixShort(
86 cl::desc("Print size in radix:"),
87 cl::values(clEnumValN(octal, "o", "Print size in octal"),
88 clEnumValN(decimal, "d", "Print size in decimal"),
89 clEnumValN(hexadecimal, "x", "Print size in hexadecimal")),
90 cl::init(decimal), cl::cat(SizeCat));
92 static cl::opt<bool>
93 TotalSizes("totals",
94 cl::desc("Print totals of all objects - Berkeley format only"),
95 cl::init(false), cl::cat(SizeCat));
97 static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"),
98 cl::aliasopt(TotalSizes));
100 static cl::list<std::string>
101 InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
103 static cl::extrahelp
104 HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
106 static bool HadError = false;
108 static std::string ToolName;
110 static void error(const Twine &Message, StringRef File) {
111 HadError = true;
112 WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n";
115 // This version of error() prints the archive name and member name, for example:
116 // "libx.a(foo.o)" after the ToolName before the error message. It sets
117 // HadError but returns allowing the code to move on to other archive members.
118 static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
119 StringRef ArchitectureName = StringRef()) {
120 HadError = true;
121 WithColor::error(errs(), ToolName) << "'" << FileName << "'";
123 Expected<StringRef> NameOrErr = C.getName();
124 // TODO: if we have a error getting the name then it would be nice to print
125 // the index of which archive member this is and or its offset in the
126 // archive instead of "???" as the name.
127 if (!NameOrErr) {
128 consumeError(NameOrErr.takeError());
129 errs() << "(" << "???" << ")";
130 } else
131 errs() << "(" << NameOrErr.get() << ")";
133 if (!ArchitectureName.empty())
134 errs() << " (for architecture " << ArchitectureName << ") ";
136 std::string Buf;
137 raw_string_ostream OS(Buf);
138 logAllUnhandledErrors(std::move(E), OS);
139 OS.flush();
140 errs() << ": " << Buf << "\n";
143 // 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
144 // before the error message. It sets HadError but returns allowing the code to
145 // move on to other architecture slices.
146 static void error(llvm::Error E, StringRef FileName,
147 StringRef ArchitectureName = StringRef()) {
148 HadError = true;
149 WithColor::error(errs(), ToolName) << "'" << FileName << "'";
151 if (!ArchitectureName.empty())
152 errs() << " (for architecture " << ArchitectureName << ") ";
154 std::string Buf;
155 raw_string_ostream OS(Buf);
156 logAllUnhandledErrors(std::move(E), OS);
157 OS.flush();
158 errs() << ": " << Buf << "\n";
161 /// Get the length of the string that represents @p num in Radix including the
162 /// leading 0x or 0 for hexadecimal and octal respectively.
163 static size_t getNumLengthAsString(uint64_t num) {
164 APInt conv(64, num);
165 SmallString<32> result;
166 conv.toString(result, Radix, false, true);
167 return result.size();
170 /// Return the printing format for the Radix.
171 static const char *getRadixFmt() {
172 switch (Radix) {
173 case octal:
174 return PRIo64;
175 case decimal:
176 return PRIu64;
177 case hexadecimal:
178 return PRIx64;
180 return nullptr;
183 /// Remove unneeded ELF sections from calculation
184 static bool considerForSize(ObjectFile *Obj, SectionRef Section) {
185 if (!Obj->isELF())
186 return true;
187 switch (static_cast<ELFSectionRef>(Section).getType()) {
188 case ELF::SHT_NULL:
189 case ELF::SHT_SYMTAB:
190 case ELF::SHT_STRTAB:
191 case ELF::SHT_REL:
192 case ELF::SHT_RELA:
193 return false;
195 return true;
198 /// Total size of all ELF common symbols
199 static uint64_t getCommonSize(ObjectFile *Obj) {
200 uint64_t TotalCommons = 0;
201 for (auto &Sym : Obj->symbols())
202 if (Obj->getSymbolFlags(Sym.getRawDataRefImpl()) & SymbolRef::SF_Common)
203 TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl());
204 return TotalCommons;
207 /// Print the size of each Mach-O segment and section in @p MachO.
209 /// This is when used when @c OutputFormat is darwin and produces the same
210 /// output as darwin's size(1) -m output.
211 static void printDarwinSectionSizes(MachOObjectFile *MachO) {
212 std::string fmtbuf;
213 raw_string_ostream fmt(fmtbuf);
214 const char *radix_fmt = getRadixFmt();
215 if (Radix == hexadecimal)
216 fmt << "0x";
217 fmt << "%" << radix_fmt;
219 uint32_t Filetype = MachO->getHeader().filetype;
221 uint64_t total = 0;
222 for (const auto &Load : MachO->load_commands()) {
223 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
224 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
225 outs() << "Segment " << Seg.segname << ": "
226 << format(fmt.str().c_str(), Seg.vmsize);
227 if (DarwinLongFormat)
228 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
229 << Seg.fileoff << ")";
230 outs() << "\n";
231 total += Seg.vmsize;
232 uint64_t sec_total = 0;
233 for (unsigned J = 0; J < Seg.nsects; ++J) {
234 MachO::section_64 Sec = MachO->getSection64(Load, J);
235 if (Filetype == MachO::MH_OBJECT)
236 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
237 << format("%.16s", &Sec.sectname) << "): ";
238 else
239 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
240 outs() << format(fmt.str().c_str(), Sec.size);
241 if (DarwinLongFormat)
242 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
243 << Sec.offset << ")";
244 outs() << "\n";
245 sec_total += Sec.size;
247 if (Seg.nsects != 0)
248 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
249 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
250 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
251 uint64_t Seg_vmsize = Seg.vmsize;
252 outs() << "Segment " << Seg.segname << ": "
253 << format(fmt.str().c_str(), Seg_vmsize);
254 if (DarwinLongFormat)
255 outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff "
256 << Seg.fileoff << ")";
257 outs() << "\n";
258 total += Seg.vmsize;
259 uint64_t sec_total = 0;
260 for (unsigned J = 0; J < Seg.nsects; ++J) {
261 MachO::section Sec = MachO->getSection(Load, J);
262 if (Filetype == MachO::MH_OBJECT)
263 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
264 << format("%.16s", &Sec.sectname) << "): ";
265 else
266 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
267 uint64_t Sec_size = Sec.size;
268 outs() << format(fmt.str().c_str(), Sec_size);
269 if (DarwinLongFormat)
270 outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset "
271 << Sec.offset << ")";
272 outs() << "\n";
273 sec_total += Sec.size;
275 if (Seg.nsects != 0)
276 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
279 outs() << "total " << format(fmt.str().c_str(), total) << "\n";
282 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
284 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
285 /// produces the same output as darwin's size(1) default output.
286 static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
287 uint64_t total_text = 0;
288 uint64_t total_data = 0;
289 uint64_t total_objc = 0;
290 uint64_t total_others = 0;
291 for (const auto &Load : MachO->load_commands()) {
292 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
293 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
294 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
295 for (unsigned J = 0; J < Seg.nsects; ++J) {
296 MachO::section_64 Sec = MachO->getSection64(Load, J);
297 StringRef SegmentName = StringRef(Sec.segname);
298 if (SegmentName == "__TEXT")
299 total_text += Sec.size;
300 else if (SegmentName == "__DATA")
301 total_data += Sec.size;
302 else if (SegmentName == "__OBJC")
303 total_objc += Sec.size;
304 else
305 total_others += Sec.size;
307 } else {
308 StringRef SegmentName = StringRef(Seg.segname);
309 if (SegmentName == "__TEXT")
310 total_text += Seg.vmsize;
311 else if (SegmentName == "__DATA")
312 total_data += Seg.vmsize;
313 else if (SegmentName == "__OBJC")
314 total_objc += Seg.vmsize;
315 else
316 total_others += Seg.vmsize;
318 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
319 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
320 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
321 for (unsigned J = 0; J < Seg.nsects; ++J) {
322 MachO::section Sec = MachO->getSection(Load, J);
323 StringRef SegmentName = StringRef(Sec.segname);
324 if (SegmentName == "__TEXT")
325 total_text += Sec.size;
326 else if (SegmentName == "__DATA")
327 total_data += Sec.size;
328 else if (SegmentName == "__OBJC")
329 total_objc += Sec.size;
330 else
331 total_others += Sec.size;
333 } else {
334 StringRef SegmentName = StringRef(Seg.segname);
335 if (SegmentName == "__TEXT")
336 total_text += Seg.vmsize;
337 else if (SegmentName == "__DATA")
338 total_data += Seg.vmsize;
339 else if (SegmentName == "__OBJC")
340 total_objc += Seg.vmsize;
341 else
342 total_others += Seg.vmsize;
346 uint64_t total = total_text + total_data + total_objc + total_others;
348 if (!BerkeleyHeaderPrinted) {
349 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
350 BerkeleyHeaderPrinted = true;
352 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
353 << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
354 << "\t";
357 /// Print the size of each section in @p Obj.
359 /// The format used is determined by @c OutputFormat and @c Radix.
360 static void printObjectSectionSizes(ObjectFile *Obj) {
361 uint64_t total = 0;
362 std::string fmtbuf;
363 raw_string_ostream fmt(fmtbuf);
364 const char *radix_fmt = getRadixFmt();
366 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
367 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
368 // let it fall through to OutputFormat berkeley.
369 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
370 if (OutputFormat == darwin && MachO)
371 printDarwinSectionSizes(MachO);
372 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
373 // darwin's default berkeley format for Mach-O files.
374 else if (MachO && OutputFormat == berkeley)
375 printDarwinSegmentSizes(MachO);
376 else if (OutputFormat == sysv) {
377 // Run two passes over all sections. The first gets the lengths needed for
378 // formatting the output. The second actually does the output.
379 std::size_t max_name_len = strlen("section");
380 std::size_t max_size_len = strlen("size");
381 std::size_t max_addr_len = strlen("addr");
382 for (const SectionRef &Section : Obj->sections()) {
383 if (!considerForSize(Obj, Section))
384 continue;
385 uint64_t size = Section.getSize();
386 total += size;
388 Expected<StringRef> name_or_err = Section.getName();
389 if (!name_or_err) {
390 error(name_or_err.takeError(), Obj->getFileName());
391 return;
394 uint64_t addr = Section.getAddress();
395 max_name_len = std::max(max_name_len, name_or_err->size());
396 max_size_len = std::max(max_size_len, getNumLengthAsString(size));
397 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
400 // Add extra padding.
401 max_name_len += 2;
402 max_size_len += 2;
403 max_addr_len += 2;
405 // Setup header format.
406 fmt << "%-" << max_name_len << "s "
407 << "%" << max_size_len << "s "
408 << "%" << max_addr_len << "s\n";
410 // Print header
411 outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
412 static_cast<const char *>("size"),
413 static_cast<const char *>("addr"));
414 fmtbuf.clear();
416 // Setup per section format.
417 fmt << "%-" << max_name_len << "s "
418 << "%#" << max_size_len << radix_fmt << " "
419 << "%#" << max_addr_len << radix_fmt << "\n";
421 // Print each section.
422 for (const SectionRef &Section : Obj->sections()) {
423 if (!considerForSize(Obj, Section))
424 continue;
426 Expected<StringRef> name_or_err = Section.getName();
427 if (!name_or_err) {
428 error(name_or_err.takeError(), Obj->getFileName());
429 return;
432 uint64_t size = Section.getSize();
433 uint64_t addr = Section.getAddress();
434 outs() << format(fmt.str().c_str(), name_or_err->str().c_str(), size, addr);
437 if (ELFCommons) {
438 uint64_t CommonSize = getCommonSize(Obj);
439 total += CommonSize;
440 outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(),
441 CommonSize, static_cast<uint64_t>(0));
444 // Print total.
445 fmtbuf.clear();
446 fmt << "%-" << max_name_len << "s "
447 << "%#" << max_size_len << radix_fmt << "\n";
448 outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
449 total);
450 } else {
451 // The Berkeley format does not display individual section sizes. It
452 // displays the cumulative size for each section type.
453 uint64_t total_text = 0;
454 uint64_t total_data = 0;
455 uint64_t total_bss = 0;
457 // Make one pass over the section table to calculate sizes.
458 for (const SectionRef &Section : Obj->sections()) {
459 uint64_t size = Section.getSize();
460 bool isText = Section.isBerkeleyText();
461 bool isData = Section.isBerkeleyData();
462 bool isBSS = Section.isBSS();
463 if (isText)
464 total_text += size;
465 else if (isData)
466 total_data += size;
467 else if (isBSS)
468 total_bss += size;
471 if (ELFCommons)
472 total_bss += getCommonSize(Obj);
474 total = total_text + total_data + total_bss;
476 if (TotalSizes) {
477 TotalObjectText += total_text;
478 TotalObjectData += total_data;
479 TotalObjectBss += total_bss;
480 TotalObjectTotal += total;
483 if (!BerkeleyHeaderPrinted) {
484 outs() << " text\t"
485 " data\t"
486 " bss\t"
488 << (Radix == octal ? "oct" : "dec")
489 << "\t"
490 " hex\t"
491 "filename\n";
492 BerkeleyHeaderPrinted = true;
495 // Print result.
496 fmt << "%#7" << radix_fmt << "\t"
497 << "%#7" << radix_fmt << "\t"
498 << "%#7" << radix_fmt << "\t";
499 outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
500 fmtbuf.clear();
501 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
502 << "%7" PRIx64 "\t";
503 outs() << format(fmt.str().c_str(), total, total);
507 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
508 /// is a list of architecture flags specified then check to make sure this
509 /// Mach-O file is one of those architectures or all architectures was
510 /// specificed. If not then an error is generated and this routine returns
511 /// false. Else it returns true.
512 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
513 auto *MachO = dyn_cast<MachOObjectFile>(O);
515 if (!MachO || ArchAll || ArchFlags.empty())
516 return true;
518 MachO::mach_header H;
519 MachO::mach_header_64 H_64;
520 Triple T;
521 if (MachO->is64Bit()) {
522 H_64 = MachO->MachOObjectFile::getHeader64();
523 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
524 } else {
525 H = MachO->MachOObjectFile::getHeader();
526 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
528 if (none_of(ArchFlags, [&](const std::string &Name) {
529 return Name == T.getArchName();
530 })) {
531 error("no architecture specified", Filename);
532 return false;
534 return true;
537 /// Print the section sizes for @p file. If @p file is an archive, print the
538 /// section sizes for each archive member.
539 static void printFileSectionSizes(StringRef file) {
541 // Attempt to open the binary.
542 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
543 if (!BinaryOrErr) {
544 error(BinaryOrErr.takeError(), file);
545 return;
547 Binary &Bin = *BinaryOrErr.get().getBinary();
549 if (Archive *a = dyn_cast<Archive>(&Bin)) {
550 // This is an archive. Iterate over each member and display its sizes.
551 Error Err = Error::success();
552 for (auto &C : a->children(Err)) {
553 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
554 if (!ChildOrErr) {
555 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
556 error(std::move(E), a->getFileName(), C);
557 continue;
559 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
560 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
561 if (!checkMachOAndArchFlags(o, file))
562 return;
563 if (OutputFormat == sysv)
564 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n";
565 else if (MachO && OutputFormat == darwin)
566 outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
567 printObjectSectionSizes(o);
568 if (OutputFormat == berkeley) {
569 if (MachO)
570 outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
571 else
572 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
576 if (Err)
577 error(std::move(Err), a->getFileName());
578 } else if (MachOUniversalBinary *UB =
579 dyn_cast<MachOUniversalBinary>(&Bin)) {
580 // If we have a list of architecture flags specified dump only those.
581 if (!ArchAll && !ArchFlags.empty()) {
582 // Look for a slice in the universal binary that matches each ArchFlag.
583 bool ArchFound;
584 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
585 ArchFound = false;
586 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
587 E = UB->end_objects();
588 I != E; ++I) {
589 if (ArchFlags[i] == I->getArchFlagName()) {
590 ArchFound = true;
591 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
592 if (UO) {
593 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
594 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
595 if (OutputFormat == sysv)
596 outs() << o->getFileName() << " :\n";
597 else if (MachO && OutputFormat == darwin) {
598 if (MoreThanOneFile || ArchFlags.size() > 1)
599 outs() << o->getFileName() << " (for architecture "
600 << I->getArchFlagName() << "): \n";
602 printObjectSectionSizes(o);
603 if (OutputFormat == berkeley) {
604 if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
605 outs() << o->getFileName() << " (for architecture "
606 << I->getArchFlagName() << ")";
607 outs() << "\n";
610 } else if (auto E = isNotObjectErrorInvalidFileType(
611 UO.takeError())) {
612 error(std::move(E), file, ArchFlags.size() > 1 ?
613 StringRef(I->getArchFlagName()) : StringRef());
614 return;
615 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
616 I->getAsArchive()) {
617 std::unique_ptr<Archive> &UA = *AOrErr;
618 // This is an archive. Iterate over each member and display its
619 // sizes.
620 Error Err = Error::success();
621 for (auto &C : UA->children(Err)) {
622 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
623 if (!ChildOrErr) {
624 if (auto E = isNotObjectErrorInvalidFileType(
625 ChildOrErr.takeError()))
626 error(std::move(E), UA->getFileName(), C,
627 ArchFlags.size() > 1 ?
628 StringRef(I->getArchFlagName()) : StringRef());
629 continue;
631 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
632 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
633 if (OutputFormat == sysv)
634 outs() << o->getFileName() << " (ex " << UA->getFileName()
635 << "):\n";
636 else if (MachO && OutputFormat == darwin)
637 outs() << UA->getFileName() << "(" << o->getFileName()
638 << ")"
639 << " (for architecture " << I->getArchFlagName()
640 << "):\n";
641 printObjectSectionSizes(o);
642 if (OutputFormat == berkeley) {
643 if (MachO) {
644 outs() << UA->getFileName() << "(" << o->getFileName()
645 << ")";
646 if (ArchFlags.size() > 1)
647 outs() << " (for architecture " << I->getArchFlagName()
648 << ")";
649 outs() << "\n";
650 } else
651 outs() << o->getFileName() << " (ex " << UA->getFileName()
652 << ")\n";
656 if (Err)
657 error(std::move(Err), UA->getFileName());
658 } else {
659 consumeError(AOrErr.takeError());
660 error("mach-o universal file for architecture " +
661 StringRef(I->getArchFlagName()) +
662 " is not a mach-o file or an archive file",
663 file);
667 if (!ArchFound) {
668 error("file does not contain architecture " + ArchFlags[i], file);
669 return;
672 return;
674 // No architecture flags were specified so if this contains a slice that
675 // matches the host architecture dump only that.
676 if (!ArchAll) {
677 StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
678 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
679 E = UB->end_objects();
680 I != E; ++I) {
681 if (HostArchName == I->getArchFlagName()) {
682 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
683 if (UO) {
684 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
685 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
686 if (OutputFormat == sysv)
687 outs() << o->getFileName() << " :\n";
688 else if (MachO && OutputFormat == darwin) {
689 if (MoreThanOneFile)
690 outs() << o->getFileName() << " (for architecture "
691 << I->getArchFlagName() << "):\n";
693 printObjectSectionSizes(o);
694 if (OutputFormat == berkeley) {
695 if (!MachO || MoreThanOneFile)
696 outs() << o->getFileName() << " (for architecture "
697 << I->getArchFlagName() << ")";
698 outs() << "\n";
701 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
702 error(std::move(E), file);
703 return;
704 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
705 I->getAsArchive()) {
706 std::unique_ptr<Archive> &UA = *AOrErr;
707 // This is an archive. Iterate over each member and display its
708 // sizes.
709 Error Err = Error::success();
710 for (auto &C : UA->children(Err)) {
711 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
712 if (!ChildOrErr) {
713 if (auto E = isNotObjectErrorInvalidFileType(
714 ChildOrErr.takeError()))
715 error(std::move(E), UA->getFileName(), C);
716 continue;
718 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
719 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
720 if (OutputFormat == sysv)
721 outs() << o->getFileName() << " (ex " << UA->getFileName()
722 << "):\n";
723 else if (MachO && OutputFormat == darwin)
724 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
725 << " (for architecture " << I->getArchFlagName()
726 << "):\n";
727 printObjectSectionSizes(o);
728 if (OutputFormat == berkeley) {
729 if (MachO)
730 outs() << UA->getFileName() << "(" << o->getFileName()
731 << ")\n";
732 else
733 outs() << o->getFileName() << " (ex " << UA->getFileName()
734 << ")\n";
738 if (Err)
739 error(std::move(Err), UA->getFileName());
740 } else {
741 consumeError(AOrErr.takeError());
742 error("mach-o universal file for architecture " +
743 StringRef(I->getArchFlagName()) +
744 " is not a mach-o file or an archive file",
745 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 for architecture " +
820 StringRef(I->getArchFlagName()) +
821 " is not a mach-o file or an archive file",
822 file);
825 } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
826 if (!checkMachOAndArchFlags(o, file))
827 return;
828 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
829 if (OutputFormat == sysv)
830 outs() << o->getFileName() << " :\n";
831 else if (MachO && OutputFormat == darwin && MoreThanOneFile)
832 outs() << o->getFileName() << ":\n";
833 printObjectSectionSizes(o);
834 if (OutputFormat == berkeley) {
835 if (!MachO || MoreThanOneFile)
836 outs() << o->getFileName();
837 outs() << "\n";
839 } else {
840 error("unsupported file type", file);
842 // System V adds an extra newline at the end of each file.
843 if (OutputFormat == sysv)
844 outs() << "\n";
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(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 printBerkeleyTotals();
894 if (HadError)
895 return 1;