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