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