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