* configure: Regenerate.
[external/binutils.git] / bfd / pef.c
1 /* PEF support for BFD.
2    Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3    2009, 2011  Free Software Foundation, Inc.
4
5    This file is part of BFD, the Binary File Descriptor library.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21
22 /* PEF (Preferred Executable Format) is the binary file format for late
23    classic Mac OS versions (before Darwin).  It is supported by both m68k
24    and PowerPc.  It is also called CFM (Code Fragment Manager).  */
25
26 #include "sysdep.h"
27 #include "safe-ctype.h"
28 #include "pef.h"
29 #include "pef-traceback.h"
30 #include "bfd.h"
31 #include "libbfd.h"
32 #include "libiberty.h"
33
34 #ifndef BFD_IO_FUNCS
35 #define BFD_IO_FUNCS 0
36 #endif
37
38 #define bfd_pef_close_and_cleanup                   _bfd_generic_close_and_cleanup
39 #define bfd_pef_bfd_free_cached_info                _bfd_generic_bfd_free_cached_info
40 #define bfd_pef_new_section_hook                    _bfd_generic_new_section_hook
41 #define bfd_pef_bfd_is_local_label_name             bfd_generic_is_local_label_name
42 #define bfd_pef_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
43 #define bfd_pef_get_lineno                          _bfd_nosymbols_get_lineno
44 #define bfd_pef_find_nearest_line                   _bfd_nosymbols_find_nearest_line
45 #define bfd_pef_find_inliner_info                   _bfd_nosymbols_find_inliner_info
46 #define bfd_pef_bfd_make_debug_symbol               _bfd_nosymbols_bfd_make_debug_symbol
47 #define bfd_pef_read_minisymbols                    _bfd_generic_read_minisymbols
48 #define bfd_pef_minisymbol_to_symbol                _bfd_generic_minisymbol_to_symbol
49 #define bfd_pef_set_arch_mach                       _bfd_generic_set_arch_mach
50 #define bfd_pef_get_section_contents                _bfd_generic_get_section_contents
51 #define bfd_pef_set_section_contents                _bfd_generic_set_section_contents
52 #define bfd_pef_bfd_get_relocated_section_contents  bfd_generic_get_relocated_section_contents
53 #define bfd_pef_bfd_relax_section                   bfd_generic_relax_section
54 #define bfd_pef_bfd_gc_sections                     bfd_generic_gc_sections
55 #define bfd_pef_bfd_lookup_section_flags            bfd_generic_lookup_section_flags
56 #define bfd_pef_bfd_merge_sections                  bfd_generic_merge_sections
57 #define bfd_pef_bfd_is_group_section                bfd_generic_is_group_section
58 #define bfd_pef_bfd_discard_group                   bfd_generic_discard_group
59 #define bfd_pef_section_already_linked              _bfd_generic_section_already_linked
60 #define bfd_pef_bfd_define_common_symbol            bfd_generic_define_common_symbol
61 #define bfd_pef_bfd_link_hash_table_create          _bfd_generic_link_hash_table_create
62 #define bfd_pef_bfd_link_hash_table_free            _bfd_generic_link_hash_table_free
63 #define bfd_pef_bfd_link_add_symbols                _bfd_generic_link_add_symbols
64 #define bfd_pef_bfd_link_just_syms                  _bfd_generic_link_just_syms
65 #define bfd_pef_bfd_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   struct bfd_preserve preserve;
587   bfd_pef_header header;
588
589   preserve.marker = NULL;
590   if (bfd_pef_read_header (abfd, &header) != 0)
591     goto wrong;
592
593   if (header.tag1 != BFD_PEF_TAG1 || header.tag2 != BFD_PEF_TAG2)
594     goto wrong;
595
596   preserve.marker = bfd_zalloc (abfd, sizeof (bfd_pef_data_struct));
597   if (preserve.marker == NULL
598       || !bfd_preserve_save (abfd, &preserve))
599     goto fail;
600
601   if (bfd_pef_scan (abfd, &header,
602                     (bfd_pef_data_struct *) preserve.marker) != 0)
603     goto wrong;
604
605   bfd_preserve_finish (abfd, &preserve);
606   return abfd->xvec;
607
608  wrong:
609   bfd_set_error (bfd_error_wrong_format);
610
611  fail:
612   if (preserve.marker != NULL)
613     bfd_preserve_restore (abfd, &preserve);
614   return NULL;
615 }
616
617 static int
618 bfd_pef_parse_traceback_tables (bfd *abfd,
619                                 asection *sec,
620                                 unsigned char *buf,
621                                 size_t len,
622                                 long *nsym,
623                                 asymbol **csym)
624 {
625   char *name;
626
627   asymbol function;
628   asymbol traceback;
629
630   const char *const tbprefix = "__traceback_";
631   size_t tbnamelen;
632
633   size_t pos = 0;
634   unsigned long count = 0;
635   int ret;
636
637   for (;;)
638     {
639       /* We're reading symbols two at a time.  */
640       if (csym && ((csym[count] == NULL) || (csym[count + 1] == NULL)))
641         break;
642
643       pos += 3;
644       pos -= (pos % 4);
645
646       while ((pos + 4) <= len)
647         {
648           if (bfd_getb32 (buf + pos) == 0)
649             break;
650           pos += 4;
651         }
652
653       if ((pos + 4) > len)
654         break;
655
656       ret = bfd_pef_parse_traceback_table (abfd, sec, buf, len, pos + 4,
657                                            &function, 0);
658       if (ret < 0)
659         {
660           /* Skip over 0x0L to advance to next possible traceback table.  */
661           pos += 4;
662           continue;
663         }
664
665       BFD_ASSERT (function.name != NULL);
666
667       /* Don't bother to compute the name if we are just
668          counting symbols.  */
669       if (csym)
670         {
671           tbnamelen = strlen (tbprefix) + strlen (function.name);
672           name = bfd_alloc (abfd, tbnamelen + 1);
673           if (name == NULL)
674             {
675               bfd_release (abfd, (void *) function.name);
676               function.name = NULL;
677               break;
678             }
679           snprintf (name, tbnamelen + 1, "%s%s", tbprefix, function.name);
680           traceback.name = name;
681           traceback.value = pos;
682           traceback.the_bfd = abfd;
683           traceback.section = sec;
684           traceback.flags = 0;
685           traceback.udata.i = ret;
686
687           *(csym[count]) = function;
688           *(csym[count + 1]) = traceback;
689         }
690
691       pos += ret;
692       count += 2;
693     }
694
695   *nsym = count;
696   return 0;
697 }
698
699 static int
700 bfd_pef_parse_function_stub (bfd *abfd ATTRIBUTE_UNUSED,
701                              unsigned char *buf,
702                              size_t len,
703                              unsigned long *offset)
704 {
705   BFD_ASSERT (len == 24);
706
707   if ((bfd_getb32 (buf) & 0xffff0000) != 0x81820000)
708     return -1;
709   if (bfd_getb32 (buf + 4) != 0x90410014)
710     return -1;
711   if (bfd_getb32 (buf + 8) != 0x800c0000)
712     return -1;
713   if (bfd_getb32 (buf + 12) != 0x804c0004)
714     return -1;
715   if (bfd_getb32 (buf + 16) != 0x7c0903a6)
716     return -1;
717   if (bfd_getb32 (buf + 20) != 0x4e800420)
718     return -1;
719
720   if (offset != NULL)
721     *offset = (bfd_getb32 (buf) & 0x0000ffff) / 4;
722
723   return 0;
724 }
725
726 static int
727 bfd_pef_parse_function_stubs (bfd *abfd,
728                               asection *codesec,
729                               unsigned char *codebuf,
730                               size_t codelen,
731                               unsigned char *loaderbuf,
732                               size_t loaderlen,
733                               unsigned long *nsym,
734                               asymbol **csym)
735 {
736   const char *const sprefix = "__stub_";
737   size_t codepos = 0;
738   unsigned long count = 0;
739   bfd_pef_loader_header header;
740   bfd_pef_imported_library *libraries = NULL;
741   bfd_pef_imported_symbol *imports = NULL;
742   unsigned long i;
743   int ret;
744
745   if (loaderlen < 56)
746     goto error;
747
748   ret = bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header);
749   if (ret < 0)
750     goto error;
751
752   libraries = bfd_malloc
753     (header.imported_library_count * sizeof (bfd_pef_imported_library));
754   imports = bfd_malloc
755     (header.total_imported_symbol_count * sizeof (bfd_pef_imported_symbol));
756
757   if (loaderlen < (56 + (header.imported_library_count * 24)))
758     goto error;
759   for (i = 0; i < header.imported_library_count; i++)
760     {
761       ret = bfd_pef_parse_imported_library
762         (abfd, loaderbuf + 56 + (i * 24), 24, &libraries[i]);
763       if (ret < 0)
764         goto error;
765     }
766
767   if (loaderlen < (56 + (header.imported_library_count * 24)
768                    + (header.total_imported_symbol_count * 4)))
769     goto error;
770   for (i = 0; i < header.total_imported_symbol_count; i++)
771     {
772       ret = (bfd_pef_parse_imported_symbol
773              (abfd,
774               loaderbuf + 56 + (header.imported_library_count * 24) + (i * 4),
775               4, &imports[i]));
776       if (ret < 0)
777         goto error;
778     }
779
780   codepos = 0;
781
782   for (;;)
783     {
784       asymbol sym;
785       const char *symname;
786       char *name;
787       unsigned long sym_index;
788
789       if (csym && (csym[count] == NULL))
790         break;
791
792       codepos += 3;
793       codepos -= (codepos % 4);
794
795       while ((codepos + 4) <= codelen)
796         {
797           if ((bfd_getb32 (codebuf + codepos) & 0xffff0000) == 0x81820000)
798             break;
799           codepos += 4;
800         }
801
802       if ((codepos + 4) > codelen)
803         break;
804
805       ret = bfd_pef_parse_function_stub (abfd, codebuf + codepos, 24, &sym_index);
806       if (ret < 0)
807         {
808           codepos += 24;
809           continue;
810         }
811
812       if (sym_index >= header.total_imported_symbol_count)
813         {
814           codepos += 24;
815           continue;
816         }
817
818       {
819         size_t max, namelen;
820         const char *s;
821
822         if (loaderlen < (header.loader_strings_offset + imports[sym_index].name))
823           goto error;
824
825         max = loaderlen - (header.loader_strings_offset + imports[sym_index].name);
826         symname = (char *) loaderbuf;
827         symname += header.loader_strings_offset + imports[sym_index].name;
828         namelen = 0;
829         for (s = symname; s < (symname + max); s++)
830           {
831             if (*s == '\0')
832               break;
833             if (! ISPRINT (*s))
834               goto error;
835             namelen++;
836           }
837         if (*s != '\0')
838           goto error;
839
840         name = bfd_alloc (abfd, strlen (sprefix) + namelen + 1);
841         if (name == NULL)
842           break;
843
844         snprintf (name, strlen (sprefix) + namelen + 1, "%s%s",
845                   sprefix, symname);
846         sym.name = name;
847       }
848
849       sym.value = codepos;
850       sym.the_bfd = abfd;
851       sym.section = codesec;
852       sym.flags = 0;
853       sym.udata.i = 0;
854
855       codepos += 24;
856
857       if (csym != NULL)
858         *(csym[count]) = sym;
859
860       count++;
861     }
862
863   goto end;
864
865  end:
866   if (libraries != NULL)
867     free (libraries);
868   if (imports != NULL)
869     free (imports);
870   *nsym = count;
871   return 0;
872
873  error:
874   if (libraries != NULL)
875     free (libraries);
876   if (imports != NULL)
877     free (imports);
878   *nsym = count;
879   return -1;
880 }
881
882 static long
883 bfd_pef_parse_symbols (bfd *abfd, asymbol **csym)
884 {
885   unsigned long count = 0;
886
887   asection *codesec = NULL;
888   unsigned char *codebuf = NULL;
889   size_t codelen = 0;
890
891   asection *loadersec = NULL;
892   unsigned char *loaderbuf = NULL;
893   size_t loaderlen = 0;
894
895   codesec = bfd_get_section_by_name (abfd, "code");
896   if (codesec != NULL)
897     {
898       codelen = codesec->size;
899       codebuf = bfd_malloc (codelen);
900       if (bfd_seek (abfd, codesec->filepos, SEEK_SET) < 0)
901         goto end;
902       if (bfd_bread ((void *) codebuf, codelen, abfd) != codelen)
903         goto end;
904     }
905
906   loadersec = bfd_get_section_by_name (abfd, "loader");
907   if (loadersec != NULL)
908     {
909       loaderlen = loadersec->size;
910       loaderbuf = bfd_malloc (loaderlen);
911       if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0)
912         goto end;
913       if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen)
914         goto end;
915     }
916
917   count = 0;
918   if (codesec != NULL)
919     {
920       long ncount = 0;
921       bfd_pef_parse_traceback_tables (abfd, codesec, codebuf, codelen,
922                                       &ncount, csym);
923       count += ncount;
924     }
925
926   if ((codesec != NULL) && (loadersec != NULL))
927     {
928       unsigned long ncount = 0;
929       bfd_pef_parse_function_stubs
930         (abfd, codesec, codebuf, codelen, loaderbuf, loaderlen, &ncount,
931          (csym != NULL) ? (csym + count) : NULL);
932       count += ncount;
933     }
934
935   if (csym != NULL)
936     csym[count] = NULL;
937
938  end:
939   if (codebuf != NULL)
940     free (codebuf);
941
942   if (loaderbuf != NULL)
943     free (loaderbuf);
944
945   return count;
946 }
947
948 static long
949 bfd_pef_count_symbols (bfd *abfd)
950 {
951   return bfd_pef_parse_symbols (abfd, NULL);
952 }
953
954 static long
955 bfd_pef_get_symtab_upper_bound (bfd *abfd)
956 {
957   long nsyms = bfd_pef_count_symbols (abfd);
958
959   if (nsyms < 0)
960     return nsyms;
961   return ((nsyms + 1) * sizeof (asymbol *));
962 }
963
964 static long
965 bfd_pef_canonicalize_symtab (bfd *abfd, asymbol **alocation)
966 {
967   long i;
968   asymbol *syms;
969   long ret;
970   long nsyms = bfd_pef_count_symbols (abfd);
971
972   if (nsyms < 0)
973     return nsyms;
974
975   syms = bfd_alloc (abfd, nsyms * sizeof (asymbol));
976   if (syms == NULL)
977     return -1;
978
979   for (i = 0; i < nsyms; i++)
980     alocation[i] = &syms[i];
981
982   alocation[nsyms] = NULL;
983
984   ret = bfd_pef_parse_symbols (abfd, alocation);
985   if (ret != nsyms)
986     return 0;
987
988   return ret;
989 }
990
991 #define bfd_pef_make_empty_symbol _bfd_generic_make_empty_symbol
992
993 static void
994 bfd_pef_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
995                          asymbol *symbol,
996                          symbol_info *ret)
997 {
998   bfd_symbol_info (symbol, ret);
999 }
1000
1001 static int
1002 bfd_pef_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
1003                         struct bfd_link_info *info ATTRIBUTE_UNUSED)
1004 {
1005   return 0;
1006 }
1007
1008 const bfd_target pef_vec =
1009 {
1010   "pef",                        /* Name.  */
1011   bfd_target_pef_flavour,       /* Flavour.  */
1012   BFD_ENDIAN_BIG,               /* Byteorder.  */
1013   BFD_ENDIAN_BIG,               /* Header_byteorder.  */
1014   (HAS_RELOC | EXEC_P |         /* Object flags.  */
1015    HAS_LINENO | HAS_DEBUG |
1016    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
1017   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
1018    | SEC_ROM | SEC_HAS_CONTENTS), /* Section_flags.  */
1019   0,                            /* Symbol_leading_char.  */
1020   ' ',                          /* AR_pad_char.  */
1021   16,                           /* AR_max_namelen.  */
1022   0,                            /* match priority.  */
1023   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1024   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1025   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* Data.  */
1026   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1027   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1028   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* Headers.  */
1029   {                             /* bfd_check_format.  */
1030     _bfd_dummy_target,
1031     bfd_pef_object_p,           /* bfd_check_format.  */
1032     _bfd_dummy_target,
1033     _bfd_dummy_target,
1034   },
1035   {                             /* bfd_set_format.  */
1036     bfd_false,
1037     bfd_pef_mkobject,
1038     bfd_false,
1039     bfd_false,
1040   },
1041   {                             /* bfd_write_contents.  */
1042     bfd_false,
1043     bfd_true,
1044     bfd_false,
1045     bfd_false,
1046   },
1047
1048   BFD_JUMP_TABLE_GENERIC (bfd_pef),
1049   BFD_JUMP_TABLE_COPY (_bfd_generic),
1050   BFD_JUMP_TABLE_CORE (_bfd_nocore),
1051   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
1052   BFD_JUMP_TABLE_SYMBOLS (bfd_pef),
1053   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1054   BFD_JUMP_TABLE_WRITE (bfd_pef),
1055   BFD_JUMP_TABLE_LINK (bfd_pef),
1056   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1057
1058   NULL,
1059
1060   NULL
1061 };
1062
1063 #define bfd_pef_xlib_close_and_cleanup              _bfd_generic_close_and_cleanup
1064 #define bfd_pef_xlib_bfd_free_cached_info           _bfd_generic_bfd_free_cached_info
1065 #define bfd_pef_xlib_new_section_hook               _bfd_generic_new_section_hook
1066 #define bfd_pef_xlib_get_section_contents           _bfd_generic_get_section_contents
1067 #define bfd_pef_xlib_set_section_contents           _bfd_generic_set_section_contents
1068 #define bfd_pef_xlib_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
1069 #define bfd_pef_xlib_set_section_contents_in_window _bfd_generic_set_section_contents_in_window
1070
1071 static int
1072 bfd_pef_xlib_read_header (bfd *abfd, bfd_pef_xlib_header *header)
1073 {
1074   unsigned char buf[76];
1075
1076   bfd_seek (abfd, 0, SEEK_SET);
1077
1078   if (bfd_bread ((void *) buf, 76, abfd) != 76)
1079     return -1;
1080
1081   header->tag1 = bfd_getb32 (buf);
1082   header->tag2 = bfd_getb32 (buf + 4);
1083   header->current_format = bfd_getb32 (buf + 8);
1084   header->container_strings_offset = bfd_getb32 (buf + 12);
1085   header->export_hash_offset = bfd_getb32 (buf + 16);
1086   header->export_key_offset = bfd_getb32 (buf + 20);
1087   header->export_symbol_offset = bfd_getb32 (buf + 24);
1088   header->export_names_offset = bfd_getb32 (buf + 28);
1089   header->export_hash_table_power = bfd_getb32 (buf + 32);
1090   header->exported_symbol_count = bfd_getb32 (buf + 36);
1091   header->frag_name_offset = bfd_getb32 (buf + 40);
1092   header->frag_name_length = bfd_getb32 (buf + 44);
1093   header->dylib_path_offset = bfd_getb32 (buf + 48);
1094   header->dylib_path_length = bfd_getb32 (buf + 52);
1095   header->cpu_family = bfd_getb32 (buf + 56);
1096   header->cpu_model = bfd_getb32 (buf + 60);
1097   header->date_time_stamp = bfd_getb32 (buf + 64);
1098   header->current_version = bfd_getb32 (buf + 68);
1099   header->old_definition_version = bfd_getb32 (buf + 72);
1100   header->old_implementation_version = bfd_getb32 (buf + 76);
1101
1102   return 0;
1103 }
1104
1105 static int
1106 bfd_pef_xlib_scan (bfd *abfd, bfd_pef_xlib_header *header)
1107 {
1108   bfd_pef_xlib_data_struct *mdata = NULL;
1109
1110   mdata = bfd_alloc (abfd, sizeof (* mdata));
1111   if (mdata == NULL)
1112     return -1;
1113
1114   mdata->header = *header;
1115
1116   abfd->flags = (abfd->xvec->object_flags
1117                  | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS)));
1118
1119   abfd->tdata.pef_xlib_data = mdata;
1120
1121   return 0;
1122 }
1123
1124 static const bfd_target *
1125 bfd_pef_xlib_object_p (bfd *abfd)
1126 {
1127   struct bfd_preserve preserve;
1128   bfd_pef_xlib_header header;
1129
1130   if (bfd_pef_xlib_read_header (abfd, &header) != 0)
1131     {
1132       bfd_set_error (bfd_error_wrong_format);
1133       return NULL;
1134     }
1135
1136   if ((header.tag1 != BFD_PEF_XLIB_TAG1)
1137       || ((header.tag2 != BFD_PEF_VLIB_TAG2)
1138           && (header.tag2 != BFD_PEF_BLIB_TAG2)))
1139     {
1140       bfd_set_error (bfd_error_wrong_format);
1141       return NULL;
1142     }
1143
1144   if (! bfd_preserve_save (abfd, &preserve))
1145     {
1146       bfd_set_error (bfd_error_wrong_format);
1147       return NULL;
1148     }
1149
1150   if (bfd_pef_xlib_scan (abfd, &header) != 0)
1151     {
1152       bfd_preserve_restore (abfd, &preserve);
1153       bfd_set_error (bfd_error_wrong_format);
1154       return NULL;
1155     }
1156
1157   bfd_preserve_finish (abfd, &preserve);
1158   return abfd->xvec;
1159 }
1160
1161 const bfd_target pef_xlib_vec =
1162 {
1163   "pef-xlib",                   /* Name.  */
1164   bfd_target_pef_xlib_flavour,  /* Flavour.  */
1165   BFD_ENDIAN_BIG,               /* Byteorder */
1166   BFD_ENDIAN_BIG,               /* Header_byteorder.  */
1167   (HAS_RELOC | EXEC_P |         /* Object flags.  */
1168    HAS_LINENO | HAS_DEBUG |
1169    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
1170   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
1171    | SEC_ROM | SEC_HAS_CONTENTS),/* Section_flags.  */
1172   0,                            /* Symbol_leading_char.  */
1173   ' ',                          /* AR_pad_char.  */
1174   16,                           /* AR_max_namelen.  */
1175   0,                            /* match priority.  */
1176   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1177   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1178   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* Data.  */
1179   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1180   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1181   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* Headers.  */
1182   {                             /* bfd_check_format.  */
1183     _bfd_dummy_target,
1184     bfd_pef_xlib_object_p,      /* bfd_check_format.  */
1185     _bfd_dummy_target,
1186     _bfd_dummy_target,
1187   },
1188   {                             /* bfd_set_format.  */
1189     bfd_false,
1190     bfd_pef_mkobject,
1191     bfd_false,
1192     bfd_false,
1193   },
1194   {                             /* bfd_write_contents.  */
1195     bfd_false,
1196     bfd_true,
1197     bfd_false,
1198     bfd_false,
1199   },
1200
1201   BFD_JUMP_TABLE_GENERIC (bfd_pef_xlib),
1202   BFD_JUMP_TABLE_COPY (_bfd_generic),
1203   BFD_JUMP_TABLE_CORE (_bfd_nocore),
1204   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
1205   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
1206   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1207   BFD_JUMP_TABLE_WRITE (_bfd_nowrite),
1208   BFD_JUMP_TABLE_LINK (_bfd_nolink),
1209   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1210
1211   NULL,
1212
1213   NULL
1214 };