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
16 * The Original Code is foldelf.cpp, released
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.
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
58 //----------------------------------------------------------------------
60 char* opt_type
= "func";
61 char* opt_section
= ".text";
63 //----------------------------------------------------------------------
66 hexdump(ostream
& out
, const char* bytes
, size_t count
)
72 out
.form("%08lx: ", off
);
74 const char* p
= bytes
+ off
;
78 out
.form("%02x", p
[j
++] & 0xff);
82 out
.form("%02x ", p
[j
++] & 0xff);
89 out
<< ((j
%2) ? " " : " ");
91 for (j
= 0; j
< 16; ++j
) {
93 out
.put(isprint(p
[j
]) ? p
[j
] : '.');
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
;
114 if (hdr
->e_ident
[EI_CLASS
] != ELFCLASS32
) {
115 cerr
<< "not a 32-bit elf file" << endl
;
119 if (hdr
->e_ident
[EI_DATA
] != ELFDATA2LSB
) {
120 cerr
<< "not a little endian elf file" << endl
;
124 if (hdr
->e_ident
[EI_VERSION
] != EV_CURRENT
) {
125 cerr
<< "incompatible version" << endl
;
132 //----------------------------------------------------------------------
134 class elf_symbol
: public Elf32_Sym
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 //----------------------------------------------------------------------
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";
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";
173 st_type(const char* type
)
175 if (strcmp(type
, "none") == 0) {
178 else if (strcmp(type
, "object") == 0) {
181 else if (strcmp(type
, "func") == 0) {
189 //----------------------------------------------------------------------
191 typedef vector
<elf_symbol
> elf_symbol_table
;
192 typedef map
< basic_string
<char>, elf_symbol_table
> elf_text_map
;
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)
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
;
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
) {
218 else if (name
== ".symtab") {
219 symtabsh
= shdrs
+ i
;
221 else if (name
== ".strtab") {
222 strtabsh
= shdrs
+ i
;
227 char* strtab
= mapping
+ strtabsh
->sh_offset
;
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
) &&
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();
259 const elf_symbol_table
& syms
= entry
->second
;
261 if (syms
.size() <= 1)
264 int sz
= syms
.begin()->st_size
;
266 totalbytes
+= sz
* syms
.size();
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
;
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());
282 cout
<< "bytes unique=" << uniquebytes
<< ", total=" << totalbytes
<< endl
;
283 cout
<< "entries unique=" << uniquecount
<< ", total=" << totalcount
<< endl
;
287 process_file(const char* name
)
289 int fd
= open(name
, O_RDWR
);
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
);
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\
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, '?' },
326 main(int argc
, char* argv
[])
329 int option_index
= 0;
330 int c
= getopt_long(argc
, argv
, "t:s:", opts
, &option_index
);
340 opt_section
= optarg
;
349 for (int i
= optind
; i
< argc
; ++i
)
350 process_file(argv
[i
]);