diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /gnu/usr.bin/gdb/bfd |
initial import of NetBSD tree
Diffstat (limited to 'gnu/usr.bin/gdb/bfd')
55 files changed, 23823 insertions, 0 deletions
diff --git a/gnu/usr.bin/gdb/bfd/Makefile b/gnu/usr.bin/gdb/bfd/Makefile new file mode 100644 index 00000000000..9957bb300b4 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/Makefile @@ -0,0 +1,24 @@ +# $Id: Makefile,v 1.1 1995/10/18 08:39:50 deraadt Exp $ + +LIB= bfd +NOPROFILE= +NOPIC= + +CFLAGS+= -I$(.CURDIR)/arch/$(MACHINE_ARCH) -I$(.CURDIR) \ + -I$(.CURDIR)/../include +.PATH: $(.CURDIR)/arch/$(MACHINE_ARCH) + +SRCS= archive.c archures.c bfd.c cache.c coffgen.c core.c ctor.c \ + format.c init.c libbfd.c opncls.c reloc.c seclet.c section.c \ + syms.c targets.c ecoff.c elf.c srec.c aout32.c \ + stab-syms.c netbsd-core.c + +.include "arch/$(MACHINE_ARCH)/Makefile.inc" + +targets.o archures.o: $(.CURDIR)/$(.TARGET:S/.o$/.c/) + ${COMPILE.c} $(VECTORS) -o $(.TARGET) $(.IMPSRC) + + +install: + +.include <bsd.lib.mk> diff --git a/gnu/usr.bin/gdb/bfd/aout-target.h b/gnu/usr.bin/gdb/bfd/aout-target.h new file mode 100644 index 00000000000..3db04dd513c --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/aout-target.h @@ -0,0 +1,449 @@ +/* Define a target vector and some small routines for a variant of a.out. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: aout-target.h,v 1.1 1995/10/18 08:39:50 deraadt Exp $ +*/ + +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" +/*#include "libaout.h"*/ + +extern CONST struct reloc_howto_struct * NAME(aout,reloc_type_lookup) (); + +/* Set parameters about this a.out file that are machine-dependent. + This routine is called from some_aout_object_p just before it returns. */ +#ifndef MY_callback +static bfd_target * +DEFUN(MY(callback),(abfd), + bfd *abfd) +{ + struct internal_exec *execp = exec_hdr (abfd); + + /* Calculate the file positions of the parts of a newly read aout header */ + obj_textsec (abfd)->_raw_size = N_TXTSIZE(*execp); + + /* The virtual memory addresses of the sections */ + obj_textsec (abfd)->vma = N_TXTADDR(*execp); + obj_datasec (abfd)->vma = N_DATADDR(*execp); + obj_bsssec (abfd)->vma = N_BSSADDR(*execp); + + /* The file offsets of the sections */ + obj_textsec (abfd)->filepos = N_TXTOFF (*execp); + obj_datasec (abfd)->filepos = N_DATOFF (*execp); + + /* + * XXX - A few hacks to be able to read .o files and kernels. + * should probably be done in `netbsd.h' by better macro + * definitions (see also `include/aout/aout64.h') + */ + if ((execp->a_entry & ~(N_SEGSIZE(x)-1)) > obj_textsec (abfd)->vma) { + obj_textsec (abfd)->vma += (execp->a_entry & ~(N_SEGSIZE(x)-1)) - N_TXTADDR(*execp); + obj_datasec (abfd)->vma += (execp->a_entry & ~(N_SEGSIZE(x)-1)) - N_TXTADDR(*execp); + obj_bsssec (abfd)->vma += (execp->a_entry & ~(N_SEGSIZE(x)-1)) - N_TXTADDR(*execp); + } + if (execp->a_entry == 0 && N_MAGIC(*execp) == OMAGIC || + execp->a_entry < N_SEGSIZE(x) && N_MAGIC(*execp) == ZMAGIC ) { + obj_textsec (abfd)->vma -= N_TXTADDR(*execp); + obj_datasec (abfd)->vma -= N_TXTADDR(*execp); + obj_bsssec (abfd)->vma -= N_TXTADDR(*execp); + } + + /* The file offsets of the relocation info */ + obj_textsec (abfd)->rel_filepos = N_TRELOFF(*execp); + obj_datasec (abfd)->rel_filepos = N_DRELOFF(*execp); + + /* The file offsets of the string table and symbol table. */ + obj_sym_filepos (abfd) = N_SYMOFF (*execp); + obj_str_filepos (abfd) = N_STROFF (*execp); + + /* Determine the architecture and machine type of the object file. */ +#ifdef SET_ARCH_MACH + SET_ARCH_MACH(abfd, *execp); +#else + bfd_default_set_arch_mach(abfd, DEFAULT_ARCH, 0); +#endif + + /* Don't set sizes now -- can't be sure until we know arch & mach. + Sizes get set in set_sizes callback, later. */ +#if 0 + adata(abfd).page_size = PAGE_SIZE; +#ifdef SEGMENT_SIZE + adata(abfd).segment_size = SEGMENT_SIZE; +#else + adata(abfd).segment_size = PAGE_SIZE; +#endif + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; +#endif + + return abfd->xvec; +} +#endif + +#ifndef MY_object_p +/* Finish up the reading of an a.out file header */ + +static bfd_target * +DEFUN(MY(object_p),(abfd), + bfd *abfd) +{ + struct external_exec exec_bytes; /* Raw exec header from file */ + struct internal_exec exec; /* Cleaned-up exec header */ + bfd_target *target; + + if (bfd_read ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd) + != EXEC_BYTES_SIZE) { + bfd_error = wrong_format; + return 0; + } + +#ifdef NO_SWAP_MAGIC + memcpy (&exec.a_info, exec_bytes.e_info, sizeof(exec.a_info)); +#else + exec.a_info = bfd_h_get_32 (abfd, exec_bytes.e_info); +#endif /* NO_SWAP_MAGIC */ + + if (N_BADMAG (exec)) return 0; +#ifdef MACHTYPE_OK + if (!(MACHTYPE_OK (N_MACHTYPE (exec)))) return 0; +#endif + + NAME(aout,swap_exec_header_in)(abfd, &exec_bytes, &exec); + target = NAME(aout,some_aout_object_p) (abfd, &exec, MY(callback)); + +#ifdef ENTRY_CAN_BE_ZERO + /* The NEWSOS3 entry-point is/was 0, which (amongst other lossage) + * means that it isn't obvious if EXEC_P should be set. + * All of the following must be true for an executable: + * There must be no relocations, the bfd can be neither an + * archive nor an archive element, and the file must be executable. */ + + if (exec.a_trsize + exec.a_drsize == 0 + && bfd_get_format(abfd) == bfd_object && abfd->my_archive == NULL) + { + struct stat buf; +#ifndef S_IXUSR +#define S_IXUSR 0100 /* Execute by owner. */ +#endif + if (stat(abfd->filename, &buf) == 0 && (buf.st_mode & S_IXUSR)) + abfd->flags |= EXEC_P; + } +#endif /* ENTRY_CAN_BE_ZERO */ + + return target; +} +#define MY_object_p MY(object_p) +#endif + + +#ifndef MY_mkobject +static boolean +DEFUN(MY(mkobject),(abfd), + bfd *abfd) +{ + if (NAME(aout,mkobject)(abfd) == false) + return false; +#if 0 /* Sizes get set in set_sizes callback, later, after we know + the architecture and machine. */ + adata(abfd).page_size = PAGE_SIZE; +#ifdef SEGMENT_SIZE + adata(abfd).segment_size = SEGMENT_SIZE; +#else + adata(abfd).segment_size = PAGE_SIZE; +#endif + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; +#endif + return true; +} +#define MY_mkobject MY(mkobject) +#endif + +/* Write an object file. + Section contents have already been written. We write the + file header, symbols, and relocation. */ + +#ifndef MY_write_object_contents +static boolean +DEFUN(MY(write_object_contents),(abfd), + bfd *abfd) +{ + struct external_exec exec_bytes; + struct internal_exec *execp = exec_hdr (abfd); + +#if CHOOSE_RELOC_SIZE + CHOOSE_RELOC_SIZE(abfd); +#else + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; +#endif + + WRITE_HEADERS(abfd, execp); + + return true; +} +#define MY_write_object_contents MY(write_object_contents) +#endif + +#ifndef MY_set_sizes +static boolean +DEFUN(MY(set_sizes),(abfd), bfd *abfd) +{ + adata(abfd).page_size = PAGE_SIZE; +#ifdef SEGMENT_SIZE + adata(abfd).segment_size = SEGMENT_SIZE; +#else + adata(abfd).segment_size = PAGE_SIZE; +#endif + adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; + return true; +} +#define MY_set_sizes MY(set_sizes) +#endif + +#ifndef MY_backend_data +static CONST struct aout_backend_data MY(backend_data) = { + 0, /* zmagic contiguous */ + 0, /* text incl header */ + 0, /* text vma? */ + MY_set_sizes, + 0, /* exec header is counted */ +}; +#define MY_backend_data &MY(backend_data) +#endif + +/* We assume BFD generic archive files. */ +#ifndef MY_openr_next_archived_file +#define MY_openr_next_archived_file bfd_generic_openr_next_archived_file +#endif +#ifndef MY_generic_stat_arch_elt +#define MY_generic_stat_arch_elt bfd_generic_stat_arch_elt +#endif +#ifndef MY_slurp_armap +#define MY_slurp_armap bfd_slurp_bsd_armap +#endif +#ifndef MY_slurp_extended_name_table +#define MY_slurp_extended_name_table _bfd_slurp_extended_name_table +#endif +#ifndef MY_write_armap +#define MY_write_armap bsd_write_armap +#endif +#ifndef MY_truncate_arname +#define MY_truncate_arname bfd_bsd_truncate_arname +#endif + +/* No core file defined here -- configure in trad-core.c separately. */ +#ifndef MY_core_file_failing_command +#define MY_core_file_failing_command _bfd_dummy_core_file_failing_command +#endif +#ifndef MY_core_file_failing_signal +#define MY_core_file_failing_signal _bfd_dummy_core_file_failing_signal +#endif +#ifndef MY_core_file_matches_executable_p +#define MY_core_file_matches_executable_p \ + _bfd_dummy_core_file_matches_executable_p +#endif +#ifndef MY_core_file_p +#define MY_core_file_p _bfd_dummy_target +#endif + +#ifndef MY_bfd_debug_info_start +#define MY_bfd_debug_info_start bfd_void +#endif +#ifndef MY_bfd_debug_info_end +#define MY_bfd_debug_info_end bfd_void +#endif +#ifndef MY_bfd_debug_info_accumulate +#define MY_bfd_debug_info_accumulate \ + (void (*) PARAMS ((bfd*, struct sec *))) bfd_void +#endif + +#ifndef MY_core_file_failing_command +#define MY_core_file_failing_command NAME(aout,core_file_failing_command) +#endif +#ifndef MY_core_file_failing_signal +#define MY_core_file_failing_signal NAME(aout,core_file_failing_signal) +#endif +#ifndef MY_core_file_matches_executable_p +#define MY_core_file_matches_executable_p NAME(aout,core_file_matches_executable_p) +#endif +#ifndef MY_slurp_armap +#define MY_slurp_armap NAME(aout,slurp_armap) +#endif +#ifndef MY_slurp_extended_name_table +#define MY_slurp_extended_name_table NAME(aout,slurp_extended_name_table) +#endif +#ifndef MY_truncate_arname +#define MY_truncate_arname NAME(aout,truncate_arname) +#endif +#ifndef MY_write_armap +#define MY_write_armap NAME(aout,write_armap) +#endif +#ifndef MY_close_and_cleanup +#define MY_close_and_cleanup NAME(aout,close_and_cleanup) +#endif +#ifndef MY_set_section_contents +#define MY_set_section_contents NAME(aout,set_section_contents) +#endif +#ifndef MY_get_section_contents +#define MY_get_section_contents NAME(aout,get_section_contents) +#endif +#ifndef MY_new_section_hook +#define MY_new_section_hook NAME(aout,new_section_hook) +#endif +#ifndef MY_get_symtab_upper_bound +#define MY_get_symtab_upper_bound NAME(aout,get_symtab_upper_bound) +#endif +#ifndef MY_get_symtab +#define MY_get_symtab NAME(aout,get_symtab) +#endif +#ifndef MY_get_reloc_upper_bound +#define MY_get_reloc_upper_bound NAME(aout,get_reloc_upper_bound) +#endif +#ifndef MY_canonicalize_reloc +#define MY_canonicalize_reloc NAME(aout,canonicalize_reloc) +#endif +#ifndef MY_make_empty_symbol +#define MY_make_empty_symbol NAME(aout,make_empty_symbol) +#endif +#ifndef MY_print_symbol +#define MY_print_symbol NAME(aout,print_symbol) +#endif +#ifndef MY_get_symbol_info +#define MY_get_symbol_info NAME(aout,get_symbol_info) +#endif +#ifndef MY_get_lineno +#define MY_get_lineno NAME(aout,get_lineno) +#endif +#ifndef MY_set_arch_mach +#define MY_set_arch_mach NAME(aout,set_arch_mach) +#endif +#ifndef MY_openr_next_archived_file +#define MY_openr_next_archived_file NAME(aout,openr_next_archived_file) +#endif +#ifndef MY_find_nearest_line +#define MY_find_nearest_line NAME(aout,find_nearest_line) +#endif +#ifndef MY_generic_stat_arch_elt +#define MY_generic_stat_arch_elt NAME(aout,generic_stat_arch_elt) +#endif +#ifndef MY_sizeof_headers +#define MY_sizeof_headers NAME(aout,sizeof_headers) +#endif +#ifndef MY_bfd_debug_info_start +#define MY_bfd_debug_info_start NAME(aout,bfd_debug_info_start) +#endif +#ifndef MY_bfd_debug_info_end +#define MY_bfd_debug_info_end NAME(aout,bfd_debug_info_end) +#endif +#ifndef MY_bfd_debug_info_accumulat +#define MY_bfd_debug_info_accumulat NAME(aout,bfd_debug_info_accumulat) +#endif +#ifndef MY_reloc_howto_type_lookup +#define MY_reloc_howto_type_lookup NAME(aout,reloc_type_lookup) +#endif +#ifndef MY_make_debug_symbol +#define MY_make_debug_symbol 0 +#endif + +/* Aout symbols normally have leading underscores */ +#ifndef MY_symbol_leading_char +#define MY_symbol_leading_char '_' +#endif + +/* Aout archives normally use spaces for padding */ +#ifndef AR_PAD_CHAR +#define AR_PAD_CHAR ' ' +#endif + +#ifndef MY_BFD_TARGET +bfd_target MY(vec) = +{ + TARGETNAME, /* name */ + bfd_target_aout_flavour, +#ifdef TARGET_IS_BIG_ENDIAN_P + true, /* target byte order (big) */ + true, /* target headers byte order (big) */ +#else + false, /* target byte order (little) */ + false, /* target headers byte order (little) */ +#endif + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + MY_symbol_leading_char, + AR_PAD_CHAR, /* ar_pad_char */ + 15, /* ar_max_namelen */ + 3, /* minimum alignment */ +#ifdef TARGET_IS_BIG_ENDIAN_P + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ +#else + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ +#endif + {_bfd_dummy_target, MY_object_p, /* bfd_check_format */ + bfd_generic_archive_p, MY_core_file_p}, + {bfd_false, MY_mkobject, /* bfd_set_format */ + _bfd_generic_mkarchive, bfd_false}, + {bfd_false, MY_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + MY_core_file_failing_command, + MY_core_file_failing_signal, + MY_core_file_matches_executable_p, + MY_slurp_armap, + MY_slurp_extended_name_table, + MY_truncate_arname, + MY_write_armap, + MY_close_and_cleanup, + MY_set_section_contents, + MY_get_section_contents, + MY_new_section_hook, + MY_get_symtab_upper_bound, + MY_get_symtab, + MY_get_reloc_upper_bound, + MY_canonicalize_reloc, + MY_make_empty_symbol, + MY_print_symbol, + MY_get_symbol_info, + MY_get_lineno, + MY_set_arch_mach, + MY_openr_next_archived_file, + MY_find_nearest_line, + MY_generic_stat_arch_elt, + MY_sizeof_headers, + MY_bfd_debug_info_start, + MY_bfd_debug_info_end, + MY_bfd_debug_info_accumulate, + bfd_generic_get_relocated_section_contents, + bfd_generic_relax_section, + bfd_generic_seclet_link, + MY_reloc_howto_type_lookup, + MY_make_debug_symbol, + (PTR) MY_backend_data, +}; +#endif /* MY_BFD_TARGET */ diff --git a/gnu/usr.bin/gdb/bfd/aout32.c b/gnu/usr.bin/gdb/bfd/aout32.c new file mode 100644 index 00000000000..c5c799185a7 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/aout32.c @@ -0,0 +1,26 @@ +/* BFD back-end for 32-bit a.out files. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: aout32.c,v 1.1 1995/10/18 08:39:51 deraadt Exp $ +*/ + +#define ARCH_SIZE 32 + +#include "aoutx.h" diff --git a/gnu/usr.bin/gdb/bfd/aoutx.h b/gnu/usr.bin/gdb/bfd/aoutx.h new file mode 100644 index 00000000000..6a4cd1bba80 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/aoutx.h @@ -0,0 +1,2571 @@ +/* BFD semi-generic back-end for a.out binaries. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: aoutx.h,v 1.1 1995/10/18 08:39:51 deraadt Exp $ +*/ + +/* +SECTION + a.out backends + + +DESCRIPTION + + BFD supports a number of different flavours of a.out format, + though the major differences are only the sizes of the + structures on disk, and the shape of the relocation + information. + + The support is split into a basic support file @code{aoutx.h} + and other files which derive functions from the base. One + derivation file is @code{aoutf1.h} (for a.out flavour 1), and + adds to the basic a.out functions support for sun3, sun4, 386 + and 29k a.out files, to create a target jump vector for a + specific target. + + This information is further split out into more specific files + for each machine, including @code{sunos.c} for sun3 and sun4, + @code{newsos3.c} for the Sony NEWS, and @code{demo64.c} for a + demonstration of a 64 bit a.out format. + + The base file @code{aoutx.h} defines general mechanisms for + reading and writing records to and from disk, and various + other methods which BFD requires. It is included by + @code{aout32.c} and @code{aout64.c} to form the names + aout_32_swap_exec_header_in, aout_64_swap_exec_header_in, etc. + + As an example, this is what goes on to make the back end for a + sun4, from aout32.c + +| #define ARCH_SIZE 32 +| #include "aoutx.h" + + Which exports names: + +| ... +| aout_32_canonicalize_reloc +| aout_32_find_nearest_line +| aout_32_get_lineno +| aout_32_get_reloc_upper_bound +| ... + + from sunos.c + +| #define ARCH 32 +| #define TARGET_NAME "a.out-sunos-big" +| #define VECNAME sunos_big_vec +| #include "aoutf1.h" + + requires all the names from aout32.c, and produces the jump vector + +| sunos_big_vec + + The file host-aout.c is a special case. It is for a large set + of hosts that use ``more or less standard'' a.out files, and + for which cross-debugging is not interesting. It uses the + standard 32-bit a.out support routines, but determines the + file offsets and addresses of the text, data, and BSS + sections, the machine architecture and machine type, and the + entry point address, in a host-dependent manner. Once these + values have been determined, generic code is used to handle + the object file. + + When porting it to run on a new system, you must supply: + +| HOST_PAGE_SIZE +| HOST_SEGMENT_SIZE +| HOST_MACHINE_ARCH (optional) +| HOST_MACHINE_MACHINE (optional) +| HOST_TEXT_START_ADDR +| HOST_STACK_END_ADDR + + in the file <<../include/sys/h-XXX.h>> (for your host). These + values, plus the structures and macros defined in <<a.out.h>> on + your host system, will produce a BFD target that will access + ordinary a.out files on your host. To configure a new machine + to use <<host-aout.c>., specify: + +| TDEFAULTS = -DDEFAULT_VECTOR=host_aout_big_vec +| TDEPFILES= host-aout.o trad-core.o + + in the <<config/mt-XXX>> file, and modify configure.in to use the + <<mt-XXX>> file (by setting "<<bfd_target=XXX>>") when your + configuration is selected. + +*/ + +/* Some assumptions: + * Any BFD with D_PAGED set is ZMAGIC, and vice versa. + Doesn't matter what the setting of WP_TEXT is on output, but it'll + get set on input. + * Any BFD with D_PAGED clear and WP_TEXT set is NMAGIC. + * Any BFD with both flags clear is OMAGIC. + (Just want to make these explicit, so the conditions tested in this + file make sense if you're more familiar with a.out than with BFD.) */ + +#define KEEPIT flags +#define KEEPITTYPE int + +#include <assert.h> +#include <string.h> /* For strchr and friends */ +#include "bfd.h" +#include <sysdep.h> +#include <ansidecl.h> + +struct external_exec; +#include "libaout.h" +#include "libbfd.h" +#include "aout/aout64.h" +#include "aout/stab_gnu.h" +#include "aout/ar.h" + +extern void (*bfd_error_trap)(); + +/* +SUBSECTION + relocations + +DESCRIPTION + The file @code{aoutx.h} caters for both the @emph{standard} + and @emph{extended} forms of a.out relocation records. + + The standard records are characterised by containing only an + address, a symbol index and a type field. The extended records + (used on 29ks and sparcs) also have a full integer for an + addend. + +*/ +#define CTOR_TABLE_RELOC_IDX 2 + +#define howto_table_ext NAME(aout,ext_howto_table) +#define howto_table_std NAME(aout,std_howto_table) + +reloc_howto_type howto_table_ext[] = +{ + /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */ + HOWTO(RELOC_8, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", false, 0,0x000000ff, false), + HOWTO(RELOC_16, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", false, 0,0x0000ffff, false), + HOWTO(RELOC_32, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", false, 0,0xffffffff, false), + HOWTO(RELOC_DISP8, 0, 0, 8, true, 0, complain_overflow_signed,0,"DISP8", false, 0,0x000000ff, false), + HOWTO(RELOC_DISP16, 0, 1, 16, true, 0, complain_overflow_signed,0,"DISP16", false, 0,0x0000ffff, false), + HOWTO(RELOC_DISP32, 0, 2, 32, true, 0, complain_overflow_signed,0,"DISP32", false, 0,0xffffffff, false), + HOWTO(RELOC_WDISP30,2, 2, 30, true, 0, complain_overflow_signed,0,"WDISP30", false, 0,0x3fffffff, false), + HOWTO(RELOC_WDISP22,2, 2, 22, true, 0, complain_overflow_signed,0,"WDISP22", false, 0,0x003fffff, false), + HOWTO(RELOC_HI22, 10, 2, 22, false, 0, complain_overflow_bitfield,0,"HI22", false, 0,0x003fffff, false), + HOWTO(RELOC_22, 0, 2, 22, false, 0, complain_overflow_bitfield,0,"22", false, 0,0x003fffff, false), + HOWTO(RELOC_13, 0, 2, 13, false, 0, complain_overflow_bitfield,0,"13", false, 0,0x00001fff, false), + HOWTO(RELOC_LO10, 0, 2, 10, false, 0, complain_overflow_dont,0,"LO10", false, 0,0x000003ff, false), + HOWTO(RELOC_SFA_BASE,0, 2, 32, false, 0, complain_overflow_bitfield,0,"SFA_BASE", false, 0,0xffffffff, false), + HOWTO(RELOC_SFA_OFF13,0,2, 32, false, 0, complain_overflow_bitfield,0,"SFA_OFF13",false, 0,0xffffffff, false), + HOWTO(RELOC_BASE10, 0, 2, 16, false, 0, complain_overflow_bitfield,0,"BASE10", false, 0,0x0000ffff, false), + HOWTO(RELOC_BASE13, 0, 2, 13, false, 0, complain_overflow_bitfield,0,"BASE13", false, 0,0x00001fff, false), + HOWTO(RELOC_BASE22, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"BASE22", false, 0,0x00000000, false), + HOWTO(RELOC_PC10, 0, 2, 10, false, 0, complain_overflow_bitfield,0,"PC10", false, 0,0x000003ff, false), + HOWTO(RELOC_PC22, 0, 2, 22, false, 0, complain_overflow_bitfield,0,"PC22", false, 0,0x003fffff, false), + HOWTO(RELOC_JMP_TBL,0, 2, 32, false, 0, complain_overflow_bitfield,0,"JMP_TBL", false, 0,0xffffffff, false), + HOWTO(RELOC_SEGOFF16,0, 2, 0, false, 0, complain_overflow_bitfield,0,"SEGOFF16", false, 0,0x00000000, false), + HOWTO(RELOC_GLOB_DAT,0, 2, 0, false, 0, complain_overflow_bitfield,0,"GLOB_DAT", false, 0,0x00000000, false), + HOWTO(RELOC_JMP_SLOT,0, 2, 0, false, 0, complain_overflow_bitfield,0,"JMP_SLOT", false, 0,0x00000000, false), + HOWTO(RELOC_RELATIVE,0, 2, 0, false, 0, complain_overflow_bitfield,0,"RELATIVE", false, 0,0x00000000, false), +}; + +/* Convert standard reloc records to "arelent" format (incl byte swap). */ + +reloc_howto_type howto_table_std[] = { + /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask pcdone */ +HOWTO( 0, 0, 0, 8, false, 0, complain_overflow_bitfield,0,"8", true, 0x000000ff,0x000000ff, false), +HOWTO( 1, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"16", true, 0x0000ffff,0x0000ffff, false), +HOWTO( 2, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"32", true, 0xffffffff,0xffffffff, false), +HOWTO( 3, 0, 4, 64, false, 0, complain_overflow_bitfield,0,"64", true, 0xdeaddead,0xdeaddead, false), +HOWTO( 4, 0, 0, 8, true, 0, complain_overflow_signed, 0,"DISP8", true, 0x000000ff,0x000000ff, false), +HOWTO( 5, 0, 1, 16, true, 0, complain_overflow_signed, 0,"DISP16", true, 0x0000ffff,0x0000ffff, false), +HOWTO( 6, 0, 2, 32, true, 0, complain_overflow_signed, 0,"DISP32", true, 0xffffffff,0xffffffff, false), +HOWTO( 7, 0, 4, 64, true, 0, complain_overflow_signed, 0,"DISP64", true, 0xfeedface,0xfeedface, false), +{ -1 }, +HOWTO( 9, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"BASE16", false,0xffffffff,0xffffffff, false), +HOWTO(10, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"BASE32", false,0xffffffff,0xffffffff, false), +}; + +#define TABLE_SIZE(TABLE) (sizeof(TABLE)/sizeof(TABLE[0])) + +CONST struct reloc_howto_struct * +DEFUN(NAME(aout,reloc_type_lookup),(abfd,code), + bfd *abfd AND + bfd_reloc_code_real_type code) +{ +#define EXT(i,j) case i: return &howto_table_ext[j] +#define STD(i,j) case i: return &howto_table_std[j] + int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE; + if (code == BFD_RELOC_CTOR) + switch (bfd_get_arch_info (abfd)->bits_per_address) + { + case 32: + code = BFD_RELOC_32; + break; + } + if (ext) + switch (code) + { + EXT (BFD_RELOC_32, 2); + EXT (BFD_RELOC_HI22, 8); + EXT (BFD_RELOC_LO10, 11); + EXT (BFD_RELOC_32_PCREL_S2, 6); + default: return (CONST struct reloc_howto_struct *) 0; + } + else + /* std relocs */ + switch (code) + { + STD (BFD_RELOC_16, 1); + STD (BFD_RELOC_32, 2); + STD (BFD_RELOC_8_PCREL, 4); + STD (BFD_RELOC_16_PCREL, 5); + STD (BFD_RELOC_32_PCREL, 6); + STD (BFD_RELOC_16_BASEREL, 9); + STD (BFD_RELOC_32_BASEREL, 10); + default: return (CONST struct reloc_howto_struct *) 0; + } +} + +extern bfd_error_vector_type bfd_error_vector; + +/* +SUBSECTION + Internal Entry Points + +DESCRIPTION + @code{aoutx.h} exports several routines for accessing the + contents of an a.out file, which are gathered and exported in + turn by various format specific files (eg sunos.c). + +*/ + +/* +FUNCTION + aout_<size>_swap_exec_header_in + +DESCRIPTION + Swaps the information in an executable header taken from a raw + byte stream memory image, into the internal exec_header + structure. + +SYNOPSIS + void aout_<size>_swap_exec_header_in, + (bfd *abfd, + struct external_exec *raw_bytes, + struct internal_exec *execp); +*/ + +#ifndef NAME_swap_exec_header_in +void +DEFUN(NAME(aout,swap_exec_header_in),(abfd, raw_bytes, execp), + bfd *abfd AND + struct external_exec *raw_bytes AND + struct internal_exec *execp) +{ + struct external_exec *bytes = (struct external_exec *)raw_bytes; + + /* The internal_exec structure has some fields that are unused in this + configuration (IE for i960), so ensure that all such uninitialized + fields are zero'd out. There are places where two of these structs + are memcmp'd, and thus the contents do matter. */ + memset (execp, 0, sizeof (struct internal_exec)); + /* Now fill in fields in the execp, from the bytes in the raw data. */ + execp->a_info = bfd_h_get_32 (abfd, bytes->e_info); + execp->a_text = GET_WORD (abfd, bytes->e_text); + execp->a_data = GET_WORD (abfd, bytes->e_data); + execp->a_bss = GET_WORD (abfd, bytes->e_bss); + execp->a_syms = GET_WORD (abfd, bytes->e_syms); + execp->a_entry = GET_WORD (abfd, bytes->e_entry); + execp->a_trsize = GET_WORD (abfd, bytes->e_trsize); + execp->a_drsize = GET_WORD (abfd, bytes->e_drsize); +} +#define NAME_swap_exec_header_in NAME(aout,swap_exec_header_in) +#endif + +/* +FUNCTION + aout_<size>_swap_exec_header_out + +DESCRIPTION + Swaps the information in an internal exec header structure + into the supplied buffer ready for writing to disk. + +SYNOPSIS + void aout_<size>_swap_exec_header_out + (bfd *abfd, + struct internal_exec *execp, + struct external_exec *raw_bytes); +*/ +void +DEFUN(NAME(aout,swap_exec_header_out),(abfd, execp, raw_bytes), + bfd *abfd AND + struct internal_exec *execp AND + struct external_exec *raw_bytes) +{ + struct external_exec *bytes = (struct external_exec *)raw_bytes; + + /* Now fill in fields in the raw data, from the fields in the exec struct. */ + bfd_h_put_32 (abfd, execp->a_info , bytes->e_info); + PUT_WORD (abfd, execp->a_text , bytes->e_text); + PUT_WORD (abfd, execp->a_data , bytes->e_data); + PUT_WORD (abfd, execp->a_bss , bytes->e_bss); + PUT_WORD (abfd, execp->a_syms , bytes->e_syms); + PUT_WORD (abfd, execp->a_entry , bytes->e_entry); + PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize); + PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize); +} + + + +/* +FUNCTION + aout_<size>_some_aout_object_p + +DESCRIPTION + Some A.OUT variant thinks that the file whose format we're + checking is an a.out file. Do some more checking, and set up + for access if it really is. Call back to the calling + environments "finish up" function just before returning, to + handle any last-minute setup. + +SYNOPSIS + bfd_target *aout_<size>_some_aout_object_p + (bfd *abfd, + bfd_target *(*callback_to_real_object_p)()); +*/ + +bfd_target * +DEFUN(NAME(aout,some_aout_object_p),(abfd, execp, callback_to_real_object_p), + bfd *abfd AND + struct internal_exec *execp AND + bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *))) +{ + struct aout_data_struct *rawptr, *oldrawptr; + bfd_target *result; + + rawptr = (struct aout_data_struct *) bfd_zalloc (abfd, sizeof (struct aout_data_struct )); + if (rawptr == NULL) { + bfd_error = no_memory; + return 0; + } + + oldrawptr = abfd->tdata.aout_data; + abfd->tdata.aout_data = rawptr; + + /* Copy the contents of the old tdata struct. + In particular, we want the subformat, since for hpux it was set in + hp300hpux.c:swap_exec_header_in and will be used in + hp300hpux.c:callback. */ + if (oldrawptr != NULL) + *abfd->tdata.aout_data = *oldrawptr; + + abfd->tdata.aout_data->a.hdr = &rawptr->e; + *(abfd->tdata.aout_data->a.hdr) = *execp; /* Copy in the internal_exec struct */ + execp = abfd->tdata.aout_data->a.hdr; + + /* Set the file flags */ + abfd->flags = NO_FLAGS; + if (execp->a_drsize || execp->a_trsize) + abfd->flags |= HAS_RELOC; + /* Setting of EXEC_P has been deferred to the bottom of this function */ + if (execp->a_syms) + abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS; + + if (N_MAGIC (*execp) == ZMAGIC) + { + abfd->flags |= D_PAGED|WP_TEXT; + adata(abfd).magic = z_magic; + } + else if (N_MAGIC (*execp) == NMAGIC) + { + abfd->flags |= WP_TEXT; + adata(abfd).magic = n_magic; + } + else + adata(abfd).magic = o_magic; + + bfd_get_start_address (abfd) = execp->a_entry; + + obj_aout_symbols (abfd) = (aout_symbol_type *)NULL; + bfd_get_symcount (abfd) = execp->a_syms / sizeof (struct external_nlist); + + /* The default relocation entry size is that of traditional V7 Unix. */ + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + + /* The default symbol entry size is that of traditional Unix. */ + obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE; + + /* Create the sections. This is raunchy, but bfd_close wants to reclaim + them. */ + + obj_textsec (abfd) = bfd_make_section_old_way (abfd, ".text"); + obj_datasec (abfd) = bfd_make_section_old_way (abfd, ".data"); + obj_bsssec (abfd) = bfd_make_section_old_way (abfd, ".bss"); + +#if 0 + (void)bfd_make_section (abfd, ".text"); + (void)bfd_make_section (abfd, ".data"); + (void)bfd_make_section (abfd, ".bss"); +#endif + + obj_datasec (abfd)->_raw_size = execp->a_data; + obj_bsssec (abfd)->_raw_size = execp->a_bss; + + obj_textsec (abfd)->flags = (execp->a_trsize != 0 ? + (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC) : + (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)); + obj_datasec (abfd)->flags = (execp->a_drsize != 0 ? + (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC) : + (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS)); + obj_bsssec (abfd)->flags = SEC_ALLOC; + +#ifdef THIS_IS_ONLY_DOCUMENTATION + /* The common code can't fill in these things because they depend + on either the start address of the text segment, the rounding + up of virtual addersses between segments, or the starting file + position of the text segment -- all of which varies among different + versions of a.out. */ + + /* Call back to the format-dependent code to fill in the rest of the + fields and do any further cleanup. Things that should be filled + in by the callback: */ + + struct exec *execp = exec_hdr (abfd); + + obj_textsec (abfd)->size = N_TXTSIZE(*execp); + obj_textsec (abfd)->raw_size = N_TXTSIZE(*execp); + /* data and bss are already filled in since they're so standard */ + + /* The virtual memory addresses of the sections */ + obj_textsec (abfd)->vma = N_TXTADDR(*execp); + obj_datasec (abfd)->vma = N_DATADDR(*execp); + obj_bsssec (abfd)->vma = N_BSSADDR(*execp); + + /* The file offsets of the sections */ + obj_textsec (abfd)->filepos = N_TXTOFF(*execp); + obj_datasec (abfd)->filepos = N_DATOFF(*execp); + + /* The file offsets of the relocation info */ + obj_textsec (abfd)->rel_filepos = N_TRELOFF(*execp); + obj_datasec (abfd)->rel_filepos = N_DRELOFF(*execp); + + /* The file offsets of the string table and symbol table. */ + obj_str_filepos (abfd) = N_STROFF (*execp); + obj_sym_filepos (abfd) = N_SYMOFF (*execp); + + /* Determine the architecture and machine type of the object file. */ + switch (N_MACHTYPE (*exec_hdr (abfd))) { + default: + abfd->obj_arch = bfd_arch_obscure; + break; + } + + adata(abfd)->page_size = PAGE_SIZE; + adata(abfd)->segment_size = SEGMENT_SIZE; + adata(abfd)->exec_bytes_size = EXEC_BYTES_SIZE; + + return abfd->xvec; + + /* The architecture is encoded in various ways in various a.out variants, + or is not encoded at all in some of them. The relocation size depends + on the architecture and the a.out variant. Finally, the return value + is the bfd_target vector in use. If an error occurs, return zero and + set bfd_error to the appropriate error code. + + Formats such as b.out, which have additional fields in the a.out + header, should cope with them in this callback as well. */ +#endif /* DOCUMENTATION */ + + result = (*callback_to_real_object_p)(abfd); + + /* Now that the segment addresses have been worked out, take a better + guess at whether the file is executable. If the entry point + is within the text segment, assume it is. (This makes files + executable even if their entry point address is 0, as long as + their text starts at zero.) + + At some point we should probably break down and stat the file and + declare it executable if (one of) its 'x' bits are on... */ + if ((execp->a_entry >= obj_textsec(abfd)->vma) && + (execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size)) + abfd->flags |= EXEC_P; + if (result) + { +#if 0 /* These should be set correctly anyways. */ + abfd->sections = obj_textsec (abfd); + obj_textsec (abfd)->next = obj_datasec (abfd); + obj_datasec (abfd)->next = obj_bsssec (abfd); +#endif + } + else + { + free (rawptr); + abfd->tdata.aout_data = oldrawptr; + } + return result; +} + +/* +FUNCTION + aout_<size>_mkobject + +DESCRIPTION + This routine initializes a BFD for use with a.out files. + +SYNOPSIS + boolean aout_<size>_mkobject, (bfd *); +*/ + +boolean +DEFUN(NAME(aout,mkobject),(abfd), + bfd *abfd) +{ + struct aout_data_struct *rawptr; + + bfd_error = system_call_error; + + /* Use an intermediate variable for clarity */ + rawptr = (struct aout_data_struct *)bfd_zalloc (abfd, sizeof (struct aout_data_struct )); + + if (rawptr == NULL) { + bfd_error = no_memory; + return false; + } + + abfd->tdata.aout_data = rawptr; + exec_hdr (abfd) = &(rawptr->e); + + /* For simplicity's sake we just make all the sections right here. */ + + obj_textsec (abfd) = (asection *)NULL; + obj_datasec (abfd) = (asection *)NULL; + obj_bsssec (abfd) = (asection *)NULL; + bfd_make_section (abfd, ".text"); + bfd_make_section (abfd, ".data"); + bfd_make_section (abfd, ".bss"); + bfd_make_section (abfd, BFD_ABS_SECTION_NAME); + bfd_make_section (abfd, BFD_UND_SECTION_NAME); + bfd_make_section (abfd, BFD_COM_SECTION_NAME); + + return true; +} + + +/* +FUNCTION + aout_<size>_machine_type + +DESCRIPTION + Keep track of machine architecture and machine type for + a.out's. Return the machine_type for a particular + arch&machine, or M_UNKNOWN if that exact arch&machine can't be + represented in a.out format. + + If the architecture is understood, machine type 0 (default) + should always be understood. + +SYNOPSIS + enum machine_type aout_<size>_machine_type + (enum bfd_architecture arch, + unsigned long machine)); +*/ + +enum machine_type +DEFUN(NAME(aout,machine_type),(arch, machine), + enum bfd_architecture arch AND + unsigned long machine) +{ + enum machine_type arch_flags; + + arch_flags = M_UNKNOWN; + + switch (arch) { + case bfd_arch_sparc: + if (machine == 0) arch_flags = M_SPARC; + break; + + case bfd_arch_m68k: + switch (machine) { + case 0: arch_flags = M_68010; break; + case 68000: arch_flags = M_UNKNOWN; break; + case 68010: arch_flags = M_68010; break; + case 68020: arch_flags = M_68020; break; + default: arch_flags = M_UNKNOWN; break; + } + break; + + case bfd_arch_i386: + if (machine == 0) arch_flags = M_386; + break; + + case bfd_arch_a29k: + if (machine == 0) arch_flags = M_29K; + break; + + case bfd_arch_mips: + switch (machine) { + case 0: + case 2000: + case 3000: arch_flags = M_MIPS1; break; + case 4000: + case 4400: + case 6000: arch_flags = M_MIPS2; break; + default: arch_flags = M_UNKNOWN; break; + } + break; + + default: + arch_flags = M_UNKNOWN; + } + return arch_flags; +} + + +/* +FUNCTION + aout_<size>_set_arch_mach + +DESCRIPTION + Sets the architecture and the machine of the BFD to those + values supplied. Verifies that the format can support the + architecture required. + +SYNOPSIS + boolean aout_<size>_set_arch_mach, + (bfd *, + enum bfd_architecture, + unsigned long machine)); +*/ + +boolean +DEFUN(NAME(aout,set_arch_mach),(abfd, arch, machine), + bfd *abfd AND + enum bfd_architecture arch AND + unsigned long machine) +{ + if (! bfd_default_set_arch_mach (abfd, arch, machine)) + return false; + + if (arch != bfd_arch_unknown && + NAME(aout,machine_type) (arch, machine) == M_UNKNOWN) + return false; /* We can't represent this type */ + + /* Determine the size of a relocation entry */ + switch (arch) { + case bfd_arch_sparc: + case bfd_arch_a29k: + case bfd_arch_mips: + obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE; + break; + default: + obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; + break; + } + + return (*aout_backend_info(abfd)->set_sizes) (abfd); +} + +boolean +DEFUN (NAME (aout,adjust_sizes_and_vmas), (abfd, text_size, text_end), + bfd *abfd AND bfd_size_type *text_size AND file_ptr *text_end) +{ + struct internal_exec *execp = exec_hdr (abfd); + if ((obj_textsec (abfd) == NULL) || (obj_datasec (abfd) == NULL)) + { + bfd_error = invalid_operation; + return false; + } + if (adata(abfd).magic != undecided_magic) return true; + obj_textsec(abfd)->_raw_size = + align_power(obj_textsec(abfd)->_raw_size, + obj_textsec(abfd)->alignment_power); + + *text_size = obj_textsec (abfd)->_raw_size; + /* Rule (heuristic) for when to pad to a new page. Note that there + * are (at least) two ways demand-paged (ZMAGIC) files have been + * handled. Most Berkeley-based systems start the text segment at + * (PAGE_SIZE). However, newer versions of SUNOS start the text + * segment right after the exec header; the latter is counted in the + * text segment size, and is paged in by the kernel with the rest of + * the text. */ + + /* This perhaps isn't the right way to do this, but made it simpler for me + to understand enough to implement it. Better would probably be to go + right from BFD flags to alignment/positioning characteristics. But the + old code was sloppy enough about handling the flags, and had enough + other magic, that it was a little hard for me to understand. I think + I understand it better now, but I haven't time to do the cleanup this + minute. */ + if (adata(abfd).magic == undecided_magic) + { + if (abfd->flags & D_PAGED) + /* Whether or not WP_TEXT is set -- let D_PAGED override. */ + /* @@ What about QMAGIC? */ + adata(abfd).magic = z_magic; + else if (abfd->flags & WP_TEXT) + adata(abfd).magic = n_magic; + else + adata(abfd).magic = o_magic; + } + +#ifdef BFD_AOUT_DEBUG /* requires gcc2 */ +#if __GNUC__ >= 2 + fprintf (stderr, "%s text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x,%x>\n", + ({ char *str; + switch (adata(abfd).magic) { + case n_magic: str = "NMAGIC"; break; + case o_magic: str = "OMAGIC"; break; + case z_magic: str = "ZMAGIC"; break; + default: abort (); + } + str; + }), + obj_textsec(abfd)->vma, obj_textsec(abfd)->_raw_size, obj_textsec(abfd)->alignment_power, + obj_datasec(abfd)->vma, obj_datasec(abfd)->_raw_size, obj_datasec(abfd)->alignment_power, + obj_bsssec(abfd)->vma, obj_bsssec(abfd)->_raw_size, obj_bsssec(abfd)->alignment_power); +#endif +#endif + + switch (adata(abfd).magic) + { + case o_magic: + { + file_ptr pos = adata (abfd).exec_bytes_size; + bfd_vma vma = 0; + int pad = 0; + + obj_textsec(abfd)->filepos = pos; + pos += obj_textsec(abfd)->_raw_size; + vma += obj_textsec(abfd)->_raw_size; + if (!obj_datasec(abfd)->user_set_vma) + { +#if 0 /* ?? Does alignment in the file image really matter? */ + pad = align_power (vma, obj_datasec(abfd)->alignment_power) - vma; +#endif + obj_textsec(abfd)->_raw_size += pad; + pos += pad; + vma += pad; + obj_datasec(abfd)->vma = vma; + } + obj_datasec(abfd)->filepos = pos; + pos += obj_datasec(abfd)->_raw_size; + vma += obj_datasec(abfd)->_raw_size; + if (!obj_bsssec(abfd)->user_set_vma) + { +#if 0 + pad = align_power (vma, obj_bsssec(abfd)->alignment_power) - vma; +#endif + obj_datasec(abfd)->_raw_size += pad; + pos += pad; + vma += pad; + obj_bsssec(abfd)->vma = vma; + } + obj_bsssec(abfd)->filepos = pos; + execp->a_text = obj_textsec(abfd)->_raw_size; + execp->a_data = obj_datasec(abfd)->_raw_size; + execp->a_bss = obj_bsssec(abfd)->_raw_size; + N_SET_MAGIC (*execp, OMAGIC); + } + break; + case z_magic: + { + bfd_size_type data_pad, text_pad; + file_ptr text_end; + CONST struct aout_backend_data *abdp; + int ztih; + bfd_vma data_vma; + + abdp = aout_backend_info (abfd); + ztih = abdp && abdp->text_includes_header; + obj_textsec(abfd)->filepos = (ztih + ? adata(abfd).exec_bytes_size + : adata(abfd).page_size); + if (! obj_textsec(abfd)->user_set_vma) + /* ?? Do we really need to check for relocs here? */ + obj_textsec(abfd)->vma = ((abfd->flags & HAS_RELOC) + ? 0 + : (ztih + ? (abdp->default_text_vma + + adata(abfd).exec_bytes_size) + : abdp->default_text_vma)); + /* Could take strange alignment of text section into account here? */ + + /* Find start of data. */ + text_end = obj_textsec(abfd)->filepos + obj_textsec(abfd)->_raw_size; + text_pad = BFD_ALIGN (text_end, adata(abfd).page_size) - text_end; + obj_textsec(abfd)->_raw_size += text_pad; + text_end += text_pad; + + if (!obj_datasec(abfd)->user_set_vma) + { + bfd_vma vma; + vma = obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size; + obj_datasec(abfd)->vma = BFD_ALIGN (vma, adata(abfd).segment_size); + } + data_vma = obj_datasec(abfd)->vma; + if (abdp && abdp->zmagic_mapped_contiguous) + { + text_pad = (obj_datasec(abfd)->vma + - obj_textsec(abfd)->vma + - obj_textsec(abfd)->_raw_size); + obj_textsec(abfd)->_raw_size += text_pad; + } + obj_datasec(abfd)->filepos = (obj_textsec(abfd)->filepos + + obj_textsec(abfd)->_raw_size); + + /* Fix up exec header while we're at it. */ + execp->a_text = obj_textsec(abfd)->_raw_size; + if (ztih && (!abdp || (abdp && !abdp->exec_header_not_counted))) + execp->a_text += adata(abfd).exec_bytes_size; + N_SET_MAGIC (*execp, ZMAGIC); + /* Spec says data section should be rounded up to page boundary. */ + /* If extra space in page is left after data section, fudge data + in the header so that the bss section looks smaller by that + amount. We'll start the bss section there, and lie to the OS. */ + obj_datasec(abfd)->_raw_size + = align_power (obj_datasec(abfd)->_raw_size, + obj_bsssec(abfd)->alignment_power); + execp->a_data = BFD_ALIGN (obj_datasec(abfd)->_raw_size, + adata(abfd).page_size); + data_pad = execp->a_data - obj_datasec(abfd)->_raw_size; + + if (!obj_bsssec(abfd)->user_set_vma) + obj_bsssec(abfd)->vma = (obj_datasec(abfd)->vma + + obj_datasec(abfd)->_raw_size); + if (data_pad > obj_bsssec(abfd)->_raw_size) + execp->a_bss = 0; + else + execp->a_bss = obj_bsssec(abfd)->_raw_size - data_pad; + } + break; + case n_magic: + { + file_ptr pos = adata(abfd).exec_bytes_size; + bfd_vma vma = 0; + int pad; + + obj_textsec(abfd)->filepos = pos; + if (!obj_textsec(abfd)->user_set_vma) + obj_textsec(abfd)->vma = vma; + else + vma = obj_textsec(abfd)->vma; + pos += obj_textsec(abfd)->_raw_size; + vma += obj_textsec(abfd)->_raw_size; + obj_datasec(abfd)->filepos = pos; + if (!obj_datasec(abfd)->user_set_vma) + obj_datasec(abfd)->vma = BFD_ALIGN (vma, adata(abfd).segment_size); + vma = obj_datasec(abfd)->vma; + + /* Since BSS follows data immediately, see if it needs alignment. */ + vma += obj_datasec(abfd)->_raw_size; + pad = align_power (vma, obj_bsssec(abfd)->alignment_power) - vma; + obj_datasec(abfd)->_raw_size += pad; + pos += obj_datasec(abfd)->_raw_size; + + if (!obj_bsssec(abfd)->user_set_vma) + obj_bsssec(abfd)->vma = vma; + else + vma = obj_bsssec(abfd)->vma; + } + execp->a_text = obj_textsec(abfd)->_raw_size; + execp->a_data = obj_datasec(abfd)->_raw_size; + execp->a_bss = obj_bsssec(abfd)->_raw_size; + N_SET_MAGIC (*execp, NMAGIC); + break; + default: + abort (); + } +#ifdef BFD_AOUT_DEBUG + fprintf (stderr, " text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x>\n", + obj_textsec(abfd)->vma, obj_textsec(abfd)->_raw_size, obj_textsec(abfd)->filepos, + obj_datasec(abfd)->vma, obj_datasec(abfd)->_raw_size, obj_datasec(abfd)->filepos, + obj_bsssec(abfd)->vma, obj_bsssec(abfd)->_raw_size); +#endif + return true; +} + +/* +FUNCTION + aout_<size>_new_section_hook + +DESCRIPTION + Called by the BFD in response to a @code{bfd_make_section} + request. + +SYNOPSIS + boolean aout_<size>_new_section_hook, + (bfd *abfd, + asection *newsect)); +*/ +boolean +DEFUN(NAME(aout,new_section_hook),(abfd, newsect), + bfd *abfd AND + asection *newsect) +{ + /* align to double at least */ + newsect->alignment_power = bfd_get_arch_info(abfd)->section_align_power; + + + if (bfd_get_format (abfd) == bfd_object) + { + if (obj_textsec(abfd) == NULL && !strcmp(newsect->name, ".text")) { + obj_textsec(abfd)= newsect; + newsect->target_index = N_TEXT | N_EXT; + return true; + } + + if (obj_datasec(abfd) == NULL && !strcmp(newsect->name, ".data")) { + obj_datasec(abfd) = newsect; + newsect->target_index = N_DATA | N_EXT; + return true; + } + + if (obj_bsssec(abfd) == NULL && !strcmp(newsect->name, ".bss")) { + obj_bsssec(abfd) = newsect; + newsect->target_index = N_BSS | N_EXT; + return true; + } + + } + + /* We allow more than three sections internally */ + return true; +} + +boolean +DEFUN(NAME(aout,set_section_contents),(abfd, section, location, offset, count), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + file_ptr text_end; + bfd_size_type text_size; + + if (abfd->output_has_begun == false) + { + if (NAME(aout,adjust_sizes_and_vmas) (abfd, + &text_size, + &text_end) == false) + return false; + } + + /* regardless, once we know what we're doing, we might as well get going */ + if (section != obj_bsssec(abfd)) + { + bfd_seek (abfd, section->filepos + offset, SEEK_SET); + + if (count) { + return (bfd_write ((PTR)location, 1, count, abfd) == count) ? + true : false; + } + return true; + } + return true; +} + +/* Classify stabs symbols */ + +#define sym_in_text_section(sym) \ + (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_TEXT) + +#define sym_in_data_section(sym) \ + (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_DATA) + +#define sym_in_bss_section(sym) \ + (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_BSS) + +/* Symbol is undefined if type is N_UNDF|N_EXT and if it has + zero in the "value" field. Nonzeroes there are fortrancommon + symbols. */ +#define sym_is_undefined(sym) \ + ((sym)->type == (N_UNDF | N_EXT) && (sym)->symbol.value == 0) + +/* Symbol is a global definition if N_EXT is on and if it has + a nonzero type field. */ +#define sym_is_global_defn(sym) \ + (((sym)->type & N_EXT) && (sym)->type & N_TYPE) + +/* Symbol is debugger info if any bits outside N_TYPE or N_EXT + are on. */ +#define sym_is_debugger_info(sym) \ + (((sym)->type & ~(N_EXT | N_TYPE)) || (sym)->type == N_FN) + +#define sym_is_fortrancommon(sym) \ + (((sym)->type == (N_EXT)) && (sym)->symbol.value != 0) + +/* Symbol is absolute if it has N_ABS set */ +#define sym_is_absolute(sym) \ + (((sym)->type & N_TYPE)== N_ABS) + + +#define sym_is_indirect(sym) \ + (((sym)->type & N_ABS)== N_ABS) + +/* Only in their own functions for ease of debugging; when sym flags have + stabilised these should be inlined into their (single) caller */ + +static void +DEFUN (translate_from_native_sym_flags, (sym_pointer, cache_ptr, abfd), + struct external_nlist *sym_pointer AND + aout_symbol_type * cache_ptr AND + bfd * abfd) +{ + cache_ptr->symbol.section = 0; + switch (cache_ptr->type & N_TYPE) + { + case N_SETA: + case N_SETT: + case N_SETD: + case N_SETB: + { + char *copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1); + asection *section; + asection *into_section; + + arelent_chain *reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain)); + strcpy (copy, cache_ptr->symbol.name); + + /* Make sure that this bfd has a section with the right contructor + name */ + section = bfd_get_section_by_name (abfd, copy); + if (!section) + section = bfd_make_section (abfd, copy); + + /* Build a relocation entry for the constructor */ + switch ((cache_ptr->type & N_TYPE)) + { + case N_SETA: + into_section = &bfd_abs_section; + cache_ptr->type = N_ABS; + break; + case N_SETT: + into_section = (asection *) obj_textsec (abfd); + cache_ptr->type = N_TEXT; + break; + case N_SETD: + into_section = (asection *) obj_datasec (abfd); + cache_ptr->type = N_DATA; + break; + case N_SETB: + into_section = (asection *) obj_bsssec (abfd); + cache_ptr->type = N_BSS; + break; + default: + abort (); + } + + /* Build a relocation pointing into the constuctor section + pointing at the symbol in the set vector specified */ + + reloc->relent.addend = cache_ptr->symbol.value; + cache_ptr->symbol.section = into_section->symbol->section; + reloc->relent.sym_ptr_ptr = into_section->symbol_ptr_ptr; + + + /* We modify the symbol to belong to a section depending upon the + name of the symbol - probably __CTOR__ or __DTOR__ but we don't + really care, and add to the size of the section to contain a + pointer to the symbol. Build a reloc entry to relocate to this + symbol attached to this section. */ + + section->flags = SEC_CONSTRUCTOR; + + + section->reloc_count++; + section->alignment_power = 2; + + reloc->next = section->constructor_chain; + section->constructor_chain = reloc; + reloc->relent.address = section->_raw_size; + section->_raw_size += sizeof (int *); + + reloc->relent.howto + = (obj_reloc_entry_size(abfd) == RELOC_EXT_SIZE + ? howto_table_ext : howto_table_std) + + CTOR_TABLE_RELOC_IDX; + cache_ptr->symbol.flags |= BSF_CONSTRUCTOR; + } + break; + default: + if (cache_ptr->type == N_WARNING) + { + /* This symbol is the text of a warning message, the next symbol + is the symbol to associate the warning with */ + cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING; + + /* @@ Stuffing pointers into integers is a no-no. + We can usually get away with it if the integer is + large enough though. */ + if (sizeof (cache_ptr + 1) > sizeof (bfd_vma)) + abort (); + cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1)); + + /* We furgle with the next symbol in place. + We don't want it to be undefined, we'll trample the type */ + (sym_pointer + 1)->e_type[0] = 0xff; + break; + } + if ((cache_ptr->type | N_EXT) == (N_INDR | N_EXT)) + { + /* Two symbols in a row for an INDR message. The first symbol + contains the name we will match, the second symbol contains + the name the first name is translated into. It is supplied to + us undefined. This is good, since we want to pull in any files + which define it */ + cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT; + + /* @@ Stuffing pointers into integers is a no-no. + We can usually get away with it if the integer is + large enough though. */ + if (sizeof (cache_ptr + 1) > sizeof (bfd_vma)) + abort (); + + cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1)); + cache_ptr->symbol.section = &bfd_ind_section; + } + + else if (sym_is_debugger_info (cache_ptr)) + { + cache_ptr->symbol.flags = BSF_DEBUGGING; + /* Work out the section correct for this symbol */ + switch (cache_ptr->type & N_TYPE) + { + case N_TEXT: + case N_FN: + cache_ptr->symbol.section = obj_textsec (abfd); + cache_ptr->symbol.value -= obj_textsec (abfd)->vma; + break; + case N_DATA: + cache_ptr->symbol.value -= obj_datasec (abfd)->vma; + cache_ptr->symbol.section = obj_datasec (abfd); + break; + case N_BSS: + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= obj_bsssec (abfd)->vma; + break; + default: + case N_ABS: + + cache_ptr->symbol.section = &bfd_abs_section; + break; + } + } + else + { + + if (sym_is_fortrancommon (cache_ptr)) + { + cache_ptr->symbol.flags = 0; + cache_ptr->symbol.section = &bfd_com_section; + } + else + { + + + } + + /* In a.out, the value of a symbol is always relative to the + * start of the file, if this is a data symbol we'll subtract + * the size of the text section to get the section relative + * value. If this is a bss symbol (which would be strange) + * we'll subtract the size of the previous two sections + * to find the section relative address. + */ + + if (sym_in_text_section (cache_ptr)) + { + cache_ptr->symbol.value -= obj_textsec (abfd)->vma; + cache_ptr->symbol.section = obj_textsec (abfd); + } + else if (sym_in_data_section (cache_ptr)) + { + cache_ptr->symbol.value -= obj_datasec (abfd)->vma; + cache_ptr->symbol.section = obj_datasec (abfd); + } + else if (sym_in_bss_section (cache_ptr)) + { + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= obj_bsssec (abfd)->vma; + } + else if (sym_is_undefined (cache_ptr)) + { + cache_ptr->symbol.flags = 0; + cache_ptr->symbol.section = &bfd_und_section; + } + else if (sym_is_absolute (cache_ptr)) + { + cache_ptr->symbol.section = &bfd_abs_section; + } + + if (sym_is_global_defn (cache_ptr)) + { + cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT; + } + else + { + cache_ptr->symbol.flags = BSF_LOCAL; + } + } + } + if (cache_ptr->symbol.section == 0) + abort (); +} + + + +static void +DEFUN(translate_to_native_sym_flags,(sym_pointer, cache_ptr, abfd), + struct external_nlist *sym_pointer AND + asymbol *cache_ptr AND + bfd *abfd) +{ + bfd_vma value = cache_ptr->value; + + /* mask out any existing type bits in case copying from one section + to another */ + sym_pointer->e_type[0] &= ~N_TYPE; + + + /* We attempt to order these tests by decreasing frequency of success, + according to tcov when linking the linker. */ + if (bfd_get_output_section(cache_ptr) == &bfd_abs_section) { + sym_pointer->e_type[0] |= N_ABS; + } + else if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) { + sym_pointer->e_type[0] |= N_TEXT; + } + else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) { + sym_pointer->e_type[0] |= N_DATA; + } + else if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) { + sym_pointer->e_type[0] |= N_BSS; + } + else if (bfd_get_output_section(cache_ptr) == &bfd_und_section) + { + sym_pointer->e_type[0] = (N_UNDF | N_EXT); + } + else if (bfd_get_output_section(cache_ptr) == &bfd_ind_section) + { + sym_pointer->e_type[0] = N_INDR; + } + else if (bfd_is_com_section (bfd_get_output_section (cache_ptr))) { + sym_pointer->e_type[0] = (N_UNDF | N_EXT); + } + else { + if (cache_ptr->section->output_section) + { + + bfd_error_vector.nonrepresentable_section(abfd, + bfd_get_output_section(cache_ptr)->name); + } + else + { + bfd_error_vector.nonrepresentable_section(abfd, + cache_ptr->section->name); + + } + + } + /* Turn the symbol from section relative to absolute again */ + + value += cache_ptr->section->output_section->vma + cache_ptr->section->output_offset ; + + + if (cache_ptr->flags & (BSF_WARNING)) { + (sym_pointer+1)->e_type[0] = 1; + } + + if (cache_ptr->flags & BSF_DEBUGGING) { + sym_pointer->e_type[0] = ((aout_symbol_type *)cache_ptr)->type; + } + else if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) { + sym_pointer->e_type[0] |= N_EXT; + } + if (cache_ptr->flags & BSF_CONSTRUCTOR) { + int type = ((aout_symbol_type *)cache_ptr)->type; + switch (type) + { + case N_ABS: type = N_SETA; break; + case N_TEXT: type = N_SETT; break; + case N_DATA: type = N_SETD; break; + case N_BSS: type = N_SETB; break; + } + sym_pointer->e_type[0] = type; + } + + PUT_WORD(abfd, value, sym_pointer->e_value); +} + +/* Native-level interface to symbols. */ + +/* We read the symbols into a buffer, which is discarded when this +function exits. We read the strings into a buffer large enough to +hold them all plus all the cached symbol entries. */ + +asymbol * +DEFUN(NAME(aout,make_empty_symbol),(abfd), + bfd *abfd) +{ + aout_symbol_type *new = + (aout_symbol_type *)bfd_zalloc (abfd, sizeof (aout_symbol_type)); + new->symbol.the_bfd = abfd; + + return &new->symbol; +} + +boolean +DEFUN(NAME(aout,slurp_symbol_table),(abfd), + bfd *abfd) +{ + bfd_size_type symbol_size; + bfd_size_type string_size; + unsigned char string_chars[BYTES_IN_WORD]; + struct external_nlist *syms; + char *strings; + aout_symbol_type *cached; + + /* If there's no work to be done, don't do any */ + if (obj_aout_symbols (abfd) != (aout_symbol_type *)NULL) return true; + symbol_size = exec_hdr(abfd)->a_syms; + if (symbol_size == 0) + { + bfd_error = no_symbols; + return false; + } + + bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET); + if (bfd_read ((PTR)string_chars, BYTES_IN_WORD, 1, abfd) != BYTES_IN_WORD) + return false; + string_size = GET_WORD (abfd, string_chars); + + strings =(char *) bfd_alloc(abfd, string_size + 1); + cached = (aout_symbol_type *) + bfd_zalloc(abfd, (bfd_size_type)(bfd_get_symcount (abfd) * sizeof(aout_symbol_type))); + + /* malloc this, so we can free it if simply. The symbol caching + might want to allocate onto the bfd's obstack */ + syms = (struct external_nlist *) bfd_xmalloc(symbol_size); + bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET); + if (bfd_read ((PTR)syms, 1, symbol_size, abfd) != symbol_size) + { + bailout: + if (syms) + free (syms); + if (cached) + bfd_release (abfd, cached); + if (strings) + bfd_release (abfd, strings); + return false; + } + + bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET); + if (bfd_read ((PTR)strings, 1, string_size, abfd) != string_size) + { + goto bailout; + } + strings[string_size] = 0; /* Just in case. */ + + /* OK, now walk the new symtable, cacheing symbol properties */ + { + register struct external_nlist *sym_pointer; + register struct external_nlist *sym_end = syms + bfd_get_symcount (abfd); + register aout_symbol_type *cache_ptr = cached; + + /* Run through table and copy values */ + for (sym_pointer = syms, cache_ptr = cached; + sym_pointer < sym_end; sym_pointer ++, cache_ptr++) + { + long x = GET_WORD(abfd, sym_pointer->e_strx); + cache_ptr->symbol.the_bfd = abfd; + if (x == 0) + cache_ptr->symbol.name = ""; + else if (x >= 0 && x < string_size) + cache_ptr->symbol.name = x + strings; + else + goto bailout; + + cache_ptr->symbol.value = GET_SWORD(abfd, sym_pointer->e_value); + cache_ptr->desc = bfd_h_get_16(abfd, sym_pointer->e_desc); + cache_ptr->other = bfd_h_get_8(abfd, sym_pointer->e_other); + cache_ptr->type = bfd_h_get_8(abfd, sym_pointer->e_type); + cache_ptr->symbol.udata = 0; + translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd); + } + } + + obj_aout_symbols (abfd) = cached; + free((PTR)syms); + + return true; +} + + +/* Possible improvements: + + look for strings matching trailing substrings of other strings + + better data structures? balanced trees? + + smaller per-string or per-symbol data? re-use some of the symbol's + data fields? + + also look at reducing memory use elsewhere -- maybe if we didn't have to + construct the entire symbol table at once, we could get by with smaller + amounts of VM? (What effect does that have on the string table + reductions?) + + rip this out of here, put it into its own file in bfd or libiberty, so + coff and elf can use it too. I'll work on this soon, but have more + pressing tasks right now. + + A hash table might(?) be more efficient for handling exactly the cases that + are handled now, but for trailing substring matches, I think we want to + examine the `nearest' values (reverse-)lexically, not merely impose a strict + order, nor look only for exact-match or not-match. I don't think a hash + table would be very useful for that, and I don't feel like fleshing out two + completely different implementations. [raeburn:930419.0331EDT] */ + +struct stringtab_entry { + /* Hash value for this string. Only useful so long as we aren't doing + substring matches. */ + unsigned int hash; + + /* Next node to look at, depending on whether the hash value of the string + being searched for is less than or greater than the hash value of the + current node. For now, `equal to' is lumped in with `greater than', for + space efficiency. It's not a common enough case to warrant another field + to be used for all nodes. */ + struct stringtab_entry *less; + struct stringtab_entry *greater; + + /* The string itself. */ + CONST char *string; + + /* The index allocated for this string. */ + bfd_size_type index; + +#ifdef GATHER_STATISTICS + /* How many references have there been to this string? (Not currently used; + could be dumped out for anaylsis, if anyone's interested.) */ + unsigned long count; +#endif + + /* Next node in linked list, in suggested output order. */ + struct stringtab_entry *next_to_output; +}; + +struct stringtab_data { + /* Tree of string table entries. */ + struct stringtab_entry *strings; + + /* Fudge factor used to center top node of tree. */ + int hash_zero; + + /* Next index value to issue. */ + bfd_size_type index; + + /* Index used for empty strings. Cached here because checking for them + is really easy, and we can avoid searching the tree. */ + bfd_size_type empty_string_index; + + /* These fields indicate the two ends of a singly-linked list that indicates + the order strings should be written out in. Use this order, and no + seeking will need to be done, so output efficiency should be maximized. */ + struct stringtab_entry **end; + struct stringtab_entry *output_order; + +#ifdef GATHER_STATISTICS + /* Number of strings which duplicate strings already in the table. */ + unsigned long duplicates; + + /* Number of bytes saved by not having to write all the duplicate strings. */ + unsigned long bytes_saved; + + /* Number of zero-length strings. Currently, these all turn into + references to the null byte at the end of the first string. In some + cases (possibly not all? explore this...), it should be possible to + simply write out a zero index value. */ + unsigned long empty_strings; + + /* Number of times the hash values matched but the strings were different. + Note that this includes the number of times the other string(s) occurs, so + there may only be two strings hashing to the same value, even if this + number is very large. */ + unsigned long bad_hash_matches; + + /* Null strings aren't counted in this one. + This will probably only be nonzero if we've got an input file + which was produced by `ld -r' (i.e., it's already been processed + through this code). Under some operating systems, native tools + may make all empty strings have the same index; but the pointer + check won't catch those, because to get to that stage we'd already + have to compute the checksum, which requires reading the string, + so we short-circuit that case with empty_string_index above. */ + unsigned long pointer_matches; + + /* Number of comparisons done. I figure with the algorithms in use below, + the average number of comparisons done (per symbol) should be roughly + log-base-2 of the number of unique strings. */ + unsigned long n_compares; +#endif +}; + +/* Some utility functions for the string table code. */ + +/* For speed, only hash on the first this many bytes of strings. + This number was chosen by profiling ld linking itself, with -g. */ +#define HASHMAXLEN 25 + +#define HASH_CHAR(c) (sum ^= sum >> 20, sum ^= sum << 7, sum += (c)) + +static INLINE unsigned int +hash (string, len) + unsigned char *string; + register unsigned int len; +{ + register unsigned int sum = 0; + + if (len > HASHMAXLEN) + { + HASH_CHAR (len); + len = HASHMAXLEN; + } + + while (len--) + { + HASH_CHAR (*string++); + } + return sum; +} + +static INLINE void +stringtab_init (tab) + struct stringtab_data *tab; +{ + tab->strings = 0; + tab->output_order = 0; + tab->end = &tab->output_order; + + /* Initial string table length includes size of length field. */ + tab->index = BYTES_IN_WORD; + tab->empty_string_index = -1; +#ifdef GATHER_STATISTICS + tab->duplicates = 0; + tab->empty_strings = 0; + tab->bad_hash_matches = 0; + tab->pointer_matches = 0; + tab->bytes_saved = 0; + tab->n_compares = 0; +#endif +} + +static INLINE int +compare (entry, str, hash) + struct stringtab_entry *entry; + CONST char *str; + unsigned int hash; +{ + return hash - entry->hash; +} + +#ifdef GATHER_STATISTICS +/* Don't want to have to link in math library with all bfd applications... */ +static INLINE double +log2 (num) + int num; +{ + double d = num; + int n = 0; + while (d >= 2.0) + n++, d /= 2.0; + return ((d > 1.41) ? 0.5 : 0) + n; +} +#endif + +/* Main string table routines. */ +/* Returns index in string table. Whether or not this actually adds an + entry into the string table should be irrelevant -- it just has to + return a valid index. */ +static bfd_size_type +add_to_stringtab (abfd, str, tab, check) + bfd *abfd; + CONST char *str; + struct stringtab_data *tab; + int check; +{ + struct stringtab_entry **ep; + register struct stringtab_entry *entry; + unsigned int hashval, len; + + if (str[0] == 0) + { + bfd_size_type index; + CONST bfd_size_type minus_one = -1; + +#ifdef GATHER_STATISTICS + tab->empty_strings++; +#endif + index = tab->empty_string_index; + if (index != minus_one) + { + got_empty: +#ifdef GATHER_STATISTICS + tab->bytes_saved++; + tab->duplicates++; +#endif + return index; + } + + /* Need to find it. */ + entry = tab->strings; + if (entry) + { + index = entry->index + strlen (entry->string); + tab->empty_string_index = index; + goto got_empty; + } + len = 0; + } + else + len = strlen (str); + + /* The hash_zero value is chosen such that the first symbol gets a value of + zero. With a balanced tree, this wouldn't be very useful, but without it, + we might get a more even split at the top level, instead of skewing it + badly should hash("/usr/lib/crt0.o") (or whatever) be far from zero. */ + hashval = hash (str, len) ^ tab->hash_zero; + ep = &tab->strings; + if (!*ep) + { + tab->hash_zero = hashval; + hashval = 0; + goto add_it; + } + + while (*ep) + { + register int cmp; + + entry = *ep; +#ifdef GATHER_STATISTICS + tab->n_compares++; +#endif + cmp = compare (entry, str, hashval); + /* The not-equal cases are more frequent, so check them first. */ + if (cmp > 0) + ep = &entry->greater; + else if (cmp < 0) + ep = &entry->less; + else + { + if (entry->string == str) + { +#ifdef GATHER_STATISTICS + tab->pointer_matches++; +#endif + goto match; + } + /* Compare the first bytes to save a function call if they + don't match. */ + if (entry->string[0] == str[0] && !strcmp (entry->string, str)) + { + match: +#ifdef GATHER_STATISTICS + entry->count++; + tab->bytes_saved += len + 1; + tab->duplicates++; +#endif + /* If we're in the linker, and the new string is from a new + input file which might have already had these reductions + run over it, we want to keep the new string pointer. I + don't think we're likely to see any (or nearly as many, + at least) cases where a later string is in the same location + as an earlier one rather than this one. */ + entry->string = str; + return entry->index; + } +#ifdef GATHER_STATISTICS + tab->bad_hash_matches++; +#endif + ep = &entry->greater; + } + } + + /* If we get here, nothing that's in the table already matched. + EP points to the `next' field at the end of the chain; stick a + new entry on here. */ + add_it: + entry = (struct stringtab_entry *) + bfd_alloc_by_size_t (abfd, sizeof (struct stringtab_entry)); + + entry->less = entry->greater = 0; + entry->hash = hashval; + entry->index = tab->index; + entry->string = str; + entry->next_to_output = 0; +#ifdef GATHER_STATISTICS + entry->count = 1; +#endif + + assert (*tab->end == 0); + *(tab->end) = entry; + tab->end = &entry->next_to_output; + assert (*tab->end == 0); + + { + tab->index += len + 1; + if (len == 0) + tab->empty_string_index = entry->index; + } + assert (*ep == 0); + *ep = entry; + return entry->index; +} + +static void +emit_strtab (abfd, tab) + bfd *abfd; + struct stringtab_data *tab; +{ + struct stringtab_entry *entry; +#ifdef GATHER_STATISTICS + int count = 0; +#endif + + /* Be sure to put string length into correct byte ordering before writing + it out. */ + char buffer[BYTES_IN_WORD]; + + PUT_WORD (abfd, tab->index, (unsigned char *) buffer); + bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd); + + for (entry = tab->output_order; entry; entry = entry->next_to_output) + { + bfd_write ((PTR) entry->string, 1, strlen (entry->string) + 1, abfd); +#ifdef GATHER_STATISTICS + count++; +#endif + } + +#ifdef GATHER_STATISTICS + /* Short form only, for now. + To do: Specify output file. Conditionalize on environment? Detailed + analysis if desired. */ + { + int n_syms = bfd_get_symcount (abfd); + + fprintf (stderr, "String table data for output file:\n"); + fprintf (stderr, " %8d symbols output\n", n_syms); + fprintf (stderr, " %8d duplicate strings\n", tab->duplicates); + fprintf (stderr, " %8d empty strings\n", tab->empty_strings); + fprintf (stderr, " %8d unique strings output\n", count); + fprintf (stderr, " %8d pointer matches\n", tab->pointer_matches); + fprintf (stderr, " %8d bytes saved\n", tab->bytes_saved); + fprintf (stderr, " %8d bad hash matches\n", tab->bad_hash_matches); + fprintf (stderr, " %8d hash-val comparisons\n", tab->n_compares); + if (n_syms) + { + double n_compares = tab->n_compares; + double avg_compares = n_compares / n_syms; + /* The second value here should usually be near one. */ + fprintf (stderr, + "\t average %f comparisons per symbol (%f * log2 nstrings)\n", + avg_compares, avg_compares / log2 (count)); + } + } +#endif + +/* Old code: + unsigned int count; + generic = bfd_get_outsymbols(abfd); + for (count = 0; count < bfd_get_symcount(abfd); count++) + { + asymbol *g = *(generic++); + + if (g->name) + { + size_t length = strlen(g->name)+1; + bfd_write((PTR)g->name, 1, length, abfd); + } + g->KEEPIT = (KEEPITTYPE) count; + } */ +} + +void +DEFUN(NAME(aout,write_syms),(abfd), + bfd *abfd) +{ + unsigned int count ; + asymbol **generic = bfd_get_outsymbols (abfd); + struct stringtab_data strtab; + + stringtab_init (&strtab); + + for (count = 0; count < bfd_get_symcount (abfd); count++) + { + asymbol *g = generic[count]; + struct external_nlist nsp; + + if (g->name) + PUT_WORD (abfd, add_to_stringtab (abfd, g->name, &strtab), + (unsigned char *) nsp.e_strx); + else + PUT_WORD (abfd, 0, (unsigned char *)nsp.e_strx); + + if (bfd_asymbol_flavour(g) == abfd->xvec->flavour) + { + bfd_h_put_16(abfd, aout_symbol(g)->desc, nsp.e_desc); + bfd_h_put_8(abfd, aout_symbol(g)->other, nsp.e_other); + bfd_h_put_8(abfd, aout_symbol(g)->type, nsp.e_type); + } + else + { + bfd_h_put_16(abfd,0, nsp.e_desc); + bfd_h_put_8(abfd, 0, nsp.e_other); + bfd_h_put_8(abfd, 0, nsp.e_type); + } + + translate_to_native_sym_flags (&nsp, g, abfd); + + bfd_write((PTR)&nsp,1,EXTERNAL_NLIST_SIZE, abfd); + + /* NB: `KEEPIT' currently overlays `flags', so set this only + here, at the end. */ + g->KEEPIT = count; + } + + emit_strtab (abfd, &strtab); +} + + +unsigned int +DEFUN(NAME(aout,get_symtab),(abfd, location), + bfd *abfd AND + asymbol **location) +{ + unsigned int counter = 0; + aout_symbol_type *symbase; + + if (!NAME(aout,slurp_symbol_table)(abfd)) return 0; + + for (symbase = obj_aout_symbols(abfd); counter++ < bfd_get_symcount (abfd);) + *(location++) = (asymbol *)( symbase++); + *location++ =0; + return bfd_get_symcount (abfd); +} + + +/* Standard reloc stuff */ +/* Output standard relocation information to a file in target byte order. */ + +void +DEFUN(NAME(aout,swap_std_reloc_out),(abfd, g, natptr), + bfd *abfd AND + arelent *g AND + struct reloc_std_external *natptr) +{ + int r_index; + asymbol *sym = *(g->sym_ptr_ptr); + int r_extern; + unsigned int r_length; + int r_pcrel; + int r_baserel, r_jmptable, r_relative; + unsigned int r_addend; + asection *output_section = sym->section->output_section; + + PUT_WORD(abfd, g->address, natptr->r_address); + + r_length = g->howto->size ; /* Size as a power of two */ + r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ + /* XXX This relies on relocs coming from a.out files. */ + r_baserel = (g->howto->type & 8) != 0; + /* r_jmptable, r_relative??? FIXME-soon */ + r_jmptable = 0; + r_relative = 0; + + r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; + + /* name was clobbered by aout_write_syms to be symbol index */ + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + + Absolute symbols can come in in two ways, either as an offset + from the abs section, or as a symbol which has an abs value. + check for that here + */ + + + if (bfd_is_com_section (output_section) + || output_section == &bfd_abs_section + || output_section == &bfd_und_section) + { + if (bfd_abs_section.symbol == sym) + { + /* Whoops, looked like an abs symbol, but is really an offset + from the abs section */ + r_index = 0; + r_extern = 0; + } + else + { + /* Fill in symbol */ + r_extern = 1; + r_index = stoi((*(g->sym_ptr_ptr))->KEEPIT); + + } + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_index = output_section->target_index; + } + + /* now the fun stuff */ + if (abfd->xvec->header_byteorder_big_p != false) { + natptr->r_index[0] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[2] = r_index; + natptr->r_type[0] = + (r_extern? RELOC_STD_BITS_EXTERN_BIG: 0) + | (r_pcrel? RELOC_STD_BITS_PCREL_BIG: 0) + | (r_baserel? RELOC_STD_BITS_BASEREL_BIG: 0) + | (r_jmptable? RELOC_STD_BITS_JMPTABLE_BIG: 0) + | (r_relative? RELOC_STD_BITS_RELATIVE_BIG: 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG); + } else { + natptr->r_index[2] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[0] = r_index; + natptr->r_type[0] = + (r_extern? RELOC_STD_BITS_EXTERN_LITTLE: 0) + | (r_pcrel? RELOC_STD_BITS_PCREL_LITTLE: 0) + | (r_baserel? RELOC_STD_BITS_BASEREL_LITTLE: 0) + | (r_jmptable? RELOC_STD_BITS_JMPTABLE_LITTLE: 0) + | (r_relative? RELOC_STD_BITS_RELATIVE_LITTLE: 0) + | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE); + } +} + + +/* Extended stuff */ +/* Output extended relocation information to a file in target byte order. */ + +void +DEFUN(NAME(aout,swap_ext_reloc_out),(abfd, g, natptr), + bfd *abfd AND + arelent *g AND + register struct reloc_ext_external *natptr) +{ + int r_index; + int r_extern; + unsigned int r_type; + unsigned int r_addend; + asymbol *sym = *(g->sym_ptr_ptr); + asection *output_section = sym->section->output_section; + + PUT_WORD (abfd, g->address, natptr->r_address); + + r_type = (unsigned int) g->howto->type; + + r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; + + /* If this relocation is relative to a symbol then set the + r_index to the symbols index, and the r_extern bit. + + Absolute symbols can come in in two ways, either as an offset + from the abs section, or as a symbol which has an abs value. + check for that here. */ + + if (bfd_is_com_section (output_section) + || output_section == &bfd_abs_section + || output_section == &bfd_und_section) + { + if (bfd_abs_section.symbol == sym) + { + /* Whoops, looked like an abs symbol, but is really an offset + from the abs section */ + r_index = 0; + r_extern = 0; + } + else + { + r_extern = 1; + r_index = stoi((*(g->sym_ptr_ptr))->KEEPIT); + } + } + else + { + /* Just an ordinary section */ + r_extern = 0; + r_index = output_section->target_index; + } + + /* now the fun stuff */ + if (abfd->xvec->header_byteorder_big_p != false) { + natptr->r_index[0] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[2] = r_index; + natptr->r_type[0] = + ((r_extern? RELOC_EXT_BITS_EXTERN_BIG: 0) + | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG)); + } else { + natptr->r_index[2] = r_index >> 16; + natptr->r_index[1] = r_index >> 8; + natptr->r_index[0] = r_index; + natptr->r_type[0] = + (r_extern? RELOC_EXT_BITS_EXTERN_LITTLE: 0) + | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE); + } + + PUT_WORD (abfd, r_addend, natptr->r_addend); +} + +/* BFD deals internally with all things based from the section they're + in. so, something in 10 bytes into a text section with a base of + 50 would have a symbol (.text+10) and know .text vma was 50. + + Aout keeps all it's symbols based from zero, so the symbol would + contain 60. This macro subs the base of each section from the value + to give the true offset from the section */ + + +#define MOVE_ADDRESS(ad) \ + if (r_extern) { \ + /* undefined symbol */ \ + cache_ptr->sym_ptr_ptr = symbols + r_index; \ + cache_ptr->addend = ad; \ + } else { \ + /* defined, section relative. replace symbol with pointer to \ + symbol which points to section */ \ + switch (r_index) { \ + case N_TEXT: \ + case N_TEXT | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_textsec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->textsec->vma; \ + break; \ + case N_DATA: \ + case N_DATA | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_datasec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->datasec->vma; \ + break; \ + case N_BSS: \ + case N_BSS | N_EXT: \ + cache_ptr->sym_ptr_ptr = obj_bsssec(abfd)->symbol_ptr_ptr; \ + cache_ptr->addend = ad - su->bsssec->vma; \ + break; \ + default: \ + case N_ABS: \ + case N_ABS | N_EXT: \ + cache_ptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr; \ + cache_ptr->addend = ad; \ + break; \ + } \ + } \ + +void +DEFUN(NAME(aout,swap_ext_reloc_in), (abfd, bytes, cache_ptr, symbols), + bfd *abfd AND + struct reloc_ext_external *bytes AND + arelent *cache_ptr AND + asymbol **symbols) +{ + int r_index; + int r_extern; + unsigned int r_type; + struct aoutdata *su = &(abfd->tdata.aout_data->a); + + cache_ptr->address = (GET_SWORD (abfd, bytes->r_address)); + + /* now the fun stuff */ + if (abfd->xvec->header_byteorder_big_p != false) { + r_index = (bytes->r_index[0] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[2]; + r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG)); + r_type = (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_BIG) + >> RELOC_EXT_BITS_TYPE_SH_BIG; + } else { + r_index = (bytes->r_index[2] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[0]; + r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE)); + r_type = (bytes->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE) + >> RELOC_EXT_BITS_TYPE_SH_LITTLE; + } + + cache_ptr->howto = howto_table_ext + r_type; + MOVE_ADDRESS(GET_SWORD(abfd, bytes->r_addend)); +} + +void +DEFUN(NAME(aout,swap_std_reloc_in), (abfd, bytes, cache_ptr, symbols), + bfd *abfd AND + struct reloc_std_external *bytes AND + arelent *cache_ptr AND + asymbol **symbols) +{ + int r_index; + int r_extern; + unsigned int r_length; + int r_pcrel; + int r_baserel, r_jmptable, r_relative; + struct aoutdata *su = &(abfd->tdata.aout_data->a); + int howto_idx; + + cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address); + + /* now the fun stuff */ + if (abfd->xvec->header_byteorder_big_p != false) { + r_index = (bytes->r_index[0] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[2]; + r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_BIG)); + r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_BIG)); + r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_BIG)); + r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG)); + r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG)); + r_length = (bytes->r_type[0] & RELOC_STD_BITS_LENGTH_BIG) + >> RELOC_STD_BITS_LENGTH_SH_BIG; + } else { + r_index = (bytes->r_index[2] << 16) + | (bytes->r_index[1] << 8) + | bytes->r_index[0]; + r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE)); + r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); + r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE)); + r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE)); + r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_LITTLE)); + r_length = (bytes->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE) + >> RELOC_STD_BITS_LENGTH_SH_LITTLE; + } + + howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel; + BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std)); + cache_ptr->howto = howto_table_std + howto_idx; + BFD_ASSERT (cache_ptr->howto->type != -1); + BFD_ASSERT (r_jmptable == 0); + BFD_ASSERT (r_relative == 0); + /* FIXME-soon: Roll jmptable, relative bits into howto setting */ + + MOVE_ADDRESS(0); +} + +/* Reloc hackery */ + +boolean +DEFUN(NAME(aout,slurp_reloc_table),(abfd, asect, symbols), + bfd *abfd AND + sec_ptr asect AND + asymbol **symbols) +{ + unsigned int count; + bfd_size_type reloc_size; + PTR relocs; + arelent *reloc_cache; + size_t each_size; + + if (asect->relocation) return true; + + if (asect->flags & SEC_CONSTRUCTOR) return true; + + if (asect == obj_datasec (abfd)) { + reloc_size = exec_hdr(abfd)->a_drsize; + goto doit; + } + + if (asect == obj_textsec (abfd)) { + reloc_size = exec_hdr(abfd)->a_trsize; + goto doit; + } + + bfd_error = invalid_operation; + return false; + + doit: + bfd_seek (abfd, asect->rel_filepos, SEEK_SET); + each_size = obj_reloc_entry_size (abfd); + + count = reloc_size / each_size; + + + reloc_cache = (arelent *) bfd_zalloc (abfd, (size_t)(count * sizeof + (arelent))); + if (!reloc_cache) { +nomem: + bfd_error = no_memory; + return false; + } + + relocs = (PTR) bfd_alloc (abfd, reloc_size); + if (!relocs) { + bfd_release (abfd, reloc_cache); + goto nomem; + } + + if (bfd_read (relocs, 1, reloc_size, abfd) != reloc_size) { + bfd_release (abfd, relocs); + bfd_release (abfd, reloc_cache); + bfd_error = system_call_error; + return false; + } + + if (each_size == RELOC_EXT_SIZE) { + register struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs; + unsigned int counter = 0; + arelent *cache_ptr = reloc_cache; + + for (; counter < count; counter++, rptr++, cache_ptr++) { + NAME(aout,swap_ext_reloc_in)(abfd, rptr, cache_ptr, symbols); + } + } else { + register struct reloc_std_external *rptr = (struct reloc_std_external*) relocs; + unsigned int counter = 0; + arelent *cache_ptr = reloc_cache; + + for (; counter < count; counter++, rptr++, cache_ptr++) { + NAME(aout,swap_std_reloc_in)(abfd, rptr, cache_ptr, symbols); + } + + } + + bfd_release (abfd,relocs); + asect->relocation = reloc_cache; + asect->reloc_count = count; + return true; +} + + + +/* Write out a relocation section into an object file. */ + +boolean +DEFUN(NAME(aout,squirt_out_relocs),(abfd, section), + bfd *abfd AND + asection *section) +{ + arelent **generic; + unsigned char *native, *natptr; + size_t each_size; + + unsigned int count = section->reloc_count; + size_t natsize; + + if (count == 0) return true; + + each_size = obj_reloc_entry_size (abfd); + natsize = each_size * count; + native = (unsigned char *) bfd_zalloc (abfd, natsize); + if (!native) { + bfd_error = no_memory; + return false; + } + + generic = section->orelocation; + + if (each_size == RELOC_EXT_SIZE) + { + for (natptr = native; + count != 0; + --count, natptr += each_size, ++generic) + NAME(aout,swap_ext_reloc_out) (abfd, *generic, (struct reloc_ext_external *)natptr); + } + else + { + for (natptr = native; + count != 0; + --count, natptr += each_size, ++generic) + NAME(aout,swap_std_reloc_out)(abfd, *generic, (struct reloc_std_external *)natptr); + } + + if ( bfd_write ((PTR) native, 1, natsize, abfd) != natsize) { + bfd_release(abfd, native); + return false; + } + bfd_release (abfd, native); + + return true; +} + +/* This is stupid. This function should be a boolean predicate */ +unsigned int +DEFUN(NAME(aout,canonicalize_reloc),(abfd, section, relptr, symbols), + bfd *abfd AND + sec_ptr section AND + arelent **relptr AND + asymbol **symbols) +{ + arelent *tblptr = section->relocation; + unsigned int count; + + if (!(tblptr || NAME(aout,slurp_reloc_table)(abfd, section, symbols))) + return 0; + + if (section->flags & SEC_CONSTRUCTOR) { + arelent_chain *chain = section->constructor_chain; + for (count = 0; count < section->reloc_count; count ++) { + *relptr ++ = &chain->relent; + chain = chain->next; + } + } + else { + tblptr = section->relocation; + if (!tblptr) return 0; + + for (count = 0; count++ < section->reloc_count;) + { + *relptr++ = tblptr++; + } + } + *relptr = 0; + + return section->reloc_count; +} + +unsigned int +DEFUN(NAME(aout,get_reloc_upper_bound),(abfd, asect), + bfd *abfd AND + sec_ptr asect) +{ + if (bfd_get_format (abfd) != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + if (asect->flags & SEC_CONSTRUCTOR) { + return (sizeof (arelent *) * (asect->reloc_count+1)); + } + + + if (asect == obj_datasec (abfd)) + return (sizeof (arelent *) * + ((exec_hdr(abfd)->a_drsize / obj_reloc_entry_size (abfd)) + +1)); + + if (asect == obj_textsec (abfd)) + return (sizeof (arelent *) * + ((exec_hdr(abfd)->a_trsize / obj_reloc_entry_size (abfd)) + +1)); + + bfd_error = invalid_operation; + return 0; +} + + + unsigned int +DEFUN(NAME(aout,get_symtab_upper_bound),(abfd), + bfd *abfd) +{ + if (!NAME(aout,slurp_symbol_table)(abfd)) return 0; + + return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *)); +} + alent * +DEFUN(NAME(aout,get_lineno),(ignore_abfd, ignore_symbol), + bfd *ignore_abfd AND + asymbol *ignore_symbol) +{ +return (alent *)NULL; +} + +void +DEFUN(NAME(aout,get_symbol_info),(ignore_abfd, symbol, ret), + bfd *ignore_abfd AND + asymbol *symbol AND + symbol_info *ret) +{ + bfd_symbol_info (symbol, ret); + + if (ret->type == '?') + { + int type_code = aout_symbol(symbol)->type & 0xff; + CONST char *stab_name = aout_stab_name(type_code); + static char buf[10]; + + if (stab_name == NULL) + { + sprintf(buf, "(%d)", type_code); + stab_name = buf; + } + ret->type = '-'; + ret->stab_other = (unsigned)(aout_symbol(symbol)->other & 0xff); + ret->stab_desc = (unsigned)(aout_symbol(symbol)->desc & 0xffff); + ret->stab_name = stab_name; + } +} + +void +DEFUN(NAME(aout,print_symbol),(ignore_abfd, afile, symbol, how), + bfd *ignore_abfd AND + PTR afile AND + asymbol *symbol AND + bfd_print_symbol_type how) +{ + FILE *file = (FILE *)afile; + + switch (how) { + case bfd_print_symbol_name: + if (symbol->name) + fprintf(file,"%s", symbol->name); + break; + case bfd_print_symbol_more: + fprintf(file,"%4x %2x %2x",(unsigned)(aout_symbol(symbol)->desc & 0xffff), + (unsigned)(aout_symbol(symbol)->other & 0xff), + (unsigned)(aout_symbol(symbol)->type)); + break; + case bfd_print_symbol_all: + { + CONST char *section_name = symbol->section->name; + + + bfd_print_symbol_vandf((PTR)file,symbol); + + fprintf(file," %-5s %04x %02x %02x", + section_name, + (unsigned)(aout_symbol(symbol)->desc & 0xffff), + (unsigned)(aout_symbol(symbol)->other & 0xff), + (unsigned)(aout_symbol(symbol)->type & 0xff)); + if (symbol->name) + fprintf(file," %s", symbol->name); + } + break; + } +} + +/* + provided a BFD, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. +*/ + +boolean +DEFUN(NAME(aout,find_nearest_line),(abfd, + section, + symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr), + bfd *abfd AND + asection *section AND + asymbol **symbols AND + bfd_vma offset AND + CONST char **filename_ptr AND + CONST char **functionname_ptr AND + unsigned int *line_ptr) +{ + /* Run down the file looking for the filename, function and linenumber */ + asymbol **p; + static char buffer[100]; + static char filename_buffer[200]; + CONST char *directory_name = NULL; + CONST char *main_file_name = NULL; + CONST char *current_file_name = NULL; + CONST char *line_file_name = NULL; /* Value of current_file_name at line number. */ + bfd_vma high_line_vma = ~0; + bfd_vma low_func_vma = 0; + asymbol *func = 0; + *filename_ptr = abfd->filename; + *functionname_ptr = 0; + *line_ptr = 0; + if (symbols != (asymbol **)NULL) { + for (p = symbols; *p; p++) { + aout_symbol_type *q = (aout_symbol_type *)(*p); + next: + switch (q->type){ + case N_SO: + main_file_name = current_file_name = q->symbol.name; + /* Look ahead to next symbol to check if that too is an N_SO. */ + p++; + if (*p == NULL) + break; + q = (aout_symbol_type *)(*p); + if (q->type != (int)N_SO) + goto next; + + /* Found a second N_SO First is directory; second is filename. */ + directory_name = current_file_name; + main_file_name = current_file_name = q->symbol.name; + if (obj_textsec(abfd) != section) + goto done; + break; + case N_SOL: + current_file_name = q->symbol.name; + break; + + case N_SLINE: + + case N_DSLINE: + case N_BSLINE: + /* We'll keep this if it resolves nearer than the one we have already */ + if (q->symbol.value >= offset && + q->symbol.value < high_line_vma) { + *line_ptr = q->desc; + high_line_vma = q->symbol.value; + line_file_name = current_file_name; + } + break; + case N_FUN: + { + /* We'll keep this if it is nearer than the one we have already */ + if (q->symbol.value >= low_func_vma && + q->symbol.value <= offset) { + low_func_vma = q->symbol.value; + func = (asymbol *)q; + } + if (*line_ptr && func) { + CONST char *function = func->name; + char *p; + strncpy(buffer, function, sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = 0; + /* Have to remove : stuff */ + p = strchr(buffer,':'); + if (p != NULL) { *p = '\0'; } + *functionname_ptr = buffer; + goto done; + + } + } + break; + } + } + } + + done: + if (*line_ptr) + main_file_name = line_file_name; + if (main_file_name) { + if (main_file_name[0] == '/' || directory_name == NULL) + *filename_ptr = main_file_name; + else { + sprintf(filename_buffer, "%.140s%.50s", + directory_name, main_file_name); + *filename_ptr = filename_buffer; + } + } + return true; + +} + +int +DEFUN(NAME(aout,sizeof_headers),(abfd, execable), + bfd *abfd AND + boolean execable) +{ + return adata(abfd).exec_bytes_size; +} diff --git a/gnu/usr.bin/gdb/bfd/arch/i386/Makefile.inc b/gnu/usr.bin/gdb/bfd/arch/i386/Makefile.inc new file mode 100644 index 00000000000..78987e9a0d4 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/i386/Makefile.inc @@ -0,0 +1,11 @@ +# $Id: Makefile.inc,v 1.1 1995/10/18 08:39:54 deraadt Exp $ + +SRCS+= netbsd386.c cpu-i386.c + +CFLAGS+= -DNETBSD_CORE + +VECTORS= -DDEFAULT_VECTOR=netbsd_386_vec \ + -DSELECT_ARCHITECTURES=bfd_i386_arch \ + -DSELECT_VECS='&netbsd_386_vec' + + diff --git a/gnu/usr.bin/gdb/bfd/arch/i386/cpu-i386.c b/gnu/usr.bin/gdb/bfd/arch/i386/cpu-i386.c new file mode 100644 index 00000000000..7ac7980a51f --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/i386/cpu-i386.c @@ -0,0 +1,46 @@ +/* BFD support for the Intel 386 architecture. + Copyright 1992 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: cpu-i386.c,v 1.1 1995/10/18 08:39:54 deraadt Exp $ +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +static bfd_arch_info_type arch_info_struct = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_i386, + 0, /* only 1 machine */ + "i386", + "i386", + 2, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; + +void DEFUN_VOID(bfd_i386_arch) +{ + bfd_arch_linkin(&arch_info_struct); +} diff --git a/gnu/usr.bin/gdb/bfd/arch/i386/netbsd386.c b/gnu/usr.bin/gdb/bfd/arch/i386/netbsd386.c new file mode 100644 index 00000000000..f532a0325a2 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/i386/netbsd386.c @@ -0,0 +1,40 @@ +/* BFD back-end for NetBSD/386 a.out-ish binaries. + Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: netbsd386.c,v 1.1 1995/10/18 08:39:54 deraadt Exp $ +*/ + +#define BYTES_IN_WORD 4 +#define ARCH 32 +#undef TARGET_IS_BIG_ENDIAN_P +#undef HOST_BIG_ENDIAN_P + +#define PAGE_SIZE 4096 +#define SEGMENT_SIZE PAGE_SIZE +#define __LDPGSZ 4096 + +#define DEFAULT_ARCH bfd_arch_i386 +#define MACHTYPE_OK(mtype) ((mtype) == M_386 || (mtype) == M_386_NETBSD || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(netbsd_386_,OP) +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-netbsd-386" + +#include "netbsd.h" + diff --git a/gnu/usr.bin/gdb/bfd/arch/i386/sysdep.h b/gnu/usr.bin/gdb/bfd/arch/i386/sysdep.h new file mode 100644 index 00000000000..f04ced14b59 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/i386/sysdep.h @@ -0,0 +1,46 @@ +/* $Id: sysdep.h,v 1.1 1995/10/18 08:39:54 deraadt Exp $ */ +#ifndef hosts_i386bsd_H +/* Intel 386 running any BSD Unix */ +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <string.h> +#include <sys/file.h> +#include <machine/param.h> +#include <machine/vmparam.h> + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + +#define SEEK_SET 0 +#define SEEK_CUR 1 + +#define HOST_PAGE_SIZE NBPG +#define HOST_MACHINE_ARCH bfd_arch_i386 +#define HOST_TEXT_START_ADDR USRTEXT + +/* Jolitz suggested defining HOST_STACK_END_ADDR to + (u.u_kproc.kp_eproc.e_vm.vm_maxsaddr + MAXSSIZ), which should work on + both BSDI and 386BSD, but that is believed not to work for BSD 4.4. */ + +#if defined(__bsdi__) || defined(__NetBSD__) +/* This seems to be the right thing. */ +#define HOST_STACK_END_ADDR USRSTACK +#else +/* This seems to be the right thing for 386BSD release 0.1. */ +#define HOST_STACK_END_ADDR (USRSTACK - MAXSSIZ) +#endif + +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(core_bfd) \ + ((core_bfd)->tdata.trad_core_data->u.u_sig) +#define u_comm u_kproc.kp_proc.p_comm + +#include "fopen-same.h" + +#define hosts_i386bsd_H +#endif diff --git a/gnu/usr.bin/gdb/bfd/arch/m68k/Makefile.inc b/gnu/usr.bin/gdb/bfd/arch/m68k/Makefile.inc new file mode 100644 index 00000000000..883f81a53c9 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/m68k/Makefile.inc @@ -0,0 +1,10 @@ +# $Id: Makefile.inc,v 1.1 1995/10/18 08:39:54 deraadt Exp $ + +SRCS+= netbsdm68k.c netbsdm68k4k.c cpu-m68k.c trad-core.c + +# Note: DEFAULT_VECTOR is actually ignored when SELECT_VECS is set. +VECTORS= -DDEFAULT_VECTOR=netbsd_m68k_vec \ + -DSELECT_ARCHITECTURES=bfd_m68k_arch \ + -DSELECT_VECS=' &netbsd_m68k_vec, &netbsd_m68k4k_vec, \ + &netbsd_core_vec, &trad_core_vec ' + diff --git a/gnu/usr.bin/gdb/bfd/arch/m68k/cpu-m68k.c b/gnu/usr.bin/gdb/bfd/arch/m68k/cpu-m68k.c new file mode 100644 index 00000000000..40ae90bc3be --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/m68k/cpu-m68k.c @@ -0,0 +1,55 @@ +/* BFD library support routines for architectures. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: cpu-m68k.c,v 1.1 1995/10/18 08:39:54 deraadt Exp $ +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +int bfd_default_scan_num_mach(); + + +#define N(name, print,d) \ +{ 32, 32, 8, bfd_arch_m68k, name, "m68k",print,2,d,bfd_default_compatible,bfd_default_scan, 0, } + +static bfd_arch_info_type arch_info_struct[] = +{ + N(68000,"m68k:68000",false), + N(68008,"m68k:68008",false), + N(68010,"m68k:68010",false), + N(68020,"m68k:68020",true), /* the word m68k will match this too */ + N(68030,"m68k:68030",false), + N(68040,"m68k:68040",false), + N(68070,"m68k:68070",false), + { 0 }, +} +; + + +void DEFUN_VOID(bfd_m68k_arch) +{ + unsigned int i; + for (i = 0; arch_info_struct[i].bits_per_word; i++) + { + bfd_arch_linkin(&arch_info_struct[i]); + } +} diff --git a/gnu/usr.bin/gdb/bfd/arch/m68k/netbsdm68k.c b/gnu/usr.bin/gdb/bfd/arch/m68k/netbsdm68k.c new file mode 100644 index 00000000000..c1ab49691a3 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/m68k/netbsdm68k.c @@ -0,0 +1,40 @@ +/* BFD back-end for NetBSD/m68k a.out-ish binaries. + Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: netbsdm68k.c,v 1.1 1995/10/18 08:39:55 deraadt Exp $ +*/ + +#define BYTES_IN_WORD 4 +#define ARCH 32 +#define HOST_IS_BIG_ENDIAN_P +#define TARGET_IS_BIG_ENDIAN_P + +#define PAGE_SIZE 8192 +#define SEGMENT_SIZE PAGE_SIZE +#define __LDPGSZ 8192 + +#define DEFAULT_ARCH bfd_arch_m68k +#define MACHTYPE_OK(mtype) ((mtype) == M_M68K_NETBSD || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(netbsd_m68k_,OP) +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-netbsd-m68k" + +#include "netbsd.h" + diff --git a/gnu/usr.bin/gdb/bfd/arch/m68k/netbsdm68k4k.c b/gnu/usr.bin/gdb/bfd/arch/m68k/netbsdm68k4k.c new file mode 100644 index 00000000000..da9e55a3124 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/m68k/netbsdm68k4k.c @@ -0,0 +1,40 @@ +/* BFD back-end for NetBSD/m68k a.out-ish binaries. + Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: netbsdm68k4k.c,v 1.1 1995/10/18 08:39:55 deraadt Exp $ +*/ + +#define BYTES_IN_WORD 4 +#define ARCH 32 +#define HOST_IS_BIG_ENDIAN_P +#define TARGET_IS_BIG_ENDIAN_P + +#define PAGE_SIZE 4096 +#define SEGMENT_SIZE PAGE_SIZE +#define __LDPGSZ 4096 + +#define DEFAULT_ARCH bfd_arch_m68k +#define MACHTYPE_OK(mtype) ((mtype) == M_HP300 || (mtype) == M_M68K4K_NETBSD || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(netbsd_m68k4k_,OP) +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-netbsd-m68k4k" + +#include "netbsd.h" + diff --git a/gnu/usr.bin/gdb/bfd/arch/m68k/sysdep.h b/gnu/usr.bin/gdb/bfd/arch/m68k/sysdep.h new file mode 100644 index 00000000000..c626aabfd99 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/m68k/sysdep.h @@ -0,0 +1,32 @@ +/* $Id: sysdep.h,v 1.1 1995/10/18 08:39:55 deraadt Exp $ */ +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <string.h> +#include <sys/file.h> +#include <machine/param.h> /* BSD 4.4 alpha or better */ + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + +#define SEEK_SET 0 +#define SEEK_CUR 1 + +#define HOST_PAGE_SIZE NBPG +#define HOST_SEGMENT_SIZE NBPG /* Data seg start addr rounds to NBPG */ +#define HOST_MACHINE_ARCH bfd_arch_m68k +/* #define HOST_MACHINE_MACHINE */ + +#define HOST_TEXT_START_ADDR 0 +#define HOST_STACK_END_ADDR USRSTACK + +#include "fopen-same.h" + +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(core_bfd) \ + ((core_bfd)->tdata.trad_core_data->u.u_sig) +#define u_comm u_kproc.kp_proc.p_comm diff --git a/gnu/usr.bin/gdb/bfd/arch/ns32k/Makefile.inc b/gnu/usr.bin/gdb/bfd/arch/ns32k/Makefile.inc new file mode 100644 index 00000000000..cec956983a3 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/ns32k/Makefile.inc @@ -0,0 +1,11 @@ +# $Id: Makefile.inc,v 1.1 1995/10/18 08:39:55 deraadt Exp $ + +SRCS+= netbsd-ns32k.c cpu-ns32k.c + +CFLAGS+= -DNETBSD_CORE + +VECTORS= -DDEFAULT_VECTOR=netbsd_ns32k_vec \ + -DSELECT_ARCHITECTURES=bfd_ns32k_arch \ + -DSELECT_VECS='&netbsd_ns32k_vec' + + diff --git a/gnu/usr.bin/gdb/bfd/arch/ns32k/cpu-ns32k.c b/gnu/usr.bin/gdb/bfd/arch/ns32k/cpu-ns32k.c new file mode 100644 index 00000000000..063cd684892 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/ns32k/cpu-ns32k.c @@ -0,0 +1,46 @@ +/* BFD support for the ns32k architecture. + Copyright 1992 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: cpu-ns32k.c,v 1.1 1995/10/18 08:39:55 deraadt Exp $ +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +static bfd_arch_info_type arch_info_struct = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_ns32k, + 0, /* only 1 machine */ + "ns32k", + "ns32k", + 2, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; + +void DEFUN_VOID(bfd_ns32k_arch) +{ + bfd_arch_linkin(&arch_info_struct); +} diff --git a/gnu/usr.bin/gdb/bfd/arch/ns32k/netbsd-ns32k.c b/gnu/usr.bin/gdb/bfd/arch/ns32k/netbsd-ns32k.c new file mode 100644 index 00000000000..16c6512d62e --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/ns32k/netbsd-ns32k.c @@ -0,0 +1,40 @@ +/* BFD back-end for NetBSD/ns32k a.out-ish binaries. + Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: netbsd-ns32k.c,v 1.1 1995/10/18 08:39:55 deraadt Exp $ +*/ + +#define BYTES_IN_WORD 4 +#define ARCH 32 +#undef TARGET_IS_BIG_ENDIAN_P +#undef HOST_BIG_ENDIAN_P + +#define PAGE_SIZE 4096 +#define SEGMENT_SIZE PAGE_SIZE +#define __LDPGSZ 4096 + +#define DEFAULT_ARCH bfd_arch_ns32k +#define MACHTYPE_OK(mtype) ((mtype) == M_NS32K_NETBSD || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(netbsd_ns32k_,OP) +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-netbsd-ns32k" + +#include "netbsd.h" + diff --git a/gnu/usr.bin/gdb/bfd/arch/ns32k/sysdep.h b/gnu/usr.bin/gdb/bfd/arch/ns32k/sysdep.h new file mode 100644 index 00000000000..b9de2ee3374 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/ns32k/sysdep.h @@ -0,0 +1,37 @@ +/* $Id: sysdep.h,v 1.1 1995/10/18 08:39:55 deraadt Exp $ */ +#ifndef hosts_ns32kbsd_H +/* ns32k running any BSD Unix */ +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <string.h> +#include <sys/file.h> +#include <machine/param.h> +#include <machine/vmparam.h> + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + +#define SEEK_SET 0 +#define SEEK_CUR 1 + +#define HOST_PAGE_SIZE NBPG +#define HOST_SEGMENT_SIZE NBPG /* Data seg start addr rounds to NBPG */ +#define HOST_MACHINE_ARCH bfd_arch_ns32k + +#define HOST_TEXT_START_ADDR USRTEXT +#define HOST_STACK_END_ADDR USRSTACK + +#include "fopen-same.h" + +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(core_bfd) \ + ((core_bfd)->tdata.trad_core_data->u.u_sig) +#define u_comm u_kproc.kp_proc.p_comm + +#define hosts_ns32kbsd_H +#endif diff --git a/gnu/usr.bin/gdb/bfd/arch/sparc/Makefile.inc b/gnu/usr.bin/gdb/bfd/arch/sparc/Makefile.inc new file mode 100644 index 00000000000..96a44f6c78b --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/sparc/Makefile.inc @@ -0,0 +1,11 @@ +# $Id: Makefile.inc,v 1.1 1995/10/18 08:39:55 deraadt Exp $ + +SRCS+= netbsd_sparc.c cpu-sparc.c + +CFLAGS+= -DNETBSD_CORE + +VECTORS= -DDEFAULT_VECTOR=netbsd_sparc_vec \ + -DSELECT_ARCHITECTURES=bfd_sparc_arch \ + -DSELECT_VECS='&netbsd_sparc_vec' + + diff --git a/gnu/usr.bin/gdb/bfd/arch/sparc/cpu-sparc.c b/gnu/usr.bin/gdb/bfd/arch/sparc/cpu-sparc.c new file mode 100644 index 00000000000..cf09b032cbc --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/sparc/cpu-sparc.c @@ -0,0 +1,46 @@ +/* BFD support for the SPARC architecture. + Copyright 1992 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: cpu-sparc.c,v 1.1 1995/10/18 08:39:55 deraadt Exp $ +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +static bfd_arch_info_type arch_info_struct = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_sparc, + 0, /* only 1 machine */ + "sparc", + "sparc", + 3, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; + +void DEFUN_VOID(bfd_sparc_arch) +{ + bfd_arch_linkin(&arch_info_struct); +} diff --git a/gnu/usr.bin/gdb/bfd/arch/sparc/netbsd_sparc.c b/gnu/usr.bin/gdb/bfd/arch/sparc/netbsd_sparc.c new file mode 100644 index 00000000000..f1d830a57a1 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/sparc/netbsd_sparc.c @@ -0,0 +1,21 @@ +/* $Id: netbsd_sparc.c,v 1.1 1995/10/18 08:39:55 deraadt Exp $ */ + +#define TARGET_IS_BIG_ENDIAN_P +#define HOST_BIG_ENDIAN_P +#define BYTES_IN_WORD 4 +#define ARCH 32 + +#define __LDPGSZ 8192 +#define PAGE_SIZE __LDPGSZ +#define SEGMENT_SIZE __LDPGSZ +#define MID_SPARC 138 +#define DEFAULT_ARCH bfd_arch_sparc + +#define MACHTYPE_OK(mtype) ((mtype) == MID_SPARC || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(netbsd_sparc_,OP) +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-netbsd-sparc" + +#include "netbsd.h" + diff --git a/gnu/usr.bin/gdb/bfd/arch/sparc/sysdep.h b/gnu/usr.bin/gdb/bfd/arch/sparc/sysdep.h new file mode 100644 index 00000000000..47078e67980 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/sparc/sysdep.h @@ -0,0 +1,46 @@ +/* $Id: sysdep.h,v 1.1 1995/10/18 08:39:55 deraadt Exp $ */ + +#ifndef hosts_sparc_H +#define hosts_sparc_H + +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <string.h> +#include <sys/file.h> +#include <machine/param.h> +#include <machine/vmparam.h> +#include <machine/reg.h> + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + +#define SEEK_SET 0 +#define SEEK_CUR 1 + +#include "fopen-same.h" + + +#define HOST_PAGE_SIZE NBPG +#define HOST_MACHINE_ARCH bfd_arch_sparc +#define HOST_TEXT_START_ADDR USRTEXT + +#define HOST_STACK_END_ADDR USRSTACK +/* +#define HOST_DATA_START_ADDR ((bfd_vma)u.u_kproc.kp_eproc.e_vm.vm_daddr) +*/ + +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(core_bfd) \ + ((core_bfd)->tdata.trad_core_data->u.u_sig) +#define u_comm u_kproc.kp_proc.p_comm +#define TRAD_CORE_REGPOS(core_bfd) \ + ((bfd_vma)(core_bfd)->tdata.trad_core_data->u.u_kproc.kp_proc.p_md.md_tf) + +#define CORE_FPU_OFFSET (sizeof(struct trapframe)) + +#endif diff --git a/gnu/usr.bin/gdb/bfd/arch/vax/Makefile.inc b/gnu/usr.bin/gdb/bfd/arch/vax/Makefile.inc new file mode 100644 index 00000000000..6712d24991d --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/vax/Makefile.inc @@ -0,0 +1,11 @@ +# $Id: Makefile.inc,v 1.1 1995/10/18 08:39:55 deraadt Exp $ + +SRCS+= netbsdvax.c cpu-vax.c + +CFLAGS+= -DNETBSD_CORE + +VECTORS= -DDEFAULT_VECTOR=netbsd_vax_vec \ + -DSELECT_ARCHITECTURES=bfd_vax_arch \ + -DSELECT_VECS='&netbsd_vax_vec' + + diff --git a/gnu/usr.bin/gdb/bfd/arch/vax/cpu-vax.c b/gnu/usr.bin/gdb/bfd/arch/vax/cpu-vax.c new file mode 100644 index 00000000000..09a7a6b2343 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/vax/cpu-vax.c @@ -0,0 +1,46 @@ +/* BFD support for the DEC vax architecture. + Copyright 1995 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: cpu-vax.c,v 1.1 1995/10/18 08:39:55 deraadt Exp $ +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +static bfd_arch_info_type arch_info_struct = + { + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_vax, + 0, /* only 1 machine */ + "vax", + "vax", + 2, + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; + +void DEFUN_VOID(bfd_vax_arch) +{ + bfd_arch_linkin(&arch_info_struct); +} diff --git a/gnu/usr.bin/gdb/bfd/arch/vax/netbsdvax.c b/gnu/usr.bin/gdb/bfd/arch/vax/netbsdvax.c new file mode 100644 index 00000000000..d4686c02bc1 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/vax/netbsdvax.c @@ -0,0 +1,40 @@ +/* BFD back-end for NetBSD/vax a.out-ish binaries. + Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: netbsdvax.c,v 1.1 1995/10/18 08:39:55 deraadt Exp $ +*/ + +#define BYTES_IN_WORD 4 +#define ARCH 32 +#undef TARGET_IS_BIG_ENDIAN_P +#undef HOST_BIG_ENDIAN_P + +#define PAGE_SIZE 1024 +#define SEGMENT_SIZE PAGE_SIZE +#define __LDPGSZ 1024 + +#define DEFAULT_ARCH bfd_arch_vax +#define MACHTYPE_OK(mtype) ((mtype) == M_VAX || (mtype) == M_UNKNOWN) + +#define MY(OP) CAT(netbsd_vax_,OP) +/* This needs to start with a.out so GDB knows it is an a.out variant. */ +#define TARGETNAME "a.out-netbsd-vax" + +#include "netbsd.h" + diff --git a/gnu/usr.bin/gdb/bfd/arch/vax/sysdep.h b/gnu/usr.bin/gdb/bfd/arch/vax/sysdep.h new file mode 100644 index 00000000000..d750cdaf992 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/arch/vax/sysdep.h @@ -0,0 +1,35 @@ +/* $Id: sysdep.h,v 1.1 1995/10/18 08:39:55 deraadt Exp $ */ +#ifndef hosts_vaxbsd_H +/* DEC VAX running any BSD Unix */ +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <string.h> +#include <sys/file.h> +#include <machine/param.h> + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + +#define SEEK_SET 0 +#define SEEK_CUR 1 + +#define HOST_PAGE_SIZE NBPG +#define HOST_MACHINE_ARCH bfd_arch_vax +#define HOST_TEXT_START_ADDR USRTEXT + +#define HOST_STACK_END_ADDR USRSTACK + +#define TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(core_bfd) \ + ((core_bfd)->tdata.trad_core_data->u.u_sig) +#define u_comm u_kproc.kp_proc.p_comm + +#include "fopen-same.h" + +#define hosts_vaxbsd_H +#endif diff --git a/gnu/usr.bin/gdb/bfd/archive.c b/gnu/usr.bin/gdb/bfd/archive.c new file mode 100644 index 00000000000..21ce1c8cdd1 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/archive.c @@ -0,0 +1,1773 @@ +/* BFD back-end for archive files (libraries). + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: archive.c,v 1.1 1995/10/18 08:39:51 deraadt Exp $ +*/ + +/* +@setfilename archive-info +SECTION + Archives + +DESCRIPTION + Archives are supported in BFD in <<archive.c>>. + + An archive (or library) is just another BFD. It has a symbol + table, although there's not much a user program will do with it. + + The big difference between an archive BFD and an ordinary BFD + is that the archive doesn't have sections. Instead it has a + chain of BFDs considered its contents. These BFDs can be + manipulated just like any other. The BFDs contained in an + archive opened for reading will all be opened for reading; you + may put either input or output BFDs into an archive opened for + output; it will be handled correctly when the archive is closed. + + Use <<bfd_openr_next_archived_file>> to step through all + the contents of an archive opened for input. It's not + required that you read the entire archive if you don't want + to! Read it until you find what you want. + + Archive contents of output BFDs are chained through the + <<next>> pointer in a BFD. The first one is findable through + the <<archive_head>> slot of the archive. Set it with + <<set_archive_head>> (q.v.). A given BFD may be in only one + open output archive at a time. + + As expected, the BFD archive code is more general than the + archive code of any given environment. BFD archives may + contain files of different formats (e.g., a.out and coff) and + even different architectures. You may even place archives + recursively into archives! + + This can cause unexpected confusion, since some archive + formats are more expressive than others. For instance, Intel + COFF archives can preserve long filenames; Sun a.out archives + cannot. If you move a file from the first to the second + format and back again, the filename may be truncated. + Likewise, different a.out environments have different + conventions as to how they truncate filenames, whether they + preserve directory names in filenames, etc. When + interoperating with native tools, be sure your files are + homogeneous. + + Beware: most of these formats do not react well to the + presence of spaces in filenames. We do the best we can, but + can't always handle this due to restrctions in the format of + archives. Many unix utilities are braindead in regards to + spaces and such in filenames anyway, so this shouldn't be much + of a restriction. +*/ + +/* Assumes: + o - all archive elements start on an even boundary, newline padded; + o - all arch headers are char *; + o - all arch headers are the same size (across architectures). +*/ + +/* Some formats provide a way to cram a long filename into the short + (16 chars) space provided by a bsd archive. The trick is: make a + special "file" in the front of the archive, sort of like the SYMDEF + entry. If the filename is too long to fit, put it in the extended + name table, and use its index as the filename. To prevent + confusion prepend the index with a space. This means you can't + have filenames that start with a space, but then again, many unix + utilities can't handle that anyway. + + This scheme unfortunately requires that you stand on your head in + order to write an archive since you need to put a magic file at the + front, and need to touch every entry to do so. C'est la vie. + + We support two variants of this idea: + The SVR4 format (extended name table is named "//"), + and an extended pseudo-BSD variant (extended name table is named + "ARFILENAMES/"). The origin of the latter format is uncertain. + + BSD 4.4 uses a third scheme: It writes a long filename + directly after the header. This allows 'ar q' to work. + We current can read BSD 4.4 archives, but not write them. +*/ + +/* Summary of archive member names: + + Symbol table (must be first): + "__.SYMDEF " - Symbol table, Berkeley style, produced by ranlib. + "/ " - Symbol table, system 5 style. + + Long name table (must be before regular file members): + "// " - Long name table, System 5 R4 style. + "ARFILENAMES/ " - Long name table, non-standard extended BSD (not BSD 4.4). + + Regular file members with short names: + "filename.o/ " - Regular file, System 5 style (embedded spaces ok). + "filename.o " - Regular file, Berkeley style (no embedded spaces). + + Regular files with long names (or embedded spaces, for BSD variants): + "/18 " - SVR4 style, name at offset 18 in name table. + "#1/23 " - Long name (or embedded paces) 23 characters long, + BSD 4.4 style, full name follows header. + Implemented for reading, not writing. + " 18 " - Long name 18 characters long, extended pseudo-BSD. + */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "aout/ar.h" +#include "aout/ranlib.h" +#include <errno.h> +#include <string.h> /* For memchr, strrchr and friends */ +#include <ctype.h> + +#ifndef errno +extern int errno; +#endif + +#ifdef GNU960 +#define BFD_GNU960_ARMAG(abfd) (BFD_COFF_FILE_P((abfd)) ? ARMAG : ARMAGB) +#endif + +/* Can't define this in hosts/*.h, because (e.g. in gprof) the hosts file + is included, then obstack.h, which thinks if offsetof is defined, it + doesn't need to include stddef.h. */ +/* Define offsetof for those systems which lack it */ + +#if !defined (offsetof) +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + +/* We keep a cache of archive filepointers to archive elements to + speed up searching the archive by filepos. We only add an entry to + the cache when we actually read one. We also don't sort the cache; + it's generally short enough to search linearly. + Note that the pointers here point to the front of the ar_hdr, not + to the front of the contents! +*/ +struct ar_cache { + file_ptr ptr; + bfd* arelt; + struct ar_cache *next; +}; + +#define ar_padchar(abfd) ((abfd)->xvec->ar_pad_char) +#define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen) + +#define arch_eltdata(bfd) ((struct areltdata *)((bfd)->arelt_data)) +#define arch_hdr(bfd) ((struct ar_hdr *)arch_eltdata(bfd)->arch_header) + +/* Forward declarations of functions */ + +boolean +compute_and_write_armap PARAMS ((bfd *arch, unsigned int elength)); + +static boolean +bsd_update_armap_timestamp PARAMS ((bfd *arch)); + + + +boolean +_bfd_generic_mkarchive (abfd) + bfd *abfd; +{ + abfd->tdata.aout_ar_data = (struct artdata *)bfd_zalloc(abfd, + sizeof (struct artdata)); + + if (bfd_ardata (abfd) == NULL) { + bfd_error = no_memory; + return false; + } + bfd_ardata(abfd)->cache = 0; + return true; +} + +/* +FUNCTION + bfd_get_next_mapent + +SYNOPSIS + symindex bfd_get_next_mapent(bfd *, symindex previous, carsym ** sym); + +DESCRIPTION + This function steps through an archive's symbol table (if it + has one). Successively updates <<sym>> with the next symbol's + information, returning that symbol's (internal) index into the + symbol table. + + Supply BFD_NO_MORE_SYMBOLS as the <<previous>> entry to get + the first one; returns BFD_NO_MORE_SYMBOLS when you're already + got the last one. + + A <<carsym>> is a canonical archive symbol. The only + user-visible element is its name, a null-terminated string. +*/ + +symindex +DEFUN(bfd_get_next_mapent,(abfd, prev, entry), + bfd *abfd AND + symindex prev AND + carsym **entry) +{ + if (!bfd_has_map (abfd)) { + bfd_error = invalid_operation; + return BFD_NO_MORE_SYMBOLS; + } + + if (prev == BFD_NO_MORE_SYMBOLS) prev = 0; + else if (++prev >= bfd_ardata (abfd)->symdef_count) + return BFD_NO_MORE_SYMBOLS; + + *entry = (bfd_ardata (abfd)->symdefs + prev); + return prev; +} + +/* To be called by backends only */ + +bfd * +_bfd_create_empty_archive_element_shell (obfd) + bfd *obfd; +{ + bfd *nbfd; + + nbfd = new_bfd_contained_in(obfd); + if (nbfd == NULL) + { + bfd_error = no_memory; + return NULL; + } + return nbfd; +} + +/* +FUNCTION + bfd_set_archive_head + +SYNOPSIS + boolean bfd_set_archive_head(bfd *output, bfd *new_head); + +DESCRIPTION + Used whilst processing archives. Sets the head of the chain of + BFDs contained in an archive to @var{new_head}. +*/ + +boolean +DEFUN(bfd_set_archive_head,(output_archive, new_head), + bfd *output_archive AND + bfd *new_head) +{ + + output_archive->archive_head = new_head; + return true; +} + +bfd * +look_for_bfd_in_cache (arch_bfd, filepos) + bfd *arch_bfd; + file_ptr filepos; +{ + struct ar_cache *current; + + for (current = bfd_ardata (arch_bfd)->cache; current != NULL; + current = current->next) + if (current->ptr == filepos) return current->arelt; + + return NULL; +} + +/* Kind of stupid to call cons for each one, but we don't do too many */ +boolean +add_bfd_to_cache (arch_bfd, filepos, new_elt) + bfd *arch_bfd, *new_elt; + file_ptr filepos; +{ + struct ar_cache *new_cache = (struct ar_cache *) + bfd_zalloc(arch_bfd, sizeof (struct ar_cache)); + + if (new_cache == NULL) { + bfd_error = no_memory; + return false; + } + + new_cache->ptr = filepos; + new_cache->arelt = new_elt; + new_cache->next = (struct ar_cache *)NULL; + if (bfd_ardata (arch_bfd)->cache == NULL) + bfd_ardata (arch_bfd)->cache = new_cache; + else { + struct ar_cache *current = bfd_ardata (arch_bfd)->cache; + + for (; current->next != NULL; current = current->next); + current->next = new_cache; + } + + return true; +} + + + +/* The name begins with space. Hence the rest of the name is an index into + the string table. */ +char * +get_extended_arelt_filename (arch, name) + bfd *arch; + char *name; +{ + unsigned long index = 0; + + /* Should extract string so that I can guarantee not to overflow into + the next region, but I'm too lazy. */ + errno = 0; + /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */ + index = strtol (name+1, NULL, 10); + if (errno != 0) { + bfd_error = malformed_archive; + return NULL; + } + + return bfd_ardata (arch)->extended_names + index; +} + +/* This functions reads an arch header and returns an areltdata pointer, or + NULL on error. + + Presumes the file pointer is already in the right place (ie pointing + to the ar_hdr in the file). Moves the file pointer; on success it + should be pointing to the front of the file contents; on failure it + could have been moved arbitrarily. +*/ + +struct areltdata * +snarf_ar_hdr (abfd) + bfd *abfd; +{ +#ifndef errno + extern int errno; +#endif + + struct ar_hdr hdr; + char *hdrp = (char *) &hdr; + unsigned int parsed_size; + struct areltdata *ared; + char *filename = NULL; + unsigned int namelen = 0; + unsigned int allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr); + char *allocptr = 0; + + if (bfd_read ((PTR)hdrp, 1, sizeof (struct ar_hdr), abfd) + != sizeof (struct ar_hdr)) { + bfd_error = no_more_archived_files; + return NULL; + } + if (strncmp ((hdr.ar_fmag), ARFMAG, 2)) { + bfd_error = malformed_archive; + return NULL; + } + + errno = 0; + parsed_size = strtol (hdr.ar_size, NULL, 10); + if (errno != 0) { + bfd_error = malformed_archive; + return NULL; + } + + /* extract the filename from the archive - there are two ways to + specify an extendend name table, either the first char of the + name is a space, or it's a slash. */ + if ((hdr.ar_name[0] == '/' + || (hdr.ar_name[0] == ' ' + && memchr (hdr.ar_name, '/', ar_maxnamelen(abfd)) == NULL)) + && bfd_ardata (abfd)->extended_names != NULL) { + filename = get_extended_arelt_filename (abfd, hdr.ar_name); + if (filename == NULL) { + bfd_error = malformed_archive; + return NULL; + } + } + /* BSD4.4-style long filename. + Only implemented for reading, so far! */ + else if (hdr.ar_name[0] == '#' && hdr.ar_name[1] == '1' + && hdr.ar_name[2] == '/' && isdigit(hdr.ar_name[3])) + { + /* BSD-4.4 extended name */ + namelen = atoi (&hdr.ar_name[3]); + allocsize += namelen + 1; + parsed_size -= namelen; + + allocptr = bfd_zalloc(abfd, allocsize); + if (allocptr == NULL) { + bfd_error = no_memory; + return NULL; + } + filename = allocptr + + (sizeof (struct areltdata) + sizeof (struct ar_hdr)); + if (bfd_read (filename, 1, namelen, abfd) != namelen) { + bfd_error = no_more_archived_files; + return NULL; + } + filename[namelen] = '\0'; + } + else + { + /* We judge the end of the name by looking for '/' or ' '. + Note: The SYSV format (terminated by '/') allows embedded + spaces, so only look for ' ' if we don't find '/'. */ + + namelen = 0; + while (hdr.ar_name[namelen] != '\0' && + hdr.ar_name[namelen] != '/') { + namelen++; + if (namelen == (unsigned)ar_maxnamelen(abfd)) { + namelen = 0; + while (hdr.ar_name[namelen] != ' ' + && namelen < (unsigned)ar_maxnamelen(abfd)) { + namelen++; + } + break; + } + } + + allocsize += namelen + 1; + } + + if (!allocptr) { + allocptr = bfd_zalloc(abfd, allocsize); + if (allocptr == NULL) { + bfd_error = no_memory; + return NULL; + } + } + + ared = (struct areltdata *) allocptr; + + ared->arch_header = allocptr + sizeof (struct areltdata); + memcpy ((char *) ared->arch_header, (char *) &hdr, sizeof (struct ar_hdr)); + ared->parsed_size = parsed_size; + + if (filename != NULL) ared->filename = filename; + else { + ared->filename = allocptr + (sizeof (struct areltdata) + + sizeof (struct ar_hdr)); + if (namelen) + memcpy (ared->filename, hdr.ar_name, namelen); + ared->filename[namelen] = '\0'; + } + + return ared; +} + +/* This is an internal function; it's mainly used when indexing + through the archive symbol table, but also used to get the next + element, since it handles the bookkeeping so nicely for us. +*/ + +bfd * +get_elt_at_filepos (archive, filepos) + bfd *archive; + file_ptr filepos; +{ + struct areltdata *new_areldata; + bfd *n_nfd; + + n_nfd = look_for_bfd_in_cache (archive, filepos); + if (n_nfd) + return n_nfd; + + if (0 > bfd_seek (archive, filepos, SEEK_SET)) + { + bfd_error = system_call_error; + return NULL; + } + + if ((new_areldata = snarf_ar_hdr (archive)) == NULL) + return NULL; + + n_nfd = _bfd_create_empty_archive_element_shell (archive); + if (n_nfd == NULL) + { + bfd_release (archive, (PTR)new_areldata); + return NULL; + } + + n_nfd->origin = bfd_tell (archive); + n_nfd->arelt_data = (PTR) new_areldata; + n_nfd->filename = new_areldata->filename; + + if (add_bfd_to_cache (archive, filepos, n_nfd)) + return n_nfd; + + /* huh? */ + bfd_release (archive, (PTR)n_nfd); + bfd_release (archive, (PTR)new_areldata); + return NULL; +} + +/* +FUNCTION + bfd_get_elt_at_index + +SYNOPSIS + bfd *bfd_get_elt_at_index(bfd * archive, int index); + +DESCRIPTION + Return the bfd which is referenced by the symbol indexed by <<index>>. + <<index>> should have been returned by <<bfd_get_next_mapent>> (q.v.). + +*/ +bfd * +DEFUN(bfd_get_elt_at_index,(abfd, index), + bfd *abfd AND + int index) +{ + bfd *result = + get_elt_at_filepos + (abfd, (bfd_ardata (abfd)->symdefs + index)->file_offset); + return result; +} + +/* +FUNCTION + bfd_openr_next_archived_file + +SYNOPSIS + bfd* bfd_openr_next_archived_file(bfd *archive, bfd *previous); + +DESCRIPTION + Initially provided a BFD containing an archive and NULL, opens + an inpout BFD on the first contained element and returns that. + Subsequent calls to bfd_openr_next_archived_file should pass + the archive and the previous return value to return a created + BFD to the next contained element. NULL is returned when there + are no more. + +*/ + +bfd * +bfd_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; +{ + if ((bfd_get_format (archive) != bfd_archive) || + (archive->direction == write_direction)) + { + bfd_error = invalid_operation; + return NULL; + } + + return BFD_SEND (archive, + openr_next_archived_file, + (archive, + last_file)); +} + +bfd * +bfd_generic_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; +{ + file_ptr filestart; + + if (!last_file) + filestart = bfd_ardata (archive)->first_file_filepos; + else { + unsigned int size = arelt_size(last_file); + /* Pad to an even boundary... + Note that last_file->origin can be odd in the case of + BSD-4.4-style element with a long odd size. */ + filestart = last_file->origin + size; + filestart += filestart % 2; + } + + return get_elt_at_filepos (archive, filestart); +} + + +bfd_target * +bfd_generic_archive_p (abfd) + bfd *abfd; +{ + char armag[SARMAG+1]; + + if (bfd_read ((PTR)armag, 1, SARMAG, abfd) != SARMAG) { + bfd_error = wrong_format; + return 0; + } + +#ifdef GNU960 + if (strncmp (armag, BFD_GNU960_ARMAG(abfd), SARMAG)) return 0; +#else + if (strncmp (armag, ARMAG, SARMAG) && + strncmp (armag, ARMAGB, SARMAG)) return 0; +#endif + + + + /* We are setting bfd_ardata(abfd) here, but since bfd_ardata + involves a cast, we can't do it as the left operand of assignment. */ + abfd->tdata.aout_ar_data = (struct artdata *) bfd_zalloc(abfd,sizeof (struct artdata)); + + if (bfd_ardata (abfd) == NULL) { + bfd_error = no_memory; + return 0; + } + + bfd_ardata (abfd)->first_file_filepos = SARMAG; + + if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd))) { + bfd_release(abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = NULL; + return 0; + } + + if (!BFD_SEND (abfd, _bfd_slurp_extended_name_table, (abfd))) { + bfd_release(abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = NULL; + return 0; + } + + return abfd->xvec; +} + +/* Returns false on error, true otherwise */ +static boolean +DEFUN (do_slurp_bsd_armap, (abfd), + bfd *abfd) +{ + struct areltdata *mapdata; + unsigned int counter = 0; + int *raw_armap, *rbase; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + unsigned int parsed_size; + + mapdata = snarf_ar_hdr (abfd); + if (mapdata == NULL) return false; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR)mapdata); /* Don't need it any more. */ + + raw_armap = (int *) bfd_zalloc(abfd, parsed_size); + if (raw_armap == NULL) { + bfd_error = no_memory; + return false; + } + + if (bfd_read ((PTR)raw_armap, 1, parsed_size, abfd) != parsed_size) { + bfd_error = malformed_archive; + byebye: + bfd_release (abfd, (PTR)raw_armap); + return false; + } + + ardata->symdef_count = + bfd_h_get_32(abfd, (PTR)raw_armap) / sizeof (struct symdef); + + if (ardata->symdef_count * sizeof (struct symdef) + > parsed_size - sizeof (*raw_armap)) { + /* Probably we're using the wrong byte ordering. */ + bfd_error = wrong_format; + goto byebye; + } + + ardata->cache = 0; + rbase = raw_armap+1; + ardata->symdefs = (carsym *) rbase; + stringbase = ((char *) (ardata->symdefs + ardata->symdef_count)) + 4; + + for (;counter < ardata->symdef_count; counter++) { + struct symdef *sym = ((struct symdef *) rbase) + counter; + sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase; + sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset))); + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to */ + ardata->first_file_filepos += (ardata-> first_file_filepos) %2; + /* FIXME, we should provide some way to free raw_ardata when + we are done using the strings from it. For now, it seems + to be allocated on an obstack anyway... */ + bfd_has_map (abfd) = true; + return true; +} + +/* Returns false on error, true otherwise */ +static boolean +DEFUN (do_slurp_coff_armap, (abfd), + bfd *abfd) +{ + struct areltdata *mapdata; + int *raw_armap, *rawptr; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + unsigned int stringsize; + unsigned int parsed_size; + carsym *carsyms; + unsigned int nsymz; /* Number of symbols in armap. */ + + bfd_vma (*swap) PARAMS ((bfd_byte*)); + char int_buf[sizeof(long)]; + unsigned int carsym_size, ptrsize, i; + + mapdata = snarf_ar_hdr (abfd); + if (mapdata == NULL) return false; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR)mapdata); /* Don't need it any more. */ + + if (bfd_read ((PTR)int_buf, 1, 4, abfd) != 4) { + bfd_error = malformed_archive; + return false; + } + /* It seems that all numeric information in a coff archive is always + in big endian format, nomatter the host or target. */ + swap = bfd_getb32; + nsymz = bfd_getb32((PTR)int_buf); + stringsize = parsed_size - (4 * nsymz) - 4; + +#if 1 + /* ... except that some archive formats are broken, and it may be our + fault - the i960 little endian coff sometimes has big and sometimes + little, because our tools changed. Here's a horrible hack to clean + up the crap. */ + + if (stringsize > 0xfffff) { + /* This looks dangerous, let's do it the other way around */ + nsymz = bfd_getl32((PTR)int_buf); + stringsize = parsed_size - (4 * nsymz) - 4; + swap = bfd_getl32; + } +#endif + + /* The coff armap must be read sequentially. So we construct a bsd-style + one in core all at once, for simplicity. */ + + carsym_size = (nsymz * sizeof (carsym)); + ptrsize = (4 * nsymz); + + ardata->symdefs = (carsym *) bfd_zalloc(abfd, carsym_size + stringsize + 1); + if (ardata->symdefs == NULL) { + bfd_error = no_memory; + return false; + } + carsyms = ardata->symdefs; + stringbase = ((char *) ardata->symdefs) + carsym_size; + + /* Allocate and read in the raw offsets. */ + raw_armap = (int *) bfd_alloc(abfd, ptrsize); + if (raw_armap == NULL) { + bfd_error = no_memory; + goto release_symdefs; + } + if (bfd_read ((PTR)raw_armap, 1, ptrsize, abfd) != ptrsize + || bfd_read ((PTR)stringbase, 1, stringsize, abfd) != stringsize) { + bfd_error = malformed_archive; + goto release_raw_armap; + } + + /* OK, build the carsyms */ + for (i = 0; i < nsymz; i++) { + rawptr = raw_armap + i; + carsyms->file_offset = swap((PTR)rawptr); + carsyms->name = stringbase; + while (*stringbase++) ; + carsyms++; + } + *stringbase = 0; + + ardata->symdef_count = nsymz; + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to */ + ardata->first_file_filepos += (ardata->first_file_filepos) %2; + + bfd_has_map (abfd) = true; + bfd_release (abfd, (PTR)raw_armap); + return true; + + release_raw_armap: + bfd_release (abfd, (PTR)raw_armap); + release_symdefs: + bfd_release (abfd, (PTR)(ardata)->symdefs); + return false; +} + +/* This routine can handle either coff-style or bsd-style armaps. + Returns false on error, true otherwise */ + +boolean +bfd_slurp_armap (abfd) + bfd *abfd; +{ + char nextname[17]; + int i = bfd_read ((PTR)nextname, 1, 16, abfd); + + if (i == 0) + return true; + if (i != 16) + return false; + + bfd_seek (abfd, (file_ptr) -16, SEEK_CUR); + + if (!strncmp (nextname, "__.SYMDEF ", 16)) + return do_slurp_bsd_armap (abfd); + else if (!strncmp (nextname, "/ ", 16)) + return do_slurp_coff_armap (abfd); + + bfd_has_map (abfd) = false; + return true; +} + +/* Returns false on error, true otherwise */ +/* flavor 2 of a bsd armap, similar to bfd_slurp_bsd_armap except the + header is in a slightly different order and the map name is '/'. + This flavour is used by hp300hpux. */ +boolean +bfd_slurp_bsd_armap_f2 (abfd) + bfd *abfd; +{ + struct areltdata *mapdata; + char nextname[17]; + unsigned int counter = 0; + int *raw_armap, *rbase; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + unsigned int stringsize; + int i = bfd_read ((PTR)nextname, 1, 16, abfd); + + if (i == 0) + return true; + if (i != 16) + return false; + + /* The archive has at least 16 bytes in it */ + bfd_seek (abfd, -16L, SEEK_CUR); + + if (!strncmp (nextname, "__.SYMDEF ", 16)) + return do_slurp_bsd_armap (abfd); + + if (strncmp (nextname, "/ ", 16)) + { + bfd_has_map (abfd) = false; + return true; + } + + mapdata = snarf_ar_hdr (abfd); + if (mapdata == NULL) return false; + + raw_armap = (int *) bfd_zalloc(abfd,mapdata->parsed_size); + if (raw_armap == NULL) + { + bfd_error = no_memory; + byebye: + bfd_release (abfd, (PTR)mapdata); + return false; + } + + if (bfd_read ((PTR)raw_armap, 1, mapdata->parsed_size, abfd) != + mapdata->parsed_size) + { + bfd_error = malformed_archive; + byebyebye: + bfd_release (abfd, (PTR)raw_armap); + goto byebye; + } + + ardata->symdef_count = bfd_h_get_16(abfd, (PTR)raw_armap); + + if (ardata->symdef_count * sizeof (struct symdef) + > mapdata->parsed_size - sizeof (*raw_armap)) + { + /* Probably we're using the wrong byte ordering. */ + bfd_error = wrong_format; + goto byebyebye; + } + + ardata->cache = 0; + + stringsize = bfd_h_get_32(abfd, (PTR)(((char*)raw_armap)+2)); + /* skip sym count and string sz */ + rbase = (int*)(((char*)raw_armap) + 6); + stringbase = (char *) rbase; + ardata->symdefs = (carsym *)(((char*) rbase) + stringsize); + + for (;counter < ardata->symdef_count; counter++) + { + struct symdef *sym = ((struct symdef *) ardata->symdefs) + counter; + sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase; + sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset))); + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to */ + ardata->first_file_filepos += (ardata-> first_file_filepos) %2; + /* FIXME, we should provide some way to free raw_ardata when + we are done using the strings from it. For now, it seems + to be allocated on an obstack anyway... */ + bfd_has_map (abfd) = true; + return true; +} + +/** Extended name table. + + Normally archives support only 14-character filenames. + + Intel has extended the format: longer names are stored in a special + element (the first in the archive, or second if there is an armap); + the name in the ar_hdr is replaced by <space><index into filename + element>. Index is the P.R. of an int (decimal). Data General have + extended the format by using the prefix // for the special element */ + +/* Returns false on error, true otherwise */ +boolean +_bfd_slurp_extended_name_table (abfd) + bfd *abfd; +{ + char nextname[17]; + struct areltdata *namedata; + + /* FIXME: Formatting sucks here, and in case of failure of BFD_READ, + we probably don't want to return true. */ + if (bfd_read ((PTR)nextname, 1, 16, abfd) == 16) { + + bfd_seek (abfd, (file_ptr) -16, SEEK_CUR); + + if (strncmp (nextname, "ARFILENAMES/ ", 16) != 0 && + strncmp (nextname, "// ", 16) != 0) + { + bfd_ardata (abfd)->extended_names = NULL; + return true; + } + + namedata = snarf_ar_hdr (abfd); + if (namedata == NULL) return false; + + bfd_ardata (abfd)->extended_names = bfd_zalloc(abfd,namedata->parsed_size); + if (bfd_ardata (abfd)->extended_names == NULL) { + bfd_error = no_memory; + byebye: + bfd_release (abfd, (PTR)namedata); + return false; + } + + if (bfd_read ((PTR)bfd_ardata (abfd)->extended_names, 1, + namedata->parsed_size, abfd) != namedata->parsed_size) { + bfd_error = malformed_archive; + bfd_release (abfd, (PTR)(bfd_ardata (abfd)->extended_names)); + bfd_ardata (abfd)->extended_names = NULL; + goto byebye; + } + + /* Since the archive is supposed to be printable if it contains + text, the entries in the list are newline-padded, not null + padded. In SVR4-style archives, the names also have a + trailing '/'. We'll fix both problems here.. */ + { + char *temp = bfd_ardata (abfd)->extended_names; + char *limit = temp + namedata->parsed_size; + for (; temp < limit; ++temp) + if (*temp == '\n') + temp[temp[-1] == '/' ? -1 : 0] = '\0'; + } + + /* Pad to an even boundary if you have to */ + bfd_ardata (abfd)->first_file_filepos = bfd_tell (abfd); + bfd_ardata (abfd)->first_file_filepos += + (bfd_ardata (abfd)->first_file_filepos) %2; + + /* FIXME, we can't release namedata here because it was allocated + below extended_names on the obstack... */ + /* bfd_release (abfd, namedata); */ + } + return true; +} + +#ifdef VMS + +/* Return a copy of the stuff in the filename between any :]> and a + semicolon */ +static CONST char * +DEFUN(normalize,(file), + CONST char *file) +{ + CONST char *first; + CONST char *last; + char *copy; + + first = file + strlen(file)-1; + last = first+1; + + while (first != file) + { + if (*first == ';') + last = first; + if (*first == ':' || *first == ']' ||*first == '>') + { + first++; + break; + } + first --; + } + + + copy = bfd_xmalloc(last - first + 1); + memcpy(copy, first, last-first); + copy[last-first] = 0; + + return copy; +} + +#else +static CONST char * +DEFUN (normalize, (file), + CONST char *file) +{ + CONST char * filename = strrchr(file, '/'); + + if (filename != (char *)NULL) { + filename ++; + } + else { + filename = file; + } + return filename; +} +#endif +/* Follows archive_head and produces an extended name table if necessary. + Returns (in tabloc) a pointer to an extended name table, and in tablen + the length of the table. If it makes an entry it clobbers the filename + so that the element may be written without further massage. + Returns true if it ran successfully, false if something went wrong. + A successful return may still involve a zero-length tablen! + */ +boolean +DEFUN (bfd_construct_extended_name_table, (abfd, tabloc, tablen), + bfd *abfd AND + char **tabloc AND + unsigned int *tablen) +{ + unsigned int maxname = abfd->xvec->ar_max_namelen; + unsigned int total_namelen = 0; + bfd *current; + char *strptr; + + *tablen = 0; + + /* Figure out how long the table should be */ + for (current = abfd->archive_head; current != NULL; current = current->next){ + unsigned int thislen = strlen (normalize(current->filename)); + if (thislen > maxname) total_namelen += thislen + 1; /* leave room for \n */ + } + + if (total_namelen == 0) return true; + + *tabloc = bfd_zalloc (abfd,total_namelen); + if (*tabloc == NULL) { + bfd_error = no_memory; + return false; + } + + *tablen = total_namelen; + strptr = *tabloc; + + for (current = abfd->archive_head; current != NULL; current = + current->next) { + CONST char *normal =normalize( current->filename); + unsigned int thislen = strlen (normal); + if (thislen > maxname) { + /* Works for now; may need to be re-engineered if we encounter an oddball + archive format and want to generalise this hack. */ + struct ar_hdr *hdr = arch_hdr(current); + strcpy (strptr, normal); + strptr[thislen] = '\n'; + hdr->ar_name[0] = ' '; + /* We know there will always be enough room (one of the few cases + where you may safely use sprintf). */ + sprintf ((hdr->ar_name) + 1, "%-d", (unsigned) (strptr - *tabloc)); + /* Kinda Kludgy. We should just use the returned value of sprintf + but not all implementations get this right */ + { + char *temp = hdr->ar_name +2; + for (; temp < hdr->ar_name + maxname; temp++) + if (*temp == '\0') *temp = ' '; + } + strptr += thislen + 1; + } + } + + return true; +} + +/** A couple of functions for creating ar_hdrs */ + +/* Takes a filename, returns an arelt_data for it, or NULL if it can't make one. + The filename must refer to a filename in the filesystem. + The filename field of the ar_hdr will NOT be initialized +*/ + +struct areltdata * +DEFUN(bfd_ar_hdr_from_filesystem, (abfd,filename), + bfd* abfd AND + CONST char *filename) +{ + struct stat status; + struct areltdata *ared; + struct ar_hdr *hdr; + char *temp, *temp1; + + + if (stat (filename, &status) != 0) { + bfd_error = system_call_error; + return NULL; + } + + ared = (struct areltdata *) bfd_zalloc(abfd, sizeof (struct ar_hdr) + + sizeof (struct areltdata)); + if (ared == NULL) { + bfd_error = no_memory; + return NULL; + } + hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata)); + + /* ar headers are space padded, not null padded! */ + temp = (char *) hdr; + temp1 = temp + sizeof (struct ar_hdr) - 2; + for (; temp < temp1; *(temp++) = ' '); + strncpy (hdr->ar_fmag, ARFMAG, 2); + + /* Goddamned sprintf doesn't permit MAXIMUM field lengths */ + sprintf ((hdr->ar_date), "%-12ld", status.st_mtime); + sprintf ((hdr->ar_uid), "%d", status.st_uid); + sprintf ((hdr->ar_gid), "%d", status.st_gid); + sprintf ((hdr->ar_mode), "%-8o", (unsigned) status.st_mode); + sprintf ((hdr->ar_size), "%-10ld", status.st_size); + /* Correct for a lossage in sprintf whereby it null-terminates. I cannot + understand how these C losers could design such a ramshackle bunch of + IO operations */ + temp = (char *) hdr; + temp1 = temp + sizeof (struct ar_hdr) - 2; + for (; temp < temp1; temp++) { + if (*temp == '\0') *temp = ' '; + } + strncpy (hdr->ar_fmag, ARFMAG, 2); + ared->parsed_size = status.st_size; + ared->arch_header = (char *) hdr; + + return ared; +} + +/* This is magic required by the "ar" program. Since it's + undocumented, it's undocumented. You may think that it would + take a strong stomach to write this, and it does, but it takes + even a stronger stomach to try to code around such a thing! +*/ + +struct ar_hdr * +DEFUN(bfd_special_undocumented_glue, (abfd, filename), + bfd *abfd AND + char *filename) +{ + struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename); + if (ar_elt == NULL) + return NULL; + return (struct ar_hdr *) ar_elt->arch_header; +} + + +/* Analogous to stat call */ +int +bfd_generic_stat_arch_elt (abfd, buf) + bfd *abfd; + struct stat *buf; +{ + struct ar_hdr *hdr; + char *aloser; + + if (abfd->arelt_data == NULL) { + bfd_error = invalid_operation; + return -1; + } + + hdr = arch_hdr (abfd); + +#define foo(arelt, stelt, size) \ + buf->stelt = strtol (hdr->arelt, &aloser, size); \ + if (aloser == hdr->arelt) return -1; + + foo (ar_date, st_mtime, 10); + foo (ar_uid, st_uid, 10); + foo (ar_gid, st_gid, 10); + foo (ar_mode, st_mode, 8); + + buf->st_size = arch_eltdata (abfd)->parsed_size; + + return 0; +} + +void +bfd_dont_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + CONST char *pathname; + char *arhdr; +{ + /* FIXME: This interacts unpleasantly with ar's quick-append option. + Fortunately ic960 users will never use that option. Fixing this + is very hard; fortunately I know how to do it and will do so once + intel's release is out the door. */ + + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + int length; + CONST char *filename = normalize(pathname); + int maxlen = ar_maxnamelen (abfd); + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + + if (length < maxlen) (hdr->ar_name)[length] = ar_padchar (abfd); + return; + +} + +void +bfd_bsd_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + CONST char *pathname; + char *arhdr; +{ + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + int length; + CONST char *filename = strrchr (pathname, '/'); + int maxlen = ar_maxnamelen (abfd); + + + if (filename == NULL) + filename = pathname; + else + ++filename; + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + else { + /* pathname: meet procrustes */ + memcpy (hdr->ar_name, filename, maxlen); + length = maxlen; + } + + if (length < maxlen) (hdr->ar_name)[length] = ar_padchar (abfd); +} + +/* Store name into ar header. Truncates the name to fit. + 1> strip pathname to be just the basename. + 2> if it's short enuf to fit, stuff it in. + 3> If it doesn't end with .o, truncate it to fit + 4> truncate it before the .o, append .o, stuff THAT in. +*/ + +/* This is what gnu ar does. It's better but incompatible with the bsd ar. */ +void +bfd_gnu_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + CONST char *pathname; + char *arhdr; +{ + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + int length; + CONST char *filename = strrchr (pathname, '/'); + int maxlen = ar_maxnamelen (abfd); + + if (filename == NULL) + filename = pathname; + else + ++filename; + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + else { /* pathname: meet procrustes */ + memcpy (hdr->ar_name, filename, maxlen); + if ((filename[length - 2] == '.') && (filename[length - 1] == 'o')) { + hdr->ar_name[maxlen - 2] = '.'; + hdr->ar_name[maxlen - 1] = 'o'; + } + length = maxlen; + } + + if (length < 16) (hdr->ar_name)[length] = ar_padchar (abfd); +} + + +/* The BFD is open for write and has its format set to bfd_archive */ +boolean +_bfd_write_archive_contents (arch) + bfd *arch; +{ + bfd *current; + char *etable = NULL; + unsigned int elength = 0; + boolean makemap = bfd_has_map (arch); + boolean hasobjects = false; /* if no .o's, don't bother to make a map */ + unsigned int i; + int tries; + + /* Verify the viability of all entries; if any of them live in the + filesystem (as opposed to living in an archive open for input) + then construct a fresh ar_hdr for them. + */ + for (current = arch->archive_head; current; current = current->next) { + if (bfd_write_p (current)) { + bfd_error = invalid_operation; + return false; + } + if (!current->arelt_data) { + current->arelt_data = + (PTR) bfd_ar_hdr_from_filesystem (arch, current->filename); + if (!current->arelt_data) return false; + + /* Put in the file name */ + + BFD_SEND (arch, _bfd_truncate_arname,(arch, + current->filename, + (char *) arch_hdr(current))); + + + } + + if (makemap) { /* don't bother if we won't make a map! */ + if ((bfd_check_format (current, bfd_object)) +#if 0 /* FIXME -- these are not set correctly */ + && ((bfd_get_file_flags (current) & HAS_SYMS)) +#endif + ) + hasobjects = true; + } + } + + if (!bfd_construct_extended_name_table (arch, &etable, &elength)) + return false; + + bfd_seek (arch, (file_ptr) 0, SEEK_SET); +#ifdef GNU960 + bfd_write (BFD_GNU960_ARMAG(arch), 1, SARMAG, arch); +#else + bfd_write (ARMAG, 1, SARMAG, arch); +#endif + + if (makemap && hasobjects) { + + if (compute_and_write_armap (arch, elength) != true) { + return false; + } + } + + if (elength != 0) { + struct ar_hdr hdr; + + memset ((char *)(&hdr), 0, sizeof (struct ar_hdr)); + sprintf (&(hdr.ar_name[0]), "ARFILENAMES/"); + sprintf (&(hdr.ar_size[0]), "%-10d", (int) elength); + hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n'; + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' '; + bfd_write ((char *)&hdr, 1, sizeof (struct ar_hdr), arch); + bfd_write (etable, 1, elength, arch); + if ((elength % 2) == 1) bfd_write ("\n", 1, 1, arch); + + } + + for (current = arch->archive_head; current; current = current->next) { + char buffer[DEFAULT_BUFFERSIZE]; + unsigned int remaining = arelt_size (current); + struct ar_hdr *hdr = arch_hdr(current); + /* write ar header */ + + if (bfd_write ((char *)hdr, 1, sizeof(*hdr), arch) != sizeof(*hdr)) { + syserr: + bfd_error = system_call_error; + return false; + } + if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0) goto syserr; + while (remaining) + { + unsigned int amt = DEFAULT_BUFFERSIZE; + if (amt > remaining) { + amt = remaining; + } + errno = 0; + if (bfd_read (buffer, amt, 1, current) != amt) { + if (errno) goto syserr; + /* Looks like a truncated archive. */ + bfd_error = malformed_archive; + return false; + } + if (bfd_write (buffer, amt, 1, arch) != amt) goto syserr; + remaining -= amt; + } + if ((arelt_size (current) % 2) == 1) bfd_write ("\n", 1, 1, arch); + } + + /* Verify the timestamp in the archive file. If it would + not be accepted by the linker, rewrite it until it would be. + If anything odd happens, break out and just return. + (The Berkeley linker checks the timestamp and refuses to read the + table-of-contents if it is >60 seconds less than the file's + modified-time. That painful hack requires this painful hack. */ + + tries = 1; + do { + /* FIXME! This kludge is to avoid adding a member to the xvec, + while generating a small patch for Adobe. FIXME! The + update_armap_timestamp function call should be in the xvec, + thus: + + if (bfd_update_armap_timestamp (arch) == true) break; + ^ + + Instead, we check whether in a BSD archive, and call directly. */ + + if (arch->xvec->write_armap != bsd_write_armap) + break; + if (bsd_update_armap_timestamp(arch) == true) /* FIXME!!! Vector it */ + break; + if (tries > 0) + fprintf (stderr, + "Warning: writing archive was slow: rewriting timestamp\n"); + } while (++tries < 6 ); + + return true; +} + +/* Note that the namidx for the first symbol is 0 */ + +boolean +compute_and_write_armap (arch, elength) + bfd *arch; + unsigned int elength; +{ + bfd *current; + file_ptr elt_no = 0; + struct orl *map; + int orl_max = 15000; /* fine initial default */ + int orl_count = 0; + int stridx = 0; /* string index */ + + /* Dunno if this is the best place for this info... */ + if (elength != 0) elength += sizeof (struct ar_hdr); + elength += elength %2 ; + + map = (struct orl *) bfd_zalloc (arch,orl_max * sizeof (struct orl)); + if (map == NULL) { + bfd_error = no_memory; + return false; + } + + /* Drop all the files called __.SYMDEF, we're going to make our + own */ + while (arch->archive_head && + strcmp(arch->archive_head->filename,"__.SYMDEF") == 0) + { + arch->archive_head = arch->archive_head->next; + } + /* Map over each element */ + for (current = arch->archive_head; + current != (bfd *)NULL; + current = current->next, elt_no++) + { + if ((bfd_check_format (current, bfd_object) == true) + && ((bfd_get_file_flags (current) & HAS_SYMS))) { + asymbol **syms; + unsigned int storage; + unsigned int symcount; + unsigned int src_count; + + storage = get_symtab_upper_bound (current); + if (storage != 0) { + + syms = (asymbol **) bfd_zalloc (arch,storage); + if (syms == NULL) { + bfd_error = no_memory; /* FIXME -- memory leak */ + return false; + } + symcount = bfd_canonicalize_symtab (current, syms); + + + /* Now map over all the symbols, picking out the ones we want */ + for (src_count = 0; src_count <symcount; src_count++) { + flagword flags = + (syms[src_count])->flags; + asection *sec = + syms[src_count]->section; + + if ((flags & BSF_GLOBAL || + flags & BSF_WEAK || + flags & BSF_INDIRECT || + bfd_is_com_section (sec)) + && (sec != &bfd_und_section)) { + + /* This symbol will go into the archive header */ + if (orl_count == orl_max) + { + orl_max *= 2; + map = (struct orl *) bfd_realloc (arch, (char *) map, + orl_max * sizeof (struct orl)); + } + + (map[orl_count]).name = (char **) &((syms[src_count])->name); + (map[orl_count]).pos = (file_ptr) current; + (map[orl_count]).namidx = stridx; + + stridx += strlen ((syms[src_count])->name) + 1; + ++orl_count; + } + } + } + } + } + /* OK, now we have collected all the data, let's write them out */ + if (!BFD_SEND (arch, write_armap, + (arch, elength, map, orl_count, stridx))) { + + return false; + } + + + return true; +} + +boolean +bsd_write_armap (arch, elength, map, orl_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + unsigned int orl_count; + int stridx; +{ + int padit = stridx & 1; + unsigned int ranlibsize = orl_count * sizeof (struct ranlib); + unsigned int stringsize = stridx + padit; + /* Include 8 bytes to store ranlibsize and stringsize in output. */ + unsigned int mapsize = ranlibsize + stringsize + 8; + file_ptr firstreal; + bfd *current = arch->archive_head; + bfd *last_elt = current; /* last element arch seen */ + int temp; + int count; + struct ar_hdr hdr; + struct stat statbuf; + unsigned int i; + + firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG; + + stat (arch->filename, &statbuf); + memset ((char *)(&hdr), 0, sizeof (struct ar_hdr)); + sprintf (hdr.ar_name, RANLIBMAG); + /* Remember the timestamp, to keep it holy. But fudge it a little. */ + bfd_ardata(arch)->armap_timestamp = statbuf.st_mtime + ARMAP_TIME_OFFSET; + bfd_ardata(arch)->armap_datepos = SARMAG + + offsetof(struct ar_hdr, ar_date[0]); + sprintf (hdr.ar_date, "%ld", bfd_ardata(arch)->armap_timestamp); + sprintf (hdr.ar_uid, "%d", getuid()); + sprintf (hdr.ar_gid, "%d", getgid()); + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n'; + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' '; + bfd_write ((char *)&hdr, 1, sizeof (struct ar_hdr), arch); + bfd_h_put_32(arch, (bfd_vma) ranlibsize, (PTR)&temp); + bfd_write (&temp, 1, sizeof (temp), arch); + + for (count = 0; count < orl_count; count++) { + struct symdef outs; + struct symdef *outp = &outs; + + if (((bfd *)(map[count]).pos) != last_elt) { + do { + firstreal += arelt_size (current) + sizeof (struct ar_hdr); + firstreal += firstreal % 2; + current = current->next; + } while (current != (bfd *)(map[count]).pos); + } /* if new archive element */ + + last_elt = current; + bfd_h_put_32(arch, ((map[count]).namidx),(PTR) &outs.s.string_offset); + bfd_h_put_32(arch, firstreal,(PTR) &outs.file_offset); + bfd_write ((char *)outp, 1, sizeof (outs), arch); + } + + /* now write the strings themselves */ + bfd_h_put_32(arch, stringsize, (PTR)&temp); + bfd_write ((PTR)&temp, 1, sizeof (temp), arch); + for (count = 0; count < orl_count; count++) + bfd_write (*((map[count]).name), 1, strlen (*((map[count]).name))+1, arch); + + /* The spec sez this should be a newline. But in order to be + bug-compatible for sun's ar we use a null. */ + if (padit) + bfd_write("\0",1,1,arch); + + return true; +} + + +/* At the end of archive file handling, update the timestamp in the + file, so the linker will accept it. + + Return true if the timestamp was OK, or an unusual problem happened. + Return false if we updated the timestamp. */ + +static boolean +bsd_update_armap_timestamp (arch) + bfd *arch; +{ + struct stat archstat; + struct ar_hdr hdr; + int i; + + /* Flush writes, get last-write timestamp from file, and compare it + to the timestamp IN the file. */ + bfd_flush (arch); + if (bfd_stat (arch, &archstat) == -1) { + perror ("Reading archive file mod timestamp"); + return true; /* Can't read mod time for some reason */ + } + if (archstat.st_mtime <= bfd_ardata(arch)->armap_timestamp) + return true; /* OK by the linker's rules */ + + /* Update the timestamp. */ + bfd_ardata(arch)->armap_timestamp = archstat.st_mtime + ARMAP_TIME_OFFSET; + + /* Prepare an ASCII version suitable for writing. */ + memset (hdr.ar_date, 0, sizeof (hdr.ar_date)); + sprintf (hdr.ar_date, "%ld", bfd_ardata(arch)->armap_timestamp); + for (i = 0; i < sizeof (hdr.ar_date); i++) + if (hdr.ar_date[i] == '\0') + (hdr.ar_date)[i] = ' '; + + /* Write it into the file. */ + bfd_seek (arch, bfd_ardata(arch)->armap_datepos, SEEK_SET); + if (bfd_write (hdr.ar_date, sizeof(hdr.ar_date), 1, arch) + != sizeof(hdr.ar_date)) { + perror ("Writing updated armap timestamp"); + return true; /* Some error while writing */ + } + + return false; /* We updated the timestamp successfully. */ +} + + +/* A coff armap looks like : + lARMAG + struct ar_hdr with name = '/' + number of symbols + offset of file for symbol 0 + offset of file for symbol 1 + + offset of file for symbol n-1 + symbol name 0 + symbol name 1 + + symbol name n-1 + +*/ + +boolean +coff_write_armap (arch, elength, map, symbol_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + unsigned int symbol_count; + int stridx; +{ + /* The size of the ranlib is the number of exported symbols in the + archive * the number of bytes in a int, + an int for the count */ + + unsigned int ranlibsize = (symbol_count * 4) + 4; + unsigned int stringsize = stridx; + unsigned int mapsize = stringsize + ranlibsize; + file_ptr archive_member_file_ptr; + bfd *current = arch->archive_head; + int count; + struct ar_hdr hdr; + unsigned int i; + int padit = mapsize & 1; + + if (padit) mapsize ++; + + /* work out where the first object file will go in the archive */ + archive_member_file_ptr = mapsize + elength + sizeof (struct ar_hdr) + SARMAG; + + memset ((char *)(&hdr), 0, sizeof (struct ar_hdr)); + hdr.ar_name[0] = '/'; + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + sprintf (hdr.ar_date, "%ld", (long)time (NULL)); + /* This, at least, is what Intel coff sets the values to.: */ + sprintf ((hdr.ar_uid), "%d", 0); + sprintf ((hdr.ar_gid), "%d", 0); + sprintf ((hdr.ar_mode), "%-7o",(unsigned ) 0); + hdr.ar_fmag[0] = '`'; hdr.ar_fmag[1] = '\n'; + + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' '; + + /* Write the ar header for this item and the number of symbols */ + + + bfd_write ((PTR)&hdr, 1, sizeof (struct ar_hdr), arch); + + bfd_write_bigendian_4byte_int(arch, symbol_count); + + /* Two passes, first write the file offsets for each symbol - + remembering that each offset is on a two byte boundary. */ + + /* Write out the file offset for the file associated with each + symbol, and remember to keep the offsets padded out. */ + + current = arch->archive_head; + count = 0; + while (current != (bfd *)NULL && count < symbol_count) { + /* For each symbol which is used defined in this object, write out + the object file's address in the archive */ + + while (((bfd *)(map[count]).pos) == current) { + bfd_write_bigendian_4byte_int(arch, archive_member_file_ptr); + count++; + } + /* Add size of this archive entry */ + archive_member_file_ptr += arelt_size (current) + sizeof (struct + ar_hdr); + /* remember aboout the even alignment */ + archive_member_file_ptr += archive_member_file_ptr % 2; + current = current->next; + } + + + + /* now write the strings themselves */ + for (count = 0; count < symbol_count; count++) { + bfd_write ((PTR)*((map[count]).name), + 1, + strlen (*((map[count]).name))+1, arch); + + } + /* The spec sez this should be a newline. But in order to be + bug-compatible for arc960 we use a null. */ + if (padit) + bfd_write("\0",1,1,arch); + + return true; +} diff --git a/gnu/usr.bin/gdb/bfd/archures.c b/gnu/usr.bin/gdb/bfd/archures.c new file mode 100644 index 00000000000..6b4d494d859 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/archures.c @@ -0,0 +1,737 @@ +/* BFD library support routines for architectures. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Hacked by John Gilmore and Steve Chamberlain of Cygnus Support. + + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: archures.c,v 1.1 1995/10/18 08:39:51 deraadt Exp $ +*/ + +/* + +SECTION + Architectures + + BFD's idea of an architecture is implimented in + <<archures.c>>. BFD keeps one atom in a BFD describing the + architecture of the data attached to the BFD; a pointer to a + <<bfd_arch_info_type>>. + + Pointers to structures can be requested independently of a bfd + so that an architecture's information can be interrogated + without access to an open bfd. + + The arch information is provided by each architecture package. + The set of default architectures is selected by the #define + <<SELECT_ARCHITECTURES>>. This is normally set up in the + <<config/target.mt>> file of your choice. If the name is not + defined, then all the architectures supported are included. + + When BFD starts up, all the architectures are called with an + initialize method. It is up to the architecture back end to + insert as many items into the list of architectures as it wants to; + generally this would be one for each machine and one for the + default case (an item with a machine field of 0). +*/ + +/* + +SUBSECTION + bfd_architecture + +DESCRIPTION + This enum gives the object file's CPU architecture, in a + global sense --- i.e., what processor family does it belong to? + There is another field, which indicates what processor within + the family is in use. The machine gives a number which + distingushes different versions of the architecture, + containing for example 2 and 3 for Intel i960 KA and i960 KB, + and 68020 and 68030 for Motorola 68020 and 68030. + +.enum bfd_architecture +.{ +. bfd_arch_unknown, {* File arch not known *} +. bfd_arch_obscure, {* Arch known, not one of these *} +. bfd_arch_m68k, {* Motorola 68xxx *} +. bfd_arch_vax, {* DEC Vax *} +. bfd_arch_i960, {* Intel 960 *} +. {* The order of the following is important. +. lower number indicates a machine type that +. only accepts a subset of the instructions +. available to machines with higher numbers. +. The exception is the "ca", which is +. incompatible with all other machines except +. "core". *} +. +.#define bfd_mach_i960_core 1 +.#define bfd_mach_i960_ka_sa 2 +.#define bfd_mach_i960_kb_sb 3 +.#define bfd_mach_i960_mc 4 +.#define bfd_mach_i960_xa 5 +.#define bfd_mach_i960_ca 6 +. +. bfd_arch_a29k, {* AMD 29000 *} +. bfd_arch_sparc, {* SPARC *} +. bfd_arch_mips, {* MIPS Rxxxx *} +. bfd_arch_i386, {* Intel 386 *} +. bfd_arch_we32k, {* AT&T WE32xxx *} +. bfd_arch_tahoe, {* CCI/Harris Tahoe *} +. bfd_arch_i860, {* Intel 860 *} +. bfd_arch_romp, {* IBM ROMP PC/RT *} +. bfd_arch_alliant, {* Alliant *} +. bfd_arch_convex, {* Convex *} +. bfd_arch_m88k, {* Motorola 88xxx *} +. bfd_arch_pyramid, {* Pyramid Technology *} +. bfd_arch_h8300, {* Hitachi H8/300 *} +.#define bfd_mach_h8300 1 +.#define bfd_mach_h8300h 2 +. bfd_arch_rs6000, {* IBM RS/6000 *} +. bfd_arch_hppa, {* HP PA RISC *} +. bfd_arch_z8k, {* Zilog Z8000 *} +.#define bfd_mach_z8001 1 +.#define bfd_mach_z8002 2 +. bfd_arch_h8500, {* Hitachi H8/500 *} +. bfd_arch_sh, {* Hitachi SH *} +. bfd_arch_alpha, {* Dec Alpha *} +. bfd_arch_ns32k, +. bfd_arch_last +. }; + + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* + +SUBSECTION + bfd_arch_info + +DESCRIPTION + This structure contains information on architectures for use + within BFD. + +. +.typedef struct bfd_arch_info +.{ +. int bits_per_word; +. int bits_per_address; +. int bits_per_byte; +. enum bfd_architecture arch; +. long mach; +. char *arch_name; +. CONST char *printable_name; +. unsigned int section_align_power; +. {* true if this is the default machine for the architecture *} +. boolean the_default; +. CONST struct bfd_arch_info * (*compatible) +. PARAMS ((CONST struct bfd_arch_info *a, +. CONST struct bfd_arch_info *b)); +. +. boolean (*scan) PARAMS ((CONST struct bfd_arch_info *, CONST char *)); +. {* How to disassemble an instruction, producing a printable +. representation on a specified stdio stream. This isn't +. defined for most processors at present, because of the size +. of the additional tables it would drag in, and because gdb +. wants to use a different interface. *} +. unsigned int (*disassemble) PARAMS ((bfd_vma addr, CONST char *data, +. PTR stream)); +. +. struct bfd_arch_info *next; +.} bfd_arch_info_type; +*/ + +bfd_arch_info_type *bfd_arch_info_list; + + +/* +FUNCTION + bfd_printable_name + +SYNOPSIS + CONST char *bfd_printable_name(bfd *abfd); + +DESCRIPTION + Return a printable string representing the architecture and machine + from the pointer to the arch info structure + +*/ + +CONST char * +DEFUN(bfd_printable_name, (abfd), + bfd *abfd) +{ + return abfd->arch_info->printable_name; +} + + + +/* +FUNCTION + bfd_scan_arch + +SYNOPSIS + bfd_arch_info_type *bfd_scan_arch(CONST char *); + +DESCRIPTION + This routine is provided with a string and tries to work out + if bfd supports any cpu which could be described with the name + provided. The routine returns a pointer to an arch_info + structure if a machine is found, otherwise NULL. + +*/ + +bfd_arch_info_type * +DEFUN(bfd_scan_arch,(string), + CONST char *string) +{ + struct bfd_arch_info *ap; + + /* Look through all the installed architectures */ + for (ap = bfd_arch_info_list; + ap != (bfd_arch_info_type *)NULL; + ap = ap->next) { + + if (ap->scan(ap, string)) + return ap; + } + return (bfd_arch_info_type *)NULL; +} + + + +/* +FUNCTION + bfd_arch_get_compatible + +SYNOPSIS + CONST bfd_arch_info_type *bfd_arch_get_compatible( + CONST bfd *abfd, + CONST bfd *bbfd); + +DESCRIPTION + This routine is used to determine whether two BFDs' + architectures and achine types are compatible. It calculates + the lowest common denominator between the two architectures + and machine types implied by the BFDs and returns a pointer to + an arch_info structure describing the compatible machine. +*/ + +CONST bfd_arch_info_type * +DEFUN(bfd_arch_get_compatible,(abfd, bbfd), +CONST bfd *abfd AND +CONST bfd *bbfd) + +{ + return abfd->arch_info->compatible(abfd->arch_info,bbfd->arch_info); +} + + +/* +INTERNAL_DEFINITION + bfd_default_arch_struct + +DESCRIPTION + The <<bfd_default_arch_struct>> is an item of + <<bfd_arch_info_type>> which has been initialized to a fairly + generic state. A BFD starts life by pointing to this + structure, until the correct back end has determined the real + architecture of the file. + +.extern bfd_arch_info_type bfd_default_arch_struct; + +*/ + +bfd_arch_info_type bfd_default_arch_struct = +{ + 32,32,8,bfd_arch_unknown,0,"unknown","unknown",2,true, + bfd_default_compatible, + bfd_default_scan, + 0, +}; + +/* +FUNCTION + bfd_set_arch_info + +SYNOPSIS + void bfd_set_arch_info(bfd *, bfd_arch_info_type *); + +*/ + +void DEFUN(bfd_set_arch_info,(abfd, arg), +bfd *abfd AND +bfd_arch_info_type *arg) +{ + abfd->arch_info = arg; +} + +/* +INTERNAL_FUNCTION + bfd_default_set_arch_mach + +SYNOPSIS + boolean bfd_default_set_arch_mach(bfd *abfd, + enum bfd_architecture arch, + unsigned long mach); + +DESCRIPTION + Set the architecture and machine type in a bfd. This finds the + correct pointer to structure and inserts it into the arch_info + pointer. +*/ + +boolean DEFUN(bfd_default_set_arch_mach,(abfd, arch, mach), + bfd *abfd AND + enum bfd_architecture arch AND + unsigned long mach) +{ + static struct bfd_arch_info *old_ptr = &bfd_default_arch_struct; + boolean found = false; + /* run through the table to find the one we want, we keep a little + cache to speed things up */ + if (old_ptr == 0 || arch != old_ptr->arch || mach != old_ptr->mach) { + bfd_arch_info_type *ptr; + old_ptr = (bfd_arch_info_type *)NULL; + for (ptr = bfd_arch_info_list; + ptr != (bfd_arch_info_type *)NULL; + ptr= ptr->next) { + if (ptr->arch == arch && + ((ptr->mach == mach) || (ptr->the_default && mach == 0))) { + old_ptr = ptr; + found = true; + break; + } + } + if (found==false) { + /*looked for it and it wasn't there, so put in the default */ + old_ptr = &bfd_default_arch_struct; + bfd_error = bad_value; + } + } + else { + /* it was in the cache */ + found = true; + } + + abfd->arch_info = old_ptr; + + return found; +} + + + + + +/* +FUNCTION + bfd_get_arch + +SYNOPSIS + enum bfd_architecture bfd_get_arch(bfd *abfd); + +DESCRIPTION + Returns the enumerated type which describes the supplied bfd's + architecture + +*/ + +enum bfd_architecture DEFUN(bfd_get_arch, (abfd), bfd *abfd) +{ + return abfd->arch_info->arch; +} + +/* +FUNCTION + bfd_get_mach + +SYNOPSIS + unsigned long bfd_get_mach(bfd *abfd); + +DESCRIPTION + Returns the long type which describes the supplied bfd's + machine +*/ + +unsigned long +DEFUN(bfd_get_mach, (abfd), bfd *abfd) +{ + return abfd->arch_info->mach; +} + +/* +FUNCTION + bfd_arch_bits_per_byte + +SYNOPSIS + unsigned int bfd_arch_bits_per_byte(bfd *abfd); + +DESCRIPTION + Returns the number of bits in one of the architectures bytes + +*/ + +unsigned int DEFUN(bfd_arch_bits_per_byte, (abfd), bfd *abfd) + { + return abfd->arch_info->bits_per_byte; + } + +/* +FUNCTION + bfd_arch_bits_per_address + +SYNOPSIS + unsigned int bfd_arch_bits_per_address(bfd *abfd); + +DESCRIPTION + Returns the number of bits in one of the architectures addresses +*/ + +unsigned int DEFUN(bfd_arch_bits_per_address, (abfd), bfd *abfd) + { + return abfd->arch_info->bits_per_address; + } + + +extern void bfd_a29k_arch PARAMS ((void)); +extern void bfd_alpha_arch PARAMS ((void)); +extern void bfd_h8300_arch PARAMS ((void)); +extern void bfd_h8500_arch PARAMS ((void)); +extern void bfd_hppa_arch PARAMS ((void)); +extern void bfd_i386_arch PARAMS ((void)); +extern void bfd_i960_arch PARAMS ((void)); +extern void bfd_m68k_arch PARAMS ((void)); +extern void bfd_m88k_arch PARAMS ((void)); +extern void bfd_mips_arch PARAMS ((void)); +extern void bfd_rs6000_arch PARAMS ((void)); +extern void bfd_sh_arch PARAMS ((void)); +extern void bfd_sparc_arch PARAMS ((void)); +extern void bfd_vax_arch PARAMS ((void)); +extern void bfd_we32k_arch PARAMS ((void)); +extern void bfd_z8k_arch PARAMS ((void)); +extern void bfd_ns32k_arch PARAMS ((void)); + +static void (*archures_init_table[]) PARAMS ((void)) = +{ +#ifdef SELECT_ARCHITECTURES + SELECT_ARCHITECTURES, +#else + bfd_a29k_arch, + bfd_alpha_arch, + bfd_h8300_arch, + bfd_h8500_arch, + bfd_hppa_arch, + bfd_i386_arch, + bfd_i960_arch, + bfd_m68k_arch, + bfd_m88k_arch, + bfd_mips_arch, + bfd_rs6000_arch, + bfd_sh_arch, + bfd_sparc_arch, + bfd_vax_arch, + bfd_we32k_arch, + bfd_z8k_arch, + bfd_ns32k_arch, +#endif + 0 + }; + + + +/* +INTERNAL_FUNCTION + bfd_arch_init + +SYNOPSIS + void bfd_arch_init(void); + +DESCRIPTION + This routine initializes the architecture dispatch table by + calling all installed architecture packages and getting them + to poke around. +*/ + +void +DEFUN_VOID(bfd_arch_init) +{ + void (**ptable) PARAMS ((void)); + for (ptable = archures_init_table; + *ptable ; + ptable++) + { + (*ptable)(); + } +} + + +/* +INTERNAL_FUNCTION + bfd_arch_linkin + +SYNOPSIS + void bfd_arch_linkin(bfd_arch_info_type *); + +DESCRIPTION + Link the provided arch info structure into the list +*/ + +void DEFUN(bfd_arch_linkin,(ptr), + bfd_arch_info_type *ptr) +{ + ptr->next = bfd_arch_info_list; + bfd_arch_info_list = ptr; +} + + +/* +INTERNAL_FUNCTION + bfd_default_compatible + +SYNOPSIS + CONST bfd_arch_info_type *bfd_default_compatible + (CONST bfd_arch_info_type *a, + CONST bfd_arch_info_type *b); + +DESCRIPTION + The default function for testing for compatibility. +*/ + +CONST bfd_arch_info_type * +DEFUN(bfd_default_compatible,(a,b), + CONST bfd_arch_info_type *a AND + CONST bfd_arch_info_type *b) +{ + if(a->arch != b->arch) return NULL; + + if (a->mach > b->mach) { + return a; + } + if (b->mach > a->mach) { + return b; + } + return a; +} + + +/* +INTERNAL_FUNCTION + bfd_default_scan + +SYNOPSIS + boolean bfd_default_scan(CONST struct bfd_arch_info *, CONST char *); + +DESCRIPTION + The default function for working out whether this is an + architecture hit and a machine hit. +*/ + +boolean +DEFUN(bfd_default_scan,(info, string), +CONST struct bfd_arch_info *info AND +CONST char *string) +{ + CONST char *ptr_src; + CONST char *ptr_tst; + unsigned long number; + enum bfd_architecture arch; + /* First test for an exact match */ + if (strcmp(string, info->printable_name) == 0) return true; + + /* See how much of the supplied string matches with the + architecture, eg the string m68k:68020 would match the 68k entry + up to the :, then we get left with the machine number */ + + for (ptr_src = string, + ptr_tst = info->arch_name; + *ptr_src && *ptr_tst; + ptr_src++, + ptr_tst++) + { + if (*ptr_src != *ptr_tst) break; + } + + /* Chewed up as much of the architecture as will match, skip any + colons */ + if (*ptr_src == ':') ptr_src++; + + if (*ptr_src == 0) { + /* nothing more, then only keep this one if it is the default + machine for this architecture */ + return info->the_default; + } + number = 0; + while (isdigit(*ptr_src)) { + number = number * 10 + *ptr_src - '0'; + ptr_src++; + } + + switch (number) + { + case 300: + arch = bfd_arch_h8300; + break; + + case 500: + arch = bfd_arch_h8500; + break; + + case 68010: + case 68020: + case 68030: + case 68040: + case 68332: + case 68050: + case 68000: + arch = bfd_arch_m68k; + break; + case 386: + case 80386: + case 486: + case 80486: + arch = bfd_arch_i386; + break; + case 29000: + arch = bfd_arch_a29k; + break; + + case 8000: + arch = bfd_arch_z8k; + break; + + case 32000: + arch = bfd_arch_we32k; + break; + + case 860: + case 80860: + arch = bfd_arch_i860; + break; + case 960: + case 80960: + arch = bfd_arch_i960; + break; + + case 2000: + case 3000: + case 4000: + case 4400: + arch = bfd_arch_mips; + break; + + case 6000: + arch = bfd_arch_rs6000; + break; + + default: + return false; + } + if (arch != info->arch) + return false; + + if (number != info->mach) + return false; + + return true; +} + + + + +/* +FUNCTION + bfd_get_arch_info + + +SYNOPSIS + bfd_arch_info_type * bfd_get_arch_info(bfd *); + +*/ + +bfd_arch_info_type * +DEFUN(bfd_get_arch_info,(abfd), +bfd *abfd) +{ + return abfd->arch_info; +} + + +/* +FUNCTION + bfd_lookup_arch + +SYNOPSIS + bfd_arch_info_type *bfd_lookup_arch + (enum bfd_architecture + arch, + long machine); + +DESCRIPTION + Look for the architecure info struct which matches the + arguments given. A machine of 0 will match the + machine/architecture structure which marks itself as the + default. +*/ + +bfd_arch_info_type * +DEFUN(bfd_lookup_arch,(arch, machine), +enum bfd_architecture arch AND +long machine) +{ + bfd_arch_info_type *ap; + bfd_check_init(); + for (ap = bfd_arch_info_list; + ap != (bfd_arch_info_type *)NULL; + ap = ap->next) { + if (ap->arch == arch && + ((ap->mach == machine) + || (ap->the_default && machine == 0))) { + return ap; + } + } + return (bfd_arch_info_type *)NULL; +} + + + +/* +FUNCTION + bfd_printable_arch_mach + +SYNOPSIS + CONST char * bfd_printable_arch_mach + (enum bfd_architecture arch, unsigned long machine); + +DESCRIPTION + Return a printable string representing the architecture and + machine type. + + NB. The use of this routine is depreciated. +*/ + +CONST char * +DEFUN(bfd_printable_arch_mach,(arch, machine), + enum bfd_architecture arch AND + unsigned long machine) +{ + bfd_arch_info_type *ap = bfd_lookup_arch(arch, machine); + if(ap) return ap->printable_name; + return "UNKNOWN!"; +} diff --git a/gnu/usr.bin/gdb/bfd/bfd.c b/gnu/usr.bin/gdb/bfd/bfd.c new file mode 100644 index 00000000000..f4444a5c388 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/bfd.c @@ -0,0 +1,736 @@ +/* Generic BFD library interface and support routines. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: bfd.c,v 1.1 1995/10/18 08:39:51 deraadt Exp $ +*/ + +/* +SECTION + <<typedef bfd>> + + A BFD is has type <<bfd>>; objects of this type are the + cornerstone of any application using <<libbfd>>. References + though the BFD and to data in the BFD give the entire BFD + functionality. + + Here is the struct used to define the type <<bfd>>. This + contains the major data about the file, and contains pointers + to the rest of the data. + +CODE_FRAGMENT +. +.struct _bfd +.{ +. {* The filename the application opened the BFD with. *} +. CONST char *filename; +. +. {* A pointer to the target jump table. *} +. struct bfd_target *xvec; +. +. {* To avoid dragging too many header files into every file that +. includes `<<bfd.h>>', IOSTREAM has been declared as a "char +. *", and MTIME as a "long". Their correct types, to which they +. are cast when used, are "FILE *" and "time_t". The iostream +. is the result of an fopen on the filename. *} +. char *iostream; +. +. {* Is the file being cached *} +. +. boolean cacheable; +. +. {* Marks whether there was a default target specified when the +. BFD was opened. This is used to select what matching algorithm +. to use to chose the back end. *} +. +. boolean target_defaulted; +. +. {* The caching routines use these to maintain a +. least-recently-used list of BFDs *} +. +. struct _bfd *lru_prev, *lru_next; +. +. {* When a file is closed by the caching routines, BFD retains +. state information on the file here: +. *} +. +. file_ptr where; +. +. {* and here:*} +. +. boolean opened_once; +. +. {* Set if we have a locally maintained mtime value, rather than +. getting it from the file each time: *} +. +. boolean mtime_set; +. +. {* File modified time, if mtime_set is true: *} +. +. long mtime; +. +. {* Reserved for an unimplemented file locking extension.*} +. +. int ifd; +. +. {* The format which belongs to the BFD.*} +. +. bfd_format format; +. +. {* The direction the BFD was opened with*} +. +. enum bfd_direction {no_direction = 0, +. read_direction = 1, +. write_direction = 2, +. both_direction = 3} direction; +. +. {* Format_specific flags*} +. +. flagword flags; +. +. {* Currently my_archive is tested before adding origin to +. anything. I believe that this can become always an add of +. origin, with origin set to 0 for non archive files. *} +. +. file_ptr origin; +. +. {* Remember when output has begun, to stop strange things +. happening. *} +. boolean output_has_begun; +. +. {* Pointer to linked list of sections*} +. struct sec *sections; +. +. {* The number of sections *} +. unsigned int section_count; +. +. {* Stuff only useful for object files: +. The start address. *} +. bfd_vma start_address; +. +. {* Used for input and output*} +. unsigned int symcount; +. +. {* Symbol table for output BFD*} +. struct symbol_cache_entry **outsymbols; +. +. {* Pointer to structure which contains architecture information*} +. struct bfd_arch_info *arch_info; +. +. {* Stuff only useful for archives:*} +. PTR arelt_data; +. struct _bfd *my_archive; +. struct _bfd *next; +. struct _bfd *archive_head; +. boolean has_armap; +. +. {* Used by the back end to hold private data. *} +. +. union +. { +. struct aout_data_struct *aout_data; +. struct artdata *aout_ar_data; +. struct _oasys_data *oasys_obj_data; +. struct _oasys_ar_data *oasys_ar_data; +. struct coff_tdata *coff_obj_data; +. struct ecoff_tdata *ecoff_obj_data; +. struct ieee_data_struct *ieee_data; +. struct ieee_ar_data_struct *ieee_ar_data; +. struct srec_data_struct *srec_data; +. struct tekhex_data_struct *tekhex_data; +. struct elf_obj_tdata *elf_obj_data; +. struct nlm_obj_tdata *nlm_obj_data; +. struct bout_data_struct *bout_data; +. struct sun_core_struct *sun_core_data; +. struct trad_core_struct *trad_core_data; +. struct hppa_data_struct *hppa_data; +. struct hpux_core_struct *hpux_core_data; +. struct sgi_core_struct *sgi_core_data; +. struct lynx_core_struct *lynx_core_data; +. struct osf_core_struct *osf_core_data; +. PTR any; +. } tdata; +. +. {* Used by the application to hold private data*} +. PTR usrdata; +. +. {* Where all the allocated stuff under this BFD goes *} +. struct obstack memory; +. +. {* Is this really needed in addition to usrdata? *} +. asymbol **ld_symbols; +.}; +. +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "coff/sym.h" +#include "libcoff.h" +#include "libecoff.h" +#undef obj_symbols +#include "libelf.h" + +#undef strerror +extern char *strerror(); + +/** Error handling + o - Most functions return nonzero on success (check doc for + precise semantics); 0 or NULL on error. + o - Internal errors are documented by the value of bfd_error. + If that is system_call_error then check errno. + o - The easiest way to report this to the user is to use bfd_perror. +*/ + +bfd_ec bfd_error = no_error; + +CONST char *CONST bfd_errmsgs[] = { + "No error", + "System call error", + "Invalid target", + "File in wrong format", + "Invalid operation", + "Memory exhausted", + "No symbols", + "No relocation info", + "No more archived files", + "Malformed archive", + "Symbol not found", + "File format not recognized", + "File format is ambiguous", + "Section has no contents", + "Nonrepresentable section on output", + "Symbol needs debug section which does not exist", + "Bad value", + "File truncated", + "#<Invalid error code>" + }; + +static +void +DEFUN(bfd_nonrepresentable_section,(abfd, name), + CONST bfd * CONST abfd AND + CONST char * CONST name) +{ + fprintf(stderr, + "bfd error writing file %s, format %s can't represent section %s\n", + abfd->filename, + abfd->xvec->name, + name); + exit(1); +} + +/*ARGSUSED*/ +static +void +DEFUN(bfd_undefined_symbol,(relent, seclet), + CONST arelent *relent AND + CONST struct bfd_seclet *seclet) +{ + asymbol *symbol = *(relent->sym_ptr_ptr); + fprintf(stderr, "bfd error relocating, symbol %s is undefined\n", + symbol->name); + exit(1); +} +/*ARGSUSED*/ +static +void +DEFUN(bfd_reloc_value_truncated,(relent, seclet), + CONST arelent *relent AND + struct bfd_seclet *seclet) +{ + fprintf(stderr, "bfd error relocating, value truncated\n"); + exit(1); +} +/*ARGSUSED*/ +static +void +DEFUN(bfd_reloc_is_dangerous,(relent, seclet), + CONST arelent *relent AND + CONST struct bfd_seclet *seclet) +{ + fprintf(stderr, "bfd error relocating, dangerous\n"); + exit(1); +} + +bfd_error_vector_type bfd_error_vector = + { + bfd_nonrepresentable_section , + bfd_undefined_symbol, + bfd_reloc_value_truncated, + bfd_reloc_is_dangerous, + }; + + +CONST char * +bfd_errmsg (error_tag) + bfd_ec error_tag; +{ +#ifndef errno + extern int errno; +#endif + if (error_tag == system_call_error) + return strerror (errno); + + if ((((int)error_tag <(int) no_error) || + ((int)error_tag > (int)invalid_error_code))) + error_tag = invalid_error_code;/* sanity check */ + + return bfd_errmsgs [(int)error_tag]; +} + +void +DEFUN (bfd_default_error_trap, (error_tag), + bfd_ec error_tag) +{ + fprintf(stderr, "bfd assert fail (%s)\n", bfd_errmsg(error_tag)); +} + +void (*bfd_error_trap) PARAMS ((bfd_ec)) = bfd_default_error_trap; +void (*bfd_error_nonrepresentabltrap) PARAMS ((bfd_ec)) = bfd_default_error_trap; + +void +DEFUN(bfd_perror,(message), + CONST char *message) +{ + if (bfd_error == system_call_error) + perror((char *)message); /* must be system error then... */ + else { + if (message == NULL || *message == '\0') + fprintf (stderr, "%s\n", bfd_errmsg (bfd_error)); + else + fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_error)); + } +} + + +/** Symbols */ + + +/* +FUNCTION + bfd_get_reloc_upper_bound + +SYNOPSIS + unsigned int bfd_get_reloc_upper_bound(bfd *abfd, asection *sect); + +DESCRIPTION + This function return the number of bytes required to store the + relocation information associated with section <<sect>> + attached to bfd <<abfd>> + +*/ + + +unsigned int +DEFUN(bfd_get_reloc_upper_bound,(abfd, asect), + bfd *abfd AND + sec_ptr asect) +{ + if (abfd->format != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + + return BFD_SEND (abfd, _get_reloc_upper_bound, (abfd, asect)); +} + +/* +FUNCTION + bfd_canonicalize_reloc + +SYNOPSIS + unsigned int bfd_canonicalize_reloc + (bfd *abfd, + asection *sec, + arelent **loc, + asymbol **syms); + +DESCRIPTION + This function calls the back end associated with the open + <<abfd>> and translates the external form of the relocation + information attached to <<sec>> into the internal canonical + form. The table is placed into memory at <<loc>>, which has + been preallocated, usually by a call to + <<bfd_get_reloc_upper_bound>>. + + The <<syms>> table is also needed for horrible internal magic + reasons. + + +*/ +unsigned int +DEFUN(bfd_canonicalize_reloc,(abfd, asect, location, symbols), + bfd *abfd AND + sec_ptr asect AND + arelent **location AND + asymbol **symbols) +{ + if (abfd->format != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + return BFD_SEND (abfd, _bfd_canonicalize_reloc, + (abfd, asect, location, symbols)); + } + + +/* +FUNCTION + bfd_set_file_flags + +SYNOPSIS + boolean bfd_set_file_flags(bfd *abfd, flagword flags); + +DESCRIPTION + This function attempts to set the flag word in the referenced + BFD structure to the value supplied. + + Possible errors are: + o wrong_format - The target bfd was not of object format. + o invalid_operation - The target bfd was open for reading. + o invalid_operation - + The flag word contained a bit which was not applicable to the + type of file. eg, an attempt was made to set the D_PAGED bit + on a bfd format which does not support demand paging + +*/ + +boolean +bfd_set_file_flags (abfd, flags) + bfd *abfd; + flagword flags; +{ + if (abfd->format != bfd_object) { + bfd_error = wrong_format; + return false; + } + + if (bfd_read_p (abfd)) { + bfd_error = invalid_operation; + return false; + } + + bfd_get_file_flags (abfd) = flags; + if ((flags & bfd_applicable_file_flags (abfd)) != flags) { + bfd_error = invalid_operation; + return false; + } + +return true; +} + +/* +FUNCTION + bfd_set_reloc + +SYNOPSIS + void bfd_set_reloc + (bfd *abfd, asection *sec, arelent **rel, unsigned int count) + +DESCRIPTION + This function sets the relocation pointer and count within a + section to the supplied values. + +*/ +/*ARGSUSED*/ +void +bfd_set_reloc (ignore_abfd, asect, location, count) + bfd *ignore_abfd; + sec_ptr asect; + arelent **location; + unsigned int count; +{ + asect->orelocation = location; + asect->reloc_count = count; +} + +void +bfd_assert(file, line) +char *file; +int line; +{ + fprintf(stderr, "bfd assertion fail %s:%d\n",file,line); +} + + +/* +FUNCTION + bfd_set_start_address + +DESCRIPTION + Marks the entry point of an output BFD. + +RETURNS + Returns <<true>> on success, <<false>> otherwise. + +SYNOPSIS + boolean bfd_set_start_address(bfd *, bfd_vma); +*/ + +boolean +bfd_set_start_address(abfd, vma) +bfd *abfd; +bfd_vma vma; +{ + abfd->start_address = vma; + return true; +} + + +/* +FUNCTION + The bfd_get_mtime function + +SYNOPSIS + long bfd_get_mtime(bfd *); + +DESCRIPTION + Return file modification time (as read from file system, or + from archive header for archive members). + +*/ + +long +bfd_get_mtime (abfd) + bfd *abfd; +{ + FILE *fp; + struct stat buf; + + if (abfd->mtime_set) + return abfd->mtime; + + fp = bfd_cache_lookup (abfd); + if (0 != fstat (fileno (fp), &buf)) + return 0; + + abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */ + return buf.st_mtime; +} + +/* +FUNCTION + The bfd_get_size function + +SYNOPSIS + long bfd_get_size(bfd *); + +DESCRIPTION + Return file size (as read from file system) for the file + associated with a bfd. + + Note that the initial motivation for, and use of, this routine is not + so we can get the exact size of the object the bfd applies to, since + that might not be generally possible (archive members for example?). + Although it would be ideal if someone could eventually modify + it so that such results were guaranteed. + + Instead, we want to ask questions like "is this NNN byte sized + object I'm about to try read from file offset YYY reasonable?" + As as example of where we might want to do this, some object formats + use string tables for which the first sizeof(long) bytes of the table + contain the size of the table itself, including the size bytes. + If an application tries to read what it thinks is one of these + string tables, without some way to validate the size, and for + some reason the size is wrong (byte swapping error, wrong location + for the string table, etc), the only clue is likely to be a read + error when it tries to read the table, or a "virtual memory + exhausted" error when it tries to allocated 15 bazillon bytes + of space for the 15 bazillon byte table it is about to read. + This function at least allows us to answer the quesion, "is the + size reasonable?". +*/ + +long +bfd_get_size (abfd) + bfd *abfd; +{ + FILE *fp; + struct stat buf; + + fp = bfd_cache_lookup (abfd); + if (0 != fstat (fileno (fp), &buf)) + return 0; + + return buf.st_size; +} + +/* +FUNCTION + The bfd_get_gp_size function + +SYNOPSIS + int bfd_get_gp_size(bfd *); + +DESCRIPTION + Get the maximum size of objects to be optimized using the GP + register under MIPS ECOFF. This is typically set by the -G + argument to the compiler, assembler or linker. +*/ + +int +bfd_get_gp_size (abfd) + bfd *abfd; +{ + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + return ecoff_data (abfd)->gp_size; + return 0; +} + +/* +FUNCTION + The bfd_set_gp_size function + +SYNOPSIS + void bfd_set_gp_size(bfd *, int); + +DESCRIPTION + Set the maximum size of objects to be optimized using the GP + register under ECOFF or MIPS ELF. This is typically set by + the -G argument to the compiler, assembler or linker. +*/ + +void +bfd_set_gp_size (abfd, i) + bfd *abfd; + int i; +{ + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + ecoff_data (abfd)->gp_size = i; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + elf_gp_size (abfd) = i; +} + +/* +FUNCTION + bfd_scan_vma + +DESCRIPTION + Converts, like strtoul, a numerical expression as a + string into a bfd_vma integer, and returns that integer. + (Though without as many bells and whistles as strtoul.) + The expression is assumed to be unsigned (i.e. positive). + If given a base, it is used as the base for conversion. + A base of 0 causes the function to interpret the string + in hex if a leading "0x" or "0X" is found, otherwise + in octal if a leading zero is found, otherwise in decimal. + + Overflow is not detected. + +SYNOPSIS + bfd_vma bfd_scan_vma(CONST char *string, CONST char **end, int base); +*/ + +bfd_vma +DEFUN(bfd_scan_vma,(string, end, base), + CONST char *string AND + CONST char **end AND + int base) +{ + bfd_vma value; + int digit; + + /* Let the host do it if possible. */ + if (sizeof(bfd_vma) <= sizeof(unsigned long)) + return (bfd_vma) strtoul (string, 0, base); + + /* A negative base makes no sense, and we only need to go as high as hex. */ + if ((base < 0) || (base > 16)) + return (bfd_vma) 0; + + if (base == 0) + { + if (string[0] == '0') + { + if ((string[1] == 'x') || (string[1] == 'X')) + base = 16; + /* XXX should we also allow "0b" or "0B" to set base to 2? */ + else + base = 8; + } + else + base = 10; + } + if ((base == 16) && + (string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) + string += 2; + /* XXX should we also skip over "0b" or "0B" if base is 2? */ + +/* Speed could be improved with a table like hex_value[] in gas. */ +#define HEX_VALUE(c) \ + (isxdigit(c) ? \ + (isdigit(c) ? \ + (c - '0') : \ + (10 + c - (islower(c) ? 'a' : 'A'))) : \ + 42) + + for (value = 0; (digit = HEX_VALUE(*string)) < base; string++) + { + value = value * base + digit; + } + + if (end) + *end = string; + + return value; +} + +/* +FUNCTION + stuff + +DESCRIPTION + stuff which should be documented + +.#define bfd_sizeof_headers(abfd, reloc) \ +. BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) +. +.#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ +. BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line)) +. +. {* Do these three do anything useful at all, for any back end? *} +.#define bfd_debug_info_start(abfd) \ +. BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) +. +.#define bfd_debug_info_end(abfd) \ +. BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) +. +.#define bfd_debug_info_accumulate(abfd, section) \ +. BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) +. +. +.#define bfd_stat_arch_elt(abfd, stat) \ +. BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) +. +.#define bfd_set_arch_mach(abfd, arch, mach)\ +. BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) +. +.#define bfd_get_relocated_section_contents(abfd, seclet, data, relocateable) \ +. BFD_SEND (abfd, _bfd_get_relocated_section_contents, (abfd, seclet, data, relocateable)) +. +.#define bfd_relax_section(abfd, section, symbols) \ +. BFD_SEND (abfd, _bfd_relax_section, (abfd, section, symbols)) +. +.#define bfd_seclet_link(abfd, data, relocateable) \ +. BFD_SEND (abfd, _bfd_seclet_link, (abfd, data, relocateable)) + +*/ diff --git a/gnu/usr.bin/gdb/bfd/bfd.h b/gnu/usr.bin/gdb/bfd/bfd.h new file mode 100644 index 00000000000..4efe22a42cc --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/bfd.h @@ -0,0 +1,1808 @@ +/* Main header file for the bfd library -- portable access to object files. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +** NOTE: bfd.h and bfd-in2.h are GENERATED files. Don't change them; +** instead, change bfd-in.h or the other BFD source files processed to +** generate these files. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: bfd.h,v 1.1 1995/10/18 08:39:51 deraadt Exp $ +*/ + +/* bfd.h -- The only header file required by users of the bfd library + +The bfd.h file is generated from bfd-in.h and various .c files; if you +change it, your changes will probably be lost. + +All the prototypes and definitions following the comment "THE FOLLOWING +IS EXTRACTED FROM THE SOURCE" are extracted from the source files for +BFD. If you change it, someone oneday will extract it from the source +again, and your changes will be lost. To save yourself from this bind, +change the definitions in the source in the bfd directory. Type "make +docs" and then "make headers" in that directory, and magically this file +will change to reflect your changes. + +If you don't have the tools to perform the extraction, then you are +safe from someone on your system trampling over your header files. +You should still maintain the equivalence between the source and this +file though; every change you make to the .c file should be reflected +here. */ + +#ifndef __BFD_H_SEEN__ +#define __BFD_H_SEEN__ + +#include "ansidecl.h" +#include "obstack.h" + +#define BFD_VERSION "2.2" + +#define BFD_ARCH_SIZE 32 + +#if BFD_ARCH_SIZE >= 64 +#define BFD64 +#endif + +#ifndef INLINE +#if __GNUC__ >= 2 +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +/* 64-bit type definition (if any) from bfd's sysdep.h goes here */ + + +/* forward declaration */ +typedef struct _bfd bfd; + +/* To squelch erroneous compiler warnings ("illegal pointer + combination") from the SVR3 compiler, we would like to typedef + boolean to int (it doesn't like functions which return boolean. + Making sure they are never implicitly declared to return int + doesn't seem to help). But this file is not configured based on + the host. */ +/* General rules: functions which are boolean return true on success + and false on failure (unless they're a predicate). -- bfd.doc */ +/* I'm sure this is going to break something and someone is going to + force me to change it. */ +/* typedef enum boolean {false, true} boolean; */ +/* Yup, SVR4 has a "typedef enum boolean" in <sys/types.h> -fnf */ +typedef enum bfd_boolean {false, true} boolean; + +/* A pointer to a position in a file. */ +/* FIXME: This should be using off_t from <sys/types.h>. + For now, try to avoid breaking stuff by not including <sys/types.h> here. + This will break on systems with 64-bit file offsets (e.g. 4.4BSD). + Probably the best long-term answer is to avoid using file_ptr AND off_t + in this header file, and to handle this in the BFD implementation + rather than in its interface. */ +/* typedef off_t file_ptr; */ +typedef long int file_ptr; + +/* Support for different sizes of target format ints and addresses. If the + host implements 64-bit values, it defines HOST_64_BIT to be the appropriate + type. Otherwise, this code will fall back on gcc's "long long" type if gcc + is being used. HOST_64_BIT must be defined in such a way as to be a valid + type name by itself or with "unsigned" prefixed. It should be a signed + type by itself. + + If neither is the case, then compilation will fail if 64-bit targets are + requested. If you don't request any 64-bit targets, you should be safe. */ + +#ifdef BFD64 + +#if defined (__GNUC__) && !defined (HOST_64_BIT) +#define HOST_64_BIT long long +typedef HOST_64_BIT int64_type; +typedef unsigned HOST_64_BIT uint64_type; +#endif + +#if !defined (uint64_type) && defined (__GNUC__) +#define uint64_type unsigned long long +#define int64_type long long +#define uint64_typeLOW(x) (unsigned long)(((x) & 0xffffffff)) +#define uint64_typeHIGH(x) (unsigned long)(((x) >> 32) & 0xffffffff) +#endif + +typedef unsigned HOST_64_BIT bfd_vma; +typedef HOST_64_BIT bfd_signed_vma; +typedef unsigned HOST_64_BIT bfd_size_type; +typedef unsigned HOST_64_BIT symvalue; +#define fprintf_vma(s,x) \ + fprintf(s,"%08x%08x", uint64_typeHIGH(x), uint64_typeLOW(x)) +#define sprintf_vma(s,x) \ + sprintf(s,"%08x%08x", uint64_typeHIGH(x), uint64_typeLOW(x)) +#else /* not BFD64 */ + +/* Represent a target address. Also used as a generic unsigned type + which is guaranteed to be big enough to hold any arithmetic types + we need to deal with. */ +typedef unsigned long bfd_vma; + +/* A generic signed type which is guaranteed to be big enough to hold any + arithmetic types we need to deal with. Can be assumed to be compatible + with bfd_vma in the same way that signed and unsigned ints are compatible + (as parameters, in assignment, etc). */ +typedef long bfd_signed_vma; + +typedef unsigned long symvalue; +typedef unsigned long bfd_size_type; + +/* Print a bfd_vma x on stream s. */ +#define fprintf_vma(s,x) fprintf(s, "%08lx", x) +#define sprintf_vma(s,x) sprintf(s, "%08lx", x) +#endif /* not BFD64 */ +#define printf_vma(x) fprintf_vma(stdout,x) + +typedef unsigned int flagword; /* 32 bits of flags */ + +/** File formats */ + +typedef enum bfd_format { + bfd_unknown = 0, /* file format is unknown */ + bfd_object, /* linker/assember/compiler output */ + bfd_archive, /* object archive file */ + bfd_core, /* core dump */ + bfd_type_end} /* marks the end; don't use it! */ + bfd_format; + +/* Object file flag values */ +#define NO_FLAGS 0x00 +#define HAS_RELOC 0x01 +#define EXEC_P 0x02 +#define HAS_LINENO 0x04 +#define HAS_DEBUG 0x08 +#define HAS_SYMS 0x10 +#define HAS_LOCALS 0x20 +#define DYNAMIC 0x40 +#define WP_TEXT 0x80 +#define D_PAGED 0x100 +#define BFD_IS_RELAXABLE 0x200 + +/* symbols and relocation */ + +typedef unsigned long symindex; + +#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) + +typedef enum bfd_symclass { + bfd_symclass_unknown = 0, + bfd_symclass_fcommon, /* fortran common symbols */ + bfd_symclass_global, /* global symbol, what a surprise */ + bfd_symclass_debugger, /* some debugger symbol */ + bfd_symclass_undefined /* none known */ + } symclass; + + +/* general purpose part of a symbol; + target specific parts will be found in libcoff.h, liba.out.h etc */ + + +#define bfd_get_section(x) ((x)->section) +#define bfd_get_output_section(x) ((x)->section->output_section) +#define bfd_set_section(x,y) ((x)->section) = (y) +#define bfd_asymbol_base(x) ((x)->section->vma) +#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) +#define bfd_asymbol_name(x) ((x)->name) +/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ +#define bfd_asymbol_bfd(x) ((x)->the_bfd) +#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour) + +/* This is a type pun with struct ranlib on purpose! */ +typedef struct carsym { + char *name; + file_ptr file_offset; /* look here to find the file */ +} carsym; /* to make these you call a carsymogen */ + + +/* Used in generating armaps. Perhaps just a forward definition would do? */ +struct orl { /* output ranlib */ + char **name; /* symbol name */ + file_ptr pos; /* bfd* or file position */ + int namidx; /* index into string table */ +}; + + + +/* Linenumber stuff */ +typedef struct lineno_cache_entry { + unsigned int line_number; /* Linenumber from start of function*/ + union { + struct symbol_cache_entry *sym; /* Function name */ + unsigned long offset; /* Offset into section */ + } u; +} alent; + +/* object and core file sections */ + + +#define align_power(addr, align) \ + ( ((addr) + ((1<<(align))-1)) & (-1 << (align))) + +typedef struct sec *sec_ptr; + +#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0) +#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0) +#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0) +#define bfd_section_name(bfd, ptr) ((ptr)->name) +#define bfd_section_size(bfd, ptr) (bfd_get_section_size_before_reloc(ptr)) +#define bfd_section_vma(bfd, ptr) ((ptr)->vma) +#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) +#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0) +#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata) + +#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) + +#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma= (val)), ((ptr)->user_set_vma = true), true) +#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),true) +#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),true) + +typedef struct stat stat_type; + +/** Error handling */ + +typedef enum bfd_error { + no_error = 0, system_call_error, invalid_target, + wrong_format, invalid_operation, no_memory, + no_symbols, no_relocation_info, + no_more_archived_files, malformed_archive, + symbol_not_found, file_not_recognized, + file_ambiguously_recognized, no_contents, + bfd_error_nonrepresentable_section, + no_debug_section, bad_value, + + /* An input file is shorter than expected. */ + file_truncated, + + invalid_error_code} bfd_ec; + +extern bfd_ec bfd_error; +struct reloc_cache_entry; +struct bfd_seclet; + + +typedef struct bfd_error_vector { + void (* nonrepresentable_section ) PARAMS ((CONST bfd *CONST abfd, + CONST char *CONST name)); + void (* undefined_symbol) PARAMS ((CONST struct reloc_cache_entry *rel, + CONST struct bfd_seclet *sec)); + void (* reloc_value_truncated) PARAMS ((CONST struct + reloc_cache_entry *rel, + struct bfd_seclet *sec)); + + void (* reloc_dangerous) PARAMS ((CONST struct reloc_cache_entry *rel, + CONST struct bfd_seclet *sec)); + +} bfd_error_vector_type; + +CONST char *bfd_errmsg PARAMS ((bfd_ec error_tag)); +void bfd_perror PARAMS ((CONST char *message)); + + +typedef enum bfd_print_symbol +{ + bfd_print_symbol_name, + bfd_print_symbol_more, + bfd_print_symbol_all +} bfd_print_symbol_type; + + +/* Information about a symbol that nm needs. */ + +typedef struct _symbol_info +{ + symvalue value; + char type; /* */ + CONST char *name; /* Symbol name. */ + char stab_other; /* Unused. */ + short stab_desc; /* Info for N_TYPE. */ + CONST char *stab_name; +} symbol_info; + +/* The code that implements targets can initialize a jump table with this + macro. It must name all its routines the same way (a prefix plus + the standard routine suffix), or it must #define the routines that + are not so named, before calling JUMP_TABLE in the initializer. */ + +/* Semi-portable string concatenation in cpp. + The CAT4 hack is to avoid a problem with some strict ANSI C preprocessors. + The problem is, "32_" is not a valid preprocessing token, and we don't + want extra underscores (e.g., "nlm_32_"). The XCAT2 macro will cause the + inner CAT macros to be evaluated first, producing still-valid pp-tokens. + Then the final concatenation can be done. (Sigh.) */ +#ifndef CAT +#ifdef SABER +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define CAT4(a,b,c,d) a##b##c##d +#else +#ifdef __STDC__ +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#define XCAT2(a,b) CAT(a,b) +#define CAT4(a,b,c,d) XCAT2(CAT(a,b),CAT(c,d)) +#else +#define CAT(a,b) a/**/b +#define CAT3(a,b,c) a/**/b/**/c +#define CAT4(a,b,c,d) a/**/b/**/c/**/d +#endif +#endif +#endif + +#define JUMP_TABLE(NAME)\ +CAT(NAME,_core_file_failing_command),\ +CAT(NAME,_core_file_failing_signal),\ +CAT(NAME,_core_file_matches_executable_p),\ +CAT(NAME,_slurp_armap),\ +CAT(NAME,_slurp_extended_name_table),\ +CAT(NAME,_truncate_arname),\ +CAT(NAME,_write_armap),\ +CAT(NAME,_close_and_cleanup),\ +CAT(NAME,_set_section_contents),\ +CAT(NAME,_get_section_contents),\ +CAT(NAME,_new_section_hook),\ +CAT(NAME,_get_symtab_upper_bound),\ +CAT(NAME,_get_symtab),\ +CAT(NAME,_get_reloc_upper_bound),\ +CAT(NAME,_canonicalize_reloc),\ +CAT(NAME,_make_empty_symbol),\ +CAT(NAME,_print_symbol),\ +CAT(NAME,_get_symbol_info),\ +CAT(NAME,_get_lineno),\ +CAT(NAME,_set_arch_mach),\ +CAT(NAME,_openr_next_archived_file),\ +CAT(NAME,_find_nearest_line),\ +CAT(NAME,_generic_stat_arch_elt),\ +CAT(NAME,_sizeof_headers),\ +CAT(NAME,_bfd_debug_info_start),\ +CAT(NAME,_bfd_debug_info_end),\ +CAT(NAME,_bfd_debug_info_accumulate),\ +CAT(NAME,_bfd_get_relocated_section_contents),\ +CAT(NAME,_bfd_relax_section),\ +CAT(NAME,_bfd_seclet_link),\ +CAT(NAME,_bfd_reloc_type_lookup),\ +CAT(NAME,_bfd_make_debug_symbol) + +#define COFF_SWAP_TABLE (PTR) &bfd_coff_std_swap_table + + +/* User program access to BFD facilities */ + +/* Cast from const char * to char * so that caller can assign to + a char * without a warning. */ +#define bfd_get_filename(abfd) ((char *) (abfd)->filename) +#define bfd_get_format(abfd) ((abfd)->format) +#define bfd_get_target(abfd) ((abfd)->xvec->name) +#define bfd_get_file_flags(abfd) ((abfd)->flags) +#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) +#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) +#define bfd_my_archive(abfd) ((abfd)->my_archive) +#define bfd_has_map(abfd) ((abfd)->has_armap) + +#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) +#define bfd_usrdata(abfd) ((abfd)->usrdata) + +#define bfd_get_start_address(abfd) ((abfd)->start_address) +#define bfd_get_symcount(abfd) ((abfd)->symcount) +#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) +#define bfd_count_sections(abfd) ((abfd)->section_count) + +#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) + +/* Byte swapping routines. */ + +bfd_vma bfd_getb64 PARAMS ((unsigned char *)); +bfd_vma bfd_getl64 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getb_signed_64 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getl_signed_64 PARAMS ((unsigned char *)); +bfd_vma bfd_getb32 PARAMS ((unsigned char *)); +bfd_vma bfd_getl32 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getb_signed_32 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getl_signed_32 PARAMS ((unsigned char *)); +bfd_vma bfd_getb16 PARAMS ((unsigned char *)); +bfd_vma bfd_getl16 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getb_signed_16 PARAMS ((unsigned char *)); +bfd_signed_vma bfd_getl_signed_16 PARAMS ((unsigned char *)); +void bfd_putb64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl64 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl32 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb16 PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl16 PARAMS ((bfd_vma, unsigned char *)); + +/* And more from the source. */ +void +bfd_init PARAMS ((void)); + +bfd * +bfd_openr PARAMS ((CONST char *filename, CONST char*target)); + +bfd * +bfd_fdopenr PARAMS ((CONST char *filename, CONST char *target, int fd)); + +bfd * +bfd_openw PARAMS ((CONST char *filename, CONST char *target)); + +boolean +bfd_close PARAMS ((bfd *)); + +boolean +bfd_close_all_done PARAMS ((bfd *)); + +bfd_size_type +bfd_alloc_size PARAMS ((bfd *abfd)); + +bfd * +bfd_create PARAMS ((CONST char *filename, bfd *templ)); + + + /* Byte swapping macros for user section data. */ + +#define bfd_put_8(abfd, val, ptr) \ + (*((unsigned char *)(ptr)) = (unsigned char)val) +#define bfd_put_signed_8 \ + bfd_put_8 +#define bfd_get_8(abfd, ptr) \ + (*(unsigned char *)(ptr)) +#define bfd_get_signed_8(abfd, ptr) \ + ((*(unsigned char *)(ptr) ^ 0x80) - 0x80) + +#define bfd_put_16(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx16, ((val),(ptr))) +#define bfd_put_signed_16 \ + bfd_put_16 +#define bfd_get_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx16, (ptr)) +#define bfd_get_signed_16(abfd, ptr) \ + BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) + +#define bfd_put_32(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx32, ((val),(ptr))) +#define bfd_put_signed_32 \ + bfd_put_32 +#define bfd_get_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx32, (ptr)) +#define bfd_get_signed_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_32, (ptr)) + +#define bfd_put_64(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx64, ((val), (ptr))) +#define bfd_put_signed_64 \ + bfd_put_64 +#define bfd_get_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx64, (ptr)) +#define bfd_get_signed_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_64, (ptr)) + + + /* Byte swapping macros for file header data. */ + +#define bfd_h_put_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_put_signed_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_get_8(abfd, ptr) \ + bfd_get_8 (abfd, ptr) +#define bfd_h_get_signed_8(abfd, ptr) \ + bfd_get_signed_8 (abfd, ptr) + +#define bfd_h_put_16(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx16,(val,ptr)) +#define bfd_h_put_signed_16 \ + bfd_h_put_16 +#define bfd_h_get_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx16,(ptr)) +#define bfd_h_get_signed_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr)) + +#define bfd_h_put_32(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx32,(val,ptr)) +#define bfd_h_put_signed_32 \ + bfd_h_put_32 +#define bfd_h_get_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx32,(ptr)) +#define bfd_h_get_signed_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr)) + +#define bfd_h_put_64(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_h_putx64,(val, ptr)) +#define bfd_h_put_signed_64 \ + bfd_h_put_64 +#define bfd_h_get_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx64,(ptr)) +#define bfd_h_get_signed_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr)) + +typedef struct sec +{ + /* The name of the section, the name isn't a copy, the pointer is + the same as that passed to bfd_make_section. */ + + CONST char *name; + + /* Which section is it 0.nth */ + + int index; + + /* The next section in the list belonging to the BFD, or NULL. */ + + struct sec *next; + + /* The field flags contains attributes of the section. Some of + flags are read in from the object file, and some are + synthesized from other information. */ + + flagword flags; + +#define SEC_NO_FLAGS 0x000 + + /* Tells the OS to allocate space for this section when loaded. + This would clear for a section containing debug information + only. */ +#define SEC_ALLOC 0x001 + + /* Tells the OS to load the section from the file when loading. + This would be clear for a .bss section */ +#define SEC_LOAD 0x002 + + /* The section contains data still to be relocated, so there will + be some relocation information too. */ +#define SEC_RELOC 0x004 + +#if 0 /* Obsolete ? */ +#define SEC_BALIGN 0x008 +#endif + + /* A signal to the OS that the section contains read only + data. */ +#define SEC_READONLY 0x010 + + /* The section contains code only. */ +#define SEC_CODE 0x020 + + /* The section contains data only. */ +#define SEC_DATA 0x040 + + /* The section will reside in ROM. */ +#define SEC_ROM 0x080 + + /* The section contains constructor information. This section + type is used by the linker to create lists of constructors and + destructors used by <<g++>>. When a back end sees a symbol + which should be used in a constructor list, it creates a new + section for the type of name (eg <<__CTOR_LIST__>>), attaches + the symbol to it and builds a relocation. To build the lists + of constructors, all the linker has to do is catenate all the + sections called <<__CTOR_LIST__>> and relocte the data + contained within - exactly the operations it would peform on + standard data. */ +#define SEC_CONSTRUCTOR 0x100 + + /* The section is a constuctor, and should be placed at the + end of the text, data, or bss section(?). */ +#define SEC_CONSTRUCTOR_TEXT 0x1100 +#define SEC_CONSTRUCTOR_DATA 0x2100 +#define SEC_CONSTRUCTOR_BSS 0x3100 + + /* The section has contents - a data section could be + <<SEC_ALLOC>> | <<SEC_HAS_CONTENTS>>, a debug section could be + <<SEC_HAS_CONTENTS>> */ +#define SEC_HAS_CONTENTS 0x200 + + /* An instruction to the linker not to output sections + containing this flag even if they have information which + would normally be written. */ +#define SEC_NEVER_LOAD 0x400 + + /* The section is a shared library section. The linker must leave + these completely alone, as the vma and size are used when + the executable is loaded. */ +#define SEC_SHARED_LIBRARY 0x800 + + /* The section is a common section (symbols may be defined + multiple times, the value of a symbol is the amount of + space it requires, and the largest symbol value is the one + used). Most targets have exactly one of these (which we + translate to bfd_com_section), but ECOFF has two. */ +#define SEC_IS_COMMON 0x8000 + + /* The section contains only debugging information. For + example, this is set for ELF .debug and .stab sections. + strip tests this flag to see if a section can be + discarded. */ +#define SEC_DEBUGGING 0x10000 + + /* End of section flags. */ + + /* The virtual memory address of the section - where it will be + at run time. The symbols are relocated against this. The + user_set_vma flag is maintained by bfd; if it's not set, the + backend can assign addresses (for example, in <<a.out>>, where + the default address for <<.data>> is dependent on the specific + target and various flags). */ + + bfd_vma vma; + boolean user_set_vma; + + /* The load address of the section - where it would be in a + rom image, really only used for writing section header + information. */ + + bfd_vma lma; + + /* The size of the section in bytes, as it will be output. + contains a value even if the section has no contents (eg, the + size of <<.bss>>). This will be filled in after relocation */ + + bfd_size_type _cooked_size; + + /* The size on disk of the section in bytes originally. Normally this + value is the same as the size, but if some relaxing has + been done, then this value will be bigger. */ + + bfd_size_type _raw_size; + + /* If this section is going to be output, then this value is the + offset into the output section of the first byte in the input + section. Eg, if this was going to start at the 100th byte in + the output section, this value would be 100. */ + + bfd_vma output_offset; + + /* The output section through which to map on output. */ + + struct sec *output_section; + + /* The alignment requirement of the section, as an exponent - eg + 3 aligns to 2^3 (or 8) */ + + unsigned int alignment_power; + + /* If an input section, a pointer to a vector of relocation + records for the data in this section. */ + + struct reloc_cache_entry *relocation; + + /* If an output section, a pointer to a vector of pointers to + relocation records for the data in this section. */ + + struct reloc_cache_entry **orelocation; + + /* The number of relocation records in one of the above */ + + unsigned reloc_count; + + /* Information below is back end specific - and not always used + or updated. */ + + /* File position of section data */ + + file_ptr filepos; + + /* File position of relocation info */ + + file_ptr rel_filepos; + + /* File position of line data */ + + file_ptr line_filepos; + + /* Pointer to data for applications */ + + PTR userdata; + + struct lang_output_section *otheruserdata; + + /* Attached line number information */ + + alent *lineno; + + /* Number of line number records */ + + unsigned int lineno_count; + + /* When a section is being output, this value changes as more + linenumbers are written out */ + + file_ptr moving_line_filepos; + + /* what the section number is in the target world */ + + int target_index; + + PTR used_by_bfd; + + /* If this is a constructor section then here is a list of the + relocations created to relocate items within it. */ + + struct relent_chain *constructor_chain; + + /* The BFD which owns the section. */ + + bfd *owner; + + boolean reloc_done; + /* A symbol which points at this section only */ + struct symbol_cache_entry *symbol; + struct symbol_cache_entry **symbol_ptr_ptr; + + struct bfd_seclet *seclets_head; + struct bfd_seclet *seclets_tail; +} asection ; + + + /* These sections are global, and are managed by BFD. The application + and target back end are not permitted to change the values in + these sections. */ +#define BFD_ABS_SECTION_NAME "*ABS*" +#define BFD_UND_SECTION_NAME "*UND*" +#define BFD_COM_SECTION_NAME "*COM*" +#define BFD_IND_SECTION_NAME "*IND*" + + /* the absolute section */ +extern asection bfd_abs_section; + /* Pointer to the undefined section */ +extern asection bfd_und_section; + /* Pointer to the common section */ +extern asection bfd_com_section; + /* Pointer to the indirect section */ +extern asection bfd_ind_section; + +extern struct symbol_cache_entry *bfd_abs_symbol; +extern struct symbol_cache_entry *bfd_com_symbol; +extern struct symbol_cache_entry *bfd_und_symbol; +extern struct symbol_cache_entry *bfd_ind_symbol; +#define bfd_get_section_size_before_reloc(section) \ + (section->reloc_done ? (abort(),1): (section)->_raw_size) +#define bfd_get_section_size_after_reloc(section) \ + ((section->reloc_done) ? (section)->_cooked_size: (abort(),1)) +asection * +bfd_get_section_by_name PARAMS ((bfd *abfd, CONST char *name)); + +asection * +bfd_make_section_old_way PARAMS ((bfd *, CONST char *name)); + +asection * +bfd_make_section_anyway PARAMS ((bfd *, CONST char *name)); + +asection * +bfd_make_section PARAMS ((bfd *, CONST char *name)); + +boolean +bfd_set_section_flags PARAMS ((bfd *, asection *, flagword)); + +void +bfd_map_over_sections PARAMS ((bfd *abfd, + void (*func)(bfd *abfd, + asection *sect, + PTR obj), + PTR obj)); + +boolean +bfd_set_section_size PARAMS ((bfd *, asection *, bfd_size_type val)); + +boolean +bfd_set_section_contents + PARAMS ((bfd *abfd, + asection *section, + PTR data, + file_ptr offset, + bfd_size_type count)); + +boolean +bfd_get_section_contents + PARAMS ((bfd *abfd, asection *section, PTR location, + file_ptr offset, bfd_size_type count)); + +enum bfd_architecture +{ + bfd_arch_unknown, /* File arch not known */ + bfd_arch_obscure, /* Arch known, not one of these */ + bfd_arch_m68k, /* Motorola 68xxx */ + bfd_arch_vax, /* DEC Vax */ + bfd_arch_i960, /* Intel 960 */ + /* The order of the following is important. + lower number indicates a machine type that + only accepts a subset of the instructions + available to machines with higher numbers. + The exception is the "ca", which is + incompatible with all other machines except + "core". */ + +#define bfd_mach_i960_core 1 +#define bfd_mach_i960_ka_sa 2 +#define bfd_mach_i960_kb_sb 3 +#define bfd_mach_i960_mc 4 +#define bfd_mach_i960_xa 5 +#define bfd_mach_i960_ca 6 + + bfd_arch_a29k, /* AMD 29000 */ + bfd_arch_sparc, /* SPARC */ + bfd_arch_mips, /* MIPS Rxxxx */ + bfd_arch_i386, /* Intel 386 */ + bfd_arch_we32k, /* AT&T WE32xxx */ + bfd_arch_tahoe, /* CCI/Harris Tahoe */ + bfd_arch_i860, /* Intel 860 */ + bfd_arch_romp, /* IBM ROMP PC/RT */ + bfd_arch_alliant, /* Alliant */ + bfd_arch_convex, /* Convex */ + bfd_arch_m88k, /* Motorola 88xxx */ + bfd_arch_pyramid, /* Pyramid Technology */ + bfd_arch_h8300, /* Hitachi H8/300 */ +#define bfd_mach_h8300 1 +#define bfd_mach_h8300h 2 + bfd_arch_rs6000, /* IBM RS/6000 */ + bfd_arch_hppa, /* HP PA RISC */ + bfd_arch_z8k, /* Zilog Z8000 */ +#define bfd_mach_z8001 1 +#define bfd_mach_z8002 2 + bfd_arch_h8500, /* Hitachi H8/500 */ + bfd_arch_sh, /* Hitachi SH */ + bfd_arch_alpha, /* Dec Alpha */ + bfd_arch_ns32k, /* National Semiconductor Series 32000 */ + bfd_arch_last + }; + +typedef struct bfd_arch_info +{ + int bits_per_word; + int bits_per_address; + int bits_per_byte; + enum bfd_architecture arch; + long mach; + char *arch_name; + CONST char *printable_name; + unsigned int section_align_power; + /* true if this is the default machine for the architecture */ + boolean the_default; + CONST struct bfd_arch_info * (*compatible) + PARAMS ((CONST struct bfd_arch_info *a, + CONST struct bfd_arch_info *b)); + + boolean (*scan) PARAMS ((CONST struct bfd_arch_info *, CONST char *)); + /* How to disassemble an instruction, producing a printable + representation on a specified stdio stream. This isn't + defined for most processors at present, because of the size + of the additional tables it would drag in, and because gdb + wants to use a different interface. */ + unsigned int (*disassemble) PARAMS ((bfd_vma addr, CONST char *data, + PTR stream)); + + struct bfd_arch_info *next; +} bfd_arch_info_type; +CONST char * +bfd_printable_name PARAMS ((bfd *abfd)); + +bfd_arch_info_type * +bfd_scan_arch PARAMS ((CONST char *)); + +CONST bfd_arch_info_type * +bfd_arch_get_compatible PARAMS (( + CONST bfd *abfd, + CONST bfd *bbfd)); + +void +bfd_set_arch_info PARAMS ((bfd *, bfd_arch_info_type *)); + +enum bfd_architecture +bfd_get_arch PARAMS ((bfd *abfd)); + +unsigned long +bfd_get_mach PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_byte PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_address PARAMS ((bfd *abfd)); + +bfd_arch_info_type * +bfd_get_arch_info PARAMS ((bfd *)); + +bfd_arch_info_type * +bfd_lookup_arch + PARAMS ((enum bfd_architecture + arch, + long machine)); + +CONST char * +bfd_printable_arch_mach + PARAMS ((enum bfd_architecture arch, unsigned long machine)); + +typedef enum bfd_reloc_status +{ + /* No errors detected */ + bfd_reloc_ok, + + /* The relocation was performed, but there was an overflow. */ + bfd_reloc_overflow, + + /* The address to relocate was not within the section supplied. */ + bfd_reloc_outofrange, + + /* Used by special functions */ + bfd_reloc_continue, + + /* Unused */ + bfd_reloc_notsupported, + + /* Unsupported relocation size requested. */ + bfd_reloc_other, + + /* The symbol to relocate against was undefined. */ + bfd_reloc_undefined, + + /* The relocation was performed, but may not be ok - presently + generated only when linking i960 coff files with i960 b.out + symbols. */ + bfd_reloc_dangerous + } + bfd_reloc_status_type; + + +typedef struct reloc_cache_entry +{ + /* A pointer into the canonical table of pointers */ + struct symbol_cache_entry **sym_ptr_ptr; + + /* offset in section */ + bfd_size_type address; + + /* addend for relocation value */ + bfd_vma addend; + + /* Pointer to how to perform the required relocation */ + CONST struct reloc_howto_struct *howto; + +} arelent; +enum complain_overflow +{ + /* Do not complain on overflow. */ + complain_overflow_dont, + + /* Complain if the bitfield overflows, whether it is considered + as signed or unsigned. */ + complain_overflow_bitfield, + + /* Complain if the value overflows when considered as signed + number. */ + complain_overflow_signed, + + /* Complain if the value overflows when considered as an + unsigned number. */ + complain_overflow_unsigned +}; + +typedef CONST struct reloc_howto_struct +{ + /* The type field has mainly a documetary use - the back end can + to what it wants with it, though the normally the back end's + external idea of what a reloc number would be would be stored + in this field. For example, the a PC relative word relocation + in a coff environment would have the type 023 - because that's + what the outside world calls a R_PCRWORD reloc. */ + unsigned int type; + + /* The value the final relocation is shifted right by. This drops + unwanted data from the relocation. */ + unsigned int rightshift; + + /* The size of the item to be relocated. This is *not* a + power-of-two measure. + 0 : one byte + 1 : two bytes + 2 : four bytes + 3 : nothing done (unless special_function is nonzero) + 4 : eight bytes + -2 : two bytes, result should be subtracted from the + data instead of added + There is currently no trivial way to extract a "number of + bytes" from a howto pointer. */ + int size; + + /* The number of bits in the item to be relocated. This is used + when doing overflow checking. */ + unsigned int bitsize; + + /* Notes that the relocation is relative to the location in the + data section of the addend. The relocation function will + subtract from the relocation value the address of the location + being relocated. */ + boolean pc_relative; + + /* The bit position of the reloc value in the destination. + The relocated value is left shifted by this amount. */ + unsigned int bitpos; + + /* What type of overflow error should be checked for when + relocating. */ + enum complain_overflow complain_on_overflow; + + /* If this field is non null, then the supplied function is + called rather than the normal function. This allows really + strange relocation methods to be accomodated (e.g., i960 callj + instructions). */ + bfd_reloc_status_type (*special_function) + PARAMS ((bfd *abfd, + arelent *reloc_entry, + struct symbol_cache_entry *symbol, + PTR data, + asection *input_section, + bfd *output_bfd)); + + /* The textual name of the relocation type. */ + char *name; + + /* When performing a partial link, some formats must modify the + relocations rather than the data - this flag signals this.*/ + boolean partial_inplace; + + /* The src_mask is used to select what parts of the read in data + are to be used in the relocation sum. E.g., if this was an 8 bit + bit of data which we read and relocated, this would be + 0x000000ff. When we have relocs which have an addend, such as + sun4 extended relocs, the value in the offset part of a + relocating field is garbage so we never use it. In this case + the mask would be 0x00000000. */ + bfd_vma src_mask; + + /* The dst_mask is what parts of the instruction are replaced + into the instruction. In most cases src_mask == dst_mask, + except in the above special case, where dst_mask would be + 0x000000ff, and src_mask would be 0x00000000. */ + bfd_vma dst_mask; + + /* When some formats create PC relative instructions, they leave + the value of the pc of the place being relocated in the offset + slot of the instruction, so that a PC relative relocation can + be made just by adding in an ordinary offset (e.g., sun3 a.out). + Some formats leave the displacement part of an instruction + empty (e.g., m88k bcs), this flag signals the fact.*/ + boolean pcrel_offset; + +} reloc_howto_type; +#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ + {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC} +#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN) + +#define HOWTO_PREPARE(relocation, symbol) \ + { \ + if (symbol != (asymbol *)NULL) { \ + if (bfd_is_com_section (symbol->section)) { \ + relocation = 0; \ + } \ + else { \ + relocation = symbol->value; \ + } \ + } \ +} +typedef unsigned char bfd_byte; + +typedef struct relent_chain { + arelent relent; + struct relent_chain *next; +} arelent_chain; +bfd_reloc_status_type + +bfd_perform_relocation + PARAMS ((bfd * abfd, + arelent *reloc_entry, + PTR data, + asection *input_section, + bfd *output_bfd)); + +typedef enum bfd_reloc_code_real +{ + /* Basic absolute relocations */ + BFD_RELOC_64, + BFD_RELOC_32, + BFD_RELOC_16, + BFD_RELOC_8, + + /* PC-relative relocations */ + BFD_RELOC_64_PCREL, + BFD_RELOC_32_PCREL, + BFD_RELOC_24_PCREL, /* used by i960 */ + BFD_RELOC_16_PCREL, + BFD_RELOC_8_PCREL, + + /* Linkage-table relative */ + BFD_RELOC_32_BASEREL, + BFD_RELOC_16_BASEREL, + BFD_RELOC_8_BASEREL, + + /* The type of reloc used to build a contructor table - at the moment + probably a 32 bit wide abs address, but the cpu can choose. */ + BFD_RELOC_CTOR, + + /* 8 bits wide, but used to form an address like 0xffnn */ + BFD_RELOC_8_FFnn, + + /* 32-bit pc-relative, shifted right 2 bits (i.e., 30-bit + word displacement, e.g. for SPARC) */ + BFD_RELOC_32_PCREL_S2, + + /* High 22 bits of 32-bit value, placed into lower 22 bits of + target word; simple reloc. */ + BFD_RELOC_HI22, + /* Low 10 bits. */ + BFD_RELOC_LO10, + + /* Reloc types used for i960/b.out. */ + BFD_RELOC_I960_CALLJ, + + /* now for the sparc/elf codes */ + BFD_RELOC_NONE, /* actually used */ + BFD_RELOC_SPARC_WDISP22, + BFD_RELOC_SPARC22, + BFD_RELOC_SPARC13, + BFD_RELOC_SPARC_GOT10, + BFD_RELOC_SPARC_GOT13, + BFD_RELOC_SPARC_GOT22, + BFD_RELOC_SPARC_PC10, + BFD_RELOC_SPARC_PC22, + BFD_RELOC_SPARC_WPLT30, + BFD_RELOC_SPARC_COPY, + BFD_RELOC_SPARC_GLOB_DAT, + BFD_RELOC_SPARC_JMP_SLOT, + BFD_RELOC_SPARC_RELATIVE, + BFD_RELOC_SPARC_UA32, + + /* these are a.out specific? */ + BFD_RELOC_SPARC_BASE13, + BFD_RELOC_SPARC_BASE22, + + + /* Bits 27..2 of the relocation address shifted right 2 bits; + simple reloc otherwise. */ + BFD_RELOC_MIPS_JMP, + + /* signed 16-bit pc-relative, shifted right 2 bits (e.g. for MIPS) */ + BFD_RELOC_16_PCREL_S2, + + /* High 16 bits of 32-bit value; simple reloc. */ + BFD_RELOC_HI16, + /* High 16 bits of 32-bit value but the low 16 bits will be sign + extended and added to form the final result. If the low 16 + bits form a negative number, we need to add one to the high value + to compensate for the borrow when the low bits are added. */ + BFD_RELOC_HI16_S, + /* Low 16 bits. */ + BFD_RELOC_LO16, + + /* 16 bit relocation relative to the global pointer. */ + BFD_RELOC_MIPS_GPREL, + + /* These are, so far, specific to HPPA processors. I'm not sure that some + don't duplicate other reloc types, such as BFD_RELOC_32 and _32_PCREL. + Also, many more were in the list I got that don't fit in well in the + model BFD uses, so I've omitted them for now. If we do make this reloc + type get used for code that really does implement the funky reloc types, + they'll have to be added to this list. */ + BFD_RELOC_HPPA_32, + BFD_RELOC_HPPA_11, + BFD_RELOC_HPPA_14, + BFD_RELOC_HPPA_17, + + BFD_RELOC_HPPA_L21, + BFD_RELOC_HPPA_R11, + BFD_RELOC_HPPA_R14, + BFD_RELOC_HPPA_R17, + BFD_RELOC_HPPA_LS21, + BFD_RELOC_HPPA_RS11, + BFD_RELOC_HPPA_RS14, + BFD_RELOC_HPPA_RS17, + BFD_RELOC_HPPA_LD21, + BFD_RELOC_HPPA_RD11, + BFD_RELOC_HPPA_RD14, + BFD_RELOC_HPPA_RD17, + BFD_RELOC_HPPA_LR21, + BFD_RELOC_HPPA_RR14, + BFD_RELOC_HPPA_RR17, + + BFD_RELOC_HPPA_GOTOFF_11, + BFD_RELOC_HPPA_GOTOFF_14, + BFD_RELOC_HPPA_GOTOFF_L21, + BFD_RELOC_HPPA_GOTOFF_R11, + BFD_RELOC_HPPA_GOTOFF_R14, + BFD_RELOC_HPPA_GOTOFF_LS21, + BFD_RELOC_HPPA_GOTOFF_RS11, + BFD_RELOC_HPPA_GOTOFF_RS14, + BFD_RELOC_HPPA_GOTOFF_LD21, + BFD_RELOC_HPPA_GOTOFF_RD11, + BFD_RELOC_HPPA_GOTOFF_RD14, + BFD_RELOC_HPPA_GOTOFF_LR21, + BFD_RELOC_HPPA_GOTOFF_RR14, + + BFD_RELOC_HPPA_DLT_32, + BFD_RELOC_HPPA_DLT_11, + BFD_RELOC_HPPA_DLT_14, + BFD_RELOC_HPPA_DLT_L21, + BFD_RELOC_HPPA_DLT_R11, + BFD_RELOC_HPPA_DLT_R14, + + BFD_RELOC_HPPA_ABS_CALL_11, + BFD_RELOC_HPPA_ABS_CALL_14, + BFD_RELOC_HPPA_ABS_CALL_17, + BFD_RELOC_HPPA_ABS_CALL_L21, + BFD_RELOC_HPPA_ABS_CALL_R11, + BFD_RELOC_HPPA_ABS_CALL_R14, + BFD_RELOC_HPPA_ABS_CALL_R17, + BFD_RELOC_HPPA_ABS_CALL_LS21, + BFD_RELOC_HPPA_ABS_CALL_RS11, + BFD_RELOC_HPPA_ABS_CALL_RS14, + BFD_RELOC_HPPA_ABS_CALL_RS17, + BFD_RELOC_HPPA_ABS_CALL_LD21, + BFD_RELOC_HPPA_ABS_CALL_RD11, + BFD_RELOC_HPPA_ABS_CALL_RD14, + BFD_RELOC_HPPA_ABS_CALL_RD17, + BFD_RELOC_HPPA_ABS_CALL_LR21, + BFD_RELOC_HPPA_ABS_CALL_RR14, + BFD_RELOC_HPPA_ABS_CALL_RR17, + + BFD_RELOC_HPPA_PCREL_CALL_11, + BFD_RELOC_HPPA_PCREL_CALL_12, + BFD_RELOC_HPPA_PCREL_CALL_14, + BFD_RELOC_HPPA_PCREL_CALL_17, + BFD_RELOC_HPPA_PCREL_CALL_L21, + BFD_RELOC_HPPA_PCREL_CALL_R11, + BFD_RELOC_HPPA_PCREL_CALL_R14, + BFD_RELOC_HPPA_PCREL_CALL_R17, + BFD_RELOC_HPPA_PCREL_CALL_LS21, + BFD_RELOC_HPPA_PCREL_CALL_RS11, + BFD_RELOC_HPPA_PCREL_CALL_RS14, + BFD_RELOC_HPPA_PCREL_CALL_RS17, + BFD_RELOC_HPPA_PCREL_CALL_LD21, + BFD_RELOC_HPPA_PCREL_CALL_RD11, + BFD_RELOC_HPPA_PCREL_CALL_RD14, + BFD_RELOC_HPPA_PCREL_CALL_RD17, + BFD_RELOC_HPPA_PCREL_CALL_LR21, + BFD_RELOC_HPPA_PCREL_CALL_RR14, + BFD_RELOC_HPPA_PCREL_CALL_RR17, + + BFD_RELOC_HPPA_PLABEL_32, + BFD_RELOC_HPPA_PLABEL_11, + BFD_RELOC_HPPA_PLABEL_14, + BFD_RELOC_HPPA_PLABEL_L21, + BFD_RELOC_HPPA_PLABEL_R11, + BFD_RELOC_HPPA_PLABEL_R14, + + BFD_RELOC_HPPA_UNWIND_ENTRY, + BFD_RELOC_HPPA_UNWIND_ENTRIES, + + /* i386/elf relocations */ + BFD_RELOC_386_GOT32, + BFD_RELOC_386_PLT32, + BFD_RELOC_386_COPY, + BFD_RELOC_386_GLOB_DAT, + BFD_RELOC_386_JUMP_SLOT, + BFD_RELOC_386_RELATIVE, + BFD_RELOC_386_GOTOFF, + BFD_RELOC_386_GOTPC, + + /* this must be the highest numeric value */ + BFD_RELOC_UNUSED + } bfd_reloc_code_real_type; +CONST struct reloc_howto_struct * + +bfd_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); + + +typedef struct symbol_cache_entry +{ + /* A pointer to the BFD which owns the symbol. This information + is necessary so that a back end can work out what additional + information (invisible to the application writer) is carried + with the symbol. + + This field is *almost* redundant, since you can use section->owner + instead, except that some symbols point to the global sections + bfd_{abs,com,und}_section. This could be fixed by making + these globals be per-bfd (or per-target-flavor). FIXME. */ + + struct _bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */ + + /* The text of the symbol. The name is left alone, and not copied - the + application may not alter it. */ + CONST char *name; + + /* The value of the symbol. This really should be a union of a + numeric value with a pointer, since some flags indicate that + a pointer to another symbol is stored here. */ + symvalue value; + + /* Attributes of a symbol: */ + +#define BSF_NO_FLAGS 0x00 + + /* The symbol has local scope; <<static>> in <<C>>. The value + is the offset into the section of the data. */ +#define BSF_LOCAL 0x01 + + /* The symbol has global scope; initialized data in <<C>>. The + value is the offset into the section of the data. */ +#define BSF_GLOBAL 0x02 + + /* The symbol has global scope, and is exported. The value is + the offset into the section of the data. */ +#define BSF_EXPORT BSF_GLOBAL /* no real difference */ + + /* A normal C symbol would be one of: + <<BSF_LOCAL>>, <<BSF_FORT_COMM>>, <<BSF_UNDEFINED>> or + <<BSF_GLOBAL>> */ + + /* The symbol is a debugging record. The value has an arbitary + meaning. */ +#define BSF_DEBUGGING 0x08 + + /* The symbol denotes a function entry point. Used in ELF, + perhaps others someday. */ +#define BSF_FUNCTION 0x10 + + /* Used by the linker. */ +#define BSF_KEEP 0x20 +#define BSF_KEEP_G 0x40 + + /* A weak global symbol, overridable without warnings by + a regular global symbol of the same name. */ +#define BSF_WEAK 0x80 + + /* This symbol was created to point to a section, e.g. ELF's + STT_SECTION symbols. */ +#define BSF_SECTION_SYM 0x100 + + /* The symbol used to be a common symbol, but now it is + allocated. */ +#define BSF_OLD_COMMON 0x200 + + /* The default value for common data. */ +#define BFD_FORT_COMM_DEFAULT_VALUE 0 + + /* In some files the type of a symbol sometimes alters its + location in an output file - ie in coff a <<ISFCN>> symbol + which is also <<C_EXT>> symbol appears where it was + declared and not at the end of a section. This bit is set + by the target BFD part to convey this information. */ + +#define BSF_NOT_AT_END 0x400 + + /* Signal that the symbol is the label of constructor section. */ +#define BSF_CONSTRUCTOR 0x800 + + /* Signal that the symbol is a warning symbol. If the symbol + is a warning symbol, then the value field (I know this is + tacky) will point to the asymbol which when referenced will + cause the warning. */ +#define BSF_WARNING 0x1000 + + /* Signal that the symbol is indirect. The value of the symbol + is a pointer to an undefined asymbol which contains the + name to use instead. */ +#define BSF_INDIRECT 0x2000 + + /* BSF_FILE marks symbols that contain a file name. This is used + for ELF STT_FILE symbols. */ +#define BSF_FILE 0x4000 + + flagword flags; + + /* A pointer to the section to which this symbol is + relative. This will always be non NULL, there are special + sections for undefined and absolute symbols */ + struct sec *section; + + /* Back end special data. This is being phased out in favour + of making this a union. */ + PTR udata; + +} asymbol; +#define get_symtab_upper_bound(abfd) \ + BFD_SEND (abfd, _get_symtab_upper_bound, (abfd)) +#define bfd_canonicalize_symtab(abfd, location) \ + BFD_SEND (abfd, _bfd_canonicalize_symtab,\ + (abfd, location)) +boolean +bfd_set_symtab PARAMS ((bfd *, asymbol **, unsigned int )); + +void +bfd_print_symbol_vandf PARAMS ((PTR file, asymbol *symbol)); + +#define bfd_make_empty_symbol(abfd) \ + BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) +#define bfd_make_debug_symbol(abfd,ptr,size) \ + BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) +int +bfd_decode_symclass PARAMS ((asymbol *symbol)); + +void +bfd_symbol_info PARAMS ((asymbol *symbol, symbol_info *ret)); + +struct _bfd +{ + /* The filename the application opened the BFD with. */ + CONST char *filename; + + /* A pointer to the target jump table. */ + struct bfd_target *xvec; + + /* To avoid dragging too many header files into every file that + includes `<<bfd.h>>', IOSTREAM has been declared as a "char + *", and MTIME as a "long". Their correct types, to which they + are cast when used, are "FILE *" and "time_t". The iostream + is the result of an fopen on the filename. */ + char *iostream; + + /* Is the file being cached */ + + boolean cacheable; + + /* Marks whether there was a default target specified when the + BFD was opened. This is used to select what matching algorithm + to use to chose the back end. */ + + boolean target_defaulted; + + /* The caching routines use these to maintain a + least-recently-used list of BFDs */ + + struct _bfd *lru_prev, *lru_next; + + /* When a file is closed by the caching routines, BFD retains + state information on the file here: + */ + + file_ptr where; + + /* and here:*/ + + boolean opened_once; + + /* Set if we have a locally maintained mtime value, rather than + getting it from the file each time: */ + + boolean mtime_set; + + /* File modified time, if mtime_set is true: */ + + long mtime; + + /* Reserved for an unimplemented file locking extension.*/ + + int ifd; + + /* The format which belongs to the BFD.*/ + + bfd_format format; + + /* The direction the BFD was opened with*/ + + enum bfd_direction {no_direction = 0, + read_direction = 1, + write_direction = 2, + both_direction = 3} direction; + + /* Format_specific flags*/ + + flagword flags; + + /* Currently my_archive is tested before adding origin to + anything. I believe that this can become always an add of + origin, with origin set to 0 for non archive files. */ + + file_ptr origin; + + /* Remember when output has begun, to stop strange things + happening. */ + boolean output_has_begun; + + /* Pointer to linked list of sections*/ + struct sec *sections; + + /* The number of sections */ + unsigned int section_count; + + /* Stuff only useful for object files: + The start address. */ + bfd_vma start_address; + + /* Used for input and output*/ + unsigned int symcount; + + /* Symbol table for output BFD*/ + struct symbol_cache_entry **outsymbols; + + /* Pointer to structure which contains architecture information*/ + struct bfd_arch_info *arch_info; + + /* Stuff only useful for archives:*/ + PTR arelt_data; + struct _bfd *my_archive; + struct _bfd *next; + struct _bfd *archive_head; + boolean has_armap; + + /* Used by the back end to hold private data. */ + + union + { + struct aout_data_struct *aout_data; + struct artdata *aout_ar_data; + struct _oasys_data *oasys_obj_data; + struct _oasys_ar_data *oasys_ar_data; + struct coff_tdata *coff_obj_data; + struct ecoff_tdata *ecoff_obj_data; + struct ieee_data_struct *ieee_data; + struct ieee_ar_data_struct *ieee_ar_data; + struct srec_data_struct *srec_data; + struct tekhex_data_struct *tekhex_data; + struct elf_obj_tdata *elf_obj_data; + struct nlm_obj_tdata *nlm_obj_data; + struct bout_data_struct *bout_data; + struct sun_core_struct *sun_core_data; + struct trad_core_struct *trad_core_data; + struct hppa_data_struct *hppa_data; + struct hpux_core_struct *hpux_core_data; + struct sgi_core_struct *sgi_core_data; + struct lynx_core_struct *lynx_core_data; + struct osf_core_struct *osf_core_data; + struct netbsd_core_struct *netbsd_core_data; + PTR any; + } tdata; + + /* Used by the application to hold private data*/ + PTR usrdata; + + /* Where all the allocated stuff under this BFD goes */ + struct obstack memory; + + /* Is this really needed in addition to usrdata? */ + asymbol **ld_symbols; +}; + +unsigned int +bfd_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect)); + +unsigned int +bfd_canonicalize_reloc + PARAMS ((bfd *abfd, + asection *sec, + arelent **loc, + asymbol **syms)); + +boolean +bfd_set_file_flags PARAMS ((bfd *abfd, flagword flags)); + +void +bfd_set_reloc + PARAMS ((bfd *abfd, asection *sec, arelent **rel, unsigned int count) + + ); + +boolean +bfd_set_start_address PARAMS ((bfd *, bfd_vma)); + +long +bfd_get_mtime PARAMS ((bfd *)); + +long +bfd_get_size PARAMS ((bfd *)); + +int +bfd_get_gp_size PARAMS ((bfd *)); + +void +bfd_set_gp_size PARAMS ((bfd *, int)); + +bfd_vma +bfd_scan_vma PARAMS ((CONST char *string, CONST char **end, int base)); + +#define bfd_sizeof_headers(abfd, reloc) \ + BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) + +#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ + BFD_SEND (abfd, _bfd_find_nearest_line, (abfd, sec, syms, off, file, func, line)) + + /* Do these three do anything useful at all, for any back end? */ +#define bfd_debug_info_start(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) + +#define bfd_debug_info_end(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) + +#define bfd_debug_info_accumulate(abfd, section) \ + BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) + + +#define bfd_stat_arch_elt(abfd, stat) \ + BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) + +#define bfd_set_arch_mach(abfd, arch, mach)\ + BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) + +#define bfd_get_relocated_section_contents(abfd, seclet, data, relocateable) \ + BFD_SEND (abfd, _bfd_get_relocated_section_contents, (abfd, seclet, data, relocateable)) + +#define bfd_relax_section(abfd, section, symbols) \ + BFD_SEND (abfd, _bfd_relax_section, (abfd, section, symbols)) + +#define bfd_seclet_link(abfd, data, relocateable) \ + BFD_SEND (abfd, _bfd_seclet_link, (abfd, data, relocateable)) +symindex +bfd_get_next_mapent PARAMS ((bfd *, symindex previous, carsym ** sym)); + +boolean +bfd_set_archive_head PARAMS ((bfd *output, bfd *new_head)); + +bfd * +bfd_get_elt_at_index PARAMS ((bfd * archive, int index)); + +bfd* +bfd_openr_next_archived_file PARAMS ((bfd *archive, bfd *previous)); + +CONST char * +bfd_core_file_failing_command PARAMS ((bfd *)); + +int +bfd_core_file_failing_signal PARAMS ((bfd *)); + +boolean +core_file_matches_executable_p + PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +#define BFD_SEND(bfd, message, arglist) \ + ((*((bfd)->xvec->message)) arglist) +#define BFD_SEND_FMT(bfd, message, arglist) \ + (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) +typedef struct bfd_target +{ + char *name; + enum target_flavour { + bfd_target_unknown_flavour, + bfd_target_aout_flavour, + bfd_target_coff_flavour, + bfd_target_ecoff_flavour, + bfd_target_elf_flavour, + bfd_target_ieee_flavour, + bfd_target_nlm_flavour, + bfd_target_oasys_flavour, + bfd_target_tekhex_flavour, + bfd_target_srec_flavour, + bfd_target_hppa_flavour} flavour; + boolean byteorder_big_p; + boolean header_byteorder_big_p; + flagword object_flags; + flagword section_flags; + char symbol_leading_char; + char ar_pad_char; + unsigned short ar_max_namelen; + unsigned int align_power_min; + bfd_vma (*bfd_getx64) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((bfd_byte *)); + void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx32) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((bfd_byte *)); + void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx16) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((bfd_byte *)); + void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx64) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((bfd_byte *)); + void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx32) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((bfd_byte *)); + void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx16) PARAMS ((bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((bfd_byte *)); + void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *)); + struct bfd_target * (*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *)); + boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *)); + boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *)); + char * (*_core_file_failing_command) PARAMS ((bfd *)); + int (*_core_file_failing_signal) PARAMS ((bfd *)); + boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *)); + boolean (*_bfd_slurp_armap) PARAMS ((bfd *)); + boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *)); + void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *)); + boolean (*write_armap) PARAMS ((bfd *arch, + unsigned int elength, + struct orl *map, + unsigned int orl_count, + int stridx)); + boolean (*_close_and_cleanup) PARAMS ((bfd *)); + boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); + boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, bfd_size_type)); + boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr)); + unsigned int (*_get_symtab_upper_bound) PARAMS ((bfd *)); + unsigned int (*_bfd_canonicalize_symtab) PARAMS ((bfd *, + struct symbol_cache_entry **)); + unsigned int (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr)); + unsigned int (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **, + struct symbol_cache_entry **)); + struct symbol_cache_entry * + (*_bfd_make_empty_symbol) PARAMS ((bfd *)); + void (*_bfd_print_symbol) PARAMS ((bfd *, PTR, + struct symbol_cache_entry *, + bfd_print_symbol_type)); +#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e)) + void (*_bfd_get_symbol_info) PARAMS ((bfd *, + struct symbol_cache_entry *, + symbol_info *)); +#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e)) + alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *)); + + boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); + + bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev)); + + boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd, + struct sec *section, struct symbol_cache_entry **symbols, + bfd_vma offset, CONST char **file, CONST char **func, + unsigned int *line)); + + int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *)); + + int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean)); + + void (*_bfd_debug_info_start) PARAMS ((bfd *)); + void (*_bfd_debug_info_end) PARAMS ((bfd *)); + void (*_bfd_debug_info_accumulate) PARAMS ((bfd *, struct sec *)); + + bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *, + struct bfd_seclet *, bfd_byte *data, + boolean relocateable)); + + boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *, + struct symbol_cache_entry **)); + + boolean (*_bfd_seclet_link) PARAMS ((bfd *, PTR data, + boolean relocateable)); + /* See documentation on reloc types. */ + CONST struct reloc_howto_struct * + (*reloc_type_lookup) PARAMS ((bfd *abfd, + bfd_reloc_code_real_type code)); + + /* Back-door to allow format-aware applications to create debug symbols + while using BFD for everything else. Currently used by the assembler + when creating COFF files. */ + asymbol * (*_bfd_make_debug_symbol) PARAMS (( + bfd *abfd, + void *ptr, + unsigned long size)); + PTR backend_data; +} bfd_target; +bfd_target * +bfd_find_target PARAMS ((CONST char *, bfd *)); + +CONST char ** +bfd_target_list PARAMS ((void)); + +boolean +bfd_check_format PARAMS ((bfd *abfd, bfd_format format)); + +boolean +bfd_set_format PARAMS ((bfd *, bfd_format)); + +CONST char * +bfd_format_string PARAMS ((bfd_format)); + +#endif diff --git a/gnu/usr.bin/gdb/bfd/cache.c b/gnu/usr.bin/gdb/bfd/cache.c new file mode 100644 index 00000000000..0d65ef3566f --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/cache.c @@ -0,0 +1,314 @@ +/* BFD library -- caching of file descriptors. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com). + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: cache.c,v 1.1 1995/10/18 08:39:52 deraadt Exp $ +*/ + +/* +SECTION + File Caching + + The file caching mechanism is embedded within BFD and allows + the application to open as many BFDs as it wants without + regard to the underlying operating system's file descriptor + limit (often as low as 20 open files). The module in + <<cache.c>> maintains a least recently used list of + <<BFD_CACHE_MAX_OPEN>> files, and exports the name + <<bfd_cache_lookup>> which runs around and makes sure that + the required BFD is open. If not, then it chooses a file to + close, closes it and opens the one wanted, returning its file + handle. + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* +INTERNAL_FUNCTION + BFD_CACHE_MAX_OPEN macro + +DESCRIPTION + The maximum number of files which the cache will keep open at + one time. + +.#define BFD_CACHE_MAX_OPEN 10 + +*/ + + +static boolean +bfd_cache_delete PARAMS ((bfd *)); + +/* Number of bfds on the chain. All such bfds have their file open; + if it closed, they get snipd()d from the chain. */ + +static int open_files; + +static bfd *cache_sentinel; /* Chain of BFDs with active fds we've + opened */ + +/* +INTERNAL_FUNCTION + bfd_last_cache + +SYNOPSIS + extern bfd *bfd_last_cache; + +DESCRIPTION + Zero, or a pointer to the topmost BFD on the chain. This is + used by the <<bfd_cache_lookup>> macro in @file{libbfd.h} to + determine when it can avoid a function call. +*/ + +bfd *bfd_last_cache; + +/* + * INTERNAL_FUNCTION + * bfd_cache_lookup + * + * DESCRIPTION + * Checks to see if the required BFD is the same as the last one + * looked up. If so then it can use the iostream in the BFD with + * impunity, since it can't have changed since the last lookup, + * otherwise it has to perform the complicated lookup function + * + * .#define bfd_cache_lookup(x) \ + * . ((x)==bfd_last_cache? \ + * . (FILE*)(bfd_last_cache->iostream): \ + * . bfd_cache_lookup_worker(x)) + * + * + */ + +static void +DEFUN_VOID(close_one) +{ + bfd *kill = cache_sentinel; + if (kill == 0) /* Nothing in the cache */ + return ; + + /* We can only close files that want to play this game. */ + while (!kill->cacheable) { + kill = kill->lru_prev; + if (kill == cache_sentinel) /* Nobody wants to play */ + return ; + } + + kill->where = ftell((FILE *)(kill->iostream)); + (void) bfd_cache_delete(kill); +} + +/* Cuts the BFD abfd out of the chain in the cache */ +static void +DEFUN(snip,(abfd), + bfd *abfd) +{ + abfd->lru_prev->lru_next = abfd->lru_next; + abfd->lru_next->lru_prev = abfd->lru_prev; + if (cache_sentinel == abfd) cache_sentinel = (bfd *)NULL; +} + +static boolean +DEFUN(bfd_cache_delete,(abfd), + bfd *abfd) +{ + boolean ret; + + if (fclose ((FILE *)(abfd->iostream)) == 0) + ret = true; + else + { + ret = false; + bfd_error = system_call_error; + } + snip (abfd); + abfd->iostream = NULL; + open_files--; + bfd_last_cache = 0; + return ret; +} + +static bfd * +DEFUN(insert,(x,y), + bfd *x AND + bfd *y) +{ + if (y) { + x->lru_next = y; + x->lru_prev = y->lru_prev; + y->lru_prev->lru_next = x; + y->lru_prev = x; + + } + else { + x->lru_prev = x; + x->lru_next = x; + } + return x; +} + + +/* Initialize a BFD by putting it on the cache LRU. */ + +void +DEFUN(bfd_cache_init,(abfd), + bfd *abfd) +{ + if (open_files >= BFD_CACHE_MAX_OPEN) + close_one (); + cache_sentinel = insert(abfd, cache_sentinel); + ++open_files; +} + + +/* +INTERNAL_FUNCTION + bfd_cache_close + +DESCRIPTION + Remove the BFD from the cache. If the attached file is open, + then close it too. + +SYNOPSIS + boolean bfd_cache_close (bfd *); + +RETURNS + <<false>> is returned if closing the file fails, <<true>> is + returned if all is well. +*/ +boolean +DEFUN(bfd_cache_close,(abfd), + bfd *abfd) +{ + /* If this file is open then remove from the chain */ + if (abfd->iostream) + { + return bfd_cache_delete(abfd); + } + else + { + return true; + } +} + +/* +INTERNAL_FUNCTION + bfd_open_file + +DESCRIPTION + Call the OS to open a file for this BFD. Returns the FILE * + (possibly null) that results from this operation. Sets up the + BFD so that future accesses know the file is open. If the FILE + * returned is null, then there is won't have been put in the + cache, so it won't have to be removed from it. + +SYNOPSIS + FILE* bfd_open_file(bfd *); +*/ + +FILE * +DEFUN(bfd_open_file, (abfd), + bfd *abfd) +{ + abfd->cacheable = true; /* Allow it to be closed later. */ + + if(open_files >= BFD_CACHE_MAX_OPEN) { + close_one(); + } + + switch (abfd->direction) { + case read_direction: + case no_direction: + abfd->iostream = (char *) fopen(abfd->filename, FOPEN_RB); + break; + case both_direction: + case write_direction: + if (abfd->opened_once == true) { + abfd->iostream = (char *) fopen(abfd->filename, FOPEN_RUB); + if (!abfd->iostream) { + abfd->iostream = (char *) fopen(abfd->filename, FOPEN_WUB); + } + } else { + /*open for creat */ + abfd->iostream = (char *) fopen(abfd->filename, FOPEN_WB); + abfd->opened_once = true; + } + break; + } + + if (abfd->iostream) { + bfd_cache_init (abfd); + } + + return (FILE *)(abfd->iostream); +} + +/* +INTERNAL_FUNCTION + bfd_cache_lookup_worker + +DESCRIPTION + Called when the macro <<bfd_cache_lookup>> fails to find a + quick answer. Finds a file descriptor for this BFD. If + necessary, it open it. If there are already more than + BFD_CACHE_MAX_OPEN files open, it trys to close one first, to + avoid running out of file descriptors. + +SYNOPSIS + FILE *bfd_cache_lookup_worker(bfd *); + +*/ + +FILE * +DEFUN(bfd_cache_lookup_worker,(abfd), + bfd *abfd) +{ + if (abfd->my_archive) + { + abfd = abfd->my_archive; + } + /* Is this file already open .. if so then quick exit */ + if (abfd->iostream) + { + if (abfd != cache_sentinel) { + /* Place onto head of lru chain */ + snip (abfd); + cache_sentinel = insert(abfd, cache_sentinel); + } + } + /* This is a BFD without a stream - + so it must have been closed or never opened. + find an empty cache entry and use it. */ + else + { + + if (open_files >= BFD_CACHE_MAX_OPEN) + { + close_one(); + } + + BFD_ASSERT(bfd_open_file (abfd) != (FILE *)NULL) ; + fseek((FILE *)(abfd->iostream), abfd->where, false); + } + bfd_last_cache = abfd; + return (FILE *)(abfd->iostream); +} diff --git a/gnu/usr.bin/gdb/bfd/coffgen.c b/gnu/usr.bin/gdb/bfd/coffgen.c new file mode 100644 index 00000000000..9caddbbef62 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/coffgen.c @@ -0,0 +1,1522 @@ +/* Support for the generic parts of COFF, for BFD. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: coffgen.c,v 1.1 1995/10/18 08:39:52 deraadt Exp $ +*/ + +/* Most of this hacked by Steve Chamberlain, sac@cygnus.com. + Split out of coffcode.h by Ian Taylor, ian@cygnus.com. */ + +/* This file contains COFF code that is not dependent on any + particular COFF target. There is only one version of this file in + libbfd.a, so no target specific code may be put in here. Or, to + put it another way, + + ********** DO NOT PUT TARGET SPECIFIC CODE IN THIS FILE ********** + + If you need to add some target specific behaviour, add a new hook + function to bfd_coff_backend_data. + + Some of these functions are also called by the ECOFF routines. + Those functions may not use any COFF specific information, such as + coff_data (abfd). */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "seclet.h" +#include "libcoff.h" + +static asection bfd_debug_section = { "*DEBUG*" }; + +/* Take a section header read from a coff file (in HOST byte order), + and make a BFD "section" out of it. This is used by ECOFF. */ +static boolean +DEFUN(make_a_section_from_file,(abfd, hdr, target_index), + bfd *abfd AND + struct internal_scnhdr *hdr AND + unsigned int target_index) +{ + asection *return_section; + char *name; + + /* Assorted wastage to null-terminate the name, thanks AT&T! */ + name = bfd_alloc(abfd, sizeof (hdr->s_name)+1); + if (name == NULL) { + bfd_error = no_memory; + return false; + } + strncpy(name, (char *) &hdr->s_name[0], sizeof (hdr->s_name)); + name[sizeof (hdr->s_name)] = 0; + + return_section = bfd_make_section(abfd, name); + if (return_section == NULL) + return_section = bfd_coff_make_section_hook (abfd, name); + + /* Handle several sections of the same name. For example, if an executable + has two .bss sections, GDB better be able to find both of them + (PR 3562). */ + if (return_section == NULL) + return_section = bfd_make_section_anyway (abfd, name); + + if (return_section == NULL) + return false; + + /* s_paddr is presumed to be = to s_vaddr */ + + return_section->vma = hdr->s_vaddr; + return_section->_raw_size = hdr->s_size; + return_section->filepos = hdr->s_scnptr; + return_section->rel_filepos = hdr->s_relptr; + return_section->reloc_count = hdr->s_nreloc; + + bfd_coff_set_alignment_hook (abfd, return_section, hdr); + + return_section->line_filepos = hdr->s_lnnoptr; + + return_section->lineno_count = hdr->s_nlnno; + return_section->userdata = NULL; + return_section->next = (asection *) NULL; + return_section->flags = bfd_coff_styp_to_sec_flags_hook (abfd, hdr); + + return_section->target_index = target_index; + + /* At least on i386-coff, the line number count for a shared library + section must be ignored. */ + if ((return_section->flags & SEC_SHARED_LIBRARY) != 0) + return_section->lineno_count = 0; + + if (hdr->s_nreloc != 0) + return_section->flags |= SEC_RELOC; + /* FIXME: should this check 'hdr->s_size > 0' */ + if (hdr->s_scnptr != 0) + return_section->flags |= SEC_HAS_CONTENTS; + return true; +} + +/* Read in a COFF object and make it into a BFD. This is used by + ECOFF as well. */ + +static +bfd_target * +DEFUN(coff_real_object_p,(abfd, nscns, internal_f, internal_a), + bfd *abfd AND + unsigned nscns AND + struct internal_filehdr *internal_f AND + struct internal_aouthdr *internal_a) +{ + PTR tdata; + size_t readsize; /* length of file_info */ + unsigned int scnhsz; + char *external_sections; + + /* Build a play area */ + tdata = bfd_coff_mkobject_hook (abfd, (PTR) internal_f, (PTR) internal_a); + if (tdata == NULL) + return 0; + + scnhsz = bfd_coff_scnhsz (abfd); + readsize = nscns * scnhsz; + external_sections = (char *)bfd_alloc(abfd, readsize); + + if (bfd_read((PTR)external_sections, 1, readsize, abfd) != readsize) { + goto fail; + } + + /* Now copy data as required; construct all asections etc */ + if (nscns != 0) { + unsigned int i; + for (i = 0; i < nscns; i++) { + struct internal_scnhdr tmp; + bfd_coff_swap_scnhdr_in(abfd, (PTR) (external_sections + i * scnhsz), + (PTR) &tmp); + make_a_section_from_file(abfd,&tmp, i+1); + } + } + +/* make_abs_section(abfd);*/ + + if (bfd_coff_set_arch_mach_hook (abfd, (PTR) internal_f) == false) + goto fail; + + if (!(internal_f->f_flags & F_RELFLG)) + abfd->flags |= HAS_RELOC; + if ((internal_f->f_flags & F_EXEC)) + abfd->flags |= EXEC_P; + if (!(internal_f->f_flags & F_LNNO)) + abfd->flags |= HAS_LINENO; + if (!(internal_f->f_flags & F_LSYMS)) + abfd->flags |= HAS_LOCALS; + + + bfd_get_symcount(abfd) = internal_f->f_nsyms; + if (internal_f->f_nsyms) + abfd->flags |= HAS_SYMS; + + if (internal_a != (struct internal_aouthdr *) NULL) + bfd_get_start_address (abfd) = internal_a->entry; + else + bfd_get_start_address (abfd) = 0; + + return abfd->xvec; + fail: + bfd_release(abfd, tdata); + return (bfd_target *)NULL; +} + +/* Turn a COFF file into a BFD, but fail with wrong_format if it is + not a COFF file. This is also used by ECOFF. */ + +bfd_target * +DEFUN(coff_object_p,(abfd), + bfd *abfd) +{ + unsigned int filhsz; + unsigned int aoutsz; + int nscns; + PTR filehdr; + struct internal_filehdr internal_f; + struct internal_aouthdr internal_a; + + bfd_error = system_call_error; + + /* figure out how much to read */ + filhsz = bfd_coff_filhsz (abfd); + aoutsz = bfd_coff_aoutsz (abfd); + + filehdr = bfd_alloc (abfd, filhsz); + if (filehdr == NULL) + return 0; + if (bfd_read(filehdr, 1, filhsz, abfd) != filhsz) + return 0; + bfd_coff_swap_filehdr_in(abfd, filehdr, &internal_f); + bfd_release (abfd, filehdr); + + if (bfd_coff_bad_format_hook (abfd, &internal_f) == false) { + bfd_error = wrong_format; + return 0; + } + nscns =internal_f.f_nscns; + + if (internal_f.f_opthdr) { + PTR opthdr; + + opthdr = bfd_alloc (abfd, aoutsz); + if (opthdr == NULL) + return 0;; + if (bfd_read(opthdr, 1,aoutsz, abfd) != aoutsz) { + return 0; + } + bfd_coff_swap_aouthdr_in(abfd, opthdr, (PTR)&internal_a); + } + + /* Seek past the opt hdr stuff */ + bfd_seek(abfd, (file_ptr) (internal_f.f_opthdr + filhsz), SEEK_SET); + + return coff_real_object_p(abfd, nscns, &internal_f, + (internal_f.f_opthdr != 0 + ? &internal_a + : (struct internal_aouthdr *) NULL)); +} + +/* Get the BFD section from a COFF symbol section number. */ + +struct sec * +DEFUN(coff_section_from_bfd_index,(abfd, index), + bfd *abfd AND + int index) +{ + struct sec *answer = abfd->sections; + + if (index == N_ABS) + { + return &bfd_abs_section; + } + if (index == N_UNDEF) + { + return &bfd_und_section; + } + if(index == N_DEBUG) + { + return &bfd_debug_section; + + } + + while (answer) { + if (answer->target_index == index) + return answer; + answer = answer->next; + } + BFD_ASSERT(0); + return &bfd_und_section; /* For gcc -W and lint. Never executed. */ +} + +/* Get the upper bound of a COFF symbol table. */ + +unsigned int +coff_get_symtab_upper_bound(abfd) +bfd *abfd; +{ + if (!bfd_coff_slurp_symbol_table(abfd)) + return 0; + + return (bfd_get_symcount(abfd) + 1) * (sizeof(coff_symbol_type *)); +} + + +/* Canonicalize a COFF symbol table. */ + +unsigned int +DEFUN(coff_get_symtab, (abfd, alocation), + bfd *abfd AND + asymbol **alocation) +{ + unsigned int counter = 0; + coff_symbol_type *symbase; + coff_symbol_type **location = (coff_symbol_type **) (alocation); + if (!bfd_coff_slurp_symbol_table(abfd)) + return 0; + + symbase = obj_symbols(abfd); + while (counter < bfd_get_symcount(abfd)) + { + /* This nasty code looks at the symbol to decide whether or + not it is descibes a constructor/destructor entry point. It + is structured this way to (hopefully) speed non matches */ +#if 0 + if (0 && symbase->symbol.name[9] == '$') + { + bfd_constructor_entry(abfd, + (asymbol **)location, + symbase->symbol.name[10] == 'I' ? + "CTOR" : "DTOR"); + } +#endif + *(location++) = symbase++; + counter++; + } + *location++ = 0; + return bfd_get_symcount(abfd); +} + +/* Set lineno_count for the output sections of a COFF file. */ + +int +DEFUN(coff_count_linenumbers,(abfd), + bfd *abfd) +{ + unsigned int limit = bfd_get_symcount(abfd); + unsigned int i; + int total = 0; + asymbol **p; + { + asection *s = abfd->sections->output_section; + while (s) { + BFD_ASSERT(s->lineno_count == 0); + s = s->next; + } + } + + + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) { + asymbol *q_maybe = *p; + if (bfd_asymbol_flavour(q_maybe) == bfd_target_coff_flavour) { + coff_symbol_type *q = coffsymbol(q_maybe); + if (q->lineno) { + /* + This symbol has a linenumber, increment the owning + section's linenumber count + */ + alent *l = q->lineno; + q->symbol.section->output_section->lineno_count++; + total ++; + l++; + while (l->line_number) { + total ++; + q->symbol.section->output_section->lineno_count++; + l++; + } + } + } + } + return total; +} + +/* Takes a bfd and a symbol, returns a pointer to the coff specific + area of the symbol if there is one. */ + +coff_symbol_type * +DEFUN(coff_symbol_from,(ignore_abfd, symbol), + bfd *ignore_abfd AND + asymbol *symbol) +{ + if (bfd_asymbol_flavour(symbol) != bfd_target_coff_flavour) + return (coff_symbol_type *)NULL; + + if (bfd_asymbol_bfd(symbol)->tdata.coff_obj_data == (coff_data_type*)NULL) + return (coff_symbol_type *)NULL; + + return (coff_symbol_type *) symbol; +} + +static void +DEFUN(fixup_symbol_value,(coff_symbol_ptr, syment), +coff_symbol_type *coff_symbol_ptr AND +struct internal_syment *syment) +{ + + /* Normalize the symbol flags */ + if (bfd_is_com_section (coff_symbol_ptr->symbol.section)) { + /* a common symbol is undefined with a value */ + syment->n_scnum = N_UNDEF; + syment->n_value = coff_symbol_ptr->symbol.value; + } + else if (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING) { + syment->n_value = coff_symbol_ptr->symbol.value; + } + else if (coff_symbol_ptr->symbol.section == & bfd_und_section) { + syment->n_scnum = N_UNDEF; + syment->n_value = 0; + } + else { + if (coff_symbol_ptr->symbol.section) { + syment->n_scnum = + coff_symbol_ptr->symbol.section->output_section->target_index; + + syment->n_value = + coff_symbol_ptr->symbol.value + + coff_symbol_ptr->symbol.section->output_offset + + coff_symbol_ptr->symbol.section->output_section->vma; + } + else { + BFD_ASSERT(0); + /* This can happen, but I don't know why yet (steve@cygnus.com) */ + syment->n_scnum = N_ABS; + syment->n_value = coff_symbol_ptr->symbol.value; + } + } +} + +/* run through all the symbols in the symbol table and work out what + their indexes into the symbol table will be when output + + Coff requires that each C_FILE symbol points to the next one in the + chain, and that the last one points to the first external symbol. We + do that here too. + +*/ +void +DEFUN(coff_renumber_symbols,(bfd_ptr), + bfd *bfd_ptr) +{ + unsigned int symbol_count = bfd_get_symcount(bfd_ptr); + asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; + unsigned int native_index = 0; + struct internal_syment *last_file = (struct internal_syment *)NULL; + unsigned int symbol_index; + + /* COFF demands that undefined symbols come after all other symbols. + Since we don't need to impose this extra knowledge on all our client + programs, deal with that here. Sort the symbol table; just move the + undefined symbols to the end, leaving the rest alone. */ + /* @@ Do we have some condition we could test for, so we don't always + have to do this? I don't think relocatability is quite right, but + I'm not certain. [raeburn:19920508.1711EST] */ + { + asymbol **newsyms; + int i; + + newsyms = (asymbol **) bfd_alloc_by_size_t (bfd_ptr, + sizeof (asymbol *) + * (symbol_count + 1)); + bfd_ptr->outsymbols = newsyms; + for (i = 0; i < symbol_count; i++) + if (symbol_ptr_ptr[i]->section != &bfd_und_section) + *newsyms++ = symbol_ptr_ptr[i]; + for (i = 0; i < symbol_count; i++) + if (symbol_ptr_ptr[i]->section == &bfd_und_section) + *newsyms++ = symbol_ptr_ptr[i]; + *newsyms = (asymbol *) NULL; + symbol_ptr_ptr = bfd_ptr->outsymbols; + } + + for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) + { + coff_symbol_type *coff_symbol_ptr = coff_symbol_from(bfd_ptr, symbol_ptr_ptr[symbol_index]); + if (coff_symbol_ptr && coff_symbol_ptr->native) { + combined_entry_type *s = coff_symbol_ptr->native; + int i; + + if (s->u.syment.n_sclass == C_FILE) + { + if (last_file != (struct internal_syment *)NULL) { + last_file->n_value = native_index; + } + last_file = &(s->u.syment); + } + else { + + /* Modify the symbol values according to their section and + type */ + + fixup_symbol_value(coff_symbol_ptr, &(s->u.syment)); + } + for (i = 0; i < s->u.syment.n_numaux + 1; i++) { + s[i].offset = native_index ++; + } + } + else { + native_index++; + } + } + obj_conv_table_size (bfd_ptr) = native_index; +} + +/* + Run thorough the symbol table again, and fix it so that all pointers to + entries are changed to the entries' index in the output symbol table. + +*/ +void +DEFUN(coff_mangle_symbols,(bfd_ptr), + bfd *bfd_ptr) +{ + unsigned int symbol_count = bfd_get_symcount(bfd_ptr); + asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; + unsigned int symbol_index; + + for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) + { + coff_symbol_type *coff_symbol_ptr = + coff_symbol_from(bfd_ptr, symbol_ptr_ptr[symbol_index]); + + if (coff_symbol_ptr && coff_symbol_ptr->native) { + int i; + combined_entry_type *s = coff_symbol_ptr->native; + + for (i = 0; i < s->u.syment.n_numaux ; i++) { + combined_entry_type *a = s + i + 1; + if (a->fix_tag) { + a->u.auxent.x_sym.x_tagndx.l = + a->u.auxent.x_sym.x_tagndx.p->offset; + a->fix_tag = 0; + } + if (a->fix_end) { + a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l = + a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p->offset; + a->fix_end = 0; + + } + + } + } + } +} + +static int string_size; + +static void +DEFUN(coff_fix_symbol_name,(abfd, symbol, native), + bfd *abfd AND + asymbol *symbol AND + combined_entry_type *native) +{ + unsigned int name_length; + union internal_auxent *auxent; + char * name = ( char *)(symbol->name); + + if (name == (char *) NULL) { + /* coff symbols always have names, so we'll make one up */ + symbol->name = "strange"; + name = (char *)symbol->name; + } + name_length = strlen(name); + + if (native->u.syment.n_sclass == C_FILE) { + strncpy(native->u.syment._n._n_name, ".file", SYMNMLEN); + auxent = &(native+1)->u.auxent; + + if (bfd_coff_long_filenames (abfd)) { + if (name_length <= FILNMLEN) { + strncpy(auxent->x_file.x_fname, name, FILNMLEN); + } + else { + auxent->x_file.x_n.x_offset = string_size + 4; + auxent->x_file.x_n.x_zeroes = 0; + string_size += name_length + 1; + } + } + else { + strncpy(auxent->x_file.x_fname, name, FILNMLEN); + if (name_length > FILNMLEN) { + name[FILNMLEN] = '\0'; + } + } + } + else + { /* NOT A C_FILE SYMBOL */ + if (name_length <= SYMNMLEN) { + /* This name will fit into the symbol neatly */ + strncpy(native->u.syment._n._n_name, symbol->name, SYMNMLEN); + } + else { + native->u.syment._n._n_n._n_offset = string_size + 4; + native->u.syment._n._n_n._n_zeroes = 0; + string_size += name_length + 1; + } + } +} + +#define set_index(symbol, idx) ((symbol)->udata =(PTR) (idx)) + +static unsigned int +DEFUN(coff_write_symbol,(abfd, symbol, native, written), +bfd *abfd AND +asymbol *symbol AND +combined_entry_type *native AND +unsigned int written) +{ + unsigned int numaux = native->u.syment.n_numaux; + int type = native->u.syment.n_type; + int class = native->u.syment.n_sclass; + PTR buf; + bfd_size_type symesz; + + /* @@ bfd_debug_section isn't accessible outside this file, but we know + that C_FILE symbols belong there. So move them. */ + if (native->u.syment.n_sclass == C_FILE) + symbol->section = &bfd_debug_section; + + if (symbol->section == &bfd_abs_section) + { + native->u.syment.n_scnum = N_ABS; + } + else if (symbol->section == &bfd_debug_section) + { + native->u.syment.n_scnum = N_DEBUG; + } + else if (symbol->section == &bfd_und_section) + { + native->u.syment.n_scnum = N_UNDEF; + } + else + { + native->u.syment.n_scnum = + symbol->section->output_section->target_index; + } + + + coff_fix_symbol_name(abfd, symbol, native); + + symesz = bfd_coff_symesz (abfd); + buf = bfd_alloc (abfd, symesz); + bfd_coff_swap_sym_out(abfd, &native->u.syment, buf); + bfd_write(buf, 1, symesz, abfd); + bfd_release (abfd, buf); + + if (native->u.syment.n_numaux > 0) + { + bfd_size_type auxesz; + unsigned int j; + + auxesz = bfd_coff_auxesz (abfd); + buf = bfd_alloc (abfd, auxesz); + for (j = 0; j < native->u.syment.n_numaux; j++) + { + bfd_coff_swap_aux_out(abfd, + &((native + j + 1)->u.auxent), + type, + class, + buf); + bfd_write(buf, 1, auxesz, abfd); + } + bfd_release (abfd, buf); + } + /* + Reuse somewhere in the symbol to keep the index + */ + set_index(symbol, written); + return written + 1 + numaux; +} + + +static unsigned int +DEFUN(coff_write_alien_symbol,(abfd, symbol, written), + bfd *abfd AND + asymbol *symbol AND + unsigned int written) +{ + /* + This symbol has been created by the loader, or come from a non + coff format. It has no native element to inherit, make our + own + */ + combined_entry_type *native; + combined_entry_type dummy; + native = &dummy; + native->u.syment.n_type = T_NULL; + native->u.syment.n_flags = 0; + if (symbol->section == &bfd_und_section) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + } + else if (bfd_is_com_section (symbol->section)) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + + } + + else if (symbol->flags & BSF_DEBUGGING) { + /* + remove name so it doesn't take up any space + */ + symbol->name = ""; + } + else { + native->u.syment.n_scnum = symbol->section->output_section->target_index; + native->u.syment.n_value = symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset; + /* Copy the any flags from the the file hdr into the symbol */ + { + coff_symbol_type *c = coff_symbol_from(abfd, symbol); + if (c != (coff_symbol_type *)NULL) { + native->u.syment.n_flags = bfd_asymbol_bfd(&c->symbol)->flags; + } + } + } + + native->u.syment.n_type = 0; + if (symbol->flags & BSF_LOCAL) + native->u.syment.n_sclass = C_STAT; + else + native->u.syment.n_sclass = C_EXT; + native->u.syment.n_numaux = 0; + + return coff_write_symbol(abfd, symbol, native, written); +} + +static unsigned int +DEFUN(coff_write_native_symbol,(abfd, symbol, written), +bfd *abfd AND +coff_symbol_type *symbol AND +unsigned int written) +{ + /* + Does this symbol have an ascociated line number - if so then + make it remember this symbol index. Also tag the auxent of + this symbol to point to the right place in the lineno table + */ + combined_entry_type *native = symbol->native; + + alent *lineno = symbol->lineno; + + if (lineno && !symbol->done_lineno) { + unsigned int count = 0; + lineno[count].u.offset = written; + if (native->u.syment.n_numaux) { + union internal_auxent *a = &((native+1)->u.auxent); + + a->x_sym.x_fcnary.x_fcn.x_lnnoptr = + symbol->symbol.section->output_section->moving_line_filepos; + } + /* + And count and relocate all other linenumbers + */ + + count++; + while (lineno[count].line_number) { +#if 0 +/* 13 april 92. sac +I've been told this, but still need proof: +> The second bug is also in `bfd/coffcode.h'. This bug causes the linker to screw +> up the pc-relocations for all the line numbers in COFF code. This bug isn't +> only specific to A29K implementations, but affects all systems using COFF +> format binaries. Note that in COFF object files, the line number core offsets +> output by the assembler are relative to the start of each procedure, not +> to the start of the .text section. This patch relocates the line numbers +> relative to the `native->u.syment.n_value' instead of the section virtual +> address. modular!olson@cs.arizona.edu (Jon Olson) +*/ + lineno[count].u.offset += native->u.syment.n_value; + +#else + lineno[count].u.offset += + symbol->symbol.section->output_section->vma + + symbol->symbol.section->output_offset; +#endif + count++; + } + symbol->done_lineno = true; + + symbol->symbol.section->output_section->moving_line_filepos += + count * bfd_coff_linesz (abfd); + } + return coff_write_symbol(abfd, &( symbol->symbol), native,written); +} + +void +DEFUN(coff_write_symbols,(abfd), + bfd *abfd) +{ + unsigned int i; + unsigned int limit = bfd_get_symcount(abfd); + unsigned int written = 0; + + asymbol **p; + + string_size = 0; + + + /* Seek to the right place */ + bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET); + + /* Output all the symbols we have */ + + written = 0; + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) + { + asymbol *symbol = *p; + coff_symbol_type *c_symbol = coff_symbol_from(abfd, symbol); + + if (c_symbol == (coff_symbol_type *) NULL || + c_symbol->native == (combined_entry_type *)NULL) + { + written = coff_write_alien_symbol(abfd, symbol, written); + } + else + { + written = coff_write_native_symbol(abfd, c_symbol, written); + } + + } + + bfd_get_symcount(abfd) = written; + + /* Now write out strings */ + + if (string_size != 0) + { + unsigned int size = string_size + 4; + bfd_byte buffer[4]; + + bfd_h_put_32(abfd, size, buffer); + bfd_write((PTR) buffer, 1, sizeof(buffer), abfd); + for (p = abfd->outsymbols, i = 0; + i < limit; + i++, p++) + { + asymbol *q = *p; + size_t name_length = strlen(q->name); + int maxlen; + coff_symbol_type* c_symbol = coff_symbol_from(abfd, q); + maxlen = ((c_symbol != NULL && c_symbol->native != NULL) && + (c_symbol->native->u.syment.n_sclass == C_FILE)) ? + FILNMLEN : SYMNMLEN; + + if (name_length > maxlen) { + bfd_write((PTR) (q->name), 1, name_length + 1, abfd); + } + } + } + else { + /* We would normally not write anything here, but we'll write + out 4 so that any stupid coff reader which tries to read + the string table even when there isn't one won't croak. */ + unsigned int size = 4; + bfd_byte buffer[4]; + + bfd_h_put_32 (abfd, size, buffer); + bfd_write((PTR) buffer, 1, sizeof (buffer), abfd); + } +} + +void +DEFUN(coff_write_linenumbers,(abfd), + bfd *abfd) +{ + asection *s; + bfd_size_type linesz; + PTR buff; + + linesz = bfd_coff_linesz (abfd); + buff = bfd_alloc (abfd, linesz); + for (s = abfd->sections; s != (asection *) NULL; s = s->next) { + if (s->lineno_count) { + asymbol **q = abfd->outsymbols; + bfd_seek(abfd, s->line_filepos, SEEK_SET); + /* Find all the linenumbers in this section */ + while (*q) { + asymbol *p = *q; + if (p->section->output_section == s) { + alent *l = + BFD_SEND(bfd_asymbol_bfd(p), _get_lineno, (bfd_asymbol_bfd(p), p)); + if (l) { + /* Found a linenumber entry, output */ + struct internal_lineno out; + memset( (PTR)&out, 0, sizeof(out)); + out.l_lnno = 0; + out.l_addr.l_symndx = l->u.offset; + bfd_coff_swap_lineno_out(abfd, &out, buff); + bfd_write(buff, 1, linesz, abfd); + l++; + while (l->line_number) { + out.l_lnno = l->line_number; + out.l_addr.l_symndx = l->u.offset; + bfd_coff_swap_lineno_out(abfd, &out, buff); + bfd_write(buff, 1, linesz, abfd); + l++; + } + } + } + q++; + } + } + } + bfd_release (abfd, buff); +} + +alent * +DEFUN(coff_get_lineno,(ignore_abfd, symbol), + bfd *ignore_abfd AND + asymbol *symbol) +{ + return coffsymbol(symbol)->lineno; +} + +asymbol * +coff_section_symbol (abfd, name) + bfd *abfd; + char *name; +{ + asection *sec = bfd_make_section_old_way (abfd, name); + asymbol *sym; + combined_entry_type *csym; + + sym = sec->symbol; + csym = coff_symbol_from (abfd, sym)->native; + /* Make sure back-end COFF stuff is there. */ + if (csym == 0) + { + struct foo { + coff_symbol_type sym; + /* @@FIXME This shouldn't use a fixed size!! */ + combined_entry_type e[10]; + }; + struct foo *f; + f = (struct foo *) bfd_alloc_by_size_t (abfd, sizeof (*f)); + memset ((char *) f, 0, sizeof (*f)); + coff_symbol_from (abfd, sym)->native = csym = f->e; + } + csym[0].u.syment.n_sclass = C_STAT; + csym[0].u.syment.n_numaux = 1; +/* SF_SET_STATICS (sym); @@ ??? */ + csym[1].u.auxent.x_scn.x_scnlen = sec->_raw_size; + csym[1].u.auxent.x_scn.x_nreloc = sec->reloc_count; + csym[1].u.auxent.x_scn.x_nlinno = sec->lineno_count; + + if (sec->output_section == NULL) + { + sec->output_section = sec; + sec->output_offset = 0; + } + + return sym; +} + +/* This function transforms the offsets into the symbol table into + pointers to syments. */ + +static void +DEFUN(coff_pointerize_aux,(abfd, table_base, type, class, auxent), +bfd *abfd AND +combined_entry_type *table_base AND +int type AND +int class AND +combined_entry_type *auxent) +{ + /* Don't bother if this is a file or a section */ + if (class == C_STAT && type == T_NULL) return; + if (class == C_FILE) return; + + /* Otherwise patch up */ +#define N_TMASK coff_data (abfd)->local_n_tmask +#define N_BTSHFT coff_data (abfd)->local_n_btshft + if (ISFCN(type) || ISTAG(class) || class == C_BLOCK) { + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = table_base + + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l; + auxent->fix_end = 1; + } + /* A negative tagndx is meaningless, but the SCO 3.2v4 cc can + generate one, so we must be careful to ignore it. */ + if (auxent->u.auxent.x_sym.x_tagndx.l > 0) { + auxent->u.auxent.x_sym.x_tagndx.p = + table_base + auxent->u.auxent.x_sym.x_tagndx.l; + auxent->fix_tag = 1; + } +} + +static char * +DEFUN(build_string_table,(abfd), +bfd *abfd) +{ + char string_table_size_buffer[4]; + unsigned int string_table_size; + char *string_table; + + /* At this point we should be "seek"'d to the end of the + symbols === the symbol table size. */ + if (bfd_read((char *) string_table_size_buffer, + sizeof(string_table_size_buffer), + 1, abfd) != sizeof(string_table_size)) { + bfd_error = system_call_error; + return (NULL); + } /* on error */ + + string_table_size = bfd_h_get_32(abfd, (bfd_byte *) string_table_size_buffer); + + if ((string_table = (PTR) bfd_alloc(abfd, string_table_size -= 4)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on mallocation error */ + if (bfd_read(string_table, string_table_size, 1, abfd) != string_table_size) { + bfd_error = system_call_error; + return (NULL); + } + return string_table; +} + +/* Allocate space for the ".debug" section, and read it. + We did not read the debug section until now, because + we didn't want to go to the trouble until someone needed it. */ + +static char * +DEFUN(build_debug_section,(abfd), + bfd *abfd) +{ + char *debug_section; + long position; + + asection *sect = bfd_get_section_by_name (abfd, ".debug"); + + if (!sect) { + bfd_error = no_debug_section; + return NULL; + } + + debug_section = (PTR) bfd_alloc (abfd, + bfd_get_section_size_before_reloc (sect)); + if (debug_section == NULL) { + bfd_error = no_memory; + return NULL; + } + + /* Seek to the beginning of the `.debug' section and read it. + Save the current position first; it is needed by our caller. + Then read debug section and reset the file pointer. */ + + position = bfd_tell (abfd); + bfd_seek (abfd, sect->filepos, SEEK_SET); + if (bfd_read (debug_section, + bfd_get_section_size_before_reloc (sect), 1, abfd) + != bfd_get_section_size_before_reloc(sect)) { + bfd_error = system_call_error; + return NULL; + } + bfd_seek (abfd, position, SEEK_SET); + return debug_section; +} + + +/* Return a pointer to a malloc'd copy of 'name'. 'name' may not be + \0-terminated, but will not exceed 'maxlen' characters. The copy *will* + be \0-terminated. */ +static char * +DEFUN(copy_name,(abfd, name, maxlen), + bfd *abfd AND + char *name AND + int maxlen) +{ + int len; + char *newname; + + for (len = 0; len < maxlen; ++len) { + if (name[len] == '\0') { + break; + } + } + + if ((newname = (PTR) bfd_alloc(abfd, len+1)) == NULL) { + bfd_error = no_memory; + return (NULL); + } + strncpy(newname, name, len); + newname[len] = '\0'; + return newname; +} + +/* Read a symbol table into freshly bfd_allocated memory, swap it, and + knit the symbol names into a normalized form. By normalized here I + mean that all symbols have an n_offset pointer that points to a null- + terminated string. */ + +combined_entry_type * +DEFUN(coff_get_normalized_symtab,(abfd), +bfd *abfd) +{ + combined_entry_type *internal; + combined_entry_type *internal_ptr; + combined_entry_type *symbol_ptr; + combined_entry_type *internal_end; + bfd_size_type symesz; + PTR raw; + char *raw_src; + char *raw_end; + char *string_table = NULL; + char *debug_section = NULL; + unsigned long size; + + unsigned int raw_size; + if (obj_raw_syments(abfd) != (combined_entry_type *)NULL) { + return obj_raw_syments(abfd); + } + if ((size = bfd_get_symcount(abfd) * sizeof(combined_entry_type)) == 0) { + bfd_error = no_symbols; + return (NULL); + } + + internal = (combined_entry_type *)bfd_alloc(abfd, size); + internal_end = internal + bfd_get_symcount(abfd); + + symesz = bfd_coff_symesz (abfd); + raw_size = bfd_get_symcount(abfd) * symesz; + raw = bfd_alloc(abfd,raw_size); + + if (bfd_seek(abfd, obj_sym_filepos(abfd), SEEK_SET) == -1 + || bfd_read(raw, raw_size, 1, abfd) != raw_size) { + bfd_error = system_call_error; + return (NULL); + } + /* mark the end of the symbols */ + raw_end = (char *) raw + bfd_get_symcount(abfd) * symesz; + /* + FIXME SOMEDAY. A string table size of zero is very weird, but + probably possible. If one shows up, it will probably kill us. + */ + + /* Swap all the raw entries */ + for (raw_src = (char *) raw, internal_ptr = internal; + raw_src < raw_end; + raw_src += symesz, internal_ptr++) { + + unsigned int i; + bfd_coff_swap_sym_in(abfd, (PTR)raw_src, (PTR)&internal_ptr->u.syment); + internal_ptr->fix_tag = 0; + internal_ptr->fix_end = 0; + symbol_ptr = internal_ptr; + + for (i = 0; + i < symbol_ptr->u.syment.n_numaux; + i++) + { + internal_ptr++; + raw_src += symesz; + + internal_ptr->fix_tag = 0; + internal_ptr->fix_end = 0; + bfd_coff_swap_aux_in(abfd, (PTR) raw_src, + symbol_ptr->u.syment.n_type, + symbol_ptr->u.syment.n_sclass, + &(internal_ptr->u.auxent)); + /* Remember that bal entries arn't pointerized */ + if (i != 1 || symbol_ptr->u.syment.n_sclass != C_LEAFPROC) + { + + coff_pointerize_aux(abfd, + internal, + symbol_ptr->u.syment.n_type, + symbol_ptr->u.syment.n_sclass, + internal_ptr); + } + + } + } + + /* Free all the raw stuff */ + bfd_release(abfd, raw); + + for (internal_ptr = internal; internal_ptr < internal_end; + internal_ptr ++) + { + if (internal_ptr->u.syment.n_sclass == C_FILE) { + /* make a file symbol point to the name in the auxent, since + the text ".file" is redundant */ + if ((internal_ptr+1)->u.auxent.x_file.x_n.x_zeroes == 0) { + /* the filename is a long one, point into the string table */ + if (string_table == NULL) { + string_table = build_string_table(abfd); + } + + internal_ptr->u.syment._n._n_n._n_offset = + (long) (string_table - 4 + + (internal_ptr+1)->u.auxent.x_file.x_n.x_offset); + } + else { + /* ordinary short filename, put into memory anyway */ + internal_ptr->u.syment._n._n_n._n_offset = (long) + copy_name(abfd, (internal_ptr+1)->u.auxent.x_file.x_fname, + FILNMLEN); + } + } + else { + if (internal_ptr->u.syment._n._n_n._n_zeroes != 0) { + /* This is a "short" name. Make it long. */ + unsigned long i = 0; + char *newstring = NULL; + + /* find the length of this string without walking into memory + that isn't ours. */ + for (i = 0; i < 8; ++i) { + if (internal_ptr->u.syment._n._n_name[i] == '\0') { + break; + } /* if end of string */ + } /* possible lengths of this string. */ + + if ((newstring = (PTR) bfd_alloc(abfd, ++i)) == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + memset(newstring, 0, i); + strncpy(newstring, internal_ptr->u.syment._n._n_name, i-1); + internal_ptr->u.syment._n._n_n._n_offset = (long int) newstring; + internal_ptr->u.syment._n._n_n._n_zeroes = 0; + } + else if (!bfd_coff_symname_in_debug(abfd, &internal_ptr->u.syment)) { + /* Long name already. Point symbol at the string in the table. */ + if (string_table == NULL) { + string_table = build_string_table(abfd); + } + internal_ptr->u.syment._n._n_n._n_offset = (long int) + (string_table - 4 + internal_ptr->u.syment._n._n_n._n_offset); + } + else { + /* Long name in debug section. Very similar. */ + if (debug_section == NULL) { + debug_section = build_debug_section(abfd); + } + internal_ptr->u.syment._n._n_n._n_offset = (long int) + (debug_section + internal_ptr->u.syment._n._n_n._n_offset); + } + } + internal_ptr += internal_ptr->u.syment.n_numaux; + } + + obj_raw_syments(abfd) = internal; + obj_raw_syment_count(abfd) = internal_ptr - internal; + + return (internal); +} /* coff_get_normalized_symtab() */ + +unsigned int +DEFUN (coff_get_reloc_upper_bound, (abfd, asect), + bfd *abfd AND + sec_ptr asect) +{ + if (bfd_get_format(abfd) != bfd_object) { + bfd_error = invalid_operation; + return 0; + } + return (asect->reloc_count + 1) * sizeof(arelent *); +} + +asymbol * +DEFUN (coff_make_empty_symbol, (abfd), + bfd *abfd) +{ + coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type)); + if (new == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + new->symbol.section = 0; + new->native = 0; + new->lineno = (alent *) NULL; + new->done_lineno = false; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +/* Make a debugging symbol. */ + +asymbol * +coff_bfd_make_debug_symbol (abfd, ptr, sz) + bfd *abfd; + PTR ptr; + unsigned long sz; +{ + coff_symbol_type *new = (coff_symbol_type *) bfd_alloc(abfd, sizeof(coff_symbol_type)); + if (new == NULL) { + bfd_error = no_memory; + return (NULL); + } /* on error */ + /* @@ This shouldn't be using a constant multiplier. */ + new->native = (combined_entry_type *) bfd_zalloc (abfd, sizeof (combined_entry_type) * 10); + new->symbol.section = &bfd_debug_section; + new->lineno = (alent *) NULL; + new->done_lineno = false; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +void +coff_get_symbol_info (abfd, symbol, ret) + bfd *abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +/* Print out information about COFF symbol. */ + +void +coff_print_symbol (abfd, filep, symbol, how) + bfd *abfd; + PTR filep; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) filep; + + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + + case bfd_print_symbol_more: + fprintf (file, "coff %s %s", + coffsymbol(symbol)->native ? "n" : "g", + coffsymbol(symbol)->lineno ? "l" : " "); + break; + + case bfd_print_symbol_all: + if (coffsymbol(symbol)->native) + { + unsigned int aux; + combined_entry_type *combined = coffsymbol (symbol)->native; + combined_entry_type *root = obj_raw_syments (abfd); + struct lineno_cache_entry *l = coffsymbol(symbol)->lineno; + + fprintf (file,"[%3d]", combined - root); + + fprintf (file, + "(sc %2d)(fl 0x%02x)(ty %3x)(sc %3d) (nx %d) 0x%08x %s", + combined->u.syment.n_scnum, + combined->u.syment.n_flags, + combined->u.syment.n_type, + combined->u.syment.n_sclass, + combined->u.syment.n_numaux, + combined->u.syment.n_value, + symbol->name); + + for (aux = 0; aux < combined->u.syment.n_numaux; aux++) + { + combined_entry_type *auxp = combined + aux + 1; + long tagndx; + + if (auxp->fix_tag) + tagndx = auxp->u.auxent.x_sym.x_tagndx.p - root; + else + tagndx = auxp->u.auxent.x_sym.x_tagndx.l; + + fprintf (file, "\n"); + switch (combined->u.syment.n_sclass) + { + case C_FILE: + fprintf (file, "File "); + break; + default: + + fprintf (file, "AUX lnno %d size 0x%x tagndx %d", + auxp->u.auxent.x_sym.x_misc.x_lnsz.x_lnno, + auxp->u.auxent.x_sym.x_misc.x_lnsz.x_size, + tagndx); + break; + } + } + + if (l) + { + fprintf (file, "\n%s :", l->u.sym->name); + l++; + while (l->line_number) + { + fprintf (file, "\n%4d : 0x%x", + l->line_number, + l->u.offset + symbol->section->vma); + l++; + } + } + } + else + { + bfd_print_symbol_vandf ((PTR) file, symbol); + fprintf (file, " %-5s %s %s %s", + symbol->section->name, + coffsymbol(symbol)->native ? "n" : "g", + coffsymbol(symbol)->lineno ? "l" : " ", + symbol->name); + } + } +} + +/* Provided a BFD, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. */ + +boolean +DEFUN(coff_find_nearest_line,(abfd, + section, + ignore_symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr), + bfd *abfd AND + asection *section AND + asymbol **ignore_symbols AND + bfd_vma offset AND + CONST char **filename_ptr AND + CONST char **functionname_ptr AND + unsigned int *line_ptr) +{ + static bfd *cache_abfd; + static asection *cache_section; + static bfd_vma cache_offset; + static unsigned int cache_i; + static CONST char *cache_function; + static unsigned int line_base = 0; + + unsigned int i = 0; + coff_data_type *cof = coff_data(abfd); + /* Run through the raw syments if available */ + combined_entry_type *p; + alent *l; + + + *filename_ptr = 0; + *functionname_ptr = 0; + *line_ptr = 0; + + /* Don't try and find line numbers in a non coff file */ + if (abfd->xvec->flavour != bfd_target_coff_flavour) + return false; + + if (cof == NULL) + return false; + + p = cof->raw_syments; + + for (i = 0; i < cof->raw_syment_count; i++) { + if (p->u.syment.n_sclass == C_FILE) { + /* File name has been moved into symbol */ + *filename_ptr = (char *) p->u.syment._n._n_n._n_offset; + break; + } + p += 1 + p->u.syment.n_numaux; + } + /* Now wander though the raw linenumbers of the section */ + /* + If this is the same BFD as we were previously called with and this is + the same section, and the offset we want is further down then we can + prime the lookup loop + */ + if (abfd == cache_abfd && + section == cache_section && + offset >= cache_offset) { + i = cache_i; + *functionname_ptr = cache_function; + } + else { + i = 0; + } + l = §ion->lineno[i]; + + for (; i < section->lineno_count; i++) { + if (l->line_number == 0) { + /* Get the symbol this line number points at */ + coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym); + if (coff->symbol.value > offset) + break; + *functionname_ptr = coff->symbol.name; + if (coff->native) { + combined_entry_type *s = coff->native; + s = s + 1 + s->u.syment.n_numaux; + /* + S should now point to the .bf of the function + */ + if (s->u.syment.n_numaux) { + /* + The linenumber is stored in the auxent + */ + union internal_auxent *a = &((s + 1)->u.auxent); + line_base = a->x_sym.x_misc.x_lnsz.x_lnno; + *line_ptr = line_base; + } + } + } + else { + if (l->u.offset > offset) + break; + *line_ptr = l->line_number + line_base - 1; + } + l++; + } + + cache_abfd = abfd; + cache_section = section; + cache_offset = offset; + cache_i = i; + cache_function = *functionname_ptr; + + return true; +} + +int +DEFUN(coff_sizeof_headers,(abfd, reloc), + bfd *abfd AND + boolean reloc) +{ + size_t size; + + if (reloc == false) { + size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); + } + else { + size = bfd_coff_filhsz (abfd); + } + + size += abfd->section_count * bfd_coff_scnhsz (abfd); + return size; +} diff --git a/gnu/usr.bin/gdb/bfd/core.c b/gnu/usr.bin/gdb/bfd/core.c new file mode 100644 index 00000000000..9140dc35391 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/core.c @@ -0,0 +1,109 @@ +/* Core file generic interface routines for BFD. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: core.c,v 1.1 1995/10/18 08:39:52 deraadt Exp $ +*/ + +/* +SECTION + Core files + +DESCRIPTION + Buff output this facinating topic +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + + +/* +FUNCTION + bfd_core_file_failing_command + +SYNOPSIS + CONST char *bfd_core_file_failing_command(bfd *); + +DESCRIPTION + Returns a read-only string explaining what program was running + when it failed and produced the core file being read + +*/ + +CONST char * +DEFUN(bfd_core_file_failing_command,(abfd), + bfd *abfd) +{ + if (abfd->format != bfd_core) { + bfd_error = invalid_operation; + return NULL; + } + return BFD_SEND (abfd, _core_file_failing_command, (abfd)); +} + +/* +FUNCTION + bfd_core_file_failing_signal + +SYNOPSIS + int bfd_core_file_failing_signal(bfd *); + +DESCRIPTION + Returns the signal number which caused the core dump which + generated the file the BFD is attached to. +*/ + +int +bfd_core_file_failing_signal (abfd) + bfd *abfd; +{ + if (abfd->format != bfd_core) { + bfd_error = invalid_operation; + return 0; + } + return BFD_SEND (abfd, _core_file_failing_signal, (abfd)); +} + + +/* +FUNCTION + core_file_matches_executable_p + +SYNOPSIS + boolean core_file_matches_executable_p + (bfd *core_bfd, bfd *exec_bfd); + +DESCRIPTION + Returns <<true>> if the core file attached to @var{core_bfd} + was generated by a run of the executable file attached to + @var{exec_bfd}, or else <<false>>. +*/ +boolean +core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + if ((core_bfd->format != bfd_core) || (exec_bfd->format != bfd_object)) { + bfd_error = wrong_format; + return false; + } + + return BFD_SEND (core_bfd, _core_file_matches_executable_p, + (core_bfd, exec_bfd)); +} diff --git a/gnu/usr.bin/gdb/bfd/ctor.c b/gnu/usr.bin/gdb/bfd/ctor.c new file mode 100644 index 00000000000..3712c744420 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/ctor.c @@ -0,0 +1,151 @@ +/* BFD library support routines for constructors + Copyright (C) 1990-1991 Free Software Foundation, Inc. + + Hacked by Steve Chamberlain of Cygnus Support. With some help from + Judy Chamberlain too. + + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: ctor.c,v 1.1 1995/10/18 08:39:52 deraadt Exp $ +*/ + +/* +SECTION + Constructors + + Classes in C++ have `constructors' and `destructors'. These + are functions which are called automatically by the language + whenever data of a class is created or destroyed. Class data + which is static data may also be have a type which requires + `construction', the contructor must be called before the data + can be referenced, so the contructor must be called before the + program begins. + + The common solution to this problem is for the compiler to + call a magic function as the first statement <<main>>. + This magic function, (often called <<__main>>) runs around + calling the constructors for all the things needing it. + + With COFF the compile has a bargain with the linker et al. + All constructors are given strange names, for example + <<__GLOBAL__$I$foo>> might be the label of a contructor for + the class @var{foo}. The solution on unfortunate systems + (most system V machines) is to perform a partial link on all + the <<.o>> files, do an <<nm>> on the result, run <<awk>> or some + such over the result looking for strange <<__GLOBAL__$>> + symbols, generate a C program from this, compile it and link + with the partially linked input. This process is usually + called <<collect>>. + + Some versions of <<a.out>> use something called the + <<set_vector>> mechanism. The constructor symbols are output + from the compiler with a special stab code saying that they + are constructors, and the linker can deal with them directly. + + BFD allows applications (ie the linker) to deal with + constructor information independently of their external + implimentation by providing a set of entry points for the + indiviual object back ends to call which maintains a database + of the contructor information. The application can + interrogate the database to find out what it wants. The + construction data essential for the linker to be able to + perform its job are: + + o asymbol - + The asymbol of the contructor entry point contains all the + information necessary to call the function. + + o table id - + The type of symbol, i.e., is it a constructor, a destructor or + something else someone dreamed up to make our lives difficult. + + This module takes this information and then builds extra + sections attached to the bfds which own the entry points. It + creates these sections as if they were tables of pointers to + the entry points, and builds relocation entries to go with + them so that the tables can be relocated along with the data + they reference. + + These sections are marked with a special bit + (<<SEC_CONSTRUCTOR>>) which the linker notices and do with + what it wants. + +*/ + +#include <bfd.h> +#include <sysdep.h> +#include <libbfd.h> + + + +/* +INTERNAL_FUNCTION + bfd_constructor_entry + +SYNOPSIS + void bfd_constructor_entry(bfd *abfd, + asymbol **symbol_ptr_ptr, + CONST char*type); + + +DESCRIPTION + This function is called with an a symbol describing the + function to be called, an string which descibes the xtor type, + e.g., something like "CTOR" or "DTOR" would be fine. And the bfd + which owns the function. Its duty is to create a section + called "CTOR" or "DTOR" or whatever if the bfd doesn't already + have one, and grow a relocation table for the entry points as + they accumulate. + +*/ + + +void DEFUN(bfd_constructor_entry,(abfd, symbol_ptr_ptr, type), + bfd *abfd AND + asymbol **symbol_ptr_ptr AND + CONST char *type) + +{ + /* Look up the section we're using to store the table in */ + asection *rel_section = bfd_get_section_by_name (abfd, type); + if (rel_section == (asection *)NULL) { + rel_section = bfd_make_section (abfd, type); + rel_section->flags = SEC_CONSTRUCTOR; + rel_section->alignment_power = 2; + } + + /* Create a relocation into the section which references the entry + point */ + { + arelent_chain *reloc = (arelent_chain *)bfd_alloc(abfd, + sizeof(arelent_chain)); + +/* reloc->relent.section = (asection *)NULL;*/ + reloc->relent.addend = 0; + + reloc->relent.sym_ptr_ptr = symbol_ptr_ptr; + reloc->next = rel_section->constructor_chain; + rel_section->constructor_chain = reloc; + reloc->relent.address = rel_section->_cooked_size; + /* ask the cpu which howto to use */ + reloc->relent.howto = bfd_reloc_type_lookup(abfd, BFD_RELOC_CTOR); + rel_section->_cooked_size += sizeof(int *); + rel_section->reloc_count++; + } + +} diff --git a/gnu/usr.bin/gdb/bfd/ecoff.c b/gnu/usr.bin/gdb/bfd/ecoff.c new file mode 100644 index 00000000000..ca00e95dd5b --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/ecoff.c @@ -0,0 +1,3997 @@ +/* Generic ECOFF (Extended-COFF) routines. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Original version by Per Bothner. + Full support added by Ian Lance Taylor, ian@cygnus.com. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: ecoff.c,v 1.1 1995/10/18 08:39:52 deraadt Exp $ +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "seclet.h" +#include "aout/ar.h" +#include "aout/ranlib.h" + +/* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines + some other stuff which we don't want and which conflicts with stuff + we do want. */ +#include "libaout.h" +#include "aout/aout64.h" +#undef N_ABS +#undef exec_hdr +#undef obj_sym_filepos + +#include "coff/internal.h" +#include "coff/sym.h" +#include "coff/symconst.h" +#include "coff/ecoff.h" +#include "libcoff.h" +#include "libecoff.h" + +/* Prototypes for static functions. */ + +static int ecoff_get_magic PARAMS ((bfd *abfd)); +static void ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym, + asymbol *asym, int ext, + asymbol **indirect_ptr_ptr)); +static void ecoff_emit_aggregate PARAMS ((bfd *abfd, char *string, + RNDXR *rndx, long isym, + CONST char *which)); +static char *ecoff_type_to_string PARAMS ((bfd *abfd, union aux_ext *aux_ptr, + unsigned int indx, int bigendian)); +static boolean ecoff_slurp_reloc_table PARAMS ((bfd *abfd, asection *section, + asymbol **symbols)); +static void ecoff_clear_output_flags PARAMS ((bfd *abfd)); +static boolean ecoff_rel PARAMS ((bfd *output_bfd, bfd_seclet_type *seclet, + asection *output_section, PTR data, + boolean relocateable)); +static boolean ecoff_dump_seclet PARAMS ((bfd *abfd, bfd_seclet_type *seclet, + asection *section, PTR data, + boolean relocateable)); +static long ecoff_add_string PARAMS ((bfd *output_bfd, FDR *fdr, + CONST char *string, boolean external)); +static boolean ecoff_get_debug PARAMS ((bfd *output_bfd, + bfd_seclet_type *seclet, + asection *section, + boolean relocateable)); +static void ecoff_compute_section_file_positions PARAMS ((bfd *abfd)); +static unsigned int ecoff_armap_hash PARAMS ((CONST char *s, + unsigned int *rehash, + unsigned int size, + unsigned int hlog)); + +/* This stuff is somewhat copied from coffcode.h. */ + +static asection bfd_debug_section = { "*DEBUG*" }; + +/* Create an ECOFF object. */ + +boolean +ecoff_mkobject (abfd) + bfd *abfd; +{ + abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *) + bfd_zalloc (abfd, sizeof (ecoff_data_type))); + if (abfd->tdata.ecoff_obj_data == NULL) + { + bfd_error = no_memory; + return false; + } + + /* Always create a .scommon section for every BFD. This is a hack so + that the linker has something to attach scSCommon symbols to. */ + if (bfd_make_section (abfd, SCOMMON) == NULL) + return false; + + return true; +} + +/* This is a hook called by coff_real_object_p to create any backend + specific information. */ + +PTR +ecoff_mkobject_hook (abfd, filehdr, aouthdr) + bfd *abfd; + PTR filehdr; + PTR aouthdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr; + ecoff_data_type *ecoff; + asection *regsec; + + if (ecoff_mkobject (abfd) == false) + return NULL; + + ecoff = ecoff_data (abfd); + ecoff->gp_size = 8; + ecoff->sym_filepos = internal_f->f_symptr; + + /* Create the .reginfo section to give programs outside BFD a way to + see the information stored in the a.out header. See the comment + in coff/ecoff.h. */ + regsec = bfd_make_section (abfd, REGINFO); + if (regsec == NULL) + return NULL; + + if (internal_a != (struct internal_aouthdr *) NULL) + { + int i; + + ecoff->text_start = internal_a->text_start; + ecoff->text_end = internal_a->text_start + internal_a->tsize; + ecoff->gp = internal_a->gp_value; + ecoff->gprmask = internal_a->gprmask; + for (i = 0; i < 4; i++) + ecoff->cprmask[i] = internal_a->cprmask[i]; + ecoff->fprmask = internal_a->fprmask; + if (internal_a->magic == ECOFF_AOUT_ZMAGIC) + abfd->flags |= D_PAGED; + } + + /* It turns out that no special action is required by the MIPS or + Alpha ECOFF backends. They have different information in the + a.out header, but we just copy it all (e.g., gprmask, cprmask and + fprmask) and let the swapping routines ensure that only relevant + information is written out. */ + + return (PTR) ecoff; +} + +/* This is a hook needed by SCO COFF, but we have nothing to do. */ + +asection * +ecoff_make_section_hook (abfd, name) + bfd *abfd; + char *name; +{ + return (asection *) NULL; +} + +/* Initialize a new section. */ + +boolean +ecoff_new_section_hook (abfd, section) + bfd *abfd; + asection *section; +{ + section->alignment_power = abfd->xvec->align_power_min; + + if (strcmp (section->name, _TEXT) == 0) + section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; + else if (strcmp (section->name, _DATA) == 0 + || strcmp (section->name, _SDATA) == 0) + section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; + else if (strcmp (section->name, _RDATA) == 0 + || strcmp (section->name, _LIT8) == 0 + || strcmp (section->name, _LIT4) == 0) + section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY; + else if (strcmp (section->name, _BSS) == 0 + || strcmp (section->name, _SBSS) == 0) + section->flags |= SEC_ALLOC; + else if (strcmp (section->name, REGINFO) == 0) + { + section->flags |= SEC_HAS_CONTENTS | SEC_NEVER_LOAD; + section->_raw_size = sizeof (struct ecoff_reginfo); + } + + /* Probably any other section name is SEC_NEVER_LOAD, but I'm + uncertain about .init on some systems and I don't know how shared + libraries work. */ + + return true; +} + +/* Determine the machine architecture and type. This is called from + the generic COFF routines. It is the inverse of ecoff_get_magic, + below. This could be an ECOFF backend routine, with one version + for each target, but there aren't all that many ECOFF targets. */ + +boolean +ecoff_set_arch_mach_hook (abfd, filehdr) + bfd *abfd; + PTR filehdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + enum bfd_architecture arch; + unsigned long mach; + + switch (internal_f->f_magic) + { + case MIPS_MAGIC_1: + case MIPS_MAGIC_LITTLE: + case MIPS_MAGIC_BIG: + arch = bfd_arch_mips; + mach = 3000; + break; + + case MIPS_MAGIC_LITTLE2: + case MIPS_MAGIC_BIG2: + /* MIPS ISA level 2: the r6000 */ + arch = bfd_arch_mips; + mach = 6000; + break; + + case MIPS_MAGIC_LITTLE3: + case MIPS_MAGIC_BIG3: + /* MIPS ISA level 3: the r4000 */ + arch = bfd_arch_mips; + mach = 4000; + break; + + case ALPHA_MAGIC: + arch = bfd_arch_alpha; + mach = 0; + break; + + default: + arch = bfd_arch_obscure; + mach = 0; + break; + } + + return bfd_default_set_arch_mach (abfd, arch, mach); +} + +/* Get the magic number to use based on the architecture and machine. + This is the inverse of ecoff_set_arch_mach_hook, above. */ + +static int +ecoff_get_magic (abfd) + bfd *abfd; +{ + int big, little; + + switch (bfd_get_arch (abfd)) + { + case bfd_arch_mips: + switch (bfd_get_mach (abfd)) + { + default: + case 0: + case 3000: + big = MIPS_MAGIC_BIG; + little = MIPS_MAGIC_LITTLE; + break; + + case 6000: + big = MIPS_MAGIC_BIG2; + little = MIPS_MAGIC_LITTLE2; + break; + + case 4000: + big = MIPS_MAGIC_BIG3; + little = MIPS_MAGIC_LITTLE3; + break; + } + + return abfd->xvec->byteorder_big_p ? big : little; + + case bfd_arch_alpha: + return ALPHA_MAGIC; + + default: + abort (); + return 0; + } +} + +/* Get the section s_flags to use for a section. */ + +long +ecoff_sec_to_styp_flags (name, flags) + CONST char *name; + flagword flags; +{ + long styp; + + styp = 0; + + if (strcmp (name, _TEXT) == 0) + styp = STYP_TEXT; + else if (strcmp (name, _DATA) == 0) + styp = STYP_DATA; + else if (strcmp (name, _SDATA) == 0) + styp = STYP_SDATA; + else if (strcmp (name, _RDATA) == 0) + styp = STYP_RDATA; + else if (strcmp (name, _LIT8) == 0) + styp = STYP_LIT8; + else if (strcmp (name, _LIT4) == 0) + styp = STYP_LIT4; + else if (strcmp (name, _BSS) == 0) + styp = STYP_BSS; + else if (strcmp (name, _SBSS) == 0) + styp = STYP_SBSS; + else if (strcmp (name, _INIT) == 0) + styp = STYP_ECOFF_INIT; + else if (strcmp (name, _FINI) == 0) + styp = STYP_ECOFF_FINI; + else if (flags & SEC_CODE) + styp = STYP_TEXT; + else if (flags & SEC_DATA) + styp = STYP_DATA; + else if (flags & SEC_READONLY) + styp = STYP_RDATA; + else if (flags & SEC_LOAD) + styp = STYP_REG; + else + styp = STYP_BSS; + + if (flags & SEC_NEVER_LOAD) + styp |= STYP_NOLOAD; + + return styp; +} + +/* Get the BFD flags to use for a section. */ + +flagword +ecoff_styp_to_sec_flags (abfd, hdr) + bfd *abfd; + PTR hdr; +{ + struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; + long styp_flags = internal_s->s_flags; + flagword sec_flags=0; + + if (styp_flags & STYP_NOLOAD) + sec_flags |= SEC_NEVER_LOAD; + + /* For 386 COFF, at least, an unloadable text or data section is + actually a shared library section. */ + if ((styp_flags & STYP_TEXT) + || (styp_flags & STYP_ECOFF_INIT) + || (styp_flags & STYP_ECOFF_FINI)) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_CODE | SEC_SHARED_LIBRARY; + else + sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; + } + else if ((styp_flags & STYP_DATA) + || (styp_flags & STYP_RDATA) + || (styp_flags & STYP_SDATA)) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_DATA | SEC_SHARED_LIBRARY; + else + sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; + if (styp_flags & STYP_RDATA) + sec_flags |= SEC_READONLY; + } + else if ((styp_flags & STYP_BSS) + || (styp_flags & STYP_SBSS)) + { + sec_flags |= SEC_ALLOC; + } + else if (styp_flags & STYP_INFO) + { + sec_flags |= SEC_NEVER_LOAD; + } + else if ((styp_flags & STYP_LIT8) + || (styp_flags & STYP_LIT4)) + { + sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY; + } + else + { + sec_flags |= SEC_ALLOC | SEC_LOAD; + } + + return sec_flags; +} + +/* Routines to swap auxiliary information in and out. I am assuming + that the auxiliary information format is always going to be target + independent. */ + +/* Swap in a type information record. + BIGEND says whether AUX symbols are big-endian or little-endian; this + info comes from the file header record (fh-fBigendian). */ + +void +ecoff_swap_tir_in (bigend, ext_copy, intern) + int bigend; + struct tir_ext *ext_copy; + TIR *intern; +{ + struct tir_ext ext[1]; + + *ext = *ext_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG); + intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG); + intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_BIG) + >> TIR_BITS1_BT_SH_BIG; + intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG) + >> TIR_BITS_TQ4_SH_BIG; + intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG) + >> TIR_BITS_TQ5_SH_BIG; + intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG) + >> TIR_BITS_TQ0_SH_BIG; + intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG) + >> TIR_BITS_TQ1_SH_BIG; + intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG) + >> TIR_BITS_TQ2_SH_BIG; + intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG) + >> TIR_BITS_TQ3_SH_BIG; + } else { + intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE); + intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE); + intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE) + >> TIR_BITS1_BT_SH_LITTLE; + intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE) + >> TIR_BITS_TQ4_SH_LITTLE; + intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE) + >> TIR_BITS_TQ5_SH_LITTLE; + intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE) + >> TIR_BITS_TQ0_SH_LITTLE; + intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE) + >> TIR_BITS_TQ1_SH_LITTLE; + intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE) + >> TIR_BITS_TQ2_SH_LITTLE; + intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE) + >> TIR_BITS_TQ3_SH_LITTLE; + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out a type information record. + BIGEND says whether AUX symbols are big-endian or little-endian; this + info comes from the file header record (fh-fBigendian). */ + +void +ecoff_swap_tir_out (bigend, intern_copy, ext) + int bigend; + TIR *intern_copy; + struct tir_ext *ext; +{ + TIR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0) + | (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0) + | ((intern->bt << TIR_BITS1_BT_SH_BIG) + & TIR_BITS1_BT_BIG)); + ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG) + & TIR_BITS_TQ4_BIG) + | ((intern->tq5 << TIR_BITS_TQ5_SH_BIG) + & TIR_BITS_TQ5_BIG)); + ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG) + & TIR_BITS_TQ0_BIG) + | ((intern->tq1 << TIR_BITS_TQ1_SH_BIG) + & TIR_BITS_TQ1_BIG)); + ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG) + & TIR_BITS_TQ2_BIG) + | ((intern->tq3 << TIR_BITS_TQ3_SH_BIG) + & TIR_BITS_TQ3_BIG)); + } else { + ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0) + | (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0) + | ((intern->bt << TIR_BITS1_BT_SH_LITTLE) + & TIR_BITS1_BT_LITTLE)); + ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE) + & TIR_BITS_TQ4_LITTLE) + | ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE) + & TIR_BITS_TQ5_LITTLE)); + ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE) + & TIR_BITS_TQ0_LITTLE) + | ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE) + & TIR_BITS_TQ1_LITTLE)); + ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE) + & TIR_BITS_TQ2_LITTLE) + | ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE) + & TIR_BITS_TQ3_LITTLE)); + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap in a relative symbol record. BIGEND says whether it is in + big-endian or little-endian format.*/ + +void +ecoff_swap_rndx_in (bigend, ext_copy, intern) + int bigend; + struct rndx_ext *ext_copy; + RNDXR *intern; +{ + struct rndx_ext ext[1]; + + *ext = *ext_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG) + | ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG) + >> RNDX_BITS1_RFD_SH_BIG); + intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG) + << RNDX_BITS1_INDEX_SH_LEFT_BIG) + | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG) + | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG); + } else { + intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE) + | ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE) + << RNDX_BITS1_RFD_SH_LEFT_LITTLE); + intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE) + >> RNDX_BITS1_INDEX_SH_LITTLE) + | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE) + | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_LITTLE); + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Swap out a relative symbol record. BIGEND says whether it is in + big-endian or little-endian format.*/ + +void +ecoff_swap_rndx_out (bigend, intern_copy, ext) + int bigend; + RNDXR *intern_copy; + struct rndx_ext *ext; +{ + RNDXR intern[1]; + + *intern = *intern_copy; /* Make it reasonable to do in-place. */ + + /* now the fun stuff... */ + if (bigend) { + ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG; + ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG) + & RNDX_BITS1_RFD_BIG) + | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG) + & RNDX_BITS1_INDEX_BIG)); + ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG; + ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG; + } else { + ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE; + ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE) + & RNDX_BITS1_RFD_LITTLE) + | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE) + & RNDX_BITS1_INDEX_LITTLE)); + ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE; + ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE; + } + +#ifdef TEST + if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) + abort(); +#endif +} + +/* Read in and swap the important symbolic information for an ECOFF + object file. This is called by gdb. */ + +boolean +ecoff_slurp_symbolic_info (abfd) + bfd *abfd; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + bfd_size_type external_hdr_size; + HDRR *internal_symhdr; + bfd_size_type raw_base; + bfd_size_type raw_size; + PTR raw; + bfd_size_type external_fdr_size; + char *fraw_src; + char *fraw_end; + struct fdr *fdr_ptr; + bfd_size_type raw_end; + bfd_size_type cb_end; + + /* Check whether we've already gotten it, and whether there's any to + get. */ + if (ecoff_data (abfd)->raw_syments != (PTR) NULL) + return true; + if (ecoff_data (abfd)->sym_filepos == 0) + { + bfd_get_symcount (abfd) = 0; + return true; + } + + /* At this point bfd_get_symcount (abfd) holds the number of symbols + as read from the file header, but on ECOFF this is always the + size of the symbolic information header. It would be cleaner to + handle this when we first read the file in coffgen.c. */ + external_hdr_size = backend->external_hdr_size; + if (bfd_get_symcount (abfd) != external_hdr_size) + { + bfd_error = bad_value; + return false; + } + + /* Read the symbolic information header. */ + raw = (PTR) alloca (external_hdr_size); + if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) == -1 + || (bfd_read (raw, external_hdr_size, 1, abfd) + != external_hdr_size)) + { + bfd_error = system_call_error; + return false; + } + internal_symhdr = &ecoff_data (abfd)->symbolic_header; + (*backend->swap_hdr_in) (abfd, raw, internal_symhdr); + + if (internal_symhdr->magic != backend->sym_magic) + { + bfd_error = bad_value; + return false; + } + + /* Now we can get the correct number of symbols. */ + bfd_get_symcount (abfd) = (internal_symhdr->isymMax + + internal_symhdr->iextMax); + + /* Read all the symbolic information at once. */ + raw_base = ecoff_data (abfd)->sym_filepos + external_hdr_size; + + /* Alpha ecoff makes the determination of raw_size difficult. It has + an undocumented debug data section between the symhdr and the first + documented section. And the ordering of the sections varies between + statically and dynamically linked executables. + If bfd supports SEEK_END someday, this code could be simplified. */ + + raw_end = 0; + +#define UPDATE_RAW_END(start, count, size) \ + cb_end = internal_symhdr->start + internal_symhdr->count * (size); \ + if (cb_end > raw_end) \ + raw_end = cb_end + + UPDATE_RAW_END (cbLineOffset, cbLine, sizeof (unsigned char)); + UPDATE_RAW_END (cbDnOffset, idnMax, backend->external_dnr_size); + UPDATE_RAW_END (cbPdOffset, ipdMax, backend->external_pdr_size); + UPDATE_RAW_END (cbSymOffset, isymMax, backend->external_sym_size); + UPDATE_RAW_END (cbOptOffset, ioptMax, backend->external_opt_size); + UPDATE_RAW_END (cbAuxOffset, iauxMax, sizeof (union aux_ext)); + UPDATE_RAW_END (cbSsOffset, issMax, sizeof (char)); + UPDATE_RAW_END (cbSsExtOffset, issExtMax, sizeof (char)); + UPDATE_RAW_END (cbFdOffset, ifdMax, backend->external_fdr_size); + UPDATE_RAW_END (cbRfdOffset, crfd, backend->external_rfd_size); + UPDATE_RAW_END (cbExtOffset, iextMax, backend->external_ext_size); + +#undef UPDATE_RAW_END + + raw_size = raw_end - raw_base; + if (raw_size == 0) + { + ecoff_data (abfd)->sym_filepos = 0; + return true; + } + raw = (PTR) bfd_alloc (abfd, raw_size); + if (raw == NULL) + { + bfd_error = no_memory; + return false; + } + if (bfd_read (raw, raw_size, 1, abfd) != raw_size) + { + bfd_error = system_call_error; + bfd_release (abfd, raw); + return false; + } + + ecoff_data (abfd)->raw_size = raw_size; + ecoff_data (abfd)->raw_syments = raw; + + /* Get pointers for the numeric offsets in the HDRR structure. */ +#define FIX(off1, off2, type) \ + if (internal_symhdr->off1 == 0) \ + ecoff_data (abfd)->off2 = (type) NULL; \ + else \ + ecoff_data (abfd)->off2 = (type) ((char *) raw \ + + internal_symhdr->off1 \ + - raw_base) + FIX (cbLineOffset, line, unsigned char *); + FIX (cbDnOffset, external_dnr, PTR); + FIX (cbPdOffset, external_pdr, PTR); + FIX (cbSymOffset, external_sym, PTR); + FIX (cbOptOffset, external_opt, PTR); + FIX (cbAuxOffset, external_aux, union aux_ext *); + FIX (cbSsOffset, ss, char *); + FIX (cbSsExtOffset, ssext, char *); + FIX (cbFdOffset, external_fdr, PTR); + FIX (cbRfdOffset, external_rfd, PTR); + FIX (cbExtOffset, external_ext, PTR); +#undef FIX + + /* I don't want to always swap all the data, because it will just + waste time and most programs will never look at it. The only + time the linker needs most of the debugging information swapped + is when linking big-endian and little-endian MIPS object files + together, which is not a common occurrence. + + We need to look at the fdr to deal with a lot of information in + the symbols, so we swap them here. */ + ecoff_data (abfd)->fdr = + (struct fdr *) bfd_alloc (abfd, + (internal_symhdr->ifdMax * + sizeof (struct fdr))); + if (ecoff_data (abfd)->fdr == NULL) + { + bfd_error = no_memory; + return false; + } + external_fdr_size = backend->external_fdr_size; + fdr_ptr = ecoff_data (abfd)->fdr; + fraw_src = (char *) ecoff_data (abfd)->external_fdr; + fraw_end = fraw_src + internal_symhdr->ifdMax * external_fdr_size; + for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++) + (*backend->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr); + + return true; +} + +/* ECOFF symbol table routines. The ECOFF symbol table is described + in gcc/mips-tfile.c. */ + +/* ECOFF uses two common sections. One is the usual one, and the + other is for small objects. All the small objects are kept + together, and then referenced via the gp pointer, which yields + faster assembler code. This is what we use for the small common + section. */ +static asection ecoff_scom_section; +static asymbol ecoff_scom_symbol; +static asymbol *ecoff_scom_symbol_ptr; + +/* Create an empty symbol. */ + +asymbol * +ecoff_make_empty_symbol (abfd) + bfd *abfd; +{ + ecoff_symbol_type *new; + + new = (ecoff_symbol_type *) bfd_alloc (abfd, sizeof (ecoff_symbol_type)); + if (new == (ecoff_symbol_type *) NULL) + { + bfd_error = no_memory; + return (asymbol *) NULL; + } + memset (new, 0, sizeof *new); + new->symbol.section = (asection *) NULL; + new->fdr = (FDR *) NULL; + new->local = false; + new->native = NULL; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +/* Set the BFD flags and section for an ECOFF symbol. */ + +static void +ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, indirect_ptr_ptr) + bfd *abfd; + SYMR *ecoff_sym; + asymbol *asym; + int ext; + asymbol **indirect_ptr_ptr; +{ + asym->the_bfd = abfd; + asym->value = ecoff_sym->value; + asym->section = &bfd_debug_section; + asym->udata = NULL; + + /* An indirect symbol requires two consecutive stabs symbols. */ + if (*indirect_ptr_ptr != (asymbol *) NULL) + { + BFD_ASSERT (ECOFF_IS_STAB (ecoff_sym)); + + /* @@ Stuffing pointers into integers is a no-no. + We can usually get away with it if the integer is + large enough though. */ + if (sizeof (asym) > sizeof (bfd_vma)) + abort (); + (*indirect_ptr_ptr)->value = (bfd_vma) asym; + + asym->flags = BSF_DEBUGGING; + asym->section = &bfd_und_section; + *indirect_ptr_ptr = NULL; + return; + } + + if (ECOFF_IS_STAB (ecoff_sym) + && (ECOFF_UNMARK_STAB (ecoff_sym->index) | N_EXT) == (N_INDR | N_EXT)) + { + asym->flags = BSF_DEBUGGING | BSF_INDIRECT; + asym->section = &bfd_ind_section; + /* Pass this symbol on to the next call to this function. */ + *indirect_ptr_ptr = asym; + return; + } + + /* Most symbol types are just for debugging. */ + switch (ecoff_sym->st) + { + case stGlobal: + case stStatic: + case stLabel: + case stProc: + case stStaticProc: + break; + case stNil: + if (ECOFF_IS_STAB (ecoff_sym)) + { + asym->flags = BSF_DEBUGGING; + return; + } + break; + default: + asym->flags = BSF_DEBUGGING; + return; + } + + if (ext) + asym->flags = BSF_EXPORT | BSF_GLOBAL; + else + asym->flags = BSF_LOCAL; + switch (ecoff_sym->sc) + { + case scNil: + /* Used for compiler generated labels. Leave them in the + debugging section, and mark them as local. If BSF_DEBUGGING + is set, then nm does not display them for some reason. If no + flags are set then the linker whines about them. */ + asym->flags = BSF_LOCAL; + break; + case scText: + asym->section = bfd_make_section_old_way (abfd, ".text"); + asym->value -= asym->section->vma; + break; + case scData: + asym->section = bfd_make_section_old_way (abfd, ".data"); + asym->value -= asym->section->vma; + break; + case scBss: + asym->section = bfd_make_section_old_way (abfd, ".bss"); + asym->value -= asym->section->vma; + break; + case scRegister: + asym->flags = BSF_DEBUGGING; + break; + case scAbs: + asym->section = &bfd_abs_section; + break; + case scUndefined: + asym->section = &bfd_und_section; + asym->flags = 0; + asym->value = 0; + break; + case scCdbLocal: + case scBits: + case scCdbSystem: + case scRegImage: + case scInfo: + case scUserStruct: + asym->flags = BSF_DEBUGGING; + break; + case scSData: + asym->section = bfd_make_section_old_way (abfd, ".sdata"); + asym->value -= asym->section->vma; + break; + case scSBss: + asym->section = bfd_make_section_old_way (abfd, ".sbss"); + asym->value -= asym->section->vma; + break; + case scRData: + asym->section = bfd_make_section_old_way (abfd, ".rdata"); + asym->value -= asym->section->vma; + break; + case scVar: + asym->flags = BSF_DEBUGGING; + break; + case scCommon: + if (asym->value > ecoff_data (abfd)->gp_size) + { + asym->section = &bfd_com_section; + asym->flags = 0; + break; + } + /* Fall through. */ + case scSCommon: + if (ecoff_scom_section.name == NULL) + { + /* Initialize the small common section. */ + ecoff_scom_section.name = SCOMMON; + ecoff_scom_section.flags = SEC_IS_COMMON; + ecoff_scom_section.output_section = &ecoff_scom_section; + ecoff_scom_section.symbol = &ecoff_scom_symbol; + ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr; + ecoff_scom_symbol.name = SCOMMON; + ecoff_scom_symbol.flags = BSF_SECTION_SYM; + ecoff_scom_symbol.section = &ecoff_scom_section; + ecoff_scom_symbol_ptr = &ecoff_scom_symbol; + } + asym->section = &ecoff_scom_section; + asym->flags = 0; + break; + case scVarRegister: + case scVariant: + asym->flags = BSF_DEBUGGING; + break; + case scSUndefined: + asym->section = &bfd_und_section; + asym->flags = 0; + asym->value = 0; + break; + case scInit: + asym->section = bfd_make_section_old_way (abfd, ".init"); + asym->value -= asym->section->vma; + break; + case scBasedVar: + case scXData: + case scPData: + asym->flags = BSF_DEBUGGING; + break; + case scFini: + asym->section = bfd_make_section_old_way (abfd, ".fini"); + asym->value -= asym->section->vma; + break; + default: + break; + } + + /* Look for special constructors symbols and make relocation entries + in a special construction section. These are produced by the + -fgnu-linker argument to g++. */ + if (ECOFF_IS_STAB (ecoff_sym)) + { + switch (ECOFF_UNMARK_STAB (ecoff_sym->index)) + { + default: + break; + + case N_SETA: + case N_SETT: + case N_SETD: + case N_SETB: + { + const char *name; + asection *section; + arelent_chain *reloc_chain; + unsigned int bitsize; + + /* Get a section with the same name as the symbol (usually + __CTOR_LIST__ or __DTOR_LIST__). FIXME: gcc uses the + name ___CTOR_LIST (three underscores). We need + __CTOR_LIST (two underscores), since ECOFF doesn't use + a leading underscore. This should be handled by gcc, + but instead we do it here. Actually, this should all + be done differently anyhow. */ + name = bfd_asymbol_name (asym); + if (name[0] == '_' && name[1] == '_' && name[2] == '_') + { + ++name; + asym->name = name; + } + section = bfd_get_section_by_name (abfd, name); + if (section == (asection *) NULL) + { + char *copy; + + copy = (char *) bfd_alloc (abfd, strlen (name) + 1); + strcpy (copy, name); + section = bfd_make_section (abfd, copy); + } + + /* Build a reloc pointing to this constructor. */ + reloc_chain = + (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain)); + reloc_chain->relent.sym_ptr_ptr = + bfd_get_section (asym)->symbol_ptr_ptr; + reloc_chain->relent.address = section->_raw_size; + reloc_chain->relent.addend = asym->value; + reloc_chain->relent.howto = + ecoff_backend (abfd)->constructor_reloc; + + /* Set up the constructor section to hold the reloc. */ + section->flags = SEC_CONSTRUCTOR; + ++section->reloc_count; + + /* Constructor sections must be rounded to a boundary + based on the bitsize. These are not real sections-- + they are handled specially by the linker--so the ECOFF + 16 byte alignment restriction does not apply. */ + bitsize = ecoff_backend (abfd)->constructor_bitsize; + section->alignment_power = 1; + while ((1 << section->alignment_power) < bitsize / 8) + ++section->alignment_power; + + reloc_chain->next = section->constructor_chain; + section->constructor_chain = reloc_chain; + section->_raw_size += bitsize / 8; + + /* Mark the symbol as a constructor. */ + asym->flags |= BSF_CONSTRUCTOR; + } + break; + } + } +} + +/* Read an ECOFF symbol table. */ + +boolean +ecoff_slurp_symbol_table (abfd) + bfd *abfd; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + const bfd_size_type external_ext_size = backend->external_ext_size; + const bfd_size_type external_sym_size = backend->external_sym_size; + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = backend->swap_ext_in; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = backend->swap_sym_in; + bfd_size_type internal_size; + ecoff_symbol_type *internal; + ecoff_symbol_type *internal_ptr; + asymbol *indirect_ptr; + char *eraw_src; + char *eraw_end; + FDR *fdr_ptr; + FDR *fdr_end; + + /* If we've already read in the symbol table, do nothing. */ + if (ecoff_data (abfd)->canonical_symbols != NULL) + return true; + + /* Get the symbolic information. */ + if (ecoff_slurp_symbolic_info (abfd) == false) + return false; + if (bfd_get_symcount (abfd) == 0) + return true; + + internal_size = bfd_get_symcount (abfd) * sizeof (ecoff_symbol_type); + internal = (ecoff_symbol_type *) bfd_alloc (abfd, internal_size); + if (internal == NULL) + { + bfd_error = no_memory; + return false; + } + + internal_ptr = internal; + indirect_ptr = NULL; + eraw_src = (char *) ecoff_data (abfd)->external_ext; + eraw_end = (eraw_src + + (ecoff_data (abfd)->symbolic_header.iextMax + * external_ext_size)); + for (; eraw_src < eraw_end; eraw_src += external_ext_size, internal_ptr++) + { + EXTR internal_esym; + + (*swap_ext_in) (abfd, (PTR) eraw_src, &internal_esym); + internal_ptr->symbol.name = (ecoff_data (abfd)->ssext + + internal_esym.asym.iss); + ecoff_set_symbol_info (abfd, &internal_esym.asym, + &internal_ptr->symbol, 1, &indirect_ptr); + /* The alpha uses a negative ifd field for section symbols. */ + if (internal_esym.ifd >= 0) + internal_ptr->fdr = ecoff_data (abfd)->fdr + internal_esym.ifd; + else + internal_ptr->fdr = NULL; + internal_ptr->local = false; + internal_ptr->native = (PTR) eraw_src; + } + BFD_ASSERT (indirect_ptr == (asymbol *) NULL); + + /* The local symbols must be accessed via the fdr's, because the + string and aux indices are relative to the fdr information. */ + fdr_ptr = ecoff_data (abfd)->fdr; + fdr_end = fdr_ptr + ecoff_data (abfd)->symbolic_header.ifdMax; + for (; fdr_ptr < fdr_end; fdr_ptr++) + { + char *lraw_src; + char *lraw_end; + + lraw_src = ((char *) ecoff_data (abfd)->external_sym + + fdr_ptr->isymBase * external_sym_size); + lraw_end = lraw_src + fdr_ptr->csym * external_sym_size; + for (; + lraw_src < lraw_end; + lraw_src += external_sym_size, internal_ptr++) + { + SYMR internal_sym; + + (*swap_sym_in) (abfd, (PTR) lraw_src, &internal_sym); + internal_ptr->symbol.name = (ecoff_data (abfd)->ss + + fdr_ptr->issBase + + internal_sym.iss); + ecoff_set_symbol_info (abfd, &internal_sym, + &internal_ptr->symbol, 0, &indirect_ptr); + internal_ptr->fdr = fdr_ptr; + internal_ptr->local = true; + internal_ptr->native = (PTR) lraw_src; + } + } + BFD_ASSERT (indirect_ptr == (asymbol *) NULL); + + ecoff_data (abfd)->canonical_symbols = internal; + + return true; +} + +/* Return the amount of space needed for the canonical symbols. */ + +unsigned int +ecoff_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + if (ecoff_slurp_symbolic_info (abfd) == false + || bfd_get_symcount (abfd) == 0) + return 0; + + return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *)); +} + +/* Get the canonicals symbols. */ + +unsigned int +ecoff_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + unsigned int counter = 0; + ecoff_symbol_type *symbase; + ecoff_symbol_type **location = (ecoff_symbol_type **) alocation; + + if (ecoff_slurp_symbol_table (abfd) == false + || bfd_get_symcount (abfd) == 0) + return 0; + + symbase = ecoff_data (abfd)->canonical_symbols; + while (counter < bfd_get_symcount (abfd)) + { + *(location++) = symbase++; + counter++; + } + *location++ = (ecoff_symbol_type *) NULL; + return bfd_get_symcount (abfd); +} + +/* Turn ECOFF type information into a printable string. + ecoff_emit_aggregate and ecoff_type_to_string are from + gcc/mips-tdump.c, with swapping added and used_ptr removed. */ + +/* Write aggregate information to a string. */ + +static void +ecoff_emit_aggregate (abfd, string, rndx, isym, which) + bfd *abfd; + char *string; + RNDXR *rndx; + long isym; + CONST char *which; +{ + int ifd = rndx->rfd; + int indx = rndx->index; + int sym_base, ss_base; + CONST char *name; + + if (ifd == 0xfff) + ifd = isym; + + sym_base = ecoff_data (abfd)->fdr[ifd].isymBase; + ss_base = ecoff_data (abfd)->fdr[ifd].issBase; + + if (indx == indexNil) + name = "/* no name */"; + else + { + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + SYMR sym; + + indx += sym_base; + (*backend->swap_sym_in) (abfd, + ((char *) ecoff_data (abfd)->external_sym + + indx * backend->external_sym_size), + &sym); + name = ecoff_data (abfd)->ss + ss_base + sym.iss; + } + + sprintf (string, + "%s %s { ifd = %d, index = %d }", + which, name, ifd, + indx + ecoff_data (abfd)->symbolic_header.iextMax); +} + +/* Convert the type information to string format. */ + +static char * +ecoff_type_to_string (abfd, aux_ptr, indx, bigendian) + bfd *abfd; + union aux_ext *aux_ptr; + unsigned int indx; + int bigendian; +{ + AUXU u; + struct qual { + unsigned int type; + int low_bound; + int high_bound; + int stride; + } qualifiers[7]; + + unsigned int basic_type; + int i; + static char buffer1[1024]; + static char buffer2[1024]; + char *p1 = buffer1; + char *p2 = buffer2; + RNDXR rndx; + + for (i = 0; i < 7; i++) + { + qualifiers[i].low_bound = 0; + qualifiers[i].high_bound = 0; + qualifiers[i].stride = 0; + } + + if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == -1) + return "-1 (no type)"; + ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti); + + basic_type = u.ti.bt; + qualifiers[0].type = u.ti.tq0; + qualifiers[1].type = u.ti.tq1; + qualifiers[2].type = u.ti.tq2; + qualifiers[3].type = u.ti.tq3; + qualifiers[4].type = u.ti.tq4; + qualifiers[5].type = u.ti.tq5; + qualifiers[6].type = tqNil; + + /* + * Go get the basic type. + */ + switch (basic_type) + { + case btNil: /* undefined */ + strcpy (p1, "nil"); + break; + + case btAdr: /* address - integer same size as pointer */ + strcpy (p1, "address"); + break; + + case btChar: /* character */ + strcpy (p1, "char"); + break; + + case btUChar: /* unsigned character */ + strcpy (p1, "unsigned char"); + break; + + case btShort: /* short */ + strcpy (p1, "short"); + break; + + case btUShort: /* unsigned short */ + strcpy (p1, "unsigned short"); + break; + + case btInt: /* int */ + strcpy (p1, "int"); + break; + + case btUInt: /* unsigned int */ + strcpy (p1, "unsigned int"); + break; + + case btLong: /* long */ + strcpy (p1, "long"); + break; + + case btULong: /* unsigned long */ + strcpy (p1, "unsigned long"); + break; + + case btFloat: /* float (real) */ + strcpy (p1, "float"); + break; + + case btDouble: /* Double (real) */ + strcpy (p1, "double"); + break; + + /* Structures add 1-2 aux words: + 1st word is [ST_RFDESCAPE, offset] pointer to struct def; + 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ + + case btStruct: /* Structure (Record) */ + ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, p1, &rndx, + AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + "struct"); + indx++; /* skip aux words */ + break; + + /* Unions add 1-2 aux words: + 1st word is [ST_RFDESCAPE, offset] pointer to union def; + 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ + + case btUnion: /* Union */ + ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, p1, &rndx, + AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + "union"); + indx++; /* skip aux words */ + break; + + /* Enumerations add 1-2 aux words: + 1st word is [ST_RFDESCAPE, offset] pointer to enum def; + 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ + + case btEnum: /* Enumeration */ + ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); + ecoff_emit_aggregate (abfd, p1, &rndx, + AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), + "enum"); + indx++; /* skip aux words */ + break; + + case btTypedef: /* defined via a typedef, isymRef points */ + strcpy (p1, "typedef"); + break; + + case btRange: /* subrange of int */ + strcpy (p1, "subrange"); + break; + + case btSet: /* pascal sets */ + strcpy (p1, "set"); + break; + + case btComplex: /* fortran complex */ + strcpy (p1, "complex"); + break; + + case btDComplex: /* fortran double complex */ + strcpy (p1, "double complex"); + break; + + case btIndirect: /* forward or unnamed typedef */ + strcpy (p1, "forward/unamed typedef"); + break; + + case btFixedDec: /* Fixed Decimal */ + strcpy (p1, "fixed decimal"); + break; + + case btFloatDec: /* Float Decimal */ + strcpy (p1, "float decimal"); + break; + + case btString: /* Varying Length Character String */ + strcpy (p1, "string"); + break; + + case btBit: /* Aligned Bit String */ + strcpy (p1, "bit"); + break; + + case btPicture: /* Picture */ + strcpy (p1, "picture"); + break; + + case btVoid: /* Void */ + strcpy (p1, "void"); + break; + + default: + sprintf (p1, "Unknown basic type %d", (int) basic_type); + break; + } + + p1 += strlen (buffer1); + + /* + * If this is a bitfield, get the bitsize. + */ + if (u.ti.fBitfield) + { + int bitsize; + + bitsize = AUX_GET_WIDTH (bigendian, &aux_ptr[indx++]); + sprintf (p1, " : %d", bitsize); + p1 += strlen (buffer1); + } + + + /* + * Deal with any qualifiers. + */ + if (qualifiers[0].type != tqNil) + { + /* + * Snarf up any array bounds in the correct order. Arrays + * store 5 successive words in the aux. table: + * word 0 RNDXR to type of the bounds (ie, int) + * word 1 Current file descriptor index + * word 2 low bound + * word 3 high bound (or -1 if []) + * word 4 stride size in bits + */ + for (i = 0; i < 7; i++) + { + if (qualifiers[i].type == tqArray) + { + qualifiers[i].low_bound = + AUX_GET_DNLOW (bigendian, &aux_ptr[indx+2]); + qualifiers[i].high_bound = + AUX_GET_DNHIGH (bigendian, &aux_ptr[indx+3]); + qualifiers[i].stride = + AUX_GET_WIDTH (bigendian, &aux_ptr[indx+4]); + indx += 5; + } + } + + /* + * Now print out the qualifiers. + */ + for (i = 0; i < 6; i++) + { + switch (qualifiers[i].type) + { + case tqNil: + case tqMax: + break; + + case tqPtr: + strcpy (p2, "ptr to "); + p2 += sizeof ("ptr to ")-1; + break; + + case tqVol: + strcpy (p2, "volatile "); + p2 += sizeof ("volatile ")-1; + break; + + case tqFar: + strcpy (p2, "far "); + p2 += sizeof ("far ")-1; + break; + + case tqProc: + strcpy (p2, "func. ret. "); + p2 += sizeof ("func. ret. "); + break; + + case tqArray: + { + int first_array = i; + int j; + + /* Print array bounds reversed (ie, in the order the C + programmer writes them). C is such a fun language.... */ + + while (i < 5 && qualifiers[i+1].type == tqArray) + i++; + + for (j = i; j >= first_array; j--) + { + strcpy (p2, "array ["); + p2 += sizeof ("array [")-1; + if (qualifiers[j].low_bound != 0) + sprintf (p2, + "%ld:%ld {%ld bits}", + (long) qualifiers[j].low_bound, + (long) qualifiers[j].high_bound, + (long) qualifiers[j].stride); + + else if (qualifiers[j].high_bound != -1) + sprintf (p2, + "%ld {%ld bits}", + (long) (qualifiers[j].high_bound + 1), + (long) (qualifiers[j].stride)); + + else + sprintf (p2, " {%ld bits}", (long) (qualifiers[j].stride)); + + p2 += strlen (p2); + strcpy (p2, "] of "); + p2 += sizeof ("] of ")-1; + } + } + break; + } + } + } + + strcpy (p2, buffer1); + return buffer2; +} + +/* Return information about ECOFF symbol SYMBOL in RET. */ + +void +ecoff_get_symbol_info (abfd, symbol, ret) + bfd *abfd; /* Ignored. */ + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +/* Print information about an ECOFF symbol. */ + +void +ecoff_print_symbol (abfd, filep, symbol, how) + bfd *abfd; + PTR filep; + asymbol *symbol; + bfd_print_symbol_type how; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + FILE *file = (FILE *)filep; + + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + case bfd_print_symbol_more: + if (ecoffsymbol (symbol)->local) + { + SYMR ecoff_sym; + + (*backend->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_sym); + fprintf (file, "ecoff local "); + fprintf_vma (file, (bfd_vma) ecoff_sym.value); + fprintf (file, " %x %x", (unsigned) ecoff_sym.st, + (unsigned) ecoff_sym.sc); + } + else + { + EXTR ecoff_ext; + + (*backend->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext); + fprintf (file, "ecoff extern "); + fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value); + fprintf (file, " %x %x", (unsigned) ecoff_ext.asym.st, + (unsigned) ecoff_ext.asym.sc); + } + break; + case bfd_print_symbol_all: + /* Print out the symbols in a reasonable way */ + { + char type; + int pos; + EXTR ecoff_ext; + char jmptbl; + char cobol_main; + char weakext; + + if (ecoffsymbol (symbol)->local) + { + (*backend->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext.asym); + type = 'l'; + pos = ((((char *) ecoffsymbol (symbol)->native + - (char *) ecoff_data (abfd)->external_sym) + / backend->external_sym_size) + + ecoff_data (abfd)->symbolic_header.iextMax); + jmptbl = ' '; + cobol_main = ' '; + weakext = ' '; + } + else + { + (*backend->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, + &ecoff_ext); + type = 'e'; + pos = (((char *) ecoffsymbol (symbol)->native + - (char *) ecoff_data (abfd)->external_ext) + / backend->external_ext_size); + jmptbl = ecoff_ext.jmptbl ? 'j' : ' '; + cobol_main = ecoff_ext.cobol_main ? 'c' : ' '; + weakext = ecoff_ext.weakext ? 'w' : ' '; + } + + fprintf (file, "[%3d] %c ", + pos, type); + fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value); + fprintf (file, " st %x sc %x indx %x %c%c%c %s", + (unsigned) ecoff_ext.asym.st, + (unsigned) ecoff_ext.asym.sc, + (unsigned) ecoff_ext.asym.index, + jmptbl, cobol_main, weakext, + symbol->name); + + if (ecoffsymbol (symbol)->fdr != NULL + && ecoff_ext.asym.index != indexNil) + { + unsigned int indx; + int bigendian; + bfd_size_type sym_base; + union aux_ext *aux_base; + + indx = ecoff_ext.asym.index; + + /* sym_base is used to map the fdr relative indices which + appear in the file to the position number which we are + using. */ + sym_base = ecoffsymbol (symbol)->fdr->isymBase; + if (ecoffsymbol (symbol)->local) + sym_base += ecoff_data (abfd)->symbolic_header.iextMax; + + /* aux_base is the start of the aux entries for this file; + asym.index is an offset from this. */ + aux_base = (ecoff_data (abfd)->external_aux + + ecoffsymbol (symbol)->fdr->iauxBase); + + /* The aux entries are stored in host byte order; the + order is indicated by a bit in the fdr. */ + bigendian = ecoffsymbol (symbol)->fdr->fBigendian; + + /* This switch is basically from gcc/mips-tdump.c */ + switch (ecoff_ext.asym.st) + { + case stNil: + case stLabel: + break; + + case stFile: + case stBlock: + fprintf (file, "\n End+1 symbol: %ld", + (long) (indx + sym_base)); + break; + + case stEnd: + if (ecoff_ext.asym.sc == scText + || ecoff_ext.asym.sc == scInfo) + fprintf (file, "\n First symbol: %ld", + (long) (indx + sym_base)); + else + fprintf (file, "\n First symbol: %ld", + (long) (AUX_GET_ISYM (bigendian, + &aux_base[ecoff_ext.asym.index]) + + sym_base)); + break; + + case stProc: + case stStaticProc: + if (ECOFF_IS_STAB (&ecoff_ext.asym)) + ; + else if (ecoffsymbol (symbol)->local) + fprintf (file, "\n End+1 symbol: %-7ld Type: %s", + (long) (AUX_GET_ISYM (bigendian, + &aux_base[ecoff_ext.asym.index]) + + sym_base), + ecoff_type_to_string (abfd, aux_base, indx + 1, + bigendian)); + else + fprintf (file, "\n Local symbol: %d", + (indx + + sym_base + + ecoff_data (abfd)->symbolic_header.iextMax)); + break; + + default: + if (! ECOFF_IS_STAB (&ecoff_ext.asym)) + fprintf (file, "\n Type: %s", + ecoff_type_to_string (abfd, aux_base, indx, + bigendian)); + break; + } + } + } + break; + } +} + +/* Read in the relocs for a section. */ + +static boolean +ecoff_slurp_reloc_table (abfd, section, symbols) + bfd *abfd; + asection *section; + asymbol **symbols; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + arelent *internal_relocs; + bfd_size_type external_reloc_size; + bfd_size_type external_relocs_size; + char *external_relocs; + arelent *rptr; + unsigned int i; + + if (section->relocation != (arelent *) NULL + || section->reloc_count == 0 + || (section->flags & SEC_CONSTRUCTOR) != 0) + return true; + + if (ecoff_slurp_symbol_table (abfd) == false) + return false; + + internal_relocs = (arelent *) bfd_alloc (abfd, + (sizeof (arelent) + * section->reloc_count)); + external_reloc_size = backend->external_reloc_size; + external_relocs_size = external_reloc_size * section->reloc_count; + external_relocs = (char *) bfd_alloc (abfd, external_relocs_size); + if (internal_relocs == (arelent *) NULL + || external_relocs == (char *) NULL) + { + bfd_error = no_memory; + return false; + } + if (bfd_seek (abfd, section->rel_filepos, SEEK_SET) != 0) + return false; + if (bfd_read (external_relocs, 1, external_relocs_size, abfd) + != external_relocs_size) + { + bfd_error = system_call_error; + return false; + } + + for (i = 0, rptr = internal_relocs; i < section->reloc_count; i++, rptr++) + { + struct internal_reloc intern; + + (*backend->swap_reloc_in) (abfd, + external_relocs + i * external_reloc_size, + &intern); + + if (intern.r_extern) + { + /* r_symndx is an index into the external symbols. */ + BFD_ASSERT (intern.r_symndx >= 0 + && (intern.r_symndx + < ecoff_data (abfd)->symbolic_header.iextMax)); + rptr->sym_ptr_ptr = symbols + intern.r_symndx; + rptr->addend = 0; + } + else if (intern.r_symndx == RELOC_SECTION_NONE + || intern.r_symndx == RELOC_SECTION_ABS) + { + rptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr; + rptr->addend = 0; + } + else + { + CONST char *sec_name; + asection *sec; + + /* r_symndx is a section key. */ + switch (intern.r_symndx) + { + case RELOC_SECTION_TEXT: sec_name = ".text"; break; + case RELOC_SECTION_RDATA: sec_name = ".rdata"; break; + case RELOC_SECTION_DATA: sec_name = ".data"; break; + case RELOC_SECTION_SDATA: sec_name = ".sdata"; break; + case RELOC_SECTION_SBSS: sec_name = ".sbss"; break; + case RELOC_SECTION_BSS: sec_name = ".bss"; break; + case RELOC_SECTION_INIT: sec_name = ".init"; break; + case RELOC_SECTION_LIT8: sec_name = ".lit8"; break; + case RELOC_SECTION_LIT4: sec_name = ".lit4"; break; + case RELOC_SECTION_XDATA: sec_name = ".xdata"; break; + case RELOC_SECTION_PDATA: sec_name = ".pdata"; break; + case RELOC_SECTION_LITA: sec_name = ".lita"; break; + default: abort (); + } + + sec = bfd_get_section_by_name (abfd, sec_name); + if (sec == (asection *) NULL) + abort (); + rptr->sym_ptr_ptr = sec->symbol_ptr_ptr; + + rptr->addend = - bfd_get_section_vma (abfd, sec); + } + + rptr->address = intern.r_vaddr - bfd_get_section_vma (abfd, section); + + /* Let the backend select the howto field and do any other + required processing. */ + (*backend->finish_reloc) (abfd, &intern, rptr); + } + + bfd_release (abfd, external_relocs); + + section->relocation = internal_relocs; + + return true; +} + +/* Get a canonical list of relocs. */ + +unsigned int +ecoff_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + asection *section; + arelent **relptr; + asymbol **symbols; +{ + unsigned int count; + + if (section->flags & SEC_CONSTRUCTOR) + { + arelent_chain *chain; + + /* This section has relocs made up by us, not the file, so take + them out of their chain and place them into the data area + provided. */ + for (count = 0, chain = section->constructor_chain; + count < section->reloc_count; + count++, chain = chain->next) + *relptr++ = &chain->relent; + } + else + { + arelent *tblptr; + + if (ecoff_slurp_reloc_table (abfd, section, symbols) == false) + return 0; + + tblptr = section->relocation; + if (tblptr == (arelent *) NULL) + return 0; + + for (count = 0; count < section->reloc_count; count++) + *relptr++ = tblptr++; + } + + *relptr = (arelent *) NULL; + + return section->reloc_count; +} + +/* Provided a BFD, a section and an offset into the section, calculate + and return the name of the source file and the line nearest to the + wanted location. */ + +boolean +ecoff_find_nearest_line (abfd, + section, + ignore_symbols, + offset, + filename_ptr, + functionname_ptr, + retline_ptr) + bfd *abfd; + asection *section; + asymbol **ignore_symbols; + bfd_vma offset; + CONST char **filename_ptr; + CONST char **functionname_ptr; + unsigned int *retline_ptr; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + FDR *fdr_ptr; + FDR *fdr_start; + FDR *fdr_end; + FDR *fdr_hold; + bfd_size_type external_pdr_size; + char *pdr_ptr; + char *pdr_end; + PDR pdr; + unsigned char *line_ptr; + unsigned char *line_end; + int lineno; + + /* If we're not in the .text section, we don't have any line + numbers. */ + if (strcmp (section->name, _TEXT) != 0 + || offset < ecoff_data (abfd)->text_start + || offset >= ecoff_data (abfd)->text_end) + return false; + + /* Make sure we have the FDR's. */ + if (ecoff_slurp_symbolic_info (abfd) == false + || bfd_get_symcount (abfd) == 0) + return false; + + /* Each file descriptor (FDR) has a memory address. Here we track + down which FDR we want. The FDR's are stored in increasing + memory order. If speed is ever important, this can become a + binary search. We must ignore FDR's with no PDR entries; they + will have the adr of the FDR before or after them. */ + fdr_start = ecoff_data (abfd)->fdr; + fdr_end = fdr_start + ecoff_data (abfd)->symbolic_header.ifdMax; + fdr_hold = (FDR *) NULL; + for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) + { + if (fdr_ptr->cpd == 0) + continue; + if (offset < fdr_ptr->adr) + break; + fdr_hold = fdr_ptr; + } + if (fdr_hold == (FDR *) NULL) + return false; + fdr_ptr = fdr_hold; + + /* Each FDR has a list of procedure descriptors (PDR). PDR's also + have an address, which is relative to the FDR address, and are + also stored in increasing memory order. */ + offset -= fdr_ptr->adr; + external_pdr_size = backend->external_pdr_size; + pdr_ptr = ((char *) ecoff_data (abfd)->external_pdr + + fdr_ptr->ipdFirst * external_pdr_size); + pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size; + (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + + /* The address of the first PDR is an offset which applies to the + addresses of all the PDR's. */ + offset += pdr.adr; + + for (pdr_ptr += external_pdr_size; + pdr_ptr < pdr_end; + pdr_ptr += external_pdr_size) + { + (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + if (offset < pdr.adr) + break; + } + + /* Now we can look for the actual line number. The line numbers are + stored in a very funky format, which I won't try to describe. + Note that right here pdr_ptr and pdr hold the PDR *after* the one + we want; we need this to compute line_end. */ + line_end = ecoff_data (abfd)->line; + if (pdr_ptr == pdr_end) + line_end += fdr_ptr->cbLineOffset + fdr_ptr->cbLine; + else + line_end += fdr_ptr->cbLineOffset + pdr.cbLineOffset; + + /* Now change pdr and pdr_ptr to the one we want. */ + pdr_ptr -= external_pdr_size; + (*backend->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr); + + offset -= pdr.adr; + lineno = pdr.lnLow; + line_ptr = (ecoff_data (abfd)->line + + fdr_ptr->cbLineOffset + + pdr.cbLineOffset); + while (line_ptr < line_end) + { + int delta; + int count; + + delta = *line_ptr >> 4; + if (delta >= 0x8) + delta -= 0x10; + count = (*line_ptr & 0xf) + 1; + ++line_ptr; + if (delta == -8) + { + delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff); + if (delta >= 0x8000) + delta -= 0x10000; + line_ptr += 2; + } + lineno += delta; + if (offset < count * 4) + break; + offset -= count * 4; + } + + /* If fdr_ptr->rss is -1, then this file does not have full symbols, + at least according to gdb/mipsread.c. */ + if (fdr_ptr->rss == -1) + { + *filename_ptr = NULL; + if (pdr.isym == -1) + *functionname_ptr = NULL; + else + { + EXTR proc_ext; + + (*backend->swap_ext_in) (abfd, + ((char *) ecoff_data (abfd)->external_ext + + pdr.isym * backend->external_ext_size), + &proc_ext); + *functionname_ptr = ecoff_data (abfd)->ssext + proc_ext.asym.iss; + } + } + else + { + SYMR proc_sym; + + *filename_ptr = ecoff_data (abfd)->ss + fdr_ptr->issBase + fdr_ptr->rss; + (*backend->swap_sym_in) (abfd, + ((char *) ecoff_data (abfd)->external_sym + + ((fdr_ptr->isymBase + pdr.isym) + * backend->external_sym_size)), + &proc_sym); + *functionname_ptr = (ecoff_data (abfd)->ss + + fdr_ptr->issBase + + proc_sym.iss); + } + if (lineno == ilineNil) + lineno = 0; + *retline_ptr = lineno; + return true; +} + +/* We can't use the generic linking routines for ECOFF, because we + have to handle all the debugging information. The generic link + routine just works out the section contents and attaches a list of + symbols. + + We link by looping over all the seclets. We make two passes. On + the first we set the actual section contents and determine the size + of the debugging information. On the second we accumulate the + debugging information and write it out. + + This currently always accumulates the debugging information, which + is incorrect, because it ignores the -s and -S options of the + linker. The linker needs to be modified to give us that + information in a more useful format (currently it just provides a + list of symbols which should appear in the output file). */ + +/* Clear the output_has_begun flag for all the input BFD's. We use it + to avoid linking in the debugging information for a BFD more than + once. */ + +static void +ecoff_clear_output_flags (abfd) + bfd *abfd; +{ + register asection *o; + register bfd_seclet_type *p; + + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + for (p = o->seclets_head; + p != (bfd_seclet_type *) NULL; + p = p->next) + if (p->type == bfd_indirect_seclet) + p->u.indirect.section->owner->output_has_begun = false; +} + +/* Handle an indirect seclet on the first pass. Set the contents of + the output section, and accumulate the debugging information if + any. */ + +static boolean +ecoff_rel (output_bfd, seclet, output_section, data, relocateable) + bfd *output_bfd; + bfd_seclet_type *seclet; + asection *output_section; + PTR data; + boolean relocateable; +{ + bfd *input_bfd; + HDRR *output_symhdr; + HDRR *input_symhdr; + + if ((output_section->flags & SEC_HAS_CONTENTS) + && !(output_section->flags & SEC_NEVER_LOAD) + && (output_section->flags & SEC_LOAD) + && seclet->size) + { + data = (PTR) bfd_get_relocated_section_contents (output_bfd, + seclet, + data, + relocateable); + if (bfd_set_section_contents (output_bfd, + output_section, + data, + seclet->offset, + seclet->size) + == false) + { + abort(); + } + } + + input_bfd = seclet->u.indirect.section->owner; + + /* We want to figure out how much space will be required to + incorporate all the debugging information from input_bfd. We use + the output_has_begun field to avoid adding it in more than once. + The actual incorporation is done in the second pass, in + ecoff_get_debug. The code has to parallel that code in its + manipulations of output_symhdr. */ + + if (input_bfd->output_has_begun) + return true; + input_bfd->output_has_begun = true; + + output_symhdr = &ecoff_data (output_bfd)->symbolic_header; + + if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour) + { + asymbol **symbols; + asymbol **sym_ptr; + asymbol **sym_end; + + /* We just accumulate local symbols from a non-ECOFF BFD. The + external symbols are handled separately. */ + + symbols = (asymbol **) bfd_alloc (output_bfd, + get_symtab_upper_bound (input_bfd)); + if (symbols == (asymbol **) NULL) + { + bfd_error = no_memory; + return false; + } + sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols); + + for (sym_ptr = symbols; sym_ptr < sym_end; sym_ptr++) + { + size_t len; + + len = strlen ((*sym_ptr)->name); + if (((*sym_ptr)->flags & BSF_EXPORT) == 0) + { + ++output_symhdr->isymMax; + output_symhdr->issMax += len + 1; + } + } + + bfd_release (output_bfd, (PTR) symbols); + + ++output_symhdr->ifdMax; + + return true; + } + + /* We simply add in the information from another ECOFF BFD. First + we make sure we have the symbolic information. */ + if (ecoff_slurp_symbol_table (input_bfd) == false) + return false; + if (bfd_get_symcount (input_bfd) == 0) + return true; + + input_symhdr = &ecoff_data (input_bfd)->symbolic_header; + + /* Figure out how much information we are going to be putting in. + The external symbols are handled separately. */ + output_symhdr->ilineMax += input_symhdr->ilineMax; + output_symhdr->cbLine += input_symhdr->cbLine; + output_symhdr->idnMax += input_symhdr->idnMax; + output_symhdr->ipdMax += input_symhdr->ipdMax; + output_symhdr->isymMax += input_symhdr->isymMax; + output_symhdr->ioptMax += input_symhdr->ioptMax; + output_symhdr->iauxMax += input_symhdr->iauxMax; + output_symhdr->issMax += input_symhdr->issMax; + output_symhdr->ifdMax += input_symhdr->ifdMax; + + /* The RFD's are special, since we create them if needed. */ + if (input_symhdr->crfd > 0) + output_symhdr->crfd += input_symhdr->crfd; + else + output_symhdr->crfd += input_symhdr->ifdMax; + + return true; +} + +/* Handle an arbitrary seclet on the first pass. */ + +static boolean +ecoff_dump_seclet (abfd, seclet, section, data, relocateable) + bfd *abfd; + bfd_seclet_type *seclet; + asection *section; + PTR data; + boolean relocateable; +{ + switch (seclet->type) + { + case bfd_indirect_seclet: + /* The contents of this section come from another one somewhere + else. */ + return ecoff_rel (abfd, seclet, section, data, relocateable); + + case bfd_fill_seclet: + /* Fill in the section with fill.value. This is used to pad out + sections, but we must avoid padding the .bss section. */ + if ((section->flags & SEC_HAS_CONTENTS) == 0) + { + if (seclet->u.fill.value != 0) + abort (); + } + else + { + char *d = (char *) bfd_alloc (abfd, seclet->size); + unsigned int i; + boolean ret; + + for (i = 0; i < seclet->size; i+=2) + d[i] = seclet->u.fill.value >> 8; + for (i = 1; i < seclet->size; i+=2) + d[i] = seclet->u.fill.value; + ret = bfd_set_section_contents (abfd, section, d, seclet->offset, + seclet->size); + bfd_release (abfd, (PTR) d); + return ret; + } + break; + + default: + abort(); + } + + return true; +} + +/* Add a string to the debugging information we are accumulating for a + file. Return the offset from the fdr string base or from the + external string base. */ + +static long +ecoff_add_string (output_bfd, fdr, string, external) + bfd *output_bfd; + FDR *fdr; + CONST char *string; + boolean external; +{ + HDRR *symhdr; + size_t len; + long ret; + + symhdr = &ecoff_data (output_bfd)->symbolic_header; + len = strlen (string); + if (external) + { + strcpy (ecoff_data (output_bfd)->ssext + symhdr->issExtMax, string); + ret = symhdr->issExtMax; + symhdr->issExtMax += len + 1; + } + else + { + strcpy (ecoff_data (output_bfd)->ss + symhdr->issMax, string); + ret = fdr->cbSs; + symhdr->issMax += len + 1; + fdr->cbSs += len + 1; + } + return ret; +} + +/* Accumulate the debugging information from an input section. */ + +static boolean +ecoff_get_debug (output_bfd, seclet, section, relocateable) + bfd *output_bfd; + bfd_seclet_type *seclet; + asection *section; + boolean relocateable; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (output_bfd); + const bfd_size_type external_sym_size = backend->external_sym_size; + const bfd_size_type external_pdr_size = backend->external_pdr_size; + const bfd_size_type external_fdr_size = backend->external_fdr_size; + const bfd_size_type external_rfd_size = backend->external_rfd_size; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = backend->swap_sym_in; + void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) + = backend->swap_sym_out; + void (* const swap_pdr_in) PARAMS ((bfd *, PTR, PDR *)) + = backend->swap_pdr_in; + void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)) + = backend->swap_fdr_out; + void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR)) + = backend->swap_rfd_out; + bfd *input_bfd; + HDRR *output_symhdr; + HDRR *input_symhdr; + ecoff_data_type *output_ecoff; + ecoff_data_type *input_ecoff; + unsigned int count; + char *sym_out; + ecoff_symbol_type *esym_ptr; + ecoff_symbol_type *esym_end; + FDR *fdr_ptr; + FDR *fdr_end; + char *fdr_out; + + input_bfd = seclet->u.indirect.section->owner; + + /* Don't get the information more than once. */ + if (input_bfd->output_has_begun) + return true; + input_bfd->output_has_begun = true; + + output_ecoff = ecoff_data (output_bfd); + output_symhdr = &output_ecoff->symbolic_header; + + if (input_bfd->xvec->flavour != bfd_target_ecoff_flavour) + { + FDR fdr; + asymbol **symbols; + asymbol **sym_ptr; + asymbol **sym_end; + + /* This is not an ECOFF BFD. Just gather the symbols. */ + + memset (&fdr, 0, sizeof fdr); + + fdr.adr = bfd_get_section_vma (output_bfd, section) + seclet->offset; + fdr.issBase = output_symhdr->issMax; + fdr.cbSs = 0; + fdr.rss = ecoff_add_string (output_bfd, + &fdr, + bfd_get_filename (input_bfd), + false); + fdr.isymBase = output_symhdr->isymMax; + + /* Get the local symbols from the input BFD. */ + symbols = (asymbol **) bfd_alloc (output_bfd, + get_symtab_upper_bound (input_bfd)); + if (symbols == (asymbol **) NULL) + { + bfd_error = no_memory; + return false; + } + sym_end = symbols + bfd_canonicalize_symtab (input_bfd, symbols); + + /* Handle the local symbols. Any external symbols are handled + separately. */ + fdr.csym = 0; + for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++) + { + SYMR internal_sym; + + if (((*sym_ptr)->flags & BSF_EXPORT) != 0) + continue; + memset (&internal_sym, 0, sizeof internal_sym); + internal_sym.iss = ecoff_add_string (output_bfd, + &fdr, + (*sym_ptr)->name, + false); + + if (bfd_is_com_section ((*sym_ptr)->section) + || (*sym_ptr)->section == &bfd_und_section) + internal_sym.value = (*sym_ptr)->value; + else + internal_sym.value = ((*sym_ptr)->value + + (*sym_ptr)->section->output_offset + + (*sym_ptr)->section->output_section->vma); + internal_sym.st = stNil; + internal_sym.sc = scUndefined; + internal_sym.index = indexNil; + (*swap_sym_out) (output_bfd, &internal_sym, + ((char *) output_ecoff->external_sym + + output_symhdr->isymMax * external_sym_size)); + ++fdr.csym; + ++output_symhdr->isymMax; + } + + bfd_release (output_bfd, (PTR) symbols); + + /* Leave everything else in the FDR zeroed out. This will cause + the lang field to be langC. The fBigendian field will + indicate little endian format, but it doesn't matter because + it only applies to aux fields and there are none. */ + + (*swap_fdr_out) (output_bfd, &fdr, + ((char *) output_ecoff->external_fdr + + output_symhdr->ifdMax * external_fdr_size)); + ++output_symhdr->ifdMax; + return true; + } + + /* This is an ECOFF BFD. We want to grab the information from + input_bfd and attach it to output_bfd. */ + count = bfd_get_symcount (input_bfd); + if (count == 0) + return true; + input_ecoff = ecoff_data (input_bfd); + input_symhdr = &input_ecoff->symbolic_header; + + /* I think that it is more efficient to simply copy the debugging + information from the input BFD to the output BFD. Because ECOFF + uses relative pointers for most of the debugging information, + only a little of it has to be changed at all. */ + + /* Swap in the local symbols, adjust their values, and swap them out + again. The external symbols are handled separately. */ + sym_out = ((char *) output_ecoff->external_sym + + output_symhdr->isymMax * external_sym_size); + + esym_ptr = ecoff_data (input_bfd)->canonical_symbols; + esym_end = esym_ptr + count; + for (; esym_ptr < esym_end; esym_ptr++) + { + if (esym_ptr->local) + { + SYMR sym; + + (*swap_sym_in) (input_bfd, esym_ptr->native, &sym); + + /* If we're producing an executable, move common symbols + into bss. */ + if (relocateable == false) + { + if (sym.sc == scCommon) + sym.sc = scBss; + else if (sym.sc == scSCommon) + sym.sc = scSBss; + } + + if (! bfd_is_com_section (esym_ptr->symbol.section) + && (esym_ptr->symbol.flags & BSF_DEBUGGING) == 0 + && esym_ptr->symbol.section != &bfd_und_section) + sym.value = (esym_ptr->symbol.value + + esym_ptr->symbol.section->output_offset + + esym_ptr->symbol.section->output_section->vma); + (*swap_sym_out) (output_bfd, &sym, sym_out); + sym_out += external_sym_size; + } + } + + /* That should have accounted for all the local symbols in + input_bfd. */ + + /* Copy the information that does not need swapping. */ + memcpy (output_ecoff->line + output_symhdr->cbLine, + input_ecoff->line, + input_symhdr->cbLine * sizeof (unsigned char)); + memcpy (output_ecoff->external_aux + output_symhdr->iauxMax, + input_ecoff->external_aux, + input_symhdr->iauxMax * sizeof (union aux_ext)); + memcpy (output_ecoff->ss + output_symhdr->issMax, + input_ecoff->ss, + input_symhdr->issMax * sizeof (char)); + + /* Some of the information may need to be swapped. */ + if (output_bfd->xvec->header_byteorder_big_p + == input_bfd->xvec->header_byteorder_big_p) + { + /* The two BFD's have the same endianness, so memcpy will + suffice. */ + if (input_symhdr->idnMax > 0) + memcpy (((char *) output_ecoff->external_dnr + + output_symhdr->idnMax * backend->external_dnr_size), + input_ecoff->external_dnr, + input_symhdr->idnMax * backend->external_dnr_size); + if (input_symhdr->ipdMax > 0) + memcpy (((char *) output_ecoff->external_pdr + + output_symhdr->ipdMax * external_pdr_size), + input_ecoff->external_pdr, + input_symhdr->ipdMax * external_pdr_size); + if (input_symhdr->ioptMax > 0) + memcpy (((char *) output_ecoff->external_opt + + output_symhdr->ioptMax * backend->external_opt_size), + input_ecoff->external_opt, + input_symhdr->ioptMax * backend->external_opt_size); + } + else + { + bfd_size_type sz; + char *in; + char *end; + char *out; + + /* The two BFD's have different endianness, so we must swap + everything in and out. This code would always work, but it + would be slow in the normal case. */ + sz = backend->external_dnr_size; + in = (char *) input_ecoff->external_dnr; + end = in + input_symhdr->idnMax * sz; + out = (char *) output_ecoff->external_dnr + output_symhdr->idnMax * sz; + for (; in < end; in += sz, out += sz) + { + DNR dnr; + + (*backend->swap_dnr_in) (input_bfd, in, &dnr); + (*backend->swap_dnr_out) (output_bfd, &dnr, out); + } + + sz = external_pdr_size; + in = (char *) input_ecoff->external_pdr; + end = in + input_symhdr->ipdMax * sz; + out = (char *) output_ecoff->external_pdr + output_symhdr->ipdMax * sz; + for (; in < end; in += sz, out += sz) + { + PDR pdr; + + (*swap_pdr_in) (input_bfd, in, &pdr); + (*backend->swap_pdr_out) (output_bfd, &pdr, out); + } + + sz = backend->external_opt_size; + in = (char *) input_ecoff->external_opt; + end = in + input_symhdr->ioptMax * sz; + out = (char *) output_ecoff->external_opt + output_symhdr->ioptMax * sz; + for (; in < end; in += sz, out += sz) + { + OPTR opt; + + (*backend->swap_opt_in) (input_bfd, in, &opt); + (*backend->swap_opt_out) (output_bfd, &opt, out); + } + } + + /* Set ifdbase so that the external symbols know how to adjust their + ifd values. */ + input_ecoff->ifdbase = output_symhdr->ifdMax; + + fdr_ptr = input_ecoff->fdr; + fdr_end = fdr_ptr + input_symhdr->ifdMax; + fdr_out = ((char *) output_ecoff->external_fdr + + output_symhdr->ifdMax * external_fdr_size); + for (; fdr_ptr < fdr_end; fdr_ptr++, fdr_out += external_fdr_size) + { + FDR fdr; + unsigned long pdr_off; + + fdr = *fdr_ptr; + + /* The memory address for this fdr is the address for the seclet + plus the offset to this fdr within input_bfd. For some + reason the offset of the first procedure pointer is also + added in. */ + if (fdr.cpd == 0) + pdr_off = 0; + else + { + PDR pdr; + + (*swap_pdr_in) (input_bfd, + ((char *) input_ecoff->external_pdr + + fdr.ipdFirst * external_pdr_size), + &pdr); + pdr_off = pdr.adr; + } + fdr.adr = (bfd_get_section_vma (output_bfd, section) + + seclet->offset + + (fdr_ptr->adr - input_ecoff->fdr->adr) + + pdr_off); + + fdr.issBase += output_symhdr->issMax; + fdr.isymBase += output_symhdr->isymMax; + fdr.ilineBase += output_symhdr->ilineMax; + fdr.ioptBase += output_symhdr->ioptMax; + fdr.ipdFirst += output_symhdr->ipdMax; + fdr.iauxBase += output_symhdr->iauxMax; + fdr.rfdBase += output_symhdr->crfd; + + /* If there are no RFD's, we are going to add some. We don't + want to adjust irfd for this, so that all the FDR's can share + the RFD's. */ + if (input_symhdr->crfd == 0) + fdr.crfd = input_symhdr->ifdMax; + + if (fdr.cbLine != 0) + fdr.cbLineOffset += output_symhdr->cbLine; + + (*swap_fdr_out) (output_bfd, &fdr, fdr_out); + } + + if (input_symhdr->crfd > 0) + { + void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)) + = backend->swap_rfd_in; + char *rfd_in; + char *rfd_end; + char *rfd_out; + + /* Swap and adjust the RFD's. RFD's are only created by the + linker, so this will only be necessary if one of the input + files is the result of a partial link. Presumably all + necessary RFD's are present. */ + rfd_in = (char *) input_ecoff->external_rfd; + rfd_end = rfd_in + input_symhdr->crfd * external_rfd_size; + rfd_out = ((char *) output_ecoff->external_rfd + + output_symhdr->crfd * external_rfd_size); + for (; + rfd_in < rfd_end; + rfd_in += external_rfd_size, rfd_out += external_rfd_size) + { + RFDT rfd; + + (*swap_rfd_in) (input_bfd, rfd_in, &rfd); + rfd += output_symhdr->ifdMax; + (*swap_rfd_out) (output_bfd, &rfd, rfd_out); + } + output_symhdr->crfd += input_symhdr->crfd; + } + else + { + char *rfd_out; + char *rfd_end; + RFDT rfd; + + /* Create RFD's. Some of the debugging information includes + relative file indices. These indices are taken as indices to + the RFD table if there is one, or to the global table if + there is not. If we did not create RFD's, we would have to + parse and adjust all the debugging information which contains + file indices. */ + rfd = output_symhdr->ifdMax; + rfd_out = ((char *) output_ecoff->external_rfd + + output_symhdr->crfd * external_rfd_size); + rfd_end = rfd_out + input_symhdr->ifdMax * external_rfd_size; + for (; rfd_out < rfd_end; rfd_out += external_rfd_size, rfd++) + (*swap_rfd_out) (output_bfd, &rfd, rfd_out); + output_symhdr->crfd += input_symhdr->ifdMax; + } + + /* Combine the register masks. Not all of these are used on all + targets, but that's OK because only the relevant ones will be + swapped in and out. */ + { + int i; + + output_ecoff->gprmask |= input_ecoff->gprmask; + output_ecoff->fprmask |= input_ecoff->fprmask; + for (i = 0; i < 4; i++) + output_ecoff->cprmask[i] |= input_ecoff->cprmask[i]; + } + + /* Update the counts. */ + output_symhdr->ilineMax += input_symhdr->ilineMax; + output_symhdr->cbLine += input_symhdr->cbLine; + output_symhdr->idnMax += input_symhdr->idnMax; + output_symhdr->ipdMax += input_symhdr->ipdMax; + output_symhdr->isymMax += input_symhdr->isymMax; + output_symhdr->ioptMax += input_symhdr->ioptMax; + output_symhdr->iauxMax += input_symhdr->iauxMax; + output_symhdr->issMax += input_symhdr->issMax; + output_symhdr->ifdMax += input_symhdr->ifdMax; + + return true; +} + +/* This is the actual link routine. It makes two passes over all the + seclets. */ + +boolean +ecoff_bfd_seclet_link (abfd, data, relocateable) + bfd *abfd; + PTR data; + boolean relocateable; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + HDRR *symhdr; + int ipass; + register asection *o; + register bfd_seclet_type *p; + asymbol **sym_ptr_ptr; + bfd_size_type debug_align; + bfd_size_type size; + char *raw; + + /* We accumulate the debugging information counts in the symbolic + header. */ + symhdr = &ecoff_data (abfd)->symbolic_header; + symhdr->magic = backend->sym_magic; + /* FIXME: What should the version stamp be? */ + symhdr->vstamp = 0; + symhdr->ilineMax = 0; + symhdr->cbLine = 0; + symhdr->idnMax = 0; + symhdr->ipdMax = 0; + symhdr->isymMax = 0; + symhdr->ioptMax = 0; + symhdr->iauxMax = 0; + symhdr->issMax = 0; + symhdr->issExtMax = 0; + symhdr->ifdMax = 0; + symhdr->crfd = 0; + symhdr->iextMax = 0; + + /* We need to copy over the debugging symbols from each input BFD. + When we do this copying, we have to adjust the text address in + the FDR structures, so we have to know the text address used for + the input BFD. Since we only want to copy the symbols once per + input BFD, but we are going to look at each input BFD multiple + times (once for each section it provides), we arrange to always + look at the text section first. That means that when we copy the + debugging information, we always know the text address. So we + actually do each pass in two sub passes; first the text sections, + then the non-text sections. We use the output_has_begun flag to + determine whether we have copied over the debugging information + yet. */ + + /* Do the first pass: set the output section contents and count the + debugging information. */ + ecoff_clear_output_flags (abfd); + for (ipass = 0; ipass < 2; ipass++) + { + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + /* If this is a fake section, just forget it. The register + information is handled in another way. */ + if (strcmp (o->name, SCOMMON) == 0 + || strcmp (o->name, REGINFO) == 0) + continue; + + /* For SEC_CODE sections, (flags & SEC_CODE) == 0 is false, + so they are done on pass 0. For other sections the + expression is true, so they are done on pass 1. */ + if (((o->flags & SEC_CODE) == 0) != ipass) + continue; + + for (p = o->seclets_head; + p != (bfd_seclet_type *) NULL; + p = p->next) + { + if (ecoff_dump_seclet (abfd, p, o, data, relocateable) + == false) + return false; + } + } + } + + /* We handle the external symbols differently. We use the ones + attached to the output_bfd. The linker will have already + determined which symbols are to be attached. Here we just + determine how much space we will need for them. */ + sym_ptr_ptr = bfd_get_outsymbols (abfd); + if (sym_ptr_ptr != NULL) + { + asymbol **sym_end; + + sym_end = sym_ptr_ptr + bfd_get_symcount (abfd); + for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++) + { + if (((*sym_ptr_ptr)->flags & BSF_DEBUGGING) == 0 + && ((*sym_ptr_ptr)->flags & BSF_LOCAL) == 0) + { + ++symhdr->iextMax; + symhdr->issExtMax += strlen ((*sym_ptr_ptr)->name) + 1; + } + } + } + + /* Adjust the counts so that structures are longword aligned. */ + debug_align = backend->debug_align; + --debug_align; + symhdr->cbLine = (symhdr->cbLine + debug_align) &~ debug_align; + symhdr->issMax = (symhdr->issMax + debug_align) &~ debug_align; + symhdr->issExtMax = (symhdr->issExtMax + debug_align) &~ debug_align; + + /* Now the counts in symhdr are the correct size for the debugging + information. We allocate the right amount of space, and reset + the counts so that the second pass can use them as indices. It + would be possible to output the debugging information directly to + the file in pass 2, rather than to build it in memory and then + write it out. Outputting to the file would require a lot of + seeks and small writes, though, and I think this approach is + faster. */ + size = (symhdr->cbLine * sizeof (unsigned char) + + symhdr->idnMax * backend->external_dnr_size + + symhdr->ipdMax * backend->external_pdr_size + + symhdr->isymMax * backend->external_sym_size + + symhdr->ioptMax * backend->external_opt_size + + symhdr->iauxMax * sizeof (union aux_ext) + + symhdr->issMax * sizeof (char) + + symhdr->issExtMax * sizeof (char) + + symhdr->ifdMax * backend->external_fdr_size + + symhdr->crfd * backend->external_rfd_size + + symhdr->iextMax * backend->external_ext_size); + raw = (char *) bfd_alloc (abfd, size); + if (raw == (char *) NULL) + { + bfd_error = no_memory; + return false; + } + ecoff_data (abfd)->raw_size = size; + ecoff_data (abfd)->raw_syments = (PTR) raw; + + /* Initialize the raw pointers. */ +#define SET(field, count, type, size) \ + ecoff_data (abfd)->field = (type) raw; \ + raw += symhdr->count * size + + SET (line, cbLine, unsigned char *, sizeof (unsigned char)); + SET (external_dnr, idnMax, PTR, backend->external_dnr_size); + SET (external_pdr, ipdMax, PTR, backend->external_pdr_size); + SET (external_sym, isymMax, PTR, backend->external_sym_size); + SET (external_opt, ioptMax, PTR, backend->external_opt_size); + SET (external_aux, iauxMax, union aux_ext *, sizeof (union aux_ext)); + SET (ss, issMax, char *, sizeof (char)); + SET (ssext, issExtMax, char *, sizeof (char)); + SET (external_fdr, ifdMax, PTR, backend->external_fdr_size); + SET (external_rfd, crfd, PTR, backend->external_rfd_size); + SET (external_ext, iextMax, PTR, backend->external_ext_size); +#undef SET + + /* Reset the counts so the second pass can use them to know how far + it has gotten. */ + symhdr->ilineMax = 0; + symhdr->cbLine = 0; + symhdr->idnMax = 0; + symhdr->ipdMax = 0; + symhdr->isymMax = 0; + symhdr->ioptMax = 0; + symhdr->iauxMax = 0; + symhdr->issMax = 0; + symhdr->issExtMax = 0; + symhdr->ifdMax = 0; + symhdr->crfd = 0; + symhdr->iextMax = 0; + + /* Do the second pass: accumulate the debugging information. */ + ecoff_clear_output_flags (abfd); + for (ipass = 0; ipass < 2; ipass++) + { + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + if (strcmp (o->name, SCOMMON) == 0 + || strcmp (o->name, REGINFO) == 0) + continue; + if (((o->flags & SEC_CODE) == 0) != ipass) + continue; + for (p = o->seclets_head; + p != (bfd_seclet_type *) NULL; + p = p->next) + { + if (p->type == bfd_indirect_seclet) + { + if (ecoff_get_debug (abfd, p, o, relocateable) == false) + return false; + } + } + } + } + + /* Put in the external symbols. */ + sym_ptr_ptr = bfd_get_outsymbols (abfd); + if (sym_ptr_ptr != NULL) + { + const bfd_size_type external_ext_size = backend->external_ext_size; + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = backend->swap_ext_in; + void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR)) + = backend->swap_ext_out; + char *ssext; + char *external_ext; + + ssext = ecoff_data (abfd)->ssext; + external_ext = (char *) ecoff_data (abfd)->external_ext; + for (; *sym_ptr_ptr != NULL; sym_ptr_ptr++) + { + asymbol *sym_ptr; + EXTR esym; + + sym_ptr = *sym_ptr_ptr; + + if ((sym_ptr->flags & BSF_DEBUGGING) != 0 + || (sym_ptr->flags & BSF_LOCAL) != 0) + continue; + + /* The native pointer can be NULL for a symbol created by + the linker via ecoff_make_empty_symbol. */ + if (bfd_asymbol_flavour (sym_ptr) != bfd_target_ecoff_flavour + || ecoffsymbol (sym_ptr)->native == NULL) + { + esym.jmptbl = 0; + esym.cobol_main = 0; + esym.weakext = 0; + esym.reserved = 0; + esym.ifd = ifdNil; + /* FIXME: we can do better than this for st and sc. */ + esym.asym.st = stGlobal; + esym.asym.sc = scAbs; + esym.asym.reserved = 0; + esym.asym.index = indexNil; + } + else + { + ecoff_symbol_type *ecoff_sym_ptr; + + ecoff_sym_ptr = ecoffsymbol (sym_ptr); + if (ecoff_sym_ptr->local) + abort (); + (*swap_ext_in) (abfd, ecoff_sym_ptr->native, &esym); + + /* If we're producing an executable, move common symbols + into bss. */ + if (relocateable == false) + { + if (esym.asym.sc == scCommon) + esym.asym.sc = scBss; + else if (esym.asym.sc == scSCommon) + esym.asym.sc = scSBss; + } + + /* Adjust the FDR index for the symbol by that used for + the input BFD. */ + esym.ifd += ecoff_data (bfd_asymbol_bfd (sym_ptr))->ifdbase; + } + + esym.asym.iss = symhdr->issExtMax; + + if (bfd_is_com_section (sym_ptr->section) + || sym_ptr->section == &bfd_und_section) + esym.asym.value = sym_ptr->value; + else + esym.asym.value = (sym_ptr->value + + sym_ptr->section->output_offset + + sym_ptr->section->output_section->vma); + + (*swap_ext_out) (abfd, &esym, external_ext); + + ecoff_set_sym_index (sym_ptr, symhdr->iextMax); + + external_ext += external_ext_size; + ++symhdr->iextMax; + + strcpy (ssext + symhdr->issExtMax, sym_ptr->name); + symhdr->issExtMax += strlen (sym_ptr->name) + 1; + } + } + + /* Adjust the counts so that structures are longword aligned. */ + symhdr->cbLine = (symhdr->cbLine + debug_align) &~ debug_align; + symhdr->issMax = (symhdr->issMax + debug_align) &~ debug_align; + symhdr->issExtMax = (symhdr->issExtMax + debug_align) &~ debug_align; + + return true; +} + +/* Set the architecture. The supported architecture is stored in the + backend pointer. We always set the architecture anyhow, since many + callers ignore the return value. */ + +boolean +ecoff_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + bfd_default_set_arch_mach (abfd, arch, machine); + return arch == ecoff_backend (abfd)->arch; +} + +/* Get the size of the section headers. We do not output the .scommon + section which we created in ecoff_mkobject, nor do we output any + .reginfo section. */ + +int +ecoff_sizeof_headers (abfd, reloc) + bfd *abfd; + boolean reloc; +{ + asection *current; + int c; + + c = 0; + for (current = abfd->sections; + current != (asection *)NULL; + current = current->next) + if (strcmp (current->name, SCOMMON) != 0 + && strcmp (current->name, REGINFO) != 0) + ++c; + + return (bfd_coff_filhsz (abfd) + + bfd_coff_aoutsz (abfd) + + c * bfd_coff_scnhsz (abfd)); +} + + +/* Get the contents of a section. This is where we handle reading the + .reginfo section, which implicitly holds the contents of an + ecoff_reginfo structure. */ + +boolean +ecoff_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + ecoff_data_type *tdata = ecoff_data (abfd); + struct ecoff_reginfo s; + int i; + + if (strcmp (section->name, REGINFO) != 0) + return bfd_generic_get_section_contents (abfd, section, location, + offset, count); + + s.gp_value = tdata->gp; + s.gprmask = tdata->gprmask; + for (i = 0; i < 4; i++) + s.cprmask[i] = tdata->cprmask[i]; + s.fprmask = tdata->fprmask; + + /* bfd_get_section_contents has already checked that the offset and + size is reasonable. We don't have to worry about swapping or any + such thing; the .reginfo section is defined such that the + contents are an ecoff_reginfo structure as seen on the host. */ + memcpy (location, ((char *) &s) + offset, count); + return true; +} + +/* Calculate the file position for each section, and set + reloc_filepos. */ + +static void +ecoff_compute_section_file_positions (abfd) + bfd *abfd; +{ + asection *current; + file_ptr sofar; + file_ptr old_sofar; + boolean first_data; + + if (bfd_get_start_address (abfd)) + abfd->flags |= EXEC_P; + + sofar = ecoff_sizeof_headers (abfd, false); + + first_data = true; + for (current = abfd->sections; + current != (asection *) NULL; + current = current->next) + { + /* Only deal with sections which have contents */ + if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) == 0 + || strcmp (current->name, SCOMMON) == 0 + || strcmp (current->name, REGINFO) == 0) + continue; + + /* On Ultrix, the data sections in an executable file must be + aligned to a page boundary within the file. This does not + affect the section size, though. FIXME: Does this work for + other platforms? */ + if ((abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0 + && first_data != false + && (current->flags & SEC_CODE) == 0) + { + const bfd_vma round = ecoff_backend (abfd)->round; + + sofar = (sofar + round - 1) &~ (round - 1); + first_data = false; + } + + /* Align the sections in the file to the same boundary on + which they are aligned in virtual memory. */ + old_sofar = sofar; + sofar = BFD_ALIGN (sofar, 1 << current->alignment_power); + + current->filepos = sofar; + + sofar += current->_raw_size; + + /* make sure that this section is of the right size too */ + old_sofar = sofar; + sofar = BFD_ALIGN (sofar, 1 << current->alignment_power); + current->_raw_size += sofar - old_sofar; + } + + ecoff_data (abfd)->reloc_filepos = sofar; +} + +/* Set the contents of a section. This is where we handle setting the + contents of the .reginfo section, which implicitly holds a + ecoff_reginfo structure. */ + +boolean +ecoff_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (abfd->output_has_begun == false) + ecoff_compute_section_file_positions (abfd); + + if (strcmp (section->name, REGINFO) == 0) + { + ecoff_data_type *tdata = ecoff_data (abfd); + struct ecoff_reginfo s; + int i; + + /* If the caller is only changing part of the structure, we must + retrieve the current information before the memcpy. */ + if (offset != 0 || count != sizeof (struct ecoff_reginfo)) + { + s.gp_value = tdata->gp; + s.gprmask = tdata->gprmask; + for (i = 0; i < 4; i++) + s.cprmask[i] = tdata->cprmask[i]; + s.fprmask = tdata->fprmask; + } + + /* bfd_set_section_contents has already checked that the offset + and size is reasonable. We don't have to worry about + swapping or any such thing; the .reginfo section is defined + such that the contents are an ecoff_reginfo structure as seen + on the host. */ + memcpy (((char *) &s) + offset, location, count); + + tdata->gp = s.gp_value; + tdata->gprmask = s.gprmask; + for (i = 0; i < 4; i++) + tdata->cprmask[i] = s.cprmask[i]; + tdata->fprmask = s.fprmask; + + return true; + + } + + bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET); + + if (count != 0) + return (bfd_write (location, 1, count, abfd) == count) ? true : false; + + return true; +} + +/* Write out an ECOFF file. */ + +boolean +ecoff_write_object_contents (abfd) + bfd *abfd; +{ + const struct ecoff_backend_data * const backend = ecoff_backend (abfd); + const bfd_vma round = backend->round; + const bfd_size_type filhsz = bfd_coff_filhsz (abfd); + const bfd_size_type aoutsz = bfd_coff_aoutsz (abfd); + const bfd_size_type scnhsz = bfd_coff_scnhsz (abfd); + const bfd_size_type external_hdr_size = backend->external_hdr_size; + const bfd_size_type external_reloc_size = backend->external_reloc_size; + void (* const swap_reloc_out) PARAMS ((bfd *, + const struct internal_reloc *, + PTR)) + = backend->swap_reloc_out; + asection *current; + unsigned int count; + file_ptr scn_base; + file_ptr reloc_base; + file_ptr sym_base; + unsigned long reloc_size; + unsigned long text_size; + unsigned long text_start; + unsigned long data_size; + unsigned long data_start; + unsigned long bss_size; + PTR buff; + struct internal_filehdr internal_f; + struct internal_aouthdr internal_a; + int i; + + bfd_error = system_call_error; + + if(abfd->output_has_begun == false) + ecoff_compute_section_file_positions(abfd); + + if (abfd->sections != (asection *) NULL) + scn_base = abfd->sections->filepos; + else + scn_base = 0; + reloc_base = ecoff_data (abfd)->reloc_filepos; + + count = 1; + reloc_size = 0; + for (current = abfd->sections; + current != (asection *)NULL; + current = current->next) + { + if (strcmp (current->name, SCOMMON) == 0 + || strcmp (current->name, REGINFO) == 0) + continue; + current->target_index = count; + ++count; + if (current->reloc_count != 0) + { + bfd_size_type relsize; + + current->rel_filepos = reloc_base; + relsize = current->reloc_count * external_reloc_size; + reloc_size += relsize; + reloc_base += relsize; + } + else + current->rel_filepos = 0; + } + + sym_base = reloc_base + reloc_size; + + /* At least on Ultrix, the symbol table of an executable file must + be aligned to a page boundary. FIXME: Is this true on other + platforms? */ + if ((abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0) + sym_base = (sym_base + round - 1) &~ (round - 1); + + ecoff_data (abfd)->sym_filepos = sym_base; + + if ((abfd->flags & D_PAGED) != 0) + text_size = ecoff_sizeof_headers (abfd, false); + else + text_size = 0; + text_start = 0; + data_size = 0; + data_start = 0; + bss_size = 0; + + /* Write section headers to the file. */ + + buff = (PTR) alloca (scnhsz); + internal_f.f_nscns = 0; + if (bfd_seek (abfd, (file_ptr) (filhsz + aoutsz), SEEK_SET) != 0) + return false; + for (current = abfd->sections; + current != (asection *) NULL; + current = current->next) + { + struct internal_scnhdr section; + bfd_vma vma; + + if (strcmp (current->name, SCOMMON) == 0) + { + BFD_ASSERT (bfd_get_section_size_before_reloc (current) == 0 + && current->reloc_count == 0); + continue; + } + if (strcmp (current->name, REGINFO) == 0) + { + BFD_ASSERT (current->reloc_count == 0); + continue; + } + + ++internal_f.f_nscns; + + strncpy (section.s_name, current->name, sizeof section.s_name); + + /* FIXME: is this correct for shared libraries? I think it is + but I have no platform to check. Ian Lance Taylor. */ + vma = bfd_get_section_vma (abfd, current); + if (strcmp (current->name, _LIB) == 0) + section.s_vaddr = 0; + else + section.s_vaddr = vma; + + section.s_paddr = vma; + section.s_size = bfd_get_section_size_before_reloc (current); + + /* If this section is unloadable then the scnptr will be 0. */ + if ((current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + section.s_scnptr = 0; + else + section.s_scnptr = current->filepos; + section.s_relptr = current->rel_filepos; + + /* FIXME: the lnnoptr of the .sbss or .sdata section of an + object file produced by the assembler is supposed to point to + information about how much room is required by objects of + various different sizes. I think this only matters if we + want the linker to compute the best size to use, or + something. I don't know what happens if the information is + not present. */ + section.s_lnnoptr = 0; + + section.s_nreloc = current->reloc_count; + section.s_nlnno = 0; + section.s_flags = ecoff_sec_to_styp_flags (current->name, + current->flags); + + bfd_coff_swap_scnhdr_out (abfd, (PTR) §ion, buff); + if (bfd_write (buff, 1, scnhsz, abfd) != scnhsz) + return false; + + if ((section.s_flags & STYP_TEXT) != 0) + { + text_size += bfd_get_section_size_before_reloc (current); + if (text_start == 0 || text_start > vma) + text_start = vma; + } + else if ((section.s_flags & STYP_RDATA) != 0 + || (section.s_flags & STYP_DATA) != 0 + || (section.s_flags & STYP_LIT8) != 0 + || (section.s_flags & STYP_LIT4) != 0 + || (section.s_flags & STYP_SDATA) != 0) + { + data_size += bfd_get_section_size_before_reloc (current); + if (data_start == 0 || data_start > vma) + data_start = vma; + } + else if ((section.s_flags & STYP_BSS) != 0 + || (section.s_flags & STYP_SBSS) != 0) + bss_size += bfd_get_section_size_before_reloc (current); + } + + /* Set up the file header. */ + + internal_f.f_magic = ecoff_get_magic (abfd); + + /* We will NOT put a fucking timestamp in the header here. Every + time you put it back, I will come in and take it out again. I'm + sorry. This field does not belong here. We fill it with a 0 so + it compares the same but is not a reasonable time. -- + gnu@cygnus.com. */ + internal_f.f_timdat = 0; + + if (bfd_get_symcount (abfd) != 0) + { + /* The ECOFF f_nsyms field is not actually the number of + symbols, it's the size of symbolic information header. */ + internal_f.f_nsyms = external_hdr_size; + internal_f.f_symptr = sym_base; + } + else + { + internal_f.f_nsyms = 0; + internal_f.f_symptr = 0; + } + + internal_f.f_opthdr = aoutsz; + + internal_f.f_flags = F_LNNO; + if (reloc_size == 0) + internal_f.f_flags |= F_RELFLG; + if (bfd_get_symcount (abfd) == 0) + internal_f.f_flags |= F_LSYMS; + if (abfd->flags & EXEC_P) + internal_f.f_flags |= F_EXEC; + + if (! abfd->xvec->byteorder_big_p) + internal_f.f_flags |= F_AR32WR; + else + internal_f.f_flags |= F_AR32W; + + /* Set up the ``optional'' header. */ + if ((abfd->flags & D_PAGED) != 0) + internal_a.magic = ECOFF_AOUT_ZMAGIC; + else + internal_a.magic = ECOFF_AOUT_OMAGIC; + + /* FIXME: This is what Ultrix puts in, and it makes the Ultrix + linker happy. But, is it right? */ + internal_a.vstamp = 0x20a; + + /* At least on Ultrix, these have to be rounded to page boundaries. + FIXME: Is this true on other platforms? */ + if ((abfd->flags & D_PAGED) != 0) + { + internal_a.tsize = (text_size + round - 1) &~ (round - 1); + internal_a.text_start = text_start &~ (round - 1); + internal_a.dsize = (data_size + round - 1) &~ (round - 1); + internal_a.data_start = data_start &~ (round - 1); + } + else + { + internal_a.tsize = text_size; + internal_a.text_start = text_start; + internal_a.dsize = data_size; + internal_a.data_start = data_start; + } + + /* On Ultrix, the initial portions of the .sbss and .bss segments + are at the end of the data section. The bsize field in the + optional header records how many bss bytes are required beyond + those in the data section. The value is not rounded to a page + boundary. */ + if (bss_size < internal_a.dsize - data_size) + bss_size = 0; + else + bss_size -= internal_a.dsize - data_size; + internal_a.bsize = bss_size; + internal_a.bss_start = internal_a.data_start + internal_a.dsize; + + internal_a.entry = bfd_get_start_address (abfd); + + internal_a.gp_value = ecoff_data (abfd)->gp; + + internal_a.gprmask = ecoff_data (abfd)->gprmask; + internal_a.fprmask = ecoff_data (abfd)->fprmask; + for (i = 0; i < 4; i++) + internal_a.cprmask[i] = ecoff_data (abfd)->cprmask[i]; + + /* Write out the file header and the optional header. */ + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + return false; + + buff = (PTR) alloca (filhsz); + bfd_coff_swap_filehdr_out (abfd, (PTR) &internal_f, buff); + if (bfd_write (buff, 1, filhsz, abfd) != filhsz) + return false; + + buff = (PTR) alloca (aoutsz); + bfd_coff_swap_aouthdr_out (abfd, (PTR) &internal_a, buff); + if (bfd_write (buff, 1, aoutsz, abfd) != aoutsz) + return false; + + /* Write out the relocs. */ + for (current = abfd->sections; + current != (asection *) NULL; + current = current->next) + { + arelent **reloc_ptr_ptr; + arelent **reloc_end; + char *out_ptr; + + if (current->reloc_count == 0) + continue; + + buff = bfd_alloc (abfd, current->reloc_count * external_reloc_size); + if (buff == NULL) + { + bfd_error = no_memory; + return false; + } + + reloc_ptr_ptr = current->orelocation; + reloc_end = reloc_ptr_ptr + current->reloc_count; + out_ptr = (char *) buff; + for (; + reloc_ptr_ptr < reloc_end; + reloc_ptr_ptr++, out_ptr += external_reloc_size) + { + arelent *reloc; + asymbol *sym; + struct internal_reloc in; + + memset (&in, 0, sizeof in); + + reloc = *reloc_ptr_ptr; + sym = *reloc->sym_ptr_ptr; + + in.r_vaddr = reloc->address + bfd_get_section_vma (abfd, current); + in.r_type = reloc->howto->type; + + if ((sym->flags & BSF_SECTION_SYM) == 0) + { + in.r_symndx = ecoff_get_sym_index (*reloc->sym_ptr_ptr); + in.r_extern = 1; + } + else + { + CONST char *name; + + name = bfd_get_section_name (abfd, bfd_get_section (sym)); + if (strcmp (name, ".text") == 0) + in.r_symndx = RELOC_SECTION_TEXT; + else if (strcmp (name, ".rdata") == 0) + in.r_symndx = RELOC_SECTION_RDATA; + else if (strcmp (name, ".data") == 0) + in.r_symndx = RELOC_SECTION_DATA; + else if (strcmp (name, ".sdata") == 0) + in.r_symndx = RELOC_SECTION_SDATA; + else if (strcmp (name, ".sbss") == 0) + in.r_symndx = RELOC_SECTION_SBSS; + else if (strcmp (name, ".bss") == 0) + in.r_symndx = RELOC_SECTION_BSS; + else if (strcmp (name, ".init") == 0) + in.r_symndx = RELOC_SECTION_INIT; + else if (strcmp (name, ".lit8") == 0) + in.r_symndx = RELOC_SECTION_LIT8; + else if (strcmp (name, ".lit4") == 0) + in.r_symndx = RELOC_SECTION_LIT4; + else + abort (); + in.r_extern = 0; + } + + (*swap_reloc_out) (abfd, &in, (PTR) out_ptr); + } + + if (bfd_seek (abfd, current->rel_filepos, SEEK_SET) != 0) + return false; + if (bfd_write (buff, external_reloc_size, current->reloc_count, abfd) + != external_reloc_size * current->reloc_count) + return false; + bfd_release (abfd, buff); + } + + /* Write out the symbolic debugging information. */ + if (bfd_get_symcount (abfd) > 0) + { + HDRR *symhdr; + unsigned long sym_offset; + + /* Set up the offsets in the symbolic header. */ + symhdr = &ecoff_data (abfd)->symbolic_header; + sym_offset = ecoff_data (abfd)->sym_filepos + external_hdr_size; + +#define SET(offset, size, ptr) \ + if (symhdr->size == 0) \ + symhdr->offset = 0; \ + else \ + symhdr->offset = (((char *) ecoff_data (abfd)->ptr \ + - (char *) ecoff_data (abfd)->raw_syments) \ + + sym_offset); + + SET (cbLineOffset, cbLine, line); + SET (cbDnOffset, idnMax, external_dnr); + SET (cbPdOffset, ipdMax, external_pdr); + SET (cbSymOffset, isymMax, external_sym); + SET (cbOptOffset, ioptMax, external_opt); + SET (cbAuxOffset, iauxMax, external_aux); + SET (cbSsOffset, issMax, ss); + SET (cbSsExtOffset, issExtMax, ssext); + SET (cbFdOffset, ifdMax, external_fdr); + SET (cbRfdOffset, crfd, external_rfd); + SET (cbExtOffset, iextMax, external_ext); +#undef SET + + if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos, + SEEK_SET) != 0) + return false; + buff = (PTR) alloca (external_hdr_size); + (*backend->swap_hdr_out) (abfd, &ecoff_data (abfd)->symbolic_header, + buff); + if (bfd_write (buff, 1, external_hdr_size, abfd) != external_hdr_size) + return false; + if (bfd_write ((PTR) ecoff_data (abfd)->raw_syments, 1, + ecoff_data (abfd)->raw_size, abfd) + != ecoff_data (abfd)->raw_size) + return false; + } + else if ((abfd->flags & EXEC_P) != 0 + && (abfd->flags & D_PAGED) != 0) + { + char c; + + /* A demand paged executable must occupy an even number of + pages. */ + if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1, + SEEK_SET) != 0) + return false; + if (bfd_read (&c, 1, 1, abfd) == 0) + c = 0; + if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1, + SEEK_SET) != 0) + return false; + if (bfd_write (&c, 1, 1, abfd) != 1) + return false; + } + + return true; +} + +/* Archive handling. ECOFF uses what appears to be a unique type of + archive header (which I call an armap). The byte ordering of the + armap and the contents are encoded in the name of the armap itself. + At least for now, we only support archives with the same byte + ordering in the armap and the contents. + + The first four bytes in the armap are the number of symbol + definitions. This is always a power of two. + + This is followed by the symbol definitions. Each symbol definition + occupies 8 bytes. The first four bytes are the offset from the + start of the armap strings to the null-terminated string naming + this symbol. The second four bytes are the file offset to the + archive member which defines this symbol. If the second four bytes + are 0, then this is not actually a symbol definition, and it should + be ignored. + + The symbols are hashed into the armap with a closed hashing scheme. + See the functions below for the details of the algorithm. + + We could use the hash table when looking up symbols in a library. + This would require a new BFD target entry point to replace the + bfd_get_next_mapent function used by the linker. + + After the symbol definitions comes four bytes holding the size of + the string table, followed by the string table itself. */ + +/* The name of an archive headers looks like this: + __________E[BL]E[BL]_ (with a trailing space). + The trailing space is changed to an X if the archive is changed to + indicate that the armap is out of date. + + The Alpha seems to use ________64E[BL]E[BL]_. */ + +#define ARMAP_BIG_ENDIAN 'B' +#define ARMAP_LITTLE_ENDIAN 'L' +#define ARMAP_MARKER 'E' +#define ARMAP_START_LENGTH 10 +#define ARMAP_HEADER_MARKER_INDEX 10 +#define ARMAP_HEADER_ENDIAN_INDEX 11 +#define ARMAP_OBJECT_MARKER_INDEX 12 +#define ARMAP_OBJECT_ENDIAN_INDEX 13 +#define ARMAP_END_INDEX 14 +#define ARMAP_END "_ " + +/* This is a magic number used in the hashing algorithm. */ +#define ARMAP_HASH_MAGIC 0x9dd68ab5 + +/* This returns the hash value to use for a string. It also sets + *REHASH to the rehash adjustment if the first slot is taken. SIZE + is the number of entries in the hash table, and HLOG is the log + base 2 of SIZE. */ + +static unsigned int +ecoff_armap_hash (s, rehash, size, hlog) + CONST char *s; + unsigned int *rehash; + unsigned int size; + unsigned int hlog; +{ + unsigned int hash; + + hash = *s++; + while (*s != '\0') + hash = ((hash >> 27) | (hash << 5)) + *s++; + hash *= ARMAP_HASH_MAGIC; + *rehash = (hash & (size - 1)) | 1; + return hash >> (32 - hlog); +} + +/* Read in the armap. */ + +boolean +ecoff_slurp_armap (abfd) + bfd *abfd; +{ + char nextname[17]; + unsigned int i; + struct areltdata *mapdata; + bfd_size_type parsed_size; + char *raw_armap; + struct artdata *ardata; + unsigned int count; + char *raw_ptr; + struct symdef *symdef_ptr; + char *stringbase; + + /* Get the name of the first element. */ + i = bfd_read ((PTR) nextname, 1, 16, abfd); + if (i == 0) + return true; + if (i != 16) + return false; + + bfd_seek (abfd, (file_ptr) -16, SEEK_CUR); + + /* Irix 4.0.5F apparently can use either an ECOFF armap or a + standard COFF armap. We could move the ECOFF armap stuff into + bfd_slurp_armap, but that seems inappropriate since no other + target uses this format. Instead, we check directly for a COFF + armap. */ + if (strncmp (nextname, "/ ", 16) == 0) + return bfd_slurp_armap (abfd); + + /* See if the first element is an armap. */ + if (strncmp (nextname, ecoff_backend (abfd)->armap_start, + ARMAP_START_LENGTH) != 0 + || nextname[ARMAP_HEADER_MARKER_INDEX] != ARMAP_MARKER + || (nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN + && nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN) + || nextname[ARMAP_OBJECT_MARKER_INDEX] != ARMAP_MARKER + || (nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN + && nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN) + || strncmp (nextname + ARMAP_END_INDEX, + ARMAP_END, sizeof ARMAP_END - 1) != 0) + { + bfd_has_map (abfd) = false; + return true; + } + + /* Make sure we have the right byte ordering. */ + if (((nextname[ARMAP_HEADER_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN) + ^ (abfd->xvec->header_byteorder_big_p != false)) + || ((nextname[ARMAP_OBJECT_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN) + ^ (abfd->xvec->byteorder_big_p != false))) + { + bfd_error = wrong_format; + return false; + } + + /* Read in the armap. */ + ardata = bfd_ardata (abfd); + mapdata = snarf_ar_hdr (abfd); + if (mapdata == (struct areltdata *) NULL) + return false; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR) mapdata); + + raw_armap = (char *) bfd_alloc (abfd, parsed_size); + if (raw_armap == (char *) NULL) + { + bfd_error = no_memory; + return false; + } + + if (bfd_read ((PTR) raw_armap, 1, parsed_size, abfd) != parsed_size) + { + bfd_error = malformed_archive; + bfd_release (abfd, (PTR) raw_armap); + return false; + } + + count = bfd_h_get_32 (abfd, (PTR) raw_armap); + + ardata->symdef_count = 0; + ardata->cache = (struct ar_cache *) NULL; + + /* This code used to overlay the symdefs over the raw archive data, + but that doesn't work on a 64 bit host. */ + + stringbase = raw_armap + count * 8 + 8; + +#ifdef CHECK_ARMAP_HASH + { + unsigned int hlog; + + /* Double check that I have the hashing algorithm right by making + sure that every symbol can be looked up successfully. */ + hlog = 0; + for (i = 1; i < count; i <<= 1) + hlog++; + BFD_ASSERT (i == count); + + raw_ptr = raw_armap + 4; + for (i = 0; i < count; i++, raw_ptr += 8) + { + unsigned int name_offset, file_offset; + unsigned int hash, rehash, srch; + + name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr); + file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)); + if (file_offset == 0) + continue; + hash = ecoff_armap_hash (stringbase + name_offset, &rehash, count, + hlog); + if (hash == i) + continue; + + /* See if we can rehash to this location. */ + for (srch = (hash + rehash) & (count - 1); + srch != hash && srch != i; + srch = (srch + rehash) & (count - 1)) + BFD_ASSERT (bfd_h_get_32 (abfd, (PTR) (raw_armap + 8 + srch * 8)) + != 0); + BFD_ASSERT (srch == i); + } + } + +#endif /* CHECK_ARMAP_HASH */ + + raw_ptr = raw_armap + 4; + for (i = 0; i < count; i++, raw_ptr += 8) + if (bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)) != 0) + ++ardata->symdef_count; + + symdef_ptr = ((struct symdef *) + bfd_alloc (abfd, + ardata->symdef_count * sizeof (struct symdef))); + ardata->symdefs = (carsym *) symdef_ptr; + + raw_ptr = raw_armap + 4; + for (i = 0; i < count; i++, raw_ptr += 8) + { + unsigned int name_offset, file_offset; + + file_offset = bfd_h_get_32 (abfd, (PTR) (raw_ptr + 4)); + if (file_offset == 0) + continue; + name_offset = bfd_h_get_32 (abfd, (PTR) raw_ptr); + symdef_ptr->s.name = stringbase + name_offset; + symdef_ptr->file_offset = file_offset; + ++symdef_ptr; + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary. */ + ardata->first_file_filepos += ardata->first_file_filepos % 2; + + bfd_has_map (abfd) = true; + + return true; +} + +/* Write out an armap. */ + +boolean +ecoff_write_armap (abfd, elength, map, orl_count, stridx) + bfd *abfd; + unsigned int elength; + struct orl *map; + unsigned int orl_count; + int stridx; +{ + unsigned int hashsize, hashlog; + unsigned int symdefsize; + int padit; + unsigned int stringsize; + unsigned int mapsize; + file_ptr firstreal; + struct ar_hdr hdr; + struct stat statbuf; + unsigned int i; + bfd_byte temp[4]; + bfd_byte *hashtable; + bfd *current; + bfd *last_elt; + + /* Ultrix appears to use as a hash table size the least power of two + greater than twice the number of entries. */ + for (hashlog = 0; (1 << hashlog) <= 2 * orl_count; hashlog++) + ; + hashsize = 1 << hashlog; + + symdefsize = hashsize * 8; + padit = stridx % 2; + stringsize = stridx + padit; + + /* Include 8 bytes to store symdefsize and stringsize in output. */ + mapsize = symdefsize + stringsize + 8; + + firstreal = SARMAG + sizeof (struct ar_hdr) + mapsize + elength; + + memset ((PTR) &hdr, 0, sizeof hdr); + + /* Work out the ECOFF armap name. */ + strcpy (hdr.ar_name, ecoff_backend (abfd)->armap_start); + hdr.ar_name[ARMAP_HEADER_MARKER_INDEX] = ARMAP_MARKER; + hdr.ar_name[ARMAP_HEADER_ENDIAN_INDEX] = + (abfd->xvec->header_byteorder_big_p + ? ARMAP_BIG_ENDIAN + : ARMAP_LITTLE_ENDIAN); + hdr.ar_name[ARMAP_OBJECT_MARKER_INDEX] = ARMAP_MARKER; + hdr.ar_name[ARMAP_OBJECT_ENDIAN_INDEX] = + abfd->xvec->byteorder_big_p ? ARMAP_BIG_ENDIAN : ARMAP_LITTLE_ENDIAN; + memcpy (hdr.ar_name + ARMAP_END_INDEX, ARMAP_END, sizeof ARMAP_END - 1); + + /* Write the timestamp of the archive header to be just a little bit + later than the timestamp of the file, otherwise the linker will + complain that the index is out of date. Actually, the Ultrix + linker just checks the archive name; the GNU linker may check the + date. */ + stat (abfd->filename, &statbuf); + sprintf (hdr.ar_date, "%ld", (long) (statbuf.st_mtime + 60)); + + /* The DECstation uses zeroes for the uid, gid and mode of the + armap. */ + hdr.ar_uid[0] = '0'; + hdr.ar_gid[0] = '0'; + hdr.ar_mode[0] = '0'; + + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + + hdr.ar_fmag[0] = '`'; + hdr.ar_fmag[1] = '\n'; + + /* Turn all null bytes in the header into spaces. */ + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *)(&hdr))[i] == '\0') + (((char *)(&hdr))[i]) = ' '; + + if (bfd_write ((PTR) &hdr, 1, sizeof (struct ar_hdr), abfd) + != sizeof (struct ar_hdr)) + return false; + + bfd_h_put_32 (abfd, hashsize, temp); + if (bfd_write (temp, 1, 4, abfd) != 4) + return false; + + hashtable = (bfd_byte *) bfd_zalloc (abfd, symdefsize); + + current = abfd->archive_head; + last_elt = current; + for (i = 0; i < orl_count; i++) + { + unsigned int hash, rehash; + + /* Advance firstreal to the file position of this archive + element. */ + if (((bfd *) map[i].pos) != last_elt) + { + do + { + firstreal += arelt_size (current) + sizeof (struct ar_hdr); + firstreal += firstreal % 2; + current = current->next; + } + while (current != (bfd *) map[i].pos); + } + + last_elt = current; + + hash = ecoff_armap_hash (*map[i].name, &rehash, hashsize, hashlog); + if (bfd_h_get_32 (abfd, (PTR) (hashtable + (hash * 8) + 4)) != 0) + { + unsigned int srch; + + /* The desired slot is already taken. */ + for (srch = (hash + rehash) & (hashsize - 1); + srch != hash; + srch = (srch + rehash) & (hashsize - 1)) + if (bfd_h_get_32 (abfd, (PTR) (hashtable + (srch * 8) + 4)) == 0) + break; + + BFD_ASSERT (srch != hash); + + hash = srch; + } + + bfd_h_put_32 (abfd, map[i].namidx, (PTR) (hashtable + hash * 8)); + bfd_h_put_32 (abfd, firstreal, (PTR) (hashtable + hash * 8 + 4)); + } + + if (bfd_write (hashtable, 1, symdefsize, abfd) != symdefsize) + return false; + + bfd_release (abfd, hashtable); + + /* Now write the strings. */ + bfd_h_put_32 (abfd, stringsize, temp); + if (bfd_write (temp, 1, 4, abfd) != 4) + return false; + for (i = 0; i < orl_count; i++) + { + bfd_size_type len; + + len = strlen (*map[i].name) + 1; + if (bfd_write ((PTR) (*map[i].name), 1, len, abfd) != len) + return false; + } + + /* The spec sez this should be a newline. But in order to be + bug-compatible for DECstation ar we use a null. */ + if (padit) + { + if (bfd_write ("\0", 1, 1, abfd) != 1) + return false; + } + + return true; +} + +/* See whether this BFD is an archive. If it is, read in the armap + and the extended name table. */ + +bfd_target * +ecoff_archive_p (abfd) + bfd *abfd; +{ + char armag[SARMAG + 1]; + + if (bfd_read ((PTR) armag, 1, SARMAG, abfd) != SARMAG + || strncmp (armag, ARMAG, SARMAG) != 0) + { + bfd_error = wrong_format; + return (bfd_target *) NULL; + } + + /* We are setting bfd_ardata(abfd) here, but since bfd_ardata + involves a cast, we can't do it as the left operand of + assignment. */ + abfd->tdata.aout_ar_data = + (struct artdata *) bfd_zalloc (abfd, sizeof (struct artdata)); + + if (bfd_ardata (abfd) == (struct artdata *) NULL) + { + bfd_error = no_memory; + return (bfd_target *) NULL; + } + + bfd_ardata (abfd)->first_file_filepos = SARMAG; + + if (ecoff_slurp_armap (abfd) == false + || ecoff_slurp_extended_name_table (abfd) == false) + { + bfd_release (abfd, bfd_ardata (abfd)); + abfd->tdata.aout_ar_data = (struct artdata *) NULL; + return (bfd_target *) NULL; + } + + return abfd->xvec; +} diff --git a/gnu/usr.bin/gdb/bfd/elf.c b/gnu/usr.bin/gdb/bfd/elf.c new file mode 100644 index 00000000000..b8373df09ff --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/elf.c @@ -0,0 +1,251 @@ +/* ELF executable support for BFD. + Copyright 1993 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: elf.c,v 1.1 1995/10/18 08:39:52 deraadt Exp $ +*/ + +/* + +SECTION + ELF backends + + BFD support for ELF formats is being worked on. + Currently, the best supported back ends are for sparc and i386 + (running svr4 or Solaris 2). + + Documentation of the internals of the support code still needs + to be written. The code is changing quickly enough that we + haven't bothered yet. + */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#define ARCH_SIZE 0 +#include "libelf.h" + +/* Standard ELF hash function. Do not change this function; you will + cause invalid hash tables to be generated. (Well, you would if this + were being used yet.) */ +unsigned long +DEFUN (bfd_elf_hash, (name), + CONST unsigned char *name) +{ + unsigned long h = 0; + unsigned long g; + int ch; + + while ((ch = *name++) != '\0') + { + h = (h << 4) + ch; + if ((g = (h & 0xf0000000)) != 0) + { + h ^= g >> 24; + h &= ~g; + } + } + return h; +} + +/* Read a specified number of bytes at a specified offset in an ELF + file, into a newly allocated buffer, and return a pointer to the + buffer. */ + +static char * +DEFUN (elf_read, (abfd, offset, size), + bfd * abfd AND + long offset AND + int size) +{ + char *buf; + + if ((buf = bfd_alloc (abfd, size)) == NULL) + { + bfd_error = no_memory; + return NULL; + } + if (bfd_seek (abfd, offset, SEEK_SET) == -1) + { + bfd_error = system_call_error; + return NULL; + } + if (bfd_read ((PTR) buf, size, 1, abfd) != size) + { + bfd_error = system_call_error; + return NULL; + } + return buf; +} + +boolean +DEFUN (elf_mkobject, (abfd), bfd * abfd) +{ + /* this just does initialization */ + /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */ + elf_tdata (abfd) = (struct elf_obj_tdata *) + bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); + if (elf_tdata (abfd) == 0) + { + bfd_error = no_memory; + return false; + } + /* since everything is done at close time, do we need any + initialization? */ + + return true; +} + +char * +DEFUN (elf_get_str_section, (abfd, shindex), + bfd * abfd AND + unsigned int shindex) +{ + Elf_Internal_Shdr **i_shdrp; + char *shstrtab = NULL; + unsigned int offset; + unsigned int shstrtabsize; + + i_shdrp = elf_elfsections (abfd); + if (i_shdrp == 0 || i_shdrp[shindex] == 0) + return 0; + + shstrtab = i_shdrp[shindex]->rawdata; + if (shstrtab == NULL) + { + /* No cached one, attempt to read, and cache what we read. */ + offset = i_shdrp[shindex]->sh_offset; + shstrtabsize = i_shdrp[shindex]->sh_size; + shstrtab = elf_read (abfd, offset, shstrtabsize); + i_shdrp[shindex]->rawdata = (void *) shstrtab; + } + return shstrtab; +} + +char * +DEFUN (elf_string_from_elf_section, (abfd, shindex, strindex), + bfd * abfd AND + unsigned int shindex AND + unsigned int strindex) +{ + Elf_Internal_Shdr *hdr; + + if (strindex == 0) + return ""; + + hdr = elf_elfsections (abfd)[shindex]; + + if (!hdr->rawdata + && elf_get_str_section (abfd, shindex) == NULL) + return NULL; + + return ((char *) hdr->rawdata) + strindex; +} + +/* +INTERNAL_FUNCTION + bfd_elf_find_section + +SYNOPSIS + struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name); + +DESCRIPTION + Helper functions for GDB to locate the string tables. + Since BFD hides string tables from callers, GDB needs to use an + internal hook to find them. Sun's .stabstr, in particular, + isn't even pointed to by the .stab section, so ordinary + mechanisms wouldn't work to find it, even if we had some. +*/ + +struct elf_internal_shdr * +DEFUN (bfd_elf_find_section, (abfd, name), + bfd * abfd AND + char *name) +{ + Elf_Internal_Shdr **i_shdrp; + char *shstrtab; + unsigned int max; + unsigned int i; + + i_shdrp = elf_elfsections (abfd); + if (i_shdrp != NULL) + { + shstrtab = elf_get_str_section (abfd, elf_elfheader (abfd)->e_shstrndx); + if (shstrtab != NULL) + { + max = elf_elfheader (abfd)->e_shnum; + for (i = 1; i < max; i++) + if (!strcmp (&shstrtab[i_shdrp[i]->sh_name], name)) + return i_shdrp[i]; + } + } + return 0; +} + +const struct bfd_elf_arch_map bfd_elf_arch_map[] = { + { bfd_arch_sparc, EM_SPARC }, + { bfd_arch_i386, EM_386 }, + { bfd_arch_m68k, EM_68K }, + { bfd_arch_m88k, EM_88K }, + { bfd_arch_i860, EM_860 }, + { bfd_arch_mips, EM_MIPS }, + { bfd_arch_hppa, EM_HPPA }, +}; + +const int bfd_elf_arch_map_size = sizeof (bfd_elf_arch_map) / sizeof (bfd_elf_arch_map[0]); + +const char *const bfd_elf_section_type_names[] = { + "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB", + "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE", + "SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM", +}; + +/* ELF relocs are against symbols. If we are producing relocateable + output, and the reloc is against an external symbol, and nothing + has given us any additional addend, the resulting reloc will also + be against the same symbol. In such a case, we don't want to + change anything about the way the reloc is handled, since it will + all be done at final link time. Rather than put special case code + into bfd_perform_relocation, all the reloc types use this howto + function. It just short circuits the reloc if producing + relocateable output against an external symbol. */ + +bfd_reloc_status_type +bfd_elf_generic_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; +{ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + return bfd_reloc_continue; +} diff --git a/gnu/usr.bin/gdb/bfd/format.c b/gnu/usr.bin/gdb/bfd/format.c new file mode 100644 index 00000000000..7437095a9ad --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/format.c @@ -0,0 +1,261 @@ +/* Generic BFD support for file formats. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: format.c,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +/* +SECTION + File Formats + + A format is a BFD concept of high level file contents. The + formats supported by BFD are: + + o bfd_object + + The BFD may contain data, symbols, relocations and debug info. + + o bfd_archive + + The BFD contains other BFDs and an optional index. + + o bfd_core + + The BFD contains the result of an executable core dump. + + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +extern bfd_target *target_vector[]; +extern bfd_target *default_vector[]; + + +/* +FUNCTION + bfd_check_format + +SYNOPSIS + boolean bfd_check_format(bfd *abfd, bfd_format format); + +DESCRIPTION + This routine is supplied a BFD and a format. It attempts to + verify if the file attached to the BFD is indeed compatible + with the format specified (ie, one of <<bfd_object>>, + <<bfd_archive>> or <<bfd_core>>). + + If the BFD has been set to a specific @var{target} before the + call, only the named target and format combination will be + checked. If the target has not been set, or has been set to + <<default>> then all the known target backends will be + interrogated to determine a match. If the default target + matches, it is used. If not, exactly one target must recognize + the file, or an error results. + + The function returns <<true>> on success, otherwise <<false>> + with one of the following error codes: + + o invalid_operation - + if <<format>> is not one of <<bfd_object>>, <<bfd_archive>> or + <<bfd_core>>. + + o system_call_error - + if an error occured during a read - even some file mismatches + can cause system_call_errors + + o file_not_recognised - + none of the backends recognised the file format + + o file_ambiguously_recognized - + more than one backend recognised the file format. + +*/ + +boolean +DEFUN(bfd_check_format,(abfd, format), + bfd *abfd AND + bfd_format format) +{ + bfd_target **target, *save_targ, *right_targ; + int match_count; + + if (!bfd_read_p (abfd) || + ((int)(abfd->format) < (int)bfd_unknown) || + ((int)(abfd->format) >= (int)bfd_type_end)) { + bfd_error = invalid_operation; + return false; + } + + if (abfd->format != bfd_unknown) + return (abfd->format == format)? true: false; + + + /* Since the target type was defaulted, check them + all in the hope that one will be uniquely recognized. */ + + save_targ = abfd->xvec; + match_count = 0; + right_targ = 0; + + + /* presume the answer is yes */ + abfd->format = format; + + /* If the target type was explicitly specified, just check that target. */ + + if (!abfd->target_defaulted) { + bfd_seek (abfd, (file_ptr)0, SEEK_SET); /* rewind! */ + + right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + if (right_targ) { + abfd->xvec = right_targ; /* Set the target as returned */ + return true; /* File position has moved, BTW */ + } + } + + for (target = target_vector; *target != NULL; target++) { + bfd_target *temp; + + abfd->xvec = *target; /* Change BFD's target temporarily */ + bfd_seek (abfd, (file_ptr)0, SEEK_SET); + /* If _bfd_check_format neglects to set bfd_error, assume wrong_format. + We didn't used to even pay any attention to bfd_error, so I suspect + that some _bfd_check_format might have this problem. */ + bfd_error = wrong_format; + temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + if (temp) { /* This format checks out as ok! */ + right_targ = temp; + match_count++; + /* If this is the default target, accept it, even if other targets + might match. People who want those other targets have to set + the GNUTARGET variable. */ + if (temp == default_vector[0]) + { + match_count = 1; + break; + } +#ifdef GNU960 + /* Big- and little-endian b.out archives look the same, but it doesn't + * matter: there is no difference in their headers, and member file byte + * orders will (I hope) be handled appropriately by bfd. Ditto for big + * and little coff archives. And the 4 coff/b.out object formats are + * unambiguous. So accept the first match we find. + */ + break; +#endif + } else if (bfd_error != wrong_format) { + abfd->xvec = save_targ; + abfd->format = bfd_unknown; + return false; + } + } + + if (match_count == 1) { + abfd->xvec = right_targ; /* Change BFD's target permanently */ + return true; /* File position has moved, BTW */ + } + + abfd->xvec = save_targ; /* Restore original target type */ + abfd->format = bfd_unknown; /* Restore original format */ + bfd_error = ((match_count == 0) ? file_not_recognized : + file_ambiguously_recognized); + return false; +} + + +/* +FUNCTION + bfd_set_format + +SYNOPSIS + boolean bfd_set_format(bfd *, bfd_format); + +DESCRIPTION + This function sets the file format of the supplied BFD to the + format requested. If the target set in the BFD does not + support the format requested, the format is illegal or the BFD + is not open for writing than an error occurs. + +*/ + +boolean +DEFUN(bfd_set_format,(abfd, format), + bfd *abfd AND + bfd_format format) +{ + + if (bfd_read_p (abfd) || + ((int)abfd->format < (int)bfd_unknown) || + ((int)abfd->format >= (int)bfd_type_end)) { + bfd_error = invalid_operation; + return false; + } + + if (abfd->format != bfd_unknown) + return (abfd->format == format) ? true:false; + + /* presume the answer is yes */ + abfd->format = format; + + if (!BFD_SEND_FMT (abfd, _bfd_set_format, (abfd))) { + abfd->format = bfd_unknown; + return false; + } + + return true; +} + + +/* +FUNCTION + bfd_format_string + +SYNOPSIS + CONST char *bfd_format_string(bfd_format); + +DESCRIPTION + This function takes one argument, and enumerated type + (bfd_format) and returns a pointer to a const string + <<invalid>>, <<object>>, <<archive>>, <<core>> or <<unknown>> + depending upon the value of the enumeration. +*/ + +CONST char * +DEFUN(bfd_format_string,(format), + bfd_format format) +{ + if (((int)format <(int) bfd_unknown) + || ((int)format >=(int) bfd_type_end)) + return "invalid"; + + switch (format) { + case bfd_object: + return "object"; /* linker/assember/compiler output */ + case bfd_archive: + return "archive"; /* object archive file */ + case bfd_core: + return "core"; /* core dump */ + default: + return "unknown"; + } +} diff --git a/gnu/usr.bin/gdb/bfd/init.c b/gnu/usr.bin/gdb/bfd/init.c new file mode 100644 index 00000000000..5f379a96438 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/init.c @@ -0,0 +1,81 @@ +/* bfd initialization stuff + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: init.c,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +extern void DEFUN_VOID (bfd_section_init); + +static boolean initialized = false; + +/* +SECTION + Initialization + + This is the initialization section + +*/ + +/* +FUNCTION + bfd_init + +SYNOPSIS + void bfd_init(void); + +DESCRIPTION + This routine must be called before any other bfd function to + initialize magical internal data structures. +*/ + +void DEFUN_VOID(bfd_init) +{ + if (initialized == false) { + initialized = true; + + bfd_arch_init(); + } +} + + +/* +INTERNAL_FUNCTION + bfd_check_init + +DESCRIPTION + This routine is called before any other bfd function using + initialized data is used to ensure that the structures have + been initialized. Soon this function will go away, and the bfd + library will assume that bfd_init has been called. + +SYNOPSIS + void bfd_check_init(void); +*/ + +void DEFUN_VOID(bfd_check_init) +{ + if (initialized == false) { + bfd_init(); + } +} diff --git a/gnu/usr.bin/gdb/bfd/libaout.h b/gnu/usr.bin/gdb/bfd/libaout.h new file mode 100644 index 00000000000..35523830779 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libaout.h @@ -0,0 +1,400 @@ +/* BFD back-end data structures for a.out (and similar) files. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: libaout.h,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +/* We try to encapsulate the differences in the various a.out file + variants in a few routines, and otherwise share large masses of code. + This means we only have to fix bugs in one place, most of the time. */ + +/* Parameterize the a.out code based on whether it is being built + for a 32-bit architecture or a 64-bit architecture. */ +#if ARCH_SIZE==64 +#define GET_WORD bfd_h_get_64 +#define GET_SWORD bfd_h_get_signed_64 +#define PUT_WORD bfd_h_put_64 +#ifndef NAME +#define NAME(x,y) CAT3(x,_64_,y) +#endif +#define JNAME(x) CAT(x,_64) +#define BYTES_IN_WORD 8 +#else /* ARCH_SIZE == 32 */ +#define GET_WORD bfd_h_get_32 +#define GET_SWORD bfd_h_get_signed_32 +#define PUT_WORD bfd_h_put_32 +#ifndef NAME +#define NAME(x,y) CAT3(x,_32_,y) +#endif +#define JNAME(x) CAT(x,_32) +#define BYTES_IN_WORD 4 +#endif /* ARCH_SIZE==32 */ + +/* Declare these types at file level, since they are used in parameter + lists, which have wierd scope. */ +struct external_exec; +struct internal_exec; + +/* Back-end information for various a.out targets. */ +struct aout_backend_data +{ + /* Are ZMAGIC files mapped contiguously? If so, the text section may + need more padding, if the segment size (granularity for memory access + control) is larger than the page size. */ + unsigned char zmagic_mapped_contiguous; + /* If this flag is set, ZMAGIC/NMAGIC file headers get mapped in with the + text section, which starts immediately after the file header. + If not, the text section starts on the next page. */ + unsigned char text_includes_header; + + /* If the text section VMA isn't specified, and we need an absolute + address, use this as the default. If we're producing a relocatable + file, zero is always used. */ + /* ?? Perhaps a callback would be a better choice? Will this do anything + reasonable for a format that handles multiple CPUs with different + load addresses for each? */ + bfd_vma default_text_vma; + + /* Callback for setting the page and segment sizes, if they can't be + trivially determined from the architecture. */ + boolean (*set_sizes) PARAMS ((bfd *)); + + /* zmagic files only. For go32, the length of the exec header contributes + to the size of the text section in the file for alignment purposes but + does *not* get counted in the length of the text section. */ + unsigned char exec_header_not_counted; +}; +#define aout_backend_info(abfd) \ + ((CONST struct aout_backend_data *)((abfd)->xvec->backend_data)) + +/* This is the layout in memory of a "struct exec" while we process it. + All 'lengths' are given as a number of bytes. + All 'alignments' are for relinkable files only; an alignment of + 'n' indicates the corresponding segment must begin at an + address that is a multiple of (2**n). */ + +struct internal_exec +{ + long a_info; /* Magic number and flags, packed */ + bfd_vma a_text; /* length of text, in bytes */ + bfd_vma a_data; /* length of data, in bytes */ + bfd_vma a_bss; /* length of uninitialized data area in mem */ + bfd_vma a_syms; /* length of symbol table data in file */ + bfd_vma a_entry; /* start address */ + bfd_vma a_trsize; /* length of text's relocation info, in bytes */ + bfd_vma a_drsize; /* length of data's relocation info, in bytes */ + /* Added for i960 */ + bfd_vma a_tload; /* Text runtime load address */ + bfd_vma a_dload; /* Data runtime load address */ + unsigned char a_talign; /* Alignment of text segment */ + unsigned char a_dalign; /* Alignment of data segment */ + unsigned char a_balign; /* Alignment of bss segment */ + char a_relaxable; /* Enough info for linker relax */ +}; + +/* Magic number is written +< MSB > +3130292827262524232221201918171615141312111009080706050403020100 +< FLAGS >< MACHINE TYPE >< MAGIC NUMBER > +*/ +/* Magic number for NetBSD is +<MSB > +3130292827262524232221201918171615141312111009080706050403020100 +< FLAGS >< >< MAGIC NUMBER > +*/ + +enum machine_type { + M_UNKNOWN = 0, + M_68010 = 1, + M_68020 = 2, + M_SPARC = 3, + /* skip a bunch so we don't run into any of suns numbers */ + M_386 = 100, + M_29K = 101, /* AMD 29000 */ + M_386_DYNIX = 102, /* Sequent running dynix */ + M_386_NETBSD = 134, /* NetBSD/386 binary */ + M_M68K_NETBSD = 135, /* NetBSD/m68k binary */ + M_M68K4K_NETBSD = 136, /* NetBSD/m68k4k binary */ + M_NS32K_NETBSD = 137, /* NetBSD/ns32k binary */ + M_VAX = 140, /* NetBSD/vax binary */ + M_MIPS1 = 151, /* MIPS R2000/R3000 binary */ + M_MIPS2 = 152, /* MIPS R4000/R6000 binary */ + M_HP200 = 200, /* HP 200 (68010) BSD binary */ + M_HP300 = (300 % 256), /* HP 300 (68020+68881) BSD binary */ + M_HPUX = (0x20c % 256)/* HP 200/300 HPUX binary */ +}; + +#define N_DYNAMIC(exec) ((exec).a_info & 0x8000000) + +#ifndef N_MAGIC +# define N_MAGIC(exec) ((exec).a_info & 0xffff) +#endif + +#ifndef N_MACHTYPE +# define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +#endif + +#ifndef N_FLAGS +# define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +#endif + +#ifndef N_SET_INFO +# define N_SET_INFO(exec, magic, type, flags) \ +((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0xff) << 16) \ + | (((flags) & 0xff) << 24)) +#endif + +#ifndef N_SET_MAGIC +# define N_SET_MAGIC(exec, magic) \ +((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) +#endif + +#ifndef N_SET_MACHTYPE +# define N_SET_MACHTYPE(exec, machtype) \ +((exec).a_info = \ + ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) +#endif + +#ifndef N_SET_FLAGS +# define N_SET_FLAGS(exec, flags) \ +((exec).a_info = \ + ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) +#endif + +typedef struct aout_symbol { + asymbol symbol; + short desc; + char other; + unsigned char type; +} aout_symbol_type; + +/* The `tdata' struct for all a.out-like object file formats. + Various things depend on this struct being around any time an a.out + file is being handled. An example is dbxread.c in GDB. */ + +struct aoutdata { + struct internal_exec *hdr; /* exec file header */ + aout_symbol_type *symbols; /* symtab for input bfd */ + + /* For ease, we do this */ + asection *textsec; + asection *datasec; + asection *bsssec; + + /* We remember these offsets so that after check_file_format, we have + no dependencies on the particular format of the exec_hdr. */ + file_ptr sym_filepos; + file_ptr str_filepos; + + /* Size of a relocation entry in external form */ + unsigned reloc_entry_size; + + /* Size of a symbol table entry in external form */ + unsigned symbol_entry_size; + + /* Page size - needed for alignment of demand paged files. */ + unsigned long page_size; + + /* Segment size - needed for alignment of demand paged files. */ + unsigned long segment_size; + + unsigned exec_bytes_size; + unsigned vma_adjusted : 1; + + /* used when a bfd supports several highly similar formats */ + enum { + default_format = 0, + gnu_encap_format } subformat; + + enum { + undecided_magic = 0, + z_magic, + o_magic, + n_magic } magic; +}; + +struct aout_data_struct { + struct aoutdata a; + struct internal_exec e; +}; + +#define adata(bfd) ((bfd)->tdata.aout_data->a) +#define exec_hdr(bfd) (adata(bfd).hdr) +#define obj_aout_symbols(bfd) (adata(bfd).symbols) +#define obj_textsec(bfd) (adata(bfd).textsec) +#define obj_datasec(bfd) (adata(bfd).datasec) +#define obj_bsssec(bfd) (adata(bfd).bsssec) +#define obj_sym_filepos(bfd) (adata(bfd).sym_filepos) +#define obj_str_filepos(bfd) (adata(bfd).str_filepos) +#define obj_reloc_entry_size(bfd) (adata(bfd).reloc_entry_size) +#define obj_symbol_entry_size(bfd) (adata(bfd).symbol_entry_size) +#define obj_aout_subformat(bfd) (adata(bfd).subformat) + +/* We take the address of the first element of an asymbol to ensure that the + macro is only ever applied to an asymbol */ +#define aout_symbol(asymbol) ((aout_symbol_type *)(&(asymbol)->the_bfd)) + +/* Prototype declarations for functions defined in aoutx.h */ + +boolean +NAME(aout,squirt_out_relocs) PARAMS ((bfd *abfd, asection *section)); + +bfd_target * +NAME(aout,some_aout_object_p) PARAMS ((bfd *abfd, + struct internal_exec *execp, + bfd_target * (*callback)(bfd *))); + +boolean +NAME(aout,mkobject) PARAMS ((bfd *abfd)); + +enum machine_type +NAME(aout,machine_type) PARAMS ((enum bfd_architecture arch, + unsigned long machine)); + +boolean +NAME(aout,set_arch_mach) PARAMS ((bfd *abfd, enum bfd_architecture arch, + unsigned long machine)); + +boolean +NAME(aout,new_section_hook) PARAMS ((bfd *abfd, asection *newsect)); + +boolean +NAME(aout,set_section_contents) PARAMS ((bfd *abfd, sec_ptr section, + PTR location, file_ptr offset, bfd_size_type count)); + +asymbol * +NAME(aout,make_empty_symbol) PARAMS ((bfd *abfd)); + +boolean +NAME(aout,slurp_symbol_table) PARAMS ((bfd *abfd)); + +void +NAME(aout,write_syms) PARAMS ((bfd *abfd)); + +void +NAME(aout,reclaim_symbol_table) PARAMS ((bfd *abfd)); + +unsigned int +NAME(aout,get_symtab_upper_bound) PARAMS ((bfd *abfd)); + +unsigned int +NAME(aout,get_symtab) PARAMS ((bfd *abfd, asymbol **location)); + +boolean +NAME(aout,slurp_reloc_table) PARAMS ((bfd *abfd, sec_ptr asect, + asymbol **symbols)); + +unsigned int +NAME(aout,canonicalize_reloc) PARAMS ((bfd *abfd, sec_ptr section, + arelent **relptr, asymbol **symbols)); + +unsigned int +NAME(aout,get_reloc_upper_bound) PARAMS ((bfd *abfd, sec_ptr asect)); + +void +NAME(aout,reclaim_reloc) PARAMS ((bfd *ignore_abfd, sec_ptr ignore)); + +alent * +NAME(aout,get_lineno) PARAMS ((bfd *ignore_abfd, asymbol *ignore_symbol)); + +void +NAME(aout,print_symbol) PARAMS ((bfd *ignore_abfd, PTR file, + asymbol *symbol, bfd_print_symbol_type how)); + +void +NAME(aout,get_symbol_info) PARAMS ((bfd *ignore_abfd, + asymbol *symbol, symbol_info *ret)); + +boolean +NAME(aout,close_and_cleanup) PARAMS ((bfd *abfd)); + +boolean +NAME(aout,find_nearest_line) PARAMS ((bfd *abfd, asection *section, + asymbol **symbols, bfd_vma offset, CONST char **filename_ptr, + CONST char **functionname_ptr, unsigned int *line_ptr)); + +int +NAME(aout,sizeof_headers) PARAMS ((bfd *abfd, boolean exec)); + +boolean +NAME(aout,adjust_sizes_and_vmas) PARAMS ((bfd *abfd, + bfd_size_type *text_size, file_ptr *text_end)); + +void +NAME(aout,swap_exec_header_in) PARAMS ((bfd *abfd, + struct external_exec *raw_bytes, struct internal_exec *execp)); + +void +NAME(aout,swap_exec_header_out) PARAMS ((bfd *abfd, + struct internal_exec *execp, struct external_exec *raw_bytes)); + +/* Prototypes for functions in stab-syms.c. */ + +CONST char * +aout_stab_name PARAMS ((int code)); + +/* A.out uses the generic versions of these routines... */ + +#define aout_32_get_section_contents bfd_generic_get_section_contents +#define aout_32_close_and_cleanup bfd_generic_close_and_cleanup + +#define aout_64_get_section_contents bfd_generic_get_section_contents +#define aout_64_close_and_cleanup bfd_generic_close_and_cleanup +#ifndef NO_WRITE_HEADER_KLUDGE +#define NO_WRITE_HEADER_KLUDGE 0 +#endif + +#ifndef WRITE_HEADERS +#define WRITE_HEADERS(abfd, execp) \ + { \ + bfd_size_type text_size; /* dummy vars */ \ + file_ptr text_end; \ + if (adata(abfd).magic == undecided_magic) \ + NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); \ + \ + execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \ + execp->a_entry = bfd_get_start_address (abfd); \ + \ + execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes); \ + \ + bfd_seek (abfd, (file_ptr) 0, SEEK_SET); \ + bfd_write ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd); \ + /* Now write out reloc info, followed by syms and strings */ \ + \ + if (bfd_get_symcount (abfd) != 0) \ + { \ + bfd_seek (abfd, (file_ptr)(N_SYMOFF(*execp)), SEEK_SET); \ + \ + NAME(aout,write_syms)(abfd); \ + \ + bfd_seek (abfd, (file_ptr)(N_TRELOFF(*execp)), SEEK_SET); \ + \ + if (!NAME(aout,squirt_out_relocs) (abfd, obj_textsec (abfd))) return false; \ + bfd_seek (abfd, (file_ptr)(N_DRELOFF(*execp)), SEEK_SET); \ + \ + if (!NAME(aout,squirt_out_relocs)(abfd, obj_datasec (abfd))) return false; \ + } \ + } +#endif diff --git a/gnu/usr.bin/gdb/bfd/libbfd.c b/gnu/usr.bin/gdb/bfd/libbfd.c new file mode 100644 index 00000000000..79e7b64c967 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libbfd.c @@ -0,0 +1,853 @@ +/* Assorted BFD support routines, only used internally. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: libbfd.c,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* +SECTION + libbfd + +DESCRIPTION + This file contains various routines which are used within BFD. + They are not intended for export, but are documented here for + completeness. +*/ + +boolean +DEFUN(_bfd_dummy_new_section_hook,(ignore, ignore_newsect), + bfd *ignore AND + asection *ignore_newsect) +{ + return true; +} + +boolean +DEFUN(bfd_false ,(ignore), + bfd *ignore) +{ + return false; +} + +boolean +DEFUN(bfd_true,(ignore), + bfd *ignore) +{ + return true; +} + +PTR +DEFUN(bfd_nullvoidptr,(ignore), + bfd *ignore) +{ + return (PTR)NULL; +} + +int +DEFUN(bfd_0,(ignore), + bfd *ignore) +{ + return 0; +} + +unsigned int +DEFUN(bfd_0u,(ignore), + bfd *ignore) +{ + return 0; +} + +void +DEFUN(bfd_void,(ignore), + bfd *ignore) +{ +} + +boolean +DEFUN(_bfd_dummy_core_file_matches_executable_p,(ignore_core_bfd, ignore_exec_bfd), + bfd *ignore_core_bfd AND + bfd *ignore_exec_bfd) +{ + bfd_error = invalid_operation; + return false; +} + +/* of course you can't initialize a function to be the same as another, grr */ + +char * +DEFUN(_bfd_dummy_core_file_failing_command,(ignore_abfd), + bfd *ignore_abfd) +{ + return (char *)NULL; +} + +int +DEFUN(_bfd_dummy_core_file_failing_signal,(ignore_abfd), + bfd *ignore_abfd) +{ + return 0; +} + +bfd_target * +DEFUN(_bfd_dummy_target,(ignore_abfd), + bfd *ignore_abfd) +{ + return 0; +} + +/** zalloc -- allocate and clear storage */ + + +#ifndef zalloc +char * +DEFUN(zalloc,(size), + bfd_size_type size) +{ + char *ptr = (char *) malloc ((size_t)size); + + if ((ptr != NULL) && (size != 0)) + memset(ptr,0, (size_t) size); + + return ptr; +} +#endif + +/* +INTERNAL_FUNCTION + bfd_xmalloc + +SYNOPSIS + PTR bfd_xmalloc( bfd_size_type size); + +DESCRIPTION + Like malloc, but exit if no more memory. + +*/ + +/** There is major inconsistency in how running out of memory is handled. + Some routines return a NULL, and set bfd_error to no_memory. + However, obstack routines can't do this ... */ + + +DEFUN(PTR bfd_xmalloc,(size), + bfd_size_type size) +{ + static CONST char no_memory_message[] = "Virtual memory exhausted!\n"; + PTR ptr; + if (size == 0) size = 1; + ptr = (PTR)malloc((size_t) size); + if (!ptr) + { + write (2, no_memory_message, sizeof(no_memory_message)-1); + exit (-1); + } + return ptr; +} + +/* +INTERNAL_FUNCTION + bfd_xmalloc_by_size_t + +SYNOPSIS + PTR bfd_xmalloc_by_size_t ( size_t size); + +DESCRIPTION + Like malloc, but exit if no more memory. + Uses size_t, so it's suitable for use as obstack_chunk_alloc. + */ +PTR +DEFUN(bfd_xmalloc_by_size_t, (size), + size_t size) +{ + return bfd_xmalloc ((bfd_size_type) size); +} + +/* Some IO code */ + + +/* Note that archive entries don't have streams; they share their parent's. + This allows someone to play with the iostream behind BFD's back. + + Also, note that the origin pointer points to the beginning of a file's + contents (0 for non-archive elements). For archive entries this is the + first octet in the file, NOT the beginning of the archive header. */ + +static +int DEFUN(real_read,(where, a,b, file), + PTR where AND + int a AND + int b AND + FILE *file) +{ + return fread(where, a,b,file); +} +bfd_size_type +DEFUN(bfd_read,(ptr, size, nitems, abfd), + PTR ptr AND + bfd_size_type size AND + bfd_size_type nitems AND + bfd *abfd) +{ + int nread; + nread = real_read (ptr, 1, (int)(size*nitems), bfd_cache_lookup(abfd)); +#ifdef FILE_OFFSET_IS_CHAR_INDEX + if (nread > 0) + abfd->where += nread; +#endif + return nread; +} + +bfd_size_type +DEFUN(bfd_write,(ptr, size, nitems, abfd), + CONST PTR ptr AND + bfd_size_type size AND + bfd_size_type nitems AND + bfd *abfd) +{ + int nwrote = fwrite (ptr, 1, (int)(size*nitems), bfd_cache_lookup(abfd)); +#ifdef FILE_OFFSET_IS_CHAR_INDEX + if (nwrote > 0) + abfd->where += nwrote; +#endif + return nwrote; +} + +/* +INTERNAL_FUNCTION + bfd_write_bigendian_4byte_int + +SYNOPSIS + void bfd_write_bigendian_4byte_int(bfd *abfd, int i); + +DESCRIPTION + Writes a 4 byte integer to the outputing bfd, in big endian + mode regardless of what else is going on. This is useful in + archives. + +*/ +void +DEFUN(bfd_write_bigendian_4byte_int,(abfd, i), + bfd *abfd AND + int i) +{ + bfd_byte buffer[4]; + bfd_putb32(i, buffer); + bfd_write((PTR)buffer, 4, 1, abfd); +} + +long +DEFUN(bfd_tell,(abfd), + bfd *abfd) +{ + file_ptr ptr; + + ptr = ftell (bfd_cache_lookup(abfd)); + + if (abfd->my_archive) + ptr -= abfd->origin; + abfd->where = ptr; + return ptr; +} + +int +DEFUN(bfd_flush,(abfd), + bfd *abfd) +{ + return fflush (bfd_cache_lookup(abfd)); +} + +int +DEFUN(bfd_stat,(abfd, statbuf), + bfd *abfd AND + struct stat *statbuf) +{ + return fstat (fileno(bfd_cache_lookup(abfd)), statbuf); +} + +int +DEFUN(bfd_seek,(abfd, position, direction), + bfd * CONST abfd AND + CONST file_ptr position AND + CONST int direction) +{ + int result; + FILE *f; + file_ptr file_position; + /* For the time being, a BFD may not seek to it's end. The problem + is that we don't easily have a way to recognize the end of an + element in an archive. */ + + BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); + + if (direction == SEEK_CUR && position == 0) + return 0; +#ifdef FILE_OFFSET_IS_CHAR_INDEX + if (abfd->format != bfd_archive && abfd->my_archive == 0) + { +#ifndef NDEBUG + /* Explanation for this code: I'm only about 95+% sure that the above + conditions are sufficient and that all i/o calls are properly + adjusting the `where' field. So this is sort of an `assert' + that the `where' field is correct. If we can go a while without + tripping the abort, we can probably safely disable this code, + so that the real optimizations happen. */ + file_ptr where_am_i_now; + where_am_i_now = ftell (bfd_cache_lookup (abfd)); + if (abfd->my_archive) + where_am_i_now -= abfd->origin; + if (where_am_i_now != abfd->where) + abort (); +#endif + if (direction == SEEK_SET && position == abfd->where) + return 0; + } + else + { + /* We need something smarter to optimize access to archives. + Currently, anything inside an archive is read via the file + handle for the archive. Which means that a bfd_seek on one + component affects the `current position' in the archive, as + well as in any other component. + + It might be sufficient to put a spike through the cache + abstraction, and look to the archive for the file position, + but I think we should try for something cleaner. + + In the meantime, no optimization for archives. */ + } +#endif + + f = bfd_cache_lookup (abfd); + file_position = position; + if (direction == SEEK_SET && abfd->my_archive != NULL) + file_position += abfd->origin; + + result = fseek (f, file_position, direction); + + if (result != 0) + /* Force redetermination of `where' field. */ + bfd_tell (abfd); + else + { +#ifdef FILE_OFFSET_IS_CHAR_INDEX + /* Adjust `where' field. */ + if (direction == SEEK_SET) + abfd->where = position; + else + abfd->where += position; +#endif + } + return result; +} + +/** Make a string table */ + +/*>bfd.h< + Add string to table pointed to by table, at location starting with free_ptr. + resizes the table if necessary (if it's NULL, creates it, ignoring + table_length). Updates free_ptr, table, table_length */ + +boolean +DEFUN(bfd_add_to_string_table,(table, new_string, table_length, free_ptr), + char **table AND + char *new_string AND + unsigned int *table_length AND + char **free_ptr) +{ + size_t string_length = strlen (new_string) + 1; /* include null here */ + char *base = *table; + size_t space_length = *table_length; + unsigned int offset = (base ? *free_ptr - base : 0); + + if (base == NULL) { + /* Avoid a useless regrow if we can (but of course we still + take it next time */ + space_length = (string_length < DEFAULT_STRING_SPACE_SIZE ? + DEFAULT_STRING_SPACE_SIZE : string_length+1); + base = zalloc ((bfd_size_type) space_length); + + if (base == NULL) { + bfd_error = no_memory; + return false; + } + } + + if ((size_t)(offset + string_length) >= space_length) { + /* Make sure we will have enough space */ + while ((size_t)(offset + string_length) >= space_length) + space_length += space_length/2; /* grow by 50% */ + + base = (char *) realloc (base, space_length); + if (base == NULL) { + bfd_error = no_memory; + return false; + } + + } + + memcpy (base + offset, new_string, string_length); + *table = base; + *table_length = space_length; + *free_ptr = base + offset + string_length; + + return true; +} + +/** The do-it-yourself (byte) sex-change kit */ + +/* The middle letter e.g. get<b>short indicates Big or Little endian + target machine. It doesn't matter what the byte order of the host + machine is; these routines work for either. */ + +/* FIXME: Should these take a count argument? + Answer (gnu@cygnus.com): No, but perhaps they should be inline + functions in swap.h #ifdef __GNUC__. + Gprof them later and find out. */ + +/* +FUNCTION + bfd_put_size +FUNCTION + bfd_get_size + +DESCRIPTION + These macros as used for reading and writing raw data in + sections; each access (except for bytes) is vectored through + the target format of the BFD and mangled accordingly. The + mangling performs any necessary endian translations and + removes alignment restrictions. Note that types accepted and + returned by these macros are identical so they can be swapped + around in macros--for example libaout.h defines GET_WORD to + either bfd_get_32 or bfd_get_64. + + In the put routines, val must be a bfd_vma. If we are on a + system without prototypes, the caller is responsible for making + sure that is true, with a cast if necessary. We don't cast + them in the macro definitions because that would prevent lint + or gcc -Wall from detecting sins such as passing a pointer. + To detect calling these with less than a bfd_vma, use gcc + -Wconversion on a host with 64 bit bfd_vma's. + +. +.{* Byte swapping macros for user section data. *} +. +.#define bfd_put_8(abfd, val, ptr) \ +. (*((unsigned char *)(ptr)) = (unsigned char)val) +.#define bfd_put_signed_8 \ +. bfd_put_8 +.#define bfd_get_8(abfd, ptr) \ +. (*(unsigned char *)(ptr)) +.#define bfd_get_signed_8(abfd, ptr) \ +. ((*(unsigned char *)(ptr) ^ 0x80) - 0x80) +. +.#define bfd_put_16(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx16, ((val),(ptr))) +.#define bfd_put_signed_16 \ +. bfd_put_16 +.#define bfd_get_16(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx16, (ptr)) +.#define bfd_get_signed_16(abfd, ptr) \ +. BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) +. +.#define bfd_put_32(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx32, ((val),(ptr))) +.#define bfd_put_signed_32 \ +. bfd_put_32 +.#define bfd_get_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx32, (ptr)) +.#define bfd_get_signed_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx_signed_32, (ptr)) +. +.#define bfd_put_64(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx64, ((val), (ptr))) +.#define bfd_put_signed_64 \ +. bfd_put_64 +.#define bfd_get_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx64, (ptr)) +.#define bfd_get_signed_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx_signed_64, (ptr)) +. +*/ + +/* +FUNCTION + bfd_h_put_size +FUNCTION + bfd_h_get_size + +DESCRIPTION + These macros have the same function as their <<bfd_get_x>> + bretherin, except that they are used for removing information + for the header records of object files. Believe it or not, + some object files keep their header records in big endian + order, and their data in little endian order. +. +.{* Byte swapping macros for file header data. *} +. +.#define bfd_h_put_8(abfd, val, ptr) \ +. bfd_put_8 (abfd, val, ptr) +.#define bfd_h_put_signed_8(abfd, val, ptr) \ +. bfd_put_8 (abfd, val, ptr) +.#define bfd_h_get_8(abfd, ptr) \ +. bfd_get_8 (abfd, ptr) +.#define bfd_h_get_signed_8(abfd, ptr) \ +. bfd_get_signed_8 (abfd, ptr) +. +.#define bfd_h_put_16(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_h_putx16,(val,ptr)) +.#define bfd_h_put_signed_16 \ +. bfd_h_put_16 +.#define bfd_h_get_16(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx16,(ptr)) +.#define bfd_h_get_signed_16(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_16, (ptr)) +. +.#define bfd_h_put_32(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_h_putx32,(val,ptr)) +.#define bfd_h_put_signed_32 \ +. bfd_h_put_32 +.#define bfd_h_get_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx32,(ptr)) +.#define bfd_h_get_signed_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_32, (ptr)) +. +.#define bfd_h_put_64(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_h_putx64,(val, ptr)) +.#define bfd_h_put_signed_64 \ +. bfd_h_put_64 +.#define bfd_h_get_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx64,(ptr)) +.#define bfd_h_get_signed_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_h_getx_signed_64, (ptr)) +. +*/ + +/* Sign extension to bfd_signed_vma. */ +#define COERCE16(x) (((bfd_signed_vma) (x) ^ 0x8000) - 0x8000) +#define COERCE32(x) (((bfd_signed_vma) (x) ^ 0x80000000) - 0x80000000) +#define EIGHT_GAZILLION (((HOST_64_BIT)0x80000000) << 32) +#define COERCE64(x) \ + (((bfd_signed_vma) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION) + +bfd_vma +DEFUN(bfd_getb16,(addr), + register bfd_byte *addr) +{ + return (addr[0] << 8) | addr[1]; +} + +bfd_vma +DEFUN(bfd_getl16,(addr), + register bfd_byte *addr) +{ + return (addr[1] << 8) | addr[0]; +} + +bfd_signed_vma +DEFUN(bfd_getb_signed_16,(addr), + register bfd_byte *addr) +{ + return COERCE16((addr[0] << 8) | addr[1]); +} + +bfd_signed_vma +DEFUN(bfd_getl_signed_16,(addr), + register bfd_byte *addr) +{ + return COERCE16((addr[1] << 8) | addr[0]); +} + +void +DEFUN(bfd_putb16,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ + addr[0] = (bfd_byte)(data >> 8); + addr[1] = (bfd_byte )data; +} + +void +DEFUN(bfd_putl16,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ + addr[0] = (bfd_byte )data; + addr[1] = (bfd_byte)(data >> 8); +} + +bfd_vma +bfd_getb32 (addr) + register bfd_byte *addr; +{ + return (((((bfd_vma)addr[0] << 8) | addr[1]) << 8) + | addr[2]) << 8 | addr[3]; +} + +bfd_vma +bfd_getl32 (addr) + register bfd_byte *addr; +{ + return (((((bfd_vma)addr[3] << 8) | addr[2]) << 8) + | addr[1]) << 8 | addr[0]; +} + +bfd_signed_vma +bfd_getb_signed_32 (addr) + register bfd_byte *addr; +{ + return COERCE32((((((bfd_vma)addr[0] << 8) | addr[1]) << 8) + | addr[2]) << 8 | addr[3]); +} + +bfd_signed_vma +bfd_getl_signed_32 (addr) + register bfd_byte *addr; +{ + return COERCE32((((((bfd_vma)addr[3] << 8) | addr[2]) << 8) + | addr[1]) << 8 | addr[0]); +} + +bfd_vma +DEFUN(bfd_getb64,(addr), + register bfd_byte *addr) +{ +#ifdef BFD64 + bfd_vma low, high; + + high= ((((((((addr[0]) << 8) | + addr[1]) << 8) | + addr[2]) << 8) | + addr[3]) ); + + low = (((((((((bfd_vma)addr[4]) << 8) | + addr[5]) << 8) | + addr[6]) << 8) | + addr[7])); + + return high << 32 | low; +#else + BFD_FAIL(); + return 0; +#endif + +} + +bfd_vma +DEFUN(bfd_getl64,(addr), + register bfd_byte *addr) +{ + +#ifdef BFD64 + bfd_vma low, high; + high= (((((((addr[7] << 8) | + addr[6]) << 8) | + addr[5]) << 8) | + addr[4])); + + low = ((((((((bfd_vma)addr[3] << 8) | + addr[2]) << 8) | + addr[1]) << 8) | + addr[0]) ); + + return high << 32 | low; +#else + BFD_FAIL(); + return 0; +#endif + +} + +bfd_signed_vma +DEFUN(bfd_getb_signed_64,(addr), + register bfd_byte *addr) +{ +#ifdef BFD64 + bfd_vma low, high; + + high= ((((((((addr[0]) << 8) | + addr[1]) << 8) | + addr[2]) << 8) | + addr[3]) ); + + low = (((((((((bfd_vma)addr[4]) << 8) | + addr[5]) << 8) | + addr[6]) << 8) | + addr[7])); + + return COERCE64(high << 32 | low); +#else + BFD_FAIL(); + return 0; +#endif + +} + +bfd_signed_vma +DEFUN(bfd_getl_signed_64,(addr), + register bfd_byte *addr) +{ + +#ifdef BFD64 + bfd_vma low, high; + high= (((((((addr[7] << 8) | + addr[6]) << 8) | + addr[5]) << 8) | + addr[4])); + + low = ((((((((bfd_vma)addr[3] << 8) | + addr[2]) << 8) | + addr[1]) << 8) | + addr[0]) ); + + return COERCE64(high << 32 | low); +#else + BFD_FAIL(); + return 0; +#endif + +} + +void +DEFUN(bfd_putb32,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ + addr[0] = (bfd_byte)(data >> 24); + addr[1] = (bfd_byte)(data >> 16); + addr[2] = (bfd_byte)(data >> 8); + addr[3] = (bfd_byte)data; +} + +void +DEFUN(bfd_putl32,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ + addr[0] = (bfd_byte)data; + addr[1] = (bfd_byte)(data >> 8); + addr[2] = (bfd_byte)(data >> 16); + addr[3] = (bfd_byte)(data >> 24); +} +void +DEFUN(bfd_putb64,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ +#ifdef BFD64 + addr[0] = (bfd_byte)(data >> (7*8)); + addr[1] = (bfd_byte)(data >> (6*8)); + addr[2] = (bfd_byte)(data >> (5*8)); + addr[3] = (bfd_byte)(data >> (4*8)); + addr[4] = (bfd_byte)(data >> (3*8)); + addr[5] = (bfd_byte)(data >> (2*8)); + addr[6] = (bfd_byte)(data >> (1*8)); + addr[7] = (bfd_byte)(data >> (0*8)); +#else + BFD_FAIL(); +#endif + +} + +void +DEFUN(bfd_putl64,(data, addr), + bfd_vma data AND + register bfd_byte *addr) +{ +#ifdef BFD64 + addr[7] = (bfd_byte)(data >> (7*8)); + addr[6] = (bfd_byte)(data >> (6*8)); + addr[5] = (bfd_byte)(data >> (5*8)); + addr[4] = (bfd_byte)(data >> (4*8)); + addr[3] = (bfd_byte)(data >> (3*8)); + addr[2] = (bfd_byte)(data >> (2*8)); + addr[1] = (bfd_byte)(data >> (1*8)); + addr[0] = (bfd_byte)(data >> (0*8)); +#else + BFD_FAIL(); +#endif + +} + + +/* Default implementation */ + +boolean +DEFUN(bfd_generic_get_section_contents, (abfd, section, location, offset, count), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + if (count == 0) + return true; + if ((bfd_size_type)(offset+count) > section->_raw_size + || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1 + || bfd_read(location, (bfd_size_type)1, count, abfd) != count) + return (false); /* on error */ + return (true); +} + +/* This generic function can only be used in implementations where creating + NEW sections is disallowed. It is useful in patching existing sections + in read-write files, though. See other set_section_contents functions + to see why it doesn't work for new sections. */ +boolean +DEFUN(bfd_generic_set_section_contents, (abfd, section, location, offset, count), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + if (count == 0) + return true; + if ((bfd_size_type)(offset+count) > bfd_get_section_size_after_reloc(section) + || bfd_seek(abfd, (file_ptr)(section->filepos + offset), SEEK_SET) == -1 + || bfd_write(location, (bfd_size_type)1, count, abfd) != count) + return (false); /* on error */ + return (true); +} + +/* +INTERNAL_FUNCTION + bfd_log2 + +DESCRIPTION + Return the log base 2 of the value supplied, rounded up. eg an + arg of 1025 would return 11. + +SYNOPSIS + unsigned int bfd_log2(bfd_vma x); +*/ + +unsigned +bfd_log2(x) + bfd_vma x; +{ + unsigned result = 0; + while ( (bfd_vma)(1<< result) < x) + result++; + return result; +} diff --git a/gnu/usr.bin/gdb/bfd/libbfd.h b/gnu/usr.bin/gdb/bfd/libbfd.h new file mode 100644 index 00000000000..11ee4da782d --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libbfd.h @@ -0,0 +1,276 @@ +/* libbfd.h -- Declarations used by bfd library *implementation*. + (This include file is not for users of the library.) + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: libbfd.h,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + + +/* Align an address upward to a boundary, expressed as a number of bytes. + E.g. align to an 8-byte boundary with argument of 8. */ +#define BFD_ALIGN(this, boundary) \ + ((( (this) + ((boundary) -1)) & (~((boundary)-1)))) + +/* If you want to read and write large blocks, you might want to do it + in quanta of this amount */ +#define DEFAULT_BUFFERSIZE 8192 + +/* Set a tdata field. Can't use the other macros for this, since they + do casts, and casting to the left of assignment isn't portable. */ +#define set_tdata(bfd, v) ((bfd)->tdata.any = (PTR) (v)) + +/* tdata for an archive. For an input archive, cache + needs to be free()'d. For an output archive, symdefs do. */ + +struct artdata { + file_ptr first_file_filepos; + /* Speed up searching the armap */ + struct ar_cache *cache; + bfd *archive_head; /* Only interesting in output routines */ + carsym *symdefs; /* the symdef entries */ + symindex symdef_count; /* how many there are */ + char *extended_names; /* clever intel extension */ + time_t armap_timestamp; /* Timestamp value written into armap. + This is used for BSD archives to check + that the timestamp is recent enough + for the BSD linker to not complain, + just before we finish writing an + archive. */ + file_ptr armap_datepos; /* Position within archive to seek to + rewrite the date field. */ +}; + +#define bfd_ardata(bfd) ((bfd)->tdata.aout_ar_data) + +/* Goes in bfd's arelt_data slot */ +struct areltdata { + char * arch_header; /* it's actually a string */ + unsigned int parsed_size; /* octets of filesize not including ar_hdr */ + char *filename; /* null-terminated */ +}; + +#define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size) + +char *zalloc PARAMS ((bfd_size_type size)); + +/* These routines allocate and free things on the BFD's obstack. Note + that realloc can never occur in place. */ + +PTR bfd_alloc PARAMS ((bfd *abfd, size_t size)); +PTR bfd_zalloc PARAMS ((bfd *abfd, size_t size)); +PTR bfd_realloc PARAMS ((bfd *abfd, PTR orig, size_t new)); +void bfd_alloc_grow PARAMS ((bfd *abfd, PTR thing, size_t size)); +PTR bfd_alloc_finish PARAMS ((bfd *abfd)); +PTR bfd_alloc_by_size_t PARAMS ((bfd *abfd, size_t wanted)); + +#define bfd_release(x,y) (void) obstack_free(&(x->memory),y) + + +bfd_size_type bfd_read PARAMS ((PTR ptr, bfd_size_type size, + bfd_size_type nitems, bfd *abfd)); +bfd_size_type bfd_write PARAMS ((CONST PTR ptr, bfd_size_type size, + bfd_size_type nitems, bfd *abfd)); +int bfd_seek PARAMS ((bfd* CONST abfd, CONST file_ptr fp, + CONST int direction)); +long bfd_tell PARAMS ((bfd *abfd)); + +int bfd_flush PARAMS ((bfd *abfd)); +int bfd_stat PARAMS ((bfd *abfd, struct stat *)); + +bfd * _bfd_create_empty_archive_element_shell PARAMS ((bfd *obfd)); +bfd * look_for_bfd_in_cache PARAMS ((bfd *arch_bfd, file_ptr index)); +boolean _bfd_generic_mkarchive PARAMS ((bfd *abfd)); +struct areltdata * snarf_ar_hdr PARAMS ((bfd *abfd)); +bfd_target * bfd_generic_archive_p PARAMS ((bfd *abfd)); +boolean bfd_slurp_armap PARAMS ((bfd *abfd)); +boolean bfd_slurp_bsd_armap_f2 PARAMS ((bfd *abfd)); +#define bfd_slurp_bsd_armap bfd_slurp_armap +#define bfd_slurp_coff_armap bfd_slurp_armap +boolean _bfd_slurp_extended_name_table PARAMS ((bfd *abfd)); +boolean _bfd_write_archive_contents PARAMS ((bfd *abfd)); +bfd * new_bfd PARAMS (()); + +#define DEFAULT_STRING_SPACE_SIZE 0x2000 +boolean bfd_add_to_string_table PARAMS ((char **table, char *new_string, + unsigned int *table_length, + char **free_ptr)); + +boolean bfd_false PARAMS ((bfd *ignore)); +boolean bfd_true PARAMS ((bfd *ignore)); +PTR bfd_nullvoidptr PARAMS ((bfd *ignore)); +int bfd_0 PARAMS ((bfd *ignore)); +unsigned int bfd_0u PARAMS ((bfd *ignore)); +void bfd_void PARAMS ((bfd *ignore)); + +bfd * new_bfd_contained_in PARAMS ((bfd *)); +boolean _bfd_dummy_new_section_hook PARAMS ((bfd *ignore, asection *newsect)); +char * _bfd_dummy_core_file_failing_command PARAMS ((bfd *abfd)); +int _bfd_dummy_core_file_failing_signal PARAMS ((bfd *abfd)); +boolean _bfd_dummy_core_file_matches_executable_p PARAMS ((bfd *core_bfd, + bfd *exec_bfd)); +bfd_target * _bfd_dummy_target PARAMS ((bfd *abfd)); + +void bfd_dont_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); +void bfd_bsd_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); +void bfd_gnu_truncate_arname PARAMS ((bfd *abfd, CONST char *filename, + char *hdr)); + +boolean bsd_write_armap PARAMS ((bfd *arch, unsigned int elength, + struct orl *map, unsigned int orl_count, int stridx)); + +boolean coff_write_armap PARAMS ((bfd *arch, unsigned int elength, + struct orl *map, unsigned int orl_count, int stridx)); + +bfd * bfd_generic_openr_next_archived_file PARAMS ((bfd *archive, + bfd *last_file)); + +int bfd_generic_stat_arch_elt PARAMS ((bfd *, struct stat *)); + +boolean bfd_generic_get_section_contents PARAMS ((bfd *abfd, sec_ptr section, + PTR location, file_ptr offset, + bfd_size_type count)); + +boolean bfd_generic_set_section_contents PARAMS ((bfd *abfd, sec_ptr section, + PTR location, file_ptr offset, + bfd_size_type count)); + +/* Macros to tell if bfds are read or write enabled. + + Note that bfds open for read may be scribbled into if the fd passed + to bfd_fdopenr is actually open both for read and write + simultaneously. However an output bfd will never be open for + read. Therefore sometimes you want to check bfd_read_p or + !bfd_read_p, and only sometimes bfd_write_p. +*/ + +#define bfd_read_p(abfd) ((abfd)->direction == read_direction || (abfd)->direction == both_direction) +#define bfd_write_p(abfd) ((abfd)->direction == write_direction || (abfd)->direction == both_direction) + +void bfd_assert PARAMS ((char*,int)); + +#define BFD_ASSERT(x) \ +{ if (!(x)) bfd_assert(__FILE__,__LINE__); } + +#define BFD_FAIL() \ +{ bfd_assert(__FILE__,__LINE__); } + +FILE * bfd_cache_lookup_worker PARAMS ((bfd *)); + +extern bfd *bfd_last_cache; + +/* Now Steve, what's the story here? */ +#ifdef lint +#define itos(x) "l" +#define stoi(x) 1 +#else +#define itos(x) ((char*)(x)) +#define stoi(x) ((int)(x)) +#endif + +/* Generic routine for close_and_cleanup is really just bfd_true. */ +#define bfd_generic_close_and_cleanup bfd_true + +/* And more follows */ + +void +bfd_check_init PARAMS ((void)); + +PTR +bfd_xmalloc PARAMS (( bfd_size_type size)); + +PTR +bfd_xmalloc_by_size_t PARAMS (( size_t size)); + +void +bfd_write_bigendian_4byte_int PARAMS ((bfd *abfd, int i)); + +unsigned int +bfd_log2 PARAMS ((bfd_vma x)); + +#define BFD_CACHE_MAX_OPEN 10 +extern bfd *bfd_last_cache; + +#define bfd_cache_lookup(x) \ + ((x)==bfd_last_cache? \ + (FILE*)(bfd_last_cache->iostream): \ + bfd_cache_lookup_worker(x)) +boolean +bfd_cache_close PARAMS ((bfd *)); + +FILE* +bfd_open_file PARAMS ((bfd *)); + +FILE * +bfd_cache_lookup_worker PARAMS ((bfd *)); + +void +bfd_constructor_entry PARAMS ((bfd *abfd, + asymbol **symbol_ptr_ptr, + CONST char*type)); + +CONST struct reloc_howto_struct * +bfd_default_reloc_type_lookup + PARAMS ((bfd *abfd AND + bfd_reloc_code_real_type code)); + +boolean +bfd_generic_relax_section + PARAMS ((bfd *abfd, + asection *section, + asymbol **symbols)); + +bfd_byte * + +bfd_generic_get_relocated_section_contents PARAMS ((bfd *abfd, + struct bfd_seclet *seclet, + bfd_byte *data, + boolean relocateable)); + +boolean +bfd_generic_seclet_link + PARAMS ((bfd *abfd, + PTR data, + boolean relocateable)); + +extern bfd_arch_info_type bfd_default_arch_struct; +boolean +bfd_default_set_arch_mach PARAMS ((bfd *abfd, + enum bfd_architecture arch, + unsigned long mach)); + +void +bfd_arch_init PARAMS ((void)); + +void +bfd_arch_linkin PARAMS ((bfd_arch_info_type *)); + +CONST bfd_arch_info_type * +bfd_default_compatible + PARAMS ((CONST bfd_arch_info_type *a, + CONST bfd_arch_info_type *b)); + +boolean +bfd_default_scan PARAMS ((CONST struct bfd_arch_info *, CONST char *)); + +struct elf_internal_shdr * +bfd_elf_find_section PARAMS ((bfd *abfd, char *name)); + diff --git a/gnu/usr.bin/gdb/bfd/libcoff.h b/gnu/usr.bin/gdb/bfd/libcoff.h new file mode 100644 index 00000000000..536073d40d7 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libcoff.h @@ -0,0 +1,355 @@ +/* BFD COFF object file private structure. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: libcoff.h,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + + +/* Object file tdata; access macros */ + +#define coff_data(bfd) ((bfd)->tdata.coff_obj_data) +#define exec_hdr(bfd) (coff_data(bfd)->hdr) +#define obj_symbols(bfd) (coff_data(bfd)->symbols) +#define obj_sym_filepos(bfd) (coff_data(bfd)->sym_filepos) + +#define obj_relocbase(bfd) (coff_data(bfd)->relocbase) +#define obj_raw_syments(bfd) (coff_data(bfd)->raw_syments) +#define obj_raw_syment_count(bfd) (coff_data(bfd)->raw_syment_count) +#define obj_convert(bfd) (coff_data(bfd)->conversion_table) +#define obj_conv_table_size(bfd) (coff_data(bfd)->conv_table_size) +#if CFILE_STUFF +#define obj_symbol_slew(bfd) (coff_data(bfd)->symbol_index_slew) +#else +#define obj_symbol_slew(bfd) 0 +#endif + + +/* `Tdata' information kept for COFF files. */ + +typedef struct coff_tdata +{ + struct coff_symbol_struct *symbols; /* symtab for input bfd */ + unsigned int *conversion_table; + int conv_table_size; + file_ptr sym_filepos; + + long symbol_index_slew; /* used during read to mark whether a + C_FILE symbol as been added. */ + + struct coff_ptr_struct *raw_syments; + struct lineno *raw_linenos; + unsigned int raw_syment_count; + unsigned short flags; + + /* These are only valid once writing has begun */ + long int relocbase; + + /* These members communicate important constants about the symbol table + to GDB's symbol-reading code. These `constants' unfortunately vary + from coff implementation to implementation... */ + unsigned local_n_btmask; + unsigned local_n_btshft; + unsigned local_n_tmask; + unsigned local_n_tshift; + unsigned local_symesz; + unsigned local_auxesz; + unsigned local_linesz; +} coff_data_type; + +/* We take the address of the first element of a asymbol to ensure that the + * macro is only ever applied to an asymbol. */ +#define coffsymbol(asymbol) ((coff_symbol_type *)(&((asymbol)->the_bfd))) + +/* Functions in coffgen.c. */ +extern bfd_target *coff_object_p PARAMS ((bfd *)); +extern struct sec *coff_section_from_bfd_index PARAMS ((bfd *, int)); +extern unsigned int coff_get_symtab_upper_bound PARAMS ((bfd *)); +extern unsigned int coff_get_symtab PARAMS ((bfd *, asymbol **)); +extern int coff_count_linenumbers PARAMS ((bfd *)); +extern struct coff_symbol_struct *coff_symbol_from PARAMS ((bfd *, asymbol *)); +extern void coff_renumber_symbols PARAMS ((bfd *)); +extern void coff_mangle_symbols PARAMS ((bfd *)); +extern void coff_write_symbols PARAMS ((bfd *)); +extern void coff_write_linenumbers PARAMS ((bfd *)); +extern alent *coff_get_lineno PARAMS ((bfd *, asymbol *)); +extern asymbol *coff_section_symbol PARAMS ((bfd *, char *)); +extern struct coff_ptr_struct *coff_get_normalized_symtab PARAMS ((bfd *)); +extern unsigned int coff_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +extern asymbol *coff_make_empty_symbol PARAMS ((bfd *)); +extern void coff_print_symbol PARAMS ((bfd *, PTR filep, asymbol *, + bfd_print_symbol_type how)); +extern void coff_get_symbol_info PARAMS ((bfd *, asymbol *, + symbol_info *ret)); +extern asymbol *coff_bfd_make_debug_symbol PARAMS ((bfd *, PTR, + unsigned long)); +extern boolean coff_find_nearest_line PARAMS ((bfd *, + asection *, + asymbol **, + bfd_vma offset, + CONST char **filename_ptr, + CONST char **functionname_ptr, + unsigned int *line_ptr)); +extern int coff_sizeof_headers PARAMS ((bfd *, boolean reloc)); +extern boolean bfd_coff_reloc16_relax_section PARAMS ((bfd *, + asection *, + asymbol **)); +extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_seclet *, bfd_byte *, boolean relocateable)); +extern bfd_vma bfd_coff_reloc16_get_value PARAMS ((arelent *, + struct bfd_seclet *)); + +/* And more taken from the source .. */ + +typedef struct coff_ptr_struct +{ + + /* Remembers the offset from the first symbol in the file for + this symbol. Generated by coff_renumber_symbols. */ +unsigned int offset; + + /* Should the tag field of this symbol be renumbered. + Created by coff_pointerize_aux. */ +char fix_tag; + + /* Should the endidx field of this symbol be renumbered. + Created by coff_pointerize_aux. */ +char fix_end; + + /* The container for the symbol structure as read and translated + from the file. */ + +union { + union internal_auxent auxent; + struct internal_syment syment; + } u; +} combined_entry_type; + + + /* Each canonical asymbol really looks like this: */ + +typedef struct coff_symbol_struct +{ + /* The actual symbol which the rest of BFD works with */ +asymbol symbol; + + /* A pointer to the hidden information for this symbol */ +combined_entry_type *native; + + /* A pointer to the linenumber information for this symbol */ +struct lineno_cache_entry *lineno; + + /* Have the line numbers been relocated yet ? */ +boolean done_lineno; +} coff_symbol_type; +typedef struct +{ + void (*_bfd_coff_swap_aux_in) PARAMS (( + bfd *abfd , + PTR ext, + int type, + int class , + PTR in)); + + void (*_bfd_coff_swap_sym_in) PARAMS (( + bfd *abfd , + PTR ext, + PTR in)); + + void (*_bfd_coff_swap_lineno_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + + unsigned int (*_bfd_coff_swap_aux_out) PARAMS (( + bfd *abfd, + PTR in, + int type, + int class, + PTR ext)); + + unsigned int (*_bfd_coff_swap_sym_out) PARAMS (( + bfd *abfd, + PTR in, + PTR ext)); + + unsigned int (*_bfd_coff_swap_lineno_out) PARAMS (( + bfd *abfd, + PTR in, + PTR ext)); + + unsigned int (*_bfd_coff_swap_reloc_out) PARAMS (( + bfd *abfd, + PTR src, + PTR dst)); + + unsigned int (*_bfd_coff_swap_filehdr_out) PARAMS (( + bfd *abfd, + PTR in, + PTR out)); + + unsigned int (*_bfd_coff_swap_aouthdr_out) PARAMS (( + bfd *abfd, + PTR in, + PTR out)); + + unsigned int (*_bfd_coff_swap_scnhdr_out) PARAMS (( + bfd *abfd, + PTR in, + PTR out)); + + unsigned int _bfd_filhsz; + unsigned int _bfd_aoutsz; + unsigned int _bfd_scnhsz; + unsigned int _bfd_symesz; + unsigned int _bfd_auxesz; + unsigned int _bfd_linesz; + boolean _bfd_coff_long_filenames; + void (*_bfd_coff_swap_filehdr_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + void (*_bfd_coff_swap_aouthdr_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + void (*_bfd_coff_swap_scnhdr_in) PARAMS (( + bfd *abfd, + PTR ext, + PTR in)); + boolean (*_bfd_coff_bad_format_hook) PARAMS (( + bfd *abfd, + PTR internal_filehdr)); + boolean (*_bfd_coff_set_arch_mach_hook) PARAMS (( + bfd *abfd, + PTR internal_filehdr)); + PTR (*_bfd_coff_mkobject_hook) PARAMS (( + bfd *abfd, + PTR internal_filehdr, + PTR internal_aouthdr)); + flagword (*_bfd_styp_to_sec_flags_hook) PARAMS (( + bfd *abfd, + PTR internal_scnhdr)); + asection *(*_bfd_make_section_hook) PARAMS (( + bfd *abfd, + char *name)); + void (*_bfd_set_alignment_hook) PARAMS (( + bfd *abfd, + asection *sec, + PTR internal_scnhdr)); + boolean (*_bfd_coff_slurp_symbol_table) PARAMS (( + bfd *abfd)); + boolean (*_bfd_coff_symname_in_debug) PARAMS (( + bfd *abfd, + struct internal_syment *sym)); + void (*_bfd_coff_reloc16_extra_cases) PARAMS (( + bfd *abfd, + struct bfd_seclet *seclet, + arelent *reloc, + bfd_byte *data, + unsigned int *src_ptr, + unsigned int *dst_ptr)); + int (*_bfd_coff_reloc16_estimate) PARAMS (( + asection *input_section, + asymbol **symbols, + arelent *r, + unsigned int shrink)); + +} bfd_coff_backend_data; + +#define coff_backend_info(abfd) ((bfd_coff_backend_data *) (abfd)->xvec->backend_data) + +#define bfd_coff_swap_aux_in(a,e,t,c,i) \ + ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,i)) + +#define bfd_coff_swap_sym_in(a,e,i) \ + ((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i)) + +#define bfd_coff_swap_lineno_in(a,e,i) \ + ((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i)) + +#define bfd_coff_swap_reloc_out(abfd, i, o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o)) + +#define bfd_coff_swap_lineno_out(abfd, i, o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o)) + +#define bfd_coff_swap_aux_out(abfd, i, t,c,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_aux_out) (abfd, i,t,c, o)) + +#define bfd_coff_swap_sym_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o)) + +#define bfd_coff_swap_scnhdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o)) + +#define bfd_coff_swap_filehdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o)) + +#define bfd_coff_swap_aouthdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o)) + +#define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz) +#define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz) +#define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz) +#define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz) +#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz) +#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz) +#define bfd_coff_long_filenames(abfd) (coff_backend_info (abfd)->_bfd_coff_long_filenames) +#define bfd_coff_swap_filehdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o)) + +#define bfd_coff_swap_aouthdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o)) + +#define bfd_coff_swap_scnhdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o)) + +#define bfd_coff_bad_format_hook(abfd, filehdr) \ + ((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr)) + +#define bfd_coff_set_arch_mach_hook(abfd, filehdr)\ + ((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr)) +#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\ + ((coff_backend_info (abfd)->_bfd_coff_mkobject_hook) (abfd, filehdr, aouthdr)) + +#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr)\ + ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook) (abfd, scnhdr)) + +#define bfd_coff_make_section_hook(abfd, name)\ + ((coff_backend_info (abfd)->_bfd_make_section_hook) (abfd, name)) + +#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\ + ((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr)) + +#define bfd_coff_slurp_symbol_table(abfd)\ + ((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd)) + +#define bfd_coff_symname_in_debug(abfd, sym)\ + ((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym)) + +#define bfd_coff_reloc16_extra_cases(abfd, seclet, reloc, data, src_ptr, dst_ptr)\ + ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\ + (abfd, seclet, reloc, data, src_ptr, dst_ptr)) + +#define bfd_coff_reloc16_estimate(abfd, section, symbols, reloc, shrink)\ + ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\ + (section, symbols, reloc, shrink)) + + diff --git a/gnu/usr.bin/gdb/bfd/libecoff.h b/gnu/usr.bin/gdb/bfd/libecoff.h new file mode 100644 index 00000000000..3da0fe20eec --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libecoff.h @@ -0,0 +1,268 @@ +/* BFD ECOFF object file private structure. + Copyright (C) 1993 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: libecoff.h,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +/* This is the backend information kept for ECOFF files. This + structure is constant for a particular backend. The first element + is the COFF backend data structure, so that ECOFF targets can use + the generic COFF code. */ + +#define ecoff_backend(abfd) \ + ((struct ecoff_backend_data *) (abfd)->xvec->backend_data) + +struct ecoff_backend_data +{ + /* COFF backend information. This must be the first field. */ + bfd_coff_backend_data coff; + /* Supported architecture. */ + enum bfd_architecture arch; + /* Symbol table magic number. */ + int sym_magic; + /* Initial portion of armap string. */ + const char *armap_start; + /* Alignment of debugging information. E.g., 4. */ + bfd_size_type debug_align; + /* The page boundary used to align sections in a demand-paged + executable file. E.g., 0x1000. */ + bfd_vma round; + /* Bitsize of constructor entries. */ + unsigned int constructor_bitsize; + /* Reloc to use for constructor entries. */ + CONST struct reloc_howto_struct *constructor_reloc; + /* Sizes of external symbolic information. */ + bfd_size_type external_hdr_size; + bfd_size_type external_dnr_size; + bfd_size_type external_pdr_size; + bfd_size_type external_sym_size; + bfd_size_type external_opt_size; + bfd_size_type external_fdr_size; + bfd_size_type external_rfd_size; + bfd_size_type external_ext_size; + /* Functions to swap in external symbolic data. */ + void (*swap_hdr_in) PARAMS ((bfd *, PTR, HDRR *)); + void (*swap_dnr_in) PARAMS ((bfd *, PTR, DNR *)); + void (*swap_pdr_in) PARAMS ((bfd *, PTR, PDR *)); + void (*swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)); + void (*swap_opt_in) PARAMS ((bfd *, PTR, OPTR *)); + void (*swap_fdr_in) PARAMS ((bfd *, PTR, FDR *)); + void (*swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)); + void (*swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)); + /* Functions to swap out external symbolic data. */ + void (*swap_hdr_out) PARAMS ((bfd *, const HDRR *, PTR)); + void (*swap_dnr_out) PARAMS ((bfd *, const DNR *, PTR)); + void (*swap_pdr_out) PARAMS ((bfd *, const PDR *, PTR)); + void (*swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)); + void (*swap_opt_out) PARAMS ((bfd *, const OPTR *, PTR)); + void (*swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)); + void (*swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR)); + void (*swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR)); + /* It so happens that the auxiliary type information has the same + type and format for all known ECOFF targets. I don't see any + reason that that should change, so at least for now the auxiliary + swapping information is not in this table. */ + /* External reloc size. */ + bfd_size_type external_reloc_size; + /* Reloc swapping functions. */ + void (*swap_reloc_in) PARAMS ((bfd *, PTR, struct internal_reloc *)); + void (*swap_reloc_out) PARAMS ((bfd *, const struct internal_reloc *, PTR)); + /* Backend reloc tweaking. */ + void (*finish_reloc) PARAMS ((bfd *, struct internal_reloc *, arelent *)); +}; + +/* This is the target specific information kept for ECOFF files. */ + +#define ecoff_data(abfd) ((abfd)->tdata.ecoff_obj_data) + +typedef struct ecoff_tdata +{ + /* The reloc file position, set by + ecoff_compute_section_file_positions. */ + file_ptr reloc_filepos; + + /* The symbol table file position, set by ecoff_mkobject_hook. */ + file_ptr sym_filepos; + + /* The start and end of the text segment. Only valid for an + existing file, not for one we are creating. */ + unsigned long text_start; + unsigned long text_end; + + /* The cached gp value. This is used when relocating. */ + bfd_vma gp; + + /* The maximum size of objects to optimize using gp. This is + typically set by the -G option to the compiler, assembler or + linker. */ + int gp_size; + + /* The register masks. When linking, all the masks found in the + input files are combined into the masks of the output file. + These are not all used for all targets, but that's OK, because + the relevant ones are the only ones swapped in and out. */ + unsigned long gprmask; + unsigned long fprmask; + unsigned long cprmask[4]; + + /* The size of the unswapped ECOFF symbolic information. */ + bfd_size_type raw_size; + + /* The unswapped ECOFF symbolic information. */ + PTR raw_syments; + + /* The swapped ECOFF symbolic header. */ + HDRR symbolic_header; + + /* Pointers to the unswapped symbolic information. */ + unsigned char *line; + PTR external_dnr; /* struct dnr_ext */ + PTR external_pdr; /* struct pdr_ext */ + PTR external_sym; /* struct sym_ext */ + PTR external_opt; /* struct opt_ext */ + union aux_ext *external_aux; + char *ss; + char *ssext; + PTR external_fdr; /* struct fdr_ext */ + PTR external_rfd; /* struct rfd_ext */ + PTR external_ext; /* struct ext_ext */ + + /* The swapped FDR information. */ + FDR *fdr; + + /* The FDR index. This is set for an input BFD to a link so that + the external symbols can set their FDR index correctly. */ + unsigned int ifdbase; + + /* The canonical BFD symbols. */ + struct ecoff_symbol_struct *canonical_symbols; + +} ecoff_data_type; + +/* Each canonical asymbol really looks like this. */ + +typedef struct ecoff_symbol_struct +{ + /* The actual symbol which the rest of BFD works with */ + asymbol symbol; + + /* The fdr for this symbol. */ + FDR *fdr; + + /* true if this is a local symbol rather than an external one. */ + boolean local; + + /* A pointer to the unswapped hidden information for this symbol. + This is either a struct sym_ext or a struct ext_ext, depending on + the value of the local field above. */ + PTR native; +} ecoff_symbol_type; + +/* We take the address of the first element of a asymbol to ensure that the + macro is only ever applied to an asymbol. */ +#define ecoffsymbol(asymbol) ((ecoff_symbol_type *) (&((asymbol)->the_bfd))) + +/* This is a hack borrowed from coffcode.h; we need to save the index + of an external symbol when we write it out so that can set the + symbol index correctly when we write out the relocs. */ +#define ecoff_get_sym_index(symbol) ((unsigned long) (symbol)->udata) +#define ecoff_set_sym_index(symbol, idx) ((symbol)->udata = (PTR) (idx)) + +/* Make an ECOFF object. */ +extern boolean ecoff_mkobject PARAMS ((bfd *)); + +/* Read in the ECOFF symbolic debugging information. */ +extern boolean ecoff_slurp_symbolic_info PARAMS ((bfd *)); + +/* Generic ECOFF BFD backend vectors. */ +extern asymbol *ecoff_make_empty_symbol PARAMS ((bfd *abfd)); +extern unsigned int ecoff_get_symtab_upper_bound PARAMS ((bfd *abfd)); +extern unsigned int ecoff_get_symtab PARAMS ((bfd *abfd, + asymbol **alocation)); +extern void ecoff_get_symbol_info PARAMS ((bfd *abfd, + asymbol *symbol, + symbol_info *ret)); +extern void ecoff_print_symbol PARAMS ((bfd *abfd, PTR filep, + asymbol *symbol, + bfd_print_symbol_type how)); +extern unsigned int ecoff_canonicalize_reloc PARAMS ((bfd *abfd, + asection *section, + arelent **relptr, + asymbol **symbols)); +extern boolean ecoff_find_nearest_line PARAMS ((bfd *abfd, + asection *section, + asymbol **symbols, + bfd_vma offset, + CONST char **filename_ptr, + CONST char **fnname_ptr, + unsigned int *retline_ptr)); +extern boolean ecoff_bfd_seclet_link PARAMS ((bfd *abfd, PTR data, + boolean relocateable)); +extern boolean ecoff_set_arch_mach PARAMS ((bfd *abfd, + enum bfd_architecture arch, + unsigned long machine)); +extern int ecoff_sizeof_headers PARAMS ((bfd *abfd, boolean reloc)); +extern boolean ecoff_set_section_contents PARAMS ((bfd *abfd, + asection *section, + PTR location, + file_ptr offset, + bfd_size_type count)); +extern boolean ecoff_get_section_contents PARAMS ((bfd *abfd, + asection *section, + PTR location, + file_ptr offset, + bfd_size_type count)); +extern boolean ecoff_write_object_contents PARAMS ((bfd *abfd)); +extern boolean ecoff_slurp_armap PARAMS ((bfd *abfd)); +extern boolean ecoff_write_armap PARAMS ((bfd *abfd, unsigned int elength, + struct orl *map, + unsigned int orl_count, + int stridx)); +#define ecoff_slurp_extended_name_table _bfd_slurp_extended_name_table +extern bfd_target *ecoff_archive_p PARAMS ((bfd *abfd)); +#define ecoff_get_lineno \ + ((alent *(*) PARAMS ((bfd *, asymbol *))) bfd_nullvoidptr) +#define ecoff_truncate_arname bfd_dont_truncate_arname +#define ecoff_openr_next_archived_file bfd_generic_openr_next_archived_file +#define ecoff_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define ecoff_get_reloc_upper_bound coff_get_reloc_upper_bound +#define ecoff_close_and_cleanup bfd_generic_close_and_cleanup +#define ecoff_bfd_debug_info_start bfd_void +#define ecoff_bfd_debug_info_end bfd_void +#define ecoff_bfd_debug_info_accumulate \ + ((void (*) PARAMS ((bfd *, struct sec *))) bfd_void) +#define ecoff_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define ecoff_bfd_relax_section bfd_generic_relax_section +#define ecoff_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) + +/* Hook functions for the generic COFF section reading code. */ +extern PTR ecoff_mkobject_hook PARAMS ((bfd *, PTR filehdr, PTR aouthdr)); +extern asection *ecoff_make_section_hook PARAMS ((bfd *abfd, char *name)); +extern boolean ecoff_new_section_hook PARAMS ((bfd *abfd, + asection *section)); +#define ecoff_set_alignment_hook \ + ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void) +extern boolean ecoff_set_arch_mach_hook PARAMS ((bfd *abfd, PTR filehdr)); +extern long ecoff_sec_to_styp_flags PARAMS ((CONST char *name, + flagword flags)); +extern flagword ecoff_styp_to_sec_flags PARAMS ((bfd *abfd, PTR hdr)); +extern boolean ecoff_slurp_symbol_table PARAMS ((bfd *abfd)); diff --git a/gnu/usr.bin/gdb/bfd/libelf.h b/gnu/usr.bin/gdb/bfd/libelf.h new file mode 100644 index 00000000000..c0f946786fb --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/libelf.h @@ -0,0 +1,252 @@ +/* BFD back-end data structures for ELF files. + Copyright (C) 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: libelf.h,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +#ifndef _LIBELF_H_ +#define _LIBELF_H_ 1 + +#include "elf/common.h" +#include "elf/internal.h" +#include "elf/external.h" + +/* If size isn't specified as 64 or 32, NAME macro should fail. */ +#ifndef NAME +#if ARCH_SIZE==64 +#define NAME(x,y) CAT4(x,64,_,y) +#endif +#if ARCH_SIZE==32 +#define NAME(x,y) CAT4(x,32,_,y) +#endif +#endif + +#ifndef NAME +#define NAME(x,y) CAT4(x,NOSIZE,_,y) +#endif + +#define ElfNAME(X) NAME(Elf,X) +#define elfNAME(X) NAME(elf,X) + +typedef struct +{ + asymbol symbol; + Elf_Internal_Sym internal_elf_sym; + union + { + unsigned int hppa_arg_reloc; + PTR any; + } + tc_data; +} elf_symbol_type; + +struct elf_backend_data +{ + int use_rela_p; + int elf_64_p; + enum bfd_architecture arch; + void (*elf_info_to_howto) PARAMS ((bfd *, arelent *, + Elf_Internal_Rela *)); + void (*elf_info_to_howto_rel) PARAMS ((bfd *, arelent *, + Elf_Internal_Rel *)); + bfd_vma maxpagesize; + void (*write_relocs) PARAMS ((bfd *, asection *, PTR)); + + void (*elf_backend_symbol_processing) PARAMS ((bfd *, asymbol *)); + boolean (*elf_backend_symbol_table_processing) PARAMS ((bfd *, elf_symbol_type *, int)); + boolean (*elf_backend_section_processing) PARAMS ((bfd *, Elf32_Internal_Shdr *)); + boolean (*elf_backend_section_from_shdr) PARAMS ((bfd *, Elf32_Internal_Shdr *, char *)); + boolean (*elf_backend_fake_sections) PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *)); + boolean (*elf_backend_section_from_bfd_section) PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *)); +}; + +struct elf_sym_extra +{ + int elf_sym_num; /* sym# after locals/globals are reordered */ +}; + +typedef struct elf_sym_extra Elf_Sym_Extra; + +struct bfd_elf_arch_map { + enum bfd_architecture bfd_arch; + int elf_arch; +}; + +extern const struct bfd_elf_arch_map bfd_elf_arch_map[]; +extern const int bfd_elf_arch_map_size; + +struct bfd_elf_section_data { + Elf_Internal_Shdr this_hdr; + Elf_Internal_Shdr rel_hdr; + int this_idx, rel_idx; +}; +#define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd) +#define shdr_name(abfd,shdr) (elf_shstrtab (abfd)->tab + (shdr)->sh_name) + +#define get_elf_backend_data(abfd) \ + ((struct elf_backend_data *) (abfd)->xvec->backend_data) + +struct strtab +{ + char *tab; + int nentries; + int length; +}; + +/* Some private data is stashed away for future use using the tdata pointer + in the bfd structure. */ + +struct elf_obj_tdata +{ + Elf_Internal_Ehdr elf_header[1]; /* Actual data, but ref like ptr */ + Elf_Internal_Shdr **elf_sect_ptr; + Elf_Internal_Phdr *phdr; + struct strtab *strtab_ptr; + int num_locals; + int num_globals; + Elf_Internal_Sym *internal_syms; + elf_symbol_type *symbols; /* elf_symbol_type */ + Elf_Sym_Extra *sym_extra; + asymbol **section_syms; /* STT_SECTION symbols for each section */ + int num_section_syms; /* number of section_syms allocated */ + Elf_Internal_Shdr symtab_hdr; + Elf_Internal_Shdr shstrtab_hdr; + Elf_Internal_Shdr strtab_hdr; + int symtab_section, shstrtab_section, strtab_section; + file_ptr next_file_pos; + void *prstatus; /* The raw /proc prstatus structure */ + void *prpsinfo; /* The raw /proc prpsinfo structure */ + bfd_vma gp; /* The gp value (MIPS only, for now) */ + int gp_size; /* The gp size (MIPS only, for now) */ +}; + +#define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data) +#define elf_elfheader(bfd) (elf_tdata(bfd) -> elf_header) +#define elf_elfsections(bfd) (elf_tdata(bfd) -> elf_sect_ptr) +#define elf_shstrtab(bfd) (elf_tdata(bfd) -> strtab_ptr) +#define elf_onesymtab(bfd) (elf_tdata(bfd) -> symtab_section) +#define elf_num_locals(bfd) (elf_tdata(bfd) -> num_locals) +#define elf_num_globals(bfd) (elf_tdata(bfd) -> num_globals) +#define elf_sym_extra(bfd) (elf_tdata(bfd) -> sym_extra) +#define elf_section_syms(bfd) (elf_tdata(bfd) -> section_syms) +#define elf_num_section_syms(bfd) (elf_tdata(bfd) -> num_section_syms) +#define core_prpsinfo(bfd) (elf_tdata(bfd) -> prpsinfo) +#define core_prstatus(bfd) (elf_tdata(bfd) -> prstatus) +#define obj_symbols(bfd) (elf_tdata(bfd) -> symbols) +#define obj_internal_syms(bfd) (elf_tdata(bfd) -> internal_syms) +#define elf_gp(bfd) (elf_tdata(bfd) -> gp) +#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size) + +extern char * elf_string_from_elf_section PARAMS ((bfd *, unsigned, unsigned)); +extern char * elf_get_str_section PARAMS ((bfd *, unsigned)); + +#define bfd_elf32_mkobject bfd_elf_mkobject +#define bfd_elf64_mkobject bfd_elf_mkobject +#define elf_mkobject bfd_elf_mkobject + +extern unsigned long bfd_elf_hash PARAMS ((CONST unsigned char *)); + +extern bfd_reloc_status_type bfd_elf_generic_reloc PARAMS ((bfd *, + arelent *, + asymbol *, + PTR, + asection *, + bfd *)); +extern boolean bfd_elf_mkobject PARAMS ((bfd *)); +extern Elf_Internal_Shdr *bfd_elf_find_section PARAMS ((bfd *, char *)); + +extern boolean bfd_elf32_write_object_contents PARAMS ((bfd *)); +extern boolean bfd_elf64_write_object_contents PARAMS ((bfd *)); + +extern bfd_target *bfd_elf32_object_p PARAMS ((bfd *)); +extern bfd_target *bfd_elf32_core_file_p PARAMS ((bfd *)); +extern char *bfd_elf32_core_file_failing_command PARAMS ((bfd *)); +extern int bfd_elf32_core_file_failing_signal PARAMS ((bfd *)); +extern boolean bfd_elf32_core_file_matches_executable_p PARAMS ((bfd *, + bfd *)); +extern boolean bfd_elf32_set_section_contents PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, + bfd_size_type)); + +extern unsigned int bfd_elf32_get_symtab_upper_bound PARAMS ((bfd *)); +extern unsigned int bfd_elf32_get_symtab PARAMS ((bfd *, asymbol **)); +extern unsigned int bfd_elf32_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +extern unsigned int bfd_elf32_canonicalize_reloc PARAMS ((bfd *, sec_ptr, + arelent **, + asymbol **)); +extern asymbol *bfd_elf32_make_empty_symbol PARAMS ((bfd *)); +extern void bfd_elf32_print_symbol PARAMS ((bfd *, PTR, asymbol *, + bfd_print_symbol_type)); +extern void bfd_elf32_get_symbol_info PARAMS ((bfd *, asymbol *, + symbol_info *)); +extern alent *bfd_elf32_get_lineno PARAMS ((bfd *, asymbol *)); +extern boolean bfd_elf32_set_arch_mach PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); +extern boolean bfd_elf32_find_nearest_line PARAMS ((bfd *, asection *, + asymbol **, + bfd_vma, CONST char **, + CONST char **, + unsigned int *)); +extern int bfd_elf32_sizeof_headers PARAMS ((bfd *, boolean)); +extern void bfd_elf32__write_relocs PARAMS ((bfd *, asection *, PTR)); +extern boolean bfd_elf32_new_section_hook PARAMS ((bfd *, asection *)); + +/* If the target doesn't have reloc handling written yet: */ +extern void bfd_elf32_no_info_to_howto PARAMS ((bfd *, arelent *, + Elf32_Internal_Rela *)); + +extern bfd_target *bfd_elf64_object_p PARAMS ((bfd *)); +extern bfd_target *bfd_elf64_core_file_p PARAMS ((bfd *)); +extern char *bfd_elf64_core_file_failing_command PARAMS ((bfd *)); +extern int bfd_elf64_core_file_failing_signal PARAMS ((bfd *)); +extern boolean bfd_elf64_core_file_matches_executable_p PARAMS ((bfd *, + bfd *)); +extern boolean bfd_elf64_set_section_contents PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, + bfd_size_type)); + +extern unsigned int bfd_elf64_get_symtab_upper_bound PARAMS ((bfd *)); +extern unsigned int bfd_elf64_get_symtab PARAMS ((bfd *, asymbol **)); +extern unsigned int bfd_elf64_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +extern unsigned int bfd_elf64_canonicalize_reloc PARAMS ((bfd *, sec_ptr, + arelent **, + asymbol **)); +extern asymbol *bfd_elf64_make_empty_symbol PARAMS ((bfd *)); +extern void bfd_elf64_print_symbol PARAMS ((bfd *, PTR, asymbol *, + bfd_print_symbol_type)); +extern void bfd_elf64_get_symbol_info PARAMS ((bfd *, asymbol *, + symbol_info *)); +extern alent *bfd_elf64_get_lineno PARAMS ((bfd *, asymbol *)); +extern boolean bfd_elf64_set_arch_mach PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); +extern boolean bfd_elf64_find_nearest_line PARAMS ((bfd *, asection *, + asymbol **, + bfd_vma, CONST char **, + CONST char **, + unsigned int *)); +extern int bfd_elf64_sizeof_headers PARAMS ((bfd *, boolean)); +extern void bfd_elf64__write_relocs PARAMS ((bfd *, asection *, PTR)); +extern boolean bfd_elf64_new_section_hook PARAMS ((bfd *, asection *)); + +/* If the target doesn't have reloc handling written yet: */ +extern void bfd_elf64_no_info_to_howto PARAMS ((bfd *, arelent *, + Elf64_Internal_Rela *)); + +#endif /* _LIBELF_H_ */ diff --git a/gnu/usr.bin/gdb/bfd/netbsd-core.c b/gnu/usr.bin/gdb/bfd/netbsd-core.c new file mode 100644 index 00000000000..59d2b27b099 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/netbsd-core.c @@ -0,0 +1,306 @@ +/* BFD back end for NetBSD style core files + Copyright 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Paul Kranenburg, EUR + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: netbsd-core.c,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +/* To use this file on a particular host, configure the host with these + parameters in the config/h-HOST file: + + HDEFINES=-DNETBSD_CORE + HDEPFILES=netbsd-core.o + + */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/dir.h> +#include <signal.h> +#include <sys/core.h> + +#include <errno.h> + +struct netbsd_core_struct { + struct core core; +} *rawptr; + +/* forward declarations */ + +bfd_target * netbsd_core_file_p PARAMS ((bfd *abfd)); +char * netbsd_core_file_failing_command PARAMS ((bfd *abfd)); +int netbsd_core_file_failing_signal PARAMS ((bfd *abfd)); +boolean netbsd_core_file_matches_executable_p + PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +/* Handle NetBSD-style core dump file. */ + +/* ARGSUSED */ +bfd_target * +netbsd_core_file_p (abfd) + bfd *abfd; + +{ + int i, val, offset; + asection *asect, *asect2; + struct core core; + struct coreseg coreseg; + + val = bfd_read ((void *)&core, 1, sizeof core, abfd); + if (val != sizeof core) { + /* Too small to be a core file */ + bfd_error = wrong_format; + return 0; + } + + if (CORE_GETMAGIC(core) != COREMAGIC) { + bfd_error = wrong_format; + return 0; + } + + rawptr = (struct netbsd_core_struct *) + bfd_zalloc (abfd, sizeof (struct netbsd_core_struct)); + if (rawptr == NULL) { + bfd_error = no_memory; + return 0; + } + + rawptr->core = core; + abfd->tdata.netbsd_core_data = rawptr; + + offset = core.c_hdrsize; + for (i = 0; i < core.c_nseg; i++) { + + if (bfd_seek (abfd, offset, SEEK_SET) != 0) + goto punt; + + val = bfd_read ((void *)&coreseg, 1, sizeof coreseg, abfd); + if (val != sizeof coreseg) { + bfd_error = file_truncated; + goto punt; + } + if (CORE_GETMAGIC(coreseg) != CORESEGMAGIC) { + bfd_error = wrong_format; + goto punt; + } + + offset += core.c_seghdrsize; + + asect = (asection *) zalloc (sizeof (asection)); + if (asect == NULL) { + bfd_error = no_memory; + goto punt; + } + + asect->_raw_size = coreseg.c_size; + asect->vma = coreseg.c_addr; + asect->filepos = offset; + asect->alignment_power = 2; + asect->next = abfd->sections; + abfd->sections = asect; + abfd->section_count++; + offset += coreseg.c_size; + + switch (CORE_GETFLAG(coreseg)) { + case CORE_CPU: + asect->name = ".reg"; + asect->flags = SEC_ALLOC + SEC_HAS_CONTENTS; +#ifdef CORE_FPU_OFFSET + /* Hackish... */ + asect->_raw_size = CORE_FPU_OFFSET; + asect2 = (asection *)zalloc (sizeof (asection)); + if (asect2 == NULL) { + bfd_error = no_memory; + goto punt; + } + asect2->_raw_size = coreseg.c_size - CORE_FPU_OFFSET; + asect2->vma = 0; + asect2->filepos = asect->filepos + CORE_FPU_OFFSET; + asect2->alignment_power = 2; + asect2->next = abfd->sections; + asect2->name = ".reg2"; + asect2->flags = SEC_ALLOC + SEC_HAS_CONTENTS; + abfd->sections = asect2; + abfd->section_count++; +#endif + + break; + case CORE_DATA: + asect->name = ".data"; + asect->flags = SEC_ALLOC+SEC_LOAD+SEC_HAS_CONTENTS; + break; + case CORE_STACK: + asect->name = ".stack"; + asect->flags = SEC_ALLOC+SEC_LOAD+SEC_HAS_CONTENTS; + break; + } + } + + /* OK, we believe you. You're a core file (sure, sure). */ + return abfd->xvec; + +punt: { + asection *anext; + for (asect = abfd->sections; asect; asect = anext) { + anext = asect->next; + free((void *)asect); + } + } + free ((void *)rawptr); + abfd->tdata.netbsd_core_data = NULL; + abfd->sections = NULL; + abfd->section_count = 0; + return 0; +} + +char * +netbsd_core_file_failing_command (abfd) + bfd *abfd; +{ + return abfd->tdata.netbsd_core_data->core.c_name; +} + +/* ARGSUSED */ +int +netbsd_core_file_failing_signal (abfd) + bfd *abfd; +{ + return abfd->tdata.netbsd_core_data->core.c_signo; +} + +/* ARGSUSED */ +boolean +netbsd_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + return true; /* FIXME, We have no way of telling at this point */ +} + +/* No archive file support via this BFD */ +#define netbsd_openr_next_archived_file bfd_generic_openr_next_archived_file +#define netbsd_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define netbsd_slurp_armap bfd_false +#define netbsd_slurp_extended_name_table bfd_true +#define netbsd_write_armap (boolean (*) PARAMS \ + ((bfd *arch, unsigned int elength, struct orl *map, \ + unsigned int orl_count, int stridx))) bfd_false +#define netbsd_truncate_arname bfd_dont_truncate_arname +#define aout_32_openr_next_archived_file bfd_generic_openr_next_archived_file + +#define netbsd_close_and_cleanup bfd_generic_close_and_cleanup +#define netbsd_set_section_contents (boolean (*) PARAMS \ + ((bfd *abfd, asection *section, PTR data, file_ptr offset, \ + bfd_size_type count))) bfd_false +#define netbsd_get_section_contents bfd_generic_get_section_contents +#define netbsd_new_section_hook (boolean (*) PARAMS \ + ((bfd *, sec_ptr))) bfd_true +#define netbsd_get_symtab_upper_bound bfd_0u +#define netbsd_get_symtab (unsigned int (*) PARAMS \ + ((bfd *, struct symbol_cache_entry **))) bfd_0u +#define netbsd_get_reloc_upper_bound (unsigned int (*) PARAMS \ + ((bfd *, sec_ptr))) bfd_0u +#define netbsd_canonicalize_reloc (unsigned int (*) PARAMS \ + ((bfd *, sec_ptr, arelent **, struct symbol_cache_entry**))) bfd_0u +#define netbsd_make_empty_symbol (struct symbol_cache_entry * \ + (*) PARAMS ((bfd *))) bfd_false +#define netbsd_print_symbol (void (*) PARAMS \ + ((bfd *, PTR, struct symbol_cache_entry *, \ + bfd_print_symbol_type))) bfd_false +#define netbsd_get_symbol_info (void (*) PARAMS \ + ((bfd *, struct symbol_cache_entry *, \ + symbol_info *))) bfd_false +#define netbsd_get_lineno (alent * (*) PARAMS \ + ((bfd *, struct symbol_cache_entry *))) bfd_nullvoidptr +#define netbsd_set_arch_mach (boolean (*) PARAMS \ + ((bfd *, enum bfd_architecture, unsigned long))) bfd_false +#define netbsd_find_nearest_line (boolean (*) PARAMS \ + ((bfd *abfd, struct sec *section, \ + struct symbol_cache_entry **symbols,bfd_vma offset, \ + CONST char **file, CONST char **func, unsigned int *line))) bfd_false +#define netbsd_sizeof_headers (int (*) PARAMS \ + ((bfd *, boolean))) bfd_0 + +#define netbsd_bfd_debug_info_start bfd_void +#define netbsd_bfd_debug_info_end bfd_void +#define netbsd_bfd_debug_info_accumulate (void (*) PARAMS \ + ((bfd *, struct sec *))) bfd_void +#define netbsd_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents +#define netbsd_bfd_relax_section bfd_generic_relax_section +#define netbsd_bfd_seclet_link \ + ((boolean (*) PARAMS ((bfd *, PTR, boolean))) bfd_false) +#define netbsd_bfd_reloc_type_lookup \ + ((CONST struct reloc_howto_struct *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr) +#define netbsd_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) + +/* If somebody calls any byte-swapping routines, shoot them. */ +void +netbsd_swap_abort() +{ + abort(); /* This way doesn't require any declaration for ANSI to fuck up */ +} +#define NO_GET ((bfd_vma (*) PARAMS (( bfd_byte *))) netbsd_swap_abort ) +#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) netbsd_swap_abort ) +#define NO_SIGNED_GET ((bfd_signed_vma (*) PARAMS ((bfd_byte *))) netbsd_swap_abort ) + +bfd_target netbsd_core_vec = + { + "netbsd-core", + bfd_target_unknown_flavour, + true, /* target byte order */ + true, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* symbol prefix */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + 3, /* minimum alignment power */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */ + + { /* bfd_check_format */ + _bfd_dummy_target, /* unknown format */ + _bfd_dummy_target, /* object file */ + _bfd_dummy_target, /* archive */ + netbsd_core_file_p /* a core file */ + }, + { /* bfd_set_format */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + { /* bfd_write_contents */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + + JUMP_TABLE(netbsd), + (PTR) 0 /* backend_data */ +}; diff --git a/gnu/usr.bin/gdb/bfd/netbsd.h b/gnu/usr.bin/gdb/bfd/netbsd.h new file mode 100644 index 00000000000..6b769347b08 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/netbsd.h @@ -0,0 +1,55 @@ +/* $Id: netbsd.h,v 1.1 1995/10/18 08:39:53 deraadt Exp $ */ + +/* ZMAGIC files never have the header in the text. */ +#define N_HEADER_IN_TEXT(x) 0 + +/* ZMAGIC files start at address 0. This does not apply to QMAGIC. */ +#define TEXT_START_ADDR 0 + +#define N_MAGIC(ex) \ + ( (((ex).a_info)&0xffff0000) ? (ntohl(((ex).a_info))&0xffff) : ((ex).a_info)) +#define N_MACHTYPE(ex) \ + ( (((ex).a_info)&0xffff0000) ? ((ntohl(((ex).a_info))>>16)&0x03ff) : 0 ) +# define N_FLAGS(ex) \ + ( (((ex).a_info)&0xffff0000) ? ((ntohl(((ex).a_info))>>26)&0x3f) : 0 ) +#define N_SET_INFO(ex, mag,mid,flag) \ + ( (ex).a_info = htonl( (((flag)&0x3f)<<26) | (((mid)&0x03ff)<<16) | \ + (((mag)&0xffff)) ) ) +#define N_SET_MAGIC(exec,magic) \ + ((exec).a_info = (((exec).a_info & ~0xffff) | ((magic) & 0xffff))) +#define N_SET_MACHTYPE(exec,machtype) \ + ((exec).a_info = \ + (((exec).a_info & ~(0x3ff<<16)) | (((machtype)&0xff) << 16))) +#define N_SET_FLAGS(exec, flags) \ + ((exec).a_info = ((exec).a_info & 0xffff) | (flags & 0xffff)) + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" + +#define N_GETMAGIC(ex) \ + ( (((ex).a_info)&0xffff0000) ? (ntohl(((ex).a_info))&0xffff) : ((ex).a_info)) +#define N_GETMAGIC2(ex) \ + ( (((ex).a_info)&0xffff0000) ? (ntohl(((ex).a_info))&0xffff) : \ + (((ex).a_info) | 0x10000) ) + +#define N_TXTADDR(ex) (N_GETMAGIC2(ex) == (ZMAGIC|0x10000) ? 0 : __LDPGSZ) +#define N_TXTOFF(ex) \ + ( N_GETMAGIC2(ex)==ZMAGIC || N_GETMAGIC2(ex)==(QMAGIC|0x10000) ? \ + 0 : (N_GETMAGIC2(ex)==(ZMAGIC|0x10000) ? __LDPGSZ : EXEC_BYTES_SIZE )) +#define N_ALIGN(ex,x) \ + (N_MAGIC(ex) == ZMAGIC || N_MAGIC(ex) == QMAGIC ? \ + ((x) + __LDPGSZ - 1) & ~(__LDPGSZ - 1) : (x)) +#define N_DATADDR(ex) \ + (N_GETMAGIC(ex) == OMAGIC ? N_TXTADDR(ex) + (ex).a_text : \ + (N_TXTADDR(ex) + (ex).a_text + __LDPGSZ - 1) & ~(__LDPGSZ - 1)) + +/* Data segment offset. */ +#define N_DATOFF(ex) \ + N_ALIGN(ex, N_TXTOFF(ex) + (ex).a_text) + +#define NO_SWAP_MAGIC /* magic number already in correct endian format */ + +#include "aout-target.h" + diff --git a/gnu/usr.bin/gdb/bfd/opncls.c b/gnu/usr.bin/gdb/bfd/opncls.c new file mode 100644 index 00000000000..6d1d9478694 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/opncls.c @@ -0,0 +1,537 @@ +/* opncls.c -- open and close a BFD. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: opncls.c,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +extern void bfd_cache_init PARAMS ((bfd *)); +FILE *bfd_open_file PARAMS ((bfd *)); + +/* fdopen is a loser -- we should use stdio exclusively. Unfortunately + if we do that we can't use fcntl. */ + + +#define obstack_chunk_alloc bfd_xmalloc_by_size_t +#define obstack_chunk_free free + +/* Return a new BFD. All BFD's are allocated through this routine. */ + +bfd * +new_bfd PARAMS ((void)) +{ + bfd *nbfd; + + nbfd = (bfd *)zalloc (sizeof (bfd)); + if (!nbfd) + return 0; + + bfd_check_init(); + obstack_begin((PTR)&nbfd->memory, 128); + + nbfd->arch_info = &bfd_default_arch_struct; + + nbfd->direction = no_direction; + nbfd->iostream = NULL; + nbfd->where = 0; + nbfd->sections = (asection *)NULL; + nbfd->format = bfd_unknown; + nbfd->my_archive = (bfd *)NULL; + nbfd->origin = 0; + nbfd->opened_once = false; + nbfd->output_has_begun = false; + nbfd->section_count = 0; + nbfd->usrdata = (PTR)NULL; + nbfd->cacheable = false; + nbfd->flags = NO_FLAGS; + nbfd->mtime_set = false; + + return nbfd; +} + +/* Allocate a new BFD as a member of archive OBFD. */ + +bfd * +new_bfd_contained_in (obfd) + bfd *obfd; +{ + bfd *nbfd; + + nbfd = new_bfd(); + nbfd->xvec = obfd->xvec; + nbfd->my_archive = obfd; + nbfd->direction = read_direction; + nbfd->target_defaulted = obfd->target_defaulted; + return nbfd; +} + +/* +SECTION + Opening and Closing BFDs + +*/ + +/* +FUNCTION + bfd_openr + +SYNOPSIS + bfd *bfd_openr(CONST char *filename, CONST char*target); + +DESCRIPTION + This function opens the file supplied (using <<fopen>>) with the target + supplied, it returns a pointer to the created BFD. + + If NULL is returned then an error has occured. Possible errors + are <<no_memory>>, <<invalid_target>> or <<system_call>> error. +*/ + +bfd * +DEFUN(bfd_openr, (filename, target), + CONST char *filename AND + CONST char *target) +{ + bfd *nbfd; + bfd_target *target_vec; + + nbfd = new_bfd(); + if (nbfd == NULL) { + bfd_error = no_memory; + return NULL; + } + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) { + bfd_error = invalid_target; + return NULL; + } + + nbfd->filename = filename; + nbfd->direction = read_direction; + + if (bfd_open_file (nbfd) == NULL) { + bfd_error = system_call_error; /* File didn't exist, or some such */ + bfd_release(nbfd,0); + return NULL; + } + return nbfd; +} + + +/* Don't try to `optimize' this function: + + o - We lock using stack space so that interrupting the locking + won't cause a storage leak. + o - We open the file stream last, since we don't want to have to + close it if anything goes wrong. Closing the stream means closing + the file descriptor too, even though we didn't open it. + */ +/* +FUNCTION + bfd_fdopenr + +SYNOPSIS + bfd *bfd_fdopenr(CONST char *filename, CONST char *target, int fd); + +DESCRIPTION + bfd_fdopenr is to bfd_fopenr much like fdopen is to fopen. + It opens a BFD on a file already described by the @var{fd} + supplied. + + When the file is later bfd_closed, the file descriptor will be closed. + + If the caller desires that this file descriptor be cached by BFD + (opened as needed, closed as needed to free descriptors for + other opens), with the supplied @var{fd} used as an initial + file descriptor (but subject to closure at any time), set + bfd->cacheable nonzero in the returned BFD. The default is to + assume no cacheing; the file descriptor will remain open until + bfd_close, and will not be affected by BFD operations on other + files. + + Possible errors are no_memory, invalid_target and system_call + error. +*/ + +bfd * +DEFUN(bfd_fdopenr,(filename, target, fd), + CONST char *filename AND + CONST char *target AND + int fd) +{ + bfd *nbfd; + bfd_target *target_vec; + int fdflags; + + bfd_error = system_call_error; + +#ifdef NO_FCNTL + fdflags = O_RDWR; /* Assume full access */ +#else + fdflags = fcntl (fd, F_GETFL, NULL); +#endif + if (fdflags == -1) return NULL; + + nbfd = new_bfd(); + + if (nbfd == NULL) { + bfd_error = no_memory; + return NULL; + } + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) { + bfd_error = invalid_target; + return NULL; + } +#if defined(VMS) || defined(__GO32__) + nbfd->iostream = (char *)fopen(filename, FOPEN_RB); +#else + /* (O_ACCMODE) parens are to avoid Ultrix header file bug */ + switch (fdflags & (O_ACCMODE)) { + case O_RDONLY: nbfd->iostream = (char *) fdopen (fd, FOPEN_RB); break; + case O_WRONLY: nbfd->iostream = (char *) fdopen (fd, FOPEN_RUB); break; + case O_RDWR: nbfd->iostream = (char *) fdopen (fd, FOPEN_RUB); break; + default: abort (); + } +#endif + if (nbfd->iostream == NULL) { + (void) obstack_free (&nbfd->memory, (PTR)0); + return NULL; + } + + /* OK, put everything where it belongs */ + + nbfd->filename = filename; + + /* As a special case we allow a FD open for read/write to + be written through, although doing so requires that we end + the previous clause with a preposition. */ + /* (O_ACCMODE) parens are to avoid Ultrix header file bug */ + switch (fdflags & (O_ACCMODE)) { + case O_RDONLY: nbfd->direction = read_direction; break; + case O_WRONLY: nbfd->direction = write_direction; break; + case O_RDWR: nbfd->direction = both_direction; break; + default: abort (); + } + + bfd_cache_init (nbfd); + + return nbfd; +} + +/** bfd_openw -- open for writing. + Returns a pointer to a freshly-allocated BFD on success, or NULL. + + See comment by bfd_fdopenr before you try to modify this function. */ + +/* +FUNCTION + bfd_openw + +SYNOPSIS + bfd *bfd_openw(CONST char *filename, CONST char *target); + +DESCRIPTION + Creates a BFD, associated with file @var{filename}, using the + file format @var{target}, and returns a pointer to it. + + Possible errors are system_call_error, no_memory, + invalid_target. +*/ + +bfd * +DEFUN(bfd_openw,(filename, target), + CONST char *filename AND + CONST char *target) +{ + bfd *nbfd; + bfd_target *target_vec; + + bfd_error = system_call_error; + + /* nbfd has to point to head of malloc'ed block so that bfd_close may + reclaim it correctly. */ + + nbfd = new_bfd(); + if (nbfd == NULL) { + bfd_error = no_memory; + return NULL; + } + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) return NULL; + + nbfd->filename = filename; + nbfd->direction = write_direction; + + if (bfd_open_file (nbfd) == NULL) { + bfd_error = system_call_error; /* File not writeable, etc */ + (void) obstack_free (&nbfd->memory, (PTR)0); + return NULL; + } + return nbfd; +} + +/* + +FUNCTION + bfd_close + +SYNOPSIS + boolean bfd_close(bfd *); + +DESCRIPTION + + This function closes a BFD. If the BFD was open for writing, + then pending operations are completed and the file written out + and closed. If the created file is executable, then + <<chmod>> is called to mark it as such. + + All memory attached to the BFD's obstacks is released. + + The file descriptor associated with the BFD is closed (even + if it was passed in to BFD by bfd_fdopenr). + +RETURNS + <<true>> is returned if all is ok, otherwise <<false>>. +*/ + + +boolean +DEFUN(bfd_close,(abfd), + bfd *abfd) +{ + boolean ret; + + if (!bfd_read_p(abfd)) + if (BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd)) != true) + return false; + + if (BFD_SEND (abfd, _close_and_cleanup, (abfd)) != true) return false; + + ret = bfd_cache_close(abfd); + + /* If the file was open for writing and is now executable, + make it so */ + if (ret == true + && abfd->direction == write_direction + && abfd->flags & EXEC_P) { + struct stat buf; + stat(abfd->filename, &buf); +#ifndef S_IXUSR +#define S_IXUSR 0100 /* Execute by owner. */ +#endif +#ifndef S_IXGRP +#define S_IXGRP 0010 /* Execute by group. */ +#endif +#ifndef S_IXOTH +#define S_IXOTH 0001 /* Execute by others. */ +#endif + + chmod(abfd->filename, 0777 & (buf.st_mode | S_IXUSR | S_IXGRP | S_IXOTH)); + } + (void) obstack_free (&abfd->memory, (PTR)0); + (void) free(abfd); + return ret; +} + +/* +FUNCTION + bfd_close_all_done + +SYNOPSIS + boolean bfd_close_all_done(bfd *); + +DESCRIPTION + This function closes a BFD. It differs from <<bfd_close>> + since it does not complete any pending operations. This + routine would be used if the application had just used BFD for + swapping and didn't want to use any of the writing code. + + If the created file is executable, then <<chmod>> is called + to mark it as such. + + All memory attached to the BFD's obstacks is released. + +RETURNS + <<true>> is returned if all is ok, otherwise <<false>>. + +*/ + +boolean +DEFUN(bfd_close_all_done,(abfd), + bfd *abfd) +{ + boolean ret; + + ret = bfd_cache_close(abfd); + + /* If the file was open for writing and is now executable, + make it so */ + if (ret == true + && abfd->direction == write_direction + && abfd->flags & EXEC_P) { + struct stat buf; + stat(abfd->filename, &buf); +#ifndef S_IXUSR +#define S_IXUSR 0100 /* Execute by owner. */ +#endif +#ifndef S_IXGRP +#define S_IXGRP 0010 /* Execute by group. */ +#endif +#ifndef S_IXOTH +#define S_IXOTH 0001 /* Execute by others. */ +#endif + + chmod(abfd->filename, 0x777 &(buf.st_mode | S_IXUSR | S_IXGRP | S_IXOTH)); + } + (void) obstack_free (&abfd->memory, (PTR)0); + (void) free(abfd); + return ret; +} + + +/* +FUNCTION + bfd_alloc_size + +SYNOPSIS + bfd_size_type bfd_alloc_size(bfd *abfd); + +DESCRIPTION + Return the number of bytes in the obstacks connected to the + supplied BFD. + +*/ + +bfd_size_type +DEFUN(bfd_alloc_size,(abfd), + bfd *abfd) +{ + struct _obstack_chunk *chunk = abfd->memory.chunk; + size_t size = 0; + while (chunk) { + size += chunk->limit - &(chunk->contents[0]); + chunk = chunk->prev; + } + return size; +} + + + +/* +FUNCTION + bfd_create + +SYNOPSIS + bfd *bfd_create(CONST char *filename, bfd *templ); + +DESCRIPTION + This routine creates a new BFD in the manner of + <<bfd_openw>>, but without opening a file. The new BFD + takes the target from the target used by @var{template}. The + format is always set to <<bfd_object>>. + +*/ + +bfd * +DEFUN(bfd_create,(filename, templ), + CONST char *filename AND + bfd *templ) +{ + bfd *nbfd = new_bfd(); + if (nbfd == (bfd *)NULL) { + bfd_error = no_memory; + return (bfd *)NULL; + } + nbfd->filename = filename; + if(templ) { + nbfd->xvec = templ->xvec; + } + nbfd->direction = no_direction; + bfd_set_format(nbfd, bfd_object); + return nbfd; +} + +/* +INTERNAL_FUNCTION + bfd_alloc_by_size_t + +SYNOPSIS + PTR bfd_alloc_by_size_t(bfd *abfd, size_t wanted); + +DESCRIPTION + This function allocates a block of memory in the obstack + attatched to <<abfd>> and returns a pointer to it. +*/ + + +PTR +DEFUN(bfd_alloc_by_size_t,(abfd, size), + bfd *abfd AND + size_t size) +{ + PTR res = obstack_alloc(&(abfd->memory), size); + return res; +} + +DEFUN(void bfd_alloc_grow,(abfd, ptr, size), + bfd *abfd AND + PTR ptr AND + size_t size) +{ + (void) obstack_grow(&(abfd->memory), ptr, size); +} +DEFUN(PTR bfd_alloc_finish,(abfd), + bfd *abfd) +{ + return obstack_finish(&(abfd->memory)); +} + +DEFUN(PTR bfd_alloc, (abfd, size), + bfd *abfd AND + size_t size) +{ + return bfd_alloc_by_size_t(abfd, (size_t)size); +} + +DEFUN(PTR bfd_zalloc,(abfd, size), + bfd *abfd AND + size_t size) +{ + PTR res; + res = bfd_alloc(abfd, size); + memset(res, 0, (size_t)size); + return res; +} + +DEFUN(PTR bfd_realloc,(abfd, old, size), + bfd *abfd AND + PTR old AND + size_t size) +{ + PTR res = bfd_alloc(abfd, size); + memcpy(res, old, (size_t)size); + return res; +} diff --git a/gnu/usr.bin/gdb/bfd/reloc.c b/gnu/usr.bin/gdb/bfd/reloc.c new file mode 100644 index 00000000000..4f6e0b141b9 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/reloc.c @@ -0,0 +1,1228 @@ +/* BFD support for handling relocation entries. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: reloc.c,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +/* +SECTION + Relocations + + BFD maintains relocations in much the same was as it maintains + symbols; they are left alone until required, then read in + en-mass and traslated into an internal form. There is a common + routine <<bfd_perform_relocation>> which acts upon the + canonical form to do the actual fixup. + + Note that relocations are maintained on a per section basis, + whilst symbols are maintained on a per BFD basis. + + All a back end has to do to fit the BFD interface is to create + as many <<struct reloc_cache_entry>> as there are relocations + in a particular section, and fill in the right bits: + +@menu +@* typedef arelent:: +@* howto manager:: +@end menu + +*/ +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "seclet.h" +/* +DOCDD +INODE + typedef arelent, howto manager, Relocations, Relocations + +SUBSECTION + typedef arelent + + This is the structure of a relocation entry: + +CODE_FRAGMENT +. +.typedef enum bfd_reloc_status +.{ +. {* No errors detected *} +. bfd_reloc_ok, +. +. {* The relocation was performed, but there was an overflow. *} +. bfd_reloc_overflow, +. +. {* The address to relocate was not within the section supplied. *} +. bfd_reloc_outofrange, +. +. {* Used by special functions *} +. bfd_reloc_continue, +. +. {* Unused *} +. bfd_reloc_notsupported, +. +. {* Unsupported relocation size requested. *} +. bfd_reloc_other, +. +. {* The symbol to relocate against was undefined. *} +. bfd_reloc_undefined, +. +. {* The relocation was performed, but may not be ok - presently +. generated only when linking i960 coff files with i960 b.out +. symbols. *} +. bfd_reloc_dangerous +. } +. bfd_reloc_status_type; +. +. +.typedef struct reloc_cache_entry +.{ +. {* A pointer into the canonical table of pointers *} +. struct symbol_cache_entry **sym_ptr_ptr; +. +. {* offset in section *} +. bfd_size_type address; +. +. {* addend for relocation value *} +. bfd_vma addend; +. +. {* Pointer to how to perform the required relocation *} +. CONST struct reloc_howto_struct *howto; +. +.} arelent; + +*/ + +/* +DESCRIPTION + + Here is a description of each of the fields within a relent: + + o sym_ptr_ptr + + The symbol table pointer points to a pointer to the symbol + associated with the relocation request. This would naturally + be the pointer into the table returned by the back end's + get_symtab action. @xref{Symbols}. The symbol is referenced + through a pointer to a pointer so that tools like the linker + can fix up all the symbols of the same name by modifying only + one pointer. The relocation routine looks in the symbol and + uses the base of the section the symbol is attached to and the + value of the symbol as the initial relocation offset. If the + symbol pointer is zero, then the section provided is looked up. + + o address + + The address field gives the offset in bytes from the base of + the section data which owns the relocation record to the first + byte of relocatable information. The actual data relocated + will be relative to this point - for example, a relocation + type which modifies the bottom two bytes of a four byte word + would not touch the first byte pointed to in a big endian + world. + + o addend + + The addend is a value provided by the back end to be added (!) + to the relocation offset. Its interpretation is dependent upon + the howto. For example, on the 68k the code: + + +| char foo[]; +| main() +| { +| return foo[0x12345678]; +| } + + Could be compiled into: + +| linkw fp,#-4 +| moveb @@#12345678,d0 +| extbl d0 +| unlk fp +| rts + + + This could create a reloc pointing to foo, but leave the + offset in the data (something like) + + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000006 32 _foo +| +|00000000 4e56 fffc ; linkw fp,#-4 +|00000004 1039 1234 5678 ; moveb @@#12345678,d0 +|0000000a 49c0 ; extbl d0 +|0000000c 4e5e ; unlk fp +|0000000e 4e75 ; rts + + + Using coff and an 88k, some instructions don't have enough + space in them to represent the full address range, and + pointers have to be loaded in two parts. So you'd get something like: + + +| or.u r13,r0,hi16(_foo+0x12345678) +| ld.b r2,r13,lo16(_foo+0x12345678) +| jmp r1 + + + This should create two relocs, both pointing to _foo, and with + 0x12340000 in their addend field. The data would consist of: + + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000002 HVRT16 _foo+0x12340000 +|00000006 LVRT16 _foo+0x12340000 + +|00000000 5da05678 ; or.u r13,r0,0x5678 +|00000004 1c4d5678 ; ld.b r2,r13,0x5678 +|00000008 f400c001 ; jmp r1 + + + The relocation routine digs out the value from the data, adds + it to the addend to get the original offset and then adds the + value of _foo. Note that all 32 bits have to be kept around + somewhere, to cope with carry from bit 15 to bit 16. + + One further example is the sparc and the a.out format. The + sparc has a similar problem to the 88k, in that some + instructions don't have room for an entire offset, but on the + sparc the parts are created odd sized lumps. The designers of + the a.out format chose not to use the data within the section + for storing part of the offset; all the offset is kept within + the reloc. Any thing in the data should be ignored. + +| save %sp,-112,%sp +| sethi %hi(_foo+0x12345678),%g2 +| ldsb [%g2+%lo(_foo+0x12345678)],%i0 +| ret +| restore + + Both relocs contains a pointer to foo, and the offsets would + contain junk. + + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000004 HI22 _foo+0x12345678 +|00000008 LO10 _foo+0x12345678 + +|00000000 9de3bf90 ; save %sp,-112,%sp +|00000004 05000000 ; sethi %hi(_foo+0),%g2 +|00000008 f048a000 ; ldsb [%g2+%lo(_foo+0)],%i0 +|0000000c 81c7e008 ; ret +|00000010 81e80000 ; restore + + + o howto + + The howto field can be imagined as a + relocation instruction. It is a pointer to a struct which + contains information on what to do with all the other + information in the reloc record and data section. A back end + would normally have a relocation instruction set and turn + relocations into pointers to the correct structure on input - + but it would be possible to create each howto field on demand. + +*/ + +/* +SUBSUBSECTION + <<enum complain_overflow>> + + Indicates what sort of overflow checking should be done when + performing a relocation. + +CODE_FRAGMENT +. +.enum complain_overflow +.{ +. {* Do not complain on overflow. *} +. complain_overflow_dont, +. +. {* Complain if the bitfield overflows, whether it is considered +. as signed or unsigned. *} +. complain_overflow_bitfield, +. +. {* Complain if the value overflows when considered as signed +. number. *} +. complain_overflow_signed, +. +. {* Complain if the value overflows when considered as an +. unsigned number. *} +. complain_overflow_unsigned +.}; + +*/ + +/* +SUBSUBSECTION + <<reloc_howto_type>> + + The <<reloc_howto_type>> is a structure which contains all the + information that BFD needs to know to tie up a back end's data. + +CODE_FRAGMENT +.struct symbol_cache_entry; {* Forward declaration *} +. +.typedef CONST struct reloc_howto_struct +.{ +. {* The type field has mainly a documetary use - the back end can +. to what it wants with it, though the normally the back end's +. external idea of what a reloc number would be would be stored +. in this field. For example, the a PC relative word relocation +. in a coff environment would have the type 023 - because that's +. what the outside world calls a R_PCRWORD reloc. *} +. unsigned int type; +. +. {* The value the final relocation is shifted right by. This drops +. unwanted data from the relocation. *} +. unsigned int rightshift; +. +. {* The size of the item to be relocated. This is *not* a +. power-of-two measure. +. 0 : one byte +. 1 : two bytes +. 2 : four bytes +. 3 : nothing done (unless special_function is nonzero) +. 4 : eight bytes +. -2 : two bytes, result should be subtracted from the +. data instead of added +. There is currently no trivial way to extract a "number of +. bytes" from a howto pointer. *} +. int size; +. +. {* The number of bits in the item to be relocated. This is used +. when doing overflow checking. *} +. unsigned int bitsize; +. +. {* Notes that the relocation is relative to the location in the +. data section of the addend. The relocation function will +. subtract from the relocation value the address of the location +. being relocated. *} +. boolean pc_relative; +. +. {* The bit position of the reloc value in the destination. +. The relocated value is left shifted by this amount. *} +. unsigned int bitpos; +. +. {* What type of overflow error should be checked for when +. relocating. *} +. enum complain_overflow complain_on_overflow; +. +. {* If this field is non null, then the supplied function is +. called rather than the normal function. This allows really +. strange relocation methods to be accomodated (e.g., i960 callj +. instructions). *} +. bfd_reloc_status_type (*special_function) +. PARAMS ((bfd *abfd, +. arelent *reloc_entry, +. struct symbol_cache_entry *symbol, +. PTR data, +. asection *input_section, +. bfd *output_bfd)); +. +. {* The textual name of the relocation type. *} +. char *name; +. +. {* When performing a partial link, some formats must modify the +. relocations rather than the data - this flag signals this.*} +. boolean partial_inplace; +. +. {* The src_mask is used to select what parts of the read in data +. are to be used in the relocation sum. E.g., if this was an 8 bit +. bit of data which we read and relocated, this would be +. 0x000000ff. When we have relocs which have an addend, such as +. sun4 extended relocs, the value in the offset part of a +. relocating field is garbage so we never use it. In this case +. the mask would be 0x00000000. *} +. bfd_vma src_mask; +. +. {* The dst_mask is what parts of the instruction are replaced +. into the instruction. In most cases src_mask == dst_mask, +. except in the above special case, where dst_mask would be +. 0x000000ff, and src_mask would be 0x00000000. *} +. bfd_vma dst_mask; +. +. {* When some formats create PC relative instructions, they leave +. the value of the pc of the place being relocated in the offset +. slot of the instruction, so that a PC relative relocation can +. be made just by adding in an ordinary offset (e.g., sun3 a.out). +. Some formats leave the displacement part of an instruction +. empty (e.g., m88k bcs), this flag signals the fact.*} +. boolean pcrel_offset; +. +.} reloc_howto_type; + +*/ + +/* +FUNCTION + the HOWTO macro + +DESCRIPTION + The HOWTO define is horrible and will go away. + + +.#define HOWTO(C, R,S,B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ +. {(unsigned)C,R,S,B, P, BI, O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC} + +DESCRIPTION + And will be replaced with the totally magic way. But for the + moment, we are compatible, so do it this way.. + + +.#define NEWHOWTO( FUNCTION, NAME,SIZE,REL,IN) HOWTO(0,0,SIZE,0,REL,0,complain_overflow_dont,FUNCTION, NAME,false,0,0,IN) +. +DESCRIPTION + Helper routine to turn a symbol into a relocation value. + +.#define HOWTO_PREPARE(relocation, symbol) \ +. { \ +. if (symbol != (asymbol *)NULL) { \ +. if (bfd_is_com_section (symbol->section)) { \ +. relocation = 0; \ +. } \ +. else { \ +. relocation = symbol->value; \ +. } \ +. } \ +.} + +*/ + +/* +TYPEDEF + reloc_chain + +DESCRIPTION + + How relocs are tied together + +.typedef unsigned char bfd_byte; +. +.typedef struct relent_chain { +. arelent relent; +. struct relent_chain *next; +.} arelent_chain; + +*/ + + + +/* +FUNCTION + bfd_perform_relocation + +SYNOPSIS + bfd_reloc_status_type + bfd_perform_relocation + (bfd * abfd, + arelent *reloc_entry, + PTR data, + asection *input_section, + bfd *output_bfd); + +DESCRIPTION + If an output_bfd is supplied to this function the generated + image will be relocatable, the relocations are copied to the + output file after they have been changed to reflect the new + state of the world. There are two ways of reflecting the + results of partial linkage in an output file; by modifying the + output data in place, and by modifying the relocation record. + Some native formats (e.g., basic a.out and basic coff) have no + way of specifying an addend in the relocation type, so the + addend has to go in the output data. This is no big deal + since in these formats the output data slot will always be big + enough for the addend. Complex reloc types with addends were + invented to solve just this problem. + +*/ + + +bfd_reloc_status_type +DEFUN(bfd_perform_relocation,(abfd, + reloc_entry, + data, + input_section, + output_bfd), + bfd *abfd AND + arelent *reloc_entry AND + PTR data AND + asection *input_section AND + bfd *output_bfd) +{ + bfd_vma relocation; + bfd_reloc_status_type flag = bfd_reloc_ok; + bfd_size_type addr = reloc_entry->address ; + bfd_vma output_base = 0; + reloc_howto_type *howto = reloc_entry->howto; + asection *reloc_target_output_section ; + + asymbol *symbol; + + symbol = *( reloc_entry->sym_ptr_ptr); + if ((symbol->section == &bfd_abs_section) + && output_bfd != (bfd *)NULL) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* If we are not producing relocateable output, return an error if + the symbol is not defined. An undefined weak symbol is + considered to have a value of zero (SVR4 ABI, p. 4-27). */ + if (symbol->section == &bfd_und_section + && (symbol->flags & BSF_WEAK) == 0 + && output_bfd == (bfd *) NULL) + flag = bfd_reloc_undefined; + + /* If there is a function supplied to handle this relocation type, + call it. It'll return `bfd_reloc_continue' if further processing + can be done. */ + if (howto->special_function) + { + bfd_reloc_status_type cont; + cont = howto->special_function (abfd, reloc_entry, symbol, data, + input_section, output_bfd); + if (cont != bfd_reloc_continue) + return cont; + } + + /* Is the address of the relocation really within the section? */ + if (reloc_entry->address > input_section->_cooked_size) + return bfd_reloc_outofrange; + + /* Work out which section the relocation is targetted at and the + initial relocation command value. */ + + /* Get symbol value. (Common symbols are special.) */ + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + + reloc_target_output_section = symbol->section->output_section; + + /* Convert input-section-relative symbol value to absolute. */ + if (output_bfd && howto->partial_inplace==false) + output_base = 0; + else + output_base = reloc_target_output_section->vma; + + relocation += output_base + symbol->section->output_offset; + + /* Add in supplied addend. */ + relocation += reloc_entry->addend; + + /* Here the variable relocation holds the final address of the + symbol we are relocating against, plus any addend. */ + + if (howto->pc_relative == true) + { + /* This is a PC relative relocation. We want to set RELOCATION + to the distance between the address of the symbol and the + location. RELOCATION is already the address of the symbol. + + We start by subtracting the address of the section containing + the location. + + If pcrel_offset is set, we must further subtract the position + of the location within the section. Some targets arrange for + the addend to be the negative of the position of the location + within the section; for example, i386-aout does this. For + i386-aout, pcrel_offset is false. Some other targets do not + include the position of the location; for example, m88kbcs, + or ELF. For those targets, pcrel_offset is true. + + If we are producing relocateable output, then we must ensure + that this reloc will be correctly computed when the final + relocation is done. If pcrel_offset is false we want to wind + up with the negative of the location within the section, + which means we must adjust the existing addend by the change + in the location within the section. If pcrel_offset is true + we do not want to adjust the existing addend at all. + + FIXME: This seems logical to me, but for the case of + producing relocateable output it is not what the code + actually does. I don't want to change it, because it seems + far too likely that something will break. */ + + relocation -= + input_section->output_section->vma + input_section->output_offset; + + if (howto->pcrel_offset == true) + relocation -= reloc_entry->address; + } + + if (output_bfd!= (bfd *)NULL) + { + if ( howto->partial_inplace == false) + { + /* This is a partial relocation, and we want to apply the relocation + to the reloc entry rather than the raw data. Modify the reloc + inplace to reflect what we now know. */ + reloc_entry->addend = relocation; + reloc_entry->address += input_section->output_offset; + return flag; + } + else + { + /* This is a partial relocation, but inplace, so modify the + reloc record a bit. + + If we've relocated with a symbol with a section, change + into a ref to the section belonging to the symbol. */ + + reloc_entry->address += input_section->output_offset; + + /* WTF?? */ + if (abfd->xvec->flavour == bfd_target_coff_flavour) + { + relocation -= reloc_entry->addend; + reloc_entry->addend = 0; + } + else + { + reloc_entry->addend = relocation; + } + } + } + else + { + reloc_entry->addend = 0; + } + + /* FIXME: This overflow checking is incomplete, because the value + might have overflowed before we get here. For a correct check we + need to compute the value in a size larger than bitsize, but we + can't reasonably do that for a reloc the same size as a host + machine word. + FIXME: We should also do overflow checking on the result after + adding in the value contained in the object file. */ + if (howto->complain_on_overflow != complain_overflow_dont) + { + bfd_vma check; + + /* Get the value that will be used for the relocation, but + starting at bit position zero. */ + if (howto->rightshift > howto->bitpos) + check = relocation >> (howto->rightshift - howto->bitpos); + else + check = relocation << (howto->bitpos - howto->rightshift); + switch (howto->complain_on_overflow) + { + case complain_overflow_signed: + { + /* Assumes two's complement. */ + bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; + bfd_signed_vma reloc_signed_min = ~ reloc_signed_max; + + /* The above right shift is incorrect for a signed value. + Fix it up by forcing on the upper bits. */ + if (howto->rightshift > howto->bitpos + && (bfd_signed_vma) relocation < 0) + check |= ((bfd_vma) -1 + &~ ((bfd_vma) -1 + >> (howto->rightshift - howto->bitpos))); + if ((bfd_signed_vma) check > reloc_signed_max + || (bfd_signed_vma) check < reloc_signed_min) + flag = bfd_reloc_overflow; + } + break; + case complain_overflow_unsigned: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_unsigned_max = + (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if ((bfd_vma) check > reloc_unsigned_max) + flag = bfd_reloc_overflow; + } + break; + case complain_overflow_bitfield: + { + /* Assumes two's complement. This expression avoids + overflow if howto->bitsize is the number of bits in + bfd_vma. */ + bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; + + if (((bfd_vma) check &~ reloc_bits) != 0 + && ((bfd_vma) check &~ reloc_bits) != (-1 &~ reloc_bits)) + { + /* The above right shift is incorrect for a signed + value. See if turning on the upper bits fixes the + overflow. */ + if (howto->rightshift > howto->bitpos + && (bfd_signed_vma) relocation < 0) + { + check |= ((bfd_vma) -1 + &~ ((bfd_vma) -1 + >> (howto->rightshift - howto->bitpos))); + if (((bfd_vma) check &~ reloc_bits) != (-1 &~ reloc_bits)) + flag = bfd_reloc_overflow; + } + else + flag = bfd_reloc_overflow; + } + } + break; + default: + abort (); + } + } + + /* + Either we are relocating all the way, or we don't want to apply + the relocation to the reloc entry (probably because there isn't + any room in the output format to describe addends to relocs) + */ + relocation >>= howto->rightshift; + + /* Shift everything up to where it's going to be used */ + + relocation <<= howto->bitpos; + + /* Wait for the day when all have the mask in them */ + + /* What we do: + i instruction to be left alone + o offset within instruction + r relocation offset to apply + S src mask + D dst mask + N ~dst mask + A part 1 + B part 2 + R result + + Do this: + i i i i i o o o o o from bfd_get<size> + and S S S S S to get the size offset we want + + r r r r r r r r r r to get the final value to place + and D D D D D to chop to right size + ----------------------- + A A A A A + And this: + ... i i i i i o o o o o from bfd_get<size> + and N N N N N get instruction + ----------------------- + ... B B B B B + + And then: + B B B B B + or A A A A A + ----------------------- + R R R R R R R R R R put into bfd_put<size> + */ + +#define DOIT(x) \ + x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8(abfd, (char *)data + addr); + DOIT(x); + bfd_put_8(abfd,x, (unsigned char *) data + addr); + } + break; + + case 1: + if (relocation) + { + short x = bfd_get_16(abfd, (bfd_byte *)data + addr); + DOIT(x); + bfd_put_16(abfd, x, (unsigned char *)data + addr); + } + break; + case 2: + if (relocation) + { + long x = bfd_get_32 (abfd, (bfd_byte *) data + addr); + DOIT (x); + bfd_put_32 (abfd, x, (bfd_byte *)data + addr); + } + break; + case -2: + { + long x = bfd_get_32(abfd, (bfd_byte *) data + addr); + relocation = -relocation; + DOIT(x); + bfd_put_32(abfd,x, (bfd_byte *)data + addr); + } + break; + + case 3: + /* Do nothing */ + break; + + case 4: +#ifdef BFD64 + if (relocation) + { + bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data + addr); + DOIT (x); + bfd_put_64 (abfd, x, (bfd_byte *) data + addr); + } +#else + abort (); +#endif + break; + default: + return bfd_reloc_other; + } + + return flag; +} + + + +/* +DOCDD +INODE + howto manager, , typedef arelent, Relocations + +SECTION + The howto manager + + When an application wants to create a relocation, but doesn't + know what the target machine might call it, it can find out by + using this bit of code. + +*/ + +/* +TYPEDEF + bfd_reloc_code_type + +DESCRIPTION + The insides of a reloc code. The idea is that, eventually, there + will be one enumerator for every type of relocation we ever do. + Pass one of these values to <<bfd_reloc_type_lookup>>, and it'll + return a howto pointer. + + This does mean that the application must determine the correct + enumerator value; you can't get a howto pointer from a random set + of attributes. + +CODE_FRAGMENT +. +.typedef enum bfd_reloc_code_real +.{ +. {* Basic absolute relocations *} +. BFD_RELOC_64, +. BFD_RELOC_32, +. BFD_RELOC_16, +. BFD_RELOC_8, +. +. {* PC-relative relocations *} +. BFD_RELOC_64_PCREL, +. BFD_RELOC_32_PCREL, +. BFD_RELOC_24_PCREL, {* used by i960 *} +. BFD_RELOC_16_PCREL, +. BFD_RELOC_8_PCREL, +. +. {* Linkage-table relative *} +. BFD_RELOC_32_BASEREL, +. BFD_RELOC_16_BASEREL, +. BFD_RELOC_8_BASEREL, +. +. {* The type of reloc used to build a contructor table - at the moment +. probably a 32 bit wide abs address, but the cpu can choose. *} +. BFD_RELOC_CTOR, +. +. {* 8 bits wide, but used to form an address like 0xffnn *} +. BFD_RELOC_8_FFnn, +. +. {* 32-bit pc-relative, shifted right 2 bits (i.e., 30-bit +. word displacement, e.g. for SPARC) *} +. BFD_RELOC_32_PCREL_S2, +. +. {* High 22 bits of 32-bit value, placed into lower 22 bits of +. target word; simple reloc. *} +. BFD_RELOC_HI22, +. {* Low 10 bits. *} +. BFD_RELOC_LO10, +. +. {* Reloc types used for i960/b.out. *} +. BFD_RELOC_I960_CALLJ, +. +. {* now for the sparc/elf codes *} +. BFD_RELOC_NONE, {* actually used *} +. BFD_RELOC_SPARC_WDISP22, +. BFD_RELOC_SPARC22, +. BFD_RELOC_SPARC13, +. BFD_RELOC_SPARC_GOT10, +. BFD_RELOC_SPARC_GOT13, +. BFD_RELOC_SPARC_GOT22, +. BFD_RELOC_SPARC_PC10, +. BFD_RELOC_SPARC_PC22, +. BFD_RELOC_SPARC_WPLT30, +. BFD_RELOC_SPARC_COPY, +. BFD_RELOC_SPARC_GLOB_DAT, +. BFD_RELOC_SPARC_JMP_SLOT, +. BFD_RELOC_SPARC_RELATIVE, +. BFD_RELOC_SPARC_UA32, +. +. {* these are a.out specific? *} +. BFD_RELOC_SPARC_BASE13, +. BFD_RELOC_SPARC_BASE22, +. +. +. {* Bits 27..2 of the relocation address shifted right 2 bits; +. simple reloc otherwise. *} +. BFD_RELOC_MIPS_JMP, +. +. {* signed 16-bit pc-relative, shifted right 2 bits (e.g. for MIPS) *} +. BFD_RELOC_16_PCREL_S2, +. +. {* High 16 bits of 32-bit value; simple reloc. *} +. BFD_RELOC_HI16, +. {* High 16 bits of 32-bit value but the low 16 bits will be sign +. extended and added to form the final result. If the low 16 +. bits form a negative number, we need to add one to the high value +. to compensate for the borrow when the low bits are added. *} +. BFD_RELOC_HI16_S, +. {* Low 16 bits. *} +. BFD_RELOC_LO16, +. +. {* 16 bit relocation relative to the global pointer. *} +. BFD_RELOC_MIPS_GPREL, +. +. {* These are, so far, specific to HPPA processors. I'm not sure that some +. don't duplicate other reloc types, such as BFD_RELOC_32 and _32_PCREL. +. Also, many more were in the list I got that don't fit in well in the +. model BFD uses, so I've omitted them for now. If we do make this reloc +. type get used for code that really does implement the funky reloc types, +. they'll have to be added to this list. *} +. BFD_RELOC_HPPA_32, +. BFD_RELOC_HPPA_11, +. BFD_RELOC_HPPA_14, +. BFD_RELOC_HPPA_17, +. +. BFD_RELOC_HPPA_L21, +. BFD_RELOC_HPPA_R11, +. BFD_RELOC_HPPA_R14, +. BFD_RELOC_HPPA_R17, +. BFD_RELOC_HPPA_LS21, +. BFD_RELOC_HPPA_RS11, +. BFD_RELOC_HPPA_RS14, +. BFD_RELOC_HPPA_RS17, +. BFD_RELOC_HPPA_LD21, +. BFD_RELOC_HPPA_RD11, +. BFD_RELOC_HPPA_RD14, +. BFD_RELOC_HPPA_RD17, +. BFD_RELOC_HPPA_LR21, +. BFD_RELOC_HPPA_RR14, +. BFD_RELOC_HPPA_RR17, +. +. BFD_RELOC_HPPA_GOTOFF_11, +. BFD_RELOC_HPPA_GOTOFF_14, +. BFD_RELOC_HPPA_GOTOFF_L21, +. BFD_RELOC_HPPA_GOTOFF_R11, +. BFD_RELOC_HPPA_GOTOFF_R14, +. BFD_RELOC_HPPA_GOTOFF_LS21, +. BFD_RELOC_HPPA_GOTOFF_RS11, +. BFD_RELOC_HPPA_GOTOFF_RS14, +. BFD_RELOC_HPPA_GOTOFF_LD21, +. BFD_RELOC_HPPA_GOTOFF_RD11, +. BFD_RELOC_HPPA_GOTOFF_RD14, +. BFD_RELOC_HPPA_GOTOFF_LR21, +. BFD_RELOC_HPPA_GOTOFF_RR14, +. +. BFD_RELOC_HPPA_DLT_32, +. BFD_RELOC_HPPA_DLT_11, +. BFD_RELOC_HPPA_DLT_14, +. BFD_RELOC_HPPA_DLT_L21, +. BFD_RELOC_HPPA_DLT_R11, +. BFD_RELOC_HPPA_DLT_R14, +. +. BFD_RELOC_HPPA_ABS_CALL_11, +. BFD_RELOC_HPPA_ABS_CALL_14, +. BFD_RELOC_HPPA_ABS_CALL_17, +. BFD_RELOC_HPPA_ABS_CALL_L21, +. BFD_RELOC_HPPA_ABS_CALL_R11, +. BFD_RELOC_HPPA_ABS_CALL_R14, +. BFD_RELOC_HPPA_ABS_CALL_R17, +. BFD_RELOC_HPPA_ABS_CALL_LS21, +. BFD_RELOC_HPPA_ABS_CALL_RS11, +. BFD_RELOC_HPPA_ABS_CALL_RS14, +. BFD_RELOC_HPPA_ABS_CALL_RS17, +. BFD_RELOC_HPPA_ABS_CALL_LD21, +. BFD_RELOC_HPPA_ABS_CALL_RD11, +. BFD_RELOC_HPPA_ABS_CALL_RD14, +. BFD_RELOC_HPPA_ABS_CALL_RD17, +. BFD_RELOC_HPPA_ABS_CALL_LR21, +. BFD_RELOC_HPPA_ABS_CALL_RR14, +. BFD_RELOC_HPPA_ABS_CALL_RR17, +. +. BFD_RELOC_HPPA_PCREL_CALL_11, +. BFD_RELOC_HPPA_PCREL_CALL_12, +. BFD_RELOC_HPPA_PCREL_CALL_14, +. BFD_RELOC_HPPA_PCREL_CALL_17, +. BFD_RELOC_HPPA_PCREL_CALL_L21, +. BFD_RELOC_HPPA_PCREL_CALL_R11, +. BFD_RELOC_HPPA_PCREL_CALL_R14, +. BFD_RELOC_HPPA_PCREL_CALL_R17, +. BFD_RELOC_HPPA_PCREL_CALL_LS21, +. BFD_RELOC_HPPA_PCREL_CALL_RS11, +. BFD_RELOC_HPPA_PCREL_CALL_RS14, +. BFD_RELOC_HPPA_PCREL_CALL_RS17, +. BFD_RELOC_HPPA_PCREL_CALL_LD21, +. BFD_RELOC_HPPA_PCREL_CALL_RD11, +. BFD_RELOC_HPPA_PCREL_CALL_RD14, +. BFD_RELOC_HPPA_PCREL_CALL_RD17, +. BFD_RELOC_HPPA_PCREL_CALL_LR21, +. BFD_RELOC_HPPA_PCREL_CALL_RR14, +. BFD_RELOC_HPPA_PCREL_CALL_RR17, +. +. BFD_RELOC_HPPA_PLABEL_32, +. BFD_RELOC_HPPA_PLABEL_11, +. BFD_RELOC_HPPA_PLABEL_14, +. BFD_RELOC_HPPA_PLABEL_L21, +. BFD_RELOC_HPPA_PLABEL_R11, +. BFD_RELOC_HPPA_PLABEL_R14, +. +. BFD_RELOC_HPPA_UNWIND_ENTRY, +. BFD_RELOC_HPPA_UNWIND_ENTRIES, +. +. {* i386/elf relocations *} +. BFD_RELOC_386_GOT32, +. BFD_RELOC_386_PLT32, +. BFD_RELOC_386_COPY, +. BFD_RELOC_386_GLOB_DAT, +. BFD_RELOC_386_JUMP_SLOT, +. BFD_RELOC_386_RELATIVE, +. BFD_RELOC_386_GOTOFF, +. BFD_RELOC_386_GOTPC, +. +. {* this must be the highest numeric value *} +. BFD_RELOC_UNUSED +. } bfd_reloc_code_real_type; +*/ + + +/* +SECTION + bfd_reloc_type_lookup + +SYNOPSIS + CONST struct reloc_howto_struct * + bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code); + +DESCRIPTION + This routine returns a pointer to a howto struct which when + invoked, will perform the supplied relocation on data from the + architecture noted. + +*/ + + +CONST struct reloc_howto_struct * +DEFUN(bfd_reloc_type_lookup,(abfd, code), + bfd *abfd AND + bfd_reloc_code_real_type code) +{ + return BFD_SEND (abfd, reloc_type_lookup, (abfd, code)); +} + +static reloc_howto_type bfd_howto_32 = + HOWTO(0, 00,2,32,false,0,complain_overflow_bitfield,0,"VRT32", false,0xffffffff,0xffffffff,true); + + +/* +INTERNAL_FUNCTION + bfd_default_reloc_type_lookup + +SYNOPSIS + CONST struct reloc_howto_struct *bfd_default_reloc_type_lookup + (bfd *abfd AND + bfd_reloc_code_real_type code); + +DESCRIPTION + Provides a default relocation lookup routine for any architecture. + + +*/ + +CONST struct reloc_howto_struct * +DEFUN(bfd_default_reloc_type_lookup, (abfd, code), + bfd *abfd AND + bfd_reloc_code_real_type code) +{ + switch (code) + { + case BFD_RELOC_CTOR: + /* The type of reloc used in a ctor, which will be as wide as the + address - so either a 64, 32, or 16 bitter. */ + switch (bfd_get_arch_info (abfd)->bits_per_address) { + case 64: + BFD_FAIL(); + case 32: + return &bfd_howto_32; + case 16: + BFD_FAIL(); + default: + BFD_FAIL(); + } + default: + BFD_FAIL(); + } + return (CONST struct reloc_howto_struct *)NULL; +} + + +/* +INTERNAL_FUNCTION + bfd_generic_relax_section + +SYNOPSIS + boolean bfd_generic_relax_section + (bfd *abfd, + asection *section, + asymbol **symbols); + +DESCRIPTION + Provides default handling for relaxing for back ends which + don't do relaxing -- i.e., does nothing. +*/ + +boolean +DEFUN(bfd_generic_relax_section,(abfd, section, symbols), + bfd *abfd AND + asection *section AND + asymbol **symbols) +{ + + return false; + +} + + +/* +INTERNAL_FUNCTION + bfd_generic_get_relocated_section_contents + +SYNOPSIS + bfd_byte * + bfd_generic_get_relocated_section_contents (bfd *abfd, + struct bfd_seclet *seclet, + bfd_byte *data, + boolean relocateable); + +DESCRIPTION + Provides default handling of relocation effort for back ends + which can't be bothered to do it efficiently. + +*/ + +bfd_byte * +DEFUN(bfd_generic_get_relocated_section_contents,(abfd, + seclet, + data, + relocateable), + bfd *abfd AND + struct bfd_seclet *seclet AND + bfd_byte *data AND + boolean relocateable) +{ + extern bfd_error_vector_type bfd_error_vector; + + /* Get enough memory to hold the stuff */ + bfd *input_bfd = seclet->u.indirect.section->owner; + asection *input_section = seclet->u.indirect.section; + + + + size_t reloc_size = bfd_get_reloc_upper_bound(input_bfd, input_section); + arelent **reloc_vector = (arelent **) alloca(reloc_size); + + /* read in the section */ + bfd_get_section_contents(input_bfd, + input_section, + data, + 0, + input_section->_raw_size); + +/* We're not relaxing the section, so just copy the size info */ + input_section->_cooked_size = input_section->_raw_size; + input_section->reloc_done = true; + + + if (bfd_canonicalize_reloc(input_bfd, + input_section, + reloc_vector, + seclet->u.indirect.symbols) ) + { + arelent **parent; + for (parent = reloc_vector; * parent != (arelent *)NULL; + parent++) + { + bfd_reloc_status_type r= + bfd_perform_relocation(input_bfd, + *parent, + data, + input_section, + relocateable ? abfd : (bfd *) NULL); + + if (relocateable) + { + asection *os = input_section->output_section; + + /* A partial link, so keep the relocs */ + os->orelocation[os->reloc_count] = *parent; + os->reloc_count++; + } + + if (r != bfd_reloc_ok) + { + switch (r) + { + case bfd_reloc_undefined: + bfd_error_vector.undefined_symbol(*parent, seclet); + break; + case bfd_reloc_dangerous: + bfd_error_vector.reloc_dangerous(*parent, seclet); + break; + case bfd_reloc_outofrange: + case bfd_reloc_overflow: + bfd_error_vector.reloc_value_truncated(*parent, seclet); + break; + default: + abort(); + break; + } + + } + } + } + + + return data; + + +} diff --git a/gnu/usr.bin/gdb/bfd/seclet.c b/gnu/usr.bin/gdb/bfd/seclet.c new file mode 100644 index 00000000000..e1bce053fc5 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/seclet.c @@ -0,0 +1,188 @@ +/* seclet.c + Copyright (C) 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: seclet.c,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +/* This module is part of BFD */ + + +/* The intention is that one day, all the code which uses sections + will change and use seclets instead - maybe seglet would have been + a better name.. + + Anyway, a seclet contains enough info to be able to describe an + area of output memory in one go. + + The only description so far catered for is that of the + <<bfd_indirect_seclet>>, which is a select which points to a + <<section>> and the <<asymbols>> associated with the section, so + that relocation can be done when needed. + + One day there will be more types - they will at least migrate from + the linker's data structures - also there could be extra stuff, + like a bss seclet, which descibes a lump of memory as containing + zeros compactly, without the horrible SEC_* flag cruft. + + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "seclet.h" +#include "coff/internal.h" + +/* Create a new seclet and attach it to a section. */ + +bfd_seclet_type * +DEFUN(bfd_new_seclet,(abfd, section), + bfd *abfd AND + asection *section) +{ + bfd_seclet_type *n = (bfd_seclet_type *)bfd_alloc(abfd, sizeof(bfd_seclet_type)); + if (section->seclets_tail != (bfd_seclet_type *)NULL) { + section->seclets_tail->next = n; + } + else + { + section->seclets_head = n; + } + section->seclets_tail = n; + + return n; +} + +/* Given an indirect seclet which points to an input section, relocate + the contents of the seclet and put the data in its final + destination. */ + +static boolean +DEFUN(rel,(abfd, seclet, output_section, data, relocateable), + bfd *abfd AND + bfd_seclet_type *seclet AND + asection *output_section AND + PTR data AND + boolean relocateable) +{ + if ((output_section->flags & SEC_HAS_CONTENTS) != 0 + && seclet->size) + { + data = (PTR) bfd_get_relocated_section_contents(abfd, seclet, data, + relocateable); + if(bfd_set_section_contents(abfd, + output_section, + data, + seclet->offset, + seclet->size) == false) + { + abort(); + } + } + return true; +} + +/* Put the contents of a seclet in its final destination. */ + +static boolean +DEFUN(seclet_dump_seclet,(abfd, seclet, section, data, relocateable), + bfd *abfd AND + bfd_seclet_type *seclet AND + asection *section AND + PTR data AND + boolean relocateable) +{ + switch (seclet->type) + { + case bfd_indirect_seclet: + /* The contents of this section come from another one somewhere + else */ + return rel(abfd, seclet, section, data, relocateable); + + case bfd_fill_seclet: + /* Fill in the section with us */ + { + char *d = bfd_xmalloc(seclet->size); + unsigned int i; + for (i =0; i < seclet->size; i+=2) { + d[i] = seclet->u.fill.value >> 8; + } + for (i = 1; i < seclet->size; i+=2) { + d[i] = seclet->u.fill.value ; + } + /* Don't bother to fill in empty sections */ + if (!(bfd_get_section_flags(abfd, section) & SEC_HAS_CONTENTS)) + { + return true; + } + return bfd_set_section_contents(abfd, section, d, seclet->offset, + seclet->size); + } + + default: + abort(); + } + + return true; +} + +/* +INTERNAL_FUNCTION + bfd_generic_seclet_link + +SYNOPSIS + boolean bfd_generic_seclet_link + (bfd *abfd, + PTR data, + boolean relocateable); + +DESCRIPTION + + The generic seclet linking routine. The caller should have + set up seclets for all the output sections. The DATA argument + should point to a memory area large enough to hold the largest + section. This function looks through the seclets and moves + the contents into the output sections. If RELOCATEABLE is + true, the orelocation fields of the output sections must + already be initialized. + +*/ + +boolean +DEFUN(bfd_generic_seclet_link,(abfd, data, relocateable), + bfd *abfd AND + PTR data AND + boolean relocateable) +{ + asection *o = abfd->sections; + while (o != (asection *)NULL) + { + bfd_seclet_type *p = o->seclets_head; + while (p != (bfd_seclet_type *)NULL) + { + if (seclet_dump_seclet(abfd, p, o, data, relocateable) == false) + return false; + p = p ->next; + } + o = o->next; + } + + return true; +} diff --git a/gnu/usr.bin/gdb/bfd/seclet.h b/gnu/usr.bin/gdb/bfd/seclet.h new file mode 100644 index 00000000000..8f2631ab0f2 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/seclet.h @@ -0,0 +1,58 @@ +/* Definitions of little sections (seclets) for BFD. + Copyright 1992 Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: seclet.h,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +#ifndef _SECLET_H +#define _SECLET_H + +enum bfd_seclet_enum +{ + bfd_indirect_seclet, + bfd_fill_seclet +}; + +struct bfd_seclet +{ + struct bfd_seclet *next; + enum bfd_seclet_enum type; + unsigned int offset; + unsigned int size; + union + { + struct + { + asection *section; + asymbol **symbols; + } indirect; + struct { + int value; + } fill; + } + u; +}; + +typedef struct bfd_seclet bfd_seclet_type; + +bfd_seclet_type * +bfd_new_seclet PARAMS ((bfd *, asection *)); + +#endif diff --git a/gnu/usr.bin/gdb/bfd/section.c b/gnu/usr.bin/gdb/bfd/section.c new file mode 100644 index 00000000000..4980b612238 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/section.c @@ -0,0 +1,902 @@ +/* Object file "section" support for the BFD library. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: section.c,v 1.1 1995/10/18 08:39:53 deraadt Exp $ +*/ + +/* +SECTION + Sections + + Sections are supported in BFD in <<section.c>>. + + The raw data contained within a BFD is maintained through the + section abstraction. A single BFD may have any number of + sections, and keeps hold of them by pointing to the first, + each one points to the next in the list. + +@menu +@* Section Input:: +@* Section Output:: +@* typedef asection:: +@* section prototypes:: +@end menu + +INODE +Section Input, Section Output, Sections, Sections +SUBSECTION + Section Input + + When a BFD is opened for reading, the section structures are + created and attached to the BFD. + + Each section has a name which describes the section in the + outside world - for example, <<a.out>> would contain at least + three sections, called <<.text>>, <<.data>> and <<.bss>>. + + Names need not be unique; for example a COFF file may have several + sections named .data. + + Sometimes a BFD will contain more than the 'natural' number of + sections. A back end may attach other sections containing + constructor data, or an application may add a section (using + bfd_make_section) to the sections attached to an already open + BFD. For example, the linker creates a supernumary section + <<COMMON>> for each input file's BFD to hold information about + common storage. + + The raw data is not necessarily read in at the same time as + the section descriptor is created. Some targets may leave the + data in place until a <<bfd_get_section_contents>> call is + made. Other back ends may read in all the data at once - For + example; an S-record file has to be read once to determine the + size of the data. An IEEE-695 file doesn't contain raw data in + sections, but data and relocation expressions intermixed, so + the data area has to be parsed to get out the data and + relocations. + +INODE +Section Output, typedef asection, Section Input, Sections + +SUBSECTION + Section Output + + To write a new object style BFD, the various sections to be + written have to be created. They are attached to the BFD in + the same way as input sections, data is written to the + sections using <<bfd_set_section_contents>>. + + Any program that creates or combines sections (e.g., the assembler + and linker) must use the fields <<output_section>> and + <<output_offset>> to indicate the file sections to which each + section must be written. (If the section is being created from + scratch, <<output_section>> should probably point to the section + itself, and <<output_offset>> should probably be zero.) + + The data to be written comes from input sections attached to + the output sections. The output section structure can be + considered a filter for the input section, the output section + determines the vma of the output data and the name, but the + input section determines the offset into the output section of + the data to be written. + + E.g., to create a section "O", starting at 0x100, 0x123 long, + containing two subsections, "A" at offset 0x0 (ie at vma + 0x100) and "B" at offset 0x20 (ie at vma 0x120) the structures + would look like: + +| section name "A" +| output_offset 0x00 +| size 0x20 +| output_section -----------> section name "O" +| | vma 0x100 +| section name "B" | size 0x123 +| output_offset 0x20 | +| size 0x103 | +| output_section --------| + + +SUBSECTION + Seglets + + The data within a section is stored in a <<seglet>>. These + are much like the fixups in <<gas>>. The seglet abstraction + allows the a section to grow and shrink within itself. + + A seglet knows how big it is, and which is the next seglet and + where the raw data for it is, and also points to a list of + relocations which apply to it. + + The seglet is used by the linker to perform relaxing on final + code. The application creates code which is as big as + necessary to make it work without relaxing, and the user can + select whether to relax. Sometimes relaxing takes a lot of + time. The linker runs around the relocations to see if any + are attached to data which can be shrunk, if so it does it on + a seglet by seglet basis. + +*/ + + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + + +/* +DOCDD +INODE +typedef asection, section prototypes, Section Output, Sections +SUBSECTION + typedef asection + + The shape of a section struct: + +CODE_FRAGMENT +. +.typedef struct sec +.{ +. {* The name of the section, the name isn't a copy, the pointer is +. the same as that passed to bfd_make_section. *} +. +. CONST char *name; +. +. {* Which section is it 0.nth *} +. +. int index; +. +. {* The next section in the list belonging to the BFD, or NULL. *} +. +. struct sec *next; +. +. {* The field flags contains attributes of the section. Some of +. flags are read in from the object file, and some are +. synthesized from other information. *} +. +. flagword flags; +. +.#define SEC_NO_FLAGS 0x000 +. +. {* Tells the OS to allocate space for this section when loaded. +. This would clear for a section containing debug information +. only. *} +.#define SEC_ALLOC 0x001 +. +. {* Tells the OS to load the section from the file when loading. +. This would be clear for a .bss section *} +.#define SEC_LOAD 0x002 +. +. {* The section contains data still to be relocated, so there will +. be some relocation information too. *} +.#define SEC_RELOC 0x004 +. +.#if 0 {* Obsolete ? *} +.#define SEC_BALIGN 0x008 +.#endif +. +. {* A signal to the OS that the section contains read only +. data. *} +.#define SEC_READONLY 0x010 +. +. {* The section contains code only. *} +.#define SEC_CODE 0x020 +. +. {* The section contains data only. *} +.#define SEC_DATA 0x040 +. +. {* The section will reside in ROM. *} +.#define SEC_ROM 0x080 +. +. {* The section contains constructor information. This section +. type is used by the linker to create lists of constructors and +. destructors used by <<g++>>. When a back end sees a symbol +. which should be used in a constructor list, it creates a new +. section for the type of name (eg <<__CTOR_LIST__>>), attaches +. the symbol to it and builds a relocation. To build the lists +. of constructors, all the linker has to do is catenate all the +. sections called <<__CTOR_LIST__>> and relocte the data +. contained within - exactly the operations it would peform on +. standard data. *} +.#define SEC_CONSTRUCTOR 0x100 +. +. {* The section is a constuctor, and should be placed at the +. end of the text, data, or bss section(?). *} +.#define SEC_CONSTRUCTOR_TEXT 0x1100 +.#define SEC_CONSTRUCTOR_DATA 0x2100 +.#define SEC_CONSTRUCTOR_BSS 0x3100 +. +. {* The section has contents - a data section could be +. <<SEC_ALLOC>> | <<SEC_HAS_CONTENTS>>, a debug section could be +. <<SEC_HAS_CONTENTS>> *} +.#define SEC_HAS_CONTENTS 0x200 +. +. {* An instruction to the linker not to output sections +. containing this flag even if they have information which +. would normally be written. *} +.#define SEC_NEVER_LOAD 0x400 +. +. {* The section is a shared library section. The linker must leave +. these completely alone, as the vma and size are used when +. the executable is loaded. *} +.#define SEC_SHARED_LIBRARY 0x800 +. +. {* The section is a common section (symbols may be defined +. multiple times, the value of a symbol is the amount of +. space it requires, and the largest symbol value is the one +. used). Most targets have exactly one of these (which we +. translate to bfd_com_section), but ECOFF has two. *} +.#define SEC_IS_COMMON 0x8000 +. +. {* The section contains only debugging information. For +. example, this is set for ELF .debug and .stab sections. +. strip tests this flag to see if a section can be +. discarded. *} +.#define SEC_DEBUGGING 0x10000 +. +. {* End of section flags. *} +. +. {* The virtual memory address of the section - where it will be +. at run time. The symbols are relocated against this. The +. user_set_vma flag is maintained by bfd; if it's not set, the +. backend can assign addresses (for example, in <<a.out>>, where +. the default address for <<.data>> is dependent on the specific +. target and various flags). *} +. +. bfd_vma vma; +. boolean user_set_vma; +. +. {* The load address of the section - where it would be in a +. rom image, really only used for writing section header +. information. *} +. +. bfd_vma lma; +. +. {* The size of the section in bytes, as it will be output. +. contains a value even if the section has no contents (eg, the +. size of <<.bss>>). This will be filled in after relocation *} +. +. bfd_size_type _cooked_size; +. +. {* The size on disk of the section in bytes originally. Normally this +. value is the same as the size, but if some relaxing has +. been done, then this value will be bigger. *} +. +. bfd_size_type _raw_size; +. +. {* If this section is going to be output, then this value is the +. offset into the output section of the first byte in the input +. section. Eg, if this was going to start at the 100th byte in +. the output section, this value would be 100. *} +. +. bfd_vma output_offset; +. +. {* The output section through which to map on output. *} +. +. struct sec *output_section; +. +. {* The alignment requirement of the section, as an exponent - eg +. 3 aligns to 2^3 (or 8) *} +. +. unsigned int alignment_power; +. +. {* If an input section, a pointer to a vector of relocation +. records for the data in this section. *} +. +. struct reloc_cache_entry *relocation; +. +. {* If an output section, a pointer to a vector of pointers to +. relocation records for the data in this section. *} +. +. struct reloc_cache_entry **orelocation; +. +. {* The number of relocation records in one of the above *} +. +. unsigned reloc_count; +. +. {* Information below is back end specific - and not always used +. or updated. *} +. +. {* File position of section data *} +. +. file_ptr filepos; +. +. {* File position of relocation info *} +. +. file_ptr rel_filepos; +. +. {* File position of line data *} +. +. file_ptr line_filepos; +. +. {* Pointer to data for applications *} +. +. PTR userdata; +. +. struct lang_output_section *otheruserdata; +. +. {* Attached line number information *} +. +. alent *lineno; +. +. {* Number of line number records *} +. +. unsigned int lineno_count; +. +. {* When a section is being output, this value changes as more +. linenumbers are written out *} +. +. file_ptr moving_line_filepos; +. +. {* what the section number is in the target world *} +. +. int target_index; +. +. PTR used_by_bfd; +. +. {* If this is a constructor section then here is a list of the +. relocations created to relocate items within it. *} +. +. struct relent_chain *constructor_chain; +. +. {* The BFD which owns the section. *} +. +. bfd *owner; +. +. boolean reloc_done; +. {* A symbol which points at this section only *} +. struct symbol_cache_entry *symbol; +. struct symbol_cache_entry **symbol_ptr_ptr; +. +. struct bfd_seclet *seclets_head; +. struct bfd_seclet *seclets_tail; +.} asection ; +. +. +. {* These sections are global, and are managed by BFD. The application +. and target back end are not permitted to change the values in +. these sections. *} +.#define BFD_ABS_SECTION_NAME "*ABS*" +.#define BFD_UND_SECTION_NAME "*UND*" +.#define BFD_COM_SECTION_NAME "*COM*" +.#define BFD_IND_SECTION_NAME "*IND*" +. +. {* the absolute section *} +.extern asection bfd_abs_section; +. {* Pointer to the undefined section *} +.extern asection bfd_und_section; +. {* Pointer to the common section *} +.extern asection bfd_com_section; +. {* Pointer to the indirect section *} +.extern asection bfd_ind_section; +. +.extern struct symbol_cache_entry *bfd_abs_symbol; +.extern struct symbol_cache_entry *bfd_com_symbol; +.extern struct symbol_cache_entry *bfd_und_symbol; +.extern struct symbol_cache_entry *bfd_ind_symbol; +.#define bfd_get_section_size_before_reloc(section) \ +. (section->reloc_done ? (abort(),1): (section)->_raw_size) +.#define bfd_get_section_size_after_reloc(section) \ +. ((section->reloc_done) ? (section)->_cooked_size: (abort(),1)) +*/ + +/* These symbols are global, not specific to any BFD. Therefore, anything + that tries to change them is broken, and should be repaired. */ +static CONST asymbol global_syms[] = { + /* the_bfd, name, value, attr, section [, udata] */ + { 0, BFD_COM_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_com_section }, + { 0, BFD_UND_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_und_section }, + { 0, BFD_ABS_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_abs_section }, + { 0, BFD_IND_SECTION_NAME, 0, BSF_SECTION_SYM, &bfd_ind_section }, +}; + +#define STD_SECTION(SEC, FLAGS, SYM, NAME, IDX) \ + asymbol *SYM = (asymbol *) &global_syms[IDX]; \ + asection SEC = { NAME, 0, 0, FLAGS, 0, 0, (boolean) 0, 0, 0, 0, &SEC,\ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (boolean) 0, \ + (asymbol *) &global_syms[IDX], &SYM, } + +STD_SECTION (bfd_com_section, SEC_IS_COMMON, bfd_com_symbol, BFD_COM_SECTION_NAME, 0); +STD_SECTION (bfd_und_section, 0, bfd_und_symbol, BFD_UND_SECTION_NAME, 1); +STD_SECTION (bfd_abs_section, 0, bfd_abs_symbol, BFD_ABS_SECTION_NAME, 2); +STD_SECTION (bfd_ind_section, 0, bfd_ind_symbol, BFD_IND_SECTION_NAME, 3); +#undef STD_SECTION + +/* +DOCDD +INODE +section prototypes, , typedef asection, Sections +SUBSECTION + section prototypes + +These are the functions exported by the section handling part of +<<libbfd>. +*/ + +/* +FUNCTION + bfd_get_section_by_name + +SYNOPSIS + asection *bfd_get_section_by_name(bfd *abfd, CONST char *name); + +DESCRIPTION + Runs through the provided @var{abfd} and returns the one of the + <<asection>>s who's name matches that provided, otherwise NULL. + @xref{Sections}, for more information. + + This should only be used in special cases; the normal way to process + all sections of a given name is to use bfd_map_over_sections and + strcmp on the name (or better yet, base it on the section flags + or something else) for each section. +*/ + +asection * +DEFUN(bfd_get_section_by_name,(abfd, name), + bfd *abfd AND + CONST char *name) +{ + asection *sect; + + for (sect = abfd->sections; sect != NULL; sect = sect->next) + if (!strcmp (sect->name, name)) return sect; + return NULL; +} + + +/* +FUNCTION + bfd_make_section_old_way + +SYNOPSIS + asection *bfd_make_section_old_way(bfd *, CONST char *name); + +DESCRIPTION + This function creates a new empty section called @var{name} + and attaches it to the end of the chain of sections for the + BFD supplied. An attempt to create a section with a name which + is already in use, returns its pointer without changing the + section chain. + + It has the funny name since this is the way it used to be + before is was rewritten... + + Possible errors are: + o invalid_operation - + If output has already started for this BFD. + o no_memory - + If obstack alloc fails. + +*/ + + +asection * +DEFUN(bfd_make_section_old_way,(abfd, name), + bfd *abfd AND + CONST char * name) +{ + asection *sec = bfd_get_section_by_name(abfd, name); + if (sec == (asection *)NULL) + { + sec = bfd_make_section(abfd, name); + } + return sec; +} + +/* +FUNCTION + bfd_make_section_anyway + +SYNOPSIS + asection *bfd_make_section_anyway(bfd *, CONST char *name); + +DESCRIPTION + Create a new empty section called @var{name} and attach it to the end of + the chain of sections for @var{abfd}. Create a new section even if there + is already a section with that name. + + Returns NULL and sets bfd_error on error; possible errors are: + o invalid_operation - If output has already started for @var{abfd}. + o no_memory - If obstack alloc fails. +*/ + +sec_ptr +bfd_make_section_anyway (abfd, name) + bfd *abfd; + CONST char *name; +{ + asection *newsect; + asection **prev = &abfd->sections; + asection * sect = abfd->sections; + + if (abfd->output_has_begun) + { + bfd_error = invalid_operation; + return NULL; + } + + while (sect) { + prev = §->next; + sect = sect->next; + } + + newsect = (asection *) bfd_zalloc(abfd, sizeof (asection)); + if (newsect == NULL) { + bfd_error = no_memory; + return NULL; + } + + newsect->name = name; + newsect->index = abfd->section_count++; + newsect->flags = SEC_NO_FLAGS; + + newsect->userdata = 0; + newsect->next = (asection *)NULL; + newsect->relocation = (arelent *)NULL; + newsect->reloc_count = 0; + newsect->line_filepos =0; + newsect->owner = abfd; + + /* Create a symbol whos only job is to point to this section. This is + useful for things like relocs which are relative to the base of a + section. */ + newsect->symbol = bfd_make_empty_symbol(abfd); + newsect->symbol->name = name; + newsect->symbol->value = 0; + newsect->symbol->section = newsect; + newsect->symbol->flags = BSF_SECTION_SYM; + + newsect->symbol_ptr_ptr = &newsect->symbol; + + if (BFD_SEND (abfd, _new_section_hook, (abfd, newsect)) != true) { + free (newsect); + return NULL; + } + + *prev = newsect; + return newsect; +} + +/* +FUNCTION + bfd_make_section + +SYNOPSIS + asection *bfd_make_section(bfd *, CONST char *name); + +DESCRIPTION + Like bfd_make_section_anyway, but return NULL (without setting + bfd_error) without changing the section chain if there is already a + section named @var{name}. If there is an error, return NULL and set + bfd_error. +*/ + +sec_ptr +DEFUN(bfd_make_section,(abfd, name), + bfd *abfd AND + CONST char * name) +{ + asection * sect = abfd->sections; + + if (strcmp(name, BFD_ABS_SECTION_NAME) == 0) + { + return &bfd_abs_section; + } + if (strcmp(name, BFD_COM_SECTION_NAME) == 0) + { + return &bfd_com_section; + } + if (strcmp(name, BFD_UND_SECTION_NAME) == 0) + { + return &bfd_und_section; + } + + if (strcmp(name, BFD_IND_SECTION_NAME) == 0) + { + return &bfd_ind_section; + } + + while (sect) { + if (!strcmp(sect->name, name)) return NULL; + sect = sect->next; + } + + /* The name is not already used; go ahead and make a new section. */ + return bfd_make_section_anyway (abfd, name); +} + + +/* +FUNCTION + bfd_set_section_flags + +SYNOPSIS + boolean bfd_set_section_flags(bfd *, asection *, flagword); + +DESCRIPTION + Attempts to set the attributes of the section named in the BFD + supplied to the value. Returns true on success, false on + error. Possible error returns are: + + o invalid operation - + The section cannot have one or more of the attributes + requested. For example, a .bss section in <<a.out>> may not + have the <<SEC_HAS_CONTENTS>> field set. + +*/ + +boolean +DEFUN(bfd_set_section_flags,(abfd, section, flags), + bfd *abfd AND + sec_ptr section AND + flagword flags) +{ +#if 0 + /* If you try to copy a text section from an input file (where it + has the SEC_CODE flag set) to an output file, this loses big if + the bfd_applicable_section_flags (abfd) doesn't have the SEC_CODE + set - which it doesn't, at least not for a.out. FIXME */ + + if ((flags & bfd_applicable_section_flags (abfd)) != flags) { + bfd_error = invalid_operation; + return false; + } +#endif + + section->flags = flags; + return true; +} + + +/* +FUNCTION + bfd_map_over_sections + +SYNOPSIS + void bfd_map_over_sections(bfd *abfd, + void (*func)(bfd *abfd, + asection *sect, + PTR obj), + PTR obj); + +DESCRIPTION + Calls the provided function @var{func} for each section + attached to the BFD @var{abfd}, passing @var{obj} as an + argument. The function will be called as if by + +| func(abfd, the_section, obj); + + This is the prefered method for iterating over sections, an + alternative would be to use a loop: + +| section *p; +| for (p = abfd->sections; p != NULL; p = p->next) +| func(abfd, p, ...) + + +*/ + +/*VARARGS2*/ +void +DEFUN(bfd_map_over_sections,(abfd, operation, user_storage), + bfd *abfd AND + void (*operation) PARAMS ((bfd *abfd, asection *sect, PTR obj)) AND + PTR user_storage) +{ + asection *sect; + int i = 0; + + for (sect = abfd->sections; sect != NULL; i++, sect = sect->next) + (*operation) (abfd, sect, user_storage); + + if (i != abfd->section_count) /* Debugging */ + abort(); +} + + +/* +FUNCTION + bfd_set_section_size + +SYNOPSIS + boolean bfd_set_section_size(bfd *, asection *, bfd_size_type val); + +DESCRIPTION + Sets @var{section} to the size @var{val}. If the operation is + ok, then <<true>> is returned, else <<false>>. + + Possible error returns: + o invalid_operation - + Writing has started to the BFD, so setting the size is invalid + +*/ + +boolean +DEFUN(bfd_set_section_size,(abfd, ptr, val), + bfd *abfd AND + sec_ptr ptr AND + bfd_size_type val) +{ + /* Once you've started writing to any section you cannot create or change + the size of any others. */ + + if (abfd->output_has_begun) { + bfd_error = invalid_operation; + return false; + } + + ptr->_cooked_size = val; + ptr->_raw_size = val; + + return true; +} + +/* +FUNCTION + bfd_set_section_contents + +SYNOPSIS + boolean bfd_set_section_contents + (bfd *abfd, + asection *section, + PTR data, + file_ptr offset, + bfd_size_type count); + + +DESCRIPTION + Sets the contents of the section @var{section} in BFD + @var{abfd} to the data starting in memory at @var{data}. The + data is written to the output section starting at offset + @var{offset} for @var{count} bytes. + + + + Normally <<true>> is returned, else <<false>>. Possible error + returns are: + o no_contents - + The output section does not have the <<SEC_HAS_CONTENTS>> + attribute, so nothing can be written to it. + o and some more too + + This routine is front end to the back end function + <<_bfd_set_section_contents>>. + + +*/ + +#define bfd_get_section_size_now(abfd,sec) \ +(sec->reloc_done \ + ? bfd_get_section_size_after_reloc (sec) \ + : bfd_get_section_size_before_reloc (sec)) + +boolean +DEFUN(bfd_set_section_contents,(abfd, section, location, offset, count), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + bfd_size_type sz; + + if (!bfd_get_section_flags(abfd, section) & SEC_HAS_CONTENTS) + { + bfd_error = no_contents; + return(false); + } + + if (offset < 0) + { + bad_val: + bfd_error = bad_value; + return false; + } + sz = bfd_get_section_size_now (abfd, section); + if (offset > sz + || count > sz + || offset + count > sz) + goto bad_val; + + switch (abfd->direction) + { + case read_direction: + case no_direction: + bfd_error = invalid_operation; + return false; + + case write_direction: + break; + + case both_direction: + /* File is opened for update. `output_has_begun' some time ago when + the file was created. Do not recompute sections sizes or alignments + in _bfd_set_section_content. */ + abfd->output_has_begun = true; + break; + } + + if (BFD_SEND (abfd, _bfd_set_section_contents, + (abfd, section, location, offset, count))) + { + abfd->output_has_begun = true; + return true; + } + + return false; +} + +/* +FUNCTION + bfd_get_section_contents + +SYNOPSIS + boolean bfd_get_section_contents + (bfd *abfd, asection *section, PTR location, + file_ptr offset, bfd_size_type count); + +DESCRIPTION + This function reads data from @var{section} in BFD @var{abfd} + into memory starting at @var{location}. The data is read at an + offset of @var{offset} from the start of the input section, + and is read for @var{count} bytes. + + If the contents of a constuctor with the <<SEC_CONSTUCTOR>> + flag set are requested, then the @var{location} is filled with + zeroes. If no errors occur, <<true>> is returned, else + <<false>>. + + + +*/ +boolean +DEFUN(bfd_get_section_contents,(abfd, section, location, offset, count), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + bfd_size_type sz; + + if (section->flags & SEC_CONSTRUCTOR) + { + memset(location, 0, (unsigned)count); + return true; + } + + if (offset < 0) + { + bad_val: + bfd_error = bad_value; + return false; + } + sz = bfd_get_section_size_now (abfd, section); + if (offset > sz + || count > sz + || offset + count > sz) + goto bad_val; + + if (count == 0) + /* Don't bother. */ + return true; + + return BFD_SEND (abfd, _bfd_get_section_contents, + (abfd, section, location, offset, count)); +} diff --git a/gnu/usr.bin/gdb/bfd/srec.c b/gnu/usr.bin/gdb/bfd/srec.c new file mode 100644 index 00000000000..3fc7d0b3f16 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/srec.c @@ -0,0 +1,1004 @@ +/* BFD back-end for s-record objects. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: srec.c,v 1.1 1995/10/18 08:39:54 deraadt Exp $ +*/ + +/* +SUBSECTION + S-Record handling + +DESCRIPTION + + Ordinary S-Records cannot hold anything but addresses and + data, so that's all that we implement. + + The only interesting thing is that S-Records may come out of + order and there is no header, so an initial scan is required + to discover the minimum and maximum addresses used to create + the vma and size of the only section we create. We + arbitrarily call this section ".text". + + When bfd_get_section_contents is called the file is read + again, and this time the data is placed into a bfd_alloc'd + area. + + Any number of sections may be created for output, we save them + up and output them when it's time to close the bfd. + + An s record looks like: + +EXAMPLE + S<type><length><address><data><checksum> + +DESCRIPTION + Where + o length + is the number of bytes following upto the checksum. Note that + this is not the number of chars following, since it takes two + chars to represent a byte. + o type + is one of: + 0) header record + 1) two byte address data record + 2) three byte address data record + 3) four byte address data record + 7) four byte address termination record + 8) three byte address termination record + 9) two byte address termination record + + o address + is the start address of the data following, or in the case of + a termination record, the start address of the image + o data + is the data. + o checksum + is the sum of all the raw byte data in the record, from the length + upwards, modulo 256 and subtracted from 255. + + +SUBSECTION + Symbol S-Record handling + +DESCRIPTION + Some ICE equipment understands an addition to the standard + S-Record format; symbols and their addresses can be sent + before the data. + + The format of this is: + ($$ <modulename> + (<space> <symbol> <address>)*) + $$ + + so a short symbol table could look like: + +EXAMPLE + $$ flash.x + $$ flash.c + _port6 $0 + _delay $4 + _start $14 + _etext $8036 + _edata $8036 + _end $8036 + $$ + +DESCRIPTION + We allow symbols to be anywhere in the data stream - the module names + are always ignored. + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* Macros for converting between hex and binary */ + +static CONST char digs[] = "0123456789ABCDEF"; + +static char hex_value[1 + (unsigned char)~0]; + +#define NOT_HEX 20 +#define NIBBLE(x) hex_value[(unsigned char)(x)] +#define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1])) +#define TOHEX(d, x, ch) \ + d[1] = digs[(x) & 0xf]; \ + d[0] = digs[((x)>>4)&0xf]; \ + ch += ((x) & 0xff); +#define ISHEX(x) (hex_value[(unsigned char)(x)] != NOT_HEX) + + + +static void +DEFUN_VOID(srec_init) +{ + unsigned int i; + static boolean inited = false; + + if (inited == false) + { + + inited = true; + + for (i = 0; i < sizeof (hex_value); i++) + { + hex_value[i] = NOT_HEX; + } + + for (i = 0; i < 10; i++) + { + hex_value[i + '0'] = i; + + } + for (i = 0; i < 6; i++) + { + hex_value[i + 'a'] = i+10; + hex_value[i + 'A'] = i+10; + } + } +} + + +/* The maximum number of bytes on a line is FF */ +#define MAXCHUNK 0xff +/* The number of bytes we fit onto a line on output */ +#define CHUNK 21 + +/* We cannot output our srecords as we see them, we have to glue them + together, this is done in this structure : */ + +struct srec_data_list_struct +{ + unsigned char *data; + bfd_vma where; + bfd_size_type size; + struct srec_data_list_struct *next; + + +} ; +typedef struct srec_data_list_struct srec_data_list_type; + + +typedef struct srec_data_struct +{ + srec_data_list_type *head; + unsigned int type; + + int done_symbol_read; + int count; + asymbol *symbols; + char *strings; + int symbol_idx; + int string_size; + int string_idx; +} tdata_type; + + +/* + called once per input S-Record, used to work out vma and size of data. + */ + +static bfd_vma low,high; + +static void +size_symbols(abfd, buf, len, val) +bfd *abfd; +char *buf; +int len; +int val; +{ + abfd->symcount ++; + abfd->tdata.srec_data->string_size += len + 1; +} + +static void +fillup_symbols(abfd, buf, len, val) +bfd *abfd; +char *buf; +int len; +int val; +{ + if (!abfd->tdata.srec_data->done_symbol_read) + { + asymbol *p; + if (abfd->tdata.srec_data->symbols == 0) + { + abfd->tdata.srec_data->symbols = (asymbol *)bfd_alloc(abfd, abfd->symcount * sizeof(asymbol)); + abfd->tdata.srec_data->strings = (char*)bfd_alloc(abfd, abfd->tdata.srec_data->string_size); + abfd->tdata.srec_data->symbol_idx = 0; + abfd->tdata.srec_data->string_idx = 0; + } + + p = abfd->tdata.srec_data->symbols + abfd->tdata.srec_data->symbol_idx++; + p->the_bfd = abfd; + p->name = abfd->tdata.srec_data->strings + abfd->tdata.srec_data->string_idx; + memcpy((char *)(p->name), buf, len+1); + abfd->tdata.srec_data->string_idx += len + 1; + p->value = val; + p->flags = BSF_EXPORT | BSF_GLOBAL; + p->section = &bfd_abs_section; + p->udata = 0; + } +} +static void +DEFUN(size_srec,(abfd, section, address, raw, length), + bfd *abfd AND + asection *section AND + bfd_vma address AND + bfd_byte *raw AND + unsigned int length) +{ + if (address < low) + low = address; + if (address + length > high) + high = address + length -1; +} + + +/* + called once per input S-Record, copies data from input into bfd_alloc'd area + */ + +static void +DEFUN(fillup,(abfd, section, address, raw, length), +bfd *abfd AND +asection *section AND +bfd_vma address AND +bfd_byte *raw AND +unsigned int length) +{ + unsigned int i; + bfd_byte *dst = + (bfd_byte *)(section->used_by_bfd) + address - section->vma; + /* length -1 because we don't read in the checksum */ + for (i = 0; i < length -1 ; i++) { + *dst = HEX(raw); + dst++; + raw+=2; + } +} + +/* Pass over an S-Record file, calling one of the above functions on each + record. */ + +static int white(x) +char x; +{ +return (x== ' ' || x == '\t' || x == '\n' || x == '\r'); +} +static int +skipwhite(src,abfd) +char *src; +bfd *abfd; +{ + int eof = 0; + while (white(*src) && !eof) + { + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + } + return eof; +} + +static boolean +DEFUN(srec_mkobject, (abfd), + bfd *abfd) +{ + if (abfd->tdata.srec_data == 0) + { + tdata_type *tdata = (tdata_type *)bfd_alloc(abfd, sizeof(tdata_type)); + abfd->tdata.srec_data = tdata; + tdata->type = 1; + tdata->head = (srec_data_list_type *)NULL; + } + return true; + +} + +static void +DEFUN(pass_over,(abfd, func, symbolfunc, section), + bfd *abfd AND + void (*func)() AND + void (*symbolfunc)() AND + asection *section) +{ + unsigned int bytes_on_line; + boolean eof = false; + + srec_mkobject(abfd); + /* To the front of the file */ + bfd_seek(abfd, (file_ptr)0, SEEK_SET); + while (eof == false) + { + char buffer[MAXCHUNK]; + char *src = buffer; + char type; + bfd_vma address = 0; + + /* Find first 'S' or $ */ + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + switch (*src) + { + default: + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + if (eof) return; + break; + + case '$': + /* Inside a symbol definition - just ignore the module name */ + while (*src != '\n' && !eof) + { + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + } + break; + + case ' ': + /* spaces - maybe just before a symbol */ + while (*src != '\n' && white(*src)) { + eof = skipwhite(src, abfd); + +{ + int val = 0; + int slen = 0; + char symbol[MAXCHUNK]; + + /* get the symbol part */ + while (!eof && !white(*src) && slen < MAXCHUNK) + { + symbol[slen++] = *src; + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + } + symbol[slen] = 0; + eof = skipwhite(src, abfd); + /* skip the $ for the hex value */ + if (*src == '$') + { + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + } + + /* Scan off the hex number */ + while (isxdigit(*src )) + { + val *= 16; + if (isdigit(*src)) + val += *src - '0'; + else if (isupper(*src)) { + val += *src - 'A' + 10; + } + else { + val += *src - 'a' + 10; + } + eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); + } + symbolfunc(abfd, symbol, slen, val); + } +} + break; + case 'S': + src++; + + /* Fetch the type and the length */ + bfd_read(src, 1, 3, abfd); + + type = *src++; + + if (!ISHEX (src[0]) || !ISHEX (src[1])) + break; + + bytes_on_line = HEX(src); + + if (bytes_on_line > MAXCHUNK/2) + break; + src+=2 ; + + bfd_read(src, 1 , bytes_on_line * 2, abfd); + + switch (type) { + case '0': + case '5': + /* Prologue - ignore */ + break; + case '3': + address = HEX(src); + src+=2; + bytes_on_line--; + + case '2': + address = HEX(src) | (address<<8) ; + src+=2; + bytes_on_line--; + case '1': + address = HEX(src) | (address<<8) ; + src+=2; + address = HEX(src) | (address<<8) ; + src+=2; + bytes_on_line-=2; + func(abfd,section, address, src, bytes_on_line); + break; + default: + return; + } + } + } + +} + +static bfd_target * +object_p(abfd) +bfd *abfd; +{ + asection *section; + /* We create one section called .text for all the contents, + and allocate enough room for the entire file. */ + + section = bfd_make_section(abfd, ".text"); + section->_raw_size = 0; + section->vma = 0xffffffff; + low = 0xffffffff; + high = 0; + pass_over(abfd, size_srec, size_symbols, section); + section->_raw_size = high - low; + section->vma = low; + section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; + + if (abfd->symcount) + abfd->flags |= HAS_SYMS; + return abfd->xvec; +} + +static bfd_target * +DEFUN(srec_object_p, (abfd), + bfd *abfd) +{ + char b[4]; + + srec_init(); + + bfd_seek(abfd, (file_ptr)0, SEEK_SET); + bfd_read(b, 1, 4, abfd); + + if (b[0] != 'S' || !ISHEX(b[1]) || !ISHEX(b[2]) || !ISHEX(b[3])) + return (bfd_target*) NULL; + + /* We create one section called .text for all the contents, + and allocate enough room for the entire file. */ + + return object_p(abfd); +} + + +static bfd_target * +DEFUN(symbolsrec_object_p, (abfd), + bfd *abfd) +{ + char b[4]; + + srec_init(); + + bfd_seek(abfd, (file_ptr)0, SEEK_SET); + bfd_read(b, 1, 4, abfd); + + if (b[0] != '$' || b[1] != '$') + return (bfd_target*) NULL; + + return object_p(abfd); +} + + +static boolean +DEFUN(srec_get_section_contents,(abfd, section, location, offset, count), + bfd *abfd AND + asection *section AND + PTR location AND + file_ptr offset AND + bfd_size_type count) +{ + if (section->used_by_bfd == (PTR)NULL) + { + section->used_by_bfd = (PTR)bfd_alloc (abfd, section->_raw_size); + + pass_over(abfd, fillup, fillup_symbols, section); + } + (void) memcpy((PTR)location, + (PTR)((char *)(section->used_by_bfd) + offset), + count); + return true; +} + + + +boolean +DEFUN(srec_set_arch_mach,(abfd, arch, machine), + bfd *abfd AND + enum bfd_architecture arch AND + unsigned long machine) +{ + return bfd_default_set_arch_mach(abfd, arch, machine); +} + + +/* we have to save up all the Srecords for a splurge before output, + also remember */ + +static boolean +DEFUN(srec_set_section_contents,(abfd, section, location, offset, bytes_to_do), + bfd *abfd AND + sec_ptr section AND + PTR location AND + file_ptr offset AND + bfd_size_type bytes_to_do) +{ + tdata_type *tdata = abfd->tdata.srec_data; + srec_data_list_type *entry = (srec_data_list_type *) + bfd_alloc(abfd, sizeof(srec_data_list_type)); + + if ((section->flags & SEC_ALLOC) + && (section->flags & SEC_LOAD)) + { + unsigned char *data = (unsigned char *) bfd_alloc(abfd, bytes_to_do); + memcpy(data, location, bytes_to_do); + + if ((section->lma + offset + bytes_to_do) <= 0xffff) + { + + } + else if ((section->lma + offset + bytes_to_do) <= 0xffffff + && tdata->type < 2) + { + tdata->type = 2; + } + else + { + tdata->type = 3; + } + + entry->data = data; + entry->where = section->lma + offset; + entry->size = bytes_to_do; + entry->next = tdata->head; + tdata->head = entry; + } + return true; +} + +/* Write a record of type, of the supplied number of bytes. The + supplied bytes and length don't have a checksum. That's worked out + here +*/ +static +void DEFUN(srec_write_record,(abfd, type, address, data, end), + bfd *abfd AND + char type AND + bfd_vma address AND + CONST unsigned char *data AND + CONST unsigned char *end) + +{ + char buffer[MAXCHUNK]; + + unsigned int check_sum = 0; + unsigned CONST char *src = data; + char *dst =buffer; + char *length; + + + *dst++ = 'S'; + *dst++ = '0' + type; + + length = dst; + dst+=2; /* leave room for dst*/ + + switch (type) + { + case 3: + case 7: + TOHEX(dst, (address >> 24), check_sum); + dst+=2; + case 8: + case 2: + TOHEX(dst, (address >> 16), check_sum); + dst+=2; + case 9: + case 1: + case 0: + TOHEX(dst, (address >> 8), check_sum); + dst+=2; + TOHEX(dst, (address), check_sum); + dst+=2; + break; + + } + for (src = data; src < end; src++) + { + TOHEX(dst, *src, check_sum); + dst+=2; + } + + /* Fill in the length */ + TOHEX(length, (dst - length)/2, check_sum); + check_sum &= 0xff; + check_sum = 255 - check_sum; + TOHEX(dst, check_sum, check_sum); + dst+=2; + + *dst ++ = '\r'; + *dst ++ = '\n'; + bfd_write((PTR)buffer, 1, dst - buffer , abfd); +} + + + +static void +DEFUN(srec_write_header,(abfd), + bfd *abfd) +{ + unsigned char buffer[MAXCHUNK]; + unsigned char *dst = buffer; + unsigned int i; + + /* I'll put an arbitary 40 char limit on header size */ + for (i = 0; i < 40 && abfd->filename[i]; i++) + { + *dst++ = abfd->filename[i]; + } + srec_write_record(abfd,0, 0, buffer, dst); +} + +static void +DEFUN(srec_write_section,(abfd, tdata, list), + bfd *abfd AND + tdata_type *tdata AND + srec_data_list_type *list) +{ + unsigned int bytes_written = 0; + unsigned char *location = list->data; + + while (bytes_written < list->size) + { + bfd_vma address; + + unsigned int bytes_this_chunk = list->size - bytes_written; + + if (bytes_this_chunk > CHUNK) + { + bytes_this_chunk = CHUNK; + } + + address = list->where + bytes_written; + + srec_write_record(abfd, + tdata->type, + address, + location, + location + bytes_this_chunk); + + bytes_written += bytes_this_chunk; + location += bytes_this_chunk; + } + +} + +static void +DEFUN(srec_write_terminator,(abfd, tdata), + bfd *abfd AND + tdata_type *tdata) +{ + unsigned char buffer[2]; + + srec_write_record(abfd, 10 - tdata->type, + abfd->start_address, buffer, buffer); +} + + + +static void +srec_write_symbols(abfd) + bfd *abfd; +{ + char buffer[MAXCHUNK]; + /* Dump out the symbols of a bfd */ + int i; + int len = bfd_get_symcount(abfd); + + if (len) + { + asymbol **table = bfd_get_outsymbols(abfd); + sprintf(buffer, "$$ %s\r\n", abfd->filename); + + bfd_write(buffer, strlen(buffer), 1, abfd); + + for (i = 0; i < len; i++) + { + asymbol *s = table[i]; +#if 0 + int len = strlen(s->name); + + /* If this symbol has a .[ocs] in it, it's probably a file name + and we'll output that as the module name */ + + if (len > 3 && s->name[len-2] == '.') + { + int l; + sprintf(buffer, "$$ %s\r\n", s->name); + l = strlen(buffer); + bfd_write(buffer, l, 1, abfd); + } + else +#endif + if (s->flags & (BSF_GLOBAL | BSF_LOCAL) + && (s->flags & BSF_DEBUGGING) == 0 + && s->name[0] != '.' + && s->name[0] != 't') + { + /* Just dump out non debug symbols */ + + int l; + char buf2[40], *p; + + sprintf_vma (buf2, s->value + s->section->lma); + p = buf2; + while (p[0] == '0' && p[1] != 0) + p++; + sprintf (buffer, " %s $%s\r\n", s->name, p); + l = strlen(buffer); + bfd_write(buffer, l, 1,abfd); + } + } + sprintf(buffer, "$$ \r\n"); + bfd_write(buffer, strlen(buffer), 1, abfd); + } +} + +static boolean +internal_srec_write_object_contents(abfd, symbols) + bfd *abfd; + int symbols; +{ + int bytes_written; + tdata_type *tdata = abfd->tdata.srec_data; + srec_data_list_type *list; + + bytes_written = 0; + + + if (symbols) + srec_write_symbols(abfd); + + srec_write_header(abfd); + + /* Now wander though all the sections provided and output them */ + list = tdata->head; + + while (list != (srec_data_list_type*)NULL) + { + srec_write_section(abfd, tdata, list); + list = list->next; + } + srec_write_terminator(abfd, tdata); + return true; +} + +static boolean +srec_write_object_contents(abfd) + bfd *abfd; +{ + return internal_srec_write_object_contents(abfd, 0); +} + +static boolean +symbolsrec_write_object_contents(abfd) + bfd *abfd; +{ + return internal_srec_write_object_contents(abfd, 1); +} + +static int +DEFUN(srec_sizeof_headers,(abfd, exec), + bfd *abfd AND + boolean exec) +{ +return 0; +} + +static asymbol * +DEFUN(srec_make_empty_symbol, (abfd), + bfd*abfd) +{ + asymbol *new= (asymbol *)bfd_zalloc (abfd, sizeof (asymbol)); + new->the_bfd = abfd; + return new; +} + +static unsigned int +srec_get_symtab_upper_bound(abfd) +bfd *abfd; +{ + /* Read in all the info */ + srec_get_section_contents(abfd,abfd->sections,0,0,0); + return (bfd_get_symcount(abfd) + 1) * (sizeof(asymbol *)); +} + +static unsigned int +DEFUN(srec_get_symtab, (abfd, alocation), + bfd *abfd AND + asymbol **alocation) +{ + int lim = abfd->symcount; + int i; + for (i = 0; i < lim; i++) { + alocation[i] = abfd->tdata.srec_data->symbols + i; + } + alocation[i] = 0; + return lim; +} + +void +DEFUN(srec_get_symbol_info,(ignore_abfd, symbol, ret), + bfd *ignore_abfd AND + asymbol *symbol AND + symbol_info *ret) +{ + bfd_symbol_info (symbol, ret); +} + +void +DEFUN(srec_print_symbol,(ignore_abfd, afile, symbol, how), + bfd *ignore_abfd AND + PTR afile AND + asymbol *symbol AND + bfd_print_symbol_type how) +{ + FILE *file = (FILE *)afile; + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + default: + bfd_print_symbol_vandf ((PTR) file, symbol); + fprintf (file, " %-5s %s", + symbol->section->name, + symbol->name); + + } +} + +#define FOO PROTO +#define srec_new_section_hook (FOO(boolean, (*), (bfd *, asection *)))bfd_true + +#define srec_get_reloc_upper_bound (FOO(unsigned int, (*),(bfd*, asection *)))bfd_false +#define srec_canonicalize_reloc (FOO(unsigned int, (*),(bfd*,asection *, arelent **, asymbol **))) bfd_0 + + + +#define srec_openr_next_archived_file (FOO(bfd *, (*), (bfd*,bfd*))) bfd_nullvoidptr +#define srec_find_nearest_line (FOO(boolean, (*),(bfd*,asection*,asymbol**,bfd_vma, CONST char**, CONST char**, unsigned int *))) bfd_false +#define srec_generic_stat_arch_elt (FOO(int, (*), (bfd *,struct stat *))) bfd_0 + + +#define srec_core_file_failing_command (char *(*)())(bfd_nullvoidptr) +#define srec_core_file_failing_signal (int (*)())bfd_0 +#define srec_core_file_matches_executable_p (FOO(boolean, (*),(bfd*, bfd*)))bfd_false +#define srec_slurp_armap bfd_true +#define srec_slurp_extended_name_table bfd_true +#define srec_truncate_arname (void (*)())bfd_nullvoidptr +#define srec_write_armap (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, unsigned int, int))) bfd_nullvoidptr +#define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr +#define srec_close_and_cleanup bfd_generic_close_and_cleanup +#define srec_bfd_debug_info_start bfd_void +#define srec_bfd_debug_info_end bfd_void +#define srec_bfd_debug_info_accumulate (FOO(void, (*), (bfd *, asection *))) bfd_void +#define srec_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents +#define srec_bfd_relax_section bfd_generic_relax_section +#define srec_bfd_seclet_link bfd_generic_seclet_link +#define srec_bfd_reloc_type_lookup \ + ((CONST struct reloc_howto_struct *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr) +#define srec_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) + +bfd_target srec_vec = +{ + "srec", /* name */ + bfd_target_srec_flavour, + true, /* target byte order */ + true, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS + |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + 1, /* minimum alignment */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + srec_object_p, /* bfd_check_format */ + (struct bfd_target *(*)()) bfd_nullvoidptr, + (struct bfd_target *(*)()) bfd_nullvoidptr, + }, + { + bfd_false, + srec_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + srec_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + JUMP_TABLE(srec) + }; + + + +bfd_target symbolsrec_vec = +{ + "symbolsrec", /* name */ + bfd_target_srec_flavour, + true, /* target byte order */ + true, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS + |SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + 1, /* minimum alignment */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + symbolsrec_object_p, /* bfd_check_format */ + (struct bfd_target *(*)()) bfd_nullvoidptr, + (struct bfd_target *(*)()) bfd_nullvoidptr, + }, + { + bfd_false, + srec_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + symbolsrec_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + JUMP_TABLE(srec), + (PTR) 0 + }; + diff --git a/gnu/usr.bin/gdb/bfd/stab-syms.c b/gnu/usr.bin/gdb/bfd/stab-syms.c new file mode 100644 index 00000000000..107d9c951d1 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/stab-syms.c @@ -0,0 +1,62 @@ +/* Table of stab names for the BFD library. + Copyright (C) 1990-1991 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: stab-syms.c,v 1.1 1995/10/18 08:39:54 deraadt Exp $ +*/ + +#include "bfd.h" + +#define ARCH_SIZE 32 /* Value doesn't matter. */ +#include "libaout.h" +#include "aout/aout64.h" + +/* Create a table of debugging stab-codes and corresponding names. */ + +#define __define_name(CODE, STRING) {(int)CODE, STRING}, +#define __define_stab(NAME, CODE, STRING) __define_name(CODE, STRING) +CONST struct {short code; char string[10];} aout_stab_names[] + = { +#include "aout/stab.def" + +/* These are not really stab symbols, but it is + convenient to have them here for the sake of nm. + For completeness, we could also add N_TEXT etc, but those + are never needed, since nm treats those specially. */ +__define_name (N_SETA, "SETA") /* Absolute set element symbol */ +__define_name (N_SETT, "SETT") /* Text set element symbol */ +__define_name (N_SETD, "SETD") /* Data set element symbol */ +__define_name (N_SETB, "SETB") /* Bss set element symbol */ +__define_name (N_SETV, "SETV") /* Pointer to set vector in data area. */ +__define_name (N_INDR, "INDR") +__define_name (N_WARNING, "WARNING") + }; +#undef __define_stab +#undef GNU_EXTRA_STABS + +CONST char * +DEFUN(aout_stab_name,(code), +int code) +{ + register int i = sizeof(aout_stab_names) / sizeof(aout_stab_names[0]); + while (--i >= 0) + if (aout_stab_names[i].code == code) + return aout_stab_names[i].string; + return 0; +} diff --git a/gnu/usr.bin/gdb/bfd/syms.c b/gnu/usr.bin/gdb/bfd/syms.c new file mode 100644 index 00000000000..17fff20c2c5 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/syms.c @@ -0,0 +1,530 @@ +/* Generic symbol-table support for the BFD library. + Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: syms.c,v 1.1 1995/10/18 08:39:54 deraadt Exp $ +*/ + +/* +SECTION + Symbols + + BFD trys to maintain as much symbol information as it can when + it moves information from file to file. BFD passes information + to applications though the <<asymbol>> structure. When the + application requests the symbol table, BFD reads the table in + the native form and translates parts of it into the internal + format. To maintain more than the infomation passed to + applications some targets keep some information `behind the + scenes', in a structure only the particular back end knows + about. For example, the coff back end keeps the original + symbol table structure as well as the canonical structure when + a BFD is read in. On output, the coff back end can reconstruct + the output symbol table so that no information is lost, even + information unique to coff which BFD doesn't know or + understand. If a coff symbol table was read, but was written + through an a.out back end, all the coff specific information + would be lost. The symbol table of a BFD + is not necessarily read in until a canonicalize request is + made. Then the BFD back end fills in a table provided by the + application with pointers to the canonical information. To + output symbols, the application provides BFD with a table of + pointers to pointers to <<asymbol>>s. This allows applications + like the linker to output a symbol as read, since the `behind + the scenes' information will be still available. +@menu +@* Reading Symbols:: +@* Writing Symbols:: +@* typedef asymbol:: +@* symbol handling functions:: +@end menu + +INODE +Reading Symbols, Writing Symbols, Symbols, Symbols +SUBSECTION + Reading Symbols + + There are two stages to reading a symbol table from a BFD; + allocating storage, and the actual reading process. This is an + excerpt from an appliction which reads the symbol table: + +| unsigned int storage_needed; +| asymbol **symbol_table; +| unsigned int number_of_symbols; +| unsigned int i; +| +| storage_needed = get_symtab_upper_bound (abfd); +| +| if (storage_needed == 0) { +| return ; +| } +| symbol_table = (asymbol **) bfd_xmalloc (storage_needed); +| ... +| number_of_symbols = +| bfd_canonicalize_symtab (abfd, symbol_table); +| +| for (i = 0; i < number_of_symbols; i++) { +| process_symbol (symbol_table[i]); +| } + + All storage for the symbols themselves is in an obstack + connected to the BFD, and is freed when the BFD is closed. + + +INODE +Writing Symbols, typedef asymbol, Reading Symbols, Symbols +SUBSECTION + Writing Symbols + + Writing of a symbol table is automatic when a BFD open for + writing is closed. The application attaches a vector of + pointers to pointers to symbols to the BFD being written, and + fills in the symbol count. The close and cleanup code reads + through the table provided and performs all the necessary + operations. The outputing code must always be provided with an + 'owned' symbol; one which has come from another BFD, or one + which has been created using <<bfd_make_empty_symbol>>. An + example showing the creation of a symbol table with only one element: + +| #include "bfd.h" +| main() +| { +| bfd *abfd; +| asymbol *ptrs[2]; +| asymbol *new; +| +| abfd = bfd_openw("foo","a.out-sunos-big"); +| bfd_set_format(abfd, bfd_object); +| new = bfd_make_empty_symbol(abfd); +| new->name = "dummy_symbol"; +| new->section = bfd_make_section_old_way(abfd, ".text"); +| new->flags = BSF_GLOBAL; +| new->value = 0x12345; +| +| ptrs[0] = new; +| ptrs[1] = (asymbol *)0; +| +| bfd_set_symtab(abfd, ptrs, 1); +| bfd_close(abfd); +| } +| +| ./makesym +| nm foo +| 00012345 A dummy_symbol + + Many formats cannot represent arbitary symbol information; for + instance the <<a.out>> object format does not allow an + arbitary number of sections. A symbol pointing to a section + which is not one of <<.text>>, <<.data>> or <<.bss>> cannot + be described. + +*/ + + + +/* +DOCDD +INODE +typedef asymbol, symbol handling functions, Writing Symbols, Symbols + +*/ +/* +SUBSECTION + typedef asymbol + + An <<asymbol>> has the form: + +*/ + +/* +CODE_FRAGMENT + +. +.typedef struct symbol_cache_entry +.{ +. {* A pointer to the BFD which owns the symbol. This information +. is necessary so that a back end can work out what additional +. information (invisible to the application writer) is carried +. with the symbol. +. +. This field is *almost* redundant, since you can use section->owner +. instead, except that some symbols point to the global sections +. bfd_{abs,com,und}_section. This could be fixed by making +. these globals be per-bfd (or per-target-flavor). FIXME. *} +. +. struct _bfd *the_bfd; {* Use bfd_asymbol_bfd(sym) to access this field. *} +. +. {* The text of the symbol. The name is left alone, and not copied - the +. application may not alter it. *} +. CONST char *name; +. +. {* The value of the symbol. This really should be a union of a +. numeric value with a pointer, since some flags indicate that +. a pointer to another symbol is stored here. *} +. symvalue value; +. +. {* Attributes of a symbol: *} +. +.#define BSF_NO_FLAGS 0x00 +. +. {* The symbol has local scope; <<static>> in <<C>>. The value +. is the offset into the section of the data. *} +.#define BSF_LOCAL 0x01 +. +. {* The symbol has global scope; initialized data in <<C>>. The +. value is the offset into the section of the data. *} +.#define BSF_GLOBAL 0x02 +. +. {* The symbol has global scope, and is exported. The value is +. the offset into the section of the data. *} +.#define BSF_EXPORT BSF_GLOBAL {* no real difference *} +. +. {* A normal C symbol would be one of: +. <<BSF_LOCAL>>, <<BSF_FORT_COMM>>, <<BSF_UNDEFINED>> or +. <<BSF_GLOBAL>> *} +. +. {* The symbol is a debugging record. The value has an arbitary +. meaning. *} +.#define BSF_DEBUGGING 0x08 +. +. {* The symbol denotes a function entry point. Used in ELF, +. perhaps others someday. *} +.#define BSF_FUNCTION 0x10 +. +. {* Used by the linker. *} +.#define BSF_KEEP 0x20 +.#define BSF_KEEP_G 0x40 +. +. {* A weak global symbol, overridable without warnings by +. a regular global symbol of the same name. *} +.#define BSF_WEAK 0x80 +. +. {* This symbol was created to point to a section, e.g. ELF's +. STT_SECTION symbols. *} +.#define BSF_SECTION_SYM 0x100 +. +. {* The symbol used to be a common symbol, but now it is +. allocated. *} +.#define BSF_OLD_COMMON 0x200 +. +. {* The default value for common data. *} +.#define BFD_FORT_COMM_DEFAULT_VALUE 0 +. +. {* In some files the type of a symbol sometimes alters its +. location in an output file - ie in coff a <<ISFCN>> symbol +. which is also <<C_EXT>> symbol appears where it was +. declared and not at the end of a section. This bit is set +. by the target BFD part to convey this information. *} +. +.#define BSF_NOT_AT_END 0x400 +. +. {* Signal that the symbol is the label of constructor section. *} +.#define BSF_CONSTRUCTOR 0x800 +. +. {* Signal that the symbol is a warning symbol. If the symbol +. is a warning symbol, then the value field (I know this is +. tacky) will point to the asymbol which when referenced will +. cause the warning. *} +.#define BSF_WARNING 0x1000 +. +. {* Signal that the symbol is indirect. The value of the symbol +. is a pointer to an undefined asymbol which contains the +. name to use instead. *} +.#define BSF_INDIRECT 0x2000 +. +. {* BSF_FILE marks symbols that contain a file name. This is used +. for ELF STT_FILE symbols. *} +.#define BSF_FILE 0x4000 +. +. flagword flags; +. +. {* A pointer to the section to which this symbol is +. relative. This will always be non NULL, there are special +. sections for undefined and absolute symbols *} +. struct sec *section; +. +. {* Back end special data. This is being phased out in favour +. of making this a union. *} +. PTR udata; +. +.} asymbol; +*/ + +#include "bfd.h" +#include "sysdep.h" + +#include "libbfd.h" +#include "aout/stab_gnu.h" + +/* +DOCDD +INODE +symbol handling functions, , typedef asymbol, Symbols +SUBSECTION + Symbol Handling Functions +*/ + +/* +FUNCTION + get_symtab_upper_bound + +DESCRIPTION + Returns the number of bytes required in a vector of pointers + to <<asymbols>> for all the symbols in the supplied BFD, + including a terminal NULL pointer. If there are no symbols in + the BFD, then 0 is returned. + +.#define get_symtab_upper_bound(abfd) \ +. BFD_SEND (abfd, _get_symtab_upper_bound, (abfd)) + +*/ + +/* +FUNCTION + bfd_canonicalize_symtab + +DESCRIPTION + Supplied a BFD and a pointer to an uninitialized vector of + pointers. This reads in the symbols from the BFD, and fills in + the table with pointers to the symbols, and a trailing NULL. + The routine returns the actual number of symbol pointers not + including the NULL. + + +.#define bfd_canonicalize_symtab(abfd, location) \ +. BFD_SEND (abfd, _bfd_canonicalize_symtab,\ +. (abfd, location)) + +*/ + + +/* +FUNCTION + bfd_set_symtab + +DESCRIPTION + Provided a table of pointers to symbols and a count, writes to + the output BFD the symbols when closed. + +SYNOPSIS + boolean bfd_set_symtab (bfd *, asymbol **, unsigned int ); +*/ + +boolean +bfd_set_symtab (abfd, location, symcount) + bfd *abfd; + asymbol **location; + unsigned int symcount; +{ + if ((abfd->format != bfd_object) || (bfd_read_p (abfd))) { + bfd_error = invalid_operation; + return false; + } + + bfd_get_outsymbols (abfd) = location; + bfd_get_symcount (abfd) = symcount; + return true; +} + +/* +FUNCTION + bfd_print_symbol_vandf + +DESCRIPTION + Prints the value and flags of the symbol supplied to the stream file. + +SYNOPSIS + void bfd_print_symbol_vandf(PTR file, asymbol *symbol); +*/ +void +DEFUN(bfd_print_symbol_vandf,(file, symbol), +PTR file AND +asymbol *symbol) +{ + flagword type = symbol->flags; + if (symbol->section != (asection *)NULL) + { + fprintf_vma(file, symbol->value+symbol->section->vma); + } + else + { + fprintf_vma(file, symbol->value); + } + fprintf(file," %c%c%c%c%c%c%c", + (type & BSF_LOCAL) ? 'l':' ', + (type & BSF_GLOBAL) ? 'g' : ' ', + (type & BSF_WEAK) ? 'w' : ' ', + (type & BSF_CONSTRUCTOR) ? 'C' : ' ', + (type & BSF_WARNING) ? 'W' : ' ', + (type & BSF_INDIRECT) ? 'I' : ' ', + (type & BSF_DEBUGGING) ? 'd' :' '); + +} + + +/* +FUNCTION + bfd_make_empty_symbol + +DESCRIPTION + This function creates a new <<asymbol>> structure for the BFD, + and returns a pointer to it. + + This routine is necessary, since each back end has private + information surrounding the <<asymbol>>. Building your own + <<asymbol>> and pointing to it will not create the private + information, and will cause problems later on. + +.#define bfd_make_empty_symbol(abfd) \ +. BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) +*/ + +/* +FUNCTION + bfd_make_debug_symbol + +DESCRIPTION + This function creates a new <<asymbol>> structure for the BFD, + to be used as a debugging symbol. Further details of its use have + yet to be worked out. + +.#define bfd_make_debug_symbol(abfd,ptr,size) \ +. BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) +*/ + +struct section_to_type +{ + CONST char *section; + char type; +}; + +/* Map COFF section names to POSIX/BSD single-character symbol types. + This table is probably incomplete. It is sorted for convenience of + adding entries. Since it is so short, a linear search is used. */ +static CONST struct section_to_type stt[] = { + {"*DEBUG*", 'N'}, + {".bss", 'b'}, + {".data", 'd'}, + {".sbss", 's'}, /* Small BSS (uninitialized data) */ + {".scommon", 'c'}, /* Small common */ + {".sdata", 'g'}, /* Small initialized data */ + {".text", 't'}, + {0, 0} +}; + +/* Return the single-character symbol type corresponding to + COFF section S, or '?' for an unknown COFF section. */ + +static char +coff_section_type (s) + char *s; +{ + CONST struct section_to_type *t; + + for (t = &stt[0]; t->section; t++) + if (!strcmp (s, t->section)) + return t->type; + return '?'; +} + +#ifndef islower +#define islower(c) ((c) >= 'a' && (c) <= 'z') +#endif +#ifndef toupper +#define toupper(c) (islower(c) ? ((c) & ~0x20) : (c)) +#endif + +/* +FUNCTION + bfd_decode_symclass + +DESCRIPTION + Return a character corresponding to the symbol + class of symbol, or '?' for an unknown class. + +SYNOPSIS + int bfd_decode_symclass(asymbol *symbol); +*/ +int +DEFUN(bfd_decode_symclass,(symbol), +asymbol *symbol) +{ + char c; + + if (bfd_is_com_section (symbol->section)) + return 'C'; + if (symbol->section == &bfd_und_section) + return 'U'; + if (symbol->section == &bfd_ind_section) + return 'I'; + if (!(symbol->flags & (BSF_GLOBAL|BSF_LOCAL))) + return '?'; + + if (symbol->section == &bfd_abs_section) + c = 'a'; + else if (symbol->section) + c = coff_section_type (symbol->section->name); + else + return '?'; + if (symbol->flags & BSF_GLOBAL) + c = toupper (c); + return c; + + /* We don't have to handle these cases just yet, but we will soon: + N_SETV: 'v'; + N_SETA: 'l'; + N_SETT: 'x'; + N_SETD: 'z'; + N_SETB: 's'; + N_INDR: 'i'; + */ +} + +/* +FUNCTION + bfd_symbol_info + +DESCRIPTION + Fill in the basic info about symbol that nm needs. + Additional info may be added by the back-ends after + calling this function. + +SYNOPSIS + void bfd_symbol_info(asymbol *symbol, symbol_info *ret); +*/ + +void +DEFUN(bfd_symbol_info,(symbol, ret), + asymbol *symbol AND + symbol_info *ret) +{ + ret->type = bfd_decode_symclass (symbol); + if (ret->type != 'U') + ret->value = symbol->value+symbol->section->vma; + else + ret->value = 0; + ret->name = symbol->name; +} + +void +bfd_symbol_is_absolute() +{ + abort(); +} + diff --git a/gnu/usr.bin/gdb/bfd/targets.c b/gnu/usr.bin/gdb/bfd/targets.c new file mode 100644 index 00000000000..ce1133b10e2 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/targets.c @@ -0,0 +1,645 @@ +/* Generic target-file-type support for the BFD library. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: targets.c,v 1.1 1995/10/18 08:39:54 deraadt Exp $ +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* +SECTION + Targets + +DESCRIPTION + Each port of BFD to a different machine requries the creation + of a target back end. All the back end provides to the root + part of BFD is a structure containing pointers to functions + which perform certain low level operations on files. BFD + translates the applications's requests through a pointer into + calls to the back end routines. + + When a file is opened with <<bfd_openr>>, its format and + target are unknown. BFD uses various mechanisms to determine + how to interpret the file. The operations performed are: + + o First a BFD is created by calling the internal routine + <<new_bfd>>, then <<bfd_find_target>> is called with the + target string supplied to <<bfd_openr>> and the new BFD pointer. + + o If a null target string was provided to <<bfd_find_target>>, + it looks up the environment variable <<GNUTARGET>> and uses + that as the target string. + + o If the target string is still NULL, or the target string is + <<default>>, then the first item in the target vector is used + as the target type, and <<target_defaulted>> is set to + cause <<bfd_check_format>> to loop through all the targets. + @xref{bfd_target}. @xref{Formats}. + + o Otherwise, the elements in the target vector are inspected + one by one, until a match on target name is found. When found, + that is used. + + o Otherwise the error <<invalid_target>> is returned to + <<bfd_openr>>. + + o <<bfd_openr>> attempts to open the file using + <<bfd_open_file>>, and returns the BFD. + + Once the BFD has been opened and the target selected, the file + format may be determined. This is done by calling + <<bfd_check_format>> on the BFD with a suggested format. + If <<target_defaulted>> has been set, each possible target + type is tried to see if it recognizes the specified format. The + routine returns <<true>> when the application guesses right. +@menu +@* bfd_target:: +@end menu +*/ + + +/* + +INODE + bfd_target, , Targets, Targets +DOCDD +SUBSECTION + bfd_target + +DESCRIPTION + This structure contains everything that BFD knows about a + target. It includes things like its byte order, name, what + routines to call to do various operations, etc. + + Every BFD points to a target structure with its <<xvec>> + member. + + These macros are used to dispatch to functions through the + bfd_target vector. They are used in a number of macros further + down in @file{bfd.h}, and are also used when calling various + routines by hand inside the BFD implementation. The "arglist" + argument must be parenthesized; it contains all the arguments + to the called function. + + They make the documentation (more) unpleasant to read, so if + someone wants to fix this and not break the above, please do. + +.#define BFD_SEND(bfd, message, arglist) \ +. ((*((bfd)->xvec->message)) arglist) + + For operations which index on the BFD format + +.#define BFD_SEND_FMT(bfd, message, arglist) \ +. (((bfd)->xvec->message[(int)((bfd)->format)]) arglist) + + This is the struct which defines the type of BFD this is. The + <<xvec>> member of the struct <<bfd>> itself points here. Each + module that implements access to a different target under BFD, + defines one of these. + + + FIXME, these names should be rationalised with the names of + the entry points which call them. Too bad we can't have one + macro to define them both! + +.typedef struct bfd_target +.{ + +Identifies the kind of target, eg SunOS4, Ultrix, etc. + +. char *name; + +The "flavour" of a back end is a general indication about the contents +of a file. + +. enum target_flavour { +. bfd_target_unknown_flavour, +. bfd_target_aout_flavour, +. bfd_target_coff_flavour, +. bfd_target_ecoff_flavour, +. bfd_target_elf_flavour, +. bfd_target_ieee_flavour, +. bfd_target_nlm_flavour, +. bfd_target_oasys_flavour, +. bfd_target_tekhex_flavour, +. bfd_target_srec_flavour, +. bfd_target_hppa_flavour} flavour; + +The order of bytes within the data area of a file. + +. boolean byteorder_big_p; + +The order of bytes within the header parts of a file. + +. boolean header_byteorder_big_p; + +This is a mask of all the flags which an executable may have set - +from the set <<NO_FLAGS>>, <<HAS_RELOC>>, ...<<D_PAGED>>. + +. flagword object_flags; + +This is a mask of all the flags which a section may have set - from +the set <<SEC_NO_FLAGS>>, <<SEC_ALLOC>>, ...<<SET_NEVER_LOAD>>. + +. flagword section_flags; + +The character normally found at the front of a symbol +(if any), perhaps _. + +. char symbol_leading_char; + +The pad character for filenames within an archive header. + +. char ar_pad_char; + +The maximum number of characters in an archive header. + +. unsigned short ar_max_namelen; + +The minimum alignment restriction for any section. + +. unsigned int align_power_min; + +Entries for byte swapping for data. These are different to the other +entry points, since they don't take BFD as first arg. Certain other handlers +could do the same. + +. bfd_vma (*bfd_getx64) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((bfd_byte *)); +. void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_getx32) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((bfd_byte *)); +. void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_getx16) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((bfd_byte *)); +. void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *)); + +Byte swapping for the headers + +. bfd_vma (*bfd_h_getx64) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((bfd_byte *)); +. void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_h_getx32) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((bfd_byte *)); +. void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_h_getx16) PARAMS ((bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((bfd_byte *)); +. void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *)); + +Format dependent routines: these are vectors of entry points +within the target vector structure, one for each format to check. + +Check the format of a file being read. Return bfd_target * or zero. + +. struct bfd_target * (*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *)); + +Set the format of a file being written. + +. boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *)); + +Write cached information into a file being written, at bfd_close. + +. boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *)); + +The following functions are defined in <<JUMP_TABLE>>. The idea is +that the back end writer of <<foo>> names all the routines +<<foo_>>@var{entry_point}, <<JUMP_TABLE>> will built the entries +in this structure in the right order. + +Core file entry points + +. char * (*_core_file_failing_command) PARAMS ((bfd *)); +. int (*_core_file_failing_signal) PARAMS ((bfd *)); +. boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *)); + +Archive entry points + +. boolean (*_bfd_slurp_armap) PARAMS ((bfd *)); +. boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *)); +. void (*_bfd_truncate_arname) PARAMS ((bfd *, CONST char *, char *)); +. boolean (*write_armap) PARAMS ((bfd *arch, +. unsigned int elength, +. struct orl *map, +. unsigned int orl_count, +. int stridx)); + +Standard stuff. + +. boolean (*_close_and_cleanup) PARAMS ((bfd *)); +. boolean (*_bfd_set_section_contents) PARAMS ((bfd *, sec_ptr, PTR, +. file_ptr, bfd_size_type)); +. boolean (*_bfd_get_section_contents) PARAMS ((bfd *, sec_ptr, PTR, +. file_ptr, bfd_size_type)); +. boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr)); + +Symbols and relocations + +. unsigned int (*_get_symtab_upper_bound) PARAMS ((bfd *)); +. unsigned int (*_bfd_canonicalize_symtab) PARAMS ((bfd *, +. struct symbol_cache_entry **)); +. unsigned int (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr)); +. unsigned int (*_bfd_canonicalize_reloc) PARAMS ((bfd *, sec_ptr, arelent **, +. struct symbol_cache_entry **)); +. struct symbol_cache_entry * +. (*_bfd_make_empty_symbol) PARAMS ((bfd *)); +. void (*_bfd_print_symbol) PARAMS ((bfd *, PTR, +. struct symbol_cache_entry *, +. bfd_print_symbol_type)); +.#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e)) +. void (*_bfd_get_symbol_info) PARAMS ((bfd *, +. struct symbol_cache_entry *, +. symbol_info *)); +.#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e)) + +. alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *)); +. +. boolean (*_bfd_set_arch_mach) PARAMS ((bfd *, enum bfd_architecture, +. unsigned long)); +. +. bfd * (*openr_next_archived_file) PARAMS ((bfd *arch, bfd *prev)); +. +. boolean (*_bfd_find_nearest_line) PARAMS ((bfd *abfd, +. struct sec *section, struct symbol_cache_entry **symbols, +. bfd_vma offset, CONST char **file, CONST char **func, +. unsigned int *line)); +. +. int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *)); +. +. int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean)); +. +. void (*_bfd_debug_info_start) PARAMS ((bfd *)); +. void (*_bfd_debug_info_end) PARAMS ((bfd *)); +. void (*_bfd_debug_info_accumulate) PARAMS ((bfd *, struct sec *)); +. +. bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *, +. struct bfd_seclet *, bfd_byte *data, +. boolean relocateable)); +. +. boolean (*_bfd_relax_section) PARAMS ((bfd *, struct sec *, +. struct symbol_cache_entry **)); +. +. boolean (*_bfd_seclet_link) PARAMS ((bfd *, PTR data, +. boolean relocateable)); + +. {* See documentation on reloc types. *} +. CONST struct reloc_howto_struct * +. (*reloc_type_lookup) PARAMS ((bfd *abfd, +. bfd_reloc_code_real_type code)); +. +. {* Back-door to allow format-aware applications to create debug symbols +. while using BFD for everything else. Currently used by the assembler +. when creating COFF files. *} +. asymbol * (*_bfd_make_debug_symbol) PARAMS (( +. bfd *abfd, +. void *ptr, +. unsigned long size)); + +Data for use by back-end routines, which isn't generic enough to belong +in this structure. + +. PTR backend_data; +.} bfd_target; + +*/ + +/* All known xvecs (even those that don't compile on all systems). + Alphabetized for easy reference. + They are listed a second time below, since + we can't intermix extern's and initializers. */ +extern bfd_target a29kcoff_big_vec; +extern bfd_target a_out_adobe_vec; +extern bfd_target aout_mips_big_vec; +extern bfd_target aout_mips_little_vec; +extern bfd_target apollocoff_vec; +extern bfd_target b_out_vec_big_host; +extern bfd_target b_out_vec_little_host; +extern bfd_target bfd_elf32_big_generic_vec; +extern bfd_target bfd_elf32_bigmips_vec; +extern bfd_target bfd_elf32_hppa_vec; +extern bfd_target bfd_elf32_i386_vec; +extern bfd_target bfd_elf32_i860_vec; +extern bfd_target bfd_elf32_little_generic_vec; +extern bfd_target bfd_elf32_littlemips_vec; +extern bfd_target bfd_elf32_m68k_vec; +extern bfd_target bfd_elf32_m88k_vec; +extern bfd_target bfd_elf32_sparc_vec; +extern bfd_target bfd_elf64_big_generic_vec; +extern bfd_target bfd_elf64_little_generic_vec; +extern bfd_target demo_64_vec; +extern bfd_target ecoff_big_vec; +extern bfd_target ecoff_little_vec; +extern bfd_target ecoffalpha_little_vec; +extern bfd_target h8300coff_vec; +extern bfd_target h8500coff_vec; +extern bfd_target host_aout_vec; +extern bfd_target hp300bsd_vec; +extern bfd_target hp300hpux_vec; +extern bfd_target hppa_vec; +extern bfd_target i386aout_vec; +extern bfd_target i386bsd_vec; +extern bfd_target i386coff_vec; +extern bfd_target i386linux_vec; +extern bfd_target i386lynx_aout_vec; +extern bfd_target i386lynx_coff_vec; +extern bfd_target icoff_big_vec; +extern bfd_target icoff_little_vec; +extern bfd_target ieee_vec; +extern bfd_target m68kcoff_vec; +extern bfd_target m68kcoffun_vec; +extern bfd_target m68klynx_aout_vec; +extern bfd_target m68klynx_coff_vec; +extern bfd_target m88kbcs_vec; +extern bfd_target newsos3_vec; +extern bfd_target nlm32_big_generic_vec; +extern bfd_target nlm32_i386_vec; +extern bfd_target nlm32_little_generic_vec; +extern bfd_target nlm64_big_generic_vec; +extern bfd_target nlm64_little_generic_vec; +extern bfd_target oasys_vec; +extern bfd_target rs6000coff_vec; +extern bfd_target shcoff_vec; +extern bfd_target sunos_big_vec; +extern bfd_target tekhex_vec; +extern bfd_target we32kcoff_vec; +extern bfd_target z8kcoff_vec; +extern bfd_target netbsd_386_vec; +extern bfd_target netbsd_sparc_vec; +extern bfd_target netbsd_m68k_vec; +extern bfd_target netbsd_m68k4k_vec; +extern bfd_target netbsd_ns32k_vec; +extern bfd_target netbsd_vax_vec; + +/* srec is always included. */ +extern bfd_target srec_vec; +extern bfd_target symbolsrec_vec; + +/* All of the xvecs for core files. */ +extern bfd_target aix386_core_vec; +extern bfd_target hpux_core_vec; +extern bfd_target osf_core_vec; +extern bfd_target sco_core_vec; +extern bfd_target netbsd_core_vec; +extern bfd_target trad_core_vec; + +bfd_target *target_vector[] = { + +#ifdef SELECT_VECS + + SELECT_VECS, + +#else /* not SELECT_VECS */ + +#ifdef DEFAULT_VECTOR + &DEFAULT_VECTOR, +#endif + /* This list is alphabetized to make it easy to compare + with other vector lists -- the decls above and + the case statement in configure.in. + Vectors that don't compile on all systems, or aren't finished, + should have an entry here with #if 0 around it, to show that + it wasn't omitted by mistake. */ + &a29kcoff_big_vec, + &a_out_adobe_vec, +#if 0 /* No one seems to use this. */ + &aout_mips_big_vec, +#endif + &aout_mips_little_vec, + &b_out_vec_big_host, + &b_out_vec_little_host, +#if 0 /* No one seems to use this. */ + &bfd_elf32_big_generic_vec, + &bfd_elf32_bigmips_vec, +#endif +#if 0 + &bfd_elf32_hppa_vec, +#endif + &bfd_elf32_i386_vec, + &bfd_elf32_i860_vec, +#if 0 /* No one seems to use this. */ + &bfd_elf32_little_generic_vec, + &bfd_elf32_littlemips_vec, +#endif + &bfd_elf32_m68k_vec, + &bfd_elf32_m88k_vec, + &bfd_elf32_sparc_vec, +#ifdef BFD64 /* No one seems to use this. */ + &bfd_elf64_big_generic_vec, + &bfd_elf64_little_generic_vec, +#endif +#ifdef BFD64 + &demo_64_vec, /* Only compiled if host has long-long support */ +#endif + &ecoff_big_vec, + &ecoff_little_vec, +#if 0 + &ecoffalpha_little_vec, +#endif + &h8300coff_vec, + &h8500coff_vec, +#if 0 + &host_aout_vec, +#endif +#if 0 /* Clashes with sunos_big_vec magic no. */ + &hp300bsd_vec, +#endif + &hp300hpux_vec, +#if defined (HOST_HPPAHPUX) || defined (HOST_HPPABSD) + &hppa_vec, +#endif + &i386aout_vec, + &i386bsd_vec, + &netbsd386_vec, + &i386coff_vec, +#if 0 + &i386linux_vec, +#endif + &i386lynx_aout_vec, + &i386lynx_coff_vec, + &icoff_big_vec, + &icoff_little_vec, + &ieee_vec, + &m68kcoff_vec, + &m68kcoffun_vec, + &m68klynx_aout_vec, + &m68klynx_coff_vec, + &m88kbcs_vec, + &newsos3_vec, +#if 0 /* No one seems to use this. */ + &nlm32_big_generic_vec, +#endif + &nlm32_i386_vec, +#if 0 /* No one seems to use this. */ + &nlm32_little_generic_vec, +#endif +#ifdef BFD64 + &nlm64_big_generic_vec, + &nlm64_little_generic_vec, +#endif +#if 0 + /* We have no oasys tools anymore, so we can't test any of this + anymore. If you want to test the stuff yourself, go ahead... + steve@cygnus.com + Worse, since there is no magic number for archives, there + can be annoying target mis-matches. */ + &oasys_vec, +#endif + &rs6000coff_vec, + &shcoff_vec, + &sunos_big_vec, +#if 0 + &tekhex_vec, +#endif + &we32kcoff_vec, + &z8kcoff_vec, + +#endif /* not SELECT_VECS */ + +/* Always support S-records, for convenience. */ + &srec_vec, + &symbolsrec_vec, + +/* Add any required traditional-core-file-handler. */ + +#ifdef AIX386_CORE + &aix386_core_vec, +#endif +#ifdef HPUX_CORE + &hpux_core_vec, +#endif +#ifdef OSF_CORE + &osf_core_vec, +#endif +#ifdef SCO_CORE + &sco_core_vec, +#endif +#ifdef NETBSD_CORE + &netbsd_core_vec, +#endif +#ifdef TRAD_CORE + &trad_core_vec, +#endif + + NULL /* end of list marker */ +}; + +/* default_vector[0] contains either the address of the default vector, + if there is one, or zero if there isn't. */ + +bfd_target *default_vector[] = { +#ifdef DEFAULT_VECTOR + &DEFAULT_VECTOR, +#endif + NULL +}; + + + + +/* +FUNCTION + bfd_find_target + +DESCRIPTION + Returns a pointer to the transfer vector for the object target + named target_name. If target_name is NULL, chooses the one in + the environment variable GNUTARGET; if that is null or not + defined thenthe first entry in the target list is chosen. + Passing in the string "default" or setting the environment + variable to "default" will cause the first entry in the target + list to be returned, and "target_defaulted" will be set in the + BFD. This causes <<bfd_check_format>> to loop over all the + targets to find the one that matches the file being read. + +SYNOPSIS + bfd_target *bfd_find_target(CONST char *, bfd *); +*/ + +bfd_target * +DEFUN(bfd_find_target,(target_name, abfd), + CONST char *target_name AND + bfd *abfd) +{ + bfd_target **target; + extern char *getenv (); + CONST char *targname = (target_name ? target_name : + (CONST char *) getenv ("GNUTARGET")); + + /* This is safe; the vector cannot be null */ + if (targname == NULL || !strcmp (targname, "default")) { + abfd->target_defaulted = true; + return abfd->xvec = target_vector[0]; + } + + abfd->target_defaulted = false; + + for (target = &target_vector[0]; *target != NULL; target++) { + if (!strcmp (targname, (*target)->name)) + return abfd->xvec = *target; + } + + bfd_error = invalid_target; + return NULL; +} + + +/* +FUNCTION + bfd_target_list + +DESCRIPTION + This function returns a freshly malloced NULL-terminated + vector of the names of all the valid BFD targets. Do not + modify the names + +SYNOPSIS + CONST char **bfd_target_list(void); + +*/ + +CONST char ** +DEFUN_VOID(bfd_target_list) +{ + int vec_length= 0; +#ifdef NATIVE_HPPAHPUX_COMPILER + /* The native compiler on the HP9000/700 has a bug which causes it + to loop endlessly when compiling this file. This avoids it. */ + volatile +#endif + bfd_target **target; + CONST char **name_list, **name_ptr; + + for (target = &target_vector[0]; *target != NULL; target++) + vec_length++; + + name_ptr = + name_list = (CONST char **) zalloc ((vec_length + 1) * sizeof (char **)); + + if (name_list == NULL) { + bfd_error = no_memory; + return NULL; + } + + for (target = &target_vector[0]; *target != NULL; target++) + *(name_ptr++) = (*target)->name; + + return name_list; +} diff --git a/gnu/usr.bin/gdb/bfd/trad-core.c b/gnu/usr.bin/gdb/bfd/trad-core.c new file mode 100644 index 00000000000..cd0c96993fc --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/trad-core.c @@ -0,0 +1,384 @@ +/* BFD back end for traditional Unix core files (U-area and raw sections) + Copyright 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. + Written by John Gilmore of Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: trad-core.c,v 1.1 1995/10/18 08:39:54 deraadt Exp $ +*/ + +/* To use this file on a particular host, configure the host with these + parameters in the config/h-HOST file: + + HDEFINES=-DTRAD_CORE + HDEPFILES=trad-core.o + + */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" /* BFD a.out internal data structures */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/dir.h> +#include <signal.h> + +#include <sys/user.h> /* After a.out.h */ +#if 0 +/* file.h is included by std-host.h. So we better not try to include it + twice; on some systems (dpx2) it is not protected against multiple + inclusion. I have checked that all the hosts which use this file + include sys/file.h in the hosts file. */ +#include <sys/file.h> +#endif + +#include <errno.h> + + struct trad_core_struct + { + asection *data_section; + asection *stack_section; + asection *reg_section; + struct user u; + } *rawptr; + +#define core_upage(bfd) (&((bfd)->tdata.trad_core_data->u)) +#define core_datasec(bfd) ((bfd)->tdata.trad_core_data->data_section) +#define core_stacksec(bfd) ((bfd)->tdata.trad_core_data->stack_section) +#define core_regsec(bfd) ((bfd)->tdata.trad_core_data->reg_section) + +/* forward declarations */ + +bfd_target * trad_unix_core_file_p PARAMS ((bfd *abfd)); +char * trad_unix_core_file_failing_command PARAMS ((bfd *abfd)); +int trad_unix_core_file_failing_signal PARAMS ((bfd *abfd)); +boolean trad_unix_core_file_matches_executable_p + PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +/* Handle 4.2-style (and perhaps also sysV-style) core dump file. */ + +/* ARGSUSED */ +bfd_target * +trad_unix_core_file_p (abfd) + bfd *abfd; + +{ + int val; + struct user u; + +#ifdef TRAD_CORE_USER_OFFSET + /* If defined, this macro is the file position of the user struct. */ + if (bfd_seek (abfd, TRAD_CORE_USER_OFFSET, SEEK_SET) == 0) + return 0; +#endif + + val = bfd_read ((void *)&u, 1, sizeof u, abfd); + if (val != sizeof u) + { + /* Too small to be a core file */ + bfd_error = wrong_format; + return 0; + } + + /* Sanity check perhaps??? */ + if (u.u_dsize > 0x1000000) /* Remember, it's in pages... */ + { + bfd_error = wrong_format; + return 0; + } + if (u.u_ssize > 0x1000000) + { + bfd_error = wrong_format; + return 0; + } + + /* Check that the size claimed is no greater than the file size. */ + { + FILE *stream = bfd_cache_lookup (abfd); + struct stat statbuf; + if (stream == NULL) + return 0; + if (fstat (fileno (stream), &statbuf) < 0) + { + bfd_error = system_call_error; + return 0; + } + if (NBPG * (UPAGES + u.u_dsize + u.u_ssize) > statbuf.st_size) + { + bfd_error = wrong_format; + return 0; + } + if (NBPG * (UPAGES + u.u_dsize + u.u_ssize) +#ifdef TRAD_CORE_EXTRA_SIZE_ALLOWED + /* Some systems write the file too big. */ + + TRAD_CORE_EXTRA_SIZE_ALLOWED +#endif + < statbuf.st_size) + { + /* The file is too big. Maybe it's not a core file + or we otherwise have bad values for u_dsize and u_ssize). */ + bfd_error = wrong_format; + return 0; + } + } + + /* OK, we believe you. You're a core file (sure, sure). */ + + /* Allocate both the upage and the struct core_data at once, so + a single free() will free them both. */ + rawptr = (struct trad_core_struct *) + bfd_zalloc (abfd, sizeof (struct trad_core_struct)); + if (rawptr == NULL) { + bfd_error = no_memory; + return 0; + } + + abfd->tdata.trad_core_data = rawptr; + + rawptr->u = u; /*Copy the uarea into the tdata part of the bfd */ + + /* Create the sections. This is raunchy, but bfd_close wants to free + them separately. */ + + core_stacksec(abfd) = (asection *) zalloc (sizeof (asection)); + if (core_stacksec (abfd) == NULL) { + loser: + bfd_error = no_memory; + free ((void *)rawptr); + return 0; + } + core_datasec (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_datasec (abfd) == NULL) { + loser1: + free ((void *)core_stacksec (abfd)); + goto loser; + } + core_regsec (abfd) = (asection *) zalloc (sizeof (asection)); + if (core_regsec (abfd) == NULL) { + free ((void *)core_datasec (abfd)); + goto loser1; + } + + core_stacksec (abfd)->name = ".stack"; + core_datasec (abfd)->name = ".data"; + core_regsec (abfd)->name = ".reg"; + + core_stacksec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + core_datasec (abfd)->flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; + core_regsec (abfd)->flags = SEC_ALLOC + SEC_HAS_CONTENTS; + + core_datasec (abfd)->_raw_size = NBPG * u.u_dsize; + core_stacksec (abfd)->_raw_size = NBPG * u.u_ssize; + core_regsec (abfd)->_raw_size = NBPG * UPAGES; /* Larger than sizeof struct u */ + + /* What a hack... we'd like to steal it from the exec file, + since the upage does not seem to provide it. FIXME. */ +#ifdef HOST_DATA_START_ADDR + core_datasec (abfd)->vma = HOST_DATA_START_ADDR; +#else + core_datasec (abfd)->vma = HOST_TEXT_START_ADDR + (NBPG * u.u_tsize); +#endif + +#ifdef HOST_STACK_START_ADDR + core_stacksec (abfd)->vma = HOST_STACK_START_ADDR; +#else + core_stacksec (abfd)->vma = HOST_STACK_END_ADDR - (NBPG * u.u_ssize); +#endif + + /* This is tricky. As the "register section", we give them the entire + upage and stack. u.u_ar0 points to where "register 0" is stored. + There are two tricks with this, though. One is that the rest of the + registers might be at positive or negative (or both) displacements + from *u_ar0. The other is that u_ar0 is sometimes an absolute address + in kernel memory, and on other systems it is an offset from the beginning + of the `struct user'. + + As a practical matter, we don't know where the registers actually are, + so we have to pass the whole area to GDB. We encode the value of u_ar0 + by setting the .regs section up so that its virtual memory address + 0 is at the place pointed to by u_ar0 (by setting the vma of the start + of the section to -u_ar0). GDB uses this info to locate the regs, + using minor trickery to get around the offset-or-absolute-addr problem. */ +#ifdef TRAD_CORE_REGPOS + core_regsec (abfd)->vma = TRAD_CORE_REGPOS(abfd); +#else + core_regsec (abfd)->vma = 0 - (int) u.u_ar0; +#endif + + core_datasec (abfd)->filepos = NBPG * UPAGES; +#ifdef TRAD_CORE_STACK_FILEPOS + core_stacksec (abfd)->filepos = TRAD_CORE_STACK_FILEPOS; +#else + core_stacksec (abfd)->filepos = (NBPG * UPAGES) + NBPG * u.u_dsize; +#endif + core_regsec (abfd)->filepos = 0; /* Register segment is the upage */ + + /* Align to word at least */ + core_stacksec (abfd)->alignment_power = 2; + core_datasec (abfd)->alignment_power = 2; + core_regsec (abfd)->alignment_power = 2; + + abfd->sections = core_stacksec (abfd); + core_stacksec (abfd)->next = core_datasec (abfd); + core_datasec (abfd)->next = core_regsec (abfd); + abfd->section_count = 3; + + return abfd->xvec; +} + +char * +trad_unix_core_file_failing_command (abfd) + bfd *abfd; +{ +#ifndef NO_CORE_COMMAND + char *com = abfd->tdata.trad_core_data->u.u_comm; + if (*com) + return com; + else +#endif + return 0; +} + +/* ARGSUSED */ +int +trad_unix_core_file_failing_signal (ignore_abfd) + bfd *ignore_abfd; +{ +#ifdef TRAD_UNIX_CORE_FILE_FAILING_SIGNAL + return TRAD_UNIX_CORE_FILE_FAILING_SIGNAL(ignore_abfd); +#else + return -1; /* FIXME, where is it? */ +#endif +} + +/* ARGSUSED */ +boolean +trad_unix_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + return true; /* FIXME, We have no way of telling at this point */ +} + +/* No archive file support via this BFD */ +#define trad_unix_openr_next_archived_file bfd_generic_openr_next_archived_file +#define trad_unix_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define trad_unix_slurp_armap bfd_false +#define trad_unix_slurp_extended_name_table bfd_true +#define trad_unix_write_armap (boolean (*) PARAMS \ + ((bfd *arch, unsigned int elength, struct orl *map, \ + unsigned int orl_count, int stridx))) bfd_false +#define trad_unix_truncate_arname bfd_dont_truncate_arname +#define aout_32_openr_next_archived_file bfd_generic_openr_next_archived_file + +#define trad_unix_close_and_cleanup bfd_generic_close_and_cleanup +#define trad_unix_set_section_contents (boolean (*) PARAMS \ + ((bfd *abfd, asection *section, PTR data, file_ptr offset, \ + bfd_size_type count))) bfd_false +#define trad_unix_get_section_contents bfd_generic_get_section_contents +#define trad_unix_new_section_hook (boolean (*) PARAMS \ + ((bfd *, sec_ptr))) bfd_true +#define trad_unix_get_symtab_upper_bound bfd_0u +#define trad_unix_get_symtab (unsigned int (*) PARAMS \ + ((bfd *, struct symbol_cache_entry **))) bfd_0u +#define trad_unix_get_reloc_upper_bound (unsigned int (*) PARAMS \ + ((bfd *, sec_ptr))) bfd_0u +#define trad_unix_canonicalize_reloc (unsigned int (*) PARAMS \ + ((bfd *, sec_ptr, arelent **, struct symbol_cache_entry**))) bfd_0u +#define trad_unix_make_empty_symbol (struct symbol_cache_entry * \ + (*) PARAMS ((bfd *))) bfd_false +#define trad_unix_print_symbol (void (*) PARAMS \ + ((bfd *, PTR, struct symbol_cache_entry *, \ + bfd_print_symbol_type))) bfd_false +#define trad_unix_get_symbol_info (void (*) PARAMS \ + ((bfd *, struct symbol_cache_entry *, \ + symbol_info *))) bfd_false +#define trad_unix_get_lineno (alent * (*) PARAMS \ + ((bfd *, struct symbol_cache_entry *))) bfd_nullvoidptr +#define trad_unix_set_arch_mach (boolean (*) PARAMS \ + ((bfd *, enum bfd_architecture, unsigned long))) bfd_false +#define trad_unix_find_nearest_line (boolean (*) PARAMS \ + ((bfd *abfd, struct sec *section, \ + struct symbol_cache_entry **symbols,bfd_vma offset, \ + CONST char **file, CONST char **func, unsigned int *line))) bfd_false +#define trad_unix_sizeof_headers (int (*) PARAMS \ + ((bfd *, boolean))) bfd_0 + +#define trad_unix_bfd_debug_info_start bfd_void +#define trad_unix_bfd_debug_info_end bfd_void +#define trad_unix_bfd_debug_info_accumulate (void (*) PARAMS \ + ((bfd *, struct sec *))) bfd_void +#define trad_unix_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents +#define trad_unix_bfd_relax_section bfd_generic_relax_section +#define trad_unix_bfd_seclet_link \ + ((boolean (*) PARAMS ((bfd *, PTR, boolean))) bfd_false) +#define trad_unix_bfd_reloc_type_lookup \ + ((CONST struct reloc_howto_struct *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) bfd_nullvoidptr) +#define trad_unix_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) + +/* If somebody calls any byte-swapping routines, shoot them. */ +void +swap_abort() +{ + abort(); /* This way doesn't require any declaration for ANSI to fuck up */ +} +#define NO_GET ((bfd_vma (*) PARAMS (( bfd_byte *))) swap_abort ) +#define NO_PUT ((void (*) PARAMS ((bfd_vma, bfd_byte *))) swap_abort ) +#define NO_SIGNED_GET ((bfd_signed_vma (*) PARAMS ((bfd_byte *))) swap_abort ) + +bfd_target trad_core_vec = + { + "trad-core", + bfd_target_unknown_flavour, + true, /* target byte order */ + true, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* symbol prefix */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + 3, /* minimum alignment power */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit data */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 64 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 32 bit hdrs */ + NO_GET, NO_SIGNED_GET, NO_PUT, /* 16 bit hdrs */ + + { /* bfd_check_format */ + _bfd_dummy_target, /* unknown format */ + _bfd_dummy_target, /* object file */ + _bfd_dummy_target, /* archive */ + trad_unix_core_file_p /* a core file */ + }, + { /* bfd_set_format */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + { /* bfd_write_contents */ + bfd_false, bfd_false, + bfd_false, bfd_false + }, + + JUMP_TABLE(trad_unix), + (PTR) 0 /* backend_data */ +}; |