xref: /netbsd-src/external/gpl3/binutils.old/dist/bfd/pef.c (revision 3f351f34c6d827cf017cdcff3543f6ec0c88b420)
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 
75 static int
76 bfd_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 
206 static void
207 bfd_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 
240 static void
241 bfd_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 
257 static bfd_boolean
258 bfd_pef_mkobject (bfd *abfd ATTRIBUTE_UNUSED)
259 {
260   return TRUE;
261 }
262 
263 static 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 
280 static 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 
299 static asection *
300 bfd_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 
320 int
321 bfd_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 
346 int
347 bfd_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 
366 int
367 bfd_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 
383 int
384 bfd_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 
410 void
411 bfd_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 
436 int
437 bfd_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   loaderbuf = bfd_malloc (loaderlen);
450   if (loaderbuf == NULL)
451     return -1;
452 
453   if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0
454       || bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen
455       || loaderlen < 56
456       || bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header) < 0)
457     {
458       free (loaderbuf);
459       return -1;
460     }
461 
462   bfd_pef_print_loader_header (abfd, &header, file);
463   return 0;
464 }
465 
466 int
467 bfd_pef_scan_start_address (bfd *abfd)
468 {
469   bfd_pef_loader_header header;
470   asection *section;
471 
472   asection *loadersec = NULL;
473   unsigned char *loaderbuf = NULL;
474   size_t loaderlen = 0;
475   int ret;
476 
477   loadersec = bfd_get_section_by_name (abfd, "loader");
478   if (loadersec == NULL)
479     goto end;
480 
481   loaderlen = loadersec->size;
482   loaderbuf = bfd_malloc (loaderlen);
483   if (loaderbuf == NULL)
484     goto end;
485 
486   if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0)
487     goto error;
488   if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen)
489     goto error;
490 
491   if (loaderlen < 56)
492     goto error;
493   ret = bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header);
494   if (ret < 0)
495     goto error;
496 
497   if (header.main_section < 0)
498     goto end;
499 
500   for (section = abfd->sections; section != NULL; section = section->next)
501     if ((long) (section->index + 1) == header.main_section)
502       break;
503 
504   if (section == NULL)
505     goto error;
506 
507   abfd->start_address = section->vma + header.main_offset;
508 
509  end:
510   if (loaderbuf != NULL)
511     free (loaderbuf);
512   return 0;
513 
514  error:
515   if (loaderbuf != NULL)
516     free (loaderbuf);
517   return -1;
518 }
519 
520 int
521 bfd_pef_scan (bfd *abfd,
522 	      bfd_pef_header *header,
523 	      bfd_pef_data_struct *mdata)
524 {
525   unsigned int i;
526   enum bfd_architecture cputype;
527   unsigned long cpusubtype;
528 
529   mdata->header = *header;
530 
531   bfd_pef_convert_architecture (header->architecture, &cputype, &cpusubtype);
532   if (cputype == bfd_arch_unknown)
533     {
534       _bfd_error_handler (_("bfd_pef_scan: unknown architecture 0x%lx"),
535 			  header->architecture);
536       return -1;
537     }
538   bfd_set_arch_mach (abfd, cputype, cpusubtype);
539 
540   mdata->header = *header;
541 
542   abfd->flags = (abfd->xvec->object_flags
543 		 | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS)));
544 
545   if (header->section_count != 0)
546     {
547       mdata->sections = bfd_alloc (abfd, header->section_count * sizeof (bfd_pef_section));
548 
549       if (mdata->sections == NULL)
550 	return -1;
551 
552       for (i = 0; i < header->section_count; i++)
553 	{
554 	  bfd_pef_section *cur = &mdata->sections[i];
555 	  cur->header_offset = 40 + (i * 28);
556 	  if (bfd_pef_scan_section (abfd, cur) < 0)
557 	    return -1;
558 	}
559     }
560 
561   if (bfd_pef_scan_start_address (abfd) < 0)
562     return -1;
563 
564   abfd->tdata.pef_data = mdata;
565 
566   return 0;
567 }
568 
569 static int
570 bfd_pef_read_header (bfd *abfd, bfd_pef_header *header)
571 {
572   unsigned char buf[40];
573 
574   bfd_seek (abfd, 0, SEEK_SET);
575 
576   if (bfd_bread ((void *) buf, 40, abfd) != 40)
577     return -1;
578 
579   header->tag1 = bfd_getb32 (buf);
580   header->tag2 = bfd_getb32 (buf + 4);
581   header->architecture = bfd_getb32 (buf + 8);
582   header->format_version = bfd_getb32 (buf + 12);
583   header->timestamp = bfd_getb32 (buf + 16);
584   header->old_definition_version = bfd_getb32 (buf + 20);
585   header->old_implementation_version = bfd_getb32 (buf + 24);
586   header->current_version = bfd_getb32 (buf + 28);
587   header->section_count = bfd_getb32 (buf + 32) + 1;
588   header->instantiated_section_count = bfd_getb32 (buf + 34);
589   header->reserved = bfd_getb32 (buf + 36);
590 
591   return 0;
592 }
593 
594 static const bfd_target *
595 bfd_pef_object_p (bfd *abfd)
596 {
597   bfd_pef_header header;
598   bfd_pef_data_struct *mdata;
599 
600   if (bfd_pef_read_header (abfd, &header) != 0)
601     goto wrong;
602 
603   if (header.tag1 != BFD_PEF_TAG1 || header.tag2 != BFD_PEF_TAG2)
604     goto wrong;
605 
606   mdata = (bfd_pef_data_struct *) bfd_zalloc (abfd, sizeof (*mdata));
607   if (mdata == NULL)
608     goto fail;
609 
610   if (bfd_pef_scan (abfd, &header, mdata))
611     goto wrong;
612 
613   return abfd->xvec;
614 
615  wrong:
616   bfd_set_error (bfd_error_wrong_format);
617 
618  fail:
619   return NULL;
620 }
621 
622 static int
623 bfd_pef_parse_traceback_tables (bfd *abfd,
624 				asection *sec,
625 				unsigned char *buf,
626 				size_t len,
627 				long *nsym,
628 				asymbol **csym)
629 {
630   char *name;
631 
632   asymbol function;
633   asymbol traceback;
634 
635   const char *const tbprefix = "__traceback_";
636   size_t tbnamelen;
637 
638   size_t pos = 0;
639   unsigned long count = 0;
640   int ret;
641 
642   for (;;)
643     {
644       /* We're reading symbols two at a time.  */
645       if (csym && ((csym[count] == NULL) || (csym[count + 1] == NULL)))
646 	break;
647 
648       pos += 3;
649       pos -= (pos % 4);
650 
651       while ((pos + 4) <= len)
652 	{
653 	  if (bfd_getb32 (buf + pos) == 0)
654 	    break;
655 	  pos += 4;
656 	}
657 
658       if ((pos + 4) > len)
659 	break;
660 
661       ret = bfd_pef_parse_traceback_table (abfd, sec, buf, len, pos + 4,
662 					   &function, 0);
663       if (ret < 0)
664 	{
665 	  /* Skip over 0x0L to advance to next possible traceback table.  */
666 	  pos += 4;
667 	  continue;
668 	}
669 
670       BFD_ASSERT (function.name != NULL);
671 
672       /* Don't bother to compute the name if we are just
673 	 counting symbols.  */
674       if (csym)
675 	{
676 	  tbnamelen = strlen (tbprefix) + strlen (function.name);
677 	  name = bfd_alloc (abfd, tbnamelen + 1);
678 	  if (name == NULL)
679 	    {
680 	      bfd_release (abfd, (void *) function.name);
681 	      function.name = NULL;
682 	      break;
683 	    }
684 	  snprintf (name, tbnamelen + 1, "%s%s", tbprefix, function.name);
685 	  traceback.name = name;
686 	  traceback.value = pos;
687 	  traceback.the_bfd = abfd;
688 	  traceback.section = sec;
689 	  traceback.flags = 0;
690 	  traceback.udata.i = ret;
691 
692 	  *(csym[count]) = function;
693 	  *(csym[count + 1]) = traceback;
694 	}
695 
696       pos += ret;
697       count += 2;
698     }
699 
700   *nsym = count;
701   return 0;
702 }
703 
704 static int
705 bfd_pef_parse_function_stub (bfd *abfd ATTRIBUTE_UNUSED,
706 			     unsigned char *buf,
707 			     size_t len,
708 			     unsigned long *offset)
709 {
710   BFD_ASSERT (len == 24);
711 
712   if ((bfd_getb32 (buf) & 0xffff0000) != 0x81820000)
713     return -1;
714   if (bfd_getb32 (buf + 4) != 0x90410014)
715     return -1;
716   if (bfd_getb32 (buf + 8) != 0x800c0000)
717     return -1;
718   if (bfd_getb32 (buf + 12) != 0x804c0004)
719     return -1;
720   if (bfd_getb32 (buf + 16) != 0x7c0903a6)
721     return -1;
722   if (bfd_getb32 (buf + 20) != 0x4e800420)
723     return -1;
724 
725   if (offset != NULL)
726     *offset = (bfd_getb32 (buf) & 0x0000ffff) / 4;
727 
728   return 0;
729 }
730 
731 static int
732 bfd_pef_parse_function_stubs (bfd *abfd,
733 			      asection *codesec,
734 			      unsigned char *codebuf,
735 			      size_t codelen,
736 			      unsigned char *loaderbuf,
737 			      size_t loaderlen,
738 			      unsigned long *nsym,
739 			      asymbol **csym)
740 {
741   const char *const sprefix = "__stub_";
742   size_t codepos = 0;
743   unsigned long count = 0;
744   bfd_pef_loader_header header;
745   bfd_pef_imported_library *libraries = NULL;
746   bfd_pef_imported_symbol *imports = NULL;
747   unsigned long i;
748   int ret;
749 
750   if (loaderlen < 56)
751     goto error;
752 
753   ret = bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header);
754   if (ret < 0)
755     goto error;
756 
757   libraries = bfd_malloc
758     (header.imported_library_count * sizeof (bfd_pef_imported_library));
759   imports = bfd_malloc
760     (header.total_imported_symbol_count * sizeof (bfd_pef_imported_symbol));
761   if (libraries == NULL || imports == NULL)
762     goto error;
763 
764   if (loaderlen < (56 + (header.imported_library_count * 24)))
765     goto error;
766   for (i = 0; i < header.imported_library_count; i++)
767     {
768       ret = bfd_pef_parse_imported_library
769 	(abfd, loaderbuf + 56 + (i * 24), 24, &libraries[i]);
770       if (ret < 0)
771 	goto error;
772     }
773 
774   if (loaderlen < (56 + (header.imported_library_count * 24)
775 		   + (header.total_imported_symbol_count * 4)))
776     goto error;
777   for (i = 0; i < header.total_imported_symbol_count; i++)
778     {
779       ret = (bfd_pef_parse_imported_symbol
780 	     (abfd,
781 	      loaderbuf + 56 + (header.imported_library_count * 24) + (i * 4),
782 	      4, &imports[i]));
783       if (ret < 0)
784 	goto error;
785     }
786 
787   codepos = 0;
788 
789   for (;;)
790     {
791       asymbol sym;
792       const char *symname;
793       char *name;
794       unsigned long sym_index;
795 
796       if (csym && (csym[count] == NULL))
797 	break;
798 
799       codepos += 3;
800       codepos -= (codepos % 4);
801 
802       while ((codepos + 4) <= codelen)
803 	{
804 	  if ((bfd_getb32 (codebuf + codepos) & 0xffff0000) == 0x81820000)
805 	    break;
806 	  codepos += 4;
807 	}
808 
809       if ((codepos + 24) > codelen)
810 	break;
811 
812       ret = bfd_pef_parse_function_stub (abfd, codebuf + codepos, 24, &sym_index);
813       if (ret < 0)
814 	{
815 	  codepos += 24;
816 	  continue;
817 	}
818 
819       if (sym_index >= header.total_imported_symbol_count)
820 	{
821 	  codepos += 24;
822 	  continue;
823 	}
824 
825       {
826 	size_t max, namelen;
827 	const char *s;
828 
829 	if (loaderlen < (header.loader_strings_offset + imports[sym_index].name))
830 	  goto error;
831 
832 	max = loaderlen - (header.loader_strings_offset + imports[sym_index].name);
833 	symname = (char *) loaderbuf;
834 	symname += header.loader_strings_offset + imports[sym_index].name;
835 	namelen = 0;
836 	for (s = symname; s < (symname + max); s++)
837 	  {
838 	    if (*s == '\0')
839 	      break;
840 	    if (! ISPRINT (*s))
841 	      goto error;
842 	    namelen++;
843 	  }
844 	if (*s != '\0')
845 	  goto error;
846 
847 	name = bfd_alloc (abfd, strlen (sprefix) + namelen + 1);
848 	if (name == NULL)
849 	  break;
850 
851 	snprintf (name, strlen (sprefix) + namelen + 1, "%s%s",
852 		  sprefix, symname);
853 	sym.name = name;
854       }
855 
856       sym.value = codepos;
857       sym.the_bfd = abfd;
858       sym.section = codesec;
859       sym.flags = 0;
860       sym.udata.i = 0;
861 
862       codepos += 24;
863 
864       if (csym != NULL)
865 	*(csym[count]) = sym;
866 
867       count++;
868     }
869 
870   goto end;
871 
872  end:
873   if (libraries != NULL)
874     free (libraries);
875   if (imports != NULL)
876     free (imports);
877   *nsym = count;
878   return 0;
879 
880  error:
881   if (libraries != NULL)
882     free (libraries);
883   if (imports != NULL)
884     free (imports);
885   *nsym = count;
886   return -1;
887 }
888 
889 static long
890 bfd_pef_parse_symbols (bfd *abfd, asymbol **csym)
891 {
892   unsigned long count = 0;
893 
894   asection *codesec = NULL;
895   unsigned char *codebuf = NULL;
896   size_t codelen = 0;
897 
898   asection *loadersec = NULL;
899   unsigned char *loaderbuf = NULL;
900   size_t loaderlen = 0;
901 
902   codesec = bfd_get_section_by_name (abfd, "code");
903   if (codesec != NULL)
904     {
905       codelen = codesec->size;
906       codebuf = bfd_malloc (codelen);
907       if (codebuf == NULL)
908 	goto end;
909       if (bfd_seek (abfd, codesec->filepos, SEEK_SET) < 0)
910 	goto end;
911       if (bfd_bread ((void *) codebuf, codelen, abfd) != codelen)
912 	goto end;
913     }
914 
915   loadersec = bfd_get_section_by_name (abfd, "loader");
916   if (loadersec != NULL)
917     {
918       loaderlen = loadersec->size;
919       loaderbuf = bfd_malloc (loaderlen);
920       if (loaderbuf == NULL)
921 	goto end;
922       if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0)
923 	goto end;
924       if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen)
925 	goto end;
926     }
927 
928   count = 0;
929   if (codesec != NULL)
930     {
931       long ncount = 0;
932       bfd_pef_parse_traceback_tables (abfd, codesec, codebuf, codelen,
933 				      &ncount, csym);
934       count += ncount;
935     }
936 
937   if ((codesec != NULL) && (loadersec != NULL))
938     {
939       unsigned long ncount = 0;
940       bfd_pef_parse_function_stubs
941 	(abfd, codesec, codebuf, codelen, loaderbuf, loaderlen, &ncount,
942 	 (csym != NULL) ? (csym + count) : NULL);
943       count += ncount;
944     }
945 
946   if (csym != NULL)
947     csym[count] = NULL;
948 
949  end:
950   if (codebuf != NULL)
951     free (codebuf);
952 
953   if (loaderbuf != NULL)
954     free (loaderbuf);
955 
956   return count;
957 }
958 
959 static long
960 bfd_pef_count_symbols (bfd *abfd)
961 {
962   return bfd_pef_parse_symbols (abfd, NULL);
963 }
964 
965 static long
966 bfd_pef_get_symtab_upper_bound (bfd *abfd)
967 {
968   long nsyms = bfd_pef_count_symbols (abfd);
969 
970   if (nsyms < 0)
971     return nsyms;
972   return ((nsyms + 1) * sizeof (asymbol *));
973 }
974 
975 static long
976 bfd_pef_canonicalize_symtab (bfd *abfd, asymbol **alocation)
977 {
978   long i;
979   asymbol *syms;
980   long ret;
981   long nsyms = bfd_pef_count_symbols (abfd);
982 
983   if (nsyms < 0)
984     return nsyms;
985 
986   syms = bfd_alloc (abfd, nsyms * sizeof (asymbol));
987   if (syms == NULL)
988     return -1;
989 
990   for (i = 0; i < nsyms; i++)
991     alocation[i] = &syms[i];
992 
993   alocation[nsyms] = NULL;
994 
995   ret = bfd_pef_parse_symbols (abfd, alocation);
996   if (ret != nsyms)
997     return 0;
998 
999   return ret;
1000 }
1001 
1002 #define bfd_pef_make_empty_symbol _bfd_generic_make_empty_symbol
1003 
1004 static void
1005 bfd_pef_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
1006 			 asymbol *symbol,
1007 			 symbol_info *ret)
1008 {
1009   bfd_symbol_info (symbol, ret);
1010 }
1011 
1012 static int
1013 bfd_pef_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
1014 			struct bfd_link_info *info ATTRIBUTE_UNUSED)
1015 {
1016   return 0;
1017 }
1018 
1019 const bfd_target pef_vec =
1020 {
1021   "pef",			/* Name.  */
1022   bfd_target_pef_flavour,	/* Flavour.  */
1023   BFD_ENDIAN_BIG,		/* Byteorder.  */
1024   BFD_ENDIAN_BIG,		/* Header_byteorder.  */
1025   (HAS_RELOC | EXEC_P |		/* Object flags.  */
1026    HAS_LINENO | HAS_DEBUG |
1027    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
1028   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
1029    | SEC_ROM | SEC_HAS_CONTENTS), /* Section_flags.  */
1030   0,				/* Symbol_leading_char.  */
1031   ' ',				/* AR_pad_char.  */
1032   16,				/* AR_max_namelen.  */
1033   0,				/* match priority.  */
1034   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1035   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1036   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
1037   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1038   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1039   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Headers.  */
1040   {				/* bfd_check_format.  */
1041     _bfd_dummy_target,
1042     bfd_pef_object_p,		/* bfd_check_format.  */
1043     _bfd_dummy_target,
1044     _bfd_dummy_target,
1045   },
1046   {				/* bfd_set_format.  */
1047     _bfd_bool_bfd_false_error,
1048     bfd_pef_mkobject,
1049     _bfd_bool_bfd_false_error,
1050     _bfd_bool_bfd_false_error,
1051   },
1052   {				/* bfd_write_contents.  */
1053     _bfd_bool_bfd_false_error,
1054     _bfd_bool_bfd_true,
1055     _bfd_bool_bfd_false_error,
1056     _bfd_bool_bfd_false_error,
1057   },
1058 
1059   BFD_JUMP_TABLE_GENERIC (bfd_pef),
1060   BFD_JUMP_TABLE_COPY (_bfd_generic),
1061   BFD_JUMP_TABLE_CORE (_bfd_nocore),
1062   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
1063   BFD_JUMP_TABLE_SYMBOLS (bfd_pef),
1064   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1065   BFD_JUMP_TABLE_WRITE (bfd_pef),
1066   BFD_JUMP_TABLE_LINK (bfd_pef),
1067   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1068 
1069   NULL,
1070 
1071   NULL
1072 };
1073 
1074 #define bfd_pef_xlib_close_and_cleanup		    _bfd_generic_close_and_cleanup
1075 #define bfd_pef_xlib_bfd_free_cached_info	    _bfd_generic_bfd_free_cached_info
1076 #define bfd_pef_xlib_new_section_hook		    _bfd_generic_new_section_hook
1077 #define bfd_pef_xlib_get_section_contents	    _bfd_generic_get_section_contents
1078 #define bfd_pef_xlib_set_section_contents	    _bfd_generic_set_section_contents
1079 #define bfd_pef_xlib_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
1080 #define bfd_pef_xlib_set_section_contents_in_window _bfd_generic_set_section_contents_in_window
1081 
1082 static int
1083 bfd_pef_xlib_read_header (bfd *abfd, bfd_pef_xlib_header *header)
1084 {
1085   unsigned char buf[80];
1086 
1087   bfd_seek (abfd, 0, SEEK_SET);
1088 
1089   if (bfd_bread ((void *) buf, sizeof buf, abfd) != sizeof buf)
1090     return -1;
1091 
1092   header->tag1 = bfd_getb32 (buf);
1093   header->tag2 = bfd_getb32 (buf + 4);
1094   header->current_format = bfd_getb32 (buf + 8);
1095   header->container_strings_offset = bfd_getb32 (buf + 12);
1096   header->export_hash_offset = bfd_getb32 (buf + 16);
1097   header->export_key_offset = bfd_getb32 (buf + 20);
1098   header->export_symbol_offset = bfd_getb32 (buf + 24);
1099   header->export_names_offset = bfd_getb32 (buf + 28);
1100   header->export_hash_table_power = bfd_getb32 (buf + 32);
1101   header->exported_symbol_count = bfd_getb32 (buf + 36);
1102   header->frag_name_offset = bfd_getb32 (buf + 40);
1103   header->frag_name_length = bfd_getb32 (buf + 44);
1104   header->dylib_path_offset = bfd_getb32 (buf + 48);
1105   header->dylib_path_length = bfd_getb32 (buf + 52);
1106   header->cpu_family = bfd_getb32 (buf + 56);
1107   header->cpu_model = bfd_getb32 (buf + 60);
1108   header->date_time_stamp = bfd_getb32 (buf + 64);
1109   header->current_version = bfd_getb32 (buf + 68);
1110   header->old_definition_version = bfd_getb32 (buf + 72);
1111   header->old_implementation_version = bfd_getb32 (buf + 76);
1112 
1113   return 0;
1114 }
1115 
1116 static int
1117 bfd_pef_xlib_scan (bfd *abfd, bfd_pef_xlib_header *header)
1118 {
1119   bfd_pef_xlib_data_struct *mdata = NULL;
1120 
1121   mdata = bfd_alloc (abfd, sizeof (* mdata));
1122   if (mdata == NULL)
1123     return -1;
1124 
1125   mdata->header = *header;
1126 
1127   abfd->flags = (abfd->xvec->object_flags
1128 		 | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS)));
1129 
1130   abfd->tdata.pef_xlib_data = mdata;
1131 
1132   return 0;
1133 }
1134 
1135 static const bfd_target *
1136 bfd_pef_xlib_object_p (bfd *abfd)
1137 {
1138   bfd_pef_xlib_header header;
1139 
1140   if (bfd_pef_xlib_read_header (abfd, &header) != 0)
1141     {
1142       bfd_set_error (bfd_error_wrong_format);
1143       return NULL;
1144     }
1145 
1146   if ((header.tag1 != BFD_PEF_XLIB_TAG1)
1147       || ((header.tag2 != BFD_PEF_VLIB_TAG2)
1148 	  && (header.tag2 != BFD_PEF_BLIB_TAG2)))
1149     {
1150       bfd_set_error (bfd_error_wrong_format);
1151       return NULL;
1152     }
1153 
1154   if (bfd_pef_xlib_scan (abfd, &header) != 0)
1155     {
1156       bfd_set_error (bfd_error_wrong_format);
1157       return NULL;
1158     }
1159 
1160   return abfd->xvec;
1161 }
1162 
1163 const bfd_target pef_xlib_vec =
1164 {
1165   "pef-xlib",			/* Name.  */
1166   bfd_target_pef_xlib_flavour,	/* Flavour.  */
1167   BFD_ENDIAN_BIG,		/* Byteorder */
1168   BFD_ENDIAN_BIG,		/* Header_byteorder.  */
1169   (HAS_RELOC | EXEC_P |		/* Object flags.  */
1170    HAS_LINENO | HAS_DEBUG |
1171    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
1172   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
1173    | SEC_ROM | SEC_HAS_CONTENTS),/* Section_flags.  */
1174   0,				/* Symbol_leading_char.  */
1175   ' ',				/* AR_pad_char.  */
1176   16,				/* AR_max_namelen.  */
1177   0,				/* match priority.  */
1178   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1179   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1180   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
1181   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1182   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1183   bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Headers.  */
1184   {				/* bfd_check_format.  */
1185     _bfd_dummy_target,
1186     bfd_pef_xlib_object_p,	/* bfd_check_format.  */
1187     _bfd_dummy_target,
1188     _bfd_dummy_target,
1189   },
1190   {				/* bfd_set_format.  */
1191     _bfd_bool_bfd_false_error,
1192     bfd_pef_mkobject,
1193     _bfd_bool_bfd_false_error,
1194     _bfd_bool_bfd_false_error,
1195   },
1196   {				/* bfd_write_contents.  */
1197     _bfd_bool_bfd_false_error,
1198     _bfd_bool_bfd_true,
1199     _bfd_bool_bfd_false_error,
1200     _bfd_bool_bfd_false_error,
1201   },
1202 
1203   BFD_JUMP_TABLE_GENERIC (bfd_pef_xlib),
1204   BFD_JUMP_TABLE_COPY (_bfd_generic),
1205   BFD_JUMP_TABLE_CORE (_bfd_nocore),
1206   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
1207   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
1208   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1209   BFD_JUMP_TABLE_WRITE (_bfd_nowrite),
1210   BFD_JUMP_TABLE_LINK (_bfd_nolink),
1211   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1212 
1213   NULL,
1214 
1215   NULL
1216 };
1217