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