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