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