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