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