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