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/Option/Arg.h"
22 #include "llvm/Option/ArgList.h"
23 #include "llvm/Option/Option.h"
24 #include "llvm/Support/Casting.h"
25 #include "llvm/Support/CommandLine.h"
26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/Format.h"
28 #include "llvm/Support/InitLLVM.h"
29 #include "llvm/Support/MemoryBuffer.h"
30 #include "llvm/Support/WithColor.h"
31 #include "llvm/Support/raw_ostream.h"
34 #include <system_error>
37 using namespace object
;
40 using namespace llvm::opt
; // for HelpHidden in Opts.inc
42 OPT_INVALID
= 0, // This is not an option ID.
43 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
44 HELPTEXT, METAVAR, VALUES) \
50 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
54 const opt::OptTable::Info InfoTable
[] = {
55 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
56 HELPTEXT, METAVAR, VALUES) \
58 PREFIX, NAME, HELPTEXT, \
59 METAVAR, OPT_##ID, opt::Option::KIND##Class, \
60 PARAM, FLAGS, OPT_##GROUP, \
61 OPT_##ALIAS, ALIASARGS, VALUES},
66 class SizeOptTable
: public opt::OptTable
{
68 SizeOptTable() : OptTable(InfoTable
) { setGroupedShortOptions(true); }
71 enum OutputFormatTy
{ berkeley
, sysv
, darwin
};
72 enum RadixTy
{ octal
= 8, decimal
= 10, hexadecimal
= 16 };
75 static bool ArchAll
= false;
76 static std::vector
<StringRef
> ArchFlags
;
77 static bool ELFCommons
;
78 static OutputFormatTy OutputFormat
;
79 static bool DarwinLongFormat
;
81 static bool TotalSizes
;
83 static std::vector
<std::string
> InputFilenames
;
85 static std::string ToolName
;
88 static bool HadError
= false;
89 static bool BerkeleyHeaderPrinted
= false;
90 static bool MoreThanOneFile
= false;
91 static uint64_t TotalObjectText
= 0;
92 static uint64_t TotalObjectData
= 0;
93 static uint64_t TotalObjectBss
= 0;
94 static uint64_t TotalObjectTotal
= 0;
96 static void error(const Twine
&Message
, StringRef File
= "") {
99 WithColor::error(errs(), ToolName
) << Message
<< '\n';
101 WithColor::error(errs(), ToolName
)
102 << "'" << File
<< "': " << Message
<< '\n';
105 // This version of error() prints the archive name and member name, for example:
106 // "libx.a(foo.o)" after the ToolName before the error message. It sets
107 // HadError but returns allowing the code to move on to other archive members.
108 static void error(llvm::Error E
, StringRef FileName
, const Archive::Child
&C
,
109 StringRef ArchitectureName
= StringRef()) {
111 WithColor::error(errs(), ToolName
) << "'" << FileName
<< "'";
113 Expected
<StringRef
> NameOrErr
= C
.getName();
114 // TODO: if we have a error getting the name then it would be nice to print
115 // the index of which archive member this is and or its offset in the
116 // archive instead of "???" as the name.
118 consumeError(NameOrErr
.takeError());
119 errs() << "(" << "???" << ")";
121 errs() << "(" << NameOrErr
.get() << ")";
123 if (!ArchitectureName
.empty())
124 errs() << " (for architecture " << ArchitectureName
<< ") ";
127 raw_string_ostream
OS(Buf
);
128 logAllUnhandledErrors(std::move(E
), OS
);
130 errs() << ": " << Buf
<< "\n";
133 // 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
134 // before the error message. It sets HadError but returns allowing the code to
135 // move on to other architecture slices.
136 static void error(llvm::Error E
, StringRef FileName
,
137 StringRef ArchitectureName
= StringRef()) {
139 WithColor::error(errs(), ToolName
) << "'" << FileName
<< "'";
141 if (!ArchitectureName
.empty())
142 errs() << " (for architecture " << ArchitectureName
<< ") ";
145 raw_string_ostream
OS(Buf
);
146 logAllUnhandledErrors(std::move(E
), OS
);
148 errs() << ": " << Buf
<< "\n";
151 /// Get the length of the string that represents @p num in Radix including the
152 /// leading 0x or 0 for hexadecimal and octal respectively.
153 static size_t getNumLengthAsString(uint64_t num
) {
155 SmallString
<32> result
;
156 conv
.toString(result
, Radix
, false, true);
157 return result
.size();
160 /// Return the printing format for the Radix.
161 static const char *getRadixFmt() {
173 /// Remove unneeded ELF sections from calculation
174 static bool considerForSize(ObjectFile
*Obj
, SectionRef Section
) {
177 switch (static_cast<ELFSectionRef
>(Section
).getType()) {
179 case ELF::SHT_SYMTAB
:
181 case ELF::SHT_STRTAB
:
184 return static_cast<ELFSectionRef
>(Section
).getFlags() & ELF::SHF_ALLOC
;
189 /// Total size of all ELF common symbols
190 static Expected
<uint64_t> getCommonSize(ObjectFile
*Obj
) {
191 uint64_t TotalCommons
= 0;
192 for (auto &Sym
: Obj
->symbols()) {
193 Expected
<uint32_t> SymFlagsOrErr
=
194 Obj
->getSymbolFlags(Sym
.getRawDataRefImpl());
196 return SymFlagsOrErr
.takeError();
197 if (*SymFlagsOrErr
& SymbolRef::SF_Common
)
198 TotalCommons
+= Obj
->getCommonSymbolSize(Sym
.getRawDataRefImpl());
203 /// Print the size of each Mach-O segment and section in @p MachO.
205 /// This is when used when @c OutputFormat is darwin and produces the same
206 /// output as darwin's size(1) -m output.
207 static void printDarwinSectionSizes(MachOObjectFile
*MachO
) {
209 raw_string_ostream
fmt(fmtbuf
);
210 const char *radix_fmt
= getRadixFmt();
211 if (Radix
== hexadecimal
)
213 fmt
<< "%" << radix_fmt
;
215 uint32_t Filetype
= MachO
->getHeader().filetype
;
218 for (const auto &Load
: MachO
->load_commands()) {
219 if (Load
.C
.cmd
== MachO::LC_SEGMENT_64
) {
220 MachO::segment_command_64 Seg
= MachO
->getSegment64LoadCommand(Load
);
221 outs() << "Segment " << Seg
.segname
<< ": "
222 << format(fmt
.str().c_str(), Seg
.vmsize
);
223 if (DarwinLongFormat
)
224 outs() << " (vmaddr 0x" << format("%" PRIx64
, Seg
.vmaddr
) << " fileoff "
225 << Seg
.fileoff
<< ")";
228 uint64_t sec_total
= 0;
229 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
230 MachO::section_64 Sec
= MachO
->getSection64(Load
, J
);
231 if (Filetype
== MachO::MH_OBJECT
)
232 outs() << "\tSection (" << format("%.16s", &Sec
.segname
) << ", "
233 << format("%.16s", &Sec
.sectname
) << "): ";
235 outs() << "\tSection " << format("%.16s", &Sec
.sectname
) << ": ";
236 outs() << format(fmt
.str().c_str(), Sec
.size
);
237 if (DarwinLongFormat
)
238 outs() << " (addr 0x" << format("%" PRIx64
, Sec
.addr
) << " offset "
239 << Sec
.offset
<< ")";
241 sec_total
+= Sec
.size
;
244 outs() << "\ttotal " << format(fmt
.str().c_str(), sec_total
) << "\n";
245 } else if (Load
.C
.cmd
== MachO::LC_SEGMENT
) {
246 MachO::segment_command Seg
= MachO
->getSegmentLoadCommand(Load
);
247 uint64_t Seg_vmsize
= Seg
.vmsize
;
248 outs() << "Segment " << Seg
.segname
<< ": "
249 << format(fmt
.str().c_str(), Seg_vmsize
);
250 if (DarwinLongFormat
)
251 outs() << " (vmaddr 0x" << format("%" PRIx32
, Seg
.vmaddr
) << " fileoff "
252 << Seg
.fileoff
<< ")";
255 uint64_t sec_total
= 0;
256 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
257 MachO::section Sec
= MachO
->getSection(Load
, J
);
258 if (Filetype
== MachO::MH_OBJECT
)
259 outs() << "\tSection (" << format("%.16s", &Sec
.segname
) << ", "
260 << format("%.16s", &Sec
.sectname
) << "): ";
262 outs() << "\tSection " << format("%.16s", &Sec
.sectname
) << ": ";
263 uint64_t Sec_size
= Sec
.size
;
264 outs() << format(fmt
.str().c_str(), Sec_size
);
265 if (DarwinLongFormat
)
266 outs() << " (addr 0x" << format("%" PRIx32
, Sec
.addr
) << " offset "
267 << Sec
.offset
<< ")";
269 sec_total
+= Sec
.size
;
272 outs() << "\ttotal " << format(fmt
.str().c_str(), sec_total
) << "\n";
275 outs() << "total " << format(fmt
.str().c_str(), total
) << "\n";
278 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
280 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
281 /// produces the same output as darwin's size(1) default output.
282 static void printDarwinSegmentSizes(MachOObjectFile
*MachO
) {
283 uint64_t total_text
= 0;
284 uint64_t total_data
= 0;
285 uint64_t total_objc
= 0;
286 uint64_t total_others
= 0;
287 for (const auto &Load
: MachO
->load_commands()) {
288 if (Load
.C
.cmd
== MachO::LC_SEGMENT_64
) {
289 MachO::segment_command_64 Seg
= MachO
->getSegment64LoadCommand(Load
);
290 if (MachO
->getHeader().filetype
== MachO::MH_OBJECT
) {
291 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
292 MachO::section_64 Sec
= MachO
->getSection64(Load
, J
);
293 StringRef SegmentName
= StringRef(Sec
.segname
);
294 if (SegmentName
== "__TEXT")
295 total_text
+= Sec
.size
;
296 else if (SegmentName
== "__DATA")
297 total_data
+= Sec
.size
;
298 else if (SegmentName
== "__OBJC")
299 total_objc
+= Sec
.size
;
301 total_others
+= Sec
.size
;
304 StringRef SegmentName
= StringRef(Seg
.segname
);
305 if (SegmentName
== "__TEXT")
306 total_text
+= Seg
.vmsize
;
307 else if (SegmentName
== "__DATA")
308 total_data
+= Seg
.vmsize
;
309 else if (SegmentName
== "__OBJC")
310 total_objc
+= Seg
.vmsize
;
312 total_others
+= Seg
.vmsize
;
314 } else if (Load
.C
.cmd
== MachO::LC_SEGMENT
) {
315 MachO::segment_command Seg
= MachO
->getSegmentLoadCommand(Load
);
316 if (MachO
->getHeader().filetype
== MachO::MH_OBJECT
) {
317 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
318 MachO::section Sec
= MachO
->getSection(Load
, J
);
319 StringRef SegmentName
= StringRef(Sec
.segname
);
320 if (SegmentName
== "__TEXT")
321 total_text
+= Sec
.size
;
322 else if (SegmentName
== "__DATA")
323 total_data
+= Sec
.size
;
324 else if (SegmentName
== "__OBJC")
325 total_objc
+= Sec
.size
;
327 total_others
+= Sec
.size
;
330 StringRef SegmentName
= StringRef(Seg
.segname
);
331 if (SegmentName
== "__TEXT")
332 total_text
+= Seg
.vmsize
;
333 else if (SegmentName
== "__DATA")
334 total_data
+= Seg
.vmsize
;
335 else if (SegmentName
== "__OBJC")
336 total_objc
+= Seg
.vmsize
;
338 total_others
+= Seg
.vmsize
;
342 uint64_t total
= total_text
+ total_data
+ total_objc
+ total_others
;
344 if (!BerkeleyHeaderPrinted
) {
345 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
346 BerkeleyHeaderPrinted
= true;
348 outs() << total_text
<< "\t" << total_data
<< "\t" << total_objc
<< "\t"
349 << total_others
<< "\t" << total
<< "\t" << format("%" PRIx64
, total
)
353 /// Print the size of each section in @p Obj.
355 /// The format used is determined by @c OutputFormat and @c Radix.
356 static void printObjectSectionSizes(ObjectFile
*Obj
) {
359 raw_string_ostream
fmt(fmtbuf
);
360 const char *radix_fmt
= getRadixFmt();
362 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
363 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
364 // let it fall through to OutputFormat berkeley.
365 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(Obj
);
366 if (OutputFormat
== darwin
&& MachO
)
367 printDarwinSectionSizes(MachO
);
368 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
369 // darwin's default berkeley format for Mach-O files.
370 else if (MachO
&& OutputFormat
== berkeley
)
371 printDarwinSegmentSizes(MachO
);
372 else if (OutputFormat
== sysv
) {
373 // Run two passes over all sections. The first gets the lengths needed for
374 // formatting the output. The second actually does the output.
375 std::size_t max_name_len
= strlen("section");
376 std::size_t max_size_len
= strlen("size");
377 std::size_t max_addr_len
= strlen("addr");
378 for (const SectionRef
&Section
: Obj
->sections()) {
379 if (!considerForSize(Obj
, Section
))
381 uint64_t size
= Section
.getSize();
384 Expected
<StringRef
> name_or_err
= Section
.getName();
386 error(name_or_err
.takeError(), Obj
->getFileName());
390 uint64_t addr
= Section
.getAddress();
391 max_name_len
= std::max(max_name_len
, name_or_err
->size());
392 max_size_len
= std::max(max_size_len
, getNumLengthAsString(size
));
393 max_addr_len
= std::max(max_addr_len
, getNumLengthAsString(addr
));
396 // Add extra padding.
401 // Setup header format.
402 fmt
<< "%-" << max_name_len
<< "s "
403 << "%" << max_size_len
<< "s "
404 << "%" << max_addr_len
<< "s\n";
407 outs() << format(fmt
.str().c_str(), static_cast<const char *>("section"),
408 static_cast<const char *>("size"),
409 static_cast<const char *>("addr"));
412 // Setup per section format.
413 fmt
<< "%-" << max_name_len
<< "s "
414 << "%#" << max_size_len
<< radix_fmt
<< " "
415 << "%#" << max_addr_len
<< radix_fmt
<< "\n";
417 // Print each section.
418 for (const SectionRef
&Section
: Obj
->sections()) {
419 if (!considerForSize(Obj
, Section
))
422 Expected
<StringRef
> name_or_err
= Section
.getName();
424 error(name_or_err
.takeError(), Obj
->getFileName());
428 uint64_t size
= Section
.getSize();
429 uint64_t addr
= Section
.getAddress();
430 outs() << format(fmt
.str().c_str(), name_or_err
->str().c_str(), size
, addr
);
434 if (Expected
<uint64_t> CommonSizeOrErr
= getCommonSize(Obj
)) {
435 total
+= *CommonSizeOrErr
;
436 outs() << format(fmt
.str().c_str(), std::string("*COM*").c_str(),
437 *CommonSizeOrErr
, static_cast<uint64_t>(0));
439 error(CommonSizeOrErr
.takeError(), Obj
->getFileName());
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"),
452 // The Berkeley format does not display individual section sizes. It
453 // displays the cumulative size for each section type.
454 uint64_t total_text
= 0;
455 uint64_t total_data
= 0;
456 uint64_t total_bss
= 0;
458 // Make one pass over the section table to calculate sizes.
459 for (const SectionRef
&Section
: Obj
->sections()) {
460 uint64_t size
= Section
.getSize();
461 bool isText
= Section
.isBerkeleyText();
462 bool isData
= Section
.isBerkeleyData();
463 bool isBSS
= Section
.isBSS();
473 if (Expected
<uint64_t> CommonSizeOrErr
= getCommonSize(Obj
))
474 total_bss
+= *CommonSizeOrErr
;
476 error(CommonSizeOrErr
.takeError(), Obj
->getFileName());
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 (!is_contained(ArchFlags
, T
.getArchName())) {
536 error("no architecture specified", Filename
);
542 /// Print the section sizes for @p file. If @p file is an archive, print the
543 /// section sizes for each archive member.
544 static void printFileSectionSizes(StringRef file
) {
546 // Attempt to open the binary.
547 Expected
<OwningBinary
<Binary
>> BinaryOrErr
= createBinary(file
);
549 error(BinaryOrErr
.takeError(), file
);
552 Binary
&Bin
= *BinaryOrErr
.get().getBinary();
554 if (Archive
*a
= dyn_cast
<Archive
>(&Bin
)) {
555 // This is an archive. Iterate over each member and display its sizes.
556 Error Err
= Error::success();
557 for (auto &C
: a
->children(Err
)) {
558 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
560 if (auto E
= isNotObjectErrorInvalidFileType(ChildOrErr
.takeError()))
561 error(std::move(E
), a
->getFileName(), C
);
564 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
565 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
566 if (!checkMachOAndArchFlags(o
, file
))
568 if (OutputFormat
== sysv
)
569 outs() << o
->getFileName() << " (ex " << a
->getFileName() << "):\n";
570 else if (MachO
&& OutputFormat
== darwin
)
571 outs() << a
->getFileName() << "(" << o
->getFileName() << "):\n";
572 printObjectSectionSizes(o
);
573 if (OutputFormat
== berkeley
) {
575 outs() << a
->getFileName() << "(" << o
->getFileName() << ")\n";
577 outs() << o
->getFileName() << " (ex " << a
->getFileName() << ")\n";
582 error(std::move(Err
), a
->getFileName());
583 } else if (MachOUniversalBinary
*UB
=
584 dyn_cast
<MachOUniversalBinary
>(&Bin
)) {
585 // If we have a list of architecture flags specified dump only those.
586 if (!ArchAll
&& !ArchFlags
.empty()) {
587 // Look for a slice in the universal binary that matches each ArchFlag.
589 for (unsigned i
= 0; i
< ArchFlags
.size(); ++i
) {
591 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
592 E
= UB
->end_objects();
594 if (ArchFlags
[i
] == I
->getArchFlagName()) {
596 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
598 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
599 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
600 if (OutputFormat
== sysv
)
601 outs() << o
->getFileName() << " :\n";
602 else if (MachO
&& OutputFormat
== darwin
) {
603 if (MoreThanOneFile
|| ArchFlags
.size() > 1)
604 outs() << o
->getFileName() << " (for architecture "
605 << I
->getArchFlagName() << "): \n";
607 printObjectSectionSizes(o
);
608 if (OutputFormat
== berkeley
) {
609 if (!MachO
|| MoreThanOneFile
|| ArchFlags
.size() > 1)
610 outs() << o
->getFileName() << " (for architecture "
611 << I
->getArchFlagName() << ")";
615 } else if (auto E
= isNotObjectErrorInvalidFileType(
617 error(std::move(E
), file
, ArchFlags
.size() > 1 ?
618 StringRef(I
->getArchFlagName()) : StringRef());
620 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
622 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
623 // This is an archive. Iterate over each member and display its
625 Error Err
= Error::success();
626 for (auto &C
: UA
->children(Err
)) {
627 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
629 if (auto E
= isNotObjectErrorInvalidFileType(
630 ChildOrErr
.takeError()))
631 error(std::move(E
), UA
->getFileName(), C
,
632 ArchFlags
.size() > 1 ?
633 StringRef(I
->getArchFlagName()) : StringRef());
636 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
637 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
638 if (OutputFormat
== sysv
)
639 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
641 else if (MachO
&& OutputFormat
== darwin
)
642 outs() << UA
->getFileName() << "(" << o
->getFileName()
644 << " (for architecture " << I
->getArchFlagName()
646 printObjectSectionSizes(o
);
647 if (OutputFormat
== berkeley
) {
649 outs() << UA
->getFileName() << "(" << o
->getFileName()
651 if (ArchFlags
.size() > 1)
652 outs() << " (for architecture " << I
->getArchFlagName()
656 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
662 error(std::move(Err
), UA
->getFileName());
664 consumeError(AOrErr
.takeError());
665 error("mach-o universal file for architecture " +
666 StringRef(I
->getArchFlagName()) +
667 " is not a mach-o file or an archive file",
673 error("file does not contain architecture " + ArchFlags
[i
], file
);
679 // No architecture flags were specified so if this contains a slice that
680 // matches the host architecture dump only that.
682 StringRef HostArchName
= MachOObjectFile::getHostArch().getArchName();
683 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
684 E
= UB
->end_objects();
686 if (HostArchName
== I
->getArchFlagName()) {
687 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
689 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
690 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
691 if (OutputFormat
== sysv
)
692 outs() << o
->getFileName() << " :\n";
693 else if (MachO
&& OutputFormat
== darwin
) {
695 outs() << o
->getFileName() << " (for architecture "
696 << I
->getArchFlagName() << "):\n";
698 printObjectSectionSizes(o
);
699 if (OutputFormat
== berkeley
) {
700 if (!MachO
|| MoreThanOneFile
)
701 outs() << o
->getFileName() << " (for architecture "
702 << I
->getArchFlagName() << ")";
706 } else if (auto E
= isNotObjectErrorInvalidFileType(UO
.takeError())) {
707 error(std::move(E
), file
);
709 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
711 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
712 // This is an archive. Iterate over each member and display its
714 Error Err
= Error::success();
715 for (auto &C
: UA
->children(Err
)) {
716 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
718 if (auto E
= isNotObjectErrorInvalidFileType(
719 ChildOrErr
.takeError()))
720 error(std::move(E
), UA
->getFileName(), C
);
723 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
724 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
725 if (OutputFormat
== sysv
)
726 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
728 else if (MachO
&& OutputFormat
== darwin
)
729 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
730 << " (for architecture " << I
->getArchFlagName()
732 printObjectSectionSizes(o
);
733 if (OutputFormat
== berkeley
) {
735 outs() << UA
->getFileName() << "(" << o
->getFileName()
738 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
744 error(std::move(Err
), UA
->getFileName());
746 consumeError(AOrErr
.takeError());
747 error("mach-o universal file for architecture " +
748 StringRef(I
->getArchFlagName()) +
749 " is not a mach-o file or an archive file",
756 // Either all architectures have been specified or none have been specified
757 // and this does not contain the host architecture so dump all the slices.
758 bool MoreThanOneArch
= UB
->getNumberOfObjects() > 1;
759 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
760 E
= UB
->end_objects();
762 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
764 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
765 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
766 if (OutputFormat
== sysv
)
767 outs() << o
->getFileName() << " :\n";
768 else if (MachO
&& OutputFormat
== darwin
) {
769 if (MoreThanOneFile
|| MoreThanOneArch
)
770 outs() << o
->getFileName() << " (for architecture "
771 << I
->getArchFlagName() << "):";
774 printObjectSectionSizes(o
);
775 if (OutputFormat
== berkeley
) {
776 if (!MachO
|| MoreThanOneFile
|| MoreThanOneArch
)
777 outs() << o
->getFileName() << " (for architecture "
778 << I
->getArchFlagName() << ")";
782 } else if (auto E
= isNotObjectErrorInvalidFileType(UO
.takeError())) {
783 error(std::move(E
), file
, MoreThanOneArch
?
784 StringRef(I
->getArchFlagName()) : StringRef());
786 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
788 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
789 // This is an archive. Iterate over each member and display its sizes.
790 Error Err
= Error::success();
791 for (auto &C
: UA
->children(Err
)) {
792 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
794 if (auto E
= isNotObjectErrorInvalidFileType(
795 ChildOrErr
.takeError()))
796 error(std::move(E
), UA
->getFileName(), C
, MoreThanOneArch
?
797 StringRef(I
->getArchFlagName()) : StringRef());
800 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
801 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
802 if (OutputFormat
== sysv
)
803 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
805 else if (MachO
&& OutputFormat
== darwin
)
806 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
807 << " (for architecture " << I
->getArchFlagName() << "):\n";
808 printObjectSectionSizes(o
);
809 if (OutputFormat
== berkeley
) {
811 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
812 << " (for architecture " << I
->getArchFlagName()
815 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
821 error(std::move(Err
), UA
->getFileName());
823 consumeError(AOrErr
.takeError());
824 error("mach-o universal file for architecture " +
825 StringRef(I
->getArchFlagName()) +
826 " 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 error("unsupported file type", file
);
849 static void printBerkeleyTotals() {
851 raw_string_ostream
fmt(fmtbuf
);
852 const char *radix_fmt
= getRadixFmt();
853 fmt
<< "%#7" << radix_fmt
<< "\t"
854 << "%#7" << radix_fmt
<< "\t"
855 << "%#7" << radix_fmt
<< "\t";
856 outs() << format(fmt
.str().c_str(), TotalObjectText
, TotalObjectData
,
859 fmt
<< "%7" << (Radix
== octal
? PRIo64
: PRIu64
) << "\t"
861 outs() << format(fmt
.str().c_str(), TotalObjectTotal
, TotalObjectTotal
)
865 int main(int argc
, char **argv
) {
866 InitLLVM
X(argc
, argv
);
868 StringSaver
Saver(A
);
871 opt::InputArgList Args
=
872 Tbl
.parseArgs(argc
, argv
, OPT_UNKNOWN
, Saver
, [&](StringRef Msg
) {
876 if (Args
.hasArg(OPT_help
)) {
879 (Twine(ToolName
) + " [options] <input object files>").str().c_str(),
880 "LLVM object size dumper");
881 // TODO Replace this with OptTable API once it adds extrahelp support.
882 outs() << "\nPass @FILE as argument to read options from FILE.\n";
885 if (Args
.hasArg(OPT_version
)) {
886 outs() << ToolName
<< '\n';
887 cl::PrintVersionMessage();
891 ELFCommons
= Args
.hasArg(OPT_common
);
892 DarwinLongFormat
= Args
.hasArg(OPT_l
);
893 TotalSizes
= Args
.hasArg(OPT_totals
);
894 StringRef V
= Args
.getLastArgValue(OPT_format_EQ
, "berkeley");
896 OutputFormat
= berkeley
;
897 else if (V
== "darwin")
898 OutputFormat
= darwin
;
899 else if (V
== "sysv")
902 error("--format value should be one of: 'berkeley', 'darwin', 'sysv'");
903 V
= Args
.getLastArgValue(OPT_radix_EQ
, "10");
905 Radix
= RadixTy::octal
;
907 Radix
= RadixTy::decimal
;
909 Radix
= RadixTy::hexadecimal
;
911 error("--radix value should be one of: 8, 10, 16 ");
913 for (const auto *A
: Args
.filtered(OPT_arch_EQ
)) {
914 SmallVector
<StringRef
, 2> Values
;
915 llvm::SplitString(A
->getValue(), Values
, ",");
916 for (StringRef V
: Values
) {
919 else if (MachOObjectFile::isValidArch(V
))
920 ArchFlags
.push_back(V
);
922 outs() << ToolName
<< ": for the -arch option: Unknown architecture "
923 << "named '" << V
<< "'";
929 InputFilenames
= Args
.getAllArgValues(OPT_INPUT
);
930 if (InputFilenames
.empty())
931 InputFilenames
.push_back("a.out");
933 MoreThanOneFile
= InputFilenames
.size() > 1;
934 llvm::for_each(InputFilenames
, printFileSectionSizes
);
935 if (OutputFormat
== berkeley
&& TotalSizes
)
936 printBerkeleyTotals();