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