blob: 48614d8176b6e3c790cbb877cb99090add7ee235 [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
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000060enum RadixTy {octal = 8, decimal = 10, hexadecimal = 16};
61static cl::opt<unsigned int>
62 Radix("-radix",
63 cl::desc("Print size in radix. Only 8, 10, and 16 are valid"),
64 cl::init(decimal));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000065
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000066static cl::opt<RadixTy>
67 RadixShort(cl::desc("Print size in radix:"),
68 cl::values(clEnumValN(octal, "o", "Print size in octal"),
69 clEnumValN(decimal, "d", "Print size in decimal"),
70 clEnumValN(hexadecimal, "x", "Print size in hexadecimal"),
71 clEnumValEnd),
72 cl::init(decimal));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000073
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000074static cl::list<std::string>
75 InputFilenames(cl::Positional, cl::desc("<input files>"),
76 cl::ZeroOrMore);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000077
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000078static std::string ToolName;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000079
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000080/// @brief If ec is not success, print the error and return true.
Rafael Espindola4453e42942014-06-13 03:07:50 +000081static bool error(std::error_code ec) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000082 if (!ec) return false;
83
84 outs() << ToolName << ": error reading file: " << ec.message() << ".\n";
85 outs().flush();
86 return true;
87}
88
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000089/// @brief Get the length of the string that represents @p num in Radix
90/// including the leading 0x or 0 for hexadecimal and octal respectively.
Andrew Trick7dc278d2011-09-29 01:22:31 +000091static size_t getNumLengthAsString(uint64_t num) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000092 APInt conv(64, num);
93 SmallString<32> result;
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000094 conv.toString(result, Radix, false, true);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000095 return result.size();
96}
97
Kevin Enderby246a4602014-06-17 17:54:13 +000098/// @brief Return the the printing format for the Radix.
99static const char * getRadixFmt(void) {
100 switch (Radix) {
101 case octal:
102 return PRIo64;
103 case decimal:
104 return PRIu64;
105 case hexadecimal:
106 return PRIx64;
107 }
108 return nullptr;
109}
110
111/// @brief Print the size of each Mach-O segment and section in @p MachO.
112///
113/// This is when used when @c OutputFormat is darwin and produces the same
114/// output as darwin's size(1) -m output.
115static void PrintDarwinSectionSizes(MachOObjectFile *MachO) {
116 std::string fmtbuf;
117 raw_string_ostream fmt(fmtbuf);
118 const char *radix_fmt = getRadixFmt();
119 if (Radix == hexadecimal)
120 fmt << "0x";
121 fmt << "%" << radix_fmt;
122
123 uint32_t LoadCommandCount = MachO->getHeader().ncmds;
124 uint32_t Filetype = MachO->getHeader().filetype;
125 MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
126
127 uint64_t total = 0;
128 for (unsigned I = 0; ; ++I) {
129 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
130 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
131 outs() << "Segment " << Seg.segname << ": "
132 << format(fmt.str().c_str(), Seg.vmsize);
133 if (DarwinLongFormat)
134 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr)
135 << " fileoff " << Seg.fileoff << ")";
136 outs() << "\n";
137 total += Seg.vmsize;
138 uint64_t sec_total = 0;
139 for (unsigned J = 0; J < Seg.nsects; ++J) {
140 MachO::section_64 Sec = MachO->getSection64(Load, J);
141 if (Filetype == MachO::MH_OBJECT)
142 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
143 << format("%.16s", &Sec.sectname) << "): ";
144 else
145 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
146 outs() << format(fmt.str().c_str(), Sec.size);
147 if (DarwinLongFormat)
148 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr)
149 << " offset " << Sec.offset << ")";
150 outs() << "\n";
151 sec_total += Sec.size;
152 }
153 if (Seg.nsects != 0)
154 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
155 }
156 else if (Load.C.cmd == MachO::LC_SEGMENT) {
157 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
158 outs() << "Segment " << Seg.segname << ": "
159 << format(fmt.str().c_str(), Seg.vmsize);
160 if (DarwinLongFormat)
161 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr)
162 << " fileoff " << Seg.fileoff << ")";
163 outs() << "\n";
164 total += Seg.vmsize;
165 uint64_t sec_total = 0;
166 for (unsigned J = 0; J < Seg.nsects; ++J) {
167 MachO::section Sec = MachO->getSection(Load, J);
168 if (Filetype == MachO::MH_OBJECT)
169 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
170 << format("%.16s", &Sec.sectname) << "): ";
171 else
172 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
173 outs() << format(fmt.str().c_str(), Sec.size);
174 if (DarwinLongFormat)
175 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr)
176 << " offset " << Sec.offset << ")";
177 outs() << "\n";
178 sec_total += Sec.size;
179 }
180 if (Seg.nsects != 0)
181 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
182 }
183 if (I == LoadCommandCount - 1)
184 break;
185 else
186 Load = MachO->getNextLoadCommandInfo(Load);
187 }
188 outs() << "total " << format(fmt.str().c_str(), total) << "\n";
189}
190
191/// @brief Print the summary sizes of the standard Mach-O segments in @p MachO.
192///
193/// This is when used when @c OutputFormat is berkeley with a Mach-O file and
194/// produces the same output as darwin's size(1) default output.
195static void PrintDarwinSegmentSizes(MachOObjectFile *MachO) {
196 uint32_t LoadCommandCount = MachO->getHeader().ncmds;
197 MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
198
199 uint64_t total_text = 0;
200 uint64_t total_data = 0;
201 uint64_t total_objc = 0;
202 uint64_t total_others = 0;
203 for (unsigned I = 0; ; ++I) {
204 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
205 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
206 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
207 for (unsigned J = 0; J < Seg.nsects; ++J) {
208 MachO::section_64 Sec = MachO->getSection64(Load, J);
209 StringRef SegmentName = StringRef(Sec.segname);
210 if (SegmentName == "__TEXT")
211 total_text += Sec.size;
212 else if (SegmentName == "__DATA")
213 total_data += Sec.size;
214 else if (SegmentName == "__OBJC")
215 total_objc += Sec.size;
216 else
217 total_others += Sec.size;
218 }
219 } else {
220 StringRef SegmentName = StringRef(Seg.segname);
221 if (SegmentName == "__TEXT")
222 total_text += Seg.vmsize;
223 else if (SegmentName == "__DATA")
224 total_data += Seg.vmsize;
225 else if (SegmentName == "__OBJC")
226 total_objc += Seg.vmsize;
227 else
228 total_others += Seg.vmsize;
229 }
230 }
231 else if (Load.C.cmd == MachO::LC_SEGMENT) {
232 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
233 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
234 for (unsigned J = 0; J < Seg.nsects; ++J) {
235 MachO::section Sec = MachO->getSection(Load, J);
236 StringRef SegmentName = StringRef(Sec.segname);
237 if (SegmentName == "__TEXT")
238 total_text += Sec.size;
239 else if (SegmentName == "__DATA")
240 total_data += Sec.size;
241 else if (SegmentName == "__OBJC")
242 total_objc += Sec.size;
243 else
244 total_others += Sec.size;
245 }
246 } else {
247 StringRef SegmentName = StringRef(Seg.segname);
248 if (SegmentName == "__TEXT")
249 total_text += Seg.vmsize;
250 else if (SegmentName == "__DATA")
251 total_data += Seg.vmsize;
252 else if (SegmentName == "__OBJC")
253 total_objc += Seg.vmsize;
254 else
255 total_others += Seg.vmsize;
256 }
257 }
258 if (I == LoadCommandCount - 1)
259 break;
260 else
261 Load = MachO->getNextLoadCommandInfo(Load);
262 }
263 uint64_t total = total_text + total_data + total_objc + total_others;
264
265 if (!berkeleyHeaderPrinted) {
266 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
267 berkeleyHeaderPrinted = true;
268 }
269 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
270 << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
271 << "\t";
272}
273
Alexey Samsonov48803e52014-03-13 14:37:36 +0000274/// @brief Print the size of each section in @p Obj.
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000275///
276/// The format used is determined by @c OutputFormat and @c Radix.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000277static void PrintObjectSectionSizes(ObjectFile *Obj) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000278 uint64_t total = 0;
279 std::string fmtbuf;
280 raw_string_ostream fmt(fmtbuf);
Kevin Enderby246a4602014-06-17 17:54:13 +0000281 const char *radix_fmt = getRadixFmt();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000282
Kevin Enderby246a4602014-06-17 17:54:13 +0000283 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
284 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
285 // let it fall through to OutputFormat berkeley.
286 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
287 if (OutputFormat == darwin && MachO)
288 PrintDarwinSectionSizes(MachO);
289 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
290 // darwin's default berkeley format for Mach-O files.
291 else if (MachO && OutputFormat == berkeley)
292 PrintDarwinSegmentSizes(MachO);
293 else if (OutputFormat == sysv) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000294 // Run two passes over all sections. The first gets the lengths needed for
295 // formatting the output. The second actually does the output.
296 std::size_t max_name_len = strlen("section");
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000297 std::size_t max_size_len = strlen("size");
298 std::size_t max_addr_len = strlen("addr");
Alexey Samsonov48803e52014-03-13 14:37:36 +0000299 for (const SectionRef &Section : Obj->sections()) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000300 uint64_t size = 0;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000301 if (error(Section.getSize(size)))
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000302 return;
303 total += size;
304
305 StringRef name;
306 uint64_t addr = 0;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000307 if (error(Section.getName(name)))
308 return;
309 if (error(Section.getAddress(addr)))
310 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000311 max_name_len = std::max(max_name_len, name.size());
Andrew Trick7dc278d2011-09-29 01:22:31 +0000312 max_size_len = std::max(max_size_len, getNumLengthAsString(size));
313 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000314 }
315
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000316 // Add extra padding.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000317 max_name_len += 2;
318 max_size_len += 2;
319 max_addr_len += 2;
320
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000321 // Setup header format.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000322 fmt << "%-" << max_name_len << "s "
323 << "%" << max_size_len << "s "
324 << "%" << max_addr_len << "s\n";
325
326 // Print header
327 outs() << format(fmt.str().c_str(),
328 static_cast<const char*>("section"),
329 static_cast<const char*>("size"),
330 static_cast<const char*>("addr"));
331 fmtbuf.clear();
332
333 // Setup per section format.
334 fmt << "%-" << max_name_len << "s "
335 << "%#" << max_size_len << radix_fmt << " "
336 << "%#" << max_addr_len << radix_fmt << "\n";
337
338 // Print each section.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000339 for (const SectionRef &Section : Obj->sections()) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000340 StringRef name;
341 uint64_t size = 0;
342 uint64_t addr = 0;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000343 if (error(Section.getName(name)))
344 return;
345 if (error(Section.getSize(size)))
346 return;
347 if (error(Section.getAddress(addr)))
348 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000349 std::string namestr = name;
350
Alexey Samsonov48803e52014-03-13 14:37:36 +0000351 outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000352 }
353
354 // Print total.
355 fmtbuf.clear();
356 fmt << "%-" << max_name_len << "s "
357 << "%#" << max_size_len << radix_fmt << "\n";
358 outs() << format(fmt.str().c_str(),
359 static_cast<const char*>("Total"),
360 total);
361 } else {
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000362 // The Berkeley format does not display individual section sizes. It
363 // displays the cumulative size for each section type.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000364 uint64_t total_text = 0;
365 uint64_t total_data = 0;
366 uint64_t total_bss = 0;
367
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000368 // Make one pass over the section table to calculate sizes.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000369 for (const SectionRef &Section : Obj->sections()) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000370 uint64_t size = 0;
371 bool isText = false;
372 bool isData = false;
373 bool isBSS = false;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000374 if (error(Section.getSize(size)))
375 return;
376 if (error(Section.isText(isText)))
377 return;
378 if (error(Section.isData(isData)))
379 return;
380 if (error(Section.isBSS(isBSS)))
381 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000382 if (isText)
383 total_text += size;
384 else if (isData)
385 total_data += size;
386 else if (isBSS)
387 total_bss += size;
388 }
389
390 total = total_text + total_data + total_bss;
391
Kevin Enderby246a4602014-06-17 17:54:13 +0000392 if (!berkeleyHeaderPrinted) {
393 outs() << " text data bss "
394 << (Radix == octal ? "oct" : "dec")
395 << " hex filename\n";
396 berkeleyHeaderPrinted = true;
397 }
398
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000399 // Print result.
400 fmt << "%#7" << radix_fmt << " "
401 << "%#7" << radix_fmt << " "
402 << "%#7" << radix_fmt << " ";
403 outs() << format(fmt.str().c_str(),
404 total_text,
405 total_data,
406 total_bss);
407 fmtbuf.clear();
Benjamin Kramerf3da5292011-11-05 08:57:40 +0000408 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " "
409 << "%7" PRIx64 " ";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000410 outs() << format(fmt.str().c_str(),
411 total,
412 total);
413 }
414}
415
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000416/// @brief Print the section sizes for @p file. If @p file is an archive, print
417/// the section sizes for each archive member.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000418static void PrintFileSectionSizes(StringRef file) {
419 // If file is not stdin, check that it exists.
420 if (file != "-") {
421 bool exists;
422 if (sys::fs::exists(file, exists) || !exists) {
423 errs() << ToolName << ": '" << file << "': " << "No such file\n";
424 return;
425 }
426 }
427
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000428 // Attempt to open the binary.
Rafael Espindola63da2952014-01-15 19:37:43 +0000429 ErrorOr<Binary *> BinaryOrErr = createBinary(file);
Rafael Espindola4453e42942014-06-13 03:07:50 +0000430 if (std::error_code EC = BinaryOrErr.getError()) {
Rafael Espindola63da2952014-01-15 19:37:43 +0000431 errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000432 return;
433 }
Ahmed Charles56440fd2014-03-06 05:51:42 +0000434 std::unique_ptr<Binary> binary(BinaryOrErr.get());
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000435
436 if (Archive *a = dyn_cast<Archive>(binary.get())) {
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000437 // This is an archive. Iterate over each member and display its sizes.
Rafael Espindola23a97502014-01-21 16:09:45 +0000438 for (object::Archive::child_iterator i = a->child_begin(),
439 e = a->child_end(); i != e; ++i) {
Rafael Espindolaae460022014-06-16 16:08:36 +0000440 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
441 if (std::error_code EC = ChildOrErr.getError()) {
442 errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000443 continue;
444 }
Rafael Espindolaae460022014-06-16 16:08:36 +0000445 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000446 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000447 if (OutputFormat == sysv)
448 outs() << o->getFileName() << " (ex " << a->getFileName()
449 << "):\n";
Kevin Enderby246a4602014-06-17 17:54:13 +0000450 else if(MachO && OutputFormat == darwin)
451 outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000452 PrintObjectSectionSizes(o);
Kevin Enderby246a4602014-06-17 17:54:13 +0000453 if (OutputFormat == berkeley) {
454 if (MachO)
455 outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
456 else
457 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
458 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000459 }
460 }
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000461 } else if (MachOUniversalBinary *UB =
462 dyn_cast<MachOUniversalBinary>(binary.get())) {
463 // This is a Mach-O universal binary. Iterate over each object and
464 // display its sizes.
465 bool moreThanOneArch = UB->getNumberOfObjects() > 1;
466 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
467 E = UB->end_objects();
468 I != E; ++I) {
Rafael Espindola4f7932b2014-06-23 20:41:02 +0000469 ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000470 std::unique_ptr<Archive> UA;
Rafael Espindola4f7932b2014-06-23 20:41:02 +0000471 if (UO) {
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000472 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000473 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000474 if (OutputFormat == sysv)
475 outs() << o->getFileName() << " :\n";
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000476 else if(MachO && OutputFormat == darwin) {
477 if (moreThanOneFile || moreThanOneArch)
478 outs() << o->getFileName() << " (for architecture "
479 << I->getArchTypeName() << "):";
480 outs() << "\n";
481 }
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000482 PrintObjectSectionSizes(o);
483 if (OutputFormat == berkeley) {
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000484 if (!MachO || moreThanOneFile || moreThanOneArch)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000485 outs() << o->getFileName() << " (for architecture "
486 << I->getArchTypeName() << ")";
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000487 outs() << "\n";
488 }
489 }
490 }
491 else if (!I->getAsArchive(UA)) {
492 // This is an archive. Iterate over each member and display its sizes.
493 for (object::Archive::child_iterator i = UA->child_begin(),
494 e = UA->child_end(); i != e; ++i) {
495 ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
496 if (std::error_code EC = ChildOrErr.getError()) {
497 errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
498 continue;
499 }
500 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
501 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
502 if (OutputFormat == sysv)
503 outs() << o->getFileName() << " (ex " << UA->getFileName()
504 << "):\n";
505 else if(MachO && OutputFormat == darwin)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000506 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
507 << " (for architecture " << I->getArchTypeName()
508 << "):\n";
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000509 PrintObjectSectionSizes(o);
510 if (OutputFormat == berkeley) {
511 if (MachO)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000512 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
513 << " (for architecture " << I->getArchTypeName()
514 << ")\n";
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000515 else
516 outs() << o->getFileName() << " (ex " << UA->getFileName()
517 << ")\n";
518 }
519 }
520 }
521 }
522 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000523 } else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) {
524 if (OutputFormat == sysv)
525 outs() << o->getFileName() << " :\n";
526 PrintObjectSectionSizes(o);
Kevin Enderby246a4602014-06-17 17:54:13 +0000527 if (OutputFormat == berkeley) {
528 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
529 if (!MachO || moreThanOneFile)
530 outs() << o->getFileName();
531 outs() << "\n";
532 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000533 } else {
534 errs() << ToolName << ": " << file << ": " << "Unrecognized file type.\n";
535 }
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000536 // System V adds an extra newline at the end of each file.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000537 if (OutputFormat == sysv)
538 outs() << "\n";
539}
540
541int main(int argc, char **argv) {
542 // Print a stack trace if we signal out.
543 sys::PrintStackTraceOnErrorSignal();
544 PrettyStackTraceProgram X(argc, argv);
545
546 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
547 cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
548
549 ToolName = argv[0];
550 if (OutputFormatShort.getNumOccurrences())
551 OutputFormat = OutputFormatShort;
552 if (RadixShort.getNumOccurrences())
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000553 Radix = RadixShort;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000554
555 if (InputFilenames.size() == 0)
556 InputFilenames.push_back("a.out");
557
Kevin Enderby246a4602014-06-17 17:54:13 +0000558 moreThanOneFile = InputFilenames.size() > 1;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000559 std::for_each(InputFilenames.begin(), InputFilenames.end(),
560 PrintFileSectionSizes);
561
562 return 0;
563}