Commit | Line | Data |
---|---|---|
76466873 NC |
1 | /* readelf.c -- display contents of an ELF format file |
2 | Copyright (C) 1998 Free Software Foundation, Inc. | |
3 | ||
4 | Originally developed by Eric Youngdale <eric@andante.jic.com> | |
5 | Modifications by Nick Clifton <nickc@cygnus.com> | |
6 | ||
7 | This file is part of GNU Binutils. | |
8 | ||
9 | This program is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2 of the License, or | |
12 | (at your option) any later version. | |
13 | ||
14 | This program is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with this program; if not, write to the Free Software | |
21 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
22 | 02111-1307, USA. */ | |
ebb64169 | 23 | \f |
76466873 NC |
24 | |
25 | #include <assert.h> | |
76466873 | 26 | #include <sys/stat.h> |
ebb64169 | 27 | #include <stdio.h> |
76466873 NC |
28 | |
29 | #include "readelf.h" | |
ebb64169 | 30 | #include "bucomm.h" |
c18f8aef | 31 | #include "getopt.h" |
76466873 NC |
32 | |
33 | #ifdef ANSI_PROTOTYPES | |
34 | #include <stdarg.h> | |
35 | #else | |
36 | #include <varargs.h> | |
37 | #endif | |
38 | ||
ebb64169 NC |
39 | unsigned int dynamic_addr; |
40 | unsigned int dynamic_size; | |
41 | char * dynamic_strings; | |
42 | Elf_Sym * dynamic_symbols; | |
43 | char program_interpreter [64]; | |
44 | char * program_name = "readelf"; | |
45 | int dynamic_info [DT_JMPREL + 1]; | |
46 | int version_info [16]; | |
47 | int must_swap = 0; | |
48 | int loadaddr = 0; | |
49 | unsigned int rela_addr; | |
50 | unsigned int rela_size; | |
51 | Elf_Ehdr elf_header; | |
52 | Elf_Shdr * section_headers; | |
53 | char * string_table; | |
76466873 NC |
54 | Elf_Dyn * dpnt; |
55 | Elf_Rel * rpnt; | |
ebb64169 NC |
56 | int show_name; |
57 | int do_dynamic; | |
58 | int do_syms; | |
59 | int do_reloc; | |
60 | int do_sections; | |
61 | int do_segments; | |
62 | int do_using_dynamic; | |
63 | int do_header; | |
64 | int do_dump; | |
65 | int do_version; | |
66 | long int expected_endian; | |
76466873 NC |
67 | |
68 | ||
ebb64169 | 69 | #define SECTION_NAME(X) (string_table + (X)->sh_name) |
76466873 NC |
70 | |
71 | #define NUM_DUMP_SECTS 100 | |
72 | char dump_sects [NUM_DUMP_SECTS]; | |
73 | #define HEX_DUMP 1 | |
74 | #define DISASS_DUMP 2 | |
75 | ||
76 | /* Forward declarations for dumb compilers. */ | |
ebb64169 | 77 | static char * get_dynamic_type PARAMS ((unsigned long)); |
76466873 NC |
78 | static char * get_i386_rel_type PARAMS ((bfd_vma rtype)); |
79 | static char * get_m68k_rel_type PARAMS ((bfd_vma rtype)); | |
80 | static char * get_sparc_rel_type PARAMS ((bfd_vma rtype)); | |
81 | static char * get_m32r_rel_type PARAMS ((bfd_vma rtype)); | |
82 | static char * get_v850_rel_type PARAMS ((bfd_vma rtype)); | |
83 | static char * get_d10v_rel_type PARAMS ((bfd_vma rtype)); | |
2f300fe6 | 84 | /* start-sanitize-d30v */ |
76466873 | 85 | static char * get_d30v_rel_type PARAMS ((bfd_vma rtype)); |
2f300fe6 | 86 | /* end-sanitize-d30v */ |
76466873 NC |
87 | static char * get_sh_rel_type PARAMS ((bfd_vma rtype)); |
88 | static char * get_mn10300_rel_type PARAMS ((bfd_vma rtype)); | |
89 | static char * get_mn10200_rel_type PARAMS ((bfd_vma rtype)); | |
a09db9ba | 90 | static char * get_ppc_rel_type PARAMS ((bfd_vma rtype)); |
ebb64169 NC |
91 | static void dump_relocations |
92 | PARAMS ((FILE *, unsigned long, unsigned long, Elf_Sym *, char *)); | |
93 | static char * get_file_type PARAMS ((unsigned e_type)); | |
94 | static char * get_machine_name PARAMS ((unsigned e_machine)); | |
95 | static char * get_machine_data PARAMS ((unsigned e_data)); | |
96 | static char * get_machine_flags PARAMS ((unsigned, unsigned e_machine)); | |
97 | static char * get_segment_type PARAMS ((unsigned long p_type)); | |
76466873 | 98 | static char * get_section_type_name PARAMS ((unsigned int sh_type)); |
ebb64169 NC |
99 | static char * get_symbol_binding PARAMS ((unsigned int binding)); |
100 | static char * get_symbol_type PARAMS ((unsigned int type)); | |
76466873 NC |
101 | static void usage PARAMS ((void)); |
102 | static void parse_args PARAMS ((int argc, char ** argv)); | |
ebb64169 NC |
103 | static int process_file_header PARAMS ((void)); |
104 | static void process_program_headers PARAMS ((FILE *)); | |
105 | static void process_section_headers PARAMS ((FILE *)); | |
106 | static void process_dynamic_segment PARAMS ((FILE *)); | |
107 | static void process_symbol_table PARAMS ((FILE *)); | |
108 | static void process_section_contents PARAMS ((FILE *)); | |
76466873 | 109 | static void process_file PARAMS ((char * file_name)); |
ebb64169 NC |
110 | static void process_relocs PARAMS ((FILE *)); |
111 | static void process_version_sections PARAMS ((FILE *)); | |
112 | static char * get_ver_flags PARAMS ((unsigned short flags)); | |
113 | static char * get_symbol_index_type PARAMS ((unsigned short type)); | |
76466873 | 114 | |
ebb64169 | 115 | #define NUM_ELEM(array) (sizeof (array) / sizeof ((array)[0])) |
76466873 NC |
116 | |
117 | #define SWAP2(val) ( (((val) << 8) & (0xff << 8)) \ | |
118 | | (((val) >> 8) & (0xff << 0))) | |
119 | ||
120 | #define SWAP4(val) ( (((val) << 24) & (0xff << 24)) \ | |
121 | | (((val) << 8) & (0xff << 16)) \ | |
122 | | (((val) >> 8) & (0xff << 8)) \ | |
123 | | (((val) >> 24) & (0xff << 0))) | |
124 | ||
ebb64169 NC |
125 | /* Warning: This macro assumes 8 bits in a char, |
126 | and at least 16 bits in a short, | |
127 | and at least 32 bits in a long. */ | |
128 | #define BYTE_SWAP(structure, field) \ | |
129 | if (sizeof ((structure).field) == 2) \ | |
76466873 | 130 | { \ |
ebb64169 NC |
131 | unsigned short val = (structure).field; \ |
132 | (structure).field = SWAP2 (val); \ | |
76466873 | 133 | } \ |
ebb64169 | 134 | else if (sizeof ((structure).field) != 4) \ |
76466873 NC |
135 | abort (); \ |
136 | else \ | |
137 | { \ | |
ebb64169 NC |
138 | unsigned long val = (structure).field; \ |
139 | (structure).field = SWAP4 (val); \ | |
76466873 NC |
140 | } |
141 | ||
ebb64169 NC |
142 | #define GET_DATA_ALLOC(offset, size, var, type, reason) \ |
143 | if (fseek (file, offset, SEEK_SET)) \ | |
144 | { \ | |
145 | error (_("Unable to seek to start of %s at %x\n"), reason, offset); \ | |
146 | return; \ | |
147 | } \ | |
148 | \ | |
149 | var = (type) malloc (size); \ | |
150 | \ | |
151 | if (var == NULL) \ | |
152 | { \ | |
153 | error (_("Out of memory allocating %d bytes for %s\n"), size, reason); \ | |
154 | return; \ | |
155 | } \ | |
156 | \ | |
157 | if (fread (var, size, 1, file) != 1) \ | |
158 | { \ | |
159 | error (_("Unable to read in %d bytes of %s\n"), size, reason); \ | |
160 | free (var); \ | |
161 | var = NULL; \ | |
162 | return; \ | |
163 | } | |
164 | ||
165 | ||
166 | #define GET_DATA(offset, var, reason) \ | |
167 | if (fseek (file, offset, SEEK_SET)) \ | |
168 | { \ | |
169 | error (_("Unable to seek to %x for %s\n"), offset, reason); \ | |
170 | return; \ | |
171 | } \ | |
172 | else if (fread (& var, sizeof (var), 1, file) != 1) \ | |
173 | { \ | |
174 | error (_("Unable to read data at %x for %s\n"), offset, reason); \ | |
175 | return; \ | |
176 | } | |
76466873 NC |
177 | |
178 | #ifdef ANSI_PROTOTYPES | |
179 | static void | |
180 | error (const char * message, ...) | |
181 | { | |
182 | va_list args; | |
183 | ||
184 | fprintf (stderr, _("%s: Error: "), program_name); | |
185 | va_start (args, message); | |
186 | vfprintf (stderr, message, args); | |
187 | va_end (args); | |
188 | return; | |
189 | } | |
190 | ||
191 | static void | |
192 | warn (const char * message, ...) | |
193 | { | |
194 | va_list args; | |
195 | ||
196 | fprintf (stderr, _("%s: Warning: "), program_name); | |
197 | va_start (args, message); | |
198 | vfprintf (stderr, message, args); | |
199 | va_end (args); | |
200 | return; | |
201 | } | |
202 | #else | |
203 | static void | |
204 | error (va_alist) | |
205 | { | |
206 | char * message; | |
207 | va_list args; | |
208 | ||
209 | fprintf (stderr, _("%s: Error: "), program_name); | |
210 | va_start (args); | |
211 | message = va_arg (args, char *); | |
212 | vfprintf (stderr, message, args); | |
213 | va_end (args); | |
214 | return; | |
215 | } | |
216 | ||
217 | static void | |
218 | warn (va_alist) | |
219 | va_dcl; | |
220 | { | |
221 | char * message; | |
222 | va_list args; | |
223 | ||
224 | fprintf (stderr, _("%s: Warning: "), program_name); | |
225 | va_start (args); | |
226 | message = va_arg (args, char *); | |
227 | vfprintf (stderr, message, args); | |
228 | va_end (args); | |
229 | return; | |
230 | } | |
231 | #endif | |
232 | ||
233 | ||
234 | static char * | |
235 | get_i386_rel_type (rtype) | |
236 | bfd_vma rtype; | |
237 | { | |
238 | switch (rtype) | |
239 | { | |
240 | case 0: return "R_386_NONE"; | |
241 | case 1: return "R_386_32"; | |
242 | case 2: return "R_386_PC32"; | |
243 | case 3: return "R_386_GOT32"; | |
244 | case 4: return "R_386_PLT32"; | |
245 | case 5: return "R_386_COPY"; | |
246 | case 6: return "R_386_GLOB_DAT"; | |
247 | case 7: return "R_386_JMP_SLOT"; | |
248 | case 8: return "R_386_RELATIVE"; | |
249 | case 9: return "R_386_GOTOFF"; | |
250 | case 10: return "R_386_GOTPC"; | |
251 | case 20: return "R_386_16"; | |
252 | case 21: return "R_386_PC16"; | |
253 | case 22: return "R_386_PC8"; | |
254 | case 23: return "R_386_max"; | |
255 | default: return _("*INVALID*"); | |
256 | } | |
257 | } | |
258 | ||
259 | static char * | |
260 | get_m68k_rel_type (rtype) | |
261 | bfd_vma rtype; | |
262 | { | |
263 | switch (rtype) | |
264 | { | |
265 | case 0: return "R_68K_NONE"; | |
266 | case 1: return "R_68K_32"; | |
267 | case 2: return "R_68K_16"; | |
268 | case 3: return "R_68K_8"; | |
269 | case 4: return "R_68K_PC32"; | |
270 | case 5: return "R_68K_PC16"; | |
271 | case 6: return "R_68K_PC8"; | |
272 | case 7: return "R_68K_GOT32"; | |
273 | case 8: return "R_68K_GOT16"; | |
274 | case 9: return "R_68K_GOT8"; | |
275 | case 10: return "R_68K_GOT32O"; | |
276 | case 11: return "R_68K_GOT16O"; | |
277 | case 12: return "R_68K_GOT8O"; | |
278 | case 13: return "R_68K_PLT32"; | |
279 | case 14: return "R_68K_PLT16"; | |
280 | case 15: return "R_68K_PLT8"; | |
281 | case 16: return "R_68K_PLT32O"; | |
282 | case 17: return "R_68K_PLT16O"; | |
283 | case 18: return "R_68K_PLT8O"; | |
284 | case 19: return "R_68K_COPY"; | |
285 | case 20: return "R_68K_GLOB_DAT"; | |
286 | case 21: return "R_68K_JMP_SLOT"; | |
287 | case 22: return "R_68K_RELATIVE"; | |
288 | default: return _("*INVALID*"); | |
289 | } | |
290 | } | |
291 | ||
292 | ||
293 | static char * | |
294 | get_sparc_rel_type (rtype) | |
295 | bfd_vma rtype; | |
296 | { | |
297 | switch (rtype) | |
298 | { | |
299 | case 0: return "R_SPARC_NONE"; | |
300 | case 1: return "R_SPARC_8"; | |
301 | case 2: return "R_SPARC_16"; | |
302 | case 3: return "R_SPARC_32"; | |
303 | case 4: return "R_SPARC_DISP8"; | |
304 | case 5: return "R_SPARC_DISP16"; | |
305 | case 6: return "R_SPARC_DISP32"; | |
306 | case 7: return "R_SPARC_WDISP30"; | |
307 | case 8: return "R_SPARC_WDISP22"; | |
308 | case 9: return "R_SPARC_HI22"; | |
309 | case 10: return "R_SPARC_22"; | |
310 | case 11: return "R_SPARC_13"; | |
311 | case 12: return "R_SPARC_LO10"; | |
312 | case 13: return "R_SPARC_GOT10"; | |
313 | case 14: return "R_SPARC_GOT13"; | |
314 | case 15: return "R_SPARC_GOT22"; | |
315 | case 16: return "R_SPARC_PC10"; | |
316 | case 17: return "R_SPARC_PC22"; | |
317 | case 18: return "R_SPARC_WPLT30"; | |
318 | case 19: return "R_SPARC_COPY"; | |
319 | case 20: return "R_SPARC_GLOB_DAT"; | |
320 | case 21: return "R_SPARC_JMP_SLOT"; | |
321 | case 22: return "R_SPARC_RELATIVE"; | |
322 | case 23: return "R_SPARC_UA32"; | |
323 | case 24: return "R_SPARC_10"; | |
324 | case 25: return "R_SPARC_11"; | |
325 | case 26: return "R_SPARC_64"; | |
326 | case 27: return "R_SPARC_OLO10"; | |
327 | case 28: return "R_SPARC_HH22"; | |
328 | case 29: return "R_SPARC_HM10"; | |
329 | case 30: return "R_SPARC_LM22"; | |
330 | case 31: return "R_SPARC_PC_HH22"; | |
331 | case 32: return "R_SPARC_PC_HM10"; | |
332 | case 33: return "R_SPARC_PC_LM22"; | |
333 | case 34: return "R_SPARC_WDISP16"; | |
334 | case 35: return "R_SPARC_WDISP19"; | |
335 | case 36: return "R_SPARC_UNUSED_42"; | |
336 | case 37: return "R_SPARC_7"; | |
337 | case 38: return "R_SPARC_5"; | |
338 | case 39: return "R_SPARC_6"; | |
339 | case 40: return "R_SPARC_DISP64"; | |
340 | case 41: return "R_SPARC_PLT64"; | |
341 | case 42: return "R_SPARC_HIX22"; | |
342 | case 43: return "R_SPARC_LOX10"; | |
343 | case 44: return "R_SPARC_H44"; | |
344 | case 45: return "R_SPARC_M44"; | |
345 | case 46: return "R_SPARC_L44"; | |
346 | case 47: return "R_SPARC_REGISTER"; | |
347 | case 48: return "R_SPARC_UA64"; | |
348 | case 49: return "R_SPARC_UA16"; | |
349 | case 50: return "R_SPARC_32LE"; | |
350 | default: return _("*INVALID*"); | |
351 | } | |
352 | } | |
353 | ||
354 | ||
355 | static char * | |
356 | get_m32r_rel_type (rtype) | |
357 | bfd_vma rtype; | |
358 | { | |
359 | switch (rtype) | |
360 | { | |
361 | case 0: return "R_M32R_NONE"; | |
362 | case 1: return "R_M32R_16"; | |
363 | case 2: return "R_M32R_32"; | |
364 | case 3: return "R_M32R_24"; | |
365 | case 4: return "R_M32R_10_PCREL"; | |
366 | case 5: return "R_M32R_18_PCREL"; | |
367 | case 6: return "R_M32R_26_PCREL"; | |
368 | case 7: return "R_M32R_HI16_ULO"; | |
369 | case 8: return "R_M32R_HI16_SLO"; | |
370 | case 9: return "R_M32R_LO16"; | |
371 | case 10: return "R_M32R_SDA16"; | |
372 | default: return _("*INVALID*"); | |
373 | } | |
374 | } | |
375 | ||
376 | ||
377 | static char * | |
378 | get_v850_rel_type (rtype) | |
379 | bfd_vma rtype; | |
380 | { | |
381 | switch (rtype) | |
382 | { | |
383 | case 0: return "R_V850_NONE"; | |
384 | case 1: return "R_V850_9_PCREL"; | |
385 | case 2: return "R_V850_22_PCREL"; | |
386 | case 3: return "R_V850_HI16_S"; | |
387 | case 4: return "R_V850_HI16"; | |
388 | case 5: return "R_V850_LO16"; | |
389 | case 6: return "R_V850_32"; | |
390 | case 7: return "R_V850_16"; | |
391 | case 8: return "R_V850_8"; | |
392 | case 9: return "R_V850_SDA_16_16_OFFSET"; | |
393 | case 10: return "R_V850_SDA_15_16_OFFSET"; | |
394 | case 11: return "R_V850_ZDA_16_16_OFFSET"; | |
395 | case 12: return "R_V850_ZDA_15_16_OFFSET"; | |
396 | case 13: return "R_V850_TDA_6_8_OFFSET"; | |
397 | case 14: return "R_V850_TDA_7_8_OFFSET"; | |
398 | case 15: return "R_V850_TDA_7_7_OFFSET"; | |
399 | case 16: return "R_V850_TDA_16_16_OFFSET"; | |
400 | /* start-sanitize-v850e */ | |
401 | case 17: return "R_V850_TDA_4_5_OFFSET"; | |
402 | case 18: return "R_V850_TDA_4_4_OFFSET"; | |
403 | case 19: return "R_V850_SDA_16_16_SPLIT_OFFSET"; | |
404 | case 20: return "R_V850_ZDA_16_16_SPLIT_OFFSET"; | |
405 | case 21: return "R_V850_CALLT_6_7_OFFSET"; | |
406 | case 22: return "R_V850_CALLT_16_16_OFFSET"; | |
407 | /* end-sanitize-v850e */ | |
408 | default: return _("*INVALID*"); | |
409 | } | |
410 | } | |
411 | ||
412 | ||
413 | static char * | |
414 | get_d10v_rel_type (rtype) | |
415 | bfd_vma rtype; | |
416 | { | |
417 | switch (rtype) | |
418 | { | |
419 | case 0: return "R_D10V_NONE"; | |
420 | case 1: return "R_D10V_10_PCREL_R"; | |
421 | case 2: return "R_D10V_10_PCREL_L"; | |
422 | case 3: return "R_D10V_16"; | |
423 | case 4: return "R_D10V_18"; | |
424 | case 5: return "R_D10V_18_PCREL"; | |
425 | case 6: return "R_D10V_32"; | |
426 | default: return _("*INVALID*"); | |
427 | } | |
428 | } | |
429 | ||
2f300fe6 | 430 | /* start-sanitize-d30v */ |
76466873 NC |
431 | static char * |
432 | get_d30v_rel_type (rtype) | |
433 | bfd_vma rtype; | |
434 | { | |
435 | switch (rtype) | |
436 | { | |
437 | case 0: return "R_D30V_NONE"; | |
438 | case 1: return "R_D30V_6"; | |
439 | case 2: return "R_D30V_9_PCREL"; | |
440 | case 3: return "R_D30V_9_PCREL_R"; | |
441 | case 4: return "R_D30V_15"; | |
442 | case 5: return "R_D30V_15_PCREL"; | |
443 | case 6: return "R_D30V_15_PCREL_R"; | |
444 | case 7: return "R_D30V_21"; | |
445 | case 8: return "R_D30V_21_PCREL"; | |
446 | case 9: return "R_D30V_21_PCREL_R"; | |
447 | case 10: return "R_D30V_32"; | |
448 | case 11: return "R_D30V_32_PCREL"; | |
449 | case 12: return "R_D30V_32_NORMAL"; | |
450 | default: return _("*INVALID*"); | |
451 | } | |
452 | } | |
453 | ||
2f300fe6 | 454 | /* end-sanitize-d30v */ |
76466873 NC |
455 | static char * |
456 | get_sh_rel_type (rtype) | |
457 | bfd_vma rtype; | |
458 | { | |
459 | switch (rtype) | |
460 | { | |
461 | case 0: return "R_SH_NONE"; | |
462 | case 1: return "R_SH_DIR32"; | |
463 | case 2: return "R_SH_REL32"; | |
464 | case 3: return "R_SH_DIR8WPN"; | |
465 | case 4: return "R_SH_IND12W"; | |
466 | case 5: return "R_SH_DIR8WPL"; | |
467 | case 6: return "R_SH_DIR8WPZ"; | |
468 | case 7: return "R_SH_DIR8BP"; | |
469 | case 8: return "R_SH_DIR8W"; | |
470 | case 9: return "R_SH_DIR8L"; | |
471 | case 25: return "R_SH_SWITCH16"; | |
472 | case 26: return "R_SH_SWITCH32"; | |
473 | case 27: return "R_SH_USES"; | |
474 | case 28: return "R_SH_COUNT"; | |
475 | case 29: return "R_SH_ALIGN"; | |
476 | case 30: return "R_SH_CODE"; | |
477 | case 31: return "R_SH_DATA"; | |
478 | case 32: return "R_SH_LABEL"; | |
479 | default: return _("*INVALID*"); | |
480 | } | |
481 | } | |
482 | ||
483 | ||
484 | static char * | |
485 | get_mn10300_rel_type (rtype) | |
486 | bfd_vma rtype; | |
487 | { | |
488 | switch (rtype) | |
489 | { | |
490 | case 0: return "R_MN10300_NONE"; | |
491 | case 1: return "R_MN10300_32"; | |
492 | case 2: return "R_MN10300_16"; | |
493 | case 3: return "R_MN10300_8"; | |
494 | case 4: return "R_MN10300_PCREL32"; | |
495 | case 5: return "R_MN10300_PCREL16"; | |
496 | case 6: return "R_MN10300_PCREL8"; | |
497 | default: return _("*INVALID*"); | |
498 | } | |
499 | } | |
500 | ||
501 | ||
502 | static char * | |
503 | get_mn10200_rel_type (rtype) | |
504 | bfd_vma rtype; | |
505 | { | |
506 | switch (rtype) | |
507 | { | |
508 | case 0: return "R_MN10200_NONE"; | |
509 | case 1: return "R_MN10200_32"; | |
510 | case 2: return "R_MN10200_16"; | |
511 | case 3: return "R_MN10200_8"; | |
512 | case 4: return "R_MN10200_24"; | |
513 | case 5: return "R_MN10200_PCREL8"; | |
514 | case 6: return "R_MN10200_PCREL16"; | |
515 | case 7: return "R_MN10200_PCREL24"; | |
516 | default: return _("*INVALID*"); | |
517 | } | |
518 | } | |
519 | ||
520 | ||
a09db9ba MM |
521 | static char * |
522 | get_ppc_rel_type (rtype) | |
523 | bfd_vma rtype; | |
524 | { | |
525 | switch (rtype) | |
526 | { | |
527 | case 0: return "R_PPC_NONE,"; | |
528 | case 1: return "R_PPC_ADDR32,"; | |
529 | case 2: return "R_PPC_ADDR24,"; | |
530 | case 3: return "R_PPC_ADDR16,"; | |
531 | case 4: return "R_PPC_ADDR16_LO,"; | |
532 | case 5: return "R_PPC_ADDR16_HI,"; | |
533 | case 6: return "R_PPC_ADDR16_HA,"; | |
534 | case 7: return "R_PPC_ADDR14,"; | |
535 | case 8: return "R_PPC_ADDR14_BRTAKEN,"; | |
536 | case 9: return "R_PPC_ADDR14_BRNTAKEN,"; | |
537 | case 10: return "R_PPC_REL24,"; | |
538 | case 11: return "R_PPC_REL14,"; | |
539 | case 12: return "R_PPC_REL14_BRTAKEN,"; | |
540 | case 13: return "R_PPC_REL14_BRNTAKEN,"; | |
541 | case 14: return "R_PPC_GOT16,"; | |
542 | case 15: return "R_PPC_GOT16_LO,"; | |
543 | case 16: return "R_PPC_GOT16_HI,"; | |
544 | case 17: return "R_PPC_GOT16_HA,"; | |
545 | case 18: return "R_PPC_PLT24,"; | |
546 | case 19: return "R_PPC_COPY,"; | |
547 | case 21: return "R_PPC_JMP_SLOT,"; | |
548 | case 22: return "R_PPC_RELATIVE,"; | |
549 | case 23: return "R_PPC_LOCAL24PC,"; | |
550 | case 24: return "R_PPC_UADDR32,"; | |
551 | case 25: return "R_PPC_UADDR16,"; | |
552 | case 26: return "R_PPC_REL32,"; | |
553 | case 27: return "R_PPC_PLT32,"; | |
554 | case 28: return "R_PPC_PLTREL32,"; | |
555 | case 29: return "R_PPC_PLT16_LO,"; | |
556 | case 30: return "R_PPC_PLT16_HI,"; | |
557 | case 31: return "R_PPC_PLT16_HA,"; | |
558 | case 32: return "R_PPC_SDAREL,"; | |
559 | case 33: return "R_PPC_SECTOFF,"; | |
560 | case 34: return "R_PPC_SECTOFF_LO,"; | |
561 | case 35: return "R_PPC_SECTOFF_HI,"; | |
562 | case 36: return "R_PPC_SECTOFF_HA,"; | |
563 | case 101: return "R_PPC_EMB_NADDR32,"; | |
564 | case 102: return "R_PPC_EMB_NADDR16,"; | |
565 | case 103: return "R_PPC_EMB_NADDR16_LO,"; | |
566 | case 104: return "R_PPC_EMB_NADDR16_HI,"; | |
567 | case 105: return "R_PPC_EMB_NADDR16_HA,"; | |
568 | case 106: return "R_PPC_EMB_SDAI16,"; | |
569 | case 107: return "R_PPC_EMB_SDA2I16,"; | |
570 | case 108: return "R_PPC_EMB_SDA2REL,"; | |
571 | case 109: return "R_PPC_EMB_SDA21,"; | |
572 | case 110: return "R_PPC_EMB_MRKREF,"; | |
573 | case 111: return "R_PPC_EMB_RELSEC16,"; | |
574 | case 112: return "R_PPC_EMB_RELST_LO,"; | |
575 | case 113: return "R_PPC_EMB_RELST_HI,"; | |
576 | case 114: return "R_PPC_EMB_RELST_HA,"; | |
577 | case 115: return "R_PPC_EMB_BIT_FLD,"; | |
578 | case 116: return "R_PPC_EMB_RELSDA,"; | |
579 | default: return _("*INVALID*"); | |
580 | } | |
581 | } | |
582 | ||
583 | ||
ebb64169 NC |
584 | /* Display the contents of the relocation data |
585 | found at the specified offset. */ | |
76466873 | 586 | static void |
ebb64169 NC |
587 | dump_relocations (file, rel_offset, rel_size, symtab, strtab) |
588 | FILE * file; | |
589 | unsigned long rel_offset; | |
590 | unsigned long rel_size; | |
591 | Elf_Sym * symtab; | |
592 | char * strtab; | |
76466873 | 593 | { |
ebb64169 NC |
594 | unsigned i; |
595 | int is_rela; | |
596 | Elf_Rel * rels; | |
597 | Elf_Rela * relas; | |
76466873 NC |
598 | |
599 | ||
ebb64169 NC |
600 | /* Compute number of relocations and read them in. */ |
601 | switch (elf_header.e_machine) | |
76466873 NC |
602 | { |
603 | case EM_386: | |
604 | case EM_486: | |
605 | case EM_CYGNUS_M32R: | |
606 | case EM_CYGNUS_D10V: | |
ebb64169 NC |
607 | GET_DATA_ALLOC (rel_offset, rel_size, rels, Elf_Rel *, "relocs"); |
608 | ||
76466873 NC |
609 | rel_size = rel_size / sizeof (Elf_Rel); |
610 | ||
611 | if (must_swap) | |
612 | { | |
76466873 NC |
613 | for (i = 0; i < rel_size; i++) |
614 | { | |
ebb64169 NC |
615 | BYTE_SWAP (rels[i], r_offset); |
616 | BYTE_SWAP (rels[i], r_info); | |
76466873 NC |
617 | } |
618 | } | |
619 | ||
620 | is_rela = 0; | |
ebb64169 | 621 | relas = (Elf_Rela *) rels; |
76466873 NC |
622 | break; |
623 | ||
624 | case EM_68K: | |
625 | case EM_SPARC: | |
a09db9ba | 626 | case EM_PPC: |
76466873 | 627 | case EM_CYGNUS_V850: |
2f300fe6 | 628 | /* start-sanitize-d30v */ |
76466873 | 629 | case EM_CYGNUS_D30V: |
2f300fe6 | 630 | /* end-sanitize-d30v */ |
76466873 NC |
631 | case EM_CYGNUS_MN10200: |
632 | case EM_CYGNUS_MN10300: | |
633 | case EM_SH: | |
ebb64169 NC |
634 | GET_DATA_ALLOC (rel_offset, rel_size, relas, Elf_Rela *, "relocs"); |
635 | ||
76466873 NC |
636 | rel_size = rel_size / sizeof (Elf_Rela); |
637 | ||
638 | if (must_swap) | |
639 | { | |
ebb64169 | 640 | for (i = 0; i < rel_size; i++) |
76466873 | 641 | { |
ebb64169 NC |
642 | BYTE_SWAP (relas [i], r_offset); |
643 | BYTE_SWAP (relas [i], r_info); | |
644 | BYTE_SWAP (relas [i], r_addend); | |
76466873 NC |
645 | } |
646 | } | |
647 | ||
648 | is_rela = 1; | |
ebb64169 | 649 | rels = (Elf_Rel *) relas; |
76466873 NC |
650 | break; |
651 | ||
652 | default: | |
653 | warn (_("Don't know about relocations on this machine architecture\n")); | |
654 | return; | |
655 | } | |
656 | ||
657 | if (is_rela) | |
ebb64169 NC |
658 | printf |
659 | (_(" Offset Value Type Symbol's Value Symbol's Name Addend\n")); | |
76466873 | 660 | else |
ebb64169 NC |
661 | printf |
662 | (_(" Offset Value Type Symbol's Value Symbol's Name\n")); | |
76466873 NC |
663 | |
664 | for (i = 0; i < rel_size; i++) | |
665 | { | |
ebb64169 NC |
666 | char * rtype; |
667 | bfd_vma offset; | |
668 | bfd_vma info; | |
669 | int symtab_index; | |
670 | ||
76466873 | 671 | if (is_rela) |
ebb64169 NC |
672 | { |
673 | offset = relas [i].r_offset; | |
674 | info = relas [i].r_info; | |
675 | } | |
676 | else | |
677 | { | |
678 | offset = rels [i].r_offset; | |
679 | info = rels [i].r_info; | |
680 | } | |
76466873 | 681 | |
ebb64169 | 682 | printf (" %8.8lx %5.5lx ", offset, info); |
76466873 | 683 | |
ebb64169 | 684 | switch (elf_header.e_machine) |
76466873 | 685 | { |
c18f8aef | 686 | default: |
ebb64169 | 687 | rtype = "<unknown>"; |
c18f8aef NC |
688 | break; |
689 | ||
76466873 | 690 | case EM_CYGNUS_M32R: |
ebb64169 | 691 | rtype = get_m32r_rel_type (ELF32_R_TYPE (info)); |
76466873 NC |
692 | break; |
693 | ||
694 | case EM_386: | |
695 | case EM_486: | |
ebb64169 | 696 | rtype = get_i386_rel_type (ELF32_R_TYPE (info)); |
76466873 NC |
697 | break; |
698 | ||
699 | case EM_68K: | |
ebb64169 | 700 | rtype = get_m68k_rel_type (ELF32_R_TYPE (info)); |
76466873 NC |
701 | break; |
702 | ||
703 | case EM_SPARC: | |
ebb64169 | 704 | rtype = get_sparc_rel_type (ELF32_R_TYPE (info)); |
76466873 NC |
705 | break; |
706 | ||
707 | case EM_CYGNUS_V850: | |
ebb64169 | 708 | rtype = get_v850_rel_type (ELF32_R_TYPE (info)); |
76466873 NC |
709 | break; |
710 | ||
711 | case EM_CYGNUS_D10V: | |
ebb64169 | 712 | rtype = get_d10v_rel_type (ELF32_R_TYPE (info)); |
76466873 NC |
713 | break; |
714 | ||
2f300fe6 | 715 | /* start-sanitize-d30v */ |
76466873 | 716 | case EM_CYGNUS_D30V: |
ebb64169 | 717 | rtype = get_d30v_rel_type (ELF32_R_TYPE (info)); |
76466873 NC |
718 | break; |
719 | ||
2f300fe6 | 720 | /* end-sanitize-d30v */ |
76466873 | 721 | case EM_SH: |
ebb64169 | 722 | rtype = get_sh_rel_type (ELF32_R_TYPE (info)); |
76466873 NC |
723 | break; |
724 | ||
725 | case EM_CYGNUS_MN10300: | |
ebb64169 | 726 | rtype = get_mn10300_rel_type (ELF32_R_TYPE (info)); |
76466873 NC |
727 | break; |
728 | ||
729 | case EM_CYGNUS_MN10200: | |
ebb64169 | 730 | rtype = get_mn10200_rel_type (ELF32_R_TYPE (info)); |
76466873 | 731 | break; |
a09db9ba MM |
732 | |
733 | case EM_PPC: | |
ebb64169 | 734 | rtype = get_ppc_rel_type (ELF32_R_TYPE (info)); |
a09db9ba | 735 | break; |
76466873 NC |
736 | } |
737 | ||
ebb64169 | 738 | printf ("%-21.21s", rtype); |
76466873 | 739 | |
ebb64169 | 740 | symtab_index = ELF32_R_SYM (info); |
76466873 | 741 | |
ebb64169 | 742 | if (symtab_index && symtab != NULL) |
76466873 | 743 | { |
76466873 | 744 | Elf_Sym * psym; |
ebb64169 | 745 | |
76466873 NC |
746 | psym = symtab + symtab_index; |
747 | ||
ebb64169 NC |
748 | printf (" %08lx ", psym->st_value); |
749 | ||
76466873 | 750 | if (psym->st_name == 0) |
ebb64169 NC |
751 | printf ("%-17.17s", |
752 | SECTION_NAME (section_headers + psym->st_shndx)); | |
753 | else if (strtab == NULL) | |
754 | printf (_("<string table index %d>"), psym->st_name); | |
76466873 | 755 | else |
ebb64169 | 756 | printf ("%-17.17s", strtab + psym->st_name); |
76466873 NC |
757 | |
758 | if (is_rela) | |
ebb64169 | 759 | printf (" + %lx", relas [i].r_addend); |
76466873 NC |
760 | } |
761 | ||
762 | putchar ('\n'); | |
76466873 NC |
763 | } |
764 | ||
ebb64169 NC |
765 | free (relas); |
766 | } | |
767 | ||
768 | static char * | |
769 | get_dynamic_type (type) | |
770 | unsigned long type; | |
771 | { | |
772 | static char buff [32]; | |
773 | ||
774 | switch (type) | |
775 | { | |
776 | case DT_NULL: return _("NULL"); | |
777 | case DT_NEEDED: return _("NEEDED"); | |
778 | case DT_PLTRELSZ: return _("PLTRELSZ"); | |
779 | case DT_PLTGOT: return _("PLTGOT"); | |
780 | case DT_HASH: return _("HASH"); | |
781 | case DT_STRTAB: return _("STRTAB"); | |
782 | case DT_SYMTAB: return _("SYMTAB"); | |
783 | case DT_RELA: return _("RELA"); | |
784 | case DT_RELASZ: return _("RELASZ"); | |
785 | case DT_RELAENT: return _("RELAENT"); | |
786 | case DT_STRSZ: return _("STRSZ"); | |
787 | case DT_SYMENT: return _("SYMENT"); | |
788 | case DT_INIT: return _("INIT"); | |
789 | case DT_FINI: return _("FINI"); | |
790 | case DT_SONAME: return _("SONAME"); | |
791 | case DT_RPATH: return _("RPATH"); | |
792 | case DT_SYMBOLIC: return _("SYMBOLIC"); | |
793 | case DT_REL: return _("REL"); | |
794 | case DT_RELSZ: return _("RELSZ"); | |
795 | case DT_RELENT: return _("RELENT"); | |
796 | case DT_PLTREL: return _("PLTREL"); | |
797 | case DT_DEBUG: return _("DEBUG"); | |
798 | case DT_TEXTREL: return _("TEXTREL"); | |
799 | case DT_JMPREL: return _("JMPREL"); | |
800 | case DT_VERDEF: return _("VERDEF"); | |
801 | case DT_VERDEFNUM: return _("VERDEFNUM"); | |
802 | case DT_VERNEED: return _("VERNEED"); | |
803 | case DT_VERNEEDNUM: return _("VERNEEDNUM"); | |
804 | case DT_VERSYM: return _("VERSYN"); | |
805 | case DT_AUXILIARY: return _("AUXILARY"); | |
806 | case DT_FILTER: return _("FILTER"); | |
807 | ||
808 | default: | |
809 | if ((type >= DT_LOPROC) && (type <= DT_HIPROC)) | |
810 | sprintf (buff, _("Processor Specific: (%x)"), type); | |
811 | else | |
812 | sprintf (buff, _("<unknown>: %x"), type); | |
813 | return buff; | |
814 | } | |
76466873 NC |
815 | } |
816 | ||
817 | static char * | |
818 | get_file_type (e_type) | |
a09db9ba | 819 | unsigned e_type; |
76466873 NC |
820 | { |
821 | static char buff [32]; | |
822 | ||
823 | switch (e_type) | |
824 | { | |
825 | case ET_NONE: return _("None"); | |
826 | case ET_REL: return _("Relocatable file"); | |
827 | case ET_EXEC: return _("Executable file"); | |
828 | case ET_DYN: return _("Shared object file"); | |
829 | case ET_CORE: return _("Core file"); | |
830 | ||
831 | default: | |
832 | if ((e_type >= ET_LOPROC) && (e_type <= ET_HIPROC)) | |
833 | sprintf (buff, _("Processor Specific: (%x)"), e_type); | |
834 | else | |
835 | sprintf (buff, _("<unknown>: %x"), e_type); | |
836 | return buff; | |
837 | } | |
838 | } | |
839 | ||
840 | static char * | |
841 | get_machine_name (e_machine) | |
a09db9ba | 842 | unsigned e_machine; |
76466873 NC |
843 | { |
844 | static char buff [32]; | |
845 | ||
846 | switch (e_machine) | |
847 | { | |
848 | case EM_NONE: return _("None"); | |
849 | case EM_M32: return "WE32100"; | |
850 | case EM_SPARC: return "Sparc"; | |
851 | case EM_386: return "80386"; | |
852 | case EM_68K: return "MC68000"; | |
853 | case EM_88K: return "MC88000"; | |
854 | case EM_486: return "Intel 80486"; | |
855 | case EM_860: return "Intel 80860"; | |
856 | case EM_MIPS: return "MIPS R3000 big-endian"; | |
857 | case EM_S370: return "Amdahl"; | |
858 | case EM_MIPS_RS4_BE: return "MIPS R400 big-endian"; | |
ebb64169 | 859 | case EM_OLD_SPARCV9: return "Sparc v9 (old)"; |
76466873 | 860 | case EM_PARISC: return "HPPA"; |
ebb64169 | 861 | case EM_PPC_OLD: return "Power PC (old)"; |
76466873 | 862 | case EM_SPARC32PLUS: return "Sparc v8+" ; |
ebb64169 | 863 | case EM_960: return "Intel 90860"; |
a09db9ba | 864 | case EM_PPC: return "PowerPC"; |
ebb64169 NC |
865 | case EM_V800: return "NEC V800"; |
866 | case EM_FR20: return "Fujitsu FR20"; | |
867 | case EM_RH32: return "TRW RH32"; | |
868 | case EM_MMA: return "Fujitsu MMA"; | |
76466873 | 869 | case EM_ARM: return "ARM"; |
ebb64169 | 870 | case EM_OLD_ALPHA: return "Digital Alpha (old)"; |
76466873 | 871 | case EM_SH: return "Hitachi SH"; |
ebb64169 | 872 | case EM_SPARCV9: return "Sparc v9"; |
76466873 NC |
873 | case EM_ALPHA: return "Alpha"; |
874 | case EM_CYGNUS_D10V: return "d10v"; | |
2f300fe6 | 875 | /* start-sanitize-d30v */ |
76466873 | 876 | case EM_CYGNUS_D30V: return "d30v"; |
2f300fe6 | 877 | /* end-sanitize-d30v */ |
76466873 NC |
878 | case EM_CYGNUS_M32R: return "M32r"; |
879 | case EM_CYGNUS_V850: return "v850"; | |
880 | case EM_CYGNUS_MN10300: return "mn10300"; | |
881 | case EM_CYGNUS_MN10200: return "mn10200"; | |
882 | ||
883 | default: | |
884 | sprintf (buff, _("<unknown>: %x"), e_machine); | |
885 | return buff; | |
886 | } | |
887 | } | |
888 | ||
a09db9ba MM |
889 | static char * |
890 | get_machine_flags (e_flags, e_machine) | |
891 | unsigned e_flags; | |
892 | unsigned e_machine; | |
893 | { | |
894 | static char buf [1024]; | |
895 | ||
896 | buf[0] = '\0'; | |
897 | if (e_flags) | |
898 | { | |
899 | switch (e_machine) | |
900 | { | |
901 | default: | |
902 | break; | |
903 | ||
904 | case EM_PPC: | |
905 | if (e_flags & EF_PPC_EMB) | |
906 | strcat (buf, ", emb"); | |
907 | ||
908 | if (e_flags & EF_PPC_RELOCATABLE) | |
909 | strcat (buf, ", relocatable"); | |
910 | ||
911 | if (e_flags & EF_PPC_RELOCATABLE_LIB) | |
912 | strcat (buf, ", relocatable-lib"); | |
913 | break; | |
914 | ||
915 | case EM_CYGNUS_M32R: | |
916 | if ((e_flags & EF_M32R_ARCH) == E_M32R_ARCH) | |
917 | strcat (buf, ", m32r"); | |
918 | ||
919 | /* start-sanitize-m32rx */ | |
920 | #ifdef E_M32RX_ARCH | |
921 | if ((e_flags & EF_M32R_ARCH) == E_M32RX_ARCH) | |
922 | strcat (buf, ", m32rx"); | |
923 | #endif | |
924 | /* end-sanitize-m32rx */ | |
925 | break; | |
926 | ||
927 | case EM_MIPS: | |
928 | case EM_MIPS_RS4_BE: | |
929 | if (e_flags & EF_MIPS_NOREORDER) | |
930 | strcat (buf, ", noreorder"); | |
931 | ||
932 | if (e_flags & EF_MIPS_PIC) | |
933 | strcat (buf, ", pic"); | |
934 | ||
935 | if (e_flags & EF_MIPS_CPIC) | |
936 | strcat (buf, ", cpic"); | |
937 | ||
938 | if (e_flags & EF_MIPS_ABI2) | |
939 | strcat (buf, ", abi2"); | |
940 | ||
941 | if ((e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_1) | |
942 | strcat (buf, ", mips1"); | |
943 | ||
944 | if ((e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_2) | |
945 | strcat (buf, ", mips2"); | |
946 | ||
947 | if ((e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_3) | |
948 | strcat (buf, ", mips3"); | |
949 | ||
950 | if ((e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_4) | |
951 | strcat (buf, ", mips4"); | |
952 | break; | |
953 | } | |
954 | } | |
955 | ||
956 | return buf; | |
957 | } | |
958 | ||
959 | static char * | |
960 | get_machine_data (e_data) | |
961 | unsigned e_data; | |
962 | { | |
963 | static char buff [32]; | |
964 | ||
965 | switch (e_data) | |
966 | { | |
967 | case ELFDATA2LSB: return _("ELFDATA2LSB (little endian)"); | |
968 | case ELFDATA2MSB: return _("ELFDATA2MSB (big endian)"); | |
969 | default: | |
970 | sprintf (buff, _("<unknown>: %x"), e_data); | |
971 | return buff; | |
972 | } | |
973 | } | |
974 | ||
76466873 NC |
975 | static char * |
976 | get_segment_type (p_type) | |
977 | unsigned long p_type; | |
978 | { | |
979 | static char buff [32]; | |
980 | ||
981 | switch (p_type) | |
982 | { | |
983 | case PT_NULL: return _("Unused"); | |
984 | case PT_LOAD: return _("Loadable"); | |
985 | case PT_DYNAMIC: return _("Dynamic link info"); | |
986 | case PT_INTERP: return _("Interpreter"); | |
987 | case PT_NOTE: return _("Auxillary Info"); | |
988 | case PT_SHLIB: return _("Shared Library"); | |
ebb64169 | 989 | case PT_PHDR: return _("Program Header"); |
76466873 NC |
990 | |
991 | default: | |
992 | if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) | |
993 | return _("processor specific"); | |
994 | else | |
995 | { | |
996 | sprintf (buff, _("<unknown>: %x"), p_type); | |
997 | return buff; | |
998 | } | |
999 | } | |
1000 | } | |
1001 | ||
1002 | static char * | |
1003 | get_section_type_name (sh_type) | |
1004 | unsigned int sh_type; | |
1005 | { | |
1006 | static char buff [32]; | |
1007 | ||
1008 | switch (sh_type) | |
1009 | { | |
1010 | case SHT_NULL: return _("Unused"); | |
1011 | case SHT_PROGBITS: return _("Program data"); | |
1012 | case SHT_SYMTAB: return _("Symbol table"); | |
1013 | case SHT_STRTAB: return _("String table"); | |
ebb64169 NC |
1014 | case SHT_RELA: return _("Relocations"); |
1015 | case SHT_HASH: return _("Symbol hashes"); | |
1016 | case SHT_DYNAMIC: return _("Dynamic info"); | |
76466873 NC |
1017 | case SHT_NOTE: return _("Notes"); |
1018 | case SHT_NOBITS: return _("Space, no data"); | |
ebb64169 NC |
1019 | case SHT_REL: return _("Relocations"); |
1020 | case SHT_SHLIB: return _("Shared lib info"); | |
1021 | case SHT_DYNSYM: return _("Dynamic symbols"); | |
76466873 NC |
1022 | case SHT_GNU_verdef: return _("Version definition"); |
1023 | case SHT_GNU_verneed: return _("Version needs"); | |
1024 | case SHT_GNU_versym: return _("Version symbols"); | |
1025 | case 0x6ffffff0: return "VERSYM"; | |
1026 | case 0x6ffffffc: return "VERDEF"; | |
1027 | case 0x7ffffffd: return "AUXILIARY"; | |
1028 | case 0x7fffffff: return "FILTER"; | |
1029 | ||
1030 | default: | |
1031 | if ((sh_type >= SHT_LOPROC) && (sh_type <= SHT_HIPROC)) | |
ebb64169 | 1032 | sprintf (buff, _("cpu defined (%d)"), sh_type - SHT_LOPROC); |
76466873 | 1033 | else if ((sh_type >= SHT_LOUSER) && (sh_type <= SHT_HIUSER)) |
ebb64169 | 1034 | sprintf (buff, _("app defined (%d)"), sh_type - SHT_LOUSER); |
76466873 | 1035 | else |
ebb64169 NC |
1036 | sprintf (buff, _("<unknown>: %x"), sh_type); |
1037 | return buff; | |
76466873 NC |
1038 | } |
1039 | } | |
1040 | ||
1041 | struct option options [] = | |
1042 | { | |
1043 | {"all", no_argument, 0, 'a'}, | |
1044 | {"file-header", no_argument, 0, 'h'}, | |
1045 | {"program-headers", no_argument, 0, 'l'}, | |
ebb64169 | 1046 | {"headers", no_argument, 0, 'e'}, |
76466873 NC |
1047 | {"segments", no_argument, 0, 'l'}, |
1048 | {"sections", no_argument, 0, 'S'}, | |
ebb64169 | 1049 | {"section-headers", no_argument, 0, 'S'}, |
76466873 NC |
1050 | {"symbols", no_argument, 0, 's'}, |
1051 | {"relocs", no_argument, 0, 'r'}, | |
1052 | {"dynamic", no_argument, 0, 'd'}, | |
1053 | {"version-info", no_argument, 0, 'V'}, | |
1054 | {"use-dynamic", no_argument, 0, 'D'}, | |
1055 | ||
1056 | {"hex-dump", required_argument, 0, 'x'}, | |
1057 | #ifdef SUPPORT_DISASSEMBLY | |
1058 | {"instruction-dump", required_argument, 0, 'i'}, | |
1059 | #endif | |
1060 | ||
1061 | {"version", no_argument, 0, 'v'}, | |
1062 | {"help", no_argument, 0, 'H'}, | |
1063 | ||
1064 | {0, no_argument, 0, 0} | |
1065 | }; | |
1066 | ||
1067 | static void | |
1068 | usage () | |
1069 | { | |
59bbaa19 ILT |
1070 | fprintf (stdout, _("Usage: readelf {options} elf-file(s)\n")); |
1071 | fprintf (stdout, _(" Options are:\n")); | |
ebb64169 | 1072 | fprintf (stdout, _(" -a or --all Equivalent to: -h -l -S -s -r -d -V\n")); |
59bbaa19 ILT |
1073 | fprintf (stdout, _(" -h or --file-header Display the ELF file header\n")); |
1074 | fprintf (stdout, _(" -l or --program-headers or --segments\n")); | |
1075 | fprintf (stdout, _(" Display the program headers\n")); | |
ebb64169 NC |
1076 | fprintf (stdout, _(" -S or --section-headers or --sections\n")); |
1077 | fprintf (stdout, _(" Display the sections' header\n")); | |
1078 | fprintf (stdout, _(" -e or --headers Equivalent to: -h -l -S\n")); | |
59bbaa19 ILT |
1079 | fprintf (stdout, _(" -s or --symbols Display the symbol table\n")); |
1080 | fprintf (stdout, _(" -r or --relocs Display the relocations (if present)\n")); | |
ebb64169 | 1081 | fprintf (stdout, _(" -d or --dynamic Display the dynamic segment (if present)\n")); |
59bbaa19 ILT |
1082 | fprintf (stdout, _(" -V or --version-info Display the version sections (if present)\n")); |
1083 | fprintf (stdout, _(" -D or --use-dynamic Use the dynamic section info when displaying symbols\n")); | |
1084 | fprintf (stdout, _(" -x <number> or --hex-dump=<number>\n")); | |
1085 | fprintf (stdout, _(" Dump the contents of section <number>\n")); | |
76466873 | 1086 | #ifdef SUPPORT_DISASSEMBLY |
59bbaa19 ILT |
1087 | fprintf (stdout, _(" -i <number> or --instruction-dump=<number>\n")); |
1088 | fprintf (stdout, _(" Disassemble the contents of section <number>\n")); | |
76466873 | 1089 | #endif |
59bbaa19 ILT |
1090 | fprintf (stdout, _(" -v or --version Display the version number of readelf\n")); |
1091 | fprintf (stdout, _(" -H or --help Display this information\n")); | |
1092 | fprintf (stdout, _("Report bugs to bug-gnu-utils@gnu.org\n")); | |
76466873 NC |
1093 | |
1094 | exit (0); | |
1095 | } | |
1096 | ||
1097 | static void | |
1098 | parse_args (argc, argv) | |
1099 | int argc; | |
1100 | char ** argv; | |
1101 | { | |
59bbaa19 | 1102 | int c; |
ebb64169 | 1103 | |
76466873 NC |
1104 | if (argc < 2) |
1105 | usage (); | |
1106 | ||
1107 | while ((c = getopt_long | |
ebb64169 | 1108 | (argc, argv, "ersahldSDx:i:vV", options, NULL)) != EOF) |
76466873 NC |
1109 | { |
1110 | char * cp; | |
1111 | int section; | |
1112 | ||
1113 | switch (c) | |
1114 | { | |
1115 | case 'H': | |
1116 | usage (); | |
1117 | break; | |
1118 | ||
1119 | case 'a': | |
ebb64169 NC |
1120 | do_syms ++; |
1121 | do_reloc ++; | |
1122 | do_dynamic ++; | |
1123 | do_header ++; | |
1124 | do_sections ++; | |
1125 | do_segments ++; | |
1126 | do_version ++; | |
1127 | break; | |
1128 | case 'e': | |
1129 | do_header ++; | |
1130 | do_sections ++; | |
1131 | do_segments ++; | |
76466873 NC |
1132 | break; |
1133 | case 'D': | |
ebb64169 | 1134 | do_using_dynamic ++; |
76466873 NC |
1135 | break; |
1136 | case 'r': | |
ebb64169 | 1137 | do_reloc ++; |
76466873 NC |
1138 | break; |
1139 | case 'h': | |
ebb64169 | 1140 | do_header ++; |
76466873 NC |
1141 | break; |
1142 | case 'l': | |
ebb64169 | 1143 | do_segments ++; |
76466873 NC |
1144 | break; |
1145 | case 's': | |
ebb64169 | 1146 | do_syms ++; |
76466873 NC |
1147 | break; |
1148 | case 'S': | |
ebb64169 | 1149 | do_sections ++; |
76466873 NC |
1150 | break; |
1151 | case 'd': | |
ebb64169 | 1152 | do_dynamic ++; |
76466873 NC |
1153 | break; |
1154 | case 'x': | |
1155 | do_dump ++; | |
1156 | section = strtoul (optarg, & cp, 0); | |
1157 | if (! * cp && section >= 0 && section < NUM_DUMP_SECTS) | |
1158 | { | |
1159 | dump_sects [section] |= HEX_DUMP; | |
1160 | break; | |
1161 | } | |
1162 | goto oops; | |
1163 | #ifdef SUPPORT_DISASSEMBLY | |
1164 | case 'i': | |
1165 | do_dump ++; | |
1166 | section = strtoul (optarg, & cp, 0); | |
1167 | if (! * cp && section >= 0 && section < NUM_DUMP_SECTS) | |
1168 | { | |
1169 | dump_sects [section] |= DISASS_DUMP; | |
1170 | break; | |
1171 | } | |
1172 | goto oops; | |
1173 | #endif | |
1174 | case 'v': | |
1175 | print_version (program_name); | |
1176 | break; | |
1177 | case 'V': | |
1178 | do_version ++; | |
1179 | break; | |
1180 | default: | |
1181 | oops: | |
1182 | /* xgettext:c-format */ | |
1183 | error (_("Invalid option '-%c'\n"), c); | |
1184 | /* Drop through. */ | |
1185 | case '?': | |
1186 | usage (); | |
1187 | } | |
1188 | } | |
1189 | ||
ebb64169 NC |
1190 | if (!do_dynamic && !do_syms && !do_reloc && !do_sections |
1191 | && !do_segments && !do_header && !do_dump && !do_version) | |
76466873 NC |
1192 | usage (); |
1193 | else if (argc < 3) | |
59bbaa19 ILT |
1194 | { |
1195 | warn (_("Nothing to do.\n")); | |
1196 | usage(); | |
1197 | } | |
76466873 NC |
1198 | } |
1199 | ||
ebb64169 | 1200 | /* Decode the data held in 'elf_header'. */ |
76466873 | 1201 | static int |
ebb64169 | 1202 | process_file_header () |
76466873 | 1203 | { |
ebb64169 NC |
1204 | if ( elf_header.e_ident [EI_MAG0] != ELFMAG0 |
1205 | || elf_header.e_ident [EI_MAG1] != ELFMAG1 | |
1206 | || elf_header.e_ident [EI_MAG2] != ELFMAG2 | |
1207 | || elf_header.e_ident [EI_MAG3] != ELFMAG3) | |
76466873 | 1208 | { |
ebb64169 NC |
1209 | error |
1210 | (_("Not an ELF file - it has the wrong magic bytes at the start\n")); | |
76466873 NC |
1211 | return 0; |
1212 | } | |
1213 | ||
ebb64169 | 1214 | if (elf_header.e_ident [EI_CLASS] != ELFCLASS32) |
76466873 NC |
1215 | { |
1216 | error (_("Not a 32 bit ELF file\n")); | |
1217 | return 0; | |
1218 | } | |
1219 | ||
ebb64169 | 1220 | if (elf_header.e_ident [EI_DATA] != expected_endian) |
76466873 | 1221 | { |
ebb64169 NC |
1222 | must_swap = 1; |
1223 | ||
1224 | BYTE_SWAP (elf_header, e_type); | |
1225 | BYTE_SWAP (elf_header, e_machine); | |
1226 | BYTE_SWAP (elf_header, e_version); | |
1227 | BYTE_SWAP (elf_header, e_entry); | |
1228 | BYTE_SWAP (elf_header, e_phoff); | |
1229 | BYTE_SWAP (elf_header, e_shoff); | |
1230 | BYTE_SWAP (elf_header, e_flags); | |
1231 | BYTE_SWAP (elf_header, e_ehsize); | |
1232 | BYTE_SWAP (elf_header, e_phentsize); | |
1233 | BYTE_SWAP (elf_header, e_phnum); | |
1234 | BYTE_SWAP (elf_header, e_shentsize); | |
1235 | BYTE_SWAP (elf_header, e_shnum); | |
1236 | BYTE_SWAP (elf_header, e_shstrndx); | |
76466873 NC |
1237 | } |
1238 | ||
1239 | if (do_header) | |
1240 | { | |
1241 | int i; | |
1242 | ||
ebb64169 NC |
1243 | printf (_("ELF Header:\n")); |
1244 | printf (_(" Magic: ")); | |
76466873 | 1245 | for (i = 0; i < EI_NIDENT; i ++) |
ebb64169 | 1246 | printf ("%2.2x ", elf_header.e_ident [i]); |
76466873 | 1247 | printf ("\n"); |
ebb64169 NC |
1248 | printf (_(" Type: %s\n"), |
1249 | get_file_type (elf_header.e_type)); | |
1250 | printf (_(" Machine: %s\n"), | |
1251 | get_machine_name (elf_header.e_machine)); | |
1252 | printf (_(" Version: 0x%lx\n"), | |
1253 | (unsigned long) elf_header.e_version); | |
1254 | ||
1255 | printf (_(" Data: %s"), | |
1256 | get_machine_data (elf_header.e_ident [EI_DATA])); | |
1257 | if (must_swap) | |
1258 | printf (_(" [byte swapping]")); | |
1259 | putchar ('\n'); | |
1260 | ||
1261 | printf (_(" Entry point address: 0x%lx\n"), | |
1262 | (unsigned long) elf_header.e_entry); | |
1263 | printf (_(" Start of program headers: %ld (bytes into file)\n"), | |
1264 | (long) elf_header.e_phoff); | |
1265 | printf (_(" Start of section headers: %ld (bytes into file)\n"), | |
1266 | (long) elf_header.e_shoff); | |
1267 | printf (_(" Flags: 0x%lx%s\n"), | |
1268 | (unsigned long) elf_header.e_flags, | |
1269 | get_machine_flags (elf_header.e_flags, elf_header.e_machine)); | |
1270 | printf (_(" Size of this header: %ld (bytes)\n"), | |
1271 | (long) elf_header.e_ehsize); | |
1272 | printf (_(" Size of program headers: %ld (bytes)\n"), | |
1273 | (long) elf_header.e_phentsize); | |
1274 | printf (_(" Number of program headers: %ld\n"), | |
1275 | (long) elf_header.e_phnum); | |
1276 | printf (_(" Size of section headers: %ld (bytes)\n"), | |
1277 | (long) elf_header.e_shentsize); | |
1278 | printf (_(" Number of section headers: %ld\n"), | |
1279 | (long) elf_header.e_shnum); | |
1280 | printf (_(" Section header string table index: %ld\n"), | |
1281 | (long) elf_header.e_shstrndx); | |
76466873 NC |
1282 | } |
1283 | ||
1284 | return 1; | |
1285 | } | |
1286 | ||
1287 | ||
1288 | static void | |
ebb64169 NC |
1289 | process_program_headers (file) |
1290 | FILE * file; | |
76466873 | 1291 | { |
ebb64169 NC |
1292 | Elf_Phdr * program_headers; |
1293 | Elf_Phdr * segment; | |
1294 | int i; | |
76466873 | 1295 | |
ebb64169 | 1296 | if (elf_header.e_phnum == 0) |
76466873 | 1297 | { |
ebb64169 NC |
1298 | if (do_segments) |
1299 | printf (_("\nThere are no program headers in this file.\n")); | |
76466873 NC |
1300 | return; |
1301 | } | |
1302 | ||
ebb64169 | 1303 | if (do_segments && !do_header) |
76466873 | 1304 | { |
ebb64169 NC |
1305 | printf (_("\nElf file is %s\n"), get_file_type (elf_header.e_type)); |
1306 | printf (_("Entry point 0x%x\n"), elf_header.e_entry); | |
76466873 | 1307 | printf (_("There are %d program headers, starting at offset %x:\n"), |
ebb64169 | 1308 | elf_header.e_phnum, elf_header.e_phoff); |
76466873 NC |
1309 | } |
1310 | ||
ebb64169 NC |
1311 | GET_DATA_ALLOC (elf_header.e_phoff, elf_header.e_phentsize * elf_header.e_phnum, |
1312 | program_headers, Elf_Phdr *, "program headers"); | |
1313 | ||
76466873 NC |
1314 | if (must_swap) |
1315 | { | |
ebb64169 | 1316 | for (i = 0; i < elf_header.e_phnum; i++) |
76466873 | 1317 | { |
ebb64169 NC |
1318 | BYTE_SWAP (program_headers [i], p_type); |
1319 | BYTE_SWAP (program_headers [i], p_flags); | |
1320 | BYTE_SWAP (program_headers [i], p_offset); | |
1321 | BYTE_SWAP (program_headers [i], p_vaddr); | |
1322 | BYTE_SWAP (program_headers [i], p_paddr); | |
1323 | BYTE_SWAP (program_headers [i], p_filesz); | |
1324 | BYTE_SWAP (program_headers [i], p_memsz); | |
1325 | BYTE_SWAP (program_headers [i], p_align); | |
76466873 NC |
1326 | } |
1327 | } | |
76466873 | 1328 | |
ebb64169 | 1329 | if (do_segments) |
76466873 | 1330 | { |
ebb64169 NC |
1331 | printf |
1332 | (_("\nProgram Header%s:\n"), elf_header.e_phnum > 1 ? "s" : ""); | |
1333 | printf | |
1334 | (_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n")); | |
76466873 NC |
1335 | } |
1336 | ||
1337 | loadaddr = -1; | |
1338 | dynamic_addr = 0; | |
1339 | ||
ebb64169 | 1340 | for (i = 0; i < elf_header.e_phnum; i++) |
76466873 | 1341 | { |
ebb64169 | 1342 | segment = program_headers + i; |
76466873 | 1343 | |
ebb64169 | 1344 | if (do_segments) |
76466873 | 1345 | { |
ebb64169 NC |
1346 | printf (" %-16.16s ", get_segment_type (segment->p_type)); |
1347 | printf ("0x%5.5lx ", segment->p_offset); | |
1348 | printf ("0x%8.8lx ", segment->p_vaddr); | |
1349 | printf ("0x%8.8lx ", segment->p_paddr); | |
1350 | printf ("0x%5.5lx 0x%5.5lx ", segment->p_filesz, segment->p_memsz); | |
76466873 | 1351 | printf ("%c%c%c ", |
ebb64169 NC |
1352 | (segment->p_flags & PF_R ? 'R' : ' '), |
1353 | (segment->p_flags & PF_W ? 'W' : ' '), | |
1354 | (segment->p_flags & PF_X ? 'E' : ' ')); | |
1355 | printf ("%#lx", segment->p_align); | |
76466873 | 1356 | } |
ebb64169 NC |
1357 | |
1358 | switch (segment->p_type) | |
76466873 | 1359 | { |
ebb64169 NC |
1360 | case PT_LOAD: |
1361 | if (loadaddr == -1) | |
1362 | loadaddr = (segment->p_vaddr & 0xfffff000) | |
1363 | - (segment->p_offset & 0xfffff000); | |
1364 | break; | |
1365 | ||
1366 | case PT_DYNAMIC: | |
76466873 | 1367 | if (dynamic_addr) |
ebb64169 | 1368 | error (_("more than one dynamic segment\n")); |
76466873 | 1369 | |
ebb64169 NC |
1370 | dynamic_addr = segment->p_offset; |
1371 | dynamic_size = segment->p_filesz; | |
1372 | break; | |
1373 | ||
1374 | case PT_INTERP: | |
1375 | if (fseek (file, segment->p_offset, SEEK_SET)) | |
1376 | error (_("Unable to find program interpreter name\n")); | |
1377 | else | |
1378 | { | |
1379 | program_interpreter[0] = 0; | |
1380 | fscanf (file, "%63s", program_interpreter); | |
1381 | ||
1382 | if (do_segments) | |
1383 | printf (_("\n [Requesting program interpreter: %s]"), | |
1384 | program_interpreter); | |
1385 | } | |
1386 | break; | |
76466873 NC |
1387 | } |
1388 | ||
ebb64169 | 1389 | if (do_segments) |
76466873 | 1390 | putc ('\n', stdout); |
76466873 NC |
1391 | } |
1392 | ||
ebb64169 NC |
1393 | if (loadaddr == -1) |
1394 | { | |
1395 | /* Very strange. */ | |
1396 | loadaddr = 0; | |
1397 | } | |
1398 | ||
1399 | if (do_segments && section_headers != NULL) | |
76466873 NC |
1400 | { |
1401 | printf (_("\n Section to Segment mapping:\n")); | |
1402 | printf (_(" Segment Sections...\n")); | |
1403 | ||
ebb64169 NC |
1404 | assert (string_table != NULL); |
1405 | ||
1406 | for (i = 0; i < elf_header.e_phnum; i++) | |
76466873 | 1407 | { |
ebb64169 NC |
1408 | int j; |
1409 | Elf_Shdr * section; | |
1410 | ||
1411 | segment = program_headers + i; | |
1412 | section = section_headers; | |
76466873 NC |
1413 | |
1414 | printf (" %2.2d ", i); | |
1415 | ||
ebb64169 | 1416 | for (j = 0; j < elf_header.e_shnum; j++, section ++) |
76466873 | 1417 | { |
ebb64169 NC |
1418 | if (section->sh_size > 0 |
1419 | /* Compare allocated sections by VMA, unallocated | |
1420 | sections by file offset. */ | |
1421 | && (section->sh_flags & SHF_ALLOC | |
1422 | ? (section->sh_addr >= segment->p_vaddr | |
1423 | && section->sh_addr + section->sh_size | |
1424 | <= segment->p_vaddr + segment->p_memsz) | |
1425 | : (section->sh_offset >= segment->p_offset | |
1426 | && (section->sh_offset + section->sh_size | |
1427 | <= segment->p_offset + segment->p_filesz)))) | |
1428 | printf ("%s ", SECTION_NAME (section)); | |
76466873 NC |
1429 | } |
1430 | ||
1431 | putc ('\n',stdout); | |
1432 | } | |
1433 | } | |
1434 | ||
ebb64169 | 1435 | free (program_headers); |
76466873 NC |
1436 | } |
1437 | ||
1438 | ||
1439 | static void | |
ebb64169 NC |
1440 | process_section_headers (file) |
1441 | FILE * file; | |
76466873 | 1442 | { |
ebb64169 NC |
1443 | Elf_Shdr * section; |
1444 | int i; | |
76466873 | 1445 | |
ebb64169 NC |
1446 | if (elf_header.e_shnum == 0) |
1447 | { | |
1448 | if (do_sections) | |
1449 | printf (_("\nThere are no sections in this file.\n")); | |
1450 | ||
1451 | section_headers = NULL; | |
1452 | return; | |
1453 | } | |
1454 | ||
1455 | if (do_sections && !do_header) | |
1456 | printf (_("There are %d section headers, starting at offset %x:\n"), | |
1457 | elf_header.e_shnum, elf_header.e_shoff); | |
1458 | ||
1459 | GET_DATA_ALLOC (elf_header.e_shoff, | |
1460 | elf_header.e_shentsize * elf_header.e_shnum, | |
1461 | section_headers, Elf_Shdr *, "section headers"); | |
1462 | ||
76466873 NC |
1463 | if (must_swap) |
1464 | { | |
ebb64169 | 1465 | for (i = 0; i < elf_header.e_shnum; i++) |
76466873 | 1466 | { |
ebb64169 NC |
1467 | BYTE_SWAP (section_headers [i], sh_name); |
1468 | BYTE_SWAP (section_headers [i], sh_type); | |
1469 | BYTE_SWAP (section_headers [i], sh_flags); | |
1470 | BYTE_SWAP (section_headers [i], sh_addr); | |
1471 | BYTE_SWAP (section_headers [i], sh_offset); | |
1472 | BYTE_SWAP (section_headers [i], sh_size); | |
1473 | BYTE_SWAP (section_headers [i], sh_link); | |
1474 | BYTE_SWAP (section_headers [i], sh_info); | |
1475 | BYTE_SWAP (section_headers [i], sh_addralign); | |
1476 | BYTE_SWAP (section_headers [i], sh_entsize); | |
76466873 | 1477 | } |
ebb64169 NC |
1478 | } |
1479 | ||
1480 | /* Read in the string table, so that we have names to display. */ | |
1481 | section = section_headers + elf_header.e_shstrndx; | |
1482 | ||
1483 | if (section->sh_size != 0) | |
1484 | { | |
1485 | unsigned long string_table_offset; | |
76466873 | 1486 | |
ebb64169 NC |
1487 | string_table_offset = section->sh_offset; |
1488 | ||
1489 | GET_DATA_ALLOC (section->sh_offset, section->sh_size, | |
1490 | string_table, char *, "string table"); | |
1491 | } | |
1492 | ||
1493 | /* Scan the sections for the dynamic symbol table | |
1494 | and dynamic string table. */ | |
1495 | dynamic_symbols = NULL; | |
1496 | dynamic_strings = NULL; | |
1497 | for (i = 0, section = section_headers; | |
1498 | i < elf_header.e_shnum; | |
1499 | i ++, section ++) | |
1500 | { | |
1501 | if (section->sh_type == SHT_DYNSYM) | |
1502 | { | |
1503 | if (dynamic_symbols != NULL) | |
1504 | { | |
1505 | error (_("File contains multiple dynamic symbol tables\n")); | |
1506 | continue; | |
1507 | } | |
1508 | ||
1509 | GET_DATA_ALLOC (section->sh_offset, section->sh_size, | |
1510 | dynamic_symbols, Elf_Sym *, "dynamic symbols"); | |
1511 | ||
1512 | if (must_swap) | |
1513 | { | |
1514 | Elf_Sym * psym; | |
1515 | ||
1516 | for (i = 0, psym = dynamic_symbols; | |
1517 | i < section->sh_size / section->sh_entsize; | |
1518 | i ++, psym ++) | |
1519 | { | |
1520 | BYTE_SWAP (* psym, st_name); | |
1521 | BYTE_SWAP (* psym, st_value); | |
1522 | BYTE_SWAP (* psym, st_size); | |
1523 | BYTE_SWAP (* psym, st_shndx); | |
1524 | } | |
1525 | } | |
1526 | } | |
1527 | else if (section->sh_type == SHT_STRTAB | |
1528 | && strcmp (SECTION_NAME (section), ".dynstr") == 0) | |
76466873 | 1529 | { |
ebb64169 NC |
1530 | if (dynamic_strings != NULL) |
1531 | { | |
1532 | error (_("File contains multiple dynamic string tables\n")); | |
1533 | continue; | |
1534 | } | |
76466873 | 1535 | |
ebb64169 NC |
1536 | GET_DATA_ALLOC (section->sh_offset, section->sh_size, |
1537 | dynamic_strings, char *, "dynamic strings"); | |
76466873 NC |
1538 | } |
1539 | } | |
ebb64169 NC |
1540 | |
1541 | if (! do_sections) | |
76466873 NC |
1542 | return; |
1543 | ||
ebb64169 NC |
1544 | printf (_("\nSection Header%s:\n"), elf_header.e_shnum > 1 ? "s" : ""); |
1545 | printf | |
1546 | (_(" [Nr] Name Type Addr Off Size ES Flg Lk In Al\n")); | |
76466873 | 1547 | |
ebb64169 NC |
1548 | for (i = 0, section = section_headers; |
1549 | i < elf_header.e_shnum; | |
1550 | i ++, section ++) | |
76466873 | 1551 | { |
ebb64169 | 1552 | printf (" [%2d] %-17.17s", i, SECTION_NAME (section)); |
76466873 | 1553 | |
ebb64169 | 1554 | printf (" %-15.15s ",get_section_type_name (section->sh_type)); |
c18f8aef | 1555 | printf ( "%8.8lx %6.6lx %6.6lx %2.2lx", |
ebb64169 NC |
1556 | section->sh_addr, |
1557 | section->sh_offset, | |
1558 | section->sh_size, | |
1559 | section->sh_entsize); | |
76466873 | 1560 | |
c18f8aef | 1561 | printf (" %c%c%c %2ld %2lx %ld \n", |
ebb64169 NC |
1562 | (section->sh_flags & SHF_WRITE ? 'W' : ' '), |
1563 | (section->sh_flags & SHF_ALLOC ? 'A' : ' '), | |
1564 | (section->sh_flags & SHF_EXECINSTR ? 'X' : ' '), | |
1565 | section->sh_link, | |
1566 | section->sh_info, | |
1567 | section->sh_addralign); | |
76466873 NC |
1568 | } |
1569 | } | |
1570 | ||
ebb64169 | 1571 | /* Process the reloc section. */ |
76466873 | 1572 | static void |
ebb64169 NC |
1573 | process_relocs (file) |
1574 | FILE * file; | |
76466873 | 1575 | { |
ebb64169 NC |
1576 | unsigned long rel_size; |
1577 | unsigned long rel_offset; | |
76466873 | 1578 | |
ebb64169 NC |
1579 | |
1580 | if (!do_reloc) | |
1581 | return; | |
1582 | ||
1583 | if (do_using_dynamic) | |
76466873 | 1584 | { |
ebb64169 NC |
1585 | rel_size = 0; |
1586 | rel_offset = 0; | |
76466873 | 1587 | |
ebb64169 | 1588 | if (dynamic_info [DT_REL]) |
76466873 | 1589 | { |
ebb64169 NC |
1590 | rel_offset = dynamic_info [DT_REL]; |
1591 | rel_size = dynamic_info [DT_RELSZ]; | |
76466873 | 1592 | } |
ebb64169 | 1593 | else if (dynamic_info [DT_RELA]) |
76466873 | 1594 | { |
ebb64169 NC |
1595 | rel_offset = dynamic_info [DT_RELA]; |
1596 | rel_size = dynamic_info [DT_RELASZ]; | |
1597 | } | |
1598 | else if (dynamic_info [DT_JMPREL]) | |
1599 | { | |
1600 | rel_offset = dynamic_info [DT_JMPREL]; | |
1601 | rel_size = dynamic_info [DT_PLTRELSZ]; | |
1602 | } | |
1603 | ||
1604 | if (rel_size) | |
1605 | { | |
1606 | printf (_("\nRelocation section at offset 0x%x contains %d bytes:\n"), | |
1607 | rel_offset, rel_size); | |
76466873 | 1608 | |
ebb64169 NC |
1609 | dump_relocations (file, rel_offset - loadaddr, rel_size, |
1610 | dynamic_symbols, dynamic_strings); | |
76466873 | 1611 | } |
ebb64169 NC |
1612 | else |
1613 | printf (_("\nThere are no dynamic relocations in this file.\n")); | |
76466873 NC |
1614 | } |
1615 | else | |
1616 | { | |
ebb64169 NC |
1617 | Elf_Shdr * section; |
1618 | unsigned long i; | |
1619 | int found = 0; | |
1620 | ||
1621 | assert (string_table != NULL); | |
1622 | ||
1623 | for (i = 0, section = section_headers; | |
1624 | i < elf_header.e_shnum; | |
1625 | i++, section ++) | |
1626 | { | |
1627 | if ( section->sh_type != SHT_RELA | |
1628 | && section->sh_type != SHT_REL) | |
1629 | continue; | |
1630 | ||
1631 | rel_offset = section->sh_offset; | |
1632 | rel_size = section->sh_size; | |
1633 | ||
1634 | if (rel_size) | |
1635 | { | |
1636 | Elf_Shdr * strsec; | |
1637 | Elf_Shdr * symsec; | |
1638 | Elf_Sym * symtab; | |
1639 | char * strtab; | |
1640 | ||
1641 | printf (_("\nRelocation section '%s' at offset 0x%x contains %d entries:\n"), | |
1642 | SECTION_NAME (section), rel_offset, | |
1643 | rel_size / section->sh_entsize); | |
1644 | ||
1645 | symsec = section_headers + section->sh_link; | |
1646 | ||
1647 | GET_DATA_ALLOC (symsec->sh_offset, symsec->sh_size, symtab, | |
1648 | Elf_Sym *, "symbols"); | |
1649 | ||
1650 | if (must_swap) | |
1651 | { | |
1652 | unsigned int si; | |
1653 | ||
1654 | for (si = 0; | |
1655 | si < symsec->sh_size / symsec->sh_entsize; | |
1656 | si ++) | |
1657 | { | |
1658 | BYTE_SWAP (symtab [si], st_name); | |
1659 | BYTE_SWAP (symtab [si], st_value); | |
1660 | BYTE_SWAP (symtab [si], st_size); | |
1661 | BYTE_SWAP (symtab [si], st_shndx); | |
1662 | } | |
1663 | } | |
1664 | ||
1665 | strsec = section_headers + symsec->sh_link; | |
1666 | ||
1667 | GET_DATA_ALLOC (strsec->sh_offset, strsec->sh_size, strtab, | |
1668 | char *, "string table"); | |
1669 | ||
1670 | dump_relocations (file, rel_offset, rel_size, symtab, strtab); | |
1671 | ||
1672 | free (strtab); | |
1673 | free (symtab); | |
1674 | ||
1675 | found = 1; | |
1676 | } | |
1677 | } | |
1678 | ||
1679 | if (! found) | |
1680 | printf (_("\nThere are no relocations in this file.\n")); | |
76466873 | 1681 | } |
ebb64169 | 1682 | } |
76466873 | 1683 | |
ebb64169 NC |
1684 | |
1685 | /* Parse the dynamic segment */ | |
1686 | static void | |
1687 | process_dynamic_segment (file) | |
1688 | FILE * file; | |
1689 | { | |
1690 | Elf_Dyn * dynamic_segment; | |
1691 | Elf_Dyn * entry; | |
1692 | unsigned int i; | |
76466873 | 1693 | |
ebb64169 | 1694 | if (dynamic_size == 0) |
76466873 | 1695 | { |
ebb64169 NC |
1696 | if (do_dynamic) |
1697 | printf (_("\nThere is no dynamic segment in this file.\n")); | |
1698 | ||
1699 | return; | |
1700 | } | |
1701 | ||
1702 | GET_DATA_ALLOC (dynamic_addr, dynamic_size, | |
1703 | dynamic_segment, Elf_Dyn *, "dynamic segment"); | |
1704 | ||
1705 | dynamic_size = dynamic_size / sizeof (Elf_Dyn); | |
76466873 | 1706 | |
ebb64169 | 1707 | if (must_swap) |
76466873 | 1708 | { |
ebb64169 | 1709 | for (i = 0; i < dynamic_size; i++) |
76466873 | 1710 | { |
ebb64169 NC |
1711 | BYTE_SWAP (dynamic_segment [i], d_tag); |
1712 | BYTE_SWAP (dynamic_segment [i], d_un.d_val); | |
1713 | } | |
1714 | } | |
76466873 | 1715 | |
ebb64169 NC |
1716 | /* Find the appropriate symbol table. */ |
1717 | if (dynamic_symbols == NULL) | |
1718 | { | |
1719 | for (i = 0, entry = dynamic_segment; | |
1720 | i < dynamic_size; | |
1721 | ++i, ++ entry) | |
1722 | { | |
1723 | unsigned long offset; | |
1724 | long num_syms; | |
1725 | ||
1726 | if (entry->d_tag != DT_SYMTAB) | |
1727 | continue; | |
1728 | ||
1729 | dynamic_info [DT_SYMTAB] = entry->d_un.d_val; | |
1730 | ||
1731 | /* Since we do not know how big the symbol table is, | |
1732 | we default to reading in the entire file (!) and | |
1733 | processing that. This is overkill, I know, but it | |
1734 | should work. */ | |
1735 | ||
1736 | offset = entry->d_un.d_val - loadaddr; | |
1737 | if (fseek (file, 0, SEEK_END)) | |
1738 | error (_("Unable to seek to end of file!")); | |
1739 | ||
1740 | num_syms = (ftell (file) - offset) / sizeof (Elf_Sym); | |
1741 | ||
1742 | if (num_syms < 1) | |
1743 | { | |
1744 | error (_("Unable to determine the number of symbols to load\n")); | |
1745 | continue; | |
1746 | } | |
1747 | ||
1748 | GET_DATA_ALLOC (offset, num_syms * sizeof (Elf_Sym), | |
1749 | dynamic_symbols, Elf_Sym *, "dynamic symbols"); | |
1750 | ||
1751 | if (must_swap) | |
1752 | { | |
1753 | Elf_Sym * psym; | |
1754 | ||
1755 | for (i = 0, psym = dynamic_symbols; | |
1756 | i < num_syms; | |
1757 | i ++, psym ++) | |
1758 | { | |
1759 | BYTE_SWAP (* psym, st_name); | |
1760 | BYTE_SWAP (* psym, st_value); | |
1761 | BYTE_SWAP (* psym, st_size); | |
1762 | BYTE_SWAP (* psym, st_shndx); | |
1763 | } | |
1764 | } | |
1765 | ||
1766 | break; | |
1767 | } | |
1768 | } | |
1769 | ||
1770 | /* Similarly find a string table. */ | |
1771 | if (dynamic_strings == NULL) | |
1772 | { | |
1773 | for (i = 0, entry = dynamic_segment; | |
1774 | i < dynamic_size; | |
1775 | ++i, ++ entry) | |
1776 | { | |
1777 | unsigned long offset; | |
1778 | long str_tab_len; | |
1779 | ||
1780 | if (entry->d_tag != DT_STRTAB) | |
1781 | continue; | |
1782 | ||
1783 | dynamic_info [DT_STRTAB] = entry->d_un.d_val; | |
1784 | ||
1785 | /* Since we do not know how big the string table is, | |
1786 | we default to reading in the entire file (!) and | |
1787 | processing that. This is overkill, I know, but it | |
1788 | should work. */ | |
1789 | ||
1790 | offset = entry->d_un.d_val - loadaddr; | |
1791 | if (fseek (file, 0, SEEK_END)) | |
1792 | error (_("Unable to seek to end of file\n")); | |
1793 | str_tab_len = ftell (file) - offset; | |
1794 | ||
1795 | if (str_tab_len < 1) | |
1796 | { | |
1797 | error (_("Unable to determine the length of the dynamic string table\n")); | |
1798 | continue; | |
1799 | } | |
1800 | ||
1801 | GET_DATA_ALLOC (offset, str_tab_len, dynamic_strings, char *, | |
1802 | "dynamic string table"); | |
1803 | ||
1804 | break; | |
1805 | } | |
1806 | } | |
1807 | ||
1808 | if (do_dynamic && dynamic_addr) | |
1809 | printf (_("\nDynamic segement at offset 0x%x contains %d entries:\n"), | |
1810 | dynamic_addr, dynamic_size); | |
1811 | if (do_dynamic) | |
1812 | printf (_(" Tag Type Name/Value\n")); | |
1813 | ||
1814 | for (i = 0, entry = dynamic_segment; | |
1815 | i < dynamic_size; | |
1816 | i++, entry ++) | |
1817 | { | |
1818 | if (do_dynamic) | |
1819 | printf (_(" 0x%-6.6x (%-11.11s) "), | |
1820 | entry->d_tag, | |
1821 | get_dynamic_type (entry->d_tag)); | |
1822 | ||
1823 | switch (entry->d_tag) | |
1824 | { | |
1825 | case DT_AUXILIARY: | |
1826 | case DT_FILTER: | |
1827 | if (do_dynamic) | |
1828 | { | |
1829 | if (entry->d_tag == DT_AUXILIARY) | |
1830 | printf (_("Auxiliary library")); | |
1831 | else | |
1832 | printf (_("Filter library")); | |
1833 | ||
1834 | if (dynamic_strings) | |
1835 | printf (": [%s]\n", dynamic_strings + entry->d_un.d_val); | |
1836 | else | |
1837 | printf (": %#lx\n", entry->d_un.d_val); | |
1838 | } | |
1839 | break; | |
76466873 NC |
1840 | |
1841 | case DT_NULL : | |
1842 | case DT_NEEDED : | |
1843 | case DT_PLTRELSZ: | |
1844 | case DT_PLTGOT : | |
1845 | case DT_HASH : | |
1846 | case DT_STRTAB : | |
1847 | case DT_SYMTAB : | |
1848 | case DT_RELA : | |
1849 | case DT_RELASZ : | |
1850 | case DT_RELAENT : | |
1851 | case DT_STRSZ : | |
1852 | case DT_SYMENT : | |
1853 | case DT_INIT : | |
1854 | case DT_FINI : | |
1855 | case DT_SONAME : | |
1856 | case DT_RPATH : | |
1857 | case DT_SYMBOLIC: | |
1858 | case DT_REL : | |
1859 | case DT_RELSZ : | |
1860 | case DT_RELENT : | |
1861 | case DT_PLTREL : | |
1862 | case DT_DEBUG : | |
1863 | case DT_TEXTREL : | |
1864 | case DT_JMPREL : | |
ebb64169 | 1865 | dynamic_info [entry->d_tag] = entry->d_un.d_val; |
76466873 NC |
1866 | |
1867 | if (do_dynamic) | |
1868 | { | |
ebb64169 NC |
1869 | char * name; |
1870 | ||
1871 | if (dynamic_strings == NULL) | |
1872 | name = NULL; | |
1873 | else | |
1874 | name = dynamic_strings + entry->d_un.d_val; | |
76466873 | 1875 | |
ebb64169 | 1876 | if (name) |
76466873 | 1877 | { |
ebb64169 | 1878 | switch (entry->d_tag) |
76466873 NC |
1879 | { |
1880 | case DT_NEEDED: | |
ebb64169 | 1881 | printf (_("Shared library: [%s]"), name); |
76466873 | 1882 | |
ebb64169 | 1883 | if (strcmp (name, program_interpreter)) |
76466873 NC |
1884 | printf ("\n"); |
1885 | else | |
1886 | printf (_(" program interpreter\n")); | |
1887 | break; | |
1888 | ||
1889 | case DT_SONAME: | |
ebb64169 | 1890 | printf (_("Library soname: [%s]\n"), name); |
76466873 NC |
1891 | break; |
1892 | ||
1893 | case DT_RPATH: | |
ebb64169 | 1894 | printf (_("Library rpath: [%s]\n"), name); |
76466873 NC |
1895 | break; |
1896 | ||
1897 | default: | |
ebb64169 | 1898 | printf ("%#lx\n", entry->d_un.d_val); |
76466873 NC |
1899 | } |
1900 | } | |
1901 | else | |
ebb64169 | 1902 | printf ("%#lx\n", entry->d_un.d_val); |
76466873 NC |
1903 | } |
1904 | break; | |
1905 | ||
1906 | default: | |
ebb64169 | 1907 | if ((entry->d_tag >= DT_VERSYM) && (entry->d_tag <= DT_VERNEEDNUM)) |
76466873 | 1908 | { |
ebb64169 NC |
1909 | version_info [DT_VERSIONTAGIDX (entry->d_tag)] = |
1910 | entry->d_un.d_val; | |
76466873 NC |
1911 | |
1912 | if (do_dynamic) | |
ebb64169 | 1913 | printf ("%#lx\n", entry->d_un.d_ptr); |
76466873 | 1914 | } |
76466873 NC |
1915 | break; |
1916 | } | |
ebb64169 NC |
1917 | } |
1918 | ||
1919 | free (dynamic_segment); | |
1920 | } | |
1921 | ||
1922 | static char * | |
1923 | get_ver_flags (unsigned short flags) | |
1924 | { | |
1925 | static char buff [32]; | |
1926 | ||
1927 | buff[0] = 0; | |
1928 | ||
1929 | if (flags == 0) | |
1930 | return _("none"); | |
1931 | ||
1932 | if (flags & VER_FLG_BASE) | |
1933 | strcat (buff, "BASE "); | |
1934 | ||
1935 | if (flags & VER_FLG_WEAK) | |
1936 | { | |
1937 | if (flags & VER_FLG_BASE) | |
1938 | strcat (buff, "| "); | |
76466873 | 1939 | |
ebb64169 | 1940 | strcat (buff, "WEAK "); |
76466873 NC |
1941 | } |
1942 | ||
ebb64169 NC |
1943 | if (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)) |
1944 | strcat (buff, "| <unknown>"); | |
1945 | ||
1946 | return buff; | |
1947 | } | |
1948 | ||
1949 | /* Display the contents of the version sections. */ | |
1950 | static void | |
1951 | process_version_sections (file) | |
1952 | FILE * file; | |
1953 | { | |
1954 | Elf_Shdr * section; | |
1955 | unsigned i; | |
1956 | int found = 0; | |
1957 | ||
1958 | if (! do_version) | |
1959 | return; | |
1960 | ||
1961 | for (i = 0, section = section_headers; | |
1962 | i < elf_header.e_shnum; | |
1963 | i++, section ++) | |
76466873 | 1964 | { |
ebb64169 | 1965 | switch (section->sh_type) |
76466873 | 1966 | { |
ebb64169 NC |
1967 | case SHT_GNU_verdef: |
1968 | { | |
1969 | Elf_Verdef * verdef_section; | |
1970 | unsigned int idx; | |
1971 | unsigned int cnt; | |
76466873 | 1972 | |
ebb64169 | 1973 | found = 1; |
76466873 | 1974 | |
ebb64169 NC |
1975 | printf (_("\nVersion definition section '%s' contains %d entries:\n"), |
1976 | SECTION_NAME (section), section->sh_info); | |
1977 | ||
1978 | printf (_(" Addr: %#08x Offset: %#08x Link: %x (%s)\n"), | |
1979 | section->sh_addr, section->sh_offset, section->sh_link, | |
1980 | SECTION_NAME (section_headers + section->sh_link)); | |
76466873 | 1981 | |
ebb64169 NC |
1982 | GET_DATA_ALLOC (section->sh_offset, section->sh_size, |
1983 | verdef_section, Elf_Verdef *, | |
1984 | "version definition section"); | |
1985 | ||
1986 | for (idx = cnt = 0; cnt < section->sh_info; ++ cnt) | |
1987 | { | |
1988 | Elf_Verdef * ent; | |
1989 | Elf_Verdaux * aux; | |
1990 | int j; | |
1991 | int isum; | |
1992 | ||
1993 | ent = (Elf_Verdef *) (((char *) verdef_section) + idx); | |
1994 | ||
1995 | if (must_swap) | |
1996 | { | |
1997 | BYTE_SWAP (* ent, vd_version); | |
1998 | BYTE_SWAP (* ent, vd_flags); | |
1999 | BYTE_SWAP (* ent, vd_ndx); | |
2000 | BYTE_SWAP (* ent, vd_cnt); | |
2001 | BYTE_SWAP (* ent, vd_hash); | |
2002 | BYTE_SWAP (* ent, vd_aux); | |
2003 | BYTE_SWAP (* ent, vd_next); | |
2004 | } | |
2005 | ||
2006 | printf (_(" %#06x: Rev: %d Flags: %s"), | |
2007 | idx, ent->vd_version, get_ver_flags (ent->vd_flags)); | |
2008 | ||
2009 | printf (_(" Index: %d Cnt: %d "), ent->vd_ndx, ent->vd_cnt); | |
2010 | ||
2011 | aux = (Elf_Verdaux *) ((char *) ent + ent->vd_aux); | |
2012 | ||
2013 | if (must_swap) | |
2014 | { | |
2015 | BYTE_SWAP (* aux, vda_name); | |
2016 | BYTE_SWAP (* aux, vda_next); | |
2017 | } | |
2018 | ||
2019 | if (dynamic_strings) | |
2020 | printf (_("Name: %s\n"), dynamic_strings + aux->vda_name); | |
2021 | else | |
2022 | printf (_("Name index: %d\n"), aux->vda_name); | |
2023 | ||
2024 | j = 1; | |
2025 | isum = idx + ent->vd_aux; | |
2026 | ||
2027 | while (j < ent->vd_cnt) | |
2028 | { | |
2029 | isum += aux->vda_next; | |
2030 | ||
2031 | aux = (Elf_Verdaux *)((char *) aux + aux->vda_next); | |
2032 | ||
2033 | if (must_swap) | |
2034 | { | |
2035 | BYTE_SWAP (* aux, vda_name); | |
2036 | BYTE_SWAP (* aux, vda_next); | |
2037 | } | |
2038 | ||
2039 | if (dynamic_strings) | |
2040 | printf (_(" %#06x: Parent %d: %s\n"), | |
2041 | isum, j, dynamic_strings + aux->vda_name); | |
2042 | else | |
2043 | printf (_(" %#06x: Parent %d, name index: %d\n"), | |
2044 | isum, j, aux->vda_name); | |
2045 | ||
2046 | ++j; | |
2047 | } | |
2048 | ||
2049 | idx += ent->vd_next; | |
2050 | } | |
2051 | ||
2052 | free (verdef_section); | |
2053 | } | |
2054 | break; | |
2055 | ||
2056 | case SHT_GNU_verneed: | |
2057 | { | |
2058 | Elf_Verneed * verneed_section; | |
2059 | unsigned int idx; | |
2060 | unsigned int cnt; | |
2061 | ||
2062 | found = 1; | |
2063 | ||
2064 | printf (_("\nVersion needs section '%s' contains %d entries:\n"), | |
2065 | SECTION_NAME (section), section->sh_info); | |
2066 | ||
2067 | printf (_(" Addr: %#08x Offset: %#08x Link to section: %d (%s)\n"), | |
2068 | section->sh_addr, section->sh_offset, section->sh_link, | |
2069 | SECTION_NAME (section_headers + section->sh_link)); | |
2070 | ||
2071 | GET_DATA_ALLOC (section->sh_offset, section->sh_size, | |
2072 | verneed_section, Elf_Verneed *, | |
2073 | "version need section"); | |
2074 | ||
2075 | for (idx = cnt = 0; cnt < section->sh_info; ++cnt) | |
2076 | { | |
2077 | Elf_Verneed * ent; | |
2078 | Elf_Vernaux * aux; | |
2079 | int j; | |
2080 | int isum; | |
2081 | ||
2082 | ent = verneed_section + idx / sizeof (Elf_Verneed); | |
2083 | ||
2084 | if (must_swap) | |
2085 | { | |
2086 | BYTE_SWAP (* ent, vn_version); | |
2087 | BYTE_SWAP (* ent, vn_cnt); | |
2088 | BYTE_SWAP (* ent, vn_file); | |
2089 | BYTE_SWAP (* ent, vn_aux); | |
2090 | BYTE_SWAP (* ent, vn_next); | |
2091 | } | |
2092 | ||
2093 | printf (_(" %#06x: Version: %d"), idx, ent->vn_version); | |
2094 | ||
2095 | if (dynamic_strings) | |
2096 | printf (_(" File: %s"), dynamic_strings + ent->vn_file); | |
2097 | else | |
2098 | printf (_(" File: %x"), ent->vn_file); | |
76466873 | 2099 | |
ebb64169 NC |
2100 | printf (_(" Cnt: %d\n"), ent->vn_cnt); |
2101 | ||
2102 | aux = (Elf_Vernaux *)((char *) ent + ent->vn_aux); | |
2103 | ||
2104 | for (j = 0, isum = idx + ent->vn_aux; j < ent->vn_cnt; ++j) | |
2105 | { | |
2106 | if (must_swap) | |
2107 | { | |
2108 | BYTE_SWAP (* aux, vna_hash); | |
2109 | BYTE_SWAP (* aux, vna_flags); | |
2110 | BYTE_SWAP (* aux, vna_other); | |
2111 | BYTE_SWAP (* aux, vna_name); | |
2112 | BYTE_SWAP (* aux, vna_next); | |
2113 | } | |
2114 | ||
2115 | if (dynamic_strings) | |
2116 | printf (_(" %#06x: Name: %s"), | |
2117 | isum, dynamic_strings + aux->vna_name); | |
2118 | else | |
2119 | printf (_(" %#06x: Name index: %x"), | |
2120 | isum, aux->vna_name); | |
2121 | ||
2122 | printf (_(" Flags: %s Version: %d\n"), | |
2123 | get_ver_flags (aux->vna_flags), aux->vna_other); | |
2124 | ||
2125 | isum += aux->vna_next; | |
2126 | aux = (Elf_Vernaux *)((char *) aux + aux->vna_next); | |
2127 | } | |
2128 | ||
2129 | idx += ent->vn_next; | |
2130 | } | |
2131 | } | |
2132 | break; | |
2133 | ||
2134 | case SHT_GNU_versym: | |
2135 | { | |
2136 | Elf_Shdr * link_section = section_headers + section->sh_link; | |
2137 | int total = section->sh_size / section->sh_entsize; | |
2138 | int cnt; | |
2139 | unsigned short * p; | |
2140 | char * strtab; | |
2141 | Elf_Sym * symbols; | |
2142 | Elf_Shdr * string_sec; | |
2143 | ||
2144 | found = 1; | |
2145 | ||
2146 | GET_DATA_ALLOC (link_section->sh_offset, link_section->sh_size, | |
2147 | symbols, Elf_Sym *, "version symbols section"); | |
2148 | ||
2149 | if (must_swap) | |
2150 | { | |
2151 | int k; | |
2152 | ||
2153 | for (k = link_section->sh_size / link_section->sh_entsize; | |
2154 | k --;) | |
2155 | { | |
2156 | BYTE_SWAP (symbols [k], st_name); | |
2157 | BYTE_SWAP (symbols [k], st_value); | |
2158 | BYTE_SWAP (symbols [k], st_size); | |
2159 | BYTE_SWAP (symbols [k], st_shndx); | |
2160 | } | |
2161 | } | |
2162 | ||
2163 | string_sec = section_headers + link_section->sh_link; | |
2164 | ||
2165 | GET_DATA_ALLOC (string_sec->sh_offset, string_sec->sh_size, | |
2166 | strtab, char *, "version string table"); | |
2167 | ||
2168 | printf (_("\nVersion symbols section '%s' contains %d entries:\n"), | |
2169 | SECTION_NAME (section), total); | |
2170 | ||
2171 | printf (_(" Addr: %#08x Offset: %#08x Link: %x (%s)\n"), | |
2172 | section->sh_addr, section->sh_offset, section->sh_link, | |
2173 | SECTION_NAME (link_section)); | |
2174 | ||
2175 | GET_DATA_ALLOC (version_info [DT_VERSIONTAGIDX (DT_VERSYM)] - loadaddr, | |
2176 | total * sizeof (unsigned short), p, | |
2177 | unsigned short *, "version symbol data"); | |
2178 | ||
2179 | if (must_swap) | |
2180 | { | |
2181 | int k; | |
2182 | for (k = total; k--;) | |
2183 | p [k] = SWAP2 (p [k]); | |
2184 | } | |
2185 | ||
2186 | for (cnt = 0; cnt < total; cnt += 4) | |
2187 | { | |
2188 | int j, nn; | |
2189 | ||
2190 | printf (" %03x:", cnt); | |
2191 | ||
2192 | for (j = 0; (j < 4) && (cnt + j) < total; ++j) | |
2193 | switch (p[cnt + j]) | |
2194 | { | |
2195 | case 0: | |
2196 | printf (" 0 (*local*) "); | |
2197 | break; | |
2198 | ||
2199 | case 1: | |
2200 | printf (" 1 (*global*) "); | |
2201 | break; | |
2202 | ||
2203 | default: | |
2204 | nn = printf ("%4x%c", p[cnt + j] & 0x7fff, | |
2205 | p[cnt + j] & 0x8000 ? 'h' : ' '); | |
2206 | ||
2207 | if (symbols [cnt + j].st_shndx < SHN_LORESERVE | |
2208 | && section_headers[symbols [cnt + j].st_shndx].sh_type | |
2209 | == SHT_NOBITS) | |
2210 | { | |
2211 | /* We must test both. */ | |
2212 | Elf_Verneed vn; | |
2213 | Elf_Vernaux vna; | |
2214 | unsigned long offset; | |
2215 | ||
2216 | offset = version_info [DT_VERSIONTAGIDX (DT_VERNEED)] | |
2217 | - loadaddr; | |
2218 | ||
2219 | do | |
2220 | { | |
2221 | unsigned long vna_off; | |
2222 | ||
2223 | GET_DATA (offset, vn, "version need"); | |
2224 | ||
2225 | if (must_swap) | |
2226 | { | |
2227 | BYTE_SWAP (vn, vn_aux); | |
2228 | BYTE_SWAP (vn, vn_next); | |
2229 | } | |
2230 | ||
2231 | vna_off = offset + vn.vn_aux; | |
2232 | ||
2233 | do | |
2234 | { | |
2235 | GET_DATA (vna_off, vna, | |
2236 | "version need aux (1)"); | |
2237 | ||
2238 | if (must_swap) | |
2239 | { | |
2240 | BYTE_SWAP (vna, vna_next); | |
2241 | BYTE_SWAP (vna, vna_other); | |
2242 | } | |
2243 | ||
2244 | vna_off += vna.vna_next; | |
2245 | } | |
2246 | while (vna.vna_other != p[cnt + j] | |
2247 | && vna.vna_next != 0); | |
2248 | ||
2249 | if (vna.vna_other == p[cnt + j]) | |
2250 | { | |
2251 | if (must_swap) | |
2252 | BYTE_SWAP (vna, vna_name); | |
2253 | ||
2254 | nn += printf ("(%11.11s)", | |
2255 | strtab + vna.vna_name); | |
2256 | break; | |
2257 | } | |
2258 | else if (vn.vn_next == 0) | |
2259 | { | |
2260 | if (p[cnt + j] != 0x8001) | |
2261 | { | |
2262 | Elf_Verdef vd; | |
2263 | Elf_Verdaux vda; | |
2264 | ||
2265 | offset = version_info | |
2266 | [DT_VERSIONTAGIDX (DT_VERDEF)] | |
2267 | - loadaddr; | |
2268 | ||
2269 | do | |
2270 | { | |
2271 | GET_DATA (offset, vd, | |
2272 | "version definition"); | |
2273 | ||
2274 | if (must_swap) | |
2275 | { | |
2276 | BYTE_SWAP (vd, vd_next); | |
2277 | BYTE_SWAP (vd, vd_ndx); | |
2278 | } | |
2279 | ||
2280 | offset += vd.vd_next; | |
2281 | } | |
2282 | while (vd.vd_ndx != (p[cnt + j] & 0x7fff) | |
2283 | && vd.vd_next != 0); | |
2284 | ||
2285 | if (vd.vd_ndx == (p[cnt + j] & 0x7fff)) | |
2286 | { | |
2287 | if (must_swap) | |
2288 | BYTE_SWAP (vd, vd_aux); | |
2289 | ||
2290 | GET_DATA (offset + vd.vd_aux, vda, | |
2291 | "version definition aux"); | |
2292 | ||
2293 | if (must_swap) | |
2294 | BYTE_SWAP (vda, vda_name); | |
2295 | ||
2296 | nn += printf ("(%11.11s)", | |
2297 | strtab + vda.vda_name); | |
2298 | } | |
2299 | } | |
2300 | ||
2301 | break; | |
2302 | } | |
2303 | else | |
2304 | offset += vn.vn_next; | |
2305 | } | |
2306 | while (vn.vn_next); | |
2307 | } | |
2308 | else if (symbols [cnt + j].st_shndx == SHN_UNDEF) | |
2309 | { | |
2310 | Elf_Vernaux a; | |
2311 | Elf_Verneed v; | |
2312 | unsigned long offset; | |
2313 | ||
2314 | offset = version_info [DT_VERSIONTAGIDX (DT_VERNEED)] | |
2315 | - loadaddr; | |
2316 | ||
2317 | do | |
2318 | { | |
2319 | unsigned long a_off; | |
2320 | ||
2321 | GET_DATA (offset, v, "version need"); | |
2322 | ||
2323 | if (must_swap) | |
2324 | { | |
2325 | BYTE_SWAP (v, vn_aux); | |
2326 | BYTE_SWAP (v, vn_next); | |
2327 | } | |
2328 | ||
2329 | a_off = offset + v.vn_aux; | |
2330 | ||
2331 | do | |
2332 | { | |
2333 | GET_DATA (a_off, a, "version need aux (2)"); | |
2334 | ||
2335 | if (must_swap) | |
2336 | { | |
2337 | BYTE_SWAP (a, vna_next); | |
2338 | BYTE_SWAP (a, vna_other); | |
2339 | } | |
2340 | ||
2341 | a_off += a.vna_next; | |
2342 | } | |
2343 | while (a.vna_other != p[cnt + j] | |
2344 | && a.vna_next != 0); | |
2345 | ||
2346 | if (a.vna_other == p[cnt + j]) | |
2347 | { | |
2348 | if (must_swap) | |
2349 | BYTE_SWAP (a, vna_name); | |
2350 | ||
2351 | nn += printf ("(%11.11s)", | |
2352 | strtab + a.vna_name); | |
2353 | ||
2354 | break; | |
2355 | } | |
2356 | ||
2357 | offset += v.vn_next; | |
2358 | } | |
2359 | while (v.vn_next); | |
2360 | } | |
2361 | else | |
2362 | { | |
2363 | if (p[cnt + j] != 0x8001) | |
2364 | { | |
2365 | Elf_Verdaux a; | |
2366 | Elf_Verdef v; | |
2367 | unsigned long offset; | |
2368 | ||
2369 | offset = version_info | |
2370 | [DT_VERSIONTAGIDX (DT_VERDEF)] - loadaddr; | |
2371 | ||
2372 | do | |
2373 | { | |
2374 | GET_DATA (offset, v, "version def"); | |
2375 | ||
2376 | if (must_swap) | |
2377 | { | |
2378 | BYTE_SWAP (v, vd_next); | |
2379 | BYTE_SWAP (v, vd_ndx); | |
2380 | } | |
2381 | ||
2382 | offset += v.vd_next; | |
2383 | } | |
2384 | while (v.vd_ndx != (p[cnt + j] & 0x7fff) | |
2385 | && v.vd_next != 0); | |
2386 | ||
2387 | if (v.vd_ndx == (p[cnt + j] & 0x7fff)) | |
2388 | { | |
2389 | if (must_swap) | |
2390 | BYTE_SWAP (v, vd_aux); | |
2391 | ||
2392 | GET_DATA (offset - v.vd_next + v.vd_aux, a, | |
2393 | "version def aux"); | |
2394 | ||
2395 | if (must_swap) | |
2396 | BYTE_SWAP (a, vda_name); | |
2397 | ||
2398 | nn += printf ("(%11.11s)", | |
2399 | strtab + a.vda_name); | |
2400 | } | |
2401 | } | |
2402 | } | |
2403 | ||
2404 | if (nn < 18) | |
2405 | printf ("%*c", 18 - nn, ' '); | |
2406 | } | |
2407 | ||
2408 | putchar ('\n'); | |
2409 | } | |
2410 | ||
2411 | free (p); | |
2412 | free (strtab); | |
2413 | free (symbols); | |
2414 | } | |
2415 | break; | |
2416 | ||
2417 | default: | |
76466873 NC |
2418 | } |
2419 | } | |
2420 | ||
ebb64169 NC |
2421 | if (! found) |
2422 | printf (_("\nNo version information found in this file.\n")); | |
2423 | } | |
2424 | ||
2425 | static char * | |
2426 | get_symbol_binding (binding) | |
2427 | unsigned int binding; | |
2428 | { | |
2429 | static char buff [32]; | |
2430 | ||
2431 | switch (binding) | |
2432 | { | |
2433 | case STB_LOCAL: return _("LOCAL"); | |
2434 | case STB_GLOBAL: return _("GLOBAL"); | |
2435 | case STB_WEAK: return _("WEAK"); | |
2436 | default: | |
2437 | if (binding >= STB_LOPROC && binding <= STB_HIPROC) | |
2438 | sprintf (buff, _("<processor specific>: %d"), binding); | |
2439 | else | |
2440 | sprintf (buff, _("<unknown>: %d"), binding); | |
2441 | return buff; | |
2442 | } | |
2443 | } | |
2444 | ||
2445 | static char * | |
2446 | get_symbol_type (type) | |
2447 | unsigned int type; | |
2448 | { | |
2449 | static char buff [32]; | |
2450 | ||
2451 | switch (type) | |
2452 | { | |
2453 | case STT_NOTYPE: return _("NOTYPE"); | |
2454 | case STT_OBJECT: return _("OBJECT"); | |
2455 | case STT_FUNC: return _("FUNC"); | |
2456 | case STT_SECTION: return _("SECTION"); | |
2457 | case STT_FILE: return _("FILE"); | |
2458 | default: | |
2459 | if (type >= STT_LOPROC && type <= STT_HIPROC) | |
2460 | sprintf (buff, _("<processor specific>: %d"), type); | |
2461 | else | |
2462 | sprintf (buff, _("<unknown>: %d"), type); | |
2463 | return buff; | |
2464 | } | |
2465 | } | |
2466 | ||
2467 | static char * | |
2468 | get_symbol_index_type (type) | |
2469 | unsigned short type; | |
2470 | { | |
2471 | switch (type) | |
2472 | { | |
2473 | case SHN_UNDEF: return "UND"; | |
2474 | case SHN_ABS: return "ABS"; | |
2475 | case SHN_COMMON: return "COM"; | |
2476 | default: | |
2477 | if (type >= SHN_LOPROC && type <= SHN_HIPROC) | |
2478 | return "PRC"; | |
2479 | else if (type >= SHN_LORESERVE && type <= SHN_HIRESERVE) | |
2480 | return "RSV"; | |
2481 | else | |
2482 | { | |
2483 | static char buff [32]; | |
2484 | ||
2485 | sprintf (buff, "%3d", type); | |
2486 | return buff; | |
2487 | } | |
2488 | } | |
76466873 NC |
2489 | } |
2490 | ||
ebb64169 | 2491 | |
76466873 NC |
2492 | /* Dump the symbol table */ |
2493 | static void | |
ebb64169 NC |
2494 | process_symbol_table (file) |
2495 | FILE * file; | |
76466873 | 2496 | { |
ebb64169 | 2497 | Elf_Shdr * section; |
76466873 NC |
2498 | |
2499 | if (! do_syms) | |
2500 | return; | |
2501 | ||
ebb64169 | 2502 | if (dynamic_info [DT_HASH] && do_using_dynamic && dynamic_strings != NULL) |
76466873 | 2503 | { |
ebb64169 NC |
2504 | int nbuckets; |
2505 | int nchains; | |
2506 | int * buckets; | |
76466873 NC |
2507 | int * chains; |
2508 | int hn; | |
2509 | int si; | |
76466873 | 2510 | |
ebb64169 NC |
2511 | if (fseek (file, dynamic_info [DT_HASH] - loadaddr, SEEK_SET)) |
2512 | { | |
2513 | error (_("Unable to seek to start of dynamic information")); | |
2514 | return; | |
2515 | } | |
2516 | ||
2517 | if (fread (& nbuckets, sizeof (nbuckets), 1, file) != 1) | |
2518 | { | |
2519 | error (_("Failed to read in number of buckets\n")); | |
2520 | return; | |
2521 | } | |
2522 | ||
2523 | if (fread (& nchains, sizeof (nchains), 1, file) != 1) | |
2524 | { | |
2525 | error (_("Failed to read in number of chains\n")); | |
2526 | return; | |
2527 | } | |
2528 | ||
2529 | if (must_swap) | |
2530 | { | |
2531 | nbuckets = SWAP4 (nbuckets); | |
2532 | nchains = SWAP4 (nchains); | |
2533 | } | |
2534 | ||
2535 | buckets = (int *) malloc (nbuckets * sizeof (* buckets)); | |
2536 | if (buckets == NULL) | |
2537 | { | |
2538 | error (_("Failed to allocate space for buckets\n")); | |
2539 | return; | |
2540 | } | |
2541 | ||
2542 | if (fread (buckets, sizeof (* buckets), nbuckets, file) != nbuckets) | |
2543 | { | |
2544 | error (_("Unable to read in buckets\n")); | |
2545 | return; | |
2546 | } | |
2547 | ||
2548 | chains = (int *) malloc (nchains * sizeof (* chains)); | |
2549 | if (chains == NULL) | |
2550 | { | |
2551 | error (_("Failed to allocate space for chains\n")); | |
2552 | free (buckets); | |
2553 | return; | |
2554 | } | |
76466873 | 2555 | |
ebb64169 NC |
2556 | if (fread (chains, sizeof (* chains), nchains, file) != nchains) |
2557 | { | |
2558 | error (_("Unable to read in chains!\n")); | |
2559 | free (buckets); | |
2560 | return; | |
2561 | } | |
2562 | ||
2563 | if (must_swap) | |
2564 | { | |
2565 | for (si = nbuckets; si--;) | |
2566 | buckets [si] = SWAP4 (buckets [si]); | |
76466873 | 2567 | |
ebb64169 NC |
2568 | for (si = nchains; si--;) |
2569 | chains [si] = SWAP4 (chains [si]); | |
2570 | } | |
2571 | ||
2572 | printf (_("\nSymbol table for image:\n")); | |
76466873 NC |
2573 | printf (_(" Num Buc: Value Size Type Bind Ot Ndx Name\n")); |
2574 | ||
ebb64169 | 2575 | for (hn = 0; hn < nbuckets; hn++) |
76466873 | 2576 | { |
ebb64169 | 2577 | if (! buckets [hn]) |
76466873 NC |
2578 | continue; |
2579 | ||
ebb64169 | 2580 | for (si = buckets [hn]; si; si = chains [si]) |
76466873 | 2581 | { |
ebb64169 NC |
2582 | Elf_Sym * psym; |
2583 | ||
2584 | psym = dynamic_symbols + si; | |
76466873 | 2585 | |
ebb64169 NC |
2586 | printf (" %3d %3d: %8lx %5ld %6s %6s %2d ", si, hn, |
2587 | psym->st_value, | |
2588 | psym->st_size, | |
2589 | get_symbol_type (ELF_ST_TYPE (psym->st_info)), | |
2590 | get_symbol_binding (ELF_ST_BIND (psym->st_info)), | |
2591 | psym->st_other); | |
2592 | ||
2593 | printf ("%3.3s", get_symbol_index_type (psym->st_shndx)); | |
76466873 | 2594 | |
ebb64169 | 2595 | printf (" %s\n", dynamic_strings + psym->st_name); |
76466873 NC |
2596 | } |
2597 | } | |
ebb64169 NC |
2598 | |
2599 | free (buckets); | |
2600 | free (chains); | |
76466873 NC |
2601 | } |
2602 | else if (!do_using_dynamic) | |
2603 | { | |
ebb64169 NC |
2604 | unsigned int i; |
2605 | ||
2606 | for (i = 0, section = section_headers; | |
2607 | i < elf_header.e_shnum; | |
2608 | i++, section++) | |
76466873 NC |
2609 | { |
2610 | unsigned int si; | |
ebb64169 NC |
2611 | char * strtab; |
2612 | Elf_Sym * symtab; | |
2613 | Elf_Sym * psym; | |
2614 | ||
76466873 | 2615 | |
ebb64169 NC |
2616 | if ( section->sh_type != SHT_SYMTAB |
2617 | && section->sh_type != SHT_DYNSYM) | |
76466873 NC |
2618 | continue; |
2619 | ||
ebb64169 NC |
2620 | printf (_("\nSymbol table '%s' contains %d entries:\n"), |
2621 | SECTION_NAME (section), | |
2622 | section->sh_size / section->sh_entsize); | |
76466873 | 2623 | printf (_(" Num: Value Size Type Bind Ot Ndx Name\n")); |
76466873 | 2624 | |
ebb64169 NC |
2625 | GET_DATA_ALLOC (section->sh_offset, section->sh_size, symtab, |
2626 | Elf_Sym *, "symbol section"); | |
76466873 | 2627 | |
ebb64169 NC |
2628 | if (must_swap) |
2629 | { | |
2630 | for (si = 0; si < section->sh_size / section->sh_entsize; si ++) | |
2631 | { | |
2632 | BYTE_SWAP (symtab [si], st_name); | |
2633 | BYTE_SWAP (symtab [si], st_value); | |
2634 | BYTE_SWAP (symtab [si], st_size); | |
2635 | BYTE_SWAP (symtab [si], st_shndx); | |
76466873 | 2636 | } |
ebb64169 NC |
2637 | } |
2638 | ||
2639 | if (section->sh_link == elf_header.e_shstrndx) | |
2640 | strtab = string_table; | |
2641 | else | |
2642 | { | |
2643 | Elf_Shdr * string_sec = section_headers + section->sh_link; | |
2644 | ||
2645 | GET_DATA_ALLOC (string_sec->sh_offset, string_sec->sh_size, | |
2646 | strtab, char *, "string table"); | |
2647 | } | |
2648 | ||
2649 | for (si = 0, psym = symtab; | |
2650 | si < section->sh_size / section->sh_entsize; | |
2651 | si ++, psym ++) | |
2652 | { | |
c18f8aef | 2653 | printf (" %3d: %8lx %5ld %-7s %-6s %2d ", si, |
76466873 NC |
2654 | psym->st_value, |
2655 | psym->st_size, | |
ebb64169 NC |
2656 | get_symbol_type (ELF_ST_TYPE (psym->st_info)), |
2657 | get_symbol_binding (ELF_ST_BIND (psym->st_info)), | |
76466873 NC |
2658 | psym->st_other); |
2659 | ||
2660 | if (psym->st_shndx == 0) | |
2661 | printf ("UND"); | |
2662 | else if ((psym->st_shndx & 0xffff) == 0xfff1) | |
2663 | printf ("ABS"); | |
2664 | else if ((psym->st_shndx & 0xffff) == 0xfff2) | |
2665 | printf ("COM"); | |
2666 | else | |
2667 | printf ("%3d", psym->st_shndx); | |
76466873 | 2668 | |
ebb64169 NC |
2669 | printf (" %s", strtab + psym->st_name); |
2670 | ||
2671 | if (section->sh_type == SHT_DYNSYM && | |
2672 | version_info [DT_VERSIONTAGIDX (DT_VERSYM)] != 0) | |
76466873 | 2673 | { |
ebb64169 NC |
2674 | unsigned short vers_data; |
2675 | unsigned long offset; | |
2676 | int is_nobits; | |
2677 | int check_def; | |
2678 | ||
2679 | offset = version_info [DT_VERSIONTAGIDX (DT_VERSYM)] | |
2680 | - loadaddr; | |
2681 | ||
2682 | GET_DATA (offset + si * sizeof (vers_data), vers_data, | |
2683 | "version data"); | |
2684 | ||
2685 | if (must_swap) | |
2686 | vers_data = SWAP2 (vers_data); | |
2687 | ||
2688 | is_nobits = psym->st_shndx < SHN_LORESERVE ? | |
2689 | (section_headers [psym->st_shndx].sh_type == SHT_NOBITS) | |
2690 | : 0; | |
76466873 | 2691 | |
ebb64169 NC |
2692 | check_def = (psym->st_shndx != SHN_UNDEF); |
2693 | ||
2694 | if ((vers_data & 0x8000) || vers_data > 1) | |
76466873 | 2695 | { |
ebb64169 | 2696 | if (is_nobits || ! check_def) |
76466873 | 2697 | { |
ebb64169 NC |
2698 | Elf_Verneed vn; |
2699 | Elf_Vernaux vna; | |
2700 | ||
2701 | /* We must test both. */ | |
2702 | offset = version_info | |
2703 | [DT_VERSIONTAGIDX (DT_VERNEED)] - loadaddr; | |
2704 | ||
2705 | GET_DATA (offset, vn, "version need"); | |
76466873 | 2706 | |
ebb64169 | 2707 | if (must_swap) |
76466873 | 2708 | { |
ebb64169 NC |
2709 | BYTE_SWAP (vn, vn_aux); |
2710 | BYTE_SWAP (vn, vn_next); | |
2711 | } | |
2712 | ||
2713 | do | |
2714 | { | |
2715 | unsigned long vna_off; | |
2716 | ||
2717 | vna_off = offset + vn.vn_aux; | |
2718 | ||
2719 | do | |
2720 | { | |
2721 | GET_DATA (vna_off, vna, | |
2722 | "version need aux (3)"); | |
2723 | ||
2724 | if (must_swap) | |
2725 | { | |
2726 | BYTE_SWAP (vna, vna_other); | |
2727 | BYTE_SWAP (vna, vna_next); | |
2728 | } | |
2729 | ||
2730 | vna_off += vna.vna_next; | |
2731 | } | |
2732 | while (vna.vna_other != vers_data | |
2733 | && vna.vna_next != 0); | |
76466873 | 2734 | |
ebb64169 NC |
2735 | if (vna.vna_other == vers_data) |
2736 | break; | |
2737 | ||
2738 | offset += vn.vn_next; | |
76466873 | 2739 | } |
ebb64169 | 2740 | while (vn.vn_next != 0); |
76466873 | 2741 | |
ebb64169 NC |
2742 | if (vna.vna_other == vers_data) |
2743 | printf ("@%s (%d)", | |
2744 | strtab + vna.vna_name, vna.vna_other); | |
2745 | else if (! is_nobits) | |
2746 | error (_("bad dynamic symbol")); | |
2747 | else | |
2748 | check_def = 1; | |
76466873 NC |
2749 | } |
2750 | ||
ebb64169 | 2751 | if (check_def) |
76466873 | 2752 | { |
ebb64169 NC |
2753 | if (vers_data != 0x8001) |
2754 | { | |
2755 | Elf_Verdef vd; | |
2756 | Elf_Verdaux vda; | |
2757 | unsigned long offset; | |
2758 | ||
2759 | offset = | |
2760 | version_info [DT_VERSIONTAGIDX (DT_VERDEF)] | |
2761 | - loadaddr; | |
2762 | ||
2763 | do | |
2764 | { | |
2765 | GET_DATA (offset, vd, "version def"); | |
2766 | ||
2767 | if (must_swap) | |
2768 | { | |
2769 | BYTE_SWAP (vd, vd_ndx); | |
2770 | BYTE_SWAP (vd, vd_aux); | |
2771 | BYTE_SWAP (vd, vd_next); | |
2772 | } | |
2773 | ||
2774 | offset += vd.vd_next; | |
2775 | } | |
2776 | while (vd.vd_ndx != (vers_data & 0x7fff) | |
2777 | && vd.vd_next != 0); | |
2778 | ||
2779 | offset -= vd.vd_next; | |
2780 | offset += vd.vd_aux; | |
2781 | ||
2782 | GET_DATA (offset, vda, "version def aux"); | |
2783 | ||
2784 | if (must_swap) | |
2785 | BYTE_SWAP (vda, vda_name); | |
2786 | ||
2787 | if (psym->st_name != vda.vda_name) | |
2788 | printf ((vers_data & 0x8000) | |
2789 | ? "@%s" : "@@%s", | |
2790 | strtab + vda.vda_name); | |
2791 | } | |
76466873 | 2792 | } |
76466873 NC |
2793 | } |
2794 | } | |
2795 | ||
ebb64169 | 2796 | putchar ('\n'); |
76466873 | 2797 | } |
76466873 | 2798 | |
ebb64169 NC |
2799 | free (symtab); |
2800 | if (strtab != string_table) | |
2801 | free (strtab); | |
76466873 NC |
2802 | } |
2803 | } | |
ebb64169 NC |
2804 | else |
2805 | printf | |
2806 | (_("\nDynamic symbol information is not available for displaying symbols.\n")); | |
76466873 NC |
2807 | } |
2808 | ||
2809 | static void | |
ebb64169 NC |
2810 | process_section_contents (file) |
2811 | FILE * file; | |
76466873 | 2812 | { |
ebb64169 NC |
2813 | Elf_Shdr * section; |
2814 | unsigned int i; | |
76466873 NC |
2815 | |
2816 | if (! do_dump) | |
2817 | return; | |
2818 | ||
ebb64169 NC |
2819 | for (i = 0, section = section_headers; |
2820 | i < elf_header.e_shnum; | |
2821 | i ++, section ++) | |
76466873 | 2822 | { |
76466873 NC |
2823 | #ifdef SUPPORT_DISASSEMBLY |
2824 | /* See if we need an assembly dump of this section */ | |
2825 | ||
2826 | if ((i < NUM_DUMP_SECTS) && (dump_sects[i] & DISASS_DUMP)) | |
2827 | { | |
ebb64169 NC |
2828 | printf (_("\nAssembly dump of section %s\n"), |
2829 | SECTION_NAME (section)); | |
2830 | ||
2831 | /* XXX -- to be done --- XXX */ | |
2832 | } | |
2833 | #endif | |
2834 | /* See if we need a hex dump of this section. */ | |
2835 | if ((i < NUM_DUMP_SECTS) && (dump_sects[i] & HEX_DUMP)) | |
2836 | { | |
2837 | int bytes; | |
2838 | int addr; | |
2839 | unsigned char * data; | |
2840 | char * start; | |
2841 | ||
2842 | printf (_("\nHex dump of section '%s':\n"), SECTION_NAME (section)); | |
76466873 | 2843 | |
ebb64169 NC |
2844 | bytes = section->sh_size; |
2845 | addr = section->sh_addr; | |
2846 | ||
2847 | GET_DATA_ALLOC (section->sh_offset, bytes, start, char *, | |
2848 | "section data"); | |
2849 | ||
2850 | data = start; | |
76466873 | 2851 | |
ebb64169 | 2852 | while (bytes) |
76466873 | 2853 | { |
ebb64169 NC |
2854 | int j; |
2855 | int k; | |
2856 | int lbytes; | |
2857 | ||
2858 | lbytes = (bytes > 16 ? 16 : bytes); | |
2859 | ||
2860 | printf (" 0x%8.8x ", addr); | |
76466873 | 2861 | |
ebb64169 | 2862 | switch (elf_header.e_ident [EI_DATA]) |
76466873 | 2863 | { |
ebb64169 NC |
2864 | case ELFDATA2LSB: |
2865 | for (j = 15; j >= 0; j --) | |
2866 | { | |
2867 | if (j < lbytes) | |
2868 | printf ("%2.2x", data [j]); | |
2869 | else | |
2870 | printf (" "); | |
2871 | ||
2872 | if (!(j & 0x3)) | |
2873 | printf (" "); | |
2874 | } | |
2875 | break; | |
2876 | ||
2877 | case ELFDATA2MSB: | |
2878 | for (j = 0; j < 16; j++) | |
2879 | { | |
2880 | if (j < lbytes) | |
2881 | printf ("%2.2x", data [j]); | |
2882 | else | |
2883 | printf (" "); | |
2884 | ||
2885 | if ((j & 3) == 3) | |
2886 | printf (" "); | |
2887 | } | |
2888 | break; | |
2889 | } | |
2890 | ||
2891 | for (j = 0; j < lbytes; j++) | |
2892 | { | |
2893 | k = data [j]; | |
2894 | if (k >= ' ' && k < 0x80) | |
2895 | printf ("%c", k); | |
2896 | else | |
2897 | printf ("."); | |
2898 | } | |
2899 | ||
2900 | putchar ('\n'); | |
2901 | ||
2902 | data += lbytes; | |
2903 | addr += lbytes; | |
2904 | bytes -= lbytes; | |
2905 | } | |
2906 | ||
2907 | free (start); | |
2908 | } | |
76466873 NC |
2909 | } |
2910 | } | |
2911 | ||
2912 | static void | |
2913 | process_file (file_name) | |
2914 | char * file_name; | |
2915 | { | |
ebb64169 | 2916 | FILE * file; |
76466873 | 2917 | struct stat statbuf; |
ebb64169 | 2918 | unsigned int i; |
76466873 | 2919 | |
ebb64169 NC |
2920 | if (stat (file_name, & statbuf) < 0) |
2921 | { | |
2922 | error (_("Cannot stat input file %s.\n"), file_name); | |
2923 | return; | |
2924 | } | |
2925 | ||
2926 | file = fopen (file_name, "rb"); | |
2927 | if (file == NULL) | |
76466873 NC |
2928 | { |
2929 | error (_("Input file %s not found.\n"), file_name); | |
2930 | return; | |
2931 | } | |
2932 | ||
ebb64169 | 2933 | if (fread (& elf_header, sizeof (elf_header), 1, file) != 1) |
76466873 | 2934 | { |
ebb64169 NC |
2935 | error (_("%s: Failed to read file header\n"), file_name); |
2936 | fclose (file); | |
76466873 NC |
2937 | return; |
2938 | } | |
2939 | ||
ebb64169 NC |
2940 | /* Initialise per file variables. */ |
2941 | must_swap = 0; | |
76466873 | 2942 | |
ebb64169 NC |
2943 | for (i = NUM_ELEM (version_info); i--;) |
2944 | version_info [i] = 0; | |
76466873 | 2945 | |
ebb64169 NC |
2946 | for (i = NUM_ELEM (dynamic_info); i--;) |
2947 | dynamic_info [i] = 0; | |
76466873 | 2948 | |
ebb64169 NC |
2949 | |
2950 | /* Process the file. */ | |
76466873 NC |
2951 | if (show_name) |
2952 | printf (_("\nFile: %s\n"), file_name); | |
2953 | ||
ebb64169 | 2954 | if (! process_file_header ()) |
76466873 | 2955 | { |
ebb64169 | 2956 | fclose (file); |
76466873 NC |
2957 | return; |
2958 | } | |
76466873 | 2959 | |
ebb64169 | 2960 | process_section_headers (file); |
76466873 | 2961 | |
ebb64169 NC |
2962 | process_program_headers (file); |
2963 | ||
2964 | process_dynamic_segment (file); | |
2965 | ||
2966 | process_relocs (file); | |
2967 | ||
2968 | process_symbol_table (file); | |
76466873 | 2969 | |
ebb64169 | 2970 | process_version_sections (file); |
76466873 | 2971 | |
ebb64169 NC |
2972 | process_section_contents (file); |
2973 | ||
2974 | fclose (file); | |
76466873 | 2975 | |
ebb64169 NC |
2976 | if (section_headers) |
2977 | { | |
2978 | free (section_headers); | |
2979 | section_headers = NULL; | |
2980 | } | |
76466873 | 2981 | |
ebb64169 | 2982 | if (string_table) |
76466873 | 2983 | { |
ebb64169 NC |
2984 | free (string_table); |
2985 | string_table = NULL; | |
2986 | } | |
76466873 | 2987 | |
ebb64169 NC |
2988 | if (dynamic_strings) |
2989 | { | |
2990 | free (dynamic_strings); | |
2991 | dynamic_strings = NULL; | |
2992 | } | |
2993 | ||
2994 | if (dynamic_symbols) | |
2995 | { | |
2996 | free (dynamic_symbols); | |
2997 | dynamic_symbols = NULL; | |
76466873 NC |
2998 | } |
2999 | } | |
3000 | ||
3001 | #ifdef SUPPORT_DISASSEMBLY | |
3002 | /* Needed by the i386 disassembler. For extra credit, someone could | |
3003 | fix this so that we insert symbolic addresses here, esp for GOT/PLT | |
3004 | symbols */ | |
3005 | ||
3006 | void | |
3007 | print_address (unsigned int addr, FILE * outfile) | |
3008 | { | |
3009 | fprintf (outfile,"0x%8.8x", addr); | |
3010 | } | |
3011 | ||
3012 | /* Needed by the i386 disassembler. */ | |
3013 | void | |
3014 | db_task_printsym (unsigned int addr) | |
3015 | { | |
3016 | print_address (addr, stderr); | |
3017 | } | |
3018 | #endif | |
3019 | ||
3020 | int | |
3021 | main (argc, argv) | |
3022 | int argc; | |
3023 | char ** argv; | |
3024 | { | |
3025 | parse_args (argc, argv); | |
3026 | ||
3027 | expected_endian = 0x12345678; | |
3028 | ||
3029 | if (* ((char *) & expected_endian) == 0x12) | |
3030 | expected_endian = ELFDATA2MSB; | |
3031 | else | |
3032 | expected_endian = ELFDATA2LSB; | |
3033 | ||
3034 | if (optind < (argc - 1)) | |
3035 | show_name = 1; | |
3036 | ||
3037 | while (optind < argc) | |
3038 | process_file (argv [optind ++]); | |
3039 | ||
3040 | return 0; | |
3041 | } |