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