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