xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp (revision 62cfcf62f627e5093fb37026a6d8c98e4d2ef04c)
1*62cfcf62SDimitry Andric //===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===//
2*62cfcf62SDimitry Andric //
3*62cfcf62SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*62cfcf62SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*62cfcf62SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*62cfcf62SDimitry Andric //
7*62cfcf62SDimitry Andric //===----------------------------------------------------------------------===//
8*62cfcf62SDimitry Andric //
9*62cfcf62SDimitry Andric // This program is a utility that works like traditional Unix "size",
10*62cfcf62SDimitry Andric // that is, it prints out the size of each section, and the total size of all
11*62cfcf62SDimitry Andric // sections.
12*62cfcf62SDimitry Andric //
13*62cfcf62SDimitry Andric //===----------------------------------------------------------------------===//
14*62cfcf62SDimitry Andric 
15*62cfcf62SDimitry Andric #include "llvm/ADT/APInt.h"
16*62cfcf62SDimitry Andric #include "llvm/Object/Archive.h"
17*62cfcf62SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
18*62cfcf62SDimitry Andric #include "llvm/Object/MachO.h"
19*62cfcf62SDimitry Andric #include "llvm/Object/MachOUniversal.h"
20*62cfcf62SDimitry Andric #include "llvm/Object/ObjectFile.h"
21*62cfcf62SDimitry Andric #include "llvm/Support/Casting.h"
22*62cfcf62SDimitry Andric #include "llvm/Support/CommandLine.h"
23*62cfcf62SDimitry Andric #include "llvm/Support/FileSystem.h"
24*62cfcf62SDimitry Andric #include "llvm/Support/Format.h"
25*62cfcf62SDimitry Andric #include "llvm/Support/InitLLVM.h"
26*62cfcf62SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
27*62cfcf62SDimitry Andric #include "llvm/Support/WithColor.h"
28*62cfcf62SDimitry Andric #include "llvm/Support/raw_ostream.h"
29*62cfcf62SDimitry Andric #include <algorithm>
30*62cfcf62SDimitry Andric #include <string>
31*62cfcf62SDimitry Andric #include <system_error>
32*62cfcf62SDimitry Andric 
33*62cfcf62SDimitry Andric using namespace llvm;
34*62cfcf62SDimitry Andric using namespace object;
35*62cfcf62SDimitry Andric 
36*62cfcf62SDimitry Andric cl::OptionCategory SizeCat("llvm-size Options");
37*62cfcf62SDimitry Andric 
38*62cfcf62SDimitry Andric enum OutputFormatTy { berkeley, sysv, darwin };
39*62cfcf62SDimitry Andric static cl::opt<OutputFormatTy>
40*62cfcf62SDimitry Andric     OutputFormat("format", cl::desc("Specify output format"),
41*62cfcf62SDimitry Andric                  cl::values(clEnumVal(sysv, "System V format"),
42*62cfcf62SDimitry Andric                             clEnumVal(berkeley, "Berkeley format"),
43*62cfcf62SDimitry Andric                             clEnumVal(darwin, "Darwin -m format")),
44*62cfcf62SDimitry Andric                  cl::init(berkeley), cl::cat(SizeCat));
45*62cfcf62SDimitry Andric 
46*62cfcf62SDimitry Andric static cl::opt<OutputFormatTy>
47*62cfcf62SDimitry Andric     OutputFormatShort(cl::desc("Specify output format"),
48*62cfcf62SDimitry Andric                       cl::values(clEnumValN(sysv, "A", "System V format"),
49*62cfcf62SDimitry Andric                                  clEnumValN(berkeley, "B", "Berkeley format"),
50*62cfcf62SDimitry Andric                                  clEnumValN(darwin, "m", "Darwin -m format")),
51*62cfcf62SDimitry Andric                       cl::init(berkeley), cl::cat(SizeCat));
52*62cfcf62SDimitry Andric 
53*62cfcf62SDimitry Andric static bool BerkeleyHeaderPrinted = false;
54*62cfcf62SDimitry Andric static bool MoreThanOneFile = false;
55*62cfcf62SDimitry Andric static uint64_t TotalObjectText = 0;
56*62cfcf62SDimitry Andric static uint64_t TotalObjectData = 0;
57*62cfcf62SDimitry Andric static uint64_t TotalObjectBss = 0;
58*62cfcf62SDimitry Andric static uint64_t TotalObjectTotal = 0;
59*62cfcf62SDimitry Andric 
60*62cfcf62SDimitry Andric cl::opt<bool>
61*62cfcf62SDimitry Andric     DarwinLongFormat("l",
62*62cfcf62SDimitry Andric                      cl::desc("When format is darwin, use long format "
63*62cfcf62SDimitry Andric                               "to include addresses and offsets."),
64*62cfcf62SDimitry Andric                      cl::cat(SizeCat));
65*62cfcf62SDimitry Andric 
66*62cfcf62SDimitry Andric cl::opt<bool>
67*62cfcf62SDimitry Andric     ELFCommons("common",
68*62cfcf62SDimitry Andric                cl::desc("Print common symbols in the ELF file.  When using "
69*62cfcf62SDimitry Andric                         "Berkeley format, this is added to bss."),
70*62cfcf62SDimitry Andric                cl::init(false), cl::cat(SizeCat));
71*62cfcf62SDimitry Andric 
72*62cfcf62SDimitry Andric static cl::list<std::string>
73*62cfcf62SDimitry Andric     ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
74*62cfcf62SDimitry Andric               cl::ZeroOrMore, cl::cat(SizeCat));
75*62cfcf62SDimitry Andric static bool ArchAll = false;
76*62cfcf62SDimitry Andric 
77*62cfcf62SDimitry Andric enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
78*62cfcf62SDimitry Andric static cl::opt<RadixTy> Radix(
79*62cfcf62SDimitry Andric     "radix", cl::desc("Print size in radix"), cl::init(decimal),
80*62cfcf62SDimitry Andric     cl::values(clEnumValN(octal, "8", "Print size in octal"),
81*62cfcf62SDimitry Andric                clEnumValN(decimal, "10", "Print size in decimal"),
82*62cfcf62SDimitry Andric                clEnumValN(hexadecimal, "16", "Print size in hexadecimal")),
83*62cfcf62SDimitry Andric     cl::cat(SizeCat));
84*62cfcf62SDimitry Andric 
85*62cfcf62SDimitry Andric static cl::opt<RadixTy> RadixShort(
86*62cfcf62SDimitry Andric     cl::desc("Print size in radix:"),
87*62cfcf62SDimitry Andric     cl::values(clEnumValN(octal, "o", "Print size in octal"),
88*62cfcf62SDimitry Andric                clEnumValN(decimal, "d", "Print size in decimal"),
89*62cfcf62SDimitry Andric                clEnumValN(hexadecimal, "x", "Print size in hexadecimal")),
90*62cfcf62SDimitry Andric     cl::init(decimal), cl::cat(SizeCat));
91*62cfcf62SDimitry Andric 
92*62cfcf62SDimitry Andric static cl::opt<bool>
93*62cfcf62SDimitry Andric     TotalSizes("totals",
94*62cfcf62SDimitry Andric                cl::desc("Print totals of all objects - Berkeley format only"),
95*62cfcf62SDimitry Andric                cl::init(false), cl::cat(SizeCat));
96*62cfcf62SDimitry Andric 
97*62cfcf62SDimitry Andric static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"),
98*62cfcf62SDimitry Andric                                  cl::aliasopt(TotalSizes));
99*62cfcf62SDimitry Andric 
100*62cfcf62SDimitry Andric static cl::list<std::string>
101*62cfcf62SDimitry Andric     InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
102*62cfcf62SDimitry Andric 
103*62cfcf62SDimitry Andric static cl::extrahelp
104*62cfcf62SDimitry Andric     HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
105*62cfcf62SDimitry Andric 
106*62cfcf62SDimitry Andric static bool HadError = false;
107*62cfcf62SDimitry Andric 
108*62cfcf62SDimitry Andric static std::string ToolName;
109*62cfcf62SDimitry Andric 
110*62cfcf62SDimitry Andric static void error(const Twine &Message, StringRef File) {
111*62cfcf62SDimitry Andric   HadError = true;
112*62cfcf62SDimitry Andric   WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n";
113*62cfcf62SDimitry Andric }
114*62cfcf62SDimitry Andric 
115*62cfcf62SDimitry Andric // This version of error() prints the archive name and member name, for example:
116*62cfcf62SDimitry Andric // "libx.a(foo.o)" after the ToolName before the error message.  It sets
117*62cfcf62SDimitry Andric // HadError but returns allowing the code to move on to other archive members.
118*62cfcf62SDimitry Andric static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
119*62cfcf62SDimitry Andric                   StringRef ArchitectureName = StringRef()) {
120*62cfcf62SDimitry Andric   HadError = true;
121*62cfcf62SDimitry Andric   WithColor::error(errs(), ToolName) << "'" << FileName << "'";
122*62cfcf62SDimitry Andric 
123*62cfcf62SDimitry Andric   Expected<StringRef> NameOrErr = C.getName();
124*62cfcf62SDimitry Andric   // TODO: if we have a error getting the name then it would be nice to print
125*62cfcf62SDimitry Andric   // the index of which archive member this is and or its offset in the
126*62cfcf62SDimitry Andric   // archive instead of "???" as the name.
127*62cfcf62SDimitry Andric   if (!NameOrErr) {
128*62cfcf62SDimitry Andric     consumeError(NameOrErr.takeError());
129*62cfcf62SDimitry Andric     errs() << "(" << "???" << ")";
130*62cfcf62SDimitry Andric   } else
131*62cfcf62SDimitry Andric     errs() << "(" << NameOrErr.get() << ")";
132*62cfcf62SDimitry Andric 
133*62cfcf62SDimitry Andric   if (!ArchitectureName.empty())
134*62cfcf62SDimitry Andric     errs() << " (for architecture " << ArchitectureName << ") ";
135*62cfcf62SDimitry Andric 
136*62cfcf62SDimitry Andric   std::string Buf;
137*62cfcf62SDimitry Andric   raw_string_ostream OS(Buf);
138*62cfcf62SDimitry Andric   logAllUnhandledErrors(std::move(E), OS);
139*62cfcf62SDimitry Andric   OS.flush();
140*62cfcf62SDimitry Andric   errs() << ": " << Buf << "\n";
141*62cfcf62SDimitry Andric }
142*62cfcf62SDimitry Andric 
143*62cfcf62SDimitry Andric // 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*62cfcf62SDimitry Andric // before the error message.  It sets HadError but returns allowing the code to
145*62cfcf62SDimitry Andric // move on to other architecture slices.
146*62cfcf62SDimitry Andric static void error(llvm::Error E, StringRef FileName,
147*62cfcf62SDimitry Andric                   StringRef ArchitectureName = StringRef()) {
148*62cfcf62SDimitry Andric   HadError = true;
149*62cfcf62SDimitry Andric   WithColor::error(errs(), ToolName) << "'" << FileName << "'";
150*62cfcf62SDimitry Andric 
151*62cfcf62SDimitry Andric   if (!ArchitectureName.empty())
152*62cfcf62SDimitry Andric     errs() << " (for architecture " << ArchitectureName << ") ";
153*62cfcf62SDimitry Andric 
154*62cfcf62SDimitry Andric   std::string Buf;
155*62cfcf62SDimitry Andric   raw_string_ostream OS(Buf);
156*62cfcf62SDimitry Andric   logAllUnhandledErrors(std::move(E), OS);
157*62cfcf62SDimitry Andric   OS.flush();
158*62cfcf62SDimitry Andric   errs() << ": " << Buf << "\n";
159*62cfcf62SDimitry Andric }
160*62cfcf62SDimitry Andric 
161*62cfcf62SDimitry Andric /// Get the length of the string that represents @p num in Radix including the
162*62cfcf62SDimitry Andric /// leading 0x or 0 for hexadecimal and octal respectively.
163*62cfcf62SDimitry Andric static size_t getNumLengthAsString(uint64_t num) {
164*62cfcf62SDimitry Andric   APInt conv(64, num);
165*62cfcf62SDimitry Andric   SmallString<32> result;
166*62cfcf62SDimitry Andric   conv.toString(result, Radix, false, true);
167*62cfcf62SDimitry Andric   return result.size();
168*62cfcf62SDimitry Andric }
169*62cfcf62SDimitry Andric 
170*62cfcf62SDimitry Andric /// Return the printing format for the Radix.
171*62cfcf62SDimitry Andric static const char *getRadixFmt() {
172*62cfcf62SDimitry Andric   switch (Radix) {
173*62cfcf62SDimitry Andric   case octal:
174*62cfcf62SDimitry Andric     return PRIo64;
175*62cfcf62SDimitry Andric   case decimal:
176*62cfcf62SDimitry Andric     return PRIu64;
177*62cfcf62SDimitry Andric   case hexadecimal:
178*62cfcf62SDimitry Andric     return PRIx64;
179*62cfcf62SDimitry Andric   }
180*62cfcf62SDimitry Andric   return nullptr;
181*62cfcf62SDimitry Andric }
182*62cfcf62SDimitry Andric 
183*62cfcf62SDimitry Andric /// Remove unneeded ELF sections from calculation
184*62cfcf62SDimitry Andric static bool considerForSize(ObjectFile *Obj, SectionRef Section) {
185*62cfcf62SDimitry Andric   if (!Obj->isELF())
186*62cfcf62SDimitry Andric     return true;
187*62cfcf62SDimitry Andric   switch (static_cast<ELFSectionRef>(Section).getType()) {
188*62cfcf62SDimitry Andric   case ELF::SHT_NULL:
189*62cfcf62SDimitry Andric   case ELF::SHT_SYMTAB:
190*62cfcf62SDimitry Andric   case ELF::SHT_STRTAB:
191*62cfcf62SDimitry Andric   case ELF::SHT_REL:
192*62cfcf62SDimitry Andric   case ELF::SHT_RELA:
193*62cfcf62SDimitry Andric     return false;
194*62cfcf62SDimitry Andric   }
195*62cfcf62SDimitry Andric   return true;
196*62cfcf62SDimitry Andric }
197*62cfcf62SDimitry Andric 
198*62cfcf62SDimitry Andric /// Total size of all ELF common symbols
199*62cfcf62SDimitry Andric static uint64_t getCommonSize(ObjectFile *Obj) {
200*62cfcf62SDimitry Andric   uint64_t TotalCommons = 0;
201*62cfcf62SDimitry Andric   for (auto &Sym : Obj->symbols())
202*62cfcf62SDimitry Andric     if (Obj->getSymbolFlags(Sym.getRawDataRefImpl()) & SymbolRef::SF_Common)
203*62cfcf62SDimitry Andric       TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl());
204*62cfcf62SDimitry Andric   return TotalCommons;
205*62cfcf62SDimitry Andric }
206*62cfcf62SDimitry Andric 
207*62cfcf62SDimitry Andric /// Print the size of each Mach-O segment and section in @p MachO.
208*62cfcf62SDimitry Andric ///
209*62cfcf62SDimitry Andric /// This is when used when @c OutputFormat is darwin and produces the same
210*62cfcf62SDimitry Andric /// output as darwin's size(1) -m output.
211*62cfcf62SDimitry Andric static void printDarwinSectionSizes(MachOObjectFile *MachO) {
212*62cfcf62SDimitry Andric   std::string fmtbuf;
213*62cfcf62SDimitry Andric   raw_string_ostream fmt(fmtbuf);
214*62cfcf62SDimitry Andric   const char *radix_fmt = getRadixFmt();
215*62cfcf62SDimitry Andric   if (Radix == hexadecimal)
216*62cfcf62SDimitry Andric     fmt << "0x";
217*62cfcf62SDimitry Andric   fmt << "%" << radix_fmt;
218*62cfcf62SDimitry Andric 
219*62cfcf62SDimitry Andric   uint32_t Filetype = MachO->getHeader().filetype;
220*62cfcf62SDimitry Andric 
221*62cfcf62SDimitry Andric   uint64_t total = 0;
222*62cfcf62SDimitry Andric   for (const auto &Load : MachO->load_commands()) {
223*62cfcf62SDimitry Andric     if (Load.C.cmd == MachO::LC_SEGMENT_64) {
224*62cfcf62SDimitry Andric       MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
225*62cfcf62SDimitry Andric       outs() << "Segment " << Seg.segname << ": "
226*62cfcf62SDimitry Andric              << format(fmt.str().c_str(), Seg.vmsize);
227*62cfcf62SDimitry Andric       if (DarwinLongFormat)
228*62cfcf62SDimitry Andric         outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
229*62cfcf62SDimitry Andric                << Seg.fileoff << ")";
230*62cfcf62SDimitry Andric       outs() << "\n";
231*62cfcf62SDimitry Andric       total += Seg.vmsize;
232*62cfcf62SDimitry Andric       uint64_t sec_total = 0;
233*62cfcf62SDimitry Andric       for (unsigned J = 0; J < Seg.nsects; ++J) {
234*62cfcf62SDimitry Andric         MachO::section_64 Sec = MachO->getSection64(Load, J);
235*62cfcf62SDimitry Andric         if (Filetype == MachO::MH_OBJECT)
236*62cfcf62SDimitry Andric           outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
237*62cfcf62SDimitry Andric                  << format("%.16s", &Sec.sectname) << "): ";
238*62cfcf62SDimitry Andric         else
239*62cfcf62SDimitry Andric           outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
240*62cfcf62SDimitry Andric         outs() << format(fmt.str().c_str(), Sec.size);
241*62cfcf62SDimitry Andric         if (DarwinLongFormat)
242*62cfcf62SDimitry Andric           outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
243*62cfcf62SDimitry Andric                  << Sec.offset << ")";
244*62cfcf62SDimitry Andric         outs() << "\n";
245*62cfcf62SDimitry Andric         sec_total += Sec.size;
246*62cfcf62SDimitry Andric       }
247*62cfcf62SDimitry Andric       if (Seg.nsects != 0)
248*62cfcf62SDimitry Andric         outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
249*62cfcf62SDimitry Andric     } else if (Load.C.cmd == MachO::LC_SEGMENT) {
250*62cfcf62SDimitry Andric       MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
251*62cfcf62SDimitry Andric       uint64_t Seg_vmsize = Seg.vmsize;
252*62cfcf62SDimitry Andric       outs() << "Segment " << Seg.segname << ": "
253*62cfcf62SDimitry Andric              << format(fmt.str().c_str(), Seg_vmsize);
254*62cfcf62SDimitry Andric       if (DarwinLongFormat)
255*62cfcf62SDimitry Andric         outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff "
256*62cfcf62SDimitry Andric                << Seg.fileoff << ")";
257*62cfcf62SDimitry Andric       outs() << "\n";
258*62cfcf62SDimitry Andric       total += Seg.vmsize;
259*62cfcf62SDimitry Andric       uint64_t sec_total = 0;
260*62cfcf62SDimitry Andric       for (unsigned J = 0; J < Seg.nsects; ++J) {
261*62cfcf62SDimitry Andric         MachO::section Sec = MachO->getSection(Load, J);
262*62cfcf62SDimitry Andric         if (Filetype == MachO::MH_OBJECT)
263*62cfcf62SDimitry Andric           outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
264*62cfcf62SDimitry Andric                  << format("%.16s", &Sec.sectname) << "): ";
265*62cfcf62SDimitry Andric         else
266*62cfcf62SDimitry Andric           outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
267*62cfcf62SDimitry Andric         uint64_t Sec_size = Sec.size;
268*62cfcf62SDimitry Andric         outs() << format(fmt.str().c_str(), Sec_size);
269*62cfcf62SDimitry Andric         if (DarwinLongFormat)
270*62cfcf62SDimitry Andric           outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset "
271*62cfcf62SDimitry Andric                  << Sec.offset << ")";
272*62cfcf62SDimitry Andric         outs() << "\n";
273*62cfcf62SDimitry Andric         sec_total += Sec.size;
274*62cfcf62SDimitry Andric       }
275*62cfcf62SDimitry Andric       if (Seg.nsects != 0)
276*62cfcf62SDimitry Andric         outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
277*62cfcf62SDimitry Andric     }
278*62cfcf62SDimitry Andric   }
279*62cfcf62SDimitry Andric   outs() << "total " << format(fmt.str().c_str(), total) << "\n";
280*62cfcf62SDimitry Andric }
281*62cfcf62SDimitry Andric 
282*62cfcf62SDimitry Andric /// Print the summary sizes of the standard Mach-O segments in @p MachO.
283*62cfcf62SDimitry Andric ///
284*62cfcf62SDimitry Andric /// This is when used when @c OutputFormat is berkeley with a Mach-O file and
285*62cfcf62SDimitry Andric /// produces the same output as darwin's size(1) default output.
286*62cfcf62SDimitry Andric static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
287*62cfcf62SDimitry Andric   uint64_t total_text = 0;
288*62cfcf62SDimitry Andric   uint64_t total_data = 0;
289*62cfcf62SDimitry Andric   uint64_t total_objc = 0;
290*62cfcf62SDimitry Andric   uint64_t total_others = 0;
291*62cfcf62SDimitry Andric   for (const auto &Load : MachO->load_commands()) {
292*62cfcf62SDimitry Andric     if (Load.C.cmd == MachO::LC_SEGMENT_64) {
293*62cfcf62SDimitry Andric       MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
294*62cfcf62SDimitry Andric       if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
295*62cfcf62SDimitry Andric         for (unsigned J = 0; J < Seg.nsects; ++J) {
296*62cfcf62SDimitry Andric           MachO::section_64 Sec = MachO->getSection64(Load, J);
297*62cfcf62SDimitry Andric           StringRef SegmentName = StringRef(Sec.segname);
298*62cfcf62SDimitry Andric           if (SegmentName == "__TEXT")
299*62cfcf62SDimitry Andric             total_text += Sec.size;
300*62cfcf62SDimitry Andric           else if (SegmentName == "__DATA")
301*62cfcf62SDimitry Andric             total_data += Sec.size;
302*62cfcf62SDimitry Andric           else if (SegmentName == "__OBJC")
303*62cfcf62SDimitry Andric             total_objc += Sec.size;
304*62cfcf62SDimitry Andric           else
305*62cfcf62SDimitry Andric             total_others += Sec.size;
306*62cfcf62SDimitry Andric         }
307*62cfcf62SDimitry Andric       } else {
308*62cfcf62SDimitry Andric         StringRef SegmentName = StringRef(Seg.segname);
309*62cfcf62SDimitry Andric         if (SegmentName == "__TEXT")
310*62cfcf62SDimitry Andric           total_text += Seg.vmsize;
311*62cfcf62SDimitry Andric         else if (SegmentName == "__DATA")
312*62cfcf62SDimitry Andric           total_data += Seg.vmsize;
313*62cfcf62SDimitry Andric         else if (SegmentName == "__OBJC")
314*62cfcf62SDimitry Andric           total_objc += Seg.vmsize;
315*62cfcf62SDimitry Andric         else
316*62cfcf62SDimitry Andric           total_others += Seg.vmsize;
317*62cfcf62SDimitry Andric       }
318*62cfcf62SDimitry Andric     } else if (Load.C.cmd == MachO::LC_SEGMENT) {
319*62cfcf62SDimitry Andric       MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
320*62cfcf62SDimitry Andric       if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
321*62cfcf62SDimitry Andric         for (unsigned J = 0; J < Seg.nsects; ++J) {
322*62cfcf62SDimitry Andric           MachO::section Sec = MachO->getSection(Load, J);
323*62cfcf62SDimitry Andric           StringRef SegmentName = StringRef(Sec.segname);
324*62cfcf62SDimitry Andric           if (SegmentName == "__TEXT")
325*62cfcf62SDimitry Andric             total_text += Sec.size;
326*62cfcf62SDimitry Andric           else if (SegmentName == "__DATA")
327*62cfcf62SDimitry Andric             total_data += Sec.size;
328*62cfcf62SDimitry Andric           else if (SegmentName == "__OBJC")
329*62cfcf62SDimitry Andric             total_objc += Sec.size;
330*62cfcf62SDimitry Andric           else
331*62cfcf62SDimitry Andric             total_others += Sec.size;
332*62cfcf62SDimitry Andric         }
333*62cfcf62SDimitry Andric       } else {
334*62cfcf62SDimitry Andric         StringRef SegmentName = StringRef(Seg.segname);
335*62cfcf62SDimitry Andric         if (SegmentName == "__TEXT")
336*62cfcf62SDimitry Andric           total_text += Seg.vmsize;
337*62cfcf62SDimitry Andric         else if (SegmentName == "__DATA")
338*62cfcf62SDimitry Andric           total_data += Seg.vmsize;
339*62cfcf62SDimitry Andric         else if (SegmentName == "__OBJC")
340*62cfcf62SDimitry Andric           total_objc += Seg.vmsize;
341*62cfcf62SDimitry Andric         else
342*62cfcf62SDimitry Andric           total_others += Seg.vmsize;
343*62cfcf62SDimitry Andric       }
344*62cfcf62SDimitry Andric     }
345*62cfcf62SDimitry Andric   }
346*62cfcf62SDimitry Andric   uint64_t total = total_text + total_data + total_objc + total_others;
347*62cfcf62SDimitry Andric 
348*62cfcf62SDimitry Andric   if (!BerkeleyHeaderPrinted) {
349*62cfcf62SDimitry Andric     outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
350*62cfcf62SDimitry Andric     BerkeleyHeaderPrinted = true;
351*62cfcf62SDimitry Andric   }
352*62cfcf62SDimitry Andric   outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
353*62cfcf62SDimitry Andric          << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
354*62cfcf62SDimitry Andric          << "\t";
355*62cfcf62SDimitry Andric }
356*62cfcf62SDimitry Andric 
357*62cfcf62SDimitry Andric /// Print the size of each section in @p Obj.
358*62cfcf62SDimitry Andric ///
359*62cfcf62SDimitry Andric /// The format used is determined by @c OutputFormat and @c Radix.
360*62cfcf62SDimitry Andric static void printObjectSectionSizes(ObjectFile *Obj) {
361*62cfcf62SDimitry Andric   uint64_t total = 0;
362*62cfcf62SDimitry Andric   std::string fmtbuf;
363*62cfcf62SDimitry Andric   raw_string_ostream fmt(fmtbuf);
364*62cfcf62SDimitry Andric   const char *radix_fmt = getRadixFmt();
365*62cfcf62SDimitry Andric 
366*62cfcf62SDimitry Andric   // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
367*62cfcf62SDimitry Andric   // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
368*62cfcf62SDimitry Andric   // let it fall through to OutputFormat berkeley.
369*62cfcf62SDimitry Andric   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
370*62cfcf62SDimitry Andric   if (OutputFormat == darwin && MachO)
371*62cfcf62SDimitry Andric     printDarwinSectionSizes(MachO);
372*62cfcf62SDimitry Andric   // If we have a MachOObjectFile and the OutputFormat is berkeley print as
373*62cfcf62SDimitry Andric   // darwin's default berkeley format for Mach-O files.
374*62cfcf62SDimitry Andric   else if (MachO && OutputFormat == berkeley)
375*62cfcf62SDimitry Andric     printDarwinSegmentSizes(MachO);
376*62cfcf62SDimitry Andric   else if (OutputFormat == sysv) {
377*62cfcf62SDimitry Andric     // Run two passes over all sections. The first gets the lengths needed for
378*62cfcf62SDimitry Andric     // formatting the output. The second actually does the output.
379*62cfcf62SDimitry Andric     std::size_t max_name_len = strlen("section");
380*62cfcf62SDimitry Andric     std::size_t max_size_len = strlen("size");
381*62cfcf62SDimitry Andric     std::size_t max_addr_len = strlen("addr");
382*62cfcf62SDimitry Andric     for (const SectionRef &Section : Obj->sections()) {
383*62cfcf62SDimitry Andric       if (!considerForSize(Obj, Section))
384*62cfcf62SDimitry Andric         continue;
385*62cfcf62SDimitry Andric       uint64_t size = Section.getSize();
386*62cfcf62SDimitry Andric       total += size;
387*62cfcf62SDimitry Andric 
388*62cfcf62SDimitry Andric       Expected<StringRef> name_or_err = Section.getName();
389*62cfcf62SDimitry Andric       if (!name_or_err) {
390*62cfcf62SDimitry Andric         error(name_or_err.takeError(), Obj->getFileName());
391*62cfcf62SDimitry Andric         return;
392*62cfcf62SDimitry Andric       }
393*62cfcf62SDimitry Andric 
394*62cfcf62SDimitry Andric       uint64_t addr = Section.getAddress();
395*62cfcf62SDimitry Andric       max_name_len = std::max(max_name_len, name_or_err->size());
396*62cfcf62SDimitry Andric       max_size_len = std::max(max_size_len, getNumLengthAsString(size));
397*62cfcf62SDimitry Andric       max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
398*62cfcf62SDimitry Andric     }
399*62cfcf62SDimitry Andric 
400*62cfcf62SDimitry Andric     // Add extra padding.
401*62cfcf62SDimitry Andric     max_name_len += 2;
402*62cfcf62SDimitry Andric     max_size_len += 2;
403*62cfcf62SDimitry Andric     max_addr_len += 2;
404*62cfcf62SDimitry Andric 
405*62cfcf62SDimitry Andric     // Setup header format.
406*62cfcf62SDimitry Andric     fmt << "%-" << max_name_len << "s "
407*62cfcf62SDimitry Andric         << "%" << max_size_len << "s "
408*62cfcf62SDimitry Andric         << "%" << max_addr_len << "s\n";
409*62cfcf62SDimitry Andric 
410*62cfcf62SDimitry Andric     // Print header
411*62cfcf62SDimitry Andric     outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
412*62cfcf62SDimitry Andric                      static_cast<const char *>("size"),
413*62cfcf62SDimitry Andric                      static_cast<const char *>("addr"));
414*62cfcf62SDimitry Andric     fmtbuf.clear();
415*62cfcf62SDimitry Andric 
416*62cfcf62SDimitry Andric     // Setup per section format.
417*62cfcf62SDimitry Andric     fmt << "%-" << max_name_len << "s "
418*62cfcf62SDimitry Andric         << "%#" << max_size_len << radix_fmt << " "
419*62cfcf62SDimitry Andric         << "%#" << max_addr_len << radix_fmt << "\n";
420*62cfcf62SDimitry Andric 
421*62cfcf62SDimitry Andric     // Print each section.
422*62cfcf62SDimitry Andric     for (const SectionRef &Section : Obj->sections()) {
423*62cfcf62SDimitry Andric       if (!considerForSize(Obj, Section))
424*62cfcf62SDimitry Andric         continue;
425*62cfcf62SDimitry Andric 
426*62cfcf62SDimitry Andric       Expected<StringRef> name_or_err = Section.getName();
427*62cfcf62SDimitry Andric       if (!name_or_err) {
428*62cfcf62SDimitry Andric         error(name_or_err.takeError(), Obj->getFileName());
429*62cfcf62SDimitry Andric         return;
430*62cfcf62SDimitry Andric       }
431*62cfcf62SDimitry Andric 
432*62cfcf62SDimitry Andric       uint64_t size = Section.getSize();
433*62cfcf62SDimitry Andric       uint64_t addr = Section.getAddress();
434*62cfcf62SDimitry Andric       outs() << format(fmt.str().c_str(), name_or_err->str().c_str(), size, addr);
435*62cfcf62SDimitry Andric     }
436*62cfcf62SDimitry Andric 
437*62cfcf62SDimitry Andric     if (ELFCommons) {
438*62cfcf62SDimitry Andric       uint64_t CommonSize = getCommonSize(Obj);
439*62cfcf62SDimitry Andric       total += CommonSize;
440*62cfcf62SDimitry Andric       outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(),
441*62cfcf62SDimitry Andric                        CommonSize, static_cast<uint64_t>(0));
442*62cfcf62SDimitry Andric     }
443*62cfcf62SDimitry Andric 
444*62cfcf62SDimitry Andric     // Print total.
445*62cfcf62SDimitry Andric     fmtbuf.clear();
446*62cfcf62SDimitry Andric     fmt << "%-" << max_name_len << "s "
447*62cfcf62SDimitry Andric         << "%#" << max_size_len << radix_fmt << "\n";
448*62cfcf62SDimitry Andric     outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
449*62cfcf62SDimitry Andric                      total)
450*62cfcf62SDimitry Andric            << "\n\n";
451*62cfcf62SDimitry Andric   } else {
452*62cfcf62SDimitry Andric     // The Berkeley format does not display individual section sizes. It
453*62cfcf62SDimitry Andric     // displays the cumulative size for each section type.
454*62cfcf62SDimitry Andric     uint64_t total_text = 0;
455*62cfcf62SDimitry Andric     uint64_t total_data = 0;
456*62cfcf62SDimitry Andric     uint64_t total_bss = 0;
457*62cfcf62SDimitry Andric 
458*62cfcf62SDimitry Andric     // Make one pass over the section table to calculate sizes.
459*62cfcf62SDimitry Andric     for (const SectionRef &Section : Obj->sections()) {
460*62cfcf62SDimitry Andric       uint64_t size = Section.getSize();
461*62cfcf62SDimitry Andric       bool isText = Section.isBerkeleyText();
462*62cfcf62SDimitry Andric       bool isData = Section.isBerkeleyData();
463*62cfcf62SDimitry Andric       bool isBSS = Section.isBSS();
464*62cfcf62SDimitry Andric       if (isText)
465*62cfcf62SDimitry Andric         total_text += size;
466*62cfcf62SDimitry Andric       else if (isData)
467*62cfcf62SDimitry Andric         total_data += size;
468*62cfcf62SDimitry Andric       else if (isBSS)
469*62cfcf62SDimitry Andric         total_bss += size;
470*62cfcf62SDimitry Andric     }
471*62cfcf62SDimitry Andric 
472*62cfcf62SDimitry Andric     if (ELFCommons)
473*62cfcf62SDimitry Andric       total_bss += getCommonSize(Obj);
474*62cfcf62SDimitry Andric 
475*62cfcf62SDimitry Andric     total = total_text + total_data + total_bss;
476*62cfcf62SDimitry Andric 
477*62cfcf62SDimitry Andric     if (TotalSizes) {
478*62cfcf62SDimitry Andric       TotalObjectText += total_text;
479*62cfcf62SDimitry Andric       TotalObjectData += total_data;
480*62cfcf62SDimitry Andric       TotalObjectBss += total_bss;
481*62cfcf62SDimitry Andric       TotalObjectTotal += total;
482*62cfcf62SDimitry Andric     }
483*62cfcf62SDimitry Andric 
484*62cfcf62SDimitry Andric     if (!BerkeleyHeaderPrinted) {
485*62cfcf62SDimitry Andric       outs() << "   text\t"
486*62cfcf62SDimitry Andric                 "   data\t"
487*62cfcf62SDimitry Andric                 "    bss\t"
488*62cfcf62SDimitry Andric                 "    "
489*62cfcf62SDimitry Andric              << (Radix == octal ? "oct" : "dec")
490*62cfcf62SDimitry Andric              << "\t"
491*62cfcf62SDimitry Andric                 "    hex\t"
492*62cfcf62SDimitry Andric                 "filename\n";
493*62cfcf62SDimitry Andric       BerkeleyHeaderPrinted = true;
494*62cfcf62SDimitry Andric     }
495*62cfcf62SDimitry Andric 
496*62cfcf62SDimitry Andric     // Print result.
497*62cfcf62SDimitry Andric     fmt << "%#7" << radix_fmt << "\t"
498*62cfcf62SDimitry Andric         << "%#7" << radix_fmt << "\t"
499*62cfcf62SDimitry Andric         << "%#7" << radix_fmt << "\t";
500*62cfcf62SDimitry Andric     outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
501*62cfcf62SDimitry Andric     fmtbuf.clear();
502*62cfcf62SDimitry Andric     fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
503*62cfcf62SDimitry Andric         << "%7" PRIx64 "\t";
504*62cfcf62SDimitry Andric     outs() << format(fmt.str().c_str(), total, total);
505*62cfcf62SDimitry Andric   }
506*62cfcf62SDimitry Andric }
507*62cfcf62SDimitry Andric 
508*62cfcf62SDimitry Andric /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
509*62cfcf62SDimitry Andric /// is a list of architecture flags specified then check to make sure this
510*62cfcf62SDimitry Andric /// Mach-O file is one of those architectures or all architectures was
511*62cfcf62SDimitry Andric /// specificed.  If not then an error is generated and this routine returns
512*62cfcf62SDimitry Andric /// false.  Else it returns true.
513*62cfcf62SDimitry Andric static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
514*62cfcf62SDimitry Andric   auto *MachO = dyn_cast<MachOObjectFile>(O);
515*62cfcf62SDimitry Andric 
516*62cfcf62SDimitry Andric   if (!MachO || ArchAll || ArchFlags.empty())
517*62cfcf62SDimitry Andric     return true;
518*62cfcf62SDimitry Andric 
519*62cfcf62SDimitry Andric   MachO::mach_header H;
520*62cfcf62SDimitry Andric   MachO::mach_header_64 H_64;
521*62cfcf62SDimitry Andric   Triple T;
522*62cfcf62SDimitry Andric   if (MachO->is64Bit()) {
523*62cfcf62SDimitry Andric     H_64 = MachO->MachOObjectFile::getHeader64();
524*62cfcf62SDimitry Andric     T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
525*62cfcf62SDimitry Andric   } else {
526*62cfcf62SDimitry Andric     H = MachO->MachOObjectFile::getHeader();
527*62cfcf62SDimitry Andric     T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
528*62cfcf62SDimitry Andric   }
529*62cfcf62SDimitry Andric   if (none_of(ArchFlags, [&](const std::string &Name) {
530*62cfcf62SDimitry Andric         return Name == T.getArchName();
531*62cfcf62SDimitry Andric       })) {
532*62cfcf62SDimitry Andric     error("no architecture specified", Filename);
533*62cfcf62SDimitry Andric     return false;
534*62cfcf62SDimitry Andric   }
535*62cfcf62SDimitry Andric   return true;
536*62cfcf62SDimitry Andric }
537*62cfcf62SDimitry Andric 
538*62cfcf62SDimitry Andric /// Print the section sizes for @p file. If @p file is an archive, print the
539*62cfcf62SDimitry Andric /// section sizes for each archive member.
540*62cfcf62SDimitry Andric static void printFileSectionSizes(StringRef file) {
541*62cfcf62SDimitry Andric 
542*62cfcf62SDimitry Andric   // Attempt to open the binary.
543*62cfcf62SDimitry Andric   Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
544*62cfcf62SDimitry Andric   if (!BinaryOrErr) {
545*62cfcf62SDimitry Andric     error(BinaryOrErr.takeError(), file);
546*62cfcf62SDimitry Andric     return;
547*62cfcf62SDimitry Andric   }
548*62cfcf62SDimitry Andric   Binary &Bin = *BinaryOrErr.get().getBinary();
549*62cfcf62SDimitry Andric 
550*62cfcf62SDimitry Andric   if (Archive *a = dyn_cast<Archive>(&Bin)) {
551*62cfcf62SDimitry Andric     // This is an archive. Iterate over each member and display its sizes.
552*62cfcf62SDimitry Andric     Error Err = Error::success();
553*62cfcf62SDimitry Andric     for (auto &C : a->children(Err)) {
554*62cfcf62SDimitry Andric       Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
555*62cfcf62SDimitry Andric       if (!ChildOrErr) {
556*62cfcf62SDimitry Andric         if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
557*62cfcf62SDimitry Andric           error(std::move(E), a->getFileName(), C);
558*62cfcf62SDimitry Andric         continue;
559*62cfcf62SDimitry Andric       }
560*62cfcf62SDimitry Andric       if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
561*62cfcf62SDimitry Andric         MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
562*62cfcf62SDimitry Andric         if (!checkMachOAndArchFlags(o, file))
563*62cfcf62SDimitry Andric           return;
564*62cfcf62SDimitry Andric         if (OutputFormat == sysv)
565*62cfcf62SDimitry Andric           outs() << o->getFileName() << "   (ex " << a->getFileName() << "):\n";
566*62cfcf62SDimitry Andric         else if (MachO && OutputFormat == darwin)
567*62cfcf62SDimitry Andric           outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
568*62cfcf62SDimitry Andric         printObjectSectionSizes(o);
569*62cfcf62SDimitry Andric         if (OutputFormat == berkeley) {
570*62cfcf62SDimitry Andric           if (MachO)
571*62cfcf62SDimitry Andric             outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
572*62cfcf62SDimitry Andric           else
573*62cfcf62SDimitry Andric             outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
574*62cfcf62SDimitry Andric         }
575*62cfcf62SDimitry Andric       }
576*62cfcf62SDimitry Andric     }
577*62cfcf62SDimitry Andric     if (Err)
578*62cfcf62SDimitry Andric       error(std::move(Err), a->getFileName());
579*62cfcf62SDimitry Andric   } else if (MachOUniversalBinary *UB =
580*62cfcf62SDimitry Andric                  dyn_cast<MachOUniversalBinary>(&Bin)) {
581*62cfcf62SDimitry Andric     // If we have a list of architecture flags specified dump only those.
582*62cfcf62SDimitry Andric     if (!ArchAll && !ArchFlags.empty()) {
583*62cfcf62SDimitry Andric       // Look for a slice in the universal binary that matches each ArchFlag.
584*62cfcf62SDimitry Andric       bool ArchFound;
585*62cfcf62SDimitry Andric       for (unsigned i = 0; i < ArchFlags.size(); ++i) {
586*62cfcf62SDimitry Andric         ArchFound = false;
587*62cfcf62SDimitry Andric         for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
588*62cfcf62SDimitry Andric                                                    E = UB->end_objects();
589*62cfcf62SDimitry Andric              I != E; ++I) {
590*62cfcf62SDimitry Andric           if (ArchFlags[i] == I->getArchFlagName()) {
591*62cfcf62SDimitry Andric             ArchFound = true;
592*62cfcf62SDimitry Andric             Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
593*62cfcf62SDimitry Andric             if (UO) {
594*62cfcf62SDimitry Andric               if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
595*62cfcf62SDimitry Andric                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
596*62cfcf62SDimitry Andric                 if (OutputFormat == sysv)
597*62cfcf62SDimitry Andric                   outs() << o->getFileName() << "  :\n";
598*62cfcf62SDimitry Andric                 else if (MachO && OutputFormat == darwin) {
599*62cfcf62SDimitry Andric                   if (MoreThanOneFile || ArchFlags.size() > 1)
600*62cfcf62SDimitry Andric                     outs() << o->getFileName() << " (for architecture "
601*62cfcf62SDimitry Andric                            << I->getArchFlagName() << "): \n";
602*62cfcf62SDimitry Andric                 }
603*62cfcf62SDimitry Andric                 printObjectSectionSizes(o);
604*62cfcf62SDimitry Andric                 if (OutputFormat == berkeley) {
605*62cfcf62SDimitry Andric                   if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
606*62cfcf62SDimitry Andric                     outs() << o->getFileName() << " (for architecture "
607*62cfcf62SDimitry Andric                            << I->getArchFlagName() << ")";
608*62cfcf62SDimitry Andric                   outs() << "\n";
609*62cfcf62SDimitry Andric                 }
610*62cfcf62SDimitry Andric               }
611*62cfcf62SDimitry Andric             } else if (auto E = isNotObjectErrorInvalidFileType(
612*62cfcf62SDimitry Andric                        UO.takeError())) {
613*62cfcf62SDimitry Andric               error(std::move(E), file, ArchFlags.size() > 1 ?
614*62cfcf62SDimitry Andric                     StringRef(I->getArchFlagName()) : StringRef());
615*62cfcf62SDimitry Andric               return;
616*62cfcf62SDimitry Andric             } else if (Expected<std::unique_ptr<Archive>> AOrErr =
617*62cfcf62SDimitry Andric                            I->getAsArchive()) {
618*62cfcf62SDimitry Andric               std::unique_ptr<Archive> &UA = *AOrErr;
619*62cfcf62SDimitry Andric               // This is an archive. Iterate over each member and display its
620*62cfcf62SDimitry Andric               // sizes.
621*62cfcf62SDimitry Andric               Error Err = Error::success();
622*62cfcf62SDimitry Andric               for (auto &C : UA->children(Err)) {
623*62cfcf62SDimitry Andric                 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
624*62cfcf62SDimitry Andric                 if (!ChildOrErr) {
625*62cfcf62SDimitry Andric                   if (auto E = isNotObjectErrorInvalidFileType(
626*62cfcf62SDimitry Andric                                     ChildOrErr.takeError()))
627*62cfcf62SDimitry Andric                     error(std::move(E), UA->getFileName(), C,
628*62cfcf62SDimitry Andric                           ArchFlags.size() > 1 ?
629*62cfcf62SDimitry Andric                           StringRef(I->getArchFlagName()) : StringRef());
630*62cfcf62SDimitry Andric                   continue;
631*62cfcf62SDimitry Andric                 }
632*62cfcf62SDimitry Andric                 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
633*62cfcf62SDimitry Andric                   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
634*62cfcf62SDimitry Andric                   if (OutputFormat == sysv)
635*62cfcf62SDimitry Andric                     outs() << o->getFileName() << "   (ex " << UA->getFileName()
636*62cfcf62SDimitry Andric                            << "):\n";
637*62cfcf62SDimitry Andric                   else if (MachO && OutputFormat == darwin)
638*62cfcf62SDimitry Andric                     outs() << UA->getFileName() << "(" << o->getFileName()
639*62cfcf62SDimitry Andric                            << ")"
640*62cfcf62SDimitry Andric                            << " (for architecture " << I->getArchFlagName()
641*62cfcf62SDimitry Andric                            << "):\n";
642*62cfcf62SDimitry Andric                   printObjectSectionSizes(o);
643*62cfcf62SDimitry Andric                   if (OutputFormat == berkeley) {
644*62cfcf62SDimitry Andric                     if (MachO) {
645*62cfcf62SDimitry Andric                       outs() << UA->getFileName() << "(" << o->getFileName()
646*62cfcf62SDimitry Andric                              << ")";
647*62cfcf62SDimitry Andric                       if (ArchFlags.size() > 1)
648*62cfcf62SDimitry Andric                         outs() << " (for architecture " << I->getArchFlagName()
649*62cfcf62SDimitry Andric                                << ")";
650*62cfcf62SDimitry Andric                       outs() << "\n";
651*62cfcf62SDimitry Andric                     } else
652*62cfcf62SDimitry Andric                       outs() << o->getFileName() << " (ex " << UA->getFileName()
653*62cfcf62SDimitry Andric                              << ")\n";
654*62cfcf62SDimitry Andric                   }
655*62cfcf62SDimitry Andric                 }
656*62cfcf62SDimitry Andric               }
657*62cfcf62SDimitry Andric               if (Err)
658*62cfcf62SDimitry Andric                 error(std::move(Err), UA->getFileName());
659*62cfcf62SDimitry Andric             } else {
660*62cfcf62SDimitry Andric               consumeError(AOrErr.takeError());
661*62cfcf62SDimitry Andric               error("mach-o universal file for architecture " +
662*62cfcf62SDimitry Andric                         StringRef(I->getArchFlagName()) +
663*62cfcf62SDimitry Andric                         " is not a mach-o file or an archive file",
664*62cfcf62SDimitry Andric                     file);
665*62cfcf62SDimitry Andric             }
666*62cfcf62SDimitry Andric           }
667*62cfcf62SDimitry Andric         }
668*62cfcf62SDimitry Andric         if (!ArchFound) {
669*62cfcf62SDimitry Andric           error("file does not contain architecture " + ArchFlags[i], file);
670*62cfcf62SDimitry Andric           return;
671*62cfcf62SDimitry Andric         }
672*62cfcf62SDimitry Andric       }
673*62cfcf62SDimitry Andric       return;
674*62cfcf62SDimitry Andric     }
675*62cfcf62SDimitry Andric     // No architecture flags were specified so if this contains a slice that
676*62cfcf62SDimitry Andric     // matches the host architecture dump only that.
677*62cfcf62SDimitry Andric     if (!ArchAll) {
678*62cfcf62SDimitry Andric       StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
679*62cfcf62SDimitry Andric       for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
680*62cfcf62SDimitry Andric                                                  E = UB->end_objects();
681*62cfcf62SDimitry Andric            I != E; ++I) {
682*62cfcf62SDimitry Andric         if (HostArchName == I->getArchFlagName()) {
683*62cfcf62SDimitry Andric           Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
684*62cfcf62SDimitry Andric           if (UO) {
685*62cfcf62SDimitry Andric             if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
686*62cfcf62SDimitry Andric               MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
687*62cfcf62SDimitry Andric               if (OutputFormat == sysv)
688*62cfcf62SDimitry Andric                 outs() << o->getFileName() << "  :\n";
689*62cfcf62SDimitry Andric               else if (MachO && OutputFormat == darwin) {
690*62cfcf62SDimitry Andric                 if (MoreThanOneFile)
691*62cfcf62SDimitry Andric                   outs() << o->getFileName() << " (for architecture "
692*62cfcf62SDimitry Andric                          << I->getArchFlagName() << "):\n";
693*62cfcf62SDimitry Andric               }
694*62cfcf62SDimitry Andric               printObjectSectionSizes(o);
695*62cfcf62SDimitry Andric               if (OutputFormat == berkeley) {
696*62cfcf62SDimitry Andric                 if (!MachO || MoreThanOneFile)
697*62cfcf62SDimitry Andric                   outs() << o->getFileName() << " (for architecture "
698*62cfcf62SDimitry Andric                          << I->getArchFlagName() << ")";
699*62cfcf62SDimitry Andric                 outs() << "\n";
700*62cfcf62SDimitry Andric               }
701*62cfcf62SDimitry Andric             }
702*62cfcf62SDimitry Andric           } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
703*62cfcf62SDimitry Andric             error(std::move(E), file);
704*62cfcf62SDimitry Andric             return;
705*62cfcf62SDimitry Andric           } else if (Expected<std::unique_ptr<Archive>> AOrErr =
706*62cfcf62SDimitry Andric                          I->getAsArchive()) {
707*62cfcf62SDimitry Andric             std::unique_ptr<Archive> &UA = *AOrErr;
708*62cfcf62SDimitry Andric             // This is an archive. Iterate over each member and display its
709*62cfcf62SDimitry Andric             // sizes.
710*62cfcf62SDimitry Andric             Error Err = Error::success();
711*62cfcf62SDimitry Andric             for (auto &C : UA->children(Err)) {
712*62cfcf62SDimitry Andric               Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
713*62cfcf62SDimitry Andric               if (!ChildOrErr) {
714*62cfcf62SDimitry Andric                 if (auto E = isNotObjectErrorInvalidFileType(
715*62cfcf62SDimitry Andric                                 ChildOrErr.takeError()))
716*62cfcf62SDimitry Andric                   error(std::move(E), UA->getFileName(), C);
717*62cfcf62SDimitry Andric                 continue;
718*62cfcf62SDimitry Andric               }
719*62cfcf62SDimitry Andric               if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
720*62cfcf62SDimitry Andric                 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
721*62cfcf62SDimitry Andric                 if (OutputFormat == sysv)
722*62cfcf62SDimitry Andric                   outs() << o->getFileName() << "   (ex " << UA->getFileName()
723*62cfcf62SDimitry Andric                          << "):\n";
724*62cfcf62SDimitry Andric                 else if (MachO && OutputFormat == darwin)
725*62cfcf62SDimitry Andric                   outs() << UA->getFileName() << "(" << o->getFileName() << ")"
726*62cfcf62SDimitry Andric                          << " (for architecture " << I->getArchFlagName()
727*62cfcf62SDimitry Andric                          << "):\n";
728*62cfcf62SDimitry Andric                 printObjectSectionSizes(o);
729*62cfcf62SDimitry Andric                 if (OutputFormat == berkeley) {
730*62cfcf62SDimitry Andric                   if (MachO)
731*62cfcf62SDimitry Andric                     outs() << UA->getFileName() << "(" << o->getFileName()
732*62cfcf62SDimitry Andric                            << ")\n";
733*62cfcf62SDimitry Andric                   else
734*62cfcf62SDimitry Andric                     outs() << o->getFileName() << " (ex " << UA->getFileName()
735*62cfcf62SDimitry Andric                            << ")\n";
736*62cfcf62SDimitry Andric                 }
737*62cfcf62SDimitry Andric               }
738*62cfcf62SDimitry Andric             }
739*62cfcf62SDimitry Andric             if (Err)
740*62cfcf62SDimitry Andric               error(std::move(Err), UA->getFileName());
741*62cfcf62SDimitry Andric           } else {
742*62cfcf62SDimitry Andric             consumeError(AOrErr.takeError());
743*62cfcf62SDimitry Andric             error("mach-o universal file for architecture " +
744*62cfcf62SDimitry Andric                       StringRef(I->getArchFlagName()) +
745*62cfcf62SDimitry Andric                       " is not a mach-o file or an archive file",
746*62cfcf62SDimitry Andric                   file);
747*62cfcf62SDimitry Andric           }
748*62cfcf62SDimitry Andric           return;
749*62cfcf62SDimitry Andric         }
750*62cfcf62SDimitry Andric       }
751*62cfcf62SDimitry Andric     }
752*62cfcf62SDimitry Andric     // Either all architectures have been specified or none have been specified
753*62cfcf62SDimitry Andric     // and this does not contain the host architecture so dump all the slices.
754*62cfcf62SDimitry Andric     bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
755*62cfcf62SDimitry Andric     for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
756*62cfcf62SDimitry Andric                                                E = UB->end_objects();
757*62cfcf62SDimitry Andric          I != E; ++I) {
758*62cfcf62SDimitry Andric       Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
759*62cfcf62SDimitry Andric       if (UO) {
760*62cfcf62SDimitry Andric         if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
761*62cfcf62SDimitry Andric           MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
762*62cfcf62SDimitry Andric           if (OutputFormat == sysv)
763*62cfcf62SDimitry Andric             outs() << o->getFileName() << "  :\n";
764*62cfcf62SDimitry Andric           else if (MachO && OutputFormat == darwin) {
765*62cfcf62SDimitry Andric             if (MoreThanOneFile || MoreThanOneArch)
766*62cfcf62SDimitry Andric               outs() << o->getFileName() << " (for architecture "
767*62cfcf62SDimitry Andric                      << I->getArchFlagName() << "):";
768*62cfcf62SDimitry Andric             outs() << "\n";
769*62cfcf62SDimitry Andric           }
770*62cfcf62SDimitry Andric           printObjectSectionSizes(o);
771*62cfcf62SDimitry Andric           if (OutputFormat == berkeley) {
772*62cfcf62SDimitry Andric             if (!MachO || MoreThanOneFile || MoreThanOneArch)
773*62cfcf62SDimitry Andric               outs() << o->getFileName() << " (for architecture "
774*62cfcf62SDimitry Andric                      << I->getArchFlagName() << ")";
775*62cfcf62SDimitry Andric             outs() << "\n";
776*62cfcf62SDimitry Andric           }
777*62cfcf62SDimitry Andric         }
778*62cfcf62SDimitry Andric       } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
779*62cfcf62SDimitry Andric         error(std::move(E), file, MoreThanOneArch ?
780*62cfcf62SDimitry Andric               StringRef(I->getArchFlagName()) : StringRef());
781*62cfcf62SDimitry Andric         return;
782*62cfcf62SDimitry Andric       } else if (Expected<std::unique_ptr<Archive>> AOrErr =
783*62cfcf62SDimitry Andric                          I->getAsArchive()) {
784*62cfcf62SDimitry Andric         std::unique_ptr<Archive> &UA = *AOrErr;
785*62cfcf62SDimitry Andric         // This is an archive. Iterate over each member and display its sizes.
786*62cfcf62SDimitry Andric         Error Err = Error::success();
787*62cfcf62SDimitry Andric         for (auto &C : UA->children(Err)) {
788*62cfcf62SDimitry Andric           Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
789*62cfcf62SDimitry Andric           if (!ChildOrErr) {
790*62cfcf62SDimitry Andric             if (auto E = isNotObjectErrorInvalidFileType(
791*62cfcf62SDimitry Andric                               ChildOrErr.takeError()))
792*62cfcf62SDimitry Andric               error(std::move(E), UA->getFileName(), C, MoreThanOneArch ?
793*62cfcf62SDimitry Andric                     StringRef(I->getArchFlagName()) : StringRef());
794*62cfcf62SDimitry Andric             continue;
795*62cfcf62SDimitry Andric           }
796*62cfcf62SDimitry Andric           if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
797*62cfcf62SDimitry Andric             MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
798*62cfcf62SDimitry Andric             if (OutputFormat == sysv)
799*62cfcf62SDimitry Andric               outs() << o->getFileName() << "   (ex " << UA->getFileName()
800*62cfcf62SDimitry Andric                      << "):\n";
801*62cfcf62SDimitry Andric             else if (MachO && OutputFormat == darwin)
802*62cfcf62SDimitry Andric               outs() << UA->getFileName() << "(" << o->getFileName() << ")"
803*62cfcf62SDimitry Andric                      << " (for architecture " << I->getArchFlagName() << "):\n";
804*62cfcf62SDimitry Andric             printObjectSectionSizes(o);
805*62cfcf62SDimitry Andric             if (OutputFormat == berkeley) {
806*62cfcf62SDimitry Andric               if (MachO)
807*62cfcf62SDimitry Andric                 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
808*62cfcf62SDimitry Andric                        << " (for architecture " << I->getArchFlagName()
809*62cfcf62SDimitry Andric                        << ")\n";
810*62cfcf62SDimitry Andric               else
811*62cfcf62SDimitry Andric                 outs() << o->getFileName() << " (ex " << UA->getFileName()
812*62cfcf62SDimitry Andric                        << ")\n";
813*62cfcf62SDimitry Andric             }
814*62cfcf62SDimitry Andric           }
815*62cfcf62SDimitry Andric         }
816*62cfcf62SDimitry Andric         if (Err)
817*62cfcf62SDimitry Andric           error(std::move(Err), UA->getFileName());
818*62cfcf62SDimitry Andric       } else {
819*62cfcf62SDimitry Andric         consumeError(AOrErr.takeError());
820*62cfcf62SDimitry Andric         error("mach-o universal file for architecture " +
821*62cfcf62SDimitry Andric                   StringRef(I->getArchFlagName()) +
822*62cfcf62SDimitry Andric                   " is not a mach-o file or an archive file",
823*62cfcf62SDimitry Andric               file);
824*62cfcf62SDimitry Andric       }
825*62cfcf62SDimitry Andric     }
826*62cfcf62SDimitry Andric   } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
827*62cfcf62SDimitry Andric     if (!checkMachOAndArchFlags(o, file))
828*62cfcf62SDimitry Andric       return;
829*62cfcf62SDimitry Andric     MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
830*62cfcf62SDimitry Andric     if (OutputFormat == sysv)
831*62cfcf62SDimitry Andric       outs() << o->getFileName() << "  :\n";
832*62cfcf62SDimitry Andric     else if (MachO && OutputFormat == darwin && MoreThanOneFile)
833*62cfcf62SDimitry Andric       outs() << o->getFileName() << ":\n";
834*62cfcf62SDimitry Andric     printObjectSectionSizes(o);
835*62cfcf62SDimitry Andric     if (OutputFormat == berkeley) {
836*62cfcf62SDimitry Andric       if (!MachO || MoreThanOneFile)
837*62cfcf62SDimitry Andric         outs() << o->getFileName();
838*62cfcf62SDimitry Andric       outs() << "\n";
839*62cfcf62SDimitry Andric     }
840*62cfcf62SDimitry Andric   } else {
841*62cfcf62SDimitry Andric     error("unsupported file type", file);
842*62cfcf62SDimitry Andric   }
843*62cfcf62SDimitry Andric }
844*62cfcf62SDimitry Andric 
845*62cfcf62SDimitry Andric static void printBerkeleyTotals() {
846*62cfcf62SDimitry Andric   std::string fmtbuf;
847*62cfcf62SDimitry Andric   raw_string_ostream fmt(fmtbuf);
848*62cfcf62SDimitry Andric   const char *radix_fmt = getRadixFmt();
849*62cfcf62SDimitry Andric   fmt << "%#7" << radix_fmt << "\t"
850*62cfcf62SDimitry Andric       << "%#7" << radix_fmt << "\t"
851*62cfcf62SDimitry Andric       << "%#7" << radix_fmt << "\t";
852*62cfcf62SDimitry Andric   outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData,
853*62cfcf62SDimitry Andric                    TotalObjectBss);
854*62cfcf62SDimitry Andric   fmtbuf.clear();
855*62cfcf62SDimitry Andric   fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
856*62cfcf62SDimitry Andric       << "%7" PRIx64 "\t";
857*62cfcf62SDimitry Andric   outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal)
858*62cfcf62SDimitry Andric          << "(TOTALS)\n";
859*62cfcf62SDimitry Andric }
860*62cfcf62SDimitry Andric 
861*62cfcf62SDimitry Andric int main(int argc, char **argv) {
862*62cfcf62SDimitry Andric   InitLLVM X(argc, argv);
863*62cfcf62SDimitry Andric   cl::HideUnrelatedOptions(SizeCat);
864*62cfcf62SDimitry Andric   cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
865*62cfcf62SDimitry Andric 
866*62cfcf62SDimitry Andric   ToolName = argv[0];
867*62cfcf62SDimitry Andric   if (OutputFormatShort.getNumOccurrences())
868*62cfcf62SDimitry Andric     OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
869*62cfcf62SDimitry Andric   if (RadixShort.getNumOccurrences())
870*62cfcf62SDimitry Andric     Radix = RadixShort.getValue();
871*62cfcf62SDimitry Andric 
872*62cfcf62SDimitry Andric   for (StringRef Arch : ArchFlags) {
873*62cfcf62SDimitry Andric     if (Arch == "all") {
874*62cfcf62SDimitry Andric       ArchAll = true;
875*62cfcf62SDimitry Andric     } else {
876*62cfcf62SDimitry Andric       if (!MachOObjectFile::isValidArch(Arch)) {
877*62cfcf62SDimitry Andric         outs() << ToolName << ": for the -arch option: Unknown architecture "
878*62cfcf62SDimitry Andric                << "named '" << Arch << "'";
879*62cfcf62SDimitry Andric         return 1;
880*62cfcf62SDimitry Andric       }
881*62cfcf62SDimitry Andric     }
882*62cfcf62SDimitry Andric   }
883*62cfcf62SDimitry Andric 
884*62cfcf62SDimitry Andric   if (InputFilenames.empty())
885*62cfcf62SDimitry Andric     InputFilenames.push_back("a.out");
886*62cfcf62SDimitry Andric 
887*62cfcf62SDimitry Andric   MoreThanOneFile = InputFilenames.size() > 1;
888*62cfcf62SDimitry Andric   llvm::for_each(InputFilenames, printFileSectionSizes);
889*62cfcf62SDimitry Andric   if (OutputFormat == berkeley && TotalSizes)
890*62cfcf62SDimitry Andric     printBerkeleyTotals();
891*62cfcf62SDimitry Andric 
892*62cfcf62SDimitry Andric   if (HadError)
893*62cfcf62SDimitry Andric     return 1;
894*62cfcf62SDimitry Andric }
895