brintos

brintos / llvm-project-archived public Read only

0
0
Text · 35.4 KiB · ec94db4 Raw
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