llvm-size.cpp 34 KB

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