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