[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / llvm / tools / llvm-size / llvm-size.cpp
blob1c7484ba5496ba2110bda1949ca6668137f6e1e9
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/Option/Arg.h"
22 #include "llvm/Option/ArgList.h"
23 #include "llvm/Option/Option.h"
24 #include "llvm/Support/Casting.h"
25 #include "llvm/Support/CommandLine.h"
26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/Format.h"
28 #include "llvm/Support/InitLLVM.h"
29 #include "llvm/Support/MemoryBuffer.h"
30 #include "llvm/Support/WithColor.h"
31 #include "llvm/Support/raw_ostream.h"
32 #include <algorithm>
33 #include <string>
34 #include <system_error>
36 using namespace llvm;
37 using namespace object;
39 namespace {
40 using namespace llvm::opt; // for HelpHidden in Opts.inc
41 enum ID {
42 OPT_INVALID = 0, // This is not an option ID.
43 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
44 HELPTEXT, METAVAR, VALUES) \
45 OPT_##ID,
46 #include "Opts.inc"
47 #undef OPTION
50 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
51 #include "Opts.inc"
52 #undef PREFIX
54 const opt::OptTable::Info InfoTable[] = {
55 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
56 HELPTEXT, METAVAR, VALUES) \
57 { \
58 PREFIX, NAME, HELPTEXT, \
59 METAVAR, OPT_##ID, opt::Option::KIND##Class, \
60 PARAM, FLAGS, OPT_##GROUP, \
61 OPT_##ALIAS, ALIASARGS, VALUES},
62 #include "Opts.inc"
63 #undef OPTION
66 class SizeOptTable : public opt::OptTable {
67 public:
68 SizeOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
71 enum OutputFormatTy { berkeley, sysv, darwin };
72 enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
73 } // namespace
75 static bool ArchAll = false;
76 static std::vector<StringRef> ArchFlags;
77 static bool ELFCommons;
78 static OutputFormatTy OutputFormat;
79 static bool DarwinLongFormat;
80 static RadixTy Radix;
81 static bool TotalSizes;
83 static std::vector<std::string> InputFilenames;
85 static std::string ToolName;
87 // States
88 static bool HadError = false;
89 static bool BerkeleyHeaderPrinted = false;
90 static bool MoreThanOneFile = false;
91 static uint64_t TotalObjectText = 0;
92 static uint64_t TotalObjectData = 0;
93 static uint64_t TotalObjectBss = 0;
94 static uint64_t TotalObjectTotal = 0;
96 static void error(const Twine &Message, StringRef File = "") {
97 HadError = true;
98 if (File.empty())
99 WithColor::error(errs(), ToolName) << Message << '\n';
100 else
101 WithColor::error(errs(), ToolName)
102 << "'" << File << "': " << Message << '\n';
105 // This version of error() prints the archive name and member name, for example:
106 // "libx.a(foo.o)" after the ToolName before the error message. It sets
107 // HadError but returns allowing the code to move on to other archive members.
108 static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
109 StringRef ArchitectureName = StringRef()) {
110 HadError = true;
111 WithColor::error(errs(), ToolName) << "'" << FileName << "'";
113 Expected<StringRef> NameOrErr = C.getName();
114 // TODO: if we have a error getting the name then it would be nice to print
115 // the index of which archive member this is and or its offset in the
116 // archive instead of "???" as the name.
117 if (!NameOrErr) {
118 consumeError(NameOrErr.takeError());
119 errs() << "(" << "???" << ")";
120 } else
121 errs() << "(" << NameOrErr.get() << ")";
123 if (!ArchitectureName.empty())
124 errs() << " (for architecture " << ArchitectureName << ") ";
126 std::string Buf;
127 raw_string_ostream OS(Buf);
128 logAllUnhandledErrors(std::move(E), OS);
129 OS.flush();
130 errs() << ": " << Buf << "\n";
133 // 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
134 // before the error message. It sets HadError but returns allowing the code to
135 // move on to other architecture slices.
136 static void error(llvm::Error E, StringRef FileName,
137 StringRef ArchitectureName = StringRef()) {
138 HadError = true;
139 WithColor::error(errs(), ToolName) << "'" << FileName << "'";
141 if (!ArchitectureName.empty())
142 errs() << " (for architecture " << ArchitectureName << ") ";
144 std::string Buf;
145 raw_string_ostream OS(Buf);
146 logAllUnhandledErrors(std::move(E), OS);
147 OS.flush();
148 errs() << ": " << Buf << "\n";
151 /// Get the length of the string that represents @p num in Radix including the
152 /// leading 0x or 0 for hexadecimal and octal respectively.
153 static size_t getNumLengthAsString(uint64_t num) {
154 APInt conv(64, num);
155 SmallString<32> result;
156 conv.toString(result, Radix, false, true);
157 return result.size();
160 /// Return the printing format for the Radix.
161 static const char *getRadixFmt() {
162 switch (Radix) {
163 case octal:
164 return PRIo64;
165 case decimal:
166 return PRIu64;
167 case hexadecimal:
168 return PRIx64;
170 return nullptr;
173 /// Remove unneeded ELF sections from calculation
174 static bool considerForSize(ObjectFile *Obj, SectionRef Section) {
175 if (!Obj->isELF())
176 return true;
177 switch (static_cast<ELFSectionRef>(Section).getType()) {
178 case ELF::SHT_NULL:
179 case ELF::SHT_SYMTAB:
180 return false;
181 case ELF::SHT_STRTAB:
182 case ELF::SHT_REL:
183 case ELF::SHT_RELA:
184 return static_cast<ELFSectionRef>(Section).getFlags() & ELF::SHF_ALLOC;
186 return true;
189 /// Total size of all ELF common symbols
190 static Expected<uint64_t> getCommonSize(ObjectFile *Obj) {
191 uint64_t TotalCommons = 0;
192 for (auto &Sym : Obj->symbols()) {
193 Expected<uint32_t> SymFlagsOrErr =
194 Obj->getSymbolFlags(Sym.getRawDataRefImpl());
195 if (!SymFlagsOrErr)
196 return SymFlagsOrErr.takeError();
197 if (*SymFlagsOrErr & SymbolRef::SF_Common)
198 TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl());
200 return TotalCommons;
203 /// Print the size of each Mach-O segment and section in @p MachO.
205 /// This is when used when @c OutputFormat is darwin and produces the same
206 /// output as darwin's size(1) -m output.
207 static void printDarwinSectionSizes(MachOObjectFile *MachO) {
208 std::string fmtbuf;
209 raw_string_ostream fmt(fmtbuf);
210 const char *radix_fmt = getRadixFmt();
211 if (Radix == hexadecimal)
212 fmt << "0x";
213 fmt << "%" << radix_fmt;
215 uint32_t Filetype = MachO->getHeader().filetype;
217 uint64_t total = 0;
218 for (const auto &Load : MachO->load_commands()) {
219 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
220 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
221 outs() << "Segment " << Seg.segname << ": "
222 << format(fmt.str().c_str(), Seg.vmsize);
223 if (DarwinLongFormat)
224 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
225 << Seg.fileoff << ")";
226 outs() << "\n";
227 total += Seg.vmsize;
228 uint64_t sec_total = 0;
229 for (unsigned J = 0; J < Seg.nsects; ++J) {
230 MachO::section_64 Sec = MachO->getSection64(Load, J);
231 if (Filetype == MachO::MH_OBJECT)
232 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
233 << format("%.16s", &Sec.sectname) << "): ";
234 else
235 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
236 outs() << format(fmt.str().c_str(), Sec.size);
237 if (DarwinLongFormat)
238 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
239 << Sec.offset << ")";
240 outs() << "\n";
241 sec_total += Sec.size;
243 if (Seg.nsects != 0)
244 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
245 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
246 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
247 uint64_t Seg_vmsize = Seg.vmsize;
248 outs() << "Segment " << Seg.segname << ": "
249 << format(fmt.str().c_str(), Seg_vmsize);
250 if (DarwinLongFormat)
251 outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff "
252 << Seg.fileoff << ")";
253 outs() << "\n";
254 total += Seg.vmsize;
255 uint64_t sec_total = 0;
256 for (unsigned J = 0; J < Seg.nsects; ++J) {
257 MachO::section Sec = MachO->getSection(Load, J);
258 if (Filetype == MachO::MH_OBJECT)
259 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
260 << format("%.16s", &Sec.sectname) << "): ";
261 else
262 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
263 uint64_t Sec_size = Sec.size;
264 outs() << format(fmt.str().c_str(), Sec_size);
265 if (DarwinLongFormat)
266 outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset "
267 << Sec.offset << ")";
268 outs() << "\n";
269 sec_total += Sec.size;
271 if (Seg.nsects != 0)
272 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
275 outs() << "total " << format(fmt.str().c_str(), total) << "\n";
278 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
280 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
281 /// produces the same output as darwin's size(1) default output.
282 static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
283 uint64_t total_text = 0;
284 uint64_t total_data = 0;
285 uint64_t total_objc = 0;
286 uint64_t total_others = 0;
287 for (const auto &Load : MachO->load_commands()) {
288 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
289 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
290 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
291 for (unsigned J = 0; J < Seg.nsects; ++J) {
292 MachO::section_64 Sec = MachO->getSection64(Load, J);
293 StringRef SegmentName = StringRef(Sec.segname);
294 if (SegmentName == "__TEXT")
295 total_text += Sec.size;
296 else if (SegmentName == "__DATA")
297 total_data += Sec.size;
298 else if (SegmentName == "__OBJC")
299 total_objc += Sec.size;
300 else
301 total_others += Sec.size;
303 } else {
304 StringRef SegmentName = StringRef(Seg.segname);
305 if (SegmentName == "__TEXT")
306 total_text += Seg.vmsize;
307 else if (SegmentName == "__DATA")
308 total_data += Seg.vmsize;
309 else if (SegmentName == "__OBJC")
310 total_objc += Seg.vmsize;
311 else
312 total_others += Seg.vmsize;
314 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
315 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
316 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
317 for (unsigned J = 0; J < Seg.nsects; ++J) {
318 MachO::section Sec = MachO->getSection(Load, J);
319 StringRef SegmentName = StringRef(Sec.segname);
320 if (SegmentName == "__TEXT")
321 total_text += Sec.size;
322 else if (SegmentName == "__DATA")
323 total_data += Sec.size;
324 else if (SegmentName == "__OBJC")
325 total_objc += Sec.size;
326 else
327 total_others += Sec.size;
329 } else {
330 StringRef SegmentName = StringRef(Seg.segname);
331 if (SegmentName == "__TEXT")
332 total_text += Seg.vmsize;
333 else if (SegmentName == "__DATA")
334 total_data += Seg.vmsize;
335 else if (SegmentName == "__OBJC")
336 total_objc += Seg.vmsize;
337 else
338 total_others += Seg.vmsize;
342 uint64_t total = total_text + total_data + total_objc + total_others;
344 if (!BerkeleyHeaderPrinted) {
345 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
346 BerkeleyHeaderPrinted = true;
348 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
349 << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
350 << "\t";
353 /// Print the size of each section in @p Obj.
355 /// The format used is determined by @c OutputFormat and @c Radix.
356 static void printObjectSectionSizes(ObjectFile *Obj) {
357 uint64_t total = 0;
358 std::string fmtbuf;
359 raw_string_ostream fmt(fmtbuf);
360 const char *radix_fmt = getRadixFmt();
362 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
363 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
364 // let it fall through to OutputFormat berkeley.
365 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
366 if (OutputFormat == darwin && MachO)
367 printDarwinSectionSizes(MachO);
368 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
369 // darwin's default berkeley format for Mach-O files.
370 else if (MachO && OutputFormat == berkeley)
371 printDarwinSegmentSizes(MachO);
372 else if (OutputFormat == sysv) {
373 // Run two passes over all sections. The first gets the lengths needed for
374 // formatting the output. The second actually does the output.
375 std::size_t max_name_len = strlen("section");
376 std::size_t max_size_len = strlen("size");
377 std::size_t max_addr_len = strlen("addr");
378 for (const SectionRef &Section : Obj->sections()) {
379 if (!considerForSize(Obj, Section))
380 continue;
381 uint64_t size = Section.getSize();
382 total += size;
384 Expected<StringRef> name_or_err = Section.getName();
385 if (!name_or_err) {
386 error(name_or_err.takeError(), Obj->getFileName());
387 return;
390 uint64_t addr = Section.getAddress();
391 max_name_len = std::max(max_name_len, name_or_err->size());
392 max_size_len = std::max(max_size_len, getNumLengthAsString(size));
393 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
396 // Add extra padding.
397 max_name_len += 2;
398 max_size_len += 2;
399 max_addr_len += 2;
401 // Setup header format.
402 fmt << "%-" << max_name_len << "s "
403 << "%" << max_size_len << "s "
404 << "%" << max_addr_len << "s\n";
406 // Print header
407 outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
408 static_cast<const char *>("size"),
409 static_cast<const char *>("addr"));
410 fmtbuf.clear();
412 // Setup per section format.
413 fmt << "%-" << max_name_len << "s "
414 << "%#" << max_size_len << radix_fmt << " "
415 << "%#" << max_addr_len << radix_fmt << "\n";
417 // Print each section.
418 for (const SectionRef &Section : Obj->sections()) {
419 if (!considerForSize(Obj, Section))
420 continue;
422 Expected<StringRef> name_or_err = Section.getName();
423 if (!name_or_err) {
424 error(name_or_err.takeError(), Obj->getFileName());
425 return;
428 uint64_t size = Section.getSize();
429 uint64_t addr = Section.getAddress();
430 outs() << format(fmt.str().c_str(), name_or_err->str().c_str(), size, addr);
433 if (ELFCommons) {
434 if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) {
435 total += *CommonSizeOrErr;
436 outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(),
437 *CommonSizeOrErr, static_cast<uint64_t>(0));
438 } else {
439 error(CommonSizeOrErr.takeError(), Obj->getFileName());
440 return;
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 << "\n\n";
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 if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj))
474 total_bss += *CommonSizeOrErr;
475 else {
476 error(CommonSizeOrErr.takeError(), Obj->getFileName());
477 return;
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 (!is_contained(ArchFlags, T.getArchName())) {
536 error("no architecture specified", Filename);
537 return false;
539 return true;
542 /// Print the section sizes for @p file. If @p file is an archive, print the
543 /// section sizes for each archive member.
544 static void printFileSectionSizes(StringRef file) {
546 // Attempt to open the binary.
547 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
548 if (!BinaryOrErr) {
549 error(BinaryOrErr.takeError(), file);
550 return;
552 Binary &Bin = *BinaryOrErr.get().getBinary();
554 if (Archive *a = dyn_cast<Archive>(&Bin)) {
555 // This is an archive. Iterate over each member and display its sizes.
556 Error Err = Error::success();
557 for (auto &C : a->children(Err)) {
558 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
559 if (!ChildOrErr) {
560 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
561 error(std::move(E), a->getFileName(), C);
562 continue;
564 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
565 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
566 if (!checkMachOAndArchFlags(o, file))
567 return;
568 if (OutputFormat == sysv)
569 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n";
570 else if (MachO && OutputFormat == darwin)
571 outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
572 printObjectSectionSizes(o);
573 if (OutputFormat == berkeley) {
574 if (MachO)
575 outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
576 else
577 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
581 if (Err)
582 error(std::move(Err), a->getFileName());
583 } else if (MachOUniversalBinary *UB =
584 dyn_cast<MachOUniversalBinary>(&Bin)) {
585 // If we have a list of architecture flags specified dump only those.
586 if (!ArchAll && !ArchFlags.empty()) {
587 // Look for a slice in the universal binary that matches each ArchFlag.
588 bool ArchFound;
589 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
590 ArchFound = false;
591 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
592 E = UB->end_objects();
593 I != E; ++I) {
594 if (ArchFlags[i] == I->getArchFlagName()) {
595 ArchFound = true;
596 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
597 if (UO) {
598 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
599 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
600 if (OutputFormat == sysv)
601 outs() << o->getFileName() << " :\n";
602 else if (MachO && OutputFormat == darwin) {
603 if (MoreThanOneFile || ArchFlags.size() > 1)
604 outs() << o->getFileName() << " (for architecture "
605 << I->getArchFlagName() << "): \n";
607 printObjectSectionSizes(o);
608 if (OutputFormat == berkeley) {
609 if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
610 outs() << o->getFileName() << " (for architecture "
611 << I->getArchFlagName() << ")";
612 outs() << "\n";
615 } else if (auto E = isNotObjectErrorInvalidFileType(
616 UO.takeError())) {
617 error(std::move(E), file, ArchFlags.size() > 1 ?
618 StringRef(I->getArchFlagName()) : StringRef());
619 return;
620 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
621 I->getAsArchive()) {
622 std::unique_ptr<Archive> &UA = *AOrErr;
623 // This is an archive. Iterate over each member and display its
624 // sizes.
625 Error Err = Error::success();
626 for (auto &C : UA->children(Err)) {
627 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
628 if (!ChildOrErr) {
629 if (auto E = isNotObjectErrorInvalidFileType(
630 ChildOrErr.takeError()))
631 error(std::move(E), UA->getFileName(), C,
632 ArchFlags.size() > 1 ?
633 StringRef(I->getArchFlagName()) : StringRef());
634 continue;
636 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
637 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
638 if (OutputFormat == sysv)
639 outs() << o->getFileName() << " (ex " << UA->getFileName()
640 << "):\n";
641 else if (MachO && OutputFormat == darwin)
642 outs() << UA->getFileName() << "(" << o->getFileName()
643 << ")"
644 << " (for architecture " << I->getArchFlagName()
645 << "):\n";
646 printObjectSectionSizes(o);
647 if (OutputFormat == berkeley) {
648 if (MachO) {
649 outs() << UA->getFileName() << "(" << o->getFileName()
650 << ")";
651 if (ArchFlags.size() > 1)
652 outs() << " (for architecture " << I->getArchFlagName()
653 << ")";
654 outs() << "\n";
655 } else
656 outs() << o->getFileName() << " (ex " << UA->getFileName()
657 << ")\n";
661 if (Err)
662 error(std::move(Err), UA->getFileName());
663 } else {
664 consumeError(AOrErr.takeError());
665 error("mach-o universal file for architecture " +
666 StringRef(I->getArchFlagName()) +
667 " is not a mach-o file or an archive file",
668 file);
672 if (!ArchFound) {
673 error("file does not contain architecture " + ArchFlags[i], file);
674 return;
677 return;
679 // No architecture flags were specified so if this contains a slice that
680 // matches the host architecture dump only that.
681 if (!ArchAll) {
682 StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
683 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
684 E = UB->end_objects();
685 I != E; ++I) {
686 if (HostArchName == I->getArchFlagName()) {
687 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
688 if (UO) {
689 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
690 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
691 if (OutputFormat == sysv)
692 outs() << o->getFileName() << " :\n";
693 else if (MachO && OutputFormat == darwin) {
694 if (MoreThanOneFile)
695 outs() << o->getFileName() << " (for architecture "
696 << I->getArchFlagName() << "):\n";
698 printObjectSectionSizes(o);
699 if (OutputFormat == berkeley) {
700 if (!MachO || MoreThanOneFile)
701 outs() << o->getFileName() << " (for architecture "
702 << I->getArchFlagName() << ")";
703 outs() << "\n";
706 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
707 error(std::move(E), file);
708 return;
709 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
710 I->getAsArchive()) {
711 std::unique_ptr<Archive> &UA = *AOrErr;
712 // This is an archive. Iterate over each member and display its
713 // sizes.
714 Error Err = Error::success();
715 for (auto &C : UA->children(Err)) {
716 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
717 if (!ChildOrErr) {
718 if (auto E = isNotObjectErrorInvalidFileType(
719 ChildOrErr.takeError()))
720 error(std::move(E), UA->getFileName(), C);
721 continue;
723 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
724 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
725 if (OutputFormat == sysv)
726 outs() << o->getFileName() << " (ex " << UA->getFileName()
727 << "):\n";
728 else if (MachO && OutputFormat == darwin)
729 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
730 << " (for architecture " << I->getArchFlagName()
731 << "):\n";
732 printObjectSectionSizes(o);
733 if (OutputFormat == berkeley) {
734 if (MachO)
735 outs() << UA->getFileName() << "(" << o->getFileName()
736 << ")\n";
737 else
738 outs() << o->getFileName() << " (ex " << UA->getFileName()
739 << ")\n";
743 if (Err)
744 error(std::move(Err), UA->getFileName());
745 } else {
746 consumeError(AOrErr.takeError());
747 error("mach-o universal file for architecture " +
748 StringRef(I->getArchFlagName()) +
749 " is not a mach-o file or an archive file",
750 file);
752 return;
756 // Either all architectures have been specified or none have been specified
757 // and this does not contain the host architecture so dump all the slices.
758 bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
759 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
760 E = UB->end_objects();
761 I != E; ++I) {
762 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
763 if (UO) {
764 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
765 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
766 if (OutputFormat == sysv)
767 outs() << o->getFileName() << " :\n";
768 else if (MachO && OutputFormat == darwin) {
769 if (MoreThanOneFile || MoreThanOneArch)
770 outs() << o->getFileName() << " (for architecture "
771 << I->getArchFlagName() << "):";
772 outs() << "\n";
774 printObjectSectionSizes(o);
775 if (OutputFormat == berkeley) {
776 if (!MachO || MoreThanOneFile || MoreThanOneArch)
777 outs() << o->getFileName() << " (for architecture "
778 << I->getArchFlagName() << ")";
779 outs() << "\n";
782 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
783 error(std::move(E), file, MoreThanOneArch ?
784 StringRef(I->getArchFlagName()) : StringRef());
785 return;
786 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
787 I->getAsArchive()) {
788 std::unique_ptr<Archive> &UA = *AOrErr;
789 // This is an archive. Iterate over each member and display its sizes.
790 Error Err = Error::success();
791 for (auto &C : UA->children(Err)) {
792 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
793 if (!ChildOrErr) {
794 if (auto E = isNotObjectErrorInvalidFileType(
795 ChildOrErr.takeError()))
796 error(std::move(E), UA->getFileName(), C, MoreThanOneArch ?
797 StringRef(I->getArchFlagName()) : StringRef());
798 continue;
800 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
801 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
802 if (OutputFormat == sysv)
803 outs() << o->getFileName() << " (ex " << UA->getFileName()
804 << "):\n";
805 else if (MachO && OutputFormat == darwin)
806 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
807 << " (for architecture " << I->getArchFlagName() << "):\n";
808 printObjectSectionSizes(o);
809 if (OutputFormat == berkeley) {
810 if (MachO)
811 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
812 << " (for architecture " << I->getArchFlagName()
813 << ")\n";
814 else
815 outs() << o->getFileName() << " (ex " << UA->getFileName()
816 << ")\n";
820 if (Err)
821 error(std::move(Err), UA->getFileName());
822 } else {
823 consumeError(AOrErr.takeError());
824 error("mach-o universal file for architecture " +
825 StringRef(I->getArchFlagName()) +
826 " is not a mach-o file or an archive file",
827 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 error("unsupported file type", file);
849 static void printBerkeleyTotals() {
850 std::string fmtbuf;
851 raw_string_ostream fmt(fmtbuf);
852 const char *radix_fmt = getRadixFmt();
853 fmt << "%#7" << radix_fmt << "\t"
854 << "%#7" << radix_fmt << "\t"
855 << "%#7" << radix_fmt << "\t";
856 outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData,
857 TotalObjectBss);
858 fmtbuf.clear();
859 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
860 << "%7" PRIx64 "\t";
861 outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal)
862 << "(TOTALS)\n";
865 int main(int argc, char **argv) {
866 InitLLVM X(argc, argv);
867 BumpPtrAllocator A;
868 StringSaver Saver(A);
869 SizeOptTable Tbl;
870 ToolName = argv[0];
871 opt::InputArgList Args =
872 Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
873 error(Msg);
874 exit(1);
876 if (Args.hasArg(OPT_help)) {
877 Tbl.printHelp(
878 outs(),
879 (Twine(ToolName) + " [options] <input object files>").str().c_str(),
880 "LLVM object size dumper");
881 // TODO Replace this with OptTable API once it adds extrahelp support.
882 outs() << "\nPass @FILE as argument to read options from FILE.\n";
883 return 0;
885 if (Args.hasArg(OPT_version)) {
886 outs() << ToolName << '\n';
887 cl::PrintVersionMessage();
888 return 0;
891 ELFCommons = Args.hasArg(OPT_common);
892 DarwinLongFormat = Args.hasArg(OPT_l);
893 TotalSizes = Args.hasArg(OPT_totals);
894 StringRef V = Args.getLastArgValue(OPT_format_EQ, "berkeley");
895 if (V == "berkeley")
896 OutputFormat = berkeley;
897 else if (V == "darwin")
898 OutputFormat = darwin;
899 else if (V == "sysv")
900 OutputFormat = sysv;
901 else
902 error("--format value should be one of: 'berkeley', 'darwin', 'sysv'");
903 V = Args.getLastArgValue(OPT_radix_EQ, "10");
904 if (V == "8")
905 Radix = RadixTy::octal;
906 else if (V == "10")
907 Radix = RadixTy::decimal;
908 else if (V == "16")
909 Radix = RadixTy::hexadecimal;
910 else
911 error("--radix value should be one of: 8, 10, 16 ");
913 for (const auto *A : Args.filtered(OPT_arch_EQ)) {
914 SmallVector<StringRef, 2> Values;
915 llvm::SplitString(A->getValue(), Values, ",");
916 for (StringRef V : Values) {
917 if (V == "all")
918 ArchAll = true;
919 else if (MachOObjectFile::isValidArch(V))
920 ArchFlags.push_back(V);
921 else {
922 outs() << ToolName << ": for the -arch option: Unknown architecture "
923 << "named '" << V << "'";
924 return 1;
929 InputFilenames = Args.getAllArgValues(OPT_INPUT);
930 if (InputFilenames.empty())
931 InputFilenames.push_back("a.out");
933 MoreThanOneFile = InputFilenames.size() > 1;
934 llvm::for_each(InputFilenames, printFileSectionSizes);
935 if (OutputFormat == berkeley && TotalSizes)
936 printBerkeleyTotals();
938 if (HadError)
939 return 1;