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