* elf64-ppc.c (ppc64_elf_func_desc_adjust): Don't emit out-of-line
[platform/upstream/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 (abfd, header, mdata)
511      bfd *abfd;
512      bfd_pef_header *header;
513      bfd_pef_data_struct *mdata;
514 {
515   unsigned int i;
516   enum bfd_architecture cputype;
517   unsigned long cpusubtype;
518
519   mdata->header = *header;
520
521   bfd_pef_convert_architecture (header->architecture, &cputype, &cpusubtype);
522   if (cputype == bfd_arch_unknown)
523     {
524       (*_bfd_error_handler) (_("bfd_pef_scan: unknown architecture 0x%lx"),
525                                header->architecture);
526       return -1;
527     }
528   bfd_set_arch_mach (abfd, cputype, cpusubtype);
529
530   mdata->header = *header;
531
532   abfd->flags = (abfd->xvec->object_flags
533                  | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS)));
534
535   if (header->section_count != 0)
536     {
537       mdata->sections = bfd_alloc (abfd, header->section_count * sizeof (bfd_pef_section));
538
539       if (mdata->sections == NULL)
540         return -1;
541
542       for (i = 0; i < header->section_count; i++)
543         {
544           bfd_pef_section *cur = &mdata->sections[i];
545           cur->header_offset = 40 + (i * 28);
546           if (bfd_pef_scan_section (abfd, cur) < 0)
547             return -1;
548         }
549     }
550
551   if (bfd_pef_scan_start_address (abfd) < 0)
552     return -1;
553
554   abfd->tdata.pef_data = mdata;
555
556   return 0;
557 }
558
559 static int
560 bfd_pef_read_header (bfd *abfd, bfd_pef_header *header)
561 {
562   unsigned char buf[40];
563
564   bfd_seek (abfd, 0, SEEK_SET);
565
566   if (bfd_bread ((void *) buf, 40, abfd) != 40)
567     return -1;
568
569   header->tag1 = bfd_getb32 (buf);
570   header->tag2 = bfd_getb32 (buf + 4);
571   header->architecture = bfd_getb32 (buf + 8);
572   header->format_version = bfd_getb32 (buf + 12);
573   header->timestamp = bfd_getb32 (buf + 16);
574   header->old_definition_version = bfd_getb32 (buf + 20);
575   header->old_implementation_version = bfd_getb32 (buf + 24);
576   header->current_version = bfd_getb32 (buf + 28);
577   header->section_count = bfd_getb32 (buf + 32) + 1;
578   header->instantiated_section_count = bfd_getb32 (buf + 34);
579   header->reserved = bfd_getb32 (buf + 36);
580
581   return 0;
582 }
583
584 static const bfd_target *
585 bfd_pef_object_p (bfd *abfd)
586 {
587   struct bfd_preserve preserve;
588   bfd_pef_header header;
589
590   preserve.marker = NULL;
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   preserve.marker = bfd_zalloc (abfd, sizeof (bfd_pef_data_struct));
598   if (preserve.marker == NULL
599       || !bfd_preserve_save (abfd, &preserve))
600     goto fail;
601
602   if (bfd_pef_scan (abfd, &header,
603                     (bfd_pef_data_struct *) preserve.marker) != 0)
604     goto wrong;
605
606   bfd_preserve_finish (abfd, &preserve);
607   return abfd->xvec;
608
609  wrong:
610   bfd_set_error (bfd_error_wrong_format);
611
612  fail:
613   if (preserve.marker != NULL)
614     bfd_preserve_restore (abfd, &preserve);
615   return NULL;
616 }
617
618 static int
619 bfd_pef_parse_traceback_tables (bfd *abfd,
620                                 asection *sec,
621                                 unsigned char *buf,
622                                 size_t len,
623                                 long *nsym,
624                                 asymbol **csym)
625 {
626   char *name;
627
628   asymbol function;
629   asymbol traceback;
630
631   const char *const tbprefix = "__traceback_";
632   size_t tbnamelen;
633
634   size_t pos = 0;
635   unsigned long count = 0;
636   int ret;
637
638   for (;;)
639     {
640       /* We're reading symbols two at a time.  */
641       if (csym && ((csym[count] == NULL) || (csym[count + 1] == NULL)))
642         break;
643
644       pos += 3;
645       pos -= (pos % 4);
646
647       while ((pos + 4) <= len)
648         {
649           if (bfd_getb32 (buf + pos) == 0)
650             break;
651           pos += 4;
652         }
653
654       if ((pos + 4) > len)
655         break;
656
657       ret = bfd_pef_parse_traceback_table (abfd, sec, buf, len, pos + 4,
658                                            &function, 0);
659       if (ret < 0)
660         {
661           /* Skip over 0x0L to advance to next possible traceback table.  */
662           pos += 4;
663           continue;
664         }
665
666       BFD_ASSERT (function.name != NULL);
667
668       /* Don't bother to compute the name if we are just
669          counting symbols.  */
670       if (csym)
671         {
672           tbnamelen = strlen (tbprefix) + strlen (function.name);
673           name = bfd_alloc (abfd, tbnamelen + 1);
674           if (name == NULL)
675             {
676               bfd_release (abfd, (void *) function.name);
677               function.name = NULL;
678               break;
679             }
680           snprintf (name, tbnamelen + 1, "%s%s", tbprefix, function.name);
681           traceback.name = name;
682           traceback.value = pos;
683           traceback.the_bfd = abfd;
684           traceback.section = sec;
685           traceback.flags = 0;
686           traceback.udata.i = ret;
687
688           *(csym[count]) = function;
689           *(csym[count + 1]) = traceback;
690         }
691
692       pos += ret;
693       count += 2;
694     }
695
696   *nsym = count;
697   return 0;
698 }
699
700 static int
701 bfd_pef_parse_function_stub (bfd *abfd ATTRIBUTE_UNUSED,
702                              unsigned char *buf,
703                              size_t len,
704                              unsigned long *offset)
705 {
706   BFD_ASSERT (len == 24);
707
708   if ((bfd_getb32 (buf) & 0xffff0000) != 0x81820000)
709     return -1;
710   if (bfd_getb32 (buf + 4) != 0x90410014)
711     return -1;
712   if (bfd_getb32 (buf + 8) != 0x800c0000)
713     return -1;
714   if (bfd_getb32 (buf + 12) != 0x804c0004)
715     return -1;
716   if (bfd_getb32 (buf + 16) != 0x7c0903a6)
717     return -1;
718   if (bfd_getb32 (buf + 20) != 0x4e800420)
719     return -1;
720
721   if (offset != NULL)
722     *offset = (bfd_getb32 (buf) & 0x0000ffff) / 4;
723
724   return 0;
725 }
726
727 static int
728 bfd_pef_parse_function_stubs (bfd *abfd,
729                               asection *codesec,
730                               unsigned char *codebuf,
731                               size_t codelen,
732                               unsigned char *loaderbuf,
733                               size_t loaderlen,
734                               unsigned long *nsym,
735                               asymbol **csym)
736 {
737   const char *const sprefix = "__stub_";
738   size_t codepos = 0;
739   unsigned long count = 0;
740   bfd_pef_loader_header header;
741   bfd_pef_imported_library *libraries = NULL;
742   bfd_pef_imported_symbol *imports = NULL;
743   unsigned long i;
744   int ret;
745
746   if (loaderlen < 56)
747     goto error;
748
749   ret = bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header);
750   if (ret < 0)
751     goto error;
752
753   libraries = bfd_malloc
754     (header.imported_library_count * sizeof (bfd_pef_imported_library));
755   imports = bfd_malloc
756     (header.total_imported_symbol_count * sizeof (bfd_pef_imported_symbol));
757
758   if (loaderlen < (56 + (header.imported_library_count * 24)))
759     goto error;
760   for (i = 0; i < header.imported_library_count; i++)
761     {
762       ret = bfd_pef_parse_imported_library
763         (abfd, loaderbuf + 56 + (i * 24), 24, &libraries[i]);
764       if (ret < 0)
765         goto error;
766     }
767
768   if (loaderlen < (56 + (header.imported_library_count * 24)
769                    + (header.total_imported_symbol_count * 4)))
770     goto error;
771   for (i = 0; i < header.total_imported_symbol_count; i++)
772     {
773       ret = (bfd_pef_parse_imported_symbol
774              (abfd,
775               loaderbuf + 56 + (header.imported_library_count * 24) + (i * 4),
776               4, &imports[i]));
777       if (ret < 0)
778         goto error;
779     }
780
781   codepos = 0;
782
783   for (;;)
784     {
785       asymbol sym;
786       const char *symname;
787       char *name;
788       unsigned long sym_index;
789
790       if (csym && (csym[count] == NULL))
791         break;
792
793       codepos += 3;
794       codepos -= (codepos % 4);
795
796       while ((codepos + 4) <= codelen)
797         {
798           if ((bfd_getb32 (codebuf + codepos) & 0xffff0000) == 0x81820000)
799             break;
800           codepos += 4;
801         }
802
803       if ((codepos + 4) > codelen)
804         break;
805
806       ret = bfd_pef_parse_function_stub (abfd, codebuf + codepos, 24, &sym_index);
807       if (ret < 0)
808         {
809           codepos += 24;
810           continue;
811         }
812
813       if (sym_index >= header.total_imported_symbol_count)
814         {
815           codepos += 24;
816           continue;
817         }
818
819       {
820         size_t max, namelen;
821         const char *s;
822
823         if (loaderlen < (header.loader_strings_offset + imports[sym_index].name))
824           goto error;
825
826         max = loaderlen - (header.loader_strings_offset + imports[sym_index].name);
827         symname = (char *) loaderbuf;
828         symname += header.loader_strings_offset + imports[sym_index].name;
829         namelen = 0;
830         for (s = symname; s < (symname + max); s++)
831           {
832             if (*s == '\0')
833               break;
834             if (! ISPRINT (*s))
835               goto error;
836             namelen++;
837           }
838         if (*s != '\0')
839           goto error;
840
841         name = bfd_alloc (abfd, strlen (sprefix) + namelen + 1);
842         if (name == NULL)
843           break;
844
845         snprintf (name, strlen (sprefix) + namelen + 1, "%s%s",
846                   sprefix, symname);
847         sym.name = name;
848       }
849
850       sym.value = codepos;
851       sym.the_bfd = abfd;
852       sym.section = codesec;
853       sym.flags = 0;
854       sym.udata.i = 0;
855
856       codepos += 24;
857
858       if (csym != NULL)
859         *(csym[count]) = sym;
860
861       count++;
862     }
863
864   goto end;
865
866  end:
867   if (libraries != NULL)
868     free (libraries);
869   if (imports != NULL)
870     free (imports);
871   *nsym = count;
872   return 0;
873
874  error:
875   if (libraries != NULL)
876     free (libraries);
877   if (imports != NULL)
878     free (imports);
879   *nsym = count;
880   return -1;
881 }
882
883 static long
884 bfd_pef_parse_symbols (bfd *abfd, asymbol **csym)
885 {
886   unsigned long count = 0;
887
888   asection *codesec = NULL;
889   unsigned char *codebuf = NULL;
890   size_t codelen = 0;
891
892   asection *loadersec = NULL;
893   unsigned char *loaderbuf = NULL;
894   size_t loaderlen = 0;
895
896   codesec = bfd_get_section_by_name (abfd, "code");
897   if (codesec != NULL)
898     {
899       codelen = codesec->size;
900       codebuf = bfd_malloc (codelen);
901       if (bfd_seek (abfd, codesec->filepos, SEEK_SET) < 0)
902         goto end;
903       if (bfd_bread ((void *) codebuf, codelen, abfd) != codelen)
904         goto end;
905     }
906
907   loadersec = bfd_get_section_by_name (abfd, "loader");
908   if (loadersec != NULL)
909     {
910       loaderlen = loadersec->size;
911       loaderbuf = bfd_malloc (loaderlen);
912       if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0)
913         goto end;
914       if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen)
915         goto end;
916     }
917
918   count = 0;
919   if (codesec != NULL)
920     {
921       long ncount = 0;
922       bfd_pef_parse_traceback_tables (abfd, codesec, codebuf, codelen,
923                                       &ncount, csym);
924       count += ncount;
925     }
926
927   if ((codesec != NULL) && (loadersec != NULL))
928     {
929       unsigned long ncount = 0;
930       bfd_pef_parse_function_stubs
931         (abfd, codesec, codebuf, codelen, loaderbuf, loaderlen, &ncount,
932          (csym != NULL) ? (csym + count) : NULL);
933       count += ncount;
934     }
935
936   if (csym != NULL)
937     csym[count] = NULL;
938
939  end:
940   if (codebuf != NULL)
941     free (codebuf);
942
943   if (loaderbuf != NULL)
944     free (loaderbuf);
945
946   return count;
947 }
948
949 static long
950 bfd_pef_count_symbols (bfd *abfd)
951 {
952   return bfd_pef_parse_symbols (abfd, NULL);
953 }
954
955 static long
956 bfd_pef_get_symtab_upper_bound (bfd *abfd)
957 {
958   long nsyms = bfd_pef_count_symbols (abfd);
959
960   if (nsyms < 0)
961     return nsyms;
962   return ((nsyms + 1) * sizeof (asymbol *));
963 }
964
965 static long
966 bfd_pef_canonicalize_symtab (bfd *abfd, asymbol **alocation)
967 {
968   long i;
969   asymbol *syms;
970   long ret;
971   long nsyms = bfd_pef_count_symbols (abfd);
972
973   if (nsyms < 0)
974     return nsyms;
975
976   syms = bfd_alloc (abfd, nsyms * sizeof (asymbol));
977   if (syms == NULL)
978     return -1;
979
980   for (i = 0; i < nsyms; i++)
981     alocation[i] = &syms[i];
982
983   alocation[nsyms] = NULL;
984
985   ret = bfd_pef_parse_symbols (abfd, alocation);
986   if (ret != nsyms)
987     return 0;
988
989   return ret;
990 }
991
992 #define bfd_pef_make_empty_symbol _bfd_generic_make_empty_symbol
993
994 static void
995 bfd_pef_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
996                          asymbol *symbol,
997                          symbol_info *ret)
998 {
999   bfd_symbol_info (symbol, ret);
1000 }
1001
1002 static int
1003 bfd_pef_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
1004                         struct bfd_link_info *info ATTRIBUTE_UNUSED)
1005 {
1006   return 0;
1007 }
1008
1009 const bfd_target pef_vec =
1010 {
1011   "pef",                        /* Name.  */
1012   bfd_target_pef_flavour,       /* Flavour.  */
1013   BFD_ENDIAN_BIG,               /* Byteorder.  */
1014   BFD_ENDIAN_BIG,               /* Header_byteorder.  */
1015   (HAS_RELOC | EXEC_P |         /* Object flags.  */
1016    HAS_LINENO | HAS_DEBUG |
1017    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
1018   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
1019    | SEC_ROM | SEC_HAS_CONTENTS), /* Section_flags.  */
1020   0,                            /* Symbol_leading_char.  */
1021   ' ',                          /* AR_pad_char.  */
1022   16,                           /* AR_max_namelen.  */
1023   0,                            /* match priority.  */
1024   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1025   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1026   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* Data.  */
1027   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1028   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1029   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* Headers.  */
1030   {                             /* bfd_check_format.  */
1031     _bfd_dummy_target,
1032     bfd_pef_object_p,           /* bfd_check_format.  */
1033     _bfd_dummy_target,
1034     _bfd_dummy_target,
1035   },
1036   {                             /* bfd_set_format.  */
1037     bfd_false,
1038     bfd_pef_mkobject,
1039     bfd_false,
1040     bfd_false,
1041   },
1042   {                             /* bfd_write_contents.  */
1043     bfd_false,
1044     bfd_true,
1045     bfd_false,
1046     bfd_false,
1047   },
1048
1049   BFD_JUMP_TABLE_GENERIC (bfd_pef),
1050   BFD_JUMP_TABLE_COPY (_bfd_generic),
1051   BFD_JUMP_TABLE_CORE (_bfd_nocore),
1052   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
1053   BFD_JUMP_TABLE_SYMBOLS (bfd_pef),
1054   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1055   BFD_JUMP_TABLE_WRITE (bfd_pef),
1056   BFD_JUMP_TABLE_LINK (bfd_pef),
1057   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1058
1059   NULL,
1060
1061   NULL
1062 };
1063
1064 #define bfd_pef_xlib_close_and_cleanup              _bfd_generic_close_and_cleanup
1065 #define bfd_pef_xlib_bfd_free_cached_info           _bfd_generic_bfd_free_cached_info
1066 #define bfd_pef_xlib_new_section_hook               _bfd_generic_new_section_hook
1067 #define bfd_pef_xlib_get_section_contents           _bfd_generic_get_section_contents
1068 #define bfd_pef_xlib_set_section_contents           _bfd_generic_set_section_contents
1069 #define bfd_pef_xlib_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
1070 #define bfd_pef_xlib_set_section_contents_in_window _bfd_generic_set_section_contents_in_window
1071
1072 static int
1073 bfd_pef_xlib_read_header (bfd *abfd, bfd_pef_xlib_header *header)
1074 {
1075   unsigned char buf[76];
1076
1077   bfd_seek (abfd, 0, SEEK_SET);
1078
1079   if (bfd_bread ((void *) buf, 76, abfd) != 76)
1080     return -1;
1081
1082   header->tag1 = bfd_getb32 (buf);
1083   header->tag2 = bfd_getb32 (buf + 4);
1084   header->current_format = bfd_getb32 (buf + 8);
1085   header->container_strings_offset = bfd_getb32 (buf + 12);
1086   header->export_hash_offset = bfd_getb32 (buf + 16);
1087   header->export_key_offset = bfd_getb32 (buf + 20);
1088   header->export_symbol_offset = bfd_getb32 (buf + 24);
1089   header->export_names_offset = bfd_getb32 (buf + 28);
1090   header->export_hash_table_power = bfd_getb32 (buf + 32);
1091   header->exported_symbol_count = bfd_getb32 (buf + 36);
1092   header->frag_name_offset = bfd_getb32 (buf + 40);
1093   header->frag_name_length = bfd_getb32 (buf + 44);
1094   header->dylib_path_offset = bfd_getb32 (buf + 48);
1095   header->dylib_path_length = bfd_getb32 (buf + 52);
1096   header->cpu_family = bfd_getb32 (buf + 56);
1097   header->cpu_model = bfd_getb32 (buf + 60);
1098   header->date_time_stamp = bfd_getb32 (buf + 64);
1099   header->current_version = bfd_getb32 (buf + 68);
1100   header->old_definition_version = bfd_getb32 (buf + 72);
1101   header->old_implementation_version = bfd_getb32 (buf + 76);
1102
1103   return 0;
1104 }
1105
1106 static int
1107 bfd_pef_xlib_scan (bfd *abfd, bfd_pef_xlib_header *header)
1108 {
1109   bfd_pef_xlib_data_struct *mdata = NULL;
1110
1111   mdata = bfd_alloc (abfd, sizeof (* mdata));
1112   if (mdata == NULL)
1113     return -1;
1114
1115   mdata->header = *header;
1116
1117   abfd->flags = (abfd->xvec->object_flags
1118                  | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS)));
1119
1120   abfd->tdata.pef_xlib_data = mdata;
1121
1122   return 0;
1123 }
1124
1125 static const bfd_target *
1126 bfd_pef_xlib_object_p (bfd *abfd)
1127 {
1128   struct bfd_preserve preserve;
1129   bfd_pef_xlib_header header;
1130
1131   if (bfd_pef_xlib_read_header (abfd, &header) != 0)
1132     {
1133       bfd_set_error (bfd_error_wrong_format);
1134       return NULL;
1135     }
1136
1137   if ((header.tag1 != BFD_PEF_XLIB_TAG1)
1138       || ((header.tag2 != BFD_PEF_VLIB_TAG2)
1139           && (header.tag2 != BFD_PEF_BLIB_TAG2)))
1140     {
1141       bfd_set_error (bfd_error_wrong_format);
1142       return NULL;
1143     }
1144
1145   if (! bfd_preserve_save (abfd, &preserve))
1146     {
1147       bfd_set_error (bfd_error_wrong_format);
1148       return NULL;
1149     }
1150
1151   if (bfd_pef_xlib_scan (abfd, &header) != 0)
1152     {
1153       bfd_preserve_restore (abfd, &preserve);
1154       bfd_set_error (bfd_error_wrong_format);
1155       return NULL;
1156     }
1157
1158   bfd_preserve_finish (abfd, &preserve);
1159   return abfd->xvec;
1160 }
1161
1162 const bfd_target pef_xlib_vec =
1163 {
1164   "pef-xlib",                   /* Name.  */
1165   bfd_target_pef_xlib_flavour,  /* Flavour.  */
1166   BFD_ENDIAN_BIG,               /* Byteorder */
1167   BFD_ENDIAN_BIG,               /* Header_byteorder.  */
1168   (HAS_RELOC | EXEC_P |         /* Object flags.  */
1169    HAS_LINENO | HAS_DEBUG |
1170    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
1171   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
1172    | SEC_ROM | SEC_HAS_CONTENTS),/* Section_flags.  */
1173   0,                            /* Symbol_leading_char.  */
1174   ' ',                          /* AR_pad_char.  */
1175   16,                           /* AR_max_namelen.  */
1176   0,                            /* match priority.  */
1177   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1178   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1179   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* Data.  */
1180   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1181   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1182   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* Headers.  */
1183   {                             /* bfd_check_format.  */
1184     _bfd_dummy_target,
1185     bfd_pef_xlib_object_p,      /* bfd_check_format.  */
1186     _bfd_dummy_target,
1187     _bfd_dummy_target,
1188   },
1189   {                             /* bfd_set_format.  */
1190     bfd_false,
1191     bfd_pef_mkobject,
1192     bfd_false,
1193     bfd_false,
1194   },
1195   {                             /* bfd_write_contents.  */
1196     bfd_false,
1197     bfd_true,
1198     bfd_false,
1199     bfd_false,
1200   },
1201
1202   BFD_JUMP_TABLE_GENERIC (bfd_pef_xlib),
1203   BFD_JUMP_TABLE_COPY (_bfd_generic),
1204   BFD_JUMP_TABLE_CORE (_bfd_nocore),
1205   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
1206   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
1207   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1208   BFD_JUMP_TABLE_WRITE (_bfd_nowrite),
1209   BFD_JUMP_TABLE_LINK (_bfd_nolink),
1210   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1211
1212   NULL,
1213
1214   NULL
1215 };