1 //===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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
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/raw_ostream.h"
30 #include <system_error>
33 using namespace object
;
35 cl::OptionCategory
SizeCat("llvm-size Options");
37 enum OutputFormatTy
{ berkeley
, sysv
, darwin
};
38 static cl::opt
<OutputFormatTy
>
39 OutputFormat("format", cl::desc("Specify output format"),
40 cl::values(clEnumVal(sysv
, "System V format"),
41 clEnumVal(berkeley
, "Berkeley format"),
42 clEnumVal(darwin
, "Darwin -m format")),
43 cl::init(berkeley
), cl::cat(SizeCat
));
45 static cl::opt
<OutputFormatTy
>
46 OutputFormatShort(cl::desc("Specify output format"),
47 cl::values(clEnumValN(sysv
, "A", "System V format"),
48 clEnumValN(berkeley
, "B", "Berkeley format"),
49 clEnumValN(darwin
, "m", "Darwin -m format")),
50 cl::init(berkeley
), cl::cat(SizeCat
));
52 static bool BerkeleyHeaderPrinted
= false;
53 static bool MoreThanOneFile
= false;
54 static uint64_t TotalObjectText
= 0;
55 static uint64_t TotalObjectData
= 0;
56 static uint64_t TotalObjectBss
= 0;
57 static uint64_t TotalObjectTotal
= 0;
61 cl::desc("When format is darwin, use long format "
62 "to include addresses and offsets."),
67 cl::desc("Print common symbols in the ELF file. When using "
68 "Berkely format, this is added to bss."),
69 cl::init(false), cl::cat(SizeCat
));
71 static cl::list
<std::string
>
72 ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
73 cl::ZeroOrMore
, cl::cat(SizeCat
));
74 static bool ArchAll
= false;
76 enum RadixTy
{ octal
= 8, decimal
= 10, hexadecimal
= 16 };
77 static cl::opt
<RadixTy
> Radix(
78 "radix", cl::desc("Print size in radix"), cl::init(decimal
),
79 cl::values(clEnumValN(octal
, "8", "Print size in octal"),
80 clEnumValN(decimal
, "10", "Print size in decimal"),
81 clEnumValN(hexadecimal
, "16", "Print size in hexadecimal")),
84 static cl::opt
<RadixTy
> RadixShort(
85 cl::desc("Print size in radix:"),
86 cl::values(clEnumValN(octal
, "o", "Print size in octal"),
87 clEnumValN(decimal
, "d", "Print size in decimal"),
88 clEnumValN(hexadecimal
, "x", "Print size in hexadecimal")),
89 cl::init(decimal
), cl::cat(SizeCat
));
93 cl::desc("Print totals of all objects - Berkeley format only"),
94 cl::init(false), cl::cat(SizeCat
));
96 static cl::alias
TotalSizesShort("t", cl::desc("Short for --totals"),
97 cl::aliasopt(TotalSizes
));
99 static cl::list
<std::string
>
100 InputFilenames(cl::Positional
, cl::desc("<input files>"), cl::ZeroOrMore
);
103 HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
105 static bool HadError
= false;
107 static std::string ToolName
;
109 /// If ec is not success, print the error and return true.
110 static bool error(std::error_code ec
) {
115 errs() << ToolName
<< ": error reading file: " << ec
.message() << ".\n";
120 static bool error(Twine Message
) {
122 errs() << ToolName
<< ": " << Message
<< ".\n";
127 // This version of error() prints the archive name and member name, for example:
128 // "libx.a(foo.o)" after the ToolName before the error message. It sets
129 // HadError but returns allowing the code to move on to other archive members.
130 static void error(llvm::Error E
, StringRef FileName
, const Archive::Child
&C
,
131 StringRef ArchitectureName
= StringRef()) {
133 errs() << ToolName
<< ": " << FileName
;
135 Expected
<StringRef
> NameOrErr
= C
.getName();
136 // TODO: if we have a error getting the name then it would be nice to print
137 // the index of which archive member this is and or its offset in the
138 // archive instead of "???" as the name.
140 consumeError(NameOrErr
.takeError());
141 errs() << "(" << "???" << ")";
143 errs() << "(" << NameOrErr
.get() << ")";
145 if (!ArchitectureName
.empty())
146 errs() << " (for architecture " << ArchitectureName
<< ") ";
149 raw_string_ostream
OS(Buf
);
150 logAllUnhandledErrors(std::move(E
), OS
);
152 errs() << " " << Buf
<< "\n";
155 // 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
156 // before the error message. It sets HadError but returns allowing the code to
157 // move on to other architecture slices.
158 static void error(llvm::Error E
, StringRef FileName
,
159 StringRef ArchitectureName
= StringRef()) {
161 errs() << ToolName
<< ": " << FileName
;
163 if (!ArchitectureName
.empty())
164 errs() << " (for architecture " << ArchitectureName
<< ") ";
167 raw_string_ostream
OS(Buf
);
168 logAllUnhandledErrors(std::move(E
), OS
);
170 errs() << " " << Buf
<< "\n";
173 /// Get the length of the string that represents @p num in Radix including the
174 /// leading 0x or 0 for hexadecimal and octal respectively.
175 static size_t getNumLengthAsString(uint64_t num
) {
177 SmallString
<32> result
;
178 conv
.toString(result
, Radix
, false, true);
179 return result
.size();
182 /// Return the printing format for the Radix.
183 static const char *getRadixFmt() {
195 /// Remove unneeded ELF sections from calculation
196 static bool considerForSize(ObjectFile
*Obj
, SectionRef Section
) {
199 switch (static_cast<ELFSectionRef
>(Section
).getType()) {
201 case ELF::SHT_SYMTAB
:
202 case ELF::SHT_STRTAB
:
210 /// Total size of all ELF common symbols
211 static uint64_t getCommonSize(ObjectFile
*Obj
) {
212 uint64_t TotalCommons
= 0;
213 for (auto &Sym
: Obj
->symbols())
214 if (Obj
->getSymbolFlags(Sym
.getRawDataRefImpl()) & SymbolRef::SF_Common
)
215 TotalCommons
+= Obj
->getCommonSymbolSize(Sym
.getRawDataRefImpl());
219 /// Print the size of each Mach-O segment and section in @p MachO.
221 /// This is when used when @c OutputFormat is darwin and produces the same
222 /// output as darwin's size(1) -m output.
223 static void printDarwinSectionSizes(MachOObjectFile
*MachO
) {
225 raw_string_ostream
fmt(fmtbuf
);
226 const char *radix_fmt
= getRadixFmt();
227 if (Radix
== hexadecimal
)
229 fmt
<< "%" << radix_fmt
;
231 uint32_t Filetype
= MachO
->getHeader().filetype
;
234 for (const auto &Load
: MachO
->load_commands()) {
235 if (Load
.C
.cmd
== MachO::LC_SEGMENT_64
) {
236 MachO::segment_command_64 Seg
= MachO
->getSegment64LoadCommand(Load
);
237 outs() << "Segment " << Seg
.segname
<< ": "
238 << format(fmt
.str().c_str(), Seg
.vmsize
);
239 if (DarwinLongFormat
)
240 outs() << " (vmaddr 0x" << format("%" PRIx64
, Seg
.vmaddr
) << " fileoff "
241 << Seg
.fileoff
<< ")";
244 uint64_t sec_total
= 0;
245 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
246 MachO::section_64 Sec
= MachO
->getSection64(Load
, J
);
247 if (Filetype
== MachO::MH_OBJECT
)
248 outs() << "\tSection (" << format("%.16s", &Sec
.segname
) << ", "
249 << format("%.16s", &Sec
.sectname
) << "): ";
251 outs() << "\tSection " << format("%.16s", &Sec
.sectname
) << ": ";
252 outs() << format(fmt
.str().c_str(), Sec
.size
);
253 if (DarwinLongFormat
)
254 outs() << " (addr 0x" << format("%" PRIx64
, Sec
.addr
) << " offset "
255 << Sec
.offset
<< ")";
257 sec_total
+= Sec
.size
;
260 outs() << "\ttotal " << format(fmt
.str().c_str(), sec_total
) << "\n";
261 } else if (Load
.C
.cmd
== MachO::LC_SEGMENT
) {
262 MachO::segment_command Seg
= MachO
->getSegmentLoadCommand(Load
);
263 uint64_t Seg_vmsize
= Seg
.vmsize
;
264 outs() << "Segment " << Seg
.segname
<< ": "
265 << format(fmt
.str().c_str(), Seg_vmsize
);
266 if (DarwinLongFormat
)
267 outs() << " (vmaddr 0x" << format("%" PRIx32
, Seg
.vmaddr
) << " fileoff "
268 << Seg
.fileoff
<< ")";
271 uint64_t sec_total
= 0;
272 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
273 MachO::section Sec
= MachO
->getSection(Load
, J
);
274 if (Filetype
== MachO::MH_OBJECT
)
275 outs() << "\tSection (" << format("%.16s", &Sec
.segname
) << ", "
276 << format("%.16s", &Sec
.sectname
) << "): ";
278 outs() << "\tSection " << format("%.16s", &Sec
.sectname
) << ": ";
279 uint64_t Sec_size
= Sec
.size
;
280 outs() << format(fmt
.str().c_str(), Sec_size
);
281 if (DarwinLongFormat
)
282 outs() << " (addr 0x" << format("%" PRIx32
, Sec
.addr
) << " offset "
283 << Sec
.offset
<< ")";
285 sec_total
+= Sec
.size
;
288 outs() << "\ttotal " << format(fmt
.str().c_str(), sec_total
) << "\n";
291 outs() << "total " << format(fmt
.str().c_str(), total
) << "\n";
294 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
296 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
297 /// produces the same output as darwin's size(1) default output.
298 static void printDarwinSegmentSizes(MachOObjectFile
*MachO
) {
299 uint64_t total_text
= 0;
300 uint64_t total_data
= 0;
301 uint64_t total_objc
= 0;
302 uint64_t total_others
= 0;
303 for (const auto &Load
: MachO
->load_commands()) {
304 if (Load
.C
.cmd
== MachO::LC_SEGMENT_64
) {
305 MachO::segment_command_64 Seg
= MachO
->getSegment64LoadCommand(Load
);
306 if (MachO
->getHeader().filetype
== MachO::MH_OBJECT
) {
307 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
308 MachO::section_64 Sec
= MachO
->getSection64(Load
, J
);
309 StringRef SegmentName
= StringRef(Sec
.segname
);
310 if (SegmentName
== "__TEXT")
311 total_text
+= Sec
.size
;
312 else if (SegmentName
== "__DATA")
313 total_data
+= Sec
.size
;
314 else if (SegmentName
== "__OBJC")
315 total_objc
+= Sec
.size
;
317 total_others
+= Sec
.size
;
320 StringRef SegmentName
= StringRef(Seg
.segname
);
321 if (SegmentName
== "__TEXT")
322 total_text
+= Seg
.vmsize
;
323 else if (SegmentName
== "__DATA")
324 total_data
+= Seg
.vmsize
;
325 else if (SegmentName
== "__OBJC")
326 total_objc
+= Seg
.vmsize
;
328 total_others
+= Seg
.vmsize
;
330 } else if (Load
.C
.cmd
== MachO::LC_SEGMENT
) {
331 MachO::segment_command Seg
= MachO
->getSegmentLoadCommand(Load
);
332 if (MachO
->getHeader().filetype
== MachO::MH_OBJECT
) {
333 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
334 MachO::section Sec
= MachO
->getSection(Load
, J
);
335 StringRef SegmentName
= StringRef(Sec
.segname
);
336 if (SegmentName
== "__TEXT")
337 total_text
+= Sec
.size
;
338 else if (SegmentName
== "__DATA")
339 total_data
+= Sec
.size
;
340 else if (SegmentName
== "__OBJC")
341 total_objc
+= Sec
.size
;
343 total_others
+= Sec
.size
;
346 StringRef SegmentName
= StringRef(Seg
.segname
);
347 if (SegmentName
== "__TEXT")
348 total_text
+= Seg
.vmsize
;
349 else if (SegmentName
== "__DATA")
350 total_data
+= Seg
.vmsize
;
351 else if (SegmentName
== "__OBJC")
352 total_objc
+= Seg
.vmsize
;
354 total_others
+= Seg
.vmsize
;
358 uint64_t total
= total_text
+ total_data
+ total_objc
+ total_others
;
360 if (!BerkeleyHeaderPrinted
) {
361 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
362 BerkeleyHeaderPrinted
= true;
364 outs() << total_text
<< "\t" << total_data
<< "\t" << total_objc
<< "\t"
365 << total_others
<< "\t" << total
<< "\t" << format("%" PRIx64
, total
)
369 /// Print the size of each section in @p Obj.
371 /// The format used is determined by @c OutputFormat and @c Radix.
372 static void printObjectSectionSizes(ObjectFile
*Obj
) {
375 raw_string_ostream
fmt(fmtbuf
);
376 const char *radix_fmt
= getRadixFmt();
378 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
379 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
380 // let it fall through to OutputFormat berkeley.
381 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(Obj
);
382 if (OutputFormat
== darwin
&& MachO
)
383 printDarwinSectionSizes(MachO
);
384 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
385 // darwin's default berkeley format for Mach-O files.
386 else if (MachO
&& OutputFormat
== berkeley
)
387 printDarwinSegmentSizes(MachO
);
388 else if (OutputFormat
== sysv
) {
389 // Run two passes over all sections. The first gets the lengths needed for
390 // formatting the output. The second actually does the output.
391 std::size_t max_name_len
= strlen("section");
392 std::size_t max_size_len
= strlen("size");
393 std::size_t max_addr_len
= strlen("addr");
394 for (const SectionRef
&Section
: Obj
->sections()) {
395 if (!considerForSize(Obj
, Section
))
397 uint64_t size
= Section
.getSize();
401 if (error(Section
.getName(name
)))
403 uint64_t addr
= Section
.getAddress();
404 max_name_len
= std::max(max_name_len
, name
.size());
405 max_size_len
= std::max(max_size_len
, getNumLengthAsString(size
));
406 max_addr_len
= std::max(max_addr_len
, getNumLengthAsString(addr
));
409 // Add extra padding.
414 // Setup header format.
415 fmt
<< "%-" << max_name_len
<< "s "
416 << "%" << max_size_len
<< "s "
417 << "%" << max_addr_len
<< "s\n";
420 outs() << format(fmt
.str().c_str(), static_cast<const char *>("section"),
421 static_cast<const char *>("size"),
422 static_cast<const char *>("addr"));
425 // Setup per section format.
426 fmt
<< "%-" << max_name_len
<< "s "
427 << "%#" << max_size_len
<< radix_fmt
<< " "
428 << "%#" << max_addr_len
<< radix_fmt
<< "\n";
430 // Print each section.
431 for (const SectionRef
&Section
: Obj
->sections()) {
432 if (!considerForSize(Obj
, Section
))
435 if (error(Section
.getName(name
)))
437 uint64_t size
= Section
.getSize();
438 uint64_t addr
= Section
.getAddress();
439 std::string namestr
= name
;
441 outs() << format(fmt
.str().c_str(), namestr
.c_str(), size
, addr
);
445 uint64_t CommonSize
= getCommonSize(Obj
);
447 outs() << format(fmt
.str().c_str(), std::string("*COM*").c_str(),
448 CommonSize
, static_cast<uint64_t>(0));
453 fmt
<< "%-" << max_name_len
<< "s "
454 << "%#" << max_size_len
<< radix_fmt
<< "\n";
455 outs() << format(fmt
.str().c_str(), static_cast<const char *>("Total"),
458 // The Berkeley format does not display individual section sizes. It
459 // displays the cumulative size for each section type.
460 uint64_t total_text
= 0;
461 uint64_t total_data
= 0;
462 uint64_t total_bss
= 0;
464 // Make one pass over the section table to calculate sizes.
465 for (const SectionRef
&Section
: Obj
->sections()) {
466 uint64_t size
= Section
.getSize();
467 bool isText
= Section
.isBerkeleyText();
468 bool isData
= Section
.isBerkeleyData();
469 bool isBSS
= Section
.isBSS();
479 total_bss
+= getCommonSize(Obj
);
481 total
= total_text
+ total_data
+ total_bss
;
484 TotalObjectText
+= total_text
;
485 TotalObjectData
+= total_data
;
486 TotalObjectBss
+= total_bss
;
487 TotalObjectTotal
+= total
;
490 if (!BerkeleyHeaderPrinted
) {
495 << (Radix
== octal
? "oct" : "dec")
499 BerkeleyHeaderPrinted
= true;
503 fmt
<< "%#7" << radix_fmt
<< "\t"
504 << "%#7" << radix_fmt
<< "\t"
505 << "%#7" << radix_fmt
<< "\t";
506 outs() << format(fmt
.str().c_str(), total_text
, total_data
, total_bss
);
508 fmt
<< "%7" << (Radix
== octal
? PRIo64
: PRIu64
) << "\t"
510 outs() << format(fmt
.str().c_str(), total
, total
);
514 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
515 /// is a list of architecture flags specified then check to make sure this
516 /// Mach-O file is one of those architectures or all architectures was
517 /// specificed. If not then an error is generated and this routine returns
518 /// false. Else it returns true.
519 static bool checkMachOAndArchFlags(ObjectFile
*O
, StringRef Filename
) {
520 auto *MachO
= dyn_cast
<MachOObjectFile
>(O
);
522 if (!MachO
|| ArchAll
|| ArchFlags
.empty())
525 MachO::mach_header H
;
526 MachO::mach_header_64 H_64
;
528 if (MachO
->is64Bit()) {
529 H_64
= MachO
->MachOObjectFile::getHeader64();
530 T
= MachOObjectFile::getArchTriple(H_64
.cputype
, H_64
.cpusubtype
);
532 H
= MachO
->MachOObjectFile::getHeader();
533 T
= MachOObjectFile::getArchTriple(H
.cputype
, H
.cpusubtype
);
535 if (none_of(ArchFlags
, [&](const std::string
&Name
) {
536 return Name
== T
.getArchName();
538 error(Filename
+ ": No architecture specified");
544 /// Print the section sizes for @p file. If @p file is an archive, print the
545 /// section sizes for each archive member.
546 static void printFileSectionSizes(StringRef file
) {
548 // Attempt to open the binary.
549 Expected
<OwningBinary
<Binary
>> BinaryOrErr
= createBinary(file
);
551 error(BinaryOrErr
.takeError(), file
);
554 Binary
&Bin
= *BinaryOrErr
.get().getBinary();
556 if (Archive
*a
= dyn_cast
<Archive
>(&Bin
)) {
557 // This is an archive. Iterate over each member and display its sizes.
558 Error Err
= Error::success();
559 for (auto &C
: a
->children(Err
)) {
560 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
562 if (auto E
= isNotObjectErrorInvalidFileType(ChildOrErr
.takeError()))
563 error(std::move(E
), a
->getFileName(), C
);
566 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
567 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
568 if (!checkMachOAndArchFlags(o
, file
))
570 if (OutputFormat
== sysv
)
571 outs() << o
->getFileName() << " (ex " << a
->getFileName() << "):\n";
572 else if (MachO
&& OutputFormat
== darwin
)
573 outs() << a
->getFileName() << "(" << o
->getFileName() << "):\n";
574 printObjectSectionSizes(o
);
575 if (OutputFormat
== berkeley
) {
577 outs() << a
->getFileName() << "(" << o
->getFileName() << ")\n";
579 outs() << o
->getFileName() << " (ex " << a
->getFileName() << ")\n";
584 error(std::move(Err
), a
->getFileName());
585 } else if (MachOUniversalBinary
*UB
=
586 dyn_cast
<MachOUniversalBinary
>(&Bin
)) {
587 // If we have a list of architecture flags specified dump only those.
588 if (!ArchAll
&& !ArchFlags
.empty()) {
589 // Look for a slice in the universal binary that matches each ArchFlag.
591 for (unsigned i
= 0; i
< ArchFlags
.size(); ++i
) {
593 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
594 E
= UB
->end_objects();
596 if (ArchFlags
[i
] == I
->getArchFlagName()) {
598 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
600 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
601 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
602 if (OutputFormat
== sysv
)
603 outs() << o
->getFileName() << " :\n";
604 else if (MachO
&& OutputFormat
== darwin
) {
605 if (MoreThanOneFile
|| ArchFlags
.size() > 1)
606 outs() << o
->getFileName() << " (for architecture "
607 << I
->getArchFlagName() << "): \n";
609 printObjectSectionSizes(o
);
610 if (OutputFormat
== berkeley
) {
611 if (!MachO
|| MoreThanOneFile
|| ArchFlags
.size() > 1)
612 outs() << o
->getFileName() << " (for architecture "
613 << I
->getArchFlagName() << ")";
617 } else if (auto E
= isNotObjectErrorInvalidFileType(
619 error(std::move(E
), file
, ArchFlags
.size() > 1 ?
620 StringRef(I
->getArchFlagName()) : StringRef());
622 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
624 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
625 // This is an archive. Iterate over each member and display its
627 Error Err
= Error::success();
628 for (auto &C
: UA
->children(Err
)) {
629 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
631 if (auto E
= isNotObjectErrorInvalidFileType(
632 ChildOrErr
.takeError()))
633 error(std::move(E
), UA
->getFileName(), C
,
634 ArchFlags
.size() > 1 ?
635 StringRef(I
->getArchFlagName()) : StringRef());
638 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
639 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
640 if (OutputFormat
== sysv
)
641 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
643 else if (MachO
&& OutputFormat
== darwin
)
644 outs() << UA
->getFileName() << "(" << o
->getFileName()
646 << " (for architecture " << I
->getArchFlagName()
648 printObjectSectionSizes(o
);
649 if (OutputFormat
== berkeley
) {
651 outs() << UA
->getFileName() << "(" << o
->getFileName()
653 if (ArchFlags
.size() > 1)
654 outs() << " (for architecture " << I
->getArchFlagName()
658 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
664 error(std::move(Err
), UA
->getFileName());
666 consumeError(AOrErr
.takeError());
667 error("Mach-O universal file: " + file
+ " for architecture " +
668 StringRef(I
->getArchFlagName()) +
669 " is not a Mach-O file or an archive file");
674 errs() << ToolName
<< ": file: " << file
675 << " does not contain architecture" << ArchFlags
[i
] << ".\n";
681 // No architecture flags were specified so if this contains a slice that
682 // matches the host architecture dump only that.
684 StringRef HostArchName
= MachOObjectFile::getHostArch().getArchName();
685 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
686 E
= UB
->end_objects();
688 if (HostArchName
== I
->getArchFlagName()) {
689 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
691 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
692 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
693 if (OutputFormat
== sysv
)
694 outs() << o
->getFileName() << " :\n";
695 else if (MachO
&& OutputFormat
== darwin
) {
697 outs() << o
->getFileName() << " (for architecture "
698 << I
->getArchFlagName() << "):\n";
700 printObjectSectionSizes(o
);
701 if (OutputFormat
== berkeley
) {
702 if (!MachO
|| MoreThanOneFile
)
703 outs() << o
->getFileName() << " (for architecture "
704 << I
->getArchFlagName() << ")";
708 } else if (auto E
= isNotObjectErrorInvalidFileType(UO
.takeError())) {
709 error(std::move(E
), file
);
711 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
713 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
714 // This is an archive. Iterate over each member and display its
716 Error Err
= Error::success();
717 for (auto &C
: UA
->children(Err
)) {
718 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
720 if (auto E
= isNotObjectErrorInvalidFileType(
721 ChildOrErr
.takeError()))
722 error(std::move(E
), UA
->getFileName(), C
);
725 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
726 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
727 if (OutputFormat
== sysv
)
728 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
730 else if (MachO
&& OutputFormat
== darwin
)
731 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
732 << " (for architecture " << I
->getArchFlagName()
734 printObjectSectionSizes(o
);
735 if (OutputFormat
== berkeley
) {
737 outs() << UA
->getFileName() << "(" << o
->getFileName()
740 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
746 error(std::move(Err
), UA
->getFileName());
748 consumeError(AOrErr
.takeError());
749 error("Mach-O universal file: " + file
+ " for architecture " +
750 StringRef(I
->getArchFlagName()) +
751 " is not a Mach-O file or an archive file");
757 // Either all architectures have been specified or none have been specified
758 // and this does not contain the host architecture so dump all the slices.
759 bool MoreThanOneArch
= UB
->getNumberOfObjects() > 1;
760 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
761 E
= UB
->end_objects();
763 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
765 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
766 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
767 if (OutputFormat
== sysv
)
768 outs() << o
->getFileName() << " :\n";
769 else if (MachO
&& OutputFormat
== darwin
) {
770 if (MoreThanOneFile
|| MoreThanOneArch
)
771 outs() << o
->getFileName() << " (for architecture "
772 << I
->getArchFlagName() << "):";
775 printObjectSectionSizes(o
);
776 if (OutputFormat
== berkeley
) {
777 if (!MachO
|| MoreThanOneFile
|| MoreThanOneArch
)
778 outs() << o
->getFileName() << " (for architecture "
779 << I
->getArchFlagName() << ")";
783 } else if (auto E
= isNotObjectErrorInvalidFileType(UO
.takeError())) {
784 error(std::move(E
), file
, MoreThanOneArch
?
785 StringRef(I
->getArchFlagName()) : StringRef());
787 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
789 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
790 // This is an archive. Iterate over each member and display its sizes.
791 Error Err
= Error::success();
792 for (auto &C
: UA
->children(Err
)) {
793 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
795 if (auto E
= isNotObjectErrorInvalidFileType(
796 ChildOrErr
.takeError()))
797 error(std::move(E
), UA
->getFileName(), C
, MoreThanOneArch
?
798 StringRef(I
->getArchFlagName()) : StringRef());
801 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
802 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
803 if (OutputFormat
== sysv
)
804 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
806 else if (MachO
&& OutputFormat
== darwin
)
807 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
808 << " (for architecture " << I
->getArchFlagName() << "):\n";
809 printObjectSectionSizes(o
);
810 if (OutputFormat
== berkeley
) {
812 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
813 << " (for architecture " << I
->getArchFlagName()
816 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
822 error(std::move(Err
), UA
->getFileName());
824 consumeError(AOrErr
.takeError());
825 error("Mach-O universal file: " + file
+ " for architecture " +
826 StringRef(I
->getArchFlagName()) +
827 " is not a Mach-O file or an archive file");
830 } else if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&Bin
)) {
831 if (!checkMachOAndArchFlags(o
, file
))
833 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
834 if (OutputFormat
== sysv
)
835 outs() << o
->getFileName() << " :\n";
836 else if (MachO
&& OutputFormat
== darwin
&& MoreThanOneFile
)
837 outs() << o
->getFileName() << ":\n";
838 printObjectSectionSizes(o
);
839 if (OutputFormat
== berkeley
) {
840 if (!MachO
|| MoreThanOneFile
)
841 outs() << o
->getFileName();
845 errs() << ToolName
<< ": " << file
<< ": "
846 << "Unrecognized file type.\n";
848 // System V adds an extra newline at the end of each file.
849 if (OutputFormat
== sysv
)
853 static void printBerkelyTotals() {
855 raw_string_ostream
fmt(fmtbuf
);
856 const char *radix_fmt
= getRadixFmt();
857 fmt
<< "%#7" << radix_fmt
<< "\t"
858 << "%#7" << radix_fmt
<< "\t"
859 << "%#7" << radix_fmt
<< "\t";
860 outs() << format(fmt
.str().c_str(), TotalObjectText
, TotalObjectData
,
863 fmt
<< "%7" << (Radix
== octal
? PRIo64
: PRIu64
) << "\t"
865 outs() << format(fmt
.str().c_str(), TotalObjectTotal
, TotalObjectTotal
)
869 int main(int argc
, char **argv
) {
870 InitLLVM
X(argc
, argv
);
871 cl::HideUnrelatedOptions(SizeCat
);
872 cl::ParseCommandLineOptions(argc
, argv
, "llvm object size dumper\n");
875 if (OutputFormatShort
.getNumOccurrences())
876 OutputFormat
= static_cast<OutputFormatTy
>(OutputFormatShort
);
877 if (RadixShort
.getNumOccurrences())
878 Radix
= RadixShort
.getValue();
880 for (StringRef Arch
: ArchFlags
) {
884 if (!MachOObjectFile::isValidArch(Arch
)) {
885 outs() << ToolName
<< ": for the -arch option: Unknown architecture "
886 << "named '" << Arch
<< "'";
892 if (InputFilenames
.empty())
893 InputFilenames
.push_back("a.out");
895 MoreThanOneFile
= InputFilenames
.size() > 1;
896 llvm::for_each(InputFilenames
, printFileSectionSizes
);
897 if (OutputFormat
== berkeley
&& TotalSizes
)
898 printBerkelyTotals();