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/WithColor.h"
28 #include "llvm/Support/raw_ostream.h"
31 #include <system_error>
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;
62 cl::desc("When format is darwin, use long format "
63 "to include addresses and offsets."),
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")),
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
));
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
);
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
) {
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()) {
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.
128 consumeError(NameOrErr
.takeError());
129 errs() << "(" << "???" << ")";
131 errs() << "(" << NameOrErr
.get() << ")";
133 if (!ArchitectureName
.empty())
134 errs() << " (for architecture " << ArchitectureName
<< ") ";
137 raw_string_ostream
OS(Buf
);
138 logAllUnhandledErrors(std::move(E
), OS
);
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()) {
149 WithColor::error(errs(), ToolName
) << "'" << FileName
<< "'";
151 if (!ArchitectureName
.empty())
152 errs() << " (for architecture " << ArchitectureName
<< ") ";
155 raw_string_ostream
OS(Buf
);
156 logAllUnhandledErrors(std::move(E
), OS
);
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
) {
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() {
183 /// Remove unneeded ELF sections from calculation
184 static bool considerForSize(ObjectFile
*Obj
, SectionRef Section
) {
187 switch (static_cast<ELFSectionRef
>(Section
).getType()) {
189 case ELF::SHT_SYMTAB
:
190 case ELF::SHT_STRTAB
:
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());
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
) {
213 raw_string_ostream
fmt(fmtbuf
);
214 const char *radix_fmt
= getRadixFmt();
215 if (Radix
== hexadecimal
)
217 fmt
<< "%" << radix_fmt
;
219 uint32_t Filetype
= MachO
->getHeader().filetype
;
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
<< ")";
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
) << "): ";
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
<< ")";
245 sec_total
+= Sec
.size
;
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
<< ")";
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
) << "): ";
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
<< ")";
273 sec_total
+= Sec
.size
;
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
;
305 total_others
+= Sec
.size
;
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
;
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
;
331 total_others
+= Sec
.size
;
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
;
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
)
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
) {
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
))
385 uint64_t size
= Section
.getSize();
388 Expected
<StringRef
> name_or_err
= Section
.getName();
390 error(name_or_err
.takeError(), Obj
->getFileName());
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.
405 // Setup header format.
406 fmt
<< "%-" << max_name_len
<< "s "
407 << "%" << max_size_len
<< "s "
408 << "%" << max_addr_len
<< "s\n";
411 outs() << format(fmt
.str().c_str(), static_cast<const char *>("section"),
412 static_cast<const char *>("size"),
413 static_cast<const char *>("addr"));
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
))
426 Expected
<StringRef
> name_or_err
= Section
.getName();
428 error(name_or_err
.takeError(), Obj
->getFileName());
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
);
438 uint64_t CommonSize
= getCommonSize(Obj
);
440 outs() << format(fmt
.str().c_str(), std::string("*COM*").c_str(),
441 CommonSize
, static_cast<uint64_t>(0));
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"),
451 // The Berkeley format does not display individual section sizes. It
452 // displays the cumulative size for each section type.
453 uint64_t total_text
= 0;
454 uint64_t total_data
= 0;
455 uint64_t total_bss
= 0;
457 // Make one pass over the section table to calculate sizes.
458 for (const SectionRef
&Section
: Obj
->sections()) {
459 uint64_t size
= Section
.getSize();
460 bool isText
= Section
.isBerkeleyText();
461 bool isData
= Section
.isBerkeleyData();
462 bool isBSS
= Section
.isBSS();
472 total_bss
+= getCommonSize(Obj
);
474 total
= total_text
+ total_data
+ total_bss
;
477 TotalObjectText
+= total_text
;
478 TotalObjectData
+= total_data
;
479 TotalObjectBss
+= total_bss
;
480 TotalObjectTotal
+= total
;
483 if (!BerkeleyHeaderPrinted
) {
488 << (Radix
== octal
? "oct" : "dec")
492 BerkeleyHeaderPrinted
= true;
496 fmt
<< "%#7" << radix_fmt
<< "\t"
497 << "%#7" << radix_fmt
<< "\t"
498 << "%#7" << radix_fmt
<< "\t";
499 outs() << format(fmt
.str().c_str(), total_text
, total_data
, total_bss
);
501 fmt
<< "%7" << (Radix
== octal
? PRIo64
: PRIu64
) << "\t"
503 outs() << format(fmt
.str().c_str(), total
, total
);
507 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
508 /// is a list of architecture flags specified then check to make sure this
509 /// Mach-O file is one of those architectures or all architectures was
510 /// specificed. If not then an error is generated and this routine returns
511 /// false. Else it returns true.
512 static bool checkMachOAndArchFlags(ObjectFile
*O
, StringRef Filename
) {
513 auto *MachO
= dyn_cast
<MachOObjectFile
>(O
);
515 if (!MachO
|| ArchAll
|| ArchFlags
.empty())
518 MachO::mach_header H
;
519 MachO::mach_header_64 H_64
;
521 if (MachO
->is64Bit()) {
522 H_64
= MachO
->MachOObjectFile::getHeader64();
523 T
= MachOObjectFile::getArchTriple(H_64
.cputype
, H_64
.cpusubtype
);
525 H
= MachO
->MachOObjectFile::getHeader();
526 T
= MachOObjectFile::getArchTriple(H
.cputype
, H
.cpusubtype
);
528 if (none_of(ArchFlags
, [&](const std::string
&Name
) {
529 return Name
== T
.getArchName();
531 error("no architecture specified", Filename
);
537 /// Print the section sizes for @p file. If @p file is an archive, print the
538 /// section sizes for each archive member.
539 static void printFileSectionSizes(StringRef file
) {
541 // Attempt to open the binary.
542 Expected
<OwningBinary
<Binary
>> BinaryOrErr
= createBinary(file
);
544 error(BinaryOrErr
.takeError(), file
);
547 Binary
&Bin
= *BinaryOrErr
.get().getBinary();
549 if (Archive
*a
= dyn_cast
<Archive
>(&Bin
)) {
550 // This is an archive. Iterate over each member and display its sizes.
551 Error Err
= Error::success();
552 for (auto &C
: a
->children(Err
)) {
553 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
555 if (auto E
= isNotObjectErrorInvalidFileType(ChildOrErr
.takeError()))
556 error(std::move(E
), a
->getFileName(), C
);
559 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
560 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
561 if (!checkMachOAndArchFlags(o
, file
))
563 if (OutputFormat
== sysv
)
564 outs() << o
->getFileName() << " (ex " << a
->getFileName() << "):\n";
565 else if (MachO
&& OutputFormat
== darwin
)
566 outs() << a
->getFileName() << "(" << o
->getFileName() << "):\n";
567 printObjectSectionSizes(o
);
568 if (OutputFormat
== berkeley
) {
570 outs() << a
->getFileName() << "(" << o
->getFileName() << ")\n";
572 outs() << o
->getFileName() << " (ex " << a
->getFileName() << ")\n";
577 error(std::move(Err
), a
->getFileName());
578 } else if (MachOUniversalBinary
*UB
=
579 dyn_cast
<MachOUniversalBinary
>(&Bin
)) {
580 // If we have a list of architecture flags specified dump only those.
581 if (!ArchAll
&& !ArchFlags
.empty()) {
582 // Look for a slice in the universal binary that matches each ArchFlag.
584 for (unsigned i
= 0; i
< ArchFlags
.size(); ++i
) {
586 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
587 E
= UB
->end_objects();
589 if (ArchFlags
[i
] == I
->getArchFlagName()) {
591 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
593 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
594 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
595 if (OutputFormat
== sysv
)
596 outs() << o
->getFileName() << " :\n";
597 else if (MachO
&& OutputFormat
== darwin
) {
598 if (MoreThanOneFile
|| ArchFlags
.size() > 1)
599 outs() << o
->getFileName() << " (for architecture "
600 << I
->getArchFlagName() << "): \n";
602 printObjectSectionSizes(o
);
603 if (OutputFormat
== berkeley
) {
604 if (!MachO
|| MoreThanOneFile
|| ArchFlags
.size() > 1)
605 outs() << o
->getFileName() << " (for architecture "
606 << I
->getArchFlagName() << ")";
610 } else if (auto E
= isNotObjectErrorInvalidFileType(
612 error(std::move(E
), file
, ArchFlags
.size() > 1 ?
613 StringRef(I
->getArchFlagName()) : StringRef());
615 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
617 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
618 // This is an archive. Iterate over each member and display its
620 Error Err
= Error::success();
621 for (auto &C
: UA
->children(Err
)) {
622 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
624 if (auto E
= isNotObjectErrorInvalidFileType(
625 ChildOrErr
.takeError()))
626 error(std::move(E
), UA
->getFileName(), C
,
627 ArchFlags
.size() > 1 ?
628 StringRef(I
->getArchFlagName()) : StringRef());
631 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
632 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
633 if (OutputFormat
== sysv
)
634 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
636 else if (MachO
&& OutputFormat
== darwin
)
637 outs() << UA
->getFileName() << "(" << o
->getFileName()
639 << " (for architecture " << I
->getArchFlagName()
641 printObjectSectionSizes(o
);
642 if (OutputFormat
== berkeley
) {
644 outs() << UA
->getFileName() << "(" << o
->getFileName()
646 if (ArchFlags
.size() > 1)
647 outs() << " (for architecture " << I
->getArchFlagName()
651 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
657 error(std::move(Err
), UA
->getFileName());
659 consumeError(AOrErr
.takeError());
660 error("mach-o universal file for architecture " +
661 StringRef(I
->getArchFlagName()) +
662 " is not a mach-o file or an archive file",
668 error("file does not contain architecture " + ArchFlags
[i
], file
);
674 // No architecture flags were specified so if this contains a slice that
675 // matches the host architecture dump only that.
677 StringRef HostArchName
= MachOObjectFile::getHostArch().getArchName();
678 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
679 E
= UB
->end_objects();
681 if (HostArchName
== I
->getArchFlagName()) {
682 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
684 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
685 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
686 if (OutputFormat
== sysv
)
687 outs() << o
->getFileName() << " :\n";
688 else if (MachO
&& OutputFormat
== darwin
) {
690 outs() << o
->getFileName() << " (for architecture "
691 << I
->getArchFlagName() << "):\n";
693 printObjectSectionSizes(o
);
694 if (OutputFormat
== berkeley
) {
695 if (!MachO
|| MoreThanOneFile
)
696 outs() << o
->getFileName() << " (for architecture "
697 << I
->getArchFlagName() << ")";
701 } else if (auto E
= isNotObjectErrorInvalidFileType(UO
.takeError())) {
702 error(std::move(E
), file
);
704 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
706 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
707 // This is an archive. Iterate over each member and display its
709 Error Err
= Error::success();
710 for (auto &C
: UA
->children(Err
)) {
711 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
713 if (auto E
= isNotObjectErrorInvalidFileType(
714 ChildOrErr
.takeError()))
715 error(std::move(E
), UA
->getFileName(), C
);
718 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
719 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
720 if (OutputFormat
== sysv
)
721 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
723 else if (MachO
&& OutputFormat
== darwin
)
724 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
725 << " (for architecture " << I
->getArchFlagName()
727 printObjectSectionSizes(o
);
728 if (OutputFormat
== berkeley
) {
730 outs() << UA
->getFileName() << "(" << o
->getFileName()
733 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
739 error(std::move(Err
), UA
->getFileName());
741 consumeError(AOrErr
.takeError());
742 error("mach-o universal file for architecture " +
743 StringRef(I
->getArchFlagName()) +
744 " is not a mach-o file or an archive file",
751 // Either all architectures have been specified or none have been specified
752 // and this does not contain the host architecture so dump all the slices.
753 bool MoreThanOneArch
= UB
->getNumberOfObjects() > 1;
754 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
755 E
= UB
->end_objects();
757 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
759 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
760 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
761 if (OutputFormat
== sysv
)
762 outs() << o
->getFileName() << " :\n";
763 else if (MachO
&& OutputFormat
== darwin
) {
764 if (MoreThanOneFile
|| MoreThanOneArch
)
765 outs() << o
->getFileName() << " (for architecture "
766 << I
->getArchFlagName() << "):";
769 printObjectSectionSizes(o
);
770 if (OutputFormat
== berkeley
) {
771 if (!MachO
|| MoreThanOneFile
|| MoreThanOneArch
)
772 outs() << o
->getFileName() << " (for architecture "
773 << I
->getArchFlagName() << ")";
777 } else if (auto E
= isNotObjectErrorInvalidFileType(UO
.takeError())) {
778 error(std::move(E
), file
, MoreThanOneArch
?
779 StringRef(I
->getArchFlagName()) : StringRef());
781 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
783 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
784 // This is an archive. Iterate over each member and display its sizes.
785 Error Err
= Error::success();
786 for (auto &C
: UA
->children(Err
)) {
787 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
789 if (auto E
= isNotObjectErrorInvalidFileType(
790 ChildOrErr
.takeError()))
791 error(std::move(E
), UA
->getFileName(), C
, MoreThanOneArch
?
792 StringRef(I
->getArchFlagName()) : StringRef());
795 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
796 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
797 if (OutputFormat
== sysv
)
798 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
800 else if (MachO
&& OutputFormat
== darwin
)
801 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
802 << " (for architecture " << I
->getArchFlagName() << "):\n";
803 printObjectSectionSizes(o
);
804 if (OutputFormat
== berkeley
) {
806 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
807 << " (for architecture " << I
->getArchFlagName()
810 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
816 error(std::move(Err
), UA
->getFileName());
818 consumeError(AOrErr
.takeError());
819 error("mach-o universal file for architecture " +
820 StringRef(I
->getArchFlagName()) +
821 " is not a mach-o file or an archive file",
825 } else if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&Bin
)) {
826 if (!checkMachOAndArchFlags(o
, file
))
828 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
829 if (OutputFormat
== sysv
)
830 outs() << o
->getFileName() << " :\n";
831 else if (MachO
&& OutputFormat
== darwin
&& MoreThanOneFile
)
832 outs() << o
->getFileName() << ":\n";
833 printObjectSectionSizes(o
);
834 if (OutputFormat
== berkeley
) {
835 if (!MachO
|| MoreThanOneFile
)
836 outs() << o
->getFileName();
840 error("unsupported file type", file
);
842 // System V adds an extra newline at the end of each file.
843 if (OutputFormat
== sysv
)
847 static void printBerkeleyTotals() {
849 raw_string_ostream
fmt(fmtbuf
);
850 const char *radix_fmt
= getRadixFmt();
851 fmt
<< "%#7" << radix_fmt
<< "\t"
852 << "%#7" << radix_fmt
<< "\t"
853 << "%#7" << radix_fmt
<< "\t";
854 outs() << format(fmt
.str().c_str(), TotalObjectText
, TotalObjectData
,
857 fmt
<< "%7" << (Radix
== octal
? PRIo64
: PRIu64
) << "\t"
859 outs() << format(fmt
.str().c_str(), TotalObjectTotal
, TotalObjectTotal
)
863 int main(int argc
, char **argv
) {
864 InitLLVM
X(argc
, argv
);
865 cl::HideUnrelatedOptions(SizeCat
);
866 cl::ParseCommandLineOptions(argc
, argv
, "llvm object size dumper\n");
869 if (OutputFormatShort
.getNumOccurrences())
870 OutputFormat
= static_cast<OutputFormatTy
>(OutputFormatShort
);
871 if (RadixShort
.getNumOccurrences())
872 Radix
= RadixShort
.getValue();
874 for (StringRef Arch
: ArchFlags
) {
878 if (!MachOObjectFile::isValidArch(Arch
)) {
879 outs() << ToolName
<< ": for the -arch option: Unknown architecture "
880 << "named '" << Arch
<< "'";
886 if (InputFilenames
.empty())
887 InputFilenames
.push_back("a.out");
889 MoreThanOneFile
= InputFilenames
.size() > 1;
890 llvm::for_each(InputFilenames
, printFileSectionSizes
);
891 if (OutputFormat
== berkeley
&& TotalSizes
)
892 printBerkeleyTotals();