diff options
Diffstat (limited to 'contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp | 910 | 
1 files changed, 910 insertions, 0 deletions
| diff --git a/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp b/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp new file mode 100644 index 000000000000..987270e98c48 --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp @@ -0,0 +1,910 @@ +//===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that works like traditional Unix "size", +// that is, it prints out the size of each section, and the total size of all +// sections. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/APInt.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <string> +#include <system_error> + +using namespace llvm; +using namespace object; + +cl::OptionCategory SizeCat("llvm-size Options"); + +enum OutputFormatTy { berkeley, sysv, darwin }; +static cl::opt<OutputFormatTy> +    OutputFormat("format", cl::desc("Specify output format"), +                 cl::values(clEnumVal(sysv, "System V format"), +                            clEnumVal(berkeley, "Berkeley format"), +                            clEnumVal(darwin, "Darwin -m format")), +                 cl::init(berkeley), cl::cat(SizeCat)); + +static cl::opt<OutputFormatTy> +    OutputFormatShort(cl::desc("Specify output format"), +                      cl::values(clEnumValN(sysv, "A", "System V format"), +                                 clEnumValN(berkeley, "B", "Berkeley format"), +                                 clEnumValN(darwin, "m", "Darwin -m format")), +                      cl::init(berkeley), cl::cat(SizeCat)); + +static bool BerkeleyHeaderPrinted = false; +static bool MoreThanOneFile = false; +static uint64_t TotalObjectText = 0; +static uint64_t TotalObjectData = 0; +static uint64_t TotalObjectBss = 0; +static uint64_t TotalObjectTotal = 0; + +cl::opt<bool> +    DarwinLongFormat("l", +                     cl::desc("When format is darwin, use long format " +                              "to include addresses and offsets."), +                     cl::cat(SizeCat)); + +cl::opt<bool> +    ELFCommons("common", +               cl::desc("Print common symbols in the ELF file.  When using " +                        "Berkeley format, this is added to bss."), +               cl::init(false), cl::cat(SizeCat)); + +static cl::list<std::string> +    ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), +              cl::ZeroOrMore, cl::cat(SizeCat)); +static bool ArchAll = false; + +enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 }; +static cl::opt<RadixTy> Radix( +    "radix", cl::desc("Print size in radix"), cl::init(decimal), +    cl::values(clEnumValN(octal, "8", "Print size in octal"), +               clEnumValN(decimal, "10", "Print size in decimal"), +               clEnumValN(hexadecimal, "16", "Print size in hexadecimal")), +    cl::cat(SizeCat)); + +static cl::opt<RadixTy> RadixShort( +    cl::desc("Print size in radix:"), +    cl::values(clEnumValN(octal, "o", "Print size in octal"), +               clEnumValN(decimal, "d", "Print size in decimal"), +               clEnumValN(hexadecimal, "x", "Print size in hexadecimal")), +    cl::init(decimal), cl::cat(SizeCat)); + +static cl::opt<bool> +    TotalSizes("totals", +               cl::desc("Print totals of all objects - Berkeley format only"), +               cl::init(false), cl::cat(SizeCat)); + +static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"), +                                 cl::aliasopt(TotalSizes)); + +static cl::list<std::string> +    InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore); + +static cl::extrahelp +    HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); + +static bool HadError = false; + +static std::string ToolName; + +static void error(const Twine &Message, StringRef File) { +  HadError = true; +  WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n"; +} + +// This version of error() prints the archive name and member name, for example: +// "libx.a(foo.o)" after the ToolName before the error message.  It sets +// HadError but returns allowing the code to move on to other archive members. +static void error(llvm::Error E, StringRef FileName, const Archive::Child &C, +                  StringRef ArchitectureName = StringRef()) { +  HadError = true; +  WithColor::error(errs(), ToolName) << "'" << FileName << "'"; + +  Expected<StringRef> NameOrErr = C.getName(); +  // TODO: if we have a error getting the name then it would be nice to print +  // the index of which archive member this is and or its offset in the +  // archive instead of "???" as the name. +  if (!NameOrErr) { +    consumeError(NameOrErr.takeError()); +    errs() << "(" << "???" << ")"; +  } else +    errs() << "(" << NameOrErr.get() << ")"; + +  if (!ArchitectureName.empty()) +    errs() << " (for architecture " << ArchitectureName << ") "; + +  std::string Buf; +  raw_string_ostream OS(Buf); +  logAllUnhandledErrors(std::move(E), OS); +  OS.flush(); +  errs() << ": " << Buf << "\n"; +} + +// This version of error() prints the file name and which architecture slice it // is from, for example: "foo.o (for architecture i386)" after the ToolName +// before the error message.  It sets HadError but returns allowing the code to +// move on to other architecture slices. +static void error(llvm::Error E, StringRef FileName, +                  StringRef ArchitectureName = StringRef()) { +  HadError = true; +  WithColor::error(errs(), ToolName) << "'" << FileName << "'"; + +  if (!ArchitectureName.empty()) +    errs() << " (for architecture " << ArchitectureName << ") "; + +  std::string Buf; +  raw_string_ostream OS(Buf); +  logAllUnhandledErrors(std::move(E), OS); +  OS.flush(); +  errs() << ": " << Buf << "\n"; +} + +/// Get the length of the string that represents @p num in Radix including the +/// leading 0x or 0 for hexadecimal and octal respectively. +static size_t getNumLengthAsString(uint64_t num) { +  APInt conv(64, num); +  SmallString<32> result; +  conv.toString(result, Radix, false, true); +  return result.size(); +} + +/// Return the printing format for the Radix. +static const char *getRadixFmt() { +  switch (Radix) { +  case octal: +    return PRIo64; +  case decimal: +    return PRIu64; +  case hexadecimal: +    return PRIx64; +  } +  return nullptr; +} + +/// Remove unneeded ELF sections from calculation +static bool considerForSize(ObjectFile *Obj, SectionRef Section) { +  if (!Obj->isELF()) +    return true; +  switch (static_cast<ELFSectionRef>(Section).getType()) { +  case ELF::SHT_NULL: +  case ELF::SHT_SYMTAB: +    return false; +  case ELF::SHT_STRTAB: +  case ELF::SHT_REL: +  case ELF::SHT_RELA: +    return static_cast<ELFSectionRef>(Section).getFlags() & ELF::SHF_ALLOC; +  } +  return true; +} + +/// Total size of all ELF common symbols +static Expected<uint64_t> getCommonSize(ObjectFile *Obj) { +  uint64_t TotalCommons = 0; +  for (auto &Sym : Obj->symbols()) { +    Expected<uint32_t> SymFlagsOrErr = +        Obj->getSymbolFlags(Sym.getRawDataRefImpl()); +    if (!SymFlagsOrErr) +      return SymFlagsOrErr.takeError(); +    if (*SymFlagsOrErr & SymbolRef::SF_Common) +      TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl()); +  } +  return TotalCommons; +} + +/// Print the size of each Mach-O segment and section in @p MachO. +/// +/// This is when used when @c OutputFormat is darwin and produces the same +/// output as darwin's size(1) -m output. +static void printDarwinSectionSizes(MachOObjectFile *MachO) { +  std::string fmtbuf; +  raw_string_ostream fmt(fmtbuf); +  const char *radix_fmt = getRadixFmt(); +  if (Radix == hexadecimal) +    fmt << "0x"; +  fmt << "%" << radix_fmt; + +  uint32_t Filetype = MachO->getHeader().filetype; + +  uint64_t total = 0; +  for (const auto &Load : MachO->load_commands()) { +    if (Load.C.cmd == MachO::LC_SEGMENT_64) { +      MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); +      outs() << "Segment " << Seg.segname << ": " +             << format(fmt.str().c_str(), Seg.vmsize); +      if (DarwinLongFormat) +        outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff " +               << Seg.fileoff << ")"; +      outs() << "\n"; +      total += Seg.vmsize; +      uint64_t sec_total = 0; +      for (unsigned J = 0; J < Seg.nsects; ++J) { +        MachO::section_64 Sec = MachO->getSection64(Load, J); +        if (Filetype == MachO::MH_OBJECT) +          outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " +                 << format("%.16s", &Sec.sectname) << "): "; +        else +          outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; +        outs() << format(fmt.str().c_str(), Sec.size); +        if (DarwinLongFormat) +          outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset " +                 << Sec.offset << ")"; +        outs() << "\n"; +        sec_total += Sec.size; +      } +      if (Seg.nsects != 0) +        outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; +    } else if (Load.C.cmd == MachO::LC_SEGMENT) { +      MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); +      uint64_t Seg_vmsize = Seg.vmsize; +      outs() << "Segment " << Seg.segname << ": " +             << format(fmt.str().c_str(), Seg_vmsize); +      if (DarwinLongFormat) +        outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff " +               << Seg.fileoff << ")"; +      outs() << "\n"; +      total += Seg.vmsize; +      uint64_t sec_total = 0; +      for (unsigned J = 0; J < Seg.nsects; ++J) { +        MachO::section Sec = MachO->getSection(Load, J); +        if (Filetype == MachO::MH_OBJECT) +          outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " +                 << format("%.16s", &Sec.sectname) << "): "; +        else +          outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; +        uint64_t Sec_size = Sec.size; +        outs() << format(fmt.str().c_str(), Sec_size); +        if (DarwinLongFormat) +          outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset " +                 << Sec.offset << ")"; +        outs() << "\n"; +        sec_total += Sec.size; +      } +      if (Seg.nsects != 0) +        outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; +    } +  } +  outs() << "total " << format(fmt.str().c_str(), total) << "\n"; +} + +/// Print the summary sizes of the standard Mach-O segments in @p MachO. +/// +/// This is when used when @c OutputFormat is berkeley with a Mach-O file and +/// produces the same output as darwin's size(1) default output. +static void printDarwinSegmentSizes(MachOObjectFile *MachO) { +  uint64_t total_text = 0; +  uint64_t total_data = 0; +  uint64_t total_objc = 0; +  uint64_t total_others = 0; +  for (const auto &Load : MachO->load_commands()) { +    if (Load.C.cmd == MachO::LC_SEGMENT_64) { +      MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); +      if (MachO->getHeader().filetype == MachO::MH_OBJECT) { +        for (unsigned J = 0; J < Seg.nsects; ++J) { +          MachO::section_64 Sec = MachO->getSection64(Load, J); +          StringRef SegmentName = StringRef(Sec.segname); +          if (SegmentName == "__TEXT") +            total_text += Sec.size; +          else if (SegmentName == "__DATA") +            total_data += Sec.size; +          else if (SegmentName == "__OBJC") +            total_objc += Sec.size; +          else +            total_others += Sec.size; +        } +      } else { +        StringRef SegmentName = StringRef(Seg.segname); +        if (SegmentName == "__TEXT") +          total_text += Seg.vmsize; +        else if (SegmentName == "__DATA") +          total_data += Seg.vmsize; +        else if (SegmentName == "__OBJC") +          total_objc += Seg.vmsize; +        else +          total_others += Seg.vmsize; +      } +    } else if (Load.C.cmd == MachO::LC_SEGMENT) { +      MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); +      if (MachO->getHeader().filetype == MachO::MH_OBJECT) { +        for (unsigned J = 0; J < Seg.nsects; ++J) { +          MachO::section Sec = MachO->getSection(Load, J); +          StringRef SegmentName = StringRef(Sec.segname); +          if (SegmentName == "__TEXT") +            total_text += Sec.size; +          else if (SegmentName == "__DATA") +            total_data += Sec.size; +          else if (SegmentName == "__OBJC") +            total_objc += Sec.size; +          else +            total_others += Sec.size; +        } +      } else { +        StringRef SegmentName = StringRef(Seg.segname); +        if (SegmentName == "__TEXT") +          total_text += Seg.vmsize; +        else if (SegmentName == "__DATA") +          total_data += Seg.vmsize; +        else if (SegmentName == "__OBJC") +          total_objc += Seg.vmsize; +        else +          total_others += Seg.vmsize; +      } +    } +  } +  uint64_t total = total_text + total_data + total_objc + total_others; + +  if (!BerkeleyHeaderPrinted) { +    outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n"; +    BerkeleyHeaderPrinted = true; +  } +  outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t" +         << total_others << "\t" << total << "\t" << format("%" PRIx64, total) +         << "\t"; +} + +/// Print the size of each section in @p Obj. +/// +/// The format used is determined by @c OutputFormat and @c Radix. +static void printObjectSectionSizes(ObjectFile *Obj) { +  uint64_t total = 0; +  std::string fmtbuf; +  raw_string_ostream fmt(fmtbuf); +  const char *radix_fmt = getRadixFmt(); + +  // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's +  // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object +  // let it fall through to OutputFormat berkeley. +  MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj); +  if (OutputFormat == darwin && MachO) +    printDarwinSectionSizes(MachO); +  // If we have a MachOObjectFile and the OutputFormat is berkeley print as +  // darwin's default berkeley format for Mach-O files. +  else if (MachO && OutputFormat == berkeley) +    printDarwinSegmentSizes(MachO); +  else if (OutputFormat == sysv) { +    // Run two passes over all sections. The first gets the lengths needed for +    // formatting the output. The second actually does the output. +    std::size_t max_name_len = strlen("section"); +    std::size_t max_size_len = strlen("size"); +    std::size_t max_addr_len = strlen("addr"); +    for (const SectionRef &Section : Obj->sections()) { +      if (!considerForSize(Obj, Section)) +        continue; +      uint64_t size = Section.getSize(); +      total += size; + +      Expected<StringRef> name_or_err = Section.getName(); +      if (!name_or_err) { +        error(name_or_err.takeError(), Obj->getFileName()); +        return; +      } + +      uint64_t addr = Section.getAddress(); +      max_name_len = std::max(max_name_len, name_or_err->size()); +      max_size_len = std::max(max_size_len, getNumLengthAsString(size)); +      max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr)); +    } + +    // Add extra padding. +    max_name_len += 2; +    max_size_len += 2; +    max_addr_len += 2; + +    // Setup header format. +    fmt << "%-" << max_name_len << "s " +        << "%" << max_size_len << "s " +        << "%" << max_addr_len << "s\n"; + +    // Print header +    outs() << format(fmt.str().c_str(), static_cast<const char *>("section"), +                     static_cast<const char *>("size"), +                     static_cast<const char *>("addr")); +    fmtbuf.clear(); + +    // Setup per section format. +    fmt << "%-" << max_name_len << "s " +        << "%#" << max_size_len << radix_fmt << " " +        << "%#" << max_addr_len << radix_fmt << "\n"; + +    // Print each section. +    for (const SectionRef &Section : Obj->sections()) { +      if (!considerForSize(Obj, Section)) +        continue; + +      Expected<StringRef> name_or_err = Section.getName(); +      if (!name_or_err) { +        error(name_or_err.takeError(), Obj->getFileName()); +        return; +      } + +      uint64_t size = Section.getSize(); +      uint64_t addr = Section.getAddress(); +      outs() << format(fmt.str().c_str(), name_or_err->str().c_str(), size, addr); +    } + +    if (ELFCommons) { +      if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) { +        total += *CommonSizeOrErr; +        outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(), +                         *CommonSizeOrErr, static_cast<uint64_t>(0)); +      } else { +        error(CommonSizeOrErr.takeError(), Obj->getFileName()); +        return; +      } +    } + +    // Print total. +    fmtbuf.clear(); +    fmt << "%-" << max_name_len << "s " +        << "%#" << max_size_len << radix_fmt << "\n"; +    outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"), +                     total) +           << "\n\n"; +  } else { +    // The Berkeley format does not display individual section sizes. It +    // displays the cumulative size for each section type. +    uint64_t total_text = 0; +    uint64_t total_data = 0; +    uint64_t total_bss = 0; + +    // Make one pass over the section table to calculate sizes. +    for (const SectionRef &Section : Obj->sections()) { +      uint64_t size = Section.getSize(); +      bool isText = Section.isBerkeleyText(); +      bool isData = Section.isBerkeleyData(); +      bool isBSS = Section.isBSS(); +      if (isText) +        total_text += size; +      else if (isData) +        total_data += size; +      else if (isBSS) +        total_bss += size; +    } + +    if (ELFCommons) { +      if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) +        total_bss += *CommonSizeOrErr; +      else { +        error(CommonSizeOrErr.takeError(), Obj->getFileName()); +        return; +      } +    } + +    total = total_text + total_data + total_bss; + +    if (TotalSizes) { +      TotalObjectText += total_text; +      TotalObjectData += total_data; +      TotalObjectBss += total_bss; +      TotalObjectTotal += total; +    } + +    if (!BerkeleyHeaderPrinted) { +      outs() << "   text\t" +                "   data\t" +                "    bss\t" +                "    " +             << (Radix == octal ? "oct" : "dec") +             << "\t" +                "    hex\t" +                "filename\n"; +      BerkeleyHeaderPrinted = true; +    } + +    // Print result. +    fmt << "%#7" << radix_fmt << "\t" +        << "%#7" << radix_fmt << "\t" +        << "%#7" << radix_fmt << "\t"; +    outs() << format(fmt.str().c_str(), total_text, total_data, total_bss); +    fmtbuf.clear(); +    fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" +        << "%7" PRIx64 "\t"; +    outs() << format(fmt.str().c_str(), total, total); +  } +} + +/// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there +/// is a list of architecture flags specified then check to make sure this +/// Mach-O file is one of those architectures or all architectures was +/// specificed.  If not then an error is generated and this routine returns +/// false.  Else it returns true. +static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { +  auto *MachO = dyn_cast<MachOObjectFile>(O); + +  if (!MachO || ArchAll || ArchFlags.empty()) +    return true; + +  MachO::mach_header H; +  MachO::mach_header_64 H_64; +  Triple T; +  if (MachO->is64Bit()) { +    H_64 = MachO->MachOObjectFile::getHeader64(); +    T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); +  } else { +    H = MachO->MachOObjectFile::getHeader(); +    T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); +  } +  if (none_of(ArchFlags, [&](const std::string &Name) { +        return Name == T.getArchName(); +      })) { +    error("no architecture specified", Filename); +    return false; +  } +  return true; +} + +/// Print the section sizes for @p file. If @p file is an archive, print the +/// section sizes for each archive member. +static void printFileSectionSizes(StringRef file) { + +  // Attempt to open the binary. +  Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file); +  if (!BinaryOrErr) { +    error(BinaryOrErr.takeError(), file); +    return; +  } +  Binary &Bin = *BinaryOrErr.get().getBinary(); + +  if (Archive *a = dyn_cast<Archive>(&Bin)) { +    // This is an archive. Iterate over each member and display its sizes. +    Error Err = Error::success(); +    for (auto &C : a->children(Err)) { +      Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); +      if (!ChildOrErr) { +        if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) +          error(std::move(E), a->getFileName(), C); +        continue; +      } +      if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { +        MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); +        if (!checkMachOAndArchFlags(o, file)) +          return; +        if (OutputFormat == sysv) +          outs() << o->getFileName() << "   (ex " << a->getFileName() << "):\n"; +        else if (MachO && OutputFormat == darwin) +          outs() << a->getFileName() << "(" << o->getFileName() << "):\n"; +        printObjectSectionSizes(o); +        if (OutputFormat == berkeley) { +          if (MachO) +            outs() << a->getFileName() << "(" << o->getFileName() << ")\n"; +          else +            outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; +        } +      } +    } +    if (Err) +      error(std::move(Err), a->getFileName()); +  } else if (MachOUniversalBinary *UB = +                 dyn_cast<MachOUniversalBinary>(&Bin)) { +    // If we have a list of architecture flags specified dump only those. +    if (!ArchAll && !ArchFlags.empty()) { +      // Look for a slice in the universal binary that matches each ArchFlag. +      bool ArchFound; +      for (unsigned i = 0; i < ArchFlags.size(); ++i) { +        ArchFound = false; +        for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), +                                                   E = UB->end_objects(); +             I != E; ++I) { +          if (ArchFlags[i] == I->getArchFlagName()) { +            ArchFound = true; +            Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); +            if (UO) { +              if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { +                MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); +                if (OutputFormat == sysv) +                  outs() << o->getFileName() << "  :\n"; +                else if (MachO && OutputFormat == darwin) { +                  if (MoreThanOneFile || ArchFlags.size() > 1) +                    outs() << o->getFileName() << " (for architecture " +                           << I->getArchFlagName() << "): \n"; +                } +                printObjectSectionSizes(o); +                if (OutputFormat == berkeley) { +                  if (!MachO || MoreThanOneFile || ArchFlags.size() > 1) +                    outs() << o->getFileName() << " (for architecture " +                           << I->getArchFlagName() << ")"; +                  outs() << "\n"; +                } +              } +            } else if (auto E = isNotObjectErrorInvalidFileType( +                       UO.takeError())) { +              error(std::move(E), file, ArchFlags.size() > 1 ? +                    StringRef(I->getArchFlagName()) : StringRef()); +              return; +            } else if (Expected<std::unique_ptr<Archive>> AOrErr = +                           I->getAsArchive()) { +              std::unique_ptr<Archive> &UA = *AOrErr; +              // This is an archive. Iterate over each member and display its +              // sizes. +              Error Err = Error::success(); +              for (auto &C : UA->children(Err)) { +                Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); +                if (!ChildOrErr) { +                  if (auto E = isNotObjectErrorInvalidFileType( +                                    ChildOrErr.takeError())) +                    error(std::move(E), UA->getFileName(), C, +                          ArchFlags.size() > 1 ? +                          StringRef(I->getArchFlagName()) : StringRef()); +                  continue; +                } +                if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { +                  MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); +                  if (OutputFormat == sysv) +                    outs() << o->getFileName() << "   (ex " << UA->getFileName() +                           << "):\n"; +                  else if (MachO && OutputFormat == darwin) +                    outs() << UA->getFileName() << "(" << o->getFileName() +                           << ")" +                           << " (for architecture " << I->getArchFlagName() +                           << "):\n"; +                  printObjectSectionSizes(o); +                  if (OutputFormat == berkeley) { +                    if (MachO) { +                      outs() << UA->getFileName() << "(" << o->getFileName() +                             << ")"; +                      if (ArchFlags.size() > 1) +                        outs() << " (for architecture " << I->getArchFlagName() +                               << ")"; +                      outs() << "\n"; +                    } else +                      outs() << o->getFileName() << " (ex " << UA->getFileName() +                             << ")\n"; +                  } +                } +              } +              if (Err) +                error(std::move(Err), UA->getFileName()); +            } else { +              consumeError(AOrErr.takeError()); +              error("mach-o universal file for architecture " + +                        StringRef(I->getArchFlagName()) + +                        " is not a mach-o file or an archive file", +                    file); +            } +          } +        } +        if (!ArchFound) { +          error("file does not contain architecture " + ArchFlags[i], file); +          return; +        } +      } +      return; +    } +    // No architecture flags were specified so if this contains a slice that +    // matches the host architecture dump only that. +    if (!ArchAll) { +      StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); +      for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), +                                                 E = UB->end_objects(); +           I != E; ++I) { +        if (HostArchName == I->getArchFlagName()) { +          Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); +          if (UO) { +            if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { +              MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); +              if (OutputFormat == sysv) +                outs() << o->getFileName() << "  :\n"; +              else if (MachO && OutputFormat == darwin) { +                if (MoreThanOneFile) +                  outs() << o->getFileName() << " (for architecture " +                         << I->getArchFlagName() << "):\n"; +              } +              printObjectSectionSizes(o); +              if (OutputFormat == berkeley) { +                if (!MachO || MoreThanOneFile) +                  outs() << o->getFileName() << " (for architecture " +                         << I->getArchFlagName() << ")"; +                outs() << "\n"; +              } +            } +          } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { +            error(std::move(E), file); +            return; +          } else if (Expected<std::unique_ptr<Archive>> AOrErr = +                         I->getAsArchive()) { +            std::unique_ptr<Archive> &UA = *AOrErr; +            // This is an archive. Iterate over each member and display its +            // sizes. +            Error Err = Error::success(); +            for (auto &C : UA->children(Err)) { +              Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); +              if (!ChildOrErr) { +                if (auto E = isNotObjectErrorInvalidFileType( +                                ChildOrErr.takeError())) +                  error(std::move(E), UA->getFileName(), C); +                continue; +              } +              if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { +                MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); +                if (OutputFormat == sysv) +                  outs() << o->getFileName() << "   (ex " << UA->getFileName() +                         << "):\n"; +                else if (MachO && OutputFormat == darwin) +                  outs() << UA->getFileName() << "(" << o->getFileName() << ")" +                         << " (for architecture " << I->getArchFlagName() +                         << "):\n"; +                printObjectSectionSizes(o); +                if (OutputFormat == berkeley) { +                  if (MachO) +                    outs() << UA->getFileName() << "(" << o->getFileName() +                           << ")\n"; +                  else +                    outs() << o->getFileName() << " (ex " << UA->getFileName() +                           << ")\n"; +                } +              } +            } +            if (Err) +              error(std::move(Err), UA->getFileName()); +          } else { +            consumeError(AOrErr.takeError()); +            error("mach-o universal file for architecture " + +                      StringRef(I->getArchFlagName()) + +                      " is not a mach-o file or an archive file", +                  file); +          } +          return; +        } +      } +    } +    // Either all architectures have been specified or none have been specified +    // and this does not contain the host architecture so dump all the slices. +    bool MoreThanOneArch = UB->getNumberOfObjects() > 1; +    for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), +                                               E = UB->end_objects(); +         I != E; ++I) { +      Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); +      if (UO) { +        if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { +          MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); +          if (OutputFormat == sysv) +            outs() << o->getFileName() << "  :\n"; +          else if (MachO && OutputFormat == darwin) { +            if (MoreThanOneFile || MoreThanOneArch) +              outs() << o->getFileName() << " (for architecture " +                     << I->getArchFlagName() << "):"; +            outs() << "\n"; +          } +          printObjectSectionSizes(o); +          if (OutputFormat == berkeley) { +            if (!MachO || MoreThanOneFile || MoreThanOneArch) +              outs() << o->getFileName() << " (for architecture " +                     << I->getArchFlagName() << ")"; +            outs() << "\n"; +          } +        } +      } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { +        error(std::move(E), file, MoreThanOneArch ? +              StringRef(I->getArchFlagName()) : StringRef()); +        return; +      } else if (Expected<std::unique_ptr<Archive>> AOrErr = +                         I->getAsArchive()) { +        std::unique_ptr<Archive> &UA = *AOrErr; +        // This is an archive. Iterate over each member and display its sizes. +        Error Err = Error::success(); +        for (auto &C : UA->children(Err)) { +          Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); +          if (!ChildOrErr) { +            if (auto E = isNotObjectErrorInvalidFileType( +                              ChildOrErr.takeError())) +              error(std::move(E), UA->getFileName(), C, MoreThanOneArch ? +                    StringRef(I->getArchFlagName()) : StringRef()); +            continue; +          } +          if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { +            MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); +            if (OutputFormat == sysv) +              outs() << o->getFileName() << "   (ex " << UA->getFileName() +                     << "):\n"; +            else if (MachO && OutputFormat == darwin) +              outs() << UA->getFileName() << "(" << o->getFileName() << ")" +                     << " (for architecture " << I->getArchFlagName() << "):\n"; +            printObjectSectionSizes(o); +            if (OutputFormat == berkeley) { +              if (MachO) +                outs() << UA->getFileName() << "(" << o->getFileName() << ")" +                       << " (for architecture " << I->getArchFlagName() +                       << ")\n"; +              else +                outs() << o->getFileName() << " (ex " << UA->getFileName() +                       << ")\n"; +            } +          } +        } +        if (Err) +          error(std::move(Err), UA->getFileName()); +      } else { +        consumeError(AOrErr.takeError()); +        error("mach-o universal file for architecture " + +                  StringRef(I->getArchFlagName()) + +                  " is not a mach-o file or an archive file", +              file); +      } +    } +  } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) { +    if (!checkMachOAndArchFlags(o, file)) +      return; +    MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); +    if (OutputFormat == sysv) +      outs() << o->getFileName() << "  :\n"; +    else if (MachO && OutputFormat == darwin && MoreThanOneFile) +      outs() << o->getFileName() << ":\n"; +    printObjectSectionSizes(o); +    if (OutputFormat == berkeley) { +      if (!MachO || MoreThanOneFile) +        outs() << o->getFileName(); +      outs() << "\n"; +    } +  } else { +    error("unsupported file type", file); +  } +} + +static void printBerkeleyTotals() { +  std::string fmtbuf; +  raw_string_ostream fmt(fmtbuf); +  const char *radix_fmt = getRadixFmt(); +  fmt << "%#7" << radix_fmt << "\t" +      << "%#7" << radix_fmt << "\t" +      << "%#7" << radix_fmt << "\t"; +  outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData, +                   TotalObjectBss); +  fmtbuf.clear(); +  fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" +      << "%7" PRIx64 "\t"; +  outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal) +         << "(TOTALS)\n"; +} + +int main(int argc, char **argv) { +  InitLLVM X(argc, argv); +  cl::HideUnrelatedOptions(SizeCat); +  cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n"); + +  ToolName = argv[0]; +  if (OutputFormatShort.getNumOccurrences()) +    OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort); +  if (RadixShort.getNumOccurrences()) +    Radix = RadixShort.getValue(); + +  for (StringRef Arch : ArchFlags) { +    if (Arch == "all") { +      ArchAll = true; +    } else { +      if (!MachOObjectFile::isValidArch(Arch)) { +        outs() << ToolName << ": for the -arch option: Unknown architecture " +               << "named '" << Arch << "'"; +        return 1; +      } +    } +  } + +  if (InputFilenames.empty()) +    InputFilenames.push_back("a.out"); + +  MoreThanOneFile = InputFilenames.size() > 1; +  llvm::for_each(InputFilenames, printFileSectionSizes); +  if (OutputFormat == berkeley && TotalSizes) +    printBerkeleyTotals(); + +  if (HadError) +    return 1; +} | 
