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