blob: bc4d0d41228faf9b3117533d83b368f5282e999d [file] [log] [blame]
Michael J. Spencerc4ad4662011-09-28 20:57:46 +00001//===-- llvm-size.cpp - Print the size of each object section -------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This program is a utility that works like traditional Unix "size",
11// that is, it prints out the size of each section, and the total size of all
12// sections.
13//
14//===----------------------------------------------------------------------===//
15
16#include "llvm/ADT/APInt.h"
17#include "llvm/Object/Archive.h"
18#include "llvm/Object/ObjectFile.h"
Kevin Enderby246a4602014-06-17 17:54:13 +000019#include "llvm/Object/MachO.h"
Kevin Enderby4b8fc282014-06-18 22:04:40 +000020#include "llvm/Object/MachOUniversal.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"
25#include "llvm/Support/ManagedStatic.h"
26#include "llvm/Support/MemoryBuffer.h"
27#include "llvm/Support/PrettyStackTrace.h"
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000028#include "llvm/Support/Signals.h"
Chandler Carruth4d88a1c2012-12-04 10:44:52 +000029#include "llvm/Support/raw_ostream.h"
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000030#include <algorithm>
31#include <string>
Rafael Espindolaa6e9c3e2014-06-12 17:38:55 +000032#include <system_error>
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000033using namespace llvm;
34using namespace object;
35
Kevin Enderby246a4602014-06-17 17:54:13 +000036enum OutputFormatTy {berkeley, sysv, darwin};
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000037static cl::opt<OutputFormatTy>
38 OutputFormat("format",
39 cl::desc("Specify output format"),
40 cl::values(clEnumVal(sysv, "System V format"),
41 clEnumVal(berkeley, "Berkeley format"),
Kevin Enderby246a4602014-06-17 17:54:13 +000042 clEnumVal(darwin, "Darwin -m format"), clEnumValEnd),
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000043 cl::init(berkeley));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000044
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000045static cl::opt<OutputFormatTy>
46 OutputFormatShort(cl::desc("Specify output format"),
47 cl::values(clEnumValN(sysv, "A", "System V format"),
48 clEnumValN(berkeley, "B", "Berkeley format"),
Kevin Enderby14a96ac2014-06-20 00:04:16 +000049 clEnumValN(darwin, "m", "Darwin -m format"),
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000050 clEnumValEnd),
51 cl::init(berkeley));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000052
Kevin Enderby246a4602014-06-17 17:54:13 +000053static bool berkeleyHeaderPrinted = false;
54static bool moreThanOneFile = false;
55
56cl::opt<bool> DarwinLongFormat("l",
57 cl::desc("When format is darwin, use long format "
58 "to include addresses and offsets."));
59
Kevin Enderbyafef4c92014-07-01 17:19:10 +000060static cl::list<std::string>
61 ArchFlags("arch",
62 cl::desc("architecture(s) from a Mach-O file to dump"),
63 cl::ZeroOrMore);
64bool ArchAll = false;
65
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000066enum RadixTy {octal = 8, decimal = 10, hexadecimal = 16};
67static cl::opt<unsigned int>
68 Radix("-radix",
69 cl::desc("Print size in radix. Only 8, 10, and 16 are valid"),
70 cl::init(decimal));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000071
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000072static cl::opt<RadixTy>
73 RadixShort(cl::desc("Print size in radix:"),
74 cl::values(clEnumValN(octal, "o", "Print size in octal"),
75 clEnumValN(decimal, "d", "Print size in decimal"),
76 clEnumValN(hexadecimal, "x", "Print size in hexadecimal"),
77 clEnumValEnd),
78 cl::init(decimal));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000079
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000080static cl::list<std::string>
81 InputFilenames(cl::Positional, cl::desc("<input files>"),
82 cl::ZeroOrMore);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000083
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000084static std::string ToolName;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000085
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000086/// @brief If ec is not success, print the error and return true.
Rafael Espindola4453e42942014-06-13 03:07:50 +000087static bool error(std::error_code ec) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000088 if (!ec) return false;
89
90 outs() << ToolName << ": error reading file: " << ec.message() << ".\n";
91 outs().flush();
92 return true;
93}
94
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000095/// @brief Get the length of the string that represents @p num in Radix
96/// including the leading 0x or 0 for hexadecimal and octal respectively.
Andrew Trick7dc278d2011-09-29 01:22:31 +000097static size_t getNumLengthAsString(uint64_t num) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000098 APInt conv(64, num);
99 SmallString<32> result;
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000100 conv.toString(result, Radix, false, true);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000101 return result.size();
102}
103
Kevin Enderby246a4602014-06-17 17:54:13 +0000104/// @brief Return the the printing format for the Radix.
105static const char * getRadixFmt(void) {
106 switch (Radix) {
107 case octal:
108 return PRIo64;
109 case decimal:
110 return PRIu64;
111 case hexadecimal:
112 return PRIx64;
113 }
114 return nullptr;
115}
116
117/// @brief Print the size of each Mach-O segment and section in @p MachO.
118///
119/// This is when used when @c OutputFormat is darwin and produces the same
120/// output as darwin's size(1) -m output.
121static void PrintDarwinSectionSizes(MachOObjectFile *MachO) {
122 std::string fmtbuf;
123 raw_string_ostream fmt(fmtbuf);
124 const char *radix_fmt = getRadixFmt();
125 if (Radix == hexadecimal)
126 fmt << "0x";
127 fmt << "%" << radix_fmt;
128
129 uint32_t LoadCommandCount = MachO->getHeader().ncmds;
130 uint32_t Filetype = MachO->getHeader().filetype;
131 MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
132
133 uint64_t total = 0;
134 for (unsigned I = 0; ; ++I) {
135 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
136 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
137 outs() << "Segment " << Seg.segname << ": "
138 << format(fmt.str().c_str(), Seg.vmsize);
139 if (DarwinLongFormat)
140 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr)
141 << " fileoff " << Seg.fileoff << ")";
142 outs() << "\n";
143 total += Seg.vmsize;
144 uint64_t sec_total = 0;
145 for (unsigned J = 0; J < Seg.nsects; ++J) {
146 MachO::section_64 Sec = MachO->getSection64(Load, J);
147 if (Filetype == MachO::MH_OBJECT)
148 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
149 << format("%.16s", &Sec.sectname) << "): ";
150 else
151 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
152 outs() << format(fmt.str().c_str(), Sec.size);
153 if (DarwinLongFormat)
154 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr)
155 << " offset " << Sec.offset << ")";
156 outs() << "\n";
157 sec_total += Sec.size;
158 }
159 if (Seg.nsects != 0)
160 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
161 }
162 else if (Load.C.cmd == MachO::LC_SEGMENT) {
163 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
164 outs() << "Segment " << Seg.segname << ": "
165 << format(fmt.str().c_str(), Seg.vmsize);
166 if (DarwinLongFormat)
167 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr)
168 << " fileoff " << Seg.fileoff << ")";
169 outs() << "\n";
170 total += Seg.vmsize;
171 uint64_t sec_total = 0;
172 for (unsigned J = 0; J < Seg.nsects; ++J) {
173 MachO::section Sec = MachO->getSection(Load, J);
174 if (Filetype == MachO::MH_OBJECT)
175 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
176 << format("%.16s", &Sec.sectname) << "): ";
177 else
178 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
179 outs() << format(fmt.str().c_str(), Sec.size);
180 if (DarwinLongFormat)
181 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr)
182 << " offset " << Sec.offset << ")";
183 outs() << "\n";
184 sec_total += Sec.size;
185 }
186 if (Seg.nsects != 0)
187 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
188 }
189 if (I == LoadCommandCount - 1)
190 break;
191 else
192 Load = MachO->getNextLoadCommandInfo(Load);
193 }
194 outs() << "total " << format(fmt.str().c_str(), total) << "\n";
195}
196
197/// @brief Print the summary sizes of the standard Mach-O segments in @p MachO.
198///
199/// This is when used when @c OutputFormat is berkeley with a Mach-O file and
200/// produces the same output as darwin's size(1) default output.
201static void PrintDarwinSegmentSizes(MachOObjectFile *MachO) {
202 uint32_t LoadCommandCount = MachO->getHeader().ncmds;
203 MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
204
205 uint64_t total_text = 0;
206 uint64_t total_data = 0;
207 uint64_t total_objc = 0;
208 uint64_t total_others = 0;
209 for (unsigned I = 0; ; ++I) {
210 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
211 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
212 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
213 for (unsigned J = 0; J < Seg.nsects; ++J) {
214 MachO::section_64 Sec = MachO->getSection64(Load, J);
215 StringRef SegmentName = StringRef(Sec.segname);
216 if (SegmentName == "__TEXT")
217 total_text += Sec.size;
218 else if (SegmentName == "__DATA")
219 total_data += Sec.size;
220 else if (SegmentName == "__OBJC")
221 total_objc += Sec.size;
222 else
223 total_others += Sec.size;
224 }
225 } else {
226 StringRef SegmentName = StringRef(Seg.segname);
227 if (SegmentName == "__TEXT")
228 total_text += Seg.vmsize;
229 else if (SegmentName == "__DATA")
230 total_data += Seg.vmsize;
231 else if (SegmentName == "__OBJC")
232 total_objc += Seg.vmsize;
233 else
234 total_others += Seg.vmsize;
235 }
236 }
237 else if (Load.C.cmd == MachO::LC_SEGMENT) {
238 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
239 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
240 for (unsigned J = 0; J < Seg.nsects; ++J) {
241 MachO::section Sec = MachO->getSection(Load, J);
242 StringRef SegmentName = StringRef(Sec.segname);
243 if (SegmentName == "__TEXT")
244 total_text += Sec.size;
245 else if (SegmentName == "__DATA")
246 total_data += Sec.size;
247 else if (SegmentName == "__OBJC")
248 total_objc += Sec.size;
249 else
250 total_others += Sec.size;
251 }
252 } else {
253 StringRef SegmentName = StringRef(Seg.segname);
254 if (SegmentName == "__TEXT")
255 total_text += Seg.vmsize;
256 else if (SegmentName == "__DATA")
257 total_data += Seg.vmsize;
258 else if (SegmentName == "__OBJC")
259 total_objc += Seg.vmsize;
260 else
261 total_others += Seg.vmsize;
262 }
263 }
264 if (I == LoadCommandCount - 1)
265 break;
266 else
267 Load = MachO->getNextLoadCommandInfo(Load);
268 }
269 uint64_t total = total_text + total_data + total_objc + total_others;
270
271 if (!berkeleyHeaderPrinted) {
272 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
273 berkeleyHeaderPrinted = true;
274 }
275 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
276 << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
277 << "\t";
278}
279
Alexey Samsonov48803e52014-03-13 14:37:36 +0000280/// @brief Print the size of each section in @p Obj.
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000281///
282/// The format used is determined by @c OutputFormat and @c Radix.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000283static void PrintObjectSectionSizes(ObjectFile *Obj) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000284 uint64_t total = 0;
285 std::string fmtbuf;
286 raw_string_ostream fmt(fmtbuf);
Kevin Enderby246a4602014-06-17 17:54:13 +0000287 const char *radix_fmt = getRadixFmt();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000288
Kevin Enderby246a4602014-06-17 17:54:13 +0000289 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
290 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
291 // let it fall through to OutputFormat berkeley.
292 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
293 if (OutputFormat == darwin && MachO)
294 PrintDarwinSectionSizes(MachO);
295 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
296 // darwin's default berkeley format for Mach-O files.
297 else if (MachO && OutputFormat == berkeley)
298 PrintDarwinSegmentSizes(MachO);
299 else if (OutputFormat == sysv) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000300 // Run two passes over all sections. The first gets the lengths needed for
301 // formatting the output. The second actually does the output.
302 std::size_t max_name_len = strlen("section");
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000303 std::size_t max_size_len = strlen("size");
304 std::size_t max_addr_len = strlen("addr");
Alexey Samsonov48803e52014-03-13 14:37:36 +0000305 for (const SectionRef &Section : Obj->sections()) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000306 uint64_t size = 0;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000307 if (error(Section.getSize(size)))
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000308 return;
309 total += size;
310
311 StringRef name;
312 uint64_t addr = 0;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000313 if (error(Section.getName(name)))
314 return;
315 if (error(Section.getAddress(addr)))
316 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000317 max_name_len = std::max(max_name_len, name.size());
Andrew Trick7dc278d2011-09-29 01:22:31 +0000318 max_size_len = std::max(max_size_len, getNumLengthAsString(size));
319 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000320 }
321
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000322 // Add extra padding.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000323 max_name_len += 2;
324 max_size_len += 2;
325 max_addr_len += 2;
326
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000327 // Setup header format.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000328 fmt << "%-" << max_name_len << "s "
329 << "%" << max_size_len << "s "
330 << "%" << max_addr_len << "s\n";
331
332 // Print header
333 outs() << format(fmt.str().c_str(),
334 static_cast<const char*>("section"),
335 static_cast<const char*>("size"),
336 static_cast<const char*>("addr"));
337 fmtbuf.clear();
338
339 // Setup per section format.
340 fmt << "%-" << max_name_len << "s "
341 << "%#" << max_size_len << radix_fmt << " "
342 << "%#" << max_addr_len << radix_fmt << "\n";
343
344 // Print each section.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000345 for (const SectionRef &Section : Obj->sections()) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000346 StringRef name;
347 uint64_t size = 0;
348 uint64_t addr = 0;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000349 if (error(Section.getName(name)))
350 return;
351 if (error(Section.getSize(size)))
352 return;
353 if (error(Section.getAddress(addr)))
354 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000355 std::string namestr = name;
356
Alexey Samsonov48803e52014-03-13 14:37:36 +0000357 outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000358 }
359
360 // Print total.
361 fmtbuf.clear();
362 fmt << "%-" << max_name_len << "s "
363 << "%#" << max_size_len << radix_fmt << "\n";
364 outs() << format(fmt.str().c_str(),
365 static_cast<const char*>("Total"),
366 total);
367 } else {
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000368 // The Berkeley format does not display individual section sizes. It
369 // displays the cumulative size for each section type.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000370 uint64_t total_text = 0;
371 uint64_t total_data = 0;
372 uint64_t total_bss = 0;
373
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000374 // Make one pass over the section table to calculate sizes.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000375 for (const SectionRef &Section : Obj->sections()) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000376 uint64_t size = 0;
377 bool isText = false;
378 bool isData = false;
379 bool isBSS = false;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000380 if (error(Section.getSize(size)))
381 return;
382 if (error(Section.isText(isText)))
383 return;
384 if (error(Section.isData(isData)))
385 return;
386 if (error(Section.isBSS(isBSS)))
387 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000388 if (isText)
389 total_text += size;
390 else if (isData)
391 total_data += size;
392 else if (isBSS)
393 total_bss += size;
394 }
395
396 total = total_text + total_data + total_bss;
397
Kevin Enderby246a4602014-06-17 17:54:13 +0000398 if (!berkeleyHeaderPrinted) {
399 outs() << " text data bss "
400 << (Radix == octal ? "oct" : "dec")
401 << " hex filename\n";
402 berkeleyHeaderPrinted = true;
403 }
404
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000405 // Print result.
406 fmt << "%#7" << radix_fmt << " "
407 << "%#7" << radix_fmt << " "
408 << "%#7" << radix_fmt << " ";
409 outs() << format(fmt.str().c_str(),
410 total_text,
411 total_data,
412 total_bss);
413 fmtbuf.clear();
Benjamin Kramerf3da5292011-11-05 08:57:40 +0000414 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " "
415 << "%7" PRIx64 " ";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000416 outs() << format(fmt.str().c_str(),
417 total,
418 total);
419 }
420}
421
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000422/// @brief Checks to see if the @p o ObjectFile is a Mach-O file and if it is
423/// and there is a list of architecture flags specified then check to
424/// make sure this Mach-O file is one of those architectures or all
425/// architectures was specificed. If not then an error is generated and
426/// this routine returns false. Else it returns true.
427static bool checkMachOAndArchFlags(ObjectFile *o, StringRef file) {
428 if (isa<MachOObjectFile>(o) && !ArchAll && ArchFlags.size() != 0) {
429 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
430 bool ArchFound = false;
431 MachO::mach_header H;
432 MachO::mach_header_64 H_64;
433 Triple T;
434 if (MachO->is64Bit()) {
435 H_64 = MachO->MachOObjectFile::getHeader64();
436 T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype);
437 } else {
438 H = MachO->MachOObjectFile::getHeader();
439 T = MachOObjectFile::getArch(H.cputype, H.cpusubtype);
440 }
441 unsigned i;
442 for (i = 0; i < ArchFlags.size(); ++i){
443 if (ArchFlags[i] == T.getArchName())
444 ArchFound = true;
445 break;
446 }
447 if (!ArchFound) {
448 errs() << ToolName << ": file: " << file
449 << " does not contain architecture: " << ArchFlags[i] << ".\n";
450 return false;
451 }
452 }
453 return true;
454}
455
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000456/// @brief Print the section sizes for @p file. If @p file is an archive, print
457/// the section sizes for each archive member.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000458static void PrintFileSectionSizes(StringRef file) {
459 // If file is not stdin, check that it exists.
460 if (file != "-") {
461 bool exists;
462 if (sys::fs::exists(file, exists) || !exists) {
463 errs() << ToolName << ": '" << file << "': " << "No such file\n";
464 return;
465 }
466 }
467
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000468 // Attempt to open the binary.
Rafael Espindola63da2952014-01-15 19:37:43 +0000469 ErrorOr<Binary *> BinaryOrErr = createBinary(file);
Rafael Espindola4453e42942014-06-13 03:07:50 +0000470 if (std::error_code EC = BinaryOrErr.getError()) {
Rafael Espindola63da2952014-01-15 19:37:43 +0000471 errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000472 return;
473 }
Ahmed Charles56440fd2014-03-06 05:51:42 +0000474 std::unique_ptr<Binary> binary(BinaryOrErr.get());
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000475
476 if (Archive *a = dyn_cast<Archive>(binary.get())) {
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000477 // This is an archive. Iterate over each member and display its sizes.
Rafael Espindola23a97502014-01-21 16:09:45 +0000478 for (object::Archive::child_iterator i = a->child_begin(),
479 e = a->child_end(); i != e; ++i) {
Rafael Espindolaae460022014-06-16 16:08:36 +0000480 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
481 if (std::error_code EC = ChildOrErr.getError()) {
482 errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000483 continue;
484 }
Rafael Espindolaae460022014-06-16 16:08:36 +0000485 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000486 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000487 if (!checkMachOAndArchFlags(o, file))
488 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000489 if (OutputFormat == sysv)
490 outs() << o->getFileName() << " (ex " << a->getFileName()
491 << "):\n";
Kevin Enderby246a4602014-06-17 17:54:13 +0000492 else if(MachO && OutputFormat == darwin)
493 outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000494 PrintObjectSectionSizes(o);
Kevin Enderby246a4602014-06-17 17:54:13 +0000495 if (OutputFormat == berkeley) {
496 if (MachO)
497 outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
498 else
499 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
500 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000501 }
502 }
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000503 } else if (MachOUniversalBinary *UB =
504 dyn_cast<MachOUniversalBinary>(binary.get())) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000505 // If we have a list of architecture flags specified dump only those.
506 if (!ArchAll && ArchFlags.size() != 0) {
507 // Look for a slice in the universal binary that matches each ArchFlag.
508 bool ArchFound;
509 for (unsigned i = 0; i < ArchFlags.size(); ++i){
510 ArchFound = false;
511 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
512 E = UB->end_objects();
513 I != E; ++I) {
514 if (ArchFlags[i] == I->getArchTypeName()){
515 ArchFound = true;
516 ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
517 std::unique_ptr<Archive> UA;
518 if (UO) {
519 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
520 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
521 if (OutputFormat == sysv)
522 outs() << o->getFileName() << " :\n";
523 else if(MachO && OutputFormat == darwin) {
524 if (moreThanOneFile || ArchFlags.size() > 1)
525 outs() << o->getFileName() << " (for architecture "
526 << I->getArchTypeName() << "): \n";
527 }
528 PrintObjectSectionSizes(o);
529 if (OutputFormat == berkeley) {
530 if (!MachO || moreThanOneFile || ArchFlags.size() > 1)
531 outs() << o->getFileName() << " (for architecture "
532 << I->getArchTypeName() << ")";
533 outs() << "\n";
534 }
535 }
536 }
537 else if (!I->getAsArchive(UA)) {
538 // This is an archive. Iterate over each member and display its
539 //sizes.
540 for (object::Archive::child_iterator i = UA->child_begin(),
541 e = UA->child_end();
542 i != e; ++i) {
543 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
544 if (std::error_code EC = ChildOrErr.getError()) {
545 errs() << ToolName << ": " << file << ": " << EC.message()
546 << ".\n";
547 continue;
548 }
549 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
550 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
551 if (OutputFormat == sysv)
552 outs() << o->getFileName() << " (ex " << UA->getFileName()
553 << "):\n";
554 else if(MachO && OutputFormat == darwin)
555 outs() << UA->getFileName() << "(" << o->getFileName()
556 << ")" << " (for architecture "
557 << I->getArchTypeName() << "):\n";
558 PrintObjectSectionSizes(o);
559 if (OutputFormat == berkeley) {
560 if (MachO) {
561 outs() << UA->getFileName() << "(" << o->getFileName()
562 << ")";
563 if (ArchFlags.size() > 1)
564 outs() << " (for architecture "
565 << I->getArchTypeName() << ")";
566 outs() << "\n";
567 }
568 else
569 outs() << o->getFileName() << " (ex " << UA->getFileName()
570 << ")\n";
571 }
572 }
573 }
574 }
575 }
576 }
577 if (!ArchFound) {
578 errs() << ToolName << ": file: " << file
579 << " does not contain architecture" << ArchFlags[i] << ".\n";
580 return;
581 }
582 }
583 return;
584 }
585 // No architecture flags were specified so if this contains a slice that
586 // matches the host architecture dump only that.
587 if (!ArchAll) {
588 StringRef HostArchName =
589 MachOObjectFile::getHostArch().getArchName();
590 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
591 E = UB->end_objects();
592 I != E; ++I) {
593 if (HostArchName == I->getArchTypeName()){
594 ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
595 std::unique_ptr<Archive> UA;
596 if (UO) {
597 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
598 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
599 if (OutputFormat == sysv)
600 outs() << o->getFileName() << " :\n";
601 else if(MachO && OutputFormat == darwin) {
602 if (moreThanOneFile)
603 outs() << o->getFileName() << " (for architecture "
604 << I->getArchTypeName() << "):\n";
605 }
606 PrintObjectSectionSizes(o);
607 if (OutputFormat == berkeley) {
608 if (!MachO || moreThanOneFile)
609 outs() << o->getFileName() << " (for architecture "
610 << I->getArchTypeName() << ")";
611 outs() << "\n";
612 }
613 }
614 }
615 else if (!I->getAsArchive(UA)) {
616 // This is an archive. Iterate over each member and display its
617 // sizes.
618 for (object::Archive::child_iterator i = UA->child_begin(),
619 e = UA->child_end();
620 i != e; ++i) {
621 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
622 if (std::error_code EC = ChildOrErr.getError()) {
623 errs() << ToolName << ": " << file << ": " << EC.message()
624 << ".\n";
625 continue;
626 }
627 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
628 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
629 if (OutputFormat == sysv)
630 outs() << o->getFileName() << " (ex " << UA->getFileName()
631 << "):\n";
632 else if(MachO && OutputFormat == darwin)
633 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
634 << " (for architecture " << I->getArchTypeName()
635 << "):\n";
636 PrintObjectSectionSizes(o);
637 if (OutputFormat == berkeley) {
638 if (MachO)
639 outs() << UA->getFileName() << "(" << o->getFileName()
640 << ")\n";
641 else
642 outs() << o->getFileName() << " (ex " << UA->getFileName()
643 << ")\n";
644 }
645 }
646 }
647 }
648 return;
649 }
650 }
651 }
652 // Either all architectures have been specified or none have been specified
653 // and this does not contain the host architecture so dump all the slices.
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000654 bool moreThanOneArch = UB->getNumberOfObjects() > 1;
655 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
656 E = UB->end_objects();
657 I != E; ++I) {
Rafael Espindola4f7932b2014-06-23 20:41:02 +0000658 ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000659 std::unique_ptr<Archive> UA;
Rafael Espindola4f7932b2014-06-23 20:41:02 +0000660 if (UO) {
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000661 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000662 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000663 if (OutputFormat == sysv)
664 outs() << o->getFileName() << " :\n";
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000665 else if(MachO && OutputFormat == darwin) {
666 if (moreThanOneFile || moreThanOneArch)
667 outs() << o->getFileName() << " (for architecture "
668 << I->getArchTypeName() << "):";
669 outs() << "\n";
670 }
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000671 PrintObjectSectionSizes(o);
672 if (OutputFormat == berkeley) {
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000673 if (!MachO || moreThanOneFile || moreThanOneArch)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000674 outs() << o->getFileName() << " (for architecture "
675 << I->getArchTypeName() << ")";
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000676 outs() << "\n";
677 }
678 }
679 }
680 else if (!I->getAsArchive(UA)) {
681 // This is an archive. Iterate over each member and display its sizes.
682 for (object::Archive::child_iterator i = UA->child_begin(),
683 e = UA->child_end(); i != e; ++i) {
684 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
685 if (std::error_code EC = ChildOrErr.getError()) {
686 errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
687 continue;
688 }
689 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
690 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
691 if (OutputFormat == sysv)
692 outs() << o->getFileName() << " (ex " << UA->getFileName()
693 << "):\n";
694 else if(MachO && OutputFormat == darwin)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000695 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
696 << " (for architecture " << I->getArchTypeName()
697 << "):\n";
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000698 PrintObjectSectionSizes(o);
699 if (OutputFormat == berkeley) {
700 if (MachO)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000701 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
702 << " (for architecture " << I->getArchTypeName()
703 << ")\n";
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000704 else
705 outs() << o->getFileName() << " (ex " << UA->getFileName()
706 << ")\n";
707 }
708 }
709 }
710 }
711 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000712 } else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000713 if (!checkMachOAndArchFlags(o, file))
714 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000715 if (OutputFormat == sysv)
716 outs() << o->getFileName() << " :\n";
717 PrintObjectSectionSizes(o);
Kevin Enderby246a4602014-06-17 17:54:13 +0000718 if (OutputFormat == berkeley) {
719 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
720 if (!MachO || moreThanOneFile)
721 outs() << o->getFileName();
722 outs() << "\n";
723 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000724 } else {
725 errs() << ToolName << ": " << file << ": " << "Unrecognized file type.\n";
726 }
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000727 // System V adds an extra newline at the end of each file.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000728 if (OutputFormat == sysv)
729 outs() << "\n";
730}
731
732int main(int argc, char **argv) {
733 // Print a stack trace if we signal out.
734 sys::PrintStackTraceOnErrorSignal();
735 PrettyStackTraceProgram X(argc, argv);
736
737 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
738 cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
739
740 ToolName = argv[0];
741 if (OutputFormatShort.getNumOccurrences())
742 OutputFormat = OutputFormatShort;
743 if (RadixShort.getNumOccurrences())
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000744 Radix = RadixShort;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000745
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000746 for (unsigned i = 0; i < ArchFlags.size(); ++i){
747 if (ArchFlags[i] == "all") {
748 ArchAll = true;
749 }
750 else {
751 Triple T = MachOObjectFile::getArch(ArchFlags[i]);
752 if (T.getArch() == Triple::UnknownArch){
753 outs() << ToolName << ": for the -arch option: Unknown architecture "
754 << "named '" << ArchFlags[i] << "'";
755 return 1;
756 }
757 }
758 }
759
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000760 if (InputFilenames.size() == 0)
761 InputFilenames.push_back("a.out");
762
Kevin Enderby246a4602014-06-17 17:54:13 +0000763 moreThanOneFile = InputFilenames.size() > 1;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000764 std::for_each(InputFilenames.begin(), InputFilenames.end(),
765 PrintFileSectionSizes);
766
767 return 0;
768}