xref: /netbsd-src/external/gpl3/binutils.old/dist/bfd/pef.c (revision 9fb66d812c00ebfb445c0b47dea128f32aa6fe96)
1 /* PEF support for BFD.
2    Copyright (C) 1999-2018 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 };
1204