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