Remove bfd stub function casts.
[external/binutils.git] / bfd / pef.c
1 /* PEF support for BFD.
2    Copyright (C) 1999-2018 Free Software Foundation, Inc.
3
4    This file is part of BFD, the Binary File Descriptor library.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20
21 /* PEF (Preferred Executable Format) is the binary file format for late
22    classic Mac OS versions (before Darwin).  It is supported by both m68k
23    and PowerPc.  It is also called CFM (Code Fragment Manager).  */
24
25 #include "sysdep.h"
26 #include "safe-ctype.h"
27 #include "pef.h"
28 #include "pef-traceback.h"
29 #include "bfd.h"
30 #include "libbfd.h"
31 #include "libiberty.h"
32
33 #ifndef BFD_IO_FUNCS
34 #define BFD_IO_FUNCS 0
35 #endif
36
37 #define bfd_pef_close_and_cleanup                   _bfd_generic_close_and_cleanup
38 #define bfd_pef_bfd_free_cached_info                _bfd_generic_bfd_free_cached_info
39 #define bfd_pef_new_section_hook                    _bfd_generic_new_section_hook
40 #define bfd_pef_bfd_is_local_label_name             bfd_generic_is_local_label_name
41 #define bfd_pef_bfd_is_target_special_symbol        _bfd_bool_bfd_asymbol_false
42 #define bfd_pef_get_lineno                          _bfd_nosymbols_get_lineno
43 #define bfd_pef_find_nearest_line                   _bfd_nosymbols_find_nearest_line
44 #define bfd_pef_find_line                           _bfd_nosymbols_find_line
45 #define bfd_pef_find_inliner_info                   _bfd_nosymbols_find_inliner_info
46 #define bfd_pef_get_symbol_version_string           _bfd_nosymbols_get_symbol_version_string
47 #define bfd_pef_bfd_make_debug_symbol               _bfd_nosymbols_bfd_make_debug_symbol
48 #define bfd_pef_read_minisymbols                    _bfd_generic_read_minisymbols
49 #define bfd_pef_minisymbol_to_symbol                _bfd_generic_minisymbol_to_symbol
50 #define bfd_pef_set_arch_mach                       _bfd_generic_set_arch_mach
51 #define bfd_pef_get_section_contents                _bfd_generic_get_section_contents
52 #define bfd_pef_set_section_contents                _bfd_generic_set_section_contents
53 #define bfd_pef_bfd_get_relocated_section_contents  bfd_generic_get_relocated_section_contents
54 #define bfd_pef_bfd_relax_section                   bfd_generic_relax_section
55 #define bfd_pef_bfd_gc_sections                     bfd_generic_gc_sections
56 #define bfd_pef_bfd_lookup_section_flags            bfd_generic_lookup_section_flags
57 #define bfd_pef_bfd_merge_sections                  bfd_generic_merge_sections
58 #define bfd_pef_bfd_is_group_section                bfd_generic_is_group_section
59 #define bfd_pef_bfd_discard_group                   bfd_generic_discard_group
60 #define bfd_pef_section_already_linked              _bfd_generic_section_already_linked
61 #define bfd_pef_bfd_define_common_symbol            bfd_generic_define_common_symbol
62 #define bfd_pef_bfd_define_start_stop               bfd_generic_define_start_stop
63 #define bfd_pef_bfd_link_hash_table_create          _bfd_generic_link_hash_table_create
64 #define bfd_pef_bfd_link_add_symbols                _bfd_generic_link_add_symbols
65 #define bfd_pef_bfd_link_just_syms                  _bfd_generic_link_just_syms
66 #define bfd_pef_bfd_copy_link_hash_symbol_type \
67   _bfd_generic_copy_link_hash_symbol_type
68 #define bfd_pef_bfd_final_link                      _bfd_generic_final_link
69 #define bfd_pef_bfd_link_split_section              _bfd_generic_link_split_section
70 #define bfd_pef_get_section_contents_in_window      _bfd_generic_get_section_contents_in_window
71 #define bfd_pef_bfd_link_check_relocs               _bfd_generic_link_check_relocs
72
73 static int
74 bfd_pef_parse_traceback_table (bfd *abfd,
75                                asection *section,
76                                unsigned char *buf,
77                                size_t len,
78                                size_t pos,
79                                asymbol *sym,
80                                FILE *file)
81 {
82   struct traceback_table table;
83   size_t offset;
84   const char *s;
85   asymbol tmpsymbol;
86
87   if (sym == NULL)
88     sym = & tmpsymbol;
89
90   sym->name = NULL;
91   sym->value = 0;
92   sym->the_bfd = abfd;
93   sym->section = section;
94   sym->flags = 0;
95   sym->udata.i = 0;
96
97   /* memcpy is fine since all fields are unsigned char.  */
98   if ((pos + 8) > len)
99     return -1;
100   memcpy (&table, buf + pos, 8);
101
102   /* Calling code relies on returned symbols having a name and
103      correct offset.  */
104   if ((table.lang != TB_C) && (table.lang != TB_CPLUSPLUS))
105     return -1;
106
107   if (! (table.flags2 & TB_NAME_PRESENT))
108     return -1;
109
110   if (! (table.flags1 & TB_HAS_TBOFF))
111     return -1;
112
113   offset = 8;
114
115   if ((table.flags5 & TB_FLOATPARAMS) || (table.fixedparams))
116     offset += 4;
117
118   if (table.flags1 & TB_HAS_TBOFF)
119     {
120       struct traceback_table_tboff off;
121
122       if ((pos + offset + 4) > len)
123         return -1;
124       off.tb_offset = bfd_getb32 (buf + pos + offset);
125       offset += 4;
126
127       /* Need to subtract 4 because the offset includes the 0x0L
128          preceding the table.  */
129       if (file != NULL)
130         fprintf (file, " [offset = 0x%lx]", off.tb_offset);
131
132       if ((file == NULL) && ((off.tb_offset + 4) > (pos + offset)))
133         return -1;
134
135       sym->value = pos - off.tb_offset - 4;
136     }
137
138   if (table.flags2 & TB_INT_HNDL)
139     offset += 4;
140
141   if (table.flags1 & TB_HAS_CTL)
142     {
143       struct traceback_table_anchors anchors;
144
145       if ((pos + offset + 4) > len)
146         return -1;
147       anchors.ctl_info = bfd_getb32 (buf + pos + offset);
148       offset += 4;
149
150       if (anchors.ctl_info > 1024)
151         return -1;
152
153       offset += anchors.ctl_info * 4;
154     }
155
156   if (table.flags2 & TB_NAME_PRESENT)
157     {
158       struct traceback_table_routine name;
159       char *namebuf;
160
161       if ((pos + offset + 2) > len)
162         return -1;
163       name.name_len = bfd_getb16 (buf + pos + offset);
164       offset += 2;
165
166       if (name.name_len > 4096)
167         return -1;
168
169       if ((pos + offset + name.name_len) > len)
170         return -1;
171
172       namebuf = bfd_alloc (abfd, name.name_len + 1);
173       if (namebuf == NULL)
174         return -1;
175
176       memcpy (namebuf, buf + pos + offset, name.name_len);
177       namebuf[name.name_len] = '\0';
178
179       /* Strip leading period inserted by compiler.  */
180       if (namebuf[0] == '.')
181         memmove (namebuf, namebuf + 1, name.name_len + 1);
182
183       sym->name = namebuf;
184
185       for (s = sym->name; (*s != '\0'); s++)
186         if (! ISPRINT (*s))
187           return -1;
188
189       offset += name.name_len;
190     }
191
192   if (table.flags2 & TB_USES_ALLOCA)
193     offset += 4;
194
195   if (table.flags4 & TB_HAS_VEC_INFO)
196     offset += 4;
197
198   if (file != NULL)
199     fprintf (file, " [length = 0x%lx]", (unsigned long) offset);
200
201   return offset;
202 }
203
204 static void
205 bfd_pef_print_symbol (bfd *abfd,
206                       void * afile,
207                       asymbol *symbol,
208                       bfd_print_symbol_type how)
209 {
210   FILE *file = (FILE *) afile;
211
212   switch (how)
213     {
214     case bfd_print_symbol_name:
215       fprintf (file, "%s", symbol->name);
216       break;
217     default:
218       bfd_print_symbol_vandf (abfd, (void *) file, symbol);
219       fprintf (file, " %-5s %s", symbol->section->name, symbol->name);
220       if (CONST_STRNEQ (symbol->name, "__traceback_"))
221         {
222           unsigned char *buf = xmalloc (symbol->udata.i);
223           size_t offset = symbol->value + 4;
224           size_t len = symbol->udata.i;
225           int ret;
226
227           bfd_get_section_contents (abfd, symbol->section, buf, offset, len);
228           ret = bfd_pef_parse_traceback_table (abfd, symbol->section, buf,
229                                                len, 0, NULL, file);
230           if (ret < 0)
231             fprintf (file, " [ERROR]");
232           free (buf);
233         }
234     }
235 }
236
237 static void
238 bfd_pef_convert_architecture (unsigned long architecture,
239                               enum bfd_architecture *type,
240                               unsigned long *subtype)
241 {
242   const unsigned long ARCH_POWERPC = 0x70777063; /* 'pwpc'.  */
243   const unsigned long ARCH_M68K = 0x6d36386b; /* 'm68k'.  */
244
245   *subtype = bfd_arch_unknown;
246   *type = bfd_arch_unknown;
247
248   if (architecture == ARCH_POWERPC)
249     *type = bfd_arch_powerpc;
250   else if (architecture == ARCH_M68K)
251     *type = bfd_arch_m68k;
252 }
253
254 static bfd_boolean
255 bfd_pef_mkobject (bfd *abfd ATTRIBUTE_UNUSED)
256 {
257   return TRUE;
258 }
259
260 static const char *bfd_pef_section_name (bfd_pef_section *section)
261 {
262   switch (section->section_kind)
263     {
264     case BFD_PEF_SECTION_CODE: return "code";
265     case BFD_PEF_SECTION_UNPACKED_DATA: return "unpacked-data";
266     case BFD_PEF_SECTION_PACKED_DATA: return "packed-data";
267     case BFD_PEF_SECTION_CONSTANT: return "constant";
268     case BFD_PEF_SECTION_LOADER: return "loader";
269     case BFD_PEF_SECTION_DEBUG: return "debug";
270     case BFD_PEF_SECTION_EXEC_DATA: return "exec-data";
271     case BFD_PEF_SECTION_EXCEPTION: return "exception";
272     case BFD_PEF_SECTION_TRACEBACK: return "traceback";
273     default: return "unknown";
274     }
275 }
276
277 static unsigned long bfd_pef_section_flags (bfd_pef_section *section)
278 {
279   switch (section->section_kind)
280     {
281     case BFD_PEF_SECTION_CODE:
282       return SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC | SEC_CODE;
283     case BFD_PEF_SECTION_UNPACKED_DATA:
284     case BFD_PEF_SECTION_PACKED_DATA:
285     case BFD_PEF_SECTION_CONSTANT:
286     case BFD_PEF_SECTION_LOADER:
287     case BFD_PEF_SECTION_DEBUG:
288     case BFD_PEF_SECTION_EXEC_DATA:
289     case BFD_PEF_SECTION_EXCEPTION:
290     case BFD_PEF_SECTION_TRACEBACK:
291     default:
292       return SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
293     }
294 }
295
296 static asection *
297 bfd_pef_make_bfd_section (bfd *abfd, bfd_pef_section *section)
298 {
299   asection *bfdsec;
300   const char *name = bfd_pef_section_name (section);
301
302   bfdsec = bfd_make_section_anyway (abfd, name);
303   if (bfdsec == NULL)
304     return NULL;
305
306   bfdsec->vma = section->default_address + section->container_offset;
307   bfdsec->lma = section->default_address + section->container_offset;
308   bfdsec->size = section->container_length;
309   bfdsec->filepos = section->container_offset;
310   bfdsec->alignment_power = section->alignment;
311
312   bfdsec->flags = bfd_pef_section_flags (section);
313
314   return bfdsec;
315 }
316
317 int
318 bfd_pef_parse_loader_header (bfd *abfd ATTRIBUTE_UNUSED,
319                              unsigned char *buf,
320                              size_t len,
321                              bfd_pef_loader_header *header)
322 {
323   BFD_ASSERT (len == 56);
324
325   header->main_section = bfd_getb32 (buf);
326   header->main_offset = bfd_getb32 (buf + 4);
327   header->init_section = bfd_getb32 (buf + 8);
328   header->init_offset = bfd_getb32 (buf + 12);
329   header->term_section = bfd_getb32 (buf + 16);
330   header->term_offset = bfd_getb32 (buf + 20);
331   header->imported_library_count = bfd_getb32 (buf + 24);
332   header->total_imported_symbol_count = bfd_getb32 (buf + 28);
333   header->reloc_section_count = bfd_getb32 (buf + 32);
334   header->reloc_instr_offset = bfd_getb32 (buf + 36);
335   header->loader_strings_offset = bfd_getb32 (buf + 40);
336   header->export_hash_offset = bfd_getb32 (buf + 44);
337   header->export_hash_table_power = bfd_getb32 (buf + 48);
338   header->exported_symbol_count = bfd_getb32 (buf + 52);
339
340   return 0;
341 }
342
343 int
344 bfd_pef_parse_imported_library (bfd *abfd ATTRIBUTE_UNUSED,
345                                 unsigned char *buf,
346                                 size_t len,
347                                 bfd_pef_imported_library *header)
348 {
349   BFD_ASSERT (len == 24);
350
351   header->name_offset = bfd_getb32 (buf);
352   header->old_implementation_version = bfd_getb32 (buf + 4);
353   header->current_version = bfd_getb32 (buf + 8);
354   header->imported_symbol_count = bfd_getb32 (buf + 12);
355   header->first_imported_symbol = bfd_getb32 (buf + 16);
356   header->options = buf[20];
357   header->reserved_a = buf[21];
358   header->reserved_b = bfd_getb16 (buf + 22);
359
360   return 0;
361 }
362
363 int
364 bfd_pef_parse_imported_symbol (bfd *abfd ATTRIBUTE_UNUSED,
365                                unsigned char *buf,
366                                size_t len,
367                                bfd_pef_imported_symbol *symbol)
368 {
369   unsigned long value;
370
371   BFD_ASSERT (len == 4);
372
373   value = bfd_getb32 (buf);
374   symbol->symbol_class = value >> 24;
375   symbol->name = value & 0x00ffffff;
376
377   return 0;
378 }
379
380 int
381 bfd_pef_scan_section (bfd *abfd, bfd_pef_section *section)
382 {
383   unsigned char buf[28];
384
385   bfd_seek (abfd, section->header_offset, SEEK_SET);
386   if (bfd_bread ((void *) buf, 28, abfd) != 28)
387     return -1;
388
389   section->name_offset = bfd_h_get_32 (abfd, buf);
390   section->default_address = bfd_h_get_32 (abfd, buf + 4);
391   section->total_length = bfd_h_get_32 (abfd, buf + 8);
392   section->unpacked_length = bfd_h_get_32 (abfd, buf + 12);
393   section->container_length = bfd_h_get_32 (abfd, buf + 16);
394   section->container_offset = bfd_h_get_32 (abfd, buf + 20);
395   section->section_kind = buf[24];
396   section->share_kind = buf[25];
397   section->alignment = buf[26];
398   section->reserved = buf[27];
399
400   section->bfd_section = bfd_pef_make_bfd_section (abfd, section);
401   if (section->bfd_section == NULL)
402     return -1;
403
404   return 0;
405 }
406
407 void
408 bfd_pef_print_loader_header (bfd *abfd ATTRIBUTE_UNUSED,
409                              bfd_pef_loader_header *header,
410                              FILE *file)
411 {
412   fprintf (file, "main_section: %ld\n", header->main_section);
413   fprintf (file, "main_offset: %lu\n", header->main_offset);
414   fprintf (file, "init_section: %ld\n", header->init_section);
415   fprintf (file, "init_offset: %lu\n", header->init_offset);
416   fprintf (file, "term_section: %ld\n", header->term_section);
417   fprintf (file, "term_offset: %lu\n", header->term_offset);
418   fprintf (file, "imported_library_count: %lu\n",
419            header->imported_library_count);
420   fprintf (file, "total_imported_symbol_count: %lu\n",
421            header->total_imported_symbol_count);
422   fprintf (file, "reloc_section_count: %lu\n", header->reloc_section_count);
423   fprintf (file, "reloc_instr_offset: %lu\n", header->reloc_instr_offset);
424   fprintf (file, "loader_strings_offset: %lu\n",
425            header->loader_strings_offset);
426   fprintf (file, "export_hash_offset: %lu\n", header->export_hash_offset);
427   fprintf (file, "export_hash_table_power: %lu\n",
428            header->export_hash_table_power);
429   fprintf (file, "exported_symbol_count: %lu\n",
430            header->exported_symbol_count);
431 }
432
433 int
434 bfd_pef_print_loader_section (bfd *abfd, FILE *file)
435 {
436   bfd_pef_loader_header header;
437   asection *loadersec = NULL;
438   unsigned char *loaderbuf = NULL;
439   size_t loaderlen = 0;
440
441   loadersec = bfd_get_section_by_name (abfd, "loader");
442   if (loadersec == NULL)
443     return -1;
444
445   loaderlen = loadersec->size;
446   loaderbuf = bfd_malloc (loaderlen);
447
448   if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0
449       || bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen
450       || loaderlen < 56
451       || bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header) < 0)
452     {
453       free (loaderbuf);
454       return -1;
455     }
456
457   bfd_pef_print_loader_header (abfd, &header, file);
458   return 0;
459 }
460
461 int
462 bfd_pef_scan_start_address (bfd *abfd)
463 {
464   bfd_pef_loader_header header;
465   asection *section;
466
467   asection *loadersec = NULL;
468   unsigned char *loaderbuf = NULL;
469   size_t loaderlen = 0;
470   int ret;
471
472   loadersec = bfd_get_section_by_name (abfd, "loader");
473   if (loadersec == NULL)
474     goto end;
475
476   loaderlen = loadersec->size;
477   loaderbuf = bfd_malloc (loaderlen);
478   if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0)
479     goto error;
480   if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen)
481     goto error;
482
483   if (loaderlen < 56)
484     goto error;
485   ret = bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header);
486   if (ret < 0)
487     goto error;
488
489   if (header.main_section < 0)
490     goto end;
491
492   for (section = abfd->sections; section != NULL; section = section->next)
493     if ((long) (section->index + 1) == header.main_section)
494       break;
495
496   if (section == NULL)
497     goto error;
498
499   abfd->start_address = section->vma + header.main_offset;
500
501  end:
502   if (loaderbuf != NULL)
503     free (loaderbuf);
504   return 0;
505
506  error:
507   if (loaderbuf != NULL)
508     free (loaderbuf);
509   return -1;
510 }
511
512 int
513 bfd_pef_scan (bfd *abfd,
514               bfd_pef_header *header,
515               bfd_pef_data_struct *mdata)
516 {
517   unsigned int i;
518   enum bfd_architecture cputype;
519   unsigned long cpusubtype;
520
521   mdata->header = *header;
522
523   bfd_pef_convert_architecture (header->architecture, &cputype, &cpusubtype);
524   if (cputype == bfd_arch_unknown)
525     {
526       _bfd_error_handler (_("bfd_pef_scan: unknown architecture 0x%lx"),
527                           header->architecture);
528       return -1;
529     }
530   bfd_set_arch_mach (abfd, cputype, cpusubtype);
531
532   mdata->header = *header;
533
534   abfd->flags = (abfd->xvec->object_flags
535                  | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS)));
536
537   if (header->section_count != 0)
538     {
539       mdata->sections = bfd_alloc (abfd, header->section_count * sizeof (bfd_pef_section));
540
541       if (mdata->sections == NULL)
542         return -1;
543
544       for (i = 0; i < header->section_count; i++)
545         {
546           bfd_pef_section *cur = &mdata->sections[i];
547           cur->header_offset = 40 + (i * 28);
548           if (bfd_pef_scan_section (abfd, cur) < 0)
549             return -1;
550         }
551     }
552
553   if (bfd_pef_scan_start_address (abfd) < 0)
554     return -1;
555
556   abfd->tdata.pef_data = mdata;
557
558   return 0;
559 }
560
561 static int
562 bfd_pef_read_header (bfd *abfd, bfd_pef_header *header)
563 {
564   unsigned char buf[40];
565
566   bfd_seek (abfd, 0, SEEK_SET);
567
568   if (bfd_bread ((void *) buf, 40, abfd) != 40)
569     return -1;
570
571   header->tag1 = bfd_getb32 (buf);
572   header->tag2 = bfd_getb32 (buf + 4);
573   header->architecture = bfd_getb32 (buf + 8);
574   header->format_version = bfd_getb32 (buf + 12);
575   header->timestamp = bfd_getb32 (buf + 16);
576   header->old_definition_version = bfd_getb32 (buf + 20);
577   header->old_implementation_version = bfd_getb32 (buf + 24);
578   header->current_version = bfd_getb32 (buf + 28);
579   header->section_count = bfd_getb32 (buf + 32) + 1;
580   header->instantiated_section_count = bfd_getb32 (buf + 34);
581   header->reserved = bfd_getb32 (buf + 36);
582
583   return 0;
584 }
585
586 static const bfd_target *
587 bfd_pef_object_p (bfd *abfd)
588 {
589   bfd_pef_header header;
590   bfd_pef_data_struct *mdata;
591
592   if (bfd_pef_read_header (abfd, &header) != 0)
593     goto wrong;
594
595   if (header.tag1 != BFD_PEF_TAG1 || header.tag2 != BFD_PEF_TAG2)
596     goto wrong;
597
598   mdata = (bfd_pef_data_struct *) bfd_zalloc (abfd, sizeof (*mdata));
599   if (mdata == NULL)
600     goto fail;
601
602   if (bfd_pef_scan (abfd, &header, mdata))
603     goto wrong;
604
605   return abfd->xvec;
606
607  wrong:
608   bfd_set_error (bfd_error_wrong_format);
609
610  fail:
611   return NULL;
612 }
613
614 static int
615 bfd_pef_parse_traceback_tables (bfd *abfd,
616                                 asection *sec,
617                                 unsigned char *buf,
618                                 size_t len,
619                                 long *nsym,
620                                 asymbol **csym)
621 {
622   char *name;
623
624   asymbol function;
625   asymbol traceback;
626
627   const char *const tbprefix = "__traceback_";
628   size_t tbnamelen;
629
630   size_t pos = 0;
631   unsigned long count = 0;
632   int ret;
633
634   for (;;)
635     {
636       /* We're reading symbols two at a time.  */
637       if (csym && ((csym[count] == NULL) || (csym[count + 1] == NULL)))
638         break;
639
640       pos += 3;
641       pos -= (pos % 4);
642
643       while ((pos + 4) <= len)
644         {
645           if (bfd_getb32 (buf + pos) == 0)
646             break;
647           pos += 4;
648         }
649
650       if ((pos + 4) > len)
651         break;
652
653       ret = bfd_pef_parse_traceback_table (abfd, sec, buf, len, pos + 4,
654                                            &function, 0);
655       if (ret < 0)
656         {
657           /* Skip over 0x0L to advance to next possible traceback table.  */
658           pos += 4;
659           continue;
660         }
661
662       BFD_ASSERT (function.name != NULL);
663
664       /* Don't bother to compute the name if we are just
665          counting symbols.  */
666       if (csym)
667         {
668           tbnamelen = strlen (tbprefix) + strlen (function.name);
669           name = bfd_alloc (abfd, tbnamelen + 1);
670           if (name == NULL)
671             {
672               bfd_release (abfd, (void *) function.name);
673               function.name = NULL;
674               break;
675             }
676           snprintf (name, tbnamelen + 1, "%s%s", tbprefix, function.name);
677           traceback.name = name;
678           traceback.value = pos;
679           traceback.the_bfd = abfd;
680           traceback.section = sec;
681           traceback.flags = 0;
682           traceback.udata.i = ret;
683
684           *(csym[count]) = function;
685           *(csym[count + 1]) = traceback;
686         }
687
688       pos += ret;
689       count += 2;
690     }
691
692   *nsym = count;
693   return 0;
694 }
695
696 static int
697 bfd_pef_parse_function_stub (bfd *abfd ATTRIBUTE_UNUSED,
698                              unsigned char *buf,
699                              size_t len,
700                              unsigned long *offset)
701 {
702   BFD_ASSERT (len == 24);
703
704   if ((bfd_getb32 (buf) & 0xffff0000) != 0x81820000)
705     return -1;
706   if (bfd_getb32 (buf + 4) != 0x90410014)
707     return -1;
708   if (bfd_getb32 (buf + 8) != 0x800c0000)
709     return -1;
710   if (bfd_getb32 (buf + 12) != 0x804c0004)
711     return -1;
712   if (bfd_getb32 (buf + 16) != 0x7c0903a6)
713     return -1;
714   if (bfd_getb32 (buf + 20) != 0x4e800420)
715     return -1;
716
717   if (offset != NULL)
718     *offset = (bfd_getb32 (buf) & 0x0000ffff) / 4;
719
720   return 0;
721 }
722
723 static int
724 bfd_pef_parse_function_stubs (bfd *abfd,
725                               asection *codesec,
726                               unsigned char *codebuf,
727                               size_t codelen,
728                               unsigned char *loaderbuf,
729                               size_t loaderlen,
730                               unsigned long *nsym,
731                               asymbol **csym)
732 {
733   const char *const sprefix = "__stub_";
734   size_t codepos = 0;
735   unsigned long count = 0;
736   bfd_pef_loader_header header;
737   bfd_pef_imported_library *libraries = NULL;
738   bfd_pef_imported_symbol *imports = NULL;
739   unsigned long i;
740   int ret;
741
742   if (loaderlen < 56)
743     goto error;
744
745   ret = bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header);
746   if (ret < 0)
747     goto error;
748
749   libraries = bfd_malloc
750     (header.imported_library_count * sizeof (bfd_pef_imported_library));
751   imports = bfd_malloc
752     (header.total_imported_symbol_count * sizeof (bfd_pef_imported_symbol));
753
754   if (loaderlen < (56 + (header.imported_library_count * 24)))
755     goto error;
756   for (i = 0; i < header.imported_library_count; i++)
757     {
758       ret = bfd_pef_parse_imported_library
759         (abfd, loaderbuf + 56 + (i * 24), 24, &libraries[i]);
760       if (ret < 0)
761         goto error;
762     }
763
764   if (loaderlen < (56 + (header.imported_library_count * 24)
765                    + (header.total_imported_symbol_count * 4)))
766     goto error;
767   for (i = 0; i < header.total_imported_symbol_count; i++)
768     {
769       ret = (bfd_pef_parse_imported_symbol
770              (abfd,
771               loaderbuf + 56 + (header.imported_library_count * 24) + (i * 4),
772               4, &imports[i]));
773       if (ret < 0)
774         goto error;
775     }
776
777   codepos = 0;
778
779   for (;;)
780     {
781       asymbol sym;
782       const char *symname;
783       char *name;
784       unsigned long sym_index;
785
786       if (csym && (csym[count] == NULL))
787         break;
788
789       codepos += 3;
790       codepos -= (codepos % 4);
791
792       while ((codepos + 4) <= codelen)
793         {
794           if ((bfd_getb32 (codebuf + codepos) & 0xffff0000) == 0x81820000)
795             break;
796           codepos += 4;
797         }
798
799       if ((codepos + 4) > codelen)
800         break;
801
802       ret = bfd_pef_parse_function_stub (abfd, codebuf + codepos, 24, &sym_index);
803       if (ret < 0)
804         {
805           codepos += 24;
806           continue;
807         }
808
809       if (sym_index >= header.total_imported_symbol_count)
810         {
811           codepos += 24;
812           continue;
813         }
814
815       {
816         size_t max, namelen;
817         const char *s;
818
819         if (loaderlen < (header.loader_strings_offset + imports[sym_index].name))
820           goto error;
821
822         max = loaderlen - (header.loader_strings_offset + imports[sym_index].name);
823         symname = (char *) loaderbuf;
824         symname += header.loader_strings_offset + imports[sym_index].name;
825         namelen = 0;
826         for (s = symname; s < (symname + max); s++)
827           {
828             if (*s == '\0')
829               break;
830             if (! ISPRINT (*s))
831               goto error;
832             namelen++;
833           }
834         if (*s != '\0')
835           goto error;
836
837         name = bfd_alloc (abfd, strlen (sprefix) + namelen + 1);
838         if (name == NULL)
839           break;
840
841         snprintf (name, strlen (sprefix) + namelen + 1, "%s%s",
842                   sprefix, symname);
843         sym.name = name;
844       }
845
846       sym.value = codepos;
847       sym.the_bfd = abfd;
848       sym.section = codesec;
849       sym.flags = 0;
850       sym.udata.i = 0;
851
852       codepos += 24;
853
854       if (csym != NULL)
855         *(csym[count]) = sym;
856
857       count++;
858     }
859
860   goto end;
861
862  end:
863   if (libraries != NULL)
864     free (libraries);
865   if (imports != NULL)
866     free (imports);
867   *nsym = count;
868   return 0;
869
870  error:
871   if (libraries != NULL)
872     free (libraries);
873   if (imports != NULL)
874     free (imports);
875   *nsym = count;
876   return -1;
877 }
878
879 static long
880 bfd_pef_parse_symbols (bfd *abfd, asymbol **csym)
881 {
882   unsigned long count = 0;
883
884   asection *codesec = NULL;
885   unsigned char *codebuf = NULL;
886   size_t codelen = 0;
887
888   asection *loadersec = NULL;
889   unsigned char *loaderbuf = NULL;
890   size_t loaderlen = 0;
891
892   codesec = bfd_get_section_by_name (abfd, "code");
893   if (codesec != NULL)
894     {
895       codelen = codesec->size;
896       codebuf = bfd_malloc (codelen);
897       if (bfd_seek (abfd, codesec->filepos, SEEK_SET) < 0)
898         goto end;
899       if (bfd_bread ((void *) codebuf, codelen, abfd) != codelen)
900         goto end;
901     }
902
903   loadersec = bfd_get_section_by_name (abfd, "loader");
904   if (loadersec != NULL)
905     {
906       loaderlen = loadersec->size;
907       loaderbuf = bfd_malloc (loaderlen);
908       if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0)
909         goto end;
910       if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen)
911         goto end;
912     }
913
914   count = 0;
915   if (codesec != NULL)
916     {
917       long ncount = 0;
918       bfd_pef_parse_traceback_tables (abfd, codesec, codebuf, codelen,
919                                       &ncount, csym);
920       count += ncount;
921     }
922
923   if ((codesec != NULL) && (loadersec != NULL))
924     {
925       unsigned long ncount = 0;
926       bfd_pef_parse_function_stubs
927         (abfd, codesec, codebuf, codelen, loaderbuf, loaderlen, &ncount,
928          (csym != NULL) ? (csym + count) : NULL);
929       count += ncount;
930     }
931
932   if (csym != NULL)
933     csym[count] = NULL;
934
935  end:
936   if (codebuf != NULL)
937     free (codebuf);
938
939   if (loaderbuf != NULL)
940     free (loaderbuf);
941
942   return count;
943 }
944
945 static long
946 bfd_pef_count_symbols (bfd *abfd)
947 {
948   return bfd_pef_parse_symbols (abfd, NULL);
949 }
950
951 static long
952 bfd_pef_get_symtab_upper_bound (bfd *abfd)
953 {
954   long nsyms = bfd_pef_count_symbols (abfd);
955
956   if (nsyms < 0)
957     return nsyms;
958   return ((nsyms + 1) * sizeof (asymbol *));
959 }
960
961 static long
962 bfd_pef_canonicalize_symtab (bfd *abfd, asymbol **alocation)
963 {
964   long i;
965   asymbol *syms;
966   long ret;
967   long nsyms = bfd_pef_count_symbols (abfd);
968
969   if (nsyms < 0)
970     return nsyms;
971
972   syms = bfd_alloc (abfd, nsyms * sizeof (asymbol));
973   if (syms == NULL)
974     return -1;
975
976   for (i = 0; i < nsyms; i++)
977     alocation[i] = &syms[i];
978
979   alocation[nsyms] = NULL;
980
981   ret = bfd_pef_parse_symbols (abfd, alocation);
982   if (ret != nsyms)
983     return 0;
984
985   return ret;
986 }
987
988 #define bfd_pef_make_empty_symbol _bfd_generic_make_empty_symbol
989
990 static void
991 bfd_pef_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
992                          asymbol *symbol,
993                          symbol_info *ret)
994 {
995   bfd_symbol_info (symbol, ret);
996 }
997
998 static int
999 bfd_pef_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
1000                         struct bfd_link_info *info ATTRIBUTE_UNUSED)
1001 {
1002   return 0;
1003 }
1004
1005 const bfd_target pef_vec =
1006 {
1007   "pef",                        /* Name.  */
1008   bfd_target_pef_flavour,       /* Flavour.  */
1009   BFD_ENDIAN_BIG,               /* Byteorder.  */
1010   BFD_ENDIAN_BIG,               /* Header_byteorder.  */
1011   (HAS_RELOC | EXEC_P |         /* Object flags.  */
1012    HAS_LINENO | HAS_DEBUG |
1013    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
1014   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
1015    | SEC_ROM | SEC_HAS_CONTENTS), /* Section_flags.  */
1016   0,                            /* Symbol_leading_char.  */
1017   ' ',                          /* AR_pad_char.  */
1018   16,                           /* AR_max_namelen.  */
1019   0,                            /* match priority.  */
1020   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1021   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1022   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* Data.  */
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,   /* Headers.  */
1026   {                             /* bfd_check_format.  */
1027     _bfd_dummy_target,
1028     bfd_pef_object_p,           /* bfd_check_format.  */
1029     _bfd_dummy_target,
1030     _bfd_dummy_target,
1031   },
1032   {                             /* bfd_set_format.  */
1033     _bfd_bool_bfd_false_error,
1034     bfd_pef_mkobject,
1035     _bfd_bool_bfd_false_error,
1036     _bfd_bool_bfd_false_error,
1037   },
1038   {                             /* bfd_write_contents.  */
1039     _bfd_bool_bfd_false_error,
1040     _bfd_bool_bfd_true,
1041     _bfd_bool_bfd_false_error,
1042     _bfd_bool_bfd_false_error,
1043   },
1044
1045   BFD_JUMP_TABLE_GENERIC (bfd_pef),
1046   BFD_JUMP_TABLE_COPY (_bfd_generic),
1047   BFD_JUMP_TABLE_CORE (_bfd_nocore),
1048   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
1049   BFD_JUMP_TABLE_SYMBOLS (bfd_pef),
1050   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1051   BFD_JUMP_TABLE_WRITE (bfd_pef),
1052   BFD_JUMP_TABLE_LINK (bfd_pef),
1053   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1054
1055   NULL,
1056
1057   NULL
1058 };
1059
1060 #define bfd_pef_xlib_close_and_cleanup              _bfd_generic_close_and_cleanup
1061 #define bfd_pef_xlib_bfd_free_cached_info           _bfd_generic_bfd_free_cached_info
1062 #define bfd_pef_xlib_new_section_hook               _bfd_generic_new_section_hook
1063 #define bfd_pef_xlib_get_section_contents           _bfd_generic_get_section_contents
1064 #define bfd_pef_xlib_set_section_contents           _bfd_generic_set_section_contents
1065 #define bfd_pef_xlib_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
1066 #define bfd_pef_xlib_set_section_contents_in_window _bfd_generic_set_section_contents_in_window
1067
1068 static int
1069 bfd_pef_xlib_read_header (bfd *abfd, bfd_pef_xlib_header *header)
1070 {
1071   unsigned char buf[80];
1072
1073   bfd_seek (abfd, 0, SEEK_SET);
1074
1075   if (bfd_bread ((void *) buf, sizeof buf, abfd) != sizeof buf)
1076     return -1;
1077
1078   header->tag1 = bfd_getb32 (buf);
1079   header->tag2 = bfd_getb32 (buf + 4);
1080   header->current_format = bfd_getb32 (buf + 8);
1081   header->container_strings_offset = bfd_getb32 (buf + 12);
1082   header->export_hash_offset = bfd_getb32 (buf + 16);
1083   header->export_key_offset = bfd_getb32 (buf + 20);
1084   header->export_symbol_offset = bfd_getb32 (buf + 24);
1085   header->export_names_offset = bfd_getb32 (buf + 28);
1086   header->export_hash_table_power = bfd_getb32 (buf + 32);
1087   header->exported_symbol_count = bfd_getb32 (buf + 36);
1088   header->frag_name_offset = bfd_getb32 (buf + 40);
1089   header->frag_name_length = bfd_getb32 (buf + 44);
1090   header->dylib_path_offset = bfd_getb32 (buf + 48);
1091   header->dylib_path_length = bfd_getb32 (buf + 52);
1092   header->cpu_family = bfd_getb32 (buf + 56);
1093   header->cpu_model = bfd_getb32 (buf + 60);
1094   header->date_time_stamp = bfd_getb32 (buf + 64);
1095   header->current_version = bfd_getb32 (buf + 68);
1096   header->old_definition_version = bfd_getb32 (buf + 72);
1097   header->old_implementation_version = bfd_getb32 (buf + 76);
1098
1099   return 0;
1100 }
1101
1102 static int
1103 bfd_pef_xlib_scan (bfd *abfd, bfd_pef_xlib_header *header)
1104 {
1105   bfd_pef_xlib_data_struct *mdata = NULL;
1106
1107   mdata = bfd_alloc (abfd, sizeof (* mdata));
1108   if (mdata == NULL)
1109     return -1;
1110
1111   mdata->header = *header;
1112
1113   abfd->flags = (abfd->xvec->object_flags
1114                  | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS)));
1115
1116   abfd->tdata.pef_xlib_data = mdata;
1117
1118   return 0;
1119 }
1120
1121 static const bfd_target *
1122 bfd_pef_xlib_object_p (bfd *abfd)
1123 {
1124   bfd_pef_xlib_header header;
1125
1126   if (bfd_pef_xlib_read_header (abfd, &header) != 0)
1127     {
1128       bfd_set_error (bfd_error_wrong_format);
1129       return NULL;
1130     }
1131
1132   if ((header.tag1 != BFD_PEF_XLIB_TAG1)
1133       || ((header.tag2 != BFD_PEF_VLIB_TAG2)
1134           && (header.tag2 != BFD_PEF_BLIB_TAG2)))
1135     {
1136       bfd_set_error (bfd_error_wrong_format);
1137       return NULL;
1138     }
1139
1140   if (bfd_pef_xlib_scan (abfd, &header) != 0)
1141     {
1142       bfd_set_error (bfd_error_wrong_format);
1143       return NULL;
1144     }
1145
1146   return abfd->xvec;
1147 }
1148
1149 const bfd_target pef_xlib_vec =
1150 {
1151   "pef-xlib",                   /* Name.  */
1152   bfd_target_pef_xlib_flavour,  /* Flavour.  */
1153   BFD_ENDIAN_BIG,               /* Byteorder */
1154   BFD_ENDIAN_BIG,               /* Header_byteorder.  */
1155   (HAS_RELOC | EXEC_P |         /* Object flags.  */
1156    HAS_LINENO | HAS_DEBUG |
1157    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
1158   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
1159    | SEC_ROM | SEC_HAS_CONTENTS),/* Section_flags.  */
1160   0,                            /* Symbol_leading_char.  */
1161   ' ',                          /* AR_pad_char.  */
1162   16,                           /* AR_max_namelen.  */
1163   0,                            /* match priority.  */
1164   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1165   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1166   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* Data.  */
1167   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1168   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1169   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* Headers.  */
1170   {                             /* bfd_check_format.  */
1171     _bfd_dummy_target,
1172     bfd_pef_xlib_object_p,      /* bfd_check_format.  */
1173     _bfd_dummy_target,
1174     _bfd_dummy_target,
1175   },
1176   {                             /* bfd_set_format.  */
1177     _bfd_bool_bfd_false_error,
1178     bfd_pef_mkobject,
1179     _bfd_bool_bfd_false_error,
1180     _bfd_bool_bfd_false_error,
1181   },
1182   {                             /* bfd_write_contents.  */
1183     _bfd_bool_bfd_false_error,
1184     _bfd_bool_bfd_true,
1185     _bfd_bool_bfd_false_error,
1186     _bfd_bool_bfd_false_error,
1187   },
1188
1189   BFD_JUMP_TABLE_GENERIC (bfd_pef_xlib),
1190   BFD_JUMP_TABLE_COPY (_bfd_generic),
1191   BFD_JUMP_TABLE_CORE (_bfd_nocore),
1192   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
1193   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
1194   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1195   BFD_JUMP_TABLE_WRITE (_bfd_nowrite),
1196   BFD_JUMP_TABLE_LINK (_bfd_nolink),
1197   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1198
1199   NULL,
1200
1201   NULL
1202 };