[clang][bytecode][NFC] Only get expr when checking for UB (#125397)
[llvm-project.git] / llvm / tools / llvm-size / llvm-size.cpp
blob0d7bf24832670224f4890527bb48ffccfd714ff0
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/LLVMDriver.h"
29 #include "llvm/Support/MemoryBuffer.h"
30 #include "llvm/Support/WithColor.h"
31 #include "llvm/Support/raw_ostream.h"
32 #include <algorithm>
33 #include <string>
34 #include <system_error>
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(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
44 #include "Opts.inc"
45 #undef OPTION
48 #define OPTTABLE_STR_TABLE_CODE
49 #include "Opts.inc"
50 #undef OPTTABLE_STR_TABLE_CODE
52 #define OPTTABLE_PREFIXES_TABLE_CODE
53 #include "Opts.inc"
54 #undef OPTTABLE_PREFIXES_TABLE_CODE
56 static constexpr opt::OptTable::Info InfoTable[] = {
57 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
58 #include "Opts.inc"
59 #undef OPTION
62 class SizeOptTable : public opt::GenericOptTable {
63 public:
64 SizeOptTable()
65 : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
66 setGroupedShortOptions(true);
70 enum OutputFormatTy { berkeley, sysv, darwin };
71 enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
72 } // namespace
74 static bool ArchAll = false;
75 static std::vector<StringRef> ArchFlags;
76 static bool ELFCommons;
77 static OutputFormatTy OutputFormat;
78 static bool DarwinLongFormat;
79 static RadixTy Radix;
80 static bool TotalSizes;
82 static std::vector<std::string> InputFilenames;
84 static std::string ToolName;
86 // States
87 static bool HadError = false;
88 static bool BerkeleyHeaderPrinted = false;
89 static bool MoreThanOneFile = false;
90 static uint64_t TotalObjectText = 0;
91 static uint64_t TotalObjectData = 0;
92 static uint64_t TotalObjectBss = 0;
93 static uint64_t TotalObjectTotal = 0;
95 static void error(const Twine &Message, StringRef File = "") {
96 HadError = true;
97 if (File.empty())
98 WithColor::error(errs(), ToolName) << Message << '\n';
99 else
100 WithColor::error(errs(), ToolName)
101 << "'" << File << "': " << Message << '\n';
104 // This version of error() prints the archive name and member name, for example:
105 // "libx.a(foo.o)" after the ToolName before the error message. It sets
106 // HadError but returns allowing the code to move on to other archive members.
107 static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
108 StringRef ArchitectureName = StringRef()) {
109 HadError = true;
110 WithColor::error(errs(), ToolName) << "'" << FileName << "'";
112 Expected<StringRef> NameOrErr = C.getName();
113 // TODO: if we have a error getting the name then it would be nice to print
114 // the index of which archive member this is and or its offset in the
115 // archive instead of "???" as the name.
116 if (!NameOrErr) {
117 consumeError(NameOrErr.takeError());
118 errs() << "(" << "???" << ")";
119 } else
120 errs() << "(" << NameOrErr.get() << ")";
122 if (!ArchitectureName.empty())
123 errs() << " (for architecture " << ArchitectureName << ") ";
125 std::string Buf;
126 raw_string_ostream OS(Buf);
127 logAllUnhandledErrors(std::move(E), OS);
128 OS.flush();
129 errs() << ": " << Buf << "\n";
132 // 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
133 // before the error message. It sets HadError but returns allowing the code to
134 // move on to other architecture slices.
135 static void error(llvm::Error E, StringRef FileName,
136 StringRef ArchitectureName = StringRef()) {
137 HadError = true;
138 WithColor::error(errs(), ToolName) << "'" << FileName << "'";
140 if (!ArchitectureName.empty())
141 errs() << " (for architecture " << ArchitectureName << ") ";
143 std::string Buf;
144 raw_string_ostream OS(Buf);
145 logAllUnhandledErrors(std::move(E), OS);
146 OS.flush();
147 errs() << ": " << Buf << "\n";
150 /// Get the length of the string that represents @p num in Radix including the
151 /// leading 0x or 0 for hexadecimal and octal respectively.
152 static size_t getNumLengthAsString(uint64_t num) {
153 APInt conv(64, num);
154 SmallString<32> result;
155 conv.toString(result, Radix, false, true);
156 return result.size();
159 /// Return the printing format for the Radix.
160 static const char *getRadixFmt() {
161 switch (Radix) {
162 case octal:
163 return PRIo64;
164 case decimal:
165 return PRIu64;
166 case hexadecimal:
167 return PRIx64;
169 return nullptr;
172 /// Remove unneeded ELF sections from calculation
173 static bool considerForSize(ObjectFile *Obj, SectionRef Section) {
174 if (!Obj->isELF())
175 return true;
176 switch (static_cast<ELFSectionRef>(Section).getType()) {
177 case ELF::SHT_NULL:
178 case ELF::SHT_SYMTAB:
179 return false;
180 case ELF::SHT_STRTAB:
181 case ELF::SHT_REL:
182 case ELF::SHT_RELA:
183 return static_cast<ELFSectionRef>(Section).getFlags() & ELF::SHF_ALLOC;
185 return true;
188 /// Total size of all ELF common symbols
189 static Expected<uint64_t> getCommonSize(ObjectFile *Obj) {
190 uint64_t TotalCommons = 0;
191 for (auto &Sym : Obj->symbols()) {
192 Expected<uint32_t> SymFlagsOrErr =
193 Obj->getSymbolFlags(Sym.getRawDataRefImpl());
194 if (!SymFlagsOrErr)
195 return SymFlagsOrErr.takeError();
196 if (*SymFlagsOrErr & SymbolRef::SF_Common)
197 TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl());
199 return TotalCommons;
202 /// Print the size of each Mach-O segment and section in @p MachO.
204 /// This is when used when @c OutputFormat is darwin and produces the same
205 /// output as darwin's size(1) -m output.
206 static void printDarwinSectionSizes(MachOObjectFile *MachO) {
207 std::string fmtbuf;
208 raw_string_ostream fmt(fmtbuf);
209 const char *radix_fmt = getRadixFmt();
210 if (Radix == hexadecimal)
211 fmt << "0x";
212 fmt << "%" << radix_fmt;
214 uint32_t Filetype = MachO->getHeader().filetype;
216 uint64_t total = 0;
217 for (const auto &Load : MachO->load_commands()) {
218 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
219 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
220 outs() << "Segment " << Seg.segname << ": "
221 << format(fmtbuf.c_str(), Seg.vmsize);
222 if (DarwinLongFormat)
223 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
224 << Seg.fileoff << ")";
225 outs() << "\n";
226 total += Seg.vmsize;
227 uint64_t sec_total = 0;
228 for (unsigned J = 0; J < Seg.nsects; ++J) {
229 MachO::section_64 Sec = MachO->getSection64(Load, J);
230 if (Filetype == MachO::MH_OBJECT)
231 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
232 << format("%.16s", &Sec.sectname) << "): ";
233 else
234 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
235 outs() << format(fmtbuf.c_str(), Sec.size);
236 if (DarwinLongFormat)
237 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
238 << Sec.offset << ")";
239 outs() << "\n";
240 sec_total += Sec.size;
242 if (Seg.nsects != 0)
243 outs() << "\ttotal " << format(fmtbuf.c_str(), sec_total) << "\n";
244 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
245 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
246 uint64_t Seg_vmsize = Seg.vmsize;
247 outs() << "Segment " << Seg.segname << ": "
248 << format(fmtbuf.c_str(), Seg_vmsize);
249 if (DarwinLongFormat)
250 outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff "
251 << Seg.fileoff << ")";
252 outs() << "\n";
253 total += Seg.vmsize;
254 uint64_t sec_total = 0;
255 for (unsigned J = 0; J < Seg.nsects; ++J) {
256 MachO::section Sec = MachO->getSection(Load, J);
257 if (Filetype == MachO::MH_OBJECT)
258 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
259 << format("%.16s", &Sec.sectname) << "): ";
260 else
261 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
262 uint64_t Sec_size = Sec.size;
263 outs() << format(fmtbuf.c_str(), Sec_size);
264 if (DarwinLongFormat)
265 outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset "
266 << Sec.offset << ")";
267 outs() << "\n";
268 sec_total += Sec.size;
270 if (Seg.nsects != 0)
271 outs() << "\ttotal " << format(fmtbuf.c_str(), sec_total) << "\n";
274 outs() << "total " << format(fmtbuf.c_str(), total) << "\n";
277 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
279 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
280 /// produces the same output as darwin's size(1) default output.
281 static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
282 uint64_t total_text = 0;
283 uint64_t total_data = 0;
284 uint64_t total_objc = 0;
285 uint64_t total_others = 0;
286 for (const auto &Load : MachO->load_commands()) {
287 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
288 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
289 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
290 for (unsigned J = 0; J < Seg.nsects; ++J) {
291 MachO::section_64 Sec = MachO->getSection64(Load, J);
292 StringRef SegmentName = StringRef(Sec.segname);
293 if (SegmentName == "__TEXT")
294 total_text += Sec.size;
295 else if (SegmentName == "__DATA")
296 total_data += Sec.size;
297 else if (SegmentName == "__OBJC")
298 total_objc += Sec.size;
299 else
300 total_others += Sec.size;
302 } else {
303 StringRef SegmentName = StringRef(Seg.segname);
304 if (SegmentName == "__TEXT")
305 total_text += Seg.vmsize;
306 else if (SegmentName == "__DATA")
307 total_data += Seg.vmsize;
308 else if (SegmentName == "__OBJC")
309 total_objc += Seg.vmsize;
310 else
311 total_others += Seg.vmsize;
313 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
314 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
315 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
316 for (unsigned J = 0; J < Seg.nsects; ++J) {
317 MachO::section Sec = MachO->getSection(Load, J);
318 StringRef SegmentName = StringRef(Sec.segname);
319 if (SegmentName == "__TEXT")
320 total_text += Sec.size;
321 else if (SegmentName == "__DATA")
322 total_data += Sec.size;
323 else if (SegmentName == "__OBJC")
324 total_objc += Sec.size;
325 else
326 total_others += Sec.size;
328 } else {
329 StringRef SegmentName = StringRef(Seg.segname);
330 if (SegmentName == "__TEXT")
331 total_text += Seg.vmsize;
332 else if (SegmentName == "__DATA")
333 total_data += Seg.vmsize;
334 else if (SegmentName == "__OBJC")
335 total_objc += Seg.vmsize;
336 else
337 total_others += Seg.vmsize;
341 uint64_t total = total_text + total_data + total_objc + total_others;
343 if (!BerkeleyHeaderPrinted) {
344 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
345 BerkeleyHeaderPrinted = true;
347 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
348 << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
349 << "\t";
352 /// Print the size of each section in @p Obj.
354 /// The format used is determined by @c OutputFormat and @c Radix.
355 static void printObjectSectionSizes(ObjectFile *Obj) {
356 uint64_t total = 0;
357 std::string fmtbuf;
358 raw_string_ostream fmt(fmtbuf);
359 const char *radix_fmt = getRadixFmt();
361 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
362 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
363 // let it fall through to OutputFormat berkeley.
364 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
365 if (OutputFormat == darwin && MachO)
366 printDarwinSectionSizes(MachO);
367 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
368 // darwin's default berkeley format for Mach-O files.
369 else if (MachO && OutputFormat == berkeley)
370 printDarwinSegmentSizes(MachO);
371 else if (OutputFormat == sysv) {
372 // Run two passes over all sections. The first gets the lengths needed for
373 // formatting the output. The second actually does the output.
374 std::size_t max_name_len = strlen("section");
375 std::size_t max_size_len = strlen("size");
376 std::size_t max_addr_len = strlen("addr");
377 for (const SectionRef &Section : Obj->sections()) {
378 if (!considerForSize(Obj, Section))
379 continue;
380 uint64_t size = Section.getSize();
381 total += size;
383 Expected<StringRef> name_or_err = Section.getName();
384 if (!name_or_err) {
385 error(name_or_err.takeError(), Obj->getFileName());
386 return;
389 uint64_t addr = Section.getAddress();
390 max_name_len = std::max(max_name_len, name_or_err->size());
391 max_size_len = std::max(max_size_len, getNumLengthAsString(size));
392 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
395 // Add extra padding.
396 max_name_len += 2;
397 max_size_len += 2;
398 max_addr_len += 2;
400 // Setup header format.
401 fmt << "%-" << max_name_len << "s "
402 << "%" << max_size_len << "s "
403 << "%" << max_addr_len << "s\n";
405 // Print header
406 outs() << format(fmtbuf.c_str(), static_cast<const char *>("section"),
407 static_cast<const char *>("size"),
408 static_cast<const char *>("addr"));
409 fmtbuf.clear();
411 // Setup per section format.
412 fmt << "%-" << max_name_len << "s "
413 << "%#" << max_size_len << radix_fmt << " "
414 << "%#" << max_addr_len << radix_fmt << "\n";
416 // Print each section.
417 for (const SectionRef &Section : Obj->sections()) {
418 if (!considerForSize(Obj, Section))
419 continue;
421 Expected<StringRef> name_or_err = Section.getName();
422 if (!name_or_err) {
423 error(name_or_err.takeError(), Obj->getFileName());
424 return;
427 uint64_t size = Section.getSize();
428 uint64_t addr = Section.getAddress();
429 outs() << format(fmtbuf.c_str(), name_or_err->str().c_str(), size, addr);
432 if (ELFCommons) {
433 if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) {
434 total += *CommonSizeOrErr;
435 outs() << format(fmtbuf.c_str(), std::string("*COM*").c_str(),
436 *CommonSizeOrErr, static_cast<uint64_t>(0));
437 } else {
438 error(CommonSizeOrErr.takeError(), Obj->getFileName());
439 return;
443 // Print total.
444 fmtbuf.clear();
445 fmt << "%-" << max_name_len << "s "
446 << "%#" << max_size_len << radix_fmt << "\n";
447 outs() << format(fmtbuf.c_str(), static_cast<const char *>("Total"), total)
448 << "\n\n";
449 } else {
450 // The Berkeley format does not display individual section sizes. It
451 // displays the cumulative size for each section type.
452 uint64_t total_text = 0;
453 uint64_t total_data = 0;
454 uint64_t total_bss = 0;
456 // Make one pass over the section table to calculate sizes.
457 for (const SectionRef &Section : Obj->sections()) {
458 uint64_t size = Section.getSize();
459 bool isText = Section.isBerkeleyText();
460 bool isData = Section.isBerkeleyData();
461 bool isBSS = Section.isBSS();
462 if (isText)
463 total_text += size;
464 else if (isData)
465 total_data += size;
466 else if (isBSS)
467 total_bss += size;
470 if (ELFCommons) {
471 if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj))
472 total_bss += *CommonSizeOrErr;
473 else {
474 error(CommonSizeOrErr.takeError(), Obj->getFileName());
475 return;
479 total = total_text + total_data + total_bss;
481 if (TotalSizes) {
482 TotalObjectText += total_text;
483 TotalObjectData += total_data;
484 TotalObjectBss += total_bss;
485 TotalObjectTotal += total;
488 if (!BerkeleyHeaderPrinted) {
489 outs() << " text\t"
490 " data\t"
491 " bss\t"
493 << (Radix == octal ? "oct" : "dec")
494 << "\t"
495 " hex\t"
496 "filename\n";
497 BerkeleyHeaderPrinted = true;
500 // Print result.
501 fmt << "%#7" << radix_fmt << "\t"
502 << "%#7" << radix_fmt << "\t"
503 << "%#7" << radix_fmt << "\t";
504 outs() << format(fmtbuf.c_str(), total_text, total_data, total_bss);
505 fmtbuf.clear();
506 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
507 << "%7" PRIx64 "\t";
508 outs() << format(fmtbuf.c_str(), total, total);
512 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
513 /// is a list of architecture flags specified then check to make sure this
514 /// Mach-O file is one of those architectures or all architectures was
515 /// specificed. If not then an error is generated and this routine returns
516 /// false. Else it returns true.
517 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
518 auto *MachO = dyn_cast<MachOObjectFile>(O);
520 if (!MachO || ArchAll || ArchFlags.empty())
521 return true;
523 MachO::mach_header H;
524 MachO::mach_header_64 H_64;
525 Triple T;
526 if (MachO->is64Bit()) {
527 H_64 = MachO->MachOObjectFile::getHeader64();
528 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
529 } else {
530 H = MachO->MachOObjectFile::getHeader();
531 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
533 if (!is_contained(ArchFlags, T.getArchName())) {
534 error("no architecture specified", Filename);
535 return false;
537 return true;
540 /// Print the section sizes for @p file. If @p file is an archive, print the
541 /// section sizes for each archive member.
542 static void printFileSectionSizes(StringRef file) {
544 // Attempt to open the binary.
545 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
546 if (!BinaryOrErr) {
547 error(BinaryOrErr.takeError(), file);
548 return;
550 Binary &Bin = *BinaryOrErr.get().getBinary();
552 if (Archive *a = dyn_cast<Archive>(&Bin)) {
553 // This is an archive. Iterate over each member and display its sizes.
554 Error Err = Error::success();
555 for (auto &C : a->children(Err)) {
556 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
557 if (!ChildOrErr) {
558 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
559 error(std::move(E), a->getFileName(), C);
560 continue;
562 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
563 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
564 if (!checkMachOAndArchFlags(o, file))
565 return;
566 if (OutputFormat == sysv)
567 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n";
568 else if (MachO && OutputFormat == darwin)
569 outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
570 printObjectSectionSizes(o);
571 if (!MachO && OutputFormat == darwin)
572 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
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 (!MachO && OutputFormat == darwin)
840 outs() << o->getFileName() << "\n";
841 if (OutputFormat == berkeley) {
842 if (!MachO || MoreThanOneFile)
843 outs() << o->getFileName();
844 outs() << "\n";
846 } else {
847 error("unsupported file type", file);
851 static void printBerkeleyTotals() {
852 std::string fmtbuf;
853 raw_string_ostream fmt(fmtbuf);
854 const char *radix_fmt = getRadixFmt();
855 fmt << "%#7" << radix_fmt << "\t"
856 << "%#7" << radix_fmt << "\t"
857 << "%#7" << radix_fmt << "\t";
858 outs() << format(fmtbuf.c_str(), TotalObjectText, TotalObjectData,
859 TotalObjectBss);
860 fmtbuf.clear();
861 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
862 << "%7" PRIx64 "\t";
863 outs() << format(fmtbuf.c_str(), TotalObjectTotal, TotalObjectTotal)
864 << "(TOTALS)\n";
867 int llvm_size_main(int argc, char **argv, const llvm::ToolContext &) {
868 BumpPtrAllocator A;
869 StringSaver Saver(A);
870 SizeOptTable Tbl;
871 ToolName = argv[0];
872 opt::InputArgList Args =
873 Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
874 error(Msg);
875 exit(1);
877 if (Args.hasArg(OPT_help)) {
878 Tbl.printHelp(
879 outs(),
880 (Twine(ToolName) + " [options] <input object files>").str().c_str(),
881 "LLVM object size dumper");
882 // TODO Replace this with OptTable API once it adds extrahelp support.
883 outs() << "\nPass @FILE as argument to read options from FILE.\n";
884 return 0;
886 if (Args.hasArg(OPT_version)) {
887 outs() << ToolName << '\n';
888 cl::PrintVersionMessage();
889 return 0;
892 ELFCommons = Args.hasArg(OPT_common);
893 DarwinLongFormat = Args.hasArg(OPT_l);
894 TotalSizes = Args.hasArg(OPT_totals);
895 StringRef V = Args.getLastArgValue(OPT_format_EQ, "berkeley");
896 if (V == "berkeley")
897 OutputFormat = berkeley;
898 else if (V == "darwin")
899 OutputFormat = darwin;
900 else if (V == "sysv")
901 OutputFormat = sysv;
902 else
903 error("--format value should be one of: 'berkeley', 'darwin', 'sysv'");
904 V = Args.getLastArgValue(OPT_radix_EQ, "10");
905 if (V == "8")
906 Radix = RadixTy::octal;
907 else if (V == "10")
908 Radix = RadixTy::decimal;
909 else if (V == "16")
910 Radix = RadixTy::hexadecimal;
911 else
912 error("--radix value should be one of: 8, 10, 16 ");
914 for (const auto *A : Args.filtered(OPT_arch_EQ)) {
915 SmallVector<StringRef, 2> Values;
916 llvm::SplitString(A->getValue(), Values, ",");
917 for (StringRef V : Values) {
918 if (V == "all")
919 ArchAll = true;
920 else if (MachOObjectFile::isValidArch(V))
921 ArchFlags.push_back(V);
922 else {
923 outs() << ToolName << ": for the -arch option: Unknown architecture "
924 << "named '" << V << "'";
925 return 1;
930 InputFilenames = Args.getAllArgValues(OPT_INPUT);
931 if (InputFilenames.empty())
932 InputFilenames.push_back("a.out");
934 MoreThanOneFile = InputFilenames.size() > 1;
935 llvm::for_each(InputFilenames, printFileSectionSizes);
936 if (OutputFormat == berkeley && TotalSizes)
937 printBerkeleyTotals();
939 if (HadError)
940 return 1;
941 return 0;