1 //===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This program is a utility that works like traditional Unix "size",
11 // that is, it prints out the size of each section, and the total size of all
12 // sections.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "llvm/ADT/APInt.h"
17 #include "llvm/Object/Archive.h"
18 #include "llvm/Object/ELFObjectFile.h"
19 #include "llvm/Object/MachO.h"
20 #include "llvm/Object/MachOUniversal.h"
21 #include "llvm/Object/ObjectFile.h"
22 #include "llvm/Support/Casting.h"
23 #include "llvm/Support/CommandLine.h"
24 #include "llvm/Support/FileSystem.h"
25 #include "llvm/Support/Format.h"
26 #include "llvm/Support/ManagedStatic.h"
27 #include "llvm/Support/MemoryBuffer.h"
28 #include "llvm/Support/PrettyStackTrace.h"
29 #include "llvm/Support/Signals.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include <algorithm>
32 #include <string>
33 #include <system_error>
34
35 using namespace llvm;
36 using namespace object;
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"), clEnumValEnd),
44 cl::init(berkeley));
45
46 static cl::opt<OutputFormatTy> OutputFormatShort(
47 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"), clEnumValEnd),
51 cl::init(berkeley));
52
53 static bool BerkeleyHeaderPrinted = false;
54 static bool MoreThanOneFile = false;
55
56 cl::opt<bool>
57 DarwinLongFormat("l", cl::desc("When format is darwin, use long format "
58 "to include addresses and offsets."));
59
60 cl::opt<bool>
61 ELFCommons("common",
62 cl::desc("Print common symbols in the ELF file. When using "
63 "Berkely format, this is added to bss."),
64 cl::init(false));
65
66 static cl::list<std::string>
67 ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
68 cl::ZeroOrMore);
69 bool ArchAll = false;
70
71 enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
72 static cl::opt<unsigned int>
73 Radix("-radix", cl::desc("Print size in radix. Only 8, 10, and 16 are valid"),
74 cl::init(decimal));
75
76 static cl::opt<RadixTy>
77 RadixShort(cl::desc("Print size in radix:"),
78 cl::values(clEnumValN(octal, "o", "Print size in octal"),
79 clEnumValN(decimal, "d", "Print size in decimal"),
80 clEnumValN(hexadecimal, "x", "Print size in hexadecimal"),
81 clEnumValEnd),
82 cl::init(decimal));
83
84 static cl::list<std::string>
85 InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
86
87 bool HadError = false;
88
89 static std::string ToolName;
90
91 /// If ec is not success, print the error and return true.
error(std::error_code ec)92 static bool error(std::error_code ec) {
93 if (!ec)
94 return false;
95
96 HadError = true;
97 errs() << ToolName << ": error reading file: " << ec.message() << ".\n";
98 errs().flush();
99 return true;
100 }
101
error(Twine Message)102 static bool error(Twine Message) {
103 HadError = true;
104 errs() << ToolName << ": " << Message << ".\n";
105 errs().flush();
106 return true;
107 }
108
109 // This version of error() prints the archive name and member name, for example:
110 // "libx.a(foo.o)" after the ToolName before the error message. It sets
111 // 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 ())112 static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
113 StringRef ArchitectureName = StringRef()) {
114 HadError = true;
115 errs() << ToolName << ": " << FileName;
116
117 ErrorOr<StringRef> NameOrErr = C.getName();
118 // TODO: if we have a error getting the name then it would be nice to print
119 // the index of which archive member this is and or its offset in the
120 // archive instead of "???" as the name.
121 if (NameOrErr.getError())
122 errs() << "(" << "???" << ")";
123 else
124 errs() << "(" << NameOrErr.get() << ")";
125
126 if (!ArchitectureName.empty())
127 errs() << " (for architecture " << ArchitectureName << ") ";
128
129 std::string Buf;
130 raw_string_ostream OS(Buf);
131 logAllUnhandledErrors(std::move(E), OS, "");
132 OS.flush();
133 errs() << " " << Buf << "\n";
134 }
135
136 // 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
137 // before the error message. It sets HadError but returns allowing the code to
138 // move on to other architecture slices.
error(llvm::Error E,StringRef FileName,StringRef ArchitectureName=StringRef ())139 static void error(llvm::Error E, StringRef FileName,
140 StringRef ArchitectureName = StringRef()) {
141 HadError = true;
142 errs() << ToolName << ": " << FileName;
143
144 if (!ArchitectureName.empty())
145 errs() << " (for architecture " << ArchitectureName << ") ";
146
147 std::string Buf;
148 raw_string_ostream OS(Buf);
149 logAllUnhandledErrors(std::move(E), OS, "");
150 OS.flush();
151 errs() << " " << Buf << "\n";
152 }
153
154 /// Get the length of the string that represents @p num in Radix including the
155 /// leading 0x or 0 for hexadecimal and octal respectively.
getNumLengthAsString(uint64_t num)156 static size_t getNumLengthAsString(uint64_t num) {
157 APInt conv(64, num);
158 SmallString<32> result;
159 conv.toString(result, Radix, false, true);
160 return result.size();
161 }
162
163 /// Return the printing format for the Radix.
getRadixFmt()164 static const char *getRadixFmt() {
165 switch (Radix) {
166 case octal:
167 return PRIo64;
168 case decimal:
169 return PRIu64;
170 case hexadecimal:
171 return PRIx64;
172 }
173 return nullptr;
174 }
175
176 /// Remove unneeded ELF sections from calculation
considerForSize(ObjectFile * Obj,SectionRef Section)177 static bool considerForSize(ObjectFile *Obj, SectionRef Section) {
178 if (!Obj->isELF())
179 return true;
180 switch (static_cast<ELFSectionRef>(Section).getType()) {
181 case ELF::SHT_NULL:
182 case ELF::SHT_SYMTAB:
183 case ELF::SHT_STRTAB:
184 case ELF::SHT_REL:
185 case ELF::SHT_RELA:
186 return false;
187 }
188 return true;
189 }
190
191 /// Total size of all ELF common symbols
getCommonSize(ObjectFile * Obj)192 static uint64_t getCommonSize(ObjectFile *Obj) {
193 uint64_t TotalCommons = 0;
194 for (auto &Sym : Obj->symbols())
195 if (Obj->getSymbolFlags(Sym.getRawDataRefImpl()) & SymbolRef::SF_Common)
196 TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl());
197 return TotalCommons;
198 }
199
200 /// Print the size of each Mach-O segment and section in @p MachO.
201 ///
202 /// This is when used when @c OutputFormat is darwin and produces the same
203 /// output as darwin's size(1) -m output.
printDarwinSectionSizes(MachOObjectFile * MachO)204 static void printDarwinSectionSizes(MachOObjectFile *MachO) {
205 std::string fmtbuf;
206 raw_string_ostream fmt(fmtbuf);
207 const char *radix_fmt = getRadixFmt();
208 if (Radix == hexadecimal)
209 fmt << "0x";
210 fmt << "%" << radix_fmt;
211
212 uint32_t Filetype = MachO->getHeader().filetype;
213
214 uint64_t total = 0;
215 for (const auto &Load : MachO->load_commands()) {
216 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
217 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
218 outs() << "Segment " << Seg.segname << ": "
219 << format(fmt.str().c_str(), Seg.vmsize);
220 if (DarwinLongFormat)
221 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
222 << Seg.fileoff << ")";
223 outs() << "\n";
224 total += Seg.vmsize;
225 uint64_t sec_total = 0;
226 for (unsigned J = 0; J < Seg.nsects; ++J) {
227 MachO::section_64 Sec = MachO->getSection64(Load, J);
228 if (Filetype == MachO::MH_OBJECT)
229 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
230 << format("%.16s", &Sec.sectname) << "): ";
231 else
232 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
233 outs() << format(fmt.str().c_str(), Sec.size);
234 if (DarwinLongFormat)
235 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
236 << Sec.offset << ")";
237 outs() << "\n";
238 sec_total += Sec.size;
239 }
240 if (Seg.nsects != 0)
241 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
242 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
243 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
244 uint64_t Seg_vmsize = Seg.vmsize;
245 outs() << "Segment " << Seg.segname << ": "
246 << format(fmt.str().c_str(), Seg_vmsize);
247 if (DarwinLongFormat)
248 outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff "
249 << Seg.fileoff << ")";
250 outs() << "\n";
251 total += Seg.vmsize;
252 uint64_t sec_total = 0;
253 for (unsigned J = 0; J < Seg.nsects; ++J) {
254 MachO::section Sec = MachO->getSection(Load, J);
255 if (Filetype == MachO::MH_OBJECT)
256 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
257 << format("%.16s", &Sec.sectname) << "): ";
258 else
259 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
260 uint64_t Sec_size = Sec.size;
261 outs() << format(fmt.str().c_str(), Sec_size);
262 if (DarwinLongFormat)
263 outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset "
264 << Sec.offset << ")";
265 outs() << "\n";
266 sec_total += Sec.size;
267 }
268 if (Seg.nsects != 0)
269 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
270 }
271 }
272 outs() << "total " << format(fmt.str().c_str(), total) << "\n";
273 }
274
275 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
276 ///
277 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
278 /// produces the same output as darwin's size(1) default output.
printDarwinSegmentSizes(MachOObjectFile * MachO)279 static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
280 uint64_t total_text = 0;
281 uint64_t total_data = 0;
282 uint64_t total_objc = 0;
283 uint64_t total_others = 0;
284 for (const auto &Load : MachO->load_commands()) {
285 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
286 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
287 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
288 for (unsigned J = 0; J < Seg.nsects; ++J) {
289 MachO::section_64 Sec = MachO->getSection64(Load, J);
290 StringRef SegmentName = StringRef(Sec.segname);
291 if (SegmentName == "__TEXT")
292 total_text += Sec.size;
293 else if (SegmentName == "__DATA")
294 total_data += Sec.size;
295 else if (SegmentName == "__OBJC")
296 total_objc += Sec.size;
297 else
298 total_others += Sec.size;
299 }
300 } else {
301 StringRef SegmentName = StringRef(Seg.segname);
302 if (SegmentName == "__TEXT")
303 total_text += Seg.vmsize;
304 else if (SegmentName == "__DATA")
305 total_data += Seg.vmsize;
306 else if (SegmentName == "__OBJC")
307 total_objc += Seg.vmsize;
308 else
309 total_others += Seg.vmsize;
310 }
311 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
312 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
313 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
314 for (unsigned J = 0; J < Seg.nsects; ++J) {
315 MachO::section Sec = MachO->getSection(Load, J);
316 StringRef SegmentName = StringRef(Sec.segname);
317 if (SegmentName == "__TEXT")
318 total_text += Sec.size;
319 else if (SegmentName == "__DATA")
320 total_data += Sec.size;
321 else if (SegmentName == "__OBJC")
322 total_objc += Sec.size;
323 else
324 total_others += Sec.size;
325 }
326 } else {
327 StringRef SegmentName = StringRef(Seg.segname);
328 if (SegmentName == "__TEXT")
329 total_text += Seg.vmsize;
330 else if (SegmentName == "__DATA")
331 total_data += Seg.vmsize;
332 else if (SegmentName == "__OBJC")
333 total_objc += Seg.vmsize;
334 else
335 total_others += Seg.vmsize;
336 }
337 }
338 }
339 uint64_t total = total_text + total_data + total_objc + total_others;
340
341 if (!BerkeleyHeaderPrinted) {
342 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
343 BerkeleyHeaderPrinted = true;
344 }
345 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
346 << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
347 << "\t";
348 }
349
350 /// Print the size of each section in @p Obj.
351 ///
352 /// The format used is determined by @c OutputFormat and @c Radix.
printObjectSectionSizes(ObjectFile * Obj)353 static void printObjectSectionSizes(ObjectFile *Obj) {
354 uint64_t total = 0;
355 std::string fmtbuf;
356 raw_string_ostream fmt(fmtbuf);
357 const char *radix_fmt = getRadixFmt();
358
359 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
360 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
361 // let it fall through to OutputFormat berkeley.
362 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
363 if (OutputFormat == darwin && MachO)
364 printDarwinSectionSizes(MachO);
365 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
366 // darwin's default berkeley format for Mach-O files.
367 else if (MachO && OutputFormat == berkeley)
368 printDarwinSegmentSizes(MachO);
369 else if (OutputFormat == sysv) {
370 // Run two passes over all sections. The first gets the lengths needed for
371 // formatting the output. The second actually does the output.
372 std::size_t max_name_len = strlen("section");
373 std::size_t max_size_len = strlen("size");
374 std::size_t max_addr_len = strlen("addr");
375 for (const SectionRef &Section : Obj->sections()) {
376 if (!considerForSize(Obj, Section))
377 continue;
378 uint64_t size = Section.getSize();
379 total += size;
380
381 StringRef name;
382 if (error(Section.getName(name)))
383 return;
384 uint64_t addr = Section.getAddress();
385 max_name_len = std::max(max_name_len, name.size());
386 max_size_len = std::max(max_size_len, getNumLengthAsString(size));
387 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
388 }
389
390 // Add extra padding.
391 max_name_len += 2;
392 max_size_len += 2;
393 max_addr_len += 2;
394
395 // Setup header format.
396 fmt << "%-" << max_name_len << "s "
397 << "%" << max_size_len << "s "
398 << "%" << max_addr_len << "s\n";
399
400 // Print header
401 outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
402 static_cast<const char *>("size"),
403 static_cast<const char *>("addr"));
404 fmtbuf.clear();
405
406 // Setup per section format.
407 fmt << "%-" << max_name_len << "s "
408 << "%#" << max_size_len << radix_fmt << " "
409 << "%#" << max_addr_len << radix_fmt << "\n";
410
411 // Print each section.
412 for (const SectionRef &Section : Obj->sections()) {
413 if (!considerForSize(Obj, Section))
414 continue;
415 StringRef name;
416 if (error(Section.getName(name)))
417 return;
418 uint64_t size = Section.getSize();
419 uint64_t addr = Section.getAddress();
420 std::string namestr = name;
421
422 outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr);
423 }
424
425 if (ELFCommons) {
426 uint64_t CommonSize = getCommonSize(Obj);
427 total += CommonSize;
428 outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(),
429 CommonSize, static_cast<uint64_t>(0));
430 }
431
432 // Print total.
433 fmtbuf.clear();
434 fmt << "%-" << max_name_len << "s "
435 << "%#" << max_size_len << radix_fmt << "\n";
436 outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
437 total);
438 } else {
439 // The Berkeley format does not display individual section sizes. It
440 // displays the cumulative size for each section type.
441 uint64_t total_text = 0;
442 uint64_t total_data = 0;
443 uint64_t total_bss = 0;
444
445 // Make one pass over the section table to calculate sizes.
446 for (const SectionRef &Section : Obj->sections()) {
447 uint64_t size = Section.getSize();
448 bool isText = Section.isText();
449 bool isData = Section.isData();
450 bool isBSS = Section.isBSS();
451 if (isText)
452 total_text += size;
453 else if (isData)
454 total_data += size;
455 else if (isBSS)
456 total_bss += size;
457 }
458
459 if (ELFCommons)
460 total_bss += getCommonSize(Obj);
461
462 total = total_text + total_data + total_bss;
463
464 if (!BerkeleyHeaderPrinted) {
465 outs() << " text data bss "
466 << (Radix == octal ? "oct" : "dec") << " hex filename\n";
467 BerkeleyHeaderPrinted = true;
468 }
469
470 // Print result.
471 fmt << "%#7" << radix_fmt << " "
472 << "%#7" << radix_fmt << " "
473 << "%#7" << radix_fmt << " ";
474 outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
475 fmtbuf.clear();
476 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " "
477 << "%7" PRIx64 " ";
478 outs() << format(fmt.str().c_str(), total, total);
479 }
480 }
481
482 /// Checks to see if the @p o ObjectFile is a Mach-O file and if it is and there
483 /// is a list of architecture flags specified then check to make sure this
484 /// Mach-O file is one of those architectures or all architectures was
485 /// specificed. If not then an error is generated and this routine returns
486 /// false. Else it returns true.
checkMachOAndArchFlags(ObjectFile * o,StringRef file)487 static bool checkMachOAndArchFlags(ObjectFile *o, StringRef file) {
488 if (isa<MachOObjectFile>(o) && !ArchAll && ArchFlags.size() != 0) {
489 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
490 bool ArchFound = false;
491 MachO::mach_header H;
492 MachO::mach_header_64 H_64;
493 Triple T;
494 if (MachO->is64Bit()) {
495 H_64 = MachO->MachOObjectFile::getHeader64();
496 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
497 } else {
498 H = MachO->MachOObjectFile::getHeader();
499 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
500 }
501 unsigned i;
502 for (i = 0; i < ArchFlags.size(); ++i) {
503 if (ArchFlags[i] == T.getArchName())
504 ArchFound = true;
505 break;
506 }
507 if (!ArchFound) {
508 errs() << ToolName << ": file: " << file
509 << " does not contain architecture: " << ArchFlags[i] << ".\n";
510 return false;
511 }
512 }
513 return true;
514 }
515
516 /// Print the section sizes for @p file. If @p file is an archive, print the
517 /// section sizes for each archive member.
printFileSectionSizes(StringRef file)518 static void printFileSectionSizes(StringRef file) {
519
520 // Attempt to open the binary.
521 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
522 if (!BinaryOrErr) {
523 error(errorToErrorCode(BinaryOrErr.takeError()));
524 return;
525 }
526 Binary &Bin = *BinaryOrErr.get().getBinary();
527
528 if (Archive *a = dyn_cast<Archive>(&Bin)) {
529 // This is an archive. Iterate over each member and display its sizes.
530 Error Err;
531 for (auto &C : a->children(Err)) {
532 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
533 if (!ChildOrErr) {
534 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
535 error(std::move(E), a->getFileName(), C);
536 continue;
537 }
538 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
539 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
540 if (!checkMachOAndArchFlags(o, file))
541 return;
542 if (OutputFormat == sysv)
543 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n";
544 else if (MachO && OutputFormat == darwin)
545 outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
546 printObjectSectionSizes(o);
547 if (OutputFormat == berkeley) {
548 if (MachO)
549 outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
550 else
551 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
552 }
553 }
554 }
555 if (Err)
556 error(std::move(Err), a->getFileName());
557 } else if (MachOUniversalBinary *UB =
558 dyn_cast<MachOUniversalBinary>(&Bin)) {
559 // If we have a list of architecture flags specified dump only those.
560 if (!ArchAll && ArchFlags.size() != 0) {
561 // Look for a slice in the universal binary that matches each ArchFlag.
562 bool ArchFound;
563 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
564 ArchFound = false;
565 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
566 E = UB->end_objects();
567 I != E; ++I) {
568 if (ArchFlags[i] == I->getArchTypeName()) {
569 ArchFound = true;
570 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
571 if (UO) {
572 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
573 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
574 if (OutputFormat == sysv)
575 outs() << o->getFileName() << " :\n";
576 else if (MachO && OutputFormat == darwin) {
577 if (MoreThanOneFile || ArchFlags.size() > 1)
578 outs() << o->getFileName() << " (for architecture "
579 << I->getArchTypeName() << "): \n";
580 }
581 printObjectSectionSizes(o);
582 if (OutputFormat == berkeley) {
583 if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
584 outs() << o->getFileName() << " (for architecture "
585 << I->getArchTypeName() << ")";
586 outs() << "\n";
587 }
588 }
589 } else if (auto E = isNotObjectErrorInvalidFileType(
590 UO.takeError())) {
591 error(std::move(E), file, ArchFlags.size() > 1 ?
592 StringRef(I->getArchTypeName()) : StringRef());
593 return;
594 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
595 I->getAsArchive()) {
596 std::unique_ptr<Archive> &UA = *AOrErr;
597 // This is an archive. Iterate over each member and display its
598 // sizes.
599 Error Err;
600 for (auto &C : UA->children(Err)) {
601 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
602 if (!ChildOrErr) {
603 if (auto E = isNotObjectErrorInvalidFileType(
604 ChildOrErr.takeError()))
605 error(std::move(E), UA->getFileName(), C,
606 ArchFlags.size() > 1 ?
607 StringRef(I->getArchTypeName()) : StringRef());
608 continue;
609 }
610 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
611 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
612 if (OutputFormat == sysv)
613 outs() << o->getFileName() << " (ex " << UA->getFileName()
614 << "):\n";
615 else if (MachO && OutputFormat == darwin)
616 outs() << UA->getFileName() << "(" << o->getFileName()
617 << ")"
618 << " (for architecture " << I->getArchTypeName()
619 << "):\n";
620 printObjectSectionSizes(o);
621 if (OutputFormat == berkeley) {
622 if (MachO) {
623 outs() << UA->getFileName() << "(" << o->getFileName()
624 << ")";
625 if (ArchFlags.size() > 1)
626 outs() << " (for architecture " << I->getArchTypeName()
627 << ")";
628 outs() << "\n";
629 } else
630 outs() << o->getFileName() << " (ex " << UA->getFileName()
631 << ")\n";
632 }
633 }
634 }
635 if (Err)
636 error(std::move(Err), UA->getFileName());
637 } else {
638 consumeError(AOrErr.takeError());
639 error("Mach-O universal file: " + file + " for architecture " +
640 StringRef(I->getArchTypeName()) +
641 " is not a Mach-O file or an archive file");
642 }
643 }
644 }
645 if (!ArchFound) {
646 errs() << ToolName << ": file: " << file
647 << " does not contain architecture" << ArchFlags[i] << ".\n";
648 return;
649 }
650 }
651 return;
652 }
653 // No architecture flags were specified so if this contains a slice that
654 // matches the host architecture dump only that.
655 if (!ArchAll) {
656 StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
657 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
658 E = UB->end_objects();
659 I != E; ++I) {
660 if (HostArchName == I->getArchTypeName()) {
661 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
662 if (UO) {
663 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
664 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
665 if (OutputFormat == sysv)
666 outs() << o->getFileName() << " :\n";
667 else if (MachO && OutputFormat == darwin) {
668 if (MoreThanOneFile)
669 outs() << o->getFileName() << " (for architecture "
670 << I->getArchTypeName() << "):\n";
671 }
672 printObjectSectionSizes(o);
673 if (OutputFormat == berkeley) {
674 if (!MachO || MoreThanOneFile)
675 outs() << o->getFileName() << " (for architecture "
676 << I->getArchTypeName() << ")";
677 outs() << "\n";
678 }
679 }
680 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
681 error(std::move(E), file);
682 return;
683 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
684 I->getAsArchive()) {
685 std::unique_ptr<Archive> &UA = *AOrErr;
686 // This is an archive. Iterate over each member and display its
687 // sizes.
688 Error Err;
689 for (auto &C : UA->children(Err)) {
690 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
691 if (!ChildOrErr) {
692 if (auto E = isNotObjectErrorInvalidFileType(
693 ChildOrErr.takeError()))
694 error(std::move(E), UA->getFileName(), C);
695 continue;
696 }
697 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
698 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
699 if (OutputFormat == sysv)
700 outs() << o->getFileName() << " (ex " << UA->getFileName()
701 << "):\n";
702 else if (MachO && OutputFormat == darwin)
703 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
704 << " (for architecture " << I->getArchTypeName()
705 << "):\n";
706 printObjectSectionSizes(o);
707 if (OutputFormat == berkeley) {
708 if (MachO)
709 outs() << UA->getFileName() << "(" << o->getFileName()
710 << ")\n";
711 else
712 outs() << o->getFileName() << " (ex " << UA->getFileName()
713 << ")\n";
714 }
715 }
716 }
717 if (Err)
718 error(std::move(Err), UA->getFileName());
719 } else {
720 consumeError(AOrErr.takeError());
721 error("Mach-O universal file: " + file + " for architecture " +
722 StringRef(I->getArchTypeName()) +
723 " is not a Mach-O file or an archive file");
724 }
725 return;
726 }
727 }
728 }
729 // Either all architectures have been specified or none have been specified
730 // and this does not contain the host architecture so dump all the slices.
731 bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
732 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
733 E = UB->end_objects();
734 I != E; ++I) {
735 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
736 if (UO) {
737 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
738 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
739 if (OutputFormat == sysv)
740 outs() << o->getFileName() << " :\n";
741 else if (MachO && OutputFormat == darwin) {
742 if (MoreThanOneFile || MoreThanOneArch)
743 outs() << o->getFileName() << " (for architecture "
744 << I->getArchTypeName() << "):";
745 outs() << "\n";
746 }
747 printObjectSectionSizes(o);
748 if (OutputFormat == berkeley) {
749 if (!MachO || MoreThanOneFile || MoreThanOneArch)
750 outs() << o->getFileName() << " (for architecture "
751 << I->getArchTypeName() << ")";
752 outs() << "\n";
753 }
754 }
755 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
756 error(std::move(E), file, MoreThanOneArch ?
757 StringRef(I->getArchTypeName()) : StringRef());
758 return;
759 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
760 I->getAsArchive()) {
761 std::unique_ptr<Archive> &UA = *AOrErr;
762 // This is an archive. Iterate over each member and display its sizes.
763 Error Err;
764 for (auto &C : UA->children(Err)) {
765 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
766 if (!ChildOrErr) {
767 if (auto E = isNotObjectErrorInvalidFileType(
768 ChildOrErr.takeError()))
769 error(std::move(E), UA->getFileName(), C, MoreThanOneArch ?
770 StringRef(I->getArchTypeName()) : StringRef());
771 continue;
772 }
773 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
774 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
775 if (OutputFormat == sysv)
776 outs() << o->getFileName() << " (ex " << UA->getFileName()
777 << "):\n";
778 else if (MachO && OutputFormat == darwin)
779 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
780 << " (for architecture " << I->getArchTypeName() << "):\n";
781 printObjectSectionSizes(o);
782 if (OutputFormat == berkeley) {
783 if (MachO)
784 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
785 << " (for architecture " << I->getArchTypeName()
786 << ")\n";
787 else
788 outs() << o->getFileName() << " (ex " << UA->getFileName()
789 << ")\n";
790 }
791 }
792 }
793 if (Err)
794 error(std::move(Err), UA->getFileName());
795 } else {
796 consumeError(AOrErr.takeError());
797 error("Mach-O universal file: " + file + " for architecture " +
798 StringRef(I->getArchTypeName()) +
799 " is not a Mach-O file or an archive file");
800 }
801 }
802 } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
803 if (!checkMachOAndArchFlags(o, file))
804 return;
805 if (OutputFormat == sysv)
806 outs() << o->getFileName() << " :\n";
807 printObjectSectionSizes(o);
808 if (OutputFormat == berkeley) {
809 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
810 if (!MachO || MoreThanOneFile)
811 outs() << o->getFileName();
812 outs() << "\n";
813 }
814 } else {
815 errs() << ToolName << ": " << file << ": "
816 << "Unrecognized file type.\n";
817 }
818 // System V adds an extra newline at the end of each file.
819 if (OutputFormat == sysv)
820 outs() << "\n";
821 }
822
main(int argc,char ** argv)823 int main(int argc, char **argv) {
824 // Print a stack trace if we signal out.
825 sys::PrintStackTraceOnErrorSignal(argv[0]);
826 PrettyStackTraceProgram X(argc, argv);
827
828 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
829 cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
830
831 ToolName = argv[0];
832 if (OutputFormatShort.getNumOccurrences())
833 OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
834 if (RadixShort.getNumOccurrences())
835 Radix = RadixShort;
836
837 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
838 if (ArchFlags[i] == "all") {
839 ArchAll = true;
840 } else {
841 if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
842 outs() << ToolName << ": for the -arch option: Unknown architecture "
843 << "named '" << ArchFlags[i] << "'";
844 return 1;
845 }
846 }
847 }
848
849 if (InputFilenames.size() == 0)
850 InputFilenames.push_back("a.out");
851
852 MoreThanOneFile = InputFilenames.size() > 1;
853 std::for_each(InputFilenames.begin(), InputFilenames.end(),
854 printFileSectionSizes);
855
856 if (HadError)
857 return 1;
858 }
859