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