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