* ld-cris/expdyn6.d, ld-cris/weakref2.d, ld-cris/expdyn7.d,
[binutils.git] / bfd / pef.c
blobbb0d6c5c96f185df1ebccc2812dccab74ba96829
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. */
21 #include <ctype.h>
23 #include "pef.h"
24 #include "pef-traceback.h"
26 #include "bfd.h"
27 #include "sysdep.h"
28 #include "libbfd.h"
30 #include "libiberty.h"
32 #ifndef BFD_IO_FUNCS
33 #define BFD_IO_FUNCS 0
34 #endif
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));
104 static void
105 bfd_pef_print_symbol (abfd, afile, symbol, how)
106 bfd *abfd;
107 PTR afile;
108 asymbol *symbol;
109 bfd_print_symbol_type how;
111 FILE *file = (FILE *) afile;
112 switch (how) {
113 case bfd_print_symbol_name:
114 fprintf (file, "%s", symbol->name);
115 break;
116 default:
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;
123 int ret;
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);
127 if (ret < 0) {
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;
151 static boolean
152 bfd_pef_mkobject (abfd)
153 bfd *abfd ATTRIBUTE_UNUSED;
155 return true;
158 static int
159 bfd_pef_parse_traceback_table (abfd, section, buf, len, pos, sym, file)
160 bfd *abfd;
161 asection *section;
162 unsigned char *buf;
163 size_t len;
164 size_t pos;
165 asymbol *sym;
166 FILE *file;
168 struct traceback_table table;
169 size_t offset;
170 const char *s;
171 asymbol tmpsymbol;
173 if (sym == NULL) { sym = &tmpsymbol; }
175 sym->name = NULL;
176 sym->value = 0;
177 sym->the_bfd = abfd;
178 sym->section = section;
179 sym->flags = 0;
180 sym->udata.i = 0;
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)) {
190 return -1;
192 if (! (table.flags2 & TB_NAME_PRESENT)) {
193 return -1;
195 if (! table.flags1 & TB_HAS_TBOFF) {
196 return -1;
199 offset = 8;
201 if ((table.flags5 & TB_FLOATPARAMS) || (table.fixedparams)) {
202 offset += 4;
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);
211 offset += 4;
213 /* need to subtract 4 because the offset includes the 0x0L
214 preceding the table */
216 if (file != NULL) {
217 fprintf (file, " [offset = 0x%lx]", off.tb_offset);
220 if ((file == NULL) && ((off.tb_offset + 4) > (pos + offset))) {
221 return -1;
223 sym->value = pos - off.tb_offset - 4;
226 if (table.flags2 & TB_INT_HNDL) {
227 offset += 4;
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);
236 offset += 4;
238 if (anchors.ctl_info > 1024) {
239 return -1;
242 offset += anchors.ctl_info * 4;
245 if (table.flags2 & TB_NAME_PRESENT) {
247 struct traceback_table_routine name;
248 char *namebuf;
250 if ((pos + offset + 2) > len) { return -1; }
251 name.name_len = bfd_getb16 (buf + pos + offset);
252 offset += 2;
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);
269 sym->name = namebuf;
271 for (s = sym->name; (*s != '\0'); s++) {
272 if (! isprint (*s)) {
273 return -1;
277 offset += name.name_len;
280 if (table.flags2 & TB_USES_ALLOCA) {
281 offset += 4;
284 if (table.flags4 & TB_HAS_VEC_INFO) {
285 offset += 4;
288 if (file != NULL) {
289 fprintf (file, " [length = 0x%lx]", (long) offset);
291 return 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:
325 default:
326 return SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
330 static asection *
331 bfd_pef_make_bfd_section (abfd, section)
332 bfd *abfd;
333 bfd_pef_section *section;
335 asection *bfdsec;
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);
349 return bfdsec;
352 int bfd_pef_parse_loader_header (abfd, buf, len, header)
353 bfd *abfd ATTRIBUTE_UNUSED;
354 unsigned char *buf;
355 size_t len;
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);
375 return 0;
378 int bfd_pef_parse_imported_library (abfd, buf, len, header)
379 bfd *abfd ATTRIBUTE_UNUSED;
380 unsigned char *buf;
381 size_t len;
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);
395 return 0;
398 int bfd_pef_parse_imported_symbol (abfd, buf, len, symbol)
399 bfd *abfd ATTRIBUTE_UNUSED;
400 unsigned char *buf;
401 size_t len;
402 bfd_pef_imported_symbol *symbol;
404 unsigned long value;
406 BFD_ASSERT (len == 4);
408 value = bfd_getb32 (buf);
409 symbol->class = value >> 24;
410 symbol->name = value & 0x00ffffff;
412 return 0;
415 int bfd_pef_scan_section (abfd, section)
416 bfd *abfd;
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; }
438 return 0;
441 void
442 bfd_pef_print_loader_header (abfd, header, file)
443 bfd *abfd ATTRIBUTE_UNUSED;
444 bfd_pef_loader_header *header;
445 FILE *file;
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)
465 bfd *abfd;
466 FILE *file;
468 bfd_pef_loader_header header;
469 asection *loadersec = NULL;
470 unsigned char *loaderbuf = NULL;
471 size_t loaderlen = 0;
472 int ret;
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);
489 return 0;
493 bfd_pef_scan_start_address (abfd)
494 bfd *abfd;
496 bfd_pef_loader_header header;
497 asection *section;
499 asection *loadersec = NULL;
500 unsigned char *loaderbuf = NULL;
501 size_t loaderlen = 0;
502 int ret;
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;
526 end:
527 if (loaderbuf != NULL) { free (loaderbuf); }
528 return 0;
530 error:
531 if (loaderbuf != NULL) { free (loaderbuf); }
532 return -1;
536 bfd_pef_scan (abfd, header)
537 bfd *abfd;
538 bfd_pef_header *header;
540 unsigned int i;
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)) {
546 return -1;
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);
556 return -1;
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) {
566 mdata->sections =
567 ((bfd_pef_section *)
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) {
575 return -1;
580 if (bfd_pef_scan_start_address (abfd) < 0) {
581 #if 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;
585 return -1;
586 #endif
589 abfd->tdata.pef_data = mdata;
591 return 0;
594 static int
595 bfd_pef_read_header (abfd, header)
596 bfd *abfd;
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);
617 return 0;
620 static const bfd_target *
621 bfd_pef_object_p (abfd)
622 bfd *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);
631 return NULL;
634 if (bfd_pef_scan (abfd, &header) != 0) {
635 abfd->tdata.pef_data = NULL;
636 bfd_set_error (bfd_error_wrong_format);
637 return NULL;
640 return abfd->xvec;
643 static int bfd_pef_parse_traceback_tables (abfd, sec, buf, len, nsym, csym)
644 bfd *abfd;
645 asection *sec;
646 unsigned char *buf;
647 size_t len;
648 long *nsym;
649 asymbol **csym;
651 char *name;
653 asymbol function;
654 asymbol traceback;
656 const char *const tbprefix = "__traceback_";
657 size_t tbnamelen;
659 size_t pos = 0;
660 unsigned long count = 0;
661 int ret;
663 for (;;) {
665 /* we're reading symbols two at a time */
667 if (csym && ((csym[count] == NULL) || (csym[count + 1] == NULL))) {
668 break;
671 pos += 3;
672 pos -= (pos % 4);
674 while ((pos + 4) <= len) {
675 if (bfd_getb32 (buf + pos) == 0) {
676 break;
678 pos += 4;
681 if ((pos + 4) > len) {
682 break;
685 ret = bfd_pef_parse_traceback_table (abfd, sec, buf, len, pos + 4, &function, 0);
686 if (ret < 0) {
687 /* skip over 0x0L to advance to next possible traceback table */
688 pos += 4;
689 continue;
692 BFD_ASSERT (function.name != NULL);
694 /* Don't bother to compute the name if we are just
695 counting symbols */
697 if (csym)
699 tbnamelen = strlen (tbprefix) + strlen (function.name);
700 name = bfd_alloc (abfd, tbnamelen + 1);
701 if (name == NULL) {
702 bfd_release (abfd, (PTR) function.name);
703 function.name = NULL;
704 break;
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;
711 traceback.flags = 0;
712 traceback.udata.i = ret;
714 *(csym[count]) = function;
715 *(csym[count + 1]) = traceback;
718 pos += ret;
719 count += 2;
722 *nsym = count;
723 return 0;
726 static int bfd_pef_parse_function_stub (abfd, buf, len, offset)
727 bfd *abfd ATTRIBUTE_UNUSED;
728 unsigned char *buf;
729 size_t len;
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;
745 return 0;
748 static int bfd_pef_parse_function_stubs (abfd, codesec, codebuf, codelen, loaderbuf, loaderlen, nsym, csym)
749 bfd *abfd;
750 asection *codesec;
751 unsigned char *codebuf;
752 size_t codelen;
753 unsigned char *loaderbuf;
754 size_t loaderlen;
755 unsigned long *nsym;
756 asymbol **csym;
758 const char *const sprefix = "__stub_";
760 size_t codepos = 0;
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;
767 unsigned long i;
768 int ret;
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)))
788 { goto error; }
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; }
795 codepos = 0;
797 for (;;) {
799 asymbol sym;
800 const char *symname;
801 char *name;
802 unsigned long index;
803 int ret;
805 if (csym && (csym[count] == NULL)) { break; }
807 codepos += 3;
808 codepos -= (codepos % 4);
810 while ((codepos + 4) <= codelen) {
811 if ((bfd_getb32 (codebuf + codepos) & 0xffff0000) == 0x81820000) {
812 break;
814 codepos += 4;
817 if ((codepos + 4) > codelen) {
818 break;
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; }
827 size_t max, namelen;
828 const char *s;
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;
834 namelen = 0;
835 for (s = symname; s < (symname + max); s++) {
836 if (*s == '\0') { break; }
837 if (! isprint (*s)) { goto error; }
838 namelen++;
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);
846 sym.name = name;
849 sym.value = codepos;
850 sym.the_bfd = abfd;
851 sym.section = codesec;
852 sym.flags = 0;
853 sym.udata.i = 0;
855 codepos += 24;
857 if (csym != NULL) {
858 *(csym[count]) = sym;
860 count++;
863 goto end;
865 end:
866 if (libraries != NULL) { free (libraries); }
867 if (imports != NULL) { free (imports); }
868 *nsym = count;
869 return 0;
871 error:
872 if (libraries != NULL) { free (libraries); }
873 if (imports != NULL) { free (imports); }
874 *nsym = count;
875 return -1;
878 static long bfd_pef_parse_symbols (abfd, csym)
879 bfd *abfd;
880 asymbol **csym;
882 unsigned long count = 0;
884 asection *codesec = NULL;
885 unsigned char *codebuf = NULL;
886 size_t codelen = 0;
888 asection *loadersec = NULL;
889 unsigned char *loaderbuf = NULL;
890 size_t loaderlen = 0;
892 codesec = bfd_get_section_by_name (abfd, "code");
893 if (codesec != NULL)
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; }
910 count = 0;
911 if (codesec != NULL)
913 unsigned long ncount = 0;
914 bfd_pef_parse_traceback_tables (abfd, codesec, codebuf, codelen, &ncount, csym);
915 count += ncount;
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);
924 count += ncount;
927 if (csym != NULL) {
928 csym[count] = NULL;
931 end:
932 if (codebuf != NULL)
933 free (codebuf);
935 if (loaderbuf != NULL)
936 free (loaderbuf);
938 return count;
941 static long
942 bfd_pef_count_symbols (abfd)
943 bfd *abfd;
945 return bfd_pef_parse_symbols (abfd, NULL);
948 static long
949 bfd_pef_get_symtab_upper_bound (abfd)
950 bfd *abfd;
952 long nsyms = bfd_pef_count_symbols (abfd);
953 if (nsyms < 0) { return nsyms; }
954 return ((nsyms + 1) * sizeof (asymbol *));
957 static long
958 bfd_pef_get_symtab (abfd, alocation)
959 bfd *abfd;
960 asymbol **alocation;
962 long i;
963 asymbol *syms;
964 long ret;
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);
978 if (ret != nsyms) {
979 return 0;
982 return ret;
985 static asymbol *
986 bfd_pef_make_empty_symbol (abfd)
987 bfd *abfd;
989 return (asymbol *) bfd_alloc (abfd, sizeof (asymbol));
992 static void
993 bfd_pef_get_symbol_info (abfd, symbol, ret)
994 bfd *abfd ATTRIBUTE_UNUSED;
995 asymbol *symbol;
996 symbol_info *ret;
998 bfd_symbol_info (symbol, ret);
1001 static int
1002 bfd_pef_sizeof_headers (abfd, exec)
1003 bfd *abfd ATTRIBUTE_UNUSED;
1004 boolean exec ATTRIBUTE_UNUSED;
1006 return 0;
1009 const bfd_target pef_vec =
1011 "pef", /* name */
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 */
1030 _bfd_dummy_target,
1031 bfd_pef_object_p, /* bfd_check_format */
1032 _bfd_dummy_target,
1033 _bfd_dummy_target,
1035 { /* bfd_set_format */
1036 bfd_false,
1037 bfd_pef_mkobject,
1038 bfd_false,
1039 bfd_false,
1041 { /* bfd_write_contents */
1042 bfd_false,
1043 bfd_true,
1044 bfd_false,
1045 bfd_false,
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),
1058 NULL,
1060 NULL
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
1071 static int
1072 bfd_pef_xlib_read_header (abfd, header)
1073 bfd *abfd;
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);
1103 return 0;
1107 bfd_pef_xlib_scan (abfd, header)
1108 bfd *abfd;
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))) {
1115 return -1;
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;
1128 return 0;
1131 static const bfd_target *
1132 bfd_pef_xlib_object_p (abfd)
1133 bfd *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);
1142 return NULL;
1145 if (bfd_pef_xlib_scan (abfd, &header) != 0) {
1146 abfd->tdata.pef_xlib_data = NULL;
1147 bfd_set_error (bfd_error_wrong_format);
1148 return NULL;
1151 return abfd->xvec;
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 */
1175 _bfd_dummy_target,
1176 bfd_pef_xlib_object_p, /* bfd_check_format */
1177 _bfd_dummy_target,
1178 _bfd_dummy_target,
1180 { /* bfd_set_format */
1181 bfd_false,
1182 bfd_pef_mkobject,
1183 bfd_false,
1184 bfd_false,
1186 { /* bfd_write_contents */
1187 bfd_false,
1188 bfd_true,
1189 bfd_false,
1190 bfd_false,
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),
1203 NULL,
1205 NULL