1 /* PEF support for BFD.
2 Copyright 1999, 2000, 2001, 2002
3 Free Software Foundation, Inc.
5 This file is part of BFD, the Binary File Descriptor library.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
24 #include "pef-traceback.h"
30 #include "libiberty.h"
33 #define BFD_IO_FUNCS 0
36 #define bfd_pef_close_and_cleanup _bfd_generic_close_and_cleanup
37 #define bfd_pef_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
38 #define bfd_pef_new_section_hook _bfd_generic_new_section_hook
39 #define bfd_pef_bfd_is_local_label_name bfd_generic_is_local_label_name
40 #define bfd_pef_get_lineno _bfd_nosymbols_get_lineno
41 #define bfd_pef_find_nearest_line _bfd_nosymbols_find_nearest_line
42 #define bfd_pef_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
43 #define bfd_pef_read_minisymbols _bfd_generic_read_minisymbols
44 #define bfd_pef_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
46 #define bfd_pef_get_reloc_upper_bound _bfd_norelocs_get_reloc_upper_bound
47 #define bfd_pef_canonicalize_reloc _bfd_norelocs_canonicalize_reloc
48 #define bfd_pef_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
50 #define bfd_pef_set_arch_mach _bfd_generic_set_arch_mach
52 #define bfd_pef_get_section_contents _bfd_generic_get_section_contents
53 #define bfd_pef_set_section_contents _bfd_generic_set_section_contents
55 #define bfd_pef_bfd_get_relocated_section_contents \
56 bfd_generic_get_relocated_section_contents
57 #define bfd_pef_bfd_relax_section bfd_generic_relax_section
58 #define bfd_pef_bfd_gc_sections bfd_generic_gc_sections
59 #define bfd_pef_bfd_merge_sections bfd_generic_merge_sections
60 #define bfd_pef_bfd_discard_group bfd_generic_discard_group
61 #define bfd_pef_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
62 #define bfd_pef_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
63 #define bfd_pef_bfd_link_add_symbols _bfd_generic_link_add_symbols
64 #define bfd_pef_bfd_link_just_syms _bfd_generic_link_just_syms
65 #define bfd_pef_bfd_final_link _bfd_generic_final_link
66 #define bfd_pef_bfd_link_split_section _bfd_generic_link_split_section
67 #define bfd_pef_get_section_contents_in_window \
68 _bfd_generic_get_section_contents_in_window
70 static void bfd_pef_print_symbol
71 PARAMS ((bfd
*abfd
, PTR afile
, asymbol
*symbol
, bfd_print_symbol_type how
));
72 static void bfd_pef_convert_architecture
73 PARAMS ((unsigned long architecture
,
74 enum bfd_architecture
*type
, unsigned long *subtype
));
75 static boolean bfd_pef_mkobject
PARAMS ((bfd
*abfd
));
76 static int bfd_pef_parse_traceback_table
77 PARAMS ((bfd
*abfd
, asection
*section
, unsigned char *buf
,
78 size_t len
, size_t pos
, asymbol
*sym
, FILE *file
));
79 static const char *bfd_pef_section_name
PARAMS ((bfd_pef_section
*section
));
80 static unsigned long bfd_pef_section_flags
PARAMS ((bfd_pef_section
*section
));
81 static asection
*bfd_pef_make_bfd_section
PARAMS ((bfd
*abfd
, bfd_pef_section
*section
));
82 static int bfd_pef_read_header
PARAMS ((bfd
*abfd
, bfd_pef_header
*header
));
83 static const bfd_target
*bfd_pef_object_p
PARAMS ((bfd
*));
84 static int bfd_pef_parse_traceback_tables
85 PARAMS ((bfd
*abfd
, asection
*sec
, unsigned char *buf
,
86 size_t len
, long *nsym
, asymbol
**csym
));
87 static int bfd_pef_parse_function_stub
88 PARAMS ((bfd
*abfd
, unsigned char *buf
, size_t len
, unsigned long *offset
));
89 static int bfd_pef_parse_function_stubs
90 PARAMS ((bfd
*abfd
, asection
*codesec
, unsigned char *codebuf
, size_t codelen
,
91 unsigned char *loaderbuf
, size_t loaderlen
, unsigned long *nsym
, asymbol
**csym
));
92 static long bfd_pef_parse_symbols
PARAMS ((bfd
*abfd
, asymbol
**csym
));
93 static long bfd_pef_count_symbols
PARAMS ((bfd
*abfd
));
94 static long bfd_pef_get_symtab_upper_bound
PARAMS ((bfd
*));
95 static long bfd_pef_get_symtab
PARAMS ((bfd
*, asymbol
**));
96 static asymbol
*bfd_pef_make_empty_symbol
PARAMS ((bfd
*));
97 static void bfd_pef_get_symbol_info
PARAMS ((bfd
*, asymbol
*, symbol_info
*));
98 static int bfd_pef_sizeof_headers
PARAMS ((bfd
*, boolean
));
100 static int bfd_pef_xlib_read_header
PARAMS ((bfd
*abfd
, bfd_pef_xlib_header
*header
));
101 static int bfd_pef_xlib_scan
PARAMS ((bfd
*abfd
, bfd_pef_xlib_header
*header
));
102 static const bfd_target
*bfd_pef_xlib_object_p
PARAMS ((bfd
*abfd
));
105 bfd_pef_print_symbol (abfd
, afile
, symbol
, how
)
109 bfd_print_symbol_type how
;
111 FILE *file
= (FILE *) afile
;
113 case bfd_print_symbol_name
:
114 fprintf (file
, "%s", symbol
->name
);
117 bfd_print_symbol_vandf (abfd
, (PTR
) file
, symbol
);
118 fprintf (file
, " %-5s %s", symbol
->section
->name
, symbol
->name
);
119 if (strncmp (symbol
->name
, "__traceback_", strlen ("__traceback_")) == 0) {
120 char *buf
= alloca (symbol
->udata
.i
);
121 size_t offset
= symbol
->value
+ 4;
122 size_t len
= symbol
->udata
.i
;
125 bfd_get_section_contents (abfd
, symbol
->section
, buf
, offset
, len
);
126 ret
= bfd_pef_parse_traceback_table (abfd
, symbol
->section
, buf
, len
, 0, NULL
, file
);
128 fprintf (file
, " [ERROR]");
134 static void bfd_pef_convert_architecture (architecture
, type
, subtype
)
135 unsigned long architecture
;
136 enum bfd_architecture
*type
;
137 unsigned long *subtype
;
139 *subtype
= bfd_arch_unknown
;
140 *type
= bfd_arch_unknown
;
142 const unsigned long ARCH_POWERPC
= 0x70777063; /* 'pwpc' */
143 const unsigned long ARCH_M68K
= 0x6d36386b; /* 'm68k' */
145 if (architecture
== ARCH_POWERPC
)
146 *type
= bfd_arch_powerpc
;
147 else if (architecture
== ARCH_M68K
)
148 *type
= bfd_arch_m68k
;
152 bfd_pef_mkobject (abfd
)
153 bfd
*abfd ATTRIBUTE_UNUSED
;
159 bfd_pef_parse_traceback_table (abfd
, section
, buf
, len
, pos
, sym
, file
)
168 struct traceback_table table
;
173 if (sym
== NULL
) { sym
= &tmpsymbol
; }
178 sym
->section
= section
;
182 /* memcpy is fine since all fields are unsigned char */
184 if ((pos
+ 8) > len
) { return -1; }
185 memcpy (&table
, buf
+ pos
, 8);
187 /* calling code relies on returned symbols having a name and correct offset */
189 if ((table
.lang
!= TB_C
) && (table
.lang
!= TB_CPLUSPLUS
)) {
192 if (! (table
.flags2
& TB_NAME_PRESENT
)) {
195 if (! table
.flags1
& TB_HAS_TBOFF
) {
201 if ((table
.flags5
& TB_FLOATPARAMS
) || (table
.fixedparams
)) {
205 if (table
.flags1
& TB_HAS_TBOFF
) {
207 struct traceback_table_tboff off
;
209 if ((pos
+ offset
+ 4) > len
) { return -1; }
210 off
.tb_offset
= bfd_getb32 (buf
+ pos
+ offset
);
213 /* need to subtract 4 because the offset includes the 0x0L
214 preceding the table */
217 fprintf (file
, " [offset = 0x%lx]", off
.tb_offset
);
220 if ((file
== NULL
) && ((off
.tb_offset
+ 4) > (pos
+ offset
))) {
223 sym
->value
= pos
- off
.tb_offset
- 4;
226 if (table
.flags2
& TB_INT_HNDL
) {
230 if (table
.flags1
& TB_HAS_CTL
) {
232 struct traceback_table_anchors anchors
;
234 if ((pos
+ offset
+ 4) > len
) { return -1; }
235 anchors
.ctl_info
= bfd_getb32 (buf
+ pos
+ offset
);
238 if (anchors
.ctl_info
> 1024) {
242 offset
+= anchors
.ctl_info
* 4;
245 if (table
.flags2
& TB_NAME_PRESENT
) {
247 struct traceback_table_routine name
;
250 if ((pos
+ offset
+ 2) > len
) { return -1; }
251 name
.name_len
= bfd_getb16 (buf
+ pos
+ offset
);
254 if (name
.name_len
> 4096) { return -1; }
256 if ((pos
+ offset
+ name
.name_len
) > len
) { return -1; }
258 namebuf
= (char *) bfd_alloc (abfd
, name
.name_len
+ 1);
259 if (namebuf
== NULL
) { return -1; }
261 memcpy (namebuf
, buf
+ pos
+ offset
, name
.name_len
);
262 namebuf
[name
.name_len
] = '\0';
264 /* strip leading period inserted by compiler */
265 if (namebuf
[0] == '.') {
266 memmove (namebuf
, namebuf
+ 1, name
.name_len
+ 1);
271 for (s
= sym
->name
; (*s
!= '\0'); s
++) {
272 if (! isprint (*s
)) {
277 offset
+= name
.name_len
;
280 if (table
.flags2
& TB_USES_ALLOCA
) {
284 if (table
.flags4
& TB_HAS_VEC_INFO
) {
289 fprintf (file
, " [length = 0x%lx]", (long) offset
);
294 static const char *bfd_pef_section_name (section
)
295 bfd_pef_section
*section
;
297 switch (section
->section_kind
) {
298 case BFD_PEF_SECTION_CODE
: return "code";
299 case BFD_PEF_SECTION_UNPACKED_DATA
: return "unpacked-data";
300 case BFD_PEF_SECTION_PACKED_DATA
: return "packed-data";
301 case BFD_PEF_SECTION_CONSTANT
: return "constant";
302 case BFD_PEF_SECTION_LOADER
: return "loader";
303 case BFD_PEF_SECTION_DEBUG
: return "debug";
304 case BFD_PEF_SECTION_EXEC_DATA
: return "exec-data";
305 case BFD_PEF_SECTION_EXCEPTION
: return "exception";
306 case BFD_PEF_SECTION_TRACEBACK
: return "traceback";
307 default: return "unknown";
311 static unsigned long bfd_pef_section_flags (section
)
312 bfd_pef_section
*section
;
314 switch (section
->section_kind
) {
315 case BFD_PEF_SECTION_CODE
:
316 return SEC_HAS_CONTENTS
| SEC_LOAD
| SEC_ALLOC
| SEC_CODE
;
317 case BFD_PEF_SECTION_UNPACKED_DATA
:
318 case BFD_PEF_SECTION_PACKED_DATA
:
319 case BFD_PEF_SECTION_CONSTANT
:
320 case BFD_PEF_SECTION_LOADER
:
321 case BFD_PEF_SECTION_DEBUG
:
322 case BFD_PEF_SECTION_EXEC_DATA
:
323 case BFD_PEF_SECTION_EXCEPTION
:
324 case BFD_PEF_SECTION_TRACEBACK
:
326 return SEC_HAS_CONTENTS
| SEC_LOAD
| SEC_ALLOC
;
331 bfd_pef_make_bfd_section (abfd
, section
)
333 bfd_pef_section
*section
;
336 const char *name
= bfd_pef_section_name (section
);
338 bfdsec
= bfd_make_section_anyway (abfd
, name
);
339 if (bfdsec
== NULL
) { return NULL
; }
341 bfdsec
->vma
= section
->default_address
+ section
->container_offset
;
342 bfdsec
->lma
= section
->default_address
+ section
->container_offset
;
343 bfdsec
->_raw_size
= section
->container_length
;
344 bfdsec
->filepos
= section
->container_offset
;
345 bfdsec
->alignment_power
= section
->alignment
;
347 bfdsec
->flags
= bfd_pef_section_flags (section
);
352 int bfd_pef_parse_loader_header (abfd
, buf
, len
, header
)
353 bfd
*abfd ATTRIBUTE_UNUSED
;
356 bfd_pef_loader_header
*header
;
358 BFD_ASSERT (len
== 56);
360 header
->main_section
= bfd_getb32 (buf
);
361 header
->main_offset
= bfd_getb32 (buf
+ 4);
362 header
->init_section
= bfd_getb32 (buf
+ 8);
363 header
->init_offset
= bfd_getb32 (buf
+ 12);
364 header
->term_section
= bfd_getb32 (buf
+ 16);
365 header
->term_offset
= bfd_getb32 (buf
+ 20);
366 header
->imported_library_count
= bfd_getb32 (buf
+ 24);
367 header
->total_imported_symbol_count
= bfd_getb32 (buf
+ 28);
368 header
->reloc_section_count
= bfd_getb32 (buf
+ 32);
369 header
->reloc_instr_offset
= bfd_getb32 (buf
+ 36);
370 header
->loader_strings_offset
= bfd_getb32 (buf
+ 40);
371 header
->export_hash_offset
= bfd_getb32 (buf
+ 44);
372 header
->export_hash_table_power
= bfd_getb32 (buf
+ 48);
373 header
->exported_symbol_count
= bfd_getb32 (buf
+ 52);
378 int bfd_pef_parse_imported_library (abfd
, buf
, len
, header
)
379 bfd
*abfd ATTRIBUTE_UNUSED
;
382 bfd_pef_imported_library
*header
;
384 BFD_ASSERT (len
== 24);
386 header
->name_offset
= bfd_getb32 (buf
);
387 header
->old_implementation_version
= bfd_getb32 (buf
+ 4);
388 header
->current_version
= bfd_getb32 (buf
+ 8);
389 header
->imported_symbol_count
= bfd_getb32 (buf
+ 12);
390 header
->first_imported_symbol
= bfd_getb32 (buf
+ 16);
391 header
->options
= buf
[20];
392 header
->reserved_a
= buf
[21];
393 header
->reserved_b
= bfd_getb16 (buf
+ 22);
398 int bfd_pef_parse_imported_symbol (abfd
, buf
, len
, symbol
)
399 bfd
*abfd ATTRIBUTE_UNUSED
;
402 bfd_pef_imported_symbol
*symbol
;
406 BFD_ASSERT (len
== 4);
408 value
= bfd_getb32 (buf
);
409 symbol
->class = value
>> 24;
410 symbol
->name
= value
& 0x00ffffff;
415 int bfd_pef_scan_section (abfd
, section
)
417 bfd_pef_section
*section
;
419 unsigned char buf
[28];
421 bfd_seek (abfd
, section
->header_offset
, SEEK_SET
);
422 if (bfd_bread ((PTR
) buf
, 28, abfd
) != 28) { return -1; }
424 section
->name_offset
= bfd_h_get_32 (abfd
, buf
);
425 section
->default_address
= bfd_h_get_32 (abfd
, buf
+ 4);
426 section
->total_length
= bfd_h_get_32 (abfd
, buf
+ 8);
427 section
->unpacked_length
= bfd_h_get_32 (abfd
, buf
+ 12);
428 section
->container_length
= bfd_h_get_32 (abfd
, buf
+ 16);
429 section
->container_offset
= bfd_h_get_32 (abfd
, buf
+ 20);
430 section
->section_kind
= buf
[24];
431 section
->share_kind
= buf
[25];
432 section
->alignment
= buf
[26];
433 section
->reserved
= buf
[27];
435 section
->bfd_section
= bfd_pef_make_bfd_section (abfd
, section
);
436 if (section
->bfd_section
== NULL
) { return -1; }
442 bfd_pef_print_loader_header (abfd
, header
, file
)
443 bfd
*abfd ATTRIBUTE_UNUSED
;
444 bfd_pef_loader_header
*header
;
447 fprintf (file
, "main_section: %ld\n", header
->main_section
);
448 fprintf (file
, "main_offset: %lu\n", header
->main_offset
);
449 fprintf (file
, "init_section: %ld\n", header
->init_section
);
450 fprintf (file
, "init_offset: %lu\n", header
->init_offset
);
451 fprintf (file
, "term_section: %ld\n", header
->term_section
);
452 fprintf (file
, "term_offset: %lu\n", header
->term_offset
);
453 fprintf (file
, "imported_library_count: %lu\n", header
->imported_library_count
);
454 fprintf (file
, "total_imported_symbol_count: %lu\n", header
->total_imported_symbol_count
);
455 fprintf (file
, "reloc_section_count: %lu\n", header
->reloc_section_count
);
456 fprintf (file
, "reloc_instr_offset: %lu\n", header
->reloc_instr_offset
);
457 fprintf (file
, "loader_strings_offset: %lu\n", header
->loader_strings_offset
);
458 fprintf (file
, "export_hash_offset: %lu\n", header
->export_hash_offset
);
459 fprintf (file
, "export_hash_table_power: %lu\n", header
->export_hash_table_power
);
460 fprintf (file
, "exported_symbol_count: %lu\n", header
->exported_symbol_count
);
464 bfd_pef_print_loader_section (abfd
, file
)
468 bfd_pef_loader_header header
;
469 asection
*loadersec
= NULL
;
470 unsigned char *loaderbuf
= NULL
;
471 size_t loaderlen
= 0;
474 loadersec
= bfd_get_section_by_name (abfd
, "loader");
475 if (loadersec
== NULL
) { return -1; }
477 loaderlen
= bfd_section_size (abfd
, loadersec
);
478 loaderbuf
= (unsigned char *) bfd_malloc (loaderlen
);
479 if (bfd_seek (abfd
, loadersec
->filepos
, SEEK_SET
) < 0)
480 { free (loaderbuf
); return -1; }
481 if (bfd_bread ((PTR
) loaderbuf
, loaderlen
, abfd
) != loaderlen
)
482 { free (loaderbuf
); return -1; }
484 if (loaderlen
< 56) { free (loaderbuf
); return -1; }
485 ret
= bfd_pef_parse_loader_header (abfd
, loaderbuf
, 56, &header
);
486 if (ret
< 0) { free (loaderbuf
); return -1; }
488 bfd_pef_print_loader_header (abfd
, &header
, file
);
493 bfd_pef_scan_start_address (abfd
)
496 bfd_pef_loader_header header
;
499 asection
*loadersec
= NULL
;
500 unsigned char *loaderbuf
= NULL
;
501 size_t loaderlen
= 0;
504 loadersec
= bfd_get_section_by_name (abfd
, "loader");
505 if (loadersec
== NULL
) { goto end
; }
507 loaderlen
= bfd_section_size (abfd
, loadersec
);
508 loaderbuf
= (unsigned char *) bfd_malloc (loaderlen
);
509 if (bfd_seek (abfd
, loadersec
->filepos
, SEEK_SET
) < 0) { goto error
; }
510 if (bfd_bread ((PTR
) loaderbuf
, loaderlen
, abfd
) != loaderlen
) { goto error
; }
512 if (loaderlen
< 56) { goto error
; }
513 ret
= bfd_pef_parse_loader_header (abfd
, loaderbuf
, 56, &header
);
514 if (ret
< 0) { goto error
; }
516 if (header
.main_section
< 0) { goto end
; }
518 for (section
= abfd
->sections
; section
!= NULL
; section
= section
->next
) {
519 if ((section
->index
+ 1) == header
.main_section
) { break; }
522 if (section
== NULL
) { goto error
; }
524 abfd
->start_address
= section
->vma
+ header
.main_offset
;
527 if (loaderbuf
!= NULL
) { free (loaderbuf
); }
531 if (loaderbuf
!= NULL
) { free (loaderbuf
); }
536 bfd_pef_scan (abfd
, header
)
538 bfd_pef_header
*header
;
541 bfd_pef_data_struct
*mdata
= NULL
;
542 enum bfd_architecture cputype
;
543 unsigned long cpusubtype
;
545 if ((header
->tag1
!= BFD_PEF_TAG1
) || (header
->tag2
!= BFD_PEF_TAG2
)) {
549 mdata
= ((bfd_pef_data_struct
*)
550 bfd_alloc (abfd
, sizeof (bfd_pef_data_struct
)));
551 if (mdata
== NULL
) { return -1; }
553 bfd_pef_convert_architecture (header
->architecture
, &cputype
, &cpusubtype
);
554 if (cputype
== bfd_arch_unknown
) {
555 fprintf (stderr
, "bfd_pef_scan: unknown architecture 0x%lx\n", header
->architecture
);
558 bfd_set_arch_mach (abfd
, cputype
, cpusubtype
);
560 mdata
->header
= *header
;
562 abfd
->flags
= abfd
->xvec
->object_flags
| (abfd
->flags
& (BFD_IN_MEMORY
| BFD_IO_FUNCS
));
564 if (header
->section_count
!= 0) {
568 bfd_alloc (abfd
, header
->section_count
* sizeof (bfd_pef_section
)));
569 if (mdata
->sections
== NULL
) { return -1; }
571 for (i
= 0; i
< header
->section_count
; i
++) {
572 bfd_pef_section
*cur
= &mdata
->sections
[i
];
573 cur
->header_offset
= 40 + (i
* 28);
574 if (bfd_pef_scan_section (abfd
, cur
) < 0) {
580 if (bfd_pef_scan_start_address (abfd
) < 0) {
582 fprintf (stderr
, "bfd_pef_scan: unable to scan start address: %s\n",
583 bfd_errmsg (bfd_get_error ()));
584 abfd
->tdata
.pef_data
= NULL
;
589 abfd
->tdata
.pef_data
= mdata
;
595 bfd_pef_read_header (abfd
, header
)
597 bfd_pef_header
*header
;
599 unsigned char buf
[40];
601 bfd_seek (abfd
, 0, SEEK_SET
);
603 if (bfd_bread ((PTR
) buf
, 40, abfd
) != 40) { return -1; }
605 header
->tag1
= bfd_getb32 (buf
);
606 header
->tag2
= bfd_getb32 (buf
+ 4);
607 header
->architecture
= bfd_getb32 (buf
+ 8);
608 header
->format_version
= bfd_getb32 (buf
+ 12);
609 header
->timestamp
= bfd_getb32 (buf
+ 16);
610 header
->old_definition_version
= bfd_getb32 (buf
+ 20);
611 header
->old_implementation_version
= bfd_getb32 (buf
+ 24);
612 header
->current_version
= bfd_getb32 (buf
+ 28);
613 header
->section_count
= bfd_getb32 (buf
+ 32) + 1;
614 header
->instantiated_section_count
= bfd_getb32 (buf
+ 34);
615 header
->reserved
= bfd_getb32 (buf
+ 36);
620 static const bfd_target
*
621 bfd_pef_object_p (abfd
)
624 bfd_pef_header header
;
626 abfd
->tdata
.pef_data
= NULL
;
628 if (bfd_pef_read_header (abfd
, &header
) != 0) {
629 abfd
->tdata
.pef_data
= NULL
;
630 bfd_set_error (bfd_error_wrong_format
);
634 if (bfd_pef_scan (abfd
, &header
) != 0) {
635 abfd
->tdata
.pef_data
= NULL
;
636 bfd_set_error (bfd_error_wrong_format
);
643 static int bfd_pef_parse_traceback_tables (abfd
, sec
, buf
, len
, nsym
, csym
)
656 const char *const tbprefix
= "__traceback_";
660 unsigned long count
= 0;
665 /* we're reading symbols two at a time */
667 if (csym
&& ((csym
[count
] == NULL
) || (csym
[count
+ 1] == NULL
))) {
674 while ((pos
+ 4) <= len
) {
675 if (bfd_getb32 (buf
+ pos
) == 0) {
681 if ((pos
+ 4) > len
) {
685 ret
= bfd_pef_parse_traceback_table (abfd
, sec
, buf
, len
, pos
+ 4, &function
, 0);
687 /* skip over 0x0L to advance to next possible traceback table */
692 BFD_ASSERT (function
.name
!= NULL
);
694 /* Don't bother to compute the name if we are just
699 tbnamelen
= strlen (tbprefix
) + strlen (function
.name
);
700 name
= bfd_alloc (abfd
, tbnamelen
+ 1);
702 bfd_release (abfd
, (PTR
) function
.name
);
703 function
.name
= NULL
;
706 snprintf (name
, tbnamelen
+ 1, "%s%s", tbprefix
, function
.name
);
707 traceback
.name
= name
;
708 traceback
.value
= pos
;
709 traceback
.the_bfd
= abfd
;
710 traceback
.section
= sec
;
712 traceback
.udata
.i
= ret
;
714 *(csym
[count
]) = function
;
715 *(csym
[count
+ 1]) = traceback
;
726 static int bfd_pef_parse_function_stub (abfd
, buf
, len
, offset
)
727 bfd
*abfd ATTRIBUTE_UNUSED
;
730 unsigned long *offset
;
732 BFD_ASSERT (len
== 24);
734 if ((bfd_getb32 (buf
) & 0xffff0000) != 0x81820000) { return -1; }
735 if (bfd_getb32 (buf
+ 4) != 0x90410014) { return -1; }
736 if (bfd_getb32 (buf
+ 8) != 0x800c0000) { return -1; }
737 if (bfd_getb32 (buf
+ 12) != 0x804c0004) { return -1; }
738 if (bfd_getb32 (buf
+ 16) != 0x7c0903a6) { return -1; }
739 if (bfd_getb32 (buf
+ 20) != 0x4e800420) { return -1; }
741 if (offset
!= NULL
) {
742 *offset
= (bfd_getb32 (buf
) & 0x0000ffff) / 4;
748 static int bfd_pef_parse_function_stubs (abfd
, codesec
, codebuf
, codelen
, loaderbuf
, loaderlen
, nsym
, csym
)
751 unsigned char *codebuf
;
753 unsigned char *loaderbuf
;
758 const char *const sprefix
= "__stub_";
761 unsigned long count
= 0;
763 bfd_pef_loader_header header
;
764 bfd_pef_imported_library
*libraries
= NULL
;
765 bfd_pef_imported_symbol
*imports
= NULL
;
770 if (loaderlen
< 56) { goto error
; }
772 ret
= bfd_pef_parse_loader_header (abfd
, loaderbuf
, 56, &header
);
773 if (ret
< 0) { goto error
; }
775 libraries
= (bfd_pef_imported_library
*) bfd_malloc
776 (header
.imported_library_count
* sizeof (bfd_pef_imported_library
));
777 imports
= (bfd_pef_imported_symbol
*) bfd_malloc
778 (header
.total_imported_symbol_count
* sizeof (bfd_pef_imported_symbol
));
780 if (loaderlen
< (56 + (header
.imported_library_count
* 24))) { goto error
; }
781 for (i
= 0; i
< header
.imported_library_count
; i
++) {
782 ret
= bfd_pef_parse_imported_library
783 (abfd
, loaderbuf
+ 56 + (i
* 24), 24, &libraries
[i
]);
784 if (ret
< 0) { goto error
; }
787 if (loaderlen
< (56 + (header
.imported_library_count
* 24) + (header
.total_imported_symbol_count
* 4)))
789 for (i
= 0; i
< header
.total_imported_symbol_count
; i
++) {
790 ret
= bfd_pef_parse_imported_symbol
791 (abfd
, loaderbuf
+ 56 + (header
.imported_library_count
* 24) + (i
* 4), 4, &imports
[i
]);
792 if (ret
< 0) { goto error
; }
805 if (csym
&& (csym
[count
] == NULL
)) { break; }
808 codepos
-= (codepos
% 4);
810 while ((codepos
+ 4) <= codelen
) {
811 if ((bfd_getb32 (codebuf
+ codepos
) & 0xffff0000) == 0x81820000) {
817 if ((codepos
+ 4) > codelen
) {
821 ret
= bfd_pef_parse_function_stub (abfd
, codebuf
+ codepos
, 24, &index
);
822 if (ret
< 0) { codepos
+= 24; continue; }
824 if (index
>= header
.total_imported_symbol_count
) { codepos
+= 24; continue; }
830 if (loaderlen
< (header
.loader_strings_offset
+ imports
[index
].name
)) { goto error
; }
832 max
= loaderlen
- (header
.loader_strings_offset
+ imports
[index
].name
);
833 symname
= loaderbuf
+ header
.loader_strings_offset
+ imports
[index
].name
;
835 for (s
= symname
; s
< (symname
+ max
); s
++) {
836 if (*s
== '\0') { break; }
837 if (! isprint (*s
)) { goto error
; }
840 if (*s
!= '\0') { goto error
; }
842 name
= bfd_alloc (abfd
, strlen (sprefix
) + namelen
+ 1);
843 if (name
== NULL
) { break; }
845 snprintf (name
, strlen (sprefix
) + namelen
+ 1, "%s%s", sprefix
, symname
);
851 sym
.section
= codesec
;
858 *(csym
[count
]) = sym
;
866 if (libraries
!= NULL
) { free (libraries
); }
867 if (imports
!= NULL
) { free (imports
); }
872 if (libraries
!= NULL
) { free (libraries
); }
873 if (imports
!= NULL
) { free (imports
); }
878 static long bfd_pef_parse_symbols (abfd
, csym
)
882 unsigned long count
= 0;
884 asection
*codesec
= NULL
;
885 unsigned char *codebuf
= NULL
;
888 asection
*loadersec
= NULL
;
889 unsigned char *loaderbuf
= NULL
;
890 size_t loaderlen
= 0;
892 codesec
= bfd_get_section_by_name (abfd
, "code");
895 codelen
= bfd_section_size (abfd
, codesec
);
896 codebuf
= (unsigned char *) bfd_malloc (codelen
);
897 if (bfd_seek (abfd
, codesec
->filepos
, SEEK_SET
) < 0) { goto end
; }
898 if (bfd_bread ((PTR
) codebuf
, codelen
, abfd
) != codelen
) { goto end
; }
901 loadersec
= bfd_get_section_by_name (abfd
, "loader");
902 if (loadersec
!= NULL
)
904 loaderlen
= bfd_section_size (abfd
, loadersec
);
905 loaderbuf
= (unsigned char *) bfd_malloc (loaderlen
);
906 if (bfd_seek (abfd
, loadersec
->filepos
, SEEK_SET
) < 0) { goto end
; }
907 if (bfd_bread ((PTR
) loaderbuf
, loaderlen
, abfd
) != loaderlen
) { goto end
; }
913 unsigned long ncount
= 0;
914 bfd_pef_parse_traceback_tables (abfd
, codesec
, codebuf
, codelen
, &ncount
, csym
);
918 if ((codesec
!= NULL
) && (loadersec
!= NULL
))
920 unsigned long ncount
= 0;
921 bfd_pef_parse_function_stubs
922 (abfd
, codesec
, codebuf
, codelen
, loaderbuf
, loaderlen
, &ncount
,
923 (csym
!= NULL
) ? (csym
+ count
) : NULL
);
935 if (loaderbuf
!= NULL
)
942 bfd_pef_count_symbols (abfd
)
945 return bfd_pef_parse_symbols (abfd
, NULL
);
949 bfd_pef_get_symtab_upper_bound (abfd
)
952 long nsyms
= bfd_pef_count_symbols (abfd
);
953 if (nsyms
< 0) { return nsyms
; }
954 return ((nsyms
+ 1) * sizeof (asymbol
*));
958 bfd_pef_get_symtab (abfd
, alocation
)
966 long nsyms
= bfd_pef_count_symbols (abfd
);
967 if (nsyms
< 0) { return nsyms
; }
969 syms
= bfd_alloc (abfd
, nsyms
* sizeof (asymbol
));
970 if (syms
== NULL
) { return -1; }
972 for (i
= 0; i
< nsyms
; i
++) {
973 alocation
[i
] = &syms
[i
];
975 alocation
[nsyms
] = NULL
;
977 ret
= bfd_pef_parse_symbols (abfd
, alocation
);
986 bfd_pef_make_empty_symbol (abfd
)
989 return (asymbol
*) bfd_alloc (abfd
, sizeof (asymbol
));
993 bfd_pef_get_symbol_info (abfd
, symbol
, ret
)
994 bfd
*abfd ATTRIBUTE_UNUSED
;
998 bfd_symbol_info (symbol
, ret
);
1002 bfd_pef_sizeof_headers (abfd
, exec
)
1003 bfd
*abfd ATTRIBUTE_UNUSED
;
1004 boolean exec ATTRIBUTE_UNUSED
;
1009 const bfd_target pef_vec
=
1012 bfd_target_pef_flavour
, /* flavour */
1013 BFD_ENDIAN_BIG
, /* byteorder */
1014 BFD_ENDIAN_BIG
, /* header_byteorder */
1015 (HAS_RELOC
| EXEC_P
| /* object flags */
1016 HAS_LINENO
| HAS_DEBUG
|
1017 HAS_SYMS
| HAS_LOCALS
| DYNAMIC
| WP_TEXT
| D_PAGED
),
1018 (SEC_ALLOC
| SEC_LOAD
| SEC_READONLY
| SEC_CODE
| SEC_DATA
1019 | SEC_ROM
| SEC_HAS_CONTENTS
), /* section_flags */
1020 0, /* symbol_leading_char */
1021 ' ', /* ar_pad_char */
1022 16, /* ar_max_namelen */
1023 bfd_getb64
, bfd_getb_signed_64
, bfd_putb64
,
1024 bfd_getb32
, bfd_getb_signed_32
, bfd_putb32
,
1025 bfd_getb16
, bfd_getb_signed_16
, bfd_putb16
, /* data */
1026 bfd_getb64
, bfd_getb_signed_64
, bfd_putb64
,
1027 bfd_getb32
, bfd_getb_signed_32
, bfd_putb32
,
1028 bfd_getb16
, bfd_getb_signed_16
, bfd_putb16
, /* hdrs */
1029 { /* bfd_check_format */
1031 bfd_pef_object_p
, /* bfd_check_format */
1035 { /* bfd_set_format */
1041 { /* bfd_write_contents */
1048 BFD_JUMP_TABLE_GENERIC (bfd_pef
),
1049 BFD_JUMP_TABLE_COPY (_bfd_generic
),
1050 BFD_JUMP_TABLE_CORE (_bfd_nocore
),
1051 BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive
),
1052 BFD_JUMP_TABLE_SYMBOLS (bfd_pef
),
1053 BFD_JUMP_TABLE_RELOCS (bfd_pef
),
1054 BFD_JUMP_TABLE_WRITE (bfd_pef
),
1055 BFD_JUMP_TABLE_LINK (bfd_pef
),
1056 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic
),
1063 #define bfd_pef_xlib_close_and_cleanup _bfd_generic_close_and_cleanup
1064 #define bfd_pef_xlib_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
1065 #define bfd_pef_xlib_new_section_hook _bfd_generic_new_section_hook
1066 #define bfd_pef_xlib_get_section_contents _bfd_generic_get_section_contents
1067 #define bfd_pef_xlib_set_section_contents _bfd_generic_set_section_contents
1068 #define bfd_pef_xlib_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
1069 #define bfd_pef_xlib_set_section_contents_in_window _bfd_generic_set_section_contents_in_window
1072 bfd_pef_xlib_read_header (abfd
, header
)
1074 bfd_pef_xlib_header
*header
;
1076 unsigned char buf
[76];
1078 bfd_seek (abfd
, 0, SEEK_SET
);
1080 if (bfd_bread ((PTR
) buf
, 76, abfd
) != 76) { return -1; }
1082 header
->tag1
= bfd_getb32 (buf
);
1083 header
->tag2
= bfd_getb32 (buf
+ 4);
1084 header
->current_format
= bfd_getb32 (buf
+ 8);
1085 header
->container_strings_offset
= bfd_getb32 (buf
+ 12);
1086 header
->export_hash_offset
= bfd_getb32 (buf
+ 16);
1087 header
->export_key_offset
= bfd_getb32 (buf
+ 20);
1088 header
->export_symbol_offset
= bfd_getb32 (buf
+ 24);
1089 header
->export_names_offset
= bfd_getb32 (buf
+ 28);
1090 header
->export_hash_table_power
= bfd_getb32 (buf
+ 32);
1091 header
->exported_symbol_count
= bfd_getb32 (buf
+ 36);
1092 header
->frag_name_offset
= bfd_getb32 (buf
+ 40);
1093 header
->frag_name_length
= bfd_getb32 (buf
+ 44);
1094 header
->dylib_path_offset
= bfd_getb32 (buf
+ 48);
1095 header
->dylib_path_length
= bfd_getb32 (buf
+ 52);
1096 header
->cpu_family
= bfd_getb32 (buf
+ 56);
1097 header
->cpu_model
= bfd_getb32 (buf
+ 60);
1098 header
->date_time_stamp
= bfd_getb32 (buf
+ 64);
1099 header
->current_version
= bfd_getb32 (buf
+ 68);
1100 header
->old_definition_version
= bfd_getb32 (buf
+ 72);
1101 header
->old_implementation_version
= bfd_getb32 (buf
+ 76);
1107 bfd_pef_xlib_scan (abfd
, header
)
1109 bfd_pef_xlib_header
*header
;
1111 bfd_pef_xlib_data_struct
*mdata
= NULL
;
1113 if ((header
->tag1
!= BFD_PEF_XLIB_TAG1
)
1114 || ((header
->tag2
!= BFD_PEF_VLIB_TAG2
) && (header
->tag2
!= BFD_PEF_BLIB_TAG2
))) {
1118 mdata
= ((bfd_pef_xlib_data_struct
*)
1119 bfd_alloc (abfd
, sizeof (bfd_pef_xlib_data_struct
)));
1120 if (mdata
== NULL
) { return -1; }
1122 mdata
->header
= *header
;
1124 abfd
->flags
= abfd
->xvec
->object_flags
| (abfd
->flags
& (BFD_IN_MEMORY
| BFD_IO_FUNCS
));
1126 abfd
->tdata
.pef_xlib_data
= mdata
;
1131 static const bfd_target
*
1132 bfd_pef_xlib_object_p (abfd
)
1135 bfd_pef_xlib_header header
;
1137 abfd
->tdata
.pef_xlib_data
= NULL
;
1139 if (bfd_pef_xlib_read_header (abfd
, &header
) != 0) {
1140 abfd
->tdata
.pef_xlib_data
= NULL
;
1141 bfd_set_error (bfd_error_wrong_format
);
1145 if (bfd_pef_xlib_scan (abfd
, &header
) != 0) {
1146 abfd
->tdata
.pef_xlib_data
= NULL
;
1147 bfd_set_error (bfd_error_wrong_format
);
1154 const bfd_target pef_xlib_vec
=
1156 "pef-xlib", /* name */
1157 bfd_target_pef_xlib_flavour
, /* flavour */
1158 BFD_ENDIAN_BIG
, /* byteorder */
1159 BFD_ENDIAN_BIG
, /* header_byteorder */
1160 (HAS_RELOC
| EXEC_P
| /* object flags */
1161 HAS_LINENO
| HAS_DEBUG
|
1162 HAS_SYMS
| HAS_LOCALS
| DYNAMIC
| WP_TEXT
| D_PAGED
),
1163 (SEC_ALLOC
| SEC_LOAD
| SEC_READONLY
| SEC_CODE
| SEC_DATA
1164 | SEC_ROM
| SEC_HAS_CONTENTS
), /* section_flags */
1165 0, /* symbol_leading_char */
1166 ' ', /* ar_pad_char */
1167 16, /* ar_max_namelen */
1168 bfd_getb64
, bfd_getb_signed_64
, bfd_putb64
,
1169 bfd_getb32
, bfd_getb_signed_32
, bfd_putb32
,
1170 bfd_getb16
, bfd_getb_signed_16
, bfd_putb16
, /* data */
1171 bfd_getb64
, bfd_getb_signed_64
, bfd_putb64
,
1172 bfd_getb32
, bfd_getb_signed_32
, bfd_putb32
,
1173 bfd_getb16
, bfd_getb_signed_16
, bfd_putb16
, /* hdrs */
1174 { /* bfd_check_format */
1176 bfd_pef_xlib_object_p
, /* bfd_check_format */
1180 { /* bfd_set_format */
1186 { /* bfd_write_contents */
1193 BFD_JUMP_TABLE_GENERIC (bfd_pef_xlib
),
1194 BFD_JUMP_TABLE_COPY (_bfd_generic
),
1195 BFD_JUMP_TABLE_CORE (_bfd_nocore
),
1196 BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive
),
1197 BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols
),
1198 BFD_JUMP_TABLE_RELOCS (_bfd_norelocs
),
1199 BFD_JUMP_TABLE_WRITE (_bfd_nowrite
),
1200 BFD_JUMP_TABLE_LINK (_bfd_nolink
),
1201 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic
),