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