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