162cfcf62SDimitry Andric //===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===// 262cfcf62SDimitry Andric // 362cfcf62SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 462cfcf62SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 562cfcf62SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 662cfcf62SDimitry Andric // 762cfcf62SDimitry Andric //===----------------------------------------------------------------------===// 862cfcf62SDimitry Andric // 962cfcf62SDimitry Andric // This program is a utility that works like traditional Unix "size", 1062cfcf62SDimitry Andric // that is, it prints out the size of each section, and the total size of all 1162cfcf62SDimitry Andric // sections. 1262cfcf62SDimitry Andric // 1362cfcf62SDimitry Andric //===----------------------------------------------------------------------===// 1462cfcf62SDimitry Andric 1562cfcf62SDimitry Andric #include "llvm/ADT/APInt.h" 1662cfcf62SDimitry Andric #include "llvm/Object/Archive.h" 1762cfcf62SDimitry Andric #include "llvm/Object/ELFObjectFile.h" 1862cfcf62SDimitry Andric #include "llvm/Object/MachO.h" 1962cfcf62SDimitry Andric #include "llvm/Object/MachOUniversal.h" 2062cfcf62SDimitry Andric #include "llvm/Object/ObjectFile.h" 2162cfcf62SDimitry Andric #include "llvm/Support/Casting.h" 2262cfcf62SDimitry Andric #include "llvm/Support/CommandLine.h" 2362cfcf62SDimitry Andric #include "llvm/Support/FileSystem.h" 2462cfcf62SDimitry Andric #include "llvm/Support/Format.h" 2562cfcf62SDimitry Andric #include "llvm/Support/InitLLVM.h" 2662cfcf62SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 2762cfcf62SDimitry Andric #include "llvm/Support/WithColor.h" 2862cfcf62SDimitry Andric #include "llvm/Support/raw_ostream.h" 2962cfcf62SDimitry Andric #include <algorithm> 3062cfcf62SDimitry Andric #include <string> 3162cfcf62SDimitry Andric #include <system_error> 3262cfcf62SDimitry Andric 3362cfcf62SDimitry Andric using namespace llvm; 3462cfcf62SDimitry Andric using namespace object; 3562cfcf62SDimitry Andric 3662cfcf62SDimitry Andric cl::OptionCategory SizeCat("llvm-size Options"); 3762cfcf62SDimitry Andric 3862cfcf62SDimitry Andric enum OutputFormatTy { berkeley, sysv, darwin }; 3962cfcf62SDimitry Andric static cl::opt<OutputFormatTy> 4062cfcf62SDimitry Andric OutputFormat("format", cl::desc("Specify output format"), 4162cfcf62SDimitry Andric cl::values(clEnumVal(sysv, "System V format"), 4262cfcf62SDimitry Andric clEnumVal(berkeley, "Berkeley format"), 4362cfcf62SDimitry Andric clEnumVal(darwin, "Darwin -m format")), 4462cfcf62SDimitry Andric cl::init(berkeley), cl::cat(SizeCat)); 4562cfcf62SDimitry Andric 4662cfcf62SDimitry Andric static cl::opt<OutputFormatTy> 4762cfcf62SDimitry Andric OutputFormatShort(cl::desc("Specify output format"), 4862cfcf62SDimitry Andric cl::values(clEnumValN(sysv, "A", "System V format"), 4962cfcf62SDimitry Andric clEnumValN(berkeley, "B", "Berkeley format"), 5062cfcf62SDimitry Andric clEnumValN(darwin, "m", "Darwin -m format")), 5162cfcf62SDimitry Andric cl::init(berkeley), cl::cat(SizeCat)); 5262cfcf62SDimitry Andric 5362cfcf62SDimitry Andric static bool BerkeleyHeaderPrinted = false; 5462cfcf62SDimitry Andric static bool MoreThanOneFile = false; 5562cfcf62SDimitry Andric static uint64_t TotalObjectText = 0; 5662cfcf62SDimitry Andric static uint64_t TotalObjectData = 0; 5762cfcf62SDimitry Andric static uint64_t TotalObjectBss = 0; 5862cfcf62SDimitry Andric static uint64_t TotalObjectTotal = 0; 5962cfcf62SDimitry Andric 6062cfcf62SDimitry Andric cl::opt<bool> 6162cfcf62SDimitry Andric DarwinLongFormat("l", 6262cfcf62SDimitry Andric cl::desc("When format is darwin, use long format " 6362cfcf62SDimitry Andric "to include addresses and offsets."), 6462cfcf62SDimitry Andric cl::cat(SizeCat)); 6562cfcf62SDimitry Andric 6662cfcf62SDimitry Andric cl::opt<bool> 6762cfcf62SDimitry Andric ELFCommons("common", 6862cfcf62SDimitry Andric cl::desc("Print common symbols in the ELF file. When using " 6962cfcf62SDimitry Andric "Berkeley format, this is added to bss."), 7062cfcf62SDimitry Andric cl::init(false), cl::cat(SizeCat)); 7162cfcf62SDimitry Andric 7262cfcf62SDimitry Andric static cl::list<std::string> 7362cfcf62SDimitry Andric ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), 7462cfcf62SDimitry Andric cl::ZeroOrMore, cl::cat(SizeCat)); 7562cfcf62SDimitry Andric static bool ArchAll = false; 7662cfcf62SDimitry Andric 7762cfcf62SDimitry Andric enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 }; 7862cfcf62SDimitry Andric static cl::opt<RadixTy> Radix( 7962cfcf62SDimitry Andric "radix", cl::desc("Print size in radix"), cl::init(decimal), 8062cfcf62SDimitry Andric cl::values(clEnumValN(octal, "8", "Print size in octal"), 8162cfcf62SDimitry Andric clEnumValN(decimal, "10", "Print size in decimal"), 8262cfcf62SDimitry Andric clEnumValN(hexadecimal, "16", "Print size in hexadecimal")), 8362cfcf62SDimitry Andric cl::cat(SizeCat)); 8462cfcf62SDimitry Andric 8562cfcf62SDimitry Andric static cl::opt<RadixTy> RadixShort( 8662cfcf62SDimitry Andric cl::desc("Print size in radix:"), 8762cfcf62SDimitry Andric cl::values(clEnumValN(octal, "o", "Print size in octal"), 8862cfcf62SDimitry Andric clEnumValN(decimal, "d", "Print size in decimal"), 8962cfcf62SDimitry Andric clEnumValN(hexadecimal, "x", "Print size in hexadecimal")), 9062cfcf62SDimitry Andric cl::init(decimal), cl::cat(SizeCat)); 9162cfcf62SDimitry Andric 9262cfcf62SDimitry Andric static cl::opt<bool> 9362cfcf62SDimitry Andric TotalSizes("totals", 9462cfcf62SDimitry Andric cl::desc("Print totals of all objects - Berkeley format only"), 9562cfcf62SDimitry Andric cl::init(false), cl::cat(SizeCat)); 9662cfcf62SDimitry Andric 9762cfcf62SDimitry Andric static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"), 9862cfcf62SDimitry Andric cl::aliasopt(TotalSizes)); 9962cfcf62SDimitry Andric 10062cfcf62SDimitry Andric static cl::list<std::string> 10162cfcf62SDimitry Andric InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore); 10262cfcf62SDimitry Andric 10362cfcf62SDimitry Andric static cl::extrahelp 10462cfcf62SDimitry Andric HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); 10562cfcf62SDimitry Andric 10662cfcf62SDimitry Andric static bool HadError = false; 10762cfcf62SDimitry Andric 10862cfcf62SDimitry Andric static std::string ToolName; 10962cfcf62SDimitry Andric 11062cfcf62SDimitry Andric static void error(const Twine &Message, StringRef File) { 11162cfcf62SDimitry Andric HadError = true; 11262cfcf62SDimitry Andric WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n"; 11362cfcf62SDimitry Andric } 11462cfcf62SDimitry Andric 11562cfcf62SDimitry Andric // This version of error() prints the archive name and member name, for example: 11662cfcf62SDimitry Andric // "libx.a(foo.o)" after the ToolName before the error message. It sets 11762cfcf62SDimitry Andric // HadError but returns allowing the code to move on to other archive members. 11862cfcf62SDimitry Andric static void error(llvm::Error E, StringRef FileName, const Archive::Child &C, 11962cfcf62SDimitry Andric StringRef ArchitectureName = StringRef()) { 12062cfcf62SDimitry Andric HadError = true; 12162cfcf62SDimitry Andric WithColor::error(errs(), ToolName) << "'" << FileName << "'"; 12262cfcf62SDimitry Andric 12362cfcf62SDimitry Andric Expected<StringRef> NameOrErr = C.getName(); 12462cfcf62SDimitry Andric // TODO: if we have a error getting the name then it would be nice to print 12562cfcf62SDimitry Andric // the index of which archive member this is and or its offset in the 12662cfcf62SDimitry Andric // archive instead of "???" as the name. 12762cfcf62SDimitry Andric if (!NameOrErr) { 12862cfcf62SDimitry Andric consumeError(NameOrErr.takeError()); 12962cfcf62SDimitry Andric errs() << "(" << "???" << ")"; 13062cfcf62SDimitry Andric } else 13162cfcf62SDimitry Andric errs() << "(" << NameOrErr.get() << ")"; 13262cfcf62SDimitry Andric 13362cfcf62SDimitry Andric if (!ArchitectureName.empty()) 13462cfcf62SDimitry Andric errs() << " (for architecture " << ArchitectureName << ") "; 13562cfcf62SDimitry Andric 13662cfcf62SDimitry Andric std::string Buf; 13762cfcf62SDimitry Andric raw_string_ostream OS(Buf); 13862cfcf62SDimitry Andric logAllUnhandledErrors(std::move(E), OS); 13962cfcf62SDimitry Andric OS.flush(); 14062cfcf62SDimitry Andric errs() << ": " << Buf << "\n"; 14162cfcf62SDimitry Andric } 14262cfcf62SDimitry Andric 14362cfcf62SDimitry Andric // 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 14462cfcf62SDimitry Andric // before the error message. It sets HadError but returns allowing the code to 14562cfcf62SDimitry Andric // move on to other architecture slices. 14662cfcf62SDimitry Andric static void error(llvm::Error E, StringRef FileName, 14762cfcf62SDimitry Andric StringRef ArchitectureName = StringRef()) { 14862cfcf62SDimitry Andric HadError = true; 14962cfcf62SDimitry Andric WithColor::error(errs(), ToolName) << "'" << FileName << "'"; 15062cfcf62SDimitry Andric 15162cfcf62SDimitry Andric if (!ArchitectureName.empty()) 15262cfcf62SDimitry Andric errs() << " (for architecture " << ArchitectureName << ") "; 15362cfcf62SDimitry Andric 15462cfcf62SDimitry Andric std::string Buf; 15562cfcf62SDimitry Andric raw_string_ostream OS(Buf); 15662cfcf62SDimitry Andric logAllUnhandledErrors(std::move(E), OS); 15762cfcf62SDimitry Andric OS.flush(); 15862cfcf62SDimitry Andric errs() << ": " << Buf << "\n"; 15962cfcf62SDimitry Andric } 16062cfcf62SDimitry Andric 16162cfcf62SDimitry Andric /// Get the length of the string that represents @p num in Radix including the 16262cfcf62SDimitry Andric /// leading 0x or 0 for hexadecimal and octal respectively. 16362cfcf62SDimitry Andric static size_t getNumLengthAsString(uint64_t num) { 16462cfcf62SDimitry Andric APInt conv(64, num); 16562cfcf62SDimitry Andric SmallString<32> result; 16662cfcf62SDimitry Andric conv.toString(result, Radix, false, true); 16762cfcf62SDimitry Andric return result.size(); 16862cfcf62SDimitry Andric } 16962cfcf62SDimitry Andric 17062cfcf62SDimitry Andric /// Return the printing format for the Radix. 17162cfcf62SDimitry Andric static const char *getRadixFmt() { 17262cfcf62SDimitry Andric switch (Radix) { 17362cfcf62SDimitry Andric case octal: 17462cfcf62SDimitry Andric return PRIo64; 17562cfcf62SDimitry Andric case decimal: 17662cfcf62SDimitry Andric return PRIu64; 17762cfcf62SDimitry Andric case hexadecimal: 17862cfcf62SDimitry Andric return PRIx64; 17962cfcf62SDimitry Andric } 18062cfcf62SDimitry Andric return nullptr; 18162cfcf62SDimitry Andric } 18262cfcf62SDimitry Andric 18362cfcf62SDimitry Andric /// Remove unneeded ELF sections from calculation 18462cfcf62SDimitry Andric static bool considerForSize(ObjectFile *Obj, SectionRef Section) { 18562cfcf62SDimitry Andric if (!Obj->isELF()) 18662cfcf62SDimitry Andric return true; 18762cfcf62SDimitry Andric switch (static_cast<ELFSectionRef>(Section).getType()) { 18862cfcf62SDimitry Andric case ELF::SHT_NULL: 18962cfcf62SDimitry Andric case ELF::SHT_SYMTAB: 190*5ffd83dbSDimitry Andric return false; 19162cfcf62SDimitry Andric case ELF::SHT_STRTAB: 19262cfcf62SDimitry Andric case ELF::SHT_REL: 19362cfcf62SDimitry Andric case ELF::SHT_RELA: 194*5ffd83dbSDimitry Andric return static_cast<ELFSectionRef>(Section).getFlags() & ELF::SHF_ALLOC; 19562cfcf62SDimitry Andric } 19662cfcf62SDimitry Andric return true; 19762cfcf62SDimitry Andric } 19862cfcf62SDimitry Andric 19962cfcf62SDimitry Andric /// Total size of all ELF common symbols 200*5ffd83dbSDimitry Andric static Expected<uint64_t> getCommonSize(ObjectFile *Obj) { 20162cfcf62SDimitry Andric uint64_t TotalCommons = 0; 202*5ffd83dbSDimitry Andric for (auto &Sym : Obj->symbols()) { 203*5ffd83dbSDimitry Andric Expected<uint32_t> SymFlagsOrErr = 204*5ffd83dbSDimitry Andric Obj->getSymbolFlags(Sym.getRawDataRefImpl()); 205*5ffd83dbSDimitry Andric if (!SymFlagsOrErr) 206*5ffd83dbSDimitry Andric return SymFlagsOrErr.takeError(); 207*5ffd83dbSDimitry Andric if (*SymFlagsOrErr & SymbolRef::SF_Common) 20862cfcf62SDimitry Andric TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl()); 209*5ffd83dbSDimitry Andric } 21062cfcf62SDimitry Andric return TotalCommons; 21162cfcf62SDimitry Andric } 21262cfcf62SDimitry Andric 21362cfcf62SDimitry Andric /// Print the size of each Mach-O segment and section in @p MachO. 21462cfcf62SDimitry Andric /// 21562cfcf62SDimitry Andric /// This is when used when @c OutputFormat is darwin and produces the same 21662cfcf62SDimitry Andric /// output as darwin's size(1) -m output. 21762cfcf62SDimitry Andric static void printDarwinSectionSizes(MachOObjectFile *MachO) { 21862cfcf62SDimitry Andric std::string fmtbuf; 21962cfcf62SDimitry Andric raw_string_ostream fmt(fmtbuf); 22062cfcf62SDimitry Andric const char *radix_fmt = getRadixFmt(); 22162cfcf62SDimitry Andric if (Radix == hexadecimal) 22262cfcf62SDimitry Andric fmt << "0x"; 22362cfcf62SDimitry Andric fmt << "%" << radix_fmt; 22462cfcf62SDimitry Andric 22562cfcf62SDimitry Andric uint32_t Filetype = MachO->getHeader().filetype; 22662cfcf62SDimitry Andric 22762cfcf62SDimitry Andric uint64_t total = 0; 22862cfcf62SDimitry Andric for (const auto &Load : MachO->load_commands()) { 22962cfcf62SDimitry Andric if (Load.C.cmd == MachO::LC_SEGMENT_64) { 23062cfcf62SDimitry Andric MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); 23162cfcf62SDimitry Andric outs() << "Segment " << Seg.segname << ": " 23262cfcf62SDimitry Andric << format(fmt.str().c_str(), Seg.vmsize); 23362cfcf62SDimitry Andric if (DarwinLongFormat) 23462cfcf62SDimitry Andric outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff " 23562cfcf62SDimitry Andric << Seg.fileoff << ")"; 23662cfcf62SDimitry Andric outs() << "\n"; 23762cfcf62SDimitry Andric total += Seg.vmsize; 23862cfcf62SDimitry Andric uint64_t sec_total = 0; 23962cfcf62SDimitry Andric for (unsigned J = 0; J < Seg.nsects; ++J) { 24062cfcf62SDimitry Andric MachO::section_64 Sec = MachO->getSection64(Load, J); 24162cfcf62SDimitry Andric if (Filetype == MachO::MH_OBJECT) 24262cfcf62SDimitry Andric outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " 24362cfcf62SDimitry Andric << format("%.16s", &Sec.sectname) << "): "; 24462cfcf62SDimitry Andric else 24562cfcf62SDimitry Andric outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; 24662cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), Sec.size); 24762cfcf62SDimitry Andric if (DarwinLongFormat) 24862cfcf62SDimitry Andric outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset " 24962cfcf62SDimitry Andric << Sec.offset << ")"; 25062cfcf62SDimitry Andric outs() << "\n"; 25162cfcf62SDimitry Andric sec_total += Sec.size; 25262cfcf62SDimitry Andric } 25362cfcf62SDimitry Andric if (Seg.nsects != 0) 25462cfcf62SDimitry Andric outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; 25562cfcf62SDimitry Andric } else if (Load.C.cmd == MachO::LC_SEGMENT) { 25662cfcf62SDimitry Andric MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); 25762cfcf62SDimitry Andric uint64_t Seg_vmsize = Seg.vmsize; 25862cfcf62SDimitry Andric outs() << "Segment " << Seg.segname << ": " 25962cfcf62SDimitry Andric << format(fmt.str().c_str(), Seg_vmsize); 26062cfcf62SDimitry Andric if (DarwinLongFormat) 26162cfcf62SDimitry Andric outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff " 26262cfcf62SDimitry Andric << Seg.fileoff << ")"; 26362cfcf62SDimitry Andric outs() << "\n"; 26462cfcf62SDimitry Andric total += Seg.vmsize; 26562cfcf62SDimitry Andric uint64_t sec_total = 0; 26662cfcf62SDimitry Andric for (unsigned J = 0; J < Seg.nsects; ++J) { 26762cfcf62SDimitry Andric MachO::section Sec = MachO->getSection(Load, J); 26862cfcf62SDimitry Andric if (Filetype == MachO::MH_OBJECT) 26962cfcf62SDimitry Andric outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " 27062cfcf62SDimitry Andric << format("%.16s", &Sec.sectname) << "): "; 27162cfcf62SDimitry Andric else 27262cfcf62SDimitry Andric outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; 27362cfcf62SDimitry Andric uint64_t Sec_size = Sec.size; 27462cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), Sec_size); 27562cfcf62SDimitry Andric if (DarwinLongFormat) 27662cfcf62SDimitry Andric outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset " 27762cfcf62SDimitry Andric << Sec.offset << ")"; 27862cfcf62SDimitry Andric outs() << "\n"; 27962cfcf62SDimitry Andric sec_total += Sec.size; 28062cfcf62SDimitry Andric } 28162cfcf62SDimitry Andric if (Seg.nsects != 0) 28262cfcf62SDimitry Andric outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; 28362cfcf62SDimitry Andric } 28462cfcf62SDimitry Andric } 28562cfcf62SDimitry Andric outs() << "total " << format(fmt.str().c_str(), total) << "\n"; 28662cfcf62SDimitry Andric } 28762cfcf62SDimitry Andric 28862cfcf62SDimitry Andric /// Print the summary sizes of the standard Mach-O segments in @p MachO. 28962cfcf62SDimitry Andric /// 29062cfcf62SDimitry Andric /// This is when used when @c OutputFormat is berkeley with a Mach-O file and 29162cfcf62SDimitry Andric /// produces the same output as darwin's size(1) default output. 29262cfcf62SDimitry Andric static void printDarwinSegmentSizes(MachOObjectFile *MachO) { 29362cfcf62SDimitry Andric uint64_t total_text = 0; 29462cfcf62SDimitry Andric uint64_t total_data = 0; 29562cfcf62SDimitry Andric uint64_t total_objc = 0; 29662cfcf62SDimitry Andric uint64_t total_others = 0; 29762cfcf62SDimitry Andric for (const auto &Load : MachO->load_commands()) { 29862cfcf62SDimitry Andric if (Load.C.cmd == MachO::LC_SEGMENT_64) { 29962cfcf62SDimitry Andric MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); 30062cfcf62SDimitry Andric if (MachO->getHeader().filetype == MachO::MH_OBJECT) { 30162cfcf62SDimitry Andric for (unsigned J = 0; J < Seg.nsects; ++J) { 30262cfcf62SDimitry Andric MachO::section_64 Sec = MachO->getSection64(Load, J); 30362cfcf62SDimitry Andric StringRef SegmentName = StringRef(Sec.segname); 30462cfcf62SDimitry Andric if (SegmentName == "__TEXT") 30562cfcf62SDimitry Andric total_text += Sec.size; 30662cfcf62SDimitry Andric else if (SegmentName == "__DATA") 30762cfcf62SDimitry Andric total_data += Sec.size; 30862cfcf62SDimitry Andric else if (SegmentName == "__OBJC") 30962cfcf62SDimitry Andric total_objc += Sec.size; 31062cfcf62SDimitry Andric else 31162cfcf62SDimitry Andric total_others += Sec.size; 31262cfcf62SDimitry Andric } 31362cfcf62SDimitry Andric } else { 31462cfcf62SDimitry Andric StringRef SegmentName = StringRef(Seg.segname); 31562cfcf62SDimitry Andric if (SegmentName == "__TEXT") 31662cfcf62SDimitry Andric total_text += Seg.vmsize; 31762cfcf62SDimitry Andric else if (SegmentName == "__DATA") 31862cfcf62SDimitry Andric total_data += Seg.vmsize; 31962cfcf62SDimitry Andric else if (SegmentName == "__OBJC") 32062cfcf62SDimitry Andric total_objc += Seg.vmsize; 32162cfcf62SDimitry Andric else 32262cfcf62SDimitry Andric total_others += Seg.vmsize; 32362cfcf62SDimitry Andric } 32462cfcf62SDimitry Andric } else if (Load.C.cmd == MachO::LC_SEGMENT) { 32562cfcf62SDimitry Andric MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); 32662cfcf62SDimitry Andric if (MachO->getHeader().filetype == MachO::MH_OBJECT) { 32762cfcf62SDimitry Andric for (unsigned J = 0; J < Seg.nsects; ++J) { 32862cfcf62SDimitry Andric MachO::section Sec = MachO->getSection(Load, J); 32962cfcf62SDimitry Andric StringRef SegmentName = StringRef(Sec.segname); 33062cfcf62SDimitry Andric if (SegmentName == "__TEXT") 33162cfcf62SDimitry Andric total_text += Sec.size; 33262cfcf62SDimitry Andric else if (SegmentName == "__DATA") 33362cfcf62SDimitry Andric total_data += Sec.size; 33462cfcf62SDimitry Andric else if (SegmentName == "__OBJC") 33562cfcf62SDimitry Andric total_objc += Sec.size; 33662cfcf62SDimitry Andric else 33762cfcf62SDimitry Andric total_others += Sec.size; 33862cfcf62SDimitry Andric } 33962cfcf62SDimitry Andric } else { 34062cfcf62SDimitry Andric StringRef SegmentName = StringRef(Seg.segname); 34162cfcf62SDimitry Andric if (SegmentName == "__TEXT") 34262cfcf62SDimitry Andric total_text += Seg.vmsize; 34362cfcf62SDimitry Andric else if (SegmentName == "__DATA") 34462cfcf62SDimitry Andric total_data += Seg.vmsize; 34562cfcf62SDimitry Andric else if (SegmentName == "__OBJC") 34662cfcf62SDimitry Andric total_objc += Seg.vmsize; 34762cfcf62SDimitry Andric else 34862cfcf62SDimitry Andric total_others += Seg.vmsize; 34962cfcf62SDimitry Andric } 35062cfcf62SDimitry Andric } 35162cfcf62SDimitry Andric } 35262cfcf62SDimitry Andric uint64_t total = total_text + total_data + total_objc + total_others; 35362cfcf62SDimitry Andric 35462cfcf62SDimitry Andric if (!BerkeleyHeaderPrinted) { 35562cfcf62SDimitry Andric outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n"; 35662cfcf62SDimitry Andric BerkeleyHeaderPrinted = true; 35762cfcf62SDimitry Andric } 35862cfcf62SDimitry Andric outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t" 35962cfcf62SDimitry Andric << total_others << "\t" << total << "\t" << format("%" PRIx64, total) 36062cfcf62SDimitry Andric << "\t"; 36162cfcf62SDimitry Andric } 36262cfcf62SDimitry Andric 36362cfcf62SDimitry Andric /// Print the size of each section in @p Obj. 36462cfcf62SDimitry Andric /// 36562cfcf62SDimitry Andric /// The format used is determined by @c OutputFormat and @c Radix. 36662cfcf62SDimitry Andric static void printObjectSectionSizes(ObjectFile *Obj) { 36762cfcf62SDimitry Andric uint64_t total = 0; 36862cfcf62SDimitry Andric std::string fmtbuf; 36962cfcf62SDimitry Andric raw_string_ostream fmt(fmtbuf); 37062cfcf62SDimitry Andric const char *radix_fmt = getRadixFmt(); 37162cfcf62SDimitry Andric 37262cfcf62SDimitry Andric // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's 37362cfcf62SDimitry Andric // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object 37462cfcf62SDimitry Andric // let it fall through to OutputFormat berkeley. 37562cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj); 37662cfcf62SDimitry Andric if (OutputFormat == darwin && MachO) 37762cfcf62SDimitry Andric printDarwinSectionSizes(MachO); 37862cfcf62SDimitry Andric // If we have a MachOObjectFile and the OutputFormat is berkeley print as 37962cfcf62SDimitry Andric // darwin's default berkeley format for Mach-O files. 38062cfcf62SDimitry Andric else if (MachO && OutputFormat == berkeley) 38162cfcf62SDimitry Andric printDarwinSegmentSizes(MachO); 38262cfcf62SDimitry Andric else if (OutputFormat == sysv) { 38362cfcf62SDimitry Andric // Run two passes over all sections. The first gets the lengths needed for 38462cfcf62SDimitry Andric // formatting the output. The second actually does the output. 38562cfcf62SDimitry Andric std::size_t max_name_len = strlen("section"); 38662cfcf62SDimitry Andric std::size_t max_size_len = strlen("size"); 38762cfcf62SDimitry Andric std::size_t max_addr_len = strlen("addr"); 38862cfcf62SDimitry Andric for (const SectionRef &Section : Obj->sections()) { 38962cfcf62SDimitry Andric if (!considerForSize(Obj, Section)) 39062cfcf62SDimitry Andric continue; 39162cfcf62SDimitry Andric uint64_t size = Section.getSize(); 39262cfcf62SDimitry Andric total += size; 39362cfcf62SDimitry Andric 39462cfcf62SDimitry Andric Expected<StringRef> name_or_err = Section.getName(); 39562cfcf62SDimitry Andric if (!name_or_err) { 39662cfcf62SDimitry Andric error(name_or_err.takeError(), Obj->getFileName()); 39762cfcf62SDimitry Andric return; 39862cfcf62SDimitry Andric } 39962cfcf62SDimitry Andric 40062cfcf62SDimitry Andric uint64_t addr = Section.getAddress(); 40162cfcf62SDimitry Andric max_name_len = std::max(max_name_len, name_or_err->size()); 40262cfcf62SDimitry Andric max_size_len = std::max(max_size_len, getNumLengthAsString(size)); 40362cfcf62SDimitry Andric max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr)); 40462cfcf62SDimitry Andric } 40562cfcf62SDimitry Andric 40662cfcf62SDimitry Andric // Add extra padding. 40762cfcf62SDimitry Andric max_name_len += 2; 40862cfcf62SDimitry Andric max_size_len += 2; 40962cfcf62SDimitry Andric max_addr_len += 2; 41062cfcf62SDimitry Andric 41162cfcf62SDimitry Andric // Setup header format. 41262cfcf62SDimitry Andric fmt << "%-" << max_name_len << "s " 41362cfcf62SDimitry Andric << "%" << max_size_len << "s " 41462cfcf62SDimitry Andric << "%" << max_addr_len << "s\n"; 41562cfcf62SDimitry Andric 41662cfcf62SDimitry Andric // Print header 41762cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), static_cast<const char *>("section"), 41862cfcf62SDimitry Andric static_cast<const char *>("size"), 41962cfcf62SDimitry Andric static_cast<const char *>("addr")); 42062cfcf62SDimitry Andric fmtbuf.clear(); 42162cfcf62SDimitry Andric 42262cfcf62SDimitry Andric // Setup per section format. 42362cfcf62SDimitry Andric fmt << "%-" << max_name_len << "s " 42462cfcf62SDimitry Andric << "%#" << max_size_len << radix_fmt << " " 42562cfcf62SDimitry Andric << "%#" << max_addr_len << radix_fmt << "\n"; 42662cfcf62SDimitry Andric 42762cfcf62SDimitry Andric // Print each section. 42862cfcf62SDimitry Andric for (const SectionRef &Section : Obj->sections()) { 42962cfcf62SDimitry Andric if (!considerForSize(Obj, Section)) 43062cfcf62SDimitry Andric continue; 43162cfcf62SDimitry Andric 43262cfcf62SDimitry Andric Expected<StringRef> name_or_err = Section.getName(); 43362cfcf62SDimitry Andric if (!name_or_err) { 43462cfcf62SDimitry Andric error(name_or_err.takeError(), Obj->getFileName()); 43562cfcf62SDimitry Andric return; 43662cfcf62SDimitry Andric } 43762cfcf62SDimitry Andric 43862cfcf62SDimitry Andric uint64_t size = Section.getSize(); 43962cfcf62SDimitry Andric uint64_t addr = Section.getAddress(); 44062cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), name_or_err->str().c_str(), size, addr); 44162cfcf62SDimitry Andric } 44262cfcf62SDimitry Andric 44362cfcf62SDimitry Andric if (ELFCommons) { 444*5ffd83dbSDimitry Andric if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) { 445*5ffd83dbSDimitry Andric total += *CommonSizeOrErr; 44662cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(), 447*5ffd83dbSDimitry Andric *CommonSizeOrErr, static_cast<uint64_t>(0)); 448*5ffd83dbSDimitry Andric } else { 449*5ffd83dbSDimitry Andric error(CommonSizeOrErr.takeError(), Obj->getFileName()); 450*5ffd83dbSDimitry Andric return; 451*5ffd83dbSDimitry Andric } 45262cfcf62SDimitry Andric } 45362cfcf62SDimitry Andric 45462cfcf62SDimitry Andric // Print total. 45562cfcf62SDimitry Andric fmtbuf.clear(); 45662cfcf62SDimitry Andric fmt << "%-" << max_name_len << "s " 45762cfcf62SDimitry Andric << "%#" << max_size_len << radix_fmt << "\n"; 45862cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"), 45962cfcf62SDimitry Andric total) 46062cfcf62SDimitry Andric << "\n\n"; 46162cfcf62SDimitry Andric } else { 46262cfcf62SDimitry Andric // The Berkeley format does not display individual section sizes. It 46362cfcf62SDimitry Andric // displays the cumulative size for each section type. 46462cfcf62SDimitry Andric uint64_t total_text = 0; 46562cfcf62SDimitry Andric uint64_t total_data = 0; 46662cfcf62SDimitry Andric uint64_t total_bss = 0; 46762cfcf62SDimitry Andric 46862cfcf62SDimitry Andric // Make one pass over the section table to calculate sizes. 46962cfcf62SDimitry Andric for (const SectionRef &Section : Obj->sections()) { 47062cfcf62SDimitry Andric uint64_t size = Section.getSize(); 47162cfcf62SDimitry Andric bool isText = Section.isBerkeleyText(); 47262cfcf62SDimitry Andric bool isData = Section.isBerkeleyData(); 47362cfcf62SDimitry Andric bool isBSS = Section.isBSS(); 47462cfcf62SDimitry Andric if (isText) 47562cfcf62SDimitry Andric total_text += size; 47662cfcf62SDimitry Andric else if (isData) 47762cfcf62SDimitry Andric total_data += size; 47862cfcf62SDimitry Andric else if (isBSS) 47962cfcf62SDimitry Andric total_bss += size; 48062cfcf62SDimitry Andric } 48162cfcf62SDimitry Andric 482*5ffd83dbSDimitry Andric if (ELFCommons) { 483*5ffd83dbSDimitry Andric if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) 484*5ffd83dbSDimitry Andric total_bss += *CommonSizeOrErr; 485*5ffd83dbSDimitry Andric else { 486*5ffd83dbSDimitry Andric error(CommonSizeOrErr.takeError(), Obj->getFileName()); 487*5ffd83dbSDimitry Andric return; 488*5ffd83dbSDimitry Andric } 489*5ffd83dbSDimitry Andric } 49062cfcf62SDimitry Andric 49162cfcf62SDimitry Andric total = total_text + total_data + total_bss; 49262cfcf62SDimitry Andric 49362cfcf62SDimitry Andric if (TotalSizes) { 49462cfcf62SDimitry Andric TotalObjectText += total_text; 49562cfcf62SDimitry Andric TotalObjectData += total_data; 49662cfcf62SDimitry Andric TotalObjectBss += total_bss; 49762cfcf62SDimitry Andric TotalObjectTotal += total; 49862cfcf62SDimitry Andric } 49962cfcf62SDimitry Andric 50062cfcf62SDimitry Andric if (!BerkeleyHeaderPrinted) { 50162cfcf62SDimitry Andric outs() << " text\t" 50262cfcf62SDimitry Andric " data\t" 50362cfcf62SDimitry Andric " bss\t" 50462cfcf62SDimitry Andric " " 50562cfcf62SDimitry Andric << (Radix == octal ? "oct" : "dec") 50662cfcf62SDimitry Andric << "\t" 50762cfcf62SDimitry Andric " hex\t" 50862cfcf62SDimitry Andric "filename\n"; 50962cfcf62SDimitry Andric BerkeleyHeaderPrinted = true; 51062cfcf62SDimitry Andric } 51162cfcf62SDimitry Andric 51262cfcf62SDimitry Andric // Print result. 51362cfcf62SDimitry Andric fmt << "%#7" << radix_fmt << "\t" 51462cfcf62SDimitry Andric << "%#7" << radix_fmt << "\t" 51562cfcf62SDimitry Andric << "%#7" << radix_fmt << "\t"; 51662cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), total_text, total_data, total_bss); 51762cfcf62SDimitry Andric fmtbuf.clear(); 51862cfcf62SDimitry Andric fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" 51962cfcf62SDimitry Andric << "%7" PRIx64 "\t"; 52062cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), total, total); 52162cfcf62SDimitry Andric } 52262cfcf62SDimitry Andric } 52362cfcf62SDimitry Andric 52462cfcf62SDimitry Andric /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there 52562cfcf62SDimitry Andric /// is a list of architecture flags specified then check to make sure this 52662cfcf62SDimitry Andric /// Mach-O file is one of those architectures or all architectures was 52762cfcf62SDimitry Andric /// specificed. If not then an error is generated and this routine returns 52862cfcf62SDimitry Andric /// false. Else it returns true. 52962cfcf62SDimitry Andric static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { 53062cfcf62SDimitry Andric auto *MachO = dyn_cast<MachOObjectFile>(O); 53162cfcf62SDimitry Andric 53262cfcf62SDimitry Andric if (!MachO || ArchAll || ArchFlags.empty()) 53362cfcf62SDimitry Andric return true; 53462cfcf62SDimitry Andric 53562cfcf62SDimitry Andric MachO::mach_header H; 53662cfcf62SDimitry Andric MachO::mach_header_64 H_64; 53762cfcf62SDimitry Andric Triple T; 53862cfcf62SDimitry Andric if (MachO->is64Bit()) { 53962cfcf62SDimitry Andric H_64 = MachO->MachOObjectFile::getHeader64(); 54062cfcf62SDimitry Andric T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); 54162cfcf62SDimitry Andric } else { 54262cfcf62SDimitry Andric H = MachO->MachOObjectFile::getHeader(); 54362cfcf62SDimitry Andric T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); 54462cfcf62SDimitry Andric } 54562cfcf62SDimitry Andric if (none_of(ArchFlags, [&](const std::string &Name) { 54662cfcf62SDimitry Andric return Name == T.getArchName(); 54762cfcf62SDimitry Andric })) { 54862cfcf62SDimitry Andric error("no architecture specified", Filename); 54962cfcf62SDimitry Andric return false; 55062cfcf62SDimitry Andric } 55162cfcf62SDimitry Andric return true; 55262cfcf62SDimitry Andric } 55362cfcf62SDimitry Andric 55462cfcf62SDimitry Andric /// Print the section sizes for @p file. If @p file is an archive, print the 55562cfcf62SDimitry Andric /// section sizes for each archive member. 55662cfcf62SDimitry Andric static void printFileSectionSizes(StringRef file) { 55762cfcf62SDimitry Andric 55862cfcf62SDimitry Andric // Attempt to open the binary. 55962cfcf62SDimitry Andric Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file); 56062cfcf62SDimitry Andric if (!BinaryOrErr) { 56162cfcf62SDimitry Andric error(BinaryOrErr.takeError(), file); 56262cfcf62SDimitry Andric return; 56362cfcf62SDimitry Andric } 56462cfcf62SDimitry Andric Binary &Bin = *BinaryOrErr.get().getBinary(); 56562cfcf62SDimitry Andric 56662cfcf62SDimitry Andric if (Archive *a = dyn_cast<Archive>(&Bin)) { 56762cfcf62SDimitry Andric // This is an archive. Iterate over each member and display its sizes. 56862cfcf62SDimitry Andric Error Err = Error::success(); 56962cfcf62SDimitry Andric for (auto &C : a->children(Err)) { 57062cfcf62SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 57162cfcf62SDimitry Andric if (!ChildOrErr) { 57262cfcf62SDimitry Andric if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) 57362cfcf62SDimitry Andric error(std::move(E), a->getFileName(), C); 57462cfcf62SDimitry Andric continue; 57562cfcf62SDimitry Andric } 57662cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 57762cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 57862cfcf62SDimitry Andric if (!checkMachOAndArchFlags(o, file)) 57962cfcf62SDimitry Andric return; 58062cfcf62SDimitry Andric if (OutputFormat == sysv) 58162cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n"; 58262cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) 58362cfcf62SDimitry Andric outs() << a->getFileName() << "(" << o->getFileName() << "):\n"; 58462cfcf62SDimitry Andric printObjectSectionSizes(o); 58562cfcf62SDimitry Andric if (OutputFormat == berkeley) { 58662cfcf62SDimitry Andric if (MachO) 58762cfcf62SDimitry Andric outs() << a->getFileName() << "(" << o->getFileName() << ")\n"; 58862cfcf62SDimitry Andric else 58962cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; 59062cfcf62SDimitry Andric } 59162cfcf62SDimitry Andric } 59262cfcf62SDimitry Andric } 59362cfcf62SDimitry Andric if (Err) 59462cfcf62SDimitry Andric error(std::move(Err), a->getFileName()); 59562cfcf62SDimitry Andric } else if (MachOUniversalBinary *UB = 59662cfcf62SDimitry Andric dyn_cast<MachOUniversalBinary>(&Bin)) { 59762cfcf62SDimitry Andric // If we have a list of architecture flags specified dump only those. 59862cfcf62SDimitry Andric if (!ArchAll && !ArchFlags.empty()) { 59962cfcf62SDimitry Andric // Look for a slice in the universal binary that matches each ArchFlag. 60062cfcf62SDimitry Andric bool ArchFound; 60162cfcf62SDimitry Andric for (unsigned i = 0; i < ArchFlags.size(); ++i) { 60262cfcf62SDimitry Andric ArchFound = false; 60362cfcf62SDimitry Andric for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 60462cfcf62SDimitry Andric E = UB->end_objects(); 60562cfcf62SDimitry Andric I != E; ++I) { 60662cfcf62SDimitry Andric if (ArchFlags[i] == I->getArchFlagName()) { 60762cfcf62SDimitry Andric ArchFound = true; 60862cfcf62SDimitry Andric Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 60962cfcf62SDimitry Andric if (UO) { 61062cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 61162cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 61262cfcf62SDimitry Andric if (OutputFormat == sysv) 61362cfcf62SDimitry Andric outs() << o->getFileName() << " :\n"; 61462cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) { 61562cfcf62SDimitry Andric if (MoreThanOneFile || ArchFlags.size() > 1) 61662cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 61762cfcf62SDimitry Andric << I->getArchFlagName() << "): \n"; 61862cfcf62SDimitry Andric } 61962cfcf62SDimitry Andric printObjectSectionSizes(o); 62062cfcf62SDimitry Andric if (OutputFormat == berkeley) { 62162cfcf62SDimitry Andric if (!MachO || MoreThanOneFile || ArchFlags.size() > 1) 62262cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 62362cfcf62SDimitry Andric << I->getArchFlagName() << ")"; 62462cfcf62SDimitry Andric outs() << "\n"; 62562cfcf62SDimitry Andric } 62662cfcf62SDimitry Andric } 62762cfcf62SDimitry Andric } else if (auto E = isNotObjectErrorInvalidFileType( 62862cfcf62SDimitry Andric UO.takeError())) { 62962cfcf62SDimitry Andric error(std::move(E), file, ArchFlags.size() > 1 ? 63062cfcf62SDimitry Andric StringRef(I->getArchFlagName()) : StringRef()); 63162cfcf62SDimitry Andric return; 63262cfcf62SDimitry Andric } else if (Expected<std::unique_ptr<Archive>> AOrErr = 63362cfcf62SDimitry Andric I->getAsArchive()) { 63462cfcf62SDimitry Andric std::unique_ptr<Archive> &UA = *AOrErr; 63562cfcf62SDimitry Andric // This is an archive. Iterate over each member and display its 63662cfcf62SDimitry Andric // sizes. 63762cfcf62SDimitry Andric Error Err = Error::success(); 63862cfcf62SDimitry Andric for (auto &C : UA->children(Err)) { 63962cfcf62SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 64062cfcf62SDimitry Andric if (!ChildOrErr) { 64162cfcf62SDimitry Andric if (auto E = isNotObjectErrorInvalidFileType( 64262cfcf62SDimitry Andric ChildOrErr.takeError())) 64362cfcf62SDimitry Andric error(std::move(E), UA->getFileName(), C, 64462cfcf62SDimitry Andric ArchFlags.size() > 1 ? 64562cfcf62SDimitry Andric StringRef(I->getArchFlagName()) : StringRef()); 64662cfcf62SDimitry Andric continue; 64762cfcf62SDimitry Andric } 64862cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 64962cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 65062cfcf62SDimitry Andric if (OutputFormat == sysv) 65162cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 65262cfcf62SDimitry Andric << "):\n"; 65362cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) 65462cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() 65562cfcf62SDimitry Andric << ")" 65662cfcf62SDimitry Andric << " (for architecture " << I->getArchFlagName() 65762cfcf62SDimitry Andric << "):\n"; 65862cfcf62SDimitry Andric printObjectSectionSizes(o); 65962cfcf62SDimitry Andric if (OutputFormat == berkeley) { 66062cfcf62SDimitry Andric if (MachO) { 66162cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() 66262cfcf62SDimitry Andric << ")"; 66362cfcf62SDimitry Andric if (ArchFlags.size() > 1) 66462cfcf62SDimitry Andric outs() << " (for architecture " << I->getArchFlagName() 66562cfcf62SDimitry Andric << ")"; 66662cfcf62SDimitry Andric outs() << "\n"; 66762cfcf62SDimitry Andric } else 66862cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 66962cfcf62SDimitry Andric << ")\n"; 67062cfcf62SDimitry Andric } 67162cfcf62SDimitry Andric } 67262cfcf62SDimitry Andric } 67362cfcf62SDimitry Andric if (Err) 67462cfcf62SDimitry Andric error(std::move(Err), UA->getFileName()); 67562cfcf62SDimitry Andric } else { 67662cfcf62SDimitry Andric consumeError(AOrErr.takeError()); 67762cfcf62SDimitry Andric error("mach-o universal file for architecture " + 67862cfcf62SDimitry Andric StringRef(I->getArchFlagName()) + 67962cfcf62SDimitry Andric " is not a mach-o file or an archive file", 68062cfcf62SDimitry Andric file); 68162cfcf62SDimitry Andric } 68262cfcf62SDimitry Andric } 68362cfcf62SDimitry Andric } 68462cfcf62SDimitry Andric if (!ArchFound) { 68562cfcf62SDimitry Andric error("file does not contain architecture " + ArchFlags[i], file); 68662cfcf62SDimitry Andric return; 68762cfcf62SDimitry Andric } 68862cfcf62SDimitry Andric } 68962cfcf62SDimitry Andric return; 69062cfcf62SDimitry Andric } 69162cfcf62SDimitry Andric // No architecture flags were specified so if this contains a slice that 69262cfcf62SDimitry Andric // matches the host architecture dump only that. 69362cfcf62SDimitry Andric if (!ArchAll) { 69462cfcf62SDimitry Andric StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); 69562cfcf62SDimitry Andric for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 69662cfcf62SDimitry Andric E = UB->end_objects(); 69762cfcf62SDimitry Andric I != E; ++I) { 69862cfcf62SDimitry Andric if (HostArchName == I->getArchFlagName()) { 69962cfcf62SDimitry Andric Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 70062cfcf62SDimitry Andric if (UO) { 70162cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 70262cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 70362cfcf62SDimitry Andric if (OutputFormat == sysv) 70462cfcf62SDimitry Andric outs() << o->getFileName() << " :\n"; 70562cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) { 70662cfcf62SDimitry Andric if (MoreThanOneFile) 70762cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 70862cfcf62SDimitry Andric << I->getArchFlagName() << "):\n"; 70962cfcf62SDimitry Andric } 71062cfcf62SDimitry Andric printObjectSectionSizes(o); 71162cfcf62SDimitry Andric if (OutputFormat == berkeley) { 71262cfcf62SDimitry Andric if (!MachO || MoreThanOneFile) 71362cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 71462cfcf62SDimitry Andric << I->getArchFlagName() << ")"; 71562cfcf62SDimitry Andric outs() << "\n"; 71662cfcf62SDimitry Andric } 71762cfcf62SDimitry Andric } 71862cfcf62SDimitry Andric } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 71962cfcf62SDimitry Andric error(std::move(E), file); 72062cfcf62SDimitry Andric return; 72162cfcf62SDimitry Andric } else if (Expected<std::unique_ptr<Archive>> AOrErr = 72262cfcf62SDimitry Andric I->getAsArchive()) { 72362cfcf62SDimitry Andric std::unique_ptr<Archive> &UA = *AOrErr; 72462cfcf62SDimitry Andric // This is an archive. Iterate over each member and display its 72562cfcf62SDimitry Andric // sizes. 72662cfcf62SDimitry Andric Error Err = Error::success(); 72762cfcf62SDimitry Andric for (auto &C : UA->children(Err)) { 72862cfcf62SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 72962cfcf62SDimitry Andric if (!ChildOrErr) { 73062cfcf62SDimitry Andric if (auto E = isNotObjectErrorInvalidFileType( 73162cfcf62SDimitry Andric ChildOrErr.takeError())) 73262cfcf62SDimitry Andric error(std::move(E), UA->getFileName(), C); 73362cfcf62SDimitry Andric continue; 73462cfcf62SDimitry Andric } 73562cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 73662cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 73762cfcf62SDimitry Andric if (OutputFormat == sysv) 73862cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 73962cfcf62SDimitry Andric << "):\n"; 74062cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) 74162cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() << ")" 74262cfcf62SDimitry Andric << " (for architecture " << I->getArchFlagName() 74362cfcf62SDimitry Andric << "):\n"; 74462cfcf62SDimitry Andric printObjectSectionSizes(o); 74562cfcf62SDimitry Andric if (OutputFormat == berkeley) { 74662cfcf62SDimitry Andric if (MachO) 74762cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() 74862cfcf62SDimitry Andric << ")\n"; 74962cfcf62SDimitry Andric else 75062cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 75162cfcf62SDimitry Andric << ")\n"; 75262cfcf62SDimitry Andric } 75362cfcf62SDimitry Andric } 75462cfcf62SDimitry Andric } 75562cfcf62SDimitry Andric if (Err) 75662cfcf62SDimitry Andric error(std::move(Err), UA->getFileName()); 75762cfcf62SDimitry Andric } else { 75862cfcf62SDimitry Andric consumeError(AOrErr.takeError()); 75962cfcf62SDimitry Andric error("mach-o universal file for architecture " + 76062cfcf62SDimitry Andric StringRef(I->getArchFlagName()) + 76162cfcf62SDimitry Andric " is not a mach-o file or an archive file", 76262cfcf62SDimitry Andric file); 76362cfcf62SDimitry Andric } 76462cfcf62SDimitry Andric return; 76562cfcf62SDimitry Andric } 76662cfcf62SDimitry Andric } 76762cfcf62SDimitry Andric } 76862cfcf62SDimitry Andric // Either all architectures have been specified or none have been specified 76962cfcf62SDimitry Andric // and this does not contain the host architecture so dump all the slices. 77062cfcf62SDimitry Andric bool MoreThanOneArch = UB->getNumberOfObjects() > 1; 77162cfcf62SDimitry Andric for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 77262cfcf62SDimitry Andric E = UB->end_objects(); 77362cfcf62SDimitry Andric I != E; ++I) { 77462cfcf62SDimitry Andric Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 77562cfcf62SDimitry Andric if (UO) { 77662cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 77762cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 77862cfcf62SDimitry Andric if (OutputFormat == sysv) 77962cfcf62SDimitry Andric outs() << o->getFileName() << " :\n"; 78062cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) { 78162cfcf62SDimitry Andric if (MoreThanOneFile || MoreThanOneArch) 78262cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 78362cfcf62SDimitry Andric << I->getArchFlagName() << "):"; 78462cfcf62SDimitry Andric outs() << "\n"; 78562cfcf62SDimitry Andric } 78662cfcf62SDimitry Andric printObjectSectionSizes(o); 78762cfcf62SDimitry Andric if (OutputFormat == berkeley) { 78862cfcf62SDimitry Andric if (!MachO || MoreThanOneFile || MoreThanOneArch) 78962cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 79062cfcf62SDimitry Andric << I->getArchFlagName() << ")"; 79162cfcf62SDimitry Andric outs() << "\n"; 79262cfcf62SDimitry Andric } 79362cfcf62SDimitry Andric } 79462cfcf62SDimitry Andric } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 79562cfcf62SDimitry Andric error(std::move(E), file, MoreThanOneArch ? 79662cfcf62SDimitry Andric StringRef(I->getArchFlagName()) : StringRef()); 79762cfcf62SDimitry Andric return; 79862cfcf62SDimitry Andric } else if (Expected<std::unique_ptr<Archive>> AOrErr = 79962cfcf62SDimitry Andric I->getAsArchive()) { 80062cfcf62SDimitry Andric std::unique_ptr<Archive> &UA = *AOrErr; 80162cfcf62SDimitry Andric // This is an archive. Iterate over each member and display its sizes. 80262cfcf62SDimitry Andric Error Err = Error::success(); 80362cfcf62SDimitry Andric for (auto &C : UA->children(Err)) { 80462cfcf62SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 80562cfcf62SDimitry Andric if (!ChildOrErr) { 80662cfcf62SDimitry Andric if (auto E = isNotObjectErrorInvalidFileType( 80762cfcf62SDimitry Andric ChildOrErr.takeError())) 80862cfcf62SDimitry Andric error(std::move(E), UA->getFileName(), C, MoreThanOneArch ? 80962cfcf62SDimitry Andric StringRef(I->getArchFlagName()) : StringRef()); 81062cfcf62SDimitry Andric continue; 81162cfcf62SDimitry Andric } 81262cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 81362cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 81462cfcf62SDimitry Andric if (OutputFormat == sysv) 81562cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 81662cfcf62SDimitry Andric << "):\n"; 81762cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) 81862cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() << ")" 81962cfcf62SDimitry Andric << " (for architecture " << I->getArchFlagName() << "):\n"; 82062cfcf62SDimitry Andric printObjectSectionSizes(o); 82162cfcf62SDimitry Andric if (OutputFormat == berkeley) { 82262cfcf62SDimitry Andric if (MachO) 82362cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() << ")" 82462cfcf62SDimitry Andric << " (for architecture " << I->getArchFlagName() 82562cfcf62SDimitry Andric << ")\n"; 82662cfcf62SDimitry Andric else 82762cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 82862cfcf62SDimitry Andric << ")\n"; 82962cfcf62SDimitry Andric } 83062cfcf62SDimitry Andric } 83162cfcf62SDimitry Andric } 83262cfcf62SDimitry Andric if (Err) 83362cfcf62SDimitry Andric error(std::move(Err), UA->getFileName()); 83462cfcf62SDimitry Andric } else { 83562cfcf62SDimitry Andric consumeError(AOrErr.takeError()); 83662cfcf62SDimitry Andric error("mach-o universal file for architecture " + 83762cfcf62SDimitry Andric StringRef(I->getArchFlagName()) + 83862cfcf62SDimitry Andric " is not a mach-o file or an archive file", 83962cfcf62SDimitry Andric file); 84062cfcf62SDimitry Andric } 84162cfcf62SDimitry Andric } 84262cfcf62SDimitry Andric } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) { 84362cfcf62SDimitry Andric if (!checkMachOAndArchFlags(o, file)) 84462cfcf62SDimitry Andric return; 84562cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 84662cfcf62SDimitry Andric if (OutputFormat == sysv) 84762cfcf62SDimitry Andric outs() << o->getFileName() << " :\n"; 84862cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin && MoreThanOneFile) 84962cfcf62SDimitry Andric outs() << o->getFileName() << ":\n"; 85062cfcf62SDimitry Andric printObjectSectionSizes(o); 85162cfcf62SDimitry Andric if (OutputFormat == berkeley) { 85262cfcf62SDimitry Andric if (!MachO || MoreThanOneFile) 85362cfcf62SDimitry Andric outs() << o->getFileName(); 85462cfcf62SDimitry Andric outs() << "\n"; 85562cfcf62SDimitry Andric } 85662cfcf62SDimitry Andric } else { 85762cfcf62SDimitry Andric error("unsupported file type", file); 85862cfcf62SDimitry Andric } 85962cfcf62SDimitry Andric } 86062cfcf62SDimitry Andric 86162cfcf62SDimitry Andric static void printBerkeleyTotals() { 86262cfcf62SDimitry Andric std::string fmtbuf; 86362cfcf62SDimitry Andric raw_string_ostream fmt(fmtbuf); 86462cfcf62SDimitry Andric const char *radix_fmt = getRadixFmt(); 86562cfcf62SDimitry Andric fmt << "%#7" << radix_fmt << "\t" 86662cfcf62SDimitry Andric << "%#7" << radix_fmt << "\t" 86762cfcf62SDimitry Andric << "%#7" << radix_fmt << "\t"; 86862cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData, 86962cfcf62SDimitry Andric TotalObjectBss); 87062cfcf62SDimitry Andric fmtbuf.clear(); 87162cfcf62SDimitry Andric fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" 87262cfcf62SDimitry Andric << "%7" PRIx64 "\t"; 87362cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal) 87462cfcf62SDimitry Andric << "(TOTALS)\n"; 87562cfcf62SDimitry Andric } 87662cfcf62SDimitry Andric 87762cfcf62SDimitry Andric int main(int argc, char **argv) { 87862cfcf62SDimitry Andric InitLLVM X(argc, argv); 87962cfcf62SDimitry Andric cl::HideUnrelatedOptions(SizeCat); 88062cfcf62SDimitry Andric cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n"); 88162cfcf62SDimitry Andric 88262cfcf62SDimitry Andric ToolName = argv[0]; 88362cfcf62SDimitry Andric if (OutputFormatShort.getNumOccurrences()) 88462cfcf62SDimitry Andric OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort); 88562cfcf62SDimitry Andric if (RadixShort.getNumOccurrences()) 88662cfcf62SDimitry Andric Radix = RadixShort.getValue(); 88762cfcf62SDimitry Andric 88862cfcf62SDimitry Andric for (StringRef Arch : ArchFlags) { 88962cfcf62SDimitry Andric if (Arch == "all") { 89062cfcf62SDimitry Andric ArchAll = true; 89162cfcf62SDimitry Andric } else { 89262cfcf62SDimitry Andric if (!MachOObjectFile::isValidArch(Arch)) { 89362cfcf62SDimitry Andric outs() << ToolName << ": for the -arch option: Unknown architecture " 89462cfcf62SDimitry Andric << "named '" << Arch << "'"; 89562cfcf62SDimitry Andric return 1; 89662cfcf62SDimitry Andric } 89762cfcf62SDimitry Andric } 89862cfcf62SDimitry Andric } 89962cfcf62SDimitry Andric 90062cfcf62SDimitry Andric if (InputFilenames.empty()) 90162cfcf62SDimitry Andric InputFilenames.push_back("a.out"); 90262cfcf62SDimitry Andric 90362cfcf62SDimitry Andric MoreThanOneFile = InputFilenames.size() > 1; 90462cfcf62SDimitry Andric llvm::for_each(InputFilenames, printFileSectionSizes); 90562cfcf62SDimitry Andric if (OutputFormat == berkeley && TotalSizes) 90662cfcf62SDimitry Andric printBerkeleyTotals(); 90762cfcf62SDimitry Andric 90862cfcf62SDimitry Andric if (HadError) 90962cfcf62SDimitry Andric return 1; 91062cfcf62SDimitry Andric } 911