Bug 458256. Use LoadLibraryW instead of LoadLibrary (patch by DougT). r+sr=vlad
[wine-gecko.git] / tools / footprint / foldelf.cpp
blobcf9d1ee40c4bec37f1a61abc041b3ade9a28f7ea
1 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is foldelf.cpp, released
17 * November 28, 2000.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 2000
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
25 * Chris Waterson <waterson@netscape.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 /* This program reads an ELF file and computes information about
42 * redundancies.
45 #include <algorithm>
46 #include <fstream>
47 #include <string>
48 #include <vector>
49 #include <map>
50 #include <elf.h>
51 #include <sys/mman.h>
52 #include <sys/stat.h>
53 #include <fcntl.h>
54 #include <unistd.h>
55 #include <errno.h>
56 #include <getopt.h>
58 //----------------------------------------------------------------------
60 char* opt_type = "func";
61 char* opt_section = ".text";
63 //----------------------------------------------------------------------
65 static void
66 hexdump(ostream& out, const char* bytes, size_t count)
68 hex(out);
70 size_t off = 0;
71 while (off < count) {
72 out.form("%08lx: ", off);
74 const char* p = bytes + off;
76 int j = 0;
77 while (j < 16) {
78 out.form("%02x", p[j++] & 0xff);
79 if (j + off >= count)
80 break;
82 out.form("%02x ", p[j++] & 0xff);
83 if (j + off >= count)
84 break;
87 // Pad
88 for (; j < 16; ++j)
89 out << ((j%2) ? " " : " ");
91 for (j = 0; j < 16; ++j) {
92 if (j + off < count)
93 out.put(isprint(p[j]) ? p[j] : '.');
96 out << endl;
97 off += 16;
101 //----------------------------------------------------------------------
104 verify_elf_header(const Elf32_Ehdr* hdr)
106 if (hdr->e_ident[EI_MAG0] != ELFMAG0
107 || hdr->e_ident[EI_MAG1] != ELFMAG1
108 || hdr->e_ident[EI_MAG2] != ELFMAG2
109 || hdr->e_ident[EI_MAG3] != ELFMAG3) {
110 cerr << "not an elf file" << endl;
111 return -1;
114 if (hdr->e_ident[EI_CLASS] != ELFCLASS32) {
115 cerr << "not a 32-bit elf file" << endl;
116 return -1;
119 if (hdr->e_ident[EI_DATA] != ELFDATA2LSB) {
120 cerr << "not a little endian elf file" << endl;
121 return -1;
124 if (hdr->e_ident[EI_VERSION] != EV_CURRENT) {
125 cerr << "incompatible version" << endl;
126 return -1;
129 return 0;
132 //----------------------------------------------------------------------
134 class elf_symbol : public Elf32_Sym
136 public:
137 elf_symbol(const Elf32_Sym& sym)
138 { ::memcpy(static_cast<Elf32_Sym*>(this), &sym, sizeof(Elf32_Sym)); }
140 friend bool operator==(const elf_symbol& lhs, const elf_symbol& rhs) {
141 return 0 == ::memcmp(static_cast<const Elf32_Sym*>(&lhs),
142 static_cast<const Elf32_Sym*>(&rhs),
143 sizeof(Elf32_Sym)); }
146 //----------------------------------------------------------------------
148 static const char*
149 st_bind(unsigned char info)
151 switch (ELF32_ST_BIND(info)) {
152 case STB_LOCAL: return "local";
153 case STB_GLOBAL: return "global";
154 case STB_WEAK: return "weak";
155 default: return "unknown";
159 static const char*
160 st_type(unsigned char info)
162 switch (ELF32_ST_TYPE(info)) {
163 case STT_NOTYPE: return "none";
164 case STT_OBJECT: return "object";
165 case STT_FUNC: return "func";
166 case STT_SECTION: return "section";
167 case STT_FILE: return "file";
168 default: return "unknown";
172 static unsigned char
173 st_type(const char* type)
175 if (strcmp(type, "none") == 0) {
176 return STT_NOTYPE;
178 else if (strcmp(type, "object") == 0) {
179 return STT_OBJECT;
181 else if (strcmp(type, "func") == 0) {
182 return STT_FUNC;
184 else {
185 return 0;
189 //----------------------------------------------------------------------
191 typedef vector<elf_symbol> elf_symbol_table;
192 typedef map< basic_string<char>, elf_symbol_table > elf_text_map;
194 void
195 process_mapping(char* mapping, size_t size)
197 const Elf32_Ehdr* ehdr = reinterpret_cast<Elf32_Ehdr*>(mapping);
198 if (verify_elf_header(ehdr) < 0)
199 return;
201 // find the section headers
202 const Elf32_Shdr* shdrs = reinterpret_cast<Elf32_Shdr*>(mapping + ehdr->e_shoff);
204 // find the section header string table, .shstrtab
205 const Elf32_Shdr* shstrtabsh = shdrs + ehdr->e_shstrndx;
206 const char* shstrtab = mapping + shstrtabsh->sh_offset;
208 // find the sections we care about
209 const Elf32_Shdr *symtabsh, *strtabsh, *textsh;
210 int textndx;
212 for (int i = 0; i < ehdr->e_shnum; ++i) {
213 basic_string<char> name(shstrtab + shdrs[i].sh_name);
214 if (name == opt_section) {
215 textsh = shdrs + i;
216 textndx = i;
218 else if (name == ".symtab") {
219 symtabsh = shdrs + i;
221 else if (name == ".strtab") {
222 strtabsh = shdrs + i;
226 // find the .strtab
227 char* strtab = mapping + strtabsh->sh_offset;
229 // find the .text
230 char* text = mapping + textsh->sh_offset;
231 int textaddr = textsh->sh_addr;
233 // find the symbol table
234 int nentries = symtabsh->sh_size / sizeof(Elf32_Sym);
235 Elf32_Sym* symtab = reinterpret_cast<Elf32_Sym*>(mapping + symtabsh->sh_offset);
237 // look for symbols in the .text section
238 elf_text_map textmap;
240 for (int i = 0; i < nentries; ++i) {
241 const Elf32_Sym* sym = symtab + i;
242 if (sym->st_shndx == textndx &&
243 ELF32_ST_TYPE(sym->st_info) == st_type(opt_type) &&
244 sym->st_size) {
245 basic_string<char> functext(text + sym->st_value - textaddr, sym->st_size);
247 elf_symbol_table& syms = textmap[functext];
248 if (syms.end() == find(syms.begin(), syms.end(), elf_symbol(*sym)))
249 syms.insert(syms.end(), *sym);
253 int uniquebytes = 0, totalbytes = 0;
254 int uniquecount = 0, totalcount = 0;
256 for (elf_text_map::const_iterator entry = textmap.begin();
257 entry != textmap.end();
258 ++entry) {
259 const elf_symbol_table& syms = entry->second;
261 if (syms.size() <= 1)
262 continue;
264 int sz = syms.begin()->st_size;
265 uniquebytes += sz;
266 totalbytes += sz * syms.size();
267 uniquecount += 1;
268 totalcount += syms.size();
270 for (elf_symbol_table::const_iterator sym = syms.begin(); sym != syms.end(); ++sym)
271 cout << strtab + sym->st_name << endl;
273 dec(cout);
274 cout << syms.size() << " copies of " << sz << " bytes";
275 cout << " (" << ((syms.size() - 1) * sz) << " redundant bytes)" << endl;
277 hexdump(cout, entry->first.data(), entry->first.size());
278 cout << endl;
281 dec(cout);
282 cout << "bytes unique=" << uniquebytes << ", total=" << totalbytes << endl;
283 cout << "entries unique=" << uniquecount << ", total=" << totalcount << endl;
286 void
287 process_file(const char* name)
289 int fd = open(name, O_RDWR);
290 if (fd >= 0) {
291 struct stat statbuf;
292 if (fstat(fd, &statbuf) >= 0) {
293 size_t size = statbuf.st_size;
295 void* mapping = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
296 if (mapping != MAP_FAILED) {
297 process_mapping(static_cast<char*>(mapping), size);
298 munmap(mapping, size);
301 close(fd);
305 static void
306 usage()
308 cerr << "foldelf [--section=<section>] [--type=<type>] [file ...]\n\
309 --section, -s the section of the ELF file to scan; defaults\n\
310 to ``.text''. Valid values include any section\n\
311 of the ELF file.\n\
312 --type, -t the type of object to examine in the section;\n\
313 defaults to ``func''. Valid values include\n\
314 ``none'', ``func'', or ``object''.\n";
318 static struct option opts[] = {
319 { "type", required_argument, 0, 't' },
320 { "section", required_argument, 0, 's' },
321 { "help", no_argument, 0, '?' },
322 { 0, 0, 0, 0 }
326 main(int argc, char* argv[])
328 while (1) {
329 int option_index = 0;
330 int c = getopt_long(argc, argv, "t:s:", opts, &option_index);
332 if (c < 0) break;
334 switch (c) {
335 case 't':
336 opt_type = optarg;
337 break;
339 case 's':
340 opt_section = optarg;
341 break;
343 case '?':
344 usage();
345 break;
349 for (int i = optind; i < argc; ++i)
350 process_file(argv[i]);
352 return 0;