blob: f0ec7fa6af6a38c56fe90205f0d685ee2a17af5d [file] [log] [blame]
Michael J. Spencerc4ad4662011-09-28 20:57:46 +00001//===-- 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
16#include "llvm/ADT/APInt.h"
17#include "llvm/Object/Archive.h"
18#include "llvm/Object/ObjectFile.h"
19#include "llvm/Support/Casting.h"
20#include "llvm/Support/CommandLine.h"
21#include "llvm/Support/FileSystem.h"
22#include "llvm/Support/Format.h"
23#include "llvm/Support/ManagedStatic.h"
24#include "llvm/Support/MemoryBuffer.h"
25#include "llvm/Support/PrettyStackTrace.h"
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000026#include "llvm/Support/Signals.h"
Chandler Carruth4d88a1c2012-12-04 10:44:52 +000027#include "llvm/Support/raw_ostream.h"
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000028#include <algorithm>
29#include <string>
Rafael Espindolaa6e9c3e2014-06-12 17:38:55 +000030#include <system_error>
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000031using namespace llvm;
32using namespace object;
Rafael Espindola3acea392014-06-12 21:46:39 +000033using std::error_code;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000034
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000035enum OutputFormatTy {berkeley, sysv};
36static cl::opt<OutputFormatTy>
37 OutputFormat("format",
38 cl::desc("Specify output format"),
39 cl::values(clEnumVal(sysv, "System V format"),
40 clEnumVal(berkeley, "Berkeley format"),
41 clEnumValEnd),
42 cl::init(berkeley));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000043
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000044static cl::opt<OutputFormatTy>
45 OutputFormatShort(cl::desc("Specify output format"),
46 cl::values(clEnumValN(sysv, "A", "System V format"),
47 clEnumValN(berkeley, "B", "Berkeley format"),
48 clEnumValEnd),
49 cl::init(berkeley));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000050
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000051enum RadixTy {octal = 8, decimal = 10, hexadecimal = 16};
52static cl::opt<unsigned int>
53 Radix("-radix",
54 cl::desc("Print size in radix. Only 8, 10, and 16 are valid"),
55 cl::init(decimal));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000056
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000057static cl::opt<RadixTy>
58 RadixShort(cl::desc("Print size in radix:"),
59 cl::values(clEnumValN(octal, "o", "Print size in octal"),
60 clEnumValN(decimal, "d", "Print size in decimal"),
61 clEnumValN(hexadecimal, "x", "Print size in hexadecimal"),
62 clEnumValEnd),
63 cl::init(decimal));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000064
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000065static cl::list<std::string>
66 InputFilenames(cl::Positional, cl::desc("<input files>"),
67 cl::ZeroOrMore);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000068
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000069static std::string ToolName;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000070
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000071/// @brief If ec is not success, print the error and return true.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000072static bool error(error_code ec) {
73 if (!ec) return false;
74
75 outs() << ToolName << ": error reading file: " << ec.message() << ".\n";
76 outs().flush();
77 return true;
78}
79
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000080/// @brief Get the length of the string that represents @p num in Radix
81/// including the leading 0x or 0 for hexadecimal and octal respectively.
Andrew Trick7dc278d2011-09-29 01:22:31 +000082static size_t getNumLengthAsString(uint64_t num) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000083 APInt conv(64, num);
84 SmallString<32> result;
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000085 conv.toString(result, Radix, false, true);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000086 return result.size();
87}
88
Alexey Samsonov48803e52014-03-13 14:37:36 +000089/// @brief Print the size of each section in @p Obj.
Michael J. Spencercc5f8d42011-09-29 00:59:18 +000090///
91/// The format used is determined by @c OutputFormat and @c Radix.
Alexey Samsonov48803e52014-03-13 14:37:36 +000092static void PrintObjectSectionSizes(ObjectFile *Obj) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000093 uint64_t total = 0;
94 std::string fmtbuf;
95 raw_string_ostream fmt(fmtbuf);
96
Craig Toppere6cb63e2014-04-25 04:24:47 +000097 const char *radix_fmt = nullptr;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000098 switch (Radix) {
99 case octal:
Benjamin Kramerf3da5292011-11-05 08:57:40 +0000100 radix_fmt = PRIo64;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000101 break;
102 case decimal:
Benjamin Kramerf3da5292011-11-05 08:57:40 +0000103 radix_fmt = PRIu64;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000104 break;
105 case hexadecimal:
Benjamin Kramerf3da5292011-11-05 08:57:40 +0000106 radix_fmt = PRIx64;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000107 break;
108 }
109 if (OutputFormat == sysv) {
110 // Run two passes over all sections. The first gets the lengths needed for
111 // formatting the output. The second actually does the output.
112 std::size_t max_name_len = strlen("section");
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000113 std::size_t max_size_len = strlen("size");
114 std::size_t max_addr_len = strlen("addr");
Alexey Samsonov48803e52014-03-13 14:37:36 +0000115 for (const SectionRef &Section : Obj->sections()) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000116 uint64_t size = 0;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000117 if (error(Section.getSize(size)))
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000118 return;
119 total += size;
120
121 StringRef name;
122 uint64_t addr = 0;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000123 if (error(Section.getName(name)))
124 return;
125 if (error(Section.getAddress(addr)))
126 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000127 max_name_len = std::max(max_name_len, name.size());
Andrew Trick7dc278d2011-09-29 01:22:31 +0000128 max_size_len = std::max(max_size_len, getNumLengthAsString(size));
129 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000130 }
131
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000132 // Add extra padding.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000133 max_name_len += 2;
134 max_size_len += 2;
135 max_addr_len += 2;
136
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000137 // Setup header format.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000138 fmt << "%-" << max_name_len << "s "
139 << "%" << max_size_len << "s "
140 << "%" << max_addr_len << "s\n";
141
142 // Print header
143 outs() << format(fmt.str().c_str(),
144 static_cast<const char*>("section"),
145 static_cast<const char*>("size"),
146 static_cast<const char*>("addr"));
147 fmtbuf.clear();
148
149 // Setup per section format.
150 fmt << "%-" << max_name_len << "s "
151 << "%#" << max_size_len << radix_fmt << " "
152 << "%#" << max_addr_len << radix_fmt << "\n";
153
154 // Print each section.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000155 for (const SectionRef &Section : Obj->sections()) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000156 StringRef name;
157 uint64_t size = 0;
158 uint64_t addr = 0;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000159 if (error(Section.getName(name)))
160 return;
161 if (error(Section.getSize(size)))
162 return;
163 if (error(Section.getAddress(addr)))
164 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000165 std::string namestr = name;
166
Alexey Samsonov48803e52014-03-13 14:37:36 +0000167 outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000168 }
169
170 // Print total.
171 fmtbuf.clear();
172 fmt << "%-" << max_name_len << "s "
173 << "%#" << max_size_len << radix_fmt << "\n";
174 outs() << format(fmt.str().c_str(),
175 static_cast<const char*>("Total"),
176 total);
177 } else {
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000178 // The Berkeley format does not display individual section sizes. It
179 // displays the cumulative size for each section type.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000180 uint64_t total_text = 0;
181 uint64_t total_data = 0;
182 uint64_t total_bss = 0;
183
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000184 // Make one pass over the section table to calculate sizes.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000185 for (const SectionRef &Section : Obj->sections()) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000186 uint64_t size = 0;
187 bool isText = false;
188 bool isData = false;
189 bool isBSS = false;
Alexey Samsonov48803e52014-03-13 14:37:36 +0000190 if (error(Section.getSize(size)))
191 return;
192 if (error(Section.isText(isText)))
193 return;
194 if (error(Section.isData(isData)))
195 return;
196 if (error(Section.isBSS(isBSS)))
197 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000198 if (isText)
199 total_text += size;
200 else if (isData)
201 total_data += size;
202 else if (isBSS)
203 total_bss += size;
204 }
205
206 total = total_text + total_data + total_bss;
207
208 // Print result.
209 fmt << "%#7" << radix_fmt << " "
210 << "%#7" << radix_fmt << " "
211 << "%#7" << radix_fmt << " ";
212 outs() << format(fmt.str().c_str(),
213 total_text,
214 total_data,
215 total_bss);
216 fmtbuf.clear();
Benjamin Kramerf3da5292011-11-05 08:57:40 +0000217 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " "
218 << "%7" PRIx64 " ";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000219 outs() << format(fmt.str().c_str(),
220 total,
221 total);
222 }
223}
224
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000225/// @brief Print the section sizes for @p file. If @p file is an archive, print
226/// the section sizes for each archive member.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000227static void PrintFileSectionSizes(StringRef file) {
228 // If file is not stdin, check that it exists.
229 if (file != "-") {
230 bool exists;
231 if (sys::fs::exists(file, exists) || !exists) {
232 errs() << ToolName << ": '" << file << "': " << "No such file\n";
233 return;
234 }
235 }
236
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000237 // Attempt to open the binary.
Rafael Espindola63da2952014-01-15 19:37:43 +0000238 ErrorOr<Binary *> BinaryOrErr = createBinary(file);
239 if (error_code EC = BinaryOrErr.getError()) {
240 errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000241 return;
242 }
Ahmed Charles56440fd2014-03-06 05:51:42 +0000243 std::unique_ptr<Binary> binary(BinaryOrErr.get());
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000244
245 if (Archive *a = dyn_cast<Archive>(binary.get())) {
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000246 // This is an archive. Iterate over each member and display its sizes.
Rafael Espindola23a97502014-01-21 16:09:45 +0000247 for (object::Archive::child_iterator i = a->child_begin(),
248 e = a->child_end(); i != e; ++i) {
Ahmed Charles56440fd2014-03-06 05:51:42 +0000249 std::unique_ptr<Binary> child;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000250 if (error_code ec = i->getAsBinary(child)) {
251 errs() << ToolName << ": " << file << ": " << ec.message() << ".\n";
252 continue;
253 }
254 if (ObjectFile *o = dyn_cast<ObjectFile>(child.get())) {
255 if (OutputFormat == sysv)
256 outs() << o->getFileName() << " (ex " << a->getFileName()
257 << "):\n";
258 PrintObjectSectionSizes(o);
259 if (OutputFormat == berkeley)
260 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
261 }
262 }
263 } else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) {
264 if (OutputFormat == sysv)
265 outs() << o->getFileName() << " :\n";
266 PrintObjectSectionSizes(o);
267 if (OutputFormat == berkeley)
268 outs() << o->getFileName() << "\n";
269 } else {
270 errs() << ToolName << ": " << file << ": " << "Unrecognized file type.\n";
271 }
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000272 // System V adds an extra newline at the end of each file.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000273 if (OutputFormat == sysv)
274 outs() << "\n";
275}
276
277int main(int argc, char **argv) {
278 // Print a stack trace if we signal out.
279 sys::PrintStackTraceOnErrorSignal();
280 PrettyStackTraceProgram X(argc, argv);
281
282 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
283 cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
284
285 ToolName = argv[0];
286 if (OutputFormatShort.getNumOccurrences())
287 OutputFormat = OutputFormatShort;
288 if (RadixShort.getNumOccurrences())
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000289 Radix = RadixShort;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000290
291 if (InputFilenames.size() == 0)
292 InputFilenames.push_back("a.out");
293
294 if (OutputFormat == berkeley)
295 outs() << " text data bss "
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000296 << (Radix == octal ? "oct" : "dec")
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000297 << " hex filename\n";
298
299 std::for_each(InputFilenames.begin(), InputFilenames.end(),
300 PrintFileSectionSizes);
301
302 return 0;
303}