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