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