|
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <stdio.h> |
|
17 #include <string.h> |
|
18 #include <stdlib.h> |
|
19 |
|
20 |
|
21 #include <tools/elfdefs.h> |
|
22 #define DEFAULT_VERSION 2 |
|
23 |
|
24 #define ELFADDR(rtype, p, o) (rtype *)(((char *)p) + o) |
|
25 |
|
26 FILE *OUTFILE; |
|
27 |
|
28 void croak(char * s) |
|
29 { |
|
30 printf("GENINF ERROR: %s\n", s); |
|
31 exit(EXIT_FAILURE); |
|
32 } |
|
33 |
|
34 void croak2(char * s1, char * s2) |
|
35 { |
|
36 printf("GENINF ERROR: %s %s\n", s1, s2); |
|
37 exit(EXIT_FAILURE); |
|
38 } |
|
39 |
|
40 int GetFileSize(FILE * f, char * file) |
|
41 { |
|
42 int r = fseek(f, 0, SEEK_END); |
|
43 if (r) croak2("can't seek to end of file:", file); |
|
44 r = ftell(f); |
|
45 rewind(f); |
|
46 return r; |
|
47 } |
|
48 |
|
49 void EnsureElf(Elf32_Ehdr* eh) |
|
50 { |
|
51 if (!(eh->e_ident[EI_MAG0] == ELFMAG0 && |
|
52 eh->e_ident[EI_MAG1] == ELFMAG1 && |
|
53 eh->e_ident[EI_MAG2] == ELFMAG2 && |
|
54 eh->e_ident[EI_MAG3] == ELFMAG3)) |
|
55 croak("Invalid ELF magic.\n"); |
|
56 if (eh->e_ident[EI_CLASS] != ELFCLASS32) |
|
57 croak("File is not a 32 bit ELF object file.\n"); |
|
58 if (eh->e_ident[EI_DATA] != ELFDATA2LSB) |
|
59 croak("File data encoding is not Little Endian.\n"); |
|
60 if (eh->e_machine != EM_ARM) |
|
61 croak("File does not target ARM/THUMB processors.\n"); |
|
62 |
|
63 } |
|
64 |
|
65 |
|
66 Elf32_Ehdr* OpenElfFile (char* file) |
|
67 { |
|
68 Elf32_Ehdr* eh; |
|
69 FILE* f = fopen(file, "rb"); |
|
70 if (!f) |
|
71 croak2("can't open file:", file); |
|
72 |
|
73 int fsize = GetFileSize(f, file); |
|
74 |
|
75 eh = (Elf32_Ehdr*)malloc(fsize); |
|
76 if (!eh) |
|
77 croak("Out of memory"); |
|
78 |
|
79 if (fread(eh, fsize, 1, f) != 1) |
|
80 croak2("Can't read file", file); |
|
81 |
|
82 EnsureElf(eh); |
|
83 |
|
84 return eh; |
|
85 } |
|
86 |
|
87 typedef struct NameList |
|
88 { |
|
89 NameList * nl_next; |
|
90 char * nl_name; |
|
91 unsigned int nl_size; |
|
92 } NameList; |
|
93 |
|
94 |
|
95 static NameList * ExportedData = 0; |
|
96 static NameList * ExportedCode = 0; |
|
97 //Workaround for compiler defect(To avoid export of static symbols) |
|
98 static NameList * LocalSymbols = 0; |
|
99 |
|
100 |
|
101 NameList* IsPresentInList(char * name, NameList * list) |
|
102 { |
|
103 NameList * e = list; |
|
104 while (e) { |
|
105 if (!strcmp(name, e->nl_name)) |
|
106 return e; |
|
107 else |
|
108 e = e->nl_next; |
|
109 } |
|
110 return 0; |
|
111 } |
|
112 |
|
113 NameList* IsExportedData(char * name) |
|
114 { |
|
115 return IsPresentInList(name,ExportedData); |
|
116 } |
|
117 |
|
118 NameList* IsExportedCode(char * name) |
|
119 { |
|
120 return IsPresentInList(name,ExportedCode); |
|
121 } |
|
122 |
|
123 //Workaround for compiler defect(To avoid export of local symbols) |
|
124 NameList* IsLocalSymbol(char * name) |
|
125 { |
|
126 return IsPresentInList(name,LocalSymbols); |
|
127 } |
|
128 |
|
129 void AddToList(char * name, NameList *& list, unsigned int aSymSz) |
|
130 { |
|
131 NameList * ed = new NameList; |
|
132 ed->nl_name = name; |
|
133 ed->nl_size = aSymSz; |
|
134 ed->nl_next = list; |
|
135 list = ed; |
|
136 } |
|
137 |
|
138 void AddExportedData(char * name, unsigned int aSymSz) |
|
139 { |
|
140 AddToList(name, ExportedData, aSymSz); |
|
141 } |
|
142 |
|
143 void AddExportedCode(char * name, unsigned int aSymSz) |
|
144 { |
|
145 AddToList(name, ExportedCode, aSymSz); |
|
146 } |
|
147 |
|
148 //Workaround for compiler defect(To avoid export of local symbols) |
|
149 void AddLocalSymbols(char * name) |
|
150 { |
|
151 AddToList(name, LocalSymbols, 0); |
|
152 } |
|
153 |
|
154 void InitSymbolsLists(Elf32_Ehdr * eh,Elf32_Shdr * shdr,int shnum) |
|
155 { |
|
156 Elf32_Sym * symtab = 0; |
|
157 int nSyms = 0; |
|
158 char * strtab = 0; |
|
159 |
|
160 for (int i = 0; (i < shnum); i++) { |
|
161 if (shdr[i].sh_type == SHT_SYMTAB) { |
|
162 symtab = ELFADDR(Elf32_Sym, eh, shdr[i].sh_offset); |
|
163 nSyms = shdr[i].sh_size / shdr[i].sh_entsize; |
|
164 strtab = ELFADDR(char, eh, shdr[shdr[i].sh_link].sh_offset); |
|
165 break; |
|
166 } |
|
167 } |
|
168 for (i = 0; i < nSyms; i++) { |
|
169 if (symtab[i].st_info == ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT)) { |
|
170 char * name = ELFADDR(char, strtab, symtab[i].st_name); |
|
171 AddExportedData(name, symtab[i].st_size); |
|
172 } else if (symtab[i].st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)) { |
|
173 char * name = ELFADDR(char, strtab, symtab[i].st_name); |
|
174 AddExportedCode(name, symtab[i].st_size); |
|
175 } |
|
176 else if (symtab[i].st_info == ELF32_ST_INFO(STB_LOCAL, STT_FUNC) || |
|
177 symtab[i].st_info == ELF32_ST_INFO(STB_LOCAL, STT_OBJECT)) { |
|
178 // Workaround for compiler defect to avoid export of local symbols |
|
179 char * name = ELFADDR(char, strtab, symtab[i].st_name); |
|
180 AddLocalSymbols(name); |
|
181 } |
|
182 } |
|
183 } |
|
184 |
|
185 #define DIRECTIVE_TAG "#<SYMEDIT>#" |
|
186 #define DIRECTIVE_TAG_SIZE (sizeof(DIRECTIVE_TAG) - 1) |
|
187 #define EXPORT_DIRECTIVE "EXPORT " |
|
188 #define EXPORT_DIRECTIVE_SIZE (sizeof(EXPORT_DIRECTIVE) - 1) |
|
189 |
|
190 void PrintExportsFromSection(char * section, int size) |
|
191 { |
|
192 if (strncmp(DIRECTIVE_TAG, section, DIRECTIVE_TAG_SIZE) != 0) |
|
193 croak("Unrecognized .directive tag"); |
|
194 section += (DIRECTIVE_TAG_SIZE + 1); |
|
195 size -= (DIRECTIVE_TAG_SIZE + 1); |
|
196 // The separator for the following entries is 0x0A (i.e. \n). |
|
197 // We're only interested in lines starting with EXPORT |
|
198 char eolchar = '\n'; |
|
199 NameList* aDataSymbol; |
|
200 while (size > 0) { |
|
201 |
|
202 char * eolp = (char *)memchr(section, eolchar, size); |
|
203 int linelength = (eolp - section) + 1; |
|
204 if (!strncmp(EXPORT_DIRECTIVE, section, EXPORT_DIRECTIVE_SIZE)) { |
|
205 char * symbol = section + EXPORT_DIRECTIVE_SIZE; |
|
206 int symbolsize = linelength - EXPORT_DIRECTIVE_SIZE - 1; |
|
207 // null-terminate the string - doesn't matter that we side effect the |
|
208 // section since we won't see it again and saves making a copy. |
|
209 symbol[symbolsize] = 0; |
|
210 if (IsExportedCode(symbol)) { |
|
211 fprintf(OUTFILE, " %s\n", symbol); |
|
212 |
|
213 } else if ( (aDataSymbol = IsExportedData(symbol)) != 0) { |
|
214 fprintf(OUTFILE, " %s DATA %d\n", symbol, aDataSymbol->nl_size); |
|
215 } |
|
216 else { |
|
217 //All those symbols included from static libs that are |
|
218 //treated as exported because of the dll_runtime compiler |
|
219 //option.Such symbols donot figure out in the symbol table. |
|
220 //Hence are handled separately here. |
|
221 |
|
222 //Workaround for compiler defect - To avoid export of local symbols |
|
223 if(!IsLocalSymbol(symbol)) |
|
224 { |
|
225 fprintf(OUTFILE, " %s\n", symbol); |
|
226 } |
|
227 |
|
228 } |
|
229 } |
|
230 size -= linelength; |
|
231 section += linelength; |
|
232 } |
|
233 } |
|
234 |
|
235 void PrintABIv1ExportSymbols (Elf32_Ehdr * eh) |
|
236 { |
|
237 int shoff = eh->e_shoff; // offset of section header table |
|
238 if (shoff) { |
|
239 Elf32_Shdr * shdr = ELFADDR(Elf32_Shdr, eh, shoff); |
|
240 |
|
241 int shnum = eh->e_shnum; // number of section headers |
|
242 |
|
243 // e_shnum will be 0 if the number of sections is >= SHN_LORESERVE (0xff00) |
|
244 // If this is the case, sh_size contains the actual number of section headers. |
|
245 // If sh_size is 0, there really aren't any section headers. |
|
246 if (!shnum) |
|
247 shnum = shdr->sh_size; |
|
248 |
|
249 int shstrndx = eh->e_shstrndx; |
|
250 |
|
251 // If the section name string table index is >= SHN_LORESERVE (0xff00), shstrndx |
|
252 // contains SHN_XINDEX (0xffff). |
|
253 // If this is the case, sh_link contains the actual index of the section name string |
|
254 // table, otherwise sh_link is 0. |
|
255 |
|
256 if (shstrndx >= 65535) |
|
257 shstrndx = shdr->sh_link; |
|
258 |
|
259 // Initialize list of global data symbols |
|
260 InitSymbolsLists(eh,shdr,shnum); |
|
261 |
|
262 int snameoffset = shdr[shstrndx].sh_offset; // offset in file of sections' names |
|
263 char * sname = ELFADDR(char, eh, snameoffset); |
|
264 for (int i = 0; i < shnum; i++) { |
|
265 if (i != shstrndx) { |
|
266 if (!strcmp(".directive", &sname[shdr[i].sh_name])) { |
|
267 // we're in business. print the section to stdout |
|
268 char * data = ELFADDR(char, eh, shdr[i].sh_offset); |
|
269 int size = shdr[i].sh_size; |
|
270 PrintExportsFromSection(data, size); |
|
271 } |
|
272 } |
|
273 } |
|
274 } |
|
275 } |
|
276 |
|
277 void PrintABIv2ExportSymbols(Elf32_Ehdr *eh) |
|
278 { |
|
279 int shoff = eh->e_shoff; // offset of section header table |
|
280 if (shoff) { |
|
281 Elf32_Shdr * shdr = ELFADDR(Elf32_Shdr, eh, shoff); |
|
282 |
|
283 int shnum = eh->e_shnum; // number of section headers |
|
284 |
|
285 // e_shnum will be 0 if the number of sections is >= SHN_LORESERVE (0xff00) |
|
286 // If this is the case, sh_size contains the actual number of section headers. |
|
287 // If sh_size is 0, there really aren't any section headers. |
|
288 if (!shnum) |
|
289 shnum = shdr->sh_size; |
|
290 |
|
291 int shstrndx = eh->e_shstrndx; |
|
292 |
|
293 // If the section name string table index is >= SHN_LORESERVE (0xff00), shstrndx |
|
294 // contains SHN_XINDEX (0xffff). |
|
295 // If this is the case, sh_link contains the actual index of the section name string |
|
296 // table, otherwise sh_link is 0. |
|
297 |
|
298 if (shstrndx >= 65535) |
|
299 shstrndx = shdr->sh_link; |
|
300 |
|
301 //Get the symbol table |
|
302 Elf32_Sym * symtab = 0; |
|
303 int nSyms = 0; |
|
304 char * strtab = 0; |
|
305 |
|
306 for (int i = 0; (i < shnum); i++) { |
|
307 if (shdr[i].sh_type == SHT_DYNSYM) { |
|
308 symtab = ELFADDR(Elf32_Sym, eh, shdr[i].sh_offset); |
|
309 nSyms = shdr[i].sh_size / shdr[i].sh_entsize; |
|
310 strtab = ELFADDR(char, eh, shdr[shdr[i].sh_link].sh_offset); |
|
311 break; |
|
312 } |
|
313 } |
|
314 for (i = 0; i < nSyms; i++) { |
|
315 if (symtab[i].st_info == ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT)) { |
|
316 char * name = ELFADDR(char, strtab, symtab[i].st_name); |
|
317 char * CodeSection = ELFADDR(char, eh, shdr[symtab[i].st_shndx].sh_offset); |
|
318 Elf32_Word *aLocation = ELFADDR(Elf32_Word, CodeSection, symtab[i].st_value); |
|
319 int ordinal = *aLocation; |
|
320 fprintf(OUTFILE, "%s %d DATA %d %d\n",name, ordinal, symtab[i].st_size); |
|
321 } else if (symtab[i].st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)) { |
|
322 char * name = ELFADDR(char, strtab, symtab[i].st_name); |
|
323 char * CodeSection = ELFADDR(char, eh, shdr[symtab[i].st_shndx].sh_offset); |
|
324 Elf32_Word *aLocation = ELFADDR(Elf32_Word, CodeSection, symtab[i].st_value); |
|
325 int ordinal = *aLocation; |
|
326 fprintf(OUTFILE, "%s %d \n",name, ordinal); |
|
327 } |
|
328 } |
|
329 } |
|
330 } |
|
331 |
|
332 void PrintSONAME(Elf32_Ehdr *eh) |
|
333 { |
|
334 int shoff = eh->e_shoff; // offset of section header table |
|
335 if (shoff) { |
|
336 Elf32_Shdr * shdr = ELFADDR(Elf32_Shdr, eh, shoff); |
|
337 |
|
338 int shnum = eh->e_shnum; // number of section headers |
|
339 |
|
340 // e_shnum will be 0 if the number of sections is >= SHN_LORESERVE (0xff00) |
|
341 // If this is the case, sh_size contains the actual number of section headers. |
|
342 // If sh_size is 0, there really aren't any section headers. |
|
343 if (!shnum) |
|
344 shnum = shdr->sh_size; |
|
345 |
|
346 int shstrndx = eh->e_shstrndx; |
|
347 char *aSHdrStrTab = ELFADDR(char, eh, shdr[shstrndx].sh_offset); |
|
348 int i; |
|
349 Elf32_Verdef *aVerDef = 0; |
|
350 char *aStringTab = 0; |
|
351 for(i = 0; i < shnum; i++) { |
|
352 if(strcmp(aSHdrStrTab + shdr[i].sh_name, ".version_d") == 0) { |
|
353 aVerDef = ELFADDR(Elf32_Verdef,eh , shdr[i].sh_offset ); |
|
354 aStringTab = ELFADDR(char, eh, shdr[shdr[i].sh_link].sh_offset); |
|
355 break; |
|
356 } |
|
357 } |
|
358 if(!aVerDef) |
|
359 return; |
|
360 char *aLinkAsName; |
|
361 while(aVerDef) { |
|
362 if(aVerDef->vd_ndx == DEFAULT_VERSION){ |
|
363 Elf32_Verdaux *aVerAux = ELFADDR(Elf32_Verdaux, aVerDef, aVerDef->vd_aux); |
|
364 aLinkAsName = ELFADDR(char, aStringTab, aVerAux->vda_name); |
|
365 fprintf(OUTFILE, "%s \n", aLinkAsName); |
|
366 break; |
|
367 } |
|
368 aVerDef = ELFADDR(Elf32_Verdef, aVerDef, aVerDef->vd_next); |
|
369 } |
|
370 } |
|
371 } |
|
372 |
|
373 int main(int argc, char** argv) |
|
374 { |
|
375 if( argc < 2 ) |
|
376 { |
|
377 return EXIT_FAILURE; |
|
378 } |
|
379 |
|
380 char* file = argv[argc - 1];//The last arg is the file name |
|
381 int idx = 0; |
|
382 bool outFileOpt = false; |
|
383 bool proxyDso = false; |
|
384 bool soname = false; |
|
385 while(idx < argc ) |
|
386 { |
|
387 if((stricmp(argv[idx], "-o") == 0) && ((idx + 1) < argc) ) |
|
388 { |
|
389 idx++; |
|
390 char *outfilename = argv[idx]; |
|
391 OUTFILE = fopen(outfilename, "wb"); |
|
392 outFileOpt = true; |
|
393 } |
|
394 else if(stricmp(argv[idx], "-d") == 0) |
|
395 { |
|
396 proxyDso = true; |
|
397 } |
|
398 else if(stricmp(argv[idx], "-s") == 0) |
|
399 { |
|
400 soname = true; |
|
401 } |
|
402 idx++; |
|
403 } |
|
404 |
|
405 if(!outFileOpt) |
|
406 { |
|
407 OUTFILE = stdout; |
|
408 } |
|
409 |
|
410 Elf32_Ehdr * eh = OpenElfFile(file); |
|
411 |
|
412 if( soname ) { |
|
413 PrintSONAME(eh); |
|
414 } |
|
415 else if( !proxyDso ) { |
|
416 PrintABIv1ExportSymbols(eh); |
|
417 } |
|
418 else { |
|
419 PrintABIv2ExportSymbols(eh); |
|
420 } |
|
421 return EXIT_SUCCESS; |
|
422 } |
|
423 |
|
424 |
|
425 |
|
426 |
|
427 |
|
428 |