1 //===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This program is a utility that works like traditional Unix "size", 10 // that is, it prints out the size of each section, and the total size of all 11 // sections. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/ADT/APInt.h" 16 #include "llvm/Object/Archive.h" 17 #include "llvm/Object/ELFObjectFile.h" 18 #include "llvm/Object/MachO.h" 19 #include "llvm/Object/MachOUniversal.h" 20 #include "llvm/Object/ObjectFile.h" 21 #include "llvm/Option/Arg.h" 22 #include "llvm/Option/ArgList.h" 23 #include "llvm/Option/Option.h" 24 #include "llvm/Support/Casting.h" 25 #include "llvm/Support/CommandLine.h" 26 #include "llvm/Support/FileSystem.h" 27 #include "llvm/Support/Format.h" 28 #include "llvm/Support/InitLLVM.h" 29 #include "llvm/Support/LLVMDriver.h" 30 #include "llvm/Support/MemoryBuffer.h" 31 #include "llvm/Support/WithColor.h" 32 #include "llvm/Support/raw_ostream.h" 33 #include <algorithm> 34 #include <string> 35 #include <system_error> 36 37 using namespace llvm; 38 using namespace object; 39 40 namespace { 41 using namespace llvm::opt; // for HelpHidden in Opts.inc 42 enum ID { 43 OPT_INVALID = 0, // This is not an option ID. 44 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 45 HELPTEXT, METAVAR, VALUES) \ 46 OPT_##ID, 47 #include "Opts.inc" 48 #undef OPTION 49 }; 50 51 #define PREFIX(NAME, VALUE) \ 52 static constexpr StringLiteral NAME##_init[] = VALUE; \ 53 static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ 54 std::size(NAME##_init) - 1); 55 #include "Opts.inc" 56 #undef PREFIX 57 58 static constexpr opt::OptTable::Info InfoTable[] = { 59 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 60 HELPTEXT, METAVAR, VALUES) \ 61 { \ 62 PREFIX, NAME, HELPTEXT, \ 63 METAVAR, OPT_##ID, opt::Option::KIND##Class, \ 64 PARAM, FLAGS, OPT_##GROUP, \ 65 OPT_##ALIAS, ALIASARGS, VALUES}, 66 #include "Opts.inc" 67 #undef OPTION 68 }; 69 70 class SizeOptTable : public opt::GenericOptTable { 71 public: 72 SizeOptTable() : GenericOptTable(InfoTable) { setGroupedShortOptions(true); } 73 }; 74 75 enum OutputFormatTy { berkeley, sysv, darwin }; 76 enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 }; 77 } // namespace 78 79 static bool ArchAll = false; 80 static std::vector<StringRef> ArchFlags; 81 static bool ELFCommons; 82 static OutputFormatTy OutputFormat; 83 static bool DarwinLongFormat; 84 static RadixTy Radix; 85 static bool TotalSizes; 86 87 static std::vector<std::string> InputFilenames; 88 89 static std::string ToolName; 90 91 // States 92 static bool HadError = false; 93 static bool BerkeleyHeaderPrinted = false; 94 static bool MoreThanOneFile = false; 95 static uint64_t TotalObjectText = 0; 96 static uint64_t TotalObjectData = 0; 97 static uint64_t TotalObjectBss = 0; 98 static uint64_t TotalObjectTotal = 0; 99 100 static void error(const Twine &Message, StringRef File = "") { 101 HadError = true; 102 if (File.empty()) 103 WithColor::error(errs(), ToolName) << Message << '\n'; 104 else 105 WithColor::error(errs(), ToolName) 106 << "'" << File << "': " << Message << '\n'; 107 } 108 109 // This version of error() prints the archive name and member name, for example: 110 // "libx.a(foo.o)" after the ToolName before the error message. It sets 111 // HadError but returns allowing the code to move on to other archive members. 112 static void error(llvm::Error E, StringRef FileName, const Archive::Child &C, 113 StringRef ArchitectureName = StringRef()) { 114 HadError = true; 115 WithColor::error(errs(), ToolName) << "'" << FileName << "'"; 116 117 Expected<StringRef> NameOrErr = C.getName(); 118 // TODO: if we have a error getting the name then it would be nice to print 119 // the index of which archive member this is and or its offset in the 120 // archive instead of "???" as the name. 121 if (!NameOrErr) { 122 consumeError(NameOrErr.takeError()); 123 errs() << "(" << "???" << ")"; 124 } else 125 errs() << "(" << NameOrErr.get() << ")"; 126 127 if (!ArchitectureName.empty()) 128 errs() << " (for architecture " << ArchitectureName << ") "; 129 130 std::string Buf; 131 raw_string_ostream OS(Buf); 132 logAllUnhandledErrors(std::move(E), OS); 133 OS.flush(); 134 errs() << ": " << Buf << "\n"; 135 } 136 137 // 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 138 // before the error message. It sets HadError but returns allowing the code to 139 // move on to other architecture slices. 140 static void error(llvm::Error E, StringRef FileName, 141 StringRef ArchitectureName = StringRef()) { 142 HadError = true; 143 WithColor::error(errs(), ToolName) << "'" << FileName << "'"; 144 145 if (!ArchitectureName.empty()) 146 errs() << " (for architecture " << ArchitectureName << ") "; 147 148 std::string Buf; 149 raw_string_ostream OS(Buf); 150 logAllUnhandledErrors(std::move(E), OS); 151 OS.flush(); 152 errs() << ": " << Buf << "\n"; 153 } 154 155 /// Get the length of the string that represents @p num in Radix including the 156 /// leading 0x or 0 for hexadecimal and octal respectively. 157 static size_t getNumLengthAsString(uint64_t num) { 158 APInt conv(64, num); 159 SmallString<32> result; 160 conv.toString(result, Radix, false, true); 161 return result.size(); 162 } 163 164 /// Return the printing format for the Radix. 165 static const char *getRadixFmt() { 166 switch (Radix) { 167 case octal: 168 return PRIo64; 169 case decimal: 170 return PRIu64; 171 case hexadecimal: 172 return PRIx64; 173 } 174 return nullptr; 175 } 176 177 /// Remove unneeded ELF sections from calculation 178 static bool considerForSize(ObjectFile *Obj, SectionRef Section) { 179 if (!Obj->isELF()) 180 return true; 181 switch (static_cast<ELFSectionRef>(Section).getType()) { 182 case ELF::SHT_NULL: 183 case ELF::SHT_SYMTAB: 184 return false; 185 case ELF::SHT_STRTAB: 186 case ELF::SHT_REL: 187 case ELF::SHT_RELA: 188 return static_cast<ELFSectionRef>(Section).getFlags() & ELF::SHF_ALLOC; 189 } 190 return true; 191 } 192 193 /// Total size of all ELF common symbols 194 static Expected<uint64_t> getCommonSize(ObjectFile *Obj) { 195 uint64_t TotalCommons = 0; 196 for (auto &Sym : Obj->symbols()) { 197 Expected<uint32_t> SymFlagsOrErr = 198 Obj->getSymbolFlags(Sym.getRawDataRefImpl()); 199 if (!SymFlagsOrErr) 200 return SymFlagsOrErr.takeError(); 201 if (*SymFlagsOrErr & SymbolRef::SF_Common) 202 TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl()); 203 } 204 return TotalCommons; 205 } 206 207 /// Print the size of each Mach-O segment and section in @p MachO. 208 /// 209 /// This is when used when @c OutputFormat is darwin and produces the same 210 /// output as darwin's size(1) -m output. 211 static void printDarwinSectionSizes(MachOObjectFile *MachO) { 212 std::string fmtbuf; 213 raw_string_ostream fmt(fmtbuf); 214 const char *radix_fmt = getRadixFmt(); 215 if (Radix == hexadecimal) 216 fmt << "0x"; 217 fmt << "%" << radix_fmt; 218 219 uint32_t Filetype = MachO->getHeader().filetype; 220 221 uint64_t total = 0; 222 for (const auto &Load : MachO->load_commands()) { 223 if (Load.C.cmd == MachO::LC_SEGMENT_64) { 224 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); 225 outs() << "Segment " << Seg.segname << ": " 226 << format(fmt.str().c_str(), Seg.vmsize); 227 if (DarwinLongFormat) 228 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff " 229 << Seg.fileoff << ")"; 230 outs() << "\n"; 231 total += Seg.vmsize; 232 uint64_t sec_total = 0; 233 for (unsigned J = 0; J < Seg.nsects; ++J) { 234 MachO::section_64 Sec = MachO->getSection64(Load, J); 235 if (Filetype == MachO::MH_OBJECT) 236 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " 237 << format("%.16s", &Sec.sectname) << "): "; 238 else 239 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; 240 outs() << format(fmt.str().c_str(), Sec.size); 241 if (DarwinLongFormat) 242 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset " 243 << Sec.offset << ")"; 244 outs() << "\n"; 245 sec_total += Sec.size; 246 } 247 if (Seg.nsects != 0) 248 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; 249 } else if (Load.C.cmd == MachO::LC_SEGMENT) { 250 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); 251 uint64_t Seg_vmsize = Seg.vmsize; 252 outs() << "Segment " << Seg.segname << ": " 253 << format(fmt.str().c_str(), Seg_vmsize); 254 if (DarwinLongFormat) 255 outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff " 256 << Seg.fileoff << ")"; 257 outs() << "\n"; 258 total += Seg.vmsize; 259 uint64_t sec_total = 0; 260 for (unsigned J = 0; J < Seg.nsects; ++J) { 261 MachO::section Sec = MachO->getSection(Load, J); 262 if (Filetype == MachO::MH_OBJECT) 263 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " 264 << format("%.16s", &Sec.sectname) << "): "; 265 else 266 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; 267 uint64_t Sec_size = Sec.size; 268 outs() << format(fmt.str().c_str(), Sec_size); 269 if (DarwinLongFormat) 270 outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset " 271 << Sec.offset << ")"; 272 outs() << "\n"; 273 sec_total += Sec.size; 274 } 275 if (Seg.nsects != 0) 276 outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; 277 } 278 } 279 outs() << "total " << format(fmt.str().c_str(), total) << "\n"; 280 } 281 282 /// Print the summary sizes of the standard Mach-O segments in @p MachO. 283 /// 284 /// This is when used when @c OutputFormat is berkeley with a Mach-O file and 285 /// produces the same output as darwin's size(1) default output. 286 static void printDarwinSegmentSizes(MachOObjectFile *MachO) { 287 uint64_t total_text = 0; 288 uint64_t total_data = 0; 289 uint64_t total_objc = 0; 290 uint64_t total_others = 0; 291 for (const auto &Load : MachO->load_commands()) { 292 if (Load.C.cmd == MachO::LC_SEGMENT_64) { 293 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); 294 if (MachO->getHeader().filetype == MachO::MH_OBJECT) { 295 for (unsigned J = 0; J < Seg.nsects; ++J) { 296 MachO::section_64 Sec = MachO->getSection64(Load, J); 297 StringRef SegmentName = StringRef(Sec.segname); 298 if (SegmentName == "__TEXT") 299 total_text += Sec.size; 300 else if (SegmentName == "__DATA") 301 total_data += Sec.size; 302 else if (SegmentName == "__OBJC") 303 total_objc += Sec.size; 304 else 305 total_others += Sec.size; 306 } 307 } else { 308 StringRef SegmentName = StringRef(Seg.segname); 309 if (SegmentName == "__TEXT") 310 total_text += Seg.vmsize; 311 else if (SegmentName == "__DATA") 312 total_data += Seg.vmsize; 313 else if (SegmentName == "__OBJC") 314 total_objc += Seg.vmsize; 315 else 316 total_others += Seg.vmsize; 317 } 318 } else if (Load.C.cmd == MachO::LC_SEGMENT) { 319 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); 320 if (MachO->getHeader().filetype == MachO::MH_OBJECT) { 321 for (unsigned J = 0; J < Seg.nsects; ++J) { 322 MachO::section Sec = MachO->getSection(Load, J); 323 StringRef SegmentName = StringRef(Sec.segname); 324 if (SegmentName == "__TEXT") 325 total_text += Sec.size; 326 else if (SegmentName == "__DATA") 327 total_data += Sec.size; 328 else if (SegmentName == "__OBJC") 329 total_objc += Sec.size; 330 else 331 total_others += Sec.size; 332 } 333 } else { 334 StringRef SegmentName = StringRef(Seg.segname); 335 if (SegmentName == "__TEXT") 336 total_text += Seg.vmsize; 337 else if (SegmentName == "__DATA") 338 total_data += Seg.vmsize; 339 else if (SegmentName == "__OBJC") 340 total_objc += Seg.vmsize; 341 else 342 total_others += Seg.vmsize; 343 } 344 } 345 } 346 uint64_t total = total_text + total_data + total_objc + total_others; 347 348 if (!BerkeleyHeaderPrinted) { 349 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n"; 350 BerkeleyHeaderPrinted = true; 351 } 352 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t" 353 << total_others << "\t" << total << "\t" << format("%" PRIx64, total) 354 << "\t"; 355 } 356 357 /// Print the size of each section in @p Obj. 358 /// 359 /// The format used is determined by @c OutputFormat and @c Radix. 360 static void printObjectSectionSizes(ObjectFile *Obj) { 361 uint64_t total = 0; 362 std::string fmtbuf; 363 raw_string_ostream fmt(fmtbuf); 364 const char *radix_fmt = getRadixFmt(); 365 366 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's 367 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object 368 // let it fall through to OutputFormat berkeley. 369 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj); 370 if (OutputFormat == darwin && MachO) 371 printDarwinSectionSizes(MachO); 372 // If we have a MachOObjectFile and the OutputFormat is berkeley print as 373 // darwin's default berkeley format for Mach-O files. 374 else if (MachO && OutputFormat == berkeley) 375 printDarwinSegmentSizes(MachO); 376 else if (OutputFormat == sysv) { 377 // Run two passes over all sections. The first gets the lengths needed for 378 // formatting the output. The second actually does the output. 379 std::size_t max_name_len = strlen("section"); 380 std::size_t max_size_len = strlen("size"); 381 std::size_t max_addr_len = strlen("addr"); 382 for (const SectionRef &Section : Obj->sections()) { 383 if (!considerForSize(Obj, Section)) 384 continue; 385 uint64_t size = Section.getSize(); 386 total += size; 387 388 Expected<StringRef> name_or_err = Section.getName(); 389 if (!name_or_err) { 390 error(name_or_err.takeError(), Obj->getFileName()); 391 return; 392 } 393 394 uint64_t addr = Section.getAddress(); 395 max_name_len = std::max(max_name_len, name_or_err->size()); 396 max_size_len = std::max(max_size_len, getNumLengthAsString(size)); 397 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr)); 398 } 399 400 // Add extra padding. 401 max_name_len += 2; 402 max_size_len += 2; 403 max_addr_len += 2; 404 405 // Setup header format. 406 fmt << "%-" << max_name_len << "s " 407 << "%" << max_size_len << "s " 408 << "%" << max_addr_len << "s\n"; 409 410 // Print header 411 outs() << format(fmt.str().c_str(), static_cast<const char *>("section"), 412 static_cast<const char *>("size"), 413 static_cast<const char *>("addr")); 414 fmtbuf.clear(); 415 416 // Setup per section format. 417 fmt << "%-" << max_name_len << "s " 418 << "%#" << max_size_len << radix_fmt << " " 419 << "%#" << max_addr_len << radix_fmt << "\n"; 420 421 // Print each section. 422 for (const SectionRef &Section : Obj->sections()) { 423 if (!considerForSize(Obj, Section)) 424 continue; 425 426 Expected<StringRef> name_or_err = Section.getName(); 427 if (!name_or_err) { 428 error(name_or_err.takeError(), Obj->getFileName()); 429 return; 430 } 431 432 uint64_t size = Section.getSize(); 433 uint64_t addr = Section.getAddress(); 434 outs() << format(fmt.str().c_str(), name_or_err->str().c_str(), size, addr); 435 } 436 437 if (ELFCommons) { 438 if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) { 439 total += *CommonSizeOrErr; 440 outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(), 441 *CommonSizeOrErr, static_cast<uint64_t>(0)); 442 } else { 443 error(CommonSizeOrErr.takeError(), Obj->getFileName()); 444 return; 445 } 446 } 447 448 // Print total. 449 fmtbuf.clear(); 450 fmt << "%-" << max_name_len << "s " 451 << "%#" << max_size_len << radix_fmt << "\n"; 452 outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"), 453 total) 454 << "\n\n"; 455 } else { 456 // The Berkeley format does not display individual section sizes. It 457 // displays the cumulative size for each section type. 458 uint64_t total_text = 0; 459 uint64_t total_data = 0; 460 uint64_t total_bss = 0; 461 462 // Make one pass over the section table to calculate sizes. 463 for (const SectionRef &Section : Obj->sections()) { 464 uint64_t size = Section.getSize(); 465 bool isText = Section.isBerkeleyText(); 466 bool isData = Section.isBerkeleyData(); 467 bool isBSS = Section.isBSS(); 468 if (isText) 469 total_text += size; 470 else if (isData) 471 total_data += size; 472 else if (isBSS) 473 total_bss += size; 474 } 475 476 if (ELFCommons) { 477 if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) 478 total_bss += *CommonSizeOrErr; 479 else { 480 error(CommonSizeOrErr.takeError(), Obj->getFileName()); 481 return; 482 } 483 } 484 485 total = total_text + total_data + total_bss; 486 487 if (TotalSizes) { 488 TotalObjectText += total_text; 489 TotalObjectData += total_data; 490 TotalObjectBss += total_bss; 491 TotalObjectTotal += total; 492 } 493 494 if (!BerkeleyHeaderPrinted) { 495 outs() << " text\t" 496 " data\t" 497 " bss\t" 498 " " 499 << (Radix == octal ? "oct" : "dec") 500 << "\t" 501 " hex\t" 502 "filename\n"; 503 BerkeleyHeaderPrinted = true; 504 } 505 506 // Print result. 507 fmt << "%#7" << radix_fmt << "\t" 508 << "%#7" << radix_fmt << "\t" 509 << "%#7" << radix_fmt << "\t"; 510 outs() << format(fmt.str().c_str(), total_text, total_data, total_bss); 511 fmtbuf.clear(); 512 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" 513 << "%7" PRIx64 "\t"; 514 outs() << format(fmt.str().c_str(), total, total); 515 } 516 } 517 518 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there 519 /// is a list of architecture flags specified then check to make sure this 520 /// Mach-O file is one of those architectures or all architectures was 521 /// specificed. If not then an error is generated and this routine returns 522 /// false. Else it returns true. 523 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { 524 auto *MachO = dyn_cast<MachOObjectFile>(O); 525 526 if (!MachO || ArchAll || ArchFlags.empty()) 527 return true; 528 529 MachO::mach_header H; 530 MachO::mach_header_64 H_64; 531 Triple T; 532 if (MachO->is64Bit()) { 533 H_64 = MachO->MachOObjectFile::getHeader64(); 534 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); 535 } else { 536 H = MachO->MachOObjectFile::getHeader(); 537 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); 538 } 539 if (!is_contained(ArchFlags, T.getArchName())) { 540 error("no architecture specified", Filename); 541 return false; 542 } 543 return true; 544 } 545 546 /// Print the section sizes for @p file. If @p file is an archive, print the 547 /// section sizes for each archive member. 548 static void printFileSectionSizes(StringRef file) { 549 550 // Attempt to open the binary. 551 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file); 552 if (!BinaryOrErr) { 553 error(BinaryOrErr.takeError(), file); 554 return; 555 } 556 Binary &Bin = *BinaryOrErr.get().getBinary(); 557 558 if (Archive *a = dyn_cast<Archive>(&Bin)) { 559 // This is an archive. Iterate over each member and display its sizes. 560 Error Err = Error::success(); 561 for (auto &C : a->children(Err)) { 562 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 563 if (!ChildOrErr) { 564 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) 565 error(std::move(E), a->getFileName(), C); 566 continue; 567 } 568 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 569 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 570 if (!checkMachOAndArchFlags(o, file)) 571 return; 572 if (OutputFormat == sysv) 573 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n"; 574 else if (MachO && OutputFormat == darwin) 575 outs() << a->getFileName() << "(" << o->getFileName() << "):\n"; 576 printObjectSectionSizes(o); 577 if (!MachO && OutputFormat == darwin) 578 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; 579 if (OutputFormat == berkeley) { 580 if (MachO) 581 outs() << a->getFileName() << "(" << o->getFileName() << ")\n"; 582 else 583 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; 584 } 585 } 586 } 587 if (Err) 588 error(std::move(Err), a->getFileName()); 589 } else if (MachOUniversalBinary *UB = 590 dyn_cast<MachOUniversalBinary>(&Bin)) { 591 // If we have a list of architecture flags specified dump only those. 592 if (!ArchAll && !ArchFlags.empty()) { 593 // Look for a slice in the universal binary that matches each ArchFlag. 594 bool ArchFound; 595 for (unsigned i = 0; i < ArchFlags.size(); ++i) { 596 ArchFound = false; 597 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 598 E = UB->end_objects(); 599 I != E; ++I) { 600 if (ArchFlags[i] == I->getArchFlagName()) { 601 ArchFound = true; 602 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 603 if (UO) { 604 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 605 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 606 if (OutputFormat == sysv) 607 outs() << o->getFileName() << " :\n"; 608 else if (MachO && OutputFormat == darwin) { 609 if (MoreThanOneFile || ArchFlags.size() > 1) 610 outs() << o->getFileName() << " (for architecture " 611 << I->getArchFlagName() << "): \n"; 612 } 613 printObjectSectionSizes(o); 614 if (OutputFormat == berkeley) { 615 if (!MachO || MoreThanOneFile || ArchFlags.size() > 1) 616 outs() << o->getFileName() << " (for architecture " 617 << I->getArchFlagName() << ")"; 618 outs() << "\n"; 619 } 620 } 621 } else if (auto E = isNotObjectErrorInvalidFileType( 622 UO.takeError())) { 623 error(std::move(E), file, ArchFlags.size() > 1 ? 624 StringRef(I->getArchFlagName()) : StringRef()); 625 return; 626 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 627 I->getAsArchive()) { 628 std::unique_ptr<Archive> &UA = *AOrErr; 629 // This is an archive. Iterate over each member and display its 630 // sizes. 631 Error Err = Error::success(); 632 for (auto &C : UA->children(Err)) { 633 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 634 if (!ChildOrErr) { 635 if (auto E = isNotObjectErrorInvalidFileType( 636 ChildOrErr.takeError())) 637 error(std::move(E), UA->getFileName(), C, 638 ArchFlags.size() > 1 ? 639 StringRef(I->getArchFlagName()) : StringRef()); 640 continue; 641 } 642 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 643 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 644 if (OutputFormat == sysv) 645 outs() << o->getFileName() << " (ex " << UA->getFileName() 646 << "):\n"; 647 else if (MachO && OutputFormat == darwin) 648 outs() << UA->getFileName() << "(" << o->getFileName() 649 << ")" 650 << " (for architecture " << I->getArchFlagName() 651 << "):\n"; 652 printObjectSectionSizes(o); 653 if (OutputFormat == berkeley) { 654 if (MachO) { 655 outs() << UA->getFileName() << "(" << o->getFileName() 656 << ")"; 657 if (ArchFlags.size() > 1) 658 outs() << " (for architecture " << I->getArchFlagName() 659 << ")"; 660 outs() << "\n"; 661 } else 662 outs() << o->getFileName() << " (ex " << UA->getFileName() 663 << ")\n"; 664 } 665 } 666 } 667 if (Err) 668 error(std::move(Err), UA->getFileName()); 669 } else { 670 consumeError(AOrErr.takeError()); 671 error("mach-o universal file for architecture " + 672 StringRef(I->getArchFlagName()) + 673 " is not a mach-o file or an archive file", 674 file); 675 } 676 } 677 } 678 if (!ArchFound) { 679 error("file does not contain architecture " + ArchFlags[i], file); 680 return; 681 } 682 } 683 return; 684 } 685 // No architecture flags were specified so if this contains a slice that 686 // matches the host architecture dump only that. 687 if (!ArchAll) { 688 StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); 689 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 690 E = UB->end_objects(); 691 I != E; ++I) { 692 if (HostArchName == I->getArchFlagName()) { 693 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 694 if (UO) { 695 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 696 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 697 if (OutputFormat == sysv) 698 outs() << o->getFileName() << " :\n"; 699 else if (MachO && OutputFormat == darwin) { 700 if (MoreThanOneFile) 701 outs() << o->getFileName() << " (for architecture " 702 << I->getArchFlagName() << "):\n"; 703 } 704 printObjectSectionSizes(o); 705 if (OutputFormat == berkeley) { 706 if (!MachO || MoreThanOneFile) 707 outs() << o->getFileName() << " (for architecture " 708 << I->getArchFlagName() << ")"; 709 outs() << "\n"; 710 } 711 } 712 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 713 error(std::move(E), file); 714 return; 715 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 716 I->getAsArchive()) { 717 std::unique_ptr<Archive> &UA = *AOrErr; 718 // This is an archive. Iterate over each member and display its 719 // sizes. 720 Error Err = Error::success(); 721 for (auto &C : UA->children(Err)) { 722 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 723 if (!ChildOrErr) { 724 if (auto E = isNotObjectErrorInvalidFileType( 725 ChildOrErr.takeError())) 726 error(std::move(E), UA->getFileName(), C); 727 continue; 728 } 729 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 730 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 731 if (OutputFormat == sysv) 732 outs() << o->getFileName() << " (ex " << UA->getFileName() 733 << "):\n"; 734 else if (MachO && OutputFormat == darwin) 735 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 736 << " (for architecture " << I->getArchFlagName() 737 << "):\n"; 738 printObjectSectionSizes(o); 739 if (OutputFormat == berkeley) { 740 if (MachO) 741 outs() << UA->getFileName() << "(" << o->getFileName() 742 << ")\n"; 743 else 744 outs() << o->getFileName() << " (ex " << UA->getFileName() 745 << ")\n"; 746 } 747 } 748 } 749 if (Err) 750 error(std::move(Err), UA->getFileName()); 751 } else { 752 consumeError(AOrErr.takeError()); 753 error("mach-o universal file for architecture " + 754 StringRef(I->getArchFlagName()) + 755 " is not a mach-o file or an archive file", 756 file); 757 } 758 return; 759 } 760 } 761 } 762 // Either all architectures have been specified or none have been specified 763 // and this does not contain the host architecture so dump all the slices. 764 bool MoreThanOneArch = UB->getNumberOfObjects() > 1; 765 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 766 E = UB->end_objects(); 767 I != E; ++I) { 768 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 769 if (UO) { 770 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 771 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 772 if (OutputFormat == sysv) 773 outs() << o->getFileName() << " :\n"; 774 else if (MachO && OutputFormat == darwin) { 775 if (MoreThanOneFile || MoreThanOneArch) 776 outs() << o->getFileName() << " (for architecture " 777 << I->getArchFlagName() << "):"; 778 outs() << "\n"; 779 } 780 printObjectSectionSizes(o); 781 if (OutputFormat == berkeley) { 782 if (!MachO || MoreThanOneFile || MoreThanOneArch) 783 outs() << o->getFileName() << " (for architecture " 784 << I->getArchFlagName() << ")"; 785 outs() << "\n"; 786 } 787 } 788 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 789 error(std::move(E), file, MoreThanOneArch ? 790 StringRef(I->getArchFlagName()) : StringRef()); 791 return; 792 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 793 I->getAsArchive()) { 794 std::unique_ptr<Archive> &UA = *AOrErr; 795 // This is an archive. Iterate over each member and display its sizes. 796 Error Err = Error::success(); 797 for (auto &C : UA->children(Err)) { 798 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 799 if (!ChildOrErr) { 800 if (auto E = isNotObjectErrorInvalidFileType( 801 ChildOrErr.takeError())) 802 error(std::move(E), UA->getFileName(), C, MoreThanOneArch ? 803 StringRef(I->getArchFlagName()) : StringRef()); 804 continue; 805 } 806 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 807 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 808 if (OutputFormat == sysv) 809 outs() << o->getFileName() << " (ex " << UA->getFileName() 810 << "):\n"; 811 else if (MachO && OutputFormat == darwin) 812 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 813 << " (for architecture " << I->getArchFlagName() << "):\n"; 814 printObjectSectionSizes(o); 815 if (OutputFormat == berkeley) { 816 if (MachO) 817 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 818 << " (for architecture " << I->getArchFlagName() 819 << ")\n"; 820 else 821 outs() << o->getFileName() << " (ex " << UA->getFileName() 822 << ")\n"; 823 } 824 } 825 } 826 if (Err) 827 error(std::move(Err), UA->getFileName()); 828 } else { 829 consumeError(AOrErr.takeError()); 830 error("mach-o universal file for architecture " + 831 StringRef(I->getArchFlagName()) + 832 " is not a mach-o file or an archive file", 833 file); 834 } 835 } 836 } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) { 837 if (!checkMachOAndArchFlags(o, file)) 838 return; 839 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 840 if (OutputFormat == sysv) 841 outs() << o->getFileName() << " :\n"; 842 else if (MachO && OutputFormat == darwin && MoreThanOneFile) 843 outs() << o->getFileName() << ":\n"; 844 printObjectSectionSizes(o); 845 if (!MachO && OutputFormat == darwin) 846 outs() << o->getFileName() << "\n"; 847 if (OutputFormat == berkeley) { 848 if (!MachO || MoreThanOneFile) 849 outs() << o->getFileName(); 850 outs() << "\n"; 851 } 852 } else { 853 error("unsupported file type", file); 854 } 855 } 856 857 static void printBerkeleyTotals() { 858 std::string fmtbuf; 859 raw_string_ostream fmt(fmtbuf); 860 const char *radix_fmt = getRadixFmt(); 861 fmt << "%#7" << radix_fmt << "\t" 862 << "%#7" << radix_fmt << "\t" 863 << "%#7" << radix_fmt << "\t"; 864 outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData, 865 TotalObjectBss); 866 fmtbuf.clear(); 867 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" 868 << "%7" PRIx64 "\t"; 869 outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal) 870 << "(TOTALS)\n"; 871 } 872 873 int llvm_size_main(int argc, char **argv, const llvm::ToolContext &) { 874 InitLLVM X(argc, argv); 875 BumpPtrAllocator A; 876 StringSaver Saver(A); 877 SizeOptTable Tbl; 878 ToolName = argv[0]; 879 opt::InputArgList Args = 880 Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { 881 error(Msg); 882 exit(1); 883 }); 884 if (Args.hasArg(OPT_help)) { 885 Tbl.printHelp( 886 outs(), 887 (Twine(ToolName) + " [options] <input object files>").str().c_str(), 888 "LLVM object size dumper"); 889 // TODO Replace this with OptTable API once it adds extrahelp support. 890 outs() << "\nPass @FILE as argument to read options from FILE.\n"; 891 return 0; 892 } 893 if (Args.hasArg(OPT_version)) { 894 outs() << ToolName << '\n'; 895 cl::PrintVersionMessage(); 896 return 0; 897 } 898 899 ELFCommons = Args.hasArg(OPT_common); 900 DarwinLongFormat = Args.hasArg(OPT_l); 901 TotalSizes = Args.hasArg(OPT_totals); 902 StringRef V = Args.getLastArgValue(OPT_format_EQ, "berkeley"); 903 if (V == "berkeley") 904 OutputFormat = berkeley; 905 else if (V == "darwin") 906 OutputFormat = darwin; 907 else if (V == "sysv") 908 OutputFormat = sysv; 909 else 910 error("--format value should be one of: 'berkeley', 'darwin', 'sysv'"); 911 V = Args.getLastArgValue(OPT_radix_EQ, "10"); 912 if (V == "8") 913 Radix = RadixTy::octal; 914 else if (V == "10") 915 Radix = RadixTy::decimal; 916 else if (V == "16") 917 Radix = RadixTy::hexadecimal; 918 else 919 error("--radix value should be one of: 8, 10, 16 "); 920 921 for (const auto *A : Args.filtered(OPT_arch_EQ)) { 922 SmallVector<StringRef, 2> Values; 923 llvm::SplitString(A->getValue(), Values, ","); 924 for (StringRef V : Values) { 925 if (V == "all") 926 ArchAll = true; 927 else if (MachOObjectFile::isValidArch(V)) 928 ArchFlags.push_back(V); 929 else { 930 outs() << ToolName << ": for the -arch option: Unknown architecture " 931 << "named '" << V << "'"; 932 return 1; 933 } 934 } 935 } 936 937 InputFilenames = Args.getAllArgValues(OPT_INPUT); 938 if (InputFilenames.empty()) 939 InputFilenames.push_back("a.out"); 940 941 MoreThanOneFile = InputFilenames.size() > 1; 942 llvm::for_each(InputFilenames, printFileSectionSizes); 943 if (OutputFormat == berkeley && TotalSizes) 944 printBerkeleyTotals(); 945 946 if (HadError) 947 return 1; 948 return 0; 949 } 950