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