llvm-size.cpp 35 KB

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