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