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/LLVMDriver.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(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
48 #define PREFIX(NAME, VALUE) \
49 static constexpr StringLiteral NAME##_init[] = VALUE; \
50 static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
51 std::size(NAME##_init) - 1);
55 static constexpr opt::OptTable::Info InfoTable
[] = {
56 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
61 class SizeOptTable
: public opt::GenericOptTable
{
63 SizeOptTable() : GenericOptTable(InfoTable
) { setGroupedShortOptions(true); }
66 enum OutputFormatTy
{ berkeley
, sysv
, darwin
};
67 enum RadixTy
{ octal
= 8, decimal
= 10, hexadecimal
= 16 };
70 static bool ArchAll
= false;
71 static std::vector
<StringRef
> ArchFlags
;
72 static bool ELFCommons
;
73 static OutputFormatTy OutputFormat
;
74 static bool DarwinLongFormat
;
76 static bool TotalSizes
;
78 static std::vector
<std::string
> InputFilenames
;
80 static std::string ToolName
;
83 static bool HadError
= false;
84 static bool BerkeleyHeaderPrinted
= false;
85 static bool MoreThanOneFile
= false;
86 static uint64_t TotalObjectText
= 0;
87 static uint64_t TotalObjectData
= 0;
88 static uint64_t TotalObjectBss
= 0;
89 static uint64_t TotalObjectTotal
= 0;
91 static void error(const Twine
&Message
, StringRef File
= "") {
94 WithColor::error(errs(), ToolName
) << Message
<< '\n';
96 WithColor::error(errs(), ToolName
)
97 << "'" << File
<< "': " << Message
<< '\n';
100 // This version of error() prints the archive name and member name, for example:
101 // "libx.a(foo.o)" after the ToolName before the error message. It sets
102 // HadError but returns allowing the code to move on to other archive members.
103 static void error(llvm::Error E
, StringRef FileName
, const Archive::Child
&C
,
104 StringRef ArchitectureName
= StringRef()) {
106 WithColor::error(errs(), ToolName
) << "'" << FileName
<< "'";
108 Expected
<StringRef
> NameOrErr
= C
.getName();
109 // TODO: if we have a error getting the name then it would be nice to print
110 // the index of which archive member this is and or its offset in the
111 // archive instead of "???" as the name.
113 consumeError(NameOrErr
.takeError());
114 errs() << "(" << "???" << ")";
116 errs() << "(" << NameOrErr
.get() << ")";
118 if (!ArchitectureName
.empty())
119 errs() << " (for architecture " << ArchitectureName
<< ") ";
122 raw_string_ostream
OS(Buf
);
123 logAllUnhandledErrors(std::move(E
), OS
);
125 errs() << ": " << Buf
<< "\n";
128 // 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
129 // before the error message. It sets HadError but returns allowing the code to
130 // move on to other architecture slices.
131 static void error(llvm::Error E
, StringRef FileName
,
132 StringRef ArchitectureName
= StringRef()) {
134 WithColor::error(errs(), ToolName
) << "'" << FileName
<< "'";
136 if (!ArchitectureName
.empty())
137 errs() << " (for architecture " << ArchitectureName
<< ") ";
140 raw_string_ostream
OS(Buf
);
141 logAllUnhandledErrors(std::move(E
), OS
);
143 errs() << ": " << Buf
<< "\n";
146 /// Get the length of the string that represents @p num in Radix including the
147 /// leading 0x or 0 for hexadecimal and octal respectively.
148 static size_t getNumLengthAsString(uint64_t num
) {
150 SmallString
<32> result
;
151 conv
.toString(result
, Radix
, false, true);
152 return result
.size();
155 /// Return the printing format for the Radix.
156 static const char *getRadixFmt() {
168 /// Remove unneeded ELF sections from calculation
169 static bool considerForSize(ObjectFile
*Obj
, SectionRef Section
) {
172 switch (static_cast<ELFSectionRef
>(Section
).getType()) {
174 case ELF::SHT_SYMTAB
:
176 case ELF::SHT_STRTAB
:
179 return static_cast<ELFSectionRef
>(Section
).getFlags() & ELF::SHF_ALLOC
;
184 /// Total size of all ELF common symbols
185 static Expected
<uint64_t> getCommonSize(ObjectFile
*Obj
) {
186 uint64_t TotalCommons
= 0;
187 for (auto &Sym
: Obj
->symbols()) {
188 Expected
<uint32_t> SymFlagsOrErr
=
189 Obj
->getSymbolFlags(Sym
.getRawDataRefImpl());
191 return SymFlagsOrErr
.takeError();
192 if (*SymFlagsOrErr
& SymbolRef::SF_Common
)
193 TotalCommons
+= Obj
->getCommonSymbolSize(Sym
.getRawDataRefImpl());
198 /// Print the size of each Mach-O segment and section in @p MachO.
200 /// This is when used when @c OutputFormat is darwin and produces the same
201 /// output as darwin's size(1) -m output.
202 static void printDarwinSectionSizes(MachOObjectFile
*MachO
) {
204 raw_string_ostream
fmt(fmtbuf
);
205 const char *radix_fmt
= getRadixFmt();
206 if (Radix
== hexadecimal
)
208 fmt
<< "%" << radix_fmt
;
210 uint32_t Filetype
= MachO
->getHeader().filetype
;
213 for (const auto &Load
: MachO
->load_commands()) {
214 if (Load
.C
.cmd
== MachO::LC_SEGMENT_64
) {
215 MachO::segment_command_64 Seg
= MachO
->getSegment64LoadCommand(Load
);
216 outs() << "Segment " << Seg
.segname
<< ": "
217 << format(fmt
.str().c_str(), Seg
.vmsize
);
218 if (DarwinLongFormat
)
219 outs() << " (vmaddr 0x" << format("%" PRIx64
, Seg
.vmaddr
) << " fileoff "
220 << Seg
.fileoff
<< ")";
223 uint64_t sec_total
= 0;
224 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
225 MachO::section_64 Sec
= MachO
->getSection64(Load
, J
);
226 if (Filetype
== MachO::MH_OBJECT
)
227 outs() << "\tSection (" << format("%.16s", &Sec
.segname
) << ", "
228 << format("%.16s", &Sec
.sectname
) << "): ";
230 outs() << "\tSection " << format("%.16s", &Sec
.sectname
) << ": ";
231 outs() << format(fmt
.str().c_str(), Sec
.size
);
232 if (DarwinLongFormat
)
233 outs() << " (addr 0x" << format("%" PRIx64
, Sec
.addr
) << " offset "
234 << Sec
.offset
<< ")";
236 sec_total
+= Sec
.size
;
239 outs() << "\ttotal " << format(fmt
.str().c_str(), sec_total
) << "\n";
240 } else if (Load
.C
.cmd
== MachO::LC_SEGMENT
) {
241 MachO::segment_command Seg
= MachO
->getSegmentLoadCommand(Load
);
242 uint64_t Seg_vmsize
= Seg
.vmsize
;
243 outs() << "Segment " << Seg
.segname
<< ": "
244 << format(fmt
.str().c_str(), Seg_vmsize
);
245 if (DarwinLongFormat
)
246 outs() << " (vmaddr 0x" << format("%" PRIx32
, Seg
.vmaddr
) << " fileoff "
247 << Seg
.fileoff
<< ")";
250 uint64_t sec_total
= 0;
251 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
252 MachO::section Sec
= MachO
->getSection(Load
, J
);
253 if (Filetype
== MachO::MH_OBJECT
)
254 outs() << "\tSection (" << format("%.16s", &Sec
.segname
) << ", "
255 << format("%.16s", &Sec
.sectname
) << "): ";
257 outs() << "\tSection " << format("%.16s", &Sec
.sectname
) << ": ";
258 uint64_t Sec_size
= Sec
.size
;
259 outs() << format(fmt
.str().c_str(), Sec_size
);
260 if (DarwinLongFormat
)
261 outs() << " (addr 0x" << format("%" PRIx32
, Sec
.addr
) << " offset "
262 << Sec
.offset
<< ")";
264 sec_total
+= Sec
.size
;
267 outs() << "\ttotal " << format(fmt
.str().c_str(), sec_total
) << "\n";
270 outs() << "total " << format(fmt
.str().c_str(), total
) << "\n";
273 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
275 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
276 /// produces the same output as darwin's size(1) default output.
277 static void printDarwinSegmentSizes(MachOObjectFile
*MachO
) {
278 uint64_t total_text
= 0;
279 uint64_t total_data
= 0;
280 uint64_t total_objc
= 0;
281 uint64_t total_others
= 0;
282 for (const auto &Load
: MachO
->load_commands()) {
283 if (Load
.C
.cmd
== MachO::LC_SEGMENT_64
) {
284 MachO::segment_command_64 Seg
= MachO
->getSegment64LoadCommand(Load
);
285 if (MachO
->getHeader().filetype
== MachO::MH_OBJECT
) {
286 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
287 MachO::section_64 Sec
= MachO
->getSection64(Load
, J
);
288 StringRef SegmentName
= StringRef(Sec
.segname
);
289 if (SegmentName
== "__TEXT")
290 total_text
+= Sec
.size
;
291 else if (SegmentName
== "__DATA")
292 total_data
+= Sec
.size
;
293 else if (SegmentName
== "__OBJC")
294 total_objc
+= Sec
.size
;
296 total_others
+= Sec
.size
;
299 StringRef SegmentName
= StringRef(Seg
.segname
);
300 if (SegmentName
== "__TEXT")
301 total_text
+= Seg
.vmsize
;
302 else if (SegmentName
== "__DATA")
303 total_data
+= Seg
.vmsize
;
304 else if (SegmentName
== "__OBJC")
305 total_objc
+= Seg
.vmsize
;
307 total_others
+= Seg
.vmsize
;
309 } else if (Load
.C
.cmd
== MachO::LC_SEGMENT
) {
310 MachO::segment_command Seg
= MachO
->getSegmentLoadCommand(Load
);
311 if (MachO
->getHeader().filetype
== MachO::MH_OBJECT
) {
312 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
313 MachO::section Sec
= MachO
->getSection(Load
, J
);
314 StringRef SegmentName
= StringRef(Sec
.segname
);
315 if (SegmentName
== "__TEXT")
316 total_text
+= Sec
.size
;
317 else if (SegmentName
== "__DATA")
318 total_data
+= Sec
.size
;
319 else if (SegmentName
== "__OBJC")
320 total_objc
+= Sec
.size
;
322 total_others
+= Sec
.size
;
325 StringRef SegmentName
= StringRef(Seg
.segname
);
326 if (SegmentName
== "__TEXT")
327 total_text
+= Seg
.vmsize
;
328 else if (SegmentName
== "__DATA")
329 total_data
+= Seg
.vmsize
;
330 else if (SegmentName
== "__OBJC")
331 total_objc
+= Seg
.vmsize
;
333 total_others
+= Seg
.vmsize
;
337 uint64_t total
= total_text
+ total_data
+ total_objc
+ total_others
;
339 if (!BerkeleyHeaderPrinted
) {
340 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
341 BerkeleyHeaderPrinted
= true;
343 outs() << total_text
<< "\t" << total_data
<< "\t" << total_objc
<< "\t"
344 << total_others
<< "\t" << total
<< "\t" << format("%" PRIx64
, total
)
348 /// Print the size of each section in @p Obj.
350 /// The format used is determined by @c OutputFormat and @c Radix.
351 static void printObjectSectionSizes(ObjectFile
*Obj
) {
354 raw_string_ostream
fmt(fmtbuf
);
355 const char *radix_fmt
= getRadixFmt();
357 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
358 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
359 // let it fall through to OutputFormat berkeley.
360 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(Obj
);
361 if (OutputFormat
== darwin
&& MachO
)
362 printDarwinSectionSizes(MachO
);
363 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
364 // darwin's default berkeley format for Mach-O files.
365 else if (MachO
&& OutputFormat
== berkeley
)
366 printDarwinSegmentSizes(MachO
);
367 else if (OutputFormat
== sysv
) {
368 // Run two passes over all sections. The first gets the lengths needed for
369 // formatting the output. The second actually does the output.
370 std::size_t max_name_len
= strlen("section");
371 std::size_t max_size_len
= strlen("size");
372 std::size_t max_addr_len
= strlen("addr");
373 for (const SectionRef
&Section
: Obj
->sections()) {
374 if (!considerForSize(Obj
, Section
))
376 uint64_t size
= Section
.getSize();
379 Expected
<StringRef
> name_or_err
= Section
.getName();
381 error(name_or_err
.takeError(), Obj
->getFileName());
385 uint64_t addr
= Section
.getAddress();
386 max_name_len
= std::max(max_name_len
, name_or_err
->size());
387 max_size_len
= std::max(max_size_len
, getNumLengthAsString(size
));
388 max_addr_len
= std::max(max_addr_len
, getNumLengthAsString(addr
));
391 // Add extra padding.
396 // Setup header format.
397 fmt
<< "%-" << max_name_len
<< "s "
398 << "%" << max_size_len
<< "s "
399 << "%" << max_addr_len
<< "s\n";
402 outs() << format(fmt
.str().c_str(), static_cast<const char *>("section"),
403 static_cast<const char *>("size"),
404 static_cast<const char *>("addr"));
407 // Setup per section format.
408 fmt
<< "%-" << max_name_len
<< "s "
409 << "%#" << max_size_len
<< radix_fmt
<< " "
410 << "%#" << max_addr_len
<< radix_fmt
<< "\n";
412 // Print each section.
413 for (const SectionRef
&Section
: Obj
->sections()) {
414 if (!considerForSize(Obj
, Section
))
417 Expected
<StringRef
> name_or_err
= Section
.getName();
419 error(name_or_err
.takeError(), Obj
->getFileName());
423 uint64_t size
= Section
.getSize();
424 uint64_t addr
= Section
.getAddress();
425 outs() << format(fmt
.str().c_str(), name_or_err
->str().c_str(), size
, addr
);
429 if (Expected
<uint64_t> CommonSizeOrErr
= getCommonSize(Obj
)) {
430 total
+= *CommonSizeOrErr
;
431 outs() << format(fmt
.str().c_str(), std::string("*COM*").c_str(),
432 *CommonSizeOrErr
, static_cast<uint64_t>(0));
434 error(CommonSizeOrErr
.takeError(), Obj
->getFileName());
441 fmt
<< "%-" << max_name_len
<< "s "
442 << "%#" << max_size_len
<< radix_fmt
<< "\n";
443 outs() << format(fmt
.str().c_str(), static_cast<const char *>("Total"),
447 // The Berkeley format does not display individual section sizes. It
448 // displays the cumulative size for each section type.
449 uint64_t total_text
= 0;
450 uint64_t total_data
= 0;
451 uint64_t total_bss
= 0;
453 // Make one pass over the section table to calculate sizes.
454 for (const SectionRef
&Section
: Obj
->sections()) {
455 uint64_t size
= Section
.getSize();
456 bool isText
= Section
.isBerkeleyText();
457 bool isData
= Section
.isBerkeleyData();
458 bool isBSS
= Section
.isBSS();
468 if (Expected
<uint64_t> CommonSizeOrErr
= getCommonSize(Obj
))
469 total_bss
+= *CommonSizeOrErr
;
471 error(CommonSizeOrErr
.takeError(), Obj
->getFileName());
476 total
= total_text
+ total_data
+ total_bss
;
479 TotalObjectText
+= total_text
;
480 TotalObjectData
+= total_data
;
481 TotalObjectBss
+= total_bss
;
482 TotalObjectTotal
+= total
;
485 if (!BerkeleyHeaderPrinted
) {
490 << (Radix
== octal
? "oct" : "dec")
494 BerkeleyHeaderPrinted
= true;
498 fmt
<< "%#7" << radix_fmt
<< "\t"
499 << "%#7" << radix_fmt
<< "\t"
500 << "%#7" << radix_fmt
<< "\t";
501 outs() << format(fmt
.str().c_str(), total_text
, total_data
, total_bss
);
503 fmt
<< "%7" << (Radix
== octal
? PRIo64
: PRIu64
) << "\t"
505 outs() << format(fmt
.str().c_str(), total
, total
);
509 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
510 /// is a list of architecture flags specified then check to make sure this
511 /// Mach-O file is one of those architectures or all architectures was
512 /// specificed. If not then an error is generated and this routine returns
513 /// false. Else it returns true.
514 static bool checkMachOAndArchFlags(ObjectFile
*O
, StringRef Filename
) {
515 auto *MachO
= dyn_cast
<MachOObjectFile
>(O
);
517 if (!MachO
|| ArchAll
|| ArchFlags
.empty())
520 MachO::mach_header H
;
521 MachO::mach_header_64 H_64
;
523 if (MachO
->is64Bit()) {
524 H_64
= MachO
->MachOObjectFile::getHeader64();
525 T
= MachOObjectFile::getArchTriple(H_64
.cputype
, H_64
.cpusubtype
);
527 H
= MachO
->MachOObjectFile::getHeader();
528 T
= MachOObjectFile::getArchTriple(H
.cputype
, H
.cpusubtype
);
530 if (!is_contained(ArchFlags
, 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 (!MachO
&& OutputFormat
== darwin
)
569 outs() << o
->getFileName() << " (ex " << a
->getFileName() << ")\n";
570 if (OutputFormat
== berkeley
) {
572 outs() << a
->getFileName() << "(" << o
->getFileName() << ")\n";
574 outs() << o
->getFileName() << " (ex " << a
->getFileName() << ")\n";
579 error(std::move(Err
), a
->getFileName());
580 } else if (MachOUniversalBinary
*UB
=
581 dyn_cast
<MachOUniversalBinary
>(&Bin
)) {
582 // If we have a list of architecture flags specified dump only those.
583 if (!ArchAll
&& !ArchFlags
.empty()) {
584 // Look for a slice in the universal binary that matches each ArchFlag.
586 for (unsigned i
= 0; i
< ArchFlags
.size(); ++i
) {
588 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
589 E
= UB
->end_objects();
591 if (ArchFlags
[i
] == I
->getArchFlagName()) {
593 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
595 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
596 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
597 if (OutputFormat
== sysv
)
598 outs() << o
->getFileName() << " :\n";
599 else if (MachO
&& OutputFormat
== darwin
) {
600 if (MoreThanOneFile
|| ArchFlags
.size() > 1)
601 outs() << o
->getFileName() << " (for architecture "
602 << I
->getArchFlagName() << "): \n";
604 printObjectSectionSizes(o
);
605 if (OutputFormat
== berkeley
) {
606 if (!MachO
|| MoreThanOneFile
|| ArchFlags
.size() > 1)
607 outs() << o
->getFileName() << " (for architecture "
608 << I
->getArchFlagName() << ")";
612 } else if (auto E
= isNotObjectErrorInvalidFileType(
614 error(std::move(E
), file
, ArchFlags
.size() > 1 ?
615 StringRef(I
->getArchFlagName()) : StringRef());
617 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
619 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
620 // This is an archive. Iterate over each member and display its
622 Error Err
= Error::success();
623 for (auto &C
: UA
->children(Err
)) {
624 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
626 if (auto E
= isNotObjectErrorInvalidFileType(
627 ChildOrErr
.takeError()))
628 error(std::move(E
), UA
->getFileName(), C
,
629 ArchFlags
.size() > 1 ?
630 StringRef(I
->getArchFlagName()) : StringRef());
633 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
634 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
635 if (OutputFormat
== sysv
)
636 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
638 else if (MachO
&& OutputFormat
== darwin
)
639 outs() << UA
->getFileName() << "(" << o
->getFileName()
641 << " (for architecture " << I
->getArchFlagName()
643 printObjectSectionSizes(o
);
644 if (OutputFormat
== berkeley
) {
646 outs() << UA
->getFileName() << "(" << o
->getFileName()
648 if (ArchFlags
.size() > 1)
649 outs() << " (for architecture " << I
->getArchFlagName()
653 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
659 error(std::move(Err
), UA
->getFileName());
661 consumeError(AOrErr
.takeError());
662 error("mach-o universal file for architecture " +
663 StringRef(I
->getArchFlagName()) +
664 " is not a mach-o file or an archive file",
670 error("file does not contain architecture " + ArchFlags
[i
], file
);
676 // No architecture flags were specified so if this contains a slice that
677 // matches the host architecture dump only that.
679 StringRef HostArchName
= MachOObjectFile::getHostArch().getArchName();
680 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
681 E
= UB
->end_objects();
683 if (HostArchName
== I
->getArchFlagName()) {
684 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
686 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
687 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
688 if (OutputFormat
== sysv
)
689 outs() << o
->getFileName() << " :\n";
690 else if (MachO
&& OutputFormat
== darwin
) {
692 outs() << o
->getFileName() << " (for architecture "
693 << I
->getArchFlagName() << "):\n";
695 printObjectSectionSizes(o
);
696 if (OutputFormat
== berkeley
) {
697 if (!MachO
|| MoreThanOneFile
)
698 outs() << o
->getFileName() << " (for architecture "
699 << I
->getArchFlagName() << ")";
703 } else if (auto E
= isNotObjectErrorInvalidFileType(UO
.takeError())) {
704 error(std::move(E
), file
);
706 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
708 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
709 // This is an archive. Iterate over each member and display its
711 Error Err
= Error::success();
712 for (auto &C
: UA
->children(Err
)) {
713 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
715 if (auto E
= isNotObjectErrorInvalidFileType(
716 ChildOrErr
.takeError()))
717 error(std::move(E
), UA
->getFileName(), C
);
720 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
721 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
722 if (OutputFormat
== sysv
)
723 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
725 else if (MachO
&& OutputFormat
== darwin
)
726 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
727 << " (for architecture " << I
->getArchFlagName()
729 printObjectSectionSizes(o
);
730 if (OutputFormat
== berkeley
) {
732 outs() << UA
->getFileName() << "(" << o
->getFileName()
735 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
741 error(std::move(Err
), UA
->getFileName());
743 consumeError(AOrErr
.takeError());
744 error("mach-o universal file for architecture " +
745 StringRef(I
->getArchFlagName()) +
746 " is not a mach-o file or an archive file",
753 // Either all architectures have been specified or none have been specified
754 // and this does not contain the host architecture so dump all the slices.
755 bool MoreThanOneArch
= UB
->getNumberOfObjects() > 1;
756 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
757 E
= UB
->end_objects();
759 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
761 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
762 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
763 if (OutputFormat
== sysv
)
764 outs() << o
->getFileName() << " :\n";
765 else if (MachO
&& OutputFormat
== darwin
) {
766 if (MoreThanOneFile
|| MoreThanOneArch
)
767 outs() << o
->getFileName() << " (for architecture "
768 << I
->getArchFlagName() << "):";
771 printObjectSectionSizes(o
);
772 if (OutputFormat
== berkeley
) {
773 if (!MachO
|| MoreThanOneFile
|| MoreThanOneArch
)
774 outs() << o
->getFileName() << " (for architecture "
775 << I
->getArchFlagName() << ")";
779 } else if (auto E
= isNotObjectErrorInvalidFileType(UO
.takeError())) {
780 error(std::move(E
), file
, MoreThanOneArch
?
781 StringRef(I
->getArchFlagName()) : StringRef());
783 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
785 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
786 // This is an archive. Iterate over each member and display its sizes.
787 Error Err
= Error::success();
788 for (auto &C
: UA
->children(Err
)) {
789 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
791 if (auto E
= isNotObjectErrorInvalidFileType(
792 ChildOrErr
.takeError()))
793 error(std::move(E
), UA
->getFileName(), C
, MoreThanOneArch
?
794 StringRef(I
->getArchFlagName()) : StringRef());
797 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
798 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
799 if (OutputFormat
== sysv
)
800 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
802 else if (MachO
&& OutputFormat
== darwin
)
803 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
804 << " (for architecture " << I
->getArchFlagName() << "):\n";
805 printObjectSectionSizes(o
);
806 if (OutputFormat
== berkeley
) {
808 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
809 << " (for architecture " << I
->getArchFlagName()
812 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
818 error(std::move(Err
), UA
->getFileName());
820 consumeError(AOrErr
.takeError());
821 error("mach-o universal file for architecture " +
822 StringRef(I
->getArchFlagName()) +
823 " is not a mach-o file or an archive file",
827 } else if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&Bin
)) {
828 if (!checkMachOAndArchFlags(o
, file
))
830 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
831 if (OutputFormat
== sysv
)
832 outs() << o
->getFileName() << " :\n";
833 else if (MachO
&& OutputFormat
== darwin
&& MoreThanOneFile
)
834 outs() << o
->getFileName() << ":\n";
835 printObjectSectionSizes(o
);
836 if (!MachO
&& OutputFormat
== darwin
)
837 outs() << o
->getFileName() << "\n";
838 if (OutputFormat
== berkeley
) {
839 if (!MachO
|| MoreThanOneFile
)
840 outs() << o
->getFileName();
844 error("unsupported file type", file
);
848 static void printBerkeleyTotals() {
850 raw_string_ostream
fmt(fmtbuf
);
851 const char *radix_fmt
= getRadixFmt();
852 fmt
<< "%#7" << radix_fmt
<< "\t"
853 << "%#7" << radix_fmt
<< "\t"
854 << "%#7" << radix_fmt
<< "\t";
855 outs() << format(fmt
.str().c_str(), TotalObjectText
, TotalObjectData
,
858 fmt
<< "%7" << (Radix
== octal
? PRIo64
: PRIu64
) << "\t"
860 outs() << format(fmt
.str().c_str(), TotalObjectTotal
, TotalObjectTotal
)
864 int llvm_size_main(int argc
, char **argv
, const llvm::ToolContext
&) {
866 StringSaver
Saver(A
);
869 opt::InputArgList Args
=
870 Tbl
.parseArgs(argc
, argv
, OPT_UNKNOWN
, Saver
, [&](StringRef Msg
) {
874 if (Args
.hasArg(OPT_help
)) {
877 (Twine(ToolName
) + " [options] <input object files>").str().c_str(),
878 "LLVM object size dumper");
879 // TODO Replace this with OptTable API once it adds extrahelp support.
880 outs() << "\nPass @FILE as argument to read options from FILE.\n";
883 if (Args
.hasArg(OPT_version
)) {
884 outs() << ToolName
<< '\n';
885 cl::PrintVersionMessage();
889 ELFCommons
= Args
.hasArg(OPT_common
);
890 DarwinLongFormat
= Args
.hasArg(OPT_l
);
891 TotalSizes
= Args
.hasArg(OPT_totals
);
892 StringRef V
= Args
.getLastArgValue(OPT_format_EQ
, "berkeley");
894 OutputFormat
= berkeley
;
895 else if (V
== "darwin")
896 OutputFormat
= darwin
;
897 else if (V
== "sysv")
900 error("--format value should be one of: 'berkeley', 'darwin', 'sysv'");
901 V
= Args
.getLastArgValue(OPT_radix_EQ
, "10");
903 Radix
= RadixTy::octal
;
905 Radix
= RadixTy::decimal
;
907 Radix
= RadixTy::hexadecimal
;
909 error("--radix value should be one of: 8, 10, 16 ");
911 for (const auto *A
: Args
.filtered(OPT_arch_EQ
)) {
912 SmallVector
<StringRef
, 2> Values
;
913 llvm::SplitString(A
->getValue(), Values
, ",");
914 for (StringRef V
: Values
) {
917 else if (MachOObjectFile::isValidArch(V
))
918 ArchFlags
.push_back(V
);
920 outs() << ToolName
<< ": for the -arch option: Unknown architecture "
921 << "named '" << V
<< "'";
927 InputFilenames
= Args
.getAllArgValues(OPT_INPUT
);
928 if (InputFilenames
.empty())
929 InputFilenames
.push_back("a.out");
931 MoreThanOneFile
= InputFilenames
.size() > 1;
932 llvm::for_each(InputFilenames
, printFileSectionSizes
);
933 if (OutputFormat
== berkeley
&& TotalSizes
)
934 printBerkeleyTotals();