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" 21*fe6060f1SDimitry Andric #include "llvm/Option/Arg.h" 22*fe6060f1SDimitry Andric #include "llvm/Option/ArgList.h" 23*fe6060f1SDimitry Andric #include "llvm/Option/Option.h" 2462cfcf62SDimitry Andric #include "llvm/Support/Casting.h" 2562cfcf62SDimitry Andric #include "llvm/Support/CommandLine.h" 2662cfcf62SDimitry Andric #include "llvm/Support/FileSystem.h" 2762cfcf62SDimitry Andric #include "llvm/Support/Format.h" 2862cfcf62SDimitry Andric #include "llvm/Support/InitLLVM.h" 2962cfcf62SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 3062cfcf62SDimitry Andric #include "llvm/Support/WithColor.h" 3162cfcf62SDimitry Andric #include "llvm/Support/raw_ostream.h" 3262cfcf62SDimitry Andric #include <algorithm> 3362cfcf62SDimitry Andric #include <string> 3462cfcf62SDimitry Andric #include <system_error> 3562cfcf62SDimitry Andric 3662cfcf62SDimitry Andric using namespace llvm; 3762cfcf62SDimitry Andric using namespace object; 3862cfcf62SDimitry Andric 39*fe6060f1SDimitry Andric namespace { 40*fe6060f1SDimitry Andric using namespace llvm::opt; // for HelpHidden in Opts.inc 41*fe6060f1SDimitry Andric enum ID { 42*fe6060f1SDimitry Andric OPT_INVALID = 0, // This is not an option ID. 43*fe6060f1SDimitry Andric #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 44*fe6060f1SDimitry Andric HELPTEXT, METAVAR, VALUES) \ 45*fe6060f1SDimitry Andric OPT_##ID, 46*fe6060f1SDimitry Andric #include "Opts.inc" 47*fe6060f1SDimitry Andric #undef OPTION 48*fe6060f1SDimitry Andric }; 49*fe6060f1SDimitry Andric 50*fe6060f1SDimitry Andric #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 51*fe6060f1SDimitry Andric #include "Opts.inc" 52*fe6060f1SDimitry Andric #undef PREFIX 53*fe6060f1SDimitry Andric 54*fe6060f1SDimitry Andric const opt::OptTable::Info InfoTable[] = { 55*fe6060f1SDimitry Andric #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 56*fe6060f1SDimitry Andric HELPTEXT, METAVAR, VALUES) \ 57*fe6060f1SDimitry Andric { \ 58*fe6060f1SDimitry Andric PREFIX, NAME, HELPTEXT, \ 59*fe6060f1SDimitry Andric METAVAR, OPT_##ID, opt::Option::KIND##Class, \ 60*fe6060f1SDimitry Andric PARAM, FLAGS, OPT_##GROUP, \ 61*fe6060f1SDimitry Andric OPT_##ALIAS, ALIASARGS, VALUES}, 62*fe6060f1SDimitry Andric #include "Opts.inc" 63*fe6060f1SDimitry Andric #undef OPTION 64*fe6060f1SDimitry Andric }; 65*fe6060f1SDimitry Andric 66*fe6060f1SDimitry Andric class SizeOptTable : public opt::OptTable { 67*fe6060f1SDimitry Andric public: 68*fe6060f1SDimitry Andric SizeOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); } 69*fe6060f1SDimitry Andric }; 7062cfcf62SDimitry Andric 7162cfcf62SDimitry Andric enum OutputFormatTy { berkeley, sysv, darwin }; 72*fe6060f1SDimitry Andric enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 }; 73*fe6060f1SDimitry Andric } // namespace 7462cfcf62SDimitry Andric 75*fe6060f1SDimitry Andric static bool ArchAll = false; 76*fe6060f1SDimitry Andric static std::vector<StringRef> ArchFlags; 77*fe6060f1SDimitry Andric static bool ELFCommons; 78*fe6060f1SDimitry Andric static OutputFormatTy OutputFormat; 79*fe6060f1SDimitry Andric static bool DarwinLongFormat; 80*fe6060f1SDimitry Andric static RadixTy Radix; 81*fe6060f1SDimitry Andric static bool TotalSizes; 8262cfcf62SDimitry Andric 83*fe6060f1SDimitry Andric static std::vector<std::string> InputFilenames; 84*fe6060f1SDimitry Andric 85*fe6060f1SDimitry Andric static std::string ToolName; 86*fe6060f1SDimitry Andric 87*fe6060f1SDimitry Andric // States 88*fe6060f1SDimitry Andric static bool HadError = false; 8962cfcf62SDimitry Andric static bool BerkeleyHeaderPrinted = false; 9062cfcf62SDimitry Andric static bool MoreThanOneFile = false; 9162cfcf62SDimitry Andric static uint64_t TotalObjectText = 0; 9262cfcf62SDimitry Andric static uint64_t TotalObjectData = 0; 9362cfcf62SDimitry Andric static uint64_t TotalObjectBss = 0; 9462cfcf62SDimitry Andric static uint64_t TotalObjectTotal = 0; 9562cfcf62SDimitry Andric 96*fe6060f1SDimitry Andric static void error(const Twine &Message, StringRef File = "") { 9762cfcf62SDimitry Andric HadError = true; 98*fe6060f1SDimitry Andric if (File.empty()) 99*fe6060f1SDimitry Andric WithColor::error(errs(), ToolName) << Message << '\n'; 100*fe6060f1SDimitry Andric else 101*fe6060f1SDimitry Andric WithColor::error(errs(), ToolName) 102*fe6060f1SDimitry Andric << "'" << File << "': " << Message << '\n'; 10362cfcf62SDimitry Andric } 10462cfcf62SDimitry Andric 10562cfcf62SDimitry Andric // This version of error() prints the archive name and member name, for example: 10662cfcf62SDimitry Andric // "libx.a(foo.o)" after the ToolName before the error message. It sets 10762cfcf62SDimitry Andric // HadError but returns allowing the code to move on to other archive members. 10862cfcf62SDimitry Andric static void error(llvm::Error E, StringRef FileName, const Archive::Child &C, 10962cfcf62SDimitry Andric StringRef ArchitectureName = StringRef()) { 11062cfcf62SDimitry Andric HadError = true; 11162cfcf62SDimitry Andric WithColor::error(errs(), ToolName) << "'" << FileName << "'"; 11262cfcf62SDimitry Andric 11362cfcf62SDimitry Andric Expected<StringRef> NameOrErr = C.getName(); 11462cfcf62SDimitry Andric // TODO: if we have a error getting the name then it would be nice to print 11562cfcf62SDimitry Andric // the index of which archive member this is and or its offset in the 11662cfcf62SDimitry Andric // archive instead of "???" as the name. 11762cfcf62SDimitry Andric if (!NameOrErr) { 11862cfcf62SDimitry Andric consumeError(NameOrErr.takeError()); 11962cfcf62SDimitry Andric errs() << "(" << "???" << ")"; 12062cfcf62SDimitry Andric } else 12162cfcf62SDimitry Andric errs() << "(" << NameOrErr.get() << ")"; 12262cfcf62SDimitry Andric 12362cfcf62SDimitry Andric if (!ArchitectureName.empty()) 12462cfcf62SDimitry Andric errs() << " (for architecture " << ArchitectureName << ") "; 12562cfcf62SDimitry Andric 12662cfcf62SDimitry Andric std::string Buf; 12762cfcf62SDimitry Andric raw_string_ostream OS(Buf); 12862cfcf62SDimitry Andric logAllUnhandledErrors(std::move(E), OS); 12962cfcf62SDimitry Andric OS.flush(); 13062cfcf62SDimitry Andric errs() << ": " << Buf << "\n"; 13162cfcf62SDimitry Andric } 13262cfcf62SDimitry Andric 13362cfcf62SDimitry 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 13462cfcf62SDimitry Andric // before the error message. It sets HadError but returns allowing the code to 13562cfcf62SDimitry Andric // move on to other architecture slices. 13662cfcf62SDimitry Andric static void error(llvm::Error E, StringRef FileName, 13762cfcf62SDimitry Andric StringRef ArchitectureName = StringRef()) { 13862cfcf62SDimitry Andric HadError = true; 13962cfcf62SDimitry Andric WithColor::error(errs(), ToolName) << "'" << FileName << "'"; 14062cfcf62SDimitry Andric 14162cfcf62SDimitry Andric if (!ArchitectureName.empty()) 14262cfcf62SDimitry Andric errs() << " (for architecture " << ArchitectureName << ") "; 14362cfcf62SDimitry Andric 14462cfcf62SDimitry Andric std::string Buf; 14562cfcf62SDimitry Andric raw_string_ostream OS(Buf); 14662cfcf62SDimitry Andric logAllUnhandledErrors(std::move(E), OS); 14762cfcf62SDimitry Andric OS.flush(); 14862cfcf62SDimitry Andric errs() << ": " << Buf << "\n"; 14962cfcf62SDimitry Andric } 15062cfcf62SDimitry Andric 15162cfcf62SDimitry Andric /// Get the length of the string that represents @p num in Radix including the 15262cfcf62SDimitry Andric /// leading 0x or 0 for hexadecimal and octal respectively. 15362cfcf62SDimitry Andric static size_t getNumLengthAsString(uint64_t num) { 15462cfcf62SDimitry Andric APInt conv(64, num); 15562cfcf62SDimitry Andric SmallString<32> result; 15662cfcf62SDimitry Andric conv.toString(result, Radix, false, true); 15762cfcf62SDimitry Andric return result.size(); 15862cfcf62SDimitry Andric } 15962cfcf62SDimitry Andric 16062cfcf62SDimitry Andric /// Return the printing format for the Radix. 16162cfcf62SDimitry Andric static const char *getRadixFmt() { 16262cfcf62SDimitry Andric switch (Radix) { 16362cfcf62SDimitry Andric case octal: 16462cfcf62SDimitry Andric return PRIo64; 16562cfcf62SDimitry Andric case decimal: 16662cfcf62SDimitry Andric return PRIu64; 16762cfcf62SDimitry Andric case hexadecimal: 16862cfcf62SDimitry Andric return PRIx64; 16962cfcf62SDimitry Andric } 17062cfcf62SDimitry Andric return nullptr; 17162cfcf62SDimitry Andric } 17262cfcf62SDimitry Andric 17362cfcf62SDimitry Andric /// Remove unneeded ELF sections from calculation 17462cfcf62SDimitry Andric static bool considerForSize(ObjectFile *Obj, SectionRef Section) { 17562cfcf62SDimitry Andric if (!Obj->isELF()) 17662cfcf62SDimitry Andric return true; 17762cfcf62SDimitry Andric switch (static_cast<ELFSectionRef>(Section).getType()) { 17862cfcf62SDimitry Andric case ELF::SHT_NULL: 17962cfcf62SDimitry Andric case ELF::SHT_SYMTAB: 1805ffd83dbSDimitry Andric return false; 18162cfcf62SDimitry Andric case ELF::SHT_STRTAB: 18262cfcf62SDimitry Andric case ELF::SHT_REL: 18362cfcf62SDimitry Andric case ELF::SHT_RELA: 1845ffd83dbSDimitry Andric return static_cast<ELFSectionRef>(Section).getFlags() & ELF::SHF_ALLOC; 18562cfcf62SDimitry Andric } 18662cfcf62SDimitry Andric return true; 18762cfcf62SDimitry Andric } 18862cfcf62SDimitry Andric 18962cfcf62SDimitry Andric /// Total size of all ELF common symbols 1905ffd83dbSDimitry Andric static Expected<uint64_t> getCommonSize(ObjectFile *Obj) { 19162cfcf62SDimitry Andric uint64_t TotalCommons = 0; 1925ffd83dbSDimitry Andric for (auto &Sym : Obj->symbols()) { 1935ffd83dbSDimitry Andric Expected<uint32_t> SymFlagsOrErr = 1945ffd83dbSDimitry Andric Obj->getSymbolFlags(Sym.getRawDataRefImpl()); 1955ffd83dbSDimitry Andric if (!SymFlagsOrErr) 1965ffd83dbSDimitry Andric return SymFlagsOrErr.takeError(); 1975ffd83dbSDimitry Andric if (*SymFlagsOrErr & SymbolRef::SF_Common) 19862cfcf62SDimitry Andric TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl()); 1995ffd83dbSDimitry Andric } 20062cfcf62SDimitry Andric return TotalCommons; 20162cfcf62SDimitry Andric } 20262cfcf62SDimitry Andric 20362cfcf62SDimitry Andric /// Print the size of each Mach-O segment and section in @p MachO. 20462cfcf62SDimitry Andric /// 20562cfcf62SDimitry Andric /// This is when used when @c OutputFormat is darwin and produces the same 20662cfcf62SDimitry Andric /// output as darwin's size(1) -m output. 20762cfcf62SDimitry Andric static void printDarwinSectionSizes(MachOObjectFile *MachO) { 20862cfcf62SDimitry Andric std::string fmtbuf; 20962cfcf62SDimitry Andric raw_string_ostream fmt(fmtbuf); 21062cfcf62SDimitry Andric const char *radix_fmt = getRadixFmt(); 21162cfcf62SDimitry Andric if (Radix == hexadecimal) 21262cfcf62SDimitry Andric fmt << "0x"; 21362cfcf62SDimitry Andric fmt << "%" << radix_fmt; 21462cfcf62SDimitry Andric 21562cfcf62SDimitry Andric uint32_t Filetype = MachO->getHeader().filetype; 21662cfcf62SDimitry Andric 21762cfcf62SDimitry Andric uint64_t total = 0; 21862cfcf62SDimitry Andric for (const auto &Load : MachO->load_commands()) { 21962cfcf62SDimitry Andric if (Load.C.cmd == MachO::LC_SEGMENT_64) { 22062cfcf62SDimitry Andric MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); 22162cfcf62SDimitry Andric outs() << "Segment " << Seg.segname << ": " 22262cfcf62SDimitry Andric << format(fmt.str().c_str(), Seg.vmsize); 22362cfcf62SDimitry Andric if (DarwinLongFormat) 22462cfcf62SDimitry Andric outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff " 22562cfcf62SDimitry Andric << Seg.fileoff << ")"; 22662cfcf62SDimitry Andric outs() << "\n"; 22762cfcf62SDimitry Andric total += Seg.vmsize; 22862cfcf62SDimitry Andric uint64_t sec_total = 0; 22962cfcf62SDimitry Andric for (unsigned J = 0; J < Seg.nsects; ++J) { 23062cfcf62SDimitry Andric MachO::section_64 Sec = MachO->getSection64(Load, J); 23162cfcf62SDimitry Andric if (Filetype == MachO::MH_OBJECT) 23262cfcf62SDimitry Andric outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " 23362cfcf62SDimitry Andric << format("%.16s", &Sec.sectname) << "): "; 23462cfcf62SDimitry Andric else 23562cfcf62SDimitry Andric outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; 23662cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), Sec.size); 23762cfcf62SDimitry Andric if (DarwinLongFormat) 23862cfcf62SDimitry Andric outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset " 23962cfcf62SDimitry Andric << Sec.offset << ")"; 24062cfcf62SDimitry Andric outs() << "\n"; 24162cfcf62SDimitry Andric sec_total += Sec.size; 24262cfcf62SDimitry Andric } 24362cfcf62SDimitry Andric if (Seg.nsects != 0) 24462cfcf62SDimitry Andric outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; 24562cfcf62SDimitry Andric } else if (Load.C.cmd == MachO::LC_SEGMENT) { 24662cfcf62SDimitry Andric MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); 24762cfcf62SDimitry Andric uint64_t Seg_vmsize = Seg.vmsize; 24862cfcf62SDimitry Andric outs() << "Segment " << Seg.segname << ": " 24962cfcf62SDimitry Andric << format(fmt.str().c_str(), Seg_vmsize); 25062cfcf62SDimitry Andric if (DarwinLongFormat) 25162cfcf62SDimitry Andric outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff " 25262cfcf62SDimitry Andric << Seg.fileoff << ")"; 25362cfcf62SDimitry Andric outs() << "\n"; 25462cfcf62SDimitry Andric total += Seg.vmsize; 25562cfcf62SDimitry Andric uint64_t sec_total = 0; 25662cfcf62SDimitry Andric for (unsigned J = 0; J < Seg.nsects; ++J) { 25762cfcf62SDimitry Andric MachO::section Sec = MachO->getSection(Load, J); 25862cfcf62SDimitry Andric if (Filetype == MachO::MH_OBJECT) 25962cfcf62SDimitry Andric outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " 26062cfcf62SDimitry Andric << format("%.16s", &Sec.sectname) << "): "; 26162cfcf62SDimitry Andric else 26262cfcf62SDimitry Andric outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; 26362cfcf62SDimitry Andric uint64_t Sec_size = Sec.size; 26462cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), Sec_size); 26562cfcf62SDimitry Andric if (DarwinLongFormat) 26662cfcf62SDimitry Andric outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset " 26762cfcf62SDimitry Andric << Sec.offset << ")"; 26862cfcf62SDimitry Andric outs() << "\n"; 26962cfcf62SDimitry Andric sec_total += Sec.size; 27062cfcf62SDimitry Andric } 27162cfcf62SDimitry Andric if (Seg.nsects != 0) 27262cfcf62SDimitry Andric outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; 27362cfcf62SDimitry Andric } 27462cfcf62SDimitry Andric } 27562cfcf62SDimitry Andric outs() << "total " << format(fmt.str().c_str(), total) << "\n"; 27662cfcf62SDimitry Andric } 27762cfcf62SDimitry Andric 27862cfcf62SDimitry Andric /// Print the summary sizes of the standard Mach-O segments in @p MachO. 27962cfcf62SDimitry Andric /// 28062cfcf62SDimitry Andric /// This is when used when @c OutputFormat is berkeley with a Mach-O file and 28162cfcf62SDimitry Andric /// produces the same output as darwin's size(1) default output. 28262cfcf62SDimitry Andric static void printDarwinSegmentSizes(MachOObjectFile *MachO) { 28362cfcf62SDimitry Andric uint64_t total_text = 0; 28462cfcf62SDimitry Andric uint64_t total_data = 0; 28562cfcf62SDimitry Andric uint64_t total_objc = 0; 28662cfcf62SDimitry Andric uint64_t total_others = 0; 28762cfcf62SDimitry Andric for (const auto &Load : MachO->load_commands()) { 28862cfcf62SDimitry Andric if (Load.C.cmd == MachO::LC_SEGMENT_64) { 28962cfcf62SDimitry Andric MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); 29062cfcf62SDimitry Andric if (MachO->getHeader().filetype == MachO::MH_OBJECT) { 29162cfcf62SDimitry Andric for (unsigned J = 0; J < Seg.nsects; ++J) { 29262cfcf62SDimitry Andric MachO::section_64 Sec = MachO->getSection64(Load, J); 29362cfcf62SDimitry Andric StringRef SegmentName = StringRef(Sec.segname); 29462cfcf62SDimitry Andric if (SegmentName == "__TEXT") 29562cfcf62SDimitry Andric total_text += Sec.size; 29662cfcf62SDimitry Andric else if (SegmentName == "__DATA") 29762cfcf62SDimitry Andric total_data += Sec.size; 29862cfcf62SDimitry Andric else if (SegmentName == "__OBJC") 29962cfcf62SDimitry Andric total_objc += Sec.size; 30062cfcf62SDimitry Andric else 30162cfcf62SDimitry Andric total_others += Sec.size; 30262cfcf62SDimitry Andric } 30362cfcf62SDimitry Andric } else { 30462cfcf62SDimitry Andric StringRef SegmentName = StringRef(Seg.segname); 30562cfcf62SDimitry Andric if (SegmentName == "__TEXT") 30662cfcf62SDimitry Andric total_text += Seg.vmsize; 30762cfcf62SDimitry Andric else if (SegmentName == "__DATA") 30862cfcf62SDimitry Andric total_data += Seg.vmsize; 30962cfcf62SDimitry Andric else if (SegmentName == "__OBJC") 31062cfcf62SDimitry Andric total_objc += Seg.vmsize; 31162cfcf62SDimitry Andric else 31262cfcf62SDimitry Andric total_others += Seg.vmsize; 31362cfcf62SDimitry Andric } 31462cfcf62SDimitry Andric } else if (Load.C.cmd == MachO::LC_SEGMENT) { 31562cfcf62SDimitry Andric MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); 31662cfcf62SDimitry Andric if (MachO->getHeader().filetype == MachO::MH_OBJECT) { 31762cfcf62SDimitry Andric for (unsigned J = 0; J < Seg.nsects; ++J) { 31862cfcf62SDimitry Andric MachO::section Sec = MachO->getSection(Load, J); 31962cfcf62SDimitry Andric StringRef SegmentName = StringRef(Sec.segname); 32062cfcf62SDimitry Andric if (SegmentName == "__TEXT") 32162cfcf62SDimitry Andric total_text += Sec.size; 32262cfcf62SDimitry Andric else if (SegmentName == "__DATA") 32362cfcf62SDimitry Andric total_data += Sec.size; 32462cfcf62SDimitry Andric else if (SegmentName == "__OBJC") 32562cfcf62SDimitry Andric total_objc += Sec.size; 32662cfcf62SDimitry Andric else 32762cfcf62SDimitry Andric total_others += Sec.size; 32862cfcf62SDimitry Andric } 32962cfcf62SDimitry Andric } else { 33062cfcf62SDimitry Andric StringRef SegmentName = StringRef(Seg.segname); 33162cfcf62SDimitry Andric if (SegmentName == "__TEXT") 33262cfcf62SDimitry Andric total_text += Seg.vmsize; 33362cfcf62SDimitry Andric else if (SegmentName == "__DATA") 33462cfcf62SDimitry Andric total_data += Seg.vmsize; 33562cfcf62SDimitry Andric else if (SegmentName == "__OBJC") 33662cfcf62SDimitry Andric total_objc += Seg.vmsize; 33762cfcf62SDimitry Andric else 33862cfcf62SDimitry Andric total_others += Seg.vmsize; 33962cfcf62SDimitry Andric } 34062cfcf62SDimitry Andric } 34162cfcf62SDimitry Andric } 34262cfcf62SDimitry Andric uint64_t total = total_text + total_data + total_objc + total_others; 34362cfcf62SDimitry Andric 34462cfcf62SDimitry Andric if (!BerkeleyHeaderPrinted) { 34562cfcf62SDimitry Andric outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n"; 34662cfcf62SDimitry Andric BerkeleyHeaderPrinted = true; 34762cfcf62SDimitry Andric } 34862cfcf62SDimitry Andric outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t" 34962cfcf62SDimitry Andric << total_others << "\t" << total << "\t" << format("%" PRIx64, total) 35062cfcf62SDimitry Andric << "\t"; 35162cfcf62SDimitry Andric } 35262cfcf62SDimitry Andric 35362cfcf62SDimitry Andric /// Print the size of each section in @p Obj. 35462cfcf62SDimitry Andric /// 35562cfcf62SDimitry Andric /// The format used is determined by @c OutputFormat and @c Radix. 35662cfcf62SDimitry Andric static void printObjectSectionSizes(ObjectFile *Obj) { 35762cfcf62SDimitry Andric uint64_t total = 0; 35862cfcf62SDimitry Andric std::string fmtbuf; 35962cfcf62SDimitry Andric raw_string_ostream fmt(fmtbuf); 36062cfcf62SDimitry Andric const char *radix_fmt = getRadixFmt(); 36162cfcf62SDimitry Andric 36262cfcf62SDimitry Andric // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's 36362cfcf62SDimitry Andric // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object 36462cfcf62SDimitry Andric // let it fall through to OutputFormat berkeley. 36562cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj); 36662cfcf62SDimitry Andric if (OutputFormat == darwin && MachO) 36762cfcf62SDimitry Andric printDarwinSectionSizes(MachO); 36862cfcf62SDimitry Andric // If we have a MachOObjectFile and the OutputFormat is berkeley print as 36962cfcf62SDimitry Andric // darwin's default berkeley format for Mach-O files. 37062cfcf62SDimitry Andric else if (MachO && OutputFormat == berkeley) 37162cfcf62SDimitry Andric printDarwinSegmentSizes(MachO); 37262cfcf62SDimitry Andric else if (OutputFormat == sysv) { 37362cfcf62SDimitry Andric // Run two passes over all sections. The first gets the lengths needed for 37462cfcf62SDimitry Andric // formatting the output. The second actually does the output. 37562cfcf62SDimitry Andric std::size_t max_name_len = strlen("section"); 37662cfcf62SDimitry Andric std::size_t max_size_len = strlen("size"); 37762cfcf62SDimitry Andric std::size_t max_addr_len = strlen("addr"); 37862cfcf62SDimitry Andric for (const SectionRef &Section : Obj->sections()) { 37962cfcf62SDimitry Andric if (!considerForSize(Obj, Section)) 38062cfcf62SDimitry Andric continue; 38162cfcf62SDimitry Andric uint64_t size = Section.getSize(); 38262cfcf62SDimitry Andric total += size; 38362cfcf62SDimitry Andric 38462cfcf62SDimitry Andric Expected<StringRef> name_or_err = Section.getName(); 38562cfcf62SDimitry Andric if (!name_or_err) { 38662cfcf62SDimitry Andric error(name_or_err.takeError(), Obj->getFileName()); 38762cfcf62SDimitry Andric return; 38862cfcf62SDimitry Andric } 38962cfcf62SDimitry Andric 39062cfcf62SDimitry Andric uint64_t addr = Section.getAddress(); 39162cfcf62SDimitry Andric max_name_len = std::max(max_name_len, name_or_err->size()); 39262cfcf62SDimitry Andric max_size_len = std::max(max_size_len, getNumLengthAsString(size)); 39362cfcf62SDimitry Andric max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr)); 39462cfcf62SDimitry Andric } 39562cfcf62SDimitry Andric 39662cfcf62SDimitry Andric // Add extra padding. 39762cfcf62SDimitry Andric max_name_len += 2; 39862cfcf62SDimitry Andric max_size_len += 2; 39962cfcf62SDimitry Andric max_addr_len += 2; 40062cfcf62SDimitry Andric 40162cfcf62SDimitry Andric // Setup header format. 40262cfcf62SDimitry Andric fmt << "%-" << max_name_len << "s " 40362cfcf62SDimitry Andric << "%" << max_size_len << "s " 40462cfcf62SDimitry Andric << "%" << max_addr_len << "s\n"; 40562cfcf62SDimitry Andric 40662cfcf62SDimitry Andric // Print header 40762cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), static_cast<const char *>("section"), 40862cfcf62SDimitry Andric static_cast<const char *>("size"), 40962cfcf62SDimitry Andric static_cast<const char *>("addr")); 41062cfcf62SDimitry Andric fmtbuf.clear(); 41162cfcf62SDimitry Andric 41262cfcf62SDimitry Andric // Setup per section format. 41362cfcf62SDimitry Andric fmt << "%-" << max_name_len << "s " 41462cfcf62SDimitry Andric << "%#" << max_size_len << radix_fmt << " " 41562cfcf62SDimitry Andric << "%#" << max_addr_len << radix_fmt << "\n"; 41662cfcf62SDimitry Andric 41762cfcf62SDimitry Andric // Print each section. 41862cfcf62SDimitry Andric for (const SectionRef &Section : Obj->sections()) { 41962cfcf62SDimitry Andric if (!considerForSize(Obj, Section)) 42062cfcf62SDimitry Andric continue; 42162cfcf62SDimitry Andric 42262cfcf62SDimitry Andric Expected<StringRef> name_or_err = Section.getName(); 42362cfcf62SDimitry Andric if (!name_or_err) { 42462cfcf62SDimitry Andric error(name_or_err.takeError(), Obj->getFileName()); 42562cfcf62SDimitry Andric return; 42662cfcf62SDimitry Andric } 42762cfcf62SDimitry Andric 42862cfcf62SDimitry Andric uint64_t size = Section.getSize(); 42962cfcf62SDimitry Andric uint64_t addr = Section.getAddress(); 43062cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), name_or_err->str().c_str(), size, addr); 43162cfcf62SDimitry Andric } 43262cfcf62SDimitry Andric 43362cfcf62SDimitry Andric if (ELFCommons) { 4345ffd83dbSDimitry Andric if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) { 4355ffd83dbSDimitry Andric total += *CommonSizeOrErr; 43662cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(), 4375ffd83dbSDimitry Andric *CommonSizeOrErr, static_cast<uint64_t>(0)); 4385ffd83dbSDimitry Andric } else { 4395ffd83dbSDimitry Andric error(CommonSizeOrErr.takeError(), Obj->getFileName()); 4405ffd83dbSDimitry Andric return; 4415ffd83dbSDimitry Andric } 44262cfcf62SDimitry Andric } 44362cfcf62SDimitry Andric 44462cfcf62SDimitry Andric // Print total. 44562cfcf62SDimitry Andric fmtbuf.clear(); 44662cfcf62SDimitry Andric fmt << "%-" << max_name_len << "s " 44762cfcf62SDimitry Andric << "%#" << max_size_len << radix_fmt << "\n"; 44862cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"), 44962cfcf62SDimitry Andric total) 45062cfcf62SDimitry Andric << "\n\n"; 45162cfcf62SDimitry Andric } else { 45262cfcf62SDimitry Andric // The Berkeley format does not display individual section sizes. It 45362cfcf62SDimitry Andric // displays the cumulative size for each section type. 45462cfcf62SDimitry Andric uint64_t total_text = 0; 45562cfcf62SDimitry Andric uint64_t total_data = 0; 45662cfcf62SDimitry Andric uint64_t total_bss = 0; 45762cfcf62SDimitry Andric 45862cfcf62SDimitry Andric // Make one pass over the section table to calculate sizes. 45962cfcf62SDimitry Andric for (const SectionRef &Section : Obj->sections()) { 46062cfcf62SDimitry Andric uint64_t size = Section.getSize(); 46162cfcf62SDimitry Andric bool isText = Section.isBerkeleyText(); 46262cfcf62SDimitry Andric bool isData = Section.isBerkeleyData(); 46362cfcf62SDimitry Andric bool isBSS = Section.isBSS(); 46462cfcf62SDimitry Andric if (isText) 46562cfcf62SDimitry Andric total_text += size; 46662cfcf62SDimitry Andric else if (isData) 46762cfcf62SDimitry Andric total_data += size; 46862cfcf62SDimitry Andric else if (isBSS) 46962cfcf62SDimitry Andric total_bss += size; 47062cfcf62SDimitry Andric } 47162cfcf62SDimitry Andric 4725ffd83dbSDimitry Andric if (ELFCommons) { 4735ffd83dbSDimitry Andric if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) 4745ffd83dbSDimitry Andric total_bss += *CommonSizeOrErr; 4755ffd83dbSDimitry Andric else { 4765ffd83dbSDimitry Andric error(CommonSizeOrErr.takeError(), Obj->getFileName()); 4775ffd83dbSDimitry Andric return; 4785ffd83dbSDimitry Andric } 4795ffd83dbSDimitry Andric } 48062cfcf62SDimitry Andric 48162cfcf62SDimitry Andric total = total_text + total_data + total_bss; 48262cfcf62SDimitry Andric 48362cfcf62SDimitry Andric if (TotalSizes) { 48462cfcf62SDimitry Andric TotalObjectText += total_text; 48562cfcf62SDimitry Andric TotalObjectData += total_data; 48662cfcf62SDimitry Andric TotalObjectBss += total_bss; 48762cfcf62SDimitry Andric TotalObjectTotal += total; 48862cfcf62SDimitry Andric } 48962cfcf62SDimitry Andric 49062cfcf62SDimitry Andric if (!BerkeleyHeaderPrinted) { 49162cfcf62SDimitry Andric outs() << " text\t" 49262cfcf62SDimitry Andric " data\t" 49362cfcf62SDimitry Andric " bss\t" 49462cfcf62SDimitry Andric " " 49562cfcf62SDimitry Andric << (Radix == octal ? "oct" : "dec") 49662cfcf62SDimitry Andric << "\t" 49762cfcf62SDimitry Andric " hex\t" 49862cfcf62SDimitry Andric "filename\n"; 49962cfcf62SDimitry Andric BerkeleyHeaderPrinted = true; 50062cfcf62SDimitry Andric } 50162cfcf62SDimitry Andric 50262cfcf62SDimitry Andric // Print result. 50362cfcf62SDimitry Andric fmt << "%#7" << radix_fmt << "\t" 50462cfcf62SDimitry Andric << "%#7" << radix_fmt << "\t" 50562cfcf62SDimitry Andric << "%#7" << radix_fmt << "\t"; 50662cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), total_text, total_data, total_bss); 50762cfcf62SDimitry Andric fmtbuf.clear(); 50862cfcf62SDimitry Andric fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" 50962cfcf62SDimitry Andric << "%7" PRIx64 "\t"; 51062cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), total, total); 51162cfcf62SDimitry Andric } 51262cfcf62SDimitry Andric } 51362cfcf62SDimitry Andric 51462cfcf62SDimitry Andric /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there 51562cfcf62SDimitry Andric /// is a list of architecture flags specified then check to make sure this 51662cfcf62SDimitry Andric /// Mach-O file is one of those architectures or all architectures was 51762cfcf62SDimitry Andric /// specificed. If not then an error is generated and this routine returns 51862cfcf62SDimitry Andric /// false. Else it returns true. 51962cfcf62SDimitry Andric static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { 52062cfcf62SDimitry Andric auto *MachO = dyn_cast<MachOObjectFile>(O); 52162cfcf62SDimitry Andric 52262cfcf62SDimitry Andric if (!MachO || ArchAll || ArchFlags.empty()) 52362cfcf62SDimitry Andric return true; 52462cfcf62SDimitry Andric 52562cfcf62SDimitry Andric MachO::mach_header H; 52662cfcf62SDimitry Andric MachO::mach_header_64 H_64; 52762cfcf62SDimitry Andric Triple T; 52862cfcf62SDimitry Andric if (MachO->is64Bit()) { 52962cfcf62SDimitry Andric H_64 = MachO->MachOObjectFile::getHeader64(); 53062cfcf62SDimitry Andric T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); 53162cfcf62SDimitry Andric } else { 53262cfcf62SDimitry Andric H = MachO->MachOObjectFile::getHeader(); 53362cfcf62SDimitry Andric T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); 53462cfcf62SDimitry Andric } 535e8d8bef9SDimitry Andric if (!is_contained(ArchFlags, T.getArchName())) { 53662cfcf62SDimitry Andric error("no architecture specified", Filename); 53762cfcf62SDimitry Andric return false; 53862cfcf62SDimitry Andric } 53962cfcf62SDimitry Andric return true; 54062cfcf62SDimitry Andric } 54162cfcf62SDimitry Andric 54262cfcf62SDimitry Andric /// Print the section sizes for @p file. If @p file is an archive, print the 54362cfcf62SDimitry Andric /// section sizes for each archive member. 54462cfcf62SDimitry Andric static void printFileSectionSizes(StringRef file) { 54562cfcf62SDimitry Andric 54662cfcf62SDimitry Andric // Attempt to open the binary. 54762cfcf62SDimitry Andric Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file); 54862cfcf62SDimitry Andric if (!BinaryOrErr) { 54962cfcf62SDimitry Andric error(BinaryOrErr.takeError(), file); 55062cfcf62SDimitry Andric return; 55162cfcf62SDimitry Andric } 55262cfcf62SDimitry Andric Binary &Bin = *BinaryOrErr.get().getBinary(); 55362cfcf62SDimitry Andric 55462cfcf62SDimitry Andric if (Archive *a = dyn_cast<Archive>(&Bin)) { 55562cfcf62SDimitry Andric // This is an archive. Iterate over each member and display its sizes. 55662cfcf62SDimitry Andric Error Err = Error::success(); 55762cfcf62SDimitry Andric for (auto &C : a->children(Err)) { 55862cfcf62SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 55962cfcf62SDimitry Andric if (!ChildOrErr) { 56062cfcf62SDimitry Andric if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) 56162cfcf62SDimitry Andric error(std::move(E), a->getFileName(), C); 56262cfcf62SDimitry Andric continue; 56362cfcf62SDimitry Andric } 56462cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 56562cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 56662cfcf62SDimitry Andric if (!checkMachOAndArchFlags(o, file)) 56762cfcf62SDimitry Andric return; 56862cfcf62SDimitry Andric if (OutputFormat == sysv) 56962cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n"; 57062cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) 57162cfcf62SDimitry Andric outs() << a->getFileName() << "(" << o->getFileName() << "):\n"; 57262cfcf62SDimitry Andric printObjectSectionSizes(o); 57362cfcf62SDimitry Andric if (OutputFormat == berkeley) { 57462cfcf62SDimitry Andric if (MachO) 57562cfcf62SDimitry Andric outs() << a->getFileName() << "(" << o->getFileName() << ")\n"; 57662cfcf62SDimitry Andric else 57762cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; 57862cfcf62SDimitry Andric } 57962cfcf62SDimitry Andric } 58062cfcf62SDimitry Andric } 58162cfcf62SDimitry Andric if (Err) 58262cfcf62SDimitry Andric error(std::move(Err), a->getFileName()); 58362cfcf62SDimitry Andric } else if (MachOUniversalBinary *UB = 58462cfcf62SDimitry Andric dyn_cast<MachOUniversalBinary>(&Bin)) { 58562cfcf62SDimitry Andric // If we have a list of architecture flags specified dump only those. 58662cfcf62SDimitry Andric if (!ArchAll && !ArchFlags.empty()) { 58762cfcf62SDimitry Andric // Look for a slice in the universal binary that matches each ArchFlag. 58862cfcf62SDimitry Andric bool ArchFound; 58962cfcf62SDimitry Andric for (unsigned i = 0; i < ArchFlags.size(); ++i) { 59062cfcf62SDimitry Andric ArchFound = false; 59162cfcf62SDimitry Andric for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 59262cfcf62SDimitry Andric E = UB->end_objects(); 59362cfcf62SDimitry Andric I != E; ++I) { 59462cfcf62SDimitry Andric if (ArchFlags[i] == I->getArchFlagName()) { 59562cfcf62SDimitry Andric ArchFound = true; 59662cfcf62SDimitry Andric Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 59762cfcf62SDimitry Andric if (UO) { 59862cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 59962cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 60062cfcf62SDimitry Andric if (OutputFormat == sysv) 60162cfcf62SDimitry Andric outs() << o->getFileName() << " :\n"; 60262cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) { 60362cfcf62SDimitry Andric if (MoreThanOneFile || ArchFlags.size() > 1) 60462cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 60562cfcf62SDimitry Andric << I->getArchFlagName() << "): \n"; 60662cfcf62SDimitry Andric } 60762cfcf62SDimitry Andric printObjectSectionSizes(o); 60862cfcf62SDimitry Andric if (OutputFormat == berkeley) { 60962cfcf62SDimitry Andric if (!MachO || MoreThanOneFile || ArchFlags.size() > 1) 61062cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 61162cfcf62SDimitry Andric << I->getArchFlagName() << ")"; 61262cfcf62SDimitry Andric outs() << "\n"; 61362cfcf62SDimitry Andric } 61462cfcf62SDimitry Andric } 61562cfcf62SDimitry Andric } else if (auto E = isNotObjectErrorInvalidFileType( 61662cfcf62SDimitry Andric UO.takeError())) { 61762cfcf62SDimitry Andric error(std::move(E), file, ArchFlags.size() > 1 ? 61862cfcf62SDimitry Andric StringRef(I->getArchFlagName()) : StringRef()); 61962cfcf62SDimitry Andric return; 62062cfcf62SDimitry Andric } else if (Expected<std::unique_ptr<Archive>> AOrErr = 62162cfcf62SDimitry Andric I->getAsArchive()) { 62262cfcf62SDimitry Andric std::unique_ptr<Archive> &UA = *AOrErr; 62362cfcf62SDimitry Andric // This is an archive. Iterate over each member and display its 62462cfcf62SDimitry Andric // sizes. 62562cfcf62SDimitry Andric Error Err = Error::success(); 62662cfcf62SDimitry Andric for (auto &C : UA->children(Err)) { 62762cfcf62SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 62862cfcf62SDimitry Andric if (!ChildOrErr) { 62962cfcf62SDimitry Andric if (auto E = isNotObjectErrorInvalidFileType( 63062cfcf62SDimitry Andric ChildOrErr.takeError())) 63162cfcf62SDimitry Andric error(std::move(E), UA->getFileName(), C, 63262cfcf62SDimitry Andric ArchFlags.size() > 1 ? 63362cfcf62SDimitry Andric StringRef(I->getArchFlagName()) : StringRef()); 63462cfcf62SDimitry Andric continue; 63562cfcf62SDimitry Andric } 63662cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 63762cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 63862cfcf62SDimitry Andric if (OutputFormat == sysv) 63962cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 64062cfcf62SDimitry Andric << "):\n"; 64162cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) 64262cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() 64362cfcf62SDimitry Andric << ")" 64462cfcf62SDimitry Andric << " (for architecture " << I->getArchFlagName() 64562cfcf62SDimitry Andric << "):\n"; 64662cfcf62SDimitry Andric printObjectSectionSizes(o); 64762cfcf62SDimitry Andric if (OutputFormat == berkeley) { 64862cfcf62SDimitry Andric if (MachO) { 64962cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() 65062cfcf62SDimitry Andric << ")"; 65162cfcf62SDimitry Andric if (ArchFlags.size() > 1) 65262cfcf62SDimitry Andric outs() << " (for architecture " << I->getArchFlagName() 65362cfcf62SDimitry Andric << ")"; 65462cfcf62SDimitry Andric outs() << "\n"; 65562cfcf62SDimitry Andric } else 65662cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 65762cfcf62SDimitry Andric << ")\n"; 65862cfcf62SDimitry Andric } 65962cfcf62SDimitry Andric } 66062cfcf62SDimitry Andric } 66162cfcf62SDimitry Andric if (Err) 66262cfcf62SDimitry Andric error(std::move(Err), UA->getFileName()); 66362cfcf62SDimitry Andric } else { 66462cfcf62SDimitry Andric consumeError(AOrErr.takeError()); 66562cfcf62SDimitry Andric error("mach-o universal file for architecture " + 66662cfcf62SDimitry Andric StringRef(I->getArchFlagName()) + 66762cfcf62SDimitry Andric " is not a mach-o file or an archive file", 66862cfcf62SDimitry Andric file); 66962cfcf62SDimitry Andric } 67062cfcf62SDimitry Andric } 67162cfcf62SDimitry Andric } 67262cfcf62SDimitry Andric if (!ArchFound) { 67362cfcf62SDimitry Andric error("file does not contain architecture " + ArchFlags[i], file); 67462cfcf62SDimitry Andric return; 67562cfcf62SDimitry Andric } 67662cfcf62SDimitry Andric } 67762cfcf62SDimitry Andric return; 67862cfcf62SDimitry Andric } 67962cfcf62SDimitry Andric // No architecture flags were specified so if this contains a slice that 68062cfcf62SDimitry Andric // matches the host architecture dump only that. 68162cfcf62SDimitry Andric if (!ArchAll) { 68262cfcf62SDimitry Andric StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); 68362cfcf62SDimitry Andric for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 68462cfcf62SDimitry Andric E = UB->end_objects(); 68562cfcf62SDimitry Andric I != E; ++I) { 68662cfcf62SDimitry Andric if (HostArchName == I->getArchFlagName()) { 68762cfcf62SDimitry Andric Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 68862cfcf62SDimitry Andric if (UO) { 68962cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 69062cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 69162cfcf62SDimitry Andric if (OutputFormat == sysv) 69262cfcf62SDimitry Andric outs() << o->getFileName() << " :\n"; 69362cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) { 69462cfcf62SDimitry Andric if (MoreThanOneFile) 69562cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 69662cfcf62SDimitry Andric << I->getArchFlagName() << "):\n"; 69762cfcf62SDimitry Andric } 69862cfcf62SDimitry Andric printObjectSectionSizes(o); 69962cfcf62SDimitry Andric if (OutputFormat == berkeley) { 70062cfcf62SDimitry Andric if (!MachO || MoreThanOneFile) 70162cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 70262cfcf62SDimitry Andric << I->getArchFlagName() << ")"; 70362cfcf62SDimitry Andric outs() << "\n"; 70462cfcf62SDimitry Andric } 70562cfcf62SDimitry Andric } 70662cfcf62SDimitry Andric } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 70762cfcf62SDimitry Andric error(std::move(E), file); 70862cfcf62SDimitry Andric return; 70962cfcf62SDimitry Andric } else if (Expected<std::unique_ptr<Archive>> AOrErr = 71062cfcf62SDimitry Andric I->getAsArchive()) { 71162cfcf62SDimitry Andric std::unique_ptr<Archive> &UA = *AOrErr; 71262cfcf62SDimitry Andric // This is an archive. Iterate over each member and display its 71362cfcf62SDimitry Andric // sizes. 71462cfcf62SDimitry Andric Error Err = Error::success(); 71562cfcf62SDimitry Andric for (auto &C : UA->children(Err)) { 71662cfcf62SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 71762cfcf62SDimitry Andric if (!ChildOrErr) { 71862cfcf62SDimitry Andric if (auto E = isNotObjectErrorInvalidFileType( 71962cfcf62SDimitry Andric ChildOrErr.takeError())) 72062cfcf62SDimitry Andric error(std::move(E), UA->getFileName(), C); 72162cfcf62SDimitry Andric continue; 72262cfcf62SDimitry Andric } 72362cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 72462cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 72562cfcf62SDimitry Andric if (OutputFormat == sysv) 72662cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 72762cfcf62SDimitry Andric << "):\n"; 72862cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) 72962cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() << ")" 73062cfcf62SDimitry Andric << " (for architecture " << I->getArchFlagName() 73162cfcf62SDimitry Andric << "):\n"; 73262cfcf62SDimitry Andric printObjectSectionSizes(o); 73362cfcf62SDimitry Andric if (OutputFormat == berkeley) { 73462cfcf62SDimitry Andric if (MachO) 73562cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() 73662cfcf62SDimitry Andric << ")\n"; 73762cfcf62SDimitry Andric else 73862cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 73962cfcf62SDimitry Andric << ")\n"; 74062cfcf62SDimitry Andric } 74162cfcf62SDimitry Andric } 74262cfcf62SDimitry Andric } 74362cfcf62SDimitry Andric if (Err) 74462cfcf62SDimitry Andric error(std::move(Err), UA->getFileName()); 74562cfcf62SDimitry Andric } else { 74662cfcf62SDimitry Andric consumeError(AOrErr.takeError()); 74762cfcf62SDimitry Andric error("mach-o universal file for architecture " + 74862cfcf62SDimitry Andric StringRef(I->getArchFlagName()) + 74962cfcf62SDimitry Andric " is not a mach-o file or an archive file", 75062cfcf62SDimitry Andric file); 75162cfcf62SDimitry Andric } 75262cfcf62SDimitry Andric return; 75362cfcf62SDimitry Andric } 75462cfcf62SDimitry Andric } 75562cfcf62SDimitry Andric } 75662cfcf62SDimitry Andric // Either all architectures have been specified or none have been specified 75762cfcf62SDimitry Andric // and this does not contain the host architecture so dump all the slices. 75862cfcf62SDimitry Andric bool MoreThanOneArch = UB->getNumberOfObjects() > 1; 75962cfcf62SDimitry Andric for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 76062cfcf62SDimitry Andric E = UB->end_objects(); 76162cfcf62SDimitry Andric I != E; ++I) { 76262cfcf62SDimitry Andric Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 76362cfcf62SDimitry Andric if (UO) { 76462cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 76562cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 76662cfcf62SDimitry Andric if (OutputFormat == sysv) 76762cfcf62SDimitry Andric outs() << o->getFileName() << " :\n"; 76862cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) { 76962cfcf62SDimitry Andric if (MoreThanOneFile || MoreThanOneArch) 77062cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 77162cfcf62SDimitry Andric << I->getArchFlagName() << "):"; 77262cfcf62SDimitry Andric outs() << "\n"; 77362cfcf62SDimitry Andric } 77462cfcf62SDimitry Andric printObjectSectionSizes(o); 77562cfcf62SDimitry Andric if (OutputFormat == berkeley) { 77662cfcf62SDimitry Andric if (!MachO || MoreThanOneFile || MoreThanOneArch) 77762cfcf62SDimitry Andric outs() << o->getFileName() << " (for architecture " 77862cfcf62SDimitry Andric << I->getArchFlagName() << ")"; 77962cfcf62SDimitry Andric outs() << "\n"; 78062cfcf62SDimitry Andric } 78162cfcf62SDimitry Andric } 78262cfcf62SDimitry Andric } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 78362cfcf62SDimitry Andric error(std::move(E), file, MoreThanOneArch ? 78462cfcf62SDimitry Andric StringRef(I->getArchFlagName()) : StringRef()); 78562cfcf62SDimitry Andric return; 78662cfcf62SDimitry Andric } else if (Expected<std::unique_ptr<Archive>> AOrErr = 78762cfcf62SDimitry Andric I->getAsArchive()) { 78862cfcf62SDimitry Andric std::unique_ptr<Archive> &UA = *AOrErr; 78962cfcf62SDimitry Andric // This is an archive. Iterate over each member and display its sizes. 79062cfcf62SDimitry Andric Error Err = Error::success(); 79162cfcf62SDimitry Andric for (auto &C : UA->children(Err)) { 79262cfcf62SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 79362cfcf62SDimitry Andric if (!ChildOrErr) { 79462cfcf62SDimitry Andric if (auto E = isNotObjectErrorInvalidFileType( 79562cfcf62SDimitry Andric ChildOrErr.takeError())) 79662cfcf62SDimitry Andric error(std::move(E), UA->getFileName(), C, MoreThanOneArch ? 79762cfcf62SDimitry Andric StringRef(I->getArchFlagName()) : StringRef()); 79862cfcf62SDimitry Andric continue; 79962cfcf62SDimitry Andric } 80062cfcf62SDimitry Andric if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 80162cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 80262cfcf62SDimitry Andric if (OutputFormat == sysv) 80362cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 80462cfcf62SDimitry Andric << "):\n"; 80562cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin) 80662cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() << ")" 80762cfcf62SDimitry Andric << " (for architecture " << I->getArchFlagName() << "):\n"; 80862cfcf62SDimitry Andric printObjectSectionSizes(o); 80962cfcf62SDimitry Andric if (OutputFormat == berkeley) { 81062cfcf62SDimitry Andric if (MachO) 81162cfcf62SDimitry Andric outs() << UA->getFileName() << "(" << o->getFileName() << ")" 81262cfcf62SDimitry Andric << " (for architecture " << I->getArchFlagName() 81362cfcf62SDimitry Andric << ")\n"; 81462cfcf62SDimitry Andric else 81562cfcf62SDimitry Andric outs() << o->getFileName() << " (ex " << UA->getFileName() 81662cfcf62SDimitry Andric << ")\n"; 81762cfcf62SDimitry Andric } 81862cfcf62SDimitry Andric } 81962cfcf62SDimitry Andric } 82062cfcf62SDimitry Andric if (Err) 82162cfcf62SDimitry Andric error(std::move(Err), UA->getFileName()); 82262cfcf62SDimitry Andric } else { 82362cfcf62SDimitry Andric consumeError(AOrErr.takeError()); 82462cfcf62SDimitry Andric error("mach-o universal file for architecture " + 82562cfcf62SDimitry Andric StringRef(I->getArchFlagName()) + 82662cfcf62SDimitry Andric " is not a mach-o file or an archive file", 82762cfcf62SDimitry Andric file); 82862cfcf62SDimitry Andric } 82962cfcf62SDimitry Andric } 83062cfcf62SDimitry Andric } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) { 83162cfcf62SDimitry Andric if (!checkMachOAndArchFlags(o, file)) 83262cfcf62SDimitry Andric return; 83362cfcf62SDimitry Andric MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 83462cfcf62SDimitry Andric if (OutputFormat == sysv) 83562cfcf62SDimitry Andric outs() << o->getFileName() << " :\n"; 83662cfcf62SDimitry Andric else if (MachO && OutputFormat == darwin && MoreThanOneFile) 83762cfcf62SDimitry Andric outs() << o->getFileName() << ":\n"; 83862cfcf62SDimitry Andric printObjectSectionSizes(o); 83962cfcf62SDimitry Andric if (OutputFormat == berkeley) { 84062cfcf62SDimitry Andric if (!MachO || MoreThanOneFile) 84162cfcf62SDimitry Andric outs() << o->getFileName(); 84262cfcf62SDimitry Andric outs() << "\n"; 84362cfcf62SDimitry Andric } 84462cfcf62SDimitry Andric } else { 84562cfcf62SDimitry Andric error("unsupported file type", file); 84662cfcf62SDimitry Andric } 84762cfcf62SDimitry Andric } 84862cfcf62SDimitry Andric 84962cfcf62SDimitry Andric static void printBerkeleyTotals() { 85062cfcf62SDimitry Andric std::string fmtbuf; 85162cfcf62SDimitry Andric raw_string_ostream fmt(fmtbuf); 85262cfcf62SDimitry Andric const char *radix_fmt = getRadixFmt(); 85362cfcf62SDimitry Andric fmt << "%#7" << radix_fmt << "\t" 85462cfcf62SDimitry Andric << "%#7" << radix_fmt << "\t" 85562cfcf62SDimitry Andric << "%#7" << radix_fmt << "\t"; 85662cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData, 85762cfcf62SDimitry Andric TotalObjectBss); 85862cfcf62SDimitry Andric fmtbuf.clear(); 85962cfcf62SDimitry Andric fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" 86062cfcf62SDimitry Andric << "%7" PRIx64 "\t"; 86162cfcf62SDimitry Andric outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal) 86262cfcf62SDimitry Andric << "(TOTALS)\n"; 86362cfcf62SDimitry Andric } 86462cfcf62SDimitry Andric 86562cfcf62SDimitry Andric int main(int argc, char **argv) { 86662cfcf62SDimitry Andric InitLLVM X(argc, argv); 867*fe6060f1SDimitry Andric BumpPtrAllocator A; 868*fe6060f1SDimitry Andric StringSaver Saver(A); 869*fe6060f1SDimitry Andric SizeOptTable Tbl; 87062cfcf62SDimitry Andric ToolName = argv[0]; 871*fe6060f1SDimitry Andric opt::InputArgList Args = Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, 872*fe6060f1SDimitry Andric [&](StringRef Msg) { error(Msg); }); 873*fe6060f1SDimitry Andric if (Args.hasArg(OPT_help)) { 874*fe6060f1SDimitry Andric Tbl.printHelp( 875*fe6060f1SDimitry Andric outs(), 876*fe6060f1SDimitry Andric (Twine(ToolName) + " [options] <input object files>").str().c_str(), 877*fe6060f1SDimitry Andric "LLVM object size dumper"); 878*fe6060f1SDimitry Andric // TODO Replace this with OptTable API once it adds extrahelp support. 879*fe6060f1SDimitry Andric outs() << "\nPass @FILE as argument to read options from FILE.\n"; 880*fe6060f1SDimitry Andric return 0; 881*fe6060f1SDimitry Andric } 882*fe6060f1SDimitry Andric if (Args.hasArg(OPT_version)) { 883*fe6060f1SDimitry Andric outs() << ToolName << '\n'; 884*fe6060f1SDimitry Andric cl::PrintVersionMessage(); 885*fe6060f1SDimitry Andric return 0; 886*fe6060f1SDimitry Andric } 88762cfcf62SDimitry Andric 888*fe6060f1SDimitry Andric ELFCommons = Args.hasArg(OPT_common); 889*fe6060f1SDimitry Andric DarwinLongFormat = Args.hasArg(OPT_l); 890*fe6060f1SDimitry Andric TotalSizes = Args.hasArg(OPT_totals); 891*fe6060f1SDimitry Andric StringRef V = Args.getLastArgValue(OPT_format_EQ, "berkeley"); 892*fe6060f1SDimitry Andric if (V == "berkeley") 893*fe6060f1SDimitry Andric OutputFormat = berkeley; 894*fe6060f1SDimitry Andric else if (V == "darwin") 895*fe6060f1SDimitry Andric OutputFormat = darwin; 896*fe6060f1SDimitry Andric else if (V == "sysv") 897*fe6060f1SDimitry Andric OutputFormat = sysv; 898*fe6060f1SDimitry Andric else 899*fe6060f1SDimitry Andric error("--format value should be one of: 'berkeley', 'darwin', 'sysv'"); 900*fe6060f1SDimitry Andric V = Args.getLastArgValue(OPT_radix_EQ, "10"); 901*fe6060f1SDimitry Andric if (V == "8") 902*fe6060f1SDimitry Andric Radix = RadixTy::octal; 903*fe6060f1SDimitry Andric else if (V == "10") 904*fe6060f1SDimitry Andric Radix = RadixTy::decimal; 905*fe6060f1SDimitry Andric else if (V == "16") 906*fe6060f1SDimitry Andric Radix = RadixTy::hexadecimal; 907*fe6060f1SDimitry Andric else 908*fe6060f1SDimitry Andric error("--radix value should be one of: 8, 10, 16 "); 909*fe6060f1SDimitry Andric 910*fe6060f1SDimitry Andric for (const auto *A : Args.filtered(OPT_arch_EQ)) { 911*fe6060f1SDimitry Andric SmallVector<StringRef, 2> Values; 912*fe6060f1SDimitry Andric llvm::SplitString(A->getValue(), Values, ","); 913*fe6060f1SDimitry Andric for (StringRef V : Values) { 914*fe6060f1SDimitry Andric if (V == "all") 91562cfcf62SDimitry Andric ArchAll = true; 916*fe6060f1SDimitry Andric else if (MachOObjectFile::isValidArch(V)) 917*fe6060f1SDimitry Andric ArchFlags.push_back(V); 918*fe6060f1SDimitry Andric else { 91962cfcf62SDimitry Andric outs() << ToolName << ": for the -arch option: Unknown architecture " 920*fe6060f1SDimitry Andric << "named '" << V << "'"; 92162cfcf62SDimitry Andric return 1; 92262cfcf62SDimitry Andric } 92362cfcf62SDimitry Andric } 92462cfcf62SDimitry Andric } 92562cfcf62SDimitry Andric 926*fe6060f1SDimitry Andric InputFilenames = Args.getAllArgValues(OPT_INPUT); 92762cfcf62SDimitry Andric if (InputFilenames.empty()) 92862cfcf62SDimitry Andric InputFilenames.push_back("a.out"); 92962cfcf62SDimitry Andric 93062cfcf62SDimitry Andric MoreThanOneFile = InputFilenames.size() > 1; 93162cfcf62SDimitry Andric llvm::for_each(InputFilenames, printFileSectionSizes); 93262cfcf62SDimitry Andric if (OutputFormat == berkeley && TotalSizes) 93362cfcf62SDimitry Andric printBerkeleyTotals(); 93462cfcf62SDimitry Andric 93562cfcf62SDimitry Andric if (HadError) 93662cfcf62SDimitry Andric return 1; 93762cfcf62SDimitry Andric } 938