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