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