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