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