From 3c8ea7601ed05f427ea0108e2ec73d04597e1efd Mon Sep 17 00:00:00 2001 From: "Jordan K. Hubbard" Date: Fri, 30 Dec 1994 23:33:10 +0000 Subject: [PATCH] Bring in the files added by Gary Jennejohn's gdb update. Submitted by: gj --- gnu/usr.bin/gdb/bfd/coff-i386.c | 354 ++ gnu/usr.bin/gdb/bfd/coffcode.h | 2544 ++++++++++ gnu/usr.bin/gdb/bfd/coffswap.h | 741 +++ gnu/usr.bin/gdb/bfd/ecofflink.c | 1616 +++++++ gnu/usr.bin/gdb/bfd/elf32-i386.c | 931 ++++ gnu/usr.bin/gdb/bfd/elf32-target.h | 358 ++ gnu/usr.bin/gdb/bfd/elf32.c | 23 + gnu/usr.bin/gdb/bfd/elfcode.h | 6351 +++++++++++++++++++++++++ gnu/usr.bin/gdb/bfd/genlink.h | 106 + gnu/usr.bin/gdb/bfd/hash.c | 470 ++ gnu/usr.bin/gdb/bfd/i386aout.c | 68 + gnu/usr.bin/gdb/bfd/linker.c | 2442 ++++++++++ gnu/usr.bin/gdb/gdb/annotate.c | 521 ++ gnu/usr.bin/gdb/gdb/annotate.h | 95 + gnu/usr.bin/gdb/gdb/aout/encap.h | 135 + gnu/usr.bin/gdb/gdb/aout/host.h | 22 + gnu/usr.bin/gdb/gdb/aout/reloc.h | 66 + gnu/usr.bin/gdb/gdb/bfdlink.h | 411 ++ gnu/usr.bin/gdb/gdb/coff/i386.h | 221 + gnu/usr.bin/gdb/gdb/disassemble.c | 148 + gnu/usr.bin/gdb/gdb/floatformat.h | 87 + gnu/usr.bin/gdb/gdb/fopen-bin.h | 27 + gnu/usr.bin/gdb/gdb/gdbm.h | 91 + gnu/usr.bin/gdb/gdb/ieee.h | 132 + gnu/usr.bin/gdb/gdb/kcorelow.c | 353 ++ gnu/usr.bin/gdb/gdb/libiberty.h | 107 + gnu/usr.bin/gdb/gdb/mdebugread.c | 4053 ++++++++++++++++ gnu/usr.bin/gdb/gdb/solib.c | 1549 ++++++ gnu/usr.bin/gdb/gdb/top.c | 2493 ++++++++++ gnu/usr.bin/gdb/gdb/top.h | 48 + gnu/usr.bin/gdb/libiberty/vasprintf.c | 139 + gnu/usr.bin/gdb/mmalloc/COPYING.LIB | 481 ++ 32 files changed, 27183 insertions(+) create mode 100644 gnu/usr.bin/gdb/bfd/coff-i386.c create mode 100644 gnu/usr.bin/gdb/bfd/coffcode.h create mode 100644 gnu/usr.bin/gdb/bfd/coffswap.h create mode 100644 gnu/usr.bin/gdb/bfd/ecofflink.c create mode 100644 gnu/usr.bin/gdb/bfd/elf32-i386.c create mode 100644 gnu/usr.bin/gdb/bfd/elf32-target.h create mode 100644 gnu/usr.bin/gdb/bfd/elf32.c create mode 100644 gnu/usr.bin/gdb/bfd/elfcode.h create mode 100644 gnu/usr.bin/gdb/bfd/genlink.h create mode 100644 gnu/usr.bin/gdb/bfd/hash.c create mode 100644 gnu/usr.bin/gdb/bfd/i386aout.c create mode 100644 gnu/usr.bin/gdb/bfd/linker.c create mode 100644 gnu/usr.bin/gdb/gdb/annotate.c create mode 100644 gnu/usr.bin/gdb/gdb/annotate.h create mode 100644 gnu/usr.bin/gdb/gdb/aout/encap.h create mode 100644 gnu/usr.bin/gdb/gdb/aout/host.h create mode 100644 gnu/usr.bin/gdb/gdb/aout/reloc.h create mode 100644 gnu/usr.bin/gdb/gdb/bfdlink.h create mode 100644 gnu/usr.bin/gdb/gdb/coff/i386.h create mode 100644 gnu/usr.bin/gdb/gdb/disassemble.c create mode 100644 gnu/usr.bin/gdb/gdb/floatformat.h create mode 100644 gnu/usr.bin/gdb/gdb/fopen-bin.h create mode 100644 gnu/usr.bin/gdb/gdb/gdbm.h create mode 100644 gnu/usr.bin/gdb/gdb/ieee.h create mode 100644 gnu/usr.bin/gdb/gdb/kcorelow.c create mode 100644 gnu/usr.bin/gdb/gdb/libiberty.h create mode 100644 gnu/usr.bin/gdb/gdb/mdebugread.c create mode 100644 gnu/usr.bin/gdb/gdb/solib.c create mode 100644 gnu/usr.bin/gdb/gdb/top.c create mode 100644 gnu/usr.bin/gdb/gdb/top.h create mode 100644 gnu/usr.bin/gdb/libiberty/vasprintf.c create mode 100644 gnu/usr.bin/gdb/mmalloc/COPYING.LIB diff --git a/gnu/usr.bin/gdb/bfd/coff-i386.c b/gnu/usr.bin/gdb/bfd/coff-i386.c new file mode 100644 index 00000000000..aaaedca74af --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/coff-i386.c @@ -0,0 +1,354 @@ +/* BFD back-end for Intel 386 COFF files. + Copyright 1990, 1991, 1992, 1993, 1994 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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" +#include "coff/i386.h" +#include "coff/internal.h" +#include "libcoff.h" + +static bfd_reloc_status_type coff_i386_reloc PARAMS ((bfd *abfd, + arelent *reloc_entry, + asymbol *symbol, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); + +/* The page size is a guess based on ELF. */ +#define COFF_PAGE_SIZE 0x1000 + +/* For some reason when using i386 COFF the value stored in the .text + section for a reference to a common symbol is the value itself plus + any desired offset. Ian Taylor, Cygnus Support. */ + +/* If we are producing relocateable output, we need to do some + adjustments to the object file that are not done by the + bfd_perform_relocation function. This function is called by every + reloc type to make any required adjustments. */ + +static bfd_reloc_status_type +coff_i386_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + symvalue diff; + + if (output_bfd == (bfd *) NULL) + return bfd_reloc_continue; + + if (bfd_is_com_section (symbol->section)) + { + /* We are relocating a common symbol. The current value in the + object file is ORIG + OFFSET, where ORIG is the value of the + common symbol as seen by the object file when it was compiled + (this may be zero if the symbol was undefined) and OFFSET is + the offset into the common symbol (normally zero, but may be + non-zero when referring to a field in a common structure). + ORIG is the negative of reloc_entry->addend, which is set by + the CALC_ADDEND macro below. We want to replace the value in + the object file with NEW + OFFSET, where NEW is the value of + the common symbol which we are going to put in the final + object file. NEW is symbol->value. */ + diff = symbol->value + reloc_entry->addend; + } + else + { + /* For some reason bfd_perform_relocation always effectively + ignores the addend for a COFF target when producing + relocateable output. This seems to be always wrong for 386 + COFF, so we handle the addend here instead. */ + diff = reloc_entry->addend; + } + +#define DOIT(x) \ + x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) + + if (diff != 0) + { + const reloc_howto_type *howto = reloc_entry->howto; + unsigned char *addr = (unsigned char *) data + reloc_entry->address; + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8 (abfd, addr); + DOIT (x); + bfd_put_8 (abfd, x, addr); + } + break; + + case 1: + { + short x = bfd_get_16 (abfd, addr); + DOIT (x); + bfd_put_16 (abfd, x, addr); + } + break; + + case 2: + { + long x = bfd_get_32 (abfd, addr); + DOIT (x); + bfd_put_32 (abfd, x, addr); + } + break; + + default: + abort (); + } + } + + /* Now let bfd_perform_relocation finish everything up. */ + return bfd_reloc_continue; +} + +static reloc_howto_type howto_table[] = +{ + {0}, + {1}, + {2}, + {3}, + {4}, + {5}, + HOWTO (R_DIR32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "dir32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + {7}, + {010}, + {011}, + {012}, + {013}, + {014}, + {015}, + {016}, + HOWTO (R_RELBYTE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "8", /* name */ + true, /* partial_inplace */ + 0x000000ff, /* src_mask */ + 0x000000ff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_RELWORD, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "16", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_RELLONG, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_PCRBYTE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "DISP8", /* name */ + true, /* partial_inplace */ + 0x000000ff, /* src_mask */ + 0x000000ff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_PCRWORD, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "DISP16", /* name */ + true, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + false), /* pcrel_offset */ + HOWTO (R_PCRLONG, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + coff_i386_reloc, /* special_function */ + "DISP32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + false) /* pcrel_offset */ +}; + +/* Turn a howto into a reloc nunmber */ + +#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } +#define BADMAG(x) I386BADMAG(x) +#define I386 1 /* Customize coffcode.h */ + +#define RTYPE2HOWTO(cache_ptr, dst) \ + cache_ptr->howto = howto_table + (dst)->r_type; + +/* On SCO Unix 3.2.2 the native assembler generates two .data + sections. We handle that by renaming the second one to .data2. It + does no harm to do this for any 386 COFF target. */ +#define TWO_DATA_SECS + +/* For 386 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared + library. On some other COFF targets STYP_BSS is normally + STYP_NOLOAD. */ +#define BSS_NOLOAD_IS_SHARED_LIBRARY + +/* Compute the addend of a reloc. If the reloc is to a common symbol, + the object file contains the value of the common symbol. By the + time this is called, the linker may be using a different symbol + from a different object file with a different value. Therefore, we + hack wildly to locate the original symbol from this file so that we + can make the correct adjustment. This macro sets coffsym to the + symbol from the original file, and uses it to set the addend value + correctly. If this is not a common symbol, the usual addend + calculation is done, except that an additional tweak is needed for + PC relative relocs. + FIXME: This macro refers to symbols and asect; these are from the + calling function, not the macro arguments. */ + +#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ + { \ + coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ + if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if (ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + if (coffsym != (coff_symbol_type *) NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = - coffsym->native->u.syment.n_value; \ + else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section != (asection *) NULL) \ + cache_ptr->addend = - (ptr->section->vma + ptr->value); \ + else \ + cache_ptr->addend = 0; \ + if (ptr && howto_table[reloc.r_type].pc_relative) \ + cache_ptr->addend += asect->vma; \ + } + +#include "coffcode.h" + +static const bfd_target * +i3coff_object_p(a) + bfd *a; +{ + return coff_object_p(a); +} + +const bfd_target +#ifdef TARGET_SYM + TARGET_SYM = +#else + i386coff_vec = +#endif +{ +#ifdef TARGET_NAME + TARGET_NAME, +#else + "coff-i386", /* name */ +#endif + bfd_target_coff_flavour, + false, /* data byte order is little */ + false, /* header byte order is little */ + + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + '/', /* ar_pad_char */ + 15, /* ar_max_namelen */ + + 2, /* minimum alignment power */ + 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 */ + +/* Note that we allow an object file to be treated as a core file as well. */ + {_bfd_dummy_target, i3coff_object_p, /* bfd_check_format */ + bfd_generic_archive_p, i3coff_object_p}, + {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ + bfd_false}, + {bfd_false, coff_write_object_contents, /* bfd_write_contents */ + _bfd_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (coff), + BFD_JUMP_TABLE_COPY (coff), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (coff), + BFD_JUMP_TABLE_RELOCS (coff), + BFD_JUMP_TABLE_WRITE (coff), + BFD_JUMP_TABLE_LINK (coff), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + COFF_SWAP_TABLE, +}; diff --git a/gnu/usr.bin/gdb/bfd/coffcode.h b/gnu/usr.bin/gdb/bfd/coffcode.h new file mode 100644 index 00000000000..206a38192f8 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/coffcode.h @@ -0,0 +1,2544 @@ +/* Support for the generic parts of most COFF variants, for BFD. + Copyright 1990, 1991, 1992, 1993, 1994 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. */ + +/* +Most of this hacked by Steve Chamberlain, + sac@cygnus.com +*/ +/* + +SECTION + coff backends + + BFD supports a number of different flavours of coff format. + The major differences between formats are the sizes and + alignments of fields in structures on disk, and the occasional + extra field. + + Coff in all its varieties is implemented with a few common + files and a number of implementation specific files. For + example, The 88k bcs coff format is implemented in the file + @file{coff-m88k.c}. This file @code{#include}s + @file{coff/m88k.h} which defines the external structure of the + coff format for the 88k, and @file{coff/internal.h} which + defines the internal structure. @file{coff-m88k.c} also + defines the relocations used by the 88k format + @xref{Relocations}. + + The Intel i960 processor version of coff is implemented in + @file{coff-i960.c}. This file has the same structure as + @file{coff-m88k.c}, except that it includes @file{coff/i960.h} + rather than @file{coff-m88k.h}. + +SUBSECTION + Porting to a new version of coff + + The recommended method is to select from the existing + implementations the version of coff which is most like the one + you want to use. For example, we'll say that i386 coff is + the one you select, and that your coff flavour is called foo. + Copy @file{i386coff.c} to @file{foocoff.c}, copy + @file{../include/coff/i386.h} to @file{../include/coff/foo.h}, + and add the lines to @file{targets.c} and @file{Makefile.in} + so that your new back end is used. Alter the shapes of the + structures in @file{../include/coff/foo.h} so that they match + what you need. You will probably also have to add + @code{#ifdef}s to the code in @file{coff/internal.h} and + @file{coffcode.h} if your version of coff is too wild. + + You can verify that your new BFD backend works quite simply by + building @file{objdump} from the @file{binutils} directory, + and making sure that its version of what's going on and your + host system's idea (assuming it has the pretty standard coff + dump utility, usually called @code{att-dump} or just + @code{dump}) are the same. Then clean up your code, and send + what you've done to Cygnus. Then your stuff will be in the + next release, and you won't have to keep integrating it. + +SUBSECTION + How the coff backend works + +SUBSUBSECTION + File layout + + The Coff backend is split into generic routines that are + applicable to any Coff target and routines that are specific + to a particular target. The target-specific routines are + further split into ones which are basically the same for all + Coff targets except that they use the external symbol format + or use different values for certain constants. + + The generic routines are in @file{coffgen.c}. These routines + work for any Coff target. They use some hooks into the target + specific code; the hooks are in a @code{bfd_coff_backend_data} + structure, one of which exists for each target. + + The essentially similar target-specific routines are in + @file{coffcode.h}. This header file includes executable C code. + The various Coff targets first include the appropriate Coff + header file, make any special defines that are needed, and + then include @file{coffcode.h}. + + Some of the Coff targets then also have additional routines in + the target source file itself. + + For example, @file{coff-i960.c} includes + @file{coff/internal.h} and @file{coff/i960.h}. It then + defines a few constants, such as @code{I960}, and includes + @file{coffcode.h}. Since the i960 has complex relocation + types, @file{coff-i960.c} also includes some code to + manipulate the i960 relocs. This code is not in + @file{coffcode.h} because it would not be used by any other + target. + +SUBSUBSECTION + Bit twiddling + + Each flavour of coff supported in BFD has its own header file + describing the external layout of the structures. There is also + an internal description of the coff layout, in + @file{coff/internal.h}. A major function of the + coff backend is swapping the bytes and twiddling the bits to + translate the external form of the structures into the normal + internal form. This is all performed in the + @code{bfd_swap}_@i{thing}_@i{direction} routines. Some + elements are different sizes between different versions of + coff; it is the duty of the coff version specific include file + to override the definitions of various packing routines in + @file{coffcode.h}. E.g., the size of line number entry in coff is + sometimes 16 bits, and sometimes 32 bits. @code{#define}ing + @code{PUT_LNSZ_LNNO} and @code{GET_LNSZ_LNNO} will select the + correct one. No doubt, some day someone will find a version of + coff which has a varying field size not catered to at the + moment. To port BFD, that person will have to add more @code{#defines}. + Three of the bit twiddling routines are exported to + @code{gdb}; @code{coff_swap_aux_in}, @code{coff_swap_sym_in} + and @code{coff_swap_linno_in}. @code{GDB} reads the symbol + table on its own, but uses BFD to fix things up. More of the + bit twiddlers are exported for @code{gas}; + @code{coff_swap_aux_out}, @code{coff_swap_sym_out}, + @code{coff_swap_lineno_out}, @code{coff_swap_reloc_out}, + @code{coff_swap_filehdr_out}, @code{coff_swap_aouthdr_out}, + @code{coff_swap_scnhdr_out}. @code{Gas} currently keeps track + of all the symbol table and reloc drudgery itself, thereby + saving the internal BFD overhead, but uses BFD to swap things + on the way out, making cross ports much safer. Doing so also + allows BFD (and thus the linker) to use the same header files + as @code{gas}, which makes one avenue to disaster disappear. + +SUBSUBSECTION + Symbol reading + + The simple canonical form for symbols used by BFD is not rich + enough to keep all the information available in a coff symbol + table. The back end gets around this problem by keeping the original + symbol table around, "behind the scenes". + + When a symbol table is requested (through a call to + @code{bfd_canonicalize_symtab}), a request gets through to + @code{coff_get_normalized_symtab}. This reads the symbol table from + the coff file and swaps all the structures inside into the + internal form. It also fixes up all the pointers in the table + (represented in the file by offsets from the first symbol in + the table) into physical pointers to elements in the new + internal table. This involves some work since the meanings of + fields change depending upon context: a field that is a + pointer to another structure in the symbol table at one moment + may be the size in bytes of a structure at the next. Another + pass is made over the table. All symbols which mark file names + (<> symbols) are modified so that the internal + string points to the value in the auxent (the real filename) + rather than the normal text associated with the symbol + (@code{".file"}). + + At this time the symbol names are moved around. Coff stores + all symbols less than nine characters long physically + within the symbol table; longer strings are kept at the end of + the file in the string table. This pass moves all strings + into memory and replaces them with pointers to the strings. + + + The symbol table is massaged once again, this time to create + the canonical table used by the BFD application. Each symbol + is inspected in turn, and a decision made (using the + @code{sclass} field) about the various flags to set in the + @code{asymbol}. @xref{Symbols}. The generated canonical table + shares strings with the hidden internal symbol table. + + Any linenumbers are read from the coff file too, and attached + to the symbols which own the functions the linenumbers belong to. + +SUBSUBSECTION + Symbol writing + + Writing a symbol to a coff file which didn't come from a coff + file will lose any debugging information. The @code{asymbol} + structure remembers the BFD from which the symbol was taken, and on + output the back end makes sure that the same destination target as + source target is present. + + When the symbols have come from a coff file then all the + debugging information is preserved. + + Symbol tables are provided for writing to the back end in a + vector of pointers to pointers. This allows applications like + the linker to accumulate and output large symbol tables + without having to do too much byte copying. + + This function runs through the provided symbol table and + patches each symbol marked as a file place holder + (@code{C_FILE}) to point to the next file place holder in the + list. It also marks each @code{offset} field in the list with + the offset from the first symbol of the current symbol. + + Another function of this procedure is to turn the canonical + value form of BFD into the form used by coff. Internally, BFD + expects symbol values to be offsets from a section base; so a + symbol physically at 0x120, but in a section starting at + 0x100, would have the value 0x20. Coff expects symbols to + contain their final value, so symbols have their values + changed at this point to reflect their sum with their owning + section. This transformation uses the + <> field of the @code{asymbol}'s + @code{asection} @xref{Sections}. + + o <> + + This routine runs though the provided symbol table and uses + the offsets generated by the previous pass and the pointers + generated when the symbol table was read in to create the + structured hierachy required by coff. It changes each pointer + to a symbol into the index into the symbol table of the asymbol. + + o <> + + This routine runs through the symbol table and patches up the + symbols from their internal form into the coff way, calls the + bit twiddlers, and writes out the table to the file. + +*/ + +/* +INTERNAL_DEFINITION + coff_symbol_type + +DESCRIPTION + The hidden information for an <> is described in a + <>: + +CODE_FRAGMENT +. +.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 value of this symbol be renumbered. Used for +. XCOFF C_BSTAT symbols. Set by coff_slurp_symbol_table. *} +.unsigned int fix_value : 1; +. +. {* Should the tag field of this symbol be renumbered. +. Created by coff_pointerize_aux. *} +.unsigned int fix_tag : 1; +. +. {* Should the endidx field of this symbol be renumbered. +. Created by coff_pointerize_aux. *} +.unsigned int fix_end : 1; +. +. {* Should the x_csect.x_scnlen field be renumbered. +. Created by coff_slurp_symbol_table. *} +.unsigned int fix_scnlen : 1; +. +. {* 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; + + +*/ + +#include "coffswap.h" + +/* void warning(); */ + +/* + * Return a word with STYP_* (scnhdr.s_flags) flags set to represent the + * incoming SEC_* flags. The inverse of this function is styp_to_sec_flags(). + * NOTE: If you add to/change this routine, you should mirror the changes + * in styp_to_sec_flags(). + */ +static long +sec_to_styp_flags (sec_name, sec_flags) + CONST char *sec_name; + flagword sec_flags; +{ + long styp_flags = 0; + + if (!strcmp (sec_name, _TEXT)) + { + styp_flags = STYP_TEXT; + } + else if (!strcmp (sec_name, _DATA)) + { + styp_flags = STYP_DATA; +#ifdef TWO_DATA_SECS + } + else if (!strcmp (sec_name, ".data2")) + { + styp_flags = STYP_DATA; +#endif /* TWO_DATA_SECS */ + } + else if (!strcmp (sec_name, _BSS)) + { + styp_flags = STYP_BSS; +#ifdef _COMMENT + } + else if (!strcmp (sec_name, _COMMENT)) + { + styp_flags = STYP_INFO; +#endif /* _COMMENT */ +#ifdef _LIB + } + else if (!strcmp (sec_name, _LIB)) + { + styp_flags = STYP_LIB; +#endif /* _LIB */ +#ifdef _LIT + } + else if (!strcmp (sec_name, _LIT)) + { + styp_flags = STYP_LIT; +#endif /* _LIT */ + } + else if (!strcmp (sec_name, ".debug")) + { +#ifdef STYP_DEBUG + styp_flags = STYP_DEBUG; +#else + styp_flags = STYP_INFO; +#endif + } + else if (!strcmp (sec_name, ".stab") + || !strncmp (sec_name, ".stabstr", 8)) + { + styp_flags = STYP_INFO; + } + /* Try and figure out what it should be */ + else if (sec_flags & SEC_CODE) + { + styp_flags = STYP_TEXT; + } + else if (sec_flags & SEC_DATA) + { + styp_flags = STYP_DATA; + } + else if (sec_flags & SEC_READONLY) + { +#ifdef STYP_LIT /* 29k readonly text/data section */ + styp_flags = STYP_LIT; +#else + styp_flags = STYP_TEXT; +#endif /* STYP_LIT */ + } + else if (sec_flags & SEC_LOAD) + { + styp_flags = STYP_TEXT; + } + else if (sec_flags & SEC_ALLOC) + { + styp_flags = STYP_BSS; + } + +#ifdef STYP_NOLOAD + if ((sec_flags & (SEC_NEVER_LOAD | SEC_COFF_SHARED_LIBRARY)) != 0) + styp_flags |= STYP_NOLOAD; +#endif + + return (styp_flags); +} +/* + * Return a word with SEC_* flags set to represent the incoming + * STYP_* flags (from scnhdr.s_flags). The inverse of this + * function is sec_to_styp_flags(). + * NOTE: If you add to/change this routine, you should mirror the changes + * in sec_to_styp_flags(). + */ +static flagword +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; + +#ifdef STYP_NOLOAD + if (styp_flags & STYP_NOLOAD) + { + sec_flags |= SEC_NEVER_LOAD; + } +#endif /* STYP_NOLOAD */ + + /* For 386 COFF, at least, an unloadable text or data section is + actually a shared library section. */ + if (styp_flags & STYP_TEXT) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY; + else + sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; + } + else if (styp_flags & STYP_DATA) + { + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY; + else + sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; + } + else if (styp_flags & STYP_BSS) + { +#ifdef BSS_NOLOAD_IS_SHARED_LIBRARY + if (sec_flags & SEC_NEVER_LOAD) + sec_flags |= SEC_ALLOC | SEC_COFF_SHARED_LIBRARY; + else +#endif + sec_flags |= SEC_ALLOC; + } + else if (styp_flags & STYP_INFO) + { + /* We mark these as SEC_DEBUGGING, but only if COFF_PAGE_SIZE is + defined. coff_compute_section_file_positions uses + COFF_PAGE_SIZE to ensure that the low order bits of the + section VMA and the file offset match. If we don't know + COFF_PAGE_SIZE, we can't ensure the correct correspondence, + and demand page loading of the file will fail. */ +#ifdef COFF_PAGE_SIZE + sec_flags |= SEC_DEBUGGING; +#endif + } + else + { + sec_flags |= SEC_ALLOC | SEC_LOAD; + } + +#ifdef STYP_LIT /* A29k readonly text/data section type */ + if ((styp_flags & STYP_LIT) == STYP_LIT) + { + sec_flags = (SEC_LOAD | SEC_ALLOC | SEC_READONLY); + } +#endif /* STYP_LIT */ +#ifdef STYP_OTHER_LOAD /* Other loaded sections */ + if (styp_flags & STYP_OTHER_LOAD) + { + sec_flags = (SEC_LOAD | SEC_ALLOC); + } +#endif /* STYP_SDATA */ + + return (sec_flags); +} + +#define get_index(symbol) ((long) (symbol)->udata) + +/* +INTERNAL_DEFINITION + bfd_coff_backend_data + +CODE_FRAGMENT + +Special entry points for gdb to swap in coff symbol table parts: +.typedef struct +.{ +. void (*_bfd_coff_swap_aux_in) PARAMS (( +. bfd *abfd, +. PTR ext, +. int type, +. int class, +. int indaux, +. int numaux, +. 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)); +. + +Special entry points for gas to swap out coff parts: + +. unsigned int (*_bfd_coff_swap_aux_out) PARAMS (( +. bfd *abfd, +. PTR in, +. int type, +. int class, +. int indaux, +. int numaux, +. 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)); +. + +Special entry points for generic COFF routines to call target +dependent COFF routines: + +. 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_link_info *link_info, +. struct bfd_link_order *link_order, +. arelent *reloc, +. bfd_byte *data, +. unsigned int *src_ptr, +. unsigned int *dst_ptr)); +. int (*_bfd_coff_reloc16_estimate) PARAMS (( +. bfd *abfd, +. asection *input_section, +. arelent *r, +. unsigned int shrink, +. struct bfd_link_info *link_info)); +. +.} 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,ind,num,i) \ +. ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,ind,num,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(a,i,t,c,ind,num,o) \ +. ((coff_backend_info (a)->_bfd_coff_swap_aux_out) (a,i,t,c,ind,num,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, link_info, link_order, reloc, data, src_ptr, dst_ptr)\ +. ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\ +. (abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)) +. +.#define bfd_coff_reloc16_estimate(abfd, section, reloc, shrink, link_info)\ +. ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\ +. (abfd, section, reloc, shrink, link_info)) +. +*/ + +/* See whether the magic number matches. */ + +static boolean +coff_bad_format_hook (abfd, filehdr) + bfd * abfd; + PTR filehdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + + if (BADMAG (*internal_f)) + return false; + + /* if the optional header is NULL or not the correct size then + quit; the only difference I can see between m88k dgux headers (MC88DMAGIC) + and Intel 960 readwrite headers (I960WRMAGIC) is that the + optional header is of a different size. + + But the mips keeps extra stuff in it's opthdr, so dont check + when doing that + */ + +#if defined(M88) || defined(I960) + if (internal_f->f_opthdr != 0 && AOUTSZ != internal_f->f_opthdr) + return false; +#endif + + return true; +} + +static asection * +coff_make_section_hook (abfd, name) + bfd * abfd; + char *name; +{ +#ifdef TWO_DATA_SECS + /* FIXME: This predates the call to bfd_make_section_anyway + in make_a_section_from_file, and can probably go away. */ + /* On SCO a file created by the Microsoft assembler can have two + .data sections. We use .data2 for the second one. */ + if (strcmp (name, _DATA) == 0) + return bfd_make_section (abfd, ".data2"); +#endif + return (asection *) NULL; +} + +/* + initialize a section structure with information peculiar to this + particular implementation of coff +*/ + +static boolean +coff_new_section_hook (abfd, section) + bfd * abfd; + asection * section; +{ + section->alignment_power = abfd->xvec->align_power_min; + /* Allocate aux records for section symbols, to store size and + related info. + + @@ Shouldn't use constant multiplier here! */ + coffsymbol (section->symbol)->native = + (combined_entry_type *) bfd_zalloc (abfd, + sizeof (combined_entry_type) * 10); + +#ifdef COFF_SPARC + /* This is to allow double-word operations on addresses in data or bss. */ + if (strcmp (section->name, ".data") == 0 + || strcmp (section->name, ".bss") == 0) + section->alignment_power = 3; +#endif /* COFF_SPARC */ + + return true; +} + + +#ifdef I960 + +/* Set the alignment of a BFD section. */ + +static void +coff_set_alignment_hook (abfd, section, scnhdr) + bfd * abfd; + asection * section; + PTR scnhdr; +{ + struct internal_scnhdr *hdr = (struct internal_scnhdr *) scnhdr; + unsigned int i; + + for (i = 0; i < 32; i++) + if ((1 << i) >= hdr->s_align) + break; + section->alignment_power = i; +} + +#else /* ! I960 */ + +#define coff_set_alignment_hook \ + ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void) + +#endif /* ! I960 */ + +static boolean +coff_mkobject (abfd) + bfd * abfd; +{ + coff_data_type *coff; + + abfd->tdata.coff_obj_data = (struct coff_tdata *) bfd_zalloc (abfd, sizeof (coff_data_type)); + if (abfd->tdata.coff_obj_data == 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + coff = coff_data (abfd); + coff->symbols = (coff_symbol_type *) NULL; + coff->conversion_table = (unsigned int *) NULL; + coff->raw_syments = (struct coff_ptr_struct *) NULL; + coff->raw_linenos = (struct lineno *) NULL; + coff->relocbase = 0; +/* make_abs_section(abfd);*/ + return true; +} + +/* Create the COFF backend specific information. */ + +static PTR +coff_mkobject_hook (abfd, filehdr, aouthdr) + bfd * abfd; + PTR filehdr; + PTR aouthdr; +{ + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + coff_data_type *coff; + + if (coff_mkobject (abfd) == false) + return NULL; + + coff = coff_data (abfd); + + coff->sym_filepos = internal_f->f_symptr; + coff->flags = internal_f->f_flags; + + /* These members communicate important constants about the symbol + table to GDB's symbol-reading code. These `constants' + unfortunately vary among coff implementations... */ + coff->local_n_btmask = N_BTMASK; + coff->local_n_btshft = N_BTSHFT; + coff->local_n_tmask = N_TMASK; + coff->local_n_tshift = N_TSHIFT; + coff->local_symesz = SYMESZ; + coff->local_auxesz = AUXESZ; + coff->local_linesz = LINESZ; + + return (PTR) coff; +} + +/* Determine the machine architecture and type. FIXME: This is target + dependent because the magic numbers are defined in the target + dependent header files. But there is no particular need for this. + If the magic numbers were moved to a separate file, this function + would be target independent and would also be much more successful + at linking together COFF files for different architectures. */ + +static boolean +coff_set_arch_mach_hook (abfd, filehdr) + bfd *abfd; + PTR filehdr; +{ + long machine; + enum bfd_architecture arch; + struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; + + machine = 0; + switch (internal_f->f_magic) + { +#ifdef I386MAGIC + case I386MAGIC: + case I386PTXMAGIC: + case I386AIXMAGIC: /* Danbury PS/2 AIX C Compiler */ + case LYNXCOFFMAGIC: /* shadows the m68k Lynx number below, sigh */ + arch = bfd_arch_i386; + machine = 0; + break; +#endif + +#ifdef A29K_MAGIC_BIG + case A29K_MAGIC_BIG: + case A29K_MAGIC_LITTLE: + arch = bfd_arch_a29k; + machine = 0; + break; +#endif + +#ifdef MC68MAGIC + case MC68MAGIC: + case M68MAGIC: +#ifdef MC68KBCSMAGIC + case MC68KBCSMAGIC: +#endif +#ifdef APOLLOM68KMAGIC + case APOLLOM68KMAGIC: +#endif +#ifdef LYNXCOFFMAGIC + case LYNXCOFFMAGIC: +#endif + arch = bfd_arch_m68k; + machine = 68020; + break; +#endif +#ifdef MC88MAGIC + case MC88MAGIC: + case MC88DMAGIC: + case MC88OMAGIC: + arch = bfd_arch_m88k; + machine = 88100; + break; +#endif +#ifdef Z8KMAGIC + case Z8KMAGIC: + arch = bfd_arch_z8k; + switch (internal_f->f_flags & F_MACHMASK) + { + case F_Z8001: + machine = bfd_mach_z8001; + break; + case F_Z8002: + machine = bfd_mach_z8002; + break; + default: + return false; + } + break; +#endif +#ifdef I960 +#ifdef I960ROMAGIC + case I960ROMAGIC: + case I960RWMAGIC: + arch = bfd_arch_i960; + switch (F_I960TYPE & internal_f->f_flags) + { + default: + case F_I960CORE: + machine = bfd_mach_i960_core; + break; + case F_I960KB: + machine = bfd_mach_i960_kb_sb; + break; + case F_I960MC: + machine = bfd_mach_i960_mc; + break; + case F_I960XA: + machine = bfd_mach_i960_xa; + break; + case F_I960CA: + machine = bfd_mach_i960_ca; + break; + case F_I960KA: + machine = bfd_mach_i960_ka_sa; + break; + } + break; +#endif +#endif + +#ifdef U802ROMAGIC + case U802ROMAGIC: + case U802WRMAGIC: + case U802TOCMAGIC: + arch = bfd_arch_rs6000; + machine = 6000; + break; +#endif + +#ifdef WE32KMAGIC + case WE32KMAGIC: + arch = bfd_arch_we32k; + machine = 0; + break; +#endif + +#ifdef H8300MAGIC + case H8300MAGIC: + arch = bfd_arch_h8300; + machine = bfd_mach_h8300; + /* !! FIXME this probably isn't the right place for this */ + abfd->flags |= BFD_IS_RELAXABLE; + break; +#endif + +#ifdef H8300HMAGIC + case H8300HMAGIC: + arch = bfd_arch_h8300; + machine = bfd_mach_h8300h; + /* !! FIXME this probably isn't the right place for this */ + abfd->flags |= BFD_IS_RELAXABLE; + break; +#endif + +#ifdef SH_ARCH_MAGIC + case SH_ARCH_MAGIC: + arch = bfd_arch_sh; + machine = 0; + break; +#endif + +#ifdef H8500MAGIC + case H8500MAGIC: + arch = bfd_arch_h8500; + machine = 0; + break; +#endif + +#ifdef SPARCMAGIC + case SPARCMAGIC: +#ifdef LYNXCOFFMAGIC + case LYNXCOFFMAGIC: +#endif + arch = bfd_arch_sparc; + machine = 0; + break; +#endif + + default: /* Unreadable input file type */ + arch = bfd_arch_obscure; + break; + } + + bfd_default_set_arch_mach (abfd, arch, machine); + return true; +} + +#ifdef SYMNAME_IN_DEBUG + +static boolean +symname_in_debug_hook (abfd, sym) + bfd * abfd; + struct internal_syment *sym; +{ + return SYMNAME_IN_DEBUG (sym) ? true : false; +} + +#else + +#define symname_in_debug_hook \ + (boolean (*) PARAMS ((bfd *, struct internal_syment *))) bfd_false + +#endif + +/* +SUBSUBSECTION + Writing relocations + + To write relocations, the back end steps though the + canonical relocation table and create an + @code{internal_reloc}. The symbol index to use is removed from + the @code{offset} field in the symbol table supplied. The + address comes directly from the sum of the section base + address and the relocation offset; the type is dug directly + from the howto field. Then the @code{internal_reloc} is + swapped into the shape of an @code{external_reloc} and written + out to disk. + +*/ + +static boolean +coff_write_relocs (abfd) + bfd * abfd; +{ + asection *s; + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + unsigned int i; + struct external_reloc dst; + + arelent **p = s->orelocation; + if (bfd_seek (abfd, s->rel_filepos, SEEK_SET) != 0) + return false; + for (i = 0; i < s->reloc_count; i++) + { + struct internal_reloc n; + arelent *q = p[i]; + memset ((PTR) & n, 0, sizeof (n)); + + n.r_vaddr = q->address + s->vma; + +#ifdef R_IHCONST + /* The 29k const/consth reloc pair is a real kludge. The consth + part doesn't have a symbol; it has an offset. So rebuilt + that here. */ + if (q->howto->type == R_IHCONST) + n.r_symndx = q->addend; + else +#endif + if (q->sym_ptr_ptr) + { + if (q->sym_ptr_ptr == bfd_abs_section_ptr->symbol_ptr_ptr) + /* This is a relocation relative to the absolute symbol. */ + n.r_symndx = -1; + else + { + n.r_symndx = get_index ((*(q->sym_ptr_ptr))); + /* Take notice if the symbol reloc points to a symbol + we don't have in our symbol table. What should we + do for this?? */ + if (n.r_symndx > obj_conv_table_size (abfd)) + abort (); + } + } + +#ifdef SWAP_OUT_RELOC_OFFSET + n.r_offset = q->addend; +#endif + +#ifdef SELECT_RELOC + /* Work out reloc type from what is required */ + SELECT_RELOC (n, q->howto); +#else + n.r_type = q->howto->type; +#endif + coff_swap_reloc_out (abfd, &n, &dst); + if (bfd_write ((PTR) & dst, 1, RELSZ, abfd) != RELSZ) + return false; + } + } + + return true; +} + +/* Set flags and magic number of a coff file from architecture and machine + type. Result is true if we can represent the arch&type, false if not. */ + +static boolean +coff_set_flags (abfd, magicp, flagsp) + bfd * abfd; + unsigned *magicp; + unsigned short *flagsp; +{ + switch (bfd_get_arch (abfd)) + { +#ifdef Z8KMAGIC + case bfd_arch_z8k: + *magicp = Z8KMAGIC; + switch (bfd_get_mach (abfd)) + { + case bfd_mach_z8001: + *flagsp = F_Z8001; + break; + case bfd_mach_z8002: + *flagsp = F_Z8002; + break; + default: + return false; + } + return true; +#endif +#ifdef I960ROMAGIC + + case bfd_arch_i960: + + { + unsigned flags; + *magicp = I960ROMAGIC; + /* + ((bfd_get_file_flags(abfd) & WP_TEXT) ? I960ROMAGIC : + I960RWMAGIC); FIXME??? + */ + switch (bfd_get_mach (abfd)) + { + case bfd_mach_i960_core: + flags = F_I960CORE; + break; + case bfd_mach_i960_kb_sb: + flags = F_I960KB; + break; + case bfd_mach_i960_mc: + flags = F_I960MC; + break; + case bfd_mach_i960_xa: + flags = F_I960XA; + break; + case bfd_mach_i960_ca: + flags = F_I960CA; + break; + case bfd_mach_i960_ka_sa: + flags = F_I960KA; + break; + default: + return false; + } + *flagsp = flags; + return true; + } + break; +#endif +#ifdef I386MAGIC + case bfd_arch_i386: + *magicp = I386MAGIC; +#ifdef LYNXOS + /* Just overwrite the usual value if we're doing Lynx. */ + *magicp = LYNXCOFFMAGIC; +#endif + return true; + break; +#endif +#ifdef MC68MAGIC + case bfd_arch_m68k: +#ifdef APOLLOM68KMAGIC + *magicp = APOLLO_COFF_VERSION_NUMBER; +#else + *magicp = MC68MAGIC; +#endif +#ifdef LYNXOS + /* Just overwrite the usual value if we're doing Lynx. */ + *magicp = LYNXCOFFMAGIC; +#endif + return true; + break; +#endif + +#ifdef MC88MAGIC + case bfd_arch_m88k: + *magicp = MC88OMAGIC; + return true; + break; +#endif +#ifdef H8300MAGIC + case bfd_arch_h8300: + switch (bfd_get_mach (abfd)) + { + case bfd_mach_h8300: + *magicp = H8300MAGIC; + return true; + case bfd_mach_h8300h: + *magicp = H8300HMAGIC; + return true; + } + break; +#endif + +#ifdef SH_ARCH_MAGIC + case bfd_arch_sh: + *magicp = SH_ARCH_MAGIC; + return true; + break; +#endif + +#ifdef SPARCMAGIC + case bfd_arch_sparc: + *magicp = SPARCMAGIC; +#ifdef LYNXOS + /* Just overwrite the usual value if we're doing Lynx. */ + *magicp = LYNXCOFFMAGIC; +#endif + return true; + break; +#endif + +#ifdef H8500MAGIC + case bfd_arch_h8500: + *magicp = H8500MAGIC; + return true; + break; +#endif +#ifdef A29K_MAGIC_BIG + case bfd_arch_a29k: + if (abfd->xvec->byteorder_big_p) + *magicp = A29K_MAGIC_BIG; + else + *magicp = A29K_MAGIC_LITTLE; + return true; + break; +#endif + +#ifdef WE32KMAGIC + case bfd_arch_we32k: + *magicp = WE32KMAGIC; + return true; + break; +#endif + +#ifdef U802TOCMAGIC + case bfd_arch_rs6000: + case bfd_arch_powerpc: + *magicp = U802TOCMAGIC; + return true; + break; +#endif + + default: /* Unknown architecture */ + /* return false; -- fall through to "return false" below, to avoid + "statement never reached" errors on the one below. */ + break; + } + + return false; +} + + +static boolean +coff_set_arch_mach (abfd, arch, machine) + bfd * abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + unsigned dummy1; + unsigned short dummy2; + + if (! bfd_default_set_arch_mach (abfd, arch, machine)) + return false; + + if (arch != bfd_arch_unknown && + coff_set_flags (abfd, &dummy1, &dummy2) != true) + return false; /* We can't represent this type */ + + return true; /* We're easy ... */ +} + + +/* Calculate the file position for each section. */ + +static void +coff_compute_section_file_positions (abfd) + bfd * abfd; +{ + asection *current; + asection *previous = (asection *) NULL; + file_ptr sofar = FILHSZ; +#ifndef I960 + file_ptr old_sofar; +#endif + if (bfd_get_start_address (abfd)) + { + /* A start address may have been added to the original file. In this + case it will need an optional header to record it. */ + abfd->flags |= EXEC_P; + } + + if (abfd->flags & EXEC_P) + sofar += AOUTSZ; + + sofar += abfd->section_count * SCNHSZ; + for (current = abfd->sections; + current != (asection *) NULL; + current = current->next) + { + + /* Only deal with sections which have contents */ + if (!(current->flags & SEC_HAS_CONTENTS)) + continue; + + /* Align the sections in the file to the same boundary on + which they are aligned in virtual memory. I960 doesn't + do this (FIXME) so we can stay in sync with Intel. 960 + doesn't yet page from files... */ +#ifndef I960 + { + /* make sure this section is aligned on the right boundary - by + padding the previous section up if necessary */ + + old_sofar = sofar; + sofar = BFD_ALIGN (sofar, 1 << current->alignment_power); + if (previous != (asection *) NULL) + { + previous->_raw_size += sofar - old_sofar; + } + } + +#endif + +#ifdef COFF_PAGE_SIZE + /* In demand paged files the low order bits of the file offset + must match the low order bits of the virtual address. */ + if ((abfd->flags & D_PAGED) != 0) + sofar += (current->vma - sofar) % COFF_PAGE_SIZE; +#endif + + current->filepos = sofar; + + sofar += current->_raw_size; +#ifndef I960 + /* 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; +#endif + +#ifdef _LIB + /* Force .lib sections to start at zero. The vma is then + incremented in coff_set_section_contents. This is right for + SVR3.2. */ + if (strcmp (current->name, _LIB) == 0) + bfd_set_section_vma (abfd, current, 0); +#endif + + previous = current; + } + obj_relocbase (abfd) = sofar; +} + +#ifndef RS6000COFF_C + +/* If .file, .text, .data, .bss symbols are missing, add them. */ +/* @@ Should we only be adding missing symbols, or overriding the aux + values for existing section symbols? */ +static boolean +coff_add_missing_symbols (abfd) + bfd *abfd; +{ + unsigned int nsyms = bfd_get_symcount (abfd); + asymbol **sympp = abfd->outsymbols; + asymbol **sympp2; + unsigned int i; + int need_text = 1, need_data = 1, need_bss = 1, need_file = 1; + + for (i = 0; i < nsyms; i++) + { + coff_symbol_type *csym = coff_symbol_from (abfd, sympp[i]); + CONST char *name; + if (csym) + { + /* only do this if there is a coff representation of the input + symbol */ + if (csym->native && csym->native->u.syment.n_sclass == C_FILE) + { + need_file = 0; + continue; + } + name = csym->symbol.name; + if (!name) + continue; + if (!strcmp (name, _TEXT)) + need_text = 0; +#ifdef APOLLO_M68 + else if (!strcmp (name, ".wtext")) + need_text = 0; +#endif + else if (!strcmp (name, _DATA)) + need_data = 0; + else if (!strcmp (name, _BSS)) + need_bss = 0; + } + } + /* Now i == bfd_get_symcount (abfd). */ + /* @@ For now, don't deal with .file symbol. */ + need_file = 0; + + if (!need_text && !need_data && !need_bss && !need_file) + return true; + nsyms += need_text + need_data + need_bss + need_file; + sympp2 = (asymbol **) bfd_alloc_by_size_t (abfd, nsyms * sizeof (asymbol *)); + if (!sympp2) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + memcpy (sympp2, sympp, i * sizeof (asymbol *)); + if (need_file) + { + /* @@ Generate fake .file symbol, in sympp2[i], and increment i. */ + abort (); + } + if (need_text) + sympp2[i++] = coff_section_symbol (abfd, _TEXT); + if (need_data) + sympp2[i++] = coff_section_symbol (abfd, _DATA); + if (need_bss) + sympp2[i++] = coff_section_symbol (abfd, _BSS); + BFD_ASSERT (i == nsyms); + bfd_set_symtab (abfd, sympp2, nsyms); + return true; +} + +#endif /* ! defined (RS6000COFF_C) */ + +/* SUPPRESS 558 */ +/* SUPPRESS 529 */ +static boolean +coff_write_object_contents (abfd) + bfd * abfd; +{ + asection *current; + unsigned int count; + + boolean hasrelocs = false; + boolean haslinno = false; + file_ptr reloc_base; + file_ptr lineno_base; + file_ptr sym_base; + file_ptr scn_base; + file_ptr data_base; + unsigned long reloc_size = 0; + unsigned long lnno_size = 0; + asection *text_sec = NULL; + asection *data_sec = NULL; + asection *bss_sec = NULL; + + struct internal_filehdr internal_f; + struct internal_aouthdr internal_a; + + + bfd_set_error (bfd_error_system_call); + /* Number the output sections, starting from one on the first section + with a name which doesn't start with a *. + @@ The code doesn't make this check. Is it supposed to be done, + or isn't it?? */ + count = 1; + for (current = abfd->sections; current != (asection *) NULL; + current = current->next) + { + current->target_index = count; + count++; + } + + if (abfd->output_has_begun == false) + { + coff_compute_section_file_positions (abfd); + } + + if (abfd->sections != (asection *) NULL) + { + scn_base = abfd->sections->filepos; + } + else + { + scn_base = 0; + } + if (bfd_seek (abfd, scn_base, SEEK_SET) != 0) + return false; + reloc_base = obj_relocbase (abfd); + + /* Make a pass through the symbol table to count line number entries and + put them into the correct asections */ + + lnno_size = coff_count_linenumbers (abfd) * LINESZ; + data_base = scn_base; + + /* Work out the size of the reloc and linno areas */ + + for (current = abfd->sections; current != NULL; current = + current->next) + { + /* We give section headers to +ve indexes */ + if (current->target_index > 0) + { + + reloc_size += current->reloc_count * RELSZ; + data_base += SCNHSZ; + } + + } + + lineno_base = reloc_base + reloc_size; + sym_base = lineno_base + lnno_size; + + /* Indicate in each section->line_filepos its actual file address */ + for (current = abfd->sections; current != NULL; current = + current->next) + { + if (current->target_index > 0) + { + + if (current->lineno_count) + { + current->line_filepos = lineno_base; + current->moving_line_filepos = lineno_base; + lineno_base += current->lineno_count * LINESZ; + } + else + { + current->line_filepos = 0; + } + if (current->reloc_count) + { + current->rel_filepos = reloc_base; + reloc_base += current->reloc_count * RELSZ; + } + else + { + current->rel_filepos = 0; + } + } + } + + + + /* Write section headers to the file. */ + internal_f.f_nscns = 0; + if (bfd_seek (abfd, + (file_ptr) ((abfd->flags & EXEC_P) ? + (FILHSZ + AOUTSZ) : FILHSZ), + SEEK_SET) + != 0) + return false; + + { +#if 0 + unsigned int pad = abfd->flags & D_PAGED ? data_base : 0; +#endif + unsigned int pad = 0; + + for (current = abfd->sections; + current != NULL; + current = current->next) + { + struct internal_scnhdr section; + if (current->target_index > 0) + { + internal_f.f_nscns++; + strncpy (&(section.s_name[0]), current->name, 8); +#ifdef _LIB + /* Always set s_vaddr of .lib to 0. This is right for SVR3.2 + Ian Taylor . */ + if (strcmp (current->name, _LIB) == 0) + section.s_vaddr = 0; + else +#endif + section.s_vaddr = current->lma + pad; + section.s_paddr = current->lma + pad; + section.s_size = current->_raw_size - pad; + /* + If this section has no size or is unloadable then the scnptr + will be 0 too + */ + if (current->_raw_size - pad == 0 || + (current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + { + section.s_scnptr = 0; + } + else + { + section.s_scnptr = current->filepos; + } + section.s_relptr = current->rel_filepos; + section.s_lnnoptr = current->line_filepos; + section.s_nreloc = current->reloc_count; + section.s_nlnno = current->lineno_count; + if (current->reloc_count != 0) + hasrelocs = true; + if (current->lineno_count != 0) + haslinno = true; + + section.s_flags = sec_to_styp_flags (current->name, current->flags); + + if (!strcmp (current->name, _TEXT)) + { + text_sec = current; + } + else if (!strcmp (current->name, _DATA)) + { + data_sec = current; +#ifdef TWO_DATA_SECS + } + else if (!strcmp (current->name, ".data2")) + { + data_sec = current; +#endif /* TWO_DATA_SECS */ + } + else if (!strcmp (current->name, _BSS)) + { + bss_sec = current; + } + +#ifdef I960 + section.s_align = (current->alignment_power + ? 1 << current->alignment_power + : 0); + +#endif + { + SCNHDR buff; + + coff_swap_scnhdr_out (abfd, §ion, &buff); + if (bfd_write ((PTR) (&buff), 1, SCNHSZ, abfd) != SCNHSZ) + return false; + + } + + pad = 0; + } + } + } + + + /* OK, now set up the filehdr... */ + + /* Don't include the internal abs section in the section count */ + + /* + 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) + internal_f.f_symptr = sym_base; + else + internal_f.f_symptr = 0; + + internal_f.f_flags = 0; + + if (abfd->flags & EXEC_P) + internal_f.f_opthdr = AOUTSZ; + else + internal_f.f_opthdr = 0; + + if (!hasrelocs) + internal_f.f_flags |= F_RELFLG; + if (!haslinno) + internal_f.f_flags |= F_LNNO; + if (0 == bfd_get_symcount (abfd)) + 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; + + /* + FIXME, should do something about the other byte orders and + architectures. + */ + + memset (&internal_a, 0, sizeof internal_a); + + /* Set up architecture-dependent stuff */ + + { + unsigned int magic = 0; + unsigned short flags = 0; + coff_set_flags (abfd, &magic, &flags); + internal_f.f_magic = magic; + internal_f.f_flags |= flags; + /* ...and the "opt"hdr... */ + +#ifdef A29K +#ifdef ULTRA3 /* NYU's machine */ + /* FIXME: This is a bogus check. I really want to see if there + * is a .shbss or a .shdata section, if so then set the magic + * number to indicate a shared data executable. + */ + if (internal_f.f_nscns >= 7) + internal_a.magic = SHMAGIC; /* Shared magic */ + else +#endif /* ULTRA3 */ + internal_a.magic = NMAGIC;/* Assume separate i/d */ +#define __A_MAGIC_SET__ +#endif /* A29K */ +#ifdef I960 + internal_a.magic = (magic == I960ROMAGIC ? NMAGIC : OMAGIC); +#define __A_MAGIC_SET__ +#endif /* I960 */ +#if M88 +#define __A_MAGIC_SET__ + internal_a.magic = PAGEMAGICBCS; +#endif /* M88 */ + +#if APOLLO_M68 +#define __A_MAGIC_SET__ + internal_a.magic = APOLLO_COFF_VERSION_NUMBER; +#endif + +#if M68 || WE32K +#define __A_MAGIC_SET__ + /* Never was anything here for the 68k */ +#endif /* M68 || WE32K */ + +#if I386 +#define __A_MAGIC_SET__ + internal_a.magic = ZMAGIC; +#endif /* I386 */ + +#if RS6000COFF_C +#define __A_MAGIC_SET__ + internal_a.magic = (abfd->flags & D_PAGED) ? RS6K_AOUTHDR_ZMAGIC : + (abfd->flags & WP_TEXT) ? RS6K_AOUTHDR_NMAGIC : + RS6K_AOUTHDR_OMAGIC; +#endif + +#ifndef __A_MAGIC_SET__ +#include "Your aouthdr magic number is not being set!" +#else +#undef __A_MAGIC_SET__ +#endif + } + /* Now should write relocs, strings, syms */ + obj_sym_filepos (abfd) = sym_base; + + if (bfd_get_symcount (abfd) != 0) + { +#ifndef RS6000COFF_C + if (!coff_add_missing_symbols (abfd)) + return false; +#endif + if (!coff_renumber_symbols (abfd)) + return false; + coff_mangle_symbols (abfd); + if (! coff_write_symbols (abfd)) + return false; + if (! coff_write_linenumbers (abfd)) + return false; + if (! coff_write_relocs (abfd)) + return false; + } + if (text_sec) + { + internal_a.tsize = bfd_get_section_size_before_reloc (text_sec); + internal_a.text_start = internal_a.tsize ? text_sec->vma : 0; + } + if (data_sec) + { + internal_a.dsize = bfd_get_section_size_before_reloc (data_sec); + internal_a.data_start = internal_a.dsize ? data_sec->vma : 0; + } + if (bss_sec) + { + internal_a.bsize = bfd_get_section_size_before_reloc (bss_sec); + } + + internal_a.entry = bfd_get_start_address (abfd); + internal_f.f_nsyms = bfd_get_symcount (abfd); + + /* now write them */ + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + return false; + { + FILHDR buff; + coff_swap_filehdr_out (abfd, (PTR) & internal_f, (PTR) & buff); + if (bfd_write ((PTR) & buff, 1, FILHSZ, abfd) != FILHSZ) + return false; + } + if (abfd->flags & EXEC_P) + { + AOUTHDR buff; + coff_swap_aouthdr_out (abfd, (PTR) & internal_a, (PTR) & buff); + if (bfd_write ((PTR) & buff, 1, AOUTSZ, abfd) != AOUTSZ) + return false; + } + return true; +} + +static boolean +coff_set_section_contents (abfd, section, location, offset, count) + bfd * abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (abfd->output_has_begun == false) /* set by bfd.c handler */ + coff_compute_section_file_positions (abfd); + +#ifdef _LIB + /* If this is a .lib section, bump the vma address so that it + winds up being the number of .lib sections output. This is + right for SVR3.2. Shared libraries should probably get more + generic support. Ian Taylor . */ + if (strcmp (section->name, _LIB) == 0) + ++section->lma; +#endif + + /* Don't write out bss sections - one way to do this is to + see if the filepos has not been set. */ + if (section->filepos == 0) + return true; + + if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) != 0) + return false; + + if (count != 0) + { + return (bfd_write (location, 1, count, abfd) == count) ? true : false; + } + return true; +} +#if 0 +static boolean +coff_close_and_cleanup (abfd) + bfd *abfd; +{ + if (!bfd_read_p (abfd)) + switch (abfd->format) + { + case bfd_archive: + if (!_bfd_write_archive_contents (abfd)) + return false; + break; + case bfd_object: + if (!coff_write_object_contents (abfd)) + return false; + break; + default: + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + /* We depend on bfd_close to free all the memory on the obstack. */ + /* FIXME if bfd_release is not using obstacks! */ + return true; +} + +#endif + +static PTR +buy_and_read (abfd, where, seek_direction, size) + bfd *abfd; + file_ptr where; + int seek_direction; + size_t size; +{ + PTR area = (PTR) bfd_alloc (abfd, size); + if (!area) + { + bfd_set_error (bfd_error_no_memory); + return (NULL); + } + if (bfd_seek (abfd, where, seek_direction) != 0 + || bfd_read (area, 1, size, abfd) != size) + return (NULL); + return (area); +} /* buy_and_read() */ + +/* +SUBSUBSECTION + Reading linenumbers + + Creating the linenumber table is done by reading in the entire + coff linenumber table, and creating another table for internal use. + + A coff linenumber table is structured so that each function + is marked as having a line number of 0. Each line within the + function is an offset from the first line in the function. The + base of the line number information for the table is stored in + the symbol associated with the function. + + The information is copied from the external to the internal + table, and each symbol which marks a function is marked by + pointing its... + + How does this work ? + +*/ + +static boolean +coff_slurp_line_table (abfd, asect) + bfd *abfd; + asection *asect; +{ + LINENO *native_lineno; + alent *lineno_cache; + + BFD_ASSERT (asect->lineno == (alent *) NULL); + + native_lineno = (LINENO *) buy_and_read (abfd, + asect->line_filepos, + SEEK_SET, + (size_t) (LINESZ * + asect->lineno_count)); + lineno_cache = + (alent *) bfd_alloc (abfd, (size_t) ((asect->lineno_count + 1) * sizeof (alent))); + if (lineno_cache == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + else + { + unsigned int counter = 0; + alent *cache_ptr = lineno_cache; + LINENO *src = native_lineno; + + while (counter < asect->lineno_count) + { + struct internal_lineno dst; + coff_swap_lineno_in (abfd, src, &dst); + cache_ptr->line_number = dst.l_lnno; + + if (cache_ptr->line_number == 0) + { + coff_symbol_type *sym = + (coff_symbol_type *) (dst.l_addr.l_symndx + + obj_raw_syments (abfd))->u.syment._n._n_n._n_zeroes; + cache_ptr->u.sym = (asymbol *) sym; + sym->lineno = cache_ptr; + } + else + { + cache_ptr->u.offset = dst.l_addr.l_paddr + - bfd_section_vma (abfd, asect); + } /* If no linenumber expect a symbol index */ + + cache_ptr++; + src++; + counter++; + } + cache_ptr->line_number = 0; + + } + asect->lineno = lineno_cache; + /* FIXME, free native_lineno here, or use alloca or something. */ + return true; +} + +static boolean +coff_slurp_symbol_table (abfd) + bfd * abfd; +{ + combined_entry_type *native_symbols; + coff_symbol_type *cached_area; + unsigned int *table_ptr; + + unsigned int number_of_symbols = 0; + if (obj_symbols (abfd)) + return true; + if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0) + return false; + + /* Read in the symbol table */ + if ((native_symbols = coff_get_normalized_symtab (abfd)) == NULL) + { + return (false); + } /* on error */ + + /* Allocate enough room for all the symbols in cached form */ + cached_area = + (coff_symbol_type *) + bfd_alloc (abfd, (size_t) (bfd_get_symcount (abfd) * sizeof (coff_symbol_type))); + + if (cached_area == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } /* on error */ + table_ptr = + (unsigned int *) + bfd_alloc (abfd, (size_t) (bfd_get_symcount (abfd) * sizeof (unsigned int))); + + if (table_ptr == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + else + { + coff_symbol_type *dst = cached_area; + unsigned int last_native_index = bfd_get_symcount (abfd); + unsigned int this_index = 0; + while (this_index < last_native_index) + { + combined_entry_type *src = native_symbols + this_index; + table_ptr[this_index] = number_of_symbols; + dst->symbol.the_bfd = abfd; + + dst->symbol.name = (char *) (src->u.syment._n._n_n._n_offset); + /* We use the native name field to point to the cached field. */ + src->u.syment._n._n_n._n_zeroes = (long) dst; + dst->symbol.section = coff_section_from_bfd_index (abfd, + src->u.syment.n_scnum); + dst->symbol.flags = 0; + dst->done_lineno = false; + + switch (src->u.syment.n_sclass) + { +#ifdef I960 + case C_LEAFEXT: +#if 0 + dst->symbol.value = src->u.syment.n_value - dst->symbol.section->vma; + dst->symbol.flags = BSF_EXPORT | BSF_GLOBAL; + dst->symbol.flags |= BSF_NOT_AT_END; +#endif + /* Fall through to next case */ + +#endif + + case C_EXT: +#ifdef RS6000COFF_C + case C_HIDEXT: +#endif + if ((src->u.syment.n_scnum) == 0) + { + if ((src->u.syment.n_value) == 0) + { + dst->symbol.section = bfd_und_section_ptr; + dst->symbol.value = 0; + } + else + { + dst->symbol.section = bfd_com_section_ptr; + dst->symbol.value = (src->u.syment.n_value); + } + } + else + { + /* + Base the value as an index from the base of the + section + */ + + dst->symbol.flags = BSF_EXPORT | BSF_GLOBAL; + dst->symbol.value = src->u.syment.n_value - dst->symbol.section->vma; + + if (ISFCN ((src->u.syment.n_type))) + { + /* + A function ext does not go at the end of a file + */ + dst->symbol.flags |= BSF_NOT_AT_END; + } + } + +#ifdef RS6000COFF_C + /* If this symbol has a csect aux of type LD, the scnlen field + is actually the index of the containing csect symbol. We + need to pointerize it. */ + if (src->u.syment.n_numaux > 0) + { + combined_entry_type *aux; + + aux = src + src->u.syment.n_numaux - 1; + if (SMTYP_SMTYP (aux->u.auxent.x_csect.x_smtyp) == XTY_LD) + { + aux->u.auxent.x_csect.x_scnlen.p = + native_symbols + aux->u.auxent.x_csect.x_scnlen.l; + aux->fix_scnlen = 1; + } + } +#endif + + break; + + case C_STAT: /* static */ +#ifdef I960 + case C_LEAFSTAT: /* static leaf procedure */ +#endif + case C_LABEL: /* label */ + if (src->u.syment.n_scnum == -2) + dst->symbol.flags = BSF_DEBUGGING; + else + dst->symbol.flags = BSF_LOCAL; + /* + Base the value as an index from the base of the section, if + there is one + */ + if (dst->symbol.section) + dst->symbol.value = (src->u.syment.n_value) - + dst->symbol.section->vma; + else + dst->symbol.value = (src->u.syment.n_value); + break; + + case C_MOS: /* member of structure */ + case C_EOS: /* end of structure */ +#ifdef NOTDEF /* C_AUTOARG has the same value */ +#ifdef C_GLBLREG + case C_GLBLREG: /* A29k-specific storage class */ +#endif +#endif + case C_REGPARM: /* register parameter */ + case C_REG: /* register variable */ +#ifdef C_AUTOARG + case C_AUTOARG: /* 960-specific storage class */ +#endif + case C_TPDEF: /* type definition */ + case C_ARG: + case C_AUTO: /* automatic variable */ + case C_FIELD: /* bit field */ + case C_ENTAG: /* enumeration tag */ + case C_MOE: /* member of enumeration */ + case C_MOU: /* member of union */ + case C_UNTAG: /* union tag */ + dst->symbol.flags = BSF_DEBUGGING; + dst->symbol.value = (src->u.syment.n_value); + break; + + case C_FILE: /* file name */ + case C_STRTAG: /* structure tag */ +#ifdef RS6000COFF_C + case C_BINCL: /* beginning of include file */ + case C_EINCL: /* ending of include file */ + case C_GSYM: + case C_LSYM: + case C_PSYM: + case C_RSYM: + case C_RPSYM: + case C_STSYM: + case C_DECL: + case C_ENTRY: + case C_FUN: + case C_ESTAT: +#endif + dst->symbol.flags = BSF_DEBUGGING; + dst->symbol.value = (src->u.syment.n_value); + break; + +#ifdef RS6000COFF_C + case C_BSTAT: + dst->symbol.flags = BSF_DEBUGGING; + dst->symbol.value = src->u.syment.n_value; + + /* The value is actually a symbol index. Save a pointer to + the symbol instead of the index. FIXME: This should use a + union. */ + src->u.syment.n_value = + (long) (native_symbols + src->u.syment.n_value); + src->fix_value = 1; + break; +#endif + + case C_BLOCK: /* ".bb" or ".eb" */ + case C_FCN: /* ".bf" or ".ef" */ + case C_EFCN: /* physical end of function */ + dst->symbol.flags = BSF_LOCAL; + /* + Base the value as an index from the base of the section + */ + dst->symbol.value = (src->u.syment.n_value) - dst->symbol.section->vma; + break; + + case C_NULL: + case C_EXTDEF: /* external definition */ + case C_ULABEL: /* undefined label */ + case C_USTATIC: /* undefined static */ + case C_LINE: /* line # reformatted as symbol table entry */ + case C_ALIAS: /* duplicate tag */ + case C_HIDDEN: /* ext symbol in dmert public lib */ + default: + + fprintf (stderr, "Unrecognized storage class %d (assuming debugging)\n for %s symbol `%s'\n", + src->u.syment.n_sclass, dst->symbol.section->name, + dst->symbol.name); +/* abort();*/ + dst->symbol.flags = BSF_DEBUGGING; + dst->symbol.value = (src->u.syment.n_value); + break; + } + +/* BFD_ASSERT(dst->symbol.flags != 0);*/ + + dst->native = src; + + dst->symbol.udata = 0; + dst->lineno = (alent *) NULL; + this_index += (src->u.syment.n_numaux) + 1; + dst++; + number_of_symbols++; + } /* walk the native symtab */ + } /* bfdize the native symtab */ + + obj_symbols (abfd) = cached_area; + obj_raw_syments (abfd) = native_symbols; + + obj_conv_table_size (abfd) = bfd_get_symcount (abfd); + bfd_get_symcount (abfd) = number_of_symbols; + obj_convert (abfd) = table_ptr; + /* Slurp the line tables for each section too */ + { + asection *p; + p = abfd->sections; + while (p) + { + coff_slurp_line_table (abfd, p); + p = p->next; + } + } + return true; +} /* coff_slurp_symbol_table() */ + +/* +SUBSUBSECTION + Reading relocations + + Coff relocations are easily transformed into the internal BFD form + (@code{arelent}). + + Reading a coff relocation table is done in the following stages: + + o Read the entire coff relocation table into memory. + + o Process each relocation in turn; first swap it from the + external to the internal form. + + o Turn the symbol referenced in the relocation's symbol index + into a pointer into the canonical symbol table. + This table is the same as the one returned by a call to + @code{bfd_canonicalize_symtab}. The back end will call that + routine and save the result if a canonicalization hasn't been done. + + o The reloc index is turned into a pointer to a howto + structure, in a back end specific way. For instance, the 386 + and 960 use the @code{r_type} to directly produce an index + into a howto table vector; the 88k subtracts a number from the + @code{r_type} field and creates an addend field. + + +*/ + +#ifndef CALC_ADDEND +#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ + { \ + coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ + if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ + coffsym = (obj_symbols (abfd) \ + + (cache_ptr->sym_ptr_ptr - symbols)); \ + else if (ptr) \ + coffsym = coff_symbol_from (abfd, ptr); \ + if (coffsym != (coff_symbol_type *) NULL \ + && coffsym->native->u.syment.n_scnum == 0) \ + cache_ptr->addend = 0; \ + else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ + && ptr->section != (asection *) NULL) \ + cache_ptr->addend = - (ptr->section->vma + ptr->value); \ + else \ + cache_ptr->addend = 0; \ + } +#endif + +static boolean +coff_slurp_reloc_table (abfd, asect, symbols) + bfd * abfd; + sec_ptr asect; + asymbol ** symbols; +{ + RELOC *native_relocs; + arelent *reloc_cache; + arelent *cache_ptr; + + unsigned int idx; + + if (asect->relocation) + return true; + if (asect->reloc_count == 0) + return true; + if (asect->flags & SEC_CONSTRUCTOR) + return true; + if (!coff_slurp_symbol_table (abfd)) + return false; + native_relocs = + (RELOC *) buy_and_read (abfd, + asect->rel_filepos, + SEEK_SET, + (size_t) (RELSZ * + asect->reloc_count)); + reloc_cache = (arelent *) + bfd_alloc (abfd, (size_t) (asect->reloc_count * sizeof (arelent))); + + if (reloc_cache == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + + for (idx = 0; idx < asect->reloc_count; idx++) + { +#ifdef RELOC_PROCESSING + struct internal_reloc dst; + struct external_reloc *src; + + cache_ptr = reloc_cache + idx; + src = native_relocs + idx; + bfd_swap_reloc_in (abfd, src, &dst); + + RELOC_PROCESSING (cache_ptr, &dst, symbols, abfd, asect); +#else + struct internal_reloc dst; + asymbol *ptr; + struct external_reloc *src; + + cache_ptr = reloc_cache + idx; + src = native_relocs + idx; + + bfd_swap_reloc_in (abfd, src, &dst); + + + cache_ptr->address = dst.r_vaddr; + + if (dst.r_symndx != -1) + { + /* @@ Should never be greater than count of symbols! */ + if (dst.r_symndx >= obj_conv_table_size (abfd)) + abort (); + cache_ptr->sym_ptr_ptr = symbols + obj_convert (abfd)[dst.r_symndx]; + ptr = *(cache_ptr->sym_ptr_ptr); + } + else + { + cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + ptr = 0; + } + + /* The symbols definitions that we have read in have been + relocated as if their sections started at 0. But the offsets + refering to the symbols in the raw data have not been + modified, so we have to have a negative addend to compensate. + + Note that symbols which used to be common must be left alone */ + + /* Calculate any reloc addend by looking at the symbol */ + CALC_ADDEND (abfd, ptr, dst, cache_ptr); + + cache_ptr->address -= asect->vma; +/* !! cache_ptr->section = (asection *) NULL;*/ + + /* Fill in the cache_ptr->howto field from dst.r_type */ + RTYPE2HOWTO (cache_ptr, &dst); +#endif + + } + + asect->relocation = reloc_cache; + return true; +} + + +/* This is stupid. This function should be a boolean predicate. */ +static long +coff_canonicalize_reloc (abfd, section, relptr, symbols) + bfd * abfd; + sec_ptr section; + arelent ** relptr; + asymbol ** symbols; +{ + arelent *tblptr = section->relocation; + unsigned int count = 0; + + + if (section->flags & SEC_CONSTRUCTOR) + { + /* this section has relocs made up by us, they are not in the + file, so take them out of their chain and place them into + the data area provided */ + arelent_chain *chain = section->constructor_chain; + for (count = 0; count < section->reloc_count; count++) + { + *relptr++ = &chain->relent; + chain = chain->next; + } + + } + else + { + if (! coff_slurp_reloc_table (abfd, section, symbols)) + return -1; + + tblptr = section->relocation; + + for (; count++ < section->reloc_count;) + *relptr++ = tblptr++; + + + } + *relptr = 0; + return section->reloc_count; +} + +#ifdef GNU960 +file_ptr +coff_sym_filepos (abfd) + bfd *abfd; +{ + return obj_sym_filepos (abfd); +} +#endif + +#ifndef coff_reloc16_estimate +#define coff_reloc16_estimate dummy_reloc16_estimate + +static int +dummy_reloc16_estimate (abfd, input_section, reloc, shrink, link_info) + bfd *abfd; + asection *input_section; + arelent *reloc; + unsigned int shrink; + struct bfd_link_info *link_info; +{ + abort (); +} + +#endif + +#ifndef coff_reloc16_extra_cases +#define coff_reloc16_extra_cases dummy_reloc16_extra_cases +/* This works even if abort is not declared in any header file. */ +static void +dummy_reloc16_extra_cases (abfd, link_info, link_order, reloc, data, src_ptr, + dst_ptr) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + arelent *reloc; + bfd_byte *data; + unsigned int *src_ptr; + unsigned int *dst_ptr; +{ + fprintf (stderr, "%s\n", reloc->howto->name); + abort (); +} +#endif + +static CONST bfd_coff_backend_data bfd_coff_std_swap_table = +{ + coff_swap_aux_in, coff_swap_sym_in, coff_swap_lineno_in, + coff_swap_aux_out, coff_swap_sym_out, + coff_swap_lineno_out, coff_swap_reloc_out, + coff_swap_filehdr_out, coff_swap_aouthdr_out, + coff_swap_scnhdr_out, + FILHSZ, AOUTSZ, SCNHSZ, SYMESZ, AUXESZ, LINESZ, +#ifdef COFF_LONG_FILENAMES + true, +#else + false, +#endif + coff_swap_filehdr_in, coff_swap_aouthdr_in, coff_swap_scnhdr_in, + coff_bad_format_hook, coff_set_arch_mach_hook, coff_mkobject_hook, + styp_to_sec_flags, coff_make_section_hook, coff_set_alignment_hook, + coff_slurp_symbol_table, symname_in_debug_hook, + coff_reloc16_extra_cases, coff_reloc16_estimate +}; + +#define coff_close_and_cleanup _bfd_generic_close_and_cleanup +#define coff_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define coff_get_section_contents _bfd_generic_get_section_contents + +#define coff_bfd_copy_private_section_data \ + _bfd_generic_bfd_copy_private_section_data +#define coff_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data + +#ifndef coff_bfd_is_local_label +#define coff_bfd_is_local_label bfd_generic_is_local_label +#endif + +/* The reloc lookup routine must be supplied by each individual COFF + backend. */ +#ifndef coff_bfd_reloc_type_lookup +#define coff_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup +#endif + +#define coff_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define coff_bfd_relax_section bfd_generic_relax_section +#define coff_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define coff_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define coff_bfd_final_link _bfd_generic_final_link diff --git a/gnu/usr.bin/gdb/bfd/coffswap.h b/gnu/usr.bin/gdb/bfd/coffswap.h new file mode 100644 index 00000000000..74cc46ebe21 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/coffswap.h @@ -0,0 +1,741 @@ +/* Generic COFF swapping routines, 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. */ + +/* This file contains routines used to swap COFF data. It is a header + file because the details of swapping depend on the details of the + structures used by each COFF implementation. This is included by + coffcode.h, as well as by the ECOFF backend. + + Any file which uses this must first include "coff/internal.h" and + "coff/CPU.h". The functions will then be correct for that CPU. */ + +#define PUTWORD bfd_h_put_32 +#define PUTHALF bfd_h_put_16 +#define PUTBYTE bfd_h_put_8 + +#ifndef GET_FCN_LNNOPTR +#define GET_FCN_LNNOPTR(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) +#endif + +#ifndef GET_FCN_ENDNDX +#define GET_FCN_ENDNDX(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_endndx) +#endif + +#ifndef PUT_FCN_LNNOPTR +#define PUT_FCN_LNNOPTR(abfd, in, ext) PUTWORD(abfd, in, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) +#endif +#ifndef PUT_FCN_ENDNDX +#define PUT_FCN_ENDNDX(abfd, in, ext) PUTWORD(abfd, in, (bfd_byte *) ext->x_sym.x_fcnary.x_fcn.x_endndx) +#endif +#ifndef GET_LNSZ_LNNO +#define GET_LNSZ_LNNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_lnno) +#endif +#ifndef GET_LNSZ_SIZE +#define GET_LNSZ_SIZE(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_misc.x_lnsz.x_size) +#endif +#ifndef PUT_LNSZ_LNNO +#define PUT_LNSZ_LNNO(abfd, in, ext) bfd_h_put_16(abfd, in, (bfd_byte *)ext->x_sym.x_misc.x_lnsz.x_lnno) +#endif +#ifndef PUT_LNSZ_SIZE +#define PUT_LNSZ_SIZE(abfd, in, ext) bfd_h_put_16(abfd, in, (bfd_byte*) ext->x_sym.x_misc.x_lnsz.x_size) +#endif +#ifndef GET_SCN_SCNLEN +#define GET_SCN_SCNLEN(abfd, ext) bfd_h_get_32(abfd, (bfd_byte *) ext->x_scn.x_scnlen) +#endif +#ifndef GET_SCN_NRELOC +#define GET_SCN_NRELOC(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *)ext->x_scn.x_nreloc) +#endif +#ifndef GET_SCN_NLINNO +#define GET_SCN_NLINNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *)ext->x_scn.x_nlinno) +#endif +#ifndef PUT_SCN_SCNLEN +#define PUT_SCN_SCNLEN(abfd,in, ext) bfd_h_put_32(abfd, in, (bfd_byte *) ext->x_scn.x_scnlen) +#endif +#ifndef PUT_SCN_NRELOC +#define PUT_SCN_NRELOC(abfd,in, ext) bfd_h_put_16(abfd, in, (bfd_byte *)ext->x_scn.x_nreloc) +#endif +#ifndef PUT_SCN_NLINNO +#define PUT_SCN_NLINNO(abfd,in, ext) bfd_h_put_16(abfd,in, (bfd_byte *) ext->x_scn.x_nlinno) +#endif +#ifndef GET_LINENO_LNNO +#define GET_LINENO_LNNO(abfd, ext) bfd_h_get_16(abfd, (bfd_byte *) (ext->l_lnno)); +#endif +#ifndef PUT_LINENO_LNNO +#define PUT_LINENO_LNNO(abfd,val, ext) bfd_h_put_16(abfd,val, (bfd_byte *) (ext->l_lnno)); +#endif + +/* The f_symptr field in the filehdr is sometimes 64 bits. */ +#ifndef GET_FILEHDR_SYMPTR +#define GET_FILEHDR_SYMPTR bfd_h_get_32 +#endif +#ifndef PUT_FILEHDR_SYMPTR +#define PUT_FILEHDR_SYMPTR bfd_h_put_32 +#endif + +/* Some fields in the aouthdr are sometimes 64 bits. */ +#ifndef GET_AOUTHDR_TSIZE +#define GET_AOUTHDR_TSIZE bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_TSIZE +#define PUT_AOUTHDR_TSIZE bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_DSIZE +#define GET_AOUTHDR_DSIZE bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_DSIZE +#define PUT_AOUTHDR_DSIZE bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_BSIZE +#define GET_AOUTHDR_BSIZE bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_BSIZE +#define PUT_AOUTHDR_BSIZE bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_ENTRY +#define GET_AOUTHDR_ENTRY bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_ENTRY +#define PUT_AOUTHDR_ENTRY bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_TEXT_START +#define GET_AOUTHDR_TEXT_START bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_TEXT_START +#define PUT_AOUTHDR_TEXT_START bfd_h_put_32 +#endif +#ifndef GET_AOUTHDR_DATA_START +#define GET_AOUTHDR_DATA_START bfd_h_get_32 +#endif +#ifndef PUT_AOUTHDR_DATA_START +#define PUT_AOUTHDR_DATA_START bfd_h_put_32 +#endif + +/* Some fields in the scnhdr are sometimes 64 bits. */ +#ifndef GET_SCNHDR_PADDR +#define GET_SCNHDR_PADDR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_PADDR +#define PUT_SCNHDR_PADDR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_VADDR +#define GET_SCNHDR_VADDR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_VADDR +#define PUT_SCNHDR_VADDR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_SIZE +#define GET_SCNHDR_SIZE bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_SIZE +#define PUT_SCNHDR_SIZE bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_SCNPTR +#define GET_SCNHDR_SCNPTR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_SCNPTR +#define PUT_SCNHDR_SCNPTR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_RELPTR +#define GET_SCNHDR_RELPTR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_RELPTR +#define PUT_SCNHDR_RELPTR bfd_h_put_32 +#endif +#ifndef GET_SCNHDR_LNNOPTR +#define GET_SCNHDR_LNNOPTR bfd_h_get_32 +#endif +#ifndef PUT_SCNHDR_LNNOPTR +#define PUT_SCNHDR_LNNOPTR bfd_h_put_32 +#endif + +#ifndef NO_COFF_RELOCS + +static void +bfd_swap_reloc_in (abfd, reloc_src, reloc_dst) + bfd *abfd; + RELOC *reloc_src; + struct internal_reloc *reloc_dst; +{ + reloc_dst->r_vaddr = bfd_h_get_32(abfd, (bfd_byte *)reloc_src->r_vaddr); + reloc_dst->r_symndx = bfd_h_get_signed_32(abfd, (bfd_byte *) reloc_src->r_symndx); + +#ifdef RS6000COFF_C + reloc_dst->r_type = bfd_h_get_8(abfd, reloc_src->r_type); + reloc_dst->r_size = bfd_h_get_8(abfd, reloc_src->r_size); +#else + reloc_dst->r_type = bfd_h_get_16(abfd, (bfd_byte *) reloc_src->r_type); +#endif + +#ifdef SWAP_IN_RELOC_OFFSET + reloc_dst->r_offset = SWAP_IN_RELOC_OFFSET(abfd, + (bfd_byte *) reloc_src->r_offset); +#endif +} + + +static unsigned int +coff_swap_reloc_out (abfd, src, dst) + bfd *abfd; + PTR src; + PTR dst; +{ + struct internal_reloc *reloc_src = (struct internal_reloc *)src; + struct external_reloc *reloc_dst = (struct external_reloc *)dst; + bfd_h_put_32(abfd, reloc_src->r_vaddr, (bfd_byte *) reloc_dst->r_vaddr); + bfd_h_put_32(abfd, reloc_src->r_symndx, (bfd_byte *) reloc_dst->r_symndx); + +#ifdef RS6000COFF_C + bfd_h_put_8 (abfd, reloc_src->r_type, (bfd_byte *) reloc_dst->r_type); + bfd_h_put_8 (abfd, reloc_src->r_size, (bfd_byte *) reloc_dst->r_size); +#else + bfd_h_put_16(abfd, reloc_src->r_type, (bfd_byte *) + reloc_dst->r_type); +#endif + +#ifdef SWAP_OUT_RELOC_OFFSET + SWAP_OUT_RELOC_OFFSET(abfd, + reloc_src->r_offset, + (bfd_byte *) reloc_dst->r_offset); +#endif +#ifdef SWAP_OUT_RELOC_EXTRA + SWAP_OUT_RELOC_EXTRA(abfd,reloc_src, reloc_dst); +#endif + + return sizeof(struct external_reloc); +} + +#endif /* NO_COFF_RELOCS */ + +static void +coff_swap_filehdr_in (abfd, src, dst) + bfd *abfd; + PTR src; + PTR dst; +{ + FILHDR *filehdr_src = (FILHDR *) src; + struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst; + filehdr_dst->f_magic = bfd_h_get_16(abfd, (bfd_byte *) filehdr_src->f_magic); + filehdr_dst->f_nscns = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_nscns); + filehdr_dst->f_timdat = bfd_h_get_32(abfd, (bfd_byte *)filehdr_src-> f_timdat); + filehdr_dst->f_symptr = + GET_FILEHDR_SYMPTR (abfd, (bfd_byte *) filehdr_src->f_symptr); + filehdr_dst->f_nsyms = bfd_h_get_32(abfd, (bfd_byte *)filehdr_src-> f_nsyms); + filehdr_dst->f_opthdr = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_opthdr); + filehdr_dst->f_flags = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_flags); +} + +static unsigned int +coff_swap_filehdr_out (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_filehdr *filehdr_in = (struct internal_filehdr *)in; + FILHDR *filehdr_out = (FILHDR *)out; + bfd_h_put_16(abfd, filehdr_in->f_magic, (bfd_byte *) filehdr_out->f_magic); + bfd_h_put_16(abfd, filehdr_in->f_nscns, (bfd_byte *) filehdr_out->f_nscns); + bfd_h_put_32(abfd, filehdr_in->f_timdat, (bfd_byte *) filehdr_out->f_timdat); + PUT_FILEHDR_SYMPTR (abfd, (bfd_vma) filehdr_in->f_symptr, + (bfd_byte *) filehdr_out->f_symptr); + bfd_h_put_32(abfd, filehdr_in->f_nsyms, (bfd_byte *) filehdr_out->f_nsyms); + bfd_h_put_16(abfd, filehdr_in->f_opthdr, (bfd_byte *) filehdr_out->f_opthdr); + bfd_h_put_16(abfd, filehdr_in->f_flags, (bfd_byte *) filehdr_out->f_flags); + return sizeof(FILHDR); +} + + +#ifndef NO_COFF_SYMBOLS + +static void +coff_swap_sym_in (abfd, ext1, in1) + bfd *abfd; + PTR ext1; + PTR in1; +{ + SYMENT *ext = (SYMENT *)ext1; + struct internal_syment *in = (struct internal_syment *)in1; + + if( ext->e.e_name[0] == 0) { + in->_n._n_n._n_zeroes = 0; + in->_n._n_n._n_offset = bfd_h_get_32(abfd, (bfd_byte *) ext->e.e.e_offset); + } + else { +#if SYMNMLEN != E_SYMNMLEN + -> Error, we need to cope with truncating or extending SYMNMLEN!; +#else + memcpy(in->_n._n_name, ext->e.e_name, SYMNMLEN); +#endif + } + in->n_value = bfd_h_get_32(abfd, (bfd_byte *) ext->e_value); + in->n_scnum = bfd_h_get_16(abfd, (bfd_byte *) ext->e_scnum); + if (sizeof(ext->e_type) == 2){ + in->n_type = bfd_h_get_16(abfd, (bfd_byte *) ext->e_type); + } + else { + in->n_type = bfd_h_get_32(abfd, (bfd_byte *) ext->e_type); + } + in->n_sclass = bfd_h_get_8(abfd, ext->e_sclass); + in->n_numaux = bfd_h_get_8(abfd, ext->e_numaux); +} + +static unsigned int +coff_swap_sym_out (abfd, inp, extp) + bfd *abfd; + PTR inp; + PTR extp; +{ + struct internal_syment *in = (struct internal_syment *)inp; + SYMENT *ext =(SYMENT *)extp; + if(in->_n._n_name[0] == 0) { + bfd_h_put_32(abfd, 0, (bfd_byte *) ext->e.e.e_zeroes); + bfd_h_put_32(abfd, in->_n._n_n._n_offset, (bfd_byte *) ext->e.e.e_offset); + } + else { +#if SYMNMLEN != E_SYMNMLEN + -> Error, we need to cope with truncating or extending SYMNMLEN!; +#else + memcpy(ext->e.e_name, in->_n._n_name, SYMNMLEN); +#endif + } + bfd_h_put_32(abfd, in->n_value , (bfd_byte *) ext->e_value); + bfd_h_put_16(abfd, in->n_scnum , (bfd_byte *) ext->e_scnum); + if (sizeof(ext->e_type) == 2) + { + bfd_h_put_16(abfd, in->n_type , (bfd_byte *) ext->e_type); + } + else + { + bfd_h_put_32(abfd, in->n_type , (bfd_byte *) ext->e_type); + } + bfd_h_put_8(abfd, in->n_sclass , ext->e_sclass); + bfd_h_put_8(abfd, in->n_numaux , ext->e_numaux); + return sizeof(SYMENT); +} + +static void +coff_swap_aux_in (abfd, ext1, type, class, indx, numaux, in1) + bfd *abfd; + PTR ext1; + int type; + int class; + int indx; + int numaux; + PTR in1; +{ + AUXENT *ext = (AUXENT *)ext1; + union internal_auxent *in = (union internal_auxent *)in1; + + switch (class) { + case C_FILE: + if (ext->x_file.x_fname[0] == 0) { + in->x_file.x_n.x_zeroes = 0; + in->x_file.x_n.x_offset = + bfd_h_get_32(abfd, (bfd_byte *) ext->x_file.x_n.x_offset); + } else { +#if FILNMLEN != E_FILNMLEN + -> Error, we need to cope with truncating or extending FILNMLEN!; +#else + memcpy (in->x_file.x_fname, ext->x_file.x_fname, FILNMLEN); +#endif + } + return; + + /* RS/6000 "csect" auxents */ +#ifdef RS6000COFF_C + case C_EXT: + case C_HIDEXT: + if (indx + 1 == numaux) + { + in->x_csect.x_scnlen.l = bfd_h_get_32 (abfd, ext->x_csect.x_scnlen); + in->x_csect.x_parmhash = bfd_h_get_32 (abfd, + ext->x_csect.x_parmhash); + in->x_csect.x_snhash = bfd_h_get_16 (abfd, ext->x_csect.x_snhash); + /* We don't have to hack bitfields in x_smtyp because it's + defined by shifts-and-ands, which are equivalent on all + byte orders. */ + in->x_csect.x_smtyp = bfd_h_get_8 (abfd, ext->x_csect.x_smtyp); + in->x_csect.x_smclas = bfd_h_get_8 (abfd, ext->x_csect.x_smclas); + in->x_csect.x_stab = bfd_h_get_32 (abfd, ext->x_csect.x_stab); + in->x_csect.x_snstab = bfd_h_get_16 (abfd, ext->x_csect.x_snstab); + return; + } + break; +#endif + + case C_STAT: +#ifdef C_LEAFSTAT + case C_LEAFSTAT: +#endif + case C_HIDDEN: + if (type == T_NULL) { + in->x_scn.x_scnlen = GET_SCN_SCNLEN(abfd, ext); + in->x_scn.x_nreloc = GET_SCN_NRELOC(abfd, ext); + in->x_scn.x_nlinno = GET_SCN_NLINNO(abfd, ext); + return; + } + break; + } + + in->x_sym.x_tagndx.l = bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_tagndx); +#ifndef NO_TVNDX + in->x_sym.x_tvndx = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_tvndx); +#endif + + if (ISARY(type)) { +#if DIMNUM != E_DIMNUM + -> Error, we need to cope with truncating or extending DIMNUM!; +#else + in->x_sym.x_fcnary.x_ary.x_dimen[0] = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[0]); + in->x_sym.x_fcnary.x_ary.x_dimen[1] = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[1]); + in->x_sym.x_fcnary.x_ary.x_dimen[2] = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[2]); + in->x_sym.x_fcnary.x_ary.x_dimen[3] = bfd_h_get_16(abfd, (bfd_byte *) ext->x_sym.x_fcnary.x_ary.x_dimen[3]); +#endif + } + if (class == C_BLOCK || ISFCN(type) || ISTAG(class)) { + in->x_sym.x_fcnary.x_fcn.x_lnnoptr = GET_FCN_LNNOPTR(abfd, ext); + in->x_sym.x_fcnary.x_fcn.x_endndx.l = GET_FCN_ENDNDX(abfd, ext); + } + + if (ISFCN(type)) { + in->x_sym.x_misc.x_fsize = bfd_h_get_32(abfd, (bfd_byte *) ext->x_sym.x_misc.x_fsize); + } + else { + in->x_sym.x_misc.x_lnsz.x_lnno = GET_LNSZ_LNNO(abfd, ext); + in->x_sym.x_misc.x_lnsz.x_size = GET_LNSZ_SIZE(abfd, ext); + } +} + +static unsigned int +coff_swap_aux_out (abfd, inp, type, class, indx, numaux, extp) + bfd *abfd; + PTR inp; + int type; + int class; + int indx; + int numaux; + PTR extp; +{ + union internal_auxent *in = (union internal_auxent *)inp; + AUXENT *ext = (AUXENT *)extp; + + memset((PTR)ext, 0, AUXESZ); + switch (class) { + case C_FILE: + if (in->x_file.x_fname[0] == 0) { + PUTWORD(abfd, 0, (bfd_byte *) ext->x_file.x_n.x_zeroes); + PUTWORD(abfd, + in->x_file.x_n.x_offset, + (bfd_byte *) ext->x_file.x_n.x_offset); + } + else { +#if FILNMLEN != E_FILNMLEN + -> Error, we need to cope with truncating or extending FILNMLEN!; +#else + memcpy (ext->x_file.x_fname, in->x_file.x_fname, FILNMLEN); +#endif + } + return sizeof (AUXENT); + +#ifdef RS6000COFF_C + /* RS/6000 "csect" auxents */ + case C_EXT: + case C_HIDEXT: + if (indx + 1 == numaux) + { + PUTWORD (abfd, in->x_csect.x_scnlen.l, ext->x_csect.x_scnlen); + PUTWORD (abfd, in->x_csect.x_parmhash, ext->x_csect.x_parmhash); + PUTHALF (abfd, in->x_csect.x_snhash, ext->x_csect.x_snhash); + /* We don't have to hack bitfields in x_smtyp because it's + defined by shifts-and-ands, which are equivalent on all + byte orders. */ + PUTBYTE (abfd, in->x_csect.x_smtyp, ext->x_csect.x_smtyp); + PUTBYTE (abfd, in->x_csect.x_smclas, ext->x_csect.x_smclas); + PUTWORD (abfd, in->x_csect.x_stab, ext->x_csect.x_stab); + PUTHALF (abfd, in->x_csect.x_snstab, ext->x_csect.x_snstab); + return sizeof (AUXENT); + } + break; +#endif + + case C_STAT: +#ifdef C_LEAFSTAT + case C_LEAFSTAT: +#endif + case C_HIDDEN: + if (type == T_NULL) { + PUT_SCN_SCNLEN(abfd, in->x_scn.x_scnlen, ext); + PUT_SCN_NRELOC(abfd, in->x_scn.x_nreloc, ext); + PUT_SCN_NLINNO(abfd, in->x_scn.x_nlinno, ext); + return sizeof (AUXENT); + } + break; + } + + PUTWORD(abfd, in->x_sym.x_tagndx.l, (bfd_byte *) ext->x_sym.x_tagndx); +#ifndef NO_TVNDX + bfd_h_put_16(abfd, in->x_sym.x_tvndx , (bfd_byte *) ext->x_sym.x_tvndx); +#endif + + if (class == C_BLOCK || ISFCN(type) || ISTAG(class)) { + PUT_FCN_LNNOPTR(abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr, ext); + PUT_FCN_ENDNDX(abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l, ext); + } + + if (ISFCN(type)) { + PUTWORD(abfd, in->x_sym.x_misc.x_fsize, (bfd_byte *) ext->x_sym.x_misc.x_fsize); + } + else { + if (ISARY(type)) { +#if DIMNUM != E_DIMNUM + -> Error, we need to cope with truncating or extending DIMNUM!; +#else + bfd_h_put_16(abfd, in->x_sym.x_fcnary.x_ary.x_dimen[0], (bfd_byte *)ext->x_sym.x_fcnary.x_ary.x_dimen[0]); + bfd_h_put_16(abfd, in->x_sym.x_fcnary.x_ary.x_dimen[1], (bfd_byte *)ext->x_sym.x_fcnary.x_ary.x_dimen[1]); + bfd_h_put_16(abfd, in->x_sym.x_fcnary.x_ary.x_dimen[2], (bfd_byte *)ext->x_sym.x_fcnary.x_ary.x_dimen[2]); + bfd_h_put_16(abfd, in->x_sym.x_fcnary.x_ary.x_dimen[3], (bfd_byte *)ext->x_sym.x_fcnary.x_ary.x_dimen[3]); +#endif + } + PUT_LNSZ_LNNO(abfd, in->x_sym.x_misc.x_lnsz.x_lnno, ext); + PUT_LNSZ_SIZE(abfd, in->x_sym.x_misc.x_lnsz.x_size, ext); + } + return sizeof(AUXENT); +} + +#endif /* NO_COFF_SYMBOLS */ + +#ifndef NO_COFF_LINENOS + +static void +coff_swap_lineno_in (abfd, ext1, in1) + bfd *abfd; + PTR ext1; + PTR in1; +{ + LINENO *ext = (LINENO *)ext1; + struct internal_lineno *in = (struct internal_lineno *)in1; + + in->l_addr.l_symndx = bfd_h_get_32(abfd, (bfd_byte *) ext->l_addr.l_symndx); + in->l_lnno = GET_LINENO_LNNO(abfd, ext); +} + +static unsigned int +coff_swap_lineno_out (abfd, inp, outp) + bfd *abfd; + PTR inp; + PTR outp; +{ + struct internal_lineno *in = (struct internal_lineno *)inp; + struct external_lineno *ext = (struct external_lineno *)outp; + PUTWORD(abfd, in->l_addr.l_symndx, (bfd_byte *) + ext->l_addr.l_symndx); + + PUT_LINENO_LNNO (abfd, in->l_lnno, ext); + return sizeof(struct external_lineno); +} + +#endif /* NO_COFF_LINENOS */ + + +static void +coff_swap_aouthdr_in (abfd, aouthdr_ext1, aouthdr_int1) + bfd *abfd; + PTR aouthdr_ext1; + PTR aouthdr_int1; +{ + AOUTHDR *aouthdr_ext = (AOUTHDR *) aouthdr_ext1; + struct internal_aouthdr *aouthdr_int = (struct internal_aouthdr *)aouthdr_int1; + + aouthdr_int->magic = bfd_h_get_16(abfd, (bfd_byte *) aouthdr_ext->magic); + aouthdr_int->vstamp = bfd_h_get_16(abfd, (bfd_byte *) aouthdr_ext->vstamp); + aouthdr_int->tsize = + GET_AOUTHDR_TSIZE (abfd, (bfd_byte *) aouthdr_ext->tsize); + aouthdr_int->dsize = + GET_AOUTHDR_DSIZE (abfd, (bfd_byte *) aouthdr_ext->dsize); + aouthdr_int->bsize = + GET_AOUTHDR_BSIZE (abfd, (bfd_byte *) aouthdr_ext->bsize); + aouthdr_int->entry = + GET_AOUTHDR_ENTRY (abfd, (bfd_byte *) aouthdr_ext->entry); + aouthdr_int->text_start = + GET_AOUTHDR_TEXT_START (abfd, (bfd_byte *) aouthdr_ext->text_start); + aouthdr_int->data_start = + GET_AOUTHDR_DATA_START (abfd, (bfd_byte *) aouthdr_ext->data_start); + +#ifdef I960 + aouthdr_int->tagentries = bfd_h_get_32(abfd, (bfd_byte *) aouthdr_ext->tagentries); +#endif + +#ifdef APOLLO_M68 + bfd_h_put_32(abfd, aouthdr_int->o_inlib, (bfd_byte *) aouthdr_ext->o_inlib); + bfd_h_put_32(abfd, aouthdr_int->o_sri, (bfd_byte *) aouthdr_ext->o_sri); + bfd_h_put_32(abfd, aouthdr_int->vid[0], (bfd_byte *) aouthdr_ext->vid); + bfd_h_put_32(abfd, aouthdr_int->vid[1], (bfd_byte *) aouthdr_ext->vid + 4); +#endif + + +#ifdef RS6000COFF_C + aouthdr_int->o_toc = bfd_h_get_32(abfd, aouthdr_ext->o_toc); + aouthdr_int->o_snentry = bfd_h_get_16(abfd, aouthdr_ext->o_snentry); + aouthdr_int->o_sntext = bfd_h_get_16(abfd, aouthdr_ext->o_sntext); + aouthdr_int->o_sndata = bfd_h_get_16(abfd, aouthdr_ext->o_sndata); + aouthdr_int->o_sntoc = bfd_h_get_16(abfd, aouthdr_ext->o_sntoc); + aouthdr_int->o_snloader = bfd_h_get_16(abfd, aouthdr_ext->o_snloader); + aouthdr_int->o_snbss = bfd_h_get_16(abfd, aouthdr_ext->o_snbss); + aouthdr_int->o_algntext = bfd_h_get_16(abfd, aouthdr_ext->o_algntext); + aouthdr_int->o_algndata = bfd_h_get_16(abfd, aouthdr_ext->o_algndata); + aouthdr_int->o_modtype = bfd_h_get_16(abfd, aouthdr_ext->o_modtype); + aouthdr_int->o_maxstack = bfd_h_get_32(abfd, aouthdr_ext->o_maxstack); +#endif + +#ifdef MIPSECOFF + aouthdr_int->bss_start = bfd_h_get_32(abfd, aouthdr_ext->bss_start); + aouthdr_int->gp_value = bfd_h_get_32(abfd, aouthdr_ext->gp_value); + aouthdr_int->gprmask = bfd_h_get_32(abfd, aouthdr_ext->gprmask); + aouthdr_int->cprmask[0] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[0]); + aouthdr_int->cprmask[1] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[1]); + aouthdr_int->cprmask[2] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[2]); + aouthdr_int->cprmask[3] = bfd_h_get_32(abfd, aouthdr_ext->cprmask[3]); +#endif + +#ifdef ALPHAECOFF + aouthdr_int->bss_start = bfd_h_get_64(abfd, aouthdr_ext->bss_start); + aouthdr_int->gp_value = bfd_h_get_64(abfd, aouthdr_ext->gp_value); + aouthdr_int->gprmask = bfd_h_get_32(abfd, aouthdr_ext->gprmask); + aouthdr_int->fprmask = bfd_h_get_32(abfd, aouthdr_ext->fprmask); +#endif +} + +static unsigned int +coff_swap_aouthdr_out (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_aouthdr *aouthdr_in = (struct internal_aouthdr *)in; + AOUTHDR *aouthdr_out = (AOUTHDR *)out; + + bfd_h_put_16(abfd, aouthdr_in->magic, (bfd_byte *) aouthdr_out->magic); + bfd_h_put_16(abfd, aouthdr_in->vstamp, (bfd_byte *) aouthdr_out->vstamp); + PUT_AOUTHDR_TSIZE (abfd, aouthdr_in->tsize, (bfd_byte *) aouthdr_out->tsize); + PUT_AOUTHDR_DSIZE (abfd, aouthdr_in->dsize, (bfd_byte *) aouthdr_out->dsize); + PUT_AOUTHDR_BSIZE (abfd, aouthdr_in->bsize, (bfd_byte *) aouthdr_out->bsize); + PUT_AOUTHDR_ENTRY (abfd, aouthdr_in->entry, (bfd_byte *) aouthdr_out->entry); + PUT_AOUTHDR_TEXT_START (abfd, aouthdr_in->text_start, + (bfd_byte *) aouthdr_out->text_start); + PUT_AOUTHDR_DATA_START (abfd, aouthdr_in->data_start, + (bfd_byte *) aouthdr_out->data_start); +#ifdef I960 + bfd_h_put_32(abfd, aouthdr_in->tagentries, (bfd_byte *) aouthdr_out->tagentries); +#endif + +#ifdef MIPSECOFF + bfd_h_put_32(abfd, aouthdr_in->bss_start, (bfd_byte *) aouthdr_out->bss_start); + bfd_h_put_32(abfd, aouthdr_in->gp_value, (bfd_byte *) aouthdr_out->gp_value); + bfd_h_put_32(abfd, aouthdr_in->gprmask, (bfd_byte *) aouthdr_out->gprmask); + bfd_h_put_32(abfd, aouthdr_in->cprmask[0], (bfd_byte *) aouthdr_out->cprmask[0]); + bfd_h_put_32(abfd, aouthdr_in->cprmask[1], (bfd_byte *) aouthdr_out->cprmask[1]); + bfd_h_put_32(abfd, aouthdr_in->cprmask[2], (bfd_byte *) aouthdr_out->cprmask[2]); + bfd_h_put_32(abfd, aouthdr_in->cprmask[3], (bfd_byte *) aouthdr_out->cprmask[3]); +#endif + +#ifdef ALPHAECOFF + /* FIXME: What does bldrev mean? */ + bfd_h_put_16(abfd, (bfd_vma) 2, (bfd_byte *) aouthdr_out->bldrev); + bfd_h_put_16(abfd, (bfd_vma) 0, (bfd_byte *) aouthdr_out->padding); + bfd_h_put_64(abfd, aouthdr_in->bss_start, (bfd_byte *) aouthdr_out->bss_start); + bfd_h_put_64(abfd, aouthdr_in->gp_value, (bfd_byte *) aouthdr_out->gp_value); + bfd_h_put_32(abfd, aouthdr_in->gprmask, (bfd_byte *) aouthdr_out->gprmask); + bfd_h_put_32(abfd, aouthdr_in->fprmask, (bfd_byte *) aouthdr_out->fprmask); +#endif + + return sizeof(AOUTHDR); +} + +static void +coff_swap_scnhdr_in (abfd, ext, in) + bfd *abfd; + PTR ext; + PTR in; +{ + SCNHDR *scnhdr_ext = (SCNHDR *) ext; + struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; + + memcpy(scnhdr_int->s_name, scnhdr_ext->s_name, sizeof(scnhdr_int->s_name)); + scnhdr_int->s_vaddr = + GET_SCNHDR_VADDR (abfd, (bfd_byte *) scnhdr_ext->s_vaddr); + scnhdr_int->s_paddr = + GET_SCNHDR_PADDR (abfd, (bfd_byte *) scnhdr_ext->s_paddr); + scnhdr_int->s_size = + GET_SCNHDR_SIZE (abfd, (bfd_byte *) scnhdr_ext->s_size); + + scnhdr_int->s_scnptr = + GET_SCNHDR_SCNPTR (abfd, (bfd_byte *) scnhdr_ext->s_scnptr); + scnhdr_int->s_relptr = + GET_SCNHDR_RELPTR (abfd, (bfd_byte *) scnhdr_ext->s_relptr); + scnhdr_int->s_lnnoptr = + GET_SCNHDR_LNNOPTR (abfd, (bfd_byte *) scnhdr_ext->s_lnnoptr); + scnhdr_int->s_flags = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_flags); +#if defined(M88) + scnhdr_int->s_nreloc = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_nreloc); + scnhdr_int->s_nlnno = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_nlnno); +#else + scnhdr_int->s_nreloc = bfd_h_get_16(abfd, (bfd_byte *) scnhdr_ext->s_nreloc); + scnhdr_int->s_nlnno = bfd_h_get_16(abfd, (bfd_byte *) scnhdr_ext->s_nlnno); +#endif +#ifdef I960 + scnhdr_int->s_align = bfd_h_get_32(abfd, (bfd_byte *) scnhdr_ext->s_align); +#endif +} + +static unsigned int +coff_swap_scnhdr_out (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *)in; + SCNHDR *scnhdr_ext = (SCNHDR *)out; + + memcpy(scnhdr_ext->s_name, scnhdr_int->s_name, sizeof(scnhdr_int->s_name)); + PUT_SCNHDR_VADDR (abfd, scnhdr_int->s_vaddr, + (bfd_byte *) scnhdr_ext->s_vaddr); + PUT_SCNHDR_PADDR (abfd, scnhdr_int->s_paddr, + (bfd_byte *) scnhdr_ext->s_paddr); + PUT_SCNHDR_SIZE (abfd, scnhdr_int->s_size, + (bfd_byte *) scnhdr_ext->s_size); + PUT_SCNHDR_SCNPTR (abfd, scnhdr_int->s_scnptr, + (bfd_byte *) scnhdr_ext->s_scnptr); + PUT_SCNHDR_RELPTR (abfd, scnhdr_int->s_relptr, + (bfd_byte *) scnhdr_ext->s_relptr); + PUT_SCNHDR_LNNOPTR (abfd, scnhdr_int->s_lnnoptr, + (bfd_byte *) scnhdr_ext->s_lnnoptr); + PUTWORD(abfd, scnhdr_int->s_flags, (bfd_byte *) scnhdr_ext->s_flags); +#if defined(M88) + PUTWORD(abfd, scnhdr_int->s_nlnno, (bfd_byte *) scnhdr_ext->s_nlnno); + PUTWORD(abfd, scnhdr_int->s_nreloc, (bfd_byte *) scnhdr_ext->s_nreloc); +#else + PUTHALF(abfd, scnhdr_int->s_nlnno, (bfd_byte *) scnhdr_ext->s_nlnno); + PUTHALF(abfd, scnhdr_int->s_nreloc, (bfd_byte *) scnhdr_ext->s_nreloc); +#endif + +#if defined(I960) + PUTWORD(abfd, scnhdr_int->s_align, (bfd_byte *) scnhdr_ext->s_align); +#endif + return sizeof(SCNHDR); +} diff --git a/gnu/usr.bin/gdb/bfd/ecofflink.c b/gnu/usr.bin/gdb/bfd/ecofflink.c new file mode 100644 index 00000000000..784e87478f6 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/ecofflink.c @@ -0,0 +1,1616 @@ +/* Routines to link ECOFF debugging information. + Copyright 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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "obstack.h" +#include "coff/internal.h" +#include "coff/sym.h" +#include "coff/symconst.h" +#include "coff/ecoff.h" + +static boolean ecoff_add_bytes PARAMS ((char **buf, char **bufend, + size_t need)); +static struct bfd_hash_entry *string_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); +static void ecoff_align_debug PARAMS ((bfd *abfd, + struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap)); +static boolean ecoff_write_symhdr PARAMS ((bfd *, struct ecoff_debug_info *, + const struct ecoff_debug_swap *, + file_ptr where)); + +/* Obstack allocation and deallocation routines. */ +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + +/* The minimum amount of data to allocate. */ +#define ALLOC_SIZE (4064) + +/* Add bytes to a buffer. Return success. */ + +static boolean +ecoff_add_bytes (buf, bufend, need) + char **buf; + char **bufend; + size_t need; +{ + size_t have; + size_t want; + char *newbuf; + + have = *bufend - *buf; + if (have > need) + want = ALLOC_SIZE; + else + { + want = need - have; + if (want < ALLOC_SIZE) + want = ALLOC_SIZE; + } + if (*buf == NULL) + newbuf = (char *) malloc (have + want); + else + newbuf = (char *) realloc (*buf, have + want); + if (newbuf == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + *buf = newbuf; + *bufend = *buf + have + want; + return true; +} + +/* We keep a hash table which maps strings to numbers. We use it to + map FDR names to indices in the output file, and to map local + strings when combining stabs debugging information. */ + +struct string_hash_entry +{ + struct bfd_hash_entry root; + /* FDR index or string table offset. */ + long val; + /* Next entry in string table. */ + struct string_hash_entry *next; +}; + +struct string_hash_table +{ + struct bfd_hash_table table; +}; + +/* Routine to create an entry in a string hash table. */ + +static struct bfd_hash_entry * +string_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct string_hash_entry *ret = (struct string_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct string_hash_entry *) NULL) + ret = ((struct string_hash_entry *) + bfd_hash_allocate (table, sizeof (struct string_hash_entry))); + if (ret == (struct string_hash_entry *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + /* Call the allocation method of the superclass. */ + ret = ((struct string_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->val = -1; + ret->next = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Look up an entry in an string hash table. */ + +#define string_hash_lookup(t, string, create, copy) \ + ((struct string_hash_entry *) \ + bfd_hash_lookup (&(t)->table, (string), (create), (copy))) + +/* We can't afford to read in all the debugging information when we do + a link. Instead, we build a list of these structures to show how + different parts of the input file map to the output file. */ + +struct shuffle +{ + /* The next entry in this linked list. */ + struct shuffle *next; + /* The length of the information. */ + unsigned long size; + /* Whether this information comes from a file or not. */ + boolean filep; + union + { + struct + { + /* The BFD the data comes from. */ + bfd *input_bfd; + /* The offset within input_bfd. */ + file_ptr offset; + } file; + /* The data to be written out. */ + PTR memory; + } u; +}; + +/* This structure holds information across calls to + bfd_ecoff_debug_accumulate. */ + +struct accumulate +{ + /* The FDR hash table. */ + struct string_hash_table fdr_hash; + /* The strings hash table. */ + struct string_hash_table str_hash; + /* Linked lists describing how to shuffle the input debug + information into the output file. We keep a pointer to both the + head and the tail. */ + struct shuffle *line; + struct shuffle *line_end; + struct shuffle *pdr; + struct shuffle *pdr_end; + struct shuffle *sym; + struct shuffle *sym_end; + struct shuffle *opt; + struct shuffle *opt_end; + struct shuffle *aux; + struct shuffle *aux_end; + struct shuffle *ss; + struct shuffle *ss_end; + struct string_hash_entry *ss_hash; + struct string_hash_entry *ss_hash_end; + struct shuffle *fdr; + struct shuffle *fdr_end; + struct shuffle *rfd; + struct shuffle *rfd_end; + /* The size of the largest file shuffle. */ + unsigned long largest_file_shuffle; + /* An obstack for debugging information. */ + struct obstack memory; +}; + +/* Add a file entry to a shuffle list. */ + +static boolean add_file_shuffle PARAMS ((struct accumulate *, + struct shuffle **, + struct shuffle **, bfd *, file_ptr, + unsigned long)); + +static boolean +add_file_shuffle (ainfo, head, tail, input_bfd, offset, size) + struct accumulate *ainfo; + struct shuffle **head; + struct shuffle **tail; + bfd *input_bfd; + file_ptr offset; + unsigned long size; +{ + struct shuffle *n; + + if (*tail != (struct shuffle *) NULL + && (*tail)->filep + && (*tail)->u.file.input_bfd == input_bfd + && (*tail)->u.file.offset + (*tail)->size == offset) + { + /* Just merge this entry onto the existing one. */ + (*tail)->size += size; + if ((*tail)->size > ainfo->largest_file_shuffle) + ainfo->largest_file_shuffle = (*tail)->size; + return true; + } + + n = (struct shuffle *) obstack_alloc (&ainfo->memory, + sizeof (struct shuffle)); + if (!n) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + n->next = NULL; + n->size = size; + n->filep = true; + n->u.file.input_bfd = input_bfd; + n->u.file.offset = offset; + if (*head == (struct shuffle *) NULL) + *head = n; + if (*tail != (struct shuffle *) NULL) + (*tail)->next = n; + *tail = n; + if (size > ainfo->largest_file_shuffle) + ainfo->largest_file_shuffle = size; + return true; +} + +/* Add a memory entry to a shuffle list. */ + +static boolean add_memory_shuffle PARAMS ((struct accumulate *, + struct shuffle **head, + struct shuffle **tail, + bfd_byte *data, unsigned long size)); + +static boolean +add_memory_shuffle (ainfo, head, tail, data, size) + struct accumulate *ainfo; + struct shuffle **head; + struct shuffle **tail; + bfd_byte *data; + unsigned long size; +{ + struct shuffle *n; + + n = (struct shuffle *) obstack_alloc (&ainfo->memory, + sizeof (struct shuffle)); + if (!n) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + n->next = NULL; + n->size = size; + n->filep = false; + n->u.memory = (PTR) data; + if (*head == (struct shuffle *) NULL) + *head = n; + if (*tail != (struct shuffle *) NULL) + (*tail)->next = n; + *tail = n; + return true; +} + +/* Initialize the FDR hash table. This returns a handle which is then + passed in to bfd_ecoff_debug_accumulate, et. al. */ + +/*ARGSUSED*/ +PTR +bfd_ecoff_debug_init (output_bfd, output_debug, output_swap, info) + bfd *output_bfd; + struct ecoff_debug_info *output_debug; + const struct ecoff_debug_swap *output_swap; + struct bfd_link_info *info; +{ + struct accumulate *ainfo; + + ainfo = (struct accumulate *) malloc (sizeof (struct accumulate)); + if (!ainfo) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + if (! bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc, + 1021)) + return NULL; + + ainfo->line = NULL; + ainfo->line_end = NULL; + ainfo->pdr = NULL; + ainfo->pdr_end = NULL; + ainfo->sym = NULL; + ainfo->sym_end = NULL; + ainfo->opt = NULL; + ainfo->opt_end = NULL; + ainfo->aux = NULL; + ainfo->aux_end = NULL; + ainfo->ss = NULL; + ainfo->ss_end = NULL; + ainfo->ss_hash = NULL; + ainfo->ss_hash_end = NULL; + ainfo->fdr = NULL; + ainfo->fdr_end = NULL; + ainfo->rfd = NULL; + ainfo->rfd_end = NULL; + + ainfo->largest_file_shuffle = 0; + + if (! info->relocateable) + { + if (! bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc)) + return NULL; + + /* The first entry in the string table is the empty string. */ + output_debug->symbolic_header.issMax = 1; + } + + if (!obstack_begin (&ainfo->memory, 4050)) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + return (PTR) ainfo; +} + +/* Free the accumulated debugging information. */ + +/*ARGSUSED*/ +void +bfd_ecoff_debug_free (handle, output_bfd, output_debug, output_swap, info) + PTR handle; + bfd *output_bfd; + struct ecoff_debug_info *output_debug; + const struct ecoff_debug_swap *output_swap; + struct bfd_link_info *info; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + + bfd_hash_table_free (&ainfo->fdr_hash.table); + + if (! info->relocateable) + bfd_hash_table_free (&ainfo->str_hash.table); + + obstack_free (&ainfo->memory, (PTR) NULL); + + free (ainfo); +} + +/* Accumulate the debugging information from INPUT_BFD into + OUTPUT_BFD. The INPUT_DEBUG argument points to some ECOFF + debugging information which we want to link into the information + pointed to by the OUTPUT_DEBUG argument. OUTPUT_SWAP and + INPUT_SWAP point to the swapping information needed. INFO is the + linker information structure. HANDLE is returned by + bfd_ecoff_debug_init. */ + +/*ARGSUSED*/ +boolean +bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap, + input_bfd, input_debug, input_swap, + info) + PTR handle; + bfd *output_bfd; + struct ecoff_debug_info *output_debug; + const struct ecoff_debug_swap *output_swap; + bfd *input_bfd; + struct ecoff_debug_info *input_debug; + const struct ecoff_debug_swap *input_swap; + struct bfd_link_info *info; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = input_swap->swap_sym_in; + void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)) + = input_swap->swap_rfd_in; + void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) + = output_swap->swap_sym_out; + void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)) + = output_swap->swap_fdr_out; + void (* const swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR)) + = output_swap->swap_rfd_out; + bfd_size_type external_pdr_size = output_swap->external_pdr_size; + bfd_size_type external_sym_size = output_swap->external_sym_size; + bfd_size_type external_opt_size = output_swap->external_opt_size; + bfd_size_type external_fdr_size = output_swap->external_fdr_size; + bfd_size_type external_rfd_size = output_swap->external_rfd_size; + HDRR * const output_symhdr = &output_debug->symbolic_header; + HDRR * const input_symhdr = &input_debug->symbolic_header; + bfd_vma section_adjust[scMax]; + asection *sec; + bfd_byte *fdr_start; + bfd_byte *fdr_ptr; + bfd_byte *fdr_end; + bfd_size_type fdr_add; + unsigned int copied; + RFDT i; + unsigned long sz; + bfd_byte *rfd_out; + bfd_byte *rfd_in; + bfd_byte *rfd_end; + long newrfdbase = 0; + long oldrfdbase = 0; + bfd_byte *fdr_out; + + /* Use section_adjust to hold the value to add to a symbol in a + particular section. */ + memset ((PTR) section_adjust, 0, sizeof section_adjust); + +#define SET(name, indx) \ + sec = bfd_get_section_by_name (input_bfd, name); \ + if (sec != NULL) \ + section_adjust[indx] = (sec->output_section->vma \ + + sec->output_offset \ + - sec->vma); + + SET (".text", scText); + SET (".data", scData); + SET (".bss", scBss); + SET (".sdata", scSData); + SET (".sbss", scSBss); + /* scRdata section may be either .rdata or .rodata. */ + SET (".rdata", scRData); + SET (".rodata", scRData); + SET (".init", scInit); + SET (".fini", scFini); + +#undef SET + + /* Find all the debugging information based on the FDR's. We need + to handle them whether they are swapped or not. */ + if (input_debug->fdr != (FDR *) NULL) + { + fdr_start = (bfd_byte *) input_debug->fdr; + fdr_add = sizeof (FDR); + } + else + { + fdr_start = (bfd_byte *) input_debug->external_fdr; + fdr_add = input_swap->external_fdr_size; + } + fdr_end = fdr_start + input_symhdr->ifdMax * fdr_add; + + input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd, + (input_symhdr->ifdMax + * sizeof (RFDT))); + + sz = (input_symhdr->crfd + input_symhdr->ifdMax) * external_rfd_size; + rfd_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + if (!input_debug->ifdmap || !rfd_out) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + if (!add_memory_shuffle (ainfo, &ainfo->rfd, &ainfo->rfd_end, rfd_out, sz)) + return false; + + copied = 0; + + /* Look through the FDR's to see which ones we are going to include + in the final output. We do not want duplicate FDR information + for header files, because ECOFF debugging is often very large. + When we find an FDR with no line information which can be merged, + we look it up in a hash table to ensure that we only include it + once. We keep a table mapping FDR numbers to the final number + they get with the BFD, so that we can refer to it when we write + out the external symbols. */ + for (fdr_ptr = fdr_start, i = 0; + fdr_ptr < fdr_end; + fdr_ptr += fdr_add, i++, rfd_out += external_rfd_size) + { + FDR fdr; + + if (input_debug->fdr != (FDR *) NULL) + fdr = *(FDR *) fdr_ptr; + else + (*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr); + + /* See if this FDR can be merged with an existing one. */ + if (fdr.cbLine == 0 && fdr.rss != -1 && fdr.fMerge) + { + const char *name; + char *lookup; + struct string_hash_entry *fh; + + /* We look up a string formed from the file name and the + number of symbols. Sometimes an include file will + conditionally define a typedef or something based on the + order of include files. Using the number of symbols as a + hash reduces the chance that we will merge symbol + information that should not be merged. */ + name = input_debug->ss + fdr.issBase + fdr.rss; + + lookup = (char *) malloc (strlen (name) + 20); + if (lookup == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + sprintf (lookup, "%s %lx", name, fdr.csym); + + fh = string_hash_lookup (&ainfo->fdr_hash, lookup, true, true); + free (lookup); + if (fh == (struct string_hash_entry *) NULL) + return false; + + if (fh->val != -1) + { + input_debug->ifdmap[i] = fh->val; + (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, + (PTR) rfd_out); + + /* Don't copy this FDR. */ + continue; + } + + fh->val = output_symhdr->ifdMax + copied; + } + + input_debug->ifdmap[i] = output_symhdr->ifdMax + copied; + (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, (PTR) rfd_out); + ++copied; + } + + newrfdbase = output_symhdr->crfd; + output_symhdr->crfd += input_symhdr->ifdMax; + + /* Copy over any existing RFD's. RFD's are only created by the + linker, so this will only happen for input files which are the + result of a partial link. */ + rfd_in = (bfd_byte *) input_debug->external_rfd; + rfd_end = rfd_in + input_symhdr->crfd * input_swap->external_rfd_size; + for (; + rfd_in < rfd_end; + rfd_in += input_swap->external_rfd_size) + { + RFDT rfd; + + (*swap_rfd_in) (input_bfd, (PTR) rfd_in, &rfd); + BFD_ASSERT (rfd >= 0 && rfd < input_symhdr->ifdMax); + rfd = input_debug->ifdmap[rfd]; + (*swap_rfd_out) (output_bfd, &rfd, (PTR) rfd_out); + rfd_out += external_rfd_size; + } + + oldrfdbase = output_symhdr->crfd; + output_symhdr->crfd += input_symhdr->crfd; + + /* Look through the FDR's and copy over all associated debugging + information. */ + sz = copied * external_fdr_size; + fdr_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + if (!fdr_out) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + if (!add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, fdr_out, sz)) + return false; + for (fdr_ptr = fdr_start, i = 0; + fdr_ptr < fdr_end; + fdr_ptr += fdr_add, i++) + { + FDR fdr; + bfd_vma fdr_adr; + bfd_byte *sym_out; + bfd_byte *lraw_src; + bfd_byte *lraw_end; + boolean fgotfilename; + + if (input_debug->ifdmap[i] < output_symhdr->ifdMax) + { + /* We are not copying this FDR. */ + continue; + } + + if (input_debug->fdr != (FDR *) NULL) + fdr = *(FDR *) fdr_ptr; + else + (*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr); + + fdr_adr = fdr.adr; + + /* Adjust the FDR address for any changes that may have been + made by relaxing. */ + if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) + { + struct ecoff_value_adjust *adjust; + + for (adjust = input_debug->adjust; + adjust != (struct ecoff_value_adjust *) NULL; + adjust = adjust->next) + if (fdr_adr >= adjust->start + && fdr_adr < adjust->end) + fdr.adr += adjust->adjust; + } + + /* FIXME: It is conceivable that this FDR points to the .init or + .fini section, in which case this will not do the right + thing. */ + fdr.adr += section_adjust[scText]; + + /* Swap in the local symbols, adjust their values, and swap them + out again. */ + fgotfilename = false; + sz = fdr.csym * external_sym_size; + sym_out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + if (!sym_out) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + if (!add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out, + sz)) + return false; + lraw_src = ((bfd_byte *) input_debug->external_sym + + fdr.isymBase * input_swap->external_sym_size); + lraw_end = lraw_src + fdr.csym * input_swap->external_sym_size; + for (; lraw_src < lraw_end; lraw_src += input_swap->external_sym_size) + { + SYMR internal_sym; + + (*swap_sym_in) (input_bfd, (PTR) lraw_src, &internal_sym); + + BFD_ASSERT (internal_sym.sc != scCommon + && internal_sym.sc != scSCommon); + + /* Adjust the symbol value if appropriate. */ + switch (internal_sym.st) + { + case stNil: + if (ECOFF_IS_STAB (&internal_sym)) + break; + /* Fall through. */ + case stGlobal: + case stStatic: + case stLabel: + case stProc: + case stStaticProc: + if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) + { + bfd_vma value; + struct ecoff_value_adjust *adjust; + + value = internal_sym.value; + for (adjust = input_debug->adjust; + adjust != (struct ecoff_value_adjust *) NULL; + adjust = adjust->next) + if (value >= adjust->start + && value < adjust->end) + internal_sym.value += adjust->adjust; + } + internal_sym.value += section_adjust[internal_sym.sc]; + break; + + default: + break; + } + + /* If we are doing a final link, we hash all the strings in + the local symbol table together. This reduces the amount + of space required by debugging information. We don't do + this when performing a relocateable link because it would + prevent us from easily merging different FDR's. */ + if (! info->relocateable) + { + boolean ffilename; + const char *name; + + if (! fgotfilename && internal_sym.iss == fdr.rss) + ffilename = true; + else + ffilename = false; + + /* Hash the name into the string table. */ + name = input_debug->ss + fdr.issBase + internal_sym.iss; + if (*name == '\0') + internal_sym.iss = 0; + else + { + struct string_hash_entry *sh; + + sh = string_hash_lookup (&ainfo->str_hash, name, true, true); + if (sh == (struct string_hash_entry *) NULL) + return false; + if (sh->val == -1) + { + sh->val = output_symhdr->issMax; + output_symhdr->issMax += strlen (name) + 1; + if (ainfo->ss_hash == (struct string_hash_entry *) NULL) + ainfo->ss_hash = sh; + if (ainfo->ss_hash_end + != (struct string_hash_entry *) NULL) + ainfo->ss_hash_end->next = sh; + ainfo->ss_hash_end = sh; + } + internal_sym.iss = sh->val; + } + + if (ffilename) + { + fdr.rss = internal_sym.iss; + fgotfilename = true; + } + } + + (*swap_sym_out) (output_bfd, &internal_sym, sym_out); + sym_out += external_sym_size; + } + + fdr.isymBase = output_symhdr->isymMax; + output_symhdr->isymMax += fdr.csym; + + /* Copy the information that does not need swapping. */ + + /* FIXME: If we are relaxing, we need to adjust the line + numbers. Frankly, forget it. Anybody using stabs debugging + information will not use this line number information, and + stabs are adjusted correctly. */ + if (fdr.cbLine > 0) + { + if (!add_file_shuffle (ainfo, &ainfo->line, &ainfo->line_end, + input_bfd, + input_symhdr->cbLineOffset + fdr.cbLineOffset, + fdr.cbLine)) + return false; + fdr.ilineBase = output_symhdr->ilineMax; + fdr.cbLineOffset = output_symhdr->cbLine; + output_symhdr->ilineMax += fdr.cline; + output_symhdr->cbLine += fdr.cbLine; + } + if (fdr.caux > 0) + { + if (!add_file_shuffle (ainfo, &ainfo->aux, &ainfo->aux_end, + input_bfd, + (input_symhdr->cbAuxOffset + + fdr.iauxBase * sizeof (union aux_ext)), + fdr.caux * sizeof (union aux_ext))) + return false; + fdr.iauxBase = output_symhdr->iauxMax; + output_symhdr->iauxMax += fdr.caux; + } + if (! info->relocateable) + { + + /* When are are hashing strings, we lie about the number of + strings attached to each FDR. We need to set cbSs + because some versions of dbx apparently use it to decide + how much of the string table to read in. */ + fdr.issBase = 0; + fdr.cbSs = output_symhdr->issMax; + } + else if (fdr.cbSs > 0) + { + if (!add_file_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, + input_bfd, + input_symhdr->cbSsOffset + fdr.issBase, + fdr.cbSs)) + return false; + fdr.issBase = output_symhdr->issMax; + output_symhdr->issMax += fdr.cbSs; + } + + if ((output_bfd->xvec->header_byteorder_big_p + == input_bfd->xvec->header_byteorder_big_p) + && input_debug->adjust == (struct ecoff_value_adjust *) NULL) + { + /* The two BFD's have the same endianness, and we don't have + to adjust the PDR addresses, so simply copying the + information will suffice. */ + BFD_ASSERT (external_pdr_size == input_swap->external_pdr_size); + if (fdr.cpd > 0) + { + if (!add_file_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, + input_bfd, + (input_symhdr->cbPdOffset + + fdr.ipdFirst * external_pdr_size), + fdr.cpd * external_pdr_size)) + return false; + } + BFD_ASSERT (external_opt_size == input_swap->external_opt_size); + if (fdr.copt > 0) + { + if (!add_file_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, + input_bfd, + (input_symhdr->cbOptOffset + + fdr.ioptBase * external_opt_size), + fdr.copt * external_opt_size)) + return false; + } + } + else + { + bfd_size_type outsz, insz; + bfd_byte *in; + bfd_byte *end; + bfd_byte *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 unnecessarily slow in the normal case. */ + outsz = external_pdr_size; + insz = input_swap->external_pdr_size; + in = ((bfd_byte *) input_debug->external_pdr + + fdr.ipdFirst * insz); + end = in + fdr.cpd * insz; + sz = fdr.cpd * outsz; + out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + if (!out) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + if (!add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out, + sz)) + return false; + for (; in < end; in += insz, out += outsz) + { + PDR pdr; + + (*input_swap->swap_pdr_in) (input_bfd, (PTR) in, &pdr); + + /* If we have been relaxing, we may have to adjust the + address. */ + if (input_debug->adjust != (struct ecoff_value_adjust *) NULL) + { + bfd_vma adr; + struct ecoff_value_adjust *adjust; + + adr = fdr_adr + pdr.adr; + for (adjust = input_debug->adjust; + adjust != (struct ecoff_value_adjust *) NULL; + adjust = adjust->next) + if (adr >= adjust->start + && adr < adjust->end) + pdr.adr += adjust->adjust; + } + + (*output_swap->swap_pdr_out) (output_bfd, &pdr, (PTR) out); + } + + /* Swap over the optimization information. */ + outsz = external_opt_size; + insz = input_swap->external_opt_size; + in = ((bfd_byte *) input_debug->external_opt + + fdr.ioptBase * insz); + end = in + fdr.copt * insz; + sz = fdr.copt * outsz; + out = (bfd_byte *) obstack_alloc (&ainfo->memory, sz); + if (!out) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + if (!add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out, + sz)) + return false; + for (; in < end; in += insz, out += outsz) + { + OPTR opt; + + (*input_swap->swap_opt_in) (input_bfd, (PTR) in, &opt); + (*output_swap->swap_opt_out) (output_bfd, &opt, (PTR) out); + } + } + + fdr.ipdFirst = output_symhdr->ipdMax; + output_symhdr->ipdMax += fdr.cpd; + fdr.ioptBase = output_symhdr->ioptMax; + output_symhdr->ioptMax += fdr.copt; + + if (fdr.crfd <= 0) + { + /* Point this FDR at the table of RFD's we created. */ + fdr.rfdBase = newrfdbase; + fdr.crfd = input_symhdr->ifdMax; + } + else + { + /* Point this FDR at the remapped RFD's. */ + fdr.rfdBase += oldrfdbase; + } + + (*swap_fdr_out) (output_bfd, &fdr, fdr_out); + fdr_out += external_fdr_size; + ++output_symhdr->ifdMax; + } + + return true; +} + +/* Add a string to the debugging information we are accumulating. + Return the offset from the fdr string base. */ + +static long ecoff_add_string PARAMS ((struct accumulate *, + struct bfd_link_info *, + struct ecoff_debug_info *, + FDR *fdr, const char *string)); + +static long +ecoff_add_string (ainfo, info, debug, fdr, string) + struct accumulate *ainfo; + struct bfd_link_info *info; + struct ecoff_debug_info *debug; + FDR *fdr; + const char *string; +{ + HDRR *symhdr; + size_t len; + bfd_size_type ret; + + symhdr = &debug->symbolic_header; + len = strlen (string); + if (info->relocateable) + { + if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, (PTR) string, + len + 1)) + return -1; + ret = symhdr->issMax; + symhdr->issMax += len + 1; + fdr->cbSs += len + 1; + } + else + { + struct string_hash_entry *sh; + + sh = string_hash_lookup (&ainfo->str_hash, string, true, true); + if (sh == (struct string_hash_entry *) NULL) + return -1; + if (sh->val == -1) + { + sh->val = symhdr->issMax; + symhdr->issMax += len + 1; + if (ainfo->ss_hash == (struct string_hash_entry *) NULL) + ainfo->ss_hash = sh; + if (ainfo->ss_hash_end + != (struct string_hash_entry *) NULL) + ainfo->ss_hash_end->next = sh; + ainfo->ss_hash_end = sh; + } + ret = sh->val; + } + + return ret; +} + +/* Add debugging information from a non-ECOFF file. */ + +boolean +bfd_ecoff_debug_accumulate_other (handle, output_bfd, output_debug, + output_swap, input_bfd, info) + PTR handle; + bfd *output_bfd; + struct ecoff_debug_info *output_debug; + const struct ecoff_debug_swap *output_swap; + bfd *input_bfd; + struct bfd_link_info *info; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) + = output_swap->swap_sym_out; + HDRR *output_symhdr = &output_debug->symbolic_header; + FDR fdr; + asection *sec; + asymbol **symbols; + asymbol **sym_ptr; + asymbol **sym_end; + long symsize; + long symcount; + PTR external_fdr; + + memset ((PTR) &fdr, 0, sizeof fdr); + + sec = bfd_get_section_by_name (input_bfd, ".text"); + if (sec != NULL) + fdr.adr = sec->output_section->vma + sec->output_offset; + else + { + /* FIXME: What about .init or .fini? */ + fdr.adr = 0; + } + + fdr.issBase = output_symhdr->issMax; + fdr.cbSs = 0; + fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr, + bfd_get_filename (input_bfd)); + if (fdr.rss == -1) + return false; + fdr.isymBase = output_symhdr->isymMax; + + /* Get the local symbols from the input BFD. */ + symsize = bfd_get_symtab_upper_bound (input_bfd); + if (symsize < 0) + return false; + symbols = (asymbol **) bfd_alloc (output_bfd, symsize); + if (symbols == (asymbol **) NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + symcount = bfd_canonicalize_symtab (input_bfd, symbols); + if (symcount < 0) + return false; + sym_end = symbols + symcount; + + /* 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; + PTR external_sym; + + if (((*sym_ptr)->flags & BSF_EXPORT) != 0) + continue; + memset ((PTR) &internal_sym, 0, sizeof internal_sym); + internal_sym.iss = ecoff_add_string (ainfo, info, output_debug, &fdr, + (*sym_ptr)->name); + + if (internal_sym.iss == -1) + return false; + if (bfd_is_com_section ((*sym_ptr)->section) + || bfd_is_und_section ((*sym_ptr)->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; + + external_sym = (PTR) obstack_alloc (&ainfo->memory, + output_swap->external_sym_size); + if (!external_sym) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + (*swap_sym_out) (output_bfd, &internal_sym, external_sym); + add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, + external_sym, output_swap->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. */ + external_fdr = (PTR) obstack_alloc (&ainfo->memory, + output_swap->external_fdr_size); + if (!external_fdr) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + (*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr); + add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, + external_fdr, output_swap->external_fdr_size); + + ++output_symhdr->ifdMax; + + return true; +} + +/* Set up ECOFF debugging information for the external symbols. + FIXME: This is done using a memory buffer, but it should be + probably be changed to use a shuffle structure. The assembler uses + this interface, so that must be changed to do something else. */ + +boolean +bfd_ecoff_debug_externals (abfd, debug, swap, relocateable, get_extr, + set_index) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + boolean relocateable; + boolean (*get_extr) PARAMS ((asymbol *, EXTR *)); + void (*set_index) PARAMS ((asymbol *, bfd_size_type)); +{ + HDRR * const symhdr = &debug->symbolic_header; + asymbol **sym_ptr_ptr; + size_t c; + + sym_ptr_ptr = bfd_get_outsymbols (abfd); + if (sym_ptr_ptr == NULL) + return true; + + for (c = bfd_get_symcount (abfd); c > 0; c--, sym_ptr_ptr++) + { + asymbol *sym_ptr; + EXTR esym; + + sym_ptr = *sym_ptr_ptr; + + /* Get the external symbol information. */ + if ((*get_extr) (sym_ptr, &esym) == false) + continue; + + /* 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; + } + + if (bfd_is_com_section (sym_ptr->section) + || bfd_is_und_section (sym_ptr->section) + || sym_ptr->section->output_section == (asection *) NULL) + { + /* FIXME: gas does not keep the value of a small undefined + symbol in the symbol itself, because of relocation + problems. */ + if (esym.asym.sc != scSUndefined + || esym.asym.value == 0 + || sym_ptr->value != 0) + esym.asym.value = sym_ptr->value; + } + else + esym.asym.value = (sym_ptr->value + + sym_ptr->section->output_offset + + sym_ptr->section->output_section->vma); + + if (set_index) + (*set_index) (sym_ptr, (bfd_size_type) symhdr->iextMax); + + if (! bfd_ecoff_debug_one_external (abfd, debug, swap, + sym_ptr->name, &esym)) + return false; + } + + return true; +} + +/* Add a single external symbol to the debugging information. */ + +boolean +bfd_ecoff_debug_one_external (abfd, debug, swap, name, esym) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + const char *name; + EXTR *esym; +{ + const bfd_size_type external_ext_size = swap->external_ext_size; + void (* const swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR)) + = swap->swap_ext_out; + HDRR * const symhdr = &debug->symbolic_header; + size_t namelen; + + namelen = strlen (name); + + if (debug->ssext_end - debug->ssext + < symhdr->issExtMax + namelen + 1) + { + if (ecoff_add_bytes ((char **) &debug->ssext, + (char **) &debug->ssext_end, + symhdr->issExtMax + namelen + 1) + == false) + return false; + } + if ((char *) debug->external_ext_end - (char *) debug->external_ext + < (symhdr->iextMax + 1) * external_ext_size) + { + if (ecoff_add_bytes ((char **) &debug->external_ext, + (char **) &debug->external_ext_end, + (symhdr->iextMax + 1) * external_ext_size) + == false) + return false; + } + + esym->asym.iss = symhdr->issExtMax; + + (*swap_ext_out) (abfd, esym, + ((char *) debug->external_ext + + symhdr->iextMax * swap->external_ext_size)); + + ++symhdr->iextMax; + + strcpy (debug->ssext + symhdr->issExtMax, name); + symhdr->issExtMax += namelen + 1; + + return true; +} + +/* Align the ECOFF debugging information. */ + +/*ARGSUSED*/ +static void +ecoff_align_debug (abfd, debug, swap) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; +{ + HDRR * const symhdr = &debug->symbolic_header; + bfd_size_type debug_align, aux_align, rfd_align; + size_t add; + + /* Adjust the counts so that structures are aligned. */ + debug_align = swap->debug_align; + aux_align = debug_align / sizeof (union aux_ext); + rfd_align = debug_align / swap->external_rfd_size; + + add = debug_align - (symhdr->cbLine & (debug_align - 1)); + if (add != debug_align) + { + if (debug->line != (unsigned char *) NULL) + memset ((PTR) (debug->line + symhdr->cbLine), 0, add); + symhdr->cbLine += add; + } + + add = debug_align - (symhdr->issMax & (debug_align - 1)); + if (add != debug_align) + { + if (debug->ss != (char *) NULL) + memset ((PTR) (debug->ss + symhdr->issMax), 0, add); + symhdr->issMax += add; + } + + add = debug_align - (symhdr->issExtMax & (debug_align - 1)); + if (add != debug_align) + { + if (debug->ssext != (char *) NULL) + memset ((PTR) (debug->ssext + symhdr->issExtMax), 0, add); + symhdr->issExtMax += add; + } + + add = aux_align - (symhdr->iauxMax & (aux_align - 1)); + if (add != aux_align) + { + if (debug->external_aux != (union aux_ext *) NULL) + memset ((PTR) (debug->external_aux + symhdr->iauxMax), 0, + add * sizeof (union aux_ext)); + symhdr->iauxMax += add; + } + + add = rfd_align - (symhdr->crfd & (rfd_align - 1)); + if (add != rfd_align) + { + if (debug->external_rfd != (PTR) NULL) + memset ((PTR) ((char *) debug->external_rfd + + symhdr->crfd * swap->external_rfd_size), + 0, add * swap->external_rfd_size); + symhdr->crfd += add; + } +} + +/* Return the size required by the ECOFF debugging information. */ + +bfd_size_type +bfd_ecoff_debug_size (abfd, debug, swap) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; +{ + bfd_size_type tot; + + ecoff_align_debug (abfd, debug, swap); + tot = swap->external_hdr_size; + +#define ADD(count, size) \ + tot += debug->symbolic_header.count * size + + ADD (cbLine, sizeof (unsigned char)); + ADD (idnMax, swap->external_dnr_size); + ADD (ipdMax, swap->external_pdr_size); + ADD (isymMax, swap->external_sym_size); + ADD (ioptMax, swap->external_opt_size); + ADD (iauxMax, sizeof (union aux_ext)); + ADD (issMax, sizeof (char)); + ADD (issExtMax, sizeof (char)); + ADD (ifdMax, swap->external_fdr_size); + ADD (crfd, swap->external_rfd_size); + ADD (iextMax, swap->external_ext_size); + +#undef ADD + + return tot; +} + +/* Write out the ECOFF symbolic header, given the file position it is + going to be placed at. This assumes that the counts are set + correctly. */ + +static boolean +ecoff_write_symhdr (abfd, debug, swap, where) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + file_ptr where; +{ + HDRR * const symhdr = &debug->symbolic_header; + char *buff = NULL; + + ecoff_align_debug (abfd, debug, swap); + + /* Go to the right location in the file. */ + if (bfd_seek (abfd, where, SEEK_SET) != 0) + return false; + + where += swap->external_hdr_size; + + symhdr->magic = swap->sym_magic; + + /* Fill in the file offsets. */ +#define SET(offset, count, size) \ + if (symhdr->count == 0) \ + symhdr->offset = 0; \ + else \ + { \ + symhdr->offset = where; \ + where += symhdr->count * size; \ + } + + SET (cbLineOffset, cbLine, sizeof (unsigned char)); + SET (cbDnOffset, idnMax, swap->external_dnr_size); + SET (cbPdOffset, ipdMax, swap->external_pdr_size); + SET (cbSymOffset, isymMax, swap->external_sym_size); + SET (cbOptOffset, ioptMax, swap->external_opt_size); + SET (cbAuxOffset, iauxMax, sizeof (union aux_ext)); + SET (cbSsOffset, issMax, sizeof (char)); + SET (cbSsExtOffset, issExtMax, sizeof (char)); + SET (cbFdOffset, ifdMax, swap->external_fdr_size); + SET (cbRfdOffset, crfd, swap->external_rfd_size); + SET (cbExtOffset, iextMax, swap->external_ext_size); +#undef SET + + buff = (PTR) malloc (swap->external_hdr_size); + if (buff == NULL && swap->external_hdr_size != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + (*swap->swap_hdr_out) (abfd, symhdr, buff); + if (bfd_write (buff, 1, swap->external_hdr_size, abfd) + != swap->external_hdr_size) + goto error_return; + + if (buff != NULL) + free (buff); + return true; + error_return: + if (buff != NULL) + free (buff); + return false; +} + +/* Write out the ECOFF debugging information. This function assumes + that the information (the pointers and counts) in *DEBUG have been + set correctly. WHERE is the position in the file to write the + information to. This function fills in the file offsets in the + symbolic header. */ + +boolean +bfd_ecoff_write_debug (abfd, debug, swap, where) + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + file_ptr where; +{ + HDRR * const symhdr = &debug->symbolic_header; + + if (! ecoff_write_symhdr (abfd, debug, swap, where)) + return false; + +#define WRITE(ptr, count, size, offset) \ + BFD_ASSERT (symhdr->offset == 0 || bfd_tell (abfd) == symhdr->offset); \ + if (bfd_write ((PTR) debug->ptr, size, symhdr->count, abfd) \ + != size * symhdr->count) \ + return false; + + WRITE (line, cbLine, sizeof (unsigned char), cbLineOffset); + WRITE (external_dnr, idnMax, swap->external_dnr_size, cbDnOffset); + WRITE (external_pdr, ipdMax, swap->external_pdr_size, cbPdOffset); + WRITE (external_sym, isymMax, swap->external_sym_size, cbSymOffset); + WRITE (external_opt, ioptMax, swap->external_opt_size, cbOptOffset); + WRITE (external_aux, iauxMax, sizeof (union aux_ext), cbAuxOffset); + WRITE (ss, issMax, sizeof (char), cbSsOffset); + WRITE (ssext, issExtMax, sizeof (char), cbSsExtOffset); + WRITE (external_fdr, ifdMax, swap->external_fdr_size, cbFdOffset); + WRITE (external_rfd, crfd, swap->external_rfd_size, cbRfdOffset); + WRITE (external_ext, iextMax, swap->external_ext_size, cbExtOffset); +#undef WRITE + + return true; +} + +/* Write out a shuffle list. */ + +static boolean ecoff_write_shuffle PARAMS ((bfd *, + const struct ecoff_debug_swap *, + struct shuffle *, PTR space)); + +static boolean +ecoff_write_shuffle (abfd, swap, shuffle, space) + bfd *abfd; + const struct ecoff_debug_swap *swap; + struct shuffle *shuffle; + PTR space; +{ + register struct shuffle *l; + unsigned long total; + + total = 0; + for (l = shuffle; l != (struct shuffle *) NULL; l = l->next) + { + if (! l->filep) + { + if (bfd_write (l->u.memory, 1, l->size, abfd) != l->size) + return false; + } + else + { + if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0 + || bfd_read (space, 1, l->size, l->u.file.input_bfd) != l->size + || bfd_write (space, 1, l->size, abfd) != l->size) + return false; + } + total += l->size; + } + + if ((total & (swap->debug_align - 1)) != 0) + { + int i; + bfd_byte *s; + + i = swap->debug_align - (total & (swap->debug_align - 1)); + s = (bfd_byte *) malloc (i); + if (s == NULL && i != 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + memset ((PTR) s, 0, i); + if (bfd_write ((PTR) s, 1, i, abfd) != i) + { + free (s); + return false; + } + free (s); + } + + return true; +} + +/* Write out debugging information using accumulated linker + information. */ + +boolean +bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where) + PTR handle; + bfd *abfd; + struct ecoff_debug_info *debug; + const struct ecoff_debug_swap *swap; + struct bfd_link_info *info; + file_ptr where; +{ + struct accumulate *ainfo = (struct accumulate *) handle; + PTR space = NULL; + + if (! ecoff_write_symhdr (abfd, debug, swap, where)) + goto error_return; + + space = (PTR) malloc (ainfo->largest_file_shuffle); + if (space == NULL && ainfo->largest_file_shuffle != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space) + || ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space) + || ! ecoff_write_shuffle (abfd, swap, ainfo->sym, space) + || ! ecoff_write_shuffle (abfd, swap, ainfo->opt, space) + || ! ecoff_write_shuffle (abfd, swap, ainfo->aux, space)) + goto error_return; + + /* The string table is written out from the hash table if this is a + final link. */ + if (info->relocateable) + { + BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL); + if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space)) + goto error_return; + } + else + { + unsigned long total; + bfd_byte null; + struct string_hash_entry *sh; + + BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL); + null = 0; + if (bfd_write ((PTR) &null, 1, 1, abfd) != 1) + goto error_return; + total = 1; + BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1); + for (sh = ainfo->ss_hash; + sh != (struct string_hash_entry *) NULL; + sh = sh->next) + { + size_t len; + + len = strlen (sh->root.string); + if (bfd_write ((PTR) sh->root.string, 1, len + 1, abfd) != len + 1) + goto error_return; + total += len + 1; + } + + if ((total & (swap->debug_align - 1)) != 0) + { + int i; + bfd_byte *s; + + i = swap->debug_align - (total & (swap->debug_align - 1)); + s = (bfd_byte *) malloc (i); + if (s == NULL && i != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + memset ((PTR) s, 0, i); + if (bfd_write ((PTR) s, 1, i, abfd) != i) + { + free (s); + goto error_return; + } + free (s); + } + } + + /* The external strings and symbol are not converted over to using + shuffles. FIXME: They probably should be. */ + if (bfd_write (debug->ssext, 1, debug->symbolic_header.issExtMax, abfd) + != debug->symbolic_header.issExtMax) + goto error_return; + if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0) + { + int i; + bfd_byte *s; + + i = (swap->debug_align + - (debug->symbolic_header.issExtMax & (swap->debug_align - 1))); + s = (bfd_byte *) malloc (i); + if (s == NULL && i != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + memset ((PTR) s, 0, i); + if (bfd_write ((PTR) s, 1, i, abfd) != i) + { + free (s); + goto error_return; + } + free (s); + } + + if (! ecoff_write_shuffle (abfd, swap, ainfo->fdr, space) + || ! ecoff_write_shuffle (abfd, swap, ainfo->rfd, space)) + goto error_return; + + BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0 + || debug->symbolic_header.cbExtOffset == bfd_tell (abfd)); + + if (bfd_write (debug->external_ext, swap->external_ext_size, + debug->symbolic_header.iextMax, abfd) + != debug->symbolic_header.iextMax * swap->external_ext_size) + goto error_return; + + if (space != NULL) + free (space); + return true; + + error_return: + if (space != NULL) + free (space); + return false; +} diff --git a/gnu/usr.bin/gdb/bfd/elf32-i386.c b/gnu/usr.bin/gdb/bfd/elf32-i386.c new file mode 100644 index 00000000000..d2b1ebacf9f --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/elf32-i386.c @@ -0,0 +1,931 @@ +/* Intel 80386/80486-specific support for 32-bit ELF + 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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "libelf.h" + +static CONST struct reloc_howto_struct *elf_i386_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static void elf_i386_info_to_howto + PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *)); +static void elf_i386_info_to_howto_rel + PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *)); +static boolean elf_i386_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean elf_i386_adjust_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static boolean elf_i386_allocate_dynamic_section + PARAMS ((bfd *, const char *)); +static boolean elf_i386_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean elf_i386_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **, char *)); +static boolean elf_i386_finish_dynamic_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + Elf_Internal_Sym *)); +static boolean elf_i386_finish_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +#define USE_REL 1 /* 386 uses REL relocations instead of RELA */ + +enum reloc_type + { + R_386_NONE = 0, + R_386_32, + R_386_PC32, + R_386_GOT32, + R_386_PLT32, + R_386_COPY, + R_386_GLOB_DAT, + R_386_JUMP_SLOT, + R_386_RELATIVE, + R_386_GOTOFF, + R_386_GOTPC, + R_386_max + }; + +#if 0 +static CONST char *CONST reloc_type_names[] = +{ + "R_386_NONE", + "R_386_32", + "R_386_PC32", + "R_386_GOT32", + "R_386_PLT32", + "R_386_COPY", + "R_386_GLOB_DAT", + "R_386_JUMP_SLOT", + "R_386_RELATIVE", + "R_386_GOTOFF", + "R_386_GOTPC", +}; +#endif + +static reloc_howto_type elf_howto_table[]= +{ + HOWTO(R_386_NONE, 0,0, 0,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_NONE", true,0x00000000,0x00000000,false), + HOWTO(R_386_32, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_32", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_PC32, 0,2,32,true, 0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PC32", true,0xffffffff,0xffffffff,true), + HOWTO(R_386_GOT32, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOT32", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_PLT32, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PLT32", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_COPY, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_COPY", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_GLOB_DAT, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GLOB_DAT", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_JUMP_SLOT, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_JUMP_SLOT",true,0xffffffff,0xffffffff,false), + HOWTO(R_386_RELATIVE, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_RELATIVE", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_GOTOFF, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOTOFF", true,0xffffffff,0xffffffff,false), + HOWTO(R_386_GOTPC, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOTPC", true,0xffffffff,0xffffffff,false), +}; + +#ifdef DEBUG_GEN_RELOC +#define TRACE(str) fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str) +#else +#define TRACE(str) +#endif + +static CONST struct reloc_howto_struct * +elf_i386_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + switch (code) + { + case BFD_RELOC_NONE: + TRACE ("BFD_RELOC_NONE"); + return &elf_howto_table[ (int)R_386_NONE ]; + + case BFD_RELOC_32: + TRACE ("BFD_RELOC_32"); + return &elf_howto_table[ (int)R_386_32 ]; + + case BFD_RELOC_32_PCREL: + TRACE ("BFD_RELOC_PC32"); + return &elf_howto_table[ (int)R_386_PC32 ]; + + case BFD_RELOC_386_GOT32: + TRACE ("BFD_RELOC_386_GOT32"); + return &elf_howto_table[ (int)R_386_GOT32 ]; + + case BFD_RELOC_386_PLT32: + TRACE ("BFD_RELOC_386_PLT32"); + return &elf_howto_table[ (int)R_386_PLT32 ]; + + case BFD_RELOC_386_COPY: + TRACE ("BFD_RELOC_386_COPY"); + return &elf_howto_table[ (int)R_386_COPY ]; + + case BFD_RELOC_386_GLOB_DAT: + TRACE ("BFD_RELOC_386_GLOB_DAT"); + return &elf_howto_table[ (int)R_386_GLOB_DAT ]; + + case BFD_RELOC_386_JUMP_SLOT: + TRACE ("BFD_RELOC_386_JUMP_SLOT"); + return &elf_howto_table[ (int)R_386_JUMP_SLOT ]; + + case BFD_RELOC_386_RELATIVE: + TRACE ("BFD_RELOC_386_RELATIVE"); + return &elf_howto_table[ (int)R_386_RELATIVE ]; + + case BFD_RELOC_386_GOTOFF: + TRACE ("BFD_RELOC_386_GOTOFF"); + return &elf_howto_table[ (int)R_386_GOTOFF ]; + + case BFD_RELOC_386_GOTPC: + TRACE ("BFD_RELOC_386_GOTPC"); + return &elf_howto_table[ (int)R_386_GOTPC ]; + + default: + break; + } + + TRACE ("Unknown"); + return 0; +} + +static void +elf_i386_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf32_Internal_Rela *dst; +{ + BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max); + + cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)]; +} + +static void +elf_i386_info_to_howto_rel (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf32_Internal_Rel *dst; +{ + BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max); + + cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)]; +} + +/* Functions for the i386 ELF linker. */ + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ + +#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" + +/* The size in bytes of an entry in the procedure linkage table. */ + +#define PLT_ENTRY_SIZE 16 + +/* The first entry in an absolute procedure linkage table looks like + this. See the SVR4 ABI i386 supplement to see how this works. */ + +static bfd_byte elf_i386_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x35, /* pushl contents of address */ + 0, 0, 0, 0, /* replaced with address of .got + 4. */ + 0xff, 0x25, /* jmp indirect */ + 0, 0, 0, 0, /* replaced with address of .got + 8. */ + 0, 0, 0, 0 /* pad out to 16 bytes. */ +}; + +/* Subsequent entries in an absolute procedure linkage table look like + this. */ + +static bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x25, /* jmp indirect */ + 0, 0, 0, 0, /* replaced with address of this symbol in .got. */ + 0x68, /* pushl immediate */ + 0, 0, 0, 0, /* replaced with offset into relocation table. */ + 0xe9, /* jmp relative */ + 0, 0, 0, 0 /* replaced with offset to start of .plt. */ +}; + +/* Create dynamic sections when linking against a dynamic object. */ + +static boolean +elf_i386_create_dynamic_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + register asection *s; + struct elf_link_hash_entry *h; + + /* We need to create .plt, .rel.plt, .got, .dynbss, and .rel.bss + sections. */ + + flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + + s = bfd_make_section (abfd, ".plt"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY | SEC_CODE) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + s = bfd_make_section (abfd, ".rel.plt"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + s = bfd_make_section (abfd, ".got"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got + section. We don't do this in the linker script because we don't + want to define the symbol if we are not creating a global offset + table. */ + h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, (bfd_vma) 0, + (const char *) NULL, false, get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + + /* The first three global offset table entries are reserved. */ + s->_raw_size += 3 * 4; + + /* The .dynbss section is a place to put symbols which are defined + by dynamic objects, are referenced by regular objects, and are + not functions. We must allocate space for them in the process + image and use a R_386_COPY reloc to tell the dynamic linker to + initialize them at run time. The linker script puts the .dynbss + section into the .bss section of the final image. */ + s = bfd_make_section (abfd, ".dynbss"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, SEC_ALLOC)) + return false; + + /* The .rel.bss section holds copy relocs. This section is not + normally needed. We need to create it here, though, so that the + linker will map it to an output section. If it turns out not to + be needed, we can discard it later. */ + s = bfd_make_section (abfd, ".rel.bss"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 2)) + return false; + + return true; +} + +/* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ + +static boolean +elf_i386_adjust_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + bfd *dynobj; + asection *s; + unsigned int power_of_two; + size_t align; + + dynobj = elf_hash_table (info)->dynobj; + + /* Make sure we know what is going on here. */ + BFD_ASSERT (dynobj != NULL + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + && h->root.type == bfd_link_hash_defined + && (bfd_get_flavour (h->root.u.def.section->owner) + == bfd_target_elf_flavour) + && (elf_elfheader (h->root.u.def.section->owner)->e_type + == ET_DYN) + && h->root.u.def.section->output_section == NULL); + + /* If this is a function, put it in the procedure linkage table. We + will fill in the contents of the procedure linkage table later, + when we know the address of the .got section. */ + if (h->type == STT_FUNC) + { + s = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (s != NULL); + + /* If this is the first .plt entry, make room for the special + first entry. */ + if (s->_raw_size == 0) + s->_raw_size += PLT_ENTRY_SIZE; + + /* Set the symbol to this location in the .plt. */ + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + + /* Make room for this entry. */ + s->_raw_size += PLT_ENTRY_SIZE; + + /* We also need to make an entry in the .got section. */ + + s = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (s != NULL); + s->_raw_size += 4; + + /* We also need to make an entry in the .rel.plt section. */ + + s = bfd_get_section_by_name (dynobj, ".rel.plt"); + BFD_ASSERT (s != NULL); + s->_raw_size += sizeof (Elf32_External_Rel); + + return true; + } + + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->weakdef != NULL) + { + BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined); + h->root.u.def.section = h->weakdef->root.u.def.section; + h->root.u.def.value = h->weakdef->root.u.def.value; + h->align = (bfd_size_type) -1; + return true; + } + + /* This is a reference to a symbol defined by a dynamic object which + is not a function. We must allocate it in our .dynbss section, + which will become part of the .bss section of the executable. + There will be an entry for this symbol in the .dynsym section. + The dynamic object will contain position independent code, so all + references from the dynamic object to this symbol will go through + the global offset table. The dynamic linker will use the .dynsym + entry to determine the address it must put in the global offset + table, so both the dynamic object and the regular object will + refer to the same memory location for the variable. */ + + s = bfd_get_section_by_name (dynobj, ".dynbss"); + BFD_ASSERT (s != NULL); + + /* If the symbol is currently defined in the .bss section of the + dynamic object, then it is OK to simply initialize it to zero. + If the symbol is in some other section, we must generate a + R_386_COPY reloc to tell the dynamic linker to copy the initial + value out of the dynamic object and into the runtime process + image. We need to remember the offset into the .rel.bss section + we are going to use, and we coopt the align field for this + purpose (the align field is only used for common symbols, and + these symbols are always defined). It would be cleaner to use a + new field, but that would waste memory. */ + if ((h->root.u.def.section->flags & SEC_LOAD) == 0) + h->align = (bfd_size_type) -1; + else + { + asection *srel; + + srel = bfd_get_section_by_name (dynobj, ".rel.bss"); + BFD_ASSERT (srel != NULL); + h->align = srel->_raw_size; + srel->_raw_size += sizeof (Elf32_External_Rel); + } + + /* We need to figure out the alignment required for this symbol. I + have no idea how ELF linkers handle this. */ + switch (h->size) + { + case 0: + case 1: + power_of_two = 0; + align = 1; + break; + case 2: + power_of_two = 1; + align = 2; + break; + case 3: + case 4: + power_of_two = 2; + align = 4; + break; + case 5: + case 6: + case 7: + case 8: + power_of_two = 3; + align = 8; + break; + default: + power_of_two = 4; + align = 16; + break; + } + + /* Apply the required alignment. */ + s->_raw_size = BFD_ALIGN (s->_raw_size, align); + if (power_of_two > bfd_get_section_alignment (dynobj, s)) + { + if (! bfd_set_section_alignment (dynobj, s, power_of_two)) + return false; + } + + /* Define the symbol as being at this point in the section. */ + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + + /* Increment the section size to make room for the symbol. */ + s->_raw_size += h->size; + + return true; +} + +/* Allocate contents for a section. */ + +static INLINE boolean +elf_i386_allocate_dynamic_section (dynobj, name) + bfd *dynobj; + const char *name; +{ + register asection *s; + + s = bfd_get_section_by_name (dynobj, name); + BFD_ASSERT (s != NULL); + s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + return true; +} + +/* Set the sizes of the dynamic sections. */ + +static boolean +elf_i386_size_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *s; + + dynobj = elf_hash_table (info)->dynobj; + BFD_ASSERT (dynobj != NULL); + + /* Set the contents of the .interp section to the interpreter. */ + if (! info->shared) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (s != NULL); + s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + + /* The adjust_dynamic_symbol entry point has determined the sizes of + the various dynamic sections. Allocate some memory for them to + hold contents. */ + if (! elf_i386_allocate_dynamic_section (dynobj, ".plt") + || ! elf_i386_allocate_dynamic_section (dynobj, ".rel.plt") + || ! elf_i386_allocate_dynamic_section (dynobj, ".got") + || ! elf_i386_allocate_dynamic_section (dynobj, ".rel.bss")) + return false; + + /* Add some entries to the .dynamic section. We fill in the values + later, in elf_i386_finish_dynamic_sections, but we must add the + entries now so that we get the correct size for the .dynamic + section. The DT_DEBUG entry is filled in by the dynamic linker + and used by the debugger. */ + if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)) + return false; + + s = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (s != NULL); + if (s->_raw_size != 0) + { + if (! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_REL) + || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0)) + return false; + } + + /* If we didn't need the .rel.bss section, then discard it from the + output file. This is a hack. We don't bother to do it for the + other sections because they normally are needed. */ + s = bfd_get_section_by_name (dynobj, ".rel.bss"); + BFD_ASSERT (s != NULL); + if (s->_raw_size == 0) + { + asection **spp; + + for (spp = &s->output_section->owner->sections; + *spp != s->output_section; + spp = &(*spp)->next) + ; + *spp = s->output_section->next; + --s->output_section->owner->section_count; + } + else + { + if (! bfd_elf32_add_dynamic_entry (info, DT_REL, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_RELSZ, 0) + || ! bfd_elf32_add_dynamic_entry (info, DT_RELENT, + sizeof (Elf32_External_Rel))) + return false; + } + + return true; +} + +/* Relocate an i386 ELF section. */ + +static boolean +elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections, + output_names) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; + char *output_names; +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + int r_type; + const reloc_howto_type *howto; + long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sec; + bfd_vma relocation; + bfd_reloc_status_type r; + + r_type = ELF32_R_TYPE (rel->r_info); + if (r_type < 0 || r_type >= (int) R_386_max) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + howto = elf_howto_table + r_type; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + bfd_vma val; + + sec = local_sections[r_symndx]; + val = bfd_get_32 (input_bfd, contents + rel->r_offset); + val += sec->output_offset + sym->st_value; + bfd_put_32 (input_bfd, val, contents + rel->r_offset); + } + } + + continue; + } + + /* This is a final link. */ + h = NULL; + sym = NULL; + sec = NULL; + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + } + else + { + long indx; + + indx = r_symndx - symtab_hdr->sh_info; + h = elf_sym_hashes (input_bfd)[indx]; + if (h->root.type == bfd_link_hash_defined) + { + sec = h->root.u.def.section; + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_weak) + relocation = 0; + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset))) + return false; + relocation = 0; + } + } + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, (bfd_vma) 0); + + if (r != bfd_reloc_ok) + { + switch (r) + { + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else + { + name = output_names + sym->st_name; + if (name == NULL) + return false; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return false; + } + break; + } + } + } + + return true; +} + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static boolean +elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) + bfd *output_bfd; + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + /* If this symbol is not defined by a dynamic object, or is not + referenced by a regular object, ignore it. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) + { + /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) + sym->st_shndx = SHN_ABS; + return true; + } + + BFD_ASSERT (h->root.type == bfd_link_hash_defined); + BFD_ASSERT (h->dynindx != -1); + + if (h->type == STT_FUNC) + { + asection *splt; + asection *sgot; + asection *srel; + bfd_vma plt_index; + bfd_vma got_offset; + Elf_Internal_Rel rel; + + splt = h->root.u.def.section; + BFD_ASSERT (strcmp (bfd_get_section_name (splt->owner, splt), ".plt") + == 0); + sgot = bfd_get_section_by_name (splt->owner, ".got"); + BFD_ASSERT (sgot != NULL); + srel = bfd_get_section_by_name (splt->owner, ".rel.plt"); + BFD_ASSERT (srel != NULL); + + /* FIXME: This only handles an absolute procedure linkage table. + When producing a dynamic object, we need to generate a + position independent procedure linkage table. */ + + /* Get the index in the procedure linkage table which + corresponds to this symbol. This is the index of this symbol + in all the symbols for which we are making plt entries. The + first entry in the procedure linkage table is reserved. */ + plt_index = h->root.u.def.value / PLT_ENTRY_SIZE - 1; + + /* Get the offset into the .got table of the entry that + corresponds to this function. Each .got entry is 4 bytes. + The first three are reserved. */ + got_offset = (plt_index + 3) * 4; + + /* Fill in the entry in the procedure linkage table. */ + memcpy (splt->contents + h->root.u.def.value, elf_i386_plt_entry, + PLT_ENTRY_SIZE); + bfd_put_32 (output_bfd, + (sgot->output_section->vma + + sgot->output_offset + + got_offset), + splt->contents + h->root.u.def.value + 2); + bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel), + splt->contents + h->root.u.def.value + 7); + bfd_put_32 (output_bfd, - (h->root.u.def.value + PLT_ENTRY_SIZE), + splt->contents + h->root.u.def.value + 12); + + /* Fill in the entry in the global offset table. */ + bfd_put_32 (output_bfd, + (splt->output_section->vma + + splt->output_offset + + h->root.u.def.value + + 6), + sgot->contents + got_offset); + + /* Fill in the entry in the .rel.plt section. */ + rel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + got_offset); + rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + ((Elf32_External_Rel *) srel->contents + + plt_index)); + + /* Mark the symbol as undefined, rather than as defined in the + .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + } + else + { + /* This is not a function. We have already allocated memory for + it in the .bss section (via .dynbss). All we have to do here + is create a COPY reloc if required. */ + if (h->align != (bfd_size_type) -1) + { + asection *s; + Elf_Internal_Rel rel; + + s = bfd_get_section_by_name (h->root.u.def.section->owner, + ".rel.bss"); + BFD_ASSERT (s != NULL); + + rel.r_offset = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + ((Elf32_External_Rel *) + (s->contents + h->align))); + } + } + + return true; +} + +/* Finish up the dynamic sections. */ + +static boolean +elf_i386_finish_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + asection *splt; + asection *sgot; + asection *sdyn; + Elf32_External_Dyn *dyncon, *dynconend; + + splt = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".plt"); + sgot = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".got"); + sdyn = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".dynamic"); + BFD_ASSERT (splt != NULL && sgot != NULL && sdyn != NULL); + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + const char *name; + boolean size; + + bfd_elf32_swap_dyn_in (elf_hash_table (info)->dynobj, dyncon, &dyn); + + /* My reading of the SVR4 ABI indicates that the procedure + linkage table relocs (DT_JMPREL) should be included in the + overall relocs (DT_REL). This is what Solaris does. + However, UnixWare can not handle that case. Therefore, we + override the DT_REL and DT_RELSZ entries here to make them + not include the JMPREL relocs. */ + + switch (dyn.d_tag) + { + case DT_PLTGOT: name = ".got"; size = false; break; + case DT_PLTRELSZ: name = ".rel.plt"; size = true; break; + case DT_JMPREL: name = ".rel.plt"; size = false; break; + case DT_REL: name = ".rel.bss"; size = false; break; + case DT_RELSZ: name = ".rel.bss"; size = true; break; + default: name = NULL; size = false; break; + } + + if (name != NULL) + { + asection *s; + + s = bfd_get_section_by_name (output_bfd, name); + BFD_ASSERT (s != NULL); + if (! size) + dyn.d_un.d_ptr = s->vma; + else + { + if (s->_cooked_size != 0) + dyn.d_un.d_val = s->_cooked_size; + else + dyn.d_un.d_val = s->_raw_size; + } + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + } + } + + /* Fill in the first entry in the procedure linkage table. */ + if (splt->_raw_size > 0) + { + memcpy (splt->contents, elf_i386_plt0_entry, PLT_ENTRY_SIZE); + bfd_put_32 (output_bfd, + sgot->output_section->vma + sgot->output_offset + 4, + splt->contents + 2); + bfd_put_32 (output_bfd, + sgot->output_section->vma + sgot->output_offset + 8, + splt->contents + 8); + } + + /* Fill in the first three entries in the global offset table. */ + if (sgot->_raw_size > 0) + { + bfd_put_32 (output_bfd, + sdyn->output_section->vma + sdyn->output_offset, + sgot->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); + } + + elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; + + /* UnixWare sets the entsize of .plt to 4, although that doesn't + really seem like the right value. */ + elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; + + return true; +} + +#define TARGET_LITTLE_SYM bfd_elf32_i386_vec +#define TARGET_LITTLE_NAME "elf32-i386" +#define ELF_ARCH bfd_arch_i386 +#define ELF_MACHINE_CODE EM_386 +#define elf_info_to_howto elf_i386_info_to_howto +#define elf_info_to_howto_rel elf_i386_info_to_howto_rel +#define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup +#define ELF_MAXPAGESIZE 0x1000 +#define elf_backend_create_dynamic_sections \ + elf_i386_create_dynamic_sections +#define elf_backend_adjust_dynamic_symbol \ + elf_i386_adjust_dynamic_symbol +#define elf_backend_size_dynamic_sections \ + elf_i386_size_dynamic_sections +#define elf_backend_relocate_section elf_i386_relocate_section +#define elf_backend_finish_dynamic_symbol \ + elf_i386_finish_dynamic_symbol +#define elf_backend_finish_dynamic_sections \ + elf_i386_finish_dynamic_sections + +#include "elf32-target.h" diff --git a/gnu/usr.bin/gdb/bfd/elf32-target.h b/gnu/usr.bin/gdb/bfd/elf32-target.h new file mode 100644 index 00000000000..67dabecc71f --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/elf32-target.h @@ -0,0 +1,358 @@ +/* Target definitions for 32-bit ELF + Copyright 1993, 1994 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. */ + +/* 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. + + There are two such structures here: one for big-endian machines and + one for little-endian machines. */ + +#define bfd_elf32_close_and_cleanup _bfd_generic_close_and_cleanup +#define bfd_elf32_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#ifndef bfd_elf32_get_section_contents +#define bfd_elf32_get_section_contents _bfd_generic_get_section_contents +#endif + +#define bfd_elf32_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define bfd_elf32_bfd_relax_section bfd_generic_relax_section +#define bfd_elf32_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) + +#ifndef bfd_elf32_bfd_copy_private_section_data +#define bfd_elf32_bfd_copy_private_section_data \ + ((boolean (*) PARAMS ((bfd *, asection *, bfd *, asection *))) bfd_true) +#endif +#ifndef bfd_elf32_bfd_copy_private_bfd_data +#define bfd_elf32_bfd_copy_private_bfd_data \ + ((boolean (*) PARAMS ((bfd *, bfd *))) bfd_true) +#endif +#ifndef bfd_elf32_bfd_is_local_label +#define bfd_elf32_bfd_is_local_label bfd_generic_is_local_label +#endif + +#ifndef bfd_elf32_get_dynamic_reloc_upper_bound +#define bfd_elf32_get_dynamic_reloc_upper_bound \ + _bfd_nodynamic_get_dynamic_reloc_upper_bound +#endif +#ifndef bfd_elf32_canonicalize_dynamic_reloc +#define bfd_elf32_canonicalize_dynamic_reloc \ + _bfd_nodynamic_canonicalize_dynamic_reloc +#endif + +#ifdef elf_backend_relocate_section +#ifndef bfd_elf32_bfd_link_hash_table_create +#define bfd_elf32_bfd_link_hash_table_create _bfd_elf_link_hash_table_create +#endif +#else /* ! defined (elf_backend_relocate_section) */ +/* If no backend relocate_section routine, use the generic linker. */ +#ifndef bfd_elf32_bfd_link_hash_table_create +#define bfd_elf32_bfd_link_hash_table_create \ + _bfd_generic_link_hash_table_create +#endif +#ifndef bfd_elf32_bfd_link_add_symbols +#define bfd_elf32_bfd_link_add_symbols _bfd_generic_link_add_symbols +#endif +#ifndef bfd_elf32_bfd_final_link +#define bfd_elf32_bfd_final_link _bfd_generic_final_link +#endif +#endif /* ! defined (elf_backend_relocate_section) */ + +#ifndef elf_info_to_howto_rel +#define elf_info_to_howto_rel 0 +#endif + +#ifndef ELF_MAXPAGESIZE +#define ELF_MAXPAGESIZE 1 +#endif + +#ifndef elf_backend_collect +#define elf_backend_collect false +#endif + +#ifndef elf_backend_sym_is_global +#define elf_backend_sym_is_global 0 +#endif +#ifndef elf_backend_object_p +#define elf_backend_object_p 0 +#endif +#ifndef elf_backend_symbol_processing +#define elf_backend_symbol_processing 0 +#endif +#ifndef elf_backend_symbol_table_processing +#define elf_backend_symbol_table_processing 0 +#endif +#ifndef elf_backend_section_processing +#define elf_backend_section_processing 0 +#endif +#ifndef elf_backend_section_from_shdr +#define elf_backend_section_from_shdr 0 +#endif +#ifndef elf_backend_fake_sections +#define elf_backend_fake_sections 0 +#endif +#ifndef elf_backend_section_from_bfd_section +#define elf_backend_section_from_bfd_section 0 +#endif +#ifndef elf_backend_add_symbol_hook +#define elf_backend_add_symbol_hook 0 +#endif +#ifndef elf_backend_link_output_symbol_hook +#define elf_backend_link_output_symbol_hook 0 +#endif +#ifndef elf_backend_create_dynamic_sections +#define elf_backend_create_dynamic_sections 0 +#endif +#ifndef elf_backend_adjust_dynamic_symbol +#define elf_backend_adjust_dynamic_symbol 0 +#endif +#ifndef elf_backend_size_dynamic_sections +#define elf_backend_size_dynamic_sections 0 +#endif +#ifndef elf_backend_relocate_section +#define elf_backend_relocate_section 0 +#endif +#ifndef elf_backend_finish_dynamic_symbol +#define elf_backend_finish_dynamic_symbol 0 +#endif +#ifndef elf_backend_finish_dynamic_sections +#define elf_backend_finish_dynamic_sections 0 +#endif +#ifndef elf_backend_begin_write_processing +#define elf_backend_begin_write_processing 0 +#endif +#ifndef elf_backend_final_write_processing +#define elf_backend_final_write_processing 0 +#endif +#ifndef elf_backend_ecoff_debug_swap +#define elf_backend_ecoff_debug_swap 0 +#endif + +static CONST struct elf_backend_data elf32_bed = +{ +#ifdef USE_REL + 0, /* use_rela_p */ +#else + 1, /* use_rela_p */ +#endif + 0, /* elf_64_p */ + ELF_ARCH, /* arch */ + ELF_MACHINE_CODE, /* elf_machine_code */ + ELF_MAXPAGESIZE, /* maxpagesize */ + elf_backend_collect, + elf_info_to_howto, + elf_info_to_howto_rel, + elf_backend_sym_is_global, + elf_backend_object_p, + elf_backend_symbol_processing, + elf_backend_symbol_table_processing, + elf_backend_section_processing, + elf_backend_section_from_shdr, + elf_backend_fake_sections, + elf_backend_section_from_bfd_section, + elf_backend_add_symbol_hook, + elf_backend_link_output_symbol_hook, + elf_backend_create_dynamic_sections, + elf_backend_adjust_dynamic_symbol, + elf_backend_size_dynamic_sections, + elf_backend_relocate_section, + elf_backend_finish_dynamic_symbol, + elf_backend_finish_dynamic_sections, + elf_backend_begin_write_processing, + elf_backend_final_write_processing, + elf_backend_ecoff_debug_swap +}; + +#ifdef TARGET_BIG_SYM +const bfd_target TARGET_BIG_SYM = +{ + /* name: identify kind of target */ + TARGET_BIG_NAME, + + /* flavour: general indication about file */ + bfd_target_elf_flavour, + + /* byteorder_big_p: data is big endian */ + true, + + /* header_byteorder_big_p: header is also big endian */ + true, + + /* object_flags: mask of all file flags */ + (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS | + DYNAMIC | WP_TEXT | D_PAGED), + + /* section_flags: mask of all section flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY | + SEC_CODE | SEC_DATA | SEC_DEBUGGING), + + /* leading_symbol_char: is the first char of a user symbol + predictable, and if so what is it */ + 0, + + /* ar_pad_char: pad character for filenames within an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and/or os and should be independently tunable */ + '/', + + /* ar_max_namelen: maximum number of characters in an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and should be independently tunable. This value is + a WAG (wild a** guess) */ + 14, + + /* align_power_min: minimum alignment restriction for any section + FIXME: this value may be target machine dependent */ + 3, + + /* Routines to byte-swap various sized integers from the data sections */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + + /* Routines to byte-swap various sized integers from the file headers */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + + /* bfd_check_format: check the format of a file being read */ + { _bfd_dummy_target, /* unknown format */ + bfd_elf32_object_p, /* assembler/linker output (object file) */ + bfd_generic_archive_p, /* an archive */ + bfd_elf32_core_file_p /* a core file */ + }, + + /* bfd_set_format: set the format of a file being written */ + { bfd_false, + bfd_elf_mkobject, + _bfd_generic_mkarchive, + bfd_false + }, + + /* bfd_write_contents: write cached information into a file being written */ + { bfd_false, + bfd_elf32_write_object_contents, + _bfd_write_archive_contents, + bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (bfd_elf32), + BFD_JUMP_TABLE_COPY (bfd_elf32), + BFD_JUMP_TABLE_CORE (bfd_elf32), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (bfd_elf32), + BFD_JUMP_TABLE_RELOCS (bfd_elf32), + BFD_JUMP_TABLE_WRITE (bfd_elf32), + BFD_JUMP_TABLE_LINK (bfd_elf32), + BFD_JUMP_TABLE_DYNAMIC (bfd_elf32), + + /* backend_data: */ + (PTR) &elf32_bed, +}; +#endif + +#ifdef TARGET_LITTLE_SYM +const bfd_target TARGET_LITTLE_SYM = +{ + /* name: identify kind of target */ + TARGET_LITTLE_NAME, + + /* flavour: general indication about file */ + bfd_target_elf_flavour, + + /* byteorder_big_p: data is big endian */ + false, /* Nope -- this one's little endian */ + + /* header_byteorder_big_p: header is also big endian */ + false, /* Nope -- this one's little endian */ + + /* object_flags: mask of all file flags */ + (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS | + DYNAMIC | WP_TEXT | D_PAGED), + + /* section_flags: mask of all section flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY | + SEC_CODE | SEC_DATA | SEC_DEBUGGING), + + /* leading_symbol_char: is the first char of a user symbol + predictable, and if so what is it */ + 0, + + /* ar_pad_char: pad character for filenames within an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and/or os and should be independently tunable */ + '/', + + /* ar_max_namelen: maximum number of characters in an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and should be independently tunable. This value is + a WAG (wild a** guess) */ + 14, + + /* align_power_min: minimum alignment restriction for any section + FIXME: this value may be target machine dependent */ + 3, + + /* Routines to byte-swap various sized integers from the data sections */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, + + /* Routines to byte-swap various sized integers from the file headers */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, + + /* bfd_check_format: check the format of a file being read */ + { _bfd_dummy_target, /* unknown format */ + bfd_elf32_object_p, /* assembler/linker output (object file) */ + bfd_generic_archive_p, /* an archive */ + bfd_elf32_core_file_p /* a core file */ + }, + + /* bfd_set_format: set the format of a file being written */ + { bfd_false, + bfd_elf_mkobject, + _bfd_generic_mkarchive, + bfd_false + }, + + /* bfd_write_contents: write cached information into a file being written */ + { bfd_false, + bfd_elf32_write_object_contents, + _bfd_write_archive_contents, + bfd_false + }, + + BFD_JUMP_TABLE_GENERIC (bfd_elf32), + BFD_JUMP_TABLE_COPY (bfd_elf32), + BFD_JUMP_TABLE_CORE (bfd_elf32), + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), + BFD_JUMP_TABLE_SYMBOLS (bfd_elf32), + BFD_JUMP_TABLE_RELOCS (bfd_elf32), + BFD_JUMP_TABLE_WRITE (bfd_elf32), + BFD_JUMP_TABLE_LINK (bfd_elf32), + BFD_JUMP_TABLE_DYNAMIC (bfd_elf32), + + /* backend_data: */ + (PTR) &elf32_bed, +}; +#endif diff --git a/gnu/usr.bin/gdb/bfd/elf32.c b/gnu/usr.bin/gdb/bfd/elf32.c new file mode 100644 index 00000000000..862dd2df592 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/elf32.c @@ -0,0 +1,23 @@ +/* ELF 32-bit 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. */ + +#define ARCH_SIZE 32 + + +#include "elfcode.h" diff --git a/gnu/usr.bin/gdb/bfd/elfcode.h b/gnu/usr.bin/gdb/bfd/elfcode.h new file mode 100644 index 00000000000..5d9ffd10d27 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/elfcode.h @@ -0,0 +1,6351 @@ +/* ELF executable support for BFD. + Copyright 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". Sufficient support for gdb. + + Rewritten by Mark Eichin @ Cygnus Support, from information + published in "System V Application Binary Interface", chapters 4 + and 5, as well as the various "Processor Supplement" documents + derived from it. Added support for assembler and other object file + utilities. Further work done by Ken Raeburn (Cygnus Support), Michael + Meissner (Open Software Foundation), and Peter Hoogenboom (University + of Utah) to finish and extend this. + +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. */ + +/* Problems and other issues to resolve. + + (1) BFD expects there to be some fixed number of "sections" in + the object file. I.E. there is a "section_count" variable in the + bfd structure which contains the number of sections. However, ELF + supports multiple "views" of a file. In particular, with current + implementations, executable files typically have two tables, a + program header table and a section header table, both of which + partition the executable. + + In ELF-speak, the "linking view" of the file uses the section header + table to access "sections" within the file, and the "execution view" + uses the program header table to access "segments" within the file. + "Segments" typically may contain all the data from one or more + "sections". + + Note that the section header table is optional in ELF executables, + but it is this information that is most useful to gdb. If the + section header table is missing, then gdb should probably try + to make do with the program header table. (FIXME) + + (2) The code in this file is compiled twice, once in 32-bit mode and + once in 64-bit mode. More of it should be made size-independent + and moved into elf.c. + + (3) ELF section symbols are handled rather sloppily now. This should + be cleaned up, and ELF section symbols reconciled with BFD section + symbols. + + (4) We need a published spec for 64-bit ELF. We've got some stuff here + that we're using for SPARC V9 64-bit chips, but don't assume that + it's cast in stone. + */ + +#include /* For strrchr and friends */ +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "libelf.h" + +/* Renaming structures, typedefs, macros and functions to be size-specific. */ +#define Elf_External_Ehdr NAME(Elf,External_Ehdr) +#define Elf_External_Sym NAME(Elf,External_Sym) +#define Elf_External_Shdr NAME(Elf,External_Shdr) +#define Elf_External_Phdr NAME(Elf,External_Phdr) +#define Elf_External_Rel NAME(Elf,External_Rel) +#define Elf_External_Rela NAME(Elf,External_Rela) +#define Elf_External_Dyn NAME(Elf,External_Dyn) + +#define elf_core_file_failing_command NAME(bfd_elf,core_file_failing_command) +#define elf_core_file_failing_signal NAME(bfd_elf,core_file_failing_signal) +#define elf_core_file_matches_executable_p \ + NAME(bfd_elf,core_file_matches_executable_p) +#define elf_object_p NAME(bfd_elf,object_p) +#define elf_core_file_p NAME(bfd_elf,core_file_p) +#define elf_get_symtab_upper_bound NAME(bfd_elf,get_symtab_upper_bound) +#define elf_get_dynamic_symtab_upper_bound \ + NAME(bfd_elf,get_dynamic_symtab_upper_bound) +#define elf_swap_reloc_in NAME(bfd_elf,swap_reloc_in) +#define elf_swap_reloca_in NAME(bfd_elf,swap_reloca_in) +#define elf_swap_reloc_out NAME(bfd_elf,swap_reloc_out) +#define elf_swap_reloca_out NAME(bfd_elf,swap_reloca_out) +#define elf_swap_symbol_in NAME(bfd_elf,swap_symbol_in) +#define elf_swap_symbol_out NAME(bfd_elf,swap_symbol_out) +#define elf_swap_dyn_in NAME(bfd_elf,swap_dyn_in) +#define elf_swap_dyn_out NAME(bfd_elf,swap_dyn_out) +#define elf_get_reloc_upper_bound NAME(bfd_elf,get_reloc_upper_bound) +#define elf_canonicalize_reloc NAME(bfd_elf,canonicalize_reloc) +#define elf_get_symtab NAME(bfd_elf,get_symtab) +#define elf_canonicalize_dynamic_symtab \ + NAME(bfd_elf,canonicalize_dynamic_symtab) +#define elf_make_empty_symbol NAME(bfd_elf,make_empty_symbol) +#define elf_get_symbol_info NAME(bfd_elf,get_symbol_info) +#define elf_print_symbol NAME(bfd_elf,print_symbol) +#define elf_get_lineno NAME(bfd_elf,get_lineno) +#define elf_set_arch_mach NAME(bfd_elf,set_arch_mach) +#define elf_find_nearest_line NAME(bfd_elf,find_nearest_line) +#define elf_sizeof_headers NAME(bfd_elf,sizeof_headers) +#define elf_set_section_contents NAME(bfd_elf,set_section_contents) +#define elf_no_info_to_howto NAME(bfd_elf,no_info_to_howto) +#define elf_no_info_to_howto_rel NAME(bfd_elf,no_info_to_howto_rel) +#define elf_new_section_hook NAME(bfd_elf,new_section_hook) +#define write_relocs NAME(bfd_elf,_write_relocs) +#define elf_find_section NAME(bfd_elf,find_section) +#define elf_bfd_link_add_symbols NAME(bfd_elf,bfd_link_add_symbols) +#define elf_add_dynamic_entry NAME(bfd_elf,add_dynamic_entry) +#define elf_bfd_final_link NAME(bfd_elf,bfd_final_link) + +#if ARCH_SIZE == 64 +#define ELF_R_INFO(X,Y) ELF64_R_INFO(X,Y) +#define ELF_R_SYM(X) ELF64_R_SYM(X) +#define ELF_R_TYPE(X) ELF64_R_TYPE(X) +#define ELFCLASS ELFCLASS64 +#define FILE_ALIGN 8 +#define LOG_FILE_ALIGN 3 +#endif +#if ARCH_SIZE == 32 +#define ELF_R_INFO(X,Y) ELF32_R_INFO(X,Y) +#define ELF_R_SYM(X) ELF32_R_SYM(X) +#define ELF_R_TYPE(X) ELF32_R_TYPE(X) +#define ELFCLASS ELFCLASS32 +#define FILE_ALIGN 4 +#define LOG_FILE_ALIGN 2 +#endif + +/* Forward declarations of static functions */ + +static unsigned long bfd_add_to_strtab + PARAMS ((bfd *, struct strtab *, const char *)); +static asection *section_from_elf_index PARAMS ((bfd *, unsigned int)); + +static int elf_section_from_bfd_section PARAMS ((bfd *, struct sec *)); + +static long elf_slurp_symbol_table PARAMS ((bfd *, asymbol **, boolean)); + +static boolean elf_slurp_reloc_table PARAMS ((bfd *, asection *, asymbol **)); + +static int elf_symbol_from_bfd_symbol PARAMS ((bfd *, + struct symbol_cache_entry **)); + +static boolean elf_compute_section_file_positions + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean prep_headers PARAMS ((bfd *)); +static void elf_fake_sections PARAMS ((bfd *, asection *, PTR)); +static boolean assign_section_numbers PARAMS ((bfd *)); +static file_ptr align_file_position PARAMS ((file_ptr)); +static file_ptr assign_file_position_for_section + PARAMS ((Elf_Internal_Shdr *, file_ptr, boolean)); +static boolean assign_file_positions_except_relocs PARAMS ((bfd *, boolean)); +static void assign_file_positions_for_relocs PARAMS ((bfd *)); +static bfd_size_type get_program_header_size PARAMS ((bfd *)); +static file_ptr map_program_segments + PARAMS ((bfd *, file_ptr, Elf_Internal_Shdr *, bfd_size_type)); + +static boolean elf_map_symbols PARAMS ((bfd *)); +static boolean swap_out_syms PARAMS ((bfd *)); + +static boolean bfd_section_from_shdr PARAMS ((bfd *, unsigned int shindex)); + +#ifdef DEBUG +static void elf_debug_section PARAMS ((char *, int, Elf_Internal_Shdr *)); +static void elf_debug_file PARAMS ((Elf_Internal_Ehdr *)); +#endif + +#define elf_string_from_elf_strtab(abfd,strindex) \ + elf_string_from_elf_section(abfd,elf_elfheader(abfd)->e_shstrndx,strindex) + + +/* Structure swapping routines */ + +/* Should perhaps use put_offset, put_word, etc. For now, the two versions + can be handled by explicitly specifying 32 bits or "the long type". */ +#if ARCH_SIZE == 64 +#define put_word bfd_h_put_64 +#define get_word bfd_h_get_64 +#endif +#if ARCH_SIZE == 32 +#define put_word bfd_h_put_32 +#define get_word bfd_h_get_32 +#endif + +/* Translate an ELF symbol in external format into an ELF symbol in internal + format. */ + +void +elf_swap_symbol_in (abfd, src, dst) + bfd *abfd; + Elf_External_Sym *src; + Elf_Internal_Sym *dst; +{ + dst->st_name = bfd_h_get_32 (abfd, (bfd_byte *) src->st_name); + dst->st_value = get_word (abfd, (bfd_byte *) src->st_value); + dst->st_size = get_word (abfd, (bfd_byte *) src->st_size); + dst->st_info = bfd_h_get_8 (abfd, (bfd_byte *) src->st_info); + dst->st_other = bfd_h_get_8 (abfd, (bfd_byte *) src->st_other); + dst->st_shndx = bfd_h_get_16 (abfd, (bfd_byte *) src->st_shndx); +} + +/* Translate an ELF symbol in internal format into an ELF symbol in external + format. */ + +void +elf_swap_symbol_out (abfd, src, dst) + bfd *abfd; + Elf_Internal_Sym *src; + Elf_External_Sym *dst; +{ + bfd_h_put_32 (abfd, src->st_name, dst->st_name); + put_word (abfd, src->st_value, dst->st_value); + put_word (abfd, src->st_size, dst->st_size); + bfd_h_put_8 (abfd, src->st_info, dst->st_info); + bfd_h_put_8 (abfd, src->st_other, dst->st_other); + bfd_h_put_16 (abfd, src->st_shndx, dst->st_shndx); +} + + +/* Translate an ELF file header in external format into an ELF file header in + internal format. */ + +static void +elf_swap_ehdr_in (abfd, src, dst) + bfd *abfd; + Elf_External_Ehdr *src; + Elf_Internal_Ehdr *dst; +{ + memcpy (dst->e_ident, src->e_ident, EI_NIDENT); + dst->e_type = bfd_h_get_16 (abfd, (bfd_byte *) src->e_type); + dst->e_machine = bfd_h_get_16 (abfd, (bfd_byte *) src->e_machine); + dst->e_version = bfd_h_get_32 (abfd, (bfd_byte *) src->e_version); + dst->e_entry = get_word (abfd, (bfd_byte *) src->e_entry); + dst->e_phoff = get_word (abfd, (bfd_byte *) src->e_phoff); + dst->e_shoff = get_word (abfd, (bfd_byte *) src->e_shoff); + dst->e_flags = bfd_h_get_32 (abfd, (bfd_byte *) src->e_flags); + dst->e_ehsize = bfd_h_get_16 (abfd, (bfd_byte *) src->e_ehsize); + dst->e_phentsize = bfd_h_get_16 (abfd, (bfd_byte *) src->e_phentsize); + dst->e_phnum = bfd_h_get_16 (abfd, (bfd_byte *) src->e_phnum); + dst->e_shentsize = bfd_h_get_16 (abfd, (bfd_byte *) src->e_shentsize); + dst->e_shnum = bfd_h_get_16 (abfd, (bfd_byte *) src->e_shnum); + dst->e_shstrndx = bfd_h_get_16 (abfd, (bfd_byte *) src->e_shstrndx); +} + +/* Translate an ELF file header in internal format into an ELF file header in + external format. */ + +static void +elf_swap_ehdr_out (abfd, src, dst) + bfd *abfd; + Elf_Internal_Ehdr *src; + Elf_External_Ehdr *dst; +{ + memcpy (dst->e_ident, src->e_ident, EI_NIDENT); + /* note that all elements of dst are *arrays of unsigned char* already... */ + bfd_h_put_16 (abfd, src->e_type, dst->e_type); + bfd_h_put_16 (abfd, src->e_machine, dst->e_machine); + bfd_h_put_32 (abfd, src->e_version, dst->e_version); + put_word (abfd, src->e_entry, dst->e_entry); + put_word (abfd, src->e_phoff, dst->e_phoff); + put_word (abfd, src->e_shoff, dst->e_shoff); + bfd_h_put_32 (abfd, src->e_flags, dst->e_flags); + bfd_h_put_16 (abfd, src->e_ehsize, dst->e_ehsize); + bfd_h_put_16 (abfd, src->e_phentsize, dst->e_phentsize); + bfd_h_put_16 (abfd, src->e_phnum, dst->e_phnum); + bfd_h_put_16 (abfd, src->e_shentsize, dst->e_shentsize); + bfd_h_put_16 (abfd, src->e_shnum, dst->e_shnum); + bfd_h_put_16 (abfd, src->e_shstrndx, dst->e_shstrndx); +} + + +/* Translate an ELF section header table entry in external format into an + ELF section header table entry in internal format. */ + +static void +elf_swap_shdr_in (abfd, src, dst) + bfd *abfd; + Elf_External_Shdr *src; + Elf_Internal_Shdr *dst; +{ + dst->sh_name = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_name); + dst->sh_type = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_type); + dst->sh_flags = get_word (abfd, (bfd_byte *) src->sh_flags); + dst->sh_addr = get_word (abfd, (bfd_byte *) src->sh_addr); + dst->sh_offset = get_word (abfd, (bfd_byte *) src->sh_offset); + dst->sh_size = get_word (abfd, (bfd_byte *) src->sh_size); + dst->sh_link = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_link); + dst->sh_info = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_info); + dst->sh_addralign = get_word (abfd, (bfd_byte *) src->sh_addralign); + dst->sh_entsize = get_word (abfd, (bfd_byte *) src->sh_entsize); + /* we haven't done any processing on it yet, so... */ + dst->rawdata = (void *) 0; +} + +/* Translate an ELF section header table entry in internal format into an + ELF section header table entry in external format. */ + +static void +elf_swap_shdr_out (abfd, src, dst) + bfd *abfd; + Elf_Internal_Shdr *src; + Elf_External_Shdr *dst; +{ + /* note that all elements of dst are *arrays of unsigned char* already... */ + bfd_h_put_32 (abfd, src->sh_name, dst->sh_name); + bfd_h_put_32 (abfd, src->sh_type, dst->sh_type); + put_word (abfd, src->sh_flags, dst->sh_flags); + put_word (abfd, src->sh_addr, dst->sh_addr); + put_word (abfd, src->sh_offset, dst->sh_offset); + put_word (abfd, src->sh_size, dst->sh_size); + bfd_h_put_32 (abfd, src->sh_link, dst->sh_link); + bfd_h_put_32 (abfd, src->sh_info, dst->sh_info); + put_word (abfd, src->sh_addralign, dst->sh_addralign); + put_word (abfd, src->sh_entsize, dst->sh_entsize); +} + + +/* Translate an ELF program header table entry in external format into an + ELF program header table entry in internal format. */ + +static void +elf_swap_phdr_in (abfd, src, dst) + bfd *abfd; + Elf_External_Phdr *src; + Elf_Internal_Phdr *dst; +{ + dst->p_type = bfd_h_get_32 (abfd, (bfd_byte *) src->p_type); + dst->p_flags = bfd_h_get_32 (abfd, (bfd_byte *) src->p_flags); + dst->p_offset = get_word (abfd, (bfd_byte *) src->p_offset); + dst->p_vaddr = get_word (abfd, (bfd_byte *) src->p_vaddr); + dst->p_paddr = get_word (abfd, (bfd_byte *) src->p_paddr); + dst->p_filesz = get_word (abfd, (bfd_byte *) src->p_filesz); + dst->p_memsz = get_word (abfd, (bfd_byte *) src->p_memsz); + dst->p_align = get_word (abfd, (bfd_byte *) src->p_align); +} + +static void +elf_swap_phdr_out (abfd, src, dst) + bfd *abfd; + Elf_Internal_Phdr *src; + Elf_External_Phdr *dst; +{ + /* note that all elements of dst are *arrays of unsigned char* already... */ + bfd_h_put_32 (abfd, src->p_type, dst->p_type); + put_word (abfd, src->p_offset, dst->p_offset); + put_word (abfd, src->p_vaddr, dst->p_vaddr); + put_word (abfd, src->p_paddr, dst->p_paddr); + put_word (abfd, src->p_filesz, dst->p_filesz); + put_word (abfd, src->p_memsz, dst->p_memsz); + bfd_h_put_32 (abfd, src->p_flags, dst->p_flags); + put_word (abfd, src->p_align, dst->p_align); +} + +/* Translate an ELF reloc from external format to internal format. */ +INLINE void +elf_swap_reloc_in (abfd, src, dst) + bfd *abfd; + Elf_External_Rel *src; + Elf_Internal_Rel *dst; +{ + dst->r_offset = get_word (abfd, (bfd_byte *) src->r_offset); + dst->r_info = get_word (abfd, (bfd_byte *) src->r_info); +} + +INLINE void +elf_swap_reloca_in (abfd, src, dst) + bfd *abfd; + Elf_External_Rela *src; + Elf_Internal_Rela *dst; +{ + dst->r_offset = get_word (abfd, (bfd_byte *) src->r_offset); + dst->r_info = get_word (abfd, (bfd_byte *) src->r_info); + dst->r_addend = get_word (abfd, (bfd_byte *) src->r_addend); +} + +/* Translate an ELF reloc from internal format to external format. */ +INLINE void +elf_swap_reloc_out (abfd, src, dst) + bfd *abfd; + Elf_Internal_Rel *src; + Elf_External_Rel *dst; +{ + put_word (abfd, src->r_offset, dst->r_offset); + put_word (abfd, src->r_info, dst->r_info); +} + +INLINE void +elf_swap_reloca_out (abfd, src, dst) + bfd *abfd; + Elf_Internal_Rela *src; + Elf_External_Rela *dst; +{ + put_word (abfd, src->r_offset, dst->r_offset); + put_word (abfd, src->r_info, dst->r_info); + put_word (abfd, src->r_addend, dst->r_addend); +} + +INLINE void +elf_swap_dyn_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Dyn *src; + Elf_Internal_Dyn *dst; +{ + dst->d_tag = get_word (abfd, src->d_tag); + dst->d_un.d_val = get_word (abfd, src->d_un.d_val); +} + +INLINE void +elf_swap_dyn_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Dyn *src; + Elf_External_Dyn *dst; +{ + put_word (abfd, src->d_tag, dst->d_tag); + put_word (abfd, src->d_un.d_val, dst->d_un.d_val); +} + +/* String table creation/manipulation routines */ + +static struct strtab * +bfd_new_strtab (abfd) + bfd *abfd; +{ + struct strtab *ss; + + ss = (struct strtab *) malloc (sizeof (struct strtab)); + if (!ss) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + ss->tab = malloc (1); + if (!ss->tab) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + *ss->tab = 0; + ss->nentries = 0; + ss->length = 1; + + return ss; +} + +static unsigned long +bfd_add_to_strtab (abfd, ss, str) + bfd *abfd; + struct strtab *ss; + const char *str; +{ + /* should search first, but for now: */ + /* include the trailing NUL */ + int ln = strlen (str) + 1; + + /* FIXME: This is slow. Also, we could combine this with the a.out + string table building and use a hash table, although it might not + be worth it since ELF symbols don't include debugging information + and thus have much less overlap. */ + ss->tab = realloc (ss->tab, ss->length + ln); + if (ss->tab == NULL) + { + bfd_set_error (bfd_error_no_memory); + return (unsigned long) -1; + } + + strcpy (ss->tab + ss->length, str); + ss->nentries++; + ss->length += ln; + + return ss->length - ln; +} + +static int +bfd_add_2_to_strtab (abfd, ss, str, str2) + bfd *abfd; + struct strtab *ss; + char *str; + CONST char *str2; +{ + /* should search first, but for now: */ + /* include the trailing NUL */ + int ln = strlen (str) + strlen (str2) + 1; + + /* should this be using obstacks? */ + if (ss->length) + ss->tab = realloc (ss->tab, ss->length + ln); + else + ss->tab = malloc (ln); + + BFD_ASSERT (ss->tab != 0); /* FIXME */ + strcpy (ss->tab + ss->length, str); + strcpy (ss->tab + ss->length + strlen (str), str2); + ss->nentries++; + ss->length += ln; + + return ss->length - ln; +} + +/* ELF .o/exec file reading */ + +/* Create a new bfd section from an ELF section header. */ + +static boolean +bfd_section_from_shdr (abfd, shindex) + bfd *abfd; + unsigned int shindex; +{ + Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[shindex]; + Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd); + char *name; + + name = elf_string_from_elf_strtab (abfd, hdr->sh_name); + + switch (hdr->sh_type) + { + case SHT_NULL: + /* Inactive section. Throw it away. */ + return true; + + case SHT_PROGBITS: /* Normal section with contents. */ + case SHT_DYNAMIC: /* Dynamic linking information. */ + case SHT_NOBITS: /* .bss section. */ + case SHT_HASH: /* .hash section. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + + case SHT_SYMTAB: /* A symbol table */ + if (elf_onesymtab (abfd) == shindex) + return true; + + BFD_ASSERT (hdr->sh_entsize == sizeof (Elf_External_Sym)); + BFD_ASSERT (elf_onesymtab (abfd) == 0); + elf_onesymtab (abfd) = shindex; + elf_tdata (abfd)->symtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_hdr; + abfd->flags |= HAS_SYMS; + return true; + + case SHT_DYNSYM: /* A dynamic symbol table */ + if (elf_dynsymtab (abfd) == shindex) + return true; + + BFD_ASSERT (hdr->sh_entsize == sizeof (Elf_External_Sym)); + BFD_ASSERT (elf_dynsymtab (abfd) == 0); + elf_dynsymtab (abfd) = shindex; + elf_tdata (abfd)->dynsymtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->dynsymtab_hdr; + abfd->flags |= HAS_SYMS; + + /* Besides being a symbol table, we also treat this as a regular + section, so that objcopy can handle it. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + + case SHT_STRTAB: /* A string table */ + if (hdr->rawdata != NULL) + return true; + if (ehdr->e_shstrndx == shindex) + { + elf_tdata (abfd)->shstrtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->shstrtab_hdr; + hdr->rawdata = (PTR) & elf_tdata (abfd)->shstrtab_hdr; + return true; + } + { + unsigned int i; + + for (i = 1; i < ehdr->e_shnum; i++) + { + Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; + if (hdr2->sh_link == shindex) + { + if (! bfd_section_from_shdr (abfd, i)) + return false; + if (elf_onesymtab (abfd) == i) + { + elf_tdata (abfd)->strtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = + &elf_tdata (abfd)->strtab_hdr; + return true; + } + if (elf_dynsymtab (abfd) == i) + { + elf_tdata (abfd)->dynstrtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = + &elf_tdata (abfd)->dynstrtab_hdr; + /* We also treat this as a regular section, so + that objcopy can handle it. */ + break; + } +#if 0 /* Not handling other string tables specially right now. */ + hdr2 = elf_elfsections (abfd)[i]; /* in case it moved */ + /* We have a strtab for some random other section. */ + newsect = (asection *) hdr2->rawdata; + if (!newsect) + break; + hdr->rawdata = (PTR) newsect; + hdr2 = &elf_section_data (newsect)->str_hdr; + *hdr2 = *hdr; + elf_elfsections (abfd)[shindex] = hdr2; +#endif + } + } + } + + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + + case SHT_REL: + case SHT_RELA: + /* *These* do a lot of work -- but build no sections! */ + { + asection *target_sect; + Elf_Internal_Shdr *hdr2; + int use_rela_p = get_elf_backend_data (abfd)->use_rela_p; + + /* Get the symbol table. */ + if (! bfd_section_from_shdr (abfd, hdr->sh_link)) + return false; + + /* If this reloc section does not use the main symbol table we + don't treat it as a reloc section. BFD can't adequately + represent such a section, so at least for now, we don't + try. We just present it as a normal section. */ + if (hdr->sh_link != elf_onesymtab (abfd)) + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + + /* Don't allow REL relocations on a machine that uses RELA and + vice versa. */ + /* @@ Actually, the generic ABI does suggest that both might be + used in one file. But the four ABI Processor Supplements I + have access to right now all specify that only one is used on + each of those architectures. It's conceivable that, e.g., a + bunch of absolute 32-bit relocs might be more compact in REL + form even on a RELA machine... */ + BFD_ASSERT (use_rela_p + ? (hdr->sh_type == SHT_RELA + && hdr->sh_entsize == sizeof (Elf_External_Rela)) + : (hdr->sh_type == SHT_REL + && hdr->sh_entsize == sizeof (Elf_External_Rel))); + + if (! bfd_section_from_shdr (abfd, hdr->sh_info)) + return false; + target_sect = section_from_elf_index (abfd, hdr->sh_info); + if (target_sect == NULL + || elf_section_data (target_sect) == NULL) + return false; + + hdr2 = &elf_section_data (target_sect)->rel_hdr; + *hdr2 = *hdr; + elf_elfsections (abfd)[shindex] = hdr2; + target_sect->reloc_count = hdr->sh_size / hdr->sh_entsize; + target_sect->flags |= SEC_RELOC; + target_sect->relocation = NULL; + target_sect->rel_filepos = hdr->sh_offset; + abfd->flags |= HAS_RELOC; + return true; + } + break; + + case SHT_NOTE: +#if 0 + fprintf (stderr, "Note Sections not yet supported.\n"); + BFD_FAIL (); +#endif + break; + + case SHT_SHLIB: +#if 0 + fprintf (stderr, "SHLIB Sections not supported (and non conforming.)\n"); +#endif + return true; + + default: + /* Check for any processor-specific section types. */ + { + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if (bed->elf_backend_section_from_shdr) + (*bed->elf_backend_section_from_shdr) (abfd, hdr, name); + } + break; + } + + return true; +} + +boolean +elf_new_section_hook (abfd, sec) + bfd *abfd + ; + asection *sec; +{ + struct bfd_elf_section_data *sdata; + + sdata = (struct bfd_elf_section_data *) bfd_alloc (abfd, sizeof (*sdata)); + if (!sdata) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + sec->used_by_bfd = (PTR) sdata; + memset (sdata, 0, sizeof (*sdata)); + return true; +} + +/* Create a new bfd section from an ELF program header. + + Since program segments have no names, we generate a synthetic name + of the form segment, where NUM is generally the index in the + program header table. For segments that are split (see below) we + generate the names segmenta and segmentb. + + Note that some program segments may have a file size that is different than + (less than) the memory size. All this means is that at execution the + system must allocate the amount of memory specified by the memory size, + but only initialize it with the first "file size" bytes read from the + file. This would occur for example, with program segments consisting + of combined data+bss. + + To handle the above situation, this routine generates TWO bfd sections + for the single program segment. The first has the length specified by + the file size of the segment, and the second has the length specified + by the difference between the two sizes. In effect, the segment is split + into it's initialized and uninitialized parts. + + */ + +static boolean +bfd_section_from_phdr (abfd, hdr, index) + bfd *abfd; + Elf_Internal_Phdr *hdr; + int index; +{ + asection *newsect; + char *name; + char namebuf[64]; + int split; + + split = ((hdr->p_memsz > 0) && + (hdr->p_filesz > 0) && + (hdr->p_memsz > hdr->p_filesz)); + sprintf (namebuf, split ? "segment%da" : "segment%d", index); + name = bfd_alloc (abfd, strlen (namebuf) + 1); + if (!name) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + strcpy (name, namebuf); + newsect = bfd_make_section (abfd, name); + if (newsect == NULL) + return false; + newsect->vma = hdr->p_vaddr; + newsect->_raw_size = hdr->p_filesz; + newsect->filepos = hdr->p_offset; + newsect->flags |= SEC_HAS_CONTENTS; + if (hdr->p_type == PT_LOAD) + { + newsect->flags |= SEC_ALLOC; + newsect->flags |= SEC_LOAD; + if (hdr->p_flags & PF_X) + { + /* FIXME: all we known is that it has execute PERMISSION, + may be data. */ + newsect->flags |= SEC_CODE; + } + } + if (!(hdr->p_flags & PF_W)) + { + newsect->flags |= SEC_READONLY; + } + + if (split) + { + sprintf (namebuf, "segment%db", index); + name = bfd_alloc (abfd, strlen (namebuf) + 1); + if (!name) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + strcpy (name, namebuf); + newsect = bfd_make_section (abfd, name); + if (newsect == NULL) + return false; + newsect->vma = hdr->p_vaddr + hdr->p_filesz; + newsect->_raw_size = hdr->p_memsz - hdr->p_filesz; + if (hdr->p_type == PT_LOAD) + { + newsect->flags |= SEC_ALLOC; + if (hdr->p_flags & PF_X) + newsect->flags |= SEC_CODE; + } + if (!(hdr->p_flags & PF_W)) + newsect->flags |= SEC_READONLY; + } + + return true; +} + +/* Begin processing a given object. + + First we validate the file by reading in the ELF header and checking + the magic number. */ + +static INLINE boolean +elf_file_p (x_ehdrp) + Elf_External_Ehdr *x_ehdrp; +{ + return ((x_ehdrp->e_ident[EI_MAG0] == ELFMAG0) + && (x_ehdrp->e_ident[EI_MAG1] == ELFMAG1) + && (x_ehdrp->e_ident[EI_MAG2] == ELFMAG2) + && (x_ehdrp->e_ident[EI_MAG3] == ELFMAG3)); +} + +/* Check to see if the file associated with ABFD matches the target vector + that ABFD points to. + + Note that we may be called several times with the same ABFD, but different + target vectors, most of which will not match. We have to avoid leaving + any side effects in ABFD, or any data it points to (like tdata), if the + file does not match the target vector. */ + +const bfd_target * +elf_object_p (abfd) + bfd *abfd; +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + Elf_External_Shdr x_shdr; /* Section header table entry, external form */ + Elf_Internal_Shdr *i_shdrp = NULL; /* Section header table, internal form */ + unsigned int shindex; + char *shstrtab; /* Internal copy of section header stringtab */ + struct elf_backend_data *ebd; + struct elf_obj_tdata *preserved_tdata = elf_tdata (abfd); + struct elf_obj_tdata *new_tdata = NULL; + + /* Read in the ELF header in external format. */ + + if (bfd_read ((PTR) & x_ehdr, sizeof (x_ehdr), 1, abfd) != sizeof (x_ehdr)) + { + if (bfd_get_error () != bfd_error_system_call) + goto got_wrong_format_error; + else + goto got_no_match; + } + + /* Now check to see if we have a valid ELF file, and one that BFD can + make use of. The magic number must match, the address size ('class') + and byte-swapping must match our XVEC entry, and it must have a + section header table (FIXME: See comments re sections at top of this + file). */ + + if ((elf_file_p (&x_ehdr) == false) || + (x_ehdr.e_ident[EI_VERSION] != EV_CURRENT) || + (x_ehdr.e_ident[EI_CLASS] != ELFCLASS)) + goto got_wrong_format_error; + + /* Check that file's byte order matches xvec's */ + switch (x_ehdr.e_ident[EI_DATA]) + { + case ELFDATA2MSB: /* Big-endian */ + if (!abfd->xvec->header_byteorder_big_p) + goto got_wrong_format_error; + break; + case ELFDATA2LSB: /* Little-endian */ + if (abfd->xvec->header_byteorder_big_p) + goto got_wrong_format_error; + break; + case ELFDATANONE: /* No data encoding specified */ + default: /* Unknown data encoding specified */ + goto got_wrong_format_error; + } + + /* Allocate an instance of the elf_obj_tdata structure and hook it up to + the tdata pointer in the bfd. */ + + new_tdata = ((struct elf_obj_tdata *) + bfd_zalloc (abfd, sizeof (struct elf_obj_tdata))); + if (new_tdata == NULL) + goto got_no_memory_error; + elf_tdata (abfd) = new_tdata; + + /* Now that we know the byte order, swap in the rest of the header */ + i_ehdrp = elf_elfheader (abfd); + elf_swap_ehdr_in (abfd, &x_ehdr, i_ehdrp); +#if DEBUG & 1 + elf_debug_file (i_ehdrp); +#endif + + /* If there is no section header table, we're hosed. */ + if (i_ehdrp->e_shoff == 0) + goto got_wrong_format_error; + + /* As a simple sanity check, verify that the what BFD thinks is the + size of each section header table entry actually matches the size + recorded in the file. */ + if (i_ehdrp->e_shentsize != sizeof (x_shdr)) + goto got_wrong_format_error; + + ebd = get_elf_backend_data (abfd); + + /* Check that the ELF e_machine field matches what this particular + BFD format expects. */ + if (ebd->elf_machine_code != i_ehdrp->e_machine) + { + const bfd_target * const *target_ptr; + + if (ebd->elf_machine_code != EM_NONE) + goto got_wrong_format_error; + + /* This is the generic ELF target. Let it match any ELF target + for which we do not have a specific backend. */ + for (target_ptr = bfd_target_vector; *target_ptr != NULL; target_ptr++) + { + struct elf_backend_data *back; + + if ((*target_ptr)->flavour != bfd_target_elf_flavour) + continue; + back = (struct elf_backend_data *) (*target_ptr)->backend_data; + if (back->elf_machine_code == i_ehdrp->e_machine) + { + /* target_ptr is an ELF backend which matches this + object file, so reject the generic ELF target. */ + goto got_wrong_format_error; + } + } + } + + if (i_ehdrp->e_type == ET_EXEC) + abfd->flags |= EXEC_P; + else if (i_ehdrp->e_type == ET_DYN) + abfd->flags |= DYNAMIC; + + if (i_ehdrp->e_phnum > 0) + abfd->flags |= D_PAGED; + + if (! bfd_default_set_arch_mach (abfd, ebd->arch, 0)) + goto got_no_match; + + /* Remember the entry point specified in the ELF file header. */ + bfd_get_start_address (abfd) = i_ehdrp->e_entry; + + /* Allocate space for a copy of the section header table in + internal form, seek to the section header table in the file, + read it in, and convert it to internal form. */ + i_shdrp = ((Elf_Internal_Shdr *) + bfd_alloc (abfd, sizeof (*i_shdrp) * i_ehdrp->e_shnum)); + elf_elfsections (abfd) = ((Elf_Internal_Shdr **) + bfd_alloc (abfd, + sizeof (i_shdrp) * i_ehdrp->e_shnum)); + if (!i_shdrp || !elf_elfsections (abfd)) + goto got_no_memory_error; + if (bfd_seek (abfd, i_ehdrp->e_shoff, SEEK_SET) != 0) + goto got_no_match; + for (shindex = 0; shindex < i_ehdrp->e_shnum; shindex++) + { + if (bfd_read ((PTR) & x_shdr, sizeof x_shdr, 1, abfd) != sizeof (x_shdr)) + goto got_no_match; + elf_swap_shdr_in (abfd, &x_shdr, i_shdrp + shindex); + elf_elfsections (abfd)[shindex] = i_shdrp + shindex; + } + if (i_ehdrp->e_shstrndx) + { + if (! bfd_section_from_shdr (abfd, i_ehdrp->e_shstrndx)) + goto got_no_match; + } + + /* Read in the string table containing the names of the sections. We + will need the base pointer to this table later. */ + /* We read this inline now, so that we don't have to go through + bfd_section_from_shdr with it (since this particular strtab is + used to find all of the ELF section names.) */ + + shstrtab = elf_get_str_section (abfd, i_ehdrp->e_shstrndx); + if (!shstrtab) + goto got_no_match; + + /* Once all of the section headers have been read and converted, we + can start processing them. Note that the first section header is + a dummy placeholder entry, so we ignore it. */ + + for (shindex = 1; shindex < i_ehdrp->e_shnum; shindex++) + { + if (! bfd_section_from_shdr (abfd, shindex)) + goto got_no_match; + } + + /* Let the backend double check the format and override global + information. */ + if (ebd->elf_backend_object_p) + { + if ((*ebd->elf_backend_object_p) (abfd) == false) + goto got_wrong_format_error; + } + + return (abfd->xvec); + +got_wrong_format_error: + bfd_set_error (bfd_error_wrong_format); + goto got_no_match; +got_no_memory_error: + bfd_set_error (bfd_error_no_memory); + goto got_no_match; +got_no_match: + if (new_tdata != NULL + && new_tdata->elf_sect_ptr != NULL) + bfd_release (abfd, new_tdata->elf_sect_ptr); + if (i_shdrp != NULL) + bfd_release (abfd, i_shdrp); + if (new_tdata != NULL) + bfd_release (abfd, new_tdata); + elf_tdata (abfd) = preserved_tdata; + return (NULL); +} + + +/* ELF .o/exec file writing */ + +/* Takes a bfd and a symbol, returns a pointer to the elf specific area + of the symbol if there is one. */ +static INLINE elf_symbol_type * +elf_symbol_from (ignore_abfd, symbol) + bfd *ignore_abfd; + asymbol *symbol; +{ + if (symbol->the_bfd->xvec->flavour != bfd_target_elf_flavour) + return 0; + + if (symbol->the_bfd->tdata.elf_obj_data == (struct elf_obj_tdata *) NULL) + return 0; + + return (elf_symbol_type *) symbol; +} + +void +write_relocs (abfd, sec, xxx) + bfd *abfd; + asection *sec; + PTR xxx; +{ + Elf_Internal_Shdr *rela_hdr; + Elf_External_Rela *outbound_relocas; + Elf_External_Rel *outbound_relocs; + int idx; + int use_rela_p = get_elf_backend_data (abfd)->use_rela_p; + asymbol *last_sym = 0; + int last_sym_idx = 9999999; /* should always be written before use */ + + if ((sec->flags & SEC_RELOC) == 0) + return; + + /* The linker backend writes the relocs out itself, and sets the + reloc_count field to zero to inhibit writing them here. Also, + sometimes the SEC_RELOC flag gets set even when there aren't any + relocs. */ + if (sec->reloc_count == 0) + return; + + rela_hdr = &elf_section_data (sec)->rel_hdr; + + rela_hdr->sh_size = rela_hdr->sh_entsize * sec->reloc_count; + rela_hdr->contents = (void *) bfd_alloc (abfd, rela_hdr->sh_size); + if (!rela_hdr->contents) + { + bfd_set_error (bfd_error_no_memory); + abort (); /* FIXME */ + } + + /* orelocation has the data, reloc_count has the count... */ + if (use_rela_p) + { + outbound_relocas = (Elf_External_Rela *) rela_hdr->contents; + + for (idx = 0; idx < sec->reloc_count; idx++) + { + Elf_Internal_Rela dst_rela; + Elf_External_Rela *src_rela; + arelent *ptr; + asymbol *sym; + int n; + + ptr = sec->orelocation[idx]; + src_rela = outbound_relocas + idx; + if (!(abfd->flags & EXEC_P)) + dst_rela.r_offset = ptr->address - sec->vma; + else + dst_rela.r_offset = ptr->address; + + sym = *ptr->sym_ptr_ptr; + if (sym == last_sym) + n = last_sym_idx; + else + { + last_sym = sym; + last_sym_idx = n = elf_symbol_from_bfd_symbol (abfd, &sym); + } + dst_rela.r_info = ELF_R_INFO (n, ptr->howto->type); + + dst_rela.r_addend = ptr->addend; + elf_swap_reloca_out (abfd, &dst_rela, src_rela); + } + } + else + /* REL relocations */ + { + outbound_relocs = (Elf_External_Rel *) rela_hdr->contents; + + for (idx = 0; idx < sec->reloc_count; idx++) + { + Elf_Internal_Rel dst_rel; + Elf_External_Rel *src_rel; + arelent *ptr; + int n; + asymbol *sym; + + ptr = sec->orelocation[idx]; + sym = *ptr->sym_ptr_ptr; + src_rel = outbound_relocs + idx; + if (!(abfd->flags & EXEC_P)) + dst_rel.r_offset = ptr->address - sec->vma; + else + dst_rel.r_offset = ptr->address; + + if (sym == last_sym) + n = last_sym_idx; + else + { + last_sym = sym; + last_sym_idx = n = elf_symbol_from_bfd_symbol (abfd, &sym); + } + dst_rel.r_info = ELF_R_INFO (n, ptr->howto->type); + + elf_swap_reloc_out (abfd, &dst_rel, src_rel); + } + } +} + +/* Set up an ELF internal section header for a section. */ + +/*ARGSUSED*/ +static void +elf_fake_sections (abfd, asect, ignore) + bfd *abfd; + asection *asect; + PTR ignore; +{ + Elf_Internal_Shdr *this_hdr; + + this_hdr = &elf_section_data (asect)->this_hdr; + + this_hdr->sh_name = bfd_add_to_strtab (abfd, elf_shstrtab (abfd), + asect->name); + if (this_hdr->sh_name == (unsigned long) -1) + abort (); /* FIXME */ + + this_hdr->sh_flags = 0; + if ((asect->flags & SEC_ALLOC) != 0) + this_hdr->sh_addr = asect->vma; + else + this_hdr->sh_addr = 0; + this_hdr->sh_offset = 0; + this_hdr->sh_size = asect->_raw_size; + this_hdr->sh_link = 0; + this_hdr->sh_info = 0; + this_hdr->sh_addralign = 1 << asect->alignment_power; + this_hdr->sh_entsize = 0; + + this_hdr->rawdata = (PTR) asect; + this_hdr->contents = NULL; + this_hdr->size = 0; + + /* FIXME: This should not be based on section names. */ + if (strcmp (asect->name, ".dynstr") == 0) + this_hdr->sh_type = SHT_STRTAB; + else if (strcmp (asect->name, ".hash") == 0) + { + this_hdr->sh_type = SHT_HASH; + this_hdr->sh_entsize = ARCH_SIZE / 8; + } + else if (strcmp (asect->name, ".dynsym") == 0) + { + this_hdr->sh_type = SHT_DYNSYM; + this_hdr->sh_entsize = sizeof (Elf_External_Sym); + } + else if (strcmp (asect->name, ".dynamic") == 0) + { + this_hdr->sh_type = SHT_DYNAMIC; + this_hdr->sh_entsize = sizeof (Elf_External_Dyn); + } + else if (strncmp (asect->name, ".rel.", 5) == 0) + { + this_hdr->sh_type = SHT_REL; + this_hdr->sh_entsize = sizeof (Elf_External_Rel); + } + else if (strncmp (asect->name, ".rela.", 6) == 0) + { + this_hdr->sh_type = SHT_RELA; + this_hdr->sh_entsize = sizeof (Elf_External_Rela); + } + else if (strcmp (asect->name, ".note") == 0) + this_hdr->sh_type = SHT_NOTE; + else if (strncmp (asect->name, ".stab", 5) == 0 + && strcmp (asect->name + strlen (asect->name) - 3, "str") == 0) + this_hdr->sh_type = SHT_STRTAB; + else if ((asect->flags & SEC_ALLOC) != 0 + && (asect->flags & SEC_LOAD) != 0) + this_hdr->sh_type = SHT_PROGBITS; + else if ((asect->flags & SEC_ALLOC) != 0 + && ((asect->flags & SEC_LOAD) == 0)) + { + BFD_ASSERT (strcmp (asect->name, ".bss") == 0 + || strcmp (asect->name, ".sbss") == 0); + this_hdr->sh_type = SHT_NOBITS; + } + else + { + /* Who knows? */ + this_hdr->sh_type = SHT_PROGBITS; + } + + if ((asect->flags & SEC_ALLOC) != 0) + this_hdr->sh_flags |= SHF_ALLOC; + if ((asect->flags & SEC_READONLY) == 0) + this_hdr->sh_flags |= SHF_WRITE; + if ((asect->flags & SEC_CODE) != 0) + this_hdr->sh_flags |= SHF_EXECINSTR; + + /* Check for processor-specific section types. */ + { + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if (bed->elf_backend_fake_sections) + (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect); + } + + /* If the section has relocs, set up a section header for the + SHT_REL[A] section. */ + if ((asect->flags & SEC_RELOC) != 0) + { + Elf_Internal_Shdr *rela_hdr; + int use_rela_p = get_elf_backend_data (abfd)->use_rela_p; + + rela_hdr = &elf_section_data (asect)->rel_hdr; + rela_hdr->sh_name = + bfd_add_2_to_strtab (abfd, elf_shstrtab (abfd), + use_rela_p ? ".rela" : ".rel", + asect->name); + rela_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL; + rela_hdr->sh_entsize = (use_rela_p + ? sizeof (Elf_External_Rela) + : sizeof (Elf_External_Rel)); + rela_hdr->sh_addralign = FILE_ALIGN; + rela_hdr->sh_flags = 0; + rela_hdr->sh_addr = 0; + rela_hdr->sh_size = 0; + rela_hdr->sh_offset = 0; + rela_hdr->size = 0; + } +} + +/* Assign all ELF section numbers. The dummy first section is handled here + too. The link/info pointers for the standard section types are filled + in here too, while we're at it. */ + +static boolean +assign_section_numbers (abfd) + bfd *abfd; +{ + struct elf_obj_tdata *t = elf_tdata (abfd); + asection *sec; + unsigned int section_number; + Elf_Internal_Shdr **i_shdrp; + + section_number = 1; + + for (sec = abfd->sections; sec; sec = sec->next) + { + struct bfd_elf_section_data *d = elf_section_data (sec); + + d->this_idx = section_number++; + if ((sec->flags & SEC_RELOC) == 0) + d->rel_idx = 0; + else + d->rel_idx = section_number++; + } + + t->shstrtab_section = section_number++; + elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section; + t->shstrtab_hdr.sh_size = elf_shstrtab (abfd)->length; + t->shstrtab_hdr.contents = (PTR) elf_shstrtab (abfd)->tab; + + if (abfd->symcount > 0) + { + t->symtab_section = section_number++; + t->strtab_section = section_number++; + } + + elf_elfheader (abfd)->e_shnum = section_number; + + /* Set up the list of section header pointers, in agreement with the + indices. */ + i_shdrp = ((Elf_Internal_Shdr **) + bfd_alloc (abfd, section_number * sizeof (Elf_Internal_Shdr *))); + if (i_shdrp == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + i_shdrp[0] = ((Elf_Internal_Shdr *) + bfd_alloc (abfd, sizeof (Elf_Internal_Shdr))); + if (i_shdrp[0] == NULL) + { + bfd_release (abfd, i_shdrp); + bfd_set_error (bfd_error_no_memory); + return false; + } + memset (i_shdrp[0], 0, sizeof (Elf_Internal_Shdr)); + + elf_elfsections (abfd) = i_shdrp; + + i_shdrp[t->shstrtab_section] = &t->shstrtab_hdr; + if (abfd->symcount > 0) + { + i_shdrp[t->symtab_section] = &t->symtab_hdr; + i_shdrp[t->strtab_section] = &t->strtab_hdr; + t->symtab_hdr.sh_link = t->strtab_section; + } + for (sec = abfd->sections; sec; sec = sec->next) + { + struct bfd_elf_section_data *d = elf_section_data (sec); + asection *s; + const char *name; + + i_shdrp[d->this_idx] = &d->this_hdr; + if (d->rel_idx != 0) + i_shdrp[d->rel_idx] = &d->rel_hdr; + + /* Fill in the sh_link and sh_info fields while we're at it. */ + + /* sh_link of a reloc section is the section index of the symbol + table. sh_info is the section index of the section to which + the relocation entries apply. */ + if (d->rel_idx != 0) + { + d->rel_hdr.sh_link = t->symtab_section; + d->rel_hdr.sh_info = d->this_idx; + } + + switch (d->this_hdr.sh_type) + { + case SHT_REL: + case SHT_RELA: + /* A reloc section which we are treating as a normal BFD + section. sh_link is the section index of the symbol + table. sh_info is the section index of the section to + which the relocation entries apply. We assume that an + allocated reloc section uses the dynamic symbol table. + FIXME: How can we be sure? */ + s = bfd_get_section_by_name (abfd, ".dynsym"); + if (s != NULL) + d->this_hdr.sh_link = elf_section_data (s)->this_idx; + + /* We look up the section the relocs apply to by name. */ + name = sec->name; + if (d->this_hdr.sh_type == SHT_REL) + name += 4; + else + name += 5; + s = bfd_get_section_by_name (abfd, name); + if (s != NULL) + d->this_hdr.sh_info = elf_section_data (s)->this_idx; + break; + + case SHT_STRTAB: + /* We assume that a section named .stab*str is a stabs + string section. We look for a section with the same name + but without the trailing ``str'', and set its sh_link + field to point to this section. */ + if (strncmp (sec->name, ".stab", sizeof ".stab" - 1) == 0 + && strcmp (sec->name + strlen (sec->name) - 3, "str") == 0) + { + size_t len; + char *alc; + + len = strlen (sec->name); + alc = (char *) malloc (len - 2); + if (alc == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + strncpy (alc, sec->name, len - 3); + alc[len - 3] = '\0'; + s = bfd_get_section_by_name (abfd, alc); + free (alc); + if (s != NULL) + { + elf_section_data (s)->this_hdr.sh_link = d->this_idx; + + /* This is a .stab section. */ + elf_section_data (s)->this_hdr.sh_entsize = + 4 + 2 * (ARCH_SIZE / 8); + } + } + break; + + case SHT_DYNAMIC: + case SHT_DYNSYM: + /* sh_link is the section header index of the string table + used for the dynamic entries or symbol table. */ + s = bfd_get_section_by_name (abfd, ".dynstr"); + if (s != NULL) + d->this_hdr.sh_link = elf_section_data (s)->this_idx; + break; + + case SHT_HASH: + /* sh_link is the section header index of the symbol table + this hash table is for. */ + s = bfd_get_section_by_name (abfd, ".dynsym"); + if (s != NULL) + d->this_hdr.sh_link = elf_section_data (s)->this_idx; + break; + } + } + + return true; +} + +/* Map symbol from it's internal number to the external number, moving + all local symbols to be at the head of the list. */ + +static INLINE int +sym_is_global (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + /* If the backend has a special mapping, use it. */ + if (get_elf_backend_data (abfd)->elf_backend_sym_is_global) + return ((*get_elf_backend_data (abfd)->elf_backend_sym_is_global) + (abfd, sym)); + + if (sym->flags & (BSF_GLOBAL | BSF_WEAK)) + { + if (sym->flags & BSF_LOCAL) + abort (); + return 1; + } + if (sym->section == 0) + { + /* Is this valid? */ + abort (); + + return 1; + } + if (bfd_is_und_section (sym->section)) + return 1; + if (bfd_is_com_section (sym->section)) + return 1; + if (sym->flags & (BSF_LOCAL | BSF_SECTION_SYM | BSF_FILE)) + return 0; + return 0; +} + +static boolean +elf_map_symbols (abfd) + bfd *abfd; +{ + int symcount = bfd_get_symcount (abfd); + asymbol **syms = bfd_get_outsymbols (abfd); + asymbol **sect_syms; + int num_locals = 0; + int num_globals = 0; + int num_locals2 = 0; + int num_globals2 = 0; + int max_index = 0; + int num_sections = 0; + Elf_Sym_Extra *sym_extra; + int idx; + asection *asect; + +#ifdef DEBUG + fprintf (stderr, "elf_map_symbols\n"); + fflush (stderr); +#endif + + /* Add local symbols for each section for which there are relocs. + FIXME: How can we tell which sections have relocs at this point? + Will reloc_count always be accurate? Actually, I think most ELF + targets create section symbols for all sections anyhow. */ + for (asect = abfd->sections; asect; asect = asect->next) + { + if (max_index < asect->index) + max_index = asect->index; + } + + max_index++; + elf_num_section_syms (abfd) = max_index; + sect_syms = (asymbol **) bfd_zalloc (abfd, max_index * sizeof (asymbol *)); + elf_section_syms (abfd) = sect_syms; + + if (sect_syms == 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + for (asect = abfd->sections; asect; asect = asect->next) + { + asymbol *sym = bfd_make_empty_symbol (abfd); + if (!sym) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + sym->the_bfd = abfd; + sym->name = asect->name; + sym->value = asect->vma; + sym->flags = BSF_SECTION_SYM; + sym->section = asect; + sect_syms[asect->index] = sym; + num_sections++; +#ifdef DEBUG + fprintf (stderr, + "creating section symbol, name = %s, value = 0x%.8lx, index = %d, section = 0x%.8lx\n", + asect->name, (long) asect->vma, asect->index, (long) asect); +#endif + } + + if (num_sections) + { + if (syms) + syms = (asymbol **) bfd_realloc (abfd, syms, + ((symcount + num_sections + 1) + * sizeof (asymbol *))); + else + syms = (asymbol **) bfd_alloc (abfd, + (num_sections + 1) * sizeof (asymbol *)); + if (!syms) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + for (asect = abfd->sections; asect; asect = asect->next) + { + if (sect_syms[asect->index]) + syms[symcount++] = sect_syms[asect->index]; + } + + syms[symcount] = (asymbol *) 0; + bfd_set_symtab (abfd, syms, symcount); + } + + elf_sym_extra (abfd) = sym_extra + = (Elf_Sym_Extra *) bfd_alloc (abfd, symcount * sizeof (Elf_Sym_Extra)); + if (!sym_extra) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + /* Identify and classify all of the symbols. */ + for (idx = 0; idx < symcount; idx++) + { + if (!sym_is_global (abfd, syms[idx])) + num_locals++; + else + num_globals++; + } + + /* Now provide mapping information. Add +1 for skipping over the + dummy symbol. */ + for (idx = 0; idx < symcount; idx++) + { + syms[idx]->udata = (PTR) & sym_extra[idx]; + if (!sym_is_global (abfd, syms[idx])) + sym_extra[idx].elf_sym_num = 1 + num_locals2++; + else + sym_extra[idx].elf_sym_num = 1 + num_locals + num_globals2++; + } + + elf_num_locals (abfd) = num_locals; + elf_num_globals (abfd) = num_globals; + return true; +} + +/* Compute the file positions we are going to put the sections at, and + otherwise prepare to begin writing out the ELF file. If LINK_INFO + is not NULL, this is being called by the ELF backend linker. */ + +static boolean +elf_compute_section_file_positions (abfd, link_info) + bfd *abfd; + struct bfd_link_info *link_info; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + Elf_Internal_Shdr *shstrtab_hdr; + + if (abfd->output_has_begun) + return true; + + /* Do any elf backend specific processing first. */ + if (bed->elf_backend_begin_write_processing) + (*bed->elf_backend_begin_write_processing) (abfd, link_info); + + if (! prep_headers (abfd)) + return false; + + bfd_map_over_sections (abfd, elf_fake_sections, 0); + + if (!assign_section_numbers (abfd)) + return false; + + /* The backend linker builds symbol table information itself. */ + if (link_info == NULL) + { + if (! swap_out_syms (abfd)) + return false; + } + + shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr; + /* sh_name was set in prep_headers. */ + shstrtab_hdr->sh_type = SHT_STRTAB; + shstrtab_hdr->sh_flags = 0; + shstrtab_hdr->sh_addr = 0; + shstrtab_hdr->sh_size = elf_shstrtab (abfd)->length; + shstrtab_hdr->sh_entsize = 0; + shstrtab_hdr->sh_link = 0; + shstrtab_hdr->sh_info = 0; + /* sh_offset is set in assign_file_positions_for_symtabs_and_strtabs. */ + shstrtab_hdr->sh_addralign = 1; + shstrtab_hdr->contents = (PTR) elf_shstrtab (abfd)->tab; + + if (!assign_file_positions_except_relocs (abfd, + link_info == NULL ? true : false)) + return false; + + abfd->output_has_begun = true; + + return true; +} + + +/* Align to the maximum file alignment that could be required for any + ELF data structure. */ + +static INLINE file_ptr +align_file_position (off) + file_ptr off; +{ + return (off + FILE_ALIGN - 1) & ~(FILE_ALIGN - 1); +} + +/* Assign a file position to a section, optionally aligning to the + required section alignment. */ + +static INLINE file_ptr +assign_file_position_for_section (i_shdrp, offset, align) + Elf_Internal_Shdr *i_shdrp; + file_ptr offset; + boolean align; +{ + if (align) + { + unsigned int al; + + al = i_shdrp->sh_addralign; + if (al > 1) + offset = BFD_ALIGN (offset, al); + } + i_shdrp->sh_offset = offset; + if (i_shdrp->rawdata != NULL) + ((asection *) i_shdrp->rawdata)->filepos = offset; + if (i_shdrp->sh_type != SHT_NOBITS) + offset += i_shdrp->sh_size; + return offset; +} + +/* Get the size of the program header. This is called by the linker + before any of the section VMA's are set, so it can't calculate the + correct value for a strange memory layout. */ + +static bfd_size_type +get_program_header_size (abfd) + bfd *abfd; +{ + size_t segs; + asection *s; + + /* Assume we will need exactly two PT_LOAD segments: one for text + and one for data. */ + segs = 2; + + s = bfd_get_section_by_name (abfd, ".interp"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + /* If we have a loadable interpreter section, we need a + PT_INTERP segment. In this case, assume we also need a + PT_PHDR segment, although that may not be true for all + targets. */ + segs += 2; + } + + if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) + { + /* We need a PT_DYNAMIC segment. */ + ++segs; + } + + return segs * sizeof (Elf_External_Phdr); +} + +/* Create the program header. OFF is the file offset where the + program header should be written. FIRST is the first loadable ELF + section. PHDR_SIZE is the size of the program header as returned + by get_program_header_size. */ + +static file_ptr +map_program_segments (abfd, off, first, phdr_size) + bfd *abfd; + file_ptr off; + Elf_Internal_Shdr *first; + bfd_size_type phdr_size; +{ + Elf_Internal_Phdr phdrs[10]; + unsigned int phdr_count; + Elf_Internal_Phdr *phdr; + int phdr_size_adjust; + unsigned int i; + Elf_Internal_Shdr **hdrpp; + asection *sinterp, *sdyn; + unsigned int last_type; + Elf_Internal_Ehdr *i_ehdrp; + + BFD_ASSERT ((abfd->flags & EXEC_P) != 0); + BFD_ASSERT (phdr_size / sizeof (Elf_Internal_Phdr) + <= sizeof phdrs / sizeof (phdrs[0])); + + phdr_count = 0; + phdr = phdrs; + + phdr_size_adjust = 0; + + /* If we have a loadable .interp section, we must create a PT_INTERP + segment which must precede all PT_LOAD segments. We assume that + we must also create a PT_PHDR segment, although that may not be + true for all targets. */ + sinterp = bfd_get_section_by_name (abfd, ".interp"); + if (sinterp != NULL && (sinterp->flags & SEC_LOAD) != 0) + { + BFD_ASSERT (first != NULL); + + phdr->p_type = PT_PHDR; + + phdr->p_offset = off; + + /* Account for any adjustment made because of the alignment of + the first loadable section. */ + phdr_size_adjust = (first->sh_offset - phdr_size) - off; + BFD_ASSERT (phdr_size_adjust >= 0 && phdr_size_adjust < 128); + + /* The program header precedes all loadable sections. This lets + us compute its loadable address. This depends on the linker + script. */ + phdr->p_vaddr = first->sh_addr - (phdr_size + phdr_size_adjust); + + phdr->p_paddr = 0; + phdr->p_filesz = phdr_size; + phdr->p_memsz = phdr_size; + + /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */ + phdr->p_flags = PF_R | PF_X; + + phdr->p_align = FILE_ALIGN; + BFD_ASSERT ((phdr->p_vaddr - phdr->p_offset) % FILE_ALIGN == 0); + + /* Include the ELF header in the first loadable segment. */ + phdr_size_adjust += off; + + ++phdr_count; + ++phdr; + + phdr->p_type = PT_INTERP; + phdr->p_offset = sinterp->filepos; + phdr->p_vaddr = sinterp->vma; + phdr->p_paddr = 0; + phdr->p_filesz = sinterp->_raw_size; + phdr->p_memsz = sinterp->_raw_size; + phdr->p_flags = PF_R; + phdr->p_align = 1 << bfd_get_section_alignment (abfd, sinterp); + + ++phdr_count; + ++phdr; + } + + /* Look through the sections to see how they will be divided into + program segments. The sections must be arranged in order by + sh_addr for this to work correctly. */ + phdr->p_type = PT_NULL; + last_type = SHT_PROGBITS; + for (i = 1, hdrpp = elf_elfsections (abfd) + 1; + i < elf_elfheader (abfd)->e_shnum; + i++, hdrpp++) + { + Elf_Internal_Shdr *hdr; + + hdr = *hdrpp; + + /* Ignore any section which will not be part of the process + image. */ + if ((hdr->sh_flags & SHF_ALLOC) == 0) + continue; + + /* If this section fits in the segment we are constructing, add + it in. */ + if (phdr->p_type != PT_NULL + && (hdr->sh_offset - (phdr->p_offset + phdr->p_memsz) + == hdr->sh_addr - (phdr->p_vaddr + phdr->p_memsz)) + && (last_type != SHT_NOBITS || hdr->sh_type == SHT_NOBITS)) + { + bfd_size_type adjust; + + adjust = hdr->sh_addr - (phdr->p_vaddr + phdr->p_memsz); + phdr->p_memsz += hdr->sh_size + adjust; + if (hdr->sh_type != SHT_NOBITS) + phdr->p_filesz += hdr->sh_size + adjust; + if ((hdr->sh_flags & SHF_WRITE) != 0) + phdr->p_flags |= PF_W; + if ((hdr->sh_flags & SHF_EXECINSTR) != 0) + phdr->p_flags |= PF_X; + last_type = hdr->sh_type; + continue; + } + + /* If we have a segment, move to the next one. */ + if (phdr->p_type != PT_NULL) + { + ++phdr; + ++phdr_count; + } + + /* Start a new segment. */ + phdr->p_type = PT_LOAD; + phdr->p_offset = hdr->sh_offset; + phdr->p_vaddr = hdr->sh_addr; + phdr->p_paddr = 0; + if (hdr->sh_type == SHT_NOBITS) + phdr->p_filesz = 0; + else + phdr->p_filesz = hdr->sh_size; + phdr->p_memsz = hdr->sh_size; + phdr->p_flags = PF_R; + if ((hdr->sh_flags & SHF_WRITE) != 0) + phdr->p_flags |= PF_W; + if ((hdr->sh_flags & SHF_EXECINSTR) != 0) + phdr->p_flags |= PF_X; + phdr->p_align = get_elf_backend_data (abfd)->maxpagesize; + + if (hdr == first + && sinterp != NULL + && (sinterp->flags & SEC_LOAD) != 0) + { + phdr->p_offset -= phdr_size + phdr_size_adjust; + phdr->p_vaddr -= phdr_size + phdr_size_adjust; + phdr->p_filesz += phdr_size + phdr_size_adjust; + phdr->p_memsz += phdr_size + phdr_size_adjust; + } + + last_type = hdr->sh_type; + } + + if (phdr->p_type != PT_NULL) + { + ++phdr; + ++phdr_count; + } + + /* If we have a .dynamic section, create a PT_DYNAMIC segment. */ + sdyn = bfd_get_section_by_name (abfd, ".dynamic"); + if (sdyn != NULL && (sdyn->flags & SEC_LOAD) != 0) + { + phdr->p_type = PT_DYNAMIC; + phdr->p_offset = sdyn->filepos; + phdr->p_vaddr = sdyn->vma; + phdr->p_paddr = 0; + phdr->p_filesz = sdyn->_raw_size; + phdr->p_memsz = sdyn->_raw_size; + phdr->p_flags = PF_R; + if ((sdyn->flags & SEC_READONLY) == 0) + phdr->p_flags |= PF_W; + if ((sdyn->flags & SEC_CODE) != 0) + phdr->p_flags |= PF_X; + phdr->p_align = 1 << bfd_get_section_alignment (abfd, sdyn); + + ++phdr; + ++phdr_count; + } + + /* Make sure the return value from get_program_header_size matches + what we computed here. */ + if (phdr_count != phdr_size / sizeof (Elf_External_Phdr)) + abort (); + + /* Set up program header information. */ + i_ehdrp = elf_elfheader (abfd); + i_ehdrp->e_phentsize = sizeof (Elf_External_Phdr); + i_ehdrp->e_phoff = off; + i_ehdrp->e_phnum = phdr_count; + + /* Save the program headers away. I don't think anybody uses this + information right now. */ + elf_tdata (abfd)->phdr = ((Elf_Internal_Phdr *) + bfd_alloc (abfd, + (phdr_count + * sizeof (Elf_Internal_Phdr)))); + if (elf_tdata (abfd)->phdr == NULL && phdr_count != 0) + { + bfd_set_error (bfd_error_no_memory); + return (file_ptr) -1; + } + memcpy (elf_tdata (abfd)->phdr, phdrs, + phdr_count * sizeof (Elf_Internal_Phdr)); + + /* Write out the program headers. */ + if (bfd_seek (abfd, off, SEEK_SET) != 0) + return (file_ptr) -1; + + for (i = 0, phdr = phdrs; i < phdr_count; i++, phdr++) + { + Elf_External_Phdr extphdr; + + elf_swap_phdr_out (abfd, phdr, &extphdr); + if (bfd_write (&extphdr, sizeof (Elf_External_Phdr), 1, abfd) + != sizeof (Elf_External_Phdr)) + return (file_ptr) -1; + } + + return off + phdr_count * sizeof (Elf_External_Phdr); +} + +/* Work out the file positions of all the sections. This is called by + elf_compute_section_file_positions. All the section sizes and VMAs + must be known before this is called. + + We do not consider reloc sections at this point, unless they form + part of the loadable image. Reloc sections are assigned file + positions in assign_file_positions_for_relocs, which is called by + write_object_contents and final_link. + + If DOSYMS is false, we do not assign file positions for the symbol + table or the string table. */ + +static boolean +assign_file_positions_except_relocs (abfd, dosyms) + bfd *abfd; + boolean dosyms; +{ + struct elf_obj_tdata * const tdata = elf_tdata (abfd); + Elf_Internal_Ehdr * const i_ehdrp = elf_elfheader (abfd); + Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd); + file_ptr off; + + /* Start after the ELF header. */ + off = i_ehdrp->e_ehsize; + + if ((abfd->flags & EXEC_P) == 0) + { + Elf_Internal_Shdr **hdrpp; + unsigned int i; + + /* We are not creating an executable, which means that we are + not creating a program header, and that the actual order of + the sections in the file is unimportant. */ + for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++) + { + Elf_Internal_Shdr *hdr; + + hdr = *hdrpp; + if (hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) + { + hdr->sh_offset = -1; + continue; + } + if (! dosyms + && (i == tdata->symtab_section + || i == tdata->strtab_section)) + { + hdr->sh_offset = -1; + continue; + } + + off = assign_file_position_for_section (hdr, off, true); + } + } + else + { + file_ptr phdr_off; + bfd_size_type phdr_size; + bfd_vma maxpagesize; + Elf_Internal_Shdr **hdrpp; + unsigned int i; + Elf_Internal_Shdr *first; + file_ptr phdr_map; + + /* We are creating an executable. We must create a program + header. We can't actually create the program header until we + have set the file positions for the sections, but we can + figure out how big it is going to be. */ + off = align_file_position (off); + phdr_size = get_program_header_size (abfd); + if (phdr_size == (file_ptr) -1) + return false; + phdr_off = off; + off += phdr_size; + + maxpagesize = get_elf_backend_data (abfd)->maxpagesize; + if (maxpagesize == 0) + maxpagesize = 1; + + /* FIXME: We might want to sort the sections on the sh_addr + field here. For now, we just assume that the linker will + create the sections in an appropriate order. */ + + /* Assign file positions in two passes. In the first pass, we + assign a file position to every section which forms part of + the executable image. */ + first = NULL; + for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++) + { + Elf_Internal_Shdr *hdr; + + hdr = *hdrpp; + if ((hdr->sh_flags & SHF_ALLOC) == 0) + continue; + + if (first == NULL) + first = hdr; + + if ((abfd->flags & D_PAGED) != 0) + { + /* The section VMA must equal the file position modulo + the page size. This is required by the program + header. */ + off += (hdr->sh_addr - off) % maxpagesize; + } + + off = assign_file_position_for_section (hdr, off, false); + } + + /* Assign file positions to all the sections which do not form + part of the loadable image, except for the relocs. */ + for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++) + { + Elf_Internal_Shdr *hdr; + + hdr = *hdrpp; + if ((hdr->sh_flags & SHF_ALLOC) != 0) + continue; + if (hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) + { + hdr->sh_offset = -1; + continue; + } + if (! dosyms + && (i == tdata->symtab_section + || i == tdata->strtab_section)) + { + hdr->sh_offset = -1; + continue; + } + + off = assign_file_position_for_section (hdr, off, true); + } + + phdr_map = map_program_segments (abfd, phdr_off, first, phdr_size); + if (phdr_map == (file_ptr) -1) + return false; + BFD_ASSERT (phdr_map == phdr_off + phdr_size); + } + + /* Place the section headers. */ + off = align_file_position (off); + i_ehdrp->e_shoff = off; + off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize; + + elf_tdata (abfd)->next_file_pos = off; + + return true; +} + +static boolean +prep_headers (abfd) + bfd *abfd; +{ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */ + Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */ + int count; + struct strtab *shstrtab; + + i_ehdrp = elf_elfheader (abfd); + i_shdrp = elf_elfsections (abfd); + + shstrtab = bfd_new_strtab (abfd); + if (!shstrtab) + return false; + + elf_shstrtab (abfd) = shstrtab; + + i_ehdrp->e_ident[EI_MAG0] = ELFMAG0; + i_ehdrp->e_ident[EI_MAG1] = ELFMAG1; + i_ehdrp->e_ident[EI_MAG2] = ELFMAG2; + i_ehdrp->e_ident[EI_MAG3] = ELFMAG3; + + i_ehdrp->e_ident[EI_CLASS] = ELFCLASS; + i_ehdrp->e_ident[EI_DATA] = + abfd->xvec->byteorder_big_p ? ELFDATA2MSB : ELFDATA2LSB; + i_ehdrp->e_ident[EI_VERSION] = EV_CURRENT; + + for (count = EI_PAD; count < EI_NIDENT; count++) + i_ehdrp->e_ident[count] = 0; + + if ((abfd->flags & DYNAMIC) != 0) + i_ehdrp->e_type = ET_DYN; + else if ((abfd->flags & EXEC_P) != 0) + i_ehdrp->e_type = ET_EXEC; + else + i_ehdrp->e_type = ET_REL; + + switch (bfd_get_arch (abfd)) + { + case bfd_arch_unknown: + i_ehdrp->e_machine = EM_NONE; + break; + case bfd_arch_sparc: +#if ARCH_SIZE == 64 + i_ehdrp->e_machine = EM_SPARC64; +#else + i_ehdrp->e_machine = EM_SPARC; +#endif + break; + case bfd_arch_i386: + i_ehdrp->e_machine = EM_386; + break; + case bfd_arch_m68k: + i_ehdrp->e_machine = EM_68K; + break; + case bfd_arch_m88k: + i_ehdrp->e_machine = EM_88K; + break; + case bfd_arch_i860: + i_ehdrp->e_machine = EM_860; + break; + case bfd_arch_mips: /* MIPS Rxxxx */ + i_ehdrp->e_machine = EM_MIPS; /* only MIPS R3000 */ + break; + case bfd_arch_hppa: + i_ehdrp->e_machine = EM_PARISC; + break; + case bfd_arch_powerpc: + i_ehdrp->e_machine = EM_CYGNUS_POWERPC; + break; + /* also note that EM_M32, AT&T WE32100 is unknown to bfd */ + default: + i_ehdrp->e_machine = EM_NONE; + } + i_ehdrp->e_version = EV_CURRENT; + i_ehdrp->e_ehsize = sizeof (Elf_External_Ehdr); + + /* no program header, for now. */ + i_ehdrp->e_phoff = 0; + i_ehdrp->e_phentsize = 0; + i_ehdrp->e_phnum = 0; + + /* each bfd section is section header entry */ + i_ehdrp->e_entry = bfd_get_start_address (abfd); + i_ehdrp->e_shentsize = sizeof (Elf_External_Shdr); + + /* if we're building an executable, we'll need a program header table */ + if (abfd->flags & EXEC_P) + { + /* it all happens later */ +#if 0 + i_ehdrp->e_phentsize = sizeof (Elf_External_Phdr); + + /* elf_build_phdrs() returns a (NULL-terminated) array of + Elf_Internal_Phdrs */ + i_phdrp = elf_build_phdrs (abfd, i_ehdrp, i_shdrp, &i_ehdrp->e_phnum); + i_ehdrp->e_phoff = outbase; + outbase += i_ehdrp->e_phentsize * i_ehdrp->e_phnum; +#endif + } + else + { + i_ehdrp->e_phentsize = 0; + i_phdrp = 0; + i_ehdrp->e_phoff = 0; + } + + elf_tdata (abfd)->symtab_hdr.sh_name = bfd_add_to_strtab (abfd, shstrtab, + ".symtab"); + elf_tdata (abfd)->strtab_hdr.sh_name = bfd_add_to_strtab (abfd, shstrtab, + ".strtab"); + elf_tdata (abfd)->shstrtab_hdr.sh_name = bfd_add_to_strtab (abfd, shstrtab, + ".shstrtab"); + if (elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1 + || elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1 + || elf_tdata (abfd)->shstrtab_hdr.sh_name == (unsigned int) -1) + return false; + + return true; +} + +static boolean +swap_out_syms (abfd) + bfd *abfd; +{ + if (!elf_map_symbols (abfd)) + return false; + + /* Dump out the symtabs. */ + { + int symcount = bfd_get_symcount (abfd); + asymbol **syms = bfd_get_outsymbols (abfd); + struct strtab *stt = bfd_new_strtab (abfd); + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Shdr *symstrtab_hdr; + Elf_External_Sym *outbound_syms; + int idx; + + if (!stt) + return false; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + symtab_hdr->sh_type = SHT_SYMTAB; + symtab_hdr->sh_entsize = sizeof (Elf_External_Sym); + symtab_hdr->sh_size = symtab_hdr->sh_entsize * (symcount + 1); + symtab_hdr->sh_info = elf_num_locals (abfd) + 1; + symtab_hdr->sh_addralign = FILE_ALIGN; + + symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; + symstrtab_hdr->sh_type = SHT_STRTAB; + + outbound_syms = (Elf_External_Sym *) + bfd_alloc (abfd, (1 + symcount) * sizeof (Elf_External_Sym)); + if (!outbound_syms) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + /* now generate the data (for "contents") */ + { + /* Fill in zeroth symbol and swap it out. */ + Elf_Internal_Sym sym; + sym.st_name = 0; + sym.st_value = 0; + sym.st_size = 0; + sym.st_info = 0; + sym.st_other = 0; + sym.st_shndx = SHN_UNDEF; + elf_swap_symbol_out (abfd, &sym, outbound_syms); + } + for (idx = 0; idx < symcount; idx++) + { + Elf_Internal_Sym sym; + bfd_vma value = syms[idx]->value; + elf_symbol_type *type_ptr; + + if (syms[idx]->flags & BSF_SECTION_SYM) + /* Section symbols have no names. */ + sym.st_name = 0; + else + { + sym.st_name = bfd_add_to_strtab (abfd, stt, syms[idx]->name); + if (sym.st_name == (unsigned long) -1) + return false; + } + + type_ptr = elf_symbol_from (abfd, syms[idx]); + + if (bfd_is_com_section (syms[idx]->section)) + { + /* ELF common symbols put the alignment into the `value' field, + and the size into the `size' field. This is backwards from + how BFD handles it, so reverse it here. */ + sym.st_size = value; + sym.st_value = type_ptr ? type_ptr->internal_elf_sym.st_value : 16; + sym.st_shndx = elf_section_from_bfd_section (abfd, + syms[idx]->section); + } + else + { + asection *sec = syms[idx]->section; + int shndx; + + if (sec->output_section) + { + value += sec->output_offset; + sec = sec->output_section; + } + value += sec->vma; + sym.st_value = value; + sym.st_size = type_ptr ? type_ptr->internal_elf_sym.st_size : 0; + sym.st_shndx = shndx = elf_section_from_bfd_section (abfd, sec); + if (shndx == -1) + { + asection *sec2; + /* Writing this would be a hell of a lot easier if we had + some decent documentation on bfd, and knew what to expect + of the library, and what to demand of applications. For + example, it appears that `objcopy' might not set the + section of a symbol to be a section that is actually in + the output file. */ + sec2 = bfd_get_section_by_name (abfd, sec->name); + BFD_ASSERT (sec2 != 0); + sym.st_shndx = shndx = elf_section_from_bfd_section (abfd, sec2); + BFD_ASSERT (shndx != -1); + } + } + + if (bfd_is_com_section (syms[idx]->section)) + sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_OBJECT); + else if (bfd_is_und_section (syms[idx]->section)) + sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_NOTYPE); + else if (syms[idx]->flags & BSF_SECTION_SYM) + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + else if (syms[idx]->flags & BSF_FILE) + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); + else + { + int bind = STB_LOCAL; + int type = STT_OBJECT; + unsigned int flags = syms[idx]->flags; + + if (flags & BSF_LOCAL) + bind = STB_LOCAL; + else if (flags & BSF_WEAK) + bind = STB_WEAK; + else if (flags & BSF_GLOBAL) + bind = STB_GLOBAL; + + if (flags & BSF_FUNCTION) + type = STT_FUNC; + + sym.st_info = ELF_ST_INFO (bind, type); + } + + sym.st_other = 0; + elf_swap_symbol_out (abfd, &sym, + (outbound_syms + + elf_sym_extra (abfd)[idx].elf_sym_num)); + } + + symtab_hdr->contents = (PTR) outbound_syms; + symstrtab_hdr->contents = (PTR) stt->tab; + symstrtab_hdr->sh_size = stt->length; + symstrtab_hdr->sh_type = SHT_STRTAB; + + symstrtab_hdr->sh_flags = 0; + symstrtab_hdr->sh_addr = 0; + symstrtab_hdr->sh_entsize = 0; + symstrtab_hdr->sh_link = 0; + symstrtab_hdr->sh_info = 0; + symstrtab_hdr->sh_addralign = 1; + symstrtab_hdr->size = 0; + } + + return true; +} + +static boolean +write_shdrs_and_ehdr (abfd) + bfd *abfd; +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + Elf_External_Shdr *x_shdrp; /* Section header table, external form */ + Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */ + unsigned int count; + struct strtab *shstrtab; + + i_ehdrp = elf_elfheader (abfd); + i_shdrp = elf_elfsections (abfd); + shstrtab = elf_shstrtab (abfd); + + /* swap the header before spitting it out... */ + +#if DEBUG & 1 + elf_debug_file (i_ehdrp); +#endif + elf_swap_ehdr_out (abfd, i_ehdrp, &x_ehdr); + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || (bfd_write ((PTR) & x_ehdr, sizeof (x_ehdr), 1, abfd) + != sizeof (x_ehdr))) + return false; + + /* at this point we've concocted all the ELF sections... */ + x_shdrp = (Elf_External_Shdr *) + bfd_alloc (abfd, sizeof (*x_shdrp) * (i_ehdrp->e_shnum)); + if (!x_shdrp) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + for (count = 0; count < i_ehdrp->e_shnum; count++) + { +#if DEBUG & 2 + elf_debug_section (shstrtab->tab + i_shdrp[count]->sh_name, count, + i_shdrp[count]); +#endif + elf_swap_shdr_out (abfd, i_shdrp[count], x_shdrp + count); + } + if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_shoff, SEEK_SET) != 0 + || (bfd_write ((PTR) x_shdrp, sizeof (*x_shdrp), i_ehdrp->e_shnum, abfd) + != sizeof (*x_shdrp) * i_ehdrp->e_shnum)) + return false; + + /* need to dump the string table too... */ + + return true; +} + +/* Assign file positions for all the reloc sections which are not part + of the loadable file image. */ + +static void +assign_file_positions_for_relocs (abfd) + bfd *abfd; +{ + file_ptr off; + unsigned int i; + Elf_Internal_Shdr **shdrpp; + + off = elf_tdata (abfd)->next_file_pos; + + for (i = 1, shdrpp = elf_elfsections (abfd) + 1; + i < elf_elfheader (abfd)->e_shnum; + i++, shdrpp++) + { + Elf_Internal_Shdr *shdrp; + + shdrp = *shdrpp; + if ((shdrp->sh_type == SHT_REL || shdrp->sh_type == SHT_RELA) + && shdrp->sh_offset == -1) + off = assign_file_position_for_section (shdrp, off, true); + } + + elf_tdata (abfd)->next_file_pos = off; +} + +boolean +NAME(bfd_elf,write_object_contents) (abfd) + bfd *abfd; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + Elf_Internal_Ehdr *i_ehdrp; + Elf_Internal_Shdr **i_shdrp; + unsigned int count; + + if (! abfd->output_has_begun + && ! elf_compute_section_file_positions (abfd, + (struct bfd_link_info *) NULL)) + return false; + + i_shdrp = elf_elfsections (abfd); + i_ehdrp = elf_elfheader (abfd); + + bfd_map_over_sections (abfd, write_relocs, (PTR) 0); + assign_file_positions_for_relocs (abfd); + + /* After writing the headers, we need to write the sections too... */ + for (count = 1; count < i_ehdrp->e_shnum; count++) + { + if (bed->elf_backend_section_processing) + (*bed->elf_backend_section_processing) (abfd, i_shdrp[count]); + if (i_shdrp[count]->contents) + { + if (bfd_seek (abfd, i_shdrp[count]->sh_offset, SEEK_SET) != 0 + || (bfd_write (i_shdrp[count]->contents, i_shdrp[count]->sh_size, + 1, abfd) + != i_shdrp[count]->sh_size)) + return false; + } + } + + if (bed->elf_backend_final_write_processing) + (*bed->elf_backend_final_write_processing) (abfd, NULL); + + return write_shdrs_and_ehdr (abfd); +} + +/* Given an index of a section, retrieve a pointer to it. Note + that for our purposes, sections are indexed by {1, 2, ...} with + 0 being an illegal index. */ + +/* In the original, each ELF section went into exactly one BFD + section. This doesn't really make sense, so we need a real mapping. + The mapping has to hide in the Elf_Internal_Shdr since asection + doesn't have anything like a tdata field... */ + +static asection * +section_from_elf_index (abfd, index) + bfd *abfd; + unsigned int index; +{ + /* @@ Is bfd_com_section_ptr really correct in all the places it could + be returned from this routine? */ + + if (index == SHN_ABS) + return bfd_com_section_ptr; /* not abs? */ + if (index == SHN_COMMON) + return bfd_com_section_ptr; + + if (index >= elf_elfheader (abfd)->e_shnum) + return NULL; + + { + Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[index]; + + switch (hdr->sh_type) + { + /* ELF sections that map to BFD sections */ + case SHT_PROGBITS: + case SHT_NOBITS: + case SHT_HASH: + case SHT_DYNAMIC: + if (hdr->rawdata == NULL) + { + if (! bfd_section_from_shdr (abfd, index)) + return NULL; + } + return (struct sec *) hdr->rawdata; + + default: + return bfd_abs_section_ptr; + } + } +} + +/* given a section, search the header to find them... */ +static int +elf_section_from_bfd_section (abfd, asect) + bfd *abfd; + struct sec *asect; +{ + Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd); + int index; + Elf_Internal_Shdr *hdr; + int maxindex = elf_elfheader (abfd)->e_shnum; + + if (asect->owner == NULL) + { + if (bfd_is_abs_section (asect)) + return SHN_ABS; + if (bfd_is_com_section (asect)) + return SHN_COMMON; + if (bfd_is_und_section (asect)) + return SHN_UNDEF; + return -1; + } + + BFD_ASSERT (asect->owner == abfd); + + for (index = 0; index < maxindex; index++) + { + hdr = i_shdrp[index]; + switch (hdr->sh_type) + { + /* ELF sections that map to BFD sections */ + case SHT_PROGBITS: + case SHT_NOBITS: + case SHT_NOTE: + case SHT_HASH: + case SHT_DYNAMIC: + case SHT_DYNSYM: + if (hdr->rawdata) + { + if (((struct sec *) (hdr->rawdata)) == asect) + return index; + } + break; + + case SHT_REL: + case SHT_RELA: + /* We sometimes map a reloc section to a BFD section. */ + if (hdr->sh_link != elf_onesymtab (abfd) + && (asection *) hdr->rawdata == asect) + return index; + break; + + case SHT_STRTAB: + /* We map most string tables to BFD sections. */ + if (index != elf_elfheader (abfd)->e_shstrndx + && index != elf_onesymtab (abfd) + && (asection *) hdr->rawdata == asect) + return index; + + /* FALL THROUGH */ + default: + { + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if (bed->elf_backend_section_from_bfd_section) + { + int retval; + + retval = index; + if ((*bed->elf_backend_section_from_bfd_section) + (abfd, hdr, asect, &retval)) + return retval; + } + } + break; + } + } + return -1; +} + +/* given a symbol, return the bfd index for that symbol. */ +static int +elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) + bfd *abfd; + struct symbol_cache_entry **asym_ptr_ptr; +{ + struct symbol_cache_entry *asym_ptr = *asym_ptr_ptr; + int idx; + flagword flags = asym_ptr->flags; + + /* When gas creates relocations against local labels, it creates its + own symbol for the section, but does put the symbol into the + symbol chain, so udata is 0. When the linker is generating + relocatable output, this section symbol may be for one of the + input sections rather than the output section. */ + if (asym_ptr->udata == (PTR) 0 + && (flags & BSF_SECTION_SYM) + && asym_ptr->section) + { + int indx; + + if (asym_ptr->section->output_section != NULL) + indx = asym_ptr->section->output_section->index; + else + indx = asym_ptr->section->index; + if (elf_section_syms (abfd)[indx]) + asym_ptr->udata = elf_section_syms (abfd)[indx]->udata; + } + + if (asym_ptr->udata) + idx = ((Elf_Sym_Extra *) asym_ptr->udata)->elf_sym_num; + else + { + abort (); + } + +#if DEBUG & 4 + { + + fprintf (stderr, + "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx %s\n", + (long) asym_ptr, asym_ptr->name, idx, flags, elf_symbol_flags (flags)); + fflush (stderr); + } +#endif + + return idx; +} + +static long +elf_slurp_symbol_table (abfd, symptrs, dynamic) + bfd *abfd; + asymbol **symptrs; /* Buffer for generated bfd symbols */ + boolean dynamic; +{ + Elf_Internal_Shdr *hdr; + long symcount; /* Number of external ELF symbols */ + elf_symbol_type *sym; /* Pointer to current bfd symbol */ + elf_symbol_type *symbase; /* Buffer for generated bfd symbols */ + Elf_Internal_Sym i_sym; + Elf_External_Sym *x_symp = NULL; + + /* Read each raw ELF symbol, converting from external ELF form to + internal ELF form, and then using the information to create a + canonical bfd symbol table entry. + + Note that we allocate the initial bfd canonical symbol buffer + based on a one-to-one mapping of the ELF symbols to canonical + symbols. We actually use all the ELF symbols, so there will be no + space left over at the end. When we have all the symbols, we + build the caller's pointer vector. */ + + if (dynamic) + hdr = &elf_tdata (abfd)->dynsymtab_hdr; + else + hdr = &elf_tdata (abfd)->symtab_hdr; + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) == -1) + return -1; + + symcount = hdr->sh_size / sizeof (Elf_External_Sym); + + if (symcount == 0) + sym = symbase = NULL; + else + { + long i; + + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) == -1) + return -1; + + symbase = ((elf_symbol_type *) + bfd_zalloc (abfd, symcount * sizeof (elf_symbol_type))); + if (symbase == (elf_symbol_type *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return -1; + } + sym = symbase; + + /* Temporarily allocate room for the raw ELF symbols. */ + x_symp = ((Elf_External_Sym *) + malloc (symcount * sizeof (Elf_External_Sym))); + if (x_symp == NULL && symcount != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + if (bfd_read ((PTR) x_symp, sizeof (Elf_External_Sym), symcount, abfd) + != symcount * sizeof (Elf_External_Sym)) + goto error_return; + /* Skip first symbol, which is a null dummy. */ + for (i = 1; i < symcount; i++) + { + elf_swap_symbol_in (abfd, x_symp + i, &i_sym); + memcpy (&sym->internal_elf_sym, &i_sym, sizeof (Elf_Internal_Sym)); +#ifdef ELF_KEEP_EXTSYM + memcpy (&sym->native_elf_sym, x_symp + i, sizeof (Elf_External_Sym)); +#endif + sym->symbol.the_bfd = abfd; + + sym->symbol.name = elf_string_from_elf_section (abfd, hdr->sh_link, + i_sym.st_name); + + sym->symbol.value = i_sym.st_value; + + if (i_sym.st_shndx > 0 && i_sym.st_shndx < SHN_LORESERVE) + { + sym->symbol.section = section_from_elf_index (abfd, + i_sym.st_shndx); + if (sym->symbol.section == NULL) + { + /* This symbol is in a section for which we did not + create a BFD section. Just use bfd_abs_section, + although it is wrong. FIXME. */ + sym->symbol.section = bfd_abs_section_ptr; + } + } + else if (i_sym.st_shndx == SHN_ABS) + { + sym->symbol.section = bfd_abs_section_ptr; + } + else if (i_sym.st_shndx == SHN_COMMON) + { + sym->symbol.section = bfd_com_section_ptr; + /* Elf puts the alignment into the `value' field, and + the size into the `size' field. BFD wants to see the + size in the value field, and doesn't care (at the + moment) about the alignment. */ + sym->symbol.value = i_sym.st_size; + } + else if (i_sym.st_shndx == SHN_UNDEF) + { + sym->symbol.section = bfd_und_section_ptr; + } + else + sym->symbol.section = bfd_abs_section_ptr; + + sym->symbol.value -= sym->symbol.section->vma; + + switch (ELF_ST_BIND (i_sym.st_info)) + { + case STB_LOCAL: + sym->symbol.flags |= BSF_LOCAL; + break; + case STB_GLOBAL: + sym->symbol.flags |= BSF_GLOBAL; + break; + case STB_WEAK: + sym->symbol.flags |= BSF_WEAK; + break; + } + + switch (ELF_ST_TYPE (i_sym.st_info)) + { + case STT_SECTION: + sym->symbol.flags |= BSF_SECTION_SYM | BSF_DEBUGGING; + break; + case STT_FILE: + sym->symbol.flags |= BSF_FILE | BSF_DEBUGGING; + break; + case STT_FUNC: + sym->symbol.flags |= BSF_FUNCTION; + break; + } + + if (dynamic) + sym->symbol.flags |= BSF_DYNAMIC; + + /* Do some backend-specific processing on this symbol. */ + { + struct elf_backend_data *ebd = get_elf_backend_data (abfd); + if (ebd->elf_backend_symbol_processing) + (*ebd->elf_backend_symbol_processing) (abfd, &sym->symbol); + } + + sym++; + } + } + + /* Do some backend-specific processing on this symbol table. */ + { + struct elf_backend_data *ebd = get_elf_backend_data (abfd); + if (ebd->elf_backend_symbol_table_processing) + (*ebd->elf_backend_symbol_table_processing) (abfd, symbase, symcount); + } + + /* We rely on the zalloc to clear out the final symbol entry. */ + + symcount = sym - symbase; + + /* Fill in the user's symbol pointer vector if needed. */ + if (symptrs) + { + long l = symcount; + + sym = symbase; + while (l-- > 0) + { + *symptrs++ = &sym->symbol; + sym++; + } + *symptrs = 0; /* Final null pointer */ + } + + if (x_symp != NULL) + free (x_symp); + return symcount; +error_return: + if (x_symp != NULL) + free (x_symp); + return -1; +} + +/* Return the number of bytes required to hold the symtab vector. + + Note that we base it on the count plus 1, since we will null terminate + the vector allocated based on this size. However, the ELF symbol table + always has a dummy entry as symbol #0, so it ends up even. */ + +long +elf_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + long symcount; + long symtab_size; + Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->symtab_hdr; + + symcount = hdr->sh_size / sizeof (Elf_External_Sym); + symtab_size = (symcount - 1 + 1) * (sizeof (asymbol *)); + + return symtab_size; +} + +long +elf_get_dynamic_symtab_upper_bound (abfd) + bfd *abfd; +{ + long symcount; + long symtab_size; + Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->dynsymtab_hdr; + + if (elf_dynsymtab (abfd) == 0) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + symcount = hdr->sh_size / sizeof (Elf_External_Sym); + symtab_size = (symcount - 1 + 1) * (sizeof (asymbol *)); + + return symtab_size; +} + +long +elf_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + return (asect->reloc_count + 1) * sizeof (arelent *); +} + +/* Read in and swap the external relocs. */ + +static boolean +elf_slurp_reloc_table (abfd, asect, symbols) + bfd *abfd; + asection *asect; + asymbol **symbols; +{ + struct elf_backend_data * const ebd = get_elf_backend_data (abfd); + struct bfd_elf_section_data * const d = elf_section_data (asect); + PTR allocated = NULL; + bfd_byte *native_relocs; + arelent *relents; + arelent *relent; + unsigned int i; + int entsize; + + if (asect->relocation != NULL) + return true; + + BFD_ASSERT (asect->rel_filepos == d->rel_hdr.sh_offset + && (asect->reloc_count + == d->rel_hdr.sh_size / d->rel_hdr.sh_entsize)); + + native_relocs = (bfd_byte *) elf_section_data (asect)->relocs; + if (native_relocs == NULL) + { + allocated = (PTR) malloc (d->rel_hdr.sh_size); + if (allocated == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0 + || (bfd_read (allocated, 1, d->rel_hdr.sh_size, abfd) + != d->rel_hdr.sh_size)) + goto error_return; + + native_relocs = (bfd_byte *) allocated; + } + + relents = ((arelent *) + bfd_alloc (abfd, asect->reloc_count * sizeof (arelent))); + if (relents == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + entsize = d->rel_hdr.sh_entsize; + BFD_ASSERT (entsize == sizeof (Elf_External_Rel) + || entsize == sizeof (Elf_External_Rela)); + + for (i = 0, relent = relents; + i < asect->reloc_count; + i++, relent++, native_relocs += entsize) + { + Elf_Internal_Rela rela; + Elf_Internal_Rel rel; + + if (entsize == sizeof (Elf_External_Rela)) + elf_swap_reloca_in (abfd, (Elf_External_Rela *) native_relocs, &rela); + else + { + elf_swap_reloc_in (abfd, (Elf_External_Rel *) native_relocs, &rel); + rela.r_offset = rel.r_offset; + rela.r_info = rel.r_info; + rela.r_addend = 0; + } + + /* The address of an ELF reloc is section relative for an object + file, and absolute for an executable file or shared library. + The address of a BFD reloc is always section relative. */ + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + relent->address = rela.r_offset; + else + relent->address = rela.r_offset - asect->vma; + + if (ELF_R_SYM (rela.r_info) == 0) + relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + else + { + asymbol **ps, *s; + + ps = symbols + ELF_R_SYM (rela.r_info) - 1; + s = *ps; + + /* Canonicalize ELF section symbols. FIXME: Why? */ + if ((s->flags & BSF_SECTION_SYM) == 0) + relent->sym_ptr_ptr = ps; + else + relent->sym_ptr_ptr = s->section->symbol_ptr_ptr; + } + + relent->addend = rela.r_addend; + + if (entsize == sizeof (Elf_External_Rela)) + (*ebd->elf_info_to_howto) (abfd, relent, &rela); + else + (*ebd->elf_info_to_howto_rel) (abfd, relent, &rel); + } + + asect->relocation = relents; + + if (allocated != NULL) + free (allocated); + + return true; + + error_return: + if (allocated != NULL) + free (allocated); + return false; +} + +#ifdef DEBUG +static void +elf_debug_section (str, num, hdr) + char *str; + int num; + Elf_Internal_Shdr *hdr; +{ + fprintf (stderr, "\nSection#%d '%s' 0x%.8lx\n", num, str, (long) hdr); + fprintf (stderr, + "sh_name = %ld\tsh_type = %ld\tsh_flags = %ld\n", + (long) hdr->sh_name, + (long) hdr->sh_type, + (long) hdr->sh_flags); + fprintf (stderr, + "sh_addr = %ld\tsh_offset = %ld\tsh_size = %ld\n", + (long) hdr->sh_addr, + (long) hdr->sh_offset, + (long) hdr->sh_size); + fprintf (stderr, + "sh_link = %ld\tsh_info = %ld\tsh_addralign = %ld\n", + (long) hdr->sh_link, + (long) hdr->sh_info, + (long) hdr->sh_addralign); + fprintf (stderr, "sh_entsize = %ld\n", + (long) hdr->sh_entsize); + fprintf (stderr, "rawdata = 0x%.8lx\n", (long) hdr->rawdata); + fprintf (stderr, "contents = 0x%.8lx\n", (long) hdr->contents); + fprintf (stderr, "size = %ld\n", (long) hdr->size); + fflush (stderr); +} + +static void +elf_debug_file (ehdrp) + Elf_Internal_Ehdr *ehdrp; +{ + fprintf (stderr, "e_entry = 0x%.8lx\n", (long) ehdrp->e_entry); + fprintf (stderr, "e_phoff = %ld\n", (long) ehdrp->e_phoff); + fprintf (stderr, "e_phnum = %ld\n", (long) ehdrp->e_phnum); + fprintf (stderr, "e_phentsize = %ld\n", (long) ehdrp->e_phentsize); + fprintf (stderr, "e_shoff = %ld\n", (long) ehdrp->e_shoff); + fprintf (stderr, "e_shnum = %ld\n", (long) ehdrp->e_shnum); + fprintf (stderr, "e_shentsize = %ld\n", (long) ehdrp->e_shentsize); +} +#endif + +/* Canonicalize the relocs. */ + +long +elf_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr; + unsigned int i; + + if (! elf_slurp_reloc_table (abfd, section, symbols)) + return -1; + + tblptr = section->relocation; + for (i = 0; i < section->reloc_count; i++) + *relptr++ = tblptr++; + + *relptr = NULL; + + return section->reloc_count; +} + +long +elf_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + long symcount = elf_slurp_symbol_table (abfd, alocation, false); + + if (symcount >= 0) + bfd_get_symcount (abfd) = symcount; + return symcount; +} + +long +elf_canonicalize_dynamic_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + return elf_slurp_symbol_table (abfd, alocation, true); +} + +asymbol * +elf_make_empty_symbol (abfd) + bfd *abfd; +{ + elf_symbol_type *newsym; + + newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (elf_symbol_type)); + if (!newsym) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + else + { + newsym->symbol.the_bfd = abfd; + return &newsym->symbol; + } +} + +void +elf_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +void +elf_print_symbol (ignore_abfd, filep, symbol, how) + bfd *ignore_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, "elf "); + fprintf_vma (file, symbol->value); + fprintf (file, " %lx", (long) symbol->flags); + break; + case bfd_print_symbol_all: + { + CONST char *section_name; + section_name = symbol->section ? symbol->section->name : "(*none*)"; + bfd_print_symbol_vandf ((PTR) file, symbol); + fprintf (file, " %s\t%s", + section_name, + symbol->name); + } + break; + } + +} + +alent * +elf_get_lineno (ignore_abfd, symbol) + bfd *ignore_abfd; + asymbol *symbol; +{ + fprintf (stderr, "elf_get_lineno unimplemented\n"); + fflush (stderr); + BFD_FAIL (); + return NULL; +} + +boolean +elf_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + /* If this isn't the right architecture for this backend, and this + isn't the generic backend, fail. */ + if (arch != get_elf_backend_data (abfd)->arch + && arch != bfd_arch_unknown + && get_elf_backend_data (abfd)->arch != bfd_arch_unknown) + return false; + + return bfd_default_set_arch_mach (abfd, arch, machine); +} + +boolean +elf_find_nearest_line (abfd, + section, + symbols, + offset, + filename_ptr, + functionname_ptr, + line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + CONST char **filename_ptr; + CONST char **functionname_ptr; + unsigned int *line_ptr; +{ + return false; +} + +int +elf_sizeof_headers (abfd, reloc) + bfd *abfd; + boolean reloc; +{ + int ret; + + ret = sizeof (Elf_External_Ehdr); + if (! reloc) + ret += get_program_header_size (abfd); + return ret; +} + +boolean +elf_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + Elf_Internal_Shdr *hdr; + + if (! abfd->output_has_begun + && ! elf_compute_section_file_positions (abfd, + (struct bfd_link_info *) NULL)) + return false; + + hdr = &elf_section_data (section)->this_hdr; + + if (bfd_seek (abfd, hdr->sh_offset + offset, SEEK_SET) == -1) + return false; + if (bfd_write (location, 1, count, abfd) != count) + return false; + + return true; +} + +void +elf_no_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf_Internal_Rela *dst; +{ + fprintf (stderr, "elf RELA relocation support for target machine unimplemented\n"); + fflush (stderr); + BFD_FAIL (); +} + +void +elf_no_info_to_howto_rel (abfd, cache_ptr, dst) + bfd *abfd; + arelent *cache_ptr; + Elf_Internal_Rel *dst; +{ + fprintf (stderr, "elf REL relocation support for target machine unimplemented\n"); + fflush (stderr); + BFD_FAIL (); +} + + +/* Core file support */ + +#ifdef HAVE_PROCFS /* Some core file support requires host /proc files */ +#include +#else +#define bfd_prstatus(abfd, descdata, descsz, filepos) true +#define bfd_fpregset(abfd, descdata, descsz, filepos) true +#define bfd_prpsinfo(abfd, descdata, descsz, filepos) true +#endif + +#ifdef HAVE_PROCFS + +static boolean +bfd_prstatus (abfd, descdata, descsz, filepos) + bfd *abfd; + char *descdata; + int descsz; + long filepos; +{ + asection *newsect; + prstatus_t *status = (prstatus_t *) 0; + + if (descsz == sizeof (prstatus_t)) + { + newsect = bfd_make_section (abfd, ".reg"); + if (newsect == NULL) + return false; + newsect->_raw_size = sizeof (status->pr_reg); + newsect->filepos = filepos + (long) &status->pr_reg; + newsect->flags = SEC_HAS_CONTENTS; + newsect->alignment_power = 2; + if ((core_prstatus (abfd) = bfd_alloc (abfd, descsz)) != NULL) + { + memcpy (core_prstatus (abfd), descdata, descsz); + } + } + return true; +} + +/* Stash a copy of the prpsinfo structure away for future use. */ + +static boolean +bfd_prpsinfo (abfd, descdata, descsz, filepos) + bfd *abfd; + char *descdata; + int descsz; + long filepos; +{ + if (descsz == sizeof (prpsinfo_t)) + { + if ((core_prpsinfo (abfd) = bfd_alloc (abfd, descsz)) == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + memcpy (core_prpsinfo (abfd), descdata, descsz); + } + return true; +} + +static boolean +bfd_fpregset (abfd, descdata, descsz, filepos) + bfd *abfd; + char *descdata; + int descsz; + long filepos; +{ + asection *newsect; + + newsect = bfd_make_section (abfd, ".reg2"); + if (newsect == NULL) + return false; + newsect->_raw_size = descsz; + newsect->filepos = filepos; + newsect->flags = SEC_HAS_CONTENTS; + newsect->alignment_power = 2; + return true; +} + +#endif /* HAVE_PROCFS */ + +/* Return a pointer to the args (including the command name) that were + seen by the program that generated the core dump. Note that for + some reason, a spurious space is tacked onto the end of the args + in some (at least one anyway) implementations, so strip it off if + it exists. */ + +char * +elf_core_file_failing_command (abfd) + bfd *abfd; +{ +#ifdef HAVE_PROCFS + if (core_prpsinfo (abfd)) + { + prpsinfo_t *p = core_prpsinfo (abfd); + char *scan = p->pr_psargs; + while (*scan++) + {; + } + scan -= 2; + if ((scan > p->pr_psargs) && (*scan == ' ')) + { + *scan = '\000'; + } + return p->pr_psargs; + } +#endif + return NULL; +} + +/* Return the number of the signal that caused the core dump. Presumably, + since we have a core file, we got a signal of some kind, so don't bother + checking the other process status fields, just return the signal number. + */ + +int +elf_core_file_failing_signal (abfd) + bfd *abfd; +{ +#ifdef HAVE_PROCFS + if (core_prstatus (abfd)) + { + return ((prstatus_t *) (core_prstatus (abfd)))->pr_cursig; + } +#endif + return -1; +} + +/* Check to see if the core file could reasonably be expected to have + come for the current executable file. Note that by default we return + true unless we find something that indicates that there might be a + problem. + */ + +boolean +elf_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd; + bfd *exec_bfd; +{ +#ifdef HAVE_PROCFS + char *corename; + char *execname; +#endif + + /* First, xvecs must match since both are ELF files for the same target. */ + + if (core_bfd->xvec != exec_bfd->xvec) + { + bfd_set_error (bfd_error_system_call); + return false; + } + +#ifdef HAVE_PROCFS + + /* If no prpsinfo, just return true. Otherwise, grab the last component + of the exec'd pathname from the prpsinfo. */ + + if (core_prpsinfo (core_bfd)) + { + corename = (((struct prpsinfo *) core_prpsinfo (core_bfd))->pr_fname); + } + else + { + return true; + } + + /* Find the last component of the executable pathname. */ + + if ((execname = strrchr (exec_bfd->filename, '/')) != NULL) + { + execname++; + } + else + { + execname = (char *) exec_bfd->filename; + } + + /* See if they match */ + + return strcmp (execname, corename) ? false : true; + +#else + + return true; + +#endif /* HAVE_PROCFS */ +} + +/* ELF core files contain a segment of type PT_NOTE, that holds much of + the information that would normally be available from the /proc interface + for the process, at the time the process dumped core. Currently this + includes copies of the prstatus, prpsinfo, and fpregset structures. + + Since these structures are potentially machine dependent in size and + ordering, bfd provides two levels of support for them. The first level, + available on all machines since it does not require that the host + have /proc support or the relevant include files, is to create a bfd + section for each of the prstatus, prpsinfo, and fpregset structures, + without any interpretation of their contents. With just this support, + the bfd client will have to interpret the structures itself. Even with + /proc support, it might want these full structures for it's own reasons. + + In the second level of support, where HAVE_PROCFS is defined, bfd will + pick apart the structures to gather some additional information that + clients may want, such as the general register set, the name of the + exec'ed file and its arguments, the signal (if any) that caused the + core dump, etc. + + */ + +static boolean +elf_corefile_note (abfd, hdr) + bfd *abfd; + Elf_Internal_Phdr *hdr; +{ + Elf_External_Note *x_note_p; /* Elf note, external form */ + Elf_Internal_Note i_note; /* Elf note, internal form */ + char *buf = NULL; /* Entire note segment contents */ + char *namedata; /* Name portion of the note */ + char *descdata; /* Descriptor portion of the note */ + char *sectname; /* Name to use for new section */ + long filepos; /* File offset to descriptor data */ + asection *newsect; + + if (hdr->p_filesz > 0 + && (buf = (char *) malloc (hdr->p_filesz)) != NULL + && bfd_seek (abfd, hdr->p_offset, SEEK_SET) != -1 + && bfd_read ((PTR) buf, hdr->p_filesz, 1, abfd) == hdr->p_filesz) + { + x_note_p = (Elf_External_Note *) buf; + while ((char *) x_note_p < (buf + hdr->p_filesz)) + { + i_note.namesz = bfd_h_get_32 (abfd, (bfd_byte *) x_note_p->namesz); + i_note.descsz = bfd_h_get_32 (abfd, (bfd_byte *) x_note_p->descsz); + i_note.type = bfd_h_get_32 (abfd, (bfd_byte *) x_note_p->type); + namedata = x_note_p->name; + descdata = namedata + BFD_ALIGN (i_note.namesz, 4); + filepos = hdr->p_offset + (descdata - buf); + switch (i_note.type) + { + case NT_PRSTATUS: + /* process descdata as prstatus info */ + if (! bfd_prstatus (abfd, descdata, i_note.descsz, filepos)) + return false; + sectname = ".prstatus"; + break; + case NT_FPREGSET: + /* process descdata as fpregset info */ + if (! bfd_fpregset (abfd, descdata, i_note.descsz, filepos)) + return false; + sectname = ".fpregset"; + break; + case NT_PRPSINFO: + /* process descdata as prpsinfo */ + if (! bfd_prpsinfo (abfd, descdata, i_note.descsz, filepos)) + return false; + sectname = ".prpsinfo"; + break; + default: + /* Unknown descriptor, just ignore it. */ + sectname = NULL; + break; + } + if (sectname != NULL) + { + newsect = bfd_make_section (abfd, sectname); + if (newsect == NULL) + return false; + newsect->_raw_size = i_note.descsz; + newsect->filepos = filepos; + newsect->flags = SEC_ALLOC | SEC_HAS_CONTENTS; + newsect->alignment_power = 2; + } + x_note_p = (Elf_External_Note *) + (descdata + BFD_ALIGN (i_note.descsz, 4)); + } + } + if (buf != NULL) + { + free (buf); + } + else if (hdr->p_filesz > 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + return true; + +} + +/* Core files are simply standard ELF formatted files that partition + the file using the execution view of the file (program header table) + rather than the linking view. In fact, there is no section header + table in a core file. + + The process status information (including the contents of the general + register set) and the floating point register set are stored in a + segment of type PT_NOTE. We handcraft a couple of extra bfd sections + that allow standard bfd access to the general registers (.reg) and the + floating point registers (.reg2). + + */ + +const bfd_target * +elf_core_file_p (abfd) + bfd *abfd; +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + Elf_External_Phdr x_phdr; /* Program header table entry, external form */ + Elf_Internal_Phdr *i_phdrp; /* Program header table, internal form */ + unsigned int phindex; + struct elf_backend_data *ebd; + + /* Read in the ELF header in external format. */ + + if (bfd_read ((PTR) & x_ehdr, sizeof (x_ehdr), 1, abfd) != sizeof (x_ehdr)) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* Now check to see if we have a valid ELF file, and one that BFD can + make use of. The magic number must match, the address size ('class') + and byte-swapping must match our XVEC entry, and it must have a + program header table (FIXME: See comments re segments at top of this + file). */ + + if (elf_file_p (&x_ehdr) == false) + { + wrong: + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* FIXME, Check EI_VERSION here ! */ + + { +#if ARCH_SIZE == 32 + int desired_address_size = ELFCLASS32; +#endif +#if ARCH_SIZE == 64 + int desired_address_size = ELFCLASS64; +#endif + + if (x_ehdr.e_ident[EI_CLASS] != desired_address_size) + goto wrong; + } + + /* Switch xvec to match the specified byte order. */ + switch (x_ehdr.e_ident[EI_DATA]) + { + case ELFDATA2MSB: /* Big-endian */ + if (abfd->xvec->byteorder_big_p == false) + goto wrong; + break; + case ELFDATA2LSB: /* Little-endian */ + if (abfd->xvec->byteorder_big_p == true) + goto wrong; + break; + case ELFDATANONE: /* No data encoding specified */ + default: /* Unknown data encoding specified */ + goto wrong; + } + + /* Allocate an instance of the elf_obj_tdata structure and hook it up to + the tdata pointer in the bfd. */ + + elf_tdata (abfd) = + (struct elf_obj_tdata *) bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); + if (elf_tdata (abfd) == NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + /* FIXME, `wrong' returns from this point onward, leak memory. */ + + /* Now that we know the byte order, swap in the rest of the header */ + i_ehdrp = elf_elfheader (abfd); + elf_swap_ehdr_in (abfd, &x_ehdr, i_ehdrp); +#if DEBUG & 1 + elf_debug_file (i_ehdrp); +#endif + + ebd = get_elf_backend_data (abfd); + + /* Check that the ELF e_machine field matches what this particular + BFD format expects. */ + if (ebd->elf_machine_code != i_ehdrp->e_machine) + { + const bfd_target * const *target_ptr; + + if (ebd->elf_machine_code != EM_NONE) + goto wrong; + + /* This is the generic ELF target. Let it match any ELF target + for which we do not have a specific backend. */ + for (target_ptr = bfd_target_vector; *target_ptr != NULL; target_ptr++) + { + struct elf_backend_data *back; + + if ((*target_ptr)->flavour != bfd_target_elf_flavour) + continue; + back = (struct elf_backend_data *) (*target_ptr)->backend_data; + if (back->elf_machine_code == i_ehdrp->e_machine) + { + /* target_ptr is an ELF backend which matches this + object file, so reject the generic ELF target. */ + goto wrong; + } + } + } + + /* If there is no program header, or the type is not a core file, then + we are hosed. */ + if (i_ehdrp->e_phoff == 0 || i_ehdrp->e_type != ET_CORE) + goto wrong; + + /* Allocate space for a copy of the program header table in + internal form, seek to the program header table in the file, + read it in, and convert it to internal form. As a simple sanity + check, verify that the what BFD thinks is the size of each program + header table entry actually matches the size recorded in the file. */ + + if (i_ehdrp->e_phentsize != sizeof (x_phdr)) + goto wrong; + i_phdrp = (Elf_Internal_Phdr *) + bfd_alloc (abfd, sizeof (*i_phdrp) * i_ehdrp->e_phnum); + if (!i_phdrp) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) == -1) + return NULL; + for (phindex = 0; phindex < i_ehdrp->e_phnum; phindex++) + { + if (bfd_read ((PTR) & x_phdr, sizeof (x_phdr), 1, abfd) + != sizeof (x_phdr)) + return NULL; + elf_swap_phdr_in (abfd, &x_phdr, i_phdrp + phindex); + } + + /* Once all of the program headers have been read and converted, we + can start processing them. */ + + for (phindex = 0; phindex < i_ehdrp->e_phnum; phindex++) + { + bfd_section_from_phdr (abfd, i_phdrp + phindex, phindex); + if ((i_phdrp + phindex)->p_type == PT_NOTE) + { + if (! elf_corefile_note (abfd, i_phdrp + phindex)) + return NULL; + } + } + + /* Remember the entry point specified in the ELF file header. */ + + bfd_get_start_address (abfd) = i_ehdrp->e_entry; + + return abfd->xvec; +} + +/* ELF linker code. */ + +static boolean elf_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean elf_link_add_archive_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static INLINE boolean elf_link_record_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static boolean elf_link_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static boolean elf_adjust_dynamic_symbol + PARAMS ((struct elf_link_hash_entry *, PTR)); + +/* Given an ELF BFD, add symbols to the global hash table as + appropriate. */ + +boolean +elf_bfd_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + switch (bfd_get_format (abfd)) + { + case bfd_object: + return elf_link_add_object_symbols (abfd, info); + case bfd_archive: + return elf_link_add_archive_symbols (abfd, info); + default: + bfd_set_error (bfd_error_wrong_format); + return false; + } +} + +/* Add symbols from an ELF archive file to the linker hash table. We + don't use _bfd_generic_link_add_archive_symbols because of a + problem which arises on UnixWare. The UnixWare libc.so is an + archive which includes an entry libc.so.1 which defines a bunch of + symbols. The libc.so archive also includes a number of other + object files, which also define symbols, some of which are the same + as those defined in libc.so.1. Correct linking requires that we + consider each object file in turn, and include it if it defines any + symbols we need. _bfd_generic_link_add_archive_symbols does not do + this; it looks through the list of undefined symbols, and includes + any object file which defines them. When this algorithm is used on + UnixWare, it winds up pulling in libc.so.1 early and defining a + bunch of symbols. This means that some of the other objects in the + archive are not included in the link, which is incorrect since they + precede libc.so.1 in the archive. + + Fortunately, ELF archive handling is simpler than that done by + _bfd_generic_link_add_archive_symbols, which has to allow for a.out + oddities. In ELF, if we find a symbol in the archive map, and the + symbol is currently undefined, we know that we must pull in that + object file. + + Unfortunately, we do have to make multiple passes over the symbol + table until nothing further is resolved. */ + +static boolean +elf_link_add_archive_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + symindex c; + boolean *defined = NULL; + boolean *included = NULL; + carsym *symdefs; + boolean loop; + + if (! bfd_has_map (abfd)) + { + bfd_set_error (bfd_error_no_symbols); + return false; + } + + /* Keep track of all symbols we know to be already defined, and all + files we know to be already included. This is to speed up the + second and subsequent passes. */ + c = bfd_ardata (abfd)->symdef_count; + if (c == 0) + return true; + defined = (boolean *) malloc (c * sizeof (boolean)); + included = (boolean *) malloc (c * sizeof (boolean)); + if (defined == (boolean *) NULL || included == (boolean *) NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + memset (defined, 0, c * sizeof (boolean)); + memset (included, 0, c * sizeof (boolean)); + + symdefs = bfd_ardata (abfd)->symdefs; + + do + { + file_ptr last; + symindex i; + carsym *symdef; + carsym *symdefend; + + loop = false; + last = -1; + + symdef = symdefs; + symdefend = symdef + c; + for (i = 0; symdef < symdefend; symdef++, i++) + { + struct elf_link_hash_entry *h; + bfd *element; + struct bfd_link_hash_entry *undefs_tail; + symindex mark; + + if (defined[i] || included[i]) + continue; + if (symdef->file_offset == last) + { + included[i] = true; + continue; + } + + h = elf_link_hash_lookup (elf_hash_table (info), symdef->name, + false, false, false); + if (h == (struct elf_link_hash_entry *) NULL) + continue; + if (h->root.type != bfd_link_hash_undefined) + { + defined[i] = true; + continue; + } + + /* We need to include this archive member. */ + + element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset); + if (element == (bfd *) NULL) + goto error_return; + + if (! bfd_check_format (element, bfd_object)) + goto error_return; + + /* Doublecheck that we have not included this object + already--it should be impossible, but there may be + something wrong with the archive. */ + if (element->archive_pass != 0) + { + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + element->archive_pass = 1; + + undefs_tail = info->hash->undefs_tail; + + if (! (*info->callbacks->add_archive_element) (info, element, + symdef->name)) + goto error_return; + if (! elf_link_add_object_symbols (element, info)) + goto error_return; + + /* If there are any new undefined symbols, we need to make + another pass through the archive in order to see whether + they can be defined. FIXME: This isn't perfect, because + common symbols wind up on undefs_tail and because an + undefined symbol which is defined later on in this pass + does not require another pass. This isn't a bug, but it + does make the code less efficient than it could be. */ + if (undefs_tail != info->hash->undefs_tail) + loop = true; + + /* Look backward to mark all symbols from this object file + which we have already seen in this pass. */ + mark = i; + do + { + included[mark] = true; + if (mark == 0) + break; + --mark; + } + while (symdefs[mark].file_offset == symdef->file_offset); + + /* We mark subsequent symbols from this object file as we go + on through the loop. */ + last = symdef->file_offset; + } + } + while (loop); + + free (defined); + free (included); + + return true; + + error_return: + if (defined != (boolean *) NULL) + free (defined); + if (included != (boolean *) NULL) + free (included); + return false; +} + +/* Record a new dynamic symbol. We record the dynamic symbols as we + read the input files, since we need to have a list of all of them + before we can determine the final sizes of the output sections. */ + +static INLINE boolean +elf_link_record_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + if (h->dynindx == -1) + { + h->dynindx = elf_hash_table (info)->dynsymcount; + ++elf_hash_table (info)->dynsymcount; + h->dynstr_index = bfd_add_to_strtab (elf_hash_table (info)->dynobj, + elf_hash_table (info)->dynstr, + h->root.root.string); + if (h->dynstr_index == (unsigned long) -1) + return false; + } + + return true; +} + +/* Add symbols from an ELF object file to the linker hash table. */ + +static boolean +elf_link_add_object_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + boolean (*add_symbol_hook) PARAMS ((bfd *, struct bfd_link_info *, + const Elf_Internal_Sym *, + const char **, flagword *, + asection **, bfd_vma *)); + boolean collect; + Elf_Internal_Shdr *hdr; + size_t symcount; + size_t extsymcount; + size_t extsymoff; + Elf_External_Sym *buf = NULL; + struct elf_link_hash_entry **sym_hash; + boolean dynamic; + Elf_External_Dyn *dynbuf = NULL; + struct elf_link_hash_entry *weaks; + Elf_External_Sym *esym; + Elf_External_Sym *esymend; + + add_symbol_hook = get_elf_backend_data (abfd)->elf_add_symbol_hook; + collect = get_elf_backend_data (abfd)->collect; + + hdr = &elf_tdata (abfd)->symtab_hdr; + symcount = hdr->sh_size / sizeof (Elf_External_Sym); + + /* The sh_info field of the symtab header tells us where the + external symbols start. We don't care about the local symbols at + this point. */ + if (elf_bad_symtab (abfd)) + { + extsymcount = symcount; + extsymoff = 0; + } + else + { + extsymcount = symcount - hdr->sh_info; + extsymoff = hdr->sh_info; + } + + buf = (Elf_External_Sym *) malloc (extsymcount * sizeof (Elf_External_Sym)); + if (buf == NULL && extsymcount != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + /* We store a pointer to the hash table entry for each external + symbol. */ + sym_hash = ((struct elf_link_hash_entry **) + bfd_alloc (abfd, + extsymcount * sizeof (struct elf_link_hash_entry *))); + if (sym_hash == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + elf_sym_hashes (abfd) = sym_hash; + + if (elf_elfheader (abfd)->e_type != ET_DYN) + { + dynamic = false; + + /* If we are creating a shared library, create all the dynamic + sections immediately. We need to attach them to something, + so we attach them to this BFD, provided it is the right + format. FIXME: If there are no input BFD's of the same + format as the output, we can't make a shared library. */ + if (info->shared + && elf_hash_table (info)->dynobj == NULL + && abfd->xvec == info->hash->creator) + { + if (! elf_link_create_dynamic_sections (abfd, info)) + goto error_return; + elf_hash_table (info)->dynobj = abfd; + } + } + else + { + asection *s; + const char *name; + unsigned long strindex; + + dynamic = true; + + /* You can't use -r against a dynamic object. There's no hope + of using a dynamic object which does not exactly match the + format of the output file. */ + if (info->relocateable + || info->hash->creator != abfd->xvec) + { + bfd_set_error (bfd_error_invalid_operation); + goto error_return; + } + + /* Find the name to use in a DT_NEEDED entry that refers to this + object. If the object has a DT_SONAME entry, we use it. + Otherwise, if the generic linker stuck something in + elf_dt_needed_name, we use that. Otherwise, we just use the + file name. */ + name = bfd_get_filename (abfd); + if (elf_dt_needed_name (abfd) != NULL) + name = elf_dt_needed_name (abfd); + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s != NULL) + { + Elf_External_Dyn *extdyn; + Elf_External_Dyn *extdynend; + + dynbuf = (Elf_External_Dyn *) malloc (s->_raw_size); + if (dynbuf == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf, + (file_ptr) 0, s->_raw_size)) + goto error_return; + + extdyn = dynbuf; + extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn); + for (; extdyn < extdynend; extdyn++) + { + Elf_Internal_Dyn dyn; + + elf_swap_dyn_in (abfd, extdyn, &dyn); + if (dyn.d_tag == DT_SONAME) + { + int elfsec; + unsigned long link; + + elfsec = elf_section_from_bfd_section (abfd, s); + if (elfsec == -1) + goto error_return; + link = elf_elfsections (abfd)[elfsec]->sh_link; + name = elf_string_from_elf_section (abfd, link, + dyn.d_un.d_val); + if (name == NULL) + goto error_return; + + break; + } + } + + free (dynbuf); + dynbuf = NULL; + } + + /* We do not want to include any of the sections in a dynamic + object in the output file. We hack by simply clobbering the + list of sections in the BFD. This could be handled more + cleanly by, say, a new section flag; the existing + SEC_NEVER_LOAD flag is not the one we want, because that one + still implies that the section takes up space in the output + file. */ + abfd->sections = NULL; + + /* If this is the first dynamic object found in the link, create + the special sections required for dynamic linking. We need + to put them somewhere, and attaching them to the first + dynamic object is as good place as any. */ + if (elf_hash_table (info)->dynobj == NULL) + { + if (! elf_link_create_dynamic_sections (abfd, info)) + goto error_return; + elf_hash_table (info)->dynobj = abfd; + } + + /* Add a DT_NEEDED entry for this dynamic object. */ + strindex = bfd_add_to_strtab (abfd, + elf_hash_table (info)->dynstr, + name); + + if (strindex == (unsigned long) -1) + goto error_return; + if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex)) + goto error_return; + } + + if (bfd_seek (abfd, + hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym), + SEEK_SET) != 0 + || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym), extsymcount, abfd) + != extsymcount * sizeof (Elf_External_Sym))) + goto error_return; + + weaks = NULL; + + esymend = buf + extsymcount; + for (esym = buf; esym < esymend; esym++, sym_hash++) + { + Elf_Internal_Sym sym; + int bind; + bfd_vma value; + asection *sec; + flagword flags; + const char *name; + struct elf_link_hash_entry *h = NULL; + boolean definition; + + elf_swap_symbol_in (abfd, esym, &sym); + + flags = BSF_NO_FLAGS; + sec = NULL; + value = sym.st_value; + *sym_hash = NULL; + + bind = ELF_ST_BIND (sym.st_info); + if (bind == STB_LOCAL) + { + /* This should be impossible, since ELF requires that all + global symbols follow all local symbols, and that sh_info + point to the first global symbol. Unfortunatealy, Irix 5 + screws this up. */ + continue; + } + else if (bind == STB_GLOBAL) + flags = BSF_GLOBAL; + else if (bind == STB_WEAK) + flags = BSF_WEAK; + else + { + /* Leave it up to the processor backend. */ + } + + if (sym.st_shndx == SHN_UNDEF) + sec = bfd_und_section_ptr; + else if (sym.st_shndx > 0 && sym.st_shndx < SHN_LORESERVE) + { + sec = section_from_elf_index (abfd, sym.st_shndx); + if (sec == NULL) + goto error_return; + value -= sec->vma; + } + else if (sym.st_shndx == SHN_ABS) + sec = bfd_abs_section_ptr; + else if (sym.st_shndx == SHN_COMMON) + { + sec = bfd_com_section_ptr; + /* What ELF calls the size we call the value. What ELF + calls the value we call the alignment. */ + value = sym.st_size; + } + else + { + /* Leave it up to the processor backend. */ + } + + name = elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name); + if (name == (const char *) NULL) + goto error_return; + + if (add_symbol_hook) + { + if (! (*add_symbol_hook) (abfd, info, &sym, &name, &flags, &sec, + &value)) + goto error_return; + + /* The hook function sets the name to NULL if this symbol + should be skipped for some reason. */ + if (name == (const char *) NULL) + continue; + } + + /* Sanity check that all possibilities were handled. */ + if (flags == BSF_NO_FLAGS || sec == (asection *) NULL) + { + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + if (bfd_is_und_section (sec) + || bfd_is_com_section (sec)) + definition = false; + else + definition = true; + + if (info->hash->creator->flavour == bfd_target_elf_flavour) + { + /* We need to look up the symbol now in order to get some of + the dynamic object handling right. We pass the hash + table entry in to _bfd_generic_link_add_one_symbol so + that it does not have to look it up again. */ + h = elf_link_hash_lookup (elf_hash_table (info), name, + true, false, false); + if (h == NULL) + goto error_return; + *sym_hash = h; + + /* If we are looking at a dynamic object, and this is a + definition, we need to see if it has already been defined + by some other object. If it has, we want to use the + existing definition, and we do not want to report a + multiple symbol definition error; we do this by + clobbering sec to be bfd_und_section_ptr. */ + if (dynamic && definition) + { + if (h->root.type == bfd_link_hash_defined) + sec = bfd_und_section_ptr; + } + + /* Similarly, if we are not looking at a dynamic object, and + we have a definition, we want to override any definition + we may have from a dynamic object. Symbols from regular + files always take precedence over symbols from dynamic + objects, even if they are defined after the dynamic + object in the link. */ + if (! dynamic + && definition + && h->root.type == bfd_link_hash_defined + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (bfd_get_flavour (h->root.u.def.section->owner) + == bfd_target_elf_flavour) + && (elf_elfheader (h->root.u.def.section->owner)->e_type + == ET_DYN)) + { + /* Change the hash table entry to undefined, and let + _bfd_generic_link_add_one_symbol do the right thing + with the new definition. */ + h->root.type = bfd_link_hash_undefined; + h->root.u.undef.abfd = h->root.u.def.section->owner; + h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEFINED_WEAK; + } + + /* If this is a weak definition which we are going to use, + and the symbol is currently undefined, record that the + definition is weak. */ + if (definition + && (flags & BSF_WEAK) != 0 + && ! bfd_is_und_section (sec) + && (h->root.type == bfd_link_hash_new + || h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_weak)) + h->elf_link_hash_flags |= ELF_LINK_HASH_DEFINED_WEAK; + } + + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, flags, sec, value, (const char *) NULL, + false, collect, (struct bfd_link_hash_entry **) sym_hash))) + goto error_return; + + if (dynamic + && definition + && (flags & BSF_WEAK) != 0 + && ELF_ST_TYPE (sym.st_info) != STT_FUNC + && (*sym_hash)->weakdef == NULL) + { + /* Keep a list of all weak defined non function symbols from + a dynamic object, using the weakdef field. Later in this + function we will set the weakdef field to the correct + value. We only put non-function symbols from dynamic + objects on this list, because that happens to be the only + time we need to know the normal symbol corresponding to a + weak symbol, and the information is time consuming to + figure out. If the weakdef field is not already NULL, + then this symbol was already defined by some previous + dynamic object, and we will be using that previous + definition anyhow. */ + + (*sym_hash)->weakdef = weaks; + weaks = *sym_hash; + } + + if (info->hash->creator->flavour == bfd_target_elf_flavour) + { + int old_flags; + boolean dynsym; + int new_flag; + + /* Remember the symbol size, type and alignment. */ + if (sym.st_size != 0) + { + /* FIXME: We should probably somehow give a warning if + the symbol size changes. */ + h->size = sym.st_size; + } + if (sym.st_shndx == SHN_COMMON + && sym.st_value > h->align) + h->align = sym.st_value; + if (ELF_ST_TYPE (sym.st_info) != STT_NOTYPE) + { + /* FIXME: We should probably somehow give a warning if + the symbol type changes. */ + h->type = ELF_ST_TYPE (sym.st_info); + } + + /* Set a flag in the hash table entry indicating the type of + reference or definition we just found. Keep a count of + the number of dynamic symbols we find. A dynamic symbol + is one which is referenced or defined by both a regular + object and a shared object, or one which is referenced or + defined by more than one shared object. */ + old_flags = h->elf_link_hash_flags; + dynsym = false; + if (! dynamic) + { + if (! definition) + new_flag = ELF_LINK_HASH_REF_REGULAR; + else + new_flag = ELF_LINK_HASH_DEF_REGULAR; + if ((old_flags & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_REF_DYNAMIC)) != 0) + dynsym = true; + } + else + { + if (! definition) + new_flag = ELF_LINK_HASH_REF_DYNAMIC; + else + new_flag = ELF_LINK_HASH_DEF_DYNAMIC; + if ((old_flags & new_flag) != 0) + { + if (! definition) + new_flag = ELF_LINK_HASH_REF_DYNAMIC_MULTIPLE; + else + new_flag = ELF_LINK_HASH_DEF_DYNAMIC_MULTIPLE; + dynsym = true; + } + else + { + if ((old_flags & (ELF_LINK_HASH_DEF_REGULAR + | ELF_LINK_HASH_REF_REGULAR)) != 0) + dynsym = true; + } + } + + h->elf_link_hash_flags |= new_flag; + if (dynsym && h->dynindx == -1) + { + if (! elf_link_record_dynamic_symbol (info, h)) + goto error_return; + } + } + } + + /* Now set the weakdefs field correctly for all the weak defined + symbols we found. The only way to do this is to search all the + symbols. Since we only need the information for non functions in + dynamic objects, that's the only time we actually put anything on + the list WEAKS. We need this information so that if a regular + object refers to a symbol defined weakly in a dynamic object, the + real symbol in the dynamic object is also put in the dynamic + symbols; we also must arrange for both symbols to point to the + same memory location. We could handle the general case of symbol + aliasing, but a general symbol alias can only be generated in + assembler code, handling it correctly would be very time + consuming, and other ELF linkers don't handle general aliasing + either. */ + while (weaks != NULL) + { + struct elf_link_hash_entry *hlook; + asection *slook; + bfd_vma vlook; + struct elf_link_hash_entry **hpp; + struct elf_link_hash_entry **hppend; + + hlook = weaks; + weaks = hlook->weakdef; + hlook->weakdef = NULL; + + BFD_ASSERT (hlook->root.type == bfd_link_hash_defined); + slook = hlook->root.u.def.section; + vlook = hlook->root.u.def.value; + + hpp = elf_sym_hashes (abfd); + hppend = hpp + extsymcount; + for (; hpp < hppend; hpp++) + { + struct elf_link_hash_entry *h; + + h = *hpp; + if (h != hlook + && h->root.type == bfd_link_hash_defined + && h->root.u.def.section == slook + && h->root.u.def.value == vlook) + { + hlook->weakdef = h; + + /* If the weak definition is in the list of dynamic + symbols, make sure the real definition is put there + as well. */ + if (hlook->dynindx != -1 + && h->dynindx == -1) + { + if (! elf_link_record_dynamic_symbol (info, h)) + goto error_return; + } + + break; + } + } + } + + if (buf != NULL) + free (buf); + + return true; + + error_return: + if (buf != NULL) + free (buf); + if (dynbuf != NULL) + free (dynbuf); + return false; +} + +/* Create some sections which will be filled in with dynamic linking + information. The ABFD argument is an input file which is a dynamic + object. The dynamic sections take up virtual memory space when the + final executable is run, so we need to create them before addresses + are assigned to the output sections. We work out the actual + contents and size of these sections later. */ + +static boolean +elf_link_create_dynamic_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + register asection *s; + struct elf_link_hash_entry *h; + struct elf_backend_data *bed; + + /* Note that we set the SEC_IN_MEMORY flag for all of these + sections. */ + flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + + /* A dynamically linked executable has a .interp section, but a + shared library does not. */ + if (! info->shared) + { + s = bfd_make_section (abfd, ".interp"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)) + return false; + } + + s = bfd_make_section (abfd, ".dynamic"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return false; + + /* The special symbol _DYNAMIC is always set to the start of the + .dynamic section. This call occurs before we have processed the + symbols for any dynamic object, so we don't have to worry about + overriding a dynamic definition. We could set _DYNAMIC in a + linker script, but we only want to define it if we are, in fact, + creating a .dynamic section. We don't want to define it if there + is no .dynamic section, since on some ELF platforms the start up + code examines it to decide how to initialize the process. */ + h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, "_DYNAMIC", BSF_GLOBAL, s, (bfd_vma) 0, + (const char *) NULL, false, get_elf_backend_data (abfd)->collect, + (struct bfd_link_hash_entry **) &h))) + return false; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + + s = bfd_make_section (abfd, ".dynsym"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return false; + + /* The first .dynsym symbol is a dummy. */ + elf_hash_table (info)->dynsymcount = 1; + + s = bfd_make_section (abfd, ".dynstr"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)) + return false; + + /* Create a strtab to hold the dynamic symbol names. */ + elf_hash_table (info)->dynstr = bfd_new_strtab (abfd); + if (elf_hash_table (info)->dynstr == NULL) + return false; + + s = bfd_make_section (abfd, ".hash"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return false; + + /* Let the backend create the rest of the sections. This lets the + backend set the right flags. The backend will normally create + the .got and .plt sections. */ + bed = get_elf_backend_data (abfd); + return (*bed->elf_backend_create_dynamic_sections) (abfd, info); +} + +/* Add an entry to the .dynamic table. */ + +boolean +elf_add_dynamic_entry (info, tag, val) + struct bfd_link_info *info; + bfd_vma tag; + bfd_vma val; +{ + Elf_Internal_Dyn dyn; + bfd *dynobj; + asection *s; + size_t newsize; + bfd_byte *newcontents; + + dynobj = elf_hash_table (info)->dynobj; + + s = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (s != NULL); + + newsize = s->_raw_size + sizeof (Elf_External_Dyn); + if (s->contents == NULL) + newcontents = (bfd_byte *) malloc (newsize); + else + newcontents = (bfd_byte *) realloc (s->contents, newsize); + if (newcontents == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + dyn.d_tag = tag; + dyn.d_un.d_val = val; + elf_swap_dyn_out (dynobj, &dyn, + (Elf_External_Dyn *) (newcontents + s->_raw_size)); + + s->_raw_size = newsize; + s->contents = newcontents; + + return true; +} + +/* Record an assignment to a symbol made by a linker script. We need + this in case some dynamic object refers to this symbol. */ + +/*ARGSUSED*/ +boolean +NAME(bfd_elf,record_link_assignment) (output_bfd, info, name) + bfd *output_bfd; + struct bfd_link_info *info; + const char *name; +{ + struct elf_link_hash_entry *h; + + /* This is called after we have examined all the input objects. If + the symbol does not exist, it merely means that no object refers + to it, and we can just ignore it at this point. */ + h = elf_link_hash_lookup (elf_hash_table (info), name, + false, false, false); + if (h == NULL) + return true; + + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + + if ((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_REF_DYNAMIC)) != 0 + && h->dynindx == -1) + { + if (! elf_link_record_dynamic_symbol (info, h)) + return false; + + /* If this is a weak defined symbol, and we know a corresponding + real symbol from the same dynamic object, make sure the real + symbol is also made into a dynamic symbol. */ + if (h->weakdef != NULL + && h->weakdef->dynindx == -1) + { + if (! elf_link_record_dynamic_symbol (info, h->weakdef)) + return false; + } + } + + return true; +} + +/* Array used to determine the number of hash table buckets to use + based on the number of symbols there are. If there are fewer than + 3 symbols we use 1 bucket, fewer than 17 symbols we use 3 buckets, + fewer than 37 we use 17 buckets, and so forth. We never use more + than 521 buckets. */ + +static const size_t elf_buckets[] = +{ + 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 0 +}; + +/* Set up the sizes and contents of the ELF dynamic sections. This is + called by the ELF linker emulation before_allocation routine. We + must set the sizes of the sections before the linker sets the + addresses of the various sections. */ + +boolean +NAME(bfd_elf,size_dynamic_sections) (output_bfd, info, sinterpptr) + bfd *output_bfd; + struct bfd_link_info *info; + asection **sinterpptr; +{ + bfd *dynobj; + size_t dynsymcount; + asection *s; + Elf_Internal_Sym isym; + size_t i; + size_t bucketcount; + struct elf_backend_data *bed; + + *sinterpptr = NULL; + + dynobj = elf_hash_table (info)->dynobj; + dynsymcount = elf_hash_table (info)->dynsymcount; + + /* If there were no dynamic objects in the link, there is nothing to + do here. */ + if (dynobj == NULL) + return true; + + *sinterpptr = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (*sinterpptr != NULL || info->shared); + + /* Set the size of the .dynsym and .hash sections. We counted the + number of dynamic symbols in elf_link_add_object_symbols. We + will build the contents of .dynsym and .hash when we build the + final symbol table, because until then we do not know the correct + value to give the symbols. We built the .dynstr section as we + went along in elf_link_add_object_symbols. */ + s = bfd_get_section_by_name (dynobj, ".dynsym"); + BFD_ASSERT (s != NULL); + s->_raw_size = dynsymcount * sizeof (Elf_External_Sym); + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + /* The first entry in .dynsym is a dummy symbol. */ + isym.st_value = 0; + isym.st_size = 0; + isym.st_name = 0; + isym.st_info = 0; + isym.st_other = 0; + isym.st_shndx = 0; + elf_swap_symbol_out (output_bfd, &isym, + (Elf_External_Sym *) s->contents); + + for (i = 0; elf_buckets[i] != 0; i++) + { + bucketcount = elf_buckets[i]; + if (dynsymcount < elf_buckets[i + 1]) + break; + } + + s = bfd_get_section_by_name (dynobj, ".hash"); + BFD_ASSERT (s != NULL); + s->_raw_size = (2 + bucketcount + dynsymcount) * (ARCH_SIZE / 8); + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + memset (s->contents, 0, s->_raw_size); + + put_word (output_bfd, bucketcount, s->contents); + put_word (output_bfd, dynsymcount, s->contents + (ARCH_SIZE / 8)); + + elf_hash_table (info)->bucketcount = bucketcount; + + s = bfd_get_section_by_name (dynobj, ".dynstr"); + BFD_ASSERT (s != NULL); + s->_raw_size = elf_hash_table (info)->dynstr->length; + s->contents = (unsigned char *) elf_hash_table (info)->dynstr->tab; + + /* Find all symbols which were defined in a dynamic object and make + the backend pick a reasonable value for them. */ + elf_link_hash_traverse (elf_hash_table (info), + elf_adjust_dynamic_symbol, + (PTR) info); + + /* Add some entries to the .dynamic section. We fill in some of the + values later, in elf_bfd_final_link, but we must add the entries + now so that we know the final size of the .dynamic section. */ + if (bfd_get_section_by_name (output_bfd, ".init") != NULL) + { + if (! elf_add_dynamic_entry (info, DT_INIT, 0)) + return false; + } + if (bfd_get_section_by_name (output_bfd, ".fini") != NULL) + { + if (! elf_add_dynamic_entry (info, DT_FINI, 0)) + return false; + } + if (! elf_add_dynamic_entry (info, DT_HASH, 0) + || ! elf_add_dynamic_entry (info, DT_STRTAB, 0) + || ! elf_add_dynamic_entry (info, DT_SYMTAB, 0) + || ! elf_add_dynamic_entry (info, DT_STRSZ, + elf_hash_table (info)->dynstr->length) + || ! elf_add_dynamic_entry (info, DT_SYMENT, + sizeof (Elf_External_Sym))) + return false; + + /* The backend must work out the sizes of all the other dynamic + sections. */ + bed = get_elf_backend_data (output_bfd); + if (! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info)) + return false; + + return elf_add_dynamic_entry (info, DT_NULL, 0); +} + +/* Make the backend pick a good value for a dynamic symbol. This is + called via elf_link_hash_traverse, and also calls itself + recursively. */ + +static boolean +elf_adjust_dynamic_symbol (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + struct bfd_link_info *info = (struct bfd_link_info *) data; + bfd *dynobj; + struct elf_backend_data *bed; + + /* If this symbol is not defined by a dynamic object, or is not + referenced by a regular object, ignore it. FIXME: Do we need to + worry about symbols which are defined by one dynamic object and + referenced by another one? */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) + return true; + + /* If we've already adjusted this symbol, don't do it again. This + can happen via a recursive call. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0) + return true; + + /* Don't look at this symbol again. Note that we must set this + after checking the above conditions, because we may look at a + symbol once, decide not to do anything, and then get called + recursively later after REF_REGULAR is set below. */ + h->elf_link_hash_flags |= ELF_LINK_HASH_DYNAMIC_ADJUSTED; + + /* If this is a weak definition, and we know a real definition, and + the real symbol is not itself defined by a regular object file, + then get a good value for the real definition. We handle the + real symbol first, for the convenience of the backend routine. + + Note that there is a confusing case here. If the real definition + is defined by a regular object file, we don't get the real symbol + from the dynamic object, but we do get the weak symbol. If the + processor backend uses a COPY reloc, then if some routine in the + dynamic object changes the real symbol, we will not see that + change in the corresponding weak symbol. This is the way other + ELF linkers work as well, and seems to be a result of the shared + library model. + + I will clarify this issue. Most SVR4 shared libraries define the + variable _timezone and define timezone as a weak synonym. The + tzset call changes _timezone. If you write + extern int timezone; + int _timezone = 5; + int main () { tzset (); printf ("%d %d\n", timezone, _timezone); } + you might expect that, since timezone is a synonym for _timezone, + the same number will print both times. However, if the processor + backend uses a COPY reloc, then actually timezone will be copied + into your process image, and, since you define _timezone + yourself, _timezone will not. Thus timezone and _timezone will + wind up at different memory locations. The tzset call will set + _timezone, leaving timezone unchanged. */ + + if (h->weakdef != NULL) + { + struct elf_link_hash_entry *weakdef; + + BFD_ASSERT (h->root.type == bfd_link_hash_defined); + weakdef = h->weakdef; + BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined); + BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC); + if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 + || (weakdef->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) + { + /* This symbol is defined or referenced by a regular object + file, so we will not do anything special. Clear weakdef + for the convenience of the processor backend. */ + h->weakdef = NULL; + } + else + { + /* There is an implicit reference by a regular object file + via the weak symbol. */ + weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; + if (! elf_adjust_dynamic_symbol (weakdef, (PTR) info)) + return false; + } + } + + dynobj = elf_hash_table (info)->dynobj; + bed = get_elf_backend_data (dynobj); + if (! (*bed->elf_backend_adjust_dynamic_symbol) (info, h)) + { + /* FIXME: No way to return error. */ + abort (); + } + + return true; +} + +/* Final phase of ELF linker. */ + +/* A structure we use to avoid passing large numbers of arguments. */ + +struct elf_final_link_info +{ + /* General link information. */ + struct bfd_link_info *info; + /* Output BFD. */ + bfd *output_bfd; + /* Symbol string table. */ + struct strtab *symstrtab; + /* .dynsym section. */ + asection *dynsym_sec; + /* .hash section. */ + asection *hash_sec; + /* Buffer large enough to hold contents of any section. */ + bfd_byte *contents; + /* Buffer large enough to hold external relocs of any section. */ + PTR external_relocs; + /* Buffer large enough to hold internal relocs of any section. */ + Elf_Internal_Rela *internal_relocs; + /* Buffer large enough to hold external local symbols of any input + BFD. */ + Elf_External_Sym *external_syms; + /* Buffer large enough to hold internal local symbols of any input + BFD. */ + Elf_Internal_Sym *internal_syms; + /* Array large enough to hold a symbol index for each local symbol + of any input BFD. */ + long *indices; + /* Array large enough to hold a section pointer for each local + symbol of any input BFD. */ + asection **sections; + /* Buffer to hold swapped out symbols. */ + Elf_External_Sym *symbuf; + /* Number of swapped out symbols in buffer. */ + size_t symbuf_count; + /* Number of symbols which fit in symbuf. */ + size_t symbuf_size; +}; + +static boolean elf_link_output_sym + PARAMS ((struct elf_final_link_info *, const char *, + Elf_Internal_Sym *, asection *)); +static boolean elf_link_flush_output_syms + PARAMS ((struct elf_final_link_info *)); +static boolean elf_link_output_extsym + PARAMS ((struct elf_link_hash_entry *, PTR)); +static boolean elf_link_input_bfd + PARAMS ((struct elf_final_link_info *, bfd *)); +static boolean elf_reloc_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* Do the final step of an ELF link. */ + +boolean +elf_bfd_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + struct elf_final_link_info finfo; + register asection *o; + register struct bfd_link_order *p; + register bfd *sub; + size_t max_contents_size; + size_t max_external_reloc_size; + size_t max_internal_reloc_count; + size_t max_sym_count; + file_ptr off; + Elf_Internal_Sym elfsym; + unsigned int i; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Shdr *symstrtab_hdr; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if (info->shared) + { + fprintf (stderr, + "Generating ELF shared libraries is not yet supported\n"); + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + dynobj = elf_hash_table (info)->dynobj; + + finfo.info = info; + finfo.output_bfd = abfd; + finfo.symstrtab = bfd_new_strtab (abfd); + if (finfo.symstrtab == NULL) + return false; + if (dynobj == NULL) + { + finfo.dynsym_sec = NULL; + finfo.hash_sec = NULL; + } + else + { + finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym"); + finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash"); + if (finfo.dynsym_sec == NULL + || finfo.hash_sec == NULL) + abort (); + } + finfo.contents = NULL; + finfo.external_relocs = NULL; + finfo.internal_relocs = NULL; + finfo.external_syms = NULL; + finfo.internal_syms = NULL; + finfo.indices = NULL; + finfo.sections = NULL; + finfo.symbuf = NULL; + finfo.symbuf_count = 0; + + /* Count up the number of relocations we will output for each output + section, so that we know the sizes of the reloc sections. We + also figure out some maximum sizes. */ + max_contents_size = 0; + max_external_reloc_size = 0; + max_internal_reloc_count = 0; + max_sym_count = 0; + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + o->reloc_count = 0; + + for (p = o->link_order_head; p != NULL; p = p->next) + { + if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + ++o->reloc_count; + else if (p->type == bfd_indirect_link_order) + { + asection *sec; + + sec = p->u.indirect.section; + + if (info->relocateable) + o->reloc_count += sec->reloc_count; + + if (sec->_raw_size > max_contents_size) + max_contents_size = sec->_raw_size; + if (sec->_cooked_size > max_contents_size) + max_contents_size = sec->_cooked_size; + + /* We are interested in just local symbols, not all + symbols. */ + if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour) + { + size_t sym_count; + + if (elf_bad_symtab (sec->owner)) + sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size + / sizeof (Elf_External_Sym)); + else + sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info; + + if (sym_count > max_sym_count) + max_sym_count = sym_count; + + if ((sec->flags & SEC_RELOC) != 0) + { + size_t ext_size; + + ext_size = elf_section_data (sec)->rel_hdr.sh_size; + if (ext_size > max_external_reloc_size) + max_external_reloc_size = ext_size; + if (sec->reloc_count > max_internal_reloc_count) + max_internal_reloc_count = sec->reloc_count; + } + } + } + } + + if (o->reloc_count > 0) + o->flags |= SEC_RELOC; + else + { + /* Explicitly clear the SEC_RELOC flag. The linker tends to + set it (this is probably a bug) and if it is set + assign_section_numbers will create a reloc section. */ + o->flags &=~ SEC_RELOC; + } + } + + /* Figure out the file positions for everything but the symbol table + and the relocs. We set symcount to force assign_section_numbers + to create a symbol table. */ + abfd->symcount = info->strip == strip_all ? 0 : 1; + BFD_ASSERT (! abfd->output_has_begun); + if (! elf_compute_section_file_positions (abfd, info)) + goto error_return; + + /* That created the reloc sections. Set their sizes, and assign + them file positions, and allocate some buffers. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_RELOC) != 0) + { + Elf_Internal_Shdr *rel_hdr; + register struct elf_link_hash_entry **p, **pend; + + rel_hdr = &elf_section_data (o)->rel_hdr; + + rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count; + + /* The contents field must last into write_object_contents, + so we allocate it with bfd_alloc rather than malloc. */ + rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size); + if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + p = ((struct elf_link_hash_entry **) + malloc (o->reloc_count + * sizeof (struct elf_link_hash_entry *))); + if (p == NULL && o->reloc_count != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + elf_section_data (o)->rel_hashes = p; + pend = p + o->reloc_count; + for (; p < pend; p++) + *p = NULL; + + /* Use the reloc_count field as an index when outputting the + relocs. */ + o->reloc_count = 0; + } + } + + assign_file_positions_for_relocs (abfd); + + /* We have now assigned file positions for all the sections except + .symtab and .strtab. We start the .symtab section at the current + file position, and write directly to it. We build the .strtab + section in memory. When we add .dynsym support, we will build + that in memory as well (.dynsym is smaller than .symtab). */ + abfd->symcount = 0; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + /* sh_name is set in prep_headers. */ + symtab_hdr->sh_type = SHT_SYMTAB; + symtab_hdr->sh_flags = 0; + symtab_hdr->sh_addr = 0; + symtab_hdr->sh_size = 0; + symtab_hdr->sh_entsize = sizeof (Elf_External_Sym); + /* sh_link is set in assign_section_numbers. */ + /* sh_info is set below. */ + /* sh_offset is set just below. */ + symtab_hdr->sh_addralign = 4; /* FIXME: system dependent? */ + + off = elf_tdata (abfd)->next_file_pos; + off = assign_file_position_for_section (symtab_hdr, off, true); + + /* Note that at this point elf_tdata (abfd)->next_file_pos is + incorrect. We do not yet know the size of the .symtab section. + We correct next_file_pos below, after we do know the size. */ + + /* Allocate a buffer to hold swapped out symbols. This is to avoid + continuously seeking to the right position in the file. */ + if (! info->keep_memory || max_sym_count < 20) + finfo.symbuf_size = 20; + else + finfo.symbuf_size = max_sym_count; + finfo.symbuf = ((Elf_External_Sym *) + malloc (finfo.symbuf_size * sizeof (Elf_External_Sym))); + if (finfo.symbuf == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + /* Start writing out the symbol table. The first symbol is always a + dummy symbol. */ + elfsym.st_value = 0; + elfsym.st_size = 0; + elfsym.st_info = 0; + elfsym.st_other = 0; + elfsym.st_shndx = SHN_UNDEF; + if (! elf_link_output_sym (&finfo, (const char *) NULL, + &elfsym, bfd_und_section_ptr)) + goto error_return; + +#if 0 + /* Some standard ELF linkers do this, but we don't because it causes + bootstrap comparison failures. */ + /* Output a file symbol for the output file as the second symbol. + We output this even if we are discarding local symbols, although + I'm not sure if this is correct. */ + elfsym.st_value = 0; + elfsym.st_size = 0; + elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); + elfsym.st_other = 0; + elfsym.st_shndx = SHN_ABS; + if (! elf_link_output_sym (&finfo, bfd_get_filename (abfd), + &elfsym, bfd_abs_section_ptr)) + goto error_return; +#endif + + /* Output a symbol for each section. We output these even if we are + discarding local symbols, since they are used for relocs. These + symbols have no names. We store the index of each one in the + index field of the section, so that we can find it again when + outputting relocs. */ + elfsym.st_value = 0; + elfsym.st_size = 0; + elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + elfsym.st_other = 0; + for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++) + { + o = section_from_elf_index (abfd, i); + if (! bfd_is_abs_section (o)) + o->target_index = abfd->symcount; + elfsym.st_shndx = i; + if (! elf_link_output_sym (&finfo, (const char *) NULL, + &elfsym, o)) + goto error_return; + } + + /* Allocate some memory to hold information read in from the input + files. */ + finfo.contents = (bfd_byte *) malloc (max_contents_size); + finfo.external_relocs = (PTR) malloc (max_external_reloc_size); + finfo.internal_relocs = ((Elf_Internal_Rela *) + malloc (max_internal_reloc_count + * sizeof (Elf_Internal_Rela))); + finfo.external_syms = ((Elf_External_Sym *) + malloc (max_sym_count * sizeof (Elf_External_Sym))); + finfo.internal_syms = ((Elf_Internal_Sym *) + malloc (max_sym_count * sizeof (Elf_Internal_Sym))); + finfo.indices = (long *) malloc (max_sym_count * sizeof (long)); + finfo.sections = (asection **) malloc (max_sym_count * sizeof (asection *)); + if ((finfo.contents == NULL && max_contents_size != 0) + || (finfo.external_relocs == NULL && max_external_reloc_size != 0) + || (finfo.internal_relocs == NULL && max_internal_reloc_count != 0) + || (finfo.external_syms == NULL && max_sym_count != 0) + || (finfo.internal_syms == NULL && max_sym_count != 0) + || (finfo.indices == NULL && max_sym_count != 0) + || (finfo.sections == NULL && max_sym_count != 0)) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + /* Since ELF permits relocations to be against local symbols, we + must have the local symbols available when we do the relocations. + Since we would rather only read the local symbols once, and we + would rather not keep them in memory, we handle all the + relocations for a single input file at the same time. + + Unfortunately, there is no way to know the total number of local + symbols until we have seen all of them, and the local symbol + indices precede the global symbol indices. This means that when + we are generating relocateable output, and we see a reloc against + a global symbol, we can not know the symbol index until we have + finished examining all the local symbols to see which ones we are + going to output. To deal with this, we keep the relocations in + memory, and don't output them until the end of the link. This is + an unfortunate waste of memory, but I don't see a good way around + it. Fortunately, it only happens when performing a relocateable + link, which is not the common case. FIXME: If keep_memory is set + we could write the relocs out and then read them again; I don't + know how bad the memory loss will be. */ + + for (sub = info->input_bfds; sub != NULL; sub = sub->next) + sub->output_has_begun = false; + for (o = abfd->sections; o != NULL; o = o->next) + { + for (p = o->link_order_head; p != NULL; p = p->next) + { + if (p->type == bfd_indirect_link_order + && (bfd_get_flavour (p->u.indirect.section->owner) + == bfd_target_elf_flavour)) + { + sub = p->u.indirect.section->owner; + if (! sub->output_has_begun) + { + if (! elf_link_input_bfd (&finfo, sub)) + goto error_return; + sub->output_has_begun = true; + } + } + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + { + if (! elf_reloc_link_order (abfd, info, o, p)) + goto error_return; + } + else + { + if (! _bfd_default_link_order (abfd, info, o, p)) + goto error_return; + } + } + } + + /* That wrote out all the local symbols. Finish up the symbol table + with the global symbols. */ + + /* The sh_info field records the index of the first non local + symbol. */ + symtab_hdr->sh_info = abfd->symcount; + if (dynobj != NULL) + elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = 1; + + /* We get the global symbols from the hash table. */ + elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym, + (PTR) &finfo); + + /* Flush all symbols to the file. */ + if (! elf_link_flush_output_syms (&finfo)) + return false; + + /* Now we know the size of the symtab section. */ + off += symtab_hdr->sh_size; + + /* Finish up the symbol string table (.strtab) section. */ + symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; + /* sh_name was set in prep_headers. */ + symstrtab_hdr->sh_type = SHT_STRTAB; + symstrtab_hdr->sh_flags = 0; + symstrtab_hdr->sh_addr = 0; + symstrtab_hdr->sh_size = finfo.symstrtab->length; + symstrtab_hdr->sh_entsize = 0; + symstrtab_hdr->sh_link = 0; + symstrtab_hdr->sh_info = 0; + /* sh_offset is set just below. */ + symstrtab_hdr->sh_addralign = 1; + symstrtab_hdr->contents = (PTR) finfo.symstrtab->tab; + + off = assign_file_position_for_section (symstrtab_hdr, off, true); + elf_tdata (abfd)->next_file_pos = off; + + /* Adjust the relocs to have the correct symbol indices. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + struct elf_link_hash_entry **rel_hash; + Elf_Internal_Shdr *rel_hdr; + + if ((o->flags & SEC_RELOC) == 0) + continue; + + rel_hash = elf_section_data (o)->rel_hashes; + rel_hdr = &elf_section_data (o)->rel_hdr; + for (i = 0; i < o->reloc_count; i++, rel_hash++) + { + if (*rel_hash == NULL) + continue; + + BFD_ASSERT ((*rel_hash)->indx >= 0); + + if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) + { + Elf_External_Rel *erel; + Elf_Internal_Rel irel; + + erel = (Elf_External_Rel *) rel_hdr->contents + i; + elf_swap_reloc_in (abfd, erel, &irel); + irel.r_info = ELF_R_INFO ((*rel_hash)->indx, + ELF_R_TYPE (irel.r_info)); + elf_swap_reloc_out (abfd, &irel, erel); + } + else + { + Elf_External_Rela *erela; + Elf_Internal_Rela irela; + + BFD_ASSERT (rel_hdr->sh_entsize + == sizeof (Elf_External_Rela)); + + erela = (Elf_External_Rela *) rel_hdr->contents + i; + elf_swap_reloca_in (abfd, erela, &irela); + irela.r_info = ELF_R_INFO ((*rel_hash)->indx, + ELF_R_TYPE (irela.r_info)); + elf_swap_reloca_out (abfd, &irela, erela); + } + } + + /* Set the reloc_count field to 0 to prevent write_relocs from + trying to swap the relocs out itself. */ + o->reloc_count = 0; + } + + /* If we are linking against a dynamic object, finish up the dynamic + linking information. */ + if (dynobj != NULL) + { + Elf_External_Dyn *dyncon, *dynconend; + + /* Fix up .dynamic entries. */ + o = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (o != NULL); + + dyncon = (Elf_External_Dyn *) o->contents; + dynconend = (Elf_External_Dyn *) (o->contents + o->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + const char *name; + unsigned int type; + + elf_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + break; + + case DT_INIT: + name = ".init"; + goto get_vma; + case DT_FINI: + name = ".fini"; + goto get_vma; + case DT_HASH: + name = ".hash"; + goto get_vma; + case DT_STRTAB: + name = ".dynstr"; + goto get_vma; + case DT_SYMTAB: + name = ".dynsym"; + get_vma: + o = bfd_get_section_by_name (abfd, name); + BFD_ASSERT (o != NULL); + dyn.d_un.d_ptr = o->vma; + elf_swap_dyn_out (dynobj, &dyn, dyncon); + break; + + case DT_REL: + case DT_RELA: + case DT_RELSZ: + case DT_RELASZ: + if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ) + type = SHT_REL; + else + type = SHT_RELA; + dyn.d_un.d_val = 0; + for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++) + { + Elf_Internal_Shdr *hdr; + + hdr = elf_elfsections (abfd)[i]; + if (hdr->sh_type == type + && (hdr->sh_flags & SHF_ALLOC) != 0) + { + if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ) + dyn.d_un.d_val += hdr->sh_size; + else + { + if (dyn.d_un.d_val == 0 + || hdr->sh_addr < dyn.d_un.d_val) + dyn.d_un.d_val = hdr->sh_addr; + } + } + } + elf_swap_dyn_out (dynobj, &dyn, dyncon); + break; + } + } + + if (! (*bed->elf_backend_finish_dynamic_sections) (abfd, info)) + goto error_return; + + for (o = dynobj->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_HAS_CONTENTS) == 0) + continue; + if ((o->flags & SEC_IN_MEMORY) == 0) + { + BFD_ASSERT (info->shared); + continue; + } + if (! bfd_set_section_contents (abfd, o->output_section, + o->contents, o->output_offset, + o->_raw_size)) + goto error_return; + } + } + + /* Now backend stuff. */ + if (bed->elf_backend_final_write_processing) + (*bed->elf_backend_final_write_processing) (abfd, NULL); + + if (finfo.contents != NULL) + free (finfo.contents); + if (finfo.external_relocs != NULL) + free (finfo.external_relocs); + if (finfo.internal_relocs != NULL) + free (finfo.internal_relocs); + if (finfo.external_syms != NULL) + free (finfo.external_syms); + if (finfo.internal_syms != NULL) + free (finfo.internal_syms); + if (finfo.indices != NULL) + free (finfo.indices); + if (finfo.sections != NULL) + free (finfo.sections); + if (finfo.symbuf != NULL) + free (finfo.symbuf); + for (o = abfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_RELOC) != 0 + && elf_section_data (o)->rel_hashes != NULL) + free (elf_section_data (o)->rel_hashes); + } + + return true; + + error_return: + if (finfo.contents != NULL) + free (finfo.contents); + if (finfo.external_relocs != NULL) + free (finfo.external_relocs); + if (finfo.internal_relocs != NULL) + free (finfo.internal_relocs); + if (finfo.external_syms != NULL) + free (finfo.external_syms); + if (finfo.internal_syms != NULL) + free (finfo.internal_syms); + if (finfo.indices != NULL) + free (finfo.indices); + if (finfo.sections != NULL) + free (finfo.sections); + if (finfo.symbuf != NULL) + free (finfo.symbuf); + for (o = abfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_RELOC) != 0 + && elf_section_data (o)->rel_hashes != NULL) + free (elf_section_data (o)->rel_hashes); + } + + return false; +} + +/* Add a symbol to the output symbol table. */ + +static boolean +elf_link_output_sym (finfo, name, elfsym, input_sec) + struct elf_final_link_info *finfo; + const char *name; + Elf_Internal_Sym *elfsym; + asection *input_sec; +{ + boolean (*output_symbol_hook) PARAMS ((bfd *, + struct bfd_link_info *info, + const char *, + Elf_Internal_Sym *, + asection *)); + + output_symbol_hook = get_elf_backend_data (finfo->output_bfd)-> + elf_backend_link_output_symbol_hook; + if (output_symbol_hook != NULL) + { + if (! ((*output_symbol_hook) + (finfo->output_bfd, finfo->info, name, elfsym, input_sec))) + return false; + } + + if (name == (const char *) NULL || *name == '\0') + elfsym->st_name = 0; + else + { + elfsym->st_name = bfd_add_to_strtab (finfo->output_bfd, + finfo->symstrtab, name); + if (elfsym->st_name == (unsigned long) -1) + return false; + } + + if (finfo->symbuf_count >= finfo->symbuf_size) + { + if (! elf_link_flush_output_syms (finfo)) + return false; + } + + elf_swap_symbol_out (finfo->output_bfd, elfsym, + finfo->symbuf + finfo->symbuf_count); + ++finfo->symbuf_count; + + ++finfo->output_bfd->symcount; + + return true; +} + +/* Flush the output symbols to the file. */ + +static boolean +elf_link_flush_output_syms (finfo) + struct elf_final_link_info *finfo; +{ + Elf_Internal_Shdr *symtab; + + symtab = &elf_tdata (finfo->output_bfd)->symtab_hdr; + + if (bfd_seek (finfo->output_bfd, symtab->sh_offset + symtab->sh_size, + SEEK_SET) != 0 + || (bfd_write ((PTR) finfo->symbuf, finfo->symbuf_count, + sizeof (Elf_External_Sym), finfo->output_bfd) + != finfo->symbuf_count * sizeof (Elf_External_Sym))) + return false; + + symtab->sh_size += finfo->symbuf_count * sizeof (Elf_External_Sym); + + finfo->symbuf_count = 0; + + return true; +} + +/* Add an external symbol to the symbol table. This is called from + the hash table traversal routine. */ + +static boolean +elf_link_output_extsym (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + struct elf_final_link_info *finfo = (struct elf_final_link_info *) data; + boolean strip; + Elf_Internal_Sym sym; + asection *input_sec; + + /* We don't want to output symbols that have never been mentioned by + a regular file, or that we have been told to strip. However, if + h->indx is set to -2, the symbol is used by a reloc and we must + output it. */ + if (h->indx == -2) + strip = false; + else if (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) + strip = true; + else if (finfo->info->strip == strip_all + || (finfo->info->strip == strip_some + && bfd_hash_lookup (finfo->info->keep_hash, + h->root.root.string, + false, false) == NULL)) + strip = true; + else + strip = false; + + /* If we're stripping it, and it's not a dynamic symbol, there's + nothing else to do. */ + if (strip && h->dynindx == -1) + return true; + + sym.st_value = 0; + sym.st_size = h->size; + sym.st_other = 0; + if (h->root.type == bfd_link_hash_weak + || (h->elf_link_hash_flags & ELF_LINK_HASH_DEFINED_WEAK) != 0) + sym.st_info = ELF_ST_INFO (STB_WEAK, h->type); + else + sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type); + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + abort (); + return false; + + case bfd_link_hash_undefined: + input_sec = bfd_und_section_ptr; + sym.st_shndx = SHN_UNDEF; + break; + + case bfd_link_hash_weak: + input_sec = bfd_und_section_ptr; + sym.st_shndx = SHN_UNDEF; + break; + + case bfd_link_hash_defined: + { + + input_sec = h->root.u.def.section; + if (input_sec->output_section != NULL) + { + sym.st_shndx = elf_section_from_bfd_section (finfo->output_bfd, + input_sec->output_section); + if (sym.st_shndx == (unsigned short) -1) + { + /* FIXME: No way to handle errors. */ + abort (); + } + + /* ELF symbols in relocateable files are section relative, + but in nonrelocateable files they are virtual + addresses. */ + sym.st_value = h->root.u.def.value + input_sec->output_offset; + if (! finfo->info->relocateable) + sym.st_value += input_sec->output_section->vma; + } + else + { + BFD_ASSERT (bfd_get_flavour (input_sec->owner) + == bfd_target_elf_flavour + && elf_elfheader (input_sec->owner)->e_type == ET_DYN); + sym.st_shndx = SHN_UNDEF; + input_sec = bfd_und_section_ptr; + } + } + break; + + case bfd_link_hash_common: + input_sec = bfd_com_section_ptr; + sym.st_shndx = SHN_COMMON; + if (h->align == 0) + sym.st_value = 1; + else + sym.st_value = h->align; + break; + + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + /* I have no idea how these should be handled. */ + return true; + } + + /* If this symbol should be put in the .dynsym section, then put it + there now. We have already know the symbol index. We also fill + in the entry in the .hash section. */ + if (h->dynindx != -1) + { + struct elf_backend_data *bed; + size_t bucketcount; + size_t bucket; + bfd_byte *bucketpos; + bfd_vma chain; + + sym.st_name = h->dynstr_index; + + /* Give the processor backend a chance to tweak the symbol + value, and also to finish up anything that needs to be done + for this symbol. */ + bed = get_elf_backend_data (finfo->output_bfd); + if (! ((*bed->elf_backend_finish_dynamic_symbol) + (finfo->output_bfd, finfo->info, h, &sym))) + { + /* FIXME: No way to return error. */ + abort (); + } + + elf_swap_symbol_out (finfo->output_bfd, &sym, + ((Elf_External_Sym *) finfo->dynsym_sec->contents + + h->dynindx)); + + bucketcount = elf_hash_table (finfo->info)->bucketcount; + bucket = bfd_elf_hash (h->root.root.string) % bucketcount; + bucketpos = ((bfd_byte *) finfo->hash_sec->contents + + (bucket + 2) * (ARCH_SIZE / 8)); + chain = get_word (finfo->output_bfd, bucketpos); + put_word (finfo->output_bfd, h->dynindx, bucketpos); + put_word (finfo->output_bfd, chain, + ((bfd_byte *) finfo->hash_sec->contents + + (bucketcount + 2 + h->dynindx) * (ARCH_SIZE / 8))); + } + + /* If we're stripping it, then it was just a dynamic symbol, and + there's nothing else to do. */ + if (strip) + return true; + + h->indx = finfo->output_bfd->symcount; + + if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec)) + { + /* FIXME: No way to return error. */ + abort (); + } + + return true; +} + +/* Link an input file into the linker output file. This function + handles all the sections and relocations of the input file at once. + This is so that we only have to read the local symbols once, and + don't have to keep them in memory. */ + +static boolean +elf_link_input_bfd (finfo, input_bfd) + struct elf_final_link_info *finfo; + bfd *input_bfd; +{ + boolean (*relocate_section) PARAMS ((bfd *, struct bfd_link_info *, + bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, + Elf_Internal_Sym *, + asection **, char *)); + bfd *output_bfd; + Elf_Internal_Shdr *symtab_hdr; + size_t locsymcount; + size_t extsymoff; + Elf_External_Sym *esym; + Elf_External_Sym *esymend; + Elf_Internal_Sym *isym; + long *pindex; + asection **ppsection; + asection *o; + + output_bfd = finfo->output_bfd; + relocate_section = + get_elf_backend_data (output_bfd)->elf_backend_relocate_section; + + /* If this is a dynamic object, we don't want to do anything here: + we don't want the local symbols, and we don't want the section + contents. */ + if (elf_elfheader (input_bfd)->e_type == ET_DYN) + return true; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + if (elf_bad_symtab (input_bfd)) + { + locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym); + extsymoff = 0; + } + else + { + locsymcount = symtab_hdr->sh_info; + extsymoff = symtab_hdr->sh_info; + } + + /* Read the local symbols. */ + if (locsymcount > 0 + && (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0 + || (bfd_read (finfo->external_syms, sizeof (Elf_External_Sym), + locsymcount, input_bfd) + != locsymcount * sizeof (Elf_External_Sym)))) + return false; + + /* Swap in the local symbols and write out the ones which we know + are going into the output file. */ + esym = finfo->external_syms; + esymend = esym + locsymcount; + isym = finfo->internal_syms; + pindex = finfo->indices; + ppsection = finfo->sections; + for (; esym < esymend; esym++, isym++, pindex++, ppsection++) + { + asection *isec; + const char *name; + bfd_vma oldval; + + elf_swap_symbol_in (input_bfd, esym, isym); + *pindex = -1; + + if (elf_bad_symtab (input_bfd)) + { + if (ELF_ST_BIND (isym->st_info) != STB_LOCAL) + { + *ppsection = NULL; + continue; + } + } + + if (isym->st_shndx == SHN_UNDEF) + isec = bfd_und_section_ptr; + else if (isym->st_shndx > 0 && isym->st_shndx < SHN_LORESERVE) + { + isec = section_from_elf_index (input_bfd, isym->st_shndx); + if (isec == NULL) + return false; + } + else if (isym->st_shndx == SHN_ABS) + isec = bfd_abs_section_ptr; + else if (isym->st_shndx == SHN_COMMON) + isec = bfd_com_section_ptr; + else + { + /* Who knows? */ + isec = NULL; + } + + *ppsection = isec; + + /* Don't output the first, undefined, symbol. */ + if (esym == finfo->external_syms) + continue; + + /* If we are stripping all symbols, we don't want to output this + one. */ + if (finfo->info->strip == strip_all) + continue; + + /* We never output section symbols. Instead, we use the section + symbol of the corresponding section in the output file. */ + if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) + continue; + + /* If we are discarding all local symbols, we don't want to + output this one. If we are generating a relocateable output + file, then some of the local symbols may be required by + relocs; we output them below as we discover that they are + needed. */ + if (finfo->info->discard == discard_all) + continue; + + /* Get the name of the symbol. */ + name = elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link, + isym->st_name); + if (name == NULL) + return false; + + /* See if we are discarding symbols with this name. */ + if ((finfo->info->strip == strip_some + && (bfd_hash_lookup (finfo->info->keep_hash, name, false, false) + == NULL)) + || (finfo->info->discard == discard_l + && strncmp (name, finfo->info->lprefix, + finfo->info->lprefix_len) == 0)) + continue; + + /* If we get here, we are going to output this symbol. */ + + /* Adjust the section index for the output file. */ + isym->st_shndx = elf_section_from_bfd_section (output_bfd, + isec->output_section); + if (isym->st_shndx == (unsigned short) -1) + return false; + + *pindex = output_bfd->symcount; + + /* ELF symbols in relocateable files are section relative, but + in executable files they are virtual addresses. Note that + this code assumes that all ELF sections have an associated + BFD section with a reasonable value for output_offset; below + we assume that they also have a reasonable value for + output_section. Any special sections must be set up to meet + these requirements. */ + oldval = isym->st_value; + isym->st_value += isec->output_offset; + if (! finfo->info->relocateable) + isym->st_value += isec->output_section->vma; + + if (! elf_link_output_sym (finfo, name, isym, isec)) + return false; + + /* Restore the old value for reloc handling. */ + isym->st_value = oldval; + } + + /* Relocate the contents of each section. */ + for (o = input_bfd->sections; o != NULL; o = o->next) + { + Elf_Internal_Shdr *input_rel_hdr; + + if ((o->flags & SEC_HAS_CONTENTS) == 0) + continue; + + if ((o->flags & SEC_IN_MEMORY) != 0 + && input_bfd == elf_hash_table (finfo->info)->dynobj) + { + /* Section was created by elf_link_create_dynamic_sections. + FIXME: This test is fragile. */ + continue; + } + + /* Read the contents of the section. */ + if (! bfd_get_section_contents (input_bfd, o, finfo->contents, + (file_ptr) 0, o->_raw_size)) + return false; + + if ((o->flags & SEC_RELOC) != 0) + { + PTR external_relocs; + + /* Get the external relocs. They may have been cached. */ + external_relocs = elf_section_data (o)->relocs; + if (external_relocs == NULL) + { + input_rel_hdr = &elf_section_data (o)->rel_hdr; + if ((bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET) + != 0) + || (bfd_read (finfo->external_relocs, 1, + input_rel_hdr->sh_size, input_bfd) + != input_rel_hdr->sh_size)) + return false; + external_relocs = finfo->external_relocs; + } + + /* Swap in the relocs. For convenience, we always produce + an Elf_Internal_Rela array; if the relocs are Rel, we set + the addend to 0. */ + if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) + { + Elf_External_Rel *erel; + Elf_External_Rel *erelend; + Elf_Internal_Rela *irela; + + erel = (Elf_External_Rel *) external_relocs; + erelend = erel + o->reloc_count; + irela = finfo->internal_relocs; + for (; erel < erelend; erel++, irela++) + { + Elf_Internal_Rel irel; + + elf_swap_reloc_in (input_bfd, erel, &irel); + irela->r_offset = irel.r_offset; + irela->r_info = irel.r_info; + irela->r_addend = 0; + } + } + else + { + Elf_External_Rela *erela; + Elf_External_Rela *erelaend; + Elf_Internal_Rela *irela; + + BFD_ASSERT (input_rel_hdr->sh_entsize + == sizeof (Elf_External_Rela)); + + erela = (Elf_External_Rela *) external_relocs; + erelaend = erela + o->reloc_count; + irela = finfo->internal_relocs; + for (; erela < erelaend; erela++, irela++) + elf_swap_reloca_in (input_bfd, erela, irela); + } + + /* Relocate the section by invoking a back end routine. + + The back end routine is responsible for adjusting the + section contents as necessary, and (if using Rela relocs + and generating a relocateable output file) adjusting the + reloc addend as necessary. + + The back end routine does not have to worry about setting + the reloc address or the reloc symbol index. + + The back end routine is given a pointer to the swapped in + internal symbols, and can access the hash table entries + for the external symbols via elf_sym_hashes (input_bfd). + + When generating relocateable output, the back end routine + must handle STB_LOCAL/STT_SECTION symbols specially. The + output symbol is going to be a section symbol + corresponding to the output section, which will require + the addend to be adjusted. */ + + if (! (*relocate_section) (output_bfd, finfo->info, + input_bfd, o, + finfo->contents, + finfo->internal_relocs, + finfo->internal_syms, + finfo->sections, + finfo->symstrtab->tab)) + return false; + + if (finfo->info->relocateable) + { + Elf_Internal_Rela *irela; + Elf_Internal_Rela *irelaend; + struct elf_link_hash_entry **rel_hash; + Elf_Internal_Shdr *output_rel_hdr; + + /* Adjust the reloc addresses and symbol indices. */ + + irela = finfo->internal_relocs; + irelaend = irela + o->reloc_count; + rel_hash = (elf_section_data (o->output_section)->rel_hashes + + o->output_section->reloc_count); + for (; irela < irelaend; irela++, rel_hash++) + { + long r_symndx; + Elf_Internal_Sym *isym; + asection *sec; + + irela->r_offset += o->output_offset; + + r_symndx = ELF_R_SYM (irela->r_info); + + if (r_symndx == 0) + continue; + + if (r_symndx >= locsymcount + || (elf_bad_symtab (input_bfd) + && finfo->sections[r_symndx] == NULL)) + { + long indx; + + /* This is a reloc against a global symbol. We + have not yet output all the local symbols, so + we do not know the symbol index of any global + symbol. We set the rel_hash entry for this + reloc to point to the global hash table entry + for this symbol. The symbol index is then + set at the end of elf_bfd_final_link. */ + indx = r_symndx - extsymoff; + *rel_hash = elf_sym_hashes (input_bfd)[indx]; + + /* Setting the index to -2 tells + elf_link_output_extsym that this symbol is + used by a reloc. */ + BFD_ASSERT ((*rel_hash)->indx < 0); + (*rel_hash)->indx = -2; + + continue; + } + + /* This is a reloc against a local symbol. */ + + *rel_hash = NULL; + isym = finfo->internal_syms + r_symndx; + sec = finfo->sections[r_symndx]; + if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) + { + /* I suppose the backend ought to fill in the + section of any STT_SECTION symbol against a + processor specific section. */ + if (sec != NULL && bfd_is_abs_section (sec)) + r_symndx = 0; + else if (sec == NULL || sec->owner == NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + else + { + r_symndx = sec->output_section->target_index; + if (r_symndx == 0) + abort (); + } + } + else + { + if (finfo->indices[r_symndx] == -1) + { + unsigned long link; + const char *name; + asection *osec; + + if (finfo->info->strip == strip_all) + { + /* You can't do ld -r -s. */ + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + /* This symbol was skipped earlier, but + since it is needed by a reloc, we + must output it now. */ + link = symtab_hdr->sh_link; + name = elf_string_from_elf_section (input_bfd, + link, + isym->st_name); + if (name == NULL) + return false; + + osec = sec->output_section; + isym->st_shndx = + elf_section_from_bfd_section (output_bfd, + osec); + if (isym->st_shndx == (unsigned short) -1) + return false; + + isym->st_value += sec->output_offset; + if (! finfo->info->relocateable) + isym->st_value += osec->vma; + + finfo->indices[r_symndx] = output_bfd->symcount; + + if (! elf_link_output_sym (finfo, name, isym, sec)) + return false; + } + + r_symndx = finfo->indices[r_symndx]; + } + + irela->r_info = ELF_R_INFO (r_symndx, + ELF_R_TYPE (irela->r_info)); + } + + /* Swap out the relocs. */ + output_rel_hdr = &elf_section_data (o->output_section)->rel_hdr; + BFD_ASSERT (output_rel_hdr->sh_entsize + == input_rel_hdr->sh_entsize); + irela = finfo->internal_relocs; + irelaend = irela + o->reloc_count; + if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) + { + Elf_External_Rel *erel; + + erel = ((Elf_External_Rel *) output_rel_hdr->contents + + o->output_section->reloc_count); + for (; irela < irelaend; irela++, erel++) + { + Elf_Internal_Rel irel; + + irel.r_offset = irela->r_offset; + irel.r_info = irela->r_info; + BFD_ASSERT (irela->r_addend == 0); + elf_swap_reloc_out (output_bfd, &irel, erel); + } + } + else + { + Elf_External_Rela *erela; + + BFD_ASSERT (input_rel_hdr->sh_entsize + == sizeof (Elf_External_Rela)); + erela = ((Elf_External_Rela *) output_rel_hdr->contents + + o->output_section->reloc_count); + for (; irela < irelaend; irela++, erela++) + elf_swap_reloca_out (output_bfd, irela, erela); + } + + o->output_section->reloc_count += o->reloc_count; + } + } + + /* Write out the modified section contents. */ + if (! bfd_set_section_contents (output_bfd, o->output_section, + finfo->contents, o->output_offset, + (o->_cooked_size != 0 + ? o->_cooked_size + : o->_raw_size))) + return false; + } + + return true; +} + +/* Generate a reloc when linking an ELF file. This is a reloc + requested by the linker, and does come from any input file. This + is used to build constructor and destructor tables when linking + with -Ur. */ + +static boolean +elf_reloc_link_order (output_bfd, info, output_section, link_order) + bfd *output_bfd; + struct bfd_link_info *info; + asection *output_section; + struct bfd_link_order *link_order; +{ + const reloc_howto_type *howto; + long indx; + bfd_vma offset; + struct elf_link_hash_entry **rel_hash_ptr; + Elf_Internal_Shdr *rel_hdr; + + howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); + if (howto == NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* If this is an inplace reloc, we must write the addend into the + object file. */ + if (howto->partial_inplace + && link_order->u.reloc.p->addend != 0) + { + bfd_size_type size; + bfd_reloc_status_type rstat; + bfd_byte *buf; + boolean ok; + + size = bfd_get_reloc_size (howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == (bfd_byte *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + rstat = _bfd_relocate_contents (howto, output_bfd, + link_order->u.reloc.p->addend, buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*info->callbacks->reloc_overflow) + (info, + (link_order->type == bfd_section_reloc_link_order + ? bfd_section_name (output_bfd, + link_order->u.reloc.p->u.section) + : link_order->u.reloc.p->u.name), + howto->name, link_order->u.reloc.p->addend, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + { + free (buf); + return false; + } + break; + } + ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf, + (file_ptr) link_order->offset, size); + free (buf); + if (! ok) + return false; + } + + /* Figure out the symbol index. */ + rel_hash_ptr = (elf_section_data (output_section)->rel_hashes + + output_section->reloc_count); + if (link_order->type == bfd_section_reloc_link_order) + { + indx = link_order->u.reloc.p->u.section->target_index; + if (indx == 0) + abort (); + *rel_hash_ptr = NULL; + } + else + { + struct elf_link_hash_entry *h; + + h = elf_link_hash_lookup (elf_hash_table (info), + link_order->u.reloc.p->u.name, + false, false, true); + if (h != NULL) + { + /* Setting the index to -2 tells elf_link_output_extsym that + this symbol is used by a reloc. */ + h->indx = -2; + *rel_hash_ptr = h; + indx = 0; + } + else + { + if (! ((*info->callbacks->unattached_reloc) + (info, link_order->u.reloc.p->u.name, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + return false; + indx = 0; + } + } + + /* The address of a reloc is relative to the section in a + relocateable file, and is a virtual address in an executable + file. */ + offset = link_order->offset; + if (! info->relocateable) + offset += output_section->vma; + + rel_hdr = &elf_section_data (output_section)->rel_hdr; + + if (rel_hdr->sh_type == SHT_REL) + { + Elf_Internal_Rel irel; + Elf_External_Rel *erel; + + irel.r_offset = offset; + irel.r_info = ELF_R_INFO (indx, howto->type); + erel = ((Elf_External_Rel *) rel_hdr->contents + + output_section->reloc_count); + elf_swap_reloc_out (output_bfd, &irel, erel); + } + else + { + Elf_Internal_Rela irela; + Elf_External_Rela *erela; + + irela.r_offset = offset; + irela.r_info = ELF_R_INFO (indx, howto->type); + irela.r_addend = link_order->u.reloc.p->addend; + erela = ((Elf_External_Rela *) rel_hdr->contents + + output_section->reloc_count); + elf_swap_reloca_out (output_bfd, &irela, erela); + } + + ++output_section->reloc_count; + + return true; +} diff --git a/gnu/usr.bin/gdb/bfd/genlink.h b/gnu/usr.bin/gdb/bfd/genlink.h new file mode 100644 index 00000000000..06f6bfc629c --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/genlink.h @@ -0,0 +1,106 @@ +/* genlink.h -- interface to the BFD generic linker + Copyright 1993, 1994 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. */ + +#ifndef GENLINK_H +#define GENLINK_H + +/* This header file is internal to BFD. It describes the internal + structures and functions used by the BFD generic linker, in case + any of the more specific linkers want to use or call them. Note + that some functions, such as _bfd_generic_link_hash_table_create, + are declared in libbfd.h, because they are expected to be widely + used. The functions and structures in this file will probably only + be used by a few files besides linker.c itself. In fact, this file + is not particularly complete; I have only put in the interfaces I + actually needed. */ + +/* The generic linker uses a hash table which is a derived class of + the standard linker hash table, just as the other backend specific + linkers do. Do not confuse the generic linker hash table with the + standard BFD linker hash table it is built upon. */ + +/* Generic linker hash table entries. */ + +struct generic_link_hash_entry +{ + struct bfd_link_hash_entry root; + /* Whether this symbol has been written out. */ + boolean written; + /* Symbol from input BFD. */ + asymbol *sym; +}; + +/* Generic linker hash table. */ + +struct generic_link_hash_table +{ + struct bfd_link_hash_table root; +}; + +/* Look up an entry in an generic link hash table. */ + +#define _bfd_generic_link_hash_lookup(table, string, create, copy, follow) \ + ((struct generic_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) + +/* Traverse an generic link hash table. */ + +#define _bfd_generic_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the generic link hash table from the info structure. This is + just a cast. */ + +#define _bfd_generic_hash_table(p) \ + ((struct generic_link_hash_table *) ((p)->hash)) + +/* The generic linker reads in the asymbol structures for an input BFD + and keeps them in the outsymbol and symcount fields. */ + +#define _bfd_generic_link_get_symbols(abfd) ((abfd)->outsymbols) +#define _bfd_generic_link_get_symcount(abfd) ((abfd)->symcount) + +/* Add the symbols of input_bfd to the symbols being built for + output_bfd. */ +extern boolean _bfd_generic_link_output_symbols + PARAMS ((bfd *output_bfd, bfd *input_bfd, struct bfd_link_info *, + size_t *psymalloc)); + +/* This structure is used to pass information to + _bfd_generic_link_write_global_symbol, which may be called via + _bfd_generic_link_hash_traverse. */ + +struct generic_write_global_symbol_info +{ + struct bfd_link_info *info; + bfd *output_bfd; + size_t *psymalloc; +}; + +/* Write out a single global symbol. This is expected to be called + via _bfd_generic_link_hash_traverse. The second argument must + actually be a struct generic_write_global_symbol_info *. */ +extern boolean _bfd_generic_link_write_global_symbol + PARAMS ((struct generic_link_hash_entry *, PTR)); + +#endif diff --git a/gnu/usr.bin/gdb/bfd/hash.c b/gnu/usr.bin/gdb/bfd/hash.c new file mode 100644 index 00000000000..cb11c2380e4 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/hash.c @@ -0,0 +1,470 @@ +/* hash.c -- hash table routines for BFD + Copyright (C) 1993, 94 Free Software Foundation, Inc. + Written by Steve Chamberlain + +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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "obstack.h" + +/* +SECTION + Hash Tables + +@cindex Hash tables + BFD provides a simple set of hash table functions. Routines + are provided to initialize a hash table, to free a hash table, + to look up a string in a hash table and optionally create an + entry for it, and to traverse a hash table. There is + currently no routine to delete an string from a hash table. + + The basic hash table does not permit any data to be stored + with a string. However, a hash table is designed to present a + base class from which other types of hash tables may be + derived. These derived types may store additional information + with the string. Hash tables were implemented in this way, + rather than simply providing a data pointer in a hash table + entry, because they were designed for use by the linker back + ends. The linker may create thousands of hash table entries, + and the overhead of allocating private data and storing and + following pointers becomes noticeable. + + The basic hash table code is in <>. + +@menu +@* Creating and Freeing a Hash Table:: +@* Looking Up or Entering a String:: +@* Traversing a Hash Table:: +@* Deriving a New Hash Table Type:: +@end menu + +INODE +Creating and Freeing a Hash Table, Looking Up or Entering a String, Hash Tables, Hash Tables +SUBSECTION + Creating and freeing a hash table + +@findex bfd_hash_table_init +@findex bfd_hash_table_init_n + To create a hash table, create an instance of a <> (defined in <>) and call + <> (if you know approximately how many + entries you will need, the function <>, + which takes a @var{size} argument, may be used). + <> returns <> if some sort of + error occurs. + +@findex bfd_hash_newfunc + The function <> take as an argument a + function to use to create new entries. For a basic hash + table, use the function <>. @xref{Deriving + a New Hash Table Type} for why you would want to use a + different value for this argument. + +@findex bfd_hash_allocate + <> will create an obstack which will be + used to allocate new entries. You may allocate memory on this + obstack using <>. + +@findex bfd_hash_table_free + Use <> to free up all the memory that has + been allocated for a hash table. This will not free up the + <> itself, which you must provide. + +INODE +Looking Up or Entering a String, Traversing a Hash Table, Creating and Freeing a Hash Table, Hash Tables +SUBSECTION + Looking up or entering a string + +@findex bfd_hash_lookup + The function <> is used both to look up a + string in the hash table and to create a new entry. + + If the @var{create} argument is <>, <> + will look up a string. If the string is found, it will + returns a pointer to a <>. If the + string is not found in the table <> will + return <>. You should not modify any of the fields in + the returns <>. + + If the @var{create} argument is <>, the string will be + entered into the hash table if it is not already there. + Either way a pointer to a <> will be + returned, either to the existing structure or to a newly + created one. In this case, a <> return means that an + error occurred. + + If the @var{create} argument is <>, and a new entry is + created, the @var{copy} argument is used to decide whether to + copy the string onto the hash table obstack or not. If + @var{copy} is passed as <>, you must be careful not to + deallocate or modify the string as long as the hash table + exists. + +INODE +Traversing a Hash Table, Deriving a New Hash Table Type, Looking Up or Entering a String, Hash Tables +SUBSECTION + Traversing a hash table + +@findex bfd_hash_traverse + The function <> may be used to traverse a + hash table, calling a function on each element. The traversal + is done in a random order. + + <> takes as arguments a function and a + generic <> pointer. The function is called with a + hash table entry (a <>) and the + generic pointer passed to <>. The function + must return a <> value, which indicates whether to + continue traversing the hash table. If the function returns + <>, <> will stop the traversal and + return immediately. + +INODE +Deriving a New Hash Table Type, , Traversing a Hash Table, Hash Tables +SUBSECTION + Deriving a new hash table type + + Many uses of hash tables want to store additional information + which each entry in the hash table. Some also find it + convenient to store additional information with the hash table + itself. This may be done using a derived hash table. + + Since C is not an object oriented language, creating a derived + hash table requires sticking together some boilerplate + routines with a few differences specific to the type of hash + table you want to create. + + An example of a derived hash table is the linker hash table. + The structures for this are defined in <>. The + functions are in <>. + + You may also derive a hash table from an already derived hash + table. For example, the a.out linker backend code uses a hash + table derived from the linker hash table. + +@menu +@* Define the Derived Structures:: +@* Write the Derived Creation Routine:: +@* Write Other Derived Routines:: +@end menu + +INODE +Define the Derived Structures, Write the Derived Creation Routine, Deriving a New Hash Table Type, Deriving a New Hash Table Type +SUBSUBSECTION + Define the derived structures + + You must define a structure for an entry in the hash table, + and a structure for the hash table itself. + + The first field in the structure for an entry in the hash + table must be of the type used for an entry in the hash table + you are deriving from. If you are deriving from a basic hash + table this is <>, which is defined in + <>. The first field in the structure for the hash + table itself must be of the type of the hash table you are + deriving from itself. If you are deriving from a basic hash + table, this is <>. + + For example, the linker hash table defines <> (in <>). The first field, + <>, is of type <>. Similarly, + the first field in <>, <>, + is of type <>. + +INODE +Write the Derived Creation Routine, Write Other Derived Routines, Define the Derived Structures, Deriving a New Hash Table Type +SUBSUBSECTION + Write the derived creation routine + + You must write a routine which will create and initialize an + entry in the hash table. This routine is passed as the + function argument to <>. + + In order to permit other hash tables to be derived from the + hash table you are creating, this routine must be written in a + standard way. + + The first argument to the creation routine is a pointer to a + hash table entry. This may be <>, in which case the + routine should allocate the right amount of space. Otherwise + the space has already been allocated by a hash table type + derived from this one. + + After allocating space, the creation routine must call the + creation routine of the hash table type it is derived from, + passing in a pointer to the space it just allocated. This + will initialize any fields used by the base hash table. + + Finally the creation routine must initialize any local fields + for the new hash table type. + + Here is a boilerplate example of a creation routine. + @var{function_name} is the name of the routine. + @var{entry_type} is the type of an entry in the hash table you + are creating. @var{base_newfunc} is the name of the creation + routine of the hash table type your hash table is derived + from. + +EXAMPLE + +.struct bfd_hash_entry * +.@var{function_name} (entry, table, string) +. struct bfd_hash_entry *entry; +. struct bfd_hash_table *table; +. const char *string; +.{ +. struct @var{entry_type} *ret = (@var{entry_type} *) entry; +. +. {* Allocate the structure if it has not already been allocated by a +. derived class. *} +. if (ret == (@var{entry_type} *) NULL) +. { +. ret = ((@var{entry_type} *) +. bfd_hash_allocate (table, sizeof (@var{entry_type}))); +. if (ret == (@var{entry_type} *) NULL) +. return NULL; +. } +. +. {* Call the allocation method of the base class. *} +. ret = ((@var{entry_type} *) +. @var{base_newfunc} ((struct bfd_hash_entry *) ret, table, string)); +. +. {* Initialize the local fields here. *} +. +. return (struct bfd_hash_entry *) ret; +.} + +DESCRIPTION + The creation routine for the linker hash table, which is in + <>, looks just like this example. + @var{function_name} is <<_bfd_link_hash_newfunc>>. + @var{entry_type} is <>. + @var{base_newfunc} is <>, the creation + routine for a basic hash table. + + <<_bfd_link_hash_newfunc>> also initializes the local fields + in a linker hash table entry: <>, <> and + <>. + +INODE +Write Other Derived Routines, , Write the Derived Creation Routine, Deriving a New Hash Table Type +SUBSUBSECTION + Write other derived routines + + You will want to write other routines for your new hash table, + as well. + + You will want an initialization routine which calls the + initialization routine of the hash table you are deriving from + and initializes any other local fields. For the linker hash + table, this is <<_bfd_link_hash_table_init>> in <>. + + You will want a lookup routine which calls the lookup routine + of the hash table you are deriving from and casts the result. + The linker hash table uses <> in + <> (this actually takes an additional argument which + it uses to decide how to return the looked up value). + + You may want a traversal routine. This should just call the + traversal routine of the hash table you are deriving from with + appropriate casts. The linker hash table uses + <> in <>. + + These routines may simply be defined as macros. For example, + the a.out backend linker hash table, which is derived from the + linker hash table, uses macros for the lookup and traversal + routines. These are <> and + <> in aoutx.h. +*/ + +/* Obstack allocation and deallocation routines. */ +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free + +/* The default number of entries to use when creating a hash table. */ +#define DEFAULT_SIZE (4051) + +/* Create a new hash table, given a number of entries. */ + +boolean +bfd_hash_table_init_n (table, newfunc, size) + struct bfd_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); + unsigned int size; +{ + unsigned int alloc; + + alloc = size * sizeof (struct bfd_hash_entry *); + if (!obstack_begin (&table->memory, alloc)) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + table->table = ((struct bfd_hash_entry **) + obstack_alloc (&table->memory, alloc)); + if (!table->table) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + memset ((PTR) table->table, 0, alloc); + table->size = size; + table->newfunc = newfunc; + return true; +} + +/* Create a new hash table with the default number of entries. */ + +boolean +bfd_hash_table_init (table, newfunc) + struct bfd_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return bfd_hash_table_init_n (table, newfunc, DEFAULT_SIZE); +} + +/* Free a hash table. */ + +void +bfd_hash_table_free (table) + struct bfd_hash_table *table; +{ + obstack_free (&table->memory, (PTR) NULL); +} + +/* Look up a string in a hash table. */ + +struct bfd_hash_entry * +bfd_hash_lookup (table, string, create, copy) + struct bfd_hash_table *table; + const char *string; + boolean create; + boolean copy; +{ + register const unsigned char *s; + register unsigned long hash; + register unsigned int c; + struct bfd_hash_entry *hashp; + unsigned int len; + unsigned int index; + + hash = 0; + len = 0; + s = (const unsigned char *) string; + while ((c = *s++) != '\0') + { + hash += c + (c << 17); + hash ^= hash >> 2; + ++len; + } + hash += len + (len << 17); + hash ^= hash >> 2; + + index = hash % table->size; + for (hashp = table->table[index]; + hashp != (struct bfd_hash_entry *) NULL; + hashp = hashp->next) + { + if (hashp->hash == hash + && strcmp (hashp->string, string) == 0) + return hashp; + } + + if (! create) + return (struct bfd_hash_entry *) NULL; + + hashp = (*table->newfunc) ((struct bfd_hash_entry *) NULL, table, string); + if (hashp == (struct bfd_hash_entry *) NULL) + return (struct bfd_hash_entry *) NULL; + if (copy) + { + char *new; + + new = (char *) obstack_alloc (&table->memory, len + 1); + if (!new) + { + bfd_set_error (bfd_error_no_memory); + return (struct bfd_hash_entry *) NULL; + } + strcpy (new, string); + string = new; + } + hashp->string = string; + hashp->hash = hash; + hashp->next = table->table[index]; + table->table[index] = hashp; + + return hashp; +} + +/* Base method for creating a new hash table entry. */ + +/*ARGSUSED*/ +struct bfd_hash_entry * +bfd_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + if (entry == (struct bfd_hash_entry *) NULL) + entry = ((struct bfd_hash_entry *) + bfd_hash_allocate (table, sizeof (struct bfd_hash_entry))); + return entry; +} + +/* Allocate space in a hash table. */ + +PTR +bfd_hash_allocate (table, size) + struct bfd_hash_table *table; + unsigned int size; +{ + PTR ret; + + ret = obstack_alloc (&table->memory, size); + if (ret == NULL && size != 0) + bfd_set_error (bfd_error_no_memory); + return ret; +} + +/* Traverse a hash table. */ + +void +bfd_hash_traverse (table, func, info) + struct bfd_hash_table *table; + boolean (*func) PARAMS ((struct bfd_hash_entry *, PTR)); + PTR info; +{ + unsigned int i; + + for (i = 0; i < table->size; i++) + { + struct bfd_hash_entry *p; + + for (p = table->table[i]; p != NULL; p = p->next) + { + if (! (*func) (p, info)) + return; + } + } +} diff --git a/gnu/usr.bin/gdb/bfd/i386aout.c b/gnu/usr.bin/gdb/bfd/i386aout.c new file mode 100644 index 00000000000..0771fb0e245 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/i386aout.c @@ -0,0 +1,68 @@ +/* BFD back-end for i386 a.out binaries. + Copyright 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. */ + + +/* The only 386 aout system we have here is GO32 from DJ. + These numbers make BFD work with that. If your aout 386 system + doesn't work with these, we'll have to split them into different + files. Send me (sac@cygnus.com) the runes to make it work on your + system, and I'll stick it in for the next release. */ + +#define N_HEADER_IN_TEXT(x) 0 +#define BYTES_IN_WORD 4 + +#define N_TXTOFF(x) 0x20 +#define N_TXTADDR(x) (N_MAGIC(x)==ZMAGIC ? 0x1020 : 0) + +#define N_TXTSIZE(x) ((x).a_text) +#if 0 +#define N_DATADDR(x) (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+(x).a_text) : (SEGMENT_SIZE + ((0x1020+(x).a_text-1) & ~(SEGMENT_SIZE-1)))) +#define NOSUBEXECB + +#endif +#define PAGE_SIZE 4096 +#define SEGMENT_SIZE 0x400000 +#define DEFAULT_ARCH bfd_arch_i386 + +#define MY(OP) CAT(i386aout_,OP) +#define TARGETNAME "a.out-i386" +#define NO_WRITE_HEADER_KLUDGE 1 + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libaout.h" +static boolean MY(set_sizes)(); +#define MY_backend_data &MY(backend_data) +static CONST struct aout_backend_data MY(backend_data) = { + 0, /* zmagic contiguous */ + 1, /* text incl header */ + 0, /* exec_hdr_flags */ + 0, /* text vma? */ + MY(set_sizes), + 1, /* exec header not counted */ + 0, /* add_dynamic_symbols */ + 0, /* add_one_symbol */ + 0, /* link_dynamic_object */ + 0, /* write_dynamic_symbol */ + 0, /* check_dynamic_reloc */ + 0 /* finish_dynamic_link */ +}; + +#include "aout-target.h" diff --git a/gnu/usr.bin/gdb/bfd/linker.c b/gnu/usr.bin/gdb/bfd/linker.c new file mode 100644 index 00000000000..d8275b5a0b5 --- /dev/null +++ b/gnu/usr.bin/gdb/bfd/linker.c @@ -0,0 +1,2442 @@ +/* linker.c -- BFD linker routines + Copyright (C) 1993, 94 Free Software Foundation, Inc. + Written by Steve Chamberlain and 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. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "genlink.h" + +/* +SECTION + Linker Functions + +@cindex Linker + The linker uses three special entry points in the BFD target + vector. It is not necessary to write special routines for + these entry points when creating a new BFD back end, since + generic versions are provided. However, writing them can + speed up linking and make it use significantly less runtime + memory. + + The first routine creates a hash table used by the other + routines. The second routine adds the symbols from an object + file to the hash table. The third routine takes all the + object files and links them together to create the output + file. These routines are designed so that the linker proper + does not need to know anything about the symbols in the object + files that it is linking. The linker merely arranges the + sections as directed by the linker script and lets BFD handle + the details of symbols and relocs. + + The second routine and third routines are passed a pointer to + a <> structure (defined in + <>) which holds information relevant to the link, + including the linker hash table (which was created by the + first routine) and a set of callback functions to the linker + proper. + + The generic linker routines are in <>, and use the + header file <>. As of this writing, the only back + ends which have implemented versions of these routines are + a.out (in <>) and ECOFF (in <>). The a.out + routines are used as examples throughout this section. + +@menu +@* Creating a Linker Hash Table:: +@* Adding Symbols to the Hash Table:: +@* Performing the Final Link:: +@end menu + +INODE +Creating a Linker Hash Table, Adding Symbols to the Hash Table, Linker Functions, Linker Functions +SUBSECTION + Creating a linker hash table + +@cindex _bfd_link_hash_table_create in target vector +@cindex target vector (_bfd_link_hash_table_create) + The linker routines must create a hash table, which must be + derived from <> described in + <>. @xref{Hash Tables} for information on how to + create a derived hash table. This entry point is called using + the target vector of the linker output file. + + The <<_bfd_link_hash_table_create>> entry point must allocate + and initialize an instance of the desired hash table. If the + back end does not require any additional information to be + stored with the entries in the hash table, the entry point may + simply create a <>. Most likely, + however, some additional information will be needed. + + For example, with each entry in the hash table the a.out + linker keeps the index the symbol has in the final output file + (this index number is used so that when doing a relocateable + link the symbol index used in the output file can be quickly + filled in when copying over a reloc). The a.out linker code + defines the required structures and functions for a hash table + derived from <>. The a.out linker + hash table is created by the function + <>; it simply allocates + space for the hash table, initializes it, and returns a + pointer to it. + + When writing the linker routines for a new back end, you will + generally not know exactly which fields will be required until + you have finished. You should simply create a new hash table + which defines no additional fields, and then simply add fields + as they become necessary. + +INODE +Adding Symbols to the Hash Table, Performing the Final Link, Creating a Linker Hash Table, Linker Functions +SUBSECTION + Adding symbols to the hash table + +@cindex _bfd_link_add_symbols in target vector +@cindex target vector (_bfd_link_add_symbols) + The linker proper will call the <<_bfd_link_add_symbols>> + entry point for each object file or archive which is to be + linked (typically these are the files named on the command + line, but some may also come from the linker script). The + entry point is responsible for examining the file. For an + object file, BFD must add any relevant symbol information to + the hash table. For an archive, BFD must determine which + elements of the archive should be used and adding them to the + link. + + The a.out version of this entry point is + <>. + +@menu +@* Differing file formats:: +@* Adding symbols from an object file:: +@* Adding symbols from an archive:: +@end menu + +INODE +Differing file formats, Adding symbols from an object file, Adding Symbols to the Hash Table, Adding Symbols to the Hash Table +SUBSUBSECTION + Differing file formats + + Normally all the files involved in a link will be of the same + format, but it is also possible to link together different + format object files, and the back end must support that. The + <<_bfd_link_add_symbols>> entry point is called via the target + vector of the file to be added. This has an important + consequence: the function may not assume that the hash table + is the type created by the corresponding + <<_bfd_link_hash_table_create>> vector. All the + <<_bfd_link_add_symbols>> function can assume about the hash + table is that it is derived from <>. + + Sometimes the <<_bfd_link_add_symbols>> function must store + some information in the hash table entry to be used by the + <<_bfd_final_link>> function. In such a case the <> + field of the hash table must be checked to make sure that the + hash table was created by an object file of the same format. + + The <<_bfd_final_link>> routine must be prepared to handle a + hash entry without any extra information added by the + <<_bfd_link_add_symbols>> function. A hash entry without + extra information will also occur when the linker script + directs the linker to create a symbol. Note that, regardless + of how a hash table entry is added, all the fields will be + initialized to some sort of null value by the hash table entry + initialization function. + + See <> for an example of how to + check the <> field before saving information (in this + case, the ECOFF external symbol debugging information) in a + hash table entry. + +INODE +Adding symbols from an object file, Adding symbols from an archive, Differing file formats, Adding Symbols to the Hash Table +SUBSUBSECTION + Adding symbols from an object file + + When the <<_bfd_link_add_symbols>> routine is passed an object + file, it must add all externally visible symbols in that + object file to the hash table. The actual work of adding the + symbol to the hash table is normally handled by the function + <<_bfd_generic_link_add_one_symbol>>. The + <<_bfd_link_add_symbols>> routine is responsible for reading + all the symbols from the object file and passing the correct + information to <<_bfd_generic_link_add_one_symbol>>. + + The <<_bfd_link_add_symbols>> routine should not use + <> to read the symbols. The point of + providing this routine is to avoid the overhead of converting + the symbols into generic <> structures. + +@findex _bfd_generic_link_add_one_symbol + <<_bfd_generic_link_add_one_symbol>> handles the details of + combining common symbols, warning about multiple definitions, + and so forth. It takes arguments which describe the symbol to + add, notably symbol flags, a section, and an offset. The + symbol flags include such things as <> or + <>. The section is a section in the object + file, or something like <> for an undefined + symbol or <> for a common symbol. + + If the <<_bfd_final_link>> routine is also going to need to + read the symbol information, the <<_bfd_link_add_symbols>> + routine should save it somewhere attached to the object file + BFD. However, the information should only be saved if the + <> field of the <> argument is true, so + that the <<-no-keep-memory>> linker switch is effective. + + The a.out function which adds symbols from an object file is + <>, and most of the interesting + work is in <>. The latter saves + pointers to the hash tables entries created by + <<_bfd_generic_link_add_one_symbol>> indexed by symbol number, + so that the <<_bfd_final_link>> routine does not have to call + the hash table lookup routine to locate the entry. + +INODE +Adding symbols from an archive, , Adding symbols from an object file, Adding Symbols to the Hash Table +SUBSUBSECTION + Adding symbols from an archive + + When the <<_bfd_link_add_symbols>> routine is passed an + archive, it must look through the symbols defined by the + archive and decide which elements of the archive should be + included in the link. For each such element it must call the + <> linker callback, and it must add the + symbols from the object file to the linker hash table. + +@findex _bfd_generic_link_add_archive_symbols + In most cases the work of looking through the symbols in the + archive should be done by the + <<_bfd_generic_link_add_archive_symbols>> function. This + function builds a hash table from the archive symbol table and + looks through the list of undefined symbols to see which + elements should be included. + <<_bfd_generic_link_add_archive_symbols>> is passed a function + to call to make the final decision about adding an archive + element to the link and to do the actual work of adding the + symbols to the linker hash table. + + The function passed to + <<_bfd_generic_link_add_archive_symbols>> must read the + symbols of the archive element and decide whether the archive + element should be included in the link. If the element is to + be included, the <> linker callback + routine must be called with the element as an argument, and + the elements symbols must be added to the linker hash table + just as though the element had itself been passed to the + <<_bfd_link_add_symbols>> function. + + When the a.out <<_bfd_link_add_symbols>> function receives an + archive, it calls <<_bfd_generic_link_add_archive_symbols>> + passing <> as the function + argument. <> calls + <>. If the latter decides to add + the element (an element is only added if it provides a real, + non-common, definition for a previously undefined or common + symbol) it calls the <> callback and then + <> calls + <> to actually add the symbols to the + linker hash table. + + The ECOFF back end is unusual in that it does not normally + call <<_bfd_generic_link_add_archive_symbols>>, because ECOFF + archives already contain a hash table of symbols. The ECOFF + back end searches the archive itself to avoid the overhead of + creating a new hash table. + +INODE +Performing the Final Link, , Adding Symbols to the Hash Table, Linker Functions +SUBSECTION + Performing the final link + +@cindex _bfd_link_final_link in target vector +@cindex target vector (_bfd_final_link) + When all the input files have been processed, the linker calls + the <<_bfd_final_link>> entry point of the output BFD. This + routine is responsible for producing the final output file, + which has several aspects. It must relocate the contents of + the input sections and copy the data into the output sections. + It must build an output symbol table including any local + symbols from the input files and the global symbols from the + hash table. When producing relocateable output, it must + modify the input relocs and write them into the output file. + There may also be object format dependent work to be done. + + The linker will also call the <> entry + point when the BFD is closed. The two entry points must work + together in order to produce the correct output file. + + The details of how this works are inevitably dependent upon + the specific object file format. The a.out + <<_bfd_final_link>> routine is <>. + +@menu +@* Information provided by the linker:: +@* Relocating the section contents:: +@* Writing the symbol table:: +@end menu + +INODE +Information provided by the linker, Relocating the section contents, Performing the Final Link, Performing the Final Link +SUBSUBSECTION + Information provided by the linker + + Before the linker calls the <<_bfd_final_link>> entry point, + it sets up some data structures for the function to use. + + The <> field of the <> structure + will point to a list of all the input files included in the + link. These files are linked through the <> field + of the <> structure. + + Each section in the output file will have a list of + <> structures attached to the <> + field (the <> structure is defined in + <>). These structures describe how to create the + contents of the output section in terms of the contents of + various input sections, fill constants, and, eventually, other + types of information. They also describe relocs that must be + created by the BFD backend, but do not correspond to any input + file; this is used to support -Ur, which builds constructors + while generating a relocateable object file. + +INODE +Relocating the section contents, Writing the symbol table, Information provided by the linker, Performing the Final Link +SUBSUBSECTION + Relocating the section contents + + The <<_bfd_final_link>> function should look through the + <> structures attached to each section of the + output file. Each <> structure should either be + handled specially, or it should be passed to the function + <<_bfd_default_link_order>> which will do the right thing + (<<_bfd_default_link_order>> is defined in <>). + + For efficiency, a <> of type + <> whose associated section belongs + to a BFD of the same format as the output BFD must be handled + specially. This type of <> describes part of an + output section in terms of a section belonging to one of the + input files. The <<_bfd_final_link>> function should read the + contents of the section and any associated relocs, apply the + relocs to the section contents, and write out the modified + section contents. If performing a relocateable link, the + relocs themselves must also be modified and written out. + +@findex _bfd_relocate_contents +@findex _bfd_final_link_relocate + The functions <<_bfd_relocate_contents>> and + <<_bfd_final_link_relocate>> provide some general support for + performing the actual relocations, notably overflow checking. + Their arguments include information about the symbol the + relocation is against and a <> argument + which describes the relocation to perform. These functions + are defined in <>. + + The a.out function which handles reading, relocating, and + writing section contents is <>. The + actual relocation is done in <> + and <>. + +INODE +Writing the symbol table, , Relocating the section contents, Performing the Final Link +SUBSUBSECTION + Writing the symbol table + + The <<_bfd_final_link>> function must gather all the symbols + in the input files and write them out. It must also write out + all the symbols in the global hash table. This must be + controlled by the <> and <> fields of the + <> structure. + + The local symbols of the input files will not have been + entered into the linker hash table. The <<_bfd_final_link>> + routine must consider each input file and include the symbols + in the output file. It may be convenient to do this when + looking through the <> structures, or it may be + done by stepping through the <> list. + + The <<_bfd_final_link>> routine must also traverse the global + hash table to gather all the externally visible symbols. It + is possible that most of the externally visible symbols may be + written out when considering the symbols of each input file, + but it is still necessary to traverse the hash table since the + linker script may have defined some symbols that are not in + any of the input files. The <> field in the + <> structure may be used to determine + which entries in the hash table have not already been written + out. + + The <> field of the <> structure + controls which symbols are written out. The possible values + are listed in <>. If the value is <>, + then the <> field of the <> + structure is a hash table of symbols to keep; each symbol + should be looked up in this hash table, and only symbols which + are present should be included in the output file. + + If the <> field of the <> structure + permits local symbols to be written out, the <> field + is used to further controls which local symbols are included + in the output file. If the value is <>, then all + local symbols which begin with a certain prefix are discarded; + this prefix is described by the <> and + <> fields of the <> structure. + + The a.out backend handles symbols by calling + <> on each input BFD and then + traversing the global hash table with the function + <>. It builds a string table + while writing out the symbols, which is written to the output + file at the end of <>. +*/ + +static struct bfd_hash_entry *generic_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); +static boolean generic_link_read_symbols + PARAMS ((bfd *)); +static boolean generic_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *, boolean collect)); +static boolean generic_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *, boolean collect)); +static boolean generic_link_check_archive_element_no_collect + PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded)); +static boolean generic_link_check_archive_element_collect + PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded)); +static boolean generic_link_check_archive_element + PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded, boolean collect)); +static boolean generic_link_add_symbol_list + PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **, + boolean collect)); +static boolean generic_add_output_symbol + PARAMS ((bfd *, size_t *psymalloc, asymbol *)); +static boolean default_fill_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); +static boolean default_indirect_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* The link hash table structure is defined in bfdlink.h. It provides + a base hash table which the backend specific hash tables are built + upon. */ + +/* Routine to create an entry in the link hash table. */ + +struct bfd_hash_entry * +_bfd_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct bfd_link_hash_entry *ret = (struct bfd_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct bfd_link_hash_entry *) NULL) + ret = ((struct bfd_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry))); + if (ret == (struct bfd_link_hash_entry *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + /* Call the allocation method of the superclass. */ + ret = ((struct bfd_link_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->type = bfd_link_hash_new; + ret->next = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize a link hash table. The BFD argument is the one + responsible for creating this table. */ + +boolean +_bfd_link_hash_table_init (table, abfd, newfunc) + struct bfd_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + table->creator = abfd->xvec; + table->undefs = NULL; + table->undefs_tail = NULL; + return bfd_hash_table_init (&table->table, newfunc); +} + +/* Look up a symbol in a link hash table. If follow is true, we + follow bfd_link_hash_indirect and bfd_link_hash_warning links to + the real symbol. */ + +struct bfd_link_hash_entry * +bfd_link_hash_lookup (table, string, create, copy, follow) + struct bfd_link_hash_table *table; + const char *string; + boolean create; + boolean copy; + boolean follow; +{ + struct bfd_link_hash_entry *ret; + + ret = ((struct bfd_link_hash_entry *) + bfd_hash_lookup (&table->table, string, create, copy)); + + if (follow && ret != (struct bfd_link_hash_entry *) NULL) + { + while (ret->type == bfd_link_hash_indirect + || ret->type == bfd_link_hash_warning) + ret = ret->u.i.link; + } + + return ret; +} + +/* Traverse a generic link hash table. The only reason this is not a + macro is to do better type checking. This code presumes that an + argument passed as a struct bfd_hash_entry * may be caught as a + struct bfd_link_hash_entry * with no explicit cast required on the + call. */ + +void +bfd_link_hash_traverse (table, func, info) + struct bfd_link_hash_table *table; + boolean (*func) PARAMS ((struct bfd_link_hash_entry *, PTR)); + PTR info; +{ + bfd_hash_traverse (&table->table, + ((boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) + func), + info); +} + +/* Add a symbol to the linker hash table undefs list. */ + +INLINE void +bfd_link_add_undef (table, h) + struct bfd_link_hash_table *table; + struct bfd_link_hash_entry *h; +{ + BFD_ASSERT (h->next == NULL); + if (table->undefs_tail != (struct bfd_link_hash_entry *) NULL) + table->undefs_tail->next = h; + if (table->undefs == (struct bfd_link_hash_entry *) NULL) + table->undefs = h; + table->undefs_tail = h; +} + +/* Routine to create an entry in an generic link hash table. */ + +static struct bfd_hash_entry * +generic_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct generic_link_hash_entry *ret = + (struct generic_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct generic_link_hash_entry *) NULL) + ret = ((struct generic_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry))); + if (ret == (struct generic_link_hash_entry *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + /* Call the allocation method of the superclass. */ + ret = ((struct generic_link_hash_entry *) + _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + + if (ret) + { + /* Set local fields. */ + ret->written = false; + ret->sym = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Create an generic link hash table. */ + +struct bfd_link_hash_table * +_bfd_generic_link_hash_table_create (abfd) + bfd *abfd; +{ + struct generic_link_hash_table *ret; + + ret = ((struct generic_link_hash_table *) + malloc (sizeof (struct generic_link_hash_table))); + if (!ret) + { + bfd_set_error (bfd_error_no_memory); + return (struct bfd_link_hash_table *) NULL; + } + if (! _bfd_link_hash_table_init (&ret->root, abfd, + generic_link_hash_newfunc)) + { + free (ret); + return (struct bfd_link_hash_table *) NULL; + } + return &ret->root; +} + +/* Grab the symbols for an object file when doing a generic link. We + store the symbols in the outsymbols field. We need to keep them + around for the entire link to ensure that we only read them once. + If we read them multiple times, we might wind up with relocs and + the hash table pointing to different instances of the symbol + structure. */ + +static boolean +generic_link_read_symbols (abfd) + bfd *abfd; +{ + if (abfd->outsymbols == (asymbol **) NULL) + { + long symsize; + long symcount; + + symsize = bfd_get_symtab_upper_bound (abfd); + if (symsize < 0) + return false; + abfd->outsymbols = (asymbol **) bfd_alloc (abfd, symsize); + if (abfd->outsymbols == NULL && symsize != 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + symcount = bfd_canonicalize_symtab (abfd, abfd->outsymbols); + if (symcount < 0) + return false; + abfd->symcount = symcount; + } + + return true; +} + +/* Generic function to add symbols to from an object file to the + global hash table. This version does not automatically collect + constructors by name. */ + +boolean +_bfd_generic_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + return generic_link_add_symbols (abfd, info, false); +} + +/* Generic function to add symbols from an object file to the global + hash table. This version automatically collects constructors by + name, as the collect2 program does. It should be used for any + target which does not provide some other mechanism for setting up + constructors and destructors; these are approximately those targets + for which gcc uses collect2 and do not support stabs. */ + +boolean +_bfd_generic_link_add_symbols_collect (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + return generic_link_add_symbols (abfd, info, true); +} + +/* Add symbols from an object file to the global hash table. */ + +static boolean +generic_link_add_symbols (abfd, info, collect) + bfd *abfd; + struct bfd_link_info *info; + boolean collect; +{ + boolean ret; + + switch (bfd_get_format (abfd)) + { + case bfd_object: + ret = generic_link_add_object_symbols (abfd, info, collect); + break; + case bfd_archive: + ret = (_bfd_generic_link_add_archive_symbols + (abfd, info, + (collect + ? generic_link_check_archive_element_collect + : generic_link_check_archive_element_no_collect))); + break; + default: + bfd_set_error (bfd_error_wrong_format); + ret = false; + } + + return ret; +} + +/* Add symbols from an object file to the global hash table. */ + +static boolean +generic_link_add_object_symbols (abfd, info, collect) + bfd *abfd; + struct bfd_link_info *info; + boolean collect; +{ + if (! generic_link_read_symbols (abfd)) + return false; + return generic_link_add_symbol_list (abfd, info, + _bfd_generic_link_get_symcount (abfd), + _bfd_generic_link_get_symbols (abfd), + collect); +} + +/* We build a hash table of all symbols defined in an archive. */ + +/* An archive symbol may be defined by multiple archive elements. + This linked list is used to hold the elements. */ + +struct archive_list +{ + struct archive_list *next; + int indx; +}; + +/* An entry in an archive hash table. */ + +struct archive_hash_entry +{ + struct bfd_hash_entry root; + /* Where the symbol is defined. */ + struct archive_list *defs; +}; + +/* An archive hash table itself. */ + +struct archive_hash_table +{ + struct bfd_hash_table table; +}; + +static struct bfd_hash_entry *archive_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static boolean archive_hash_table_init + PARAMS ((struct archive_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Create a new entry for an archive hash table. */ + +static struct bfd_hash_entry * +archive_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct archive_hash_entry *ret = (struct archive_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct archive_hash_entry *) NULL) + ret = ((struct archive_hash_entry *) + bfd_hash_allocate (table, sizeof (struct archive_hash_entry))); + if (ret == (struct archive_hash_entry *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + /* Call the allocation method of the superclass. */ + ret = ((struct archive_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->defs = (struct archive_list *) NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize an archive hash table. */ + +static boolean +archive_hash_table_init (table, newfunc) + struct archive_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return bfd_hash_table_init (&table->table, newfunc); +} + +/* Look up an entry in an archive hash table. */ + +#define archive_hash_lookup(t, string, create, copy) \ + ((struct archive_hash_entry *) \ + bfd_hash_lookup (&(t)->table, (string), (create), (copy))) + +/* Allocate space in an archive hash table. */ + +#define archive_hash_allocate(t, size) bfd_hash_allocate (&(t)->table, (size)) + +/* Free an archive hash table. */ + +#define archive_hash_table_free(t) bfd_hash_table_free (&(t)->table) + +/* Generic function to add symbols from an archive file to the global + hash file. This function presumes that the archive symbol table + has already been read in (this is normally done by the + bfd_check_format entry point). It looks through the undefined and + common symbols and searches the archive symbol table for them. If + it finds an entry, it includes the associated object file in the + link. + + The old linker looked through the archive symbol table for + undefined symbols. We do it the other way around, looking through + undefined symbols for symbols defined in the archive. The + advantage of the newer scheme is that we only have to look through + the list of undefined symbols once, whereas the old method had to + re-search the symbol table each time a new object file was added. + + The CHECKFN argument is used to see if an object file should be + included. CHECKFN should set *PNEEDED to true if the object file + should be included, and must also call the bfd_link_info + add_archive_element callback function and handle adding the symbols + to the global hash table. CHECKFN should only return false if some + sort of error occurs. + + For some formats, such as a.out, it is possible to look through an + object file but not actually include it in the link. The + archive_pass field in a BFD is used to avoid checking the symbols + of an object files too many times. When an object is included in + the link, archive_pass is set to -1. If an object is scanned but + not included, archive_pass is set to the pass number. The pass + number is incremented each time a new object file is included. The + pass number is used because when a new object file is included it + may create new undefined symbols which cause a previously examined + object file to be included. */ + +boolean +_bfd_generic_link_add_archive_symbols (abfd, info, checkfn) + bfd *abfd; + struct bfd_link_info *info; + boolean (*checkfn) PARAMS ((bfd *, struct bfd_link_info *, + boolean *pneeded)); +{ + carsym *arsyms; + carsym *arsym_end; + register carsym *arsym; + int pass; + struct archive_hash_table arsym_hash; + int indx; + struct bfd_link_hash_entry **pundef; + + if (! bfd_has_map (abfd)) + { + bfd_set_error (bfd_error_no_symbols); + return false; + } + + arsyms = bfd_ardata (abfd)->symdefs; + arsym_end = arsyms + bfd_ardata (abfd)->symdef_count; + + /* In order to quickly determine whether an symbol is defined in + this archive, we build a hash table of the symbols. */ + if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc)) + return false; + for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++) + { + struct archive_hash_entry *arh; + struct archive_list *l, **pp; + + arh = archive_hash_lookup (&arsym_hash, arsym->name, true, false); + if (arh == (struct archive_hash_entry *) NULL) + goto error_return; + l = ((struct archive_list *) + archive_hash_allocate (&arsym_hash, sizeof (struct archive_list))); + if (l == NULL) + goto error_return; + l->indx = indx; + for (pp = &arh->defs; + *pp != (struct archive_list *) NULL; + pp = &(*pp)->next) + ; + *pp = l; + l->next = NULL; + } + + /* The archive_pass field in the archive itself is used to + initialize PASS, sine we may search the same archive multiple + times. */ + pass = abfd->archive_pass; + if (pass == 0) + pass = 1; + + /* New undefined symbols are added to the end of the list, so we + only need to look through it once. */ + pundef = &info->hash->undefs; + while (*pundef != (struct bfd_link_hash_entry *) NULL) + { + struct bfd_link_hash_entry *h; + struct archive_hash_entry *arh; + struct archive_list *l; + + h = *pundef; + + /* When a symbol is defined, it is not necessarily removed from + the list. */ + if (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + { + /* Remove this entry from the list, for general cleanliness + and because we are going to look through the list again + if we search any more libraries. We can't remove the + entry if it is the tail, because that would lose any + entries we add to the list later on (it would also cause + us to lose track of whether the symbol has been + referenced). */ + if (*pundef != info->hash->undefs_tail) + *pundef = (*pundef)->next; + else + pundef = &(*pundef)->next; + continue; + } + + /* Look for this symbol in the archive symbol map. */ + arh = archive_hash_lookup (&arsym_hash, h->root.string, false, false); + if (arh == (struct archive_hash_entry *) NULL) + { + pundef = &(*pundef)->next; + continue; + } + + /* Look at all the objects which define this symbol. */ + for (l = arh->defs; l != (struct archive_list *) NULL; l = l->next) + { + bfd *element; + boolean needed; + + /* If the symbol has gotten defined along the way, quit. */ + if (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + break; + + element = bfd_get_elt_at_index (abfd, l->indx); + if (element == (bfd *) NULL) + goto error_return; + + /* If we've already included this element, or if we've + already checked it on this pass, continue. */ + if (element->archive_pass == -1 + || element->archive_pass == pass) + continue; + + /* If we can't figure this element out, just ignore it. */ + if (! bfd_check_format (element, bfd_object)) + { + element->archive_pass = -1; + continue; + } + + /* CHECKFN will see if this element should be included, and + go ahead and include it if appropriate. */ + if (! (*checkfn) (element, info, &needed)) + goto error_return; + + if (! needed) + element->archive_pass = pass; + else + { + element->archive_pass = -1; + + /* Increment the pass count to show that we may need to + recheck object files which were already checked. */ + ++pass; + } + } + + pundef = &(*pundef)->next; + } + + archive_hash_table_free (&arsym_hash); + + /* Save PASS in case we are called again. */ + abfd->archive_pass = pass; + + return true; + + error_return: + archive_hash_table_free (&arsym_hash); + return false; +} + +/* See if we should include an archive element. This version is used + when we do not want to automatically collect constructors based on + the symbol name, presumably because we have some other mechanism + for finding them. */ + +static boolean +generic_link_check_archive_element_no_collect (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + return generic_link_check_archive_element (abfd, info, pneeded, false); +} + +/* See if we should include an archive element. This version is used + when we want to automatically collect constructors based on the + symbol name, as collect2 does. */ + +static boolean +generic_link_check_archive_element_collect (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; +{ + return generic_link_check_archive_element (abfd, info, pneeded, true); +} + +/* See if we should include an archive element. Optionally collect + constructors. */ + +static boolean +generic_link_check_archive_element (abfd, info, pneeded, collect) + bfd *abfd; + struct bfd_link_info *info; + boolean *pneeded; + boolean collect; +{ + asymbol **pp, **ppend; + + *pneeded = false; + + if (! generic_link_read_symbols (abfd)) + return false; + + pp = _bfd_generic_link_get_symbols (abfd); + ppend = pp + _bfd_generic_link_get_symcount (abfd); + for (; pp < ppend; pp++) + { + asymbol *p; + struct bfd_link_hash_entry *h; + + p = *pp; + + /* We are only interested in globally visible symbols. */ + if (! bfd_is_com_section (p->section) + && (p->flags & (BSF_GLOBAL | BSF_INDIRECT | BSF_WEAK)) == 0) + continue; + + /* We are only interested if we know something about this + symbol, and it is undefined or common. An undefined weak + symbol (type bfd_link_hash_weak) is not considered to be a + reference when pulling files out of an archive. See the SVR4 + ABI, p. 4-27. */ + h = bfd_link_hash_lookup (info->hash, bfd_asymbol_name (p), false, + false, true); + if (h == (struct bfd_link_hash_entry *) NULL + || (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common)) + continue; + + /* P is a symbol we are looking for. */ + + if (! bfd_is_com_section (p->section)) + { + bfd_size_type symcount; + asymbol **symbols; + + /* This object file defines this symbol, so pull it in. */ + if (! (*info->callbacks->add_archive_element) (info, abfd, + bfd_asymbol_name (p))) + return false; + symcount = _bfd_generic_link_get_symcount (abfd); + symbols = _bfd_generic_link_get_symbols (abfd); + if (! generic_link_add_symbol_list (abfd, info, symcount, + symbols, collect)) + return false; + *pneeded = true; + return true; + } + + /* P is a common symbol. */ + + if (h->type == bfd_link_hash_undefined) + { + bfd *symbfd; + + symbfd = h->u.undef.abfd; + if (symbfd == (bfd *) NULL) + { + /* This symbol was created as undefined from outside + BFD. We assume that we should link in the object + file. This is for the -u option in the linker. */ + if (! (*info->callbacks->add_archive_element) + (info, abfd, bfd_asymbol_name (p))) + return false; + *pneeded = true; + return true; + } + + /* Turn the symbol into a common symbol but do not link in + the object file. This is how a.out works. Object + formats that require different semantics must implement + this function differently. This symbol is already on the + undefs list. We add the section to a common section + attached to symbfd to ensure that it is in a BFD which + will be linked in. */ + h->type = bfd_link_hash_common; + h->u.c.size = bfd_asymbol_value (p); + if (p->section == bfd_com_section_ptr) + h->u.c.section = bfd_make_section_old_way (symbfd, "COMMON"); + else + h->u.c.section = bfd_make_section_old_way (symbfd, + p->section->name); + h->u.c.section->flags = SEC_ALLOC; + } + else + { + /* Adjust the size of the common symbol if necessary. This + is how a.out works. Object formats that require + different semantics must implement this function + differently. */ + if (bfd_asymbol_value (p) > h->u.c.size) + h->u.c.size = bfd_asymbol_value (p); + } + } + + /* This archive element is not needed. */ + return true; +} + +/* Add the symbols from an object file to the global hash table. ABFD + is the object file. INFO is the linker information. SYMBOL_COUNT + is the number of symbols. SYMBOLS is the list of symbols. COLLECT + is true if constructors should be automatically collected by name + as is done by collect2. */ + +static boolean +generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect) + bfd *abfd; + struct bfd_link_info *info; + bfd_size_type symbol_count; + asymbol **symbols; + boolean collect; +{ + asymbol **pp, **ppend; + + pp = symbols; + ppend = symbols + symbol_count; + for (; pp < ppend; pp++) + { + asymbol *p; + + p = *pp; + + if ((p->flags & (BSF_INDIRECT + | BSF_WARNING + | BSF_GLOBAL + | BSF_CONSTRUCTOR + | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (p)) + || bfd_is_com_section (bfd_get_section (p)) + || bfd_is_ind_section (bfd_get_section (p))) + { + const char *name; + const char *string; + struct generic_link_hash_entry *h; + + name = bfd_asymbol_name (p); + if ((p->flags & BSF_INDIRECT) != 0 + || bfd_is_ind_section (p->section)) + string = bfd_asymbol_name ((asymbol *) p->value); + else if ((p->flags & BSF_WARNING) != 0) + { + /* The name of P is actually the warning string, and the + value is actually a pointer to the symbol to warn + about. */ + string = name; + name = bfd_asymbol_name ((asymbol *) p->value); + } + else + string = NULL; + + h = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, p->flags, bfd_get_section (p), + p->value, string, false, collect, + (struct bfd_link_hash_entry **) &h))) + return false; + + /* Save the BFD symbol so that we don't lose any backend + specific information that may be attached to it. We only + want this one if it gives more information than the + existing one; we don't want to replace a defined symbol + with an undefined one. This routine may be called with a + hash table other than the generic hash table, so we only + do this if we are certain that the hash table is a + generic one. */ + if (info->hash->creator == abfd->xvec) + { + if (h->sym == (asymbol *) NULL + || (! bfd_is_und_section (bfd_get_section (p)) + && (! bfd_is_com_section (bfd_get_section (p)) + || bfd_is_und_section (bfd_get_section (h->sym))))) + { + h->sym = p; + /* BSF_OLD_COMMON is a hack to support COFF reloc + reading, and it should go away when the COFF + linker is switched to the new version. */ + if (bfd_is_com_section (bfd_get_section (p))) + p->flags |= BSF_OLD_COMMON; + } + + /* Store a back pointer from the symbol to the hash + table entry for the benefit of relaxation code until + it gets rewritten to not use asymbol structures. */ + p->udata = (PTR) h; + } + } + } + + return true; +} + +/* We use a state table to deal with adding symbols from an object + file. The first index into the state table describes the symbol + from the object file. The second index into the state table is the + type of the symbol in the hash table. */ + +/* The symbol from the object file is turned into one of these row + values. */ + +enum link_row +{ + UNDEF_ROW, /* Undefined. */ + UNDEFW_ROW, /* Weak undefined. */ + DEF_ROW, /* Defined. */ + DEFW_ROW, /* Weak defined. */ + COMMON_ROW, /* Common. */ + INDR_ROW, /* Indirect. */ + WARN_ROW, /* Warning. */ + SET_ROW /* Member of set. */ +}; + +/* apparently needed for Hitachi 3050R(HI-UX/WE2)? */ +#undef FAIL + +/* The actions to take in the state table. */ + +enum link_action +{ + FAIL, /* Abort. */ + UND, /* Mark symbol undefined. */ + WEAK, /* Mark symbol weak undefined. */ + DEF, /* Mark symbol defined. */ + COM, /* Mark symbol common. */ + REF, /* Mark defined symbol referenced. */ + CREF, /* Possibly warn about common reference to defined symbol. */ + CDEF, /* Define existing common symbol. */ + NOACT, /* No action. */ + BIG, /* Mark symbol common using largest size. */ + MDEF, /* Multiple definition error. */ + MIND, /* Multiple indirect symbols. */ + IND, /* Make indirect symbol. */ + SET, /* Add value to set. */ + MWARN, /* Make warning symbol. */ + WARN, /* Issue warning. */ + CWARN, /* Warn if referenced, else MWARN. */ + CYCLE, /* Repeat with symbol pointed to. */ + REFC, /* Mark indirect symbol referenced and then CYCLE. */ + WARNC /* Issue warning and then CYCLE. */ +}; + +/* The state table itself. The first index is a link_row and the + second index is a bfd_link_hash_type. */ + +static const enum link_action link_action[8][7] = +{ + /* current\prev new undef weak def com indr warn */ + /* UNDEF_ROW */ {UND, NOACT, NOACT, REF, NOACT, REFC, WARNC }, + /* UNDEFW_ROW */ {WEAK, WEAK, NOACT, REF, NOACT, REFC, WARNC }, + /* DEF_ROW */ {DEF, DEF, DEF, MDEF, CDEF, MDEF, CYCLE }, + /* DEFW_ROW */ {DEF, DEF, DEF, NOACT, NOACT, NOACT, CYCLE }, + /* COMMON_ROW */ {COM, COM, COM, CREF, BIG, MDEF, WARNC }, + /* INDR_ROW */ {IND, IND, IND, MDEF, MDEF, MIND, CYCLE }, + /* WARN_ROW */ {MWARN, WARN, WARN, CWARN, WARN, CWARN, CYCLE }, + /* SET_ROW */ {SET, SET, SET, SET, SET, CYCLE, CYCLE } +}; + +/* Most of the entries in the LINK_ACTION table are straightforward, + but a few are somewhat subtle. + + A reference to an indirect symbol (UNDEF_ROW/indr or + UNDEFW_ROW/indr) is counted as a reference both to the indirect + symbol and to the symbol the indirect symbol points to. + + A reference to a warning symbol (UNDEF_ROW/warn or UNDEFW_ROW/warn) + causes the warning to be issued. + + A common definition of an indirect symbol (COMMON_ROW/indr) is + treated as a multiple definition error. Likewise for an indirect + definition of a common symbol (INDR_ROW/com). + + An indirect definition of a warning (INDR_ROW/warn) does not cause + the warning to be issued. + + If a warning is created for an indirect symbol (WARN_ROW/indr) no + warning is created for the symbol the indirect symbol points to. + + Adding an entry to a set does not count as a reference to a set, + and no warning is issued (SET_ROW/warn). */ + +/* Add a symbol to the global hash table. + ABFD is the BFD the symbol comes from. + NAME is the name of the symbol. + FLAGS is the BSF_* bits associated with the symbol. + SECTION is the section in which the symbol is defined; this may be + bfd_und_section_ptr or bfd_com_section_ptr. + VALUE is the value of the symbol, relative to the section. + STRING is used for either an indirect symbol, in which case it is + the name of the symbol to indirect to, or a warning symbol, in + which case it is the warning string. + COPY is true if NAME or STRING must be copied into locally + allocated memory if they need to be saved. + COLLECT is true if we should automatically collect gcc constructor + or destructor names as collect2 does. + HASHP, if not NULL, is a place to store the created hash table + entry; if *HASHP is not NULL, the caller has already looked up + the hash table entry, and stored it in *HASHP. */ + +boolean +_bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value, + string, copy, collect, hashp) + struct bfd_link_info *info; + bfd *abfd; + const char *name; + flagword flags; + asection *section; + bfd_vma value; + const char *string; + boolean copy; + boolean collect; + struct bfd_link_hash_entry **hashp; +{ + enum link_row row; + struct bfd_link_hash_entry *h; + boolean cycle; + + if (bfd_is_ind_section (section) + || (flags & BSF_INDIRECT) != 0) + row = INDR_ROW; + else if ((flags & BSF_WARNING) != 0) + row = WARN_ROW; + else if ((flags & BSF_CONSTRUCTOR) != 0) + row = SET_ROW; + else if (bfd_is_und_section (section)) + { + if ((flags & BSF_WEAK) != 0) + row = UNDEFW_ROW; + else + row = UNDEF_ROW; + } + else if ((flags & BSF_WEAK) != 0) + row = DEFW_ROW; + else if (bfd_is_com_section (section)) + row = COMMON_ROW; + else + row = DEF_ROW; + + if (hashp != NULL && *hashp != NULL) + { + h = *hashp; + BFD_ASSERT (strcmp (h->root.string, name) == 0); + } + else + { + h = bfd_link_hash_lookup (info->hash, name, true, copy, false); + if (h == NULL) + { + if (hashp != NULL) + *hashp = NULL; + return false; + } + } + + if (info->notice_hash != (struct bfd_hash_table *) NULL + && (bfd_hash_lookup (info->notice_hash, name, false, false) + != (struct bfd_hash_entry *) NULL)) + { + if (! (*info->callbacks->notice) (info, name, abfd, section, value)) + return false; + } + + if (hashp != (struct bfd_link_hash_entry **) NULL) + *hashp = h; + + do + { + enum link_action action; + + cycle = false; + action = link_action[(int) row][(int) h->type]; + switch (action) + { + case FAIL: + abort (); + + case NOACT: + /* Do nothing. */ + break; + + case UND: + /* Make a new undefined symbol. */ + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = abfd; + bfd_link_add_undef (info->hash, h); + break; + + case WEAK: + /* Make a new weak undefined symbol. */ + h->type = bfd_link_hash_weak; + h->u.undef.abfd = abfd; + break; + + case CDEF: + /* We have found a definition for a symbol which was + previously common. */ + BFD_ASSERT (h->type == bfd_link_hash_common); + if (! ((*info->callbacks->multiple_common) + (info, name, + h->u.c.section->owner, bfd_link_hash_common, h->u.c.size, + abfd, bfd_link_hash_defined, (bfd_vma) 0))) + return false; + /* Fall through. */ + case DEF: + /* Define a symbol. */ + h->type = bfd_link_hash_defined; + h->u.def.section = section; + h->u.def.value = value; + + /* If we have been asked to, we act like collect2 and + identify all functions that might be global constructors + and destructors and pass them up in a callback. We only + do this for certain object file types, since many object + file types can handle this automatically. */ + if (collect && name[0] == '_') + { + const char *s; + + /* A constructor or destructor name starts like this: + _+GLOBAL_[_.$][ID][_.$] + where the first [_.$] and the second are the same + character (we accept any character there, in case a + new object file format comes along with even worse + naming restrictions). */ + +#define CONS_PREFIX "GLOBAL_" +#define CONS_PREFIX_LEN (sizeof CONS_PREFIX - 1) + + s = name + 1; + while (*s == '_') + ++s; + if (s[0] == 'G' + && strncmp (s, CONS_PREFIX, CONS_PREFIX_LEN - 1) == 0) + { + char c; + + c = s[CONS_PREFIX_LEN + 1]; + if ((c == 'I' || c == 'D') + && s[CONS_PREFIX_LEN] == s[CONS_PREFIX_LEN + 2]) + { + if (! ((*info->callbacks->constructor) + (info, + c == 'I' ? true : false, + name, abfd, section, value))) + return false; + } + } + } + + break; + + case COM: + /* We have found a common definition for a symbol. */ + if (h->type == bfd_link_hash_new) + bfd_link_add_undef (info->hash, h); + h->type = bfd_link_hash_common; + h->u.c.size = value; + if (section == bfd_com_section_ptr) + { + h->u.c.section = bfd_make_section_old_way (abfd, "COMMON"); + h->u.c.section->flags = SEC_ALLOC; + } + else if (section->owner != abfd) + { + h->u.c.section = bfd_make_section_old_way (abfd, section->name); + h->u.c.section->flags = SEC_ALLOC; + } + else + h->u.c.section = section; + break; + + case REF: + /* A reference to a defined symbol. */ + if (h->next == NULL && info->hash->undefs_tail != h) + h->next = h; + break; + + case BIG: + /* We have found a common definition for a symbol which + already had a common definition. Use the maximum of the + two sizes. */ + BFD_ASSERT (h->type == bfd_link_hash_common); + if (! ((*info->callbacks->multiple_common) + (info, name, + h->u.c.section->owner, bfd_link_hash_common, h->u.c.size, + abfd, bfd_link_hash_common, value))) + return false; + if (value > h->u.c.size) + h->u.c.size = value; + break; + + case CREF: + /* We have found a common definition for a symbol which was + already defined. */ + BFD_ASSERT (h->type == bfd_link_hash_defined); + if (! ((*info->callbacks->multiple_common) + (info, name, + h->u.def.section->owner, bfd_link_hash_defined, (bfd_vma) 0, + abfd, bfd_link_hash_common, value))) + return false; + break; + + case MIND: + /* Multiple indirect symbols. This is OK if they both point + to the same symbol. */ + if (strcmp (h->u.i.link->root.string, string) == 0) + break; + /* Fall through. */ + case MDEF: + /* Handle a multiple definition. */ + { + asection *msec; + bfd_vma mval; + + switch (h->type) + { + case bfd_link_hash_defined: + msec = h->u.def.section; + mval = h->u.def.value; + break; + case bfd_link_hash_common: + msec = bfd_com_section_ptr; + mval = h->u.c.size; + break; + case bfd_link_hash_indirect: + msec = bfd_ind_section_ptr; + mval = 0; + break; + default: + abort (); + } + + if (! ((*info->callbacks->multiple_definition) + (info, name, msec->owner, msec, mval, abfd, section, + value))) + return false; + } + break; + + case IND: + /* Create an indirect symbol. */ + { + struct bfd_link_hash_entry *inh; + + /* STRING is the name of the symbol we want to indirect + to. */ + inh = bfd_link_hash_lookup (info->hash, string, true, copy, + false); + if (inh == (struct bfd_link_hash_entry *) NULL) + return false; + if (inh->type == bfd_link_hash_new) + { + inh->type = bfd_link_hash_undefined; + inh->u.undef.abfd = abfd; + bfd_link_add_undef (info->hash, inh); + } + + /* If the indirect symbol has been referenced, we need to + push the reference down to the symbol we are + referencing. */ + if (h->type != bfd_link_hash_new) + { + row = UNDEF_ROW; + cycle = true; + } + + h->type = bfd_link_hash_indirect; + h->u.i.link = inh; + } + break; + + case SET: + /* Add an entry to a set. */ + if (! (*info->callbacks->add_to_set) (info, h, BFD_RELOC_CTOR, + abfd, section, value)) + return false; + break; + + case WARNC: + /* Issue a warning and cycle. */ + if (h->u.i.warning != NULL) + { + if (! (*info->callbacks->warning) (info, h->u.i.warning)) + return false; + /* Only issue a warning once. */ + h->u.i.warning = NULL; + } + /* Fall through. */ + case CYCLE: + /* Try again with the referenced symbol. */ + h = h->u.i.link; + cycle = true; + break; + + case REFC: + /* A reference to an indirect symbol. */ + if (h->next == NULL && info->hash->undefs_tail != h) + h->next = h; + h = h->u.i.link; + cycle = true; + break; + + case WARN: + /* Issue a warning. */ + if (! (*info->callbacks->warning) (info, string)) + return false; + break; + + case CWARN: + /* Warn if this symbol has been referenced already, + otherwise either add a warning or cycle. A symbol has + been referenced if the next field is not NULL, or it is + the tail of the undefined symbol list. The REF case + above helps to ensure this. */ + if (h->next != NULL || info->hash->undefs_tail == h) + { + if (! (*info->callbacks->warning) (info, string)) + return false; + break; + } + /* Fall through. */ + case MWARN: + /* Make a warning symbol. */ + { + struct bfd_link_hash_entry *sub; + + /* STRING is the warning to give. */ + sub = ((struct bfd_link_hash_entry *) + bfd_hash_allocate (&info->hash->table, + sizeof (struct bfd_link_hash_entry))); + if (!sub) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + *sub = *h; + h->type = bfd_link_hash_warning; + h->u.i.link = sub; + if (! copy) + h->u.i.warning = string; + else + { + char *w; + + w = bfd_hash_allocate (&info->hash->table, + strlen (string) + 1); + strcpy (w, string); + h->u.i.warning = w; + } + } + break; + } + } + while (cycle); + + return true; +} + +/* Generic final link routine. */ + +boolean +_bfd_generic_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd *sub; + asection *o; + struct bfd_link_order *p; + size_t outsymalloc; + struct generic_write_global_symbol_info wginfo; + + abfd->outsymbols = (asymbol **) NULL; + abfd->symcount = 0; + outsymalloc = 0; + + /* Build the output symbol table. */ + for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next) + if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc)) + return false; + + /* Accumulate the global symbols. */ + wginfo.info = info; + wginfo.output_bfd = abfd; + wginfo.psymalloc = &outsymalloc; + _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info), + _bfd_generic_link_write_global_symbol, + (PTR) &wginfo); + + if (info->relocateable) + { + /* Allocate space for the output relocs for each section. */ + for (o = abfd->sections; + o != (asection *) NULL; + o = o->next) + { + o->reloc_count = 0; + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + ++o->reloc_count; + else if (p->type == bfd_indirect_link_order) + { + asection *input_section; + bfd *input_bfd; + long relsize; + arelent **relocs; + asymbol **symbols; + long reloc_count; + + input_section = p->u.indirect.section; + input_bfd = input_section->owner; + relsize = bfd_get_reloc_upper_bound (input_bfd, + input_section); + if (relsize < 0) + return false; + relocs = (arelent **) malloc ((size_t) relsize); + if (!relocs && relsize != 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + symbols = _bfd_generic_link_get_symbols (input_bfd); + reloc_count = bfd_canonicalize_reloc (input_bfd, + input_section, + relocs, + symbols); + if (reloc_count < 0) + return false; + BFD_ASSERT (reloc_count == input_section->reloc_count); + o->reloc_count += reloc_count; + free (relocs); + } + } + if (o->reloc_count > 0) + { + o->orelocation = ((arelent **) + bfd_alloc (abfd, + (o->reloc_count + * sizeof (arelent *)))); + if (!o->orelocation) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + o->flags |= SEC_RELOC; + /* Reset the count so that it can be used as an index + when putting in the output relocs. */ + o->reloc_count = 0; + } + } + } + + /* Handle all the link order information for the sections. */ + for (o = abfd->sections; + o != (asection *) NULL; + o = o->next) + { + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + switch (p->type) + { + case bfd_section_reloc_link_order: + case bfd_symbol_reloc_link_order: + if (! _bfd_generic_reloc_link_order (abfd, info, o, p)) + return false; + break; + default: + if (! _bfd_default_link_order (abfd, info, o, p)) + return false; + break; + } + } + } + + return true; +} + +/* Add an output symbol to the output BFD. */ + +static boolean +generic_add_output_symbol (output_bfd, psymalloc, sym) + bfd *output_bfd; + size_t *psymalloc; + asymbol *sym; +{ + if (output_bfd->symcount >= *psymalloc) + { + asymbol **newsyms; + + if (*psymalloc == 0) + *psymalloc = 124; + else + *psymalloc *= 2; + if (output_bfd->outsymbols == (asymbol **) NULL) + newsyms = (asymbol **) malloc (*psymalloc * sizeof (asymbol *)); + else + newsyms = (asymbol **) realloc (output_bfd->outsymbols, + *psymalloc * sizeof (asymbol *)); + if (newsyms == (asymbol **) NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + output_bfd->outsymbols = newsyms; + } + + output_bfd->outsymbols[output_bfd->symcount] = sym; + ++output_bfd->symcount; + + return true; +} + +/* Handle the symbols for an input BFD. */ + +boolean +_bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc) + bfd *output_bfd; + bfd *input_bfd; + struct bfd_link_info *info; + size_t *psymalloc; +{ + asymbol **sym_ptr; + asymbol **sym_end; + + if (! generic_link_read_symbols (input_bfd)) + return false; + + /* Create a filename symbol if we are supposed to. */ + if (info->create_object_symbols_section != (asection *) NULL) + { + asection *sec; + + for (sec = input_bfd->sections; + sec != (asection *) NULL; + sec = sec->next) + { + if (sec->output_section == info->create_object_symbols_section) + { + asymbol *newsym; + + newsym = bfd_make_empty_symbol (input_bfd); + if (!newsym) + return false; + newsym->name = input_bfd->filename; + newsym->value = 0; + newsym->flags = BSF_LOCAL | BSF_FILE; + newsym->section = sec; + + if (! generic_add_output_symbol (output_bfd, psymalloc, + newsym)) + return false; + + break; + } + } + } + + /* Adjust the values of the globally visible symbols, and write out + local symbols. */ + sym_ptr = _bfd_generic_link_get_symbols (input_bfd); + sym_end = sym_ptr + _bfd_generic_link_get_symcount (input_bfd); + for (; sym_ptr < sym_end; sym_ptr++) + { + asymbol *sym; + struct generic_link_hash_entry *h; + boolean output; + + h = (struct generic_link_hash_entry *) NULL; + sym = *sym_ptr; + if ((sym->flags & (BSF_INDIRECT + | BSF_WARNING + | BSF_GLOBAL + | BSF_CONSTRUCTOR + | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (sym)) + || bfd_is_com_section (bfd_get_section (sym)) + || bfd_is_ind_section (bfd_get_section (sym))) + { + h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info), + bfd_asymbol_name (sym), + false, false, true); + if (h != (struct generic_link_hash_entry *) NULL) + { + /* Force all references to this symbol to point to + the same area in memory. It is possible that + this routine will be called with a hash table + other than a generic hash table, so we double + check that. */ + if (info->hash->creator == input_bfd->xvec) + { + if (h->sym != (asymbol *) NULL) + *sym_ptr = sym = h->sym; + } + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + abort (); + case bfd_link_hash_undefined: + case bfd_link_hash_weak: + break; + case bfd_link_hash_defined: + sym->value = h->root.u.def.value; + sym->section = h->root.u.def.section; + sym->flags |= BSF_GLOBAL; + break; + case bfd_link_hash_common: + sym->value = h->root.u.c.size; + sym->flags |= BSF_GLOBAL; + if (! bfd_is_com_section (sym->section)) + { + BFD_ASSERT (bfd_is_und_section (sym->section)); + sym->section = bfd_com_section_ptr; + } + /* We do not set the section of the symbol to + h->root.u.c.section. That value was saved so + that we would know where to allocate the symbol + if it was defined. In this case the type is + still bfd_link_hash_common, so we did not define + it, so we do not want to use that section. */ + break; + } + } + } + + /* This switch is straight from the old code in + write_file_locals in ldsym.c. */ + if (info->strip == strip_some + && (bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym), + false, false) + == (struct bfd_hash_entry *) NULL)) + output = false; + else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0) + { + /* If this symbol is marked as occurring now, rather + than at the end, output it now. This is used for + COFF C_EXT FCN symbols. FIXME: There must be a + better way. */ + if (bfd_asymbol_bfd (sym) == input_bfd + && (sym->flags & BSF_NOT_AT_END) != 0) + output = true; + else + output = false; + } + else if (bfd_is_ind_section (sym->section)) + output = false; + else if ((sym->flags & BSF_DEBUGGING) != 0) + { + if (info->strip == strip_none) + output = true; + else + output = false; + } + else if (bfd_is_und_section (sym->section) + || bfd_is_com_section (sym->section)) + output = false; + else if ((sym->flags & BSF_LOCAL) != 0) + { + if ((sym->flags & BSF_WARNING) != 0) + output = false; + else + { + switch (info->discard) + { + default: + case discard_all: + output = false; + break; + case discard_l: + if (bfd_asymbol_name (sym)[0] == info->lprefix[0] + && (info->lprefix_len == 1 + || strncmp (bfd_asymbol_name (sym), info->lprefix, + info->lprefix_len) == 0)) + output = false; + else + output = true; + break; + case discard_none: + output = true; + break; + } + } + } + else if ((sym->flags & BSF_CONSTRUCTOR)) + { + if (info->strip != strip_all) + output = true; + else + output = false; + } + else + abort (); + + if (output) + { + if (! generic_add_output_symbol (output_bfd, psymalloc, sym)) + return false; + if (h != (struct generic_link_hash_entry *) NULL) + h->written = true; + } + } + + return true; +} + +/* Write out a global symbol, if it hasn't already been written out. + This is called for each symbol in the hash table. */ + +boolean +_bfd_generic_link_write_global_symbol (h, data) + struct generic_link_hash_entry *h; + PTR data; +{ + struct generic_write_global_symbol_info *wginfo = + (struct generic_write_global_symbol_info *) data; + asymbol *sym; + + if (h->written) + return true; + + h->written = true; + + if (wginfo->info->strip == strip_all + || (wginfo->info->strip == strip_some + && bfd_hash_lookup (wginfo->info->keep_hash, h->root.root.string, + false, false) == NULL)) + return true; + + if (h->sym != (asymbol *) NULL) + { + sym = h->sym; + BFD_ASSERT (strcmp (bfd_asymbol_name (sym), h->root.root.string) == 0); + } + else + { + sym = bfd_make_empty_symbol (wginfo->output_bfd); + if (!sym) + return false; + sym->name = h->root.root.string; + sym->flags = 0; + } + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + abort (); + case bfd_link_hash_undefined: + sym->section = bfd_und_section_ptr; + sym->value = 0; + break; + case bfd_link_hash_weak: + sym->section = bfd_und_section_ptr; + sym->value = 0; + sym->flags |= BSF_WEAK; + break; + case bfd_link_hash_defined: + sym->section = h->root.u.def.section; + sym->value = h->root.u.def.value; + break; + case bfd_link_hash_common: + sym->value = h->root.u.c.size; + if (sym->section == NULL) + sym->section = bfd_com_section_ptr; + else if (! bfd_is_com_section (sym->section)) + { + BFD_ASSERT (bfd_is_und_section (sym->section)); + sym->section = bfd_com_section_ptr; + } + /* Do not set the section; see _bfd_generic_link_output_symbols. */ + break; + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + /* FIXME: What should we do here? */ + break; + } + + sym->flags |= BSF_GLOBAL; + + if (! generic_add_output_symbol (wginfo->output_bfd, wginfo->psymalloc, + sym)) + { + /* FIXME: No way to return failure. */ + abort (); + } + + return true; +} + +/* Create a relocation. */ + +boolean +_bfd_generic_reloc_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + struct bfd_link_order *link_order; +{ + arelent *r; + + if (! info->relocateable) + abort (); + if (sec->orelocation == (arelent **) NULL) + abort (); + + r = (arelent *) bfd_alloc (abfd, sizeof (arelent)); + if (r == (arelent *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + r->address = link_order->offset; + r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc); + if (r->howto == (const reloc_howto_type *) NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* Get the symbol to use for the relocation. */ + if (link_order->type == bfd_section_reloc_link_order) + r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr; + else + { + struct generic_link_hash_entry *h; + + h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info), + link_order->u.reloc.p->u.name, + false, false, true); + if (h == (struct generic_link_hash_entry *) NULL + || ! h->written) + { + if (! ((*info->callbacks->unattached_reloc) + (info, link_order->u.reloc.p->u.name, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + return false; + bfd_set_error (bfd_error_bad_value); + return false; + } + r->sym_ptr_ptr = &h->sym; + } + + /* If this is an inplace reloc, write the addend to the object file. + Otherwise, store it in the reloc addend. */ + if (! r->howto->partial_inplace) + r->addend = link_order->u.reloc.p->addend; + else + { + bfd_size_type size; + bfd_reloc_status_type rstat; + bfd_byte *buf; + boolean ok; + + size = bfd_get_reloc_size (r->howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == (bfd_byte *) NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + rstat = _bfd_relocate_contents (r->howto, abfd, + link_order->u.reloc.p->addend, buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*info->callbacks->reloc_overflow) + (info, + (link_order->type == bfd_section_reloc_link_order + ? bfd_section_name (abfd, link_order->u.reloc.p->u.section) + : link_order->u.reloc.p->u.name), + r->howto->name, link_order->u.reloc.p->addend, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + { + free (buf); + return false; + } + break; + } + ok = bfd_set_section_contents (abfd, sec, (PTR) buf, + (file_ptr) link_order->offset, size); + free (buf); + if (! ok) + return false; + + r->addend = 0; + } + + sec->orelocation[sec->reloc_count] = r; + ++sec->reloc_count; + + return true; +} + +/* Allocate a new link_order for a section. */ + +struct bfd_link_order * +bfd_new_link_order (abfd, section) + bfd *abfd; + asection *section; +{ + struct bfd_link_order *new; + + new = ((struct bfd_link_order *) + bfd_alloc_by_size_t (abfd, sizeof (struct bfd_link_order))); + if (!new) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + new->type = bfd_undefined_link_order; + new->offset = 0; + new->size = 0; + new->next = (struct bfd_link_order *) NULL; + + if (section->link_order_tail != (struct bfd_link_order *) NULL) + section->link_order_tail->next = new; + else + section->link_order_head = new; + section->link_order_tail = new; + + return new; +} + +/* Default link order processing routine. Note that we can not handle + the reloc_link_order types here, since they depend upon the details + of how the particular backends generates relocs. */ + +boolean +_bfd_default_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + struct bfd_link_order *link_order; +{ + switch (link_order->type) + { + case bfd_undefined_link_order: + case bfd_section_reloc_link_order: + case bfd_symbol_reloc_link_order: + default: + abort (); + case bfd_indirect_link_order: + return default_indirect_link_order (abfd, info, sec, link_order); + case bfd_fill_link_order: + return default_fill_link_order (abfd, info, sec, link_order); + case bfd_data_link_order: + return bfd_set_section_contents (abfd, sec, + (PTR) link_order->u.data.contents, + (file_ptr) link_order->offset, + link_order->size); + } +} + +/* Default routine to handle a bfd_fill_link_order. */ + +/*ARGSUSED*/ +static boolean +default_fill_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + struct bfd_link_order *link_order; +{ + size_t size; + char *space; + size_t i; + int fill; + boolean result; + + BFD_ASSERT ((sec->flags & SEC_HAS_CONTENTS) != 0); + + size = (size_t) link_order->size; + space = (char *) malloc (size); + if (space == NULL && size != 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + fill = link_order->u.fill.value; + for (i = 0; i < size; i += 2) + space[i] = fill >> 8; + for (i = 1; i < size; i += 2) + space[i] = fill; + result = bfd_set_section_contents (abfd, sec, space, + (file_ptr) link_order->offset, + link_order->size); + free (space); + return result; +} + +/* Default routine to handle a bfd_indirect_link_order. */ + +static boolean +default_indirect_link_order (output_bfd, info, output_section, link_order) + bfd *output_bfd; + struct bfd_link_info *info; + asection *output_section; + struct bfd_link_order *link_order; +{ + asection *input_section; + bfd *input_bfd; + bfd_byte *contents = NULL; + bfd_byte *new_contents; + + BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0); + + if (link_order->size == 0) + return true; + + input_section = link_order->u.indirect.section; + input_bfd = input_section->owner; + + BFD_ASSERT (input_section->output_section == output_section); + BFD_ASSERT (input_section->output_offset == link_order->offset); + BFD_ASSERT (input_section->_cooked_size == link_order->size); + + if (info->relocateable + && input_section->reloc_count > 0 + && output_section->orelocation == (arelent **) NULL) + { + /* Space has not been allocated for the output relocations. + This can happen when we are called by a specific backend + because somebody is attempting to link together different + types of object files. Handling this case correctly is + difficult, and sometimes impossible. */ + abort (); + } + + /* Get the canonical symbols. The generic linker will always have + retrieved them by this point, but we may be being called by a + specific linker when linking different types of object files + together. */ + if (! generic_link_read_symbols (input_bfd)) + return false; + + /* Get and relocate the section contents. */ + contents = (bfd_byte *) malloc (bfd_section_size (input_bfd, input_section)); + if (contents == NULL && bfd_section_size (input_bfd, input_section) != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + new_contents = (bfd_get_relocated_section_contents + (output_bfd, info, link_order, contents, info->relocateable, + _bfd_generic_link_get_symbols (input_bfd))); + if (!new_contents) + goto error_return; + + /* Output the section contents. */ + if (! bfd_set_section_contents (output_bfd, output_section, + (PTR) new_contents, + link_order->offset, link_order->size)) + goto error_return; + + if (contents != NULL) + free (contents); + return true; + + error_return: + if (contents != NULL) + free (contents); + return false; +} + +/* A little routine to count the number of relocs in a link_order + list. */ + +unsigned int +_bfd_count_link_order_relocs (link_order) + struct bfd_link_order *link_order; +{ + register unsigned int c; + register struct bfd_link_order *l; + + c = 0; + for (l = link_order; l != (struct bfd_link_order *) NULL; l = l->next) + { + if (l->type == bfd_section_reloc_link_order + || l->type == bfd_symbol_reloc_link_order) + ++c; + } + + return c; +} diff --git a/gnu/usr.bin/gdb/gdb/annotate.c b/gnu/usr.bin/gdb/gdb/annotate.c new file mode 100644 index 00000000000..0a73fb5dcd4 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/annotate.c @@ -0,0 +1,521 @@ +/* Annotation routines for GDB. + Copyright 1986, 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +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. */ + +#include "defs.h" +#include "annotate.h" +#include "value.h" +#include "target.h" +#include "gdbtypes.h" + +static void print_value_flags PARAMS ((struct type *)); + +static void +print_value_flags (t) + struct type *t; +{ + if (can_dereference (t)) + printf_filtered ("*"); + else + printf_filtered ("-"); +} + +void +breakpoints_changed () +{ + if (annotation_level > 1) + { + target_terminal_ours (); + printf_unfiltered ("\n\032\032breakpoints-invalid\n"); + } +} + +void +annotate_breakpoint (num) + int num; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032breakpoint %d\n", num); +} + +void +annotate_watchpoint (num) + int num; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032watchpoint %d\n", num); +} + +void +annotate_starting () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032starting\n"); +} + +void +annotate_stopped () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032stopped\n"); +} + +void +annotate_exited (exitstatus) + int exitstatus; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032exited %d\n", exitstatus); +} + +void +annotate_signalled () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signalled\n"); +} + +void +annotate_signal_name () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal-name\n"); +} + +void +annotate_signal_name_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal-name-end\n"); +} + +void +annotate_signal_string () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal-string\n"); +} + +void +annotate_signal_string_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal-string-end\n"); +} + +void +annotate_signal () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal\n"); +} + +void +annotate_breakpoints_headers () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032breakpoints-headers\n"); +} + +void +annotate_field (num) + int num; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032field %d\n", num); +} + +void +annotate_breakpoints_table () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032breakpoints-table\n"); +} + +void +annotate_record () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032record\n"); +} + +void +annotate_breakpoints_table_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032breakpoints-table-end\n"); +} + +void +annotate_frames_invalid () +{ + if (annotation_level > 1) + { + target_terminal_ours (); + printf_unfiltered ("\n\032\032frames-invalid\n"); + } +} + +void +annotate_field_begin (type) + struct type *type; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032field-begin "); + print_value_flags (type); + printf_filtered ("\n"); + } +} + +void +annotate_field_name_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032field-name-end\n"); +} + +void +annotate_field_value () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032field-value\n"); +} + +void +annotate_field_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032field-end\n"); +} + +void +annotate_quit () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032quit\n"); +} + +void +annotate_error () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032error\n"); +} + +void +annotate_error_begin () +{ + if (annotation_level > 1) + fprintf_filtered (gdb_stderr, "\n\032\032error-begin\n"); +} + +void +annotate_value_history_begin (histindex, type) + int histindex; + struct type *type; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032value-history-begin %d ", histindex); + print_value_flags (type); + printf_filtered ("\n"); + } +} + +void +annotate_value_begin (type) + struct type *type; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032value-begin "); + print_value_flags (type); + printf_filtered ("\n"); + } +} + +void +annotate_value_history_value () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032value-history-value\n"); +} + +void +annotate_value_history_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032value-history-end\n"); +} + +void +annotate_value_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032value-end\n"); +} + +void +annotate_display_begin () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-begin\n"); +} + +void +annotate_display_number_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-number-end\n"); +} + +void +annotate_display_format () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-format\n"); +} + +void +annotate_display_expression () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-expression\n"); +} + +void +annotate_display_expression_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-expression-end\n"); +} + +void +annotate_display_value () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-value\n"); +} + +void +annotate_display_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032display-end\n"); +} + +void +annotate_arg_begin () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032arg-begin\n"); +} + +void +annotate_arg_name_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032arg-name-end\n"); +} + +void +annotate_arg_value (type) + struct type *type; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032arg-value "); + print_value_flags (type); + printf_filtered ("\n"); + } +} + +void +annotate_arg_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032arg-end\n"); +} + +void +annotate_source (filename, line, character, mid, pc) + char *filename; + int line; + int character; + int mid; + CORE_ADDR pc; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032source "); + else + printf_filtered ("\032\032"); + + printf_filtered ("%s:%d:%d:%s:", filename, + line, character, + mid ? "middle" : "beg"); + print_address_numeric (pc, 0, gdb_stdout); + printf_filtered ("\n"); +} + +void +annotate_frame_begin (level, pc) + int level; + CORE_ADDR pc; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032frame-begin %d ", level); + print_address_numeric (pc, 0, gdb_stdout); + printf_filtered ("\n"); + } +} + +void +annotate_function_call () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032function-call\n"); +} + +void +annotate_signal_handler_caller () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032signal-handler-caller\n"); +} + +void +annotate_frame_address () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-address\n"); +} + +void +annotate_frame_address_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-address-end\n"); +} + +void +annotate_frame_function_name () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-function-name\n"); +} + +void +annotate_frame_args () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-args\n"); +} + +void +annotate_frame_source_begin () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-source-begin\n"); +} + +void +annotate_frame_source_file () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-source-file\n"); +} + +void +annotate_frame_source_file_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-source-file-end\n"); +} + +void +annotate_frame_source_line () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-source-line\n"); +} + +void +annotate_frame_source_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-source-end\n"); +} + +void +annotate_frame_where () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-where\n"); +} + +void +annotate_frame_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032frame-end\n"); +} + +void +annotate_array_section_begin (index, elttype) + int index; + struct type *elttype; +{ + if (annotation_level > 1) + { + printf_filtered ("\n\032\032array-section-begin %d ", index); + print_value_flags (elttype); + printf_filtered ("\n"); + } +} + +void +annotate_elt_rep (repcount) + unsigned int repcount; +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032elt-rep %u\n", repcount); +} + +void +annotate_elt_rep_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032elt-rep-end\n"); +} + +void +annotate_elt () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032elt\n"); +} + +void +annotate_array_section_end () +{ + if (annotation_level > 1) + printf_filtered ("\n\032\032array-section-end\n"); +} + diff --git a/gnu/usr.bin/gdb/gdb/annotate.h b/gnu/usr.bin/gdb/gdb/annotate.h new file mode 100644 index 00000000000..0ec9765e04c --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/annotate.h @@ -0,0 +1,95 @@ +/* Annotation routines for GDB. + Copyright 1986, 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +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. */ + +extern void breakpoints_changed PARAMS ((void)); + +extern void annotate_breakpoint PARAMS ((int)); +extern void annotate_watchpoint PARAMS ((int)); +extern void annotate_starting PARAMS ((void)); +extern void annotate_stopped PARAMS ((void)); +extern void annotate_exited PARAMS ((int)); +extern void annotate_signalled PARAMS ((void)); +extern void annotate_signal_name PARAMS ((void)); +extern void annotate_signal_name_end PARAMS ((void)); +extern void annotate_signal_string PARAMS ((void)); +extern void annotate_signal_string_end PARAMS ((void)); +extern void annotate_signal PARAMS ((void)); + +extern void annotate_breakpoints_headers PARAMS ((void)); +extern void annotate_field PARAMS ((int)); +extern void annotate_breakpoints_table PARAMS ((void)); +extern void annotate_record PARAMS ((void)); +extern void annotate_breakpoints_table_end PARAMS ((void)); + +extern void annotate_frames_invalid PARAMS ((void)); + +#ifdef __STDC__ +struct type; +#endif + +extern void annotate_field_begin PARAMS ((struct type *)); +extern void annotate_field_name_end PARAMS ((void)); +extern void annotate_field_value PARAMS ((void)); +extern void annotate_field_end PARAMS ((void)); + +extern void annotate_quit PARAMS ((void)); +extern void annotate_error PARAMS ((void)); +extern void annotate_error_begin PARAMS ((void)); + +extern void annotate_value_history_begin PARAMS ((int, struct type *)); +extern void annotate_value_begin PARAMS ((struct type *)); +extern void annotate_value_history_value PARAMS ((void)); +extern void annotate_value_history_end PARAMS ((void)); +extern void annotate_value_end PARAMS ((void)); + +extern void annotate_display_begin PARAMS ((void)); +extern void annotate_display_number_end PARAMS ((void)); +extern void annotate_display_format PARAMS ((void)); +extern void annotate_display_expression PARAMS ((void)); +extern void annotate_display_expression_end PARAMS ((void)); +extern void annotate_display_value PARAMS ((void)); +extern void annotate_display_end PARAMS ((void)); + +extern void annotate_arg_begin PARAMS ((void)); +extern void annotate_arg_name_end PARAMS ((void)); +extern void annotate_arg_value PARAMS ((struct type *)); +extern void annotate_arg_end PARAMS ((void)); + +extern void annotate_source PARAMS ((char *, int, int, int, CORE_ADDR)); + +extern void annotate_frame_begin PARAMS ((int, CORE_ADDR)); +extern void annotate_function_call PARAMS ((void)); +extern void annotate_signal_handler_caller PARAMS ((void)); +extern void annotate_frame_address PARAMS ((void)); +extern void annotate_frame_address_end PARAMS ((void)); +extern void annotate_frame_function_name PARAMS ((void)); +extern void annotate_frame_args PARAMS ((void)); +extern void annotate_frame_source_begin PARAMS ((void)); +extern void annotate_frame_source_file PARAMS ((void)); +extern void annotate_frame_source_file_end PARAMS ((void)); +extern void annotate_frame_source_line PARAMS ((void)); +extern void annotate_frame_source_end PARAMS ((void)); +extern void annotate_frame_where PARAMS ((void)); +extern void annotate_frame_end PARAMS ((void)); + +extern void annotate_array_section_begin PARAMS ((int, struct type *)); +extern void annotate_elt_rep PARAMS ((unsigned int)); +extern void annotate_elt_rep_end PARAMS ((void)); +extern void annotate_elt PARAMS ((void)); +extern void annotate_array_section_end PARAMS ((void)); diff --git a/gnu/usr.bin/gdb/gdb/aout/encap.h b/gnu/usr.bin/gdb/gdb/aout/encap.h new file mode 100644 index 00000000000..cebedf38336 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/aout/encap.h @@ -0,0 +1,135 @@ +/* Yet Another Try at encapsulating bsd object files in coff. + Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. + Written by Pace Willisson 12/9/88 + + This file is obsolete. It needs to be converted to just define a bunch + of stuff that BFD can use to do coff-encapsulated files. --gnu@cygnus.com + +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. */ + +/* + * We only use the coff headers to tell the kernel + * how to exec the file. Therefore, the only fields that need to + * be filled in are the scnptr and vaddr for the text and data + * sections, and the vaddr for the bss. As far as coff is concerned, + * there is no symbol table, relocation, or line numbers. + * + * A normal bsd header (struct exec) is placed after the coff headers, + * and before the real text. I defined a the new fields 'a_machtype' + * and a_flags. If a_machtype is M_386, and a_flags & A_ENCAP is + * true, then the bsd header is preceeded by a coff header. Macros + * like N_TXTOFF and N_TXTADDR use this field to find the bsd header. + * + * The only problem is to track down the bsd exec header. The + * macros HEADER_OFFSET, etc do this. + */ + +#define N_FLAGS_COFF_ENCAPSULATE 0x20 /* coff header precedes bsd header */ + +/* Describe the COFF header used for encapsulation. */ + +struct coffheader +{ + /* filehdr */ + unsigned short f_magic; + unsigned short f_nscns; + long f_timdat; + long f_symptr; + long f_nsyms; + unsigned short f_opthdr; + unsigned short f_flags; + /* aouthdr */ + short magic; + short vstamp; + long tsize; + long dsize; + long bsize; + long entry; + long text_start; + long data_start; + struct coffscn + { + char s_name[8]; + long s_paddr; + long s_vaddr; + long s_size; + long s_scnptr; + long s_relptr; + long s_lnnoptr; + unsigned short s_nreloc; + unsigned short s_nlnno; + long s_flags; + } scns[3]; +}; + +/* Describe some of the parameters of the encapsulation, + including how to find the encapsulated BSD header. */ + +/* FIXME, this is dumb. The same tools can't handle a.outs for different + architectures, just because COFF_MAGIC is different; so you need a + separate GNU nm for every architecture!!? Unfortunately, it needs to + be this way, since the COFF_MAGIC value is determined by the kernel + we're trying to fool here. */ + +#define COFF_MAGIC_I386 0514 /* I386MAGIC */ +#define COFF_MAGIC_M68K 0520 /* MC68MAGIC */ +#define COFF_MAGIC_A29K 0x17A /* Used by asm29k cross-tools */ + +#ifdef COFF_MAGIC +short __header_offset_temp; +#define HEADER_OFFSET(f) \ + (__header_offset_temp = 0, \ + fread ((char *)&__header_offset_temp, sizeof (short), 1, (f)), \ + fseek ((f), -sizeof (short), 1), \ + __header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0) +#else +#define HEADER_OFFSET(f) 0 +#endif + +#define HEADER_SEEK(f) (fseek ((f), HEADER_OFFSET((f)), 1)) + +/* Describe the characteristics of the BSD header + that appears inside the encapsulation. */ + +/* Encapsulated coff files that are linked ZMAGIC have a text segment + offset just past the header (and a matching TXTADDR), excluding + the headers from the text segment proper but keeping the physical + layout and the virtual memory layout page-aligned. + + Non-encapsulated a.out files that are linked ZMAGIC have a text + segment that starts at 0 and an N_TXTADR similarly offset to 0. + They too are page-aligned with each other, but they include the + a.out header as part of the text. + + The _N_HDROFF gets sizeof struct exec added to it, so we have + to compensate here. See . */ + +#undef _N_HDROFF +#undef N_TXTADDR +#undef N_DATADDR + +#define _N_HDROFF(x) ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \ + sizeof (struct coffheader) : 0) + +/* Address of text segment in memory after it is loaded. */ +#define N_TXTADDR(x) \ + ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \ + sizeof (struct coffheader) + sizeof (struct exec) : 0) +#define SEGMENT_SIZE 0x400000 + +#define N_DATADDR(x) \ + ((N_FLAGS(x) & N_FLAGS_COFF_ENCAPSULATE) ? \ + (SEGMENT_SIZE + ((N_TXTADDR(x)+(x).a_text-1) & ~(SEGMENT_SIZE-1))) : \ + (N_TXTADDR(x)+(x).a_text)) diff --git a/gnu/usr.bin/gdb/gdb/aout/host.h b/gnu/usr.bin/gdb/gdb/aout/host.h new file mode 100644 index 00000000000..5d3488a62ec --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/aout/host.h @@ -0,0 +1,22 @@ +/* Parameters about the a.out format, based on the host system on which + the program is compiled. */ + +/* Address of data segment in memory after it is loaded. + It is up to you to define SEGMENT_SIZE + on machines not listed here. */ +#ifndef SEGMENT_SIZE +#if defined(hp300) || defined(pyr) +#define SEGMENT_SIZE page_size +#endif +#ifdef sony +#define SEGMENT_SIZE 0x1000 +#endif /* Sony. */ +#ifdef is68k +#define SEGMENT_SIZE 0x20000 +#endif +#if defined(m68k) && defined(PORTAR) +#define PAGE_SIZE 0x400 +#define SEGMENT_SIZE PAGE_SIZE +#endif +#endif /*!defined(SEGMENT_SIZE)*/ + diff --git a/gnu/usr.bin/gdb/gdb/aout/reloc.h b/gnu/usr.bin/gdb/gdb/aout/reloc.h new file mode 100644 index 00000000000..1811b73ff9d --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/aout/reloc.h @@ -0,0 +1,66 @@ +/* reloc.h -- Header file for relocation information. + Copyright 1989-1991 Free Software Foundation, Inc. + +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. */ + +/* Relocation types for a.out files using reloc_info_extended + (SPARC and AMD 29000). */ + +#ifndef _RELOC_H_READ_ +#define _RELOC_H_READ_ 1 + +enum reloc_type + { + RELOC_8, RELOC_16, RELOC_32, /* simple relocations */ + RELOC_DISP8, RELOC_DISP16, RELOC_DISP32, /* pc-rel displacement */ + RELOC_WDISP30, RELOC_WDISP22, + RELOC_HI22, RELOC_22, + RELOC_13, RELOC_LO10, + RELOC_SFA_BASE, RELOC_SFA_OFF13, + RELOC_BASE10, RELOC_BASE13, RELOC_BASE22, /* P.I.C. (base-relative) */ + RELOC_PC10, RELOC_PC22, /* for some sort of pc-rel P.I.C. (?) */ + RELOC_JMP_TBL, /* P.I.C. jump table */ + RELOC_SEGOFF16, /* reputedly for shared libraries somehow */ + RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE, + RELOC_11, + RELOC_WDISP2_14, + RELOC_WDISP19, + RELOC_HHI22, + RELOC_HLO10, + + /* 29K relocation types */ + RELOC_JUMPTARG, RELOC_CONST, RELOC_CONSTH, + + RELOC_WDISP14, RELOC_WDISP21, + + NO_RELOC + }; + +#define RELOC_TYPE_NAMES \ +"8", "16", "32", "DISP8", \ +"DISP16", "DISP32", "WDISP30", "WDISP22", \ +"HI22", "22", "13", "LO10", \ +"SFA_BASE", "SFAOFF13", "BASE10", "BASE13", \ +"BASE22", "PC10", "PC22", "JMP_TBL", \ +"SEGOFF16", "GLOB_DAT", "JMP_SLOT", "RELATIVE", \ +"11", "WDISP2_14", "WDISP19", "HHI22", \ +"HLO10", \ +"JUMPTARG", "CONST", "CONSTH", "WDISP14", \ +"WDISP21", \ +"NO_RELOC" + +#endif /* _RELOC_H_READ_ */ + +/* end of reloc.h */ diff --git a/gnu/usr.bin/gdb/gdb/bfdlink.h b/gnu/usr.bin/gdb/gdb/bfdlink.h new file mode 100644 index 00000000000..2f0eb66dbc6 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/bfdlink.h @@ -0,0 +1,411 @@ +/* bfdlink.h -- header file for BFD link routines + Copyright 1993 Free Software Foundation, Inc. + Written by Steve Chamberlain and 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. */ + +#ifndef BFDLINK_H +#define BFDLINK_H + +/* Which symbols to strip during a link. */ +enum bfd_link_strip +{ + strip_none, /* Don't strip any symbols. */ + strip_debugger, /* Strip debugging symbols. */ + strip_some, /* keep_hash is the list of symbols to keep. */ + strip_all /* Strip all symbols. */ +}; + +/* Which local symbols to discard during a link. This is irrelevant + if strip_all is used. */ +enum bfd_link_discard +{ + discard_none, /* Don't discard any locals. */ + discard_l, /* Discard locals with a certain prefix. */ + discard_all /* Discard all locals. */ +}; + +/* These are the possible types of an entry in the BFD link hash + table. */ + +enum bfd_link_hash_type +{ + bfd_link_hash_new, /* Symbol is new. */ + bfd_link_hash_undefined, /* Symbol seen before, but undefined. */ + bfd_link_hash_weak, /* Symbol is weak and undefined. */ + bfd_link_hash_defined, /* Symbol is defined. */ + bfd_link_hash_common, /* Symbol is common. */ + bfd_link_hash_indirect, /* Symbol is an indirect link. */ + bfd_link_hash_warning /* Like indirect, but warn if referenced. */ +}; + +/* The linking routines use a hash table which uses this structure for + its elements. */ + +struct bfd_link_hash_entry +{ + /* Base hash table entry structure. */ + struct bfd_hash_entry root; + /* Type of this entry. */ + enum bfd_link_hash_type type; + + /* Undefined and common symbols are kept in a linked list through + this field. This field is not in the union because that would + force us to remove entries from the list when we changed their + type, which would force the list to be doubly linked, which would + waste more memory. When an undefined or common symbol is + created, it should be added to this list, the head of which is in + the link hash table itself. As symbols are defined, they need + not be removed from the list; anything which reads the list must + doublecheck the symbol type. + + Weak symbols are not kept on this list. + + Defined symbols use this field as a reference marker. If the + field is not NULL, or this structure is the tail of the undefined + symbol list, the symbol has been referenced. If the symbol is + undefined and becomes defined, this field will automatically be + non-NULL since the symbol will have been on the undefined symbol + list. */ + struct bfd_link_hash_entry *next; + /* A union of information depending upon the type. */ + union + { + /* Nothing is kept for bfd_hash_new. */ + /* bfd_link_hash_undefined, bfd_link_hash_weak. */ + struct + { + bfd *abfd; /* BFD symbol was found in. */ + } undef; + /* bfd_link_hash_defined. */ + struct + { + bfd_vma value; /* Symbol value. */ + asection *section; /* Symbol section. */ + } def; + /* bfd_link_hash_indirect, bfd_link_hash_warning. */ + struct + { + struct bfd_link_hash_entry *link; /* Real symbol. */ + const char *warning; /* Warning (bfd_link_hash_warning only). */ + } i; + /* bfd_link_hash_common. */ + struct + { + bfd_vma size; /* Common symbol size. */ + asection *section; /* Symbol section. */ + } c; + } u; +}; + +/* This is the link hash table. It is a derived class of + bfd_hash_table. */ + +struct bfd_link_hash_table +{ + /* The hash table itself. */ + struct bfd_hash_table table; + /* The back end which created this hash table. This indicates the + type of the entries in the hash table, which is sometimes + important information when linking object files of different + types together. */ + const bfd_target *creator; + /* A linked list of undefined and common symbols, linked through the + next field in the bfd_link_hash_entry structure. */ + struct bfd_link_hash_entry *undefs; + /* Entries are added to the tail of the undefs list. */ + struct bfd_link_hash_entry *undefs_tail; +}; + +/* Look up an entry in a link hash table. If FOLLOW is true, this + follows bfd_link_hash_indirect and bfd_link_hash_warning links to + the real symbol. */ +extern struct bfd_link_hash_entry *bfd_link_hash_lookup + PARAMS ((struct bfd_link_hash_table *, const char *, boolean create, + boolean copy, boolean follow)); + +/* Traverse a link hash table. */ +extern void bfd_link_hash_traverse + PARAMS ((struct bfd_link_hash_table *, + boolean (*) (struct bfd_link_hash_entry *, PTR), + PTR)); + +/* Add an entry to the undefs list. */ +extern void bfd_link_add_undef + PARAMS ((struct bfd_link_hash_table *, struct bfd_link_hash_entry *)); + +/* This structure holds all the information needed to communicate + between BFD and the linker when doing a link. */ + +struct bfd_link_info +{ + /* Function callbacks. */ + const struct bfd_link_callbacks *callbacks; + /* true if BFD should generate a relocateable object file. */ + boolean relocateable; + /* true if BFD should generate a shared object. */ + boolean shared; + /* Which symbols to strip. */ + enum bfd_link_strip strip; + /* Which local symbols to discard. */ + enum bfd_link_discard discard; + /* The local symbol prefix to discard if using discard_l. */ + unsigned int lprefix_len; + const char *lprefix; + /* true if symbols should be retained in memory, false if they + should be freed and reread. */ + boolean keep_memory; + /* The list of input BFD's involved in the link. These are chained + together via the link_next field. */ + bfd *input_bfds; + /* If a symbol should be created for each input BFD, this is section + where those symbols should be placed. It must be a section in + the output BFD. It may be NULL, in which case no such symbols + will be created. This is to support CREATE_OBJECT_SYMBOLS in the + linker command language. */ + asection *create_object_symbols_section; + /* Hash table handled by BFD. */ + struct bfd_link_hash_table *hash; + /* Hash table of symbols to keep. This is NULL unless strip is + strip_some. */ + struct bfd_hash_table *keep_hash; + /* Hash table of symbols to report back via notice_callback. If + this is NULL no symbols are reported back. */ + struct bfd_hash_table *notice_hash; +}; + +/* This structures holds a set of callback functions. These are + called by the BFD linker routines. The first argument to each + callback function is the bfd_link_info structure being used. Each + function returns a boolean value. If the function returns false, + then the BFD function which called it will return with a failure + indication. */ + +struct bfd_link_callbacks +{ + /* A function which is called when an object is added from an + archive. ABFD is the archive element being added. NAME is the + name of the symbol which caused the archive element to be pulled + in. */ + boolean (*add_archive_element) PARAMS ((struct bfd_link_info *, + bfd *abfd, + const char *name)); + /* A function which is called when a symbol is found with multiple + definitions. NAME is the symbol which is defined multiple times. + OBFD is the old BFD, OSEC is the old section, OVAL is the old + value, NBFD is the new BFD, NSEC is the new section, and NVAL is + the new value. OBFD may be NULL. OSEC and NSEC may be + bfd_com_section or bfd_ind_section. */ + boolean (*multiple_definition) PARAMS ((struct bfd_link_info *, + const char *name, + bfd *obfd, + asection *osec, + bfd_vma oval, + bfd *nbfd, + asection *nsec, + bfd_vma nval)); + /* A function which is called when a common symbol is defined + multiple times. NAME is the symbol appearing multiple times. + OBFD is the BFD of the existing symbol. OTYPE is the type of the + existing symbol, either bfd_link_hash_defined or + bfd_link_hash_common. If OTYPE is bfd_link_hash_common, OSIZE is + the size of the existing symbol. NBFD is the BFD of the new + symbol. NTYPE is the type of the new symbol, either + bfd_link_hash_defined or bfd_link_hash_common. If NTYPE is + bfd_link_hash_common, NSIZE is the size of the new symbol. */ + boolean (*multiple_common) PARAMS ((struct bfd_link_info *, + const char *name, + bfd *obfd, + enum bfd_link_hash_type otype, + bfd_vma osize, + bfd *nbfd, + enum bfd_link_hash_type ntype, + bfd_vma nsize)); + /* A function which is called to add a symbol to a set. ENTRY is + the link hash table entry for the set itself (e.g., + __CTOR_LIST__). RELOC is the relocation to use for an entry in + the set when generating a relocateable file, and is also used to + get the size of the entry when generating an executable file. + ABFD, SEC and VALUE identify the value to add to the set. */ + boolean (*add_to_set) PARAMS ((struct bfd_link_info *, + struct bfd_link_hash_entry *entry, + bfd_reloc_code_real_type reloc, + bfd *abfd, asection *sec, bfd_vma value)); + /* A function which is called when the name of a g++ constructor or + destructor is found. This is only called by some object file + formats. CONSTRUCTOR is true for a constructor, false for a + destructor. This will use BFD_RELOC_CTOR when generating a + relocateable file. NAME is the name of the symbol found. ABFD, + SECTION and VALUE are the value of the symbol. */ + boolean (*constructor) PARAMS ((struct bfd_link_info *, + boolean constructor, + const char *name, bfd *abfd, asection *sec, + bfd_vma value)); + /* A function which is called when there is a reference to a warning + symbol. WARNING is the warning to be issued. */ + boolean (*warning) PARAMS ((struct bfd_link_info *, + const char *warning)); + /* A function which is called when a relocation is attempted against + an undefined symbol. NAME is the symbol which is undefined. + ABFD, SECTION and ADDRESS identify the location from which the + reference is made. */ + boolean (*undefined_symbol) PARAMS ((struct bfd_link_info *, + const char *name, bfd *abfd, + asection *section, bfd_vma address)); + /* A function which is called when a reloc overflow occurs. NAME is + the name of the symbol or section the reloc is against, + RELOC_NAME is the name of the relocation, and ADDEND is any + addend that is used. ABFD, SECTION and ADDRESS identify the + location at which the overflow occurs; if this is the result of a + bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then + ABFD will be NULL. */ + boolean (*reloc_overflow) PARAMS ((struct bfd_link_info *, + const char *name, + const char *reloc_name, bfd_vma addend, + bfd *abfd, asection *section, + bfd_vma address)); + /* A function which is called when a dangerous reloc is performed. + The canonical example is an a29k IHCONST reloc which does not + follow an IHIHALF reloc. MESSAGE is an appropriate message. + ABFD, SECTION and ADDRESS identify the location at which the + problem occurred; if this is the result of a + bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then + ABFD will be NULL. */ + boolean (*reloc_dangerous) PARAMS ((struct bfd_link_info *, + const char *message, + bfd *abfd, asection *section, + bfd_vma address)); + /* A function which is called when a reloc is found to be attached + to a symbol which is not being written out. NAME is the name of + the symbol. ABFD, SECTION and ADDRESS identify the location of + the reloc; if this is the result of a + bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then + ABFD will be NULL. */ + boolean (*unattached_reloc) PARAMS ((struct bfd_link_info *, + const char *name, + bfd *abfd, asection *section, + bfd_vma address)); + /* A function which is called when a symbol in notice_hash is + defined or referenced. NAME is the symbol. ABFD, SECTION and + ADDRESS are the value of the symbol. If SECTION is + bfd_und_section, this is a reference. */ + boolean (*notice) PARAMS ((struct bfd_link_info *, const char *name, + bfd *abfd, asection *section, bfd_vma address)); +}; + +/* The linker builds link_order structures which tell the code how to + include input data in the output file. */ + +/* These are the types of link_order structures. */ + +enum bfd_link_order_type +{ + bfd_undefined_link_order, /* Undefined. */ + bfd_indirect_link_order, /* Built from a section. */ + bfd_fill_link_order, /* Fill with a 16 bit constant. */ + bfd_data_link_order, /* Set to explicit data. */ + bfd_section_reloc_link_order, /* Relocate against a section. */ + bfd_symbol_reloc_link_order /* Relocate against a symbol. */ +}; + +/* This is the link_order structure itself. These form a chain + attached to the section whose contents they are describing. */ + +struct bfd_link_order +{ + /* Next link_order in chain. */ + struct bfd_link_order *next; + /* Type of link_order. */ + enum bfd_link_order_type type; + /* Offset within output section. */ + bfd_vma offset; + /* Size within output section. */ + bfd_size_type size; + /* Type specific information. */ + union + { + struct + { + /* Section to include. If this is used, then + section->output_section must be the section the + link_order is attached to, section->output_offset must + equal the link_order offset field, and section->_raw_size + must equal the link_order size field. Maybe these + restrictions should be relaxed someday. */ + asection *section; + } indirect; + struct + { + /* Value to fill with. */ + unsigned int value; + } fill; + struct + { + /* Data to put into file. The size field gives the number + of bytes which this field points to. */ + bfd_byte *contents; + } data; + struct + { + /* Description of reloc to generate. Used for + bfd_section_reloc_link_order and + bfd_symbol_reloc_link_order. */ + struct bfd_link_order_reloc *p; + } reloc; + } u; +}; + +/* A linker order of type bfd_section_reloc_link_order or + bfd_symbol_reloc_link_order means to create a reloc against a + section or symbol, respectively. This is used to implement -Ur to + generate relocs for the constructor tables. The + bfd_link_order_reloc structure describes the reloc that BFD should + create. It is similar to a arelent, but I didn't use arelent + because the linker does not know anything about most symbols, and + any asymbol structure it creates will be partially meaningless. + This information could logically be in the bfd_link_order struct, + but I didn't want to waste the space since these types of relocs + are relatively rare. */ + +struct bfd_link_order_reloc +{ + /* Reloc type. */ + bfd_reloc_code_real_type reloc; + + union + { + /* For type bfd_section_reloc_link_order, this is the section + the reloc should be against. This must be a section in the + output BFD, not any of the input BFDs. */ + asection *section; + /* For type bfd_symbol_reloc_link_order, this is the name of the + symbol the reloc should be against. */ + const char *name; + } u; + + /* Addend to use. The object file should contain zero. The BFD + backend is responsible for filling in the contents of the object + file correctly. For some object file formats (e.g., COFF) the + addend must be stored into in the object file, and for some + (e.g., SPARC a.out) it is kept in the reloc. */ + bfd_vma addend; +}; + +/* Allocate a new link_order for a section. */ +extern struct bfd_link_order *bfd_new_link_order PARAMS ((bfd *, asection *)); + +#endif diff --git a/gnu/usr.bin/gdb/gdb/coff/i386.h b/gnu/usr.bin/gdb/gdb/coff/i386.h new file mode 100644 index 00000000000..df80c2982be --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/coff/i386.h @@ -0,0 +1,221 @@ +/*** coff information for Intel 386/486. */ + + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + + +/* Bits for f_flags: + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (no unresolved external references) + * F_LNNO line numbers stripped from file + * F_LSYMS local symbols stripped from file + * F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax) + */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) + + + +#define I386MAGIC 0x14c +#define I386PTXMAGIC 0x154 +#define I386AIXMAGIC 0x175 + +/* This is Lynx's all-platform magic number for executables. */ + +#define LYNXCOFFMAGIC 0415 + +#define I386BADMAG(x) (((x).f_magic != I386MAGIC) \ + && (x).f_magic != I386AIXMAGIC \ + && (x).f_magic != I386PTXMAGIC \ + && (x).f_magic != LYNXCOFFMAGIC) + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + + +/********************** AOUT "OPTIONAL HEADER" **********************/ + + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry*/ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +AOUTHDR; + + +#define AOUTSZ (sizeof(AOUTHDR)) + +#define OMAGIC 0404 /* object files, eg as output */ +#define ZMAGIC 0413 /* demand load format, eg normal ld output */ +#define STMAGIC 0401 /* target shlib */ +#define SHMAGIC 0443 /* host shlib */ + + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries*/ + char s_flags[4]; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _COMMENT ".comment" +#define _LIB ".lib" + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + + +#define LINENO struct external_lineno +#define LINESZ 6 + + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + char e_zeroes[4]; + char e_offset[4]; + } e; + } e; + char e_value[4]; + char e_scnum[2]; + char e_type[2]; + char e_sclass[1]; + char e_numaux[1]; +}; + +#define N_BTMASK (0xf) +#define N_TMASK (0x30) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +union external_auxent { + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + char x_tvndx[2]; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + + +# define _ETEXT "etext" + + +/********************** RELOCATION DIRECTIVES **********************/ + + + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; +}; + + +#define RELOC struct external_reloc +#define RELSZ 10 + +#define DEFAULT_DATA_SECTION_ALIGNMENT 4 +#define DEFAULT_BSS_SECTION_ALIGNMENT 4 +#define DEFAULT_TEXT_SECTION_ALIGNMENT 4 +/* For new sections we havn't heard of before */ +#define DEFAULT_SECTION_ALIGNMENT 4 diff --git a/gnu/usr.bin/gdb/gdb/disassemble.c b/gnu/usr.bin/gdb/gdb/disassemble.c new file mode 100644 index 00000000000..87aa6cae057 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/disassemble.c @@ -0,0 +1,148 @@ +/* Select disassembly routine for specified architecture. + Copyright 1994 Free Software Foundation, Inc. + +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. */ + +#include "ansidecl.h" +#include "dis-asm.h" + +#ifdef ARCH_all +#define ARCH_a29k +#define ARCH_alpha +#define ARCH_h8300 +#define ARCH_h8500 +#define ARCH_hppa +#define ARCH_i386 +#define ARCH_i960 +#define ARCH_m68k +#define ARCH_m88k +#define ARCH_mips +#define ARCH_ns32k +#define ARCH_powerpc +#define ARCH_rs6000 +#define ARCH_sh +#define ARCH_sparc +#define ARCH_z8k +#endif + +disassembler_ftype +disassembler (abfd) + bfd *abfd; +{ + enum bfd_architecture a = bfd_get_arch (abfd); + disassembler_ftype disassemble; + + switch (a) + { + /* If you add a case to this table, also add it to the + ARCH_all definition right above this function. */ +#ifdef ARCH_a29k + case bfd_arch_a29k: + /* As far as I know we only handle big-endian 29k objects. */ + disassemble = print_insn_big_a29k; + break; +#endif +#ifdef ARCH_alpha + case bfd_arch_alpha: + disassemble = print_insn_alpha; + break; +#endif +#ifdef ARCH_h8300 + case bfd_arch_h8300: + if (bfd_get_mach(abfd) == bfd_mach_h8300h) + disassemble = print_insn_h8300h; + else + disassemble = print_insn_h8300; + break; +#endif +#ifdef ARCH_h8500 + case bfd_arch_h8500: + disassemble = print_insn_h8500; + break; +#endif +#ifdef ARCH_hppa + case bfd_arch_hppa: + disassemble = print_insn_hppa; + break; +#endif +#ifdef ARCH_i386 + case bfd_arch_i386: + disassemble = print_insn_i386; + break; +#endif +#ifdef ARCH_i960 + case bfd_arch_i960: + disassemble = print_insn_i960; + break; +#endif +#ifdef ARCH_m68k + case bfd_arch_m68k: + disassemble = print_insn_m68k; + break; +#endif +#ifdef ARCH_m88k + case bfd_arch_m88k: + disassemble = print_insn_m88k; + break; +#endif +#ifdef ARCH_ns32k + case bfd_arch_ns32k: + disassemble = print_insn_ns32k; + break; +#endif +#ifdef ARCH_mips + case bfd_arch_mips: + if (abfd->xvec->byteorder_big_p) + disassemble = print_insn_big_mips; + else + disassemble = print_insn_little_mips; + break; +#endif +#ifdef ARCH_powerpc + case bfd_arch_powerpc: + if (abfd->xvec->byteorder_big_p) + disassemble = print_insn_big_powerpc; + else + disassemble = print_insn_little_powerpc; + break; +#endif +#ifdef ARCH_rs6000 + case bfd_arch_rs6000: + disassemble = print_insn_rs6000; + break; +#endif +#ifdef ARCH_sh + case bfd_arch_sh: + disassemble = print_insn_sh; + break; +#endif +#ifdef ARCH_sparc + case bfd_arch_sparc: + disassemble = print_insn_sparc; + break; +#endif +#ifdef ARCH_z8k + case bfd_arch_z8k: + if (bfd_get_mach(abfd) == bfd_mach_z8001) + disassemble = print_insn_z8001; + else + disassemble = print_insn_z8002; + break; +#endif + default: + return 0; + } + return disassemble; +} diff --git a/gnu/usr.bin/gdb/gdb/floatformat.h b/gnu/usr.bin/gdb/gdb/floatformat.h new file mode 100644 index 00000000000..a0a53dc534c --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/floatformat.h @@ -0,0 +1,87 @@ +/* IEEE floating point support declarations, for GDB, the GNU Debugger. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +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. */ + +#if !defined (FLOATFORMAT_H) +#define FLOATFORMAT_H 1 + +#include "ansidecl.h" + +/* A floatformat consists of a sign bit, an exponent and a mantissa. Once the + bytes are concatenated according to the byteorder flag, then each of those + fields is contiguous. We number the bits with 0 being the most significant + (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field + contains with the *_start and *_len fields. */ + +enum floatformat_byteorders { floatformat_little, floatformat_big }; + +enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no }; + +struct floatformat +{ + enum floatformat_byteorders byteorder; + unsigned int totalsize; /* Total size of number in bits */ + + /* Sign bit is always one bit long. 1 means negative, 0 means positive. */ + unsigned int sign_start; + + unsigned int exp_start; + unsigned int exp_len; + /* Amount added to "true" exponent. 0x3fff for many IEEE extendeds. */ + unsigned int exp_bias; + /* Exponent value which indicates NaN. This is the actual value stored in + the float, not adjusted by the exp_bias. This usually consists of all + one bits. */ + unsigned int exp_nan; + + unsigned int man_start; + unsigned int man_len; + + /* Is the integer bit explicit or implicit? */ + enum floatformat_intbit intbit; +}; + +/* floatformats for IEEE single and double, big and little endian. */ + +extern const struct floatformat floatformat_ieee_single_big; +extern const struct floatformat floatformat_ieee_single_little; +extern const struct floatformat floatformat_ieee_double_big; +extern const struct floatformat floatformat_ieee_double_little; + +/* floatformats for various extendeds. */ + +extern const struct floatformat floatformat_i387_ext; +extern const struct floatformat floatformat_m68881_ext; +extern const struct floatformat floatformat_i960_ext; +extern const struct floatformat floatformat_m88110_ext; + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +extern void +floatformat_to_double PARAMS ((const struct floatformat *, char *, double *)); + +/* The converse: convert the double *FROM to FMT + and store where TO points. */ + +extern void +floatformat_from_double PARAMS ((const struct floatformat *, + double *, char *)); + +#endif /* defined (FLOATFORMAT_H) */ diff --git a/gnu/usr.bin/gdb/gdb/fopen-bin.h b/gnu/usr.bin/gdb/gdb/fopen-bin.h new file mode 100644 index 00000000000..b868f63d46d --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/fopen-bin.h @@ -0,0 +1,27 @@ +/* Macros for the 'type' part of an fopen, freopen or fdopen. + + [Update] + + This version is for "binary" systems, where text and binary files are + different. An example is Mess-Dose. Many Unix systems could also + cope with a "b" in the string, indicating binary files, but some reject this + (and thereby don't conform to ANSI C, but what else is new?). + + This file is designed for inclusion by host-dependent .h files. No + user application should include it directly, since that would make + the application unable to be configured for both "same" and "binary" + variant systems. */ + +#define FOPEN_RB "rb" +#define FOPEN_WB "wb" +#define FOPEN_AB "ab" +#define FOPEN_RUB "r+b" +#define FOPEN_WUB "w+b" +#define FOPEN_AUB "a+b" + +#define FOPEN_RT "r" +#define FOPEN_WT "w" +#define FOPEN_AT "a" +#define FOPEN_RUT "r+" +#define FOPEN_WUT "w+" +#define FOPEN_AUT "a+" diff --git a/gnu/usr.bin/gdb/gdb/gdbm.h b/gnu/usr.bin/gdb/gdb/gdbm.h new file mode 100644 index 00000000000..18b324db6da --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/gdbm.h @@ -0,0 +1,91 @@ +/* GNU DBM - DataBase Manager include file + Copyright 1989, 1991 Free Software Foundation, Inc. + Written by Philip A. Nelson. + +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. */ + +/* You may contact the author by: + e-mail: phil@wwu.edu + us-mail: Philip A. Nelson + Computer Science Department + Western Washington University + Bellingham, WA 98226 + phone: (206) 676-3035 + +*************************************************************************/ + +/* Parameters to gdbm_open for READERS, WRITERS, and WRITERS who + can create the database. */ +#define GDBM_READER 0 +#define GDBM_WRITER 1 +#define GDBM_WRCREAT 2 +#define GDBM_NEWDB 3 + +/* Parameters to gdbm_store for simple insertion or replacement. */ +#define GDBM_INSERT 0 +#define GDBM_REPLACE 1 + + +/* The data and key structure. This structure is defined for compatibility. */ +typedef struct { + char *dptr; + int dsize; + } datum; + + +/* The file information header. This is good enough for most applications. */ +typedef struct {int dummy[10];} *GDBM_FILE; + + +/* These are the routines! */ + +extern GDBM_FILE gdbm_open (); + +extern void gdbm_close (); + +extern datum gdbm_fetch (); + +extern int gdbm_store (); + +extern int gdbm_delete (); + +extern datum gdbm_firstkey (); + +extern datum gdbm_nextkey (); + +extern int gdbm_reorganize (); + + +/* gdbm sends back the following error codes in the variable gdbm_errno. */ +typedef enum { NO_ERROR, + MALLOC_ERROR, + BLOCK_SIZE_ERROR, + FILE_OPEN_ERROR, + FILE_WRITE_ERROR, + FILE_SEEK_ERROR, + FILE_READ_ERROR, + BAD_MAGIC_NUMBER, + EMPTY_DATABASE, + CANT_BE_READER, + CANT_BE_WRITER, + READER_CANT_RECOVER, + READER_CANT_DELETE, + READER_CANT_STORE, + READER_CANT_REORGANIZE, + UNKNOWN_UPDATE, + ITEM_NOT_FOUND, + REORGANIZE_FAILED, + CANNOT_REPLACE} + gdbm_error; diff --git a/gnu/usr.bin/gdb/gdb/ieee.h b/gnu/usr.bin/gdb/gdb/ieee.h new file mode 100644 index 00000000000..077bb48ac8b --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/ieee.h @@ -0,0 +1,132 @@ +/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file + Contributed by Cygnus Support. */ + +#define N_W_VARIABLES 8 +#define Module_Beginning 0xe0 + +typedef struct ieee_module { + char *processor; + char *module_name; +} ieee_module_begin_type; + +#define Address_Descriptor 0xec +typedef struct ieee_address { +bfd_vma number_of_bits_mau; + bfd_vma number_of_maus_in_address; + + unsigned char byte_order; +#define IEEE_LITTLE 0xcc +#define IEEE_BIG 0xcd +} ieee_address_descriptor_type; + +typedef union ieee_w_variable { + file_ptr offset[N_W_VARIABLES]; + struct { + file_ptr extension_record; + file_ptr environmental_record; + file_ptr section_part; + file_ptr external_part; + file_ptr debug_information_part; + file_ptr data_part; + file_ptr trailer_part; + file_ptr me_record; + } r; +} ieee_w_variable_type; + + + + + +typedef enum ieee_record +{ + ieee_number_start_enum = 0x00, + ieee_number_end_enum=0x7f, + ieee_number_repeat_start_enum = 0x80, + ieee_number_repeat_end_enum = 0x88, + ieee_number_repeat_4_enum = 0x84, + ieee_number_repeat_3_enum = 0x83, + ieee_number_repeat_2_enum = 0x82, + ieee_number_repeat_1_enum = 0x81, + ieee_module_beginning_enum = 0xe0, + ieee_module_end_enum = 0xe1, + ieee_extension_length_1_enum = 0xde, + ieee_extension_length_2_enum = 0xdf, + ieee_section_type_enum = 0xe6, + ieee_section_alignment_enum = 0xe7, + ieee_external_symbol_enum = 0xe8, + ieee_attribute_record_enum = 0xf1c9, + ieee_comma = 0x90, + ieee_external_reference_enum = 0xe9, + ieee_set_current_section_enum = 0xe5, + ieee_address_descriptor_enum = 0xec, + ieee_load_constant_bytes_enum = 0xed, + ieee_load_with_relocation_enum = 0xe4, + + ieee_variable_A_enum = 0xc1, + ieee_variable_B_enum = 0xc2, + ieee_variable_C_enum = 0xc3, + ieee_variable_D_enum = 0xc4, + ieee_variable_E_enum = 0xc5, + ieee_variable_F_enum = 0xc6, + ieee_variable_G_enum = 0xc7, + ieee_variable_H_enum = 0xc8, + ieee_variable_I_enum = 0xc9, + ieee_variable_J_enum = 0xca, + ieee_variable_K_enum = 0xcb, + ieee_variable_L_enum = 0xcc, + ieee_variable_M_enum = 0xcd, + ieee_variable_N_enum = 0xce, + ieee_variable_O_enum = 0xcf, + ieee_variable_P_enum = 0xd0, + ieee_variable_Q_enum = 0xd1, + ieee_variable_R_enum = 0xd2, + ieee_variable_S_enum = 0xd3, + ieee_variable_T_enum = 0xd4, + ieee_variable_U_enum = 0xd5, + ieee_variable_V_enum = 0xd6, + ieee_variable_W_enum = 0xd7, + ieee_variable_X_enum = 0xd8, + ieee_variable_Y_enum = 0xd9, + ieee_variable_Z_enum = 0xda, + ieee_function_plus_enum = 0xa5, + ieee_function_minus_enum = 0xa6, + ieee_function_signed_open_b_enum = 0xba, + ieee_function_signed_close_b_enum = 0xbb, + + ieee_function_unsigned_open_b_enum = 0xbc, + ieee_function_unsigned_close_b_enum = 0xbd, + + ieee_function_either_open_b_enum = 0xbe, + ieee_function_either_close_b_enum = 0xbf, + ieee_record_seperator_enum = 0xdb, + + ieee_e2_first_byte_enum = 0xe2, + ieee_section_size_enum = 0xe2d3, + ieee_physical_region_size_enum = 0xe2c1, + ieee_region_base_address_enum = 0xe2c2, + ieee_mau_size_enum = 0xe2c6, + ieee_m_value_enum = 0xe2cd, + ieee_section_base_address_enum = 0xe2cc, + ieee_section_offset_enum = 0xe2d2, + ieee_value_starting_address_enum = 0xe2c7, + ieee_assign_value_to_variable_enum = 0xe2d7, + ieee_set_current_pc_enum = 0xe2d0, + ieee_value_record_enum = 0xe2c9, +ieee_nn_record = 0xf0, + ieee_weak_external_reference_enum= 0xf4, + ieee_repeat_data_enum = 0xf7 +} ieee_record_enum_type; + + +typedef struct ieee_section { + unsigned int section_index; + unsigned int section_type; + char *section_name; + unsigned int parent_section_index; + unsigned int sibling_section_index; + unsigned int context_index; +} ieee_section_type; +#define IEEE_REFERENCE_BASE 11 +#define IEEE_PUBLIC_BASE 32 +#define IEEE_SECTION_NUMBER_BASE 1 + diff --git a/gnu/usr.bin/gdb/gdb/kcorelow.c b/gnu/usr.bin/gdb/gdb/kcorelow.c new file mode 100644 index 00000000000..d97c5940f55 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/kcorelow.c @@ -0,0 +1,353 @@ +/* Core dump and executable file functions below target vector, for GDB. + Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc. + +This file is part of GDB. + +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: kcorelow.c,v 1.2 1994/05/18 12:42:15 pk Exp $ +*/ + +#include "defs.h" + +#ifdef KERNEL_DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "symtab.h" +#include "command.h" +#include "bfd.h" +#include "target.h" +#include "gdbcore.h" + +static void +kcore_files_info PARAMS ((struct target_ops *)); + +static void +kcore_close PARAMS ((int)); + +static void +get_kcore_registers PARAMS ((int)); + +static int +xfer_mem PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *)); + +static int +xfer_umem PARAMS ((CORE_ADDR, char *, int, int)); + +static char *core_file; +static int core_kd = -1; +static struct proc *cur_proc; +static CORE_ADDR kernel_start; + +/* + * Read the "thing" at kernel address 'addr' into the space pointed to + * by point. The length of the "thing" is determined by the type of p. + * Result is non-zero if transfer fails. + */ +#define kvread(addr, p) \ + (target_read_memory((CORE_ADDR)(addr), (char *)(p), sizeof(*(p)))) + +extern read_pcb (int, CORE_ADDR); + +CORE_ADDR +ksym_lookup(name) +const char *name; +{ + struct minimal_symbol *sym; + + sym = lookup_minimal_symbol(name, (struct objfile *)NULL); + if (sym == NULL) + error("kernel symbol `%s' not found.", name); + + return SYMBOL_VALUE_ADDRESS(sym); +} + +static struct proc * +curProc() +{ + struct proc *p; + CORE_ADDR addr = ksym_lookup("curproc"); + + if (kvread(addr, &p)) + error("cannot read proc pointer at %x\n", addr); + return p; +} + +/* + * Set the process context to that of the proc structure at + * system address paddr. + */ +static int +set_proc_context(paddr) + CORE_ADDR paddr; +{ + struct proc p; + + if (paddr < kernel_start) + return (1); + + cur_proc = (struct proc *)paddr; +#ifdef notyet + set_kernel_boundaries(cur_proc); +#endif + + /* Fetch all registers from core file */ + target_fetch_registers (-1); + + /* Now, set up the frame cache, and print the top of stack */ + flush_cached_frames(); + set_current_frame (create_new_frame (read_fp (), read_pc ())); + select_frame (get_current_frame (), 0); + return (0); +} + +/* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + +/* ARGSUSED */ +static void +kcore_close (quitting) + int quitting; +{ + inferior_pid = 0; /* Avoid confusion from thread stuff */ + + if (core_kd) { + kvm_close(core_kd); + free(core_file); + core_file = NULL; + core_kd = -1; + } +} + +/* This routine opens and sets up the core file bfd */ + +void +kcore_open (filename, from_tty) + char *filename; + int from_tty; +{ + const char *p; + struct cleanup *old_chain; + char buf[256], *cp; + int ontop; + CORE_ADDR addr; + struct pcb pcb; + + target_preopen (from_tty); + if (!filename) { + /*error (core_kd?*/ + error ((core_kd >= 0)? + "No core file specified. (Use `detach' to stop debugging a core file.)" + : "No core file specified."); + } + + filename = tilde_expand (filename); + if (filename[0] != '/') { + cp = concat (current_directory, "/", filename, NULL); + free (filename); + filename = cp; + } + + old_chain = make_cleanup (free, filename); + + core_kd = kvm_open (exec_bfd->filename, filename, NULL, + write_files? O_RDWR: O_RDONLY, 0); + if (core_kd < 0) + perror_with_name (filename); + + /* Looks semi-reasonable. Toss the old core file and work on the new. */ + + discard_cleanups (old_chain); /* Don't free filename any more */ + core_file = filename; + unpush_target (&kcore_ops); + ontop = !push_target (&kcore_ops); + + kernel_start = bfd_get_start_address (exec_bfd); /* XXX */ + + /* print out the panic string if there is one */ + if (kvread(ksym_lookup("panicstr"), &addr) == 0 && + addr != 0 && + target_read_memory(addr, buf, sizeof(buf)) == 0) { + + for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++) + if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp))) + *cp = '?'; + *cp = '\0'; + if (buf[0] != '\0') + printf("panic: %s\n", buf); + } + + if (!ontop) { + warning ( +"you won't be able to access this core file until you terminate\n\ +your %s; do ``info files''", current_target->to_longname); + return; + } + + /* we may need this later */ + cur_proc = (struct proc *)curProc(); + /* Now, set up the frame cache, and print the top of stack */ + flush_cached_frames(); + set_current_frame (create_new_frame (read_fp (), read_pc ())); + select_frame (get_current_frame (), 0); + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +void +kcore_detach (args, from_tty) + char *args; + int from_tty; +{ + if (args) + error ("Too many arguments"); + unpush_target (&kcore_ops); + reinit_frame_cache (); + if (from_tty) + printf_filtered ("No kernel core file now.\n"); +} + +/* Get the registers out of a core file. This is the machine- + independent part. Fetch_core_registers is the machine-dependent + part, typically implemented in the xm-file for each architecture. */ + +/* We just get all the registers, so we don't use regno. */ +/* ARGSUSED */ +static void +get_kcore_registers (regno) + int regno; +{ + struct user *uaddr; + + /* find the pcb for the current process */ + if (kvread(&cur_proc->p_addr, &uaddr)) + error("cannot read u area ptr for proc at %#x", cur_proc); + if (read_pcb (core_kd, (CORE_ADDR)&uaddr->u_pcb) < 0) + error("cannot read pcb at %#x", &uaddr->u_pcb); +} + +/* If mourn is being called in all the right places, this could be say + `gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */ + +static int +ignore (addr, contents) + CORE_ADDR addr; + char *contents; +{ + return 0; +} + +static void +kcore_files_info (t) + struct target_ops *t; +{ + printf("\t`%s'\n", core_file); +} + +static int +xfer_kmem (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; +{ + int n; + + if (!memaddr) + return (0); + + if (memaddr < kernel_start) + return xfer_umem(memaddr, myaddr, len, write); + + n = write ? + kvm_write(core_kd, memaddr, myaddr, len) : + kvm_read(core_kd, memaddr, myaddr, len) ; + + if (n < 0) + return 0; + return n; +} + +static int +xfer_umem (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; /* ignored */ +{ + int n; + struct proc proc; + + if (kvread(cur_proc, &proc)) + error("cannot read proc at %#x", cur_proc); + n = kvm_uread(core_kd, &proc, memaddr, myaddr, len) ; + + if (n < 0) + return 0; + return n; +} + +static void +set_proc_cmd(arg) + char *arg; +{ + CORE_ADDR paddr; + + if (!arg) + error_no_arg("proc address for new current process"); + if (!kernel_debugging) + error("not debugging kernel"); + + paddr = (CORE_ADDR)parse_and_eval_address(arg); + if (set_proc_context(paddr)) + error("invalid proc address"); +} + +struct target_ops kcore_ops = { + "kcore", "Kernel core dump file", + "Use a core file as a target. Specify the filename of the core file.", + kcore_open, kcore_close, + find_default_attach, kcore_detach, 0, 0, /* resume, wait */ + get_kcore_registers, + 0, 0, /* store_regs, prepare_to_store */ + xfer_kmem, kcore_files_info, + ignore, ignore, /* core_insert_breakpoint, core_remove_breakpoint, */ + 0, 0, 0, 0, 0, /* terminal stuff */ + 0, 0, 0, /* kill, load, lookup sym */ + find_default_create_inferior, 0, /* mourn_inferior */ + 0, /* can_run */ + 0, /* notice_signals */ + kcore_stratum, 0, /* next */ + 0, 1, 1, 1, 0, /* all mem, mem, stack, regs, exec */ + 0, 0, /* section pointers */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_kcorelow() +{ + add_target (&kcore_ops); + add_com ("proc", class_obscure, set_proc_cmd, "Set current process context"); +} + +#endif /* KERNEL_DEBUG */ diff --git a/gnu/usr.bin/gdb/gdb/libiberty.h b/gnu/usr.bin/gdb/gdb/libiberty.h new file mode 100644 index 00000000000..9854b4c397e --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/libiberty.h @@ -0,0 +1,107 @@ +/* Function declarations for libiberty. + Written by Cygnus Support, 1994. + + The libiberty library provides a number of functions which are + missing on some operating systems. We do not declare those here, + to avoid conflicts with the system header files on operating + systems that do support those functions. In this file we only + declare those functions which are specific to libiberty. */ + +#ifndef LIBIBERTY_H +#define LIBIBERTY_H + +#include "ansidecl.h" + +/* Build an argument vector from a string. Allocates memory using + malloc. Use freeargv to free the vector. */ + +extern char **buildargv PARAMS ((char *)); + +/* Free a vector returned by buildargv. */ + +extern void freeargv PARAMS ((char **)); + +/* Return the last component of a path name. */ + +extern char *basename PARAMS ((char *)); + +/* Concatenate an arbitrary number of strings, up to (char *) NULL. + Allocates memory using xmalloc. */ + +extern char *concat PARAMS ((const char *, ...)); + +/* Check whether two file descriptors refer to the same file. */ + +extern int fdmatch PARAMS ((int fd1, int fd2)); + +/* Get the amount of time the process has run, in microseconds. */ + +extern long get_run_time PARAMS ((void)); + +/* Allocate memory filled with spaces. Allocates using malloc. */ + +extern const char *spaces PARAMS ((int count)); + +/* Return the maximum error number for which strerror will return a + string. */ + +extern int errno_max PARAMS ((void)); + +/* Return the name of an errno value (e.g., strerrno (EINVAL) returns + "EINVAL"). */ + +extern const char *strerrno PARAMS ((int)); + +/* Given the name of an errno value, return the value. */ + +extern int strtoerrno PARAMS ((const char *)); + +/* Return the maximum signal number for which strsignal will return a + string. */ + +extern int signo_max PARAMS ((void)); + +/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns + "SIGHUP"). */ + +extern const char *strsigno PARAMS ((int)); + +/* Given the name of a signal, return its number. */ + +extern int strtosigno PARAMS ((const char *)); + +/* Register a function to be run by xexit. Returns 0 on success. */ + +extern int xatexit PARAMS ((void (*fn) (void))); + +/* Exit, calling all the functions registered with xatexit. */ + +#ifndef __GNUC__ +extern void xexit PARAMS ((int status)); +#else +typedef void libiberty_voidfn PARAMS ((int status)); +__volatile__ libiberty_voidfn xexit; +#endif + +/* Set the program name used by xmalloc. */ + +extern void xmalloc_set_program_name PARAMS ((const char *)); + +/* Allocate memory without fail. If malloc fails, this will print a + message to stderr (using the name set by xmalloc_set_program_name, + if any) and then call xexit. + + FIXME: We do not declare the parameter type (size_t) in order to + avoid conflicts with other declarations of xmalloc that exist in + programs which use libiberty. */ + +extern PTR xmalloc (); + +/* Reallocate memory without fail. This works like xmalloc. + + FIXME: We do not declare the parameter types for the same reason as + xmalloc. */ + +extern PTR xrealloc (); + +#endif /* ! defined (LIBIBERTY_H) */ diff --git a/gnu/usr.bin/gdb/gdb/mdebugread.c b/gnu/usr.bin/gdb/gdb/mdebugread.c new file mode 100644 index 00000000000..8c314571bf9 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/mdebugread.c @@ -0,0 +1,4053 @@ +/* Read a symbol table in ECOFF format (Third-Eye). + Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994 + Free Software Foundation, Inc. + Original version contributed by Alessandro Forin (af@cs.cmu.edu) at + CMU. Major work by Per Bothner, John Gilmore and Ian Lance Taylor + at Cygnus Support. + +This file is part of GDB. + +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. */ + +/* This module provides the function mdebug_build_psymtabs. It reads + ECOFF debugging information into partial symbol tables. The + debugging information is read from two structures. A struct + ecoff_debug_swap includes the sizes of each ECOFF structure and + swapping routines; these are fixed for a particular target. A + struct ecoff_debug_info points to the debugging information for a + particular object file. + + ECOFF symbol tables are mostly written in the byte order of the + target machine. However, one section of the table (the auxiliary + symbol information) is written in the host byte order. There is a + bit in the other symbol info which describes which host byte order + was used. ECOFF thereby takes the trophy from Intel `b.out' for + the most brain-dead adaptation of a file format to byte order. + + This module can read all four of the known byte-order combinations, + on any type of host. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcore.h" +#include "symfile.h" +#include "objfiles.h" +#include "obstack.h" +#include "buildsym.h" +#include "stabsread.h" +#include "complaints.h" + +#if !defined (SEEK_SET) +#define SEEK_SET 0 +#define SEEK_CUR 1 +#endif + +/* These are needed if the tm.h file does not contain the necessary + mips specific definitions. */ + +#ifndef MIPS_EFI_SYMBOL_NAME +#define MIPS_EFI_SYMBOL_NAME "__GDB_EFI_INFO__" +#include "coff/sym.h" +#include "coff/symconst.h" +typedef struct mips_extra_func_info { + long numargs; + PDR pdr; +} *mips_extra_func_info_t; +#ifndef RA_REGNUM +#define RA_REGNUM 0 +#endif +#endif + +#ifdef USG +#include +#endif + +#include +#include +#include +#include + +#include "gdb-stabs.h" + +#include "bfd.h" + +#include "coff/ecoff.h" /* COFF-like aspects of ecoff files */ + +#include "libaout.h" /* Private BFD a.out information. */ +#include "aout/aout64.h" +#include "aout/stab_gnu.h" /* STABS information */ + +#include "expression.h" +#include "language.h" /* Needed inside partial-stab.h */ + +/* Provide a default mapping from a ecoff register number to a gdb REGNUM. */ +#ifndef ECOFF_REG_TO_REGNUM +#define ECOFF_REG_TO_REGNUM(num) (num) +#endif + +/* Each partial symbol table entry contains a pointer to private data + for the read_symtab() function to use when expanding a partial + symbol table entry to a full symbol table entry. + + For mdebugread this structure contains the index of the FDR that this + psymtab represents and a pointer to the BFD that the psymtab was + created from. */ + +#define PST_PRIVATE(p) ((struct symloc *)(p)->read_symtab_private) +#define FDR_IDX(p) (PST_PRIVATE(p)->fdr_idx) +#define CUR_BFD(p) (PST_PRIVATE(p)->cur_bfd) +#define DEBUG_SWAP(p) (PST_PRIVATE(p)->debug_swap) +#define DEBUG_INFO(p) (PST_PRIVATE(p)->debug_info) +#define PENDING_LIST(p) (PST_PRIVATE(p)->pending_list) + +struct symloc +{ + int fdr_idx; + bfd *cur_bfd; + const struct ecoff_debug_swap *debug_swap; + struct ecoff_debug_info *debug_info; + struct mdebug_pending **pending_list; + EXTR *extern_tab; /* Pointer to external symbols for this file. */ + int extern_count; /* Size of extern_tab. */ + enum language pst_language; +}; + +/* Things we import explicitly from other modules */ + +extern int info_verbose; + +/* Various complaints about symbol reading that don't abort the process */ + +static struct complaint bad_file_number_complaint = +{"bad file number %d", 0, 0}; + +static struct complaint index_complaint = +{"bad aux index at symbol %s", 0, 0}; + +static struct complaint aux_index_complaint = +{"bad proc end in aux found from symbol %s", 0, 0}; + +static struct complaint block_index_complaint = +{"bad aux index at block symbol %s", 0, 0}; + +static struct complaint unknown_ext_complaint = +{"unknown external symbol %s", 0, 0}; + +static struct complaint unknown_sym_complaint = +{"unknown local symbol %s", 0, 0}; + +static struct complaint unknown_st_complaint = +{"with type %d", 0, 0}; + +static struct complaint block_overflow_complaint = +{"block containing %s overfilled", 0, 0}; + +static struct complaint basic_type_complaint = +{"cannot map ECOFF basic type 0x%x for %s", 0, 0}; + +static struct complaint unknown_type_qual_complaint = +{"unknown type qualifier 0x%x", 0, 0}; + +static struct complaint array_index_type_complaint = +{"illegal array index type for %s, assuming int", 0, 0}; + +static struct complaint bad_tag_guess_complaint = +{"guessed tag type of %s incorrectly", 0, 0}; + +static struct complaint block_member_complaint = +{"declaration block contains unhandled symbol type %d", 0, 0}; + +static struct complaint stEnd_complaint = +{"stEnd with storage class %d not handled", 0, 0}; + +static struct complaint unknown_mdebug_symtype_complaint = +{"unknown symbol type 0x%x", 0, 0}; + +static struct complaint stab_unknown_complaint = +{"unknown stabs symbol %s", 0, 0}; + +static struct complaint pdr_for_nonsymbol_complaint = +{"PDR for %s, but no symbol", 0, 0}; + +static struct complaint pdr_static_symbol_complaint = +{"can't handle PDR for static proc at 0x%lx", 0, 0}; + +static struct complaint bad_setjmp_pdr_complaint = +{"fixing bad setjmp PDR from libc", 0, 0}; + +static struct complaint bad_fbitfield_complaint = +{"can't handle TIR fBitfield for %s", 0, 0}; + +static struct complaint bad_continued_complaint = +{"illegal TIR continued for %s", 0, 0}; + +static struct complaint bad_rfd_entry_complaint = +{"bad rfd entry for %s: file %d, index %d", 0, 0}; + +static struct complaint unexpected_type_code_complaint = +{"unexpected type code for %s", 0, 0}; + +static struct complaint unable_to_cross_ref_complaint = +{"unable to cross ref btTypedef for %s", 0, 0}; + +static struct complaint illegal_forward_tq0_complaint = +{"illegal tq0 in forward typedef for %s", 0, 0}; + +static struct complaint illegal_forward_bt_complaint = +{"illegal bt %d in forward typedef for %s", 0, 0}; + +static struct complaint bad_linetable_guess_complaint = +{"guessed size of linetable for %s incorrectly", 0, 0}; + +static struct complaint bad_ext_ifd_complaint = +{"bad ifd for external symbol: %d (max %d)", 0, 0}; + +static struct complaint bad_ext_iss_complaint = +{"bad iss for external symbol: %ld (max %ld)", 0, 0}; + +/* Macros and extra defs */ + +/* Puns: hard to find whether -g was used and how */ + +#define MIN_GLEVEL GLEVEL_0 +#define compare_glevel(a,b) \ + (((a) == GLEVEL_3) ? ((b) < GLEVEL_3) : \ + ((b) == GLEVEL_3) ? -1 : (int)((b) - (a))) + +/* Things that really are local to this module */ + +/* Remember what we deduced to be the source language of this psymtab. */ + +static enum language psymtab_language = language_unknown; + +/* Current BFD. */ + +static bfd *cur_bfd; + +/* How to parse debugging information for CUR_BFD. */ + +static const struct ecoff_debug_swap *debug_swap; + +/* Pointers to debugging information for CUR_BFD. */ + +static struct ecoff_debug_info *debug_info; + +/* Pointer to current file decriptor record, and its index */ + +static FDR *cur_fdr; +static int cur_fd; + +/* Index of current symbol */ + +static int cur_sdx; + +/* Note how much "debuggable" this image is. We would like + to see at least one FDR with full symbols */ + +static max_gdbinfo; +static max_glevel; + +/* When examining .o files, report on undefined symbols */ + +static int n_undef_symbols, n_undef_labels, n_undef_vars, n_undef_procs; + +/* Pseudo symbol to use when putting stabs into the symbol table. */ + +static char stabs_symbol[] = STABS_SYMBOL; + +/* Types corresponding to btComplex, btDComplex, etc. These are here + rather than in gdbtypes.c or some such, because the meaning of codes + like btComplex is specific to the mdebug debug format. FIXME: We should + be using our own types thoughout this file, instead of sometimes using + builtin_type_*. */ + +static struct type *mdebug_type_complex; +static struct type *mdebug_type_double_complex; +static struct type *mdebug_type_fixed_dec; +static struct type *mdebug_type_float_dec; +static struct type *mdebug_type_string; + +/* Forward declarations */ + +static int +upgrade_type PARAMS ((int, struct type **, int, union aux_ext *, int, char *)); + +static void +parse_partial_symbols PARAMS ((struct objfile *, + struct section_offsets *)); + +static FDR +*get_rfd PARAMS ((int, int)); + +static int +has_opaque_xref PARAMS ((FDR *, SYMR *)); + +static int +cross_ref PARAMS ((int, union aux_ext *, struct type **, enum type_code, + char **, int, char *)); + +static struct symbol * +new_symbol PARAMS ((char *)); + +static struct type * +new_type PARAMS ((char *)); + +static struct block * +new_block PARAMS ((int)); + +static struct symtab * +new_symtab PARAMS ((char *, int, int, struct objfile *)); + +static struct linetable * +new_linetable PARAMS ((int)); + +static struct blockvector * +new_bvect PARAMS ((int)); + +static int +parse_symbol PARAMS ((SYMR *, union aux_ext *, char *, int, struct section_offsets *)); + +static struct type * +parse_type PARAMS ((int, union aux_ext *, unsigned int, int *, int, char *)); + +static struct symbol * +mylookup_symbol PARAMS ((char *, struct block *, enum namespace, + enum address_class)); + +static struct block * +shrink_block PARAMS ((struct block *, struct symtab *)); + +static PTR +xzalloc PARAMS ((unsigned int)); + +static void +sort_blocks PARAMS ((struct symtab *)); + +static int +compare_blocks PARAMS ((const void *, const void *)); + +static struct partial_symtab * +new_psymtab PARAMS ((char *, struct objfile *, struct section_offsets *)); + +static void +psymtab_to_symtab_1 PARAMS ((struct partial_symtab *, char *)); + +static void +add_block PARAMS ((struct block *, struct symtab *)); + +static void +add_symbol PARAMS ((struct symbol *, struct block *)); + +static int +add_line PARAMS ((struct linetable *, int, CORE_ADDR, int)); + +static struct linetable * +shrink_linetable PARAMS ((struct linetable *)); + +static void +handle_psymbol_enumerators PARAMS ((struct objfile *, FDR *, int)); + +static char * +mdebug_next_symbol_text PARAMS ((void)); + +/* Address bounds for the signal trampoline in inferior, if any */ + +CORE_ADDR sigtramp_address, sigtramp_end; + +/* Allocate zeroed memory */ + +static PTR +xzalloc (size) + unsigned int size; +{ + PTR p = xmalloc (size); + + memset (p, 0, size); + return p; +} + +/* Exported procedure: Builds a symtab from the PST partial one. + Restores the environment in effect when PST was created, delegates + most of the work to an ancillary procedure, and sorts + and reorders the symtab list at the end */ + +static void +mdebug_psymtab_to_symtab (pst) + struct partial_symtab *pst; +{ + + if (!pst) + return; + + if (info_verbose) + { + printf_filtered ("Reading in symbols for %s...", pst->filename); + gdb_flush (gdb_stdout); + } + + next_symbol_text_func = mdebug_next_symbol_text; + + psymtab_to_symtab_1 (pst, pst->filename); + + /* Match with global symbols. This only needs to be done once, + after all of the symtabs and dependencies have been read in. */ + scan_file_globals (pst->objfile); + + if (info_verbose) + printf_filtered ("done.\n"); +} + +/* File-level interface functions */ + +/* Find a file descriptor given its index RF relative to a file CF */ + +static FDR * +get_rfd (cf, rf) + int cf, rf; +{ + FDR *fdrs; + register FDR *f; + RFDT rfd; + + fdrs = debug_info->fdr; + f = fdrs + cf; + /* Object files do not have the RFD table, all refs are absolute */ + if (f->rfdBase == 0) + return fdrs + rf; + (*debug_swap->swap_rfd_in) (cur_bfd, + ((char *) debug_info->external_rfd + + ((f->rfdBase + rf) + * debug_swap->external_rfd_size)), + &rfd); + return fdrs + rfd; +} + +/* Return a safer print NAME for a file descriptor */ + +static char * +fdr_name (f) + FDR *f; +{ + if (f->rss == -1) + return ""; + if (f->rss == 0) + return ""; + return debug_info->ss + f->issBase + f->rss; +} + + +/* Read in and parse the symtab of the file OBJFILE. Symbols from + different sections are relocated via the SECTION_OFFSETS. */ + +void +mdebug_build_psymtabs (objfile, swap, info, section_offsets) + struct objfile *objfile; + const struct ecoff_debug_swap *swap; + struct ecoff_debug_info *info; + struct section_offsets *section_offsets; +{ + cur_bfd = objfile->obfd; + debug_swap = swap; + debug_info = info; + + /* Make sure all the FDR information is swapped in. */ + if (info->fdr == (FDR *) NULL) + { + char *fdr_src; + char *fdr_end; + FDR *fdr_ptr; + + info->fdr = (FDR *) obstack_alloc (&objfile->psymbol_obstack, + (info->symbolic_header.ifdMax + * sizeof (FDR))); + fdr_src = info->external_fdr; + fdr_end = (fdr_src + + info->symbolic_header.ifdMax * swap->external_fdr_size); + fdr_ptr = info->fdr; + for (; fdr_src < fdr_end; fdr_src += swap->external_fdr_size, fdr_ptr++) + (*swap->swap_fdr_in) (objfile->obfd, fdr_src, fdr_ptr); + } + + parse_partial_symbols (objfile, section_offsets); + +#if 0 + /* Check to make sure file was compiled with -g. If not, warn the + user of this limitation. */ + if (compare_glevel (max_glevel, GLEVEL_2) < 0) + { + if (max_gdbinfo == 0) + printf_unfiltered ("\n%s not compiled with -g, debugging support is limited.\n", + objfile->name); + printf_unfiltered ("You should compile with -g2 or -g3 for best debugging support.\n"); + gdb_flush (gdb_stdout); + } +#endif +} + +/* Local utilities */ + +/* Map of FDR indexes to partial symtabs */ + +struct pst_map +{ + struct partial_symtab *pst; /* the psymtab proper */ + long n_globals; /* exported globals (external symbols) */ + long globals_offset; /* cumulative */ +}; + + +/* Utility stack, used to nest procedures and blocks properly. + It is a doubly linked list, to avoid too many alloc/free. + Since we might need it quite a few times it is NOT deallocated + after use. */ + +static struct parse_stack +{ + struct parse_stack *next, *prev; + struct symtab *cur_st; /* Current symtab. */ + struct block *cur_block; /* Block in it. */ + + /* What are we parsing. stFile, or stBlock are for files and + blocks. stProc or stStaticProc means we have seen the start of a + procedure, but not the start of the block within in. When we see + the start of that block, we change it to stNil, without pushing a + new block, i.e. stNil means both a procedure and a block. */ + + int blocktype; + + int maxsyms; /* Max symbols in this block. */ + struct type *cur_type; /* Type we parse fields for. */ + int cur_field; /* Field number in cur_type. */ + CORE_ADDR procadr; /* Start addres of this procedure */ + int numargs; /* Its argument count */ +} + + *top_stack; /* Top stack ptr */ + + +/* Enter a new lexical context */ + +static void +push_parse_stack () +{ + struct parse_stack *new; + + /* Reuse frames if possible */ + if (top_stack && top_stack->prev) + new = top_stack->prev; + else + new = (struct parse_stack *) xzalloc (sizeof (struct parse_stack)); + /* Initialize new frame with previous content */ + if (top_stack) + { + register struct parse_stack *prev = new->prev; + + *new = *top_stack; + top_stack->prev = new; + new->prev = prev; + new->next = top_stack; + } + top_stack = new; +} + +/* Exit a lexical context */ + +static void +pop_parse_stack () +{ + if (!top_stack) + return; + if (top_stack->next) + top_stack = top_stack->next; +} + + +/* Cross-references might be to things we haven't looked at + yet, e.g. type references. To avoid too many type + duplications we keep a quick fixup table, an array + of lists of references indexed by file descriptor */ + +struct mdebug_pending +{ + struct mdebug_pending *next; /* link */ + char *s; /* the unswapped symbol */ + struct type *t; /* its partial type descriptor */ +}; + + +/* The pending information is kept for an entire object file, and used + to be in the sym_private field. I took it out when I split + mdebugread from mipsread, because this might not be the only type + of symbols read from an object file. Instead, we allocate the + pending information table when we create the partial symbols, and + we store a pointer to the single table in each psymtab. */ + +static struct mdebug_pending **pending_list; + +/* Check whether we already saw symbol SH in file FH */ + +static struct mdebug_pending * +is_pending_symbol (fh, sh) + FDR *fh; + char *sh; +{ + int f_idx = fh - debug_info->fdr; + register struct mdebug_pending *p; + + /* Linear search is ok, list is typically no more than 10 deep */ + for (p = pending_list[f_idx]; p; p = p->next) + if (p->s == sh) + break; + return p; +} + +/* Add a new symbol SH of type T */ + +static void +add_pending (fh, sh, t) + FDR *fh; + char *sh; + struct type *t; +{ + int f_idx = fh - debug_info->fdr; + struct mdebug_pending *p = is_pending_symbol (fh, sh); + + /* Make sure we do not make duplicates */ + if (!p) + { + p = ((struct mdebug_pending *) + obstack_alloc (¤t_objfile->psymbol_obstack, + sizeof (struct mdebug_pending))); + p->s = sh; + p->t = t; + p->next = pending_list[f_idx]; + pending_list[f_idx] = p; + } +} + + +/* Parsing Routines proper. */ + +/* Parse a single symbol. Mostly just make up a GDB symbol for it. + For blocks, procedures and types we open a new lexical context. + This is basically just a big switch on the symbol's type. Argument + AX is the base pointer of aux symbols for this file (fh->iauxBase). + EXT_SH points to the unswapped symbol, which is needed for struct, + union, etc., types; it is NULL for an EXTR. BIGEND says whether + aux symbols are big-endian or little-endian. Return count of + SYMR's handled (normally one). */ + +static int +parse_symbol (sh, ax, ext_sh, bigend, section_offsets) + SYMR *sh; + union aux_ext *ax; + char *ext_sh; + int bigend; + struct section_offsets *section_offsets; +{ + const bfd_size_type external_sym_size = debug_swap->external_sym_size; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) = + debug_swap->swap_sym_in; + char *name; + struct symbol *s; + struct block *b; + struct mdebug_pending *pend; + struct type *t; + struct field *f; + int count = 1; + enum address_class class; + TIR tir; + long svalue = sh->value; + int bitsize; + + if (ext_sh == (char *) NULL) + name = debug_info->ssext + sh->iss; + else + name = debug_info->ss + cur_fdr->issBase + sh->iss; + + switch (sh->sc) + { + case scText: + /* The value of a stEnd symbol is the displacement from the + corresponding start symbol value, do not relocate it. */ + if (sh->st != stEnd) + sh->value += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + case scData: + case scSData: + case scRData: + case scPData: + case scXData: + sh->value += ANOFFSET (section_offsets, SECT_OFF_DATA); + break; + case scBss: + case scSBss: + sh->value += ANOFFSET (section_offsets, SECT_OFF_BSS); + break; + } + + switch (sh->st) + { + case stNil: + break; + + case stGlobal: /* external symbol, goes into global block */ + class = LOC_STATIC; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (top_stack->cur_st), + GLOBAL_BLOCK); + s = new_symbol (name); + SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value; + goto data; + + case stStatic: /* static data, goes into current block. */ + class = LOC_STATIC; + b = top_stack->cur_block; + s = new_symbol (name); + if (sh->sc == scCommon) + { + /* It is a FORTRAN common block. At least for SGI Fortran the + address is not in the symbol; we need to fix it later in + scan_file_globals. */ + int bucket = hashname (SYMBOL_NAME (s)); + SYMBOL_VALUE_CHAIN (s) = global_sym_chain[bucket]; + global_sym_chain[bucket] = s; + } + else + SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value; + goto data; + + case stLocal: /* local variable, goes into current block */ + if (sh->sc == scRegister) + { + class = LOC_REGISTER; + svalue = ECOFF_REG_TO_REGNUM (svalue); + } + else + class = LOC_LOCAL; + b = top_stack->cur_block; + s = new_symbol (name); + SYMBOL_VALUE (s) = svalue; + + data: /* Common code for symbols describing data */ + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = class; + add_symbol (s, b); + + /* Type could be missing in a number of cases */ + if (sh->sc == scUndefined || sh->sc == scNil) + SYMBOL_TYPE (s) = builtin_type_int; /* undefined? */ + else + SYMBOL_TYPE (s) = parse_type (cur_fd, ax, sh->index, 0, bigend, name); + /* Value of a data symbol is its memory address */ + break; + + case stParam: /* arg to procedure, goes into current block */ + max_gdbinfo++; + top_stack->numargs++; + + /* Special GNU C++ name. */ + if (name[0] == CPLUS_MARKER && name[1] == 't' && name[2] == 0) + name = "this"; /* FIXME, not alloc'd in obstack */ + s = new_symbol (name); + + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + switch (sh->sc) + { + case scRegister: + /* Pass by value in register. */ + SYMBOL_CLASS(s) = LOC_REGPARM; + svalue = ECOFF_REG_TO_REGNUM (svalue); + break; + case scVar: + /* Pass by reference on stack. */ + SYMBOL_CLASS(s) = LOC_REF_ARG; + break; + case scVarRegister: + /* Pass by reference in register. */ + SYMBOL_CLASS(s) = LOC_REGPARM_ADDR; + svalue = ECOFF_REG_TO_REGNUM (svalue); + break; + default: + /* Pass by value on stack. */ + SYMBOL_CLASS(s) = LOC_ARG; + break; + } + SYMBOL_VALUE (s) = svalue; + SYMBOL_TYPE (s) = parse_type (cur_fd, ax, sh->index, 0, bigend, name); + add_symbol (s, top_stack->cur_block); +#if 0 + /* FIXME: This has not been tested. See dbxread.c */ + /* Add the type of this parameter to the function/procedure + type of this block. */ + add_param_to_type (&top_stack->cur_block->function->type, s); +#endif + break; + + case stLabel: /* label, goes into current block */ + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; /* so that it can be used */ + SYMBOL_CLASS (s) = LOC_LABEL; /* but not misused */ + SYMBOL_VALUE_ADDRESS (s) = (CORE_ADDR) sh->value; + SYMBOL_TYPE (s) = builtin_type_int; + add_symbol (s, top_stack->cur_block); + break; + + case stProc: /* Procedure, usually goes into global block */ + case stStaticProc: /* Static procedure, goes into current block */ + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_BLOCK; + /* Type of the return value */ + if (sh->sc == scUndefined || sh->sc == scNil) + t = builtin_type_int; + else + t = parse_type (cur_fd, ax, sh->index + 1, 0, bigend, name); + b = top_stack->cur_block; + if (sh->st == stProc) + { + struct blockvector *bv = BLOCKVECTOR (top_stack->cur_st); + /* The next test should normally be true, but provides a + hook for nested functions (which we don't want to make + global). */ + if (b == BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + /* Irix 5 sometimes has duplicate names for the same + function. We want to add such names up at the global + level, not as a nested function. */ + else if (sh->value == top_stack->procadr) + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + } + add_symbol (s, b); + + /* Make a type for the procedure itself */ +#if 0 + /* FIXME: This has not been tested yet! See dbxread.c */ + /* Generate a template for the type of this function. The + types of the arguments will be added as we read the symbol + table. */ + memcpy (lookup_function_type (t), SYMBOL_TYPE (s), sizeof (struct type)); +#else + SYMBOL_TYPE (s) = lookup_function_type (t); +#endif + + /* Create and enter a new lexical context */ + b = new_block (top_stack->maxsyms); + SYMBOL_BLOCK_VALUE (s) = b; + BLOCK_FUNCTION (b) = s; + BLOCK_START (b) = BLOCK_END (b) = sh->value; + BLOCK_SUPERBLOCK (b) = top_stack->cur_block; + add_block (b, top_stack->cur_st); + + /* Not if we only have partial info */ + if (sh->sc == scUndefined || sh->sc == scNil) + break; + + push_parse_stack (); + top_stack->cur_block = b; + top_stack->blocktype = sh->st; + top_stack->cur_type = SYMBOL_TYPE (s); + top_stack->cur_field = -1; + top_stack->procadr = sh->value; + top_stack->numargs = 0; + break; + + /* Beginning of code for structure, union, and enum definitions. + They all share a common set of local variables, defined here. */ + { + enum type_code type_code; + char *ext_tsym; + int nfields; + long max_value; + struct field *f; + + case stStruct: /* Start a block defining a struct type */ + type_code = TYPE_CODE_STRUCT; + goto structured_common; + + case stUnion: /* Start a block defining a union type */ + type_code = TYPE_CODE_UNION; + goto structured_common; + + case stEnum: /* Start a block defining an enum type */ + type_code = TYPE_CODE_ENUM; + goto structured_common; + + case stBlock: /* Either a lexical block, or some type */ + if (sh->sc != scInfo && sh->sc != scCommon) + goto case_stBlock_code; /* Lexical block */ + + type_code = TYPE_CODE_UNDEF; /* We have a type. */ + + /* Common code for handling struct, union, enum, and/or as-yet- + unknown-type blocks of info about structured data. `type_code' + has been set to the proper TYPE_CODE, if we know it. */ + structured_common: + push_parse_stack (); + top_stack->blocktype = stBlock; + + /* First count the number of fields and the highest value. */ + nfields = 0; + max_value = 0; + for (ext_tsym = ext_sh + external_sym_size; + ; + ext_tsym += external_sym_size) + { + SYMR tsym; + + (*swap_sym_in) (cur_bfd, ext_tsym, &tsym); + + switch (tsym.st) + { + case stEnd: + goto end_of_fields; + + case stMember: + if (nfields == 0 && type_code == TYPE_CODE_UNDEF) + /* If the type of the member is Nil (or Void), + without qualifiers, assume the tag is an + enumeration. */ + if (tsym.index == indexNil) + type_code = TYPE_CODE_ENUM; + else + { + (*debug_swap->swap_tir_in) (bigend, + &ax[tsym.index].a_ti, + &tir); + if ((tir.bt == btNil || tir.bt == btVoid) + && tir.tq0 == tqNil) + type_code = TYPE_CODE_ENUM; + } + nfields++; + if (tsym.value > max_value) + max_value = tsym.value; + break; + + case stBlock: + case stUnion: + case stEnum: + case stStruct: + { +#if 0 + /* This is a no-op; is it trying to tell us something + we should be checking? */ + if (tsym.sc == scVariant); /*UNIMPLEMENTED*/ +#endif + if (tsym.index != 0) + { + /* This is something like a struct within a + struct. Skip over the fields of the inner + struct. The -1 is because the for loop will + increment ext_tsym. */ + ext_tsym = ((char *) debug_info->external_sym + + ((cur_fdr->isymBase + tsym.index - 1) + * external_sym_size)); + } + } + break; + + case stTypedef: + /* mips cc puts out a typedef for struct x if it is not yet + defined when it encounters + struct y { struct x *xp; }; + Just ignore it. */ + break; + + case stIndirect: + /* Irix5 cc puts out a stIndirect for struct x if it is not + yet defined when it encounters + struct y { struct x *xp; }; + Just ignore it. */ + break; + + default: + complain (&block_member_complaint, tsym.st); + } + } + end_of_fields:; + + /* In an stBlock, there is no way to distinguish structs, + unions, and enums at this point. This is a bug in the + original design (that has been fixed with the recent + addition of the stStruct, stUnion, and stEnum symbol + types.) The way you can tell is if/when you see a variable + or field of that type. In that case the variable's type + (in the AUX table) says if the type is struct, union, or + enum, and points back to the stBlock here. So you can + patch the tag kind up later - but only if there actually is + a variable or field of that type. + + So until we know for sure, we will guess at this point. + The heuristic is: + If the first member has index==indexNil or a void type, + assume we have an enumeration. + Otherwise, if there is more than one member, and all + the members have offset 0, assume we have a union. + Otherwise, assume we have a struct. + + The heuristic could guess wrong in the case of of an + enumeration with no members or a union with one (or zero) + members, or when all except the last field of a struct have + width zero. These are uncommon and/or illegal situations, + and in any case guessing wrong probably doesn't matter + much. + + But if we later do find out we were wrong, we fixup the tag + kind. Members of an enumeration must be handled + differently from struct/union fields, and that is harder to + patch up, but luckily we shouldn't need to. (If there are + any enumeration members, we can tell for sure it's an enum + here.) */ + + if (type_code == TYPE_CODE_UNDEF) + if (nfields > 1 && max_value == 0) + type_code = TYPE_CODE_UNION; + else + type_code = TYPE_CODE_STRUCT; + + /* Create a new type or use the pending type. */ + pend = is_pending_symbol (cur_fdr, ext_sh); + if (pend == (struct mdebug_pending *) NULL) + { + t = new_type (NULL); + add_pending (cur_fdr, ext_sh, t); + } + else + t = pend->t; + + /* Do not set the tag name if it is a compiler generated tag name + (.Fxx or .xxfake or empty) for unnamed struct/union/enums. + Alpha cc puts out an sh->iss of zero for those. */ + if (sh->iss == 0 || name[0] == '.' || name[0] == '\0') + TYPE_TAG_NAME (t) = NULL; + else + TYPE_TAG_NAME (t) = obconcat (¤t_objfile->symbol_obstack, + "", "", name); + + TYPE_CODE (t) = type_code; + TYPE_LENGTH (t) = sh->value; + TYPE_NFIELDS (t) = nfields; + TYPE_FIELDS (t) = f = ((struct field *) + TYPE_ALLOC (t, + nfields * sizeof (struct field))); + + if (type_code == TYPE_CODE_ENUM) + { + /* This is a non-empty enum. */ + + /* DEC c89 has the number of enumerators in the sh.value field, + not the type length, so we have to compensate for that + incompatibility quirk. + This might do the wrong thing for an enum with one or two + enumerators and gcc -gcoff -fshort-enums, but these cases + are hopefully rare enough. */ + if (TYPE_LENGTH (t) == TYPE_NFIELDS (t)) + TYPE_LENGTH (t) = TARGET_INT_BIT / HOST_CHAR_BIT; + for (ext_tsym = ext_sh + external_sym_size; + ; + ext_tsym += external_sym_size) + { + SYMR tsym; + struct symbol *enum_sym; + + (*swap_sym_in) (cur_bfd, ext_tsym, &tsym); + + if (tsym.st != stMember) + break; + + f->bitpos = tsym.value; + f->type = t; + f->name = debug_info->ss + cur_fdr->issBase + tsym.iss; + f->bitsize = 0; + + enum_sym = ((struct symbol *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct symbol))); + memset ((PTR) enum_sym, 0, sizeof (struct symbol)); + SYMBOL_NAME (enum_sym) = f->name; + SYMBOL_CLASS (enum_sym) = LOC_CONST; + SYMBOL_TYPE (enum_sym) = t; + SYMBOL_NAMESPACE (enum_sym) = VAR_NAMESPACE; + SYMBOL_VALUE (enum_sym) = tsym.value; + add_symbol (enum_sym, top_stack->cur_block); + + /* Skip the stMembers that we've handled. */ + count++; + f++; + } + } + /* make this the current type */ + top_stack->cur_type = t; + top_stack->cur_field = 0; + + /* Do not create a symbol for alpha cc unnamed structs. */ + if (sh->iss == 0) + break; + + /* gcc puts out an empty struct for an opaque struct definitions, + do not create a symbol for it either. */ + if (TYPE_NFIELDS (t) == 0) + { + TYPE_FLAGS (t) |= TYPE_FLAG_STUB; + break; + } + + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = STRUCT_NAMESPACE; + SYMBOL_CLASS (s) = LOC_TYPEDEF; + SYMBOL_VALUE (s) = 0; + SYMBOL_TYPE (s) = t; + add_symbol (s, top_stack->cur_block); + break; + + /* End of local variables shared by struct, union, enum, and + block (as yet unknown struct/union/enum) processing. */ + } + + case_stBlock_code: + /* beginnning of (code) block. Value of symbol + is the displacement from procedure start */ + push_parse_stack (); + + /* Do not start a new block if this is the outermost block of a + procedure. This allows the LOC_BLOCK symbol to point to the + block with the local variables, so funcname::var works. */ + if (top_stack->blocktype == stProc + || top_stack->blocktype == stStaticProc) + { + top_stack->blocktype = stNil; + break; + } + + top_stack->blocktype = stBlock; + b = new_block (top_stack->maxsyms); + BLOCK_START (b) = sh->value + top_stack->procadr; + BLOCK_SUPERBLOCK (b) = top_stack->cur_block; + top_stack->cur_block = b; + add_block (b, top_stack->cur_st); + break; + + case stEnd: /* end (of anything) */ + if (sh->sc == scInfo || sh->sc == scCommon) + { + /* Finished with type */ + top_stack->cur_type = 0; + } + else if (sh->sc == scText && + (top_stack->blocktype == stProc || + top_stack->blocktype == stStaticProc)) + { + /* Finished with procedure */ + struct blockvector *bv = BLOCKVECTOR (top_stack->cur_st); + struct mips_extra_func_info *e; + struct block *b; + int i; + + BLOCK_END (top_stack->cur_block) += sh->value; /* size */ + + /* Make up special symbol to contain procedure specific info */ + s = new_symbol (MIPS_EFI_SYMBOL_NAME); + SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE; + SYMBOL_CLASS (s) = LOC_CONST; + SYMBOL_TYPE (s) = builtin_type_void; + e = ((struct mips_extra_func_info *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct mips_extra_func_info))); + SYMBOL_VALUE (s) = (long) e; + e->numargs = top_stack->numargs; + add_symbol (s, top_stack->cur_block); + + /* Reallocate symbols, saving memory */ + b = shrink_block (top_stack->cur_block, top_stack->cur_st); + + /* f77 emits proc-level with address bounds==[0,0], + So look for such child blocks, and patch them. */ + for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i++) + { + struct block *b_bad = BLOCKVECTOR_BLOCK (bv, i); + if (BLOCK_SUPERBLOCK (b_bad) == b + && BLOCK_START (b_bad) == top_stack->procadr + && BLOCK_END (b_bad) == top_stack->procadr) + { + BLOCK_START (b_bad) = BLOCK_START (b); + BLOCK_END (b_bad) = BLOCK_END (b); + } + } + } + else if (sh->sc == scText && top_stack->blocktype == stBlock) + { + /* End of (code) block. The value of the symbol is the + displacement from the procedure`s start address of the + end of this block. */ + BLOCK_END (top_stack->cur_block) = sh->value + top_stack->procadr; + shrink_block (top_stack->cur_block, top_stack->cur_st); + } + else if (sh->sc == scText && top_stack->blocktype == stNil) + { + /* End of outermost block. Pop parse stack and ignore. The + following stEnd of stProc will take care of the block. */ + ; + } + else if (sh->sc == scText && top_stack->blocktype == stFile) + { + /* End of file. Pop parse stack and ignore. Higher + level code deals with this. */ + ; + } + else + complain (&stEnd_complaint, sh->sc); + + pop_parse_stack (); /* restore previous lexical context */ + break; + + case stMember: /* member of struct or union */ + f = &TYPE_FIELDS (top_stack->cur_type)[top_stack->cur_field++]; + f->name = name; + f->bitpos = sh->value; + bitsize = 0; + f->type = parse_type (cur_fd, ax, sh->index, &bitsize, bigend, name); + f->bitsize = bitsize; + break; + + case stIndirect: /* forward declaration on Irix5 */ + /* Forward declarations from Irix5 cc are handled by cross_ref, + skip them. */ + break; + + case stTypedef: /* type definition */ + /* Typedefs for forward declarations and opaque structs from alpha cc + are handled by cross_ref, skip them. */ + if (sh->iss == 0) + break; + + /* Parse the type or use the pending type. */ + pend = is_pending_symbol (cur_fdr, ext_sh); + if (pend == (struct mdebug_pending *) NULL) + { + t = parse_type (cur_fd, ax, sh->index, (int *)NULL, bigend, name); + add_pending (cur_fdr, ext_sh, t); + } + else + t = pend->t; + + /* mips cc puts out a typedef with the name of the struct for forward + declarations. These should not go into the symbol table and + TYPE_NAME should not be set for them. + They can't be distinguished from an intentional typedef to + the same name however: + x.h: + struct x { int ix; int jx; }; + struct xx; + x.c: + typedef struct x x; + struct xx {int ixx; int jxx; }; + generates a cross referencing stTypedef for x and xx. + The user visible effect of this is that the type of a pointer + to struct foo sometimes is given as `foo *' instead of `struct foo *'. + The problem is fixed with alpha cc and Irix5 cc. */ + + /* However if the typedef cross references to an opaque aggregate, it + is safe to omit it from the symbol table. */ + + if (has_opaque_xref (cur_fdr, sh)) + break; + s = new_symbol (name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_TYPEDEF; + SYMBOL_BLOCK_VALUE (s) = top_stack->cur_block; + SYMBOL_TYPE (s) = t; + add_symbol (s, top_stack->cur_block); + + /* Incomplete definitions of structs should not get a name. */ + if (TYPE_NAME (SYMBOL_TYPE (s)) == NULL + && (TYPE_NFIELDS (SYMBOL_TYPE (s)) != 0 + || (TYPE_CODE (SYMBOL_TYPE (s)) != TYPE_CODE_STRUCT + && TYPE_CODE (SYMBOL_TYPE (s)) != TYPE_CODE_UNION))) + { + if (TYPE_CODE (SYMBOL_TYPE (s)) == TYPE_CODE_PTR + || TYPE_CODE (SYMBOL_TYPE (s)) == TYPE_CODE_FUNC) + { + /* If we are giving a name to a type such as "pointer to + foo" or "function returning foo", we better not set + the TYPE_NAME. If the program contains "typedef char + *caddr_t;", we don't want all variables of type char + * to print as caddr_t. This is not just a + consequence of GDB's type management; CC and GCC (at + least through version 2.4) both output variables of + either type char * or caddr_t with the type + refering to the stTypedef symbol for caddr_t. If a future + compiler cleans this up it GDB is not ready for it + yet, but if it becomes ready we somehow need to + disable this check (without breaking the PCC/GCC2.4 + case). + + Sigh. + + Fortunately, this check seems not to be necessary + for anything except pointers or functions. */ + } + else + TYPE_NAME (SYMBOL_TYPE (s)) = SYMBOL_NAME (s); + } + break; + + case stFile: /* file name */ + push_parse_stack (); + top_stack->blocktype = sh->st; + break; + + /* I`ve never seen these for C */ + case stRegReloc: + break; /* register relocation */ + case stForward: + break; /* forwarding address */ + case stConstant: + break; /* constant */ + default: + complain (&unknown_mdebug_symtype_complaint, sh->st); + break; + } + + return count; +} + +/* Parse the type information provided in the raw AX entries for + the symbol SH. Return the bitfield size in BS, in case. + We must byte-swap the AX entries before we use them; BIGEND says whether + they are big-endian or little-endian (from fh->fBigendian). */ + +static struct type * +parse_type (fd, ax, aux_index, bs, bigend, sym_name) + int fd; + union aux_ext *ax; + unsigned int aux_index; + int *bs; + int bigend; + char *sym_name; +{ + /* Null entries in this map are treated specially */ + static struct type **map_bt[] = + { + &builtin_type_void, /* btNil */ + 0, /* btAdr */ + &builtin_type_char, /* btChar */ + &builtin_type_unsigned_char,/* btUChar */ + &builtin_type_short, /* btShort */ + &builtin_type_unsigned_short, /* btUShort */ + &builtin_type_int, /* btInt */ + &builtin_type_unsigned_int, /* btUInt */ + &builtin_type_long, /* btLong */ + &builtin_type_unsigned_long,/* btULong */ + &builtin_type_float, /* btFloat */ + &builtin_type_double, /* btDouble */ + 0, /* btStruct */ + 0, /* btUnion */ + 0, /* btEnum */ + 0, /* btTypedef */ + 0, /* btRange */ + 0, /* btSet */ + &mdebug_type_complex, /* btComplex */ + &mdebug_type_double_complex, /* btDComplex */ + 0, /* btIndirect */ + &mdebug_type_fixed_dec, /* btFixedDec */ + &mdebug_type_float_dec, /* btFloatDec */ + &mdebug_type_string, /* btString */ + 0, /* btBit */ + 0, /* btPicture */ + &builtin_type_void, /* btVoid */ + 0, /* DEC C++: Pointer to member */ + 0, /* DEC C++: Virtual function table */ + 0, /* DEC C++: Class (Record) */ + &builtin_type_long, /* btLong64 */ + &builtin_type_unsigned_long, /* btULong64 */ + &builtin_type_long_long, /* btLongLong64 */ + &builtin_type_unsigned_long_long, /* btULongLong64 */ + &builtin_type_unsigned_long, /* btAdr64 */ + &builtin_type_long, /* btInt64 */ + &builtin_type_unsigned_long, /* btUInt64 */ + }; + + TIR t[1]; + struct type *tp = 0; + enum type_code type_code = TYPE_CODE_UNDEF; + + /* Handle undefined types, they have indexNil. */ + if (aux_index == indexNil) + return builtin_type_int; + + /* Handle corrupt aux indices. */ + if (aux_index >= (debug_info->fdr + fd)->caux) + { + complain (&index_complaint, sym_name); + return builtin_type_int; + } + ax += aux_index; + + /* Use aux as a type information record, map its basic type. */ + (*debug_swap->swap_tir_in) (bigend, &ax->a_ti, t); + if (t->bt >= (sizeof (map_bt) / sizeof (*map_bt))) + { + complain (&basic_type_complaint, t->bt, sym_name); + return builtin_type_int; + } + if (map_bt[t->bt]) + { + tp = *map_bt[t->bt]; + } + else + { + tp = NULL; + /* Cannot use builtin types -- build our own */ + switch (t->bt) + { + case btAdr: + tp = lookup_pointer_type (builtin_type_void); + break; + case btStruct: + type_code = TYPE_CODE_STRUCT; + break; + case btUnion: + type_code = TYPE_CODE_UNION; + break; + case btEnum: + type_code = TYPE_CODE_ENUM; + break; + case btRange: + type_code = TYPE_CODE_RANGE; + break; + case btSet: + type_code = TYPE_CODE_SET; + break; + case btTypedef: + /* alpha cc uses this for typedefs. The true type will be + obtained by crossreferencing below. */ + type_code = TYPE_CODE_ERROR; + break; + default: + complain (&basic_type_complaint, t->bt, sym_name); + return builtin_type_int; + } + } + + /* Move on to next aux */ + ax++; + + if (t->fBitfield) + { + /* Inhibit core dumps with some cfront generated objects that + corrupt the TIR. */ + if (bs == (int *)NULL) + { + complain (&bad_fbitfield_complaint, sym_name); + return builtin_type_int; + } + *bs = AUX_GET_WIDTH (bigend, ax); + ax++; + } + + /* All these types really point to some (common) MIPS type + definition, and only the type-qualifiers fully identify + them. We'll make the same effort at sharing. */ + if (t->bt == btStruct || + t->bt == btUnion || + t->bt == btEnum || + + /* btSet (I think) implies that the name is a tag name, not a typedef + name. This apparently is a MIPS extension for C sets. */ + t->bt == btSet) + { + char *name; + + /* Try to cross reference this type, build new type on failure. */ + ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); + if (tp == (struct type *) NULL) + tp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + + /* DEC c89 produces cross references to qualified aggregate types, + dereference them. */ + while (TYPE_CODE (tp) == TYPE_CODE_PTR + || TYPE_CODE (tp) == TYPE_CODE_ARRAY) + tp = tp->target_type; + + /* Make sure that TYPE_CODE(tp) has an expected type code. + Any type may be returned from cross_ref if file indirect entries + are corrupted. */ + if (TYPE_CODE (tp) != TYPE_CODE_STRUCT + && TYPE_CODE (tp) != TYPE_CODE_UNION + && TYPE_CODE (tp) != TYPE_CODE_ENUM) + { + complain (&unexpected_type_code_complaint, sym_name); + } + else + { + + /* Usually, TYPE_CODE(tp) is already type_code. The main + exception is if we guessed wrong re struct/union/enum. + But for struct vs. union a wrong guess is harmless, so + don't complain(). */ + if ((TYPE_CODE (tp) == TYPE_CODE_ENUM + && type_code != TYPE_CODE_ENUM) + || (TYPE_CODE (tp) != TYPE_CODE_ENUM + && type_code == TYPE_CODE_ENUM)) + { + complain (&bad_tag_guess_complaint, sym_name); + } + + if (TYPE_CODE (tp) != type_code) + { + TYPE_CODE (tp) = type_code; + } + + /* Do not set the tag name if it is a compiler generated tag name + (.Fxx or .xxfake or empty) for unnamed struct/union/enums. */ + if (name[0] == '.' || name[0] == '\0') + TYPE_TAG_NAME (tp) = NULL; + else if (TYPE_TAG_NAME (tp) == NULL + || !STREQ (TYPE_TAG_NAME (tp), name)) + TYPE_TAG_NAME (tp) = obsavestring (name, strlen (name), + ¤t_objfile->type_obstack); + } + } + + /* All these types really point to some (common) MIPS type + definition, and only the type-qualifiers fully identify + them. We'll make the same effort at sharing. + FIXME: btIndirect cannot happen here as it is handled by the + switch t->bt above. And we are not doing any guessing on range types. */ + if (t->bt == btIndirect || + t->bt == btRange) + { + char *name; + + /* Try to cross reference this type, build new type on failure. */ + ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); + if (tp == (struct type *) NULL) + tp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + + /* Make sure that TYPE_CODE(tp) has an expected type code. + Any type may be returned from cross_ref if file indirect entries + are corrupted. */ + if (TYPE_CODE (tp) != TYPE_CODE_RANGE) + { + complain (&unexpected_type_code_complaint, sym_name); + } + else + { + /* Usually, TYPE_CODE(tp) is already type_code. The main + exception is if we guessed wrong re struct/union/enum. */ + if (TYPE_CODE (tp) != type_code) + { + complain (&bad_tag_guess_complaint, sym_name); + TYPE_CODE (tp) = type_code; + } + if (TYPE_NAME (tp) == NULL || !STREQ (TYPE_NAME (tp), name)) + TYPE_NAME (tp) = obsavestring (name, strlen (name), + ¤t_objfile->type_obstack); + } + } + if (t->bt == btTypedef) + { + char *name; + + /* Try to cross reference this type, it should succeed. */ + ax += cross_ref (fd, ax, &tp, type_code, &name, bigend, sym_name); + if (tp == (struct type *) NULL) + { + complain (&unable_to_cross_ref_complaint, sym_name); + tp = builtin_type_int; + } + } + + /* Deal with range types */ + if (t->bt == btRange) + { + TYPE_NFIELDS (tp) = 2; + TYPE_FIELDS (tp) = ((struct field *) + TYPE_ALLOC (tp, 2 * sizeof (struct field))); + TYPE_FIELD_NAME (tp, 0) = obsavestring ("Low", strlen ("Low"), + ¤t_objfile->type_obstack); + TYPE_FIELD_BITPOS (tp, 0) = AUX_GET_DNLOW (bigend, ax); + ax++; + TYPE_FIELD_NAME (tp, 1) = obsavestring ("High", strlen ("High"), + ¤t_objfile->type_obstack); + TYPE_FIELD_BITPOS (tp, 1) = AUX_GET_DNHIGH (bigend, ax); + ax++; + } + + /* Parse all the type qualifiers now. If there are more + than 6 the game will continue in the next aux */ + + while (1) + { +#define PARSE_TQ(tq) \ + if (t->tq != tqNil) \ + ax += upgrade_type(fd, &tp, t->tq, ax, bigend, sym_name); \ + else \ + break; + + PARSE_TQ (tq0); + PARSE_TQ (tq1); + PARSE_TQ (tq2); + PARSE_TQ (tq3); + PARSE_TQ (tq4); + PARSE_TQ (tq5); +#undef PARSE_TQ + + /* mips cc 2.x and gcc never put out continued aux entries. */ + if (!t->continued) + break; + + (*debug_swap->swap_tir_in) (bigend, &ax->a_ti, t); + ax++; + } + + /* Complain for illegal continuations due to corrupt aux entries. */ + if (t->continued) + complain (&bad_continued_complaint, sym_name); + + return tp; +} + +/* Make up a complex type from a basic one. Type is passed by + reference in TPP and side-effected as necessary. The type + qualifier TQ says how to handle the aux symbols at AX for + the symbol SX we are currently analyzing. BIGEND says whether + aux symbols are big-endian or little-endian. + Returns the number of aux symbols we parsed. */ + +static int +upgrade_type (fd, tpp, tq, ax, bigend, sym_name) + int fd; + struct type **tpp; + int tq; + union aux_ext *ax; + int bigend; + char *sym_name; +{ + int off; + struct type *t; + + /* Used in array processing */ + int rf, id; + FDR *fh; + struct type *range; + struct type *indx; + int lower, upper; + RNDXR rndx; + + switch (tq) + { + case tqPtr: + t = lookup_pointer_type (*tpp); + *tpp = t; + return 0; + + case tqProc: + t = lookup_function_type (*tpp); + *tpp = t; + return 0; + + case tqArray: + off = 0; + + /* Determine and record the domain type (type of index) */ + (*debug_swap->swap_rndx_in) (bigend, &ax->a_rndx, &rndx); + id = rndx.index; + rf = rndx.rfd; + if (rf == 0xfff) + { + ax++; + rf = AUX_GET_ISYM (bigend, ax); + off++; + } + fh = get_rfd (fd, rf); + + indx = parse_type (fd, debug_info->external_aux + fh->iauxBase, + id, (int *) NULL, bigend, sym_name); + + /* The bounds type should be an integer type, but might be anything + else due to corrupt aux entries. */ + if (TYPE_CODE (indx) != TYPE_CODE_INT) + { + complain (&array_index_type_complaint, sym_name); + indx = builtin_type_int; + } + + /* Get the bounds, and create the array type. */ + ax++; + lower = AUX_GET_DNLOW (bigend, ax); + ax++; + upper = AUX_GET_DNHIGH (bigend, ax); + ax++; + rf = AUX_GET_WIDTH (bigend, ax); /* bit size of array element */ + + range = create_range_type ((struct type *) NULL, indx, + lower, upper); + + t = create_array_type ((struct type *) NULL, *tpp, range); + + /* We used to fill in the supplied array element bitsize + here if the TYPE_LENGTH of the target type was zero. + This happens for a `pointer to an array of anonymous structs', + but in this case the array element bitsize is also zero, + so nothing is gained. + And we used to check the TYPE_LENGTH of the target type against + the supplied array element bitsize. + gcc causes a mismatch for `pointer to array of object', + since the sdb directives it uses do not have a way of + specifying the bitsize, but it does no harm (the + TYPE_LENGTH should be correct) and we should be able to + ignore the erroneous bitsize from the auxiliary entry safely. + dbx seems to ignore it too. */ + + *tpp = t; + return 4 + off; + + case tqVol: + /* Volatile -- currently ignored */ + return 0; + + case tqConst: + /* Const -- currently ignored */ + return 0; + + default: + complain (&unknown_type_qual_complaint, tq); + return 0; + } +} + + +/* Parse a procedure descriptor record PR. Note that the procedure is + parsed _after_ the local symbols, now we just insert the extra + information we need into a MIPS_EFI_SYMBOL_NAME symbol that has + already been placed in the procedure's main block. Note also that + images that have been partially stripped (ld -x) have been deprived + of local symbols, and we have to cope with them here. FIRST_OFF is + the offset of the first procedure for this FDR; we adjust the + address by this amount, but I don't know why. SEARCH_SYMTAB is the symtab + to look for the function which contains the MIPS_EFI_SYMBOL_NAME symbol + in question, or NULL to use top_stack->cur_block. */ + +static void parse_procedure PARAMS ((PDR *, struct symtab *, unsigned long, + struct partial_symtab *)); + +static void +parse_procedure (pr, search_symtab, first_off, pst) + PDR *pr; + struct symtab *search_symtab; + unsigned long first_off; + struct partial_symtab *pst; +{ + struct symbol *s, *i; + struct block *b; + struct mips_extra_func_info *e; + char *sh_name; + + /* Simple rule to find files linked "-x" */ + if (cur_fdr->rss == -1) + { + if (pr->isym == -1) + { + /* Static procedure at address pr->adr. Sigh. */ + /* FIXME-32x64. assuming pr->adr fits in long. */ + complain (&pdr_static_symbol_complaint, (unsigned long) pr->adr); + return; + } + else + { + /* external */ + EXTR she; + + (*debug_swap->swap_ext_in) (cur_bfd, + ((char *) debug_info->external_ext + + (pr->isym + * debug_swap->external_ext_size)), + &she); + sh_name = debug_info->ssext + she.asym.iss; + } + } + else + { + /* Full symbols */ + SYMR sh; + + (*debug_swap->swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + ((cur_fdr->isymBase + pr->isym) + * debug_swap->external_sym_size)), + &sh); + sh_name = debug_info->ss + cur_fdr->issBase + sh.iss; + } + + if (search_symtab != NULL) + { +#if 0 + /* This loses both in the case mentioned (want a static, find a global), + but also if we are looking up a non-mangled name which happens to + match the name of a mangled function. */ + /* We have to save the cur_fdr across the call to lookup_symbol. + If the pdr is for a static function and if a global function with + the same name exists, lookup_symbol will eventually read in the symtab + for the global function and clobber cur_fdr. */ + FDR *save_cur_fdr = cur_fdr; + s = lookup_symbol (sh_name, NULL, VAR_NAMESPACE, 0, NULL); + cur_fdr = save_cur_fdr; +#else + s = mylookup_symbol + (sh_name, + BLOCKVECTOR_BLOCK (BLOCKVECTOR (search_symtab), STATIC_BLOCK), + VAR_NAMESPACE, + LOC_BLOCK); +#endif + } + else + s = mylookup_symbol (sh_name, top_stack->cur_block, + VAR_NAMESPACE, LOC_BLOCK); + + if (s != 0) + { + b = SYMBOL_BLOCK_VALUE (s); + } + else + { + complain (&pdr_for_nonsymbol_complaint, sh_name); +#if 1 + return; +#else +/* FIXME -- delete. We can't do symbol allocation now; it's all done. */ + s = new_symbol (sh_name); + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_BLOCK; + /* Donno its type, hope int is ok */ + SYMBOL_TYPE (s) = lookup_function_type (builtin_type_int); + add_symbol (s, top_stack->cur_block); + /* Wont have symbols for this one */ + b = new_block (2); + SYMBOL_BLOCK_VALUE (s) = b; + BLOCK_FUNCTION (b) = s; + BLOCK_START (b) = pr->adr; + /* BOUND used to be the end of procedure's text, but the + argument is no longer passed in. */ + BLOCK_END (b) = bound; + BLOCK_SUPERBLOCK (b) = top_stack->cur_block; + add_block (b, top_stack->cur_st); +#endif + } + + i = mylookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, LOC_CONST); + + if (i) + { + e = (struct mips_extra_func_info *) SYMBOL_VALUE (i); + e->pdr = *pr; + e->pdr.isym = (long) s; + e->pdr.adr += pst->textlow - first_off; + + /* Correct incorrect setjmp procedure descriptor from the library + to make backtrace through setjmp work. */ + if (e->pdr.pcreg == 0 && STREQ (sh_name, "setjmp")) + { + complain (&bad_setjmp_pdr_complaint, 0); + e->pdr.pcreg = RA_REGNUM; + e->pdr.regmask = 0x80000000; + e->pdr.regoffset = -4; + } + } +} + +/* Relocate the extra function info pointed to by the symbol table. */ + +void +ecoff_relocate_efi (sym, delta) + struct symbol *sym; + CORE_ADDR delta; +{ + struct mips_extra_func_info *e; + + e = (struct mips_extra_func_info *) SYMBOL_VALUE (sym); + + e->pdr.adr += delta; +} + +/* Parse the external symbol ES. Just call parse_symbol() after + making sure we know where the aux are for it. + BIGEND says whether aux entries are big-endian or little-endian. + + This routine clobbers top_stack->cur_block and ->cur_st. */ + +static void parse_external PARAMS ((EXTR *, int, struct section_offsets *)); + +static void +parse_external (es, bigend, section_offsets) + EXTR *es; + int bigend; + struct section_offsets *section_offsets; +{ + union aux_ext *ax; + + if (es->ifd != ifdNil) + { + cur_fd = es->ifd; + cur_fdr = debug_info->fdr + cur_fd; + ax = debug_info->external_aux + cur_fdr->iauxBase; + } + else + { + cur_fdr = debug_info->fdr; + ax = 0; + } + + /* Reading .o files */ + if (es->asym.sc == scUndefined || es->asym.sc == scNil) + { + char *what; + switch (es->asym.st) + { + case stNil: + /* These are generated for static symbols in .o files, + ignore them. */ + return; + case stStaticProc: + case stProc: + what = "procedure"; + n_undef_procs++; + break; + case stGlobal: + what = "variable"; + n_undef_vars++; + break; + case stLabel: + what = "label"; + n_undef_labels++; + break; + default: + what = "symbol"; + break; + } + n_undef_symbols++; + /* FIXME: Turn this into a complaint? */ + if (info_verbose) + printf_filtered ("Warning: %s `%s' is undefined (in %s)\n", + what, debug_info->ssext + es->asym.iss, + fdr_name (cur_fdr)); + return; + } + + switch (es->asym.st) + { + case stProc: + case stStaticProc: + /* There is no need to parse the external procedure symbols. + If they are from objects compiled without -g, their index will + be indexNil, and the symbol definition from the minimal symbol + is preferrable (yielding a function returning int instead of int). + If the index points to a local procedure symbol, the local + symbol already provides the correct type. + Note that the index of the external procedure symbol points + to the local procedure symbol in the local symbol table, and + _not_ to the auxiliary symbol info. */ + break; + case stGlobal: + case stLabel: + /* Note that the case of a symbol with indexNil must be handled + anyways by parse_symbol(). */ + parse_symbol (&es->asym, ax, (char *) NULL, bigend, section_offsets); + break; + default: + break; + } +} + +/* Parse the line number info for file descriptor FH into + GDB's linetable LT. MIPS' encoding requires a little bit + of magic to get things out. Note also that MIPS' line + numbers can go back and forth, apparently we can live + with that and do not need to reorder our linetables */ + +static void parse_lines PARAMS ((FDR *, PDR *, struct linetable *, int, + struct partial_symtab *)); + +static void +parse_lines (fh, pr, lt, maxlines, pst) + FDR *fh; + PDR *pr; + struct linetable *lt; + int maxlines; + struct partial_symtab *pst; +{ + unsigned char *base; + int j, k; + int delta, count, lineno = 0; + unsigned long first_off = pr->adr; + + if (fh->cbLine == 0) + return; + + /* Scan by procedure descriptors */ + k = 0; + for (j = 0; j < fh->cpd; j++, pr++) + { + long l; + unsigned long adr; + unsigned char *halt; + + /* No code for this one */ + if (pr->iline == ilineNil || + pr->lnLow == -1 || pr->lnHigh == -1) + continue; + + /* Determine start and end address of compressed line bytes for + this procedure. */ + base = debug_info->line + fh->cbLineOffset; + if (j != (fh->cpd - 1)) + halt = base + pr[1].cbLineOffset; + else + halt = base + fh->cbLine; + base += pr->cbLineOffset; + + adr = pst->textlow + pr->adr - first_off; + + l = adr >> 2; /* in words */ + for (lineno = pr->lnLow; base < halt; ) + { + count = *base & 0x0f; + delta = *base++ >> 4; + if (delta >= 8) + delta -= 16; + if (delta == -8) + { + delta = (base[0] << 8) | base[1]; + if (delta >= 0x8000) + delta -= 0x10000; + base += 2; + } + lineno += delta; /* first delta is 0 */ + + /* Complain if the line table overflows. Could happen + with corrupt binaries. */ + if (lt->nitems >= maxlines) + { + complain (&bad_linetable_guess_complaint, fdr_name (fh)); + break; + } + k = add_line (lt, lineno, l, k); + l += count + 1; + } + } +} + +/* Master parsing procedure for first-pass reading of file symbols + into a partial_symtab. */ + +static void +parse_partial_symbols (objfile, section_offsets) + struct objfile *objfile; + struct section_offsets *section_offsets; +{ + const bfd_size_type external_sym_size = debug_swap->external_sym_size; + const bfd_size_type external_rfd_size = debug_swap->external_rfd_size; + const bfd_size_type external_ext_size = debug_swap->external_ext_size; + void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)) + = debug_swap->swap_ext_in; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = debug_swap->swap_sym_in; + void (* const swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)) + = debug_swap->swap_rfd_in; + int f_idx, s_idx; + HDRR *hdr = &debug_info->symbolic_header; + /* Running pointers */ + FDR *fh; + char *ext_out; + char *ext_out_end; + EXTR *ext_block; + register EXTR *ext_in; + EXTR *ext_in_end; + SYMR sh; + struct partial_symtab *pst; + + int past_first_source_file = 0; + + /* List of current psymtab's include files */ + char **psymtab_include_list; + int includes_allocated; + int includes_used; + EXTR *extern_tab; + struct pst_map *fdr_to_pst; + /* Index within current psymtab dependency list */ + struct partial_symtab **dependency_list; + int dependencies_used, dependencies_allocated; + struct cleanup *old_chain; + char *name; + enum language prev_language; + asection *text_sect; + int relocatable = 0; + + /* Irix 5.2 shared libraries have a fh->adr field of zero, but + the shared libraries are prelinked at a high memory address. + We have to adjust the start address of the object file for this case, + by setting it to the start address of the first procedure in the file. + But we should do no adjustments if we are debugging a .o file, where + the text section (and fh->adr) really starts at zero. */ + text_sect = bfd_get_section_by_name (cur_bfd, ".text"); + if (text_sect != NULL + && (bfd_get_section_flags (cur_bfd, text_sect) & SEC_RELOC)) + relocatable = 1; + + extern_tab = (EXTR *) obstack_alloc (&objfile->psymbol_obstack, + sizeof (EXTR) * hdr->iextMax); + + includes_allocated = 30; + includes_used = 0; + psymtab_include_list = (char **) alloca (includes_allocated * + sizeof (char *)); + next_symbol_text_func = mdebug_next_symbol_text; + + dependencies_allocated = 30; + dependencies_used = 0; + dependency_list = + (struct partial_symtab **) alloca (dependencies_allocated * + sizeof (struct partial_symtab *)); + + last_source_file = NULL; + + /* + * Big plan: + * + * Only parse the Local and External symbols, and the Relative FDR. + * Fixup enough of the loader symtab to be able to use it. + * Allocate space only for the file's portions we need to + * look at. (XXX) + */ + + max_gdbinfo = 0; + max_glevel = MIN_GLEVEL; + + /* Allocate the map FDR -> PST. + Minor hack: -O3 images might claim some global data belongs + to FDR -1. We`ll go along with that */ + fdr_to_pst = (struct pst_map *) xzalloc ((hdr->ifdMax + 1) * sizeof *fdr_to_pst); + old_chain = make_cleanup (free, fdr_to_pst); + fdr_to_pst++; + { + struct partial_symtab *pst = new_psymtab ("", objfile, section_offsets); + fdr_to_pst[-1].pst = pst; + FDR_IDX (pst) = -1; + } + + /* Allocate the global pending list. */ + pending_list = + ((struct mdebug_pending **) + obstack_alloc (&objfile->psymbol_obstack, + hdr->ifdMax * sizeof (struct mdebug_pending *))); + memset ((PTR) pending_list, 0, + hdr->ifdMax * sizeof (struct mdebug_pending *)); + + /* Pass 0 over external syms: swap them in. */ + ext_block = (EXTR *) xmalloc (hdr->iextMax * sizeof (EXTR)); + make_cleanup (free, ext_block); + + ext_out = (char *) debug_info->external_ext; + ext_out_end = ext_out + hdr->iextMax * external_ext_size; + ext_in = ext_block; + for (; ext_out < ext_out_end; ext_out += external_ext_size, ext_in++) + (*swap_ext_in) (cur_bfd, ext_out, ext_in); + + /* Pass 1 over external syms: Presize and partition the list */ + ext_in = ext_block; + ext_in_end = ext_in + hdr->iextMax; + for (; ext_in < ext_in_end; ext_in++) + { + /* See calls to complain below. */ + if (ext_in->ifd >= -1 + && ext_in->ifd < hdr->ifdMax + && ext_in->asym.iss >= 0 + && ext_in->asym.iss < hdr->issExtMax) + fdr_to_pst[ext_in->ifd].n_globals++; + } + + /* Pass 1.5 over files: partition out global symbol space */ + s_idx = 0; + for (f_idx = -1; f_idx < hdr->ifdMax; f_idx++) + { + fdr_to_pst[f_idx].globals_offset = s_idx; + s_idx += fdr_to_pst[f_idx].n_globals; + fdr_to_pst[f_idx].n_globals = 0; + } + + /* Pass 2 over external syms: fill in external symbols */ + ext_in = ext_block; + ext_in_end = ext_in + hdr->iextMax; + for (; ext_in < ext_in_end; ext_in++) + { + enum minimal_symbol_type ms_type = mst_text; + CORE_ADDR svalue = ext_in->asym.value; + + /* The Irix 5 native tools seem to sometimes generate bogus + external symbols. */ + if (ext_in->ifd < -1 || ext_in->ifd >= hdr->ifdMax) + { + complain (&bad_ext_ifd_complaint, ext_in->ifd, hdr->ifdMax); + continue; + } + if (ext_in->asym.iss < 0 || ext_in->asym.iss >= hdr->issExtMax) + { + complain (&bad_ext_iss_complaint, ext_in->asym.iss, + hdr->issExtMax); + continue; + } + + extern_tab[fdr_to_pst[ext_in->ifd].globals_offset + + fdr_to_pst[ext_in->ifd].n_globals++] = *ext_in; + + if (ext_in->asym.sc == scUndefined || ext_in->asym.sc == scNil) + continue; + + name = debug_info->ssext + ext_in->asym.iss; + switch (ext_in->asym.st) + { + case stProc: + svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + case stStaticProc: + ms_type = mst_file_text; + svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + case stGlobal: + if (ext_in->asym.sc == scCommon) + { + /* The value of a common symbol is its size, not its address. + Ignore it. */ + continue; + } + else if (ext_in->asym.sc == scData + || ext_in->asym.sc == scSData + || ext_in->asym.sc == scRData + || ext_in->asym.sc == scPData + || ext_in->asym.sc == scXData) + { + ms_type = mst_data; + svalue += ANOFFSET (section_offsets, SECT_OFF_DATA); + } + else + { + ms_type = mst_bss; + svalue += ANOFFSET (section_offsets, SECT_OFF_BSS); + } + break; + case stLabel: + if (ext_in->asym.sc == scAbs) + ms_type = mst_abs; + else if (ext_in->asym.sc == scText + || ext_in->asym.sc == scInit + || ext_in->asym.sc == scFini) + { + ms_type = mst_file_text; + svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT); + } + else if (ext_in->asym.sc == scData + || ext_in->asym.sc == scSData + || ext_in->asym.sc == scRData + || ext_in->asym.sc == scPData + || ext_in->asym.sc == scXData) + { + ms_type = mst_file_data; + svalue += ANOFFSET (section_offsets, SECT_OFF_DATA); + } + else + { + ms_type = mst_file_bss; + svalue += ANOFFSET (section_offsets, SECT_OFF_BSS); + } + break; + case stLocal: + /* The alpha has the section start addresses in stLocal symbols + whose name starts with a `.'. Skip those but complain for all + other stLocal symbols. */ + if (name[0] == '.') + continue; + /* Fall through. */ + default: + ms_type = mst_unknown; + complain (&unknown_ext_complaint, name); + } + prim_record_minimal_symbol (name, svalue, ms_type, objfile); + } + + /* Pass 3 over files, over local syms: fill in static symbols */ + for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) + { + struct partial_symtab *save_pst; + EXTR *ext_ptr; + CORE_ADDR textlow; + + cur_fdr = fh = debug_info->fdr + f_idx; + + if (fh->csym == 0) + { + fdr_to_pst[f_idx].pst = NULL; + continue; + } + + /* Determine the start address for this object file from the + file header and relocate it, except for Irix 5.2 zero fh->adr. */ + if (fh->cpd) + { + textlow = fh->adr; + if (relocatable || textlow != 0) + textlow += ANOFFSET (section_offsets, SECT_OFF_TEXT); + } + else + textlow = 0; + pst = start_psymtab_common (objfile, section_offsets, + fdr_name (fh), + textlow, + objfile->global_psymbols.next, + objfile->static_psymbols.next); + pst->read_symtab_private = ((char *) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct symloc))); + memset ((PTR) pst->read_symtab_private, 0, sizeof (struct symloc)); + + save_pst = pst; + FDR_IDX (pst) = f_idx; + CUR_BFD (pst) = cur_bfd; + DEBUG_SWAP (pst) = debug_swap; + DEBUG_INFO (pst) = debug_info; + PENDING_LIST (pst) = pending_list; + + /* The way to turn this into a symtab is to call... */ + pst->read_symtab = mdebug_psymtab_to_symtab; + + /* Set up language for the pst. + The language from the FDR is used if it is unambigious (e.g. cfront + with native cc and g++ will set the language to C). + Otherwise we have to deduce the language from the filename. + Native ecoff has every header file in a separate FDR, so + deduce_language_from_filename will return language_unknown for + a header file, which is not what we want. + But the FDRs for the header files are after the FDR for the source + file, so we can assign the language of the source file to the + following header files. Then we save the language in the private + pst data so that we can reuse it when building symtabs. */ + prev_language = psymtab_language; + + switch (fh->lang) + { + case langCplusplusV2: + psymtab_language = language_cplus; + break; + default: + psymtab_language = deduce_language_from_filename (fdr_name (fh)); + break; + } + if (psymtab_language == language_unknown) + psymtab_language = prev_language; + PST_PRIVATE (pst)->pst_language = psymtab_language; + + pst->texthigh = pst->textlow; + + /* For stabs-in-ecoff files, the second symbol must be @stab. + This symbol is emitted by mips-tfile to signal that the + current object file uses encapsulated stabs instead of mips + ecoff for local symbols. (It is the second symbol because + the first symbol is the stFile used to signal the start of a + file). */ + processing_gcc_compilation = 0; + if (fh->csym >= 2) + { + (*swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + (fh->isymBase + 1) * external_sym_size), + &sh); + if (STREQ (debug_info->ss + fh->issBase + sh.iss, stabs_symbol)) + processing_gcc_compilation = 2; + } + + if (processing_gcc_compilation != 0) + { + for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++) + { + int type_code; + char *namestring; + + (*swap_sym_in) (cur_bfd, + (((char *) debug_info->external_sym) + + (fh->isymBase + cur_sdx) * external_sym_size), + &sh); + type_code = ECOFF_UNMARK_STAB (sh.index); + if (!ECOFF_IS_STAB (&sh)) + { + if (sh.st == stProc || sh.st == stStaticProc) + { + long procaddr; + long isym; + + sh.value += ANOFFSET (section_offsets, SECT_OFF_TEXT); + if (sh.st == stStaticProc) + { + namestring = debug_info->ss + fh->issBase + sh.iss; + prim_record_minimal_symbol_and_info (namestring, + sh.value, + mst_file_text, + NULL, + SECT_OFF_TEXT, + objfile); + } + procaddr = sh.value; + + isym = AUX_GET_ISYM (fh->fBigendian, + (debug_info->external_aux + + fh->iauxBase + + sh.index)); + (*swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + ((fh->isymBase + isym - 1) + * external_sym_size)), + &sh); + if (sh.st == stEnd) + { + long high = procaddr + sh.value; + + /* Kludge for Irix 5.2 zero fh->adr. */ + if (!relocatable + && (pst->textlow == 0 || procaddr < pst->textlow)) + pst->textlow = procaddr; + if (high > pst->texthigh) + pst->texthigh = high; + } + } + else if (sh.st == stStatic) + { + switch (sh.sc) + { + case scUndefined: + case scNil: + case scAbs: + break; + + case scData: + case scSData: + case scRData: + case scPData: + case scXData: + namestring = debug_info->ss + fh->issBase + sh.iss; + sh.value += ANOFFSET (section_offsets, SECT_OFF_DATA); + prim_record_minimal_symbol_and_info (namestring, + sh.value, + mst_file_data, + NULL, + SECT_OFF_DATA, + objfile); + break; + + default: + namestring = debug_info->ss + fh->issBase + sh.iss; + sh.value += ANOFFSET (section_offsets, SECT_OFF_BSS); + prim_record_minimal_symbol_and_info (namestring, + sh.value, + mst_file_bss, + NULL, + SECT_OFF_BSS, + objfile); + break; + } + } + continue; + } +#define SET_NAMESTRING() \ + namestring = debug_info->ss + fh->issBase + sh.iss +#define CUR_SYMBOL_TYPE type_code +#define CUR_SYMBOL_VALUE sh.value +#define START_PSYMTAB(ofile,secoff,fname,low,symoff,global_syms,static_syms)\ + pst = save_pst +#define END_PSYMTAB(pst,ilist,ninc,c_off,c_text,dep_list,n_deps) (void)0 +#define HANDLE_RBRAC(val) \ + if ((val) > save_pst->texthigh) save_pst->texthigh = (val); +#include "partial-stab.h" + } + } + else + { + for (cur_sdx = 0; cur_sdx < fh->csym;) + { + char *name; + enum address_class class; + + (*swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + ((fh->isymBase + cur_sdx) + * external_sym_size)), + &sh); + + if (ECOFF_IS_STAB (&sh)) + { + cur_sdx++; + continue; + } + + /* Non absolute static symbols go into the minimal table. */ + if (sh.sc == scUndefined || sh.sc == scNil + || (sh.index == indexNil + && (sh.st != stStatic || sh.sc == scAbs))) + { + /* FIXME, premature? */ + cur_sdx++; + continue; + } + + name = debug_info->ss + fh->issBase + sh.iss; + + switch (sh.sc) + { + case scText: + /* The value of a stEnd symbol is the displacement from the + corresponding start symbol value, do not relocate it. */ + if (sh.st != stEnd) + sh.value += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + case scData: + case scSData: + case scRData: + case scPData: + case scXData: + sh.value += ANOFFSET (section_offsets, SECT_OFF_DATA); + break; + case scBss: + case scSBss: + sh.value += ANOFFSET (section_offsets, SECT_OFF_BSS); + break; + } + + switch (sh.st) + { + long high; + long procaddr; + int new_sdx; + + case stStaticProc: + prim_record_minimal_symbol_and_info (name, sh.value, + mst_file_text, NULL, + SECT_OFF_TEXT, objfile); + + /* FALLTHROUGH */ + + case stProc: + /* Usually there is a local and a global stProc symbol + for a function. This means that the function name + has already been entered into the mimimal symbol table + while processing the global symbols in pass 2 above. + One notable exception is the PROGRAM name from + f77 compiled executables, it is only put out as + local stProc symbol, and a global MAIN__ stProc symbol + points to it. It doesn't matter though, as gdb is + still able to find the PROGRAM name via the partial + symbol table, and the MAIN__ symbol via the minimal + symbol table. */ + if (sh.st == stProc) + ADD_PSYMBOL_TO_LIST (name, strlen (name), + VAR_NAMESPACE, LOC_BLOCK, + objfile->global_psymbols, + sh.value, psymtab_language, objfile); + else + ADD_PSYMBOL_TO_LIST (name, strlen (name), + VAR_NAMESPACE, LOC_BLOCK, + objfile->static_psymbols, + sh.value, psymtab_language, objfile); + + /* Skip over procedure to next one. */ + if (sh.index >= hdr->iauxMax) + { + /* Should not happen, but does when cross-compiling + with the MIPS compiler. FIXME -- pull later. */ + complain (&index_complaint, name); + new_sdx = cur_sdx + 1; /* Don't skip at all */ + } + else + new_sdx = AUX_GET_ISYM (fh->fBigendian, + (debug_info->external_aux + + fh->iauxBase + + sh.index)); + procaddr = sh.value; + + if (new_sdx <= cur_sdx) + { + /* This should not happen either... FIXME. */ + complain (&aux_index_complaint, name); + new_sdx = cur_sdx + 1; /* Don't skip backward */ + } + + cur_sdx = new_sdx; + (*swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + ((fh->isymBase + cur_sdx - 1) + * external_sym_size)), + &sh); + if (sh.st != stEnd) + continue; + + /* Kludge for Irix 5.2 zero fh->adr. */ + if (!relocatable + && (pst->textlow == 0 || procaddr < pst->textlow)) + pst->textlow = procaddr; + + high = procaddr + sh.value; + if (high > pst->texthigh) + pst->texthigh = high; + continue; + + case stStatic: /* Variable */ + if (sh.sc == scData + || sh.sc == scSData + || sh.sc == scRData + || sh.sc == scPData + || sh.sc == scXData) + prim_record_minimal_symbol_and_info (name, sh.value, + mst_file_data, NULL, + SECT_OFF_DATA, + objfile); + else + prim_record_minimal_symbol_and_info (name, sh.value, + mst_file_bss, NULL, + SECT_OFF_BSS, + objfile); + class = LOC_STATIC; + break; + + case stIndirect:/* Irix5 forward declaration */ + /* Skip forward declarations from Irix5 cc */ + goto skip; + + case stTypedef:/* Typedef */ + /* Skip typedefs for forward declarations and opaque + structs from alpha and mips cc. */ + if (sh.iss == 0 || has_opaque_xref (fh, &sh)) + goto skip; + class = LOC_TYPEDEF; + break; + + case stConstant: /* Constant decl */ + class = LOC_CONST; + break; + + case stUnion: + case stStruct: + case stEnum: + case stBlock: /* { }, str, un, enum*/ + /* Do not create a partial symbol for cc unnamed aggregates + and gcc empty aggregates. */ + if ((sh.sc == scInfo || sh.sc == scCommon) + && sh.iss != 0 + && sh.index != cur_sdx + 2) + { + ADD_PSYMBOL_TO_LIST (name, strlen (name), + STRUCT_NAMESPACE, LOC_TYPEDEF, + objfile->static_psymbols, + sh.value, + psymtab_language, objfile); + } + handle_psymbol_enumerators (objfile, fh, sh.st); + + /* Skip over the block */ + new_sdx = sh.index; + if (new_sdx <= cur_sdx) + { + /* This happens with the Ultrix kernel. */ + complain (&block_index_complaint, name); + new_sdx = cur_sdx + 1; /* Don't skip backward */ + } + cur_sdx = new_sdx; + continue; + + case stFile: /* File headers */ + case stLabel: /* Labels */ + case stEnd: /* Ends of files */ + goto skip; + + case stLocal: /* Local variables */ + /* Normally these are skipped because we skip over + all blocks we see. However, these can occur + as visible symbols in a .h file that contains code. */ + goto skip; + + default: + /* Both complaints are valid: one gives symbol name, + the other the offending symbol type. */ + complain (&unknown_sym_complaint, name); + complain (&unknown_st_complaint, sh.st); + cur_sdx++; + continue; + } + /* Use this gdb symbol */ + ADD_PSYMBOL_TO_LIST (name, strlen (name), + VAR_NAMESPACE, class, + objfile->static_psymbols, sh.value, + psymtab_language, objfile); + skip: + cur_sdx++; /* Go to next file symbol */ + } + + /* Now do enter the external symbols. */ + ext_ptr = &extern_tab[fdr_to_pst[f_idx].globals_offset]; + cur_sdx = fdr_to_pst[f_idx].n_globals; + PST_PRIVATE (save_pst)->extern_count = cur_sdx; + PST_PRIVATE (save_pst)->extern_tab = ext_ptr; + for (; --cur_sdx >= 0; ext_ptr++) + { + enum address_class class; + SYMR *psh; + char *name; + CORE_ADDR svalue; + + if (ext_ptr->ifd != f_idx) + abort (); + psh = &ext_ptr->asym; + + /* Do not add undefined symbols to the partial symbol table. */ + if (psh->sc == scUndefined || psh->sc == scNil) + continue; + + svalue = psh->value; + switch (psh->sc) + { + case scText: + svalue += ANOFFSET (section_offsets, SECT_OFF_TEXT); + break; + case scData: + case scSData: + case scRData: + case scPData: + case scXData: + svalue += ANOFFSET (section_offsets, SECT_OFF_DATA); + break; + case scBss: + case scSBss: + svalue += ANOFFSET (section_offsets, SECT_OFF_BSS); + break; + } + + switch (psh->st) + { + case stNil: + /* These are generated for static symbols in .o files, + ignore them. */ + continue; + case stProc: + case stStaticProc: + /* External procedure symbols have been entered + into the minimal symbol table in pass 2 above. + Ignore them, as parse_external will ignore them too. */ + continue; + case stLabel: + class = LOC_LABEL; + break; + default: + complain (&unknown_ext_complaint, + debug_info->ssext + psh->iss); + /* Fall through, pretend it's global. */ + case stGlobal: + class = LOC_STATIC; + break; + } + name = debug_info->ssext + psh->iss; + ADD_PSYMBOL_ADDR_TO_LIST (name, strlen (name), + VAR_NAMESPACE, class, + objfile->global_psymbols, + svalue, + psymtab_language, objfile); + } + } + + /* Link pst to FDR. end_psymtab returns NULL if the psymtab was + empty and put on the free list. */ + fdr_to_pst[f_idx].pst = end_psymtab (save_pst, + psymtab_include_list, includes_used, + -1, save_pst->texthigh, + dependency_list, dependencies_used); + if (objfile->ei.entry_point >= save_pst->textlow && + objfile->ei.entry_point < save_pst->texthigh) + { + objfile->ei.entry_file_lowpc = save_pst->textlow; + objfile->ei.entry_file_highpc = save_pst->texthigh; + } + } + + /* Now scan the FDRs for dependencies */ + for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) + { + fh = f_idx + debug_info->fdr; + pst = fdr_to_pst[f_idx].pst; + + if (pst == (struct partial_symtab *)NULL) + continue; + + /* This should catch stabs-in-ecoff. */ + if (fh->crfd <= 1) + continue; + + /* Skip the first file indirect entry as it is a self dependency + for source files or a reverse .h -> .c dependency for header files. */ + pst->number_of_dependencies = 0; + pst->dependencies = + ((struct partial_symtab **) + obstack_alloc (&objfile->psymbol_obstack, + ((fh->crfd - 1) + * sizeof (struct partial_symtab *)))); + for (s_idx = 1; s_idx < fh->crfd; s_idx++) + { + RFDT rh; + + (*swap_rfd_in) (cur_bfd, + ((char *) debug_info->external_rfd + + (fh->rfdBase + s_idx) * external_rfd_size), + &rh); + if (rh < 0 || rh >= hdr->ifdMax) + { + complain (&bad_file_number_complaint, rh); + continue; + } + + /* Skip self dependencies of header files. */ + if (rh == f_idx) + continue; + + /* Do not add to dependeny list if psymtab was empty. */ + if (fdr_to_pst[rh].pst == (struct partial_symtab *)NULL) + continue; + pst->dependencies[pst->number_of_dependencies++] = fdr_to_pst[rh].pst; + } + } + + /* Remove the dummy psymtab created for -O3 images above, if it is + still empty, to enable the detection of stripped executables. */ + if (objfile->psymtabs->next == NULL + && objfile->psymtabs->number_of_dependencies == 0 + && objfile->psymtabs->n_global_syms == 0 + && objfile->psymtabs->n_static_syms == 0) + objfile->psymtabs = NULL; + do_cleanups (old_chain); +} + +/* If the current psymbol has an enumerated type, we need to add + all the the enum constants to the partial symbol table. */ + +static void +handle_psymbol_enumerators (objfile, fh, stype) + struct objfile *objfile; + FDR *fh; + int stype; +{ + const bfd_size_type external_sym_size = debug_swap->external_sym_size; + void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)) + = debug_swap->swap_sym_in; + char *ext_sym = ((char *) debug_info->external_sym + + ((fh->isymBase + cur_sdx + 1) * external_sym_size)); + SYMR sh; + TIR tir; + + switch (stype) + { + case stEnum: + break; + + case stBlock: + /* It is an enumerated type if the next symbol entry is a stMember + and its auxiliary index is indexNil or its auxiliary entry + is a plain btNil or btVoid. */ + (*swap_sym_in) (cur_bfd, ext_sym, &sh); + if (sh.st != stMember) + return; + + if (sh.index == indexNil) + break; + (*debug_swap->swap_tir_in) (fh->fBigendian, + &(debug_info->external_aux + + fh->iauxBase + sh.index)->a_ti, + &tir); + if ((tir.bt != btNil && tir.bt != btVoid) || tir.tq0 != tqNil) + return; + break; + + default: + return; + } + + for (;;) + { + char *name; + + (*swap_sym_in) (cur_bfd, ext_sym, &sh); + if (sh.st != stMember) + break; + name = debug_info->ss + cur_fdr->issBase + sh.iss; + + /* Note that the value doesn't matter for enum constants + in psymtabs, just in symtabs. */ + ADD_PSYMBOL_TO_LIST (name, strlen (name), + VAR_NAMESPACE, LOC_CONST, + objfile->static_psymbols, 0, + psymtab_language, objfile); + ext_sym += external_sym_size; + } +} + +static char * +mdebug_next_symbol_text () +{ + SYMR sh; + + cur_sdx++; + (*debug_swap->swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + ((cur_fdr->isymBase + cur_sdx) + * debug_swap->external_sym_size)), + &sh); + return debug_info->ss + cur_fdr->issBase + sh.iss; +} + +/* Ancillary function to psymtab_to_symtab(). Does all the work + for turning the partial symtab PST into a symtab, recurring + first on all dependent psymtabs. The argument FILENAME is + only passed so we can see in debug stack traces what file + is being read. + + This function has a split personality, based on whether the + symbol table contains ordinary ecoff symbols, or stabs-in-ecoff. + The flow of control and even the memory allocation differs. FIXME. */ + +static void +psymtab_to_symtab_1 (pst, filename) + struct partial_symtab *pst; + char *filename; +{ + bfd_size_type external_sym_size; + bfd_size_type external_pdr_size; + void (*swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)); + void (*swap_pdr_in) PARAMS ((bfd *, PTR, PDR *)); + int i; + struct symtab *st; + FDR *fh; + struct linetable *lines; + + if (pst->readin) + return; + pst->readin = 1; + + /* Read in all partial symbtabs on which this one is dependent. + NOTE that we do have circular dependencies, sigh. We solved + that by setting pst->readin before this point. */ + + for (i = 0; i < pst->number_of_dependencies; i++) + if (!pst->dependencies[i]->readin) + { + /* Inform about additional files to be read in. */ + if (info_verbose) + { + fputs_filtered (" ", gdb_stdout); + wrap_here (""); + fputs_filtered ("and ", gdb_stdout); + wrap_here (""); + printf_filtered ("%s...", + pst->dependencies[i]->filename); + wrap_here (""); /* Flush output */ + gdb_flush (gdb_stdout); + } + /* We only pass the filename for debug purposes */ + psymtab_to_symtab_1 (pst->dependencies[i], + pst->dependencies[i]->filename); + } + + /* Do nothing if this is a dummy psymtab. */ + + if (pst->n_global_syms == 0 && pst->n_static_syms == 0 + && pst->textlow == 0 && pst->texthigh == 0) + return; + + /* Now read the symbols for this symtab */ + + cur_bfd = CUR_BFD (pst); + debug_swap = DEBUG_SWAP (pst); + debug_info = DEBUG_INFO (pst); + pending_list = PENDING_LIST (pst); + external_sym_size = debug_swap->external_sym_size; + external_pdr_size = debug_swap->external_pdr_size; + swap_sym_in = debug_swap->swap_sym_in; + swap_pdr_in = debug_swap->swap_pdr_in; + current_objfile = pst->objfile; + cur_fd = FDR_IDX (pst); + fh = ((cur_fd == -1) + ? (FDR *) NULL + : debug_info->fdr + cur_fd); + cur_fdr = fh; + + /* See comment in parse_partial_symbols about the @stabs sentinel. */ + processing_gcc_compilation = 0; + if (fh != (FDR *) NULL && fh->csym >= 2) + { + SYMR sh; + + (*swap_sym_in) (cur_bfd, + ((char *) debug_info->external_sym + + (fh->isymBase + 1) * external_sym_size), + &sh); + if (STREQ (debug_info->ss + fh->issBase + sh.iss, + stabs_symbol)) + { + /* We indicate that this is a GCC compilation so that certain + features will be enabled in stabsread/dbxread. */ + processing_gcc_compilation = 2; + } + } + + if (processing_gcc_compilation != 0) + { + char *pdr_ptr; + char *pdr_end; + int first_pdr; + unsigned long first_off = 0; + + /* This symbol table contains stabs-in-ecoff entries. */ + + /* Parse local symbols first */ + + if (fh->csym <= 2) /* FIXME, this blows psymtab->symtab ptr */ + { + current_objfile = NULL; + return; + } + for (cur_sdx = 2; cur_sdx < fh->csym; cur_sdx++) + { + SYMR sh; + char *name; + CORE_ADDR valu; + + (*swap_sym_in) (cur_bfd, + (((char *) debug_info->external_sym) + + (fh->isymBase + cur_sdx) * external_sym_size), + &sh); + name = debug_info->ss + fh->issBase + sh.iss; + valu = sh.value; + if (ECOFF_IS_STAB (&sh)) + { + int type_code = ECOFF_UNMARK_STAB (sh.index); + + /* We should never get non N_STAB symbols here, but they + should be harmless, so keep process_one_symbol from + complaining about them. */ + if (type_code & N_STAB) + { + process_one_symbol (type_code, 0, valu, name, + pst->section_offsets, pst->objfile); + } + if (type_code == N_FUN) + { + /* Make up special symbol to contain + procedure specific info */ + struct mips_extra_func_info *e = + ((struct mips_extra_func_info *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct mips_extra_func_info))); + struct symbol *s = new_symbol (MIPS_EFI_SYMBOL_NAME); + SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE; + SYMBOL_CLASS (s) = LOC_CONST; + SYMBOL_TYPE (s) = builtin_type_void; + SYMBOL_VALUE (s) = (long) e; + add_symbol_to_list (s, &local_symbols); + } + } + else if (sh.st == stLabel) + { + if (sh.index == indexNil) + { + /* This is what the gcc2_compiled and __gnu_compiled_* + show up as. So don't complain. */ + ; + } + else + /* Handle encoded stab line number. */ + record_line (current_subfile, sh.index, valu); + } + else if (sh.st == stProc || sh.st == stStaticProc + || sh.st == stStatic || sh.st == stEnd) + /* These are generated by gcc-2.x, do not complain */ + ; + else + complain (&stab_unknown_complaint, name); + } + st = end_symtab (pst->texthigh, 0, 0, pst->objfile, SECT_OFF_TEXT); + end_stabs (); + + /* Sort the symbol table now, we are done adding symbols to it. + We must do this before parse_procedure calls lookup_symbol. */ + sort_symtab_syms (st); + + /* There used to be a call to sort_blocks here, but this should not + be necessary for stabs symtabs. And as sort_blocks modifies the + start address of the GLOBAL_BLOCK to the FIRST_LOCAL_BLOCK, + it did the wrong thing if the first procedure in a file was + generated via asm statements. */ + + /* Fill in procedure info next. */ + first_pdr = 1; + pdr_ptr = ((char *) debug_info->external_pdr + + fh->ipdFirst * external_pdr_size); + pdr_end = pdr_ptr + fh->cpd * external_pdr_size; + for (; pdr_ptr < pdr_end; pdr_ptr += external_pdr_size) + { + PDR pr; + + (*swap_pdr_in) (cur_bfd, pdr_ptr, &pr); + if (first_pdr) + { + first_off = pr.adr; + first_pdr = 0; + } + parse_procedure (&pr, st, first_off, pst); + } + } + else + { + /* This symbol table contains ordinary ecoff entries. */ + + /* FIXME: doesn't use pst->section_offsets. */ + + int f_max; + int maxlines; + EXTR *ext_ptr; + + /* How many symbols will we need */ + /* FIXME, this does not count enum values. */ + f_max = pst->n_global_syms + pst->n_static_syms; + if (fh == 0) + { + maxlines = 0; + st = new_symtab ("unknown", f_max, 0, pst->objfile); + } + else + { + f_max += fh->csym + fh->cpd; + maxlines = 2 * fh->cline; + st = new_symtab (pst->filename, 2 * f_max, maxlines, pst->objfile); + + /* The proper language was already determined when building + the psymtab, use it. */ + st->language = PST_PRIVATE (pst)->pst_language; + } + + psymtab_language = st->language; + + lines = LINETABLE (st); + + /* Get a new lexical context */ + + push_parse_stack (); + top_stack->cur_st = st; + top_stack->cur_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (st), + STATIC_BLOCK); + BLOCK_START (top_stack->cur_block) = pst->textlow; + BLOCK_END (top_stack->cur_block) = 0; + top_stack->blocktype = stFile; + top_stack->maxsyms = 2 * f_max; + top_stack->cur_type = 0; + top_stack->procadr = 0; + top_stack->numargs = 0; + + if (fh) + { + char *sym_ptr; + char *sym_end; + + /* Parse local symbols first */ + sym_ptr = ((char *) debug_info->external_sym + + fh->isymBase * external_sym_size); + sym_end = sym_ptr + fh->csym * external_sym_size; + while (sym_ptr < sym_end) + { + SYMR sh; + int c; + + (*swap_sym_in) (cur_bfd, sym_ptr, &sh); + c = parse_symbol (&sh, + debug_info->external_aux + fh->iauxBase, + sym_ptr, fh->fBigendian, pst->section_offsets); + sym_ptr += c * external_sym_size; + } + + /* Linenumbers. At the end, check if we can save memory. + parse_lines has to look ahead an arbitrary number of PDR + structures, so we swap them all first. */ + if (fh->cpd > 0) + { + PDR *pr_block; + struct cleanup *old_chain; + char *pdr_ptr; + char *pdr_end; + PDR *pdr_in; + PDR *pdr_in_end; + + pr_block = (PDR *) xmalloc (fh->cpd * sizeof (PDR)); + + old_chain = make_cleanup (free, pr_block); + + pdr_ptr = ((char *) debug_info->external_pdr + + fh->ipdFirst * external_pdr_size); + pdr_end = pdr_ptr + fh->cpd * external_pdr_size; + pdr_in = pr_block; + for (; + pdr_ptr < pdr_end; + pdr_ptr += external_pdr_size, pdr_in++) + (*swap_pdr_in) (cur_bfd, pdr_ptr, pdr_in); + + parse_lines (fh, pr_block, lines, maxlines, pst); + if (lines->nitems < fh->cline) + lines = shrink_linetable (lines); + + /* Fill in procedure info next. */ + pdr_in = pr_block; + pdr_in_end = pdr_in + fh->cpd; + for (; pdr_in < pdr_in_end; pdr_in++) + parse_procedure (pdr_in, 0, pr_block->adr, pst); + + do_cleanups (old_chain); + } + } + + LINETABLE (st) = lines; + + /* .. and our share of externals. + XXX use the global list to speed up things here. how? + FIXME, Maybe quit once we have found the right number of ext's? */ + top_stack->cur_st = st; + top_stack->cur_block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (top_stack->cur_st), + GLOBAL_BLOCK); + top_stack->blocktype = stFile; + top_stack->maxsyms + = (debug_info->symbolic_header.isymMax + + debug_info->symbolic_header.ipdMax + + debug_info->symbolic_header.iextMax); + + ext_ptr = PST_PRIVATE (pst)->extern_tab; + for (i = PST_PRIVATE (pst)->extern_count; --i >= 0; ext_ptr++) + parse_external (ext_ptr, fh->fBigendian, pst->section_offsets); + + /* If there are undefined symbols, tell the user. + The alpha has an undefined symbol for every symbol that is + from a shared library, so tell the user only if verbose is on. */ + if (info_verbose && n_undef_symbols) + { + printf_filtered ("File %s contains %d unresolved references:", + st->filename, n_undef_symbols); + printf_filtered ("\n\t%4d variables\n\t%4d procedures\n\t%4d labels\n", + n_undef_vars, n_undef_procs, n_undef_labels); + n_undef_symbols = n_undef_labels = n_undef_vars = n_undef_procs = 0; + + } + pop_parse_stack (); + + st->primary = 1; + + /* Sort the symbol table now, we are done adding symbols to it.*/ + sort_symtab_syms (st); + + sort_blocks (st); + } + + /* Now link the psymtab and the symtab. */ + pst->symtab = st; + + current_objfile = NULL; +} + +/* Ancillary parsing procedures. */ + +/* Return 1 if the symbol pointed to by SH has a cross reference + to an opaque aggregate type, else 0. */ + +static int +has_opaque_xref (fh, sh) + FDR *fh; + SYMR *sh; +{ + TIR tir; + union aux_ext *ax; + RNDXR rn[1]; + unsigned int rf; + + if (sh->index == indexNil) + return 0; + + ax = debug_info->external_aux + fh->iauxBase + sh->index; + (*debug_swap->swap_tir_in) (fh->fBigendian, &ax->a_ti, &tir); + if (tir.bt != btStruct && tir.bt != btUnion && tir.bt != btEnum) + return 0; + + ax++; + (*debug_swap->swap_rndx_in) (fh->fBigendian, &ax->a_rndx, rn); + if (rn->rfd == 0xfff) + rf = AUX_GET_ISYM (fh->fBigendian, ax + 1); + else + rf = rn->rfd; + if (rf != -1) + return 0; + return 1; +} + +/* Lookup the type at relative index RN. Return it in TPP + if found and in any event come up with its name PNAME. + BIGEND says whether aux symbols are big-endian or not (from fh->fBigendian). + Return value says how many aux symbols we ate. */ + +static int +cross_ref (fd, ax, tpp, type_code, pname, bigend, sym_name) + int fd; + union aux_ext *ax; + struct type **tpp; + enum type_code type_code; /* Use to alloc new type if none is found. */ + char **pname; + int bigend; + char *sym_name; +{ + RNDXR rn[1]; + unsigned int rf; + int result = 1; + FDR *fh; + char *esh; + SYMR sh; + int xref_fd; + struct mdebug_pending *pend; + + *tpp = (struct type *)NULL; + + (*debug_swap->swap_rndx_in) (bigend, &ax->a_rndx, rn); + + /* Escape index means 'the next one' */ + if (rn->rfd == 0xfff) + { + result++; + rf = AUX_GET_ISYM (bigend, ax + 1); + } + else + { + rf = rn->rfd; + } + + /* mips cc uses a rf of -1 for opaque struct definitions. + Set TYPE_FLAG_STUB for these types so that check_stub_type will + resolve them if the struct gets defined in another compilation unit. */ + if (rf == -1) + { + *pname = ""; + *tpp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + TYPE_FLAGS (*tpp) |= TYPE_FLAG_STUB; + return result; + } + + /* mips cc uses an escaped rn->index of 0 for struct return types + of procedures that were compiled without -g. These will always remain + undefined. */ + if (rn->rfd == 0xfff && rn->index == 0) + { + *pname = ""; + return result; + } + + /* Find the relative file descriptor and the symbol in it. */ + fh = get_rfd (fd, rf); + xref_fd = fh - debug_info->fdr; + + if (rn->index >= fh->csym) + { + /* File indirect entry is corrupt. */ + *pname = ""; + complain (&bad_rfd_entry_complaint, + sym_name, xref_fd, rn->index); + return result; + } + + /* If we have processed this symbol then we left a forwarding + pointer to the type in the pending list. If not, we`ll put + it in a list of pending types, to be processed later when + the file will be. In any event, we collect the name for the + type here. */ + + esh = ((char *) debug_info->external_sym + + ((fh->isymBase + rn->index) + * debug_swap->external_sym_size)); + (*debug_swap->swap_sym_in) (cur_bfd, esh, &sh); + + /* Make sure that this type of cross reference can be handled. */ + if ((sh.sc != scInfo + || (sh.st != stBlock && sh.st != stTypedef && sh.st != stIndirect + && sh.st != stStruct && sh.st != stUnion + && sh.st != stEnum)) + && (sh.sc != scCommon || sh.st != stBlock)) + { + /* File indirect entry is corrupt. */ + *pname = ""; + complain (&bad_rfd_entry_complaint, + sym_name, xref_fd, rn->index); + return result; + } + + *pname = debug_info->ss + fh->issBase + sh.iss; + + pend = is_pending_symbol (fh, esh); + if (pend) + *tpp = pend->t; + else + { + /* We have not yet seen this type. */ + + if ((sh.iss == 0 && sh.st == stTypedef) || sh.st == stIndirect) + { + TIR tir; + + /* alpha cc puts out a stTypedef with a sh.iss of zero for + two cases: + a) forward declarations of structs/unions/enums which are not + defined in this compilation unit. + For these the type will be void. This is a bad design decision + as cross referencing across compilation units is impossible + due to the missing name. + b) forward declarations of structs/unions/enums which are defined + later in this file or in another file in the same compilation + unit. Irix5 cc uses a stIndirect symbol for this. + Simply cross reference those again to get the true type. + The forward references are not entered in the pending list and + in the symbol table. */ + + (*debug_swap->swap_tir_in) (bigend, + &(debug_info->external_aux + + fh->iauxBase + sh.index)->a_ti, + &tir); + if (tir.tq0 != tqNil) + complain (&illegal_forward_tq0_complaint, sym_name); + switch (tir.bt) + { + case btVoid: + *tpp = init_type (type_code, 0, 0, (char *) NULL, + current_objfile); + *pname = ""; + break; + + case btStruct: + case btUnion: + case btEnum: + cross_ref (xref_fd, + (debug_info->external_aux + + fh->iauxBase + sh.index + 1), + tpp, type_code, pname, + fh->fBigendian, sym_name); + break; + + default: + complain (&illegal_forward_bt_complaint, tir.bt, sym_name); + *tpp = init_type (type_code, 0, 0, (char *) NULL, + current_objfile); + break; + } + return result; + } + else if (sh.st == stTypedef) + { + /* Parse the type for a normal typedef. This might recursively call + cross_ref till we get a non typedef'ed type. + FIXME: This is not correct behaviour, but gdb currently + cannot handle typedefs without type copying. But type copying is + impossible as we might have mutual forward references between + two files and the copied type would not get filled in when + we later parse its definition. */ + *tpp = parse_type (xref_fd, + debug_info->external_aux + fh->iauxBase, + sh.index, + (int *)NULL, + fh->fBigendian, + debug_info->ss + fh->issBase + sh.iss); + } + else + { + /* Cross reference to a struct/union/enum which is defined + in another file in the same compilation unit but that file + has not been parsed yet. + Initialize the type only, it will be filled in when + it's definition is parsed. */ + *tpp = init_type (type_code, 0, 0, (char *) NULL, current_objfile); + } + add_pending (fh, esh, *tpp); + } + + /* We used one auxent normally, two if we got a "next one" rf. */ + return result; +} + + +/* Quick&dirty lookup procedure, to avoid the MI ones that require + keeping the symtab sorted */ + +static struct symbol * +mylookup_symbol (name, block, namespace, class) + char *name; + register struct block *block; + enum namespace namespace; + enum address_class class; +{ + register int bot, top, inc; + register struct symbol *sym; + + bot = 0; + top = BLOCK_NSYMS (block); + inc = name[0]; + while (bot < top) + { + sym = BLOCK_SYM (block, bot); + if (SYMBOL_NAME (sym)[0] == inc + && SYMBOL_NAMESPACE (sym) == namespace + && SYMBOL_CLASS (sym) == class + && strcmp (SYMBOL_NAME (sym), name) == 0) + return sym; + bot++; + } + block = BLOCK_SUPERBLOCK (block); + if (block) + return mylookup_symbol (name, block, namespace, class); + return 0; +} + + +/* Add a new symbol S to a block B. + Infrequently, we will need to reallocate the block to make it bigger. + We only detect this case when adding to top_stack->cur_block, since + that's the only time we know how big the block is. FIXME. */ + +static void +add_symbol (s, b) + struct symbol *s; + struct block *b; +{ + int nsyms = BLOCK_NSYMS (b)++; + struct block *origb; + struct parse_stack *stackp; + + if (b == top_stack->cur_block && + nsyms >= top_stack->maxsyms) + { + complain (&block_overflow_complaint, SYMBOL_NAME (s)); + /* In this case shrink_block is actually grow_block, since + BLOCK_NSYMS(b) is larger than its current size. */ + origb = b; + b = shrink_block (top_stack->cur_block, top_stack->cur_st); + + /* Now run through the stack replacing pointers to the + original block. shrink_block has already done this + for the blockvector and BLOCK_FUNCTION. */ + for (stackp = top_stack; stackp; stackp = stackp->next) + { + if (stackp->cur_block == origb) + { + stackp->cur_block = b; + stackp->maxsyms = BLOCK_NSYMS (b); + } + } + } + BLOCK_SYM (b, nsyms) = s; +} + +/* Add a new block B to a symtab S */ + +static void +add_block (b, s) + struct block *b; + struct symtab *s; +{ + struct blockvector *bv = BLOCKVECTOR (s); + + bv = (struct blockvector *) xrealloc ((PTR) bv, + (sizeof (struct blockvector) + + BLOCKVECTOR_NBLOCKS (bv) + * sizeof (bv->block))); + if (bv != BLOCKVECTOR (s)) + BLOCKVECTOR (s) = bv; + + BLOCKVECTOR_BLOCK (bv, BLOCKVECTOR_NBLOCKS (bv)++) = b; +} + +/* Add a new linenumber entry (LINENO,ADR) to a linevector LT. + MIPS' linenumber encoding might need more than one byte + to describe it, LAST is used to detect these continuation lines. + + Combining lines with the same line number seems like a bad idea. + E.g: There could be a line number entry with the same line number after the + prologue and GDB should not ignore it (this is a better way to find + a prologue than mips_skip_prologue). + But due to the compressed line table format there are line number entries + for the same line which are needed to bridge the gap to the next + line number entry. These entries have a bogus address info with them + and we are unable to tell them from intended duplicate line number + entries. + This is another reason why -ggdb debugging format is preferable. */ + +static int +add_line (lt, lineno, adr, last) + struct linetable *lt; + int lineno; + CORE_ADDR adr; + int last; +{ + /* DEC c89 sometimes produces zero linenos which confuse gdb. + Change them to something sensible. */ + if (lineno == 0) + lineno = 1; + if (last == 0) + last = -2; /* make sure we record first line */ + + if (last == lineno) /* skip continuation lines */ + return lineno; + + lt->item[lt->nitems].line = lineno; + lt->item[lt->nitems++].pc = adr << 2; + return lineno; +} + +/* Sorting and reordering procedures */ + +/* Blocks with a smaller low bound should come first */ + +static int +compare_blocks (arg1, arg2) + const PTR arg1; + const PTR arg2; +{ + register int addr_diff; + struct block **b1 = (struct block **) arg1; + struct block **b2 = (struct block **) arg2; + + addr_diff = (BLOCK_START ((*b1))) - (BLOCK_START ((*b2))); + if (addr_diff == 0) + return (BLOCK_END ((*b2))) - (BLOCK_END ((*b1))); + return addr_diff; +} + +/* Sort the blocks of a symtab S. + Reorder the blocks in the blockvector by code-address, + as required by some MI search routines */ + +static void +sort_blocks (s) + struct symtab *s; +{ + struct blockvector *bv = BLOCKVECTOR (s); + + if (BLOCKVECTOR_NBLOCKS (bv) <= 2) + { + /* Cosmetic */ + if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) == 0) + BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = 0; + if (BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) == 0) + BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = 0; + return; + } + /* + * This is very unfortunate: normally all functions are compiled in + * the order they are found, but if the file is compiled -O3 things + * are very different. It would be nice to find a reliable test + * to detect -O3 images in advance. + */ + if (BLOCKVECTOR_NBLOCKS (bv) > 3) + qsort (&BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK), + BLOCKVECTOR_NBLOCKS (bv) - FIRST_LOCAL_BLOCK, + sizeof (struct block *), + compare_blocks); + + { + register CORE_ADDR high = 0; + register int i, j = BLOCKVECTOR_NBLOCKS (bv); + + for (i = FIRST_LOCAL_BLOCK; i < j; i++) + if (high < BLOCK_END (BLOCKVECTOR_BLOCK (bv, i))) + high = BLOCK_END (BLOCKVECTOR_BLOCK (bv, i)); + BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = high; + } + + BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)) = + BLOCK_START (BLOCKVECTOR_BLOCK (bv, FIRST_LOCAL_BLOCK)); + + BLOCK_START (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = + BLOCK_START (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); + BLOCK_END (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = + BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK)); +} + + +/* Constructor/restructor/destructor procedures */ + +/* Allocate a new symtab for NAME. Needs an estimate of how many symbols + MAXSYMS and linenumbers MAXLINES we'll put in it */ + +static struct symtab * +new_symtab (name, maxsyms, maxlines, objfile) + char *name; + int maxsyms; + int maxlines; + struct objfile *objfile; +{ + struct symtab *s = allocate_symtab (name, objfile); + + LINETABLE (s) = new_linetable (maxlines); + + /* All symtabs must have at least two blocks */ + BLOCKVECTOR (s) = new_bvect (2); + BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK) = new_block (maxsyms); + BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK) = new_block (maxsyms); + BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)) = + BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); + + s->free_code = free_linetable; + + return (s); +} + +/* Allocate a new partial_symtab NAME */ + +static struct partial_symtab * +new_psymtab (name, objfile, section_offsets) + char *name; + struct objfile *objfile; + struct section_offsets *section_offsets; +{ + struct partial_symtab *psymtab; + + psymtab = allocate_psymtab (name, objfile); + psymtab->section_offsets = section_offsets; + + /* Keep a backpointer to the file's symbols */ + + psymtab->read_symtab_private = ((char *) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct symloc))); + memset ((PTR) psymtab->read_symtab_private, 0, sizeof (struct symloc)); + CUR_BFD (psymtab) = cur_bfd; + DEBUG_SWAP (psymtab) = debug_swap; + DEBUG_INFO (psymtab) = debug_info; + PENDING_LIST (psymtab) = pending_list; + + /* The way to turn this into a symtab is to call... */ + psymtab->read_symtab = mdebug_psymtab_to_symtab; + return (psymtab); +} + + +/* Allocate a linetable array of the given SIZE. Since the struct + already includes one item, we subtract one when calculating the + proper size to allocate. */ + +static struct linetable * +new_linetable (size) + int size; +{ + struct linetable *l; + + size = (size - 1) * sizeof (l->item) + sizeof (struct linetable); + l = (struct linetable *) xmalloc (size); + l->nitems = 0; + return l; +} + +/* Oops, too big. Shrink it. This was important with the 2.4 linetables, + I am not so sure about the 3.4 ones. + + Since the struct linetable already includes one item, we subtract one when + calculating the proper size to allocate. */ + +static struct linetable * +shrink_linetable (lt) + struct linetable *lt; +{ + + return (struct linetable *) xrealloc ((PTR) lt, + (sizeof (struct linetable) + + ((lt->nitems - 1) + * sizeof (lt->item)))); +} + +/* Allocate and zero a new blockvector of NBLOCKS blocks. */ + +static struct blockvector * +new_bvect (nblocks) + int nblocks; +{ + struct blockvector *bv; + int size; + + size = sizeof (struct blockvector) + nblocks * sizeof (struct block *); + bv = (struct blockvector *) xzalloc (size); + + BLOCKVECTOR_NBLOCKS (bv) = nblocks; + + return bv; +} + +/* Allocate and zero a new block of MAXSYMS symbols */ + +static struct block * +new_block (maxsyms) + int maxsyms; +{ + int size = sizeof (struct block) + (maxsyms - 1) * sizeof (struct symbol *); + + return (struct block *) xzalloc (size); +} + +/* Ooops, too big. Shrink block B in symtab S to its minimal size. + Shrink_block can also be used by add_symbol to grow a block. */ + +static struct block * +shrink_block (b, s) + struct block *b; + struct symtab *s; +{ + struct block *new; + struct blockvector *bv = BLOCKVECTOR (s); + int i; + + /* Just reallocate it and fix references to the old one */ + + new = (struct block *) xrealloc ((PTR) b, + (sizeof (struct block) + + ((BLOCK_NSYMS (b) - 1) + * sizeof (struct symbol *)))); + + /* Should chase pointers to old one. Fortunately, that`s just + the block`s function and inferior blocks */ + if (BLOCK_FUNCTION (new) && SYMBOL_BLOCK_VALUE (BLOCK_FUNCTION (new)) == b) + SYMBOL_BLOCK_VALUE (BLOCK_FUNCTION (new)) = new; + for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i++) + if (BLOCKVECTOR_BLOCK (bv, i) == b) + BLOCKVECTOR_BLOCK (bv, i) = new; + else if (BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, i)) == b) + BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, i)) = new; + return new; +} + +/* Create a new symbol with printname NAME */ + +static struct symbol * +new_symbol (name) + char *name; +{ + struct symbol *s = ((struct symbol *) + obstack_alloc (¤t_objfile->symbol_obstack, + sizeof (struct symbol))); + + memset ((PTR) s, 0, sizeof (*s)); + SYMBOL_NAME (s) = name; + SYMBOL_LANGUAGE (s) = psymtab_language; + SYMBOL_INIT_DEMANGLED_NAME (s, ¤t_objfile->symbol_obstack); + return s; +} + +/* Create a new type with printname NAME */ + +static struct type * +new_type (name) + char *name; +{ + struct type *t; + + t = alloc_type (current_objfile); + TYPE_NAME (t) = name; + TYPE_CPLUS_SPECIFIC (t) = (struct cplus_struct_type *) &cplus_struct_default; + return t; +} + +/* Read ECOFF debugging information from a BFD section. This is + called from elfread.c. It parses the section into a + ecoff_debug_info struct, and then lets the rest of the file handle + it as normal. */ + +void +elfmdebug_build_psymtabs (objfile, swap, sec, section_offsets) + struct objfile *objfile; + const struct ecoff_debug_swap *swap; + asection *sec; + struct section_offsets *section_offsets; +{ + bfd *abfd = objfile->obfd; + struct ecoff_debug_info *info; + + info = ((struct ecoff_debug_info *) + obstack_alloc (&objfile->psymbol_obstack, + sizeof (struct ecoff_debug_info))); + + if (!(*swap->read_debug_info) (abfd, sec, info)) + error ("Error reading ECOFF debugging information: %s", + bfd_errmsg (bfd_get_error ())); + + mdebug_build_psymtabs (objfile, swap, info, section_offsets); +} + + +/* Things used for calling functions in the inferior. + These functions are exported to our companion + mips-tdep.c file and are here because they play + with the symbol-table explicitly. */ + +/* Sigtramp: make sure we have all the necessary information + about the signal trampoline code. Since the official code + from MIPS does not do so, we make up that information ourselves. + If they fix the library (unlikely) this code will neutralize itself. */ + +/* FIXME: This function is called only by mips-tdep.c. It needs to be + here because it calls functions defined in this file, but perhaps + this could be handled in a better way. */ + +void +fixup_sigtramp () +{ + struct symbol *s; + struct symtab *st; + struct block *b, *b0 = NULL; + + sigtramp_address = -1; + + /* We have to handle the following cases here: + a) The Mips library has a sigtramp label within sigvec. + b) Irix has a _sigtramp which we want to use, but it also has sigvec. */ + s = lookup_symbol ("sigvec", 0, VAR_NAMESPACE, 0, NULL); + if (s != 0) + { + b0 = SYMBOL_BLOCK_VALUE (s); + s = lookup_symbol ("sigtramp", b0, VAR_NAMESPACE, 0, NULL); + } + if (s == 0) + { + /* No sigvec or no sigtramp inside sigvec, try _sigtramp. */ + s = lookup_symbol ("_sigtramp", 0, VAR_NAMESPACE, 0, NULL); + } + + /* But maybe this program uses its own version of sigvec */ + if (s == 0) + return; + + /* Did we or MIPSco fix the library ? */ + if (SYMBOL_CLASS (s) == LOC_BLOCK) + { + sigtramp_address = BLOCK_START (SYMBOL_BLOCK_VALUE (s)); + sigtramp_end = BLOCK_END (SYMBOL_BLOCK_VALUE (s)); + return; + } + + sigtramp_address = SYMBOL_VALUE (s); + sigtramp_end = sigtramp_address + 0x88; /* black magic */ + + /* But what symtab does it live in ? */ + st = find_pc_symtab (SYMBOL_VALUE (s)); + + /* + * Ok, there goes the fix: turn it into a procedure, with all the + * needed info. Note we make it a nested procedure of sigvec, + * which is the way the (assembly) code is actually written. + */ + SYMBOL_NAMESPACE (s) = VAR_NAMESPACE; + SYMBOL_CLASS (s) = LOC_BLOCK; + SYMBOL_TYPE (s) = init_type (TYPE_CODE_FUNC, 4, 0, (char *) NULL, + st->objfile); + TYPE_TARGET_TYPE (SYMBOL_TYPE (s)) = builtin_type_void; + + /* Need a block to allocate MIPS_EFI_SYMBOL_NAME in */ + b = new_block (1); + SYMBOL_BLOCK_VALUE (s) = b; + BLOCK_START (b) = sigtramp_address; + BLOCK_END (b) = sigtramp_end; + BLOCK_FUNCTION (b) = s; + BLOCK_SUPERBLOCK (b) = BLOCK_SUPERBLOCK (b0); + add_block (b, st); + sort_blocks (st); + + /* Make a MIPS_EFI_SYMBOL_NAME entry for it */ + { + struct mips_extra_func_info *e = + ((struct mips_extra_func_info *) + xzalloc (sizeof (struct mips_extra_func_info))); + + e->numargs = 0; /* the kernel thinks otherwise */ + e->pdr.frameoffset = 32; + e->pdr.framereg = SP_REGNUM; + /* Note that setting pcreg is no longer strictly necessary as + mips_frame_saved_pc is now aware of signal handler frames. */ + e->pdr.pcreg = PC_REGNUM; + e->pdr.regmask = -2; + /* Offset to saved r31, in the sigtramp case the saved registers + are above the frame in the sigcontext. + We have 4 alignment bytes, 12 bytes for onstack, mask and pc, + 32 * 4 bytes for the general registers, 12 bytes for mdhi, mdlo, ownedfp + and 32 * 4 bytes for the floating point registers. */ + e->pdr.regoffset = 4 + 12 + 31 * 4; + e->pdr.fregmask = -1; + /* Offset to saved f30 (first saved *double* register). */ + e->pdr.fregoffset = 4 + 12 + 32 * 4 + 12 + 30 * 4; + e->pdr.isym = (long) s; + e->pdr.adr = sigtramp_address; + + current_objfile = st->objfile; /* Keep new_symbol happy */ + s = new_symbol (MIPS_EFI_SYMBOL_NAME); + SYMBOL_VALUE (s) = (long) e; + SYMBOL_NAMESPACE (s) = LABEL_NAMESPACE; + SYMBOL_CLASS (s) = LOC_CONST; + SYMBOL_TYPE (s) = builtin_type_void; + current_objfile = NULL; + } + + BLOCK_SYM (b, BLOCK_NSYMS (b)++) = s; +} + +void +_initialize_mdebugread () +{ + /* Missing basic types */ + + /* Is a "string" the way btString means it the same as TYPE_CODE_STRING? + FIXME. */ + mdebug_type_string = + init_type (TYPE_CODE_STRING, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "string", + (struct objfile *) NULL); + + mdebug_type_complex = + init_type (TYPE_CODE_ERROR, + TARGET_COMPLEX_BIT / TARGET_CHAR_BIT, + 0, "complex", + (struct objfile *) NULL); + mdebug_type_double_complex = + init_type (TYPE_CODE_ERROR, + TARGET_DOUBLE_COMPLEX_BIT / TARGET_CHAR_BIT, + 0, "double complex", + (struct objfile *) NULL); + + /* We use TYPE_CODE_INT to print these as integers. Does this do any + good? Would we be better off with TYPE_CODE_ERROR? Should + TYPE_CODE_ERROR print things in hex if it knows the size? */ + mdebug_type_fixed_dec = + init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "fixed decimal", + (struct objfile *) NULL); + + mdebug_type_float_dec = + init_type (TYPE_CODE_ERROR, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "floating decimal", + (struct objfile *) NULL); +} diff --git a/gnu/usr.bin/gdb/gdb/solib.c b/gnu/usr.bin/gdb/gdb/solib.c new file mode 100644 index 00000000000..d4e63195a1c --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/solib.c @@ -0,0 +1,1549 @@ +/* Handle SunOS and SVR4 shared libraries for GDB, the GNU Debugger. + Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + +This file is part of GDB. + +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. */ + + +#include "defs.h" + +#include +#include +#include +#ifdef __FreeBSD__ +#include +#endif +#include +#include +#include + +#ifndef SVR4_SHARED_LIBS + /* SunOS shared libs need the nlist structure. */ +#include +#else +#include "libelf.h" +#ifndef DT_MIPS_RLD_MAP +#include "elf/mips.h" +#endif +#endif + +#include "symtab.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdbcore.h" +#include "command.h" +#include "target.h" +#include "frame.h" +#include "regex.h" +#include "inferior.h" +#include "language.h" + +#define MAX_PATH_SIZE 256 /* FIXME: Should be dynamic */ + +/* On SVR4 systems, for the initial implementation, use some runtime startup + symbol as the "startup mapping complete" breakpoint address. The models + for SunOS and SVR4 dynamic linking debugger support are different in that + SunOS hits one breakpoint when all mapping is complete while using the SVR4 + debugger support takes two breakpoint hits for each file mapped, and + there is no way to know when the "last" one is hit. Both these + mechanisms should be tied to a "breakpoint service routine" that + gets automatically executed whenever one of the breakpoints indicating + a change in mapping is hit. This is a future enhancement. (FIXME) */ + +#define BKPT_AT_SYMBOL 1 + +#if defined (BKPT_AT_SYMBOL) && defined (SVR4_SHARED_LIBS) +static char *bkpt_names[] = { +#ifdef SOLIB_BKPT_NAME + SOLIB_BKPT_NAME, /* Prefer configured name if it exists. */ +#endif + "_start", + "main", + NULL +}; +#endif + +/* Symbols which are used to locate the base of the link map structures. */ + +#ifndef SVR4_SHARED_LIBS +static char *debug_base_symbols[] = { + "_DYNAMIC", + NULL +}; +#endif + +/* local data declarations */ + +#ifndef SVR4_SHARED_LIBS + +#define LM_ADDR(so) ((so) -> lm.lm_addr) +#define LM_NEXT(so) ((so) -> lm.lm_next) +#define LM_NAME(so) ((so) -> lm.lm_name) +/* Test for first link map entry; first entry is a shared library. */ +#define IGNORE_FIRST_LINK_MAP_ENTRY(x) (0) +static struct link_dynamic dynamic_copy; +static struct link_dynamic_2 ld_2_copy; +static struct ld_debug debug_copy; +static CORE_ADDR debug_addr; +static CORE_ADDR flag_addr; + +#else /* SVR4_SHARED_LIBS */ + +#define LM_ADDR(so) ((so) -> lm.l_addr) +#define LM_NEXT(so) ((so) -> lm.l_next) +#define LM_NAME(so) ((so) -> lm.l_name) +/* Test for first link map entry; first entry is the exec-file. */ +#define IGNORE_FIRST_LINK_MAP_ENTRY(x) ((x).l_prev == NULL) +static struct r_debug debug_copy; +char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */ + +#endif /* !SVR4_SHARED_LIBS */ + +struct so_list { + struct so_list *next; /* next structure in linked list */ + struct link_map lm; /* copy of link map from inferior */ + struct link_map *lmaddr; /* addr in inferior lm was read from */ + CORE_ADDR lmend; /* upper addr bound of mapped object */ + char so_name[MAX_PATH_SIZE]; /* shared object lib name (FIXME) */ + char symbols_loaded; /* flag: symbols read in yet? */ + char from_tty; /* flag: print msgs? */ + struct objfile *objfile; /* objfile for loaded lib */ + struct section_table *sections; + struct section_table *sections_end; + struct section_table *textsection; + bfd *abfd; +}; + +static struct so_list *so_list_head; /* List of known shared objects */ +static CORE_ADDR debug_base; /* Base of dynamic linker structures */ +static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */ + +extern int +fdmatch PARAMS ((int, int)); /* In libiberty */ + +/* Local function prototypes */ + +static void +special_symbol_handling PARAMS ((struct so_list *)); + +static void +sharedlibrary_command PARAMS ((char *, int)); + +static int +enable_break PARAMS ((void)); + +static int +disable_break PARAMS ((void)); + +static void +info_sharedlibrary_command PARAMS ((char *, int)); + +static int +symbol_add_stub PARAMS ((char *)); + +static struct so_list * +find_solib PARAMS ((struct so_list *)); + +static struct link_map * +first_link_map_member PARAMS ((void)); + +static CORE_ADDR +locate_base PARAMS ((void)); + +static void +solib_map_sections PARAMS ((struct so_list *)); + +#ifdef SVR4_SHARED_LIBS + +static CORE_ADDR +elf_locate_base PARAMS ((void)); + +#else + +static void +solib_add_common_symbols PARAMS ((struct rtc_symb *, struct objfile *)); + +#endif + +/* + +LOCAL FUNCTION + + solib_map_sections -- open bfd and build sections for shared lib + +SYNOPSIS + + static void solib_map_sections (struct so_list *so) + +DESCRIPTION + + Given a pointer to one of the shared objects in our list + of mapped objects, use the recorded name to open a bfd + descriptor for the object, build a section table, and then + relocate all the section addresses by the base address at + which the shared object was mapped. + +FIXMES + + In most (all?) cases the shared object file name recorded in the + dynamic linkage tables will be a fully qualified pathname. For + cases where it isn't, do we really mimic the systems search + mechanism correctly in the below code (particularly the tilde + expansion stuff?). + */ + +static void +solib_map_sections (so) + struct so_list *so; +{ + char *filename; + char *scratch_pathname; + int scratch_chan; + struct section_table *p; + struct cleanup *old_chain; + bfd *abfd; + + filename = tilde_expand (so -> so_name); + old_chain = make_cleanup (free, filename); + + scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &scratch_pathname); + if (scratch_chan < 0) + { + scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename, + O_RDONLY, 0, &scratch_pathname); + } + if (scratch_chan < 0) + { + perror_with_name (filename); + } + /* Leave scratch_pathname allocated. abfd->name will point to it. */ + + abfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan); + if (!abfd) + { + close (scratch_chan); + error ("Could not open `%s' as an executable file: %s", + scratch_pathname, bfd_errmsg (bfd_get_error ())); + } + /* Leave bfd open, core_xfer_memory and "info files" need it. */ + so -> abfd = abfd; + abfd -> cacheable = true; + + if (!bfd_check_format (abfd, bfd_object)) + { + error ("\"%s\": not in executable format: %s.", + scratch_pathname, bfd_errmsg (bfd_get_error ())); + } + if (build_section_table (abfd, &so -> sections, &so -> sections_end)) + { + error ("Can't find the file sections in `%s': %s", + bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); + } + + for (p = so -> sections; p < so -> sections_end; p++) + { + /* Relocate the section binding addresses as recorded in the shared + object's file by the base address to which the object was actually + mapped. */ + p -> addr += (CORE_ADDR) LM_ADDR (so); + p -> endaddr += (CORE_ADDR) LM_ADDR (so); + so -> lmend = (CORE_ADDR) max (p -> endaddr, so -> lmend); + if (STREQ (p -> the_bfd_section -> name, ".text")) + { + so -> textsection = p; + } + } + + /* Free the file names, close the file now. */ + do_cleanups (old_chain); +} + +/* Read all dynamically loaded common symbol definitions from the inferior + and add them to the minimal symbol table for the shared library objfile. */ + +#ifndef SVR4_SHARED_LIBS + +/* In GDB 4.9 this routine was a real performance hog. According to + some gprof data which mtranle@paris.IntelliCorp.COM (Minh Tran-Le) + sent, almost all the time spend in solib_add (up to 20 minutes with + 35 shared libraries) was spent here, with 5/6 in + lookup_minimal_symbol and 1/6 in read_memory. + + To fix this, we moved the call to special_symbol_handling out of the + loop in solib_add, so this only gets called once, rather than once + for every shared library, and also removed the call to lookup_minimal_symbol + in this routine. */ + +static void +solib_add_common_symbols (rtc_symp, objfile) + struct rtc_symb *rtc_symp; + struct objfile *objfile; +{ + struct rtc_symb inferior_rtc_symb; + struct nlist inferior_rtc_nlist; + int len; + char *name; + char *origname; + + init_minimal_symbol_collection (); + make_cleanup (discard_minimal_symbols, 0); + + while (rtc_symp) + { + read_memory ((CORE_ADDR) rtc_symp, + (char *) &inferior_rtc_symb, + sizeof (inferior_rtc_symb)); + read_memory ((CORE_ADDR) inferior_rtc_symb.rtc_sp, + (char *) &inferior_rtc_nlist, + sizeof(inferior_rtc_nlist)); + if (inferior_rtc_nlist.n_type == N_COMM) + { + /* FIXME: The length of the symbol name is not available, but in the + current implementation the common symbol is allocated immediately + behind the name of the symbol. */ + len = inferior_rtc_nlist.n_value - inferior_rtc_nlist.n_un.n_strx; + + origname = name = xmalloc (len); + read_memory ((CORE_ADDR) inferior_rtc_nlist.n_un.n_name, name, len); + + /* Don't enter the symbol twice if the target is re-run. */ + + if (name[0] == bfd_get_symbol_leading_char (objfile->obfd)) + { + name++; + } + +#if 0 + /* I think this is unnecessary, GDB can probably deal with + duplicate minimal symbols, more or less. And the duplication + which used to happen because this was called for each shared + library is gone now that we are just called once. */ + /* FIXME: Do we really want to exclude symbols which happen + to match symbols for other locations in the inferior's + address space, even when they are in different linkage units? */ + if (lookup_minimal_symbol (name, (struct objfile *) NULL) == NULL) +#endif + { + name = obsavestring (name, strlen (name), + &objfile -> symbol_obstack); + prim_record_minimal_symbol (name, inferior_rtc_nlist.n_value, + mst_bss, objfile); + } + free (origname); + } + rtc_symp = inferior_rtc_symb.rtc_next; + } + + /* Install any minimal symbols that have been collected as the current + minimal symbols for this objfile. */ + + install_minimal_symbols (objfile); +} + +#endif /* SVR4_SHARED_LIBS */ + + +#ifdef SVR4_SHARED_LIBS + +#ifdef HANDLE_SVR4_EXEC_EMULATORS + +/* + Solaris BCP (the part of Solaris which allows it to run SunOS4 + a.out files) throws in another wrinkle. Solaris does not fill + in the usual a.out link map structures when running BCP programs, + the only way to get at them is via groping around in the dynamic + linker. + The dynamic linker and it's structures are located in the shared + C library, which gets run as the executable's "interpreter" by + the kernel. + + Note that we can assume nothing about the process state at the time + we need to find these structures. We may be stopped on the first + instruction of the interpreter (C shared library), the first + instruction of the executable itself, or somewhere else entirely + (if we attached to the process for example). +*/ + +static char *debug_base_symbols[] = { + "r_debug", /* Solaris 2.3 */ + "_r_debug", /* Solaris 2.1, 2.2 */ + NULL +}; + +static int +look_for_base PARAMS ((int, CORE_ADDR)); + +static CORE_ADDR +bfd_lookup_symbol PARAMS ((bfd *, char *)); + +/* + +LOCAL FUNCTION + + bfd_lookup_symbol -- lookup the value for a specific symbol + +SYNOPSIS + + CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname) + +DESCRIPTION + + An expensive way to lookup the value of a single symbol for + bfd's that are only temporary anyway. This is used by the + shared library support to find the address of the debugger + interface structures in the shared library. + + Note that 0 is specifically allowed as an error return (no + such symbol). +*/ + +static CORE_ADDR +bfd_lookup_symbol (abfd, symname) + bfd *abfd; + char *symname; +{ + unsigned int storage_needed; + asymbol *sym; + asymbol **symbol_table; + unsigned int number_of_symbols; + unsigned int i; + struct cleanup *back_to; + CORE_ADDR symaddr = 0; + + storage_needed = bfd_get_symtab_upper_bound (abfd); + + if (storage_needed > 0) + { + symbol_table = (asymbol **) xmalloc (storage_needed); + back_to = make_cleanup (free, (PTR)symbol_table); + number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); + + for (i = 0; i < number_of_symbols; i++) + { + sym = *symbol_table++; + if (STREQ (sym -> name, symname)) + { + /* Bfd symbols are section relative. */ + symaddr = sym -> value + sym -> section -> vma; + break; + } + } + do_cleanups (back_to); + } + return (symaddr); +} + +/* + +LOCAL FUNCTION + + look_for_base -- examine file for each mapped address segment + +SYNOPSYS + + static int look_for_base (int fd, CORE_ADDR baseaddr) + +DESCRIPTION + + This function is passed to proc_iterate_over_mappings, which + causes it to get called once for each mapped address space, with + an open file descriptor for the file mapped to that space, and the + base address of that mapped space. + + Our job is to find the debug base symbol in the file that this + fd is open on, if it exists, and if so, initialize the dynamic + linker structure base address debug_base. + + Note that this is a computationally expensive proposition, since + we basically have to open a bfd on every call, so we specifically + avoid opening the exec file. + */ + +static int +look_for_base (fd, baseaddr) + int fd; + CORE_ADDR baseaddr; +{ + bfd *interp_bfd; + CORE_ADDR address = 0; + char **symbolp; + + /* If the fd is -1, then there is no file that corresponds to this + mapped memory segment, so skip it. Also, if the fd corresponds + to the exec file, skip it as well. */ + + if (fd == -1 + || (exec_bfd != NULL + && fdmatch (fileno ((GDB_FILE *)(exec_bfd -> iostream)), fd))) + { + return (0); + } + + /* Try to open whatever random file this fd corresponds to. Note that + we have no way currently to find the filename. Don't gripe about + any problems we might have, just fail. */ + + if ((interp_bfd = bfd_fdopenr ("unnamed", gnutarget, fd)) == NULL) + { + return (0); + } + if (!bfd_check_format (interp_bfd, bfd_object)) + { + bfd_close (interp_bfd); + return (0); + } + + /* Now try to find our debug base symbol in this file, which we at + least know to be a valid ELF executable or shared library. */ + + for (symbolp = debug_base_symbols; *symbolp != NULL; symbolp++) + { + address = bfd_lookup_symbol (interp_bfd, *symbolp); + if (address != 0) + { + break; + } + } + if (address == 0) + { + bfd_close (interp_bfd); + return (0); + } + + /* Eureka! We found the symbol. But now we may need to relocate it + by the base address. If the symbol's value is less than the base + address of the shared library, then it hasn't yet been relocated + by the dynamic linker, and we have to do it ourself. FIXME: Note + that we make the assumption that the first segment that corresponds + to the shared library has the base address to which the library + was relocated. */ + + if (address < baseaddr) + { + address += baseaddr; + } + debug_base = address; + bfd_close (interp_bfd); + return (1); +} +#endif /* HANDLE_SVR4_EXEC_EMULATORS */ + +/* + +LOCAL FUNCTION + + elf_locate_base -- locate the base address of dynamic linker structs + for SVR4 elf targets. + +SYNOPSIS + + CORE_ADDR elf_locate_base (void) + +DESCRIPTION + + For SVR4 elf targets the address of the dynamic linker's runtime + structure is contained within the dynamic info section in the + executable file. The dynamic section is also mapped into the + inferior address space. Because the runtime loader fills in the + real address before starting the inferior, we have to read in the + dynamic info section from the inferior address space. + If there are any errors while trying to find the address, we + silently return 0, otherwise the found address is returned. + + */ + +static CORE_ADDR +elf_locate_base () +{ + struct elf_internal_shdr *dyninfo_sect; + int dyninfo_sect_size; + CORE_ADDR dyninfo_addr; + char *buf; + char *bufend; + + /* Find the start address of the .dynamic section. */ + dyninfo_sect = bfd_elf_find_section (exec_bfd, ".dynamic"); + if (dyninfo_sect == NULL) + return 0; + dyninfo_addr = dyninfo_sect->sh_addr; + + /* Read in .dynamic section, silently ignore errors. */ + dyninfo_sect_size = dyninfo_sect->sh_size; + buf = alloca (dyninfo_sect_size); + if (target_read_memory (dyninfo_addr, buf, dyninfo_sect_size)) + return 0; + + /* Find the DT_DEBUG entry in the the .dynamic section. + For mips elf we look for DT_MIPS_RLD_MAP, mips elf apparently has + no DT_DEBUG entries. */ + /* FIXME: In lack of a 64 bit ELF ABI the following code assumes + a 32 bit ELF ABI target. */ + for (bufend = buf + dyninfo_sect_size; + buf < bufend; + buf += sizeof (Elf32_External_Dyn)) + { + Elf32_External_Dyn *x_dynp = (Elf32_External_Dyn *)buf; + long dyn_tag; + CORE_ADDR dyn_ptr; + + dyn_tag = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_tag); + if (dyn_tag == DT_NULL) + break; + else if (dyn_tag == DT_DEBUG) + { + dyn_ptr = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_un.d_ptr); + return dyn_ptr; + } + else if (dyn_tag == DT_MIPS_RLD_MAP) + { + char pbuf[TARGET_PTR_BIT / HOST_CHAR_BIT]; + + /* DT_MIPS_RLD_MAP contains a pointer to the address + of the dynamic link structure. */ + dyn_ptr = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_un.d_ptr); + if (target_read_memory (dyn_ptr, pbuf, sizeof (pbuf))) + return 0; + return extract_unsigned_integer (pbuf, sizeof (pbuf)); + } + } + + /* DT_DEBUG entry not found. */ + return 0; +} + +#endif /* SVR4_SHARED_LIBS */ + +/* + +LOCAL FUNCTION + + locate_base -- locate the base address of dynamic linker structs + +SYNOPSIS + + CORE_ADDR locate_base (void) + +DESCRIPTION + + For both the SunOS and SVR4 shared library implementations, if the + inferior executable has been linked dynamically, there is a single + address somewhere in the inferior's data space which is the key to + locating all of the dynamic linker's runtime structures. This + address is the value of the debug base symbol. The job of this + function is to find and return that address, or to return 0 if there + is no such address (the executable is statically linked for example). + + For SunOS, the job is almost trivial, since the dynamic linker and + all of it's structures are statically linked to the executable at + link time. Thus the symbol for the address we are looking for has + already been added to the minimal symbol table for the executable's + objfile at the time the symbol file's symbols were read, and all we + have to do is look it up there. Note that we explicitly do NOT want + to find the copies in the shared library. + + The SVR4 version is a bit more complicated because the address + is contained somewhere in the dynamic info section. We have to go + to a lot more work to discover the address of the debug base symbol. + Because of this complexity, we cache the value we find and return that + value on subsequent invocations. Note there is no copy in the + executable symbol tables. + + */ + +static CORE_ADDR +locate_base () +{ + +#ifndef SVR4_SHARED_LIBS + + struct minimal_symbol *msymbol; + CORE_ADDR address = 0; + char **symbolp; + + /* For SunOS, we want to limit the search for the debug base symbol to the + executable being debugged, since there is a duplicate named symbol in the + shared library. We don't want the shared library versions. */ + + for (symbolp = debug_base_symbols; *symbolp != NULL; symbolp++) + { + msymbol = lookup_minimal_symbol (*symbolp, symfile_objfile); + if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) + { + address = SYMBOL_VALUE_ADDRESS (msymbol); + return (address); + } + } + return (0); + +#else /* SVR4_SHARED_LIBS */ + + /* Check to see if we have a currently valid address, and if so, avoid + doing all this work again and just return the cached address. If + we have no cached address, try to locate it in the dynamic info + section for ELF executables. */ + + if (debug_base == 0) + { + if (exec_bfd != NULL + && bfd_get_flavour (exec_bfd) == bfd_target_elf_flavour) + debug_base = elf_locate_base (); +#ifdef HANDLE_SVR4_EXEC_EMULATORS + /* Try it the hard way for emulated executables. */ + else if (inferior_pid != 0) + proc_iterate_over_mappings (look_for_base); +#endif + } + return (debug_base); + +#endif /* !SVR4_SHARED_LIBS */ + +} + +/* + +LOCAL FUNCTION + + first_link_map_member -- locate first member in dynamic linker's map + +SYNOPSIS + + static struct link_map *first_link_map_member (void) + +DESCRIPTION + + Read in a copy of the first member in the inferior's dynamic + link map from the inferior's dynamic linker structures, and return + a pointer to the copy in our address space. +*/ + +static struct link_map * +first_link_map_member () +{ + struct link_map *lm = NULL; + +#ifndef SVR4_SHARED_LIBS + + read_memory (debug_base, (char *) &dynamic_copy, sizeof (dynamic_copy)); + if (dynamic_copy.ld_version >= 2) + { + /* It is a version that we can deal with, so read in the secondary + structure and find the address of the link map list from it. */ + read_memory ((CORE_ADDR) dynamic_copy.ld_un.ld_2, (char *) &ld_2_copy, + sizeof (struct link_dynamic_2)); + lm = ld_2_copy.ld_loaded; + } + +#else /* SVR4_SHARED_LIBS */ + + read_memory (debug_base, (char *) &debug_copy, sizeof (struct r_debug)); + /* FIXME: Perhaps we should validate the info somehow, perhaps by + checking r_version for a known version number, or r_state for + RT_CONSISTENT. */ + lm = debug_copy.r_map; + +#endif /* !SVR4_SHARED_LIBS */ + + return (lm); +} + +/* + +LOCAL FUNCTION + + find_solib -- step through list of shared objects + +SYNOPSIS + + struct so_list *find_solib (struct so_list *so_list_ptr) + +DESCRIPTION + + This module contains the routine which finds the names of any + loaded "images" in the current process. The argument in must be + NULL on the first call, and then the returned value must be passed + in on subsequent calls. This provides the capability to "step" down + the list of loaded objects. On the last object, a NULL value is + returned. + + The arg and return value are "struct link_map" pointers, as defined + in . + */ + +static struct so_list * +find_solib (so_list_ptr) + struct so_list *so_list_ptr; /* Last lm or NULL for first one */ +{ + struct so_list *so_list_next = NULL; + struct link_map *lm = NULL; + struct so_list *new; + + if (so_list_ptr == NULL) + { + /* We are setting up for a new scan through the loaded images. */ + if ((so_list_next = so_list_head) == NULL) + { + /* We have not already read in the dynamic linking structures + from the inferior, lookup the address of the base structure. */ + debug_base = locate_base (); + if (debug_base != 0) + { + /* Read the base structure in and find the address of the first + link map list member. */ + lm = first_link_map_member (); + } + } + } + else + { + /* We have been called before, and are in the process of walking + the shared library list. Advance to the next shared object. */ + if ((lm = LM_NEXT (so_list_ptr)) == NULL) + { + /* We have hit the end of the list, so check to see if any were + added, but be quiet if we can't read from the target any more. */ + int status = target_read_memory ((CORE_ADDR) so_list_ptr -> lmaddr, + (char *) &(so_list_ptr -> lm), + sizeof (struct link_map)); + if (status == 0) + { + lm = LM_NEXT (so_list_ptr); + } + else + { + lm = NULL; + } + } + so_list_next = so_list_ptr -> next; + } + if ((so_list_next == NULL) && (lm != NULL)) + { + /* Get next link map structure from inferior image and build a local + abbreviated load_map structure */ + new = (struct so_list *) xmalloc (sizeof (struct so_list)); + memset ((char *) new, 0, sizeof (struct so_list)); + new -> lmaddr = lm; + /* Add the new node as the next node in the list, or as the root + node if this is the first one. */ + if (so_list_ptr != NULL) + { + so_list_ptr -> next = new; + } + else + { + so_list_head = new; + } + so_list_next = new; + read_memory ((CORE_ADDR) lm, (char *) &(new -> lm), + sizeof (struct link_map)); + /* For SVR4 versions, the first entry in the link map is for the + inferior executable, so we must ignore it. For some versions of + SVR4, it has no name. For others (Solaris 2.3 for example), it + does have a name, so we can no longer use a missing name to + decide when to ignore it. */ + if (!IGNORE_FIRST_LINK_MAP_ENTRY (new -> lm)) + { + int errcode; + char *buffer; + target_read_string ((CORE_ADDR) LM_NAME (new), &buffer, + MAX_PATH_SIZE - 1, &errcode); + if (errcode != 0) + error ("find_solib: Can't read pathname for load map: %s\n", + safe_strerror (errcode)); + strncpy (new -> so_name, buffer, MAX_PATH_SIZE - 1); + new -> so_name[MAX_PATH_SIZE - 1] = '\0'; + free (buffer); + solib_map_sections (new); + } + } + return (so_list_next); +} + +/* A small stub to get us past the arg-passing pinhole of catch_errors. */ + +static int +symbol_add_stub (arg) + char *arg; +{ + register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */ + + so -> objfile = + symbol_file_add (so -> so_name, so -> from_tty, + (so->textsection == NULL + ? 0 + : (unsigned int) so -> textsection -> addr), + 0, 0, 0); + return (1); +} + +/* + +GLOBAL FUNCTION + + solib_add -- add a shared library file to the symtab and section list + +SYNOPSIS + + void solib_add (char *arg_string, int from_tty, + struct target_ops *target) + +DESCRIPTION + +*/ + +void +solib_add (arg_string, from_tty, target) + char *arg_string; + int from_tty; + struct target_ops *target; +{ + register struct so_list *so = NULL; /* link map state variable */ + + /* Last shared library that we read. */ + struct so_list *so_last = NULL; + + char *re_err; + int count; + int old; + + if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL) + { + error ("Invalid regexp: %s", re_err); + } + + /* Add the shared library sections to the section table of the + specified target, if any. We have to do this before reading the + symbol files as symbol_file_add calls reinit_frame_cache and + creating a new frame might access memory in the shared library. */ + if (target) + { + /* Count how many new section_table entries there are. */ + so = NULL; + count = 0; + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + count += so -> sections_end - so -> sections; + } + } + + if (count) + { + /* Reallocate the target's section table including the new size. */ + if (target -> to_sections) + { + old = target -> to_sections_end - target -> to_sections; + target -> to_sections = (struct section_table *) + xrealloc ((char *)target -> to_sections, + (sizeof (struct section_table)) * (count + old)); + } + else + { + old = 0; + target -> to_sections = (struct section_table *) + xmalloc ((sizeof (struct section_table)) * count); + } + target -> to_sections_end = target -> to_sections + (count + old); + + /* Add these section table entries to the target's table. */ + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + count = so -> sections_end - so -> sections; + memcpy ((char *) (target -> to_sections + old), + so -> sections, + (sizeof (struct section_table)) * count); + old += count; + } + } + } + } + + /* Now add the symbol files. */ + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0] && re_exec (so -> so_name)) + { + so -> from_tty = from_tty; + if (so -> symbols_loaded) + { + if (from_tty) + { + printf_unfiltered ("Symbols already loaded for %s\n", so -> so_name); + } + } + else if (catch_errors + (symbol_add_stub, (char *) so, + "Error while reading shared library symbols:\n", + RETURN_MASK_ALL)) + { + so_last = so; + so -> symbols_loaded = 1; + } + } + } + + /* Calling this once at the end means that we put all the minimal + symbols for commons into the objfile for the last shared library. + Since they are in common, this should not be a problem. If we + delete the objfile with the minimal symbols, we can put all the + symbols into a new objfile (and will on the next call to solib_add). + + An alternate approach would be to create an objfile just for + common minsyms, thus not needing any objfile argument to + solib_add_common_symbols. */ + + if (so_last) + special_symbol_handling (so_last); +} + +/* + +LOCAL FUNCTION + + info_sharedlibrary_command -- code for "info sharedlibrary" + +SYNOPSIS + + static void info_sharedlibrary_command () + +DESCRIPTION + + Walk through the shared library list and print information + about each attached library. +*/ + +static void +info_sharedlibrary_command (ignore, from_tty) + char *ignore; + int from_tty; +{ + register struct so_list *so = NULL; /* link map state variable */ + int header_done = 0; + + if (exec_bfd == NULL) + { + printf_unfiltered ("No exec file.\n"); + return; + } + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + if (!header_done) + { + printf_unfiltered("%-12s%-12s%-12s%s\n", "From", "To", "Syms Read", + "Shared Object Library"); + header_done++; + } + /* FIXME-32x64: need print_address_numeric with field width or + some such. */ + printf_unfiltered ("%-12s", + local_hex_string_custom ((unsigned long) LM_ADDR (so), + "08l")); + printf_unfiltered ("%-12s", + local_hex_string_custom ((unsigned long) so -> lmend, + "08l")); + printf_unfiltered ("%-12s", so -> symbols_loaded ? "Yes" : "No"); + printf_unfiltered ("%s\n", so -> so_name); + } + } + if (so_list_head == NULL) + { + printf_unfiltered ("No shared libraries loaded at this time.\n"); + } +} + +/* + +GLOBAL FUNCTION + + solib_address -- check to see if an address is in a shared lib + +SYNOPSIS + + int solib_address (CORE_ADDR address) + +DESCRIPTION + + Provides a hook for other gdb routines to discover whether or + not a particular address is within the mapped address space of + a shared library. Any address between the base mapping address + and the first address beyond the end of the last mapping, is + considered to be within the shared library address space, for + our purposes. + + For example, this routine is called at one point to disable + breakpoints which are in shared libraries that are not currently + mapped in. + */ + +int +solib_address (address) + CORE_ADDR address; +{ + register struct so_list *so = 0; /* link map state variable */ + + while ((so = find_solib (so)) != NULL) + { + if (so -> so_name[0]) + { + if ((address >= (CORE_ADDR) LM_ADDR (so)) && + (address < (CORE_ADDR) so -> lmend)) + { + return (1); + } + } + } + return (0); +} + +/* Called by free_all_symtabs */ + +void +clear_solib() +{ + struct so_list *next; + char *bfd_filename; + + while (so_list_head) + { + if (so_list_head -> sections) + { + free ((PTR)so_list_head -> sections); + } + if (so_list_head -> abfd) + { + bfd_filename = bfd_get_filename (so_list_head -> abfd); + bfd_close (so_list_head -> abfd); + } + else + /* This happens for the executable on SVR4. */ + bfd_filename = NULL; + + next = so_list_head -> next; + if (bfd_filename) + free ((PTR)bfd_filename); + free ((PTR)so_list_head); + so_list_head = next; + } + debug_base = 0; +} + +/* + +LOCAL FUNCTION + + disable_break -- remove the "mapping changed" breakpoint + +SYNOPSIS + + static int disable_break () + +DESCRIPTION + + Removes the breakpoint that gets hit when the dynamic linker + completes a mapping change. + +*/ + +static int +disable_break () +{ + int status = 1; + +#ifndef SVR4_SHARED_LIBS + + int in_debugger = 0; + + /* Read the debugger structure from the inferior to retrieve the + address of the breakpoint and the original contents of the + breakpoint address. Remove the breakpoint by writing the original + contents back. */ + + read_memory (debug_addr, (char *) &debug_copy, sizeof (debug_copy)); + + /* Set `in_debugger' to zero now. */ + + write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger)); + + breakpoint_addr = (CORE_ADDR) debug_copy.ldd_bp_addr; + write_memory (breakpoint_addr, (char *) &debug_copy.ldd_bp_inst, + sizeof (debug_copy.ldd_bp_inst)); + +#else /* SVR4_SHARED_LIBS */ + + /* Note that breakpoint address and original contents are in our address + space, so we just need to write the original contents back. */ + + if (memory_remove_breakpoint (breakpoint_addr, shadow_contents) != 0) + { + status = 0; + } + +#endif /* !SVR4_SHARED_LIBS */ + + /* For the SVR4 version, we always know the breakpoint address. For the + SunOS version we don't know it until the above code is executed. + Grumble if we are stopped anywhere besides the breakpoint address. */ + + if (stop_pc != breakpoint_addr) + { + warning ("stopped at unknown breakpoint while handling shared libraries"); + } + + return (status); +} + +/* + +LOCAL FUNCTION + + enable_break -- arrange for dynamic linker to hit breakpoint + +SYNOPSIS + + int enable_break (void) + +DESCRIPTION + + Both the SunOS and the SVR4 dynamic linkers have, as part of their + debugger interface, support for arranging for the inferior to hit + a breakpoint after mapping in the shared libraries. This function + enables that breakpoint. + + For SunOS, there is a special flag location (in_debugger) which we + set to 1. When the dynamic linker sees this flag set, it will set + a breakpoint at a location known only to itself, after saving the + original contents of that place and the breakpoint address itself, + in it's own internal structures. When we resume the inferior, it + will eventually take a SIGTRAP when it runs into the breakpoint. + We handle this (in a different place) by restoring the contents of + the breakpointed location (which is only known after it stops), + chasing around to locate the shared libraries that have been + loaded, then resuming. + + For SVR4, the debugger interface structure contains a member (r_brk) + which is statically initialized at the time the shared library is + built, to the offset of a function (_r_debug_state) which is guaran- + teed to be called once before mapping in a library, and again when + the mapping is complete. At the time we are examining this member, + it contains only the unrelocated offset of the function, so we have + to do our own relocation. Later, when the dynamic linker actually + runs, it relocates r_brk to be the actual address of _r_debug_state(). + + The debugger interface structure also contains an enumeration which + is set to either RT_ADD or RT_DELETE prior to changing the mapping, + depending upon whether or not the library is being mapped or unmapped, + and then set to RT_CONSISTENT after the library is mapped/unmapped. +*/ + +static int +enable_break () +{ + int success = 0; + +#ifndef SVR4_SHARED_LIBS + + int j; + int in_debugger; + + /* Get link_dynamic structure */ + + j = target_read_memory (debug_base, (char *) &dynamic_copy, + sizeof (dynamic_copy)); + if (j) + { + /* unreadable */ + return (0); + } + + /* Calc address of debugger interface structure */ + + debug_addr = (CORE_ADDR) dynamic_copy.ldd; + + /* Calc address of `in_debugger' member of debugger interface structure */ + + flag_addr = debug_addr + (CORE_ADDR) ((char *) &debug_copy.ldd_in_debugger - + (char *) &debug_copy); + + /* Write a value of 1 to this member. */ + + in_debugger = 1; + write_memory (flag_addr, (char *) &in_debugger, sizeof (in_debugger)); + success = 1; + +#else /* SVR4_SHARED_LIBS */ + +#ifdef BKPT_AT_SYMBOL + + struct minimal_symbol *msymbol; + char **bkpt_namep; + CORE_ADDR bkpt_addr; + + /* Scan through the list of symbols, trying to look up the symbol and + set a breakpoint there. Terminate loop when we/if we succeed. */ + + breakpoint_addr = 0; + for (bkpt_namep = bkpt_names; *bkpt_namep != NULL; bkpt_namep++) + { + msymbol = lookup_minimal_symbol (*bkpt_namep, symfile_objfile); + if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) + { + bkpt_addr = SYMBOL_VALUE_ADDRESS (msymbol); + if (target_insert_breakpoint (bkpt_addr, shadow_contents) == 0) + { + breakpoint_addr = bkpt_addr; + success = 1; + break; + } + } + } + +#else /* !BKPT_AT_SYMBOL */ + + struct symtab_and_line sal; + + /* Read the debugger interface structure directly. */ + + read_memory (debug_base, (char *) &debug_copy, sizeof (debug_copy)); + + /* Set breakpoint at the debugger interface stub routine that will + be called just prior to each mapping change and again after the + mapping change is complete. Set up the (nonexistent) handler to + deal with hitting these breakpoints. (FIXME). */ + + warning ("'%s': line %d: missing SVR4 support code", __FILE__, __LINE__); + success = 1; + +#endif /* BKPT_AT_SYMBOL */ + +#endif /* !SVR4_SHARED_LIBS */ + + return (success); +} + +/* + +GLOBAL FUNCTION + + solib_create_inferior_hook -- shared library startup support + +SYNOPSIS + + void solib_create_inferior_hook() + +DESCRIPTION + + When gdb starts up the inferior, it nurses it along (through the + shell) until it is ready to execute it's first instruction. At this + point, this function gets called via expansion of the macro + SOLIB_CREATE_INFERIOR_HOOK. + + For SunOS executables, this first instruction is typically the + one at "_start", or a similar text label, regardless of whether + the executable is statically or dynamically linked. The runtime + startup code takes care of dynamically linking in any shared + libraries, once gdb allows the inferior to continue. + + For SVR4 executables, this first instruction is either the first + instruction in the dynamic linker (for dynamically linked + executables) or the instruction at "start" for statically linked + executables. For dynamically linked executables, the system + first exec's /lib/libc.so.N, which contains the dynamic linker, + and starts it running. The dynamic linker maps in any needed + shared libraries, maps in the actual user executable, and then + jumps to "start" in the user executable. + + For both SunOS shared libraries, and SVR4 shared libraries, we + can arrange to cooperate with the dynamic linker to discover the + names of shared libraries that are dynamically linked, and the + base addresses to which they are linked. + + This function is responsible for discovering those names and + addresses, and saving sufficient information about them to allow + their symbols to be read at a later time. + +FIXME + + Between enable_break() and disable_break(), this code does not + properly handle hitting breakpoints which the user might have + set in the startup code or in the dynamic linker itself. Proper + handling will probably have to wait until the implementation is + changed to use the "breakpoint handler function" method. + + Also, what if child has exit()ed? Must exit loop somehow. + */ + +void +solib_create_inferior_hook() +{ + /* If we are using the BKPT_AT_SYMBOL code, then we don't need the base + yet. In fact, in the case of a SunOS4 executable being run on + Solaris, we can't get it yet. find_solib will get it when it needs + it. */ +#if !(defined (SVR4_SHARED_LIBS) && defined (BKPT_AT_SYMBOL)) + if ((debug_base = locate_base ()) == 0) + { + /* Can't find the symbol or the executable is statically linked. */ + return; + } +#endif + + if (!enable_break ()) + { + warning ("shared library handler failed to enable breakpoint"); + return; + } + + /* Now run the target. It will eventually hit the breakpoint, at + which point all of the libraries will have been mapped in and we + can go groveling around in the dynamic linker structures to find + out what we need to know about them. */ + + clear_proceed_status (); + stop_soon_quietly = 1; + stop_signal = TARGET_SIGNAL_0; + do + { + target_resume (-1, 0, stop_signal); + wait_for_inferior (); + } + while (stop_signal != TARGET_SIGNAL_TRAP); + stop_soon_quietly = 0; + + /* We are now either at the "mapping complete" breakpoint (or somewhere + else, a condition we aren't prepared to deal with anyway), so adjust + the PC as necessary after a breakpoint, disable the breakpoint, and + add any shared libraries that were mapped in. */ + + if (DECR_PC_AFTER_BREAK) + { + stop_pc -= DECR_PC_AFTER_BREAK; + write_register (PC_REGNUM, stop_pc); + } + + if (!disable_break ()) + { + warning ("shared library handler failed to disable breakpoint"); + } + + solib_add ((char *) 0, 0, (struct target_ops *) 0); +} + +/* + +LOCAL FUNCTION + + special_symbol_handling -- additional shared library symbol handling + +SYNOPSIS + + void special_symbol_handling (struct so_list *so) + +DESCRIPTION + + Once the symbols from a shared object have been loaded in the usual + way, we are called to do any system specific symbol handling that + is needed. + + For Suns, this consists of grunging around in the dynamic linkers + structures to find symbol definitions for "common" symbols and + adding them to the minimal symbol table for the corresponding + objfile. + +*/ + +static void +special_symbol_handling (so) +struct so_list *so; +{ +#ifndef SVR4_SHARED_LIBS + int j; + + if (debug_addr == 0) + { + /* Get link_dynamic structure */ + + j = target_read_memory (debug_base, (char *) &dynamic_copy, + sizeof (dynamic_copy)); + if (j) + { + /* unreadable */ + return; + } + + /* Calc address of debugger interface structure */ + /* FIXME, this needs work for cross-debugging of core files + (byteorder, size, alignment, etc). */ + + debug_addr = (CORE_ADDR) dynamic_copy.ldd; + } + + /* Read the debugger structure from the inferior, just to make sure + we have a current copy. */ + + j = target_read_memory (debug_addr, (char *) &debug_copy, + sizeof (debug_copy)); + if (j) + return; /* unreadable */ + + /* Get common symbol definitions for the loaded object. */ + + if (debug_copy.ldd_cp) + { + solib_add_common_symbols (debug_copy.ldd_cp, so -> objfile); + } + +#endif /* !SVR4_SHARED_LIBS */ +} + + +/* + +LOCAL FUNCTION + + sharedlibrary_command -- handle command to explicitly add library + +SYNOPSIS + + static void sharedlibrary_command (char *args, int from_tty) + +DESCRIPTION + +*/ + +static void +sharedlibrary_command (args, from_tty) +char *args; +int from_tty; +{ + dont_repeat (); + solib_add (args, from_tty, (struct target_ops *) 0); +} + +void +_initialize_solib() +{ + + add_com ("sharedlibrary", class_files, sharedlibrary_command, + "Load shared object library symbols for files matching REGEXP."); + add_info ("sharedlibrary", info_sharedlibrary_command, + "Status of loaded shared object libraries."); +} diff --git a/gnu/usr.bin/gdb/gdb/top.c b/gnu/usr.bin/gdb/gdb/top.c new file mode 100644 index 00000000000..0c693feff3c --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/top.c @@ -0,0 +1,2493 @@ +/* Top level stuff for GDB, the GNU debugger. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994 + Free Software Foundation, Inc. + +This file is part of GDB. + +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. */ + +#include "defs.h" +#include "gdbcmd.h" +#include "call-cmds.h" +#include "symtab.h" +#include "inferior.h" +#include "signals.h" +#include "target.h" +#include "breakpoint.h" +#include "gdbtypes.h" +#include "expression.h" +#include "language.h" +#include "terminal.h" /* For job_control. */ +#include "annotate.h" +#include +#include "top.h" + +/* readline include files */ +#include "readline.h" +#include "history.h" + +/* readline defines this. */ +#undef savestring + +#include +#ifdef USG +/* What is this for? X_OK? */ +#include +#endif + +#include +#ifndef NO_SYS_FILE +#include +#endif +#include +#include +#include + +/* Prototypes for local functions */ + +static char * +symbol_completion_function PARAMS ((char *, int)); + +static void +command_loop_marker PARAMS ((int)); + +static void +init_main PARAMS ((void)); + +static void +init_cmd_lists PARAMS ((void)); + +static void +float_handler PARAMS ((int)); + +static void +init_signals PARAMS ((void)); + +static void +set_verbose PARAMS ((char *, int, struct cmd_list_element *)); + +static void +show_history PARAMS ((char *, int)); + +static void +set_history PARAMS ((char *, int)); + +static void +set_history_size_command PARAMS ((char *, int, struct cmd_list_element *)); + +static void +show_commands PARAMS ((char *, int)); + +static void +echo_command PARAMS ((char *, int)); + +static void +pwd_command PARAMS ((char *, int)); + +static void +show_version PARAMS ((char *, int)); + +static void +document_command PARAMS ((char *, int)); + +static void +define_command PARAMS ((char *, int)); + +static void +validate_comname PARAMS ((char *)); + +static void +help_command PARAMS ((char *, int)); + +static void +show_command PARAMS ((char *, int)); + +static void +info_command PARAMS ((char *, int)); + +static void +complete_command PARAMS ((char *, int)); + +static void +do_nothing PARAMS ((int)); + +static int +quit_cover PARAMS ((char *)); + +static void +disconnect PARAMS ((int)); + +static void +source_cleanup PARAMS ((FILE *)); + +/* If this definition isn't overridden by the header files, assume + that isatty and fileno exist on this system. */ +#ifndef ISATTY +#define ISATTY(FP) (isatty (fileno (FP))) +#endif + +/* Initialization file name for gdb. This is overridden in some configs. */ + +#ifndef GDBINIT_FILENAME +#define GDBINIT_FILENAME ".gdbinit" +#endif +char gdbinit[] = GDBINIT_FILENAME; +int inhibit_gdbinit = 0; + +/* Version number of GDB, as a string. */ + +extern char *version; + +/* Canonical host name as a string. */ + +extern char *host_name; + +/* Canonical target name as a string. */ + +extern char *target_name; + +extern char lang_frame_mismatch_warn[]; /* language.c */ + +/* Flag for whether we want all the "from_tty" gubbish printed. */ + +int caution = 1; /* Default is yes, sigh. */ + +/* + * Define all cmd_list_element's + */ + +/* Chain containing all defined commands. */ + +struct cmd_list_element *cmdlist; + +/* Chain containing all defined info subcommands. */ + +struct cmd_list_element *infolist; + +/* Chain containing all defined enable subcommands. */ + +struct cmd_list_element *enablelist; + +/* Chain containing all defined disable subcommands. */ + +struct cmd_list_element *disablelist; + +/* Chain containing all defined delete subcommands. */ + +struct cmd_list_element *deletelist; + +/* Chain containing all defined "enable breakpoint" subcommands. */ + +struct cmd_list_element *enablebreaklist; + +/* Chain containing all defined set subcommands */ + +struct cmd_list_element *setlist; + +/* Chain containing all defined unset subcommands */ + +struct cmd_list_element *unsetlist; + +/* Chain containing all defined show subcommands. */ + +struct cmd_list_element *showlist; + +/* Chain containing all defined \"set history\". */ + +struct cmd_list_element *sethistlist; + +/* Chain containing all defined \"show history\". */ + +struct cmd_list_element *showhistlist; + +/* Chain containing all defined \"unset history\". */ + +struct cmd_list_element *unsethistlist; + +/* Chain containing all defined maintenance subcommands. */ + +#if MAINTENANCE_CMDS +struct cmd_list_element *maintenancelist; +#endif + +/* Chain containing all defined "maintenance info" subcommands. */ + +#if MAINTENANCE_CMDS +struct cmd_list_element *maintenanceinfolist; +#endif + +/* Chain containing all defined "maintenance print" subcommands. */ + +#if MAINTENANCE_CMDS +struct cmd_list_element *maintenanceprintlist; +#endif + +struct cmd_list_element *setprintlist; + +struct cmd_list_element *showprintlist; + +struct cmd_list_element *setchecklist; + +struct cmd_list_element *showchecklist; + +/* stdio stream that command input is being read from. Set to stdin normally. + Set by source_command to the file we are sourcing. Set to NULL if we are + executing a user-defined command. */ + +FILE *instream; + +/* Current working directory. */ + +char *current_directory; + +/* The directory name is actually stored here (usually). */ +char gdb_dirbuf[1024]; + +/* Function to call before reading a command, if nonzero. + The function receives two args: an input stream, + and a prompt string. */ + +void (*window_hook) PARAMS ((FILE *, char *)); + +int epoch_interface; +int xgdb_verbose; + +/* gdb prints this when reading a command interactively */ +static char *prompt; + +/* Buffer used for reading command lines, and the size + allocated for it so far. */ + +char *line; +int linesize = 100; + +/* Nonzero if the current command is modified by "server ". This + affects things like recording into the command history, comamnds + repeating on RETURN, etc. This is so a user interface (emacs, GUI, + whatever) can issue its own commands and also send along commands + from the user, and have the user not notice that the user interface + is issuing commands too. */ +int server_command; + +/* Baud rate specified for talking to serial target systems. Default + is left as -1, so targets can choose their own defaults. */ +/* FIXME: This means that "show remotebaud" and gr_files_info can print -1 + or (unsigned int)-1. This is a Bad User Interface. */ + +int baud_rate = -1; + +/* Non-zero tells remote* modules to output debugging info. */ + +int remote_debug = 0; + +/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */ + +#ifndef STOP_SIGNAL +#ifdef SIGTSTP +#define STOP_SIGNAL SIGTSTP +static void stop_sig PARAMS ((int)); +#endif +#endif + +/* Some System V have job control but not sigsetmask(). */ +#if !defined (HAVE_SIGSETMASK) +#if !defined (USG) +#define HAVE_SIGSETMASK 1 +#else +#define HAVE_SIGSETMASK 0 +#endif +#endif + +#if 0 == (HAVE_SIGSETMASK) +#define sigsetmask(n) +#endif + +/* Where to go for return_to_top_level (RETURN_ERROR). */ +jmp_buf error_return; +/* Where to go for return_to_top_level (RETURN_QUIT). */ +jmp_buf quit_return; + +#ifdef KERNEL_DEBUG +/* Non-zero means we are debugging a kernel core file */ +int kernel_debugging = 0; +#endif + +/* Return for reason REASON. This generally gets back to the command + loop, but can be caught via catch_errors. */ + +NORETURN void +return_to_top_level (reason) + enum return_reason reason; +{ + quit_flag = 0; + immediate_quit = 0; + + /* Perhaps it would be cleaner to do this via the cleanup chain (not sure + I can think of a reason why that is vital, though). */ + bpstat_clear_actions(stop_bpstat); /* Clear queued breakpoint commands */ + + disable_current_display (); + do_cleanups (ALL_CLEANUPS); + + if (annotation_level > 1) + switch (reason) + { + case RETURN_QUIT: + annotate_quit (); + break; + case RETURN_ERROR: + annotate_error (); + break; + } + + (NORETURN void) longjmp + (reason == RETURN_ERROR ? error_return : quit_return, 1); +} + +/* Call FUNC with arg ARGS, catching any errors. If there is no + error, return the value returned by FUNC. If there is an error, + print ERRSTRING, print the specific error message, then return + zero. + + Must not be called with immediate_quit in effect (bad things might + happen, say we got a signal in the middle of a memcpy to quit_return). + This is an OK restriction; with very few exceptions immediate_quit can + be replaced by judicious use of QUIT. + + MASK specifies what to catch; it is normally set to + RETURN_MASK_ALL, if for no other reason than that the code which + calls catch_errors might not be set up to deal with a quit which + isn't caught. But if the code can deal with it, it generally + should be RETURN_MASK_ERROR, unless for some reason it is more + useful to abort only the portion of the operation inside the + catch_errors. Note that quit should return to the command line + fairly quickly, even if some further processing is being done. */ + +int +catch_errors (func, args, errstring, mask) + int (*func) PARAMS ((char *)); + PTR args; + char *errstring; + return_mask mask; +{ + jmp_buf saved_error; + jmp_buf saved_quit; + jmp_buf tmp_jmp; + int val; + struct cleanup *saved_cleanup_chain; + char *saved_error_pre_print; + + saved_cleanup_chain = save_cleanups (); + saved_error_pre_print = error_pre_print; + + if (mask & RETURN_MASK_ERROR) + memcpy ((char *)saved_error, (char *)error_return, sizeof (jmp_buf)); + if (mask & RETURN_MASK_QUIT) + memcpy (saved_quit, quit_return, sizeof (jmp_buf)); + error_pre_print = errstring; + + if (setjmp (tmp_jmp) == 0) + { + if (mask & RETURN_MASK_ERROR) + memcpy (error_return, tmp_jmp, sizeof (jmp_buf)); + if (mask & RETURN_MASK_QUIT) + memcpy (quit_return, tmp_jmp, sizeof (jmp_buf)); + val = (*func) (args); + } + else + val = 0; + + restore_cleanups (saved_cleanup_chain); + + error_pre_print = saved_error_pre_print; + if (mask & RETURN_MASK_ERROR) + memcpy (error_return, saved_error, sizeof (jmp_buf)); + if (mask & RETURN_MASK_QUIT) + memcpy (quit_return, saved_quit, sizeof (jmp_buf)); + return val; +} + +/* Handler for SIGHUP. */ + +static void +disconnect (signo) +int signo; +{ + catch_errors (quit_cover, NULL, + "Could not kill the program being debugged", RETURN_MASK_ALL); + signal (SIGHUP, SIG_DFL); + kill (getpid (), SIGHUP); +} + +/* Just a little helper function for disconnect(). */ + +static int +quit_cover (s) +char *s; +{ + caution = 0; /* Throw caution to the wind -- we're exiting. + This prevents asking the user dumb questions. */ + quit_command((char *)0, 0); + return 0; +} + +/* Line number we are currently in in a file which is being sourced. */ +static int source_line_number; + +/* Name of the file we are sourcing. */ +static char *source_file_name; + +/* Buffer containing the error_pre_print used by the source stuff. + Malloc'd. */ +static char *source_error; +static int source_error_allocated; + +/* Something to glom on to the start of error_pre_print if source_file_name + is set. */ +static char *source_pre_error; + +/* Clean up on error during a "source" command (or execution of a + user-defined command). */ + +static void +source_cleanup (stream) + FILE *stream; +{ + /* Restore the previous input stream. */ + instream = stream; +} + +/* Read commands from STREAM. */ +void +read_command_file (stream) + FILE *stream; +{ + struct cleanup *cleanups; + + cleanups = make_cleanup (source_cleanup, instream); + instream = stream; + command_loop (); + do_cleanups (cleanups); +} + +extern void init_proc (); + +void +gdb_init () +{ + /* Run the init function of each source file */ + + getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); + current_directory = gdb_dirbuf; + + init_cmd_lists (); /* This needs to be done first */ + initialize_all_files (); + init_main (); /* But that omits this file! Do it now */ + init_signals (); + + init_proc (); + + /* We need a default language for parsing expressions, so simple things like + "set width 0" won't fail if no language is explicitly set in a config file + or implicitly set by reading an executable during startup. */ + set_language (language_c); + expected_language = current_language; /* don't warn about the change. */ +} + +void +execute_user_command (c, args) + struct cmd_list_element *c; + char *args; +{ + register struct command_line *cmdlines; + struct cleanup *old_chain; + + if (args) + error ("User-defined commands cannot take arguments."); + + cmdlines = c->user_commands; + if (cmdlines == 0) + /* Null command */ + return; + + /* Set the instream to 0, indicating execution of a + user-defined function. */ + old_chain = make_cleanup (source_cleanup, instream); + instream = (FILE *) 0; + while (cmdlines) + { + execute_command (cmdlines->line, 0); + cmdlines = cmdlines->next; + } + do_cleanups (old_chain); +} + +/* Execute the line P as a command. + Pass FROM_TTY as second argument to the defining function. */ + +void +execute_command (p, from_tty) + char *p; + int from_tty; +{ + register struct cmd_list_element *c; + register enum language flang; + static int warned = 0; + + free_all_values (); + + /* This can happen when command_line_input hits end of file. */ + if (p == NULL) + return; + + while (*p == ' ' || *p == '\t') p++; + if (*p) + { + char *arg; + + c = lookup_cmd (&p, cmdlist, "", 0, 1); + /* Pass null arg rather than an empty one. */ + arg = *p ? p : 0; + + /* If this command has been hooked, run the hook first. */ + if (c->hook) + execute_user_command (c->hook, (char *)0); + + if (c->class == class_user) + execute_user_command (c, arg); + else if (c->type == set_cmd || c->type == show_cmd) + do_setshow_command (arg, from_tty & caution, c); + else if (c->function.cfunc == NO_FUNCTION) + error ("That is not a command, just a help topic."); + else + (*c->function.cfunc) (arg, from_tty & caution); + } + + /* Tell the user if the language has changed (except first time). */ + if (current_language != expected_language) + { + if (language_mode == language_mode_auto) { + language_info (1); /* Print what changed. */ + } + warned = 0; + } + + /* Warn the user if the working language does not match the + language of the current frame. Only warn the user if we are + actually running the program, i.e. there is a stack. */ + /* FIXME: This should be cacheing the frame and only running when + the frame changes. */ + if (target_has_stack) + { + flang = get_frame_language (); + if (!warned + && flang != language_unknown + && flang != current_language->la_language) + { + printf_filtered ("%s\n", lang_frame_mismatch_warn); + warned = 1; + } + } +} + +/* ARGSUSED */ +static void +command_loop_marker (foo) + int foo; +{ +} + +/* Read commands from `instream' and execute them + until end of file or error reading instream. */ +void +command_loop () +{ + struct cleanup *old_chain; + char *command; + int stdin_is_tty = ISATTY (stdin); + + while (!feof (instream)) + { + if (window_hook && instream == stdin) + (*window_hook) (instream, prompt); + + quit_flag = 0; + if (instream == stdin && stdin_is_tty) + reinitialize_more_filter (); + old_chain = make_cleanup (command_loop_marker, 0); + command = command_line_input (instream == stdin ? prompt : (char *) NULL, + instream == stdin, "prompt"); + if (command == 0) + return; + execute_command (command, instream == stdin); + /* Do any commands attached to breakpoint we stopped at. */ + bpstat_do_actions (&stop_bpstat); + do_cleanups (old_chain); + } +} + +/* Commands call this if they do not want to be repeated by null lines. */ + +void +dont_repeat () +{ + if (server_command) + return; + + /* If we aren't reading from standard input, we are saving the last + thing read from stdin in line and don't want to delete it. Null lines + won't repeat here in any case. */ + if (instream == stdin) + *line = 0; +} + +/* Read a line from the stream "instream" without command line editing. + + It prints PRROMPT once at the start. + Action is compatible with "readline", e.g. space for the result is + malloc'd and should be freed by the caller. + + A NULL return means end of file. */ +char * +gdb_readline (prrompt) + char *prrompt; +{ + int c; + char *result; + int input_index = 0; + int result_size = 80; + + if (prrompt) + { + /* Don't use a _filtered function here. It causes the assumed + character position to be off, since the newline we read from + the user is not accounted for. */ + fputs_unfiltered (prrompt, gdb_stdout); + gdb_flush (gdb_stdout); + } + + result = (char *) xmalloc (result_size); + + while (1) + { + /* Read from stdin if we are executing a user defined command. + This is the right thing for prompt_for_continue, at least. */ + c = fgetc (instream ? instream : stdin); + + if (c == EOF) + { + if (input_index > 0) + /* The last line does not end with a newline. Return it, and + if we are called again fgetc will still return EOF and + we'll return NULL then. */ + break; + free (result); + return NULL; + } + + if (c == '\n') + break; + + result[input_index++] = c; + while (input_index >= result_size) + { + result_size *= 2; + result = (char *) xrealloc (result, result_size); + } + } + + result[input_index++] = '\0'; + return result; +} + +/* Variables which control command line editing and history + substitution. These variables are given default values at the end + of this file. */ +static int command_editing_p; +static int history_expansion_p; +static int write_history_p; +static int history_size; +static char *history_filename; + +/* readline uses the word breaks for two things: + (1) In figuring out where to point the TEXT parameter to the + rl_completion_entry_function. Since we don't use TEXT for much, + it doesn't matter a lot what the word breaks are for this purpose, but + it does affect how much stuff M-? lists. + (2) If one of the matches contains a word break character, readline + will quote it. That's why we switch between + gdb_completer_word_break_characters and + gdb_completer_command_word_break_characters. I'm not sure when + we need this behavior (perhaps for funky characters in C++ symbols?). */ + +/* Variables which are necessary for fancy command line editing. */ +char *gdb_completer_word_break_characters = + " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,-"; + +/* When completing on command names, we remove '-' from the list of + word break characters, since we use it in command names. If the + readline library sees one in any of the current completion strings, + it thinks that the string needs to be quoted and automatically supplies + a leading quote. */ +char *gdb_completer_command_word_break_characters = + " \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,"; + +/* Characters that can be used to quote completion strings. Note that we + can't include '"' because the gdb C parser treats such quoted sequences + as strings. */ +char *gdb_completer_quote_characters = + "'"; + +/* Functions that are used as part of the fancy command line editing. */ + +/* This can be used for functions which don't want to complete on symbols + but don't want to complete on anything else either. */ +/* ARGSUSED */ +char ** +noop_completer (text, prefix) + char *text; + char *prefix; +{ + return NULL; +} + +/* Complete on filenames. */ +char ** +filename_completer (text, word) + char *text; + char *word; +{ + /* From readline. */ + extern char *filename_completion_function (); + int subsequent_name; + char **return_val; + int return_val_used; + int return_val_alloced; + + return_val_used = 0; + /* Small for testing. */ + return_val_alloced = 1; + return_val = (char **) xmalloc (return_val_alloced * sizeof (char *)); + + subsequent_name = 0; + while (1) + { + char *p; + p = filename_completion_function (text, subsequent_name); + if (return_val_used >= return_val_alloced) + { + return_val_alloced *= 2; + return_val = + (char **) xrealloc (return_val, + return_val_alloced * sizeof (char *)); + } + if (p == NULL) + { + return_val[return_val_used++] = p; + break; + } + /* Like emacs, don't complete on old versions. Especially useful + in the "source" command. */ + if (p[strlen (p) - 1] == '~') + continue; + + { + char *q; + if (word == text) + /* Return exactly p. */ + return_val[return_val_used++] = p; + else if (word > text) + { + /* Return some portion of p. */ + q = xmalloc (strlen (p) + 5); + strcpy (q, p + (word - text)); + return_val[return_val_used++] = q; + free (p); + } + else + { + /* Return some of TEXT plus p. */ + q = xmalloc (strlen (p) + (text - word) + 5); + strncpy (q, word, text - word); + q[text - word] = '\0'; + strcat (q, p); + return_val[return_val_used++] = q; + free (p); + } + } + subsequent_name = 1; + } +#if 0 + /* There is no way to do this just long enough to affect quote inserting + without also affecting the next completion. This should be fixed in + readline. FIXME. */ + /* Insure that readline does the right thing + with respect to inserting quotes. */ + rl_completer_word_break_characters = ""; +#endif + return return_val; +} + +/* Here are some useful test cases for completion. FIXME: These should + be put in the test suite. They should be tested with both M-? and TAB. + + "show output-" "radix" + "show output" "-radix" + "p" ambiguous (commands starting with p--path, print, printf, etc.) + "p " ambiguous (all symbols) + "info t foo" no completions + "info t " no completions + "info t" ambiguous ("info target", "info terminal", etc.) + "info ajksdlfk" no completions + "info ajksdlfk " no completions + "info" " " + "info " ambiguous (all info commands) + "p \"a" no completions (string constant) + "p 'a" ambiguous (all symbols starting with a) + "p b-a" ambiguous (all symbols starting with a) + "p b-" ambiguous (all symbols) + "file Make" "file" (word break hard to screw up here) + "file ../gdb.stabs/we" "ird" (needs to not break word at slash) + */ + +/* Generate completions one by one for the completer. Each time we are + called return another potential completion to the caller. The function + is misnamed; it just completes on commands or passes the buck to the + command's completer function; the stuff specific to symbol completion + is in make_symbol_completion_list. + + TEXT is readline's idea of the "word" we are looking at; we don't really + like readline's ideas about word breaking so we ignore it. + + MATCHES is the number of matches that have currently been collected from + calling this completion function. When zero, then we need to initialize, + otherwise the initialization has already taken place and we can just + return the next potential completion string. + + Returns NULL if there are no more completions, else a pointer to a string + which is a possible completion. + + RL_LINE_BUFFER is available to be looked at; it contains the entire text + of the line. RL_POINT is the offset in that line of the cursor. You + should pretend that the line ends at RL_POINT. */ + +static char * +symbol_completion_function (text, matches) + char *text; + int matches; +{ + static char **list = (char **)NULL; /* Cache of completions */ + static int index; /* Next cached completion */ + char *output = NULL; + char *tmp_command, *p; + /* Pointer within tmp_command which corresponds to text. */ + char *word; + struct cmd_list_element *c, *result_list; + + if (matches == 0) + { + /* The caller is beginning to accumulate a new set of completions, so + we need to find all of them now, and cache them for returning one at + a time on future calls. */ + + if (list) + { + /* Free the storage used by LIST, but not by the strings inside. + This is because rl_complete_internal () frees the strings. */ + free ((PTR)list); + } + list = 0; + index = 0; + + /* Choose the default set of word break characters to break completions. + If we later find out that we are doing completions on command strings + (as opposed to strings supplied by the individual command completer + functions, which can be any string) then we will switch to the + special word break set for command strings, which leaves out the + '-' character used in some commands. */ + + rl_completer_word_break_characters = + gdb_completer_word_break_characters; + + /* Decide whether to complete on a list of gdb commands or on symbols. */ + tmp_command = (char *) alloca (rl_point + 1); + p = tmp_command; + + strncpy (tmp_command, rl_line_buffer, rl_point); + tmp_command[rl_point] = '\0'; + /* Since text always contains some number of characters leading up + to rl_point, we can find the equivalent position in tmp_command + by subtracting that many characters from the end of tmp_command. */ + word = tmp_command + rl_point - strlen (text); + + if (rl_point == 0) + { + /* An empty line we want to consider ambiguous; that is, it + could be any command. */ + c = (struct cmd_list_element *) -1; + result_list = 0; + } + else + { + c = lookup_cmd_1 (&p, cmdlist, &result_list, 1); + } + + /* Move p up to the next interesting thing. */ + while (*p == ' ' || *p == '\t') + { + p++; + } + + if (!c) + { + /* It is an unrecognized command. So there are no + possible completions. */ + list = NULL; + } + else if (c == (struct cmd_list_element *) -1) + { + char *q; + + /* lookup_cmd_1 advances p up to the first ambiguous thing, but + doesn't advance over that thing itself. Do so now. */ + q = p; + while (*q && (isalnum (*q) || *q == '-' || *q == '_')) + ++q; + if (q != tmp_command + rl_point) + { + /* There is something beyond the ambiguous + command, so there are no possible completions. For + example, "info t " or "info t foo" does not complete + to anything, because "info t" can be "info target" or + "info terminal". */ + list = NULL; + } + else + { + /* We're trying to complete on the command which was ambiguous. + This we can deal with. */ + if (result_list) + { + list = complete_on_cmdlist (*result_list->prefixlist, p, + word); + } + else + { + list = complete_on_cmdlist (cmdlist, p, word); + } + /* Insure that readline does the right thing with respect to + inserting quotes. */ + rl_completer_word_break_characters = + gdb_completer_command_word_break_characters; + } + } + else + { + /* We've recognized a full command. */ + + if (p == tmp_command + rl_point) + { + /* There is no non-whitespace in the line beyond the command. */ + + if (p[-1] == ' ' || p[-1] == '\t') + { + /* The command is followed by whitespace; we need to complete + on whatever comes after command. */ + if (c->prefixlist) + { + /* It is a prefix command; what comes after it is + a subcommand (e.g. "info "). */ + list = complete_on_cmdlist (*c->prefixlist, p, word); + + /* Insure that readline does the right thing + with respect to inserting quotes. */ + rl_completer_word_break_characters = + gdb_completer_command_word_break_characters; + } + else + { + /* It is a normal command; what comes after it is + completed by the command's completer function. */ + list = (*c->completer) (p, word); + } + } + else + { + /* The command is not followed by whitespace; we need to + complete on the command itself. e.g. "p" which is a + command itself but also can complete to "print", "ptype" + etc. */ + char *q; + + /* Find the command we are completing on. */ + q = p; + while (q > tmp_command) + { + if (isalnum (q[-1]) || q[-1] == '-' || q[-1] == '_') + --q; + else + break; + } + + list = complete_on_cmdlist (result_list, q, word); + + /* Insure that readline does the right thing + with respect to inserting quotes. */ + rl_completer_word_break_characters = + gdb_completer_command_word_break_characters; + } + } + else + { + /* There is non-whitespace beyond the command. */ + + if (c->prefixlist && !c->allow_unknown) + { + /* It is an unrecognized subcommand of a prefix command, + e.g. "info adsfkdj". */ + list = NULL; + } + else + { + /* It is a normal command. */ + list = (*c->completer) (p, word); + } + } + } + } + + /* If we found a list of potential completions during initialization then + dole them out one at a time. The vector of completions is NULL + terminated, so after returning the last one, return NULL (and continue + to do so) each time we are called after that, until a new list is + available. */ + + if (list) + { + output = list[index]; + if (output) + { + index++; + } + } + +#if 0 + /* Can't do this because readline hasn't yet checked the word breaks + for figuring out whether to insert a quote. */ + if (output == NULL) + /* Make sure the word break characters are set back to normal for the + next time that readline tries to complete something. */ + rl_completer_word_break_characters = + gdb_completer_word_break_characters; +#endif + + return (output); +} + +/* Skip over a possibly quoted word (as defined by the quote characters + and word break characters the completer uses). Returns pointer to the + location after the "word". */ + +char * +skip_quoted (str) + char *str; +{ + char quote_char = '\0'; + char *scan; + + for (scan = str; *scan != '\0'; scan++) + { + if (quote_char != '\0') + { + /* Ignore everything until the matching close quote char */ + if (*scan == quote_char) + { + /* Found matching close quote. */ + scan++; + break; + } + } + else if (strchr (gdb_completer_quote_characters, *scan)) + { + /* Found start of a quoted string. */ + quote_char = *scan; + } + else if (strchr (gdb_completer_word_break_characters, *scan)) + { + break; + } + } + return (scan); +} + + +#ifdef STOP_SIGNAL +static void +stop_sig (signo) +int signo; +{ +#if STOP_SIGNAL == SIGTSTP + signal (SIGTSTP, SIG_DFL); + sigsetmask (0); + kill (getpid (), SIGTSTP); + signal (SIGTSTP, stop_sig); +#else + signal (STOP_SIGNAL, stop_sig); +#endif + printf_unfiltered ("%s", prompt); + gdb_flush (gdb_stdout); + + /* Forget about any previous command -- null line now will do nothing. */ + dont_repeat (); +} +#endif /* STOP_SIGNAL */ + +/* Initialize signal handlers. */ +static void +do_nothing (signo) +int signo; +{ +} + +static void +init_signals () +{ + signal (SIGINT, request_quit); + + /* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get + passed to the inferior, which we don't want. It would be + possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but + on BSD4.3 systems using vfork, that can affect the + GDB process as well as the inferior (the signal handling tables + might be in memory, shared between the two). Since we establish + a handler for SIGQUIT, when we call exec it will set the signal + to SIG_DFL for us. */ + signal (SIGQUIT, do_nothing); + if (signal (SIGHUP, do_nothing) != SIG_IGN) + signal (SIGHUP, disconnect); + signal (SIGFPE, float_handler); + +#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER) + signal (SIGWINCH, SIGWINCH_HANDLER); +#endif +} + +/* Read one line from the command input stream `instream' + into the local static buffer `linebuffer' (whose current length + is `linelength'). + The buffer is made bigger as necessary. + Returns the address of the start of the line. + + NULL is returned for end of file. + + *If* the instream == stdin & stdin is a terminal, the line read + is copied into the file line saver (global var char *line, + length linesize) so that it can be duplicated. + + This routine either uses fancy command line editing or + simple input as the user has requested. */ + +char * +command_line_input (prrompt, repeat, annotation_suffix) + char *prrompt; + int repeat; + char *annotation_suffix; +{ + static char *linebuffer = 0; + static unsigned linelength = 0; + register char *p; + char *p1; + char *rl; + char *local_prompt = prrompt; + register int c; + char *nline; + char got_eof = 0; + + if (annotation_level > 1 && instream == stdin) + { + local_prompt = alloca ((prrompt == NULL ? 0 : strlen (prrompt)) + + strlen (annotation_suffix) + 40); + if (prrompt == NULL) + local_prompt[0] = '\0'; + else + strcpy (local_prompt, prrompt); + strcat (local_prompt, "\n\032\032"); + strcat (local_prompt, annotation_suffix); + strcat (local_prompt, "\n"); + } + + if (linebuffer == 0) + { + linelength = 80; + linebuffer = (char *) xmalloc (linelength); + } + + p = linebuffer; + + /* Control-C quits instantly if typed while in this loop + since it should not wait until the user types a newline. */ + immediate_quit++; +#ifdef STOP_SIGNAL + if (job_control) + signal (STOP_SIGNAL, stop_sig); +#endif + + while (1) + { + /* Make sure that all output has been output. Some machines may let + you get away with leaving out some of the gdb_flush, but not all. */ + wrap_here (""); + gdb_flush (gdb_stdout); + gdb_flush (gdb_stderr); + + if (source_file_name != NULL) + { + ++source_line_number; + sprintf (source_error, + "%s%s:%d: Error in sourced command file:\n", + source_pre_error, + source_file_name, + source_line_number); + error_pre_print = source_error; + } + + if (annotation_level > 1 && instream == stdin) + { + printf_unfiltered ("\n\032\032pre-"); + printf_unfiltered (annotation_suffix); + printf_unfiltered ("\n"); + } + + /* Don't use fancy stuff if not talking to stdin. */ + if (command_editing_p && instream == stdin + && ISATTY (instream)) + rl = readline (local_prompt); + else + rl = gdb_readline (local_prompt); + + if (annotation_level > 1 && instream == stdin) + { + printf_unfiltered ("\n\032\032post-"); + printf_unfiltered (annotation_suffix); + printf_unfiltered ("\n"); + } + + if (!rl || rl == (char *) EOF) + { + got_eof = 1; + break; + } + if (strlen(rl) + 1 + (p - linebuffer) > linelength) + { + linelength = strlen(rl) + 1 + (p - linebuffer); + nline = (char *) xrealloc (linebuffer, linelength); + p += nline - linebuffer; + linebuffer = nline; + } + p1 = rl; + /* Copy line. Don't copy null at end. (Leaves line alone + if this was just a newline) */ + while (*p1) + *p++ = *p1++; + + free (rl); /* Allocated in readline. */ + + if (p == linebuffer || *(p - 1) != '\\') + break; + + p--; /* Put on top of '\'. */ + local_prompt = (char *) 0; + } + +#ifdef STOP_SIGNAL + if (job_control) + signal (STOP_SIGNAL, SIG_DFL); +#endif + immediate_quit--; + + if (got_eof) + return NULL; + +#define SERVER_COMMAND_LENGTH 7 + server_command = + (p - linebuffer > SERVER_COMMAND_LENGTH) + && STREQN (linebuffer, "server ", SERVER_COMMAND_LENGTH); + if (server_command) + { + /* Note that we don't set `line'. Between this and the check in + dont_repeat, this insures that repeating will still do the + right thing. */ + *p = '\0'; + return linebuffer + SERVER_COMMAND_LENGTH; + } + + /* Do history expansion if that is wished. */ + if (history_expansion_p && instream == stdin + && ISATTY (instream)) + { + char *history_value; + int expanded; + + *p = '\0'; /* Insert null now. */ + expanded = history_expand (linebuffer, &history_value); + if (expanded) + { + /* Print the changes. */ + printf_unfiltered ("%s\n", history_value); + + /* If there was an error, call this function again. */ + if (expanded < 0) + { + free (history_value); + return command_line_input (prrompt, repeat, annotation_suffix); + } + if (strlen (history_value) > linelength) + { + linelength = strlen (history_value) + 1; + linebuffer = (char *) xrealloc (linebuffer, linelength); + } + strcpy (linebuffer, history_value); + p = linebuffer + strlen(linebuffer); + free (history_value); + } + } + + /* If we just got an empty line, and that is supposed + to repeat the previous command, return the value in the + global buffer. */ + if (repeat) + { + if (p == linebuffer) + return line; + p1 = linebuffer; + while (*p1 == ' ' || *p1 == '\t') + p1++; + if (!*p1) + return line; + } + + *p = 0; + + /* Add line to history if appropriate. */ + if (instream == stdin + && ISATTY (stdin) && *linebuffer) + add_history (linebuffer); + + /* Note: lines consisting solely of comments are added to the command + history. This is useful when you type a command, and then + realize you don't want to execute it quite yet. You can comment + out the command and then later fetch it from the value history + and remove the '#'. The kill ring is probably better, but some + people are in the habit of commenting things out. */ + p1 = linebuffer; + while ((c = *p1++) != '\0') + { + if (c == '"') + while ((c = *p1++) != '"') + { + /* Make sure an escaped '"' doesn't make us think the string + is ended. */ + if (c == '\\') + parse_escape (&p1); + if (c == '\0') + break; + } + else if (c == '\'') + while ((c = *p1++) != '\'') + { + /* Make sure an escaped '\'' doesn't make us think the string + is ended. */ + if (c == '\\') + parse_escape (&p1); + if (c == '\0') + break; + } + else if (c == '#') + { + /* Found a comment. */ + p1[-1] = '\0'; + break; + } + } + + /* Save into global buffer if appropriate. */ + if (repeat) + { + if (linelength > linesize) + { + line = xrealloc (line, linelength); + linesize = linelength; + } + strcpy (line, linebuffer); + return line; + } + + return linebuffer; +} + +/* Read lines from the input stream + and accumulate them in a chain of struct command_line's + which is then returned. */ + +struct command_line * +read_command_lines () +{ + struct command_line *first = 0; + register struct command_line *next, *tail = 0; + register char *p, *p1; + struct cleanup *old_chain = 0; + + while (1) + { + dont_repeat (); + p = command_line_input ((char *) NULL, instream == stdin, "commands"); + if (p == NULL) + /* Treat end of file like "end". */ + break; + + /* Remove leading and trailing blanks. */ + while (*p == ' ' || *p == '\t') p++; + p1 = p + strlen (p); + while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) p1--; + + /* Is this "end"? */ + if (p1 - p == 3 && !strncmp (p, "end", 3)) + break; + + /* No => add this line to the chain of command lines. */ + next = (struct command_line *) xmalloc (sizeof (struct command_line)); + next->line = savestring (p, p1 - p); + next->next = 0; + if (tail) + { + tail->next = next; + } + else + { + /* We just read the first line. + From now on, arrange to throw away the lines we have + if we quit or get an error while inside this function. */ + first = next; + old_chain = make_cleanup (free_command_lines, &first); + } + tail = next; + } + + dont_repeat (); + + /* Now we are about to return the chain to our caller, + so freeing it becomes his responsibility. */ + if (first) + discard_cleanups (old_chain); + return first; +} + +/* Free a chain of struct command_line's. */ + +void +free_command_lines (lptr) + struct command_line **lptr; +{ + register struct command_line *l = *lptr; + register struct command_line *next; + + while (l) + { + next = l->next; + free (l->line); + free ((PTR)l); + l = next; + } +} + +/* Add an element to the list of info subcommands. */ + +void +add_info (name, fun, doc) + char *name; + void (*fun) PARAMS ((char *, int)); + char *doc; +{ + add_cmd (name, no_class, fun, doc, &infolist); +} + +/* Add an alias to the list of info subcommands. */ + +void +add_info_alias (name, oldname, abbrev_flag) + char *name; + char *oldname; + int abbrev_flag; +{ + add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist); +} + +/* The "info" command is defined as a prefix, with allow_unknown = 0. + Therefore, its own definition is called only for "info" with no args. */ + +/* ARGSUSED */ +static void +info_command (arg, from_tty) + char *arg; + int from_tty; +{ + printf_unfiltered ("\"info\" must be followed by the name of an info command.\n"); + help_list (infolist, "info ", -1, gdb_stdout); +} + +/* The "complete" command is used by Emacs to implement completion. */ + +/* ARGSUSED */ +static void +complete_command (arg, from_tty) + char *arg; + int from_tty; +{ + int i; + char *completion; + + dont_repeat (); + + if (arg == NULL) + { + rl_line_buffer[0] = '\0'; + rl_point = 0; + } + else + { + strcpy (rl_line_buffer, arg); + rl_point = strlen (arg); + } + + for (completion = symbol_completion_function (rl_line_buffer, i = 0); + completion; + completion = symbol_completion_function (rl_line_buffer, ++i)) + printf_unfiltered ("%s\n", completion); +} + +/* The "show" command with no arguments shows all the settings. */ + +/* ARGSUSED */ +static void +show_command (arg, from_tty) + char *arg; + int from_tty; +{ + cmd_show_list (showlist, from_tty, ""); +} + +/* Add an element to the list of commands. */ + +void +add_com (name, class, fun, doc) + char *name; + enum command_class class; + void (*fun) PARAMS ((char *, int)); + char *doc; +{ + add_cmd (name, class, fun, doc, &cmdlist); +} + +/* Add an alias or abbreviation command to the list of commands. */ + +void +add_com_alias (name, oldname, class, abbrev_flag) + char *name; + char *oldname; + enum command_class class; + int abbrev_flag; +{ + add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist); +} + +void +error_no_arg (why) + char *why; +{ + error ("Argument required (%s).", why); +} + +/* ARGSUSED */ +static void +help_command (command, from_tty) + char *command; + int from_tty; /* Ignored */ +{ + help_cmd (command, gdb_stdout); +} + +static void +validate_comname (comname) + char *comname; +{ + register char *p; + + if (comname == 0) + error_no_arg ("name of command to define"); + + p = comname; + while (*p) + { + if (!isalnum(*p) && *p != '-') + error ("Junk in argument list: \"%s\"", p); + p++; + } +} + +/* This is just a placeholder in the command data structures. */ +static void +user_defined_command (ignore, from_tty) + char *ignore; + int from_tty; +{ +} + +static void +define_command (comname, from_tty) + char *comname; + int from_tty; +{ + register struct command_line *cmds; + register struct cmd_list_element *c, *newc, *hookc = 0; + char *tem = comname; +#define HOOK_STRING "hook-" +#define HOOK_LEN 5 + + validate_comname (comname); + + /* Look it up, and verify that we got an exact match. */ + c = lookup_cmd (&tem, cmdlist, "", -1, 1); + if (c && !STREQ (comname, c->name)) + c = 0; + + if (c) + { + if (c->class == class_user || c->class == class_alias) + tem = "Redefine command \"%s\"? "; + else + tem = "Really redefine built-in command \"%s\"? "; + if (!query (tem, c->name)) + error ("Command \"%s\" not redefined.", c->name); + } + + /* If this new command is a hook, then mark the command which it + is hooking. Note that we allow hooking `help' commands, so that + we can hook the `stop' pseudo-command. */ + + if (!strncmp (comname, HOOK_STRING, HOOK_LEN)) + { + /* Look up cmd it hooks, and verify that we got an exact match. */ + tem = comname+HOOK_LEN; + hookc = lookup_cmd (&tem, cmdlist, "", -1, 0); + if (hookc && !STREQ (comname+HOOK_LEN, hookc->name)) + hookc = 0; + if (!hookc) + { + warning ("Your new `%s' command does not hook any existing command.", + comname); + if (!query ("Proceed? ", (char *)0)) + error ("Not confirmed."); + } + } + + comname = savestring (comname, strlen (comname)); + + /* If the rest of the commands will be case insensitive, this one + should behave in the same manner. */ + for (tem = comname; *tem; tem++) + if (isupper(*tem)) *tem = tolower(*tem); + + if (from_tty) + { + printf_unfiltered ("Type commands for definition of \"%s\".\n\ +End with a line saying just \"end\".\n", comname); + gdb_flush (gdb_stdout); + } + + cmds = read_command_lines (); + + if (c && c->class == class_user) + free_command_lines (&c->user_commands); + + newc = add_cmd (comname, class_user, user_defined_command, + (c && c->class == class_user) + ? c->doc : savestring ("User-defined.", 13), &cmdlist); + newc->user_commands = cmds; + + /* If this new command is a hook, then mark both commands as being + tied. */ + if (hookc) + { + hookc->hook = newc; /* Target gets hooked. */ + newc->hookee = hookc; /* We are marked as hooking target cmd. */ + } +} + +static void +document_command (comname, from_tty) + char *comname; + int from_tty; +{ + struct command_line *doclines; + register struct cmd_list_element *c; + char *tem = comname; + + validate_comname (comname); + + c = lookup_cmd (&tem, cmdlist, "", 0, 1); + + if (c->class != class_user) + error ("Command \"%s\" is built-in.", comname); + + if (from_tty) + printf_unfiltered ("Type documentation for \"%s\".\n\ +End with a line saying just \"end\".\n", comname); + + doclines = read_command_lines (); + + if (c->doc) free (c->doc); + + { + register struct command_line *cl1; + register int len = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + len += strlen (cl1->line) + 1; + + c->doc = (char *) xmalloc (len + 1); + *c->doc = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + { + strcat (c->doc, cl1->line); + if (cl1->next) + strcat (c->doc, "\n"); + } + } + + free_command_lines (&doclines); +} + +void +print_gnu_advertisement () +{ + printf_unfiltered ("\ +GDB is free software and you are welcome to distribute copies of it\n\ + under certain conditions; type \"show copying\" to see the conditions.\n\ +There is absolutely no warranty for GDB; type \"show warranty\" for details.\n\ +"); +} + +void +print_gdb_version (stream) + GDB_FILE *stream; +{ + fprintf_filtered (stream, "\ +GDB %s (%s", version, host_name); + + if (!STREQ (host_name, target_name)) + fprintf_filtered (stream, " --target %s", target_name); + + fprintf_filtered (stream, "), "); + wrap_here(""); + fprintf_filtered (stream, "Copyright 1994 Free Software Foundation, Inc."); +} + +/* ARGSUSED */ +static void +show_version (args, from_tty) + char *args; + int from_tty; +{ + immediate_quit++; + print_gnu_advertisement (); + print_gdb_version (gdb_stdout); + printf_filtered ("\n"); + immediate_quit--; +} + +/* xgdb calls this to reprint the usual GDB prompt. Obsolete now that xgdb + is obsolete. */ + +void +print_prompt () +{ + printf_unfiltered ("%s", prompt); + gdb_flush (gdb_stdout); +} + +void +quit_command (args, from_tty) + char *args; + int from_tty; +{ + if (inferior_pid != 0 && target_has_execution) + { + if (attach_flag) + { + if (query ("The program is running. Quit anyway (and detach it)? ")) + target_detach (args, from_tty); + else + error ("Not confirmed."); + } + else + { + if (query ("The program is running. Quit anyway (and kill it)? ")) + target_kill (); + else + error ("Not confirmed."); + } + } + /* UDI wants this, to kill the TIP. */ + target_close (1); + + /* Save the history information if it is appropriate to do so. */ + if (write_history_p && history_filename) + write_history (history_filename); + + exit (0); +} + +/* Returns whether GDB is running on a terminal and whether the user + desires that questions be asked of them on that terminal. */ + +int +input_from_terminal_p () +{ + return gdb_has_a_terminal () && (instream == stdin) & caution; +} + +/* ARGSUSED */ +static void +pwd_command (args, from_tty) + char *args; + int from_tty; +{ + if (args) error ("The \"pwd\" command does not take an argument: %s", args); + getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); + + if (!STREQ (gdb_dirbuf, current_directory)) + printf_unfiltered ("Working directory %s\n (canonically %s).\n", + current_directory, gdb_dirbuf); + else + printf_unfiltered ("Working directory %s.\n", current_directory); +} + +void +cd_command (dir, from_tty) + char *dir; + int from_tty; +{ + int len; + /* Found something other than leading repetitions of "/..". */ + int found_real_path; + char *p; + + /* If the new directory is absolute, repeat is a no-op; if relative, + repeat might be useful but is more likely to be a mistake. */ + dont_repeat (); + + if (dir == 0) + error_no_arg ("new working directory"); + + dir = tilde_expand (dir); + make_cleanup (free, dir); + + if (chdir (dir) < 0) + perror_with_name (dir); + + len = strlen (dir); + dir = savestring (dir, len - (len > 1 && dir[len-1] == '/')); + if (dir[0] == '/') + current_directory = dir; + else + { + if (current_directory[0] == '/' && current_directory[1] == '\0') + current_directory = concat (current_directory, dir, NULL); + else + current_directory = concat (current_directory, "/", dir, NULL); + free (dir); + } + + /* Now simplify any occurrences of `.' and `..' in the pathname. */ + + found_real_path = 0; + for (p = current_directory; *p;) + { + if (p[0] == '/' && p[1] == '.' && (p[2] == 0 || p[2] == '/')) + strcpy (p, p + 2); + else if (p[0] == '/' && p[1] == '.' && p[2] == '.' + && (p[3] == 0 || p[3] == '/')) + { + if (found_real_path) + { + /* Search backwards for the directory just before the "/.." + and obliterate it and the "/..". */ + char *q = p; + while (q != current_directory && q[-1] != '/') + --q; + + if (q == current_directory) + /* current_directory is + a relative pathname ("can't happen"--leave it alone). */ + ++p; + else + { + strcpy (q - 1, p + 3); + p = q - 1; + } + } + else + /* We are dealing with leading repetitions of "/..", for example + "/../..", which is the Mach super-root. */ + p += 3; + } + else + { + found_real_path = 1; + ++p; + } + } + + forget_cached_source_info (); + + if (from_tty) + pwd_command ((char *) 0, 1); +} + +struct source_cleanup_lines_args { + int old_line; + char *old_file; + char *old_pre_error; + char *old_error_pre_print; +}; + +static void +source_cleanup_lines (args) + PTR args; +{ + struct source_cleanup_lines_args *p = + (struct source_cleanup_lines_args *)args; + source_line_number = p->old_line; + source_file_name = p->old_file; + source_pre_error = p->old_pre_error; + error_pre_print = p->old_error_pre_print; +} + +/* ARGSUSED */ +void +source_command (args, from_tty) + char *args; + int from_tty; +{ + FILE *stream; + struct cleanup *old_cleanups; + char *file = args; + struct source_cleanup_lines_args old_lines; + int needed_length; + + if (file == NULL) + { + error ("source command requires pathname of file to source."); + } + + file = tilde_expand (file); + old_cleanups = make_cleanup (free, file); + + stream = fopen (file, FOPEN_RT); + if (stream == 0) + perror_with_name (file); + + make_cleanup (fclose, stream); + + old_lines.old_line = source_line_number; + old_lines.old_file = source_file_name; + old_lines.old_pre_error = source_pre_error; + old_lines.old_error_pre_print = error_pre_print; + make_cleanup (source_cleanup_lines, &old_lines); + source_line_number = 0; + source_file_name = file; + source_pre_error = error_pre_print == NULL ? "" : error_pre_print; + source_pre_error = savestring (source_pre_error, strlen (source_pre_error)); + make_cleanup (free, source_pre_error); + /* This will get set every time we read a line. So it won't stay "" for + long. */ + error_pre_print = ""; + + needed_length = strlen (source_file_name) + strlen (source_pre_error) + 80; + if (source_error_allocated < needed_length) + { + source_error_allocated *= 2; + if (source_error_allocated < needed_length) + source_error_allocated = needed_length; + if (source_error == NULL) + source_error = xmalloc (source_error_allocated); + else + source_error = xrealloc (source_error, source_error_allocated); + } + + read_command_file (stream); + + do_cleanups (old_cleanups); +} + +/* ARGSUSED */ +static void +echo_command (text, from_tty) + char *text; + int from_tty; +{ + char *p = text; + register int c; + + if (text) + while ((c = *p++) != '\0') + { + if (c == '\\') + { + /* \ at end of argument is used after spaces + so they won't be lost. */ + if (*p == 0) + return; + + c = parse_escape (&p); + if (c >= 0) + printf_filtered ("%c", c); + } + else + printf_filtered ("%c", c); + } + + /* Force this output to appear now. */ + wrap_here (""); + gdb_flush (gdb_stdout); +} + + +/* Functions to manipulate command line editing control variables. */ + +/* Number of commands to print in each call to show_commands. */ +#define Hist_print 10 +static void +show_commands (args, from_tty) + char *args; + int from_tty; +{ + /* Index for history commands. Relative to history_base. */ + int offset; + + /* Number of the history entry which we are planning to display next. + Relative to history_base. */ + static int num = 0; + + /* The first command in the history which doesn't exist (i.e. one more + than the number of the last command). Relative to history_base. */ + int hist_len; + + extern HIST_ENTRY *history_get PARAMS ((int)); + + /* Print out some of the commands from the command history. */ + /* First determine the length of the history list. */ + hist_len = history_size; + for (offset = 0; offset < history_size; offset++) + { + if (!history_get (history_base + offset)) + { + hist_len = offset; + break; + } + } + + if (args) + { + if (args[0] == '+' && args[1] == '\0') + /* "info editing +" should print from the stored position. */ + ; + else + /* "info editing " should print around command number . */ + num = (parse_and_eval_address (args) - history_base) - Hist_print / 2; + } + /* "show commands" means print the last Hist_print commands. */ + else + { + num = hist_len - Hist_print; + } + + if (num < 0) + num = 0; + + /* If there are at least Hist_print commands, we want to display the last + Hist_print rather than, say, the last 6. */ + if (hist_len - num < Hist_print) + { + num = hist_len - Hist_print; + if (num < 0) + num = 0; + } + + for (offset = num; offset < num + Hist_print && offset < hist_len; offset++) + { + printf_filtered ("%5d %s\n", history_base + offset, + (history_get (history_base + offset))->line); + } + + /* The next command we want to display is the next one that we haven't + displayed yet. */ + num += Hist_print; + + /* If the user repeats this command with return, it should do what + "show commands +" does. This is unnecessary if arg is null, + because "show commands +" is not useful after "show commands". */ + if (from_tty && args) + { + args[0] = '+'; + args[1] = '\0'; + } +} + +/* Called by do_setshow_command. */ +/* ARGSUSED */ +static void +set_history_size_command (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + if (history_size == INT_MAX) + unstifle_history (); + else if (history_size >= 0) + stifle_history (history_size); + else + { + history_size = INT_MAX; + error ("History size must be non-negative"); + } +} + +/* ARGSUSED */ +static void +set_history (args, from_tty) + char *args; + int from_tty; +{ + printf_unfiltered ("\"set history\" must be followed by the name of a history subcommand.\n"); + help_list (sethistlist, "set history ", -1, gdb_stdout); +} + +/* ARGSUSED */ +static void +show_history (args, from_tty) + char *args; + int from_tty; +{ + cmd_show_list (showhistlist, from_tty, ""); +} + +int info_verbose = 0; /* Default verbose msgs off */ + +/* Called by do_setshow_command. An elaborate joke. */ +/* ARGSUSED */ +static void +set_verbose (args, from_tty, c) + char *args; + int from_tty; + struct cmd_list_element *c; +{ + char *cmdname = "verbose"; + struct cmd_list_element *showcmd; + + showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1); + + if (info_verbose) + { + c->doc = "Set verbose printing of informational messages."; + showcmd->doc = "Show verbose printing of informational messages."; + } + else + { + c->doc = "Set verbosity."; + showcmd->doc = "Show verbosity."; + } +} + +static void +float_handler (signo) +int signo; +{ + /* This message is based on ANSI C, section 4.7. Note that integer + divide by zero causes this, so "float" is a misnomer. */ + signal (SIGFPE, float_handler); + error ("Erroneous arithmetic operation."); +} + + +static void +init_cmd_lists () +{ + cmdlist = NULL; + infolist = NULL; + enablelist = NULL; + disablelist = NULL; + deletelist = NULL; + enablebreaklist = NULL; + setlist = NULL; + unsetlist = NULL; + showlist = NULL; + sethistlist = NULL; + showhistlist = NULL; + unsethistlist = NULL; +#if MAINTENANCE_CMDS + maintenancelist = NULL; + maintenanceinfolist = NULL; + maintenanceprintlist = NULL; +#endif + setprintlist = NULL; + showprintlist = NULL; + setchecklist = NULL; + showchecklist = NULL; +} + +/* Init the history buffer. Note that we are called after the init file(s) + * have been read so that the user can change the history file via his + * .gdbinit file (for instance). The GDBHISTFILE environment variable + * overrides all of this. + */ + +void +init_history() +{ + char *tmpenv; + + tmpenv = getenv ("HISTSIZE"); + if (tmpenv) + history_size = atoi (tmpenv); + else if (!history_size) + history_size = 256; + + stifle_history (history_size); + + tmpenv = getenv ("GDBHISTFILE"); + if (tmpenv) + history_filename = savestring (tmpenv, strlen(tmpenv)); + else if (!history_filename) { + /* We include the current directory so that if the user changes + directories the file written will be the same as the one + that was read. */ + history_filename = concat (current_directory, "/.gdb_history", NULL); + } + read_history (history_filename); +} + +static void +init_main () +{ + struct cmd_list_element *c; + +#ifdef DEFAULT_PROMPT + prompt = savestring (DEFAULT_PROMPT, strlen(DEFAULT_PROMPT)); +#else + prompt = savestring ("(gdb) ", 6); +#endif +#ifdef KERNEL_DEBUG + if (kernel_debugging) + prompt = savestring ("(kgdb) ", 7); +#endif + + /* Set the important stuff up for command editing. */ + command_editing_p = 1; + history_expansion_p = 0; + write_history_p = 0; + + /* Setup important stuff for command line editing. */ + rl_completion_entry_function = (int (*)()) symbol_completion_function; + rl_completer_word_break_characters = gdb_completer_word_break_characters; + rl_completer_quote_characters = gdb_completer_quote_characters; + rl_readline_name = "gdb"; + + /* Define the classes of commands. + They will appear in the help list in the reverse of this order. */ + + add_cmd ("internals", class_maintenance, NO_FUNCTION, + "Maintenance commands.\n\ +Some gdb commands are provided just for use by gdb maintainers.\n\ +These commands are subject to frequent change, and may not be as\n\ +well documented as user commands.", + &cmdlist); + add_cmd ("obscure", class_obscure, NO_FUNCTION, "Obscure features.", &cmdlist); + add_cmd ("aliases", class_alias, NO_FUNCTION, "Aliases of other commands.", &cmdlist); + add_cmd ("user-defined", class_user, NO_FUNCTION, "User-defined commands.\n\ +The commands in this class are those defined by the user.\n\ +Use the \"define\" command to define a command.", &cmdlist); + add_cmd ("support", class_support, NO_FUNCTION, "Support facilities.", &cmdlist); + add_cmd ("status", class_info, NO_FUNCTION, "Status inquiries.", &cmdlist); + add_cmd ("files", class_files, NO_FUNCTION, "Specifying and examining files.", &cmdlist); + add_cmd ("breakpoints", class_breakpoint, NO_FUNCTION, "Making program stop at certain points.", &cmdlist); + add_cmd ("data", class_vars, NO_FUNCTION, "Examining data.", &cmdlist); + add_cmd ("stack", class_stack, NO_FUNCTION, "Examining the stack.\n\ +The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\ +counting from zero for the innermost (currently executing) frame.\n\n\ +At any time gdb identifies one frame as the \"selected\" frame.\n\ +Variable lookups are done with respect to the selected frame.\n\ +When the program being debugged stops, gdb selects the innermost frame.\n\ +The commands below can be used to select other frames by number or address.", + &cmdlist); + add_cmd ("running", class_run, NO_FUNCTION, "Running the program.", &cmdlist); + + add_com ("pwd", class_files, pwd_command, + "Print working directory. This is used for your program as well."); + c = add_cmd ("cd", class_files, cd_command, + "Set working directory to DIR for debugger and program being debugged.\n\ +The change does not take effect for the program being debugged\n\ +until the next time it is started.", &cmdlist); + c->completer = filename_completer; + + add_show_from_set + (add_set_cmd ("prompt", class_support, var_string, (char *)&prompt, + "Set gdb's prompt", + &setlist), + &showlist); + + add_com ("echo", class_support, echo_command, + "Print a constant string. Give string as argument.\n\ +C escape sequences may be used in the argument.\n\ +No newline is added at the end of the argument;\n\ +use \"\\n\" if you want a newline to be printed.\n\ +Since leading and trailing whitespace are ignored in command arguments,\n\ +if you want to print some you must use \"\\\" before leading whitespace\n\ +to be printed or after trailing whitespace."); + add_com ("document", class_support, document_command, + "Document a user-defined command.\n\ +Give command name as argument. Give documentation on following lines.\n\ +End with a line of just \"end\"."); + add_com ("define", class_support, define_command, + "Define a new command name. Command name is argument.\n\ +Definition appears on following lines, one command per line.\n\ +End with a line of just \"end\".\n\ +Use the \"document\" command to give documentation for the new command.\n\ +Commands defined in this way do not take arguments."); + +#ifdef __STDC__ + c = add_cmd ("source", class_support, source_command, + "Read commands from a file named FILE.\n\ +Note that the file \"" GDBINIT_FILENAME "\" is read automatically in this way\n\ +when gdb is started.", &cmdlist); +#else + /* Punt file name, we can't help it easily. */ + c = add_cmd ("source", class_support, source_command, + "Read commands from a file named FILE.\n\ +Note that the file \".gdbinit\" is read automatically in this way\n\ +when gdb is started.", &cmdlist); +#endif + c->completer = filename_completer; + + add_com ("quit", class_support, quit_command, "Exit gdb."); + add_com ("help", class_support, help_command, "Print list of commands."); + add_com_alias ("q", "quit", class_support, 1); + add_com_alias ("h", "help", class_support, 1); + + + c = add_set_cmd ("verbose", class_support, var_boolean, (char *)&info_verbose, + "Set ", + &setlist), + add_show_from_set (c, &showlist); + c->function.sfunc = set_verbose; + set_verbose (NULL, 0, c); + + add_show_from_set + (add_set_cmd ("editing", class_support, var_boolean, (char *)&command_editing_p, + "Set editing of command lines as they are typed.\n\ +Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\ +Without an argument, command line editing is enabled. To edit, use\n\ +EMACS-like or VI-like commands like control-P or ESC.", &setlist), + &showlist); + + add_prefix_cmd ("history", class_support, set_history, + "Generic command for setting command history parameters.", + &sethistlist, "set history ", 0, &setlist); + add_prefix_cmd ("history", class_support, show_history, + "Generic command for showing command history parameters.", + &showhistlist, "show history ", 0, &showlist); + + add_show_from_set + (add_set_cmd ("expansion", no_class, var_boolean, (char *)&history_expansion_p, + "Set history expansion on command input.\n\ +Without an argument, history expansion is enabled.", &sethistlist), + &showhistlist); + + add_show_from_set + (add_set_cmd ("save", no_class, var_boolean, (char *)&write_history_p, + "Set saving of the history record on exit.\n\ +Use \"on\" to enable to enable the saving, and \"off\" to disable it.\n\ +Without an argument, saving is enabled.", &sethistlist), + &showhistlist); + + c = add_set_cmd ("size", no_class, var_integer, (char *)&history_size, + "Set the size of the command history, \n\ +ie. the number of previous commands to keep a record of.", &sethistlist); + add_show_from_set (c, &showhistlist); + c->function.sfunc = set_history_size_command; + + add_show_from_set + (add_set_cmd ("filename", no_class, var_filename, (char *)&history_filename, + "Set the filename in which to record the command history\n\ + (the list of previous commands of which a record is kept).", &sethistlist), + &showhistlist); + + add_show_from_set + (add_set_cmd ("confirm", class_support, var_boolean, + (char *)&caution, + "Set whether to confirm potentially dangerous operations.", + &setlist), + &showlist); + + add_prefix_cmd ("info", class_info, info_command, + "Generic command for showing things about the program being debugged.", + &infolist, "info ", 0, &cmdlist); + add_com_alias ("i", "info", class_info, 1); + + add_com ("complete", class_obscure, complete_command, + "List the completions for the rest of the line as a command."); + + add_prefix_cmd ("show", class_info, show_command, + "Generic command for showing things about the debugger.", + &showlist, "show ", 0, &cmdlist); + /* Another way to get at the same thing. */ + add_info ("set", show_command, "Show all GDB settings."); + + add_cmd ("commands", no_class, show_commands, + "Show the the history of commands you typed.\n\ +You can supply a command number to start with, or a `+' to start after\n\ +the previous command number shown.", + &showlist); + + add_cmd ("version", no_class, show_version, + "Show what version of GDB this is.", &showlist); + + /* If target is open when baud changes, it doesn't take effect until the + next open (I think, not sure). */ + add_show_from_set (add_set_cmd ("remotebaud", no_class, + var_zinteger, (char *)&baud_rate, + "Set baud rate for remote serial I/O.\n\ +This value is used to set the speed of the serial port when debugging\n\ +using remote targets.", &setlist), + &showlist); + + add_show_from_set ( + add_set_cmd ("remotedebug", no_class, var_zinteger, (char *)&remote_debug, + "Set debugging of remote protocol.\n\ +When enabled, each packet sent or received with the remote target\n\ +is displayed.", &setlist), + &showlist); +} diff --git a/gnu/usr.bin/gdb/gdb/top.h b/gnu/usr.bin/gdb/gdb/top.h new file mode 100644 index 00000000000..6ae28a25da4 --- /dev/null +++ b/gnu/usr.bin/gdb/gdb/top.h @@ -0,0 +1,48 @@ +/* Top level stuff for GDB, the GNU debugger. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994 + Free Software Foundation, Inc. + +This file is part of GDB. + +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. */ + +/* From top.c. */ +extern char *line; +extern int linesize; +extern FILE *instream; +extern char gdb_dirbuf[1024]; +extern int inhibit_gdbinit; +extern int epoch_interface; +extern char gdbinit[]; + +/* Generally one should use catch_errors rather than manipulating these + directly. The exception is main(). */ +extern jmp_buf error_return; +extern jmp_buf quit_return; + +extern void print_gdb_version PARAMS ((GDB_FILE *)); +extern void print_gnu_advertisement PARAMS ((void)); + +extern void source_command PARAMS ((char *, int)); +extern void cd_command PARAMS ((char *, int)); +extern void read_command_file PARAMS ((FILE *)); +extern void init_history PARAMS ((void)); +extern void command_loop PARAMS ((void)); +extern void quit_command PARAMS ((char *, int)); + +/* From random places. */ +extern int mapped_symbol_files; +extern int readnow_symbol_files; +#define ALL_CLEANUPS ((struct cleanup *)0) diff --git a/gnu/usr.bin/gdb/libiberty/vasprintf.c b/gnu/usr.bin/gdb/libiberty/vasprintf.c new file mode 100644 index 00000000000..b3ba0ca6ca8 --- /dev/null +++ b/gnu/usr.bin/gdb/libiberty/vasprintf.c @@ -0,0 +1,139 @@ +/* Like vsprintf but provides a pointer to malloc'd storage, which must + be freed by the caller. + Copyright (C) 1994 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include + +#ifdef TEST +int global_total_width; +#endif + +unsigned long strtoul (); +char *malloc (); + +int +vasprintf (result, format, args) + char **result; + char *format; + va_list args; +{ + char *p = format; + /* Add one to make sure that it is never zero, which might cause malloc + to return NULL. */ + int total_width = strlen (format) + 1; + va_list ap = args; + + while (*p != '\0') + { + if (*p++ == '%') + { + while (strchr ("-+ #0", *p)) + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + total_width += strtoul (p, &p, 10); + if (*p == '.') + { + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + total_width += strtoul (p, &p, 10); + } + while (strchr ("hlL", *p)) + ++p; + /* Should be big enough for any format specifier except %s. */ + total_width += 30; + switch (*p) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + va_arg (ap, int); + break; + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + va_arg (ap, double); + break; + case 's': + total_width += strlen (va_arg (ap, char *)); + break; + case 'p': + case 'n': + va_arg (ap, char *); + break; + } + } + } +#ifdef TEST + global_total_width = total_width; +#endif + *result = malloc (total_width); + if (*result != NULL) + return vsprintf (*result, format, args); + else + return 0; +} + +#ifdef TEST +void +checkit (va_alist) + va_dcl +{ + va_list args; + char *format; + char *result; + + va_start (args); + format = va_arg (args, char *); + vasprintf (&result, format, args); + if (strlen (result) < global_total_width) + printf ("PASS: "); + else + printf ("FAIL: "); + printf ("%d %s\n", global_total_width, result); +} + +int +main () +{ + checkit ("%d", 0x12345678); + checkit ("%200d", 5); + checkit ("%.300d", 6); + checkit ("%100.150d", 7); + checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ +777777777777777777333333333333366666666666622222222222777777777777733333"); + checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"); +} +#endif /* TEST */ diff --git a/gnu/usr.bin/gdb/mmalloc/COPYING.LIB b/gnu/usr.bin/gdb/mmalloc/COPYING.LIB new file mode 100644 index 00000000000..eb685a5ec98 --- /dev/null +++ b/gnu/usr.bin/gdb/mmalloc/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it!