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