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(fmtbuf.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(fmtbuf.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(fmtbuf.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(fmtbuf.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(fmtbuf.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(fmtbuf.c_str(), sec_total) << "\n"; 268 } 269 } 270 outs() << "total " << format(fmtbuf.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(fmtbuf.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(fmtbuf.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(fmtbuf.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(fmtbuf.c_str(), static_cast<const char *>("Total"), total) 444 << "\n\n"; 445 } else { 446 // The Berkeley format does not display individual section sizes. It 447 // displays the cumulative size for each section type. 448 uint64_t total_text = 0; 449 uint64_t total_data = 0; 450 uint64_t total_bss = 0; 451 452 // Make one pass over the section table to calculate sizes. 453 for (const SectionRef &Section : Obj->sections()) { 454 uint64_t size = Section.getSize(); 455 bool isText = Section.isBerkeleyText(); 456 bool isData = Section.isBerkeleyData(); 457 bool isBSS = Section.isBSS(); 458 if (isText) 459 total_text += size; 460 else if (isData) 461 total_data += size; 462 else if (isBSS) 463 total_bss += size; 464 } 465 466 if (ELFCommons) { 467 if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) 468 total_bss += *CommonSizeOrErr; 469 else { 470 error(CommonSizeOrErr.takeError(), Obj->getFileName()); 471 return; 472 } 473 } 474 475 total = total_text + total_data + total_bss; 476 477 if (TotalSizes) { 478 TotalObjectText += total_text; 479 TotalObjectData += total_data; 480 TotalObjectBss += total_bss; 481 TotalObjectTotal += total; 482 } 483 484 if (!BerkeleyHeaderPrinted) { 485 outs() << " text\t" 486 " data\t" 487 " bss\t" 488 " " 489 << (Radix == octal ? "oct" : "dec") 490 << "\t" 491 " hex\t" 492 "filename\n"; 493 BerkeleyHeaderPrinted = true; 494 } 495 496 // Print result. 497 fmt << "%#7" << radix_fmt << "\t" 498 << "%#7" << radix_fmt << "\t" 499 << "%#7" << radix_fmt << "\t"; 500 outs() << format(fmtbuf.c_str(), total_text, total_data, total_bss); 501 fmtbuf.clear(); 502 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" 503 << "%7" PRIx64 "\t"; 504 outs() << format(fmtbuf.c_str(), total, total); 505 } 506 } 507 508 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there 509 /// is a list of architecture flags specified then check to make sure this 510 /// Mach-O file is one of those architectures or all architectures was 511 /// specificed. If not then an error is generated and this routine returns 512 /// false. Else it returns true. 513 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { 514 auto *MachO = dyn_cast<MachOObjectFile>(O); 515 516 if (!MachO || ArchAll || ArchFlags.empty()) 517 return true; 518 519 MachO::mach_header H; 520 MachO::mach_header_64 H_64; 521 Triple T; 522 if (MachO->is64Bit()) { 523 H_64 = MachO->MachOObjectFile::getHeader64(); 524 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); 525 } else { 526 H = MachO->MachOObjectFile::getHeader(); 527 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); 528 } 529 if (!is_contained(ArchFlags, T.getArchName())) { 530 error("no architecture specified", Filename); 531 return false; 532 } 533 return true; 534 } 535 536 /// Print the section sizes for @p file. If @p file is an archive, print the 537 /// section sizes for each archive member. 538 static void printFileSectionSizes(StringRef file) { 539 540 // Attempt to open the binary. 541 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file); 542 if (!BinaryOrErr) { 543 error(BinaryOrErr.takeError(), file); 544 return; 545 } 546 Binary &Bin = *BinaryOrErr.get().getBinary(); 547 548 if (Archive *a = dyn_cast<Archive>(&Bin)) { 549 // This is an archive. Iterate over each member and display its sizes. 550 Error Err = Error::success(); 551 for (auto &C : a->children(Err)) { 552 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 553 if (!ChildOrErr) { 554 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) 555 error(std::move(E), a->getFileName(), C); 556 continue; 557 } 558 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 559 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 560 if (!checkMachOAndArchFlags(o, file)) 561 return; 562 if (OutputFormat == sysv) 563 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n"; 564 else if (MachO && OutputFormat == darwin) 565 outs() << a->getFileName() << "(" << o->getFileName() << "):\n"; 566 printObjectSectionSizes(o); 567 if (!MachO && OutputFormat == darwin) 568 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; 569 if (OutputFormat == berkeley) { 570 if (MachO) 571 outs() << a->getFileName() << "(" << o->getFileName() << ")\n"; 572 else 573 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; 574 } 575 } 576 } 577 if (Err) 578 error(std::move(Err), a->getFileName()); 579 } else if (MachOUniversalBinary *UB = 580 dyn_cast<MachOUniversalBinary>(&Bin)) { 581 // If we have a list of architecture flags specified dump only those. 582 if (!ArchAll && !ArchFlags.empty()) { 583 // Look for a slice in the universal binary that matches each ArchFlag. 584 bool ArchFound; 585 for (unsigned i = 0; i < ArchFlags.size(); ++i) { 586 ArchFound = false; 587 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 588 E = UB->end_objects(); 589 I != E; ++I) { 590 if (ArchFlags[i] == I->getArchFlagName()) { 591 ArchFound = true; 592 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 593 if (UO) { 594 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 595 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 596 if (OutputFormat == sysv) 597 outs() << o->getFileName() << " :\n"; 598 else if (MachO && OutputFormat == darwin) { 599 if (MoreThanOneFile || ArchFlags.size() > 1) 600 outs() << o->getFileName() << " (for architecture " 601 << I->getArchFlagName() << "): \n"; 602 } 603 printObjectSectionSizes(o); 604 if (OutputFormat == berkeley) { 605 if (!MachO || MoreThanOneFile || ArchFlags.size() > 1) 606 outs() << o->getFileName() << " (for architecture " 607 << I->getArchFlagName() << ")"; 608 outs() << "\n"; 609 } 610 } 611 } else if (auto E = isNotObjectErrorInvalidFileType( 612 UO.takeError())) { 613 error(std::move(E), file, ArchFlags.size() > 1 ? 614 StringRef(I->getArchFlagName()) : StringRef()); 615 return; 616 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 617 I->getAsArchive()) { 618 std::unique_ptr<Archive> &UA = *AOrErr; 619 // This is an archive. Iterate over each member and display its 620 // sizes. 621 Error Err = Error::success(); 622 for (auto &C : UA->children(Err)) { 623 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 624 if (!ChildOrErr) { 625 if (auto E = isNotObjectErrorInvalidFileType( 626 ChildOrErr.takeError())) 627 error(std::move(E), UA->getFileName(), C, 628 ArchFlags.size() > 1 ? 629 StringRef(I->getArchFlagName()) : StringRef()); 630 continue; 631 } 632 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 633 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 634 if (OutputFormat == sysv) 635 outs() << o->getFileName() << " (ex " << UA->getFileName() 636 << "):\n"; 637 else if (MachO && OutputFormat == darwin) 638 outs() << UA->getFileName() << "(" << o->getFileName() 639 << ")" 640 << " (for architecture " << I->getArchFlagName() 641 << "):\n"; 642 printObjectSectionSizes(o); 643 if (OutputFormat == berkeley) { 644 if (MachO) { 645 outs() << UA->getFileName() << "(" << o->getFileName() 646 << ")"; 647 if (ArchFlags.size() > 1) 648 outs() << " (for architecture " << I->getArchFlagName() 649 << ")"; 650 outs() << "\n"; 651 } else 652 outs() << o->getFileName() << " (ex " << UA->getFileName() 653 << ")\n"; 654 } 655 } 656 } 657 if (Err) 658 error(std::move(Err), UA->getFileName()); 659 } else { 660 consumeError(AOrErr.takeError()); 661 error("mach-o universal file for architecture " + 662 StringRef(I->getArchFlagName()) + 663 " is not a mach-o file or an archive file", 664 file); 665 } 666 } 667 } 668 if (!ArchFound) { 669 error("file does not contain architecture " + ArchFlags[i], file); 670 return; 671 } 672 } 673 return; 674 } 675 // No architecture flags were specified so if this contains a slice that 676 // matches the host architecture dump only that. 677 if (!ArchAll) { 678 StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); 679 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 680 E = UB->end_objects(); 681 I != E; ++I) { 682 if (HostArchName == I->getArchFlagName()) { 683 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 684 if (UO) { 685 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 686 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 687 if (OutputFormat == sysv) 688 outs() << o->getFileName() << " :\n"; 689 else if (MachO && OutputFormat == darwin) { 690 if (MoreThanOneFile) 691 outs() << o->getFileName() << " (for architecture " 692 << I->getArchFlagName() << "):\n"; 693 } 694 printObjectSectionSizes(o); 695 if (OutputFormat == berkeley) { 696 if (!MachO || MoreThanOneFile) 697 outs() << o->getFileName() << " (for architecture " 698 << I->getArchFlagName() << ")"; 699 outs() << "\n"; 700 } 701 } 702 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 703 error(std::move(E), file); 704 return; 705 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 706 I->getAsArchive()) { 707 std::unique_ptr<Archive> &UA = *AOrErr; 708 // This is an archive. Iterate over each member and display its 709 // sizes. 710 Error Err = Error::success(); 711 for (auto &C : UA->children(Err)) { 712 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 713 if (!ChildOrErr) { 714 if (auto E = isNotObjectErrorInvalidFileType( 715 ChildOrErr.takeError())) 716 error(std::move(E), UA->getFileName(), C); 717 continue; 718 } 719 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 720 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 721 if (OutputFormat == sysv) 722 outs() << o->getFileName() << " (ex " << UA->getFileName() 723 << "):\n"; 724 else if (MachO && OutputFormat == darwin) 725 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 726 << " (for architecture " << I->getArchFlagName() 727 << "):\n"; 728 printObjectSectionSizes(o); 729 if (OutputFormat == berkeley) { 730 if (MachO) 731 outs() << UA->getFileName() << "(" << o->getFileName() 732 << ")\n"; 733 else 734 outs() << o->getFileName() << " (ex " << UA->getFileName() 735 << ")\n"; 736 } 737 } 738 } 739 if (Err) 740 error(std::move(Err), UA->getFileName()); 741 } else { 742 consumeError(AOrErr.takeError()); 743 error("mach-o universal file for architecture " + 744 StringRef(I->getArchFlagName()) + 745 " is not a mach-o file or an archive file", 746 file); 747 } 748 return; 749 } 750 } 751 } 752 // Either all architectures have been specified or none have been specified 753 // and this does not contain the host architecture so dump all the slices. 754 bool MoreThanOneArch = UB->getNumberOfObjects() > 1; 755 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 756 E = UB->end_objects(); 757 I != E; ++I) { 758 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 759 if (UO) { 760 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 761 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 762 if (OutputFormat == sysv) 763 outs() << o->getFileName() << " :\n"; 764 else if (MachO && OutputFormat == darwin) { 765 if (MoreThanOneFile || MoreThanOneArch) 766 outs() << o->getFileName() << " (for architecture " 767 << I->getArchFlagName() << "):"; 768 outs() << "\n"; 769 } 770 printObjectSectionSizes(o); 771 if (OutputFormat == berkeley) { 772 if (!MachO || MoreThanOneFile || MoreThanOneArch) 773 outs() << o->getFileName() << " (for architecture " 774 << I->getArchFlagName() << ")"; 775 outs() << "\n"; 776 } 777 } 778 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 779 error(std::move(E), file, MoreThanOneArch ? 780 StringRef(I->getArchFlagName()) : StringRef()); 781 return; 782 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 783 I->getAsArchive()) { 784 std::unique_ptr<Archive> &UA = *AOrErr; 785 // This is an archive. Iterate over each member and display its sizes. 786 Error Err = Error::success(); 787 for (auto &C : UA->children(Err)) { 788 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 789 if (!ChildOrErr) { 790 if (auto E = isNotObjectErrorInvalidFileType( 791 ChildOrErr.takeError())) 792 error(std::move(E), UA->getFileName(), C, MoreThanOneArch ? 793 StringRef(I->getArchFlagName()) : StringRef()); 794 continue; 795 } 796 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 797 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 798 if (OutputFormat == sysv) 799 outs() << o->getFileName() << " (ex " << UA->getFileName() 800 << "):\n"; 801 else if (MachO && OutputFormat == darwin) 802 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 803 << " (for architecture " << I->getArchFlagName() << "):\n"; 804 printObjectSectionSizes(o); 805 if (OutputFormat == berkeley) { 806 if (MachO) 807 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 808 << " (for architecture " << I->getArchFlagName() 809 << ")\n"; 810 else 811 outs() << o->getFileName() << " (ex " << UA->getFileName() 812 << ")\n"; 813 } 814 } 815 } 816 if (Err) 817 error(std::move(Err), UA->getFileName()); 818 } else { 819 consumeError(AOrErr.takeError()); 820 error("mach-o universal file for architecture " + 821 StringRef(I->getArchFlagName()) + 822 " is not a mach-o file or an archive file", 823 file); 824 } 825 } 826 } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) { 827 if (!checkMachOAndArchFlags(o, file)) 828 return; 829 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 830 if (OutputFormat == sysv) 831 outs() << o->getFileName() << " :\n"; 832 else if (MachO && OutputFormat == darwin && MoreThanOneFile) 833 outs() << o->getFileName() << ":\n"; 834 printObjectSectionSizes(o); 835 if (!MachO && OutputFormat == darwin) 836 outs() << o->getFileName() << "\n"; 837 if (OutputFormat == berkeley) { 838 if (!MachO || MoreThanOneFile) 839 outs() << o->getFileName(); 840 outs() << "\n"; 841 } 842 } else { 843 error("unsupported file type", file); 844 } 845 } 846 847 static void printBerkeleyTotals() { 848 std::string fmtbuf; 849 raw_string_ostream fmt(fmtbuf); 850 const char *radix_fmt = getRadixFmt(); 851 fmt << "%#7" << radix_fmt << "\t" 852 << "%#7" << radix_fmt << "\t" 853 << "%#7" << radix_fmt << "\t"; 854 outs() << format(fmtbuf.c_str(), TotalObjectText, TotalObjectData, 855 TotalObjectBss); 856 fmtbuf.clear(); 857 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" 858 << "%7" PRIx64 "\t"; 859 outs() << format(fmtbuf.c_str(), TotalObjectTotal, TotalObjectTotal) 860 << "(TOTALS)\n"; 861 } 862 863 int llvm_size_main(int argc, char **argv, const llvm::ToolContext &) { 864 BumpPtrAllocator A; 865 StringSaver Saver(A); 866 SizeOptTable Tbl; 867 ToolName = argv[0]; 868 opt::InputArgList Args = 869 Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { 870 error(Msg); 871 exit(1); 872 }); 873 if (Args.hasArg(OPT_help)) { 874 Tbl.printHelp( 875 outs(), 876 (Twine(ToolName) + " [options] <input object files>").str().c_str(), 877 "LLVM object size dumper"); 878 // TODO Replace this with OptTable API once it adds extrahelp support. 879 outs() << "\nPass @FILE as argument to read options from FILE.\n"; 880 return 0; 881 } 882 if (Args.hasArg(OPT_version)) { 883 outs() << ToolName << '\n'; 884 cl::PrintVersionMessage(); 885 return 0; 886 } 887 888 ELFCommons = Args.hasArg(OPT_common); 889 DarwinLongFormat = Args.hasArg(OPT_l); 890 TotalSizes = Args.hasArg(OPT_totals); 891 StringRef V = Args.getLastArgValue(OPT_format_EQ, "berkeley"); 892 if (V == "berkeley") 893 OutputFormat = berkeley; 894 else if (V == "darwin") 895 OutputFormat = darwin; 896 else if (V == "sysv") 897 OutputFormat = sysv; 898 else 899 error("--format value should be one of: 'berkeley', 'darwin', 'sysv'"); 900 V = Args.getLastArgValue(OPT_radix_EQ, "10"); 901 if (V == "8") 902 Radix = RadixTy::octal; 903 else if (V == "10") 904 Radix = RadixTy::decimal; 905 else if (V == "16") 906 Radix = RadixTy::hexadecimal; 907 else 908 error("--radix value should be one of: 8, 10, 16 "); 909 910 for (const auto *A : Args.filtered(OPT_arch_EQ)) { 911 SmallVector<StringRef, 2> Values; 912 llvm::SplitString(A->getValue(), Values, ","); 913 for (StringRef V : Values) { 914 if (V == "all") 915 ArchAll = true; 916 else if (MachOObjectFile::isValidArch(V)) 917 ArchFlags.push_back(V); 918 else { 919 outs() << ToolName << ": for the -arch option: Unknown architecture " 920 << "named '" << V << "'"; 921 return 1; 922 } 923 } 924 } 925 926 InputFilenames = Args.getAllArgValues(OPT_INPUT); 927 if (InputFilenames.empty()) 928 InputFilenames.push_back("a.out"); 929 930 MoreThanOneFile = InputFilenames.size() > 1; 931 llvm::for_each(InputFilenames, printFileSectionSizes); 932 if (OutputFormat == berkeley && TotalSizes) 933 printBerkeleyTotals(); 934 935 if (HadError) 936 return 1; 937 return 0; 938 } 939