llvm-size.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. //===-- llvm-size.cpp - Print the size of each object section -------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This program is a utility that works like traditional Unix "size",
  11. // that is, it prints out the size of each section, and the total size of all
  12. // sections.
  13. //
  14. //===----------------------------------------------------------------------===//
  15. #include "llvm/ADT/APInt.h"
  16. #include "llvm/Object/Archive.h"
  17. #include "llvm/Object/ObjectFile.h"
  18. #include "llvm/Support/Casting.h"
  19. #include "llvm/Support/CommandLine.h"
  20. #include "llvm/Support/FileSystem.h"
  21. #include "llvm/Support/Format.h"
  22. #include "llvm/Support/ManagedStatic.h"
  23. #include "llvm/Support/MemoryBuffer.h"
  24. #include "llvm/Support/PrettyStackTrace.h"
  25. #include "llvm/Support/raw_ostream.h"
  26. #include "llvm/Support/Signals.h"
  27. #include "llvm/Support/system_error.h"
  28. #include <algorithm>
  29. #include <string>
  30. using namespace llvm;
  31. using namespace object;
  32. enum OutputFormatTy {berkeley, sysv};
  33. static cl::opt<OutputFormatTy>
  34. OutputFormat("format",
  35. cl::desc("Specify output format"),
  36. cl::values(clEnumVal(sysv, "System V format"),
  37. clEnumVal(berkeley, "Berkeley format"),
  38. clEnumValEnd),
  39. cl::init(berkeley));
  40. static cl::opt<OutputFormatTy>
  41. OutputFormatShort(cl::desc("Specify output format"),
  42. cl::values(clEnumValN(sysv, "A", "System V format"),
  43. clEnumValN(berkeley, "B", "Berkeley format"),
  44. clEnumValEnd),
  45. cl::init(berkeley));
  46. enum RadixTy {octal = 8, decimal = 10, hexadecimal = 16};
  47. static cl::opt<unsigned int>
  48. Radix("-radix",
  49. cl::desc("Print size in radix. Only 8, 10, and 16 are valid"),
  50. cl::init(decimal));
  51. static cl::opt<RadixTy>
  52. RadixShort(cl::desc("Print size in radix:"),
  53. cl::values(clEnumValN(octal, "o", "Print size in octal"),
  54. clEnumValN(decimal, "d", "Print size in decimal"),
  55. clEnumValN(hexadecimal, "x", "Print size in hexadecimal"),
  56. clEnumValEnd),
  57. cl::init(decimal));
  58. static cl::list<std::string>
  59. InputFilenames(cl::Positional, cl::desc("<input files>"),
  60. cl::ZeroOrMore);
  61. static std::string ToolName;
  62. /// @brief If ec is not success, print the error and return true.
  63. static bool error(error_code ec) {
  64. if (!ec) return false;
  65. outs() << ToolName << ": error reading file: " << ec.message() << ".\n";
  66. outs().flush();
  67. return true;
  68. }
  69. /// @brief Get the length of the string that represents @p num in Radix
  70. /// including the leading 0x or 0 for hexadecimal and octal respectively.
  71. static size_t getNumLengthAsString(uint64_t num) {
  72. APInt conv(64, num);
  73. SmallString<32> result;
  74. conv.toString(result, Radix, false, true);
  75. return result.size();
  76. }
  77. /// @brief Print the size of each section in @p o.
  78. ///
  79. /// The format used is determined by @c OutputFormat and @c Radix.
  80. static void PrintObjectSectionSizes(ObjectFile *o) {
  81. uint64_t total = 0;
  82. std::string fmtbuf;
  83. raw_string_ostream fmt(fmtbuf);
  84. const char *radix_fmt = 0;
  85. switch (Radix) {
  86. case octal:
  87. radix_fmt = PRIo64;
  88. break;
  89. case decimal:
  90. radix_fmt = PRIu64;
  91. break;
  92. case hexadecimal:
  93. radix_fmt = PRIx64;
  94. break;
  95. }
  96. if (OutputFormat == sysv) {
  97. // Run two passes over all sections. The first gets the lengths needed for
  98. // formatting the output. The second actually does the output.
  99. std::size_t max_name_len = strlen("section");
  100. std::size_t max_size_len = strlen("size");
  101. std::size_t max_addr_len = strlen("addr");
  102. error_code ec;
  103. for (section_iterator i = o->begin_sections(),
  104. e = o->end_sections(); i != e;
  105. i.increment(ec)) {
  106. if (error(ec))
  107. return;
  108. uint64_t size = 0;
  109. if (error(i->getSize(size)))
  110. return;
  111. total += size;
  112. StringRef name;
  113. uint64_t addr = 0;
  114. if (error(i->getName(name))) return;
  115. if (error(i->getAddress(addr))) return;
  116. max_name_len = std::max(max_name_len, name.size());
  117. max_size_len = std::max(max_size_len, getNumLengthAsString(size));
  118. max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
  119. }
  120. // Add extra padding.
  121. max_name_len += 2;
  122. max_size_len += 2;
  123. max_addr_len += 2;
  124. // Setup header format.
  125. fmt << "%-" << max_name_len << "s "
  126. << "%" << max_size_len << "s "
  127. << "%" << max_addr_len << "s\n";
  128. // Print header
  129. outs() << format(fmt.str().c_str(),
  130. static_cast<const char*>("section"),
  131. static_cast<const char*>("size"),
  132. static_cast<const char*>("addr"));
  133. fmtbuf.clear();
  134. // Setup per section format.
  135. fmt << "%-" << max_name_len << "s "
  136. << "%#" << max_size_len << radix_fmt << " "
  137. << "%#" << max_addr_len << radix_fmt << "\n";
  138. // Print each section.
  139. for (section_iterator i = o->begin_sections(),
  140. e = o->end_sections(); i != e;
  141. i.increment(ec)) {
  142. if (error(ec))
  143. return;
  144. StringRef name;
  145. uint64_t size = 0;
  146. uint64_t addr = 0;
  147. if (error(i->getName(name))) return;
  148. if (error(i->getSize(size))) return;
  149. if (error(i->getAddress(addr))) return;
  150. std::string namestr = name;
  151. outs() << format(fmt.str().c_str(),
  152. namestr.c_str(),
  153. size,
  154. addr);
  155. }
  156. // Print total.
  157. fmtbuf.clear();
  158. fmt << "%-" << max_name_len << "s "
  159. << "%#" << max_size_len << radix_fmt << "\n";
  160. outs() << format(fmt.str().c_str(),
  161. static_cast<const char*>("Total"),
  162. total);
  163. } else {
  164. // The Berkeley format does not display individual section sizes. It
  165. // displays the cumulative size for each section type.
  166. uint64_t total_text = 0;
  167. uint64_t total_data = 0;
  168. uint64_t total_bss = 0;
  169. // Make one pass over the section table to calculate sizes.
  170. error_code ec;
  171. for (section_iterator i = o->begin_sections(),
  172. e = o->end_sections(); i != e;
  173. i.increment(ec)) {
  174. if (error(ec))
  175. return;
  176. uint64_t size = 0;
  177. bool isText = false;
  178. bool isData = false;
  179. bool isBSS = false;
  180. if (error(i->getSize(size))) return;
  181. if (error(i->isText(isText))) return;
  182. if (error(i->isData(isData))) return;
  183. if (error(i->isBSS(isBSS))) return;
  184. if (isText)
  185. total_text += size;
  186. else if (isData)
  187. total_data += size;
  188. else if (isBSS)
  189. total_bss += size;
  190. }
  191. total = total_text + total_data + total_bss;
  192. // Print result.
  193. fmt << "%#7" << radix_fmt << " "
  194. << "%#7" << radix_fmt << " "
  195. << "%#7" << radix_fmt << " ";
  196. outs() << format(fmt.str().c_str(),
  197. total_text,
  198. total_data,
  199. total_bss);
  200. fmtbuf.clear();
  201. fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " "
  202. << "%7" PRIx64 " ";
  203. outs() << format(fmt.str().c_str(),
  204. total,
  205. total);
  206. }
  207. }
  208. /// @brief Print the section sizes for @p file. If @p file is an archive, print
  209. /// the section sizes for each archive member.
  210. static void PrintFileSectionSizes(StringRef file) {
  211. // If file is not stdin, check that it exists.
  212. if (file != "-") {
  213. bool exists;
  214. if (sys::fs::exists(file, exists) || !exists) {
  215. errs() << ToolName << ": '" << file << "': " << "No such file\n";
  216. return;
  217. }
  218. }
  219. // Attempt to open the binary.
  220. OwningPtr<Binary> binary;
  221. if (error_code ec = createBinary(file, binary)) {
  222. errs() << ToolName << ": " << file << ": " << ec.message() << ".\n";
  223. return;
  224. }
  225. if (Archive *a = dyn_cast<Archive>(binary.get())) {
  226. // This is an archive. Iterate over each member and display its sizes.
  227. for (object::Archive::child_iterator i = a->begin_children(),
  228. e = a->end_children(); i != e; ++i) {
  229. OwningPtr<Binary> child;
  230. if (error_code ec = i->getAsBinary(child)) {
  231. errs() << ToolName << ": " << file << ": " << ec.message() << ".\n";
  232. continue;
  233. }
  234. if (ObjectFile *o = dyn_cast<ObjectFile>(child.get())) {
  235. if (OutputFormat == sysv)
  236. outs() << o->getFileName() << " (ex " << a->getFileName()
  237. << "):\n";
  238. PrintObjectSectionSizes(o);
  239. if (OutputFormat == berkeley)
  240. outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
  241. }
  242. }
  243. } else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) {
  244. if (OutputFormat == sysv)
  245. outs() << o->getFileName() << " :\n";
  246. PrintObjectSectionSizes(o);
  247. if (OutputFormat == berkeley)
  248. outs() << o->getFileName() << "\n";
  249. } else {
  250. errs() << ToolName << ": " << file << ": " << "Unrecognized file type.\n";
  251. }
  252. // System V adds an extra newline at the end of each file.
  253. if (OutputFormat == sysv)
  254. outs() << "\n";
  255. }
  256. int main(int argc, char **argv) {
  257. // Print a stack trace if we signal out.
  258. sys::PrintStackTraceOnErrorSignal();
  259. PrettyStackTraceProgram X(argc, argv);
  260. llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
  261. cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
  262. ToolName = argv[0];
  263. if (OutputFormatShort.getNumOccurrences())
  264. OutputFormat = OutputFormatShort;
  265. if (RadixShort.getNumOccurrences())
  266. Radix = RadixShort;
  267. if (InputFilenames.size() == 0)
  268. InputFilenames.push_back("a.out");
  269. if (OutputFormat == berkeley)
  270. outs() << " text data bss "
  271. << (Radix == octal ? "oct" : "dec")
  272. << " hex filename\n";
  273. std::for_each(InputFilenames.begin(), InputFilenames.end(),
  274. PrintFileSectionSizes);
  275. return 0;
  276. }