|
1 /* |
|
2 * Copyright (c) 2002-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 #include <elfdefs.h> |
|
23 #include <sys/stat.h> |
|
24 |
|
25 #if defined(__MSVCDOTNET__) || defined(__TOOLS2__) |
|
26 #include <iostream> |
|
27 #include <iomanip> |
|
28 using namespace std; |
|
29 #else //(!__MSVCDOTNET__ && !__TOOLS2__) |
|
30 #include <iostream.h> |
|
31 #include <iomanip.h> |
|
32 #endif //__MSVCDOTNET__ |
|
33 |
|
34 #define ADDR(rtype, p, o) (rtype *)(((char *)p) + o) |
|
35 |
|
36 bool ignoreSomeSections; |
|
37 |
|
38 void hexdump(unsigned char* data, int aSize, int offset) |
|
39 // print hex dump of relevant sections |
|
40 { |
|
41 int i=0; |
|
42 int p=0; |
|
43 while (i<aSize) |
|
44 { |
|
45 int count=0; |
|
46 if(p==0){printf("\t%06x ",offset);} // offset into section |
|
47 while (i<aSize && count<4) |
|
48 { |
|
49 printf("%02X", *data); // print 4 lots of %08x for the data expresed as 32-bit word |
|
50 data++; |
|
51 i++; |
|
52 count++; |
|
53 offset++; |
|
54 } |
|
55 |
|
56 printf(" "); |
|
57 p++; |
|
58 if (p==4) |
|
59 { |
|
60 data=data-16; |
|
61 for (int i=0;i<16;i++) //print 16 bytes of memory interpreted |
|
62 { //as ASCII characters with all non-printing |
|
63 if (*data>32 && *data <127) //characters converted to dots |
|
64 { |
|
65 printf("%1c",*data); |
|
66 } |
|
67 else |
|
68 { |
|
69 printf("."); |
|
70 } |
|
71 data++; |
|
72 } |
|
73 p=0; |
|
74 printf(" \n "); |
|
75 } |
|
76 } |
|
77 printf(" \n\n "); |
|
78 } |
|
79 |
|
80 void print_directive(unsigned char* data, int size) |
|
81 // print formatted text of directive section |
|
82 { |
|
83 printf ("\t"); |
|
84 |
|
85 for (int i=0; i<size; i++) |
|
86 { |
|
87 if ((char)data[i]>31 && (char)data[i]<127) |
|
88 { |
|
89 printf ("%c", (char)data[i]); |
|
90 } |
|
91 |
|
92 if ((char)data[i]=='\n') |
|
93 { |
|
94 printf ("\n\t"); |
|
95 } |
|
96 } |
|
97 |
|
98 printf ("\n"); |
|
99 } |
|
100 |
|
101 void print_reloc(Elf32_Ehdr* eh, Elf32_Sym* symT, unsigned char* strtab) |
|
102 // print relocation section |
|
103 { |
|
104 Elf32_Shdr* shdr = ADDR(Elf32_Shdr, eh, eh->e_shoff); |
|
105 for (int j=0;j< eh->e_shnum;j++) |
|
106 { |
|
107 char* sname = ADDR(char, eh, shdr[eh->e_shstrndx].sh_offset); |
|
108 if ( (shdr[j].sh_type==9) && |
|
109 ( (!ignoreSomeSections) || |
|
110 (strncmp(".rel.debug_", &sname[shdr[j].sh_name], 11)) |
|
111 ) |
|
112 ) |
|
113 { |
|
114 unsigned char* data = ADDR(unsigned char, eh, shdr[j].sh_offset); |
|
115 int noOfReloc=shdr[j].sh_size / shdr[j].sh_entsize; |
|
116 printf("\n\n\n\t\t\t%s\n", &sname[shdr[j].sh_name]); |
|
117 Elf32_Rel* rl=(Elf32_Rel*)data; // pointer to relocation section |
|
118 for (int i=0;i<noOfReloc;i++) |
|
119 { |
|
120 unsigned char* symbolName = strtab; // pointer to firest element of string // table which holds symbol names |
|
121 Elf32_Sym* sym = symT; // pointer to symbol table |
|
122 int symTIndx= ELF32_R_SYM(rl->r_info); // symbol Tableindex |
|
123 sym=sym+symTIndx; |
|
124 symbolName=symbolName+sym->st_name; // index into string table section |
|
125 // with symbol names |
|
126 printf("\t0x%08x \t", rl->r_offset); // prints offset into relocation section |
|
127 printf("%d", symTIndx); // symbol table index |
|
128 printf("\t%s\n",symbolName); // symbol name |
|
129 rl++; |
|
130 } |
|
131 } |
|
132 } |
|
133 } |
|
134 |
|
135 void print_GlSymbols(Elf32_Ehdr* eh, Elf32_Sym* symT, unsigned char* strtab) |
|
136 // print global symbols from Symbol Table |
|
137 { |
|
138 Elf32_Shdr* shdr = ADDR(Elf32_Shdr, eh, eh->e_shoff); |
|
139 char* sname = ADDR(char, eh, shdr[eh->e_shstrndx].sh_offset); |
|
140 for (int i=0;i< eh->e_shnum;i++) |
|
141 { |
|
142 if (!strcmp(".symtab", &sname[shdr[i].sh_name])) |
|
143 { |
|
144 int noOfSym=shdr[i].sh_size / shdr[i].sh_entsize; // number of symbols |
|
145 const char *symName =(const char *)strtab; |
|
146 int count = 1; |
|
147 printf("Global symbols:\n"); |
|
148 printf("=================\n\n"); |
|
149 for (int l=0;l< noOfSym ;l++) |
|
150 { |
|
151 symT=symT+1; |
|
152 if( ELF32_ST_BIND(symT->st_info) == 1) // searching for global symbols |
|
153 { |
|
154 symName = symName + symT->st_name; // index into string table section |
|
155 printf("%d ",count); |
|
156 printf(symName); |
|
157 printf("\n"); |
|
158 symName = symName - symT->st_name; // back to pointing to first byte of string table |
|
159 count++; |
|
160 } |
|
161 |
|
162 } |
|
163 } |
|
164 } |
|
165 } |
|
166 |
|
167 void print_elf_header(Elf32_Ehdr* eh) |
|
168 { |
|
169 // print elf header |
|
170 if (eh->e_version==1) |
|
171 printf("\tHeader version: EV_CURRENT (Current version)\n"); |
|
172 else |
|
173 printf("\tInvalid version: EV_NONE (Invalid version)\n"); |
|
174 |
|
175 if (eh->e_type==0) |
|
176 printf("\tFile Type: ET_NONE (No file type) (0)\n"); |
|
177 else if (eh->e_type==1) |
|
178 printf("\tFile Type: ET_REL (Relocatable object) (1)\n"); |
|
179 else if (eh->e_type==2) |
|
180 printf("\tFile Type: ET_EXEC (Executable file) (2)\n"); |
|
181 else if (eh->e_type==3) |
|
182 printf("\tFile Type: ET_DYN (Shared object file) (3)\n"); |
|
183 else if (eh->e_type==4) |
|
184 printf("\tFile Type: ET_CORE (Core File) (4)\n"); |
|
185 else if (eh->e_type==65280) |
|
186 printf("\tFile Type: ET_LOPROC (Precessor Specific) (ff00)\n"); |
|
187 else |
|
188 printf("\tFile Type: ET_HIPROC (Precessor Specific) (ffff)\n"); |
|
189 if (eh->e_machine==40) |
|
190 printf("\tMachine: EM_ARM (ARM)\n"); |
|
191 else |
|
192 printf("\tERROR:\tUnexpected machine\n"); |
|
193 |
|
194 printf("\tEntry offset (in SHF_ENTRYSECT section):0x%08x \n",eh->e_entry); |
|
195 printf("\tProgram header entries : %d\n",eh->e_phnum); |
|
196 printf("\tSection header entries : %d\n",eh->e_shnum); |
|
197 |
|
198 printf("\tProgram header offset : %d",eh->e_phoff); |
|
199 printf(" bytes (0x%08X",eh->e_phoff); |
|
200 printf(")\n"); |
|
201 printf("\tSection header offset : %d",eh->e_shoff); |
|
202 printf(" bytes (0x%08X",eh->e_shoff); |
|
203 printf(")\n"); |
|
204 |
|
205 printf("\tProgram header entry size : %d",eh->e_phentsize); |
|
206 printf(" bytes (0x%02X",eh->e_phentsize); |
|
207 printf(")\n"); |
|
208 printf("\tSection header entry size : %d",eh->e_shentsize); |
|
209 printf(" bytes (0x%02X",eh->e_shentsize); |
|
210 printf(")\n"); |
|
211 printf("\tSection header string table index: %d \n", eh->e_shstrndx); |
|
212 printf("\tHeader size: %d", eh->e_ehsize); |
|
213 printf(" bytes (0x%02X",eh->e_ehsize); |
|
214 printf(")\n"); |
|
215 } |
|
216 |
|
217 void print_sect_header(char* sname, Elf32_Shdr* shdr, int count) |
|
218 // print section header names |
|
219 { |
|
220 static const char* KtypeName[]={"0","SHT_PROGBITS (1)","SHT_SYMTAB (2)","SHT_STRTAB (3)", |
|
221 "SHT_RELA (4)","5", "SHT_DINAMIC (6)","7","8","SHT_REL (9)", |
|
222 "10","SHT_DINSYM (11)"}; |
|
223 |
|
224 printf("\n\n\tName\t\t:%1s\n ",&sname[shdr[count].sh_name]); |
|
225 printf("\tType\t\t: %s\n", KtypeName[shdr[count].sh_type]); |
|
226 printf("\tAddr\t\t: 0x%08X\n",shdr[count].sh_addr); |
|
227 printf("\tSize\t\t: %1d", shdr[count].sh_size); |
|
228 printf(" bytes (0x%X",shdr[count].sh_size); |
|
229 printf(")\n"); |
|
230 printf("\tEntry Size\t: %1d\n",shdr[count].sh_entsize); |
|
231 printf("\tAligment\t: %1d\n\n\n",shdr[count].sh_addralign); |
|
232 } |
|
233 |
|
234 unsigned char* findSymbolStringT(Elf32_Ehdr* eh) |
|
235 //calculate and return pointer to the first byte of string table(the one with symbol names) |
|
236 { |
|
237 Elf32_Shdr* shdr = ADDR(Elf32_Shdr, eh, eh->e_shoff); |
|
238 char* sname = ADDR(char, eh, shdr[eh->e_shstrndx].sh_offset); |
|
239 for (int i=0;i < eh->e_shnum; i++) |
|
240 { |
|
241 if (!strcmp(".strtab", &sname[shdr[i].sh_name])) |
|
242 { |
|
243 unsigned char* data = ADDR(unsigned char, eh, shdr[i].sh_offset); |
|
244 return data; //pointer to the first byte of string table section |
|
245 } |
|
246 } |
|
247 return NULL; //if not found |
|
248 } |
|
249 |
|
250 Elf32_Sym* findSymbolT(Elf32_Ehdr* eh) |
|
251 //calculate and return pointer to the first element of symbol table |
|
252 { |
|
253 Elf32_Shdr* shdr = ADDR(Elf32_Shdr, eh, eh->e_shoff); |
|
254 for (int i=0;i < eh->e_shnum;i++) |
|
255 { |
|
256 if (shdr[i].sh_type==2) |
|
257 { |
|
258 unsigned char* data = ADDR(unsigned char, eh, shdr[i].sh_offset); |
|
259 Elf32_Sym* sym=(Elf32_Sym*)data; |
|
260 return sym; //pointer to the first element of symbol table. |
|
261 } |
|
262 } |
|
263 return NULL; // if not found |
|
264 } |
|
265 |
|
266 void print_Summary(Elf32_Ehdr* eh) |
|
267 { |
|
268 //print section names |
|
269 Elf32_Shdr* shdr = ADDR(Elf32_Shdr, eh, eh->e_shoff); |
|
270 char* sname = ADDR(char, eh, shdr[eh->e_shstrndx].sh_offset); |
|
271 printf("\nSummary: \n"); |
|
272 printf("==========\n"); |
|
273 for (int i=0;i< eh->e_shnum;i++) |
|
274 { |
|
275 printf(&sname[shdr[i].sh_name]); |
|
276 printf("\n"); |
|
277 } |
|
278 } |
|
279 |
|
280 bool printAll; |
|
281 |
|
282 int do_elf_file(char* buffer, char* name) |
|
283 { |
|
284 Elf32_Ehdr* eh=(Elf32_Ehdr *)buffer; //elf header |
|
285 if (eh->e_ident[EI_MAG0] !=0x7f || eh->e_ident[EI_MAG1] != 0x45 || eh->e_ident[EI_MAG2] !=0x4c || eh->e_ident[EI_MAG3] != 0x46) |
|
286 { |
|
287 // EI_MAG0 to EI_MAG3 - A files' first 4 bytes hold a 'magic number', identifying the file as an ELF object file. |
|
288 cout << "Error: " << name << " is not a valid ELF file"; |
|
289 return 1; |
|
290 } |
|
291 if (eh->e_ident[EI_DATA] == 2) |
|
292 { |
|
293 // ELF Header size should be 52 bytes or converted into Big-Endian system 13312 |
|
294 if (eh->e_ehsize != 13312) |
|
295 { |
|
296 printf("\tERROR:\tELF Header contains invalid file type\n"); |
|
297 exit(1); |
|
298 } |
|
299 // e_ident[EI_DATA] specifies the data encoding of the processor-specific data in the object file. |
|
300 printf("\tERROR:\tData encoding ELFDATA2MSB (Big-Endian) not supported\n"); |
|
301 exit(1); |
|
302 } |
|
303 if (eh->e_ehsize != 52) |
|
304 { |
|
305 // ELF Header size should be 52 bytes |
|
306 printf("\tERROR:\tELF Header contains invalid file type\n"); |
|
307 exit(1); |
|
308 } |
|
309 int shoff = eh->e_shoff; // offset of section header table |
|
310 Elf32_Shdr* shdr = ADDR(Elf32_Shdr, eh, shoff); // calculating pointer to Secton Header Table |
|
311 // Elf32_Shdr * shdr = (Elf32_Shdr *)(buffer+shoff); |
|
312 int shnum = eh->e_shnum; // number of section headers |
|
313 int shstrndx = eh->e_shstrndx; |
|
314 int snameoffset = shdr[shstrndx].sh_offset; // offset in file of sections' names |
|
315 char* sname = ADDR(char, eh, snameoffset); // pointer to String Table which holds section names |
|
316 // char * sname = (char *)(buffer+snameoffset); |
|
317 print_elf_header(eh); // print Elf Header |
|
318 |
|
319 Elf32_Sym* symT= findSymbolT(eh); // pointer to Symbol table |
|
320 if (symT==NULL) |
|
321 { |
|
322 printf("\nSymbol table not found\n"); |
|
323 } |
|
324 unsigned char* strtab=findSymbolStringT(eh); // pointer to String table which holds symbol names |
|
325 if (strtab==NULL) |
|
326 { |
|
327 printf("\nString (the one which holds symbol names) table not found\n"); |
|
328 } |
|
329 print_reloc(eh,symT, strtab); // print relocation info showing symbol names and |
|
330 // and the name of section in which the relocaton occurs. |
|
331 for(int i = 0; i < shnum; i++) |
|
332 { |
|
333 unsigned char* data = ADDR(unsigned char, eh, shdr[i].sh_offset); //pointer to the first byte in the section |
|
334 //unsigned char * data = (unsigned char * )(buffer+shdr[i].sh_offset); |
|
335 int size = shdr[i].sh_size; // section size in bytes |
|
336 |
|
337 //print directive section |
|
338 if (!strcmp(".directive", &sname[shdr[i].sh_name])) |
|
339 { |
|
340 print_sect_header(sname, shdr, i); |
|
341 print_directive(data,size); |
|
342 } |
|
343 |
|
344 if (!strcmp(".symtab", &sname[shdr[i].sh_name])) |
|
345 { |
|
346 print_sect_header(sname, shdr, i); |
|
347 // print global symbols |
|
348 print_GlSymbols(eh,symT, strtab); |
|
349 } |
|
350 |
|
351 //print relevant section header names |
|
352 //print hex dump of relevant sections |
|
353 if (shdr[i].sh_type==1 || shdr[i].sh_type==4 || shdr[i].sh_type==6 || |
|
354 shdr[i].sh_type==9 || shdr[i].sh_type==11) |
|
355 { |
|
356 if (strcmp(".comment", &sname[shdr[i].sh_name])&& |
|
357 strcmp(".line", &sname[shdr[i].sh_name]) && |
|
358 strcmp(".hash", &sname[shdr[i].sh_name]) && |
|
359 strcmp(".note", &sname[shdr[i].sh_name]) && |
|
360 strcmp(".directive", &sname[shdr[i].sh_name]) && |
|
361 strncmp(".debug",&sname[shdr[i].sh_name] ,6)) |
|
362 { |
|
363 if ( ! ( (ignoreSomeSections) && |
|
364 (strncmp(".rel.debug_", &sname[shdr[i].sh_name], 11)==0) |
|
365 ) |
|
366 ) |
|
367 { |
|
368 print_sect_header(sname, shdr, i); |
|
369 hexdump(data,size,i); |
|
370 } |
|
371 } |
|
372 } |
|
373 if (printAll) // displays extra information |
|
374 { |
|
375 if(i!=0) |
|
376 { |
|
377 print_sect_header(sname, shdr, i); |
|
378 hexdump(data,size,i); |
|
379 } |
|
380 } |
|
381 } |
|
382 print_Summary(eh); // print section names |
|
383 return 0; |
|
384 } |
|
385 |
|
386 int read_ar_element_header(char* ptr) |
|
387 { |
|
388 int length = strtol(ptr+48,0,10); |
|
389 |
|
390 if (strncmp(ptr+58, "\x60\x0A", 2) != 0) |
|
391 { |
|
392 return -1; |
|
393 } |
|
394 return length; |
|
395 } |
|
396 |
|
397 int main(int argc, char* argv[]) |
|
398 { |
|
399 char* arg; |
|
400 int numberOfOptions=2; |
|
401 printAll=0; |
|
402 ignoreSomeSections=0; |
|
403 if (argc<2) |
|
404 { |
|
405 cout << "File not specified"; |
|
406 exit(1); |
|
407 } |
|
408 else if (argc>numberOfOptions+2) |
|
409 { |
|
410 cout << "Too many arguments"; |
|
411 exit(1); |
|
412 } |
|
413 else |
|
414 { |
|
415 for (int i=1;i<=argc-2;i++) |
|
416 { |
|
417 if ( strcmp("-i", argv[i]) ==0 ) |
|
418 { |
|
419 ignoreSomeSections=1; |
|
420 } |
|
421 else if ( strcmp("-a", argv[i]) ==0 ) |
|
422 { |
|
423 printAll=1; |
|
424 } |
|
425 } |
|
426 arg=argv[argc-1]; |
|
427 } |
|
428 |
|
429 struct stat results; |
|
430 stat(arg, &results); |
|
431 FILE *elffile; |
|
432 if((elffile = fopen(arg, "rb" )) == NULL) |
|
433 { |
|
434 cout << "Error opening file " << arg; |
|
435 exit (1); |
|
436 } |
|
437 char* buffer=new char [results.st_size];//allocating enough memory |
|
438 fread( buffer, sizeof( char ), results.st_size, elffile); |
|
439 fclose(elffile); |
|
440 |
|
441 if (strncmp(buffer, "!<arch>\x0A", 8) != 0) |
|
442 { |
|
443 // plain ELF file |
|
444 if (do_elf_file(buffer, arg) != 0) |
|
445 { |
|
446 return 1; |
|
447 } |
|
448 return 0; |
|
449 } |
|
450 |
|
451 // library file |
|
452 char* nextfile = buffer; |
|
453 int remainder = results.st_size; |
|
454 |
|
455 #define ADVANCE(n) nextfile+=(n); remainder-=(n); |
|
456 |
|
457 ADVANCE(8); |
|
458 |
|
459 while (remainder > 0) |
|
460 { |
|
461 int element_length = read_ar_element_header(nextfile); |
|
462 ADVANCE(60); |
|
463 |
|
464 if (element_length < 0 || element_length > remainder) |
|
465 { |
|
466 cout << "Error: archive file corrupt"; |
|
467 return 1; |
|
468 } |
|
469 |
|
470 if (strncmp(nextfile, "\x7F\x45\x4C\x46",4) == 0) |
|
471 { |
|
472 if (do_elf_file(nextfile, "archive_element") != 0) |
|
473 { |
|
474 return 1; |
|
475 } |
|
476 } |
|
477 element_length += element_length&1; // round up to a multiple of 2 |
|
478 ADVANCE(element_length); |
|
479 } |
|
480 |
|
481 return 0; |
|
482 } |