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 (none_of(ArchFlags, [&](const std::string &Name) { 546 return Name == T.getArchName(); 547 })) { 548 error("no architecture specified", Filename); 549 return false; 550 } 551 return true; 552 } 553 554 /// Print the section sizes for @p file. If @p file is an archive, print the 555 /// section sizes for each archive member. 556 static void printFileSectionSizes(StringRef file) { 557 558 // Attempt to open the binary. 559 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file); 560 if (!BinaryOrErr) { 561 error(BinaryOrErr.takeError(), file); 562 return; 563 } 564 Binary &Bin = *BinaryOrErr.get().getBinary(); 565 566 if (Archive *a = dyn_cast<Archive>(&Bin)) { 567 // This is an archive. Iterate over each member and display its sizes. 568 Error Err = Error::success(); 569 for (auto &C : a->children(Err)) { 570 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 571 if (!ChildOrErr) { 572 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) 573 error(std::move(E), a->getFileName(), C); 574 continue; 575 } 576 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 577 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 578 if (!checkMachOAndArchFlags(o, file)) 579 return; 580 if (OutputFormat == sysv) 581 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n"; 582 else if (MachO && OutputFormat == darwin) 583 outs() << a->getFileName() << "(" << o->getFileName() << "):\n"; 584 printObjectSectionSizes(o); 585 if (OutputFormat == berkeley) { 586 if (MachO) 587 outs() << a->getFileName() << "(" << o->getFileName() << ")\n"; 588 else 589 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; 590 } 591 } 592 } 593 if (Err) 594 error(std::move(Err), a->getFileName()); 595 } else if (MachOUniversalBinary *UB = 596 dyn_cast<MachOUniversalBinary>(&Bin)) { 597 // If we have a list of architecture flags specified dump only those. 598 if (!ArchAll && !ArchFlags.empty()) { 599 // Look for a slice in the universal binary that matches each ArchFlag. 600 bool ArchFound; 601 for (unsigned i = 0; i < ArchFlags.size(); ++i) { 602 ArchFound = false; 603 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 604 E = UB->end_objects(); 605 I != E; ++I) { 606 if (ArchFlags[i] == I->getArchFlagName()) { 607 ArchFound = true; 608 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 609 if (UO) { 610 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 611 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 612 if (OutputFormat == sysv) 613 outs() << o->getFileName() << " :\n"; 614 else if (MachO && OutputFormat == darwin) { 615 if (MoreThanOneFile || ArchFlags.size() > 1) 616 outs() << o->getFileName() << " (for architecture " 617 << I->getArchFlagName() << "): \n"; 618 } 619 printObjectSectionSizes(o); 620 if (OutputFormat == berkeley) { 621 if (!MachO || MoreThanOneFile || ArchFlags.size() > 1) 622 outs() << o->getFileName() << " (for architecture " 623 << I->getArchFlagName() << ")"; 624 outs() << "\n"; 625 } 626 } 627 } else if (auto E = isNotObjectErrorInvalidFileType( 628 UO.takeError())) { 629 error(std::move(E), file, ArchFlags.size() > 1 ? 630 StringRef(I->getArchFlagName()) : StringRef()); 631 return; 632 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 633 I->getAsArchive()) { 634 std::unique_ptr<Archive> &UA = *AOrErr; 635 // This is an archive. Iterate over each member and display its 636 // sizes. 637 Error Err = Error::success(); 638 for (auto &C : UA->children(Err)) { 639 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 640 if (!ChildOrErr) { 641 if (auto E = isNotObjectErrorInvalidFileType( 642 ChildOrErr.takeError())) 643 error(std::move(E), UA->getFileName(), C, 644 ArchFlags.size() > 1 ? 645 StringRef(I->getArchFlagName()) : StringRef()); 646 continue; 647 } 648 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 649 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 650 if (OutputFormat == sysv) 651 outs() << o->getFileName() << " (ex " << UA->getFileName() 652 << "):\n"; 653 else if (MachO && OutputFormat == darwin) 654 outs() << UA->getFileName() << "(" << o->getFileName() 655 << ")" 656 << " (for architecture " << I->getArchFlagName() 657 << "):\n"; 658 printObjectSectionSizes(o); 659 if (OutputFormat == berkeley) { 660 if (MachO) { 661 outs() << UA->getFileName() << "(" << o->getFileName() 662 << ")"; 663 if (ArchFlags.size() > 1) 664 outs() << " (for architecture " << I->getArchFlagName() 665 << ")"; 666 outs() << "\n"; 667 } else 668 outs() << o->getFileName() << " (ex " << UA->getFileName() 669 << ")\n"; 670 } 671 } 672 } 673 if (Err) 674 error(std::move(Err), UA->getFileName()); 675 } else { 676 consumeError(AOrErr.takeError()); 677 error("mach-o universal file for architecture " + 678 StringRef(I->getArchFlagName()) + 679 " is not a mach-o file or an archive file", 680 file); 681 } 682 } 683 } 684 if (!ArchFound) { 685 error("file does not contain architecture " + ArchFlags[i], file); 686 return; 687 } 688 } 689 return; 690 } 691 // No architecture flags were specified so if this contains a slice that 692 // matches the host architecture dump only that. 693 if (!ArchAll) { 694 StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); 695 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 696 E = UB->end_objects(); 697 I != E; ++I) { 698 if (HostArchName == I->getArchFlagName()) { 699 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 700 if (UO) { 701 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 702 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 703 if (OutputFormat == sysv) 704 outs() << o->getFileName() << " :\n"; 705 else if (MachO && OutputFormat == darwin) { 706 if (MoreThanOneFile) 707 outs() << o->getFileName() << " (for architecture " 708 << I->getArchFlagName() << "):\n"; 709 } 710 printObjectSectionSizes(o); 711 if (OutputFormat == berkeley) { 712 if (!MachO || MoreThanOneFile) 713 outs() << o->getFileName() << " (for architecture " 714 << I->getArchFlagName() << ")"; 715 outs() << "\n"; 716 } 717 } 718 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 719 error(std::move(E), file); 720 return; 721 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 722 I->getAsArchive()) { 723 std::unique_ptr<Archive> &UA = *AOrErr; 724 // This is an archive. Iterate over each member and display its 725 // sizes. 726 Error Err = Error::success(); 727 for (auto &C : UA->children(Err)) { 728 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 729 if (!ChildOrErr) { 730 if (auto E = isNotObjectErrorInvalidFileType( 731 ChildOrErr.takeError())) 732 error(std::move(E), UA->getFileName(), C); 733 continue; 734 } 735 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 736 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 737 if (OutputFormat == sysv) 738 outs() << o->getFileName() << " (ex " << UA->getFileName() 739 << "):\n"; 740 else if (MachO && OutputFormat == darwin) 741 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 742 << " (for architecture " << I->getArchFlagName() 743 << "):\n"; 744 printObjectSectionSizes(o); 745 if (OutputFormat == berkeley) { 746 if (MachO) 747 outs() << UA->getFileName() << "(" << o->getFileName() 748 << ")\n"; 749 else 750 outs() << o->getFileName() << " (ex " << UA->getFileName() 751 << ")\n"; 752 } 753 } 754 } 755 if (Err) 756 error(std::move(Err), UA->getFileName()); 757 } else { 758 consumeError(AOrErr.takeError()); 759 error("mach-o universal file for architecture " + 760 StringRef(I->getArchFlagName()) + 761 " is not a mach-o file or an archive file", 762 file); 763 } 764 return; 765 } 766 } 767 } 768 // Either all architectures have been specified or none have been specified 769 // and this does not contain the host architecture so dump all the slices. 770 bool MoreThanOneArch = UB->getNumberOfObjects() > 1; 771 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 772 E = UB->end_objects(); 773 I != E; ++I) { 774 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 775 if (UO) { 776 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 777 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 778 if (OutputFormat == sysv) 779 outs() << o->getFileName() << " :\n"; 780 else if (MachO && OutputFormat == darwin) { 781 if (MoreThanOneFile || MoreThanOneArch) 782 outs() << o->getFileName() << " (for architecture " 783 << I->getArchFlagName() << "):"; 784 outs() << "\n"; 785 } 786 printObjectSectionSizes(o); 787 if (OutputFormat == berkeley) { 788 if (!MachO || MoreThanOneFile || MoreThanOneArch) 789 outs() << o->getFileName() << " (for architecture " 790 << I->getArchFlagName() << ")"; 791 outs() << "\n"; 792 } 793 } 794 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 795 error(std::move(E), file, MoreThanOneArch ? 796 StringRef(I->getArchFlagName()) : StringRef()); 797 return; 798 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 799 I->getAsArchive()) { 800 std::unique_ptr<Archive> &UA = *AOrErr; 801 // This is an archive. Iterate over each member and display its sizes. 802 Error Err = Error::success(); 803 for (auto &C : UA->children(Err)) { 804 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 805 if (!ChildOrErr) { 806 if (auto E = isNotObjectErrorInvalidFileType( 807 ChildOrErr.takeError())) 808 error(std::move(E), UA->getFileName(), C, MoreThanOneArch ? 809 StringRef(I->getArchFlagName()) : StringRef()); 810 continue; 811 } 812 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 813 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 814 if (OutputFormat == sysv) 815 outs() << o->getFileName() << " (ex " << UA->getFileName() 816 << "):\n"; 817 else if (MachO && OutputFormat == darwin) 818 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 819 << " (for architecture " << I->getArchFlagName() << "):\n"; 820 printObjectSectionSizes(o); 821 if (OutputFormat == berkeley) { 822 if (MachO) 823 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 824 << " (for architecture " << I->getArchFlagName() 825 << ")\n"; 826 else 827 outs() << o->getFileName() << " (ex " << UA->getFileName() 828 << ")\n"; 829 } 830 } 831 } 832 if (Err) 833 error(std::move(Err), UA->getFileName()); 834 } else { 835 consumeError(AOrErr.takeError()); 836 error("mach-o universal file for architecture " + 837 StringRef(I->getArchFlagName()) + 838 " is not a mach-o file or an archive file", 839 file); 840 } 841 } 842 } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) { 843 if (!checkMachOAndArchFlags(o, file)) 844 return; 845 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 846 if (OutputFormat == sysv) 847 outs() << o->getFileName() << " :\n"; 848 else if (MachO && OutputFormat == darwin && MoreThanOneFile) 849 outs() << o->getFileName() << ":\n"; 850 printObjectSectionSizes(o); 851 if (OutputFormat == berkeley) { 852 if (!MachO || MoreThanOneFile) 853 outs() << o->getFileName(); 854 outs() << "\n"; 855 } 856 } else { 857 error("unsupported file type", file); 858 } 859 } 860 861 static void printBerkeleyTotals() { 862 std::string fmtbuf; 863 raw_string_ostream fmt(fmtbuf); 864 const char *radix_fmt = getRadixFmt(); 865 fmt << "%#7" << radix_fmt << "\t" 866 << "%#7" << radix_fmt << "\t" 867 << "%#7" << radix_fmt << "\t"; 868 outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData, 869 TotalObjectBss); 870 fmtbuf.clear(); 871 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" 872 << "%7" PRIx64 "\t"; 873 outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal) 874 << "(TOTALS)\n"; 875 } 876 877 int main(int argc, char **argv) { 878 InitLLVM X(argc, argv); 879 cl::HideUnrelatedOptions(SizeCat); 880 cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n"); 881 882 ToolName = argv[0]; 883 if (OutputFormatShort.getNumOccurrences()) 884 OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort); 885 if (RadixShort.getNumOccurrences()) 886 Radix = RadixShort.getValue(); 887 888 for (StringRef Arch : ArchFlags) { 889 if (Arch == "all") { 890 ArchAll = true; 891 } else { 892 if (!MachOObjectFile::isValidArch(Arch)) { 893 outs() << ToolName << ": for the -arch option: Unknown architecture " 894 << "named '" << Arch << "'"; 895 return 1; 896 } 897 } 898 } 899 900 if (InputFilenames.empty()) 901 InputFilenames.push_back("a.out"); 902 903 MoreThanOneFile = InputFilenames.size() > 1; 904 llvm::for_each(InputFilenames, printFileSectionSizes); 905 if (OutputFormat == berkeley && TotalSizes) 906 printBerkeleyTotals(); 907 908 if (HadError) 909 return 1; 910 } 911