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 enum OutputFormatTy
{ berkeley
, sysv
, darwin
};
36 static cl::opt
<OutputFormatTy
>
37 OutputFormat("format", cl::desc("Specify output format"),
38 cl::values(clEnumVal(sysv
, "System V format"),
39 clEnumVal(berkeley
, "Berkeley format"),
40 clEnumVal(darwin
, "Darwin -m format")),
43 static cl::opt
<OutputFormatTy
> OutputFormatShort(
44 cl::desc("Specify output format"),
45 cl::values(clEnumValN(sysv
, "A", "System V format"),
46 clEnumValN(berkeley
, "B", "Berkeley format"),
47 clEnumValN(darwin
, "m", "Darwin -m format")),
50 static bool BerkeleyHeaderPrinted
= false;
51 static bool MoreThanOneFile
= false;
52 static uint64_t TotalObjectText
= 0;
53 static uint64_t TotalObjectData
= 0;
54 static uint64_t TotalObjectBss
= 0;
55 static uint64_t TotalObjectTotal
= 0;
58 DarwinLongFormat("l", cl::desc("When format is darwin, use long format "
59 "to include addresses and offsets."));
63 cl::desc("Print common symbols in the ELF file. When using "
64 "Berkely format, this is added to bss."),
67 static cl::list
<std::string
>
68 ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
70 static bool ArchAll
= false;
72 enum RadixTy
{ octal
= 8, decimal
= 10, hexadecimal
= 16 };
73 static cl::opt
<RadixTy
> Radix(
74 "radix", cl::desc("Print size in radix"), cl::init(decimal
),
75 cl::values(clEnumValN(octal
, "8", "Print size in octal"),
76 clEnumValN(decimal
, "10", "Print size in decimal"),
77 clEnumValN(hexadecimal
, "16", "Print size in hexadecimal")));
79 static cl::opt
<RadixTy
>
80 RadixShort(cl::desc("Print size in radix:"),
81 cl::values(clEnumValN(octal
, "o", "Print size in octal"),
82 clEnumValN(decimal
, "d", "Print size in decimal"),
83 clEnumValN(hexadecimal
, "x", "Print size in hexadecimal")),
88 cl::desc("Print totals of all objects - Berkeley format only"),
91 static cl::alias
TotalSizesShort("t", cl::desc("Short for --totals"),
92 cl::aliasopt(TotalSizes
));
94 static cl::list
<std::string
>
95 InputFilenames(cl::Positional
, cl::desc("<input files>"), cl::ZeroOrMore
);
97 static bool HadError
= false;
99 static std::string ToolName
;
101 /// If ec is not success, print the error and return true.
102 static bool error(std::error_code ec
) {
107 errs() << ToolName
<< ": error reading file: " << ec
.message() << ".\n";
112 static bool error(Twine Message
) {
114 errs() << ToolName
<< ": " << Message
<< ".\n";
119 // This version of error() prints the archive name and member name, for example:
120 // "libx.a(foo.o)" after the ToolName before the error message. It sets
121 // HadError but returns allowing the code to move on to other archive members.
122 static void error(llvm::Error E
, StringRef FileName
, const Archive::Child
&C
,
123 StringRef ArchitectureName
= StringRef()) {
125 errs() << ToolName
<< ": " << FileName
;
127 Expected
<StringRef
> NameOrErr
= C
.getName();
128 // TODO: if we have a error getting the name then it would be nice to print
129 // the index of which archive member this is and or its offset in the
130 // archive instead of "???" as the name.
132 consumeError(NameOrErr
.takeError());
133 errs() << "(" << "???" << ")";
135 errs() << "(" << NameOrErr
.get() << ")";
137 if (!ArchitectureName
.empty())
138 errs() << " (for architecture " << ArchitectureName
<< ") ";
141 raw_string_ostream
OS(Buf
);
142 logAllUnhandledErrors(std::move(E
), OS
);
144 errs() << " " << Buf
<< "\n";
147 // 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
148 // before the error message. It sets HadError but returns allowing the code to
149 // move on to other architecture slices.
150 static void error(llvm::Error E
, StringRef FileName
,
151 StringRef ArchitectureName
= StringRef()) {
153 errs() << ToolName
<< ": " << FileName
;
155 if (!ArchitectureName
.empty())
156 errs() << " (for architecture " << ArchitectureName
<< ") ";
159 raw_string_ostream
OS(Buf
);
160 logAllUnhandledErrors(std::move(E
), OS
);
162 errs() << " " << Buf
<< "\n";
165 /// Get the length of the string that represents @p num in Radix including the
166 /// leading 0x or 0 for hexadecimal and octal respectively.
167 static size_t getNumLengthAsString(uint64_t num
) {
169 SmallString
<32> result
;
170 conv
.toString(result
, Radix
, false, true);
171 return result
.size();
174 /// Return the printing format for the Radix.
175 static const char *getRadixFmt() {
187 /// Remove unneeded ELF sections from calculation
188 static bool considerForSize(ObjectFile
*Obj
, SectionRef Section
) {
191 switch (static_cast<ELFSectionRef
>(Section
).getType()) {
193 case ELF::SHT_SYMTAB
:
194 case ELF::SHT_STRTAB
:
202 /// Total size of all ELF common symbols
203 static uint64_t getCommonSize(ObjectFile
*Obj
) {
204 uint64_t TotalCommons
= 0;
205 for (auto &Sym
: Obj
->symbols())
206 if (Obj
->getSymbolFlags(Sym
.getRawDataRefImpl()) & SymbolRef::SF_Common
)
207 TotalCommons
+= Obj
->getCommonSymbolSize(Sym
.getRawDataRefImpl());
211 /// Print the size of each Mach-O segment and section in @p MachO.
213 /// This is when used when @c OutputFormat is darwin and produces the same
214 /// output as darwin's size(1) -m output.
215 static void printDarwinSectionSizes(MachOObjectFile
*MachO
) {
217 raw_string_ostream
fmt(fmtbuf
);
218 const char *radix_fmt
= getRadixFmt();
219 if (Radix
== hexadecimal
)
221 fmt
<< "%" << radix_fmt
;
223 uint32_t Filetype
= MachO
->getHeader().filetype
;
226 for (const auto &Load
: MachO
->load_commands()) {
227 if (Load
.C
.cmd
== MachO::LC_SEGMENT_64
) {
228 MachO::segment_command_64 Seg
= MachO
->getSegment64LoadCommand(Load
);
229 outs() << "Segment " << Seg
.segname
<< ": "
230 << format(fmt
.str().c_str(), Seg
.vmsize
);
231 if (DarwinLongFormat
)
232 outs() << " (vmaddr 0x" << format("%" PRIx64
, Seg
.vmaddr
) << " fileoff "
233 << Seg
.fileoff
<< ")";
236 uint64_t sec_total
= 0;
237 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
238 MachO::section_64 Sec
= MachO
->getSection64(Load
, J
);
239 if (Filetype
== MachO::MH_OBJECT
)
240 outs() << "\tSection (" << format("%.16s", &Sec
.segname
) << ", "
241 << format("%.16s", &Sec
.sectname
) << "): ";
243 outs() << "\tSection " << format("%.16s", &Sec
.sectname
) << ": ";
244 outs() << format(fmt
.str().c_str(), Sec
.size
);
245 if (DarwinLongFormat
)
246 outs() << " (addr 0x" << format("%" PRIx64
, Sec
.addr
) << " offset "
247 << Sec
.offset
<< ")";
249 sec_total
+= Sec
.size
;
252 outs() << "\ttotal " << format(fmt
.str().c_str(), sec_total
) << "\n";
253 } else if (Load
.C
.cmd
== MachO::LC_SEGMENT
) {
254 MachO::segment_command Seg
= MachO
->getSegmentLoadCommand(Load
);
255 uint64_t Seg_vmsize
= Seg
.vmsize
;
256 outs() << "Segment " << Seg
.segname
<< ": "
257 << format(fmt
.str().c_str(), Seg_vmsize
);
258 if (DarwinLongFormat
)
259 outs() << " (vmaddr 0x" << format("%" PRIx32
, Seg
.vmaddr
) << " fileoff "
260 << Seg
.fileoff
<< ")";
263 uint64_t sec_total
= 0;
264 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
265 MachO::section Sec
= MachO
->getSection(Load
, J
);
266 if (Filetype
== MachO::MH_OBJECT
)
267 outs() << "\tSection (" << format("%.16s", &Sec
.segname
) << ", "
268 << format("%.16s", &Sec
.sectname
) << "): ";
270 outs() << "\tSection " << format("%.16s", &Sec
.sectname
) << ": ";
271 uint64_t Sec_size
= Sec
.size
;
272 outs() << format(fmt
.str().c_str(), Sec_size
);
273 if (DarwinLongFormat
)
274 outs() << " (addr 0x" << format("%" PRIx32
, Sec
.addr
) << " offset "
275 << Sec
.offset
<< ")";
277 sec_total
+= Sec
.size
;
280 outs() << "\ttotal " << format(fmt
.str().c_str(), sec_total
) << "\n";
283 outs() << "total " << format(fmt
.str().c_str(), total
) << "\n";
286 /// Print the summary sizes of the standard Mach-O segments in @p MachO.
288 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
289 /// produces the same output as darwin's size(1) default output.
290 static void printDarwinSegmentSizes(MachOObjectFile
*MachO
) {
291 uint64_t total_text
= 0;
292 uint64_t total_data
= 0;
293 uint64_t total_objc
= 0;
294 uint64_t total_others
= 0;
295 for (const auto &Load
: MachO
->load_commands()) {
296 if (Load
.C
.cmd
== MachO::LC_SEGMENT_64
) {
297 MachO::segment_command_64 Seg
= MachO
->getSegment64LoadCommand(Load
);
298 if (MachO
->getHeader().filetype
== MachO::MH_OBJECT
) {
299 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
300 MachO::section_64 Sec
= MachO
->getSection64(Load
, J
);
301 StringRef SegmentName
= StringRef(Sec
.segname
);
302 if (SegmentName
== "__TEXT")
303 total_text
+= Sec
.size
;
304 else if (SegmentName
== "__DATA")
305 total_data
+= Sec
.size
;
306 else if (SegmentName
== "__OBJC")
307 total_objc
+= Sec
.size
;
309 total_others
+= Sec
.size
;
312 StringRef SegmentName
= StringRef(Seg
.segname
);
313 if (SegmentName
== "__TEXT")
314 total_text
+= Seg
.vmsize
;
315 else if (SegmentName
== "__DATA")
316 total_data
+= Seg
.vmsize
;
317 else if (SegmentName
== "__OBJC")
318 total_objc
+= Seg
.vmsize
;
320 total_others
+= Seg
.vmsize
;
322 } else if (Load
.C
.cmd
== MachO::LC_SEGMENT
) {
323 MachO::segment_command Seg
= MachO
->getSegmentLoadCommand(Load
);
324 if (MachO
->getHeader().filetype
== MachO::MH_OBJECT
) {
325 for (unsigned J
= 0; J
< Seg
.nsects
; ++J
) {
326 MachO::section Sec
= MachO
->getSection(Load
, J
);
327 StringRef SegmentName
= StringRef(Sec
.segname
);
328 if (SegmentName
== "__TEXT")
329 total_text
+= Sec
.size
;
330 else if (SegmentName
== "__DATA")
331 total_data
+= Sec
.size
;
332 else if (SegmentName
== "__OBJC")
333 total_objc
+= Sec
.size
;
335 total_others
+= Sec
.size
;
338 StringRef SegmentName
= StringRef(Seg
.segname
);
339 if (SegmentName
== "__TEXT")
340 total_text
+= Seg
.vmsize
;
341 else if (SegmentName
== "__DATA")
342 total_data
+= Seg
.vmsize
;
343 else if (SegmentName
== "__OBJC")
344 total_objc
+= Seg
.vmsize
;
346 total_others
+= Seg
.vmsize
;
350 uint64_t total
= total_text
+ total_data
+ total_objc
+ total_others
;
352 if (!BerkeleyHeaderPrinted
) {
353 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
354 BerkeleyHeaderPrinted
= true;
356 outs() << total_text
<< "\t" << total_data
<< "\t" << total_objc
<< "\t"
357 << total_others
<< "\t" << total
<< "\t" << format("%" PRIx64
, total
)
361 /// Print the size of each section in @p Obj.
363 /// The format used is determined by @c OutputFormat and @c Radix.
364 static void printObjectSectionSizes(ObjectFile
*Obj
) {
367 raw_string_ostream
fmt(fmtbuf
);
368 const char *radix_fmt
= getRadixFmt();
370 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
371 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
372 // let it fall through to OutputFormat berkeley.
373 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(Obj
);
374 if (OutputFormat
== darwin
&& MachO
)
375 printDarwinSectionSizes(MachO
);
376 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
377 // darwin's default berkeley format for Mach-O files.
378 else if (MachO
&& OutputFormat
== berkeley
)
379 printDarwinSegmentSizes(MachO
);
380 else if (OutputFormat
== sysv
) {
381 // Run two passes over all sections. The first gets the lengths needed for
382 // formatting the output. The second actually does the output.
383 std::size_t max_name_len
= strlen("section");
384 std::size_t max_size_len
= strlen("size");
385 std::size_t max_addr_len
= strlen("addr");
386 for (const SectionRef
&Section
: Obj
->sections()) {
387 if (!considerForSize(Obj
, Section
))
389 uint64_t size
= Section
.getSize();
393 if (error(Section
.getName(name
)))
395 uint64_t addr
= Section
.getAddress();
396 max_name_len
= std::max(max_name_len
, name
.size());
397 max_size_len
= std::max(max_size_len
, getNumLengthAsString(size
));
398 max_addr_len
= std::max(max_addr_len
, getNumLengthAsString(addr
));
401 // Add extra padding.
406 // Setup header format.
407 fmt
<< "%-" << max_name_len
<< "s "
408 << "%" << max_size_len
<< "s "
409 << "%" << max_addr_len
<< "s\n";
412 outs() << format(fmt
.str().c_str(), static_cast<const char *>("section"),
413 static_cast<const char *>("size"),
414 static_cast<const char *>("addr"));
417 // Setup per section format.
418 fmt
<< "%-" << max_name_len
<< "s "
419 << "%#" << max_size_len
<< radix_fmt
<< " "
420 << "%#" << max_addr_len
<< radix_fmt
<< "\n";
422 // Print each section.
423 for (const SectionRef
&Section
: Obj
->sections()) {
424 if (!considerForSize(Obj
, Section
))
427 if (error(Section
.getName(name
)))
429 uint64_t size
= Section
.getSize();
430 uint64_t addr
= Section
.getAddress();
431 std::string namestr
= name
;
433 outs() << format(fmt
.str().c_str(), namestr
.c_str(), size
, addr
);
437 uint64_t CommonSize
= getCommonSize(Obj
);
439 outs() << format(fmt
.str().c_str(), std::string("*COM*").c_str(),
440 CommonSize
, static_cast<uint64_t>(0));
445 fmt
<< "%-" << max_name_len
<< "s "
446 << "%#" << max_size_len
<< radix_fmt
<< "\n";
447 outs() << format(fmt
.str().c_str(), static_cast<const char *>("Total"),
450 // The Berkeley format does not display individual section sizes. It
451 // displays the cumulative size for each section type.
452 uint64_t total_text
= 0;
453 uint64_t total_data
= 0;
454 uint64_t total_bss
= 0;
456 // Make one pass over the section table to calculate sizes.
457 for (const SectionRef
&Section
: Obj
->sections()) {
458 uint64_t size
= Section
.getSize();
459 bool isText
= Section
.isBerkeleyText();
460 bool isData
= Section
.isBerkeleyData();
461 bool isBSS
= Section
.isBSS();
471 total_bss
+= getCommonSize(Obj
);
473 total
= total_text
+ total_data
+ total_bss
;
476 TotalObjectText
+= total_text
;
477 TotalObjectData
+= total_data
;
478 TotalObjectBss
+= total_bss
;
479 TotalObjectTotal
+= total
;
482 if (!BerkeleyHeaderPrinted
) {
487 << (Radix
== octal
? "oct" : "dec")
491 BerkeleyHeaderPrinted
= true;
495 fmt
<< "%#7" << radix_fmt
<< "\t"
496 << "%#7" << radix_fmt
<< "\t"
497 << "%#7" << radix_fmt
<< "\t";
498 outs() << format(fmt
.str().c_str(), total_text
, total_data
, total_bss
);
500 fmt
<< "%7" << (Radix
== octal
? PRIo64
: PRIu64
) << "\t"
502 outs() << format(fmt
.str().c_str(), total
, total
);
506 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
507 /// is a list of architecture flags specified then check to make sure this
508 /// Mach-O file is one of those architectures or all architectures was
509 /// specificed. If not then an error is generated and this routine returns
510 /// false. Else it returns true.
511 static bool checkMachOAndArchFlags(ObjectFile
*O
, StringRef Filename
) {
512 auto *MachO
= dyn_cast
<MachOObjectFile
>(O
);
514 if (!MachO
|| ArchAll
|| ArchFlags
.empty())
517 MachO::mach_header H
;
518 MachO::mach_header_64 H_64
;
520 if (MachO
->is64Bit()) {
521 H_64
= MachO
->MachOObjectFile::getHeader64();
522 T
= MachOObjectFile::getArchTriple(H_64
.cputype
, H_64
.cpusubtype
);
524 H
= MachO
->MachOObjectFile::getHeader();
525 T
= MachOObjectFile::getArchTriple(H
.cputype
, H
.cpusubtype
);
527 if (none_of(ArchFlags
, [&](const std::string
&Name
) {
528 return Name
== T
.getArchName();
530 error(Filename
+ ": No architecture specified");
536 /// Print the section sizes for @p file. If @p file is an archive, print the
537 /// section sizes for each archive member.
538 static void printFileSectionSizes(StringRef file
) {
540 // Attempt to open the binary.
541 Expected
<OwningBinary
<Binary
>> BinaryOrErr
= createBinary(file
);
543 error(BinaryOrErr
.takeError(), file
);
546 Binary
&Bin
= *BinaryOrErr
.get().getBinary();
548 if (Archive
*a
= dyn_cast
<Archive
>(&Bin
)) {
549 // This is an archive. Iterate over each member and display its sizes.
550 Error Err
= Error::success();
551 for (auto &C
: a
->children(Err
)) {
552 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
554 if (auto E
= isNotObjectErrorInvalidFileType(ChildOrErr
.takeError()))
555 error(std::move(E
), a
->getFileName(), C
);
558 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
559 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
560 if (!checkMachOAndArchFlags(o
, file
))
562 if (OutputFormat
== sysv
)
563 outs() << o
->getFileName() << " (ex " << a
->getFileName() << "):\n";
564 else if (MachO
&& OutputFormat
== darwin
)
565 outs() << a
->getFileName() << "(" << o
->getFileName() << "):\n";
566 printObjectSectionSizes(o
);
567 if (OutputFormat
== berkeley
) {
569 outs() << a
->getFileName() << "(" << o
->getFileName() << ")\n";
571 outs() << o
->getFileName() << " (ex " << a
->getFileName() << ")\n";
576 error(std::move(Err
), a
->getFileName());
577 } else if (MachOUniversalBinary
*UB
=
578 dyn_cast
<MachOUniversalBinary
>(&Bin
)) {
579 // If we have a list of architecture flags specified dump only those.
580 if (!ArchAll
&& !ArchFlags
.empty()) {
581 // Look for a slice in the universal binary that matches each ArchFlag.
583 for (unsigned i
= 0; i
< ArchFlags
.size(); ++i
) {
585 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
586 E
= UB
->end_objects();
588 if (ArchFlags
[i
] == I
->getArchFlagName()) {
590 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
592 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
593 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
594 if (OutputFormat
== sysv
)
595 outs() << o
->getFileName() << " :\n";
596 else if (MachO
&& OutputFormat
== darwin
) {
597 if (MoreThanOneFile
|| ArchFlags
.size() > 1)
598 outs() << o
->getFileName() << " (for architecture "
599 << I
->getArchFlagName() << "): \n";
601 printObjectSectionSizes(o
);
602 if (OutputFormat
== berkeley
) {
603 if (!MachO
|| MoreThanOneFile
|| ArchFlags
.size() > 1)
604 outs() << o
->getFileName() << " (for architecture "
605 << I
->getArchFlagName() << ")";
609 } else if (auto E
= isNotObjectErrorInvalidFileType(
611 error(std::move(E
), file
, ArchFlags
.size() > 1 ?
612 StringRef(I
->getArchFlagName()) : StringRef());
614 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
616 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
617 // This is an archive. Iterate over each member and display its
619 Error Err
= Error::success();
620 for (auto &C
: UA
->children(Err
)) {
621 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
623 if (auto E
= isNotObjectErrorInvalidFileType(
624 ChildOrErr
.takeError()))
625 error(std::move(E
), UA
->getFileName(), C
,
626 ArchFlags
.size() > 1 ?
627 StringRef(I
->getArchFlagName()) : StringRef());
630 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
631 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
632 if (OutputFormat
== sysv
)
633 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
635 else if (MachO
&& OutputFormat
== darwin
)
636 outs() << UA
->getFileName() << "(" << o
->getFileName()
638 << " (for architecture " << I
->getArchFlagName()
640 printObjectSectionSizes(o
);
641 if (OutputFormat
== berkeley
) {
643 outs() << UA
->getFileName() << "(" << o
->getFileName()
645 if (ArchFlags
.size() > 1)
646 outs() << " (for architecture " << I
->getArchFlagName()
650 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
656 error(std::move(Err
), UA
->getFileName());
658 consumeError(AOrErr
.takeError());
659 error("Mach-O universal file: " + file
+ " for architecture " +
660 StringRef(I
->getArchFlagName()) +
661 " is not a Mach-O file or an archive file");
666 errs() << ToolName
<< ": file: " << file
667 << " does not contain architecture" << ArchFlags
[i
] << ".\n";
673 // No architecture flags were specified so if this contains a slice that
674 // matches the host architecture dump only that.
676 StringRef HostArchName
= MachOObjectFile::getHostArch().getArchName();
677 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
678 E
= UB
->end_objects();
680 if (HostArchName
== I
->getArchFlagName()) {
681 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
683 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
684 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
685 if (OutputFormat
== sysv
)
686 outs() << o
->getFileName() << " :\n";
687 else if (MachO
&& OutputFormat
== darwin
) {
689 outs() << o
->getFileName() << " (for architecture "
690 << I
->getArchFlagName() << "):\n";
692 printObjectSectionSizes(o
);
693 if (OutputFormat
== berkeley
) {
694 if (!MachO
|| MoreThanOneFile
)
695 outs() << o
->getFileName() << " (for architecture "
696 << I
->getArchFlagName() << ")";
700 } else if (auto E
= isNotObjectErrorInvalidFileType(UO
.takeError())) {
701 error(std::move(E
), file
);
703 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
705 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
706 // This is an archive. Iterate over each member and display its
708 Error Err
= Error::success();
709 for (auto &C
: UA
->children(Err
)) {
710 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
712 if (auto E
= isNotObjectErrorInvalidFileType(
713 ChildOrErr
.takeError()))
714 error(std::move(E
), UA
->getFileName(), C
);
717 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
718 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
719 if (OutputFormat
== sysv
)
720 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
722 else if (MachO
&& OutputFormat
== darwin
)
723 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
724 << " (for architecture " << I
->getArchFlagName()
726 printObjectSectionSizes(o
);
727 if (OutputFormat
== berkeley
) {
729 outs() << UA
->getFileName() << "(" << o
->getFileName()
732 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
738 error(std::move(Err
), UA
->getFileName());
740 consumeError(AOrErr
.takeError());
741 error("Mach-O universal file: " + file
+ " for architecture " +
742 StringRef(I
->getArchFlagName()) +
743 " is not a Mach-O file or an archive file");
749 // Either all architectures have been specified or none have been specified
750 // and this does not contain the host architecture so dump all the slices.
751 bool MoreThanOneArch
= UB
->getNumberOfObjects() > 1;
752 for (MachOUniversalBinary::object_iterator I
= UB
->begin_objects(),
753 E
= UB
->end_objects();
755 Expected
<std::unique_ptr
<ObjectFile
>> UO
= I
->getAsObjectFile();
757 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*UO
.get())) {
758 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
759 if (OutputFormat
== sysv
)
760 outs() << o
->getFileName() << " :\n";
761 else if (MachO
&& OutputFormat
== darwin
) {
762 if (MoreThanOneFile
|| MoreThanOneArch
)
763 outs() << o
->getFileName() << " (for architecture "
764 << I
->getArchFlagName() << "):";
767 printObjectSectionSizes(o
);
768 if (OutputFormat
== berkeley
) {
769 if (!MachO
|| MoreThanOneFile
|| MoreThanOneArch
)
770 outs() << o
->getFileName() << " (for architecture "
771 << I
->getArchFlagName() << ")";
775 } else if (auto E
= isNotObjectErrorInvalidFileType(UO
.takeError())) {
776 error(std::move(E
), file
, MoreThanOneArch
?
777 StringRef(I
->getArchFlagName()) : StringRef());
779 } else if (Expected
<std::unique_ptr
<Archive
>> AOrErr
=
781 std::unique_ptr
<Archive
> &UA
= *AOrErr
;
782 // This is an archive. Iterate over each member and display its sizes.
783 Error Err
= Error::success();
784 for (auto &C
: UA
->children(Err
)) {
785 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= C
.getAsBinary();
787 if (auto E
= isNotObjectErrorInvalidFileType(
788 ChildOrErr
.takeError()))
789 error(std::move(E
), UA
->getFileName(), C
, MoreThanOneArch
?
790 StringRef(I
->getArchFlagName()) : StringRef());
793 if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get())) {
794 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
795 if (OutputFormat
== sysv
)
796 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
798 else if (MachO
&& OutputFormat
== darwin
)
799 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
800 << " (for architecture " << I
->getArchFlagName() << "):\n";
801 printObjectSectionSizes(o
);
802 if (OutputFormat
== berkeley
) {
804 outs() << UA
->getFileName() << "(" << o
->getFileName() << ")"
805 << " (for architecture " << I
->getArchFlagName()
808 outs() << o
->getFileName() << " (ex " << UA
->getFileName()
814 error(std::move(Err
), UA
->getFileName());
816 consumeError(AOrErr
.takeError());
817 error("Mach-O universal file: " + file
+ " for architecture " +
818 StringRef(I
->getArchFlagName()) +
819 " is not a Mach-O file or an archive file");
822 } else if (ObjectFile
*o
= dyn_cast
<ObjectFile
>(&Bin
)) {
823 if (!checkMachOAndArchFlags(o
, file
))
825 MachOObjectFile
*MachO
= dyn_cast
<MachOObjectFile
>(o
);
826 if (OutputFormat
== sysv
)
827 outs() << o
->getFileName() << " :\n";
828 else if (MachO
&& OutputFormat
== darwin
&& MoreThanOneFile
)
829 outs() << o
->getFileName() << ":\n";
830 printObjectSectionSizes(o
);
831 if (OutputFormat
== berkeley
) {
832 if (!MachO
|| MoreThanOneFile
)
833 outs() << o
->getFileName();
837 errs() << ToolName
<< ": " << file
<< ": "
838 << "Unrecognized file type.\n";
840 // System V adds an extra newline at the end of each file.
841 if (OutputFormat
== sysv
)
845 static void printBerkelyTotals() {
847 raw_string_ostream
fmt(fmtbuf
);
848 const char *radix_fmt
= getRadixFmt();
849 fmt
<< "%#7" << radix_fmt
<< "\t"
850 << "%#7" << radix_fmt
<< "\t"
851 << "%#7" << radix_fmt
<< "\t";
852 outs() << format(fmt
.str().c_str(), TotalObjectText
, TotalObjectData
,
855 fmt
<< "%7" << (Radix
== octal
? PRIo64
: PRIu64
) << "\t"
857 outs() << format(fmt
.str().c_str(), TotalObjectTotal
, TotalObjectTotal
)
861 int main(int argc
, char **argv
) {
862 InitLLVM
X(argc
, argv
);
863 cl::ParseCommandLineOptions(argc
, argv
, "llvm object size dumper\n");
866 if (OutputFormatShort
.getNumOccurrences())
867 OutputFormat
= static_cast<OutputFormatTy
>(OutputFormatShort
);
868 if (RadixShort
.getNumOccurrences())
869 Radix
= RadixShort
.getValue();
871 for (StringRef Arch
: ArchFlags
) {
875 if (!MachOObjectFile::isValidArch(Arch
)) {
876 outs() << ToolName
<< ": for the -arch option: Unknown architecture "
877 << "named '" << Arch
<< "'";
883 if (InputFilenames
.empty())
884 InputFilenames
.push_back("a.out");
886 MoreThanOneFile
= InputFilenames
.size() > 1;
887 llvm::for_each(InputFilenames
, printFileSectionSizes
);
888 if (OutputFormat
== berkeley
&& TotalSizes
)
889 printBerkelyTotals();