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