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