Clang] Fix expansion of response files in -Wp after integrated-cc1 change
[llvm-project.git] / llvm / tools / llvm-size / llvm-size.cpp
blob46ece5a6f0c9d7f2573c9e2a31e9467e5ffdac8f
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 << "\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 total_bss += getCommonSize(Obj);
475 total = total_text + total_data + total_bss;
477 if (TotalSizes) {
478 TotalObjectText += total_text;
479 TotalObjectData += total_data;
480 TotalObjectBss += total_bss;
481 TotalObjectTotal += total;
484 if (!BerkeleyHeaderPrinted) {
485 outs() << " text\t"
486 " data\t"
487 " bss\t"
489 << (Radix == octal ? "oct" : "dec")
490 << "\t"
491 " hex\t"
492 "filename\n";
493 BerkeleyHeaderPrinted = true;
496 // Print result.
497 fmt << "%#7" << radix_fmt << "\t"
498 << "%#7" << radix_fmt << "\t"
499 << "%#7" << radix_fmt << "\t";
500 outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
501 fmtbuf.clear();
502 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
503 << "%7" PRIx64 "\t";
504 outs() << format(fmt.str().c_str(), total, total);
508 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
509 /// is a list of architecture flags specified then check to make sure this
510 /// Mach-O file is one of those architectures or all architectures was
511 /// specificed. If not then an error is generated and this routine returns
512 /// false. Else it returns true.
513 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
514 auto *MachO = dyn_cast<MachOObjectFile>(O);
516 if (!MachO || ArchAll || ArchFlags.empty())
517 return true;
519 MachO::mach_header H;
520 MachO::mach_header_64 H_64;
521 Triple T;
522 if (MachO->is64Bit()) {
523 H_64 = MachO->MachOObjectFile::getHeader64();
524 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
525 } else {
526 H = MachO->MachOObjectFile::getHeader();
527 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
529 if (none_of(ArchFlags, [&](const std::string &Name) {
530 return Name == T.getArchName();
531 })) {
532 error("no architecture specified", Filename);
533 return false;
535 return true;
538 /// Print the section sizes for @p file. If @p file is an archive, print the
539 /// section sizes for each archive member.
540 static void printFileSectionSizes(StringRef file) {
542 // Attempt to open the binary.
543 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
544 if (!BinaryOrErr) {
545 error(BinaryOrErr.takeError(), file);
546 return;
548 Binary &Bin = *BinaryOrErr.get().getBinary();
550 if (Archive *a = dyn_cast<Archive>(&Bin)) {
551 // This is an archive. Iterate over each member and display its sizes.
552 Error Err = Error::success();
553 for (auto &C : a->children(Err)) {
554 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
555 if (!ChildOrErr) {
556 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
557 error(std::move(E), a->getFileName(), C);
558 continue;
560 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
561 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
562 if (!checkMachOAndArchFlags(o, file))
563 return;
564 if (OutputFormat == sysv)
565 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n";
566 else if (MachO && OutputFormat == darwin)
567 outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
568 printObjectSectionSizes(o);
569 if (OutputFormat == berkeley) {
570 if (MachO)
571 outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
572 else
573 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
577 if (Err)
578 error(std::move(Err), a->getFileName());
579 } else if (MachOUniversalBinary *UB =
580 dyn_cast<MachOUniversalBinary>(&Bin)) {
581 // If we have a list of architecture flags specified dump only those.
582 if (!ArchAll && !ArchFlags.empty()) {
583 // Look for a slice in the universal binary that matches each ArchFlag.
584 bool ArchFound;
585 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
586 ArchFound = false;
587 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
588 E = UB->end_objects();
589 I != E; ++I) {
590 if (ArchFlags[i] == I->getArchFlagName()) {
591 ArchFound = true;
592 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
593 if (UO) {
594 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
595 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
596 if (OutputFormat == sysv)
597 outs() << o->getFileName() << " :\n";
598 else if (MachO && OutputFormat == darwin) {
599 if (MoreThanOneFile || ArchFlags.size() > 1)
600 outs() << o->getFileName() << " (for architecture "
601 << I->getArchFlagName() << "): \n";
603 printObjectSectionSizes(o);
604 if (OutputFormat == berkeley) {
605 if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
606 outs() << o->getFileName() << " (for architecture "
607 << I->getArchFlagName() << ")";
608 outs() << "\n";
611 } else if (auto E = isNotObjectErrorInvalidFileType(
612 UO.takeError())) {
613 error(std::move(E), file, ArchFlags.size() > 1 ?
614 StringRef(I->getArchFlagName()) : StringRef());
615 return;
616 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
617 I->getAsArchive()) {
618 std::unique_ptr<Archive> &UA = *AOrErr;
619 // This is an archive. Iterate over each member and display its
620 // sizes.
621 Error Err = Error::success();
622 for (auto &C : UA->children(Err)) {
623 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
624 if (!ChildOrErr) {
625 if (auto E = isNotObjectErrorInvalidFileType(
626 ChildOrErr.takeError()))
627 error(std::move(E), UA->getFileName(), C,
628 ArchFlags.size() > 1 ?
629 StringRef(I->getArchFlagName()) : StringRef());
630 continue;
632 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
633 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
634 if (OutputFormat == sysv)
635 outs() << o->getFileName() << " (ex " << UA->getFileName()
636 << "):\n";
637 else if (MachO && OutputFormat == darwin)
638 outs() << UA->getFileName() << "(" << o->getFileName()
639 << ")"
640 << " (for architecture " << I->getArchFlagName()
641 << "):\n";
642 printObjectSectionSizes(o);
643 if (OutputFormat == berkeley) {
644 if (MachO) {
645 outs() << UA->getFileName() << "(" << o->getFileName()
646 << ")";
647 if (ArchFlags.size() > 1)
648 outs() << " (for architecture " << I->getArchFlagName()
649 << ")";
650 outs() << "\n";
651 } else
652 outs() << o->getFileName() << " (ex " << UA->getFileName()
653 << ")\n";
657 if (Err)
658 error(std::move(Err), UA->getFileName());
659 } else {
660 consumeError(AOrErr.takeError());
661 error("mach-o universal file for architecture " +
662 StringRef(I->getArchFlagName()) +
663 " is not a mach-o file or an archive file",
664 file);
668 if (!ArchFound) {
669 error("file does not contain architecture " + ArchFlags[i], file);
670 return;
673 return;
675 // No architecture flags were specified so if this contains a slice that
676 // matches the host architecture dump only that.
677 if (!ArchAll) {
678 StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
679 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
680 E = UB->end_objects();
681 I != E; ++I) {
682 if (HostArchName == I->getArchFlagName()) {
683 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
684 if (UO) {
685 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
686 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
687 if (OutputFormat == sysv)
688 outs() << o->getFileName() << " :\n";
689 else if (MachO && OutputFormat == darwin) {
690 if (MoreThanOneFile)
691 outs() << o->getFileName() << " (for architecture "
692 << I->getArchFlagName() << "):\n";
694 printObjectSectionSizes(o);
695 if (OutputFormat == berkeley) {
696 if (!MachO || MoreThanOneFile)
697 outs() << o->getFileName() << " (for architecture "
698 << I->getArchFlagName() << ")";
699 outs() << "\n";
702 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
703 error(std::move(E), file);
704 return;
705 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
706 I->getAsArchive()) {
707 std::unique_ptr<Archive> &UA = *AOrErr;
708 // This is an archive. Iterate over each member and display its
709 // sizes.
710 Error Err = Error::success();
711 for (auto &C : UA->children(Err)) {
712 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
713 if (!ChildOrErr) {
714 if (auto E = isNotObjectErrorInvalidFileType(
715 ChildOrErr.takeError()))
716 error(std::move(E), UA->getFileName(), C);
717 continue;
719 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
720 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
721 if (OutputFormat == sysv)
722 outs() << o->getFileName() << " (ex " << UA->getFileName()
723 << "):\n";
724 else if (MachO && OutputFormat == darwin)
725 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
726 << " (for architecture " << I->getArchFlagName()
727 << "):\n";
728 printObjectSectionSizes(o);
729 if (OutputFormat == berkeley) {
730 if (MachO)
731 outs() << UA->getFileName() << "(" << o->getFileName()
732 << ")\n";
733 else
734 outs() << o->getFileName() << " (ex " << UA->getFileName()
735 << ")\n";
739 if (Err)
740 error(std::move(Err), UA->getFileName());
741 } else {
742 consumeError(AOrErr.takeError());
743 error("mach-o universal file for architecture " +
744 StringRef(I->getArchFlagName()) +
745 " is not a mach-o file or an archive file",
746 file);
748 return;
752 // Either all architectures have been specified or none have been specified
753 // and this does not contain the host architecture so dump all the slices.
754 bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
755 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
756 E = UB->end_objects();
757 I != E; ++I) {
758 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
759 if (UO) {
760 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
761 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
762 if (OutputFormat == sysv)
763 outs() << o->getFileName() << " :\n";
764 else if (MachO && OutputFormat == darwin) {
765 if (MoreThanOneFile || MoreThanOneArch)
766 outs() << o->getFileName() << " (for architecture "
767 << I->getArchFlagName() << "):";
768 outs() << "\n";
770 printObjectSectionSizes(o);
771 if (OutputFormat == berkeley) {
772 if (!MachO || MoreThanOneFile || MoreThanOneArch)
773 outs() << o->getFileName() << " (for architecture "
774 << I->getArchFlagName() << ")";
775 outs() << "\n";
778 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
779 error(std::move(E), file, MoreThanOneArch ?
780 StringRef(I->getArchFlagName()) : StringRef());
781 return;
782 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
783 I->getAsArchive()) {
784 std::unique_ptr<Archive> &UA = *AOrErr;
785 // This is an archive. Iterate over each member and display its sizes.
786 Error Err = Error::success();
787 for (auto &C : UA->children(Err)) {
788 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
789 if (!ChildOrErr) {
790 if (auto E = isNotObjectErrorInvalidFileType(
791 ChildOrErr.takeError()))
792 error(std::move(E), UA->getFileName(), C, MoreThanOneArch ?
793 StringRef(I->getArchFlagName()) : StringRef());
794 continue;
796 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
797 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
798 if (OutputFormat == sysv)
799 outs() << o->getFileName() << " (ex " << UA->getFileName()
800 << "):\n";
801 else if (MachO && OutputFormat == darwin)
802 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
803 << " (for architecture " << I->getArchFlagName() << "):\n";
804 printObjectSectionSizes(o);
805 if (OutputFormat == berkeley) {
806 if (MachO)
807 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
808 << " (for architecture " << I->getArchFlagName()
809 << ")\n";
810 else
811 outs() << o->getFileName() << " (ex " << UA->getFileName()
812 << ")\n";
816 if (Err)
817 error(std::move(Err), UA->getFileName());
818 } else {
819 consumeError(AOrErr.takeError());
820 error("mach-o universal file for architecture " +
821 StringRef(I->getArchFlagName()) +
822 " is not a mach-o file or an archive file",
823 file);
826 } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
827 if (!checkMachOAndArchFlags(o, file))
828 return;
829 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
830 if (OutputFormat == sysv)
831 outs() << o->getFileName() << " :\n";
832 else if (MachO && OutputFormat == darwin && MoreThanOneFile)
833 outs() << o->getFileName() << ":\n";
834 printObjectSectionSizes(o);
835 if (OutputFormat == berkeley) {
836 if (!MachO || MoreThanOneFile)
837 outs() << o->getFileName();
838 outs() << "\n";
840 } else {
841 error("unsupported file type", file);
845 static void printBerkeleyTotals() {
846 std::string fmtbuf;
847 raw_string_ostream fmt(fmtbuf);
848 const char *radix_fmt = getRadixFmt();
849 fmt << "%#7" << radix_fmt << "\t"
850 << "%#7" << radix_fmt << "\t"
851 << "%#7" << radix_fmt << "\t";
852 outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData,
853 TotalObjectBss);
854 fmtbuf.clear();
855 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
856 << "%7" PRIx64 "\t";
857 outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal)
858 << "(TOTALS)\n";
861 int main(int argc, char **argv) {
862 InitLLVM X(argc, argv);
863 cl::HideUnrelatedOptions(SizeCat);
864 cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
866 ToolName = argv[0];
867 if (OutputFormatShort.getNumOccurrences())
868 OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
869 if (RadixShort.getNumOccurrences())
870 Radix = RadixShort.getValue();
872 for (StringRef Arch : ArchFlags) {
873 if (Arch == "all") {
874 ArchAll = true;
875 } else {
876 if (!MachOObjectFile::isValidArch(Arch)) {
877 outs() << ToolName << ": for the -arch option: Unknown architecture "
878 << "named '" << Arch << "'";
879 return 1;
884 if (InputFilenames.empty())
885 InputFilenames.push_back("a.out");
887 MoreThanOneFile = InputFilenames.size() > 1;
888 llvm::for_each(InputFilenames, printFileSectionSizes);
889 if (OutputFormat == berkeley && TotalSizes)
890 printBerkeleyTotals();
892 if (HadError)
893 return 1;