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.
12 //
13 //===----------------------------------------------------------------------===//
14
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>
32
33 using namespace llvm;
34 using namespace object;
35
36 cl::OptionCategory SizeCat("llvm-size Options");
37
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));
45
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));
52
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;
59
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));
65
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));
71
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;
76
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));
84
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));
91
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));
96
97 static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"),
98 cl::aliasopt(TotalSizes));
99
100 static cl::list<std::string>
101 InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
102
103 static cl::extrahelp
104 HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
105
106 static bool HadError = false;
107
108 static std::string ToolName;
109
error(const Twine & Message,StringRef File)110 static void error(const Twine &Message, StringRef File) {
111 HadError = true;
112 WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n";
113 }
114
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.
error(llvm::Error E,StringRef FileName,const Archive::Child & C,StringRef ArchitectureName=StringRef ())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 << "'";
122
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() << ")";
132
133 if (!ArchitectureName.empty())
134 errs() << " (for architecture " << ArchitectureName << ") ";
135
136 std::string Buf;
137 raw_string_ostream OS(Buf);
138 logAllUnhandledErrors(std::move(E), OS);
139 OS.flush();
140 errs() << ": " << Buf << "\n";
141 }
142
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.
error(llvm::Error E,StringRef FileName,StringRef ArchitectureName=StringRef ())146 static void error(llvm::Error E, StringRef FileName,
147 StringRef ArchitectureName = StringRef()) {
148 HadError = true;
149 WithColor::error(errs(), ToolName) << "'" << FileName << "'";
150
151 if (!ArchitectureName.empty())
152 errs() << " (for architecture " << ArchitectureName << ") ";
153
154 std::string Buf;
155 raw_string_ostream OS(Buf);
156 logAllUnhandledErrors(std::move(E), OS);
157 OS.flush();
158 errs() << ": " << Buf << "\n";
159 }
160
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.
getNumLengthAsString(uint64_t num)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();
168 }
169
170 /// Return the printing format for the Radix.
getRadixFmt()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;
179 }
180 return nullptr;
181 }
182
183 /// Remove unneeded ELF sections from calculation
considerForSize(ObjectFile * Obj,SectionRef Section)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 return false;
191 case ELF::SHT_STRTAB:
192 case ELF::SHT_REL:
193 case ELF::SHT_RELA:
194 return static_cast<ELFSectionRef>(Section).getFlags() & ELF::SHF_ALLOC;
195 }
196 return true;
197 }
198
199 /// Total size of all ELF common symbols
getCommonSize(ObjectFile * Obj)200 static Expected<uint64_t> getCommonSize(ObjectFile *Obj) {
201 uint64_t TotalCommons = 0;
202 for (auto &Sym : Obj->symbols()) {
203 Expected<uint32_t> SymFlagsOrErr =
204 Obj->getSymbolFlags(Sym.getRawDataRefImpl());
205 if (!SymFlagsOrErr)
206 return SymFlagsOrErr.takeError();
207 if (*SymFlagsOrErr & SymbolRef::SF_Common)
208 TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl());
209 }
210 return TotalCommons;
211 }
212
213 /// Print the size of each Mach-O segment and section in @p MachO.
214 ///
215 /// This is when used when @c OutputFormat is darwin and produces the same
216 /// output as darwin's size(1) -m output.
printDarwinSectionSizes(MachOObjectFile * MachO)217 static void printDarwinSectionSizes(MachOObjectFile *MachO) {
218 std::string fmtbuf;
219 raw_string_ostream fmt(fmtbuf);
220 const char *radix_fmt = getRadixFmt();
221 if (Radix == hexadecimal)
222 fmt << "0x";
223 fmt << "%" << radix_fmt;
224
225 uint32_t Filetype = MachO->getHeader().filetype;
226
227 uint64_t total = 0;
228 for (const auto &Load : MachO->load_commands()) {
229 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
230 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
231 outs() << "Segment " << Seg.segname << ": "
232 << format(fmt.str().c_str(), Seg.vmsize);
233 if (DarwinLongFormat)
234 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
235 << Seg.fileoff << ")";
236 outs() << "\n";
237 total += Seg.vmsize;
238 uint64_t sec_total = 0;
239 for (unsigned J = 0; J < Seg.nsects; ++J) {
240 MachO::section_64 Sec = MachO->getSection64(Load, J);
241 if (Filetype == MachO::MH_OBJECT)
242 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
243 << format("%.16s", &Sec.sectname) << "): ";
244 else
245 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
246 outs() << format(fmt.str().c_str(), Sec.size);
247 if (DarwinLongFormat)
248 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
249 << Sec.offset << ")";
250 outs() << "\n";
251 sec_total += Sec.size;
252 }
253 if (Seg.nsects != 0)
254 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
255 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
256 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
257 uint64_t Seg_vmsize = Seg.vmsize;
258 outs() << "Segment " << Seg.segname << ": "
259 << format(fmt.str().c_str(), Seg_vmsize);
260 if (DarwinLongFormat)
261 outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff "
262 << Seg.fileoff << ")";
263 outs() << "\n";
264 total += Seg.vmsize;
265 uint64_t sec_total = 0;
266 for (unsigned J = 0; J < Seg.nsects; ++J) {
267 MachO::section Sec = MachO->getSection(Load, J);
268 if (Filetype == MachO::MH_OBJECT)
269 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
270 << format("%.16s", &Sec.sectname) << "): ";
271 else
272 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
273 uint64_t Sec_size = Sec.size;
274 outs() << format(fmt.str().c_str(), Sec_size);
275 if (DarwinLongFormat)
276 outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset "
277 << Sec.offset << ")";
278 outs() << "\n";
279 sec_total += Sec.size;
280 }
281 if (Seg.nsects != 0)
282 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
283 }
284 }
285 outs() << "total " << format(fmt.str().c_str(), total) << "\n";
286 }
287
288 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
289 ///
290 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
291 /// produces the same output as darwin's size(1) default output.
printDarwinSegmentSizes(MachOObjectFile * MachO)292 static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
293 uint64_t total_text = 0;
294 uint64_t total_data = 0;
295 uint64_t total_objc = 0;
296 uint64_t total_others = 0;
297 for (const auto &Load : MachO->load_commands()) {
298 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
299 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
300 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
301 for (unsigned J = 0; J < Seg.nsects; ++J) {
302 MachO::section_64 Sec = MachO->getSection64(Load, J);
303 StringRef SegmentName = StringRef(Sec.segname);
304 if (SegmentName == "__TEXT")
305 total_text += Sec.size;
306 else if (SegmentName == "__DATA")
307 total_data += Sec.size;
308 else if (SegmentName == "__OBJC")
309 total_objc += Sec.size;
310 else
311 total_others += Sec.size;
312 }
313 } else {
314 StringRef SegmentName = StringRef(Seg.segname);
315 if (SegmentName == "__TEXT")
316 total_text += Seg.vmsize;
317 else if (SegmentName == "__DATA")
318 total_data += Seg.vmsize;
319 else if (SegmentName == "__OBJC")
320 total_objc += Seg.vmsize;
321 else
322 total_others += Seg.vmsize;
323 }
324 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
325 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
326 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
327 for (unsigned J = 0; J < Seg.nsects; ++J) {
328 MachO::section Sec = MachO->getSection(Load, J);
329 StringRef SegmentName = StringRef(Sec.segname);
330 if (SegmentName == "__TEXT")
331 total_text += Sec.size;
332 else if (SegmentName == "__DATA")
333 total_data += Sec.size;
334 else if (SegmentName == "__OBJC")
335 total_objc += Sec.size;
336 else
337 total_others += Sec.size;
338 }
339 } else {
340 StringRef SegmentName = StringRef(Seg.segname);
341 if (SegmentName == "__TEXT")
342 total_text += Seg.vmsize;
343 else if (SegmentName == "__DATA")
344 total_data += Seg.vmsize;
345 else if (SegmentName == "__OBJC")
346 total_objc += Seg.vmsize;
347 else
348 total_others += Seg.vmsize;
349 }
350 }
351 }
352 uint64_t total = total_text + total_data + total_objc + total_others;
353
354 if (!BerkeleyHeaderPrinted) {
355 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
356 BerkeleyHeaderPrinted = true;
357 }
358 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
359 << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
360 << "\t";
361 }
362
363 /// Print the size of each section in @p Obj.
364 ///
365 /// The format used is determined by @c OutputFormat and @c Radix.
printObjectSectionSizes(ObjectFile * Obj)366 static void printObjectSectionSizes(ObjectFile *Obj) {
367 uint64_t total = 0;
368 std::string fmtbuf;
369 raw_string_ostream fmt(fmtbuf);
370 const char *radix_fmt = getRadixFmt();
371
372 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
373 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
374 // let it fall through to OutputFormat berkeley.
375 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
376 if (OutputFormat == darwin && MachO)
377 printDarwinSectionSizes(MachO);
378 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
379 // darwin's default berkeley format for Mach-O files.
380 else if (MachO && OutputFormat == berkeley)
381 printDarwinSegmentSizes(MachO);
382 else if (OutputFormat == sysv) {
383 // Run two passes over all sections. The first gets the lengths needed for
384 // formatting the output. The second actually does the output.
385 std::size_t max_name_len = strlen("section");
386 std::size_t max_size_len = strlen("size");
387 std::size_t max_addr_len = strlen("addr");
388 for (const SectionRef &Section : Obj->sections()) {
389 if (!considerForSize(Obj, Section))
390 continue;
391 uint64_t size = Section.getSize();
392 total += size;
393
394 Expected<StringRef> name_or_err = Section.getName();
395 if (!name_or_err) {
396 error(name_or_err.takeError(), Obj->getFileName());
397 return;
398 }
399
400 uint64_t addr = Section.getAddress();
401 max_name_len = std::max(max_name_len, name_or_err->size());
402 max_size_len = std::max(max_size_len, getNumLengthAsString(size));
403 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
404 }
405
406 // Add extra padding.
407 max_name_len += 2;
408 max_size_len += 2;
409 max_addr_len += 2;
410
411 // Setup header format.
412 fmt << "%-" << max_name_len << "s "
413 << "%" << max_size_len << "s "
414 << "%" << max_addr_len << "s\n";
415
416 // Print header
417 outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
418 static_cast<const char *>("size"),
419 static_cast<const char *>("addr"));
420 fmtbuf.clear();
421
422 // Setup per section format.
423 fmt << "%-" << max_name_len << "s "
424 << "%#" << max_size_len << radix_fmt << " "
425 << "%#" << max_addr_len << radix_fmt << "\n";
426
427 // Print each section.
428 for (const SectionRef &Section : Obj->sections()) {
429 if (!considerForSize(Obj, Section))
430 continue;
431
432 Expected<StringRef> name_or_err = Section.getName();
433 if (!name_or_err) {
434 error(name_or_err.takeError(), Obj->getFileName());
435 return;
436 }
437
438 uint64_t size = Section.getSize();
439 uint64_t addr = Section.getAddress();
440 outs() << format(fmt.str().c_str(), name_or_err->str().c_str(), size, addr);
441 }
442
443 if (ELFCommons) {
444 if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) {
445 total += *CommonSizeOrErr;
446 outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(),
447 *CommonSizeOrErr, static_cast<uint64_t>(0));
448 } else {
449 error(CommonSizeOrErr.takeError(), Obj->getFileName());
450 return;
451 }
452 }
453
454 // Print total.
455 fmtbuf.clear();
456 fmt << "%-" << max_name_len << "s "
457 << "%#" << max_size_len << radix_fmt << "\n";
458 outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
459 total)
460 << "\n\n";
461 } else {
462 // The Berkeley format does not display individual section sizes. It
463 // displays the cumulative size for each section type.
464 uint64_t total_text = 0;
465 uint64_t total_data = 0;
466 uint64_t total_bss = 0;
467
468 // Make one pass over the section table to calculate sizes.
469 for (const SectionRef &Section : Obj->sections()) {
470 uint64_t size = Section.getSize();
471 bool isText = Section.isBerkeleyText();
472 bool isData = Section.isBerkeleyData();
473 bool isBSS = Section.isBSS();
474 if (isText)
475 total_text += size;
476 else if (isData)
477 total_data += size;
478 else if (isBSS)
479 total_bss += size;
480 }
481
482 if (ELFCommons) {
483 if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj))
484 total_bss += *CommonSizeOrErr;
485 else {
486 error(CommonSizeOrErr.takeError(), Obj->getFileName());
487 return;
488 }
489 }
490
491 total = total_text + total_data + total_bss;
492
493 if (TotalSizes) {
494 TotalObjectText += total_text;
495 TotalObjectData += total_data;
496 TotalObjectBss += total_bss;
497 TotalObjectTotal += total;
498 }
499
500 if (!BerkeleyHeaderPrinted) {
501 outs() << " text\t"
502 " data\t"
503 " bss\t"
504 " "
505 << (Radix == octal ? "oct" : "dec")
506 << "\t"
507 " hex\t"
508 "filename\n";
509 BerkeleyHeaderPrinted = true;
510 }
511
512 // Print result.
513 fmt << "%#7" << radix_fmt << "\t"
514 << "%#7" << radix_fmt << "\t"
515 << "%#7" << radix_fmt << "\t";
516 outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
517 fmtbuf.clear();
518 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
519 << "%7" PRIx64 "\t";
520 outs() << format(fmt.str().c_str(), total, total);
521 }
522 }
523
524 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
525 /// is a list of architecture flags specified then check to make sure this
526 /// Mach-O file is one of those architectures or all architectures was
527 /// specificed. If not then an error is generated and this routine returns
528 /// false. Else it returns true.
checkMachOAndArchFlags(ObjectFile * O,StringRef Filename)529 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
530 auto *MachO = dyn_cast<MachOObjectFile>(O);
531
532 if (!MachO || ArchAll || ArchFlags.empty())
533 return true;
534
535 MachO::mach_header H;
536 MachO::mach_header_64 H_64;
537 Triple T;
538 if (MachO->is64Bit()) {
539 H_64 = MachO->MachOObjectFile::getHeader64();
540 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
541 } else {
542 H = MachO->MachOObjectFile::getHeader();
543 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
544 }
545 if (!is_contained(ArchFlags, T.getArchName())) {
546 error("no architecture specified", Filename);
547 return false;
548 }
549 return true;
550 }
551
552 /// Print the section sizes for @p file. If @p file is an archive, print the
553 /// section sizes for each archive member.
printFileSectionSizes(StringRef file)554 static void printFileSectionSizes(StringRef file) {
555
556 // Attempt to open the binary.
557 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
558 if (!BinaryOrErr) {
559 error(BinaryOrErr.takeError(), file);
560 return;
561 }
562 Binary &Bin = *BinaryOrErr.get().getBinary();
563
564 if (Archive *a = dyn_cast<Archive>(&Bin)) {
565 // This is an archive. Iterate over each member and display its sizes.
566 Error Err = Error::success();
567 for (auto &C : a->children(Err)) {
568 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
569 if (!ChildOrErr) {
570 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
571 error(std::move(E), a->getFileName(), C);
572 continue;
573 }
574 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
575 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
576 if (!checkMachOAndArchFlags(o, file))
577 return;
578 if (OutputFormat == sysv)
579 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n";
580 else if (MachO && OutputFormat == darwin)
581 outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
582 printObjectSectionSizes(o);
583 if (OutputFormat == berkeley) {
584 if (MachO)
585 outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
586 else
587 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
588 }
589 }
590 }
591 if (Err)
592 error(std::move(Err), a->getFileName());
593 } else if (MachOUniversalBinary *UB =
594 dyn_cast<MachOUniversalBinary>(&Bin)) {
595 // If we have a list of architecture flags specified dump only those.
596 if (!ArchAll && !ArchFlags.empty()) {
597 // Look for a slice in the universal binary that matches each ArchFlag.
598 bool ArchFound;
599 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
600 ArchFound = false;
601 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
602 E = UB->end_objects();
603 I != E; ++I) {
604 if (ArchFlags[i] == I->getArchFlagName()) {
605 ArchFound = true;
606 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
607 if (UO) {
608 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
609 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
610 if (OutputFormat == sysv)
611 outs() << o->getFileName() << " :\n";
612 else if (MachO && OutputFormat == darwin) {
613 if (MoreThanOneFile || ArchFlags.size() > 1)
614 outs() << o->getFileName() << " (for architecture "
615 << I->getArchFlagName() << "): \n";
616 }
617 printObjectSectionSizes(o);
618 if (OutputFormat == berkeley) {
619 if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
620 outs() << o->getFileName() << " (for architecture "
621 << I->getArchFlagName() << ")";
622 outs() << "\n";
623 }
624 }
625 } else if (auto E = isNotObjectErrorInvalidFileType(
626 UO.takeError())) {
627 error(std::move(E), file, ArchFlags.size() > 1 ?
628 StringRef(I->getArchFlagName()) : StringRef());
629 return;
630 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
631 I->getAsArchive()) {
632 std::unique_ptr<Archive> &UA = *AOrErr;
633 // This is an archive. Iterate over each member and display its
634 // sizes.
635 Error Err = Error::success();
636 for (auto &C : UA->children(Err)) {
637 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
638 if (!ChildOrErr) {
639 if (auto E = isNotObjectErrorInvalidFileType(
640 ChildOrErr.takeError()))
641 error(std::move(E), UA->getFileName(), C,
642 ArchFlags.size() > 1 ?
643 StringRef(I->getArchFlagName()) : StringRef());
644 continue;
645 }
646 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
647 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
648 if (OutputFormat == sysv)
649 outs() << o->getFileName() << " (ex " << UA->getFileName()
650 << "):\n";
651 else if (MachO && OutputFormat == darwin)
652 outs() << UA->getFileName() << "(" << o->getFileName()
653 << ")"
654 << " (for architecture " << I->getArchFlagName()
655 << "):\n";
656 printObjectSectionSizes(o);
657 if (OutputFormat == berkeley) {
658 if (MachO) {
659 outs() << UA->getFileName() << "(" << o->getFileName()
660 << ")";
661 if (ArchFlags.size() > 1)
662 outs() << " (for architecture " << I->getArchFlagName()
663 << ")";
664 outs() << "\n";
665 } else
666 outs() << o->getFileName() << " (ex " << UA->getFileName()
667 << ")\n";
668 }
669 }
670 }
671 if (Err)
672 error(std::move(Err), UA->getFileName());
673 } else {
674 consumeError(AOrErr.takeError());
675 error("mach-o universal file for architecture " +
676 StringRef(I->getArchFlagName()) +
677 " is not a mach-o file or an archive file",
678 file);
679 }
680 }
681 }
682 if (!ArchFound) {
683 error("file does not contain architecture " + ArchFlags[i], file);
684 return;
685 }
686 }
687 return;
688 }
689 // No architecture flags were specified so if this contains a slice that
690 // matches the host architecture dump only that.
691 if (!ArchAll) {
692 StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
693 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
694 E = UB->end_objects();
695 I != E; ++I) {
696 if (HostArchName == I->getArchFlagName()) {
697 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
698 if (UO) {
699 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
700 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
701 if (OutputFormat == sysv)
702 outs() << o->getFileName() << " :\n";
703 else if (MachO && OutputFormat == darwin) {
704 if (MoreThanOneFile)
705 outs() << o->getFileName() << " (for architecture "
706 << I->getArchFlagName() << "):\n";
707 }
708 printObjectSectionSizes(o);
709 if (OutputFormat == berkeley) {
710 if (!MachO || MoreThanOneFile)
711 outs() << o->getFileName() << " (for architecture "
712 << I->getArchFlagName() << ")";
713 outs() << "\n";
714 }
715 }
716 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
717 error(std::move(E), file);
718 return;
719 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
720 I->getAsArchive()) {
721 std::unique_ptr<Archive> &UA = *AOrErr;
722 // This is an archive. Iterate over each member and display its
723 // sizes.
724 Error Err = Error::success();
725 for (auto &C : UA->children(Err)) {
726 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
727 if (!ChildOrErr) {
728 if (auto E = isNotObjectErrorInvalidFileType(
729 ChildOrErr.takeError()))
730 error(std::move(E), UA->getFileName(), C);
731 continue;
732 }
733 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
734 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
735 if (OutputFormat == sysv)
736 outs() << o->getFileName() << " (ex " << UA->getFileName()
737 << "):\n";
738 else if (MachO && OutputFormat == darwin)
739 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
740 << " (for architecture " << I->getArchFlagName()
741 << "):\n";
742 printObjectSectionSizes(o);
743 if (OutputFormat == berkeley) {
744 if (MachO)
745 outs() << UA->getFileName() << "(" << o->getFileName()
746 << ")\n";
747 else
748 outs() << o->getFileName() << " (ex " << UA->getFileName()
749 << ")\n";
750 }
751 }
752 }
753 if (Err)
754 error(std::move(Err), UA->getFileName());
755 } else {
756 consumeError(AOrErr.takeError());
757 error("mach-o universal file for architecture " +
758 StringRef(I->getArchFlagName()) +
759 " is not a mach-o file or an archive file",
760 file);
761 }
762 return;
763 }
764 }
765 }
766 // Either all architectures have been specified or none have been specified
767 // and this does not contain the host architecture so dump all the slices.
768 bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
769 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
770 E = UB->end_objects();
771 I != E; ++I) {
772 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
773 if (UO) {
774 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
775 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
776 if (OutputFormat == sysv)
777 outs() << o->getFileName() << " :\n";
778 else if (MachO && OutputFormat == darwin) {
779 if (MoreThanOneFile || MoreThanOneArch)
780 outs() << o->getFileName() << " (for architecture "
781 << I->getArchFlagName() << "):";
782 outs() << "\n";
783 }
784 printObjectSectionSizes(o);
785 if (OutputFormat == berkeley) {
786 if (!MachO || MoreThanOneFile || MoreThanOneArch)
787 outs() << o->getFileName() << " (for architecture "
788 << I->getArchFlagName() << ")";
789 outs() << "\n";
790 }
791 }
792 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
793 error(std::move(E), file, MoreThanOneArch ?
794 StringRef(I->getArchFlagName()) : StringRef());
795 return;
796 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
797 I->getAsArchive()) {
798 std::unique_ptr<Archive> &UA = *AOrErr;
799 // This is an archive. Iterate over each member and display its sizes.
800 Error Err = Error::success();
801 for (auto &C : UA->children(Err)) {
802 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
803 if (!ChildOrErr) {
804 if (auto E = isNotObjectErrorInvalidFileType(
805 ChildOrErr.takeError()))
806 error(std::move(E), UA->getFileName(), C, MoreThanOneArch ?
807 StringRef(I->getArchFlagName()) : StringRef());
808 continue;
809 }
810 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
811 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
812 if (OutputFormat == sysv)
813 outs() << o->getFileName() << " (ex " << UA->getFileName()
814 << "):\n";
815 else if (MachO && OutputFormat == darwin)
816 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
817 << " (for architecture " << I->getArchFlagName() << "):\n";
818 printObjectSectionSizes(o);
819 if (OutputFormat == berkeley) {
820 if (MachO)
821 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
822 << " (for architecture " << I->getArchFlagName()
823 << ")\n";
824 else
825 outs() << o->getFileName() << " (ex " << UA->getFileName()
826 << ")\n";
827 }
828 }
829 }
830 if (Err)
831 error(std::move(Err), UA->getFileName());
832 } else {
833 consumeError(AOrErr.takeError());
834 error("mach-o universal file for architecture " +
835 StringRef(I->getArchFlagName()) +
836 " is not a mach-o file or an archive file",
837 file);
838 }
839 }
840 } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
841 if (!checkMachOAndArchFlags(o, file))
842 return;
843 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
844 if (OutputFormat == sysv)
845 outs() << o->getFileName() << " :\n";
846 else if (MachO && OutputFormat == darwin && MoreThanOneFile)
847 outs() << o->getFileName() << ":\n";
848 printObjectSectionSizes(o);
849 if (OutputFormat == berkeley) {
850 if (!MachO || MoreThanOneFile)
851 outs() << o->getFileName();
852 outs() << "\n";
853 }
854 } else {
855 error("unsupported file type", file);
856 }
857 }
858
printBerkeleyTotals()859 static void printBerkeleyTotals() {
860 std::string fmtbuf;
861 raw_string_ostream fmt(fmtbuf);
862 const char *radix_fmt = getRadixFmt();
863 fmt << "%#7" << radix_fmt << "\t"
864 << "%#7" << radix_fmt << "\t"
865 << "%#7" << radix_fmt << "\t";
866 outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData,
867 TotalObjectBss);
868 fmtbuf.clear();
869 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
870 << "%7" PRIx64 "\t";
871 outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal)
872 << "(TOTALS)\n";
873 }
874
main(int argc,char ** argv)875 int main(int argc, char **argv) {
876 InitLLVM X(argc, argv);
877 cl::HideUnrelatedOptions(SizeCat);
878 cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
879
880 ToolName = argv[0];
881 if (OutputFormatShort.getNumOccurrences())
882 OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
883 if (RadixShort.getNumOccurrences())
884 Radix = RadixShort.getValue();
885
886 for (StringRef Arch : ArchFlags) {
887 if (Arch == "all") {
888 ArchAll = true;
889 } else {
890 if (!MachOObjectFile::isValidArch(Arch)) {
891 outs() << ToolName << ": for the -arch option: Unknown architecture "
892 << "named '" << Arch << "'";
893 return 1;
894 }
895 }
896 }
897
898 if (InputFilenames.empty())
899 InputFilenames.push_back("a.out");
900
901 MoreThanOneFile = InputFilenames.size() > 1;
902 llvm::for_each(InputFilenames, printFileSectionSizes);
903 if (OutputFormat == berkeley && TotalSizes)
904 printBerkeleyTotals();
905
906 if (HadError)
907 return 1;
908 }
909