1/* PEF support for BFD.
2   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
3   Free Software Foundation, Inc.
4
5   This file is part of BFD, the Binary File Descriptor library.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
20
21#include "safe-ctype.h"
22#include "pef.h"
23#include "pef-traceback.h"
24#include "bfd.h"
25#include "sysdep.h"
26#include "libbfd.h"
27#include "libiberty.h"
28
29#ifndef BFD_IO_FUNCS
30#define BFD_IO_FUNCS 0
31#endif
32
33#define bfd_pef_close_and_cleanup                   _bfd_generic_close_and_cleanup
34#define bfd_pef_bfd_free_cached_info                _bfd_generic_bfd_free_cached_info
35#define bfd_pef_new_section_hook                    _bfd_generic_new_section_hook
36#define bfd_pef_bfd_is_local_label_name             bfd_generic_is_local_label_name
37#define bfd_pef_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
38#define bfd_pef_get_lineno                          _bfd_nosymbols_get_lineno
39#define bfd_pef_find_nearest_line                   _bfd_nosymbols_find_nearest_line
40#define bfd_pef_find_inliner_info                   _bfd_nosymbols_find_inliner_info
41#define bfd_pef_bfd_make_debug_symbol               _bfd_nosymbols_bfd_make_debug_symbol
42#define bfd_pef_read_minisymbols                    _bfd_generic_read_minisymbols
43#define bfd_pef_minisymbol_to_symbol                _bfd_generic_minisymbol_to_symbol
44#define bfd_pef_get_reloc_upper_bound               _bfd_norelocs_get_reloc_upper_bound
45#define bfd_pef_canonicalize_reloc                  _bfd_norelocs_canonicalize_reloc
46#define bfd_pef_bfd_reloc_type_lookup               _bfd_norelocs_bfd_reloc_type_lookup
47#define bfd_pef_set_arch_mach                       _bfd_generic_set_arch_mach
48#define bfd_pef_get_section_contents                _bfd_generic_get_section_contents
49#define bfd_pef_set_section_contents                _bfd_generic_set_section_contents
50#define bfd_pef_bfd_get_relocated_section_contents  bfd_generic_get_relocated_section_contents
51#define bfd_pef_bfd_relax_section                   bfd_generic_relax_section
52#define bfd_pef_bfd_gc_sections                     bfd_generic_gc_sections
53#define bfd_pef_bfd_merge_sections                  bfd_generic_merge_sections
54#define bfd_pef_bfd_is_group_section		    bfd_generic_is_group_section
55#define bfd_pef_bfd_discard_group                   bfd_generic_discard_group
56#define bfd_pef_section_already_linked	            _bfd_generic_section_already_linked
57#define bfd_pef_bfd_link_hash_table_create          _bfd_generic_link_hash_table_create
58#define bfd_pef_bfd_link_hash_table_free            _bfd_generic_link_hash_table_free
59#define bfd_pef_bfd_link_add_symbols                _bfd_generic_link_add_symbols
60#define bfd_pef_bfd_link_just_syms                  _bfd_generic_link_just_syms
61#define bfd_pef_bfd_final_link                      _bfd_generic_final_link
62#define bfd_pef_bfd_link_split_section              _bfd_generic_link_split_section
63#define bfd_pef_get_section_contents_in_window      _bfd_generic_get_section_contents_in_window
64
65static int
66bfd_pef_parse_traceback_table (bfd *abfd,
67			       asection *section,
68			       unsigned char *buf,
69			       size_t len,
70			       size_t pos,
71			       asymbol *sym,
72			       FILE *file)
73{
74  struct traceback_table table;
75  size_t offset;
76  const char *s;
77  asymbol tmpsymbol;
78
79  if (sym == NULL)
80    sym = & tmpsymbol;
81
82  sym->name = NULL;
83  sym->value = 0;
84  sym->the_bfd = abfd;
85  sym->section = section;
86  sym->flags = 0;
87  sym->udata.i = 0;
88
89  /* memcpy is fine since all fields are unsigned char.  */
90  if ((pos + 8) > len)
91    return -1;
92  memcpy (&table, buf + pos, 8);
93
94  /* Calling code relies on returned symbols having a name and
95     correct offset.  */
96  if ((table.lang != TB_C) && (table.lang != TB_CPLUSPLUS))
97    return -1;
98
99  if (! (table.flags2 & TB_NAME_PRESENT))
100    return -1;
101
102  if (! table.flags1 & TB_HAS_TBOFF)
103    return -1;
104
105  offset = 8;
106
107  if ((table.flags5 & TB_FLOATPARAMS) || (table.fixedparams))
108    offset += 4;
109
110  if (table.flags1 & TB_HAS_TBOFF)
111    {
112      struct traceback_table_tboff off;
113
114      if ((pos + offset + 4) > len)
115	return -1;
116      off.tb_offset = bfd_getb32 (buf + pos + offset);
117      offset += 4;
118
119      /* Need to subtract 4 because the offset includes the 0x0L
120	 preceding the table.  */
121      if (file != NULL)
122	fprintf (file, " [offset = 0x%lx]", off.tb_offset);
123
124      if ((file == NULL) && ((off.tb_offset + 4) > (pos + offset)))
125	return -1;
126
127      sym->value = pos - off.tb_offset - 4;
128    }
129
130  if (table.flags2 & TB_INT_HNDL)
131    offset += 4;
132
133  if (table.flags1 & TB_HAS_CTL)
134    {
135      struct traceback_table_anchors anchors;
136
137      if ((pos + offset + 4) > len)
138	return -1;
139      anchors.ctl_info = bfd_getb32 (buf + pos + offset);
140      offset += 4;
141
142      if (anchors.ctl_info > 1024)
143	return -1;
144
145      offset += anchors.ctl_info * 4;
146    }
147
148  if (table.flags2 & TB_NAME_PRESENT)
149    {
150      struct traceback_table_routine name;
151      char *namebuf;
152
153      if ((pos + offset + 2) > len)
154	return -1;
155      name.name_len = bfd_getb16 (buf + pos + offset);
156      offset += 2;
157
158      if (name.name_len > 4096)
159	return -1;
160
161      if ((pos + offset + name.name_len) > len)
162	return -1;
163
164      namebuf = bfd_alloc (abfd, name.name_len + 1);
165      if (namebuf == NULL)
166	return -1;
167
168      memcpy (namebuf, buf + pos + offset, name.name_len);
169      namebuf[name.name_len] = '\0';
170
171      /* Strip leading period inserted by compiler.  */
172      if (namebuf[0] == '.')
173	memmove (namebuf, namebuf + 1, name.name_len + 1);
174
175      sym->name = namebuf;
176
177      for (s = sym->name; (*s != '\0'); s++)
178	if (! ISPRINT (*s))
179	  return -1;
180
181      offset += name.name_len;
182    }
183
184  if (table.flags2 & TB_USES_ALLOCA)
185    offset += 4;
186
187  if (table.flags4 & TB_HAS_VEC_INFO)
188    offset += 4;
189
190  if (file != NULL)
191    fprintf (file, " [length = 0x%lx]", (long) offset);
192
193  return offset;
194}
195
196static void
197bfd_pef_print_symbol (bfd *abfd,
198		      void * afile,
199		      asymbol *symbol,
200		      bfd_print_symbol_type how)
201{
202  FILE *file = (FILE *) afile;
203
204  switch (how)
205    {
206    case bfd_print_symbol_name:
207      fprintf (file, "%s", symbol->name);
208      break;
209    default:
210      bfd_print_symbol_vandf (abfd, (void *) file, symbol);
211      fprintf (file, " %-5s %s", symbol->section->name, symbol->name);
212      if (CONST_STRNEQ (symbol->name, "__traceback_"))
213	{
214	  unsigned char *buf = alloca (symbol->udata.i);
215	  size_t offset = symbol->value + 4;
216	  size_t len = symbol->udata.i;
217	  int ret;
218
219	  bfd_get_section_contents (abfd, symbol->section, buf, offset, len);
220	  ret = bfd_pef_parse_traceback_table (abfd, symbol->section, buf,
221					       len, 0, NULL, file);
222	  if (ret < 0)
223	    fprintf (file, " [ERROR]");
224	}
225    }
226}
227
228static void
229bfd_pef_convert_architecture (unsigned long architecture,
230			      enum bfd_architecture *type,
231			      unsigned long *subtype)
232{
233  const unsigned long ARCH_POWERPC = 0x70777063; /* 'pwpc'.  */
234  const unsigned long ARCH_M68K = 0x6d36386b; /* 'm68k'.  */
235
236  *subtype = bfd_arch_unknown;
237  *type = bfd_arch_unknown;
238
239  if (architecture == ARCH_POWERPC)
240    *type = bfd_arch_powerpc;
241  else if (architecture == ARCH_M68K)
242    *type = bfd_arch_m68k;
243}
244
245static bfd_boolean
246bfd_pef_mkobject (bfd *abfd ATTRIBUTE_UNUSED)
247{
248  return TRUE;
249}
250
251static const char *bfd_pef_section_name (bfd_pef_section *section)
252{
253  switch (section->section_kind)
254    {
255    case BFD_PEF_SECTION_CODE: return "code";
256    case BFD_PEF_SECTION_UNPACKED_DATA: return "unpacked-data";
257    case BFD_PEF_SECTION_PACKED_DATA: return "packed-data";
258    case BFD_PEF_SECTION_CONSTANT: return "constant";
259    case BFD_PEF_SECTION_LOADER: return "loader";
260    case BFD_PEF_SECTION_DEBUG: return "debug";
261    case BFD_PEF_SECTION_EXEC_DATA: return "exec-data";
262    case BFD_PEF_SECTION_EXCEPTION: return "exception";
263    case BFD_PEF_SECTION_TRACEBACK: return "traceback";
264    default: return "unknown";
265    }
266}
267
268static unsigned long bfd_pef_section_flags (bfd_pef_section *section)
269{
270  switch (section->section_kind)
271    {
272    case BFD_PEF_SECTION_CODE:
273      return SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC | SEC_CODE;
274    case BFD_PEF_SECTION_UNPACKED_DATA:
275    case BFD_PEF_SECTION_PACKED_DATA:
276    case BFD_PEF_SECTION_CONSTANT:
277    case BFD_PEF_SECTION_LOADER:
278    case BFD_PEF_SECTION_DEBUG:
279    case BFD_PEF_SECTION_EXEC_DATA:
280    case BFD_PEF_SECTION_EXCEPTION:
281    case BFD_PEF_SECTION_TRACEBACK:
282    default:
283      return SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
284    }
285}
286
287static asection *
288bfd_pef_make_bfd_section (bfd *abfd, bfd_pef_section *section)
289{
290  asection *bfdsec;
291  const char *name = bfd_pef_section_name (section);
292
293  bfdsec = bfd_make_section_anyway (abfd, name);
294  if (bfdsec == NULL)
295    return NULL;
296
297  bfdsec->vma = section->default_address + section->container_offset;
298  bfdsec->lma = section->default_address + section->container_offset;
299  bfdsec->size = section->container_length;
300  bfdsec->filepos = section->container_offset;
301  bfdsec->alignment_power = section->alignment;
302
303  bfdsec->flags = bfd_pef_section_flags (section);
304
305  return bfdsec;
306}
307
308int
309bfd_pef_parse_loader_header (bfd *abfd ATTRIBUTE_UNUSED,
310			     unsigned char *buf,
311			     size_t len,
312			     bfd_pef_loader_header *header)
313{
314  BFD_ASSERT (len == 56);
315
316  header->main_section = bfd_getb32 (buf);
317  header->main_offset = bfd_getb32 (buf + 4);
318  header->init_section = bfd_getb32 (buf + 8);
319  header->init_offset = bfd_getb32 (buf + 12);
320  header->term_section = bfd_getb32 (buf + 16);
321  header->term_offset = bfd_getb32 (buf + 20);
322  header->imported_library_count = bfd_getb32 (buf + 24);
323  header->total_imported_symbol_count = bfd_getb32 (buf + 28);
324  header->reloc_section_count = bfd_getb32 (buf + 32);
325  header->reloc_instr_offset = bfd_getb32 (buf + 36);
326  header->loader_strings_offset = bfd_getb32 (buf + 40);
327  header->export_hash_offset = bfd_getb32 (buf + 44);
328  header->export_hash_table_power = bfd_getb32 (buf + 48);
329  header->exported_symbol_count = bfd_getb32 (buf + 52);
330
331  return 0;
332}
333
334int
335bfd_pef_parse_imported_library (bfd *abfd ATTRIBUTE_UNUSED,
336				unsigned char *buf,
337				size_t len,
338				bfd_pef_imported_library *header)
339{
340  BFD_ASSERT (len == 24);
341
342  header->name_offset = bfd_getb32 (buf);
343  header->old_implementation_version = bfd_getb32 (buf + 4);
344  header->current_version = bfd_getb32 (buf + 8);
345  header->imported_symbol_count = bfd_getb32 (buf + 12);
346  header->first_imported_symbol = bfd_getb32 (buf + 16);
347  header->options = buf[20];
348  header->reserved_a = buf[21];
349  header->reserved_b = bfd_getb16 (buf + 22);
350
351  return 0;
352}
353
354int
355bfd_pef_parse_imported_symbol (bfd *abfd ATTRIBUTE_UNUSED,
356			       unsigned char *buf,
357			       size_t len,
358			       bfd_pef_imported_symbol *symbol)
359{
360  unsigned long value;
361
362  BFD_ASSERT (len == 4);
363
364  value = bfd_getb32 (buf);
365  symbol->class = value >> 24;
366  symbol->name = value & 0x00ffffff;
367
368  return 0;
369}
370
371int
372bfd_pef_scan_section (bfd *abfd, bfd_pef_section *section)
373{
374  unsigned char buf[28];
375
376  bfd_seek (abfd, section->header_offset, SEEK_SET);
377  if (bfd_bread ((void *) buf, 28, abfd) != 28)
378    return -1;
379
380  section->name_offset = bfd_h_get_32 (abfd, buf);
381  section->default_address = bfd_h_get_32 (abfd, buf + 4);
382  section->total_length = bfd_h_get_32 (abfd, buf + 8);
383  section->unpacked_length = bfd_h_get_32 (abfd, buf + 12);
384  section->container_length = bfd_h_get_32 (abfd, buf + 16);
385  section->container_offset = bfd_h_get_32 (abfd, buf + 20);
386  section->section_kind = buf[24];
387  section->share_kind = buf[25];
388  section->alignment = buf[26];
389  section->reserved = buf[27];
390
391  section->bfd_section = bfd_pef_make_bfd_section (abfd, section);
392  if (section->bfd_section == NULL)
393    return -1;
394
395  return 0;
396}
397
398void
399bfd_pef_print_loader_header (bfd *abfd ATTRIBUTE_UNUSED,
400			     bfd_pef_loader_header *header,
401			     FILE *file)
402{
403  fprintf (file, "main_section: %ld\n", header->main_section);
404  fprintf (file, "main_offset: %lu\n", header->main_offset);
405  fprintf (file, "init_section: %ld\n", header->init_section);
406  fprintf (file, "init_offset: %lu\n", header->init_offset);
407  fprintf (file, "term_section: %ld\n", header->term_section);
408  fprintf (file, "term_offset: %lu\n", header->term_offset);
409  fprintf (file, "imported_library_count: %lu\n",
410	   header->imported_library_count);
411  fprintf (file, "total_imported_symbol_count: %lu\n",
412	   header->total_imported_symbol_count);
413  fprintf (file, "reloc_section_count: %lu\n", header->reloc_section_count);
414  fprintf (file, "reloc_instr_offset: %lu\n", header->reloc_instr_offset);
415  fprintf (file, "loader_strings_offset: %lu\n",
416	   header->loader_strings_offset);
417  fprintf (file, "export_hash_offset: %lu\n", header->export_hash_offset);
418  fprintf (file, "export_hash_table_power: %lu\n",
419	   header->export_hash_table_power);
420  fprintf (file, "exported_symbol_count: %lu\n",
421	   header->exported_symbol_count);
422}
423
424int
425bfd_pef_print_loader_section (bfd *abfd, FILE *file)
426{
427  bfd_pef_loader_header header;
428  asection *loadersec = NULL;
429  unsigned char *loaderbuf = NULL;
430  size_t loaderlen = 0;
431
432  loadersec = bfd_get_section_by_name (abfd, "loader");
433  if (loadersec == NULL)
434    return -1;
435
436  loaderlen = loadersec->size;
437  loaderbuf = bfd_malloc (loaderlen);
438
439  if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0
440      || bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen
441      || loaderlen < 56
442      || bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header) < 0)
443    {
444      free (loaderbuf);
445      return -1;
446    }
447
448  bfd_pef_print_loader_header (abfd, &header, file);
449  return 0;
450}
451
452int
453bfd_pef_scan_start_address (bfd *abfd)
454{
455  bfd_pef_loader_header header;
456  asection *section;
457
458  asection *loadersec = NULL;
459  unsigned char *loaderbuf = NULL;
460  size_t loaderlen = 0;
461  int ret;
462
463  loadersec = bfd_get_section_by_name (abfd, "loader");
464  if (loadersec == NULL)
465    goto end;
466
467  loaderlen = loadersec->size;
468  loaderbuf = bfd_malloc (loaderlen);
469  if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0)
470    goto error;
471  if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen)
472    goto error;
473
474  if (loaderlen < 56)
475    goto error;
476  ret = bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header);
477  if (ret < 0)
478    goto error;
479
480  if (header.main_section < 0)
481    goto end;
482
483  for (section = abfd->sections; section != NULL; section = section->next)
484    if ((section->index + 1) == header.main_section)
485      break;
486
487  if (section == NULL)
488    goto error;
489
490  abfd->start_address = section->vma + header.main_offset;
491
492 end:
493  if (loaderbuf != NULL)
494    free (loaderbuf);
495  return 0;
496
497 error:
498  if (loaderbuf != NULL)
499    free (loaderbuf);
500  return -1;
501}
502
503int
504bfd_pef_scan (abfd, header, mdata)
505     bfd *abfd;
506     bfd_pef_header *header;
507     bfd_pef_data_struct *mdata;
508{
509  unsigned int i;
510  enum bfd_architecture cputype;
511  unsigned long cpusubtype;
512
513  mdata->header = *header;
514
515  bfd_pef_convert_architecture (header->architecture, &cputype, &cpusubtype);
516  if (cputype == bfd_arch_unknown)
517    {
518      fprintf (stderr, "bfd_pef_scan: unknown architecture 0x%lx\n",
519	       header->architecture);
520      return -1;
521    }
522  bfd_set_arch_mach (abfd, cputype, cpusubtype);
523
524  mdata->header = *header;
525
526  abfd->flags = (abfd->xvec->object_flags
527		 | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS)));
528
529  if (header->section_count != 0)
530    {
531      mdata->sections = bfd_alloc (abfd, header->section_count * sizeof (bfd_pef_section));
532
533      if (mdata->sections == NULL)
534	return -1;
535
536      for (i = 0; i < header->section_count; i++)
537	{
538	  bfd_pef_section *cur = &mdata->sections[i];
539	  cur->header_offset = 40 + (i * 28);
540	  if (bfd_pef_scan_section (abfd, cur) < 0)
541	    return -1;
542	}
543    }
544
545  if (bfd_pef_scan_start_address (abfd) < 0)
546    return -1;
547
548  abfd->tdata.pef_data = mdata;
549
550  return 0;
551}
552
553static int
554bfd_pef_read_header (bfd *abfd, bfd_pef_header *header)
555{
556  unsigned char buf[40];
557
558  bfd_seek (abfd, 0, SEEK_SET);
559
560  if (bfd_bread ((void *) buf, 40, abfd) != 40)
561    return -1;
562
563  header->tag1 = bfd_getb32 (buf);
564  header->tag2 = bfd_getb32 (buf + 4);
565  header->architecture = bfd_getb32 (buf + 8);
566  header->format_version = bfd_getb32 (buf + 12);
567  header->timestamp = bfd_getb32 (buf + 16);
568  header->old_definition_version = bfd_getb32 (buf + 20);
569  header->old_implementation_version = bfd_getb32 (buf + 24);
570  header->current_version = bfd_getb32 (buf + 28);
571  header->section_count = bfd_getb32 (buf + 32) + 1;
572  header->instantiated_section_count = bfd_getb32 (buf + 34);
573  header->reserved = bfd_getb32 (buf + 36);
574
575  return 0;
576}
577
578static const bfd_target *
579bfd_pef_object_p (bfd *abfd)
580{
581  struct bfd_preserve preserve;
582  bfd_pef_header header;
583
584  preserve.marker = NULL;
585  if (bfd_pef_read_header (abfd, &header) != 0)
586    goto wrong;
587
588  if (header.tag1 != BFD_PEF_TAG1 || header.tag2 != BFD_PEF_TAG2)
589    goto wrong;
590
591  preserve.marker = bfd_zalloc (abfd, sizeof (bfd_pef_data_struct));
592  if (preserve.marker == NULL
593      || !bfd_preserve_save (abfd, &preserve))
594    goto fail;
595
596  if (bfd_pef_scan (abfd, &header,
597		    (bfd_pef_data_struct *) preserve.marker) != 0)
598    goto wrong;
599
600  bfd_preserve_finish (abfd, &preserve);
601  return abfd->xvec;
602
603 wrong:
604  bfd_set_error (bfd_error_wrong_format);
605
606 fail:
607  if (preserve.marker != NULL)
608    bfd_preserve_restore (abfd, &preserve);
609  return NULL;
610}
611
612static int
613bfd_pef_parse_traceback_tables (bfd *abfd,
614				asection *sec,
615				unsigned char *buf,
616				size_t len,
617				long *nsym,
618				asymbol **csym)
619{
620  char *name;
621
622  asymbol function;
623  asymbol traceback;
624
625  const char *const tbprefix = "__traceback_";
626  size_t tbnamelen;
627
628  size_t pos = 0;
629  unsigned long count = 0;
630  int ret;
631
632  for (;;)
633    {
634      /* We're reading symbols two at a time.  */
635      if (csym && ((csym[count] == NULL) || (csym[count + 1] == NULL)))
636	break;
637
638      pos += 3;
639      pos -= (pos % 4);
640
641      while ((pos + 4) <= len)
642	{
643	  if (bfd_getb32 (buf + pos) == 0)
644	    break;
645	  pos += 4;
646	}
647
648      if ((pos + 4) > len)
649	break;
650
651      ret = bfd_pef_parse_traceback_table (abfd, sec, buf, len, pos + 4,
652					   &function, 0);
653      if (ret < 0)
654	{
655	  /* Skip over 0x0L to advance to next possible traceback table.  */
656	  pos += 4;
657	  continue;
658	}
659
660      BFD_ASSERT (function.name != NULL);
661
662      /* Don't bother to compute the name if we are just
663	 counting symbols.  */
664      if (csym)
665	{
666	  tbnamelen = strlen (tbprefix) + strlen (function.name);
667	  name = bfd_alloc (abfd, tbnamelen + 1);
668	  if (name == NULL)
669	    {
670	      bfd_release (abfd, (void *) function.name);
671	      function.name = NULL;
672	      break;
673	    }
674	  snprintf (name, tbnamelen + 1, "%s%s", tbprefix, function.name);
675	  traceback.name = name;
676	  traceback.value = pos;
677	  traceback.the_bfd = abfd;
678	  traceback.section = sec;
679	  traceback.flags = 0;
680	  traceback.udata.i = ret;
681
682	  *(csym[count]) = function;
683	  *(csym[count + 1]) = traceback;
684	}
685
686      pos += ret;
687      count += 2;
688    }
689
690  *nsym = count;
691  return 0;
692}
693
694static int
695bfd_pef_parse_function_stub (bfd *abfd ATTRIBUTE_UNUSED,
696			     unsigned char *buf,
697			     size_t len,
698			     unsigned long *offset)
699{
700  BFD_ASSERT (len == 24);
701
702  if ((bfd_getb32 (buf) & 0xffff0000) != 0x81820000)
703    return -1;
704  if (bfd_getb32 (buf + 4) != 0x90410014)
705    return -1;
706  if (bfd_getb32 (buf + 8) != 0x800c0000)
707    return -1;
708  if (bfd_getb32 (buf + 12) != 0x804c0004)
709    return -1;
710  if (bfd_getb32 (buf + 16) != 0x7c0903a6)
711    return -1;
712  if (bfd_getb32 (buf + 20) != 0x4e800420)
713    return -1;
714
715  if (offset != NULL)
716    *offset = (bfd_getb32 (buf) & 0x0000ffff) / 4;
717
718  return 0;
719}
720
721static int
722bfd_pef_parse_function_stubs (bfd *abfd,
723			      asection *codesec,
724			      unsigned char *codebuf,
725			      size_t codelen,
726			      unsigned char *loaderbuf,
727			      size_t loaderlen,
728			      unsigned long *nsym,
729			      asymbol **csym)
730{
731  const char *const sprefix = "__stub_";
732
733  size_t codepos = 0;
734  unsigned long count = 0;
735
736  bfd_pef_loader_header header;
737  bfd_pef_imported_library *libraries = NULL;
738  bfd_pef_imported_symbol *imports = NULL;
739
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 index;
786      int ret;
787
788      if (csym && (csym[count] == NULL))
789	break;
790
791      codepos += 3;
792      codepos -= (codepos % 4);
793
794      while ((codepos + 4) <= codelen)
795	{
796	  if ((bfd_getb32 (codebuf + codepos) & 0xffff0000) == 0x81820000)
797	    break;
798	  codepos += 4;
799	}
800
801      if ((codepos + 4) > codelen)
802	break;
803
804      ret = bfd_pef_parse_function_stub (abfd, codebuf + codepos, 24, &index);
805      if (ret < 0)
806	{
807	  codepos += 24;
808	  continue;
809	}
810
811      if (index >= header.total_imported_symbol_count)
812	{
813	  codepos += 24;
814	  continue;
815	}
816
817      {
818	size_t max, namelen;
819	const char *s;
820
821	if (loaderlen < (header.loader_strings_offset + imports[index].name))
822	  goto error;
823
824	max = loaderlen - (header.loader_strings_offset + imports[index].name);
825	symname = (char *) loaderbuf;
826	symname += header.loader_strings_offset + imports[index].name;
827	namelen = 0;
828	for (s = symname; s < (symname + max); s++)
829	  {
830	    if (*s == '\0')
831	      break;
832	    if (! ISPRINT (*s))
833	      goto error;
834	    namelen++;
835	  }
836	if (*s != '\0')
837	  goto error;
838
839	name = bfd_alloc (abfd, strlen (sprefix) + namelen + 1);
840	if (name == NULL)
841	  break;
842
843	snprintf (name, strlen (sprefix) + namelen + 1, "%s%s",
844		  sprefix, symname);
845	sym.name = name;
846      }
847
848      sym.value = codepos;
849      sym.the_bfd = abfd;
850      sym.section = codesec;
851      sym.flags = 0;
852      sym.udata.i = 0;
853
854      codepos += 24;
855
856      if (csym != NULL)
857	*(csym[count]) = sym;
858
859      count++;
860    }
861
862  goto end;
863
864 end:
865  if (libraries != NULL)
866    free (libraries);
867  if (imports != NULL)
868    free (imports);
869  *nsym = count;
870  return 0;
871
872 error:
873  if (libraries != NULL)
874    free (libraries);
875  if (imports != NULL)
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      codebuf = bfd_malloc (codelen);
899      if (bfd_seek (abfd, codesec->filepos, SEEK_SET) < 0)
900	goto end;
901      if (bfd_bread ((void *) codebuf, codelen, abfd) != codelen)
902	goto end;
903    }
904
905  loadersec = bfd_get_section_by_name (abfd, "loader");
906  if (loadersec != NULL)
907    {
908      loaderlen = loadersec->size;
909      loaderbuf = bfd_malloc (loaderlen);
910      if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0)
911	goto end;
912      if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen)
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  if (codebuf != NULL)
939    free (codebuf);
940
941  if (loaderbuf != NULL)
942    free (loaderbuf);
943
944  return count;
945}
946
947static long
948bfd_pef_count_symbols (bfd *abfd)
949{
950  return bfd_pef_parse_symbols (abfd, NULL);
951}
952
953static long
954bfd_pef_get_symtab_upper_bound (bfd *abfd)
955{
956  long nsyms = bfd_pef_count_symbols (abfd);
957
958  if (nsyms < 0)
959    return nsyms;
960  return ((nsyms + 1) * sizeof (asymbol *));
961}
962
963static long
964bfd_pef_canonicalize_symtab (bfd *abfd, asymbol **alocation)
965{
966  long i;
967  asymbol *syms;
968  long ret;
969  long nsyms = bfd_pef_count_symbols (abfd);
970
971  if (nsyms < 0)
972    return nsyms;
973
974  syms = bfd_alloc (abfd, nsyms * sizeof (asymbol));
975  if (syms == NULL)
976    return -1;
977
978  for (i = 0; i < nsyms; i++)
979    alocation[i] = &syms[i];
980
981  alocation[nsyms] = NULL;
982
983  ret = bfd_pef_parse_symbols (abfd, alocation);
984  if (ret != nsyms)
985    return 0;
986
987  return ret;
988}
989
990#define bfd_pef_make_empty_symbol _bfd_generic_make_empty_symbol
991
992static void
993bfd_pef_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
994			 asymbol *symbol,
995			 symbol_info *ret)
996{
997  bfd_symbol_info (symbol, ret);
998}
999
1000static int
1001bfd_pef_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
1002			struct bfd_link_info *info ATTRIBUTE_UNUSED)
1003{
1004  return 0;
1005}
1006
1007const bfd_target pef_vec =
1008{
1009  "pef",			/* Name.  */
1010  bfd_target_pef_flavour,	/* Flavour.  */
1011  BFD_ENDIAN_BIG,		/* Byteorder.  */
1012  BFD_ENDIAN_BIG,		/* Header_byteorder.  */
1013  (HAS_RELOC | EXEC_P |		/* Object flags.  */
1014   HAS_LINENO | HAS_DEBUG |
1015   HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
1016  (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
1017   | SEC_ROM | SEC_HAS_CONTENTS), /* Section_flags.  */
1018  0,				/* Symbol_leading_char.  */
1019  ' ',				/* AR_pad_char.  */
1020  16,				/* AR_max_namelen.  */
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_false,
1035    bfd_pef_mkobject,
1036    bfd_false,
1037    bfd_false,
1038  },
1039  {				/* bfd_write_contents.  */
1040    bfd_false,
1041    bfd_true,
1042    bfd_false,
1043    bfd_false,
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_pef),
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
1069static int
1070bfd_pef_xlib_read_header (bfd *abfd, bfd_pef_xlib_header *header)
1071{
1072  unsigned char buf[76];
1073
1074  bfd_seek (abfd, 0, SEEK_SET);
1075
1076  if (bfd_bread ((void *) buf, 76, abfd) != 76)
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
1103static int
1104bfd_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
1122static const bfd_target *
1123bfd_pef_xlib_object_p (bfd *abfd)
1124{
1125  struct bfd_preserve preserve;
1126  bfd_pef_xlib_header header;
1127
1128  if (bfd_pef_xlib_read_header (abfd, &header) != 0)
1129    {
1130      bfd_set_error (bfd_error_wrong_format);
1131      return NULL;
1132    }
1133
1134  if ((header.tag1 != BFD_PEF_XLIB_TAG1)
1135      || ((header.tag2 != BFD_PEF_VLIB_TAG2)
1136	  && (header.tag2 != BFD_PEF_BLIB_TAG2)))
1137    {
1138      bfd_set_error (bfd_error_wrong_format);
1139      return NULL;
1140    }
1141
1142  if (! bfd_preserve_save (abfd, &preserve))
1143    {
1144      bfd_set_error (bfd_error_wrong_format);
1145      return NULL;
1146    }
1147
1148  if (bfd_pef_xlib_scan (abfd, &header) != 0)
1149    {
1150      bfd_preserve_restore (abfd, &preserve);
1151      bfd_set_error (bfd_error_wrong_format);
1152      return NULL;
1153    }
1154
1155  bfd_preserve_finish (abfd, &preserve);
1156  return abfd->xvec;
1157}
1158
1159const bfd_target pef_xlib_vec =
1160{
1161  "pef-xlib",			/* Name.  */
1162  bfd_target_pef_xlib_flavour,	/* Flavour.  */
1163  BFD_ENDIAN_BIG,		/* Byteorder */
1164  BFD_ENDIAN_BIG,		/* Header_byteorder.  */
1165  (HAS_RELOC | EXEC_P |		/* Object flags.  */
1166   HAS_LINENO | HAS_DEBUG |
1167   HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
1168  (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
1169   | SEC_ROM | SEC_HAS_CONTENTS),/* Section_flags.  */
1170  0,				/* Symbol_leading_char.  */
1171  ' ',				/* AR_pad_char.  */
1172  16,				/* AR_max_namelen.  */
1173  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1174  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1175  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
1176  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1177  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1178  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Headers.  */
1179  {				/* bfd_check_format.  */
1180    _bfd_dummy_target,
1181    bfd_pef_xlib_object_p,	/* bfd_check_format.  */
1182    _bfd_dummy_target,
1183    _bfd_dummy_target,
1184  },
1185  {				/* bfd_set_format.  */
1186    bfd_false,
1187    bfd_pef_mkobject,
1188    bfd_false,
1189    bfd_false,
1190  },
1191  {				/* bfd_write_contents.  */
1192    bfd_false,
1193    bfd_true,
1194    bfd_false,
1195    bfd_false,
1196  },
1197
1198  BFD_JUMP_TABLE_GENERIC (bfd_pef_xlib),
1199  BFD_JUMP_TABLE_COPY (_bfd_generic),
1200  BFD_JUMP_TABLE_CORE (_bfd_nocore),
1201  BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
1202  BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
1203  BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1204  BFD_JUMP_TABLE_WRITE (_bfd_nowrite),
1205  BFD_JUMP_TABLE_LINK (_bfd_nolink),
1206  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1207
1208  NULL,
1209
1210  NULL
1211};
1212