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