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