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<RadixTy> Radix( 75 "radix", cl::desc("Print size in radix"), cl::init(decimal), 76 cl::values(clEnumValN(octal, "8", "Print size in octal"), 77 clEnumValN(decimal, "10", "Print size in decimal"), 78 clEnumValN(hexadecimal, "16", "Print size in hexadecimal"))); 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 static 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.isBerkeleyText(); 461 bool isData = Section.isBerkeleyData(); 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\t" 485 " data\t" 486 " bss\t" 487 " " 488 << (Radix == octal ? "oct" : "dec") 489 << "\t" 490 " hex\t" 491 "filename\n"; 492 BerkeleyHeaderPrinted = true; 493 } 494 495 // Print result. 496 fmt << "%#7" << radix_fmt << "\t" 497 << "%#7" << radix_fmt << "\t" 498 << "%#7" << radix_fmt << "\t"; 499 outs() << format(fmt.str().c_str(), total_text, total_data, total_bss); 500 fmtbuf.clear(); 501 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" 502 << "%7" PRIx64 "\t"; 503 outs() << format(fmt.str().c_str(), total, total); 504 } 505 } 506 507 /// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there 508 /// is a list of architecture flags specified then check to make sure this 509 /// Mach-O file is one of those architectures or all architectures was 510 /// specificed. If not then an error is generated and this routine returns 511 /// false. Else it returns true. 512 static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { 513 auto *MachO = dyn_cast<MachOObjectFile>(O); 514 515 if (!MachO || ArchAll || ArchFlags.empty()) 516 return true; 517 518 MachO::mach_header H; 519 MachO::mach_header_64 H_64; 520 Triple T; 521 if (MachO->is64Bit()) { 522 H_64 = MachO->MachOObjectFile::getHeader64(); 523 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); 524 } else { 525 H = MachO->MachOObjectFile::getHeader(); 526 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); 527 } 528 if (none_of(ArchFlags, [&](const std::string &Name) { 529 return Name == T.getArchName(); 530 })) { 531 error(Filename + ": No architecture specified"); 532 return false; 533 } 534 return true; 535 } 536 537 /// Print the section sizes for @p file. If @p file is an archive, print the 538 /// section sizes for each archive member. 539 static void printFileSectionSizes(StringRef file) { 540 541 // Attempt to open the binary. 542 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file); 543 if (!BinaryOrErr) { 544 error(BinaryOrErr.takeError(), file); 545 return; 546 } 547 Binary &Bin = *BinaryOrErr.get().getBinary(); 548 549 if (Archive *a = dyn_cast<Archive>(&Bin)) { 550 // This is an archive. Iterate over each member and display its sizes. 551 Error Err = Error::success(); 552 for (auto &C : a->children(Err)) { 553 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 554 if (!ChildOrErr) { 555 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) 556 error(std::move(E), a->getFileName(), C); 557 continue; 558 } 559 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 560 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 561 if (!checkMachOAndArchFlags(o, file)) 562 return; 563 if (OutputFormat == sysv) 564 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n"; 565 else if (MachO && OutputFormat == darwin) 566 outs() << a->getFileName() << "(" << o->getFileName() << "):\n"; 567 printObjectSectionSizes(o); 568 if (OutputFormat == berkeley) { 569 if (MachO) 570 outs() << a->getFileName() << "(" << o->getFileName() << ")\n"; 571 else 572 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; 573 } 574 } 575 } 576 if (Err) 577 error(std::move(Err), a->getFileName()); 578 } else if (MachOUniversalBinary *UB = 579 dyn_cast<MachOUniversalBinary>(&Bin)) { 580 // If we have a list of architecture flags specified dump only those. 581 if (!ArchAll && !ArchFlags.empty()) { 582 // Look for a slice in the universal binary that matches each ArchFlag. 583 bool ArchFound; 584 for (unsigned i = 0; i < ArchFlags.size(); ++i) { 585 ArchFound = false; 586 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 587 E = UB->end_objects(); 588 I != E; ++I) { 589 if (ArchFlags[i] == I->getArchFlagName()) { 590 ArchFound = true; 591 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 592 if (UO) { 593 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 594 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 595 if (OutputFormat == sysv) 596 outs() << o->getFileName() << " :\n"; 597 else if (MachO && OutputFormat == darwin) { 598 if (MoreThanOneFile || ArchFlags.size() > 1) 599 outs() << o->getFileName() << " (for architecture " 600 << I->getArchFlagName() << "): \n"; 601 } 602 printObjectSectionSizes(o); 603 if (OutputFormat == berkeley) { 604 if (!MachO || MoreThanOneFile || ArchFlags.size() > 1) 605 outs() << o->getFileName() << " (for architecture " 606 << I->getArchFlagName() << ")"; 607 outs() << "\n"; 608 } 609 } 610 } else if (auto E = isNotObjectErrorInvalidFileType( 611 UO.takeError())) { 612 error(std::move(E), file, ArchFlags.size() > 1 ? 613 StringRef(I->getArchFlagName()) : StringRef()); 614 return; 615 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 616 I->getAsArchive()) { 617 std::unique_ptr<Archive> &UA = *AOrErr; 618 // This is an archive. Iterate over each member and display its 619 // sizes. 620 Error Err = Error::success(); 621 for (auto &C : UA->children(Err)) { 622 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 623 if (!ChildOrErr) { 624 if (auto E = isNotObjectErrorInvalidFileType( 625 ChildOrErr.takeError())) 626 error(std::move(E), UA->getFileName(), C, 627 ArchFlags.size() > 1 ? 628 StringRef(I->getArchFlagName()) : StringRef()); 629 continue; 630 } 631 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 632 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 633 if (OutputFormat == sysv) 634 outs() << o->getFileName() << " (ex " << UA->getFileName() 635 << "):\n"; 636 else if (MachO && OutputFormat == darwin) 637 outs() << UA->getFileName() << "(" << o->getFileName() 638 << ")" 639 << " (for architecture " << I->getArchFlagName() 640 << "):\n"; 641 printObjectSectionSizes(o); 642 if (OutputFormat == berkeley) { 643 if (MachO) { 644 outs() << UA->getFileName() << "(" << o->getFileName() 645 << ")"; 646 if (ArchFlags.size() > 1) 647 outs() << " (for architecture " << I->getArchFlagName() 648 << ")"; 649 outs() << "\n"; 650 } else 651 outs() << o->getFileName() << " (ex " << UA->getFileName() 652 << ")\n"; 653 } 654 } 655 } 656 if (Err) 657 error(std::move(Err), UA->getFileName()); 658 } else { 659 consumeError(AOrErr.takeError()); 660 error("Mach-O universal file: " + file + " for architecture " + 661 StringRef(I->getArchFlagName()) + 662 " is not a Mach-O file or an archive file"); 663 } 664 } 665 } 666 if (!ArchFound) { 667 errs() << ToolName << ": file: " << file 668 << " does not contain architecture" << ArchFlags[i] << ".\n"; 669 return; 670 } 671 } 672 return; 673 } 674 // No architecture flags were specified so if this contains a slice that 675 // matches the host architecture dump only that. 676 if (!ArchAll) { 677 StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); 678 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 679 E = UB->end_objects(); 680 I != E; ++I) { 681 if (HostArchName == I->getArchFlagName()) { 682 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 683 if (UO) { 684 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 685 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 686 if (OutputFormat == sysv) 687 outs() << o->getFileName() << " :\n"; 688 else if (MachO && OutputFormat == darwin) { 689 if (MoreThanOneFile) 690 outs() << o->getFileName() << " (for architecture " 691 << I->getArchFlagName() << "):\n"; 692 } 693 printObjectSectionSizes(o); 694 if (OutputFormat == berkeley) { 695 if (!MachO || MoreThanOneFile) 696 outs() << o->getFileName() << " (for architecture " 697 << I->getArchFlagName() << ")"; 698 outs() << "\n"; 699 } 700 } 701 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 702 error(std::move(E), file); 703 return; 704 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 705 I->getAsArchive()) { 706 std::unique_ptr<Archive> &UA = *AOrErr; 707 // This is an archive. Iterate over each member and display its 708 // sizes. 709 Error Err = Error::success(); 710 for (auto &C : UA->children(Err)) { 711 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 712 if (!ChildOrErr) { 713 if (auto E = isNotObjectErrorInvalidFileType( 714 ChildOrErr.takeError())) 715 error(std::move(E), UA->getFileName(), C); 716 continue; 717 } 718 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 719 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 720 if (OutputFormat == sysv) 721 outs() << o->getFileName() << " (ex " << UA->getFileName() 722 << "):\n"; 723 else if (MachO && OutputFormat == darwin) 724 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 725 << " (for architecture " << I->getArchFlagName() 726 << "):\n"; 727 printObjectSectionSizes(o); 728 if (OutputFormat == berkeley) { 729 if (MachO) 730 outs() << UA->getFileName() << "(" << o->getFileName() 731 << ")\n"; 732 else 733 outs() << o->getFileName() << " (ex " << UA->getFileName() 734 << ")\n"; 735 } 736 } 737 } 738 if (Err) 739 error(std::move(Err), UA->getFileName()); 740 } else { 741 consumeError(AOrErr.takeError()); 742 error("Mach-O universal file: " + file + " for architecture " + 743 StringRef(I->getArchFlagName()) + 744 " is not a Mach-O file or an archive file"); 745 } 746 return; 747 } 748 } 749 } 750 // Either all architectures have been specified or none have been specified 751 // and this does not contain the host architecture so dump all the slices. 752 bool MoreThanOneArch = UB->getNumberOfObjects() > 1; 753 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), 754 E = UB->end_objects(); 755 I != E; ++I) { 756 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); 757 if (UO) { 758 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { 759 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 760 if (OutputFormat == sysv) 761 outs() << o->getFileName() << " :\n"; 762 else if (MachO && OutputFormat == darwin) { 763 if (MoreThanOneFile || MoreThanOneArch) 764 outs() << o->getFileName() << " (for architecture " 765 << I->getArchFlagName() << "):"; 766 outs() << "\n"; 767 } 768 printObjectSectionSizes(o); 769 if (OutputFormat == berkeley) { 770 if (!MachO || MoreThanOneFile || MoreThanOneArch) 771 outs() << o->getFileName() << " (for architecture " 772 << I->getArchFlagName() << ")"; 773 outs() << "\n"; 774 } 775 } 776 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { 777 error(std::move(E), file, MoreThanOneArch ? 778 StringRef(I->getArchFlagName()) : StringRef()); 779 return; 780 } else if (Expected<std::unique_ptr<Archive>> AOrErr = 781 I->getAsArchive()) { 782 std::unique_ptr<Archive> &UA = *AOrErr; 783 // This is an archive. Iterate over each member and display its sizes. 784 Error Err = Error::success(); 785 for (auto &C : UA->children(Err)) { 786 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 787 if (!ChildOrErr) { 788 if (auto E = isNotObjectErrorInvalidFileType( 789 ChildOrErr.takeError())) 790 error(std::move(E), UA->getFileName(), C, MoreThanOneArch ? 791 StringRef(I->getArchFlagName()) : StringRef()); 792 continue; 793 } 794 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { 795 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 796 if (OutputFormat == sysv) 797 outs() << o->getFileName() << " (ex " << UA->getFileName() 798 << "):\n"; 799 else if (MachO && OutputFormat == darwin) 800 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 801 << " (for architecture " << I->getArchFlagName() << "):\n"; 802 printObjectSectionSizes(o); 803 if (OutputFormat == berkeley) { 804 if (MachO) 805 outs() << UA->getFileName() << "(" << o->getFileName() << ")" 806 << " (for architecture " << I->getArchFlagName() 807 << ")\n"; 808 else 809 outs() << o->getFileName() << " (ex " << UA->getFileName() 810 << ")\n"; 811 } 812 } 813 } 814 if (Err) 815 error(std::move(Err), UA->getFileName()); 816 } else { 817 consumeError(AOrErr.takeError()); 818 error("Mach-O universal file: " + file + " for architecture " + 819 StringRef(I->getArchFlagName()) + 820 " is not a Mach-O file or an archive file"); 821 } 822 } 823 } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) { 824 if (!checkMachOAndArchFlags(o, file)) 825 return; 826 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); 827 if (OutputFormat == sysv) 828 outs() << o->getFileName() << " :\n"; 829 else if (MachO && OutputFormat == darwin && MoreThanOneFile) 830 outs() << o->getFileName() << ":\n"; 831 printObjectSectionSizes(o); 832 if (OutputFormat == berkeley) { 833 if (!MachO || MoreThanOneFile) 834 outs() << o->getFileName(); 835 outs() << "\n"; 836 } 837 } else { 838 errs() << ToolName << ": " << file << ": " 839 << "Unrecognized file type.\n"; 840 } 841 // System V adds an extra newline at the end of each file. 842 if (OutputFormat == sysv) 843 outs() << "\n"; 844 } 845 846 static void printBerkelyTotals() { 847 std::string fmtbuf; 848 raw_string_ostream fmt(fmtbuf); 849 const char *radix_fmt = getRadixFmt(); 850 fmt << "%#7" << radix_fmt << "\t" 851 << "%#7" << radix_fmt << "\t" 852 << "%#7" << radix_fmt << "\t"; 853 outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData, 854 TotalObjectBss); 855 fmtbuf.clear(); 856 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" 857 << "%7" PRIx64 "\t"; 858 outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal) 859 << "(TOTALS)\n"; 860 } 861 862 int main(int argc, char **argv) { 863 InitLLVM X(argc, argv); 864 cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n"); 865 866 ToolName = argv[0]; 867 if (OutputFormatShort.getNumOccurrences()) 868 OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort); 869 if (RadixShort.getNumOccurrences()) 870 Radix = RadixShort.getValue(); 871 872 for (StringRef Arch : ArchFlags) { 873 if (Arch == "all") { 874 ArchAll = true; 875 } else { 876 if (!MachOObjectFile::isValidArch(Arch)) { 877 outs() << ToolName << ": for the -arch option: Unknown architecture " 878 << "named '" << Arch << "'"; 879 return 1; 880 } 881 } 882 } 883 884 if (InputFilenames.empty()) 885 InputFilenames.push_back("a.out"); 886 887 MoreThanOneFile = InputFilenames.size() > 1; 888 llvm::for_each(InputFilenames, printFileSectionSizes); 889 if (OutputFormat == berkeley && TotalSizes) 890 printBerkelyTotals(); 891 892 if (HadError) 893 return 1; 894 } 895