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