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