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