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