blob: 32d10abe773f293728d4ab30046cabd05129ce2d [file] [log] [blame]
Eugene Zelenkoffec81c2015-11-04 22:32:32 +00001//===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===//
Michael J. Spencerc4ad4662011-09-28 20:57:46 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Michael J. Spencerc4ad4662011-09-28 20:57:46 +00006//
7//===----------------------------------------------------------------------===//
8//
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
11// sections.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/ADT/APInt.h"
16#include "llvm/Object/Archive.h"
Rafael Espindolaa0ff5562016-02-09 21:39:49 +000017#include "llvm/Object/ELFObjectFile.h"
Kevin Enderby246a4602014-06-17 17:54:13 +000018#include "llvm/Object/MachO.h"
Kevin Enderby4b8fc282014-06-18 22:04:40 +000019#include "llvm/Object/MachOUniversal.h"
Chandler Carruthd9903882015-01-14 11:23:27 +000020#include "llvm/Object/ObjectFile.h"
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000021#include "llvm/Support/Casting.h"
22#include "llvm/Support/CommandLine.h"
23#include "llvm/Support/FileSystem.h"
24#include "llvm/Support/Format.h"
Rui Ueyama197194b2018-04-13 18:26:06 +000025#include "llvm/Support/InitLLVM.h"
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000026#include "llvm/Support/MemoryBuffer.h"
Chandler Carruth4d88a1c2012-12-04 10:44:52 +000027#include "llvm/Support/raw_ostream.h"
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000028#include <algorithm>
29#include <string>
Rafael Espindolaa6e9c3e2014-06-12 17:38:55 +000030#include <system_error>
Eugene Zelenkoffec81c2015-11-04 22:32:32 +000031
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000032using namespace llvm;
33using namespace object;
34
Kevin Enderby10769742014-07-01 22:26:31 +000035enum OutputFormatTy { berkeley, sysv, darwin };
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000036static cl::opt<OutputFormatTy>
Kevin Enderby10769742014-07-01 22:26:31 +000037OutputFormat("format", cl::desc("Specify output format"),
38 cl::values(clEnumVal(sysv, "System V format"),
39 clEnumVal(berkeley, "Berkeley format"),
Mehdi Amini732afdd2016-10-08 19:41:06 +000040 clEnumVal(darwin, "Darwin -m format")),
Kevin Enderby10769742014-07-01 22:26:31 +000041 cl::init(berkeley));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000042
Kevin Enderby10769742014-07-01 22:26:31 +000043static 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"),
Mehdi Amini732afdd2016-10-08 19:41:06 +000047 clEnumValN(darwin, "m", "Darwin -m format")),
Kevin Enderby10769742014-07-01 22:26:31 +000048 cl::init(berkeley));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000049
Rafael Espindola1dc30a42016-02-09 21:35:14 +000050static bool BerkeleyHeaderPrinted = false;
51static bool MoreThanOneFile = false;
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +000052static uint64_t TotalObjectText = 0;
53static uint64_t TotalObjectData = 0;
54static uint64_t TotalObjectBss = 0;
55static uint64_t TotalObjectTotal = 0;
Kevin Enderby246a4602014-06-17 17:54:13 +000056
Kevin Enderby10769742014-07-01 22:26:31 +000057cl::opt<bool>
58DarwinLongFormat("l", cl::desc("When format is darwin, use long format "
59 "to include addresses and offsets."));
Kevin Enderby246a4602014-06-17 17:54:13 +000060
Hemant Kulkarni274457e2016-03-28 16:48:10 +000061cl::opt<bool>
62 ELFCommons("common",
63 cl::desc("Print common symbols in the ELF file. When using "
64 "Berkely format, this is added to bss."),
65 cl::init(false));
66
Kevin Enderbyafef4c92014-07-01 17:19:10 +000067static cl::list<std::string>
Kevin Enderby10769742014-07-01 22:26:31 +000068ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
69 cl::ZeroOrMore);
Fangrui Song1e2d5cb2018-06-22 22:20:10 +000070static bool ArchAll = false;
Kevin Enderbyafef4c92014-07-01 17:19:10 +000071
Kevin Enderby10769742014-07-01 22:26:31 +000072enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
James Hendersonb3735ee2018-10-30 11:52:47 +000073static 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")));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000078
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000079static cl::opt<RadixTy>
Kevin Enderby10769742014-07-01 22:26:31 +000080RadixShort(cl::desc("Print size in radix:"),
81 cl::values(clEnumValN(octal, "o", "Print size in octal"),
82 clEnumValN(decimal, "d", "Print size in decimal"),
Mehdi Amini732afdd2016-10-08 19:41:06 +000083 clEnumValN(hexadecimal, "x", "Print size in hexadecimal")),
Kevin Enderby10769742014-07-01 22:26:31 +000084 cl::init(decimal));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000085
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +000086static cl::opt<bool>
87 TotalSizes("totals",
88 cl::desc("Print totals of all objects - Berkeley format only"),
89 cl::init(false));
90
91static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"),
92 cl::aliasopt(TotalSizes));
93
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000094static cl::list<std::string>
Kevin Enderby10769742014-07-01 22:26:31 +000095InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000096
Fangrui Song1e2d5cb2018-06-22 22:20:10 +000097static bool HadError = false;
Kevin Enderby64f7a992016-05-02 21:41:03 +000098
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000099static std::string ToolName;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000100
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000101/// If ec is not success, print the error and return true.
Rafael Espindola4453e42942014-06-13 03:07:50 +0000102static bool error(std::error_code ec) {
Kevin Enderby10769742014-07-01 22:26:31 +0000103 if (!ec)
104 return false;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000105
Kevin Enderby64f7a992016-05-02 21:41:03 +0000106 HadError = true;
Davide Italiano911eb312016-01-25 01:24:15 +0000107 errs() << ToolName << ": error reading file: " << ec.message() << ".\n";
108 errs().flush();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000109 return true;
110}
111
Kevin Enderby42398052016-06-28 23:16:13 +0000112static bool error(Twine Message) {
113 HadError = true;
114 errs() << ToolName << ": " << Message << ".\n";
115 errs().flush();
116 return true;
117}
118
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000119// 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
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000121// HadError but returns allowing the code to move on to other archive members.
Kevin Enderby9acb1092016-05-31 20:35:34 +0000122static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
123 StringRef ArchitectureName = StringRef()) {
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000124 HadError = true;
125 errs() << ToolName << ": " << FileName;
126
Kevin Enderbyf4586032016-07-29 17:44:13 +0000127 Expected<StringRef> NameOrErr = C.getName();
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000128 // 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.
Kevin Enderbyf4586032016-07-29 17:44:13 +0000131 if (!NameOrErr) {
132 consumeError(NameOrErr.takeError());
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000133 errs() << "(" << "???" << ")";
Kevin Enderbyf4586032016-07-29 17:44:13 +0000134 } else
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000135 errs() << "(" << NameOrErr.get() << ")";
136
Kevin Enderby9acb1092016-05-31 20:35:34 +0000137 if (!ArchitectureName.empty())
138 errs() << " (for architecture " << ArchitectureName << ") ";
139
140 std::string Buf;
141 raw_string_ostream OS(Buf);
Jonas Devlieghere45eb84f2018-11-11 01:46:03 +0000142 logAllUnhandledErrors(std::move(E), OS);
Kevin Enderby9acb1092016-05-31 20:35:34 +0000143 OS.flush();
144 errs() << " " << Buf << "\n";
145}
146
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
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000149// move on to other architecture slices.
Kevin Enderby9acb1092016-05-31 20:35:34 +0000150static void error(llvm::Error E, StringRef FileName,
151 StringRef ArchitectureName = StringRef()) {
152 HadError = true;
153 errs() << ToolName << ": " << FileName;
154
155 if (!ArchitectureName.empty())
156 errs() << " (for architecture " << ArchitectureName << ") ";
157
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000158 std::string Buf;
159 raw_string_ostream OS(Buf);
Jonas Devlieghere45eb84f2018-11-11 01:46:03 +0000160 logAllUnhandledErrors(std::move(E), OS);
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000161 OS.flush();
162 errs() << " " << Buf << "\n";
163}
164
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000165/// Get the length of the string that represents @p num in Radix including the
166/// leading 0x or 0 for hexadecimal and octal respectively.
Andrew Trick7dc278d2011-09-29 01:22:31 +0000167static size_t getNumLengthAsString(uint64_t num) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000168 APInt conv(64, num);
169 SmallString<32> result;
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000170 conv.toString(result, Radix, false, true);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000171 return result.size();
172}
173
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000174/// Return the printing format for the Radix.
Eugene Zelenkoffec81c2015-11-04 22:32:32 +0000175static const char *getRadixFmt() {
Kevin Enderby246a4602014-06-17 17:54:13 +0000176 switch (Radix) {
177 case octal:
178 return PRIo64;
179 case decimal:
180 return PRIu64;
181 case hexadecimal:
182 return PRIx64;
183 }
184 return nullptr;
185}
186
Rafael Espindolaa0ff5562016-02-09 21:39:49 +0000187/// Remove unneeded ELF sections from calculation
188static bool considerForSize(ObjectFile *Obj, SectionRef Section) {
189 if (!Obj->isELF())
190 return true;
191 switch (static_cast<ELFSectionRef>(Section).getType()) {
192 case ELF::SHT_NULL:
193 case ELF::SHT_SYMTAB:
194 case ELF::SHT_STRTAB:
195 case ELF::SHT_REL:
196 case ELF::SHT_RELA:
197 return false;
198 }
199 return true;
200}
201
Hemant Kulkarni274457e2016-03-28 16:48:10 +0000202/// Total size of all ELF common symbols
203static 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());
208 return TotalCommons;
209}
210
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000211/// Print the size of each Mach-O segment and section in @p MachO.
Kevin Enderby246a4602014-06-17 17:54:13 +0000212///
213/// This is when used when @c OutputFormat is darwin and produces the same
214/// output as darwin's size(1) -m output.
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000215static void printDarwinSectionSizes(MachOObjectFile *MachO) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000216 std::string fmtbuf;
217 raw_string_ostream fmt(fmtbuf);
218 const char *radix_fmt = getRadixFmt();
219 if (Radix == hexadecimal)
220 fmt << "0x";
221 fmt << "%" << radix_fmt;
222
Kevin Enderby246a4602014-06-17 17:54:13 +0000223 uint32_t Filetype = MachO->getHeader().filetype;
Kevin Enderby246a4602014-06-17 17:54:13 +0000224
225 uint64_t total = 0;
Alexey Samsonovd319c4f2015-06-03 22:19:36 +0000226 for (const auto &Load : MachO->load_commands()) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000227 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)
Kevin Enderby10769742014-07-01 22:26:31 +0000232 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
233 << Seg.fileoff << ")";
Kevin Enderby246a4602014-06-17 17:54:13 +0000234 outs() << "\n";
235 total += Seg.vmsize;
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) << "): ";
242 else
243 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
244 outs() << format(fmt.str().c_str(), Sec.size);
245 if (DarwinLongFormat)
Kevin Enderby10769742014-07-01 22:26:31 +0000246 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
247 << Sec.offset << ")";
Kevin Enderby246a4602014-06-17 17:54:13 +0000248 outs() << "\n";
249 sec_total += Sec.size;
250 }
251 if (Seg.nsects != 0)
252 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000253 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000254 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
Kevin Enderby2058e9d2016-02-09 18:33:15 +0000255 uint64_t Seg_vmsize = Seg.vmsize;
Kevin Enderby246a4602014-06-17 17:54:13 +0000256 outs() << "Segment " << Seg.segname << ": "
Kevin Enderby2058e9d2016-02-09 18:33:15 +0000257 << format(fmt.str().c_str(), Seg_vmsize);
Kevin Enderby246a4602014-06-17 17:54:13 +0000258 if (DarwinLongFormat)
Kevin Enderby2058e9d2016-02-09 18:33:15 +0000259 outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff "
Kevin Enderby10769742014-07-01 22:26:31 +0000260 << Seg.fileoff << ")";
Kevin Enderby246a4602014-06-17 17:54:13 +0000261 outs() << "\n";
262 total += Seg.vmsize;
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) << "): ";
269 else
270 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
Kevin Enderby2058e9d2016-02-09 18:33:15 +0000271 uint64_t Sec_size = Sec.size;
272 outs() << format(fmt.str().c_str(), Sec_size);
Kevin Enderby246a4602014-06-17 17:54:13 +0000273 if (DarwinLongFormat)
Kevin Enderby2058e9d2016-02-09 18:33:15 +0000274 outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset "
Kevin Enderby10769742014-07-01 22:26:31 +0000275 << Sec.offset << ")";
Kevin Enderby246a4602014-06-17 17:54:13 +0000276 outs() << "\n";
277 sec_total += Sec.size;
278 }
279 if (Seg.nsects != 0)
280 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
281 }
Kevin Enderby246a4602014-06-17 17:54:13 +0000282 }
283 outs() << "total " << format(fmt.str().c_str(), total) << "\n";
284}
285
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000286/// Print the summary sizes of the standard Mach-O segments in @p MachO.
Kevin Enderby246a4602014-06-17 17:54:13 +0000287///
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.
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000290static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000291 uint64_t total_text = 0;
292 uint64_t total_data = 0;
293 uint64_t total_objc = 0;
294 uint64_t total_others = 0;
Alexey Samsonovd319c4f2015-06-03 22:19:36 +0000295 for (const auto &Load : MachO->load_commands()) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000296 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;
308 else
309 total_others += Sec.size;
Kevin Enderby10769742014-07-01 22:26:31 +0000310 }
Kevin Enderby246a4602014-06-17 17:54:13 +0000311 } else {
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;
319 else
320 total_others += Seg.vmsize;
321 }
Kevin Enderby10769742014-07-01 22:26:31 +0000322 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000323 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;
334 else
335 total_others += Sec.size;
Kevin Enderby10769742014-07-01 22:26:31 +0000336 }
Kevin Enderby246a4602014-06-17 17:54:13 +0000337 } else {
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;
345 else
346 total_others += Seg.vmsize;
347 }
348 }
Kevin Enderby246a4602014-06-17 17:54:13 +0000349 }
350 uint64_t total = total_text + total_data + total_objc + total_others;
351
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000352 if (!BerkeleyHeaderPrinted) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000353 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000354 BerkeleyHeaderPrinted = true;
Kevin Enderby246a4602014-06-17 17:54:13 +0000355 }
356 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
357 << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
358 << "\t";
359}
360
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000361/// Print the size of each section in @p Obj.
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000362///
363/// The format used is determined by @c OutputFormat and @c Radix.
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000364static void printObjectSectionSizes(ObjectFile *Obj) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000365 uint64_t total = 0;
366 std::string fmtbuf;
367 raw_string_ostream fmt(fmtbuf);
Kevin Enderby246a4602014-06-17 17:54:13 +0000368 const char *radix_fmt = getRadixFmt();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000369
Kevin Enderby246a4602014-06-17 17:54:13 +0000370 // 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)
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000375 printDarwinSectionSizes(MachO);
Kevin Enderby246a4602014-06-17 17:54:13 +0000376 // 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)
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000379 printDarwinSegmentSizes(MachO);
Kevin Enderby246a4602014-06-17 17:54:13 +0000380 else if (OutputFormat == sysv) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000381 // 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");
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000384 std::size_t max_size_len = strlen("size");
385 std::size_t max_addr_len = strlen("addr");
Alexey Samsonov48803e52014-03-13 14:37:36 +0000386 for (const SectionRef &Section : Obj->sections()) {
Rafael Espindolaa0ff5562016-02-09 21:39:49 +0000387 if (!considerForSize(Obj, Section))
388 continue;
Rafael Espindola80291272014-10-08 15:28:58 +0000389 uint64_t size = Section.getSize();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000390 total += size;
391
392 StringRef name;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000393 if (error(Section.getName(name)))
394 return;
Rafael Espindola80291272014-10-08 15:28:58 +0000395 uint64_t addr = Section.getAddress();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000396 max_name_len = std::max(max_name_len, name.size());
Andrew Trick7dc278d2011-09-29 01:22:31 +0000397 max_size_len = std::max(max_size_len, getNumLengthAsString(size));
398 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000399 }
400
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000401 // Add extra padding.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000402 max_name_len += 2;
403 max_size_len += 2;
404 max_addr_len += 2;
405
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000406 // Setup header format.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000407 fmt << "%-" << max_name_len << "s "
408 << "%" << max_size_len << "s "
409 << "%" << max_addr_len << "s\n";
410
411 // Print header
Kevin Enderby10769742014-07-01 22:26:31 +0000412 outs() << format(fmt.str().c_str(), static_cast<const char *>("section"),
413 static_cast<const char *>("size"),
414 static_cast<const char *>("addr"));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000415 fmtbuf.clear();
416
417 // Setup per section format.
418 fmt << "%-" << max_name_len << "s "
419 << "%#" << max_size_len << radix_fmt << " "
420 << "%#" << max_addr_len << radix_fmt << "\n";
421
422 // Print each section.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000423 for (const SectionRef &Section : Obj->sections()) {
Rafael Espindolaa0ff5562016-02-09 21:39:49 +0000424 if (!considerForSize(Obj, Section))
425 continue;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000426 StringRef name;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000427 if (error(Section.getName(name)))
428 return;
Rafael Espindola80291272014-10-08 15:28:58 +0000429 uint64_t size = Section.getSize();
430 uint64_t addr = Section.getAddress();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000431 std::string namestr = name;
432
Alexey Samsonov48803e52014-03-13 14:37:36 +0000433 outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000434 }
435
Hemant Kulkarni274457e2016-03-28 16:48:10 +0000436 if (ELFCommons) {
437 uint64_t CommonSize = getCommonSize(Obj);
438 total += CommonSize;
439 outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(),
440 CommonSize, static_cast<uint64_t>(0));
441 }
442
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000443 // Print total.
444 fmtbuf.clear();
445 fmt << "%-" << max_name_len << "s "
446 << "%#" << max_size_len << radix_fmt << "\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000447 outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"),
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000448 total);
449 } else {
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000450 // The Berkeley format does not display individual section sizes. It
451 // displays the cumulative size for each section type.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000452 uint64_t total_text = 0;
453 uint64_t total_data = 0;
454 uint64_t total_bss = 0;
455
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000456 // Make one pass over the section table to calculate sizes.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000457 for (const SectionRef &Section : Obj->sections()) {
Rafael Espindola80291272014-10-08 15:28:58 +0000458 uint64_t size = Section.getSize();
Jordan Rupprecht4888c4a2018-12-13 19:40:12 +0000459 bool isText = Section.isBerkeleyText();
460 bool isData = Section.isBerkeleyData();
Rafael Espindola80291272014-10-08 15:28:58 +0000461 bool isBSS = Section.isBSS();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000462 if (isText)
463 total_text += size;
464 else if (isData)
465 total_data += size;
466 else if (isBSS)
467 total_bss += size;
468 }
469
Hemant Kulkarni274457e2016-03-28 16:48:10 +0000470 if (ELFCommons)
471 total_bss += getCommonSize(Obj);
472
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000473 total = total_text + total_data + total_bss;
474
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000475 if (TotalSizes) {
476 TotalObjectText += total_text;
477 TotalObjectData += total_data;
478 TotalObjectBss += total_bss;
479 TotalObjectTotal += total;
480 }
481
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000482 if (!BerkeleyHeaderPrinted) {
Jordan Rupprecht8d60f9b2018-09-21 23:48:12 +0000483 outs() << " text\t"
484 " data\t"
485 " bss\t"
486 " "
487 << (Radix == octal ? "oct" : "dec")
488 << "\t"
489 " hex\t"
490 "filename\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000491 BerkeleyHeaderPrinted = true;
Kevin Enderby246a4602014-06-17 17:54:13 +0000492 }
493
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000494 // Print result.
Jordan Rupprecht8d60f9b2018-09-21 23:48:12 +0000495 fmt << "%#7" << radix_fmt << "\t"
496 << "%#7" << radix_fmt << "\t"
497 << "%#7" << radix_fmt << "\t";
Kevin Enderby10769742014-07-01 22:26:31 +0000498 outs() << format(fmt.str().c_str(), total_text, total_data, total_bss);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000499 fmtbuf.clear();
Jordan Rupprecht8d60f9b2018-09-21 23:48:12 +0000500 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
501 << "%7" PRIx64 "\t";
Kevin Enderby10769742014-07-01 22:26:31 +0000502 outs() << format(fmt.str().c_str(), total, total);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000503 }
504}
505
David Majnemer91160d82016-10-31 17:11:31 +0000506/// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000507/// 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.
David Majnemer91160d82016-10-31 17:11:31 +0000511static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
512 auto *MachO = dyn_cast<MachOObjectFile>(O);
513
514 if (!MachO || ArchAll || ArchFlags.empty())
515 return true;
516
517 MachO::mach_header H;
518 MachO::mach_header_64 H_64;
519 Triple T;
520 if (MachO->is64Bit()) {
521 H_64 = MachO->MachOObjectFile::getHeader64();
522 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
523 } else {
524 H = MachO->MachOObjectFile::getHeader();
525 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
526 }
527 if (none_of(ArchFlags, [&](const std::string &Name) {
528 return Name == T.getArchName();
529 })) {
530 error(Filename + ": No architecture specified");
531 return false;
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000532 }
533 return true;
534}
535
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000536/// Print the section sizes for @p file. If @p file is an archive, print the
537/// section sizes for each archive member.
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000538static void printFileSectionSizes(StringRef file) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000539
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000540 // Attempt to open the binary.
Kevin Enderby3fcdf6a2016-04-06 22:14:09 +0000541 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
542 if (!BinaryOrErr) {
Kevin Enderby600fb3f2016-08-05 18:19:40 +0000543 error(BinaryOrErr.takeError(), file);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000544 return;
Kevin Enderby3fcdf6a2016-04-06 22:14:09 +0000545 }
Rafael Espindola48af1c22014-08-19 18:44:46 +0000546 Binary &Bin = *BinaryOrErr.get().getBinary();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000547
Rafael Espindola3f6481d2014-08-01 14:31:55 +0000548 if (Archive *a = dyn_cast<Archive>(&Bin)) {
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000549 // This is an archive. Iterate over each member and display its sizes.
Mehdi Amini41af4302016-11-11 04:28:40 +0000550 Error Err = Error::success();
Lang Hamesfc209622016-07-14 02:24:01 +0000551 for (auto &C : a->children(Err)) {
552 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000553 if (!ChildOrErr) {
554 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
Lang Hamesfc209622016-07-14 02:24:01 +0000555 error(std::move(E), a->getFileName(), C);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000556 continue;
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000557 }
Rafael Espindolaae460022014-06-16 16:08:36 +0000558 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000559 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000560 if (!checkMachOAndArchFlags(o, file))
561 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000562 if (OutputFormat == sysv)
Kevin Enderby10769742014-07-01 22:26:31 +0000563 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n";
564 else if (MachO && OutputFormat == darwin)
565 outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000566 printObjectSectionSizes(o);
Kevin Enderby246a4602014-06-17 17:54:13 +0000567 if (OutputFormat == berkeley) {
568 if (MachO)
569 outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
570 else
571 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
572 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000573 }
574 }
Lang Hamesfc209622016-07-14 02:24:01 +0000575 if (Err)
576 error(std::move(Err), a->getFileName());
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000577 } else if (MachOUniversalBinary *UB =
Rafael Espindola3f6481d2014-08-01 14:31:55 +0000578 dyn_cast<MachOUniversalBinary>(&Bin)) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000579 // If we have a list of architecture flags specified dump only those.
Jordan Rupprecht16a0de22018-12-20 00:57:06 +0000580 if (!ArchAll && !ArchFlags.empty()) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000581 // Look for a slice in the universal binary that matches each ArchFlag.
582 bool ArchFound;
Kevin Enderby10769742014-07-01 22:26:31 +0000583 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000584 ArchFound = false;
585 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
586 E = UB->end_objects();
587 I != E; ++I) {
Kevin Enderby59343a92016-12-16 22:54:02 +0000588 if (ArchFlags[i] == I->getArchFlagName()) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000589 ArchFound = true;
Kevin Enderby9acb1092016-05-31 20:35:34 +0000590 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000591 if (UO) {
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";
Kevin Enderby10769742014-07-01 22:26:31 +0000596 else if (MachO && OutputFormat == darwin) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000597 if (MoreThanOneFile || ArchFlags.size() > 1)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000598 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000599 << I->getArchFlagName() << "): \n";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000600 }
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000601 printObjectSectionSizes(o);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000602 if (OutputFormat == berkeley) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000603 if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000604 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000605 << I->getArchFlagName() << ")";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000606 outs() << "\n";
607 }
608 }
Kevin Enderby9acb1092016-05-31 20:35:34 +0000609 } else if (auto E = isNotObjectErrorInvalidFileType(
610 UO.takeError())) {
611 error(std::move(E), file, ArchFlags.size() > 1 ?
Kevin Enderby59343a92016-12-16 22:54:02 +0000612 StringRef(I->getArchFlagName()) : StringRef());
Kevin Enderby9acb1092016-05-31 20:35:34 +0000613 return;
Kevin Enderby42398052016-06-28 23:16:13 +0000614 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
Rafael Espindola0bfe8282014-12-09 21:05:36 +0000615 I->getAsArchive()) {
616 std::unique_ptr<Archive> &UA = *AOrErr;
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000617 // This is an archive. Iterate over each member and display its
Kevin Enderby10769742014-07-01 22:26:31 +0000618 // sizes.
Mehdi Amini41af4302016-11-11 04:28:40 +0000619 Error Err = Error::success();
Lang Hamesfc209622016-07-14 02:24:01 +0000620 for (auto &C : UA->children(Err)) {
621 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000622 if (!ChildOrErr) {
Kevin Enderby9acb1092016-05-31 20:35:34 +0000623 if (auto E = isNotObjectErrorInvalidFileType(
624 ChildOrErr.takeError()))
Lang Hamesfc209622016-07-14 02:24:01 +0000625 error(std::move(E), UA->getFileName(), C,
Kevin Enderby9acb1092016-05-31 20:35:34 +0000626 ArchFlags.size() > 1 ?
Kevin Enderby59343a92016-12-16 22:54:02 +0000627 StringRef(I->getArchFlagName()) : StringRef());
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000628 continue;
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000629 }
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000630 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()
634 << "):\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000635 else if (MachO && OutputFormat == darwin)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000636 outs() << UA->getFileName() << "(" << o->getFileName()
Kevin Enderby10769742014-07-01 22:26:31 +0000637 << ")"
Kevin Enderby59343a92016-12-16 22:54:02 +0000638 << " (for architecture " << I->getArchFlagName()
Kevin Enderby10769742014-07-01 22:26:31 +0000639 << "):\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000640 printObjectSectionSizes(o);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000641 if (OutputFormat == berkeley) {
642 if (MachO) {
643 outs() << UA->getFileName() << "(" << o->getFileName()
644 << ")";
645 if (ArchFlags.size() > 1)
Kevin Enderby59343a92016-12-16 22:54:02 +0000646 outs() << " (for architecture " << I->getArchFlagName()
Kevin Enderby10769742014-07-01 22:26:31 +0000647 << ")";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000648 outs() << "\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000649 } else
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000650 outs() << o->getFileName() << " (ex " << UA->getFileName()
651 << ")\n";
652 }
653 }
654 }
Lang Hamesfc209622016-07-14 02:24:01 +0000655 if (Err)
656 error(std::move(Err), UA->getFileName());
Kevin Enderby42398052016-06-28 23:16:13 +0000657 } else {
658 consumeError(AOrErr.takeError());
659 error("Mach-O universal file: " + file + " for architecture " +
Kevin Enderby59343a92016-12-16 22:54:02 +0000660 StringRef(I->getArchFlagName()) +
Kevin Enderby42398052016-06-28 23:16:13 +0000661 " is not a Mach-O file or an archive file");
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000662 }
663 }
664 }
665 if (!ArchFound) {
666 errs() << ToolName << ": file: " << file
667 << " does not contain architecture" << ArchFlags[i] << ".\n";
668 return;
669 }
670 }
671 return;
672 }
673 // No architecture flags were specified so if this contains a slice that
674 // matches the host architecture dump only that.
675 if (!ArchAll) {
Kevin Enderby10769742014-07-01 22:26:31 +0000676 StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000677 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
678 E = UB->end_objects();
679 I != E; ++I) {
Kevin Enderby59343a92016-12-16 22:54:02 +0000680 if (HostArchName == I->getArchFlagName()) {
Kevin Enderby9acb1092016-05-31 20:35:34 +0000681 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000682 if (UO) {
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";
Kevin Enderby10769742014-07-01 22:26:31 +0000687 else if (MachO && OutputFormat == darwin) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000688 if (MoreThanOneFile)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000689 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000690 << I->getArchFlagName() << "):\n";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000691 }
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000692 printObjectSectionSizes(o);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000693 if (OutputFormat == berkeley) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000694 if (!MachO || MoreThanOneFile)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000695 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000696 << I->getArchFlagName() << ")";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000697 outs() << "\n";
698 }
699 }
Kevin Enderby9acb1092016-05-31 20:35:34 +0000700 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
701 error(std::move(E), file);
702 return;
Kevin Enderby42398052016-06-28 23:16:13 +0000703 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
Rafael Espindola0bfe8282014-12-09 21:05:36 +0000704 I->getAsArchive()) {
705 std::unique_ptr<Archive> &UA = *AOrErr;
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000706 // This is an archive. Iterate over each member and display its
707 // sizes.
Mehdi Amini41af4302016-11-11 04:28:40 +0000708 Error Err = Error::success();
Lang Hamesfc209622016-07-14 02:24:01 +0000709 for (auto &C : UA->children(Err)) {
710 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000711 if (!ChildOrErr) {
Kevin Enderby9acb1092016-05-31 20:35:34 +0000712 if (auto E = isNotObjectErrorInvalidFileType(
713 ChildOrErr.takeError()))
Lang Hamesfc209622016-07-14 02:24:01 +0000714 error(std::move(E), UA->getFileName(), C);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000715 continue;
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000716 }
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000717 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()
721 << "):\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000722 else if (MachO && OutputFormat == darwin)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000723 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
Kevin Enderby59343a92016-12-16 22:54:02 +0000724 << " (for architecture " << I->getArchFlagName()
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000725 << "):\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000726 printObjectSectionSizes(o);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000727 if (OutputFormat == berkeley) {
728 if (MachO)
729 outs() << UA->getFileName() << "(" << o->getFileName()
730 << ")\n";
731 else
732 outs() << o->getFileName() << " (ex " << UA->getFileName()
733 << ")\n";
734 }
735 }
736 }
Lang Hamesfc209622016-07-14 02:24:01 +0000737 if (Err)
738 error(std::move(Err), UA->getFileName());
Kevin Enderby42398052016-06-28 23:16:13 +0000739 } else {
740 consumeError(AOrErr.takeError());
741 error("Mach-O universal file: " + file + " for architecture " +
Kevin Enderby59343a92016-12-16 22:54:02 +0000742 StringRef(I->getArchFlagName()) +
Kevin Enderby42398052016-06-28 23:16:13 +0000743 " is not a Mach-O file or an archive file");
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000744 }
745 return;
746 }
747 }
748 }
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.
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000751 bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000752 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
753 E = UB->end_objects();
754 I != E; ++I) {
Kevin Enderby9acb1092016-05-31 20:35:34 +0000755 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
Rafael Espindola4f7932b2014-06-23 20:41:02 +0000756 if (UO) {
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000757 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000758 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000759 if (OutputFormat == sysv)
760 outs() << o->getFileName() << " :\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000761 else if (MachO && OutputFormat == darwin) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000762 if (MoreThanOneFile || MoreThanOneArch)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000763 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000764 << I->getArchFlagName() << "):";
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000765 outs() << "\n";
766 }
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000767 printObjectSectionSizes(o);
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000768 if (OutputFormat == berkeley) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000769 if (!MachO || MoreThanOneFile || MoreThanOneArch)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000770 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000771 << I->getArchFlagName() << ")";
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000772 outs() << "\n";
773 }
774 }
Kevin Enderby9acb1092016-05-31 20:35:34 +0000775 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
776 error(std::move(E), file, MoreThanOneArch ?
Kevin Enderby59343a92016-12-16 22:54:02 +0000777 StringRef(I->getArchFlagName()) : StringRef());
Kevin Enderby9acb1092016-05-31 20:35:34 +0000778 return;
Kevin Enderby42398052016-06-28 23:16:13 +0000779 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
Rafael Espindola0bfe8282014-12-09 21:05:36 +0000780 I->getAsArchive()) {
781 std::unique_ptr<Archive> &UA = *AOrErr;
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000782 // This is an archive. Iterate over each member and display its sizes.
Mehdi Amini41af4302016-11-11 04:28:40 +0000783 Error Err = Error::success();
Lang Hamesfc209622016-07-14 02:24:01 +0000784 for (auto &C : UA->children(Err)) {
785 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000786 if (!ChildOrErr) {
Kevin Enderby9acb1092016-05-31 20:35:34 +0000787 if (auto E = isNotObjectErrorInvalidFileType(
788 ChildOrErr.takeError()))
Lang Hamesfc209622016-07-14 02:24:01 +0000789 error(std::move(E), UA->getFileName(), C, MoreThanOneArch ?
Kevin Enderby59343a92016-12-16 22:54:02 +0000790 StringRef(I->getArchFlagName()) : StringRef());
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000791 continue;
Kevin Enderbyac9e1552016-05-17 17:10:12 +0000792 }
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000793 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()
797 << "):\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000798 else if (MachO && OutputFormat == darwin)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000799 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
Kevin Enderby59343a92016-12-16 22:54:02 +0000800 << " (for architecture " << I->getArchFlagName() << "):\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000801 printObjectSectionSizes(o);
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000802 if (OutputFormat == berkeley) {
803 if (MachO)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000804 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
Kevin Enderby59343a92016-12-16 22:54:02 +0000805 << " (for architecture " << I->getArchFlagName()
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000806 << ")\n";
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000807 else
808 outs() << o->getFileName() << " (ex " << UA->getFileName()
809 << ")\n";
810 }
811 }
812 }
Lang Hamesfc209622016-07-14 02:24:01 +0000813 if (Err)
814 error(std::move(Err), UA->getFileName());
Kevin Enderby42398052016-06-28 23:16:13 +0000815 } else {
816 consumeError(AOrErr.takeError());
817 error("Mach-O universal file: " + file + " for architecture " +
Kevin Enderby59343a92016-12-16 22:54:02 +0000818 StringRef(I->getArchFlagName()) +
Kevin Enderby42398052016-06-28 23:16:13 +0000819 " is not a Mach-O file or an archive file");
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000820 }
821 }
Rafael Espindola3f6481d2014-08-01 14:31:55 +0000822 } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000823 if (!checkMachOAndArchFlags(o, file))
824 return;
Kevin Enderby5997c942016-12-01 19:12:55 +0000825 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000826 if (OutputFormat == sysv)
827 outs() << o->getFileName() << " :\n";
Kevin Enderby5997c942016-12-01 19:12:55 +0000828 else if (MachO && OutputFormat == darwin && MoreThanOneFile)
829 outs() << o->getFileName() << ":\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000830 printObjectSectionSizes(o);
Kevin Enderby246a4602014-06-17 17:54:13 +0000831 if (OutputFormat == berkeley) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000832 if (!MachO || MoreThanOneFile)
Kevin Enderby246a4602014-06-17 17:54:13 +0000833 outs() << o->getFileName();
834 outs() << "\n";
835 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000836 } else {
Kevin Enderby10769742014-07-01 22:26:31 +0000837 errs() << ToolName << ": " << file << ": "
838 << "Unrecognized file type.\n";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000839 }
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000840 // System V adds an extra newline at the end of each file.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000841 if (OutputFormat == sysv)
842 outs() << "\n";
843}
844
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000845static void printBerkelyTotals() {
846 std::string fmtbuf;
847 raw_string_ostream fmt(fmtbuf);
848 const char *radix_fmt = getRadixFmt();
Jordan Rupprecht8d60f9b2018-09-21 23:48:12 +0000849 fmt << "%#7" << radix_fmt << "\t"
850 << "%#7" << radix_fmt << "\t"
851 << "%#7" << radix_fmt << "\t";
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000852 outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData,
853 TotalObjectBss);
854 fmtbuf.clear();
Jordan Rupprecht8d60f9b2018-09-21 23:48:12 +0000855 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
856 << "%7" PRIx64 "\t";
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000857 outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal)
858 << "(TOTALS)\n";
859}
860
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000861int main(int argc, char **argv) {
Rui Ueyama197194b2018-04-13 18:26:06 +0000862 InitLLVM X(argc, argv);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000863 cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
864
865 ToolName = argv[0];
866 if (OutputFormatShort.getNumOccurrences())
Chris Bienemane71fb5c2015-01-22 01:49:59 +0000867 OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000868 if (RadixShort.getNumOccurrences())
James Hendersonb3735ee2018-10-30 11:52:47 +0000869 Radix = RadixShort.getValue();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000870
Fangrui Song64449e62018-11-22 00:44:17 +0000871 for (StringRef Arch : ArchFlags) {
872 if (Arch == "all") {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000873 ArchAll = true;
Kevin Enderby10769742014-07-01 22:26:31 +0000874 } else {
Fangrui Song64449e62018-11-22 00:44:17 +0000875 if (!MachOObjectFile::isValidArch(Arch)) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000876 outs() << ToolName << ": for the -arch option: Unknown architecture "
Fangrui Song64449e62018-11-22 00:44:17 +0000877 << "named '" << Arch << "'";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000878 return 1;
879 }
880 }
881 }
882
Fangrui Song64449e62018-11-22 00:44:17 +0000883 if (InputFilenames.empty())
Dimitry Andrice4f5d012017-12-18 19:46:56 +0000884 InputFilenames.push_back("a.out");
885
886 MoreThanOneFile = InputFilenames.size() > 1;
887 llvm::for_each(InputFilenames, printFileSectionSizes);
888 if (OutputFormat == berkeley && TotalSizes)
889 printBerkelyTotals();
890
Kevin Enderby64f7a992016-05-02 21:41:03 +0000891 if (HadError)
892 return 1;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000893}