diff options
-rw-r--r-- | bfd/ChangeLog | 80 | ||||
-rw-r--r-- | bfd/Makefile.am | 10 | ||||
-rw-r--r-- | bfd/Makefile.in | 17 | ||||
-rwxr-xr-x | bfd/configure | 3 | ||||
-rw-r--r-- | bfd/configure.in | 3 | ||||
-rw-r--r-- | bfd/targets.c | 2 | ||||
-rw-r--r-- | bfd/vms-alpha.c | 8968 | ||||
-rw-r--r-- | bfd/vms-gsd.c | 1082 | ||||
-rw-r--r-- | bfd/vms-hdr.c | 1382 | ||||
-rw-r--r-- | bfd/vms-misc.c | 961 | ||||
-rw-r--r-- | bfd/vms-tir.c | 2808 | ||||
-rw-r--r-- | bfd/vms.c | 1518 | ||||
-rw-r--r-- | bfd/vms.h | 878 |
13 files changed, 9304 insertions, 8408 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 3ec74f2..59e1cba 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,83 @@ +2010-04-14 Tristan Gingold <gingold@adacore.com> + + * Makefile.am (BFD32_BACKENDS): Remove vms-gsd.lo, vms-hdr.lo, + vms-tir.lo, vms.lo and add vms-alpha.lo + (BFD32_BACKENDS_CFILES): Remove vms-gsd.c, vms-hdr.c, + vms-tir.c, vms.c and add vms-alpha.c + * Makefile.in: Regenerate. + * configure.in (TDEFINES): Adjust file list for vms_alpha_vec. + Remove vms_vax_vec. + * configure: Regenerate. + * targets.c (vms_vax_vec): Remove the declaration. + (_bfd_target_vector): Remove vms_vax_vec. + * vms-alpha.c: New file. + * vms-gsd.c: Removed, rewritten in vms-alpha.c + * vms-hdr.c: Ditto. + * vms-tir.c: Ditto. + * vms.c: Ditto. + * vms-misc.c: Fix indentation and comments. Replace most of + #if VMS_DEBUG/vms_debug with vms_debug2. + (_bfd_vms_hash_newfunc): Moved to vms-alpha.c + (hash_string): Ditto. + (_bfd_vms_length_hash_symbol): Ditto. + (maybe_adjust_record_pointer_for_object): Ditto. + (_bfd_vms_get_object_record): Ditto. + (vms_get_remaining_object_record): Ditto. + (_bfd_vms_push): Ditto. + (_bfd_vms_pop): Ditto. + (_bfd_vms_get_header_values): Removed. + (_bfd_vms_get_first_record): Removed. + (vms_get_remaining_image_record): Removed. + (new_symbol): Removed. + (_bfd_vms_enter_symbol): Removed. + (_bfd_vms_save_sized_string): Use memcpy instead of strncpy. + (_bfd_vms_output_begin): Remove rechead parameter. Replace bfd + parameter with struct vms_rec_wr. + (_bfd_vms_output_push): Removed and replaced by ... + (_bfd_vms_output_begin_subrec): ... new function. + (_bfd_vms_output_alignment): Replace bfd parameter with + struct vms_rec_wr, and adjust. + (_bfd_vms_output_check): Ditto + (_bfd_vms_output_byte): Ditto. + (_bfd_vms_output_short): Ditto. + (_bfd_vms_output_long): Ditto. + (_bfd_vms_output_quad): Ditto. + (_bfd_vms_output_counted): Ditto. + (_bfd_vms_output_dump): Ditto. + (_bfd_vms_output_fill): Ditto. + (_bfd_vms_output_pop): Removed and replaced by ... + (_bfd_vms_output_end_subrec): ... new function. + (_bfd_vms_output_flush): Removed. + (_bfd_vms_output_align): New function. + (_bfd_vms_output_end): Add recwr parameter. Adjust for this new + parameter. + (vms_convert_to_var): New function imported from vms.c + (vms_convert_to_var_1): Ditto. + (vms_convert_to_var_unix_filename): Ditto. + (vms_get_module_name): Ditto. + (get_vms_time_string): Ditto. + (vms_time_to_time_t): Ditto. + (vms_rawtime_to_time_t): Ditto. + * vms.h: All macros for the VMS file format are now in include/vms. + Prototypes for vms.c, vms-gsd.c, vms-misc.c, vms-hdr.c, vms-tir.c + have been removed. + (struct vms_symbol_struct, struct stack_struct): Moved to vms-alpha.c + (struct fileinfo, struct srecinfo, struct lineinfo): Ditto. + (struct funcinfo, struct vms_private_data_struct): Ditto. + (struct vms_section_data_struct): Ditto. + (struct vms_rec_rd, stryct vms_rec_wr): New declarations. + (vms_get_module_name, get_vms_time_string): New declarations. + (vms_time_to_time_t, vms_rawtime_to_time_t): Ditto. + (_bfd_vms_output_begin_subrec, _bfd_vms_output_end_subrec): Ditto. + (_bfd_vms_save_sized_string, _bfd_vms_save_counted_string): Adjusted. + (_bfd_vms_output_begin, _bfd_vms_output_alignment): Ditto. + (_bfd_vms_output_end,_bfd_vms_output_check): Ditto. + (_bfd_vms_output_byte, _bfd_vms_output_short): Ditto. + (_bfd_vms_output_long, _bfd_vms_output_quad): Ditto. + (_bfd_vms_output_counted, _bfd_vms_output_dump): Ditto. + (_bfd_vms_output_fill): Ditto. + (bfd_vms_set_section_flags): Ditto. + 2010-04-14 Matthew Gretton-Dann <matthew.gretton-dann@arm.com> * elflink.c (_bfd_elf_merge_symbol): Tighten up the test for early diff --git a/bfd/Makefile.am b/bfd/Makefile.am index ac38177..ef545f5 100644 --- a/bfd/Makefile.am +++ b/bfd/Makefile.am @@ -391,12 +391,9 @@ BFD32_BACKENDS = \ vaxbsd.lo \ vaxnetbsd.lo \ versados.lo \ - vms-gsd.lo \ - vms-hdr.lo \ + vms-alpha.lo \ vms-lib.lo \ vms-misc.lo \ - vms-tir.lo \ - vms.lo \ xcofflink.lo \ xsym.lo \ xtensa-isa.lo \ @@ -576,12 +573,9 @@ BFD32_BACKENDS_CFILES = \ vaxbsd.c \ vaxnetbsd.c \ versados.c \ - vms-gsd.c \ - vms-hdr.c \ + vms-alpha.c \ vms-lib.c \ vms-misc.c \ - vms-tir.c \ - vms.c \ xcofflink.c \ xsym.c \ xtensa-isa.c \ diff --git a/bfd/Makefile.in b/bfd/Makefile.in index ed626c9..7134a70 100644 --- a/bfd/Makefile.in +++ b/bfd/Makefile.in @@ -688,12 +688,9 @@ BFD32_BACKENDS = \ vaxbsd.lo \ vaxnetbsd.lo \ versados.lo \ - vms-gsd.lo \ - vms-hdr.lo \ - vms-lib.lo \ vms-misc.lo \ - vms-tir.lo \ - vms.lo \ + vms-alpha.lo \ + vms-lib.lo \ xcofflink.lo \ xsym.lo \ xtensa-isa.lo \ @@ -873,12 +870,9 @@ BFD32_BACKENDS_CFILES = \ vaxbsd.c \ vaxnetbsd.c \ versados.c \ - vms-gsd.c \ - vms-hdr.c \ + vms-alpha.c \ vms-lib.c \ vms-misc.c \ - vms-tir.c \ - vms.c \ xcofflink.c \ xsym.c \ xtensa-isa.c \ @@ -1488,12 +1482,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vaxnetbsd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verilog.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/versados.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vms-gsd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vms-hdr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vms-alpha.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vms-lib.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vms-misc.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vms-tir.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vms.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xcofflink.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xsym.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xtensa-isa.Plo@am__quote@ diff --git a/bfd/configure b/bfd/configure index 928f984..7d16fab 100755 --- a/bfd/configure +++ b/bfd/configure @@ -15283,9 +15283,8 @@ do vax1knetbsd_vec) tb="$tb vax1knetbsd.lo aout32.lo" ;; vaxbsd_vec) tb="$tb vaxbsd.lo aout32.lo" ;; versados_vec) tb="$tb versados.lo" ;; - vms_alpha_vec) tb="$tb vms.lo vms-hdr.lo vms-gsd.lo vms-tir.lo vms-misc.lo vms-lib.lo"; target_size=64 ;; + vms_alpha_vec) tb="$tb vms-alpha.lo vms-misc.lo vms-lib.lo"; target_size=64 ;; vms_lib_txt_vec) tb="$tb vms-lib.lo vms-misc.lo" ;; - vms_vax_vec) tb="$tb vms.lo vms-hdr.lo vms-gsd.lo vms-tir.lo vms-misc.lo" ;; w65_vec) tb="$tb coff-w65.lo reloc16.lo" ;; we32kcoff_vec) tb="$tb coff-we32k.lo" ;; z80coff_vec) tb="$tb coff-z80.lo reloc16.lo" ;; diff --git a/bfd/configure.in b/bfd/configure.in index 28d5bdd..eb9d7e7 100644 --- a/bfd/configure.in +++ b/bfd/configure.in @@ -927,9 +927,8 @@ do vax1knetbsd_vec) tb="$tb vax1knetbsd.lo aout32.lo" ;; vaxbsd_vec) tb="$tb vaxbsd.lo aout32.lo" ;; versados_vec) tb="$tb versados.lo" ;; - vms_alpha_vec) tb="$tb vms.lo vms-hdr.lo vms-gsd.lo vms-tir.lo vms-misc.lo vms-lib.lo"; target_size=64 ;; + vms_alpha_vec) tb="$tb vms-alpha.lo vms-misc.lo vms-lib.lo"; target_size=64 ;; vms_lib_txt_vec) tb="$tb vms-lib.lo vms-misc.lo" ;; - vms_vax_vec) tb="$tb vms.lo vms-hdr.lo vms-gsd.lo vms-tir.lo vms-misc.lo" ;; w65_vec) tb="$tb coff-w65.lo reloc16.lo" ;; we32kcoff_vec) tb="$tb coff-we32k.lo" ;; z80coff_vec) tb="$tb coff-z80.lo reloc16.lo" ;; diff --git a/bfd/targets.c b/bfd/targets.c index 5ee73c4..2e330e6 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -828,7 +828,6 @@ extern const bfd_target vax1knetbsd_vec; extern const bfd_target versados_vec; extern const bfd_target vms_alpha_vec; extern const bfd_target vms_lib_txt_vec; -extern const bfd_target vms_vax_vec; extern const bfd_target w65_vec; extern const bfd_target we32kcoff_vec; extern const bfd_target x86_64pe_vec; @@ -1229,7 +1228,6 @@ static const bfd_target * const _bfd_target_vector[] = &vms_alpha_vec, #endif &vms_lib_txt_vec, - &vms_vax_vec, &w65_vec, &we32kcoff_vec, &z80coff_vec, diff --git a/bfd/vms-alpha.c b/bfd/vms-alpha.c new file mode 100644 index 0000000..e213f4ee --- /dev/null +++ b/bfd/vms-alpha.c @@ -0,0 +1,8968 @@ +/* vms.c -- BFD back-end for EVAX (openVMS/Alpha) files. + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + + Initial version written by Klaus Kaempf (kkaempf@rmi.de) + Major rewrite by Adacore. + + 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 3 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., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* TODO: + o DMT + o PIC + o Generation of shared image + o Generation of GST in image + o Relocation optimizations + o EISD for the stack + o Vectors isect + o 64 bits sections + o Entry point + ... +*/ + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "bfdver.h" + +#include "vms.h" +#include "vms/eihd.h" +#include "vms/eiha.h" +#include "vms/eihi.h" +#include "vms/eihs.h" +#include "vms/eisd.h" +#include "vms/dmt.h" +#include "vms/dst.h" +#include "vms/eihvn.h" +#include "vms/eobjrec.h" +#include "vms/egsd.h" +#include "vms/egps.h" +#include "vms/eeom.h" +#include "vms/emh.h" +#include "vms/eiaf.h" +#include "vms/shl.h" +#include "vms/eicp.h" +#include "vms/etir.h" +#include "vms/egsy.h" +#include "vms/esdf.h" +#include "vms/esdfm.h" +#include "vms/esdfv.h" +#include "vms/esrf.h" +#include "vms/egst.h" +#include "vms/dsc.h" +#include "vms/prt.h" +#include "vms/internal.h" + + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +/* The r_type field in a reloc is one of the following values. */ +#define ALPHA_R_IGNORE 0 +#define ALPHA_R_REFQUAD 1 +#define ALPHA_R_BRADDR 2 +#define ALPHA_R_HINT 3 +#define ALPHA_R_SREL16 4 +#define ALPHA_R_SREL32 5 +#define ALPHA_R_SREL64 6 +#define ALPHA_R_OP_PUSH 7 +#define ALPHA_R_OP_STORE 8 +#define ALPHA_R_OP_PSUB 9 +#define ALPHA_R_OP_PRSHIFT 10 +#define ALPHA_R_LINKAGE 11 +#define ALPHA_R_REFLONG 12 +#define ALPHA_R_CODEADDR 13 +#define ALPHA_R_NOP 14 +#define ALPHA_R_BSR 15 +#define ALPHA_R_LDA 16 +#define ALPHA_R_BOH 17 +/* These are used with DST_S_C_LINE_NUM. */ +#define DST_S_C_LINE_NUM_HEADER_SIZE 4 + +/* These are used with DST_S_C_SOURCE */ + +#define DST_S_B_PCLINE_UNSBYTE 1 +#define DST_S_W_PCLINE_UNSWORD 1 +#define DST_S_L_PCLINE_UNSLONG 1 + +#define DST_S_B_MODBEG_NAME 14 +#define DST_S_L_RTNBEG_ADDRESS 5 +#define DST_S_B_RTNBEG_NAME 13 +#define DST_S_L_RTNEND_SIZE 5 + +/* These are used with DST_S_C_SOURCE. */ +#define DST_S_C_SOURCE_HEADER_SIZE 4 + +#define DST_S_B_SRC_DF_LENGTH 1 +#define DST_S_W_SRC_DF_FILEID 3 +#define DST_S_B_SRC_DF_FILENAME 20 +#define DST_S_B_SRC_UNSBYTE 1 +#define DST_S_W_SRC_UNSWORD 1 +#define DST_S_L_SRC_UNSLONG 1 + +/* Debugger symbol definitions. */ + +#define DBG_S_L_DMT_MODBEG 0 +#define DBG_S_L_DST_SIZE 4 +#define DBG_S_W_DMT_PSECT_COUNT 8 +#define DBG_S_C_DMT_HEADER_SIZE 12 + +#define DBG_S_L_DMT_PSECT_START 0 +#define DBG_S_L_DMT_PSECT_LENGTH 4 +#define DBG_S_C_DMT_PSECT_SIZE 8 + +/* VMS module header. */ + +struct hdr_struct +{ + char hdr_b_strlvl; + int hdr_l_arch1; + int hdr_l_arch2; + int hdr_l_recsiz; + char *hdr_t_name; + char *hdr_t_version; + char *hdr_t_date; + char *hdr_c_lnm; + char *hdr_c_src; + char *hdr_c_ttl; +}; + +#define EMH_DATE_LENGTH 17 + +/* VMS End-Of-Module records (EOM/EEOM). */ + +struct eom_struct +{ + unsigned int eom_l_total_lps; + unsigned short eom_w_comcod; + bfd_boolean eom_has_transfer; + unsigned char eom_b_tfrflg; + unsigned int eom_l_psindx; + unsigned int eom_l_tfradr; +}; + +struct vms_symbol_entry +{ + bfd *owner; + + /* Common fields. */ + unsigned char typ; + unsigned char data_type; + unsigned short flags; + + /* Section and offset/value of the symbol. */ + unsigned int section; + unsigned int value; + + /* Section and offset/value for the entry point (only for subprg). */ + unsigned int code_section; + unsigned int code_value; + + /* Symbol vector offset. */ + unsigned int symbol_vector; + + /* Length of the name. */ + unsigned char namelen; + + char name[1]; +}; + +/* Stack value for push/pop commands. */ + +struct stack_struct +{ + bfd_vma value; + unsigned int reloc; +}; + +#define STACKSIZE 128 + +/* A minimal decoding of DST compilation units. We only decode + what's needed to get to the line number information. */ + +struct fileinfo +{ + char *name; + unsigned int srec; +}; + +struct srecinfo +{ + struct srecinfo *next; + unsigned int line; + unsigned int sfile; + unsigned int srec; +}; + +struct lineinfo +{ + struct lineinfo *next; + bfd_vma address; + unsigned int line; +}; + +struct funcinfo +{ + struct funcinfo *next; + char *name; + bfd_vma low; + bfd_vma high; +}; + +struct module +{ + /* Chain the previously read compilation unit. */ + struct module *next; + + /* The module name. */ + char *name; + + /* The start offset and size of debug info in the DST section. */ + unsigned int modbeg; + unsigned int size; + + /* The lowest and highest addresses contained in this compilation + unit as specified in the compilation unit header. */ + bfd_vma low; + bfd_vma high; + + /* The listing line table. */ + struct lineinfo *line_table; + + /* The source record table. */ + struct srecinfo *srec_table; + + /* A list of the functions found in this module. */ + struct funcinfo *func_table; + + /* Current allocation of file_table. */ + unsigned int file_table_count; + + /* An array of the files making up this module. */ + struct fileinfo *file_table; +}; + +/* BFD private data for alpha-vms. */ + +struct vms_private_data_struct +{ + /* If true, relocs have been read. */ + bfd_boolean reloc_done; + + /* Record input buffer. */ + struct vms_rec_rd recrd; + struct vms_rec_wr recwr; + + struct hdr_struct hdr_data; /* data from HDR/EMH record */ + struct eom_struct eom_data; /* data from EOM/EEOM record */ + unsigned int section_count; /* # of sections in following array */ + asection **sections; /* array of GSD/EGSD sections */ + + /* Array of raw symbols. */ + struct vms_symbol_entry **syms; + + /* Canonicalized symbols. */ + asymbol **csymbols; + + /* Number of symbols. */ + unsigned int gsd_sym_count; + /* Size of the syms array. */ + unsigned int max_sym_count; + /* Number of procedure symbols. */ + unsigned int norm_sym_count; + + /* Stack used to evaluate TIR/ETIR commands. */ + struct stack_struct *stack; + int stackptr; + + /* Content reading. */ + asection *image_section; /* section for image_ptr */ + file_ptr image_offset; /* Offset for image_ptr. */ + bfd_boolean image_autoextend; /* Resize section if necessary. */ + + struct module *modules; /* list of all compilation units */ + + struct dst_info *dst_info; + asection *dst_section; + + unsigned int dst_ptr_offsets_count; /* # of offsets in following array */ + unsigned int *dst_ptr_offsets; /* array of saved image_ptr offsets */ + + /* Shared library support */ + bfd_vma symvva; /* relative virtual address of symbol vector */ + unsigned int ident; + unsigned char matchctl; + + /* Shared library index. This is used for input bfd while linking. */ + unsigned int shr_index; + + /* Used to place structures in the file. */ + file_ptr file_pos; + + /* Simply linked list of eisd. */ + struct vms_internal_eisd_map *eisd_head; + struct vms_internal_eisd_map *eisd_tail; + + /* Simply linked list of eisd for shared libraries. */ + struct vms_internal_eisd_map *gbl_eisd_head; + struct vms_internal_eisd_map *gbl_eisd_tail; + + /* linkage index counter used by conditional store commands */ + int vms_linkage_index; + + /* see tc-alpha.c of gas for a description. */ + int flag_hash_long_names; /* -+, hash instead of truncate */ + int flag_show_after_trunc; /* -H, show hashing/truncation */ +}; + +#define PRIV2(abfd, name) \ + (((struct vms_private_data_struct *)(abfd)->tdata.any)->name) +#define PRIV(name) PRIV2(abfd,name) + + +/* Used to keep extra VMS specific information for a given section. + + reloc_size holds the size of the relocation stream, note this + is very different from the number of relocations as VMS relocations + are variable length. + + reloc_stream is the actual stream of relocation entries. */ + +struct vms_section_data_struct +{ + /* Maximnum number of entries in sec->relocation. */ + unsigned reloc_max; + + /* Corresponding eisd. Used only while generating executables. */ + struct vms_internal_eisd_map *eisd; + + /* PSC flags to be clear. */ + flagword no_flags; + + /* PSC flags to be set. */ + flagword flags; +}; + +#define vms_section_data(sec) \ + ((struct vms_section_data_struct *)sec->used_by_bfd) + +/* To be called from the debugger. */ +struct vms_private_data_struct *bfd_vms_get_data (bfd *abfd); + +static int vms_get_remaining_object_record (bfd *abfd, int read_so_far); +static bfd_boolean _bfd_vms_slurp_object_records (bfd * abfd); +static void alpha_vms_add_fixup_lp (struct bfd_link_info *, bfd *, bfd *); +static void alpha_vms_add_fixup_ca (struct bfd_link_info *, bfd *, bfd *); +static void alpha_vms_add_fixup_qr (struct bfd_link_info *, bfd *, bfd *, + bfd_vma); +static void alpha_vms_add_lw_reloc (struct bfd_link_info *info); +static void alpha_vms_add_qw_reloc (struct bfd_link_info *info); +static void alpha_vms_add_lw_fixup (struct bfd_link_info *, unsigned int, + bfd_vma); + +struct vector_type +{ + unsigned int max_el; + unsigned int nbr_el; + void *els; +}; + +/* Number of elements in VEC. */ + +#define VEC_COUNT(VEC) ((VEC).nbr_el) + +/* Get the address of the Nth element. */ + +#define VEC_EL(VEC, TYPE, N) (((TYPE *)((VEC).els))[N]) + +#define VEC_INIT(VEC) \ + do { \ + (VEC).max_el = 0; \ + (VEC).nbr_el = 0; \ + (VEC).els = NULL; \ + } while (0) + +/* Be sure there is room for a new element. */ + +static void vector_grow1 (struct vector_type *vec, size_t elsz); + +/* Allocate room for a new element and return its address. */ + +#define VEC_APPEND(VEC, TYPE) \ + (vector_grow1 (&VEC, sizeof (TYPE)), &VEC_EL(VEC, TYPE, (VEC).nbr_el++)) + +/* Append an element. */ + +#define VEC_APPEND_EL(VEC, TYPE, EL) \ + (*(VEC_APPEND (VEC, TYPE)) = EL) + +struct alpha_vms_vma_ref +{ + bfd_vma vma; /* Vma in the output. */ + bfd_vma ref; /* Reference in the input. */ +}; + +struct alpha_vms_shlib_el +{ + bfd *abfd; + bfd_boolean has_fixups; + + struct vector_type lp; /* Vector of bfd_vma. */ + struct vector_type ca; /* Vector of bfd_vma. */ + struct vector_type qr; /* Vector of struct alpha_vms_vma_ref. */ +}; + +/* Alpha VMS linker hash table. */ + +struct alpha_vms_link_hash_table +{ + struct bfd_link_hash_table root; + + /* Vector of shared libaries. */ + struct vector_type shrlibs; + + /* Fixup section. */ + asection *fixup; + + /* Base address. Used by fixups. */ + bfd_vma base_addr; +}; + +#define alpha_vms_link_hash(INFO) \ + ((struct alpha_vms_link_hash_table *)(INFO->hash)) + +/* Alpha VMS linker hash table entry. */ + +struct alpha_vms_link_hash_entry +{ + struct bfd_link_hash_entry root; + + /* Pointer to the original vms symbol. */ + struct vms_symbol_entry *sym; +}; + +/* Image reading. */ + +/* Read & process EIHD record. + Return TRUE on success, FALSE on error. */ + +static bfd_boolean +_bfd_vms_slurp_eihd (bfd *abfd, unsigned int *eisd_offset, + unsigned int *eihs_offset) +{ + unsigned int imgtype, size; + bfd_vma symvva; + struct vms_eihd *eihd = (struct vms_eihd *)PRIV (recrd.rec); + + vms_debug2 ((8, "_bfd_vms_slurp_eihd\n")); + + size = bfd_getl32 (eihd->size); + imgtype = bfd_getl32 (eihd->imgtype); + + if (imgtype == EIHD__K_EXE || imgtype == EIHD__K_LIM) + abfd->flags |= EXEC_P; + + symvva = bfd_getl64 (eihd->symvva); + if (symvva != 0) + { + PRIV (symvva) = symvva; + abfd->flags |= DYNAMIC; + } + + PRIV (ident) = bfd_getl32 (eihd->ident); + PRIV (matchctl) = eihd->matchctl; + + *eisd_offset = bfd_getl32 (eihd->isdoff); + *eihs_offset = bfd_getl32 (eihd->symdbgoff); + + vms_debug2 ((4, "EIHD size %d imgtype %d symvva 0x%lx eisd %d eihs %d\n", + size, imgtype, (unsigned long)symvva, + *eisd_offset, *eihs_offset)); + + return FALSE; +} + +/* Read & process EISD record. + Return TRUE on success, FALSE on error. */ + +static bfd_boolean +_bfd_vms_slurp_eisd (bfd *abfd, unsigned int offset) +{ + int section_count = 0; + + vms_debug2 ((8, "_bfd_vms_slurp_eisd\n")); + + while (1) + { + struct vms_eisd *eisd; + unsigned int rec_size; + unsigned int size; + unsigned long long vaddr; + unsigned int flags; + unsigned int vbn; + char *name = NULL; + asection *section; + flagword bfd_flags; + + eisd = (struct vms_eisd *)(PRIV (recrd.rec) + offset); + rec_size = bfd_getl32 (eisd->eisdsize); + + if (rec_size == 0) + break; + + /* Skip to next block if pad. */ + if (rec_size == 0xffffffff) + { + offset = (offset + VMS_BLOCK_SIZE) & ~(VMS_BLOCK_SIZE - 1); + continue; + } + else + offset += rec_size; + + size = bfd_getl32 (eisd->secsize); + vaddr = bfd_getl64 (eisd->virt_addr); + flags = bfd_getl32 (eisd->flags); + vbn = bfd_getl32 (eisd->vbn); + + vms_debug2 ((4, "EISD at 0x%x size 0x%x addr 0x%lx flags 0x%x blk %d\n", + offset, size, (unsigned long)vaddr, flags, vbn)); + + /* VMS combines psects from .obj files into isects in the .exe. This + process doesn't preserve enough information to reliably determine + what's in each section without examining the data. This is + especially true of DWARF debug sections. */ + bfd_flags = SEC_ALLOC; + + if (flags & EISD__M_EXE) + bfd_flags |= SEC_CODE | SEC_HAS_CONTENTS | SEC_LOAD; + + if (flags & EISD__M_NONSHRADR) + bfd_flags |= SEC_DATA | SEC_HAS_CONTENTS | SEC_LOAD; + + if (!(flags & EISD__M_WRT)) + bfd_flags |= SEC_READONLY; + + if (flags & EISD__M_DZRO) + bfd_flags |= SEC_DATA; + + if (flags & EISD__M_FIXUPVEC) + bfd_flags |= SEC_DATA | SEC_HAS_CONTENTS | SEC_LOAD; + + if (flags & EISD__M_CRF) + bfd_flags |= SEC_HAS_CONTENTS | SEC_LOAD; + + if (flags & EISD__M_GBL) + { + name = _bfd_vms_save_counted_string (eisd->gblnam); + bfd_flags |= SEC_COFF_SHARED_LIBRARY; + bfd_flags &= ~(SEC_ALLOC | SEC_LOAD); + } + else if (flags & EISD__M_FIXUPVEC) + name = "$FIXUPVEC$"; + else if (eisd->type == EISD__K_USRSTACK) + name = "$STACK$"; + else + { + const char *pfx; + + name = (char*) bfd_alloc (abfd, 32); + if (flags & EISD__M_DZRO) + pfx = "BSS"; + else if (flags & EISD__M_EXE) + pfx = "CODE"; + else if (!(flags & EISD__M_WRT)) + pfx = "RO"; + else + pfx = "LOCAL"; + BFD_ASSERT (section_count < 999); + sprintf (name, "$%s_%03d$", pfx, section_count++); + } + + section = bfd_make_section (abfd, name); + + if (!section) + return FALSE; + + section->filepos = vbn ? VMS_BLOCK_SIZE * (vbn - 1) : 0; + section->size = size; + section->vma = vaddr; + + if (!bfd_set_section_flags (abfd, section, bfd_flags)) + return FALSE; + } + + return TRUE; +} + +/* Read & process EIHS record. + Return TRUE on success, FALSE on error. */ + +static bfd_boolean +_bfd_vms_slurp_eihs (bfd *abfd, unsigned int offset) +{ + unsigned char *p = PRIV (recrd.rec) + offset; + unsigned int gstvbn = bfd_getl32 (p + EIHS__L_GSTVBN); + unsigned int gstsize ATTRIBUTE_UNUSED = bfd_getl32 (p + EIHS__L_GSTSIZE); + unsigned int dstvbn = bfd_getl32 (p + EIHS__L_DSTVBN); + unsigned int dstsize = bfd_getl32 (p + EIHS__L_DSTSIZE); + unsigned int dmtvbn = bfd_getl32 (p + EIHS__L_DMTVBN); + unsigned int dmtbytes = bfd_getl32 (p + EIHS__L_DMTBYTES); + asection *section; + +#if VMS_DEBUG + vms_debug (8, "_bfd_vms_slurp_ihs\n"); + vms_debug (4, "EIHS record gstvbn %d gstsize %d dstvbn %d dstsize %d dmtvbn %d dmtbytes %d\n", + gstvbn, gstsize, dstvbn, dstsize, dmtvbn, dmtbytes); +#endif + + if (dstvbn) + { + flagword bfd_flags = SEC_HAS_CONTENTS | SEC_DEBUGGING; + + section = bfd_make_section (abfd, "$DST$"); + if (!section) + return FALSE; + + section->size = dstsize; + section->filepos = VMS_BLOCK_SIZE * (dstvbn - 1); + + if (!bfd_set_section_flags (abfd, section, bfd_flags)) + return FALSE; + + PRIV (dst_section) = section; + abfd->flags |= (HAS_DEBUG | HAS_LINENO); + } + + if (dmtvbn) + { + flagword bfd_flags = SEC_HAS_CONTENTS | SEC_DEBUGGING; + + section = bfd_make_section (abfd, "$DMT$"); + if (!section) + return FALSE; + + section->size = dmtbytes; + section->filepos = VMS_BLOCK_SIZE * (dmtvbn - 1); + + if (!bfd_set_section_flags (abfd, section, bfd_flags)) + return FALSE; + } + + if (gstvbn) + { + flagword bfd_flags = SEC_HAS_CONTENTS; + + section = bfd_make_section (abfd, "$GST$"); + if (!section) + return FALSE; + + if (bfd_seek (abfd, VMS_BLOCK_SIZE * (gstvbn - 1), SEEK_SET)) + { + bfd_set_error (bfd_error_file_truncated); + return FALSE; + } + + if (_bfd_vms_slurp_object_records (abfd) != TRUE) + return FALSE; + + section->filepos = VMS_BLOCK_SIZE * (gstvbn - 1); + section->size = bfd_tell (abfd) - section->filepos; + + if (!bfd_set_section_flags (abfd, section, bfd_flags)) + return FALSE; + + abfd->flags |= HAS_SYMS; + } + + return TRUE; +} + +/* Object file reading. */ + +/* Object file input functions. */ + +/* Get next record from object file to vms_buf. + Set PRIV(buf_size) and return it + + This is a little tricky since it should be portable. + + The openVMS object file has 'variable length' which means that + read() returns data in chunks of (hopefully) correct and expected + size. The linker (and other tools on VMS) depend on that. Unix + doesn't know about 'formatted' files, so reading and writing such + an object file in a Unix environment is not trivial. + + With the tool 'file' (available on all VMS FTP sites), one + can view and change the attributes of a file. Changing from + 'variable length' to 'fixed length, 512 bytes' reveals the + record size at the first 2 bytes of every record. The same + may happen during the transfer of object files from VMS to Unix, + at least with UCX, the DEC implementation of TCP/IP. + + The VMS format repeats the size at bytes 2 & 3 of every record. + + On the first call (file_format == FF_UNKNOWN) we check if + the first and the third byte pair (!) of the record match. + If they do it's an object file in an Unix environment or with + wrong attributes (FF_FOREIGN), else we should be in a VMS + environment where read() returns the record size (FF_NATIVE). + + Reading is always done in 2 steps: + 1. first just the record header is read and the size extracted, + 2. then the read buffer is adjusted and the remaining bytes are + read in. + + All file I/O is done on even file positions. */ + +#define VMS_OBJECT_ADJUSTMENT 2 + +static void +maybe_adjust_record_pointer_for_object (bfd *abfd) +{ + /* Set the file format once for all on the first invocation. */ + if (PRIV (recrd.file_format) == FF_UNKNOWN) + { + if (PRIV (recrd.rec)[0] == PRIV (recrd.rec)[4] + && PRIV (recrd.rec)[1] == PRIV (recrd.rec)[5]) + PRIV (recrd.file_format) = FF_FOREIGN; + else + PRIV (recrd.file_format) = FF_NATIVE; + } + + /* The adjustment is needed only in an Unix environment. */ + if (PRIV (recrd.file_format) == FF_FOREIGN) + PRIV (recrd.rec) += VMS_OBJECT_ADJUSTMENT; +} + +/* Implement step #1 of the object record reading procedure. + Return the record type or -1 on failure. */ + +static int +_bfd_vms_get_object_record (bfd *abfd) +{ + unsigned int test_len; + int type; + int off = 0; + + vms_debug2 ((8, "_bfd_vms_get_obj_record\n")); + + test_len = 6; + + /* Skip odd alignment byte. */ + if (bfd_tell (abfd) & 1) + { + if (bfd_bread (PRIV (recrd.buf), 1, abfd) != 1) + { + bfd_set_error (bfd_error_file_truncated); + return -1; + } + /* Alignment byte may be present or not. This is not easy to + detect but all object record types are not 0 (on Alpha VMS). + We also hope that pad byte is 0. */ + if (PRIV (recrd.buf)[0]) + off = 1; + } + + /* Read the record header */ + if (bfd_bread (PRIV (recrd.buf) + off, test_len - off, abfd) + != test_len - off) + { + bfd_set_error (bfd_error_file_truncated); + return -1; + } + + /* Reset the record pointer. */ + PRIV (recrd.rec) = PRIV (recrd.buf); + maybe_adjust_record_pointer_for_object (abfd); + + if (vms_get_remaining_object_record (abfd, test_len) <= 0) + return -1; + + type = bfd_getl16 (PRIV (recrd.rec)); + + vms_debug2 ((8, "_bfd_vms_get_obj_record: rec %p, size %d, type %d\n", + PRIV (recrd.rec), PRIV (recrd.rec_size), type)); + + return type; +} + +/* Implement step #2 of the object record reading procedure. + Return the size of the record or 0 on failure. */ + +static int +vms_get_remaining_object_record (bfd *abfd, int read_so_far) +{ + unsigned int to_read; + + vms_debug2 ((8, "vms_get_remaining_obj_record\n")); + + /* Extract record size. */ + PRIV (recrd.rec_size) = bfd_getl16 (PRIV (recrd.rec) + 2); + + if (PRIV (recrd.rec_size) <= 0) + { + bfd_set_error (bfd_error_file_truncated); + return 0; + } + + /* That's what the linker manual says. */ + if (PRIV (recrd.rec_size) > EOBJ__C_MAXRECSIZ) + { + bfd_set_error (bfd_error_file_truncated); + return 0; + } + + /* Take into account object adjustment. */ + to_read = PRIV (recrd.rec_size); + if (PRIV (recrd.file_format) == FF_FOREIGN) + to_read += VMS_OBJECT_ADJUSTMENT; + + /* Adjust the buffer. */ + if (to_read > PRIV (recrd.buf_size)) + { + PRIV (recrd.buf) + = (unsigned char *) bfd_realloc (PRIV (recrd.buf), to_read); + if (PRIV (recrd.buf) == NULL) + return 0; + PRIV (recrd.buf_size) = to_read; + } + + /* Read the remaining record. */ + to_read -= read_so_far; + + vms_debug2 ((8, "vms_get_remaining_obj_record: to_read %d\n", to_read)); + + if (bfd_bread (PRIV (recrd.buf) + read_so_far, to_read, abfd) != to_read) + { + bfd_set_error (bfd_error_file_truncated); + return 0; + } + + /* Reset the record pointer. */ + PRIV (recrd.rec) = PRIV (recrd.buf); + maybe_adjust_record_pointer_for_object (abfd); + + vms_debug2 ((8, "vms_get_remaining_obj_record: size %d\n", + PRIV (recrd.rec_size))); + + return PRIV (recrd.rec_size); +} + +/* Read and process emh record. + Return TRUE on success, FALSE on error. */ + +static bfd_boolean +_bfd_vms_slurp_ehdr (bfd *abfd) +{ + unsigned char *ptr; + unsigned char *vms_rec; + int subtype; + + vms_rec = PRIV (recrd.rec); + + vms_debug2 ((2, "HDR/EMH\n")); + + subtype = bfd_getl16 (vms_rec + 4); + + vms_debug2 ((3, "subtype %d\n", subtype)); + + switch (subtype) + { + case EMH__C_MHD: + /* Module header. */ + PRIV (hdr_data).hdr_b_strlvl = vms_rec[6]; + PRIV (hdr_data).hdr_l_arch1 = bfd_getl32 (vms_rec + 8); + PRIV (hdr_data).hdr_l_arch2 = bfd_getl32 (vms_rec + 12); + PRIV (hdr_data).hdr_l_recsiz = bfd_getl32 (vms_rec + 16); + PRIV (hdr_data).hdr_t_name = _bfd_vms_save_counted_string (vms_rec + 20); + ptr = vms_rec + 20 + vms_rec[20] + 1; + PRIV (hdr_data).hdr_t_version =_bfd_vms_save_counted_string (ptr); + ptr += *ptr + 1; + PRIV (hdr_data).hdr_t_date = _bfd_vms_save_sized_string (ptr, 17); + break; + + case EMH__C_LNM: + PRIV (hdr_data).hdr_c_lnm = + _bfd_vms_save_sized_string (vms_rec, PRIV (recrd.rec_size - 6)); + break; + + case EMH__C_SRC: + PRIV (hdr_data).hdr_c_src = + _bfd_vms_save_sized_string (vms_rec, PRIV (recrd.rec_size - 6)); + break; + + case EMH__C_TTL: + PRIV (hdr_data).hdr_c_ttl = + _bfd_vms_save_sized_string (vms_rec, PRIV (recrd.rec_size - 6)); + break; + + case EMH__C_CPR: + case EMH__C_MTC: + case EMH__C_GTX: + break; + + default: + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + return TRUE; +} + +/* Typical sections for evax object files. */ + +#define EVAX_ABS_NAME "$ABS$" +#define EVAX_CODE_NAME "$CODE$" +#define EVAX_LINK_NAME "$LINK$" +#define EVAX_DATA_NAME "$DATA$" +#define EVAX_BSS_NAME "$BSS$" +#define EVAX_READONLYADDR_NAME "$READONLY_ADDR$" +#define EVAX_READONLY_NAME "$READONLY$" +#define EVAX_LITERAL_NAME "$LITERAL$" +#define EVAX_LITERALS_NAME "$LITERALS" +#define EVAX_COMMON_NAME "$COMMON$" +#define EVAX_LOCAL_NAME "$LOCAL$" + +struct sec_flags_struct +{ + const char *name; /* Name of section. */ + int vflags_always; + flagword flags_always; /* Flags we set always. */ + int vflags_hassize; + flagword flags_hassize; /* Flags we set if the section has a size > 0. */ +}; + +/* These flags are deccrtl/vaxcrtl (openVMS 6.2 Alpha) compatible. */ + +static struct sec_flags_struct evax_section_flags[] = + { + { EVAX_ABS_NAME, + (EGPS__V_SHR), + (SEC_DATA), + (EGPS__V_SHR), + (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, + { EVAX_CODE_NAME, + (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_EXE), + (SEC_CODE), + (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_EXE), + (SEC_CODE | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, + { EVAX_LITERAL_NAME, + (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD | EGPS__V_NOMOD), + (SEC_DATA | SEC_READONLY), + (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD), + (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, + { EVAX_LINK_NAME, + (EGPS__V_REL | EGPS__V_RD), + (SEC_DATA | SEC_READONLY), + (EGPS__V_REL | EGPS__V_RD), + (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, + { EVAX_DATA_NAME, + (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT | EGPS__V_NOMOD), + (SEC_DATA), + (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT), + (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, + { EVAX_BSS_NAME, + (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT | EGPS__V_NOMOD), + (SEC_NO_FLAGS), + (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT | EGPS__V_NOMOD), + (SEC_ALLOC) }, + { EVAX_READONLYADDR_NAME, + (EGPS__V_PIC | EGPS__V_REL | EGPS__V_RD), + (SEC_DATA | SEC_READONLY), + (EGPS__V_PIC | EGPS__V_REL | EGPS__V_RD), + (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, + { EVAX_READONLY_NAME, + (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD | EGPS__V_NOMOD), + (SEC_DATA | SEC_READONLY), + (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD), + (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, + { EVAX_LOCAL_NAME, + (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT), + (SEC_DATA), + (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT), + (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, + { EVAX_LITERALS_NAME, + (EGPS__V_PIC | EGPS__V_OVR), + (SEC_DATA | SEC_READONLY), + (EGPS__V_PIC | EGPS__V_OVR), + (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, + { NULL, + (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT), + (SEC_DATA), + (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT), + (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) } + }; + +/* Retrieve bfd section flags by name and size. */ + +static flagword +vms_secflag_by_name (bfd *abfd ATTRIBUTE_UNUSED, + struct sec_flags_struct *section_flags, + char *name, + int hassize) +{ + int i = 0; + + while (section_flags[i].name != NULL) + { + if (strcmp (name, section_flags[i].name) == 0) + { + if (hassize) + return section_flags[i].flags_hassize; + else + return section_flags[i].flags_always; + } + i++; + } + if (hassize) + return section_flags[i].flags_hassize; + return section_flags[i].flags_always; +} + +/* Retrieve vms section flags by name and size. */ + +static flagword +vms_esecflag_by_name (struct sec_flags_struct *section_flags, + char *name, + int hassize) +{ + int i = 0; + + while (section_flags[i].name != NULL) + { + if (strcmp (name, section_flags[i].name) == 0) + { + if (hassize) + return section_flags[i].vflags_hassize; + else + return section_flags[i].vflags_always; + } + i++; + } + if (hassize) + return section_flags[i].vflags_hassize; + return section_flags[i].vflags_always; +} + +/* Input routines. */ + +static struct vms_symbol_entry * +add_symbol (bfd *abfd, const unsigned char *ascic) +{ + struct vms_symbol_entry *entry; + int len; + + len = *ascic++; + entry = (struct vms_symbol_entry *)bfd_zalloc (abfd, sizeof (*entry) + len); + if (entry == NULL) + return NULL; + entry->namelen = len; + memcpy (entry->name, ascic, len); + entry->name[len] = 0; + entry->owner = abfd; + + if (PRIV (gsd_sym_count) >= PRIV (max_sym_count)) + { + if (PRIV (max_sym_count) == 0) + { + PRIV (max_sym_count) = 128; + PRIV (syms) = bfd_malloc + (PRIV (max_sym_count) * sizeof (struct vms_symbol_entry *)); + } + else + { + PRIV (max_sym_count) *= 2; + PRIV (syms) = bfd_realloc + (PRIV (syms), + (PRIV (max_sym_count) * sizeof (struct vms_symbol_entry *))); + } + if (PRIV (syms) == NULL) + return NULL; + } + + PRIV (syms)[PRIV (gsd_sym_count)++] = entry; + return entry; +} + +/* Read and process EGSD. Return FALSE on failure. */ + +static bfd_boolean +_bfd_vms_slurp_egsd (bfd * abfd) +{ + int gsd_type, gsd_size; + asection *section; + unsigned char *vms_rec; + flagword new_flags, old_flags; + char *name; + unsigned long base_addr; + unsigned long align_addr; + + vms_debug2 ((2, "EGSD\n")); + + PRIV (recrd.rec) += 8; /* Skip type, size, align pad. */ + PRIV (recrd.rec_size) -= 8; + + /* Calculate base address for each section. */ + base_addr = 0L; + + while (PRIV (recrd.rec_size) > 0) + { + vms_rec = PRIV (recrd.rec); + + gsd_type = bfd_getl16 (vms_rec); + gsd_size = bfd_getl16 (vms_rec + 2); + + vms_debug2 ((3, "egsd_type %d\n", gsd_type)); + + switch (gsd_type) + { + case EGSD__C_PSC: + { + /* Program section definition. */ + struct vms_egps *egps = (struct vms_egps *)vms_rec; + name = _bfd_vms_save_counted_string (&egps->namlng); + section = bfd_make_section (abfd, name); + if (!section) + return FALSE; + old_flags = bfd_getl16 (egps->flags); + vms_section_data (section)->flags = old_flags; + vms_section_data (section)->no_flags = 0; + section->size = bfd_getl32 (egps->alloc); + new_flags = vms_secflag_by_name (abfd, evax_section_flags, name, + section->size > 0); + if (!(old_flags & EGPS__V_NOMOD)) + { + new_flags |= SEC_HAS_CONTENTS; + if (old_flags & EGPS__V_REL) + new_flags |= SEC_RELOC; + } + if (!bfd_set_section_flags (abfd, section, new_flags)) + return FALSE; + section->alignment_power = egps->align; + align_addr = (1 << section->alignment_power); + if ((base_addr % align_addr) != 0) + base_addr += (align_addr - (base_addr % align_addr)); + section->vma = (bfd_vma)base_addr; + base_addr += section->size; + section->filepos = (unsigned int)-1; +#if VMS_DEBUG + vms_debug (4, "EGSD P-section %d (%s, flags %04x) ", + section->index, name, old_flags); + vms_debug (4, "%lu bytes at 0x%08lx (mem %p)\n", + (unsigned long)section->size, + (unsigned long)section->vma, section->contents); +#endif + } + break; + + case EGSD__C_SYM: + { + int nameoff; + struct vms_symbol_entry *entry; + struct vms_egsy *egsy = (struct vms_egsy *) vms_rec; + + old_flags = bfd_getl16 (egsy->flags); + if (old_flags & EGSY__V_DEF) + nameoff = ESDF__B_NAMLNG; + else + nameoff = ESRF__B_NAMLNG; + + entry = add_symbol (abfd, vms_rec + nameoff); + if (entry == NULL) + return FALSE; + + /* Allow only duplicate reference. */ + if ((entry->flags & EGSY__V_DEF) && (old_flags & EGSY__V_DEF)) + abort (); + + if (entry->typ == 0) + { + entry->typ = gsd_type; + entry->data_type = egsy->datyp; + entry->flags = old_flags; + } + + if (old_flags & EGSY__V_DEF) + { + struct vms_esdf *esdf = (struct vms_esdf *)vms_rec; + + entry->value = bfd_getl64 (esdf->value); + entry->section = bfd_getl32 (esdf->psindx); + + if (old_flags & EGSY__V_NORM) + { + PRIV (norm_sym_count)++; + + entry->code_value = bfd_getl64 (esdf->code_address); + entry->code_section = bfd_getl32 (esdf->ca_psindx); + } + } + } + break; + + case EGSD__C_SYMG: + { + int nameoff; + struct vms_symbol_entry *entry; + struct vms_egst *egst = (struct vms_egst *)vms_rec; + + old_flags = bfd_getl16 (egst->header.flags); + if (old_flags & EGSY__V_DEF) + nameoff = ESDF__B_NAMLNG; + else + nameoff = ESRF__B_NAMLNG; + + entry = add_symbol (abfd, &egst->namlng); + + if (entry == NULL) + return FALSE; + + entry->typ = gsd_type; + entry->data_type = egst->header.datyp; + entry->flags = old_flags; + + entry->symbol_vector = bfd_getl32 (egst->value); + + entry->section = bfd_getl32 (egst->psindx); + entry->value = bfd_getl64 (egst->lp_2); + + if (old_flags & EGSY__V_NORM) + { + PRIV (norm_sym_count)++; + + entry->code_value = bfd_getl64 (egst->lp_1); + entry->code_section = 0; + } + } + break; + + case EGSD__C_IDC: + case EGSD__C_SYMM: + case EGSD__C_SYMV: + default: + (*_bfd_error_handler) (_("Unknown EGSD subtype %d"), gsd_type); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + PRIV (recrd.rec_size) -= gsd_size; + PRIV (recrd.rec) += gsd_size; + } + + if (PRIV (gsd_sym_count) > 0) + abfd->flags |= HAS_SYMS; + + return TRUE; +} + +/* Stack routines for vms ETIR commands. */ + +/* Push value and section index. */ + +static void +_bfd_vms_push (bfd *abfd, bfd_vma val, unsigned int reloc) +{ + vms_debug2 ((4, "<push %08lx (0x%08x) at %d>\n", + (unsigned long)val, reloc, PRIV (stackptr))); + + PRIV (stack[PRIV (stackptr)]).value = val; + PRIV (stack[PRIV (stackptr)]).reloc = reloc; + PRIV (stackptr)++; + if (PRIV (stackptr) >= STACKSIZE) + { + bfd_set_error (bfd_error_bad_value); + (*_bfd_error_handler) (_("Stack overflow (%d) in _bfd_vms_push"), PRIV (stackptr)); + exit (1); + } +} + +/* Pop value and section index. */ + +static void +_bfd_vms_pop (bfd *abfd, bfd_vma *val, unsigned int *rel) +{ + if (PRIV (stackptr) == 0) + { + bfd_set_error (bfd_error_bad_value); + (*_bfd_error_handler) (_("Stack underflow in _bfd_vms_pop")); + exit (1); + } + PRIV (stackptr)--; + *val = PRIV (stack[PRIV (stackptr)]).value; + *rel = PRIV (stack[PRIV (stackptr)]).reloc; + + vms_debug2 ((4, "<pop %08lx (0x%08x)>\n", (unsigned long)*val, *rel)); +} + +/* Routines to fill sections contents during tir/etir read. */ + +/* Initialize image buffer pointer to be filled. */ + +static void +image_set_ptr (bfd *abfd, bfd_vma vma, int sect, struct bfd_link_info *info) +{ + asection *sec; + + vms_debug2 ((4, "image_set_ptr (0x%08x, sect=%d)\n", (unsigned)vma, sect)); + + sec = PRIV (sections)[sect]; + + if (info) + { + /* Reading contents to an output bfd. */ + + if (sec->output_section == NULL) + { + /* Section discarded. */ + vms_debug2 ((5, " section %s discarded\n", sec->name)); + + /* This is not used. */ + PRIV (image_section) = NULL; + PRIV (image_offset) = 0; + return; + } + PRIV (image_offset) = sec->output_offset + vma; + PRIV (image_section) = sec->output_section; + } + else + { + PRIV (image_offset) = vma; + PRIV (image_section) = sec; + } +} + +/* Increment image buffer pointer by offset. */ + +static void +image_inc_ptr (bfd *abfd, bfd_vma offset) +{ + vms_debug2 ((4, "image_inc_ptr (%u)\n", (unsigned)offset)); + + PRIV (image_offset) += offset; +} + +/* Save current DST location counter under specified index. */ + +static void +dst_define_location (bfd *abfd, unsigned int loc) +{ + vms_debug2 ((4, "dst_define_location (%d)\n", (int)loc)); + + /* Grow the ptr offset table if necessary. */ + if (loc + 1 > PRIV (dst_ptr_offsets_count)) + { + PRIV (dst_ptr_offsets) = bfd_realloc (PRIV (dst_ptr_offsets), + (loc + 1) * sizeof (unsigned int)); + PRIV (dst_ptr_offsets_count) = loc + 1; + } + + PRIV (dst_ptr_offsets)[loc] = PRIV (image_offset); +} + +/* Restore saved DST location counter from specified index. */ + +static void +dst_restore_location (bfd *abfd, unsigned int loc) +{ + vms_debug2 ((4, "dst_restore_location (%d)\n", (int)loc)); + + PRIV (image_offset) = PRIV (dst_ptr_offsets)[loc]; +} + +/* Retrieve saved DST location counter from specified index. */ + +static unsigned int +dst_retrieve_location (bfd *abfd, unsigned int loc) +{ + vms_debug2 ((4, "dst_retrieve_location (%d)\n", (int)loc)); + + return PRIV (dst_ptr_offsets)[loc]; +} + +/* Check that the DST section is big enough for the specified + amount of bytes. */ + +static void +dst_check_allocation (bfd *abfd, unsigned int size) +{ + asection *section = PRIV (image_section); + + section->size += size; + + /* Grow the section as necessary */ + if (section->size <= section->rawsize) + return; + do + { + if (section->rawsize == 0) + section->rawsize = 1024; + else + section->rawsize *= 2; + } + while (section->size > section->rawsize); + section->contents = bfd_realloc (section->contents, section->rawsize); +} + +/* Write multiple bytes to section image. */ + +static bfd_boolean +image_write (bfd *abfd, unsigned char *ptr, int size) +{ +#if VMS_DEBUG + _bfd_vms_debug (8, "image_write from (%p, %d) to (%ld)\n", ptr, size, + (long)PRIV (image_offset)); + _bfd_hexdump (9, ptr, size, 0); +#endif + + if (PRIV (image_autoextend)) + dst_check_allocation (abfd, size); + + if (PRIV (image_section)->contents != NULL) + { + asection *sec = PRIV (image_section); + file_ptr off = PRIV (image_offset); + + /* Check bounds. */ + if (off > (file_ptr)sec->size + || size > (file_ptr)sec->size + || off + size > (file_ptr)sec->size) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + memcpy (sec->contents + off, ptr, size); + } + + PRIV (image_offset) += size; + return TRUE; +} + +/* Write byte to section image. */ + +static bfd_boolean +image_write_b (bfd * abfd, unsigned int value) +{ + unsigned char data[1]; + + vms_debug2 ((6, "image_write_b (%02x)\n", (int) value)); + + *data = value; + + return image_write (abfd, data, sizeof (data)); +} + +/* Write 2-byte word to image. */ + +static bfd_boolean +image_write_w (bfd * abfd, unsigned int value) +{ + unsigned char data[2]; + + vms_debug2 ((6, "image_write_w (%04x)\n", (int) value)); + + bfd_putl16 (value, data); + return image_write (abfd, data, sizeof (data)); +} + +/* Write 4-byte long to image. */ + +static bfd_boolean +image_write_l (bfd * abfd, unsigned long value) +{ + unsigned char data[4]; + + vms_debug2 ((6, "image_write_l (%08lx)\n", value)); + + bfd_putl32 (value, data); + return image_write (abfd, data, sizeof (data)); +} + +/* Write 8-byte quad to image. */ + +static bfd_boolean +image_write_q (bfd * abfd, bfd_vma value) +{ + unsigned char data[8]; + + vms_debug2 ((6, "image_write_q (%08lx)\n", (unsigned long)value)); + + bfd_putl64 (value, data); + return image_write (abfd, data, sizeof (data)); +} + +static const char * +_bfd_vms_etir_name (int cmd) +{ + switch (cmd) + { + case ETIR__C_STA_GBL: return "ETIR__C_STA_GBL"; + case ETIR__C_STA_LW: return "ETIR__C_STA_LW"; + case ETIR__C_STA_QW: return "ETIR__C_STA_QW"; + case ETIR__C_STA_PQ: return "ETIR__C_STA_PQ"; + case ETIR__C_STA_LI: return "ETIR__C_STA_LI"; + case ETIR__C_STA_MOD: return "ETIR__C_STA_MOD"; + case ETIR__C_STA_CKARG: return "ETIR__C_STA_CKARG"; + case ETIR__C_STO_B: return "ETIR__C_STO_B"; + case ETIR__C_STO_W: return "ETIR__C_STO_W"; + case ETIR__C_STO_GBL: return "ETIR__C_STO_GBL"; + case ETIR__C_STO_CA: return "ETIR__C_STO_CA"; + case ETIR__C_STO_RB: return "ETIR__C_STO_RB"; + case ETIR__C_STO_AB: return "ETIR__C_STO_AB"; + case ETIR__C_STO_OFF: return "ETIR__C_STO_OFF"; + case ETIR__C_STO_IMM: return "ETIR__C_STO_IMM"; + case ETIR__C_STO_IMMR: return "ETIR__C_STO_IMMR"; + case ETIR__C_STO_LW: return "ETIR__C_STO_LW"; + case ETIR__C_STO_QW: return "ETIR__C_STO_QW"; + case ETIR__C_STO_GBL_LW: return "ETIR__C_STO_GBL_LW"; + case ETIR__C_STO_LP_PSB: return "ETIR__C_STO_LP_PSB"; + case ETIR__C_STO_HINT_GBL: return "ETIR__C_STO_HINT_GBL"; + case ETIR__C_STO_HINT_PS: return "ETIR__C_STO_HINT_PS"; + case ETIR__C_OPR_ADD: return "ETIR__C_OPR_ADD"; + case ETIR__C_OPR_SUB: return "ETIR__C_OPR_SUB"; + case ETIR__C_OPR_INSV: return "ETIR__C_OPR_INSV"; + case ETIR__C_OPR_USH: return "ETIR__C_OPR_USH"; + case ETIR__C_OPR_ROT: return "ETIR__C_OPR_ROT"; + case ETIR__C_OPR_REDEF: return "ETIR__C_OPR_REDEF"; + case ETIR__C_OPR_DFLIT: return "ETIR__C_OPR_DFLIT"; + case ETIR__C_STC_LP: return "ETIR__C_STC_LP"; + case ETIR__C_STC_GBL: return "ETIR__C_STC_GBL"; + case ETIR__C_STC_GCA: return "ETIR__C_STC_GCA"; + case ETIR__C_STC_PS: return "ETIR__C_STC_PS"; + case ETIR__C_STC_NBH_PS: return "ETIR__C_STC_NBH_PS"; + case ETIR__C_STC_NOP_GBL: return "ETIR__C_STC_NOP_GBL"; + case ETIR__C_STC_NOP_PS: return "ETIR__C_STC_NOP_PS"; + case ETIR__C_STC_BSR_GBL: return "ETIR__C_STC_BSR_GBL"; + case ETIR__C_STC_BSR_PS: return "ETIR__C_STC_BSR_PS"; + case ETIR__C_STC_LDA_GBL: return "ETIR__C_STC_LDA_GBL"; + case ETIR__C_STC_LDA_PS: return "ETIR__C_STC_LDA_PS"; + case ETIR__C_STC_BOH_GBL: return "ETIR__C_STC_BOH_GBL"; + case ETIR__C_STC_BOH_PS: return "ETIR__C_STC_BOH_PS"; + case ETIR__C_STC_NBH_GBL: return "ETIR__C_STC_NBH_GBL"; + case ETIR__C_STC_LP_PSB: return "ETIR__C_STC_LP_PSB"; + case ETIR__C_CTL_SETRB: return "ETIR__C_CTL_SETRB"; + case ETIR__C_CTL_AUGRB: return "ETIR__C_CTL_AUGRB"; + case ETIR__C_CTL_DFLOC: return "ETIR__C_CTL_DFLOC"; + case ETIR__C_CTL_STLOC: return "ETIR__C_CTL_STLOC"; + case ETIR__C_CTL_STKDL: return "ETIR__C_CTL_STKDL"; + + default: + /* These names have not yet been added to this switch statement. */ + (*_bfd_error_handler) (_("unknown ETIR command %d"), cmd); + } + + return NULL; +} +#define HIGHBIT(op) ((op & 0x80000000L) == 0x80000000L) + +static void +_bfd_vms_get_value (bfd *abfd, const unsigned char *ascic, + struct bfd_link_info *info, + bfd_vma *vma, + struct alpha_vms_link_hash_entry **hp) +{ + char name[257]; + int len; + int i; + struct alpha_vms_link_hash_entry *h; + + /* Not linking. Do not try to resolve the symbol. */ + if (info == NULL) + { + *vma = 0; + *hp = NULL; + return; + } + + len = *ascic; + for (i = 0; i < len; i++) + name[i] = ascic[i + 1]; + name[i] = 0; + + h = (struct alpha_vms_link_hash_entry *) + bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE); + + *hp = h; + + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + *vma = h->root.u.def.value + + h->root.u.def.section->output_offset + + h->root.u.def.section->output_section->vma; + else if (h && h->root.type == bfd_link_hash_undefweak) + *vma = 0; + else + { + if (!(*info->callbacks->undefined_symbol) + (info, name, abfd, PRIV (image_section), PRIV (image_offset), TRUE)) + abort (); + *vma = 0; + } +} + +#define RELC_NONE 0 +#define RELC_REL 1 +#define RELC_SHR_BASE 0x10000 +#define RELC_SEC_BASE 0x20000 +#define RELC_MASK 0x0ffff + +static unsigned int +alpha_vms_sym_to_ctxt (struct alpha_vms_link_hash_entry *h) +{ + /* Handle undefined symbols. */ + if (h == NULL || h->sym == NULL) + return RELC_NONE; + + if (h->sym->typ == EGSD__C_SYMG) + { + if (h->sym->flags & EGSY__V_REL) + return RELC_SHR_BASE + PRIV2 (h->sym->owner, shr_index); + else + { + /* Can this happen ? I'd like to see an example. */ + abort (); + } + } + if (h->sym->typ == EGSD__C_SYM) + { + if (h->sym->flags & EGSY__V_REL) + return RELC_REL; + else + return RELC_NONE; + } + abort (); +} + +static bfd_vma +alpha_vms_get_sym_value (unsigned int sect, bfd_vma addr, + struct alpha_vms_link_hash_entry *h) +{ + asection *s; + + BFD_ASSERT (h && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)); + + s = PRIV2 (h->root.u.def.section->owner, sections)[sect]; + return s->output_section->vma + s->output_offset + addr; +} + +static bfd_vma +alpha_vms_fix_sec_rel (bfd *abfd, struct bfd_link_info *info, + unsigned int rel, bfd_vma vma) +{ + asection *sec = PRIV (sections)[rel & RELC_MASK]; + + if (info) + { + if (sec->output_section == NULL) + abort (); + return vma + sec->output_section->vma + sec->output_offset; + } + else + return vma + sec->vma; +} + +static bfd_boolean +_bfd_vms_slurp_etir (bfd *abfd, struct bfd_link_info *info) +{ + unsigned char *ptr; + unsigned int length; + unsigned char *maxptr; + bfd_vma op1; + bfd_vma op2; + unsigned int rel1; + unsigned int rel2; + struct alpha_vms_link_hash_entry *h; + + PRIV (recrd.rec) += ETIR__C_HEADER_SIZE; + PRIV (recrd.rec_size) -= ETIR__C_HEADER_SIZE; + + ptr = PRIV (recrd.rec); + length = PRIV (recrd.rec_size); + maxptr = ptr + length; + + vms_debug2 ((2, "ETIR: %d bytes\n", length)); + + while (ptr < maxptr) + { + int cmd = bfd_getl16 (ptr); + int cmd_length = bfd_getl16 (ptr + 2); + + ptr += 4; + +#if VMS_DEBUG + _bfd_vms_debug (4, "etir: %s(%d)\n", + _bfd_vms_etir_name (cmd), cmd); + _bfd_hexdump (8, ptr, cmd_length - 4, (long) ptr); +#endif + + switch (cmd) + { + /* Stack global + arg: cs symbol name + + stack 32 bit value of symbol (high bits set to 0). */ + case ETIR__C_STA_GBL: + _bfd_vms_get_value (abfd, ptr, info, &op1, &h); + _bfd_vms_push (abfd, op1, alpha_vms_sym_to_ctxt (h)); + break; + + /* Stack longword + arg: lw value + + stack 32 bit value, sign extend to 64 bit. */ + case ETIR__C_STA_LW: + _bfd_vms_push (abfd, bfd_getl32 (ptr), RELC_NONE); + break; + + /* Stack quadword + arg: qw value + + stack 64 bit value of symbol. */ + case ETIR__C_STA_QW: + _bfd_vms_push (abfd, bfd_getl64 (ptr), RELC_NONE); + break; + + /* Stack psect base plus quadword offset + arg: lw section index + qw signed quadword offset (low 32 bits) + + Stack qw argument and section index + (see ETIR__C_STO_OFF, ETIR__C_CTL_SETRB). */ + case ETIR__C_STA_PQ: + { + int psect; + + psect = bfd_getl32 (ptr); + if ((unsigned int) psect >= PRIV (section_count)) + { + (*_bfd_error_handler) (_("bad section index in %s"), + _bfd_vms_etir_name (cmd)); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + op1 = bfd_getl64 (ptr + 4); + _bfd_vms_push (abfd, op1, psect | RELC_SEC_BASE); + } + break; + + case ETIR__C_STA_LI: + case ETIR__C_STA_MOD: + case ETIR__C_STA_CKARG: + (*_bfd_error_handler) (_("unsupported STA cmd %s"), + _bfd_vms_etir_name (cmd)); + return FALSE; + break; + + /* Store byte: pop stack, write byte + arg: -. */ + case ETIR__C_STO_B: + _bfd_vms_pop (abfd, &op1, &rel1); + if (rel1 != RELC_NONE) + goto bad_context; + image_write_b (abfd, (unsigned int) op1 & 0xff); + break; + + /* Store word: pop stack, write word + arg: -. */ + case ETIR__C_STO_W: + _bfd_vms_pop (abfd, &op1, &rel1); + if (rel1 != RELC_NONE) + goto bad_context; + image_write_w (abfd, (unsigned int) op1 & 0xffff); + break; + + /* Store longword: pop stack, write longword + arg: -. */ + case ETIR__C_STO_LW: + _bfd_vms_pop (abfd, &op1, &rel1); + if (rel1 & RELC_SEC_BASE) + { + op1 = alpha_vms_fix_sec_rel (abfd, info, rel1, op1); + rel1 = RELC_REL; + } + else if (rel1 & RELC_SHR_BASE) + { + alpha_vms_add_lw_fixup (info, rel1 & RELC_MASK, op1); + rel1 = RELC_NONE; + } + if (rel1 != RELC_NONE) + { + if (rel1 != RELC_REL) + abort (); + alpha_vms_add_lw_reloc (info); + } + image_write_l (abfd, op1); + break; + + /* Store quadword: pop stack, write quadword + arg: -. */ + case ETIR__C_STO_QW: + _bfd_vms_pop (abfd, &op1, &rel1); + if (rel1 & RELC_SEC_BASE) + { + op1 = alpha_vms_fix_sec_rel (abfd, info, rel1, op1); + rel1 = RELC_REL; + } + else if (rel1 & RELC_SHR_BASE) + abort (); + if (rel1 != RELC_NONE) + { + if (rel1 != RELC_REL) + abort (); + alpha_vms_add_qw_reloc (info); + } + image_write_q (abfd, op1); + break; + + /* Store immediate repeated: pop stack for repeat count + arg: lw byte count + da data. */ + case ETIR__C_STO_IMMR: + { + int size; + + size = bfd_getl32 (ptr); + _bfd_vms_pop (abfd, &op1, &rel1); + if (rel1 != RELC_NONE) + goto bad_context; + while (op1-- > 0) + image_write (abfd, ptr + 4, size); + } + break; + + /* Store global: write symbol value + arg: cs global symbol name. */ + case ETIR__C_STO_GBL: + _bfd_vms_get_value (abfd, ptr, info, &op1, &h); + if (h && h->sym) + { + if (h->sym->typ == EGSD__C_SYMG) + { + alpha_vms_add_fixup_qr + (info, abfd, h->sym->owner, h->sym->symbol_vector); + op1 = 0; + } + else + { + op1 = alpha_vms_get_sym_value (h->sym->section, + h->sym->value, h); + alpha_vms_add_qw_reloc (info); + } + } + image_write_q (abfd, op1); + break; + + /* Store code address: write address of entry point + arg: cs global symbol name (procedure). */ + case ETIR__C_STO_CA: + _bfd_vms_get_value (abfd, ptr, info, &op1, &h); + if (h && h->sym) + { + if (h->sym->flags & EGSY__V_NORM) + { + /* That's really a procedure. */ + if (h->sym->typ == EGSD__C_SYMG) + { + alpha_vms_add_fixup_ca (info, abfd, h->sym->owner); + op1 = h->sym->symbol_vector; + } + else + { + op1 = alpha_vms_get_sym_value (h->sym->code_section, + h->sym->code_value, h); + alpha_vms_add_qw_reloc (info); + } + } + else + { + /* Symbol is not a procedure. */ + abort (); + } + } + image_write_q (abfd, op1); + break; + + /* Store offset to psect: pop stack, add low 32 bits to base of psect + arg: none. */ + case ETIR__C_STO_OFF: + _bfd_vms_pop (abfd, &op1, &rel1); + + if (!(rel1 & RELC_SEC_BASE)) + abort (); + + op1 = alpha_vms_fix_sec_rel (abfd, info, rel1, op1); + rel1 = RELC_REL; + image_write_q (abfd, op1); + break; + + /* Store immediate + arg: lw count of bytes + da data. */ + case ETIR__C_STO_IMM: + { + int size; + + size = bfd_getl32 (ptr); + image_write (abfd, ptr + 4, size); + } + break; + + /* This code is 'reserved to digital' according to the openVMS + linker manual, however it is generated by the DEC C compiler + and defined in the include file. + FIXME, since the following is just a guess + store global longword: store 32bit value of symbol + arg: cs symbol name. */ + case ETIR__C_STO_GBL_LW: + _bfd_vms_get_value (abfd, ptr, info, &op1, &h); +#if 0 + abort (); +#endif + image_write_l (abfd, op1); + break; + + case ETIR__C_STO_RB: + case ETIR__C_STO_AB: + case ETIR__C_STO_LP_PSB: + (*_bfd_error_handler) (_("%s: not supported"), + _bfd_vms_etir_name (cmd)); + return FALSE; + break; + case ETIR__C_STO_HINT_GBL: + case ETIR__C_STO_HINT_PS: + (*_bfd_error_handler) (_("%s: not implemented"), + _bfd_vms_etir_name (cmd)); + return FALSE; + break; + + /* 200 Store-conditional Linkage Pair + arg: none. */ + case ETIR__C_STC_LP: + + /* 202 Store-conditional Address at global address + lw linkage index + cs global name. */ + + case ETIR__C_STC_GBL: + + /* 203 Store-conditional Code Address at global address + lw linkage index + cs procedure name. */ + case ETIR__C_STC_GCA: + + /* 204 Store-conditional Address at psect + offset + lw linkage index + lw psect index + qw offset. */ + case ETIR__C_STC_PS: + (*_bfd_error_handler) (_("%s: not supported"), + _bfd_vms_etir_name (cmd)); + return FALSE; + break; + + /* 201 Store-conditional Linkage Pair with Procedure Signature + lw linkage index + cs procedure name + by signature length + da signature. */ + + case ETIR__C_STC_LP_PSB: + _bfd_vms_get_value (abfd, ptr + 4, info, &op1, &h); + if (h && h->sym) + { + if (h->sym->typ == EGSD__C_SYMG) + { + alpha_vms_add_fixup_lp (info, abfd, h->sym->owner); + op1 = h->sym->symbol_vector; + op2 = 0; + } + else + { + op1 = alpha_vms_get_sym_value (h->sym->code_section, + h->sym->code_value, h); + op2 = alpha_vms_get_sym_value (h->sym->section, + h->sym->value, h); + } + } + else + { + /* Undefined symbol. */ + op1 = 0; + op2 = 0; + } + image_write_q (abfd, op1); + image_write_q (abfd, op2); + break; + + /* 205 Store-conditional NOP at address of global + arg: none. */ + case ETIR__C_STC_NOP_GBL: + /* ALPHA_R_NOP */ + + /* 207 Store-conditional BSR at global address + arg: none. */ + + case ETIR__C_STC_BSR_GBL: + /* ALPHA_R_BSR */ + + /* 209 Store-conditional LDA at global address + arg: none. */ + + case ETIR__C_STC_LDA_GBL: + /* ALPHA_R_LDA */ + + /* 211 Store-conditional BSR or Hint at global address + arg: none. */ + + case ETIR__C_STC_BOH_GBL: + /* Currentl ignored. */ + break; + + /* 213 Store-conditional NOP,BSR or HINT at global address + arg: none. */ + + case ETIR__C_STC_NBH_GBL: + + /* 206 Store-conditional NOP at pect + offset + arg: none. */ + + case ETIR__C_STC_NOP_PS: + + /* 208 Store-conditional BSR at pect + offset + arg: none. */ + + case ETIR__C_STC_BSR_PS: + + /* 210 Store-conditional LDA at psect + offset + arg: none. */ + + case ETIR__C_STC_LDA_PS: + + /* 212 Store-conditional BSR or Hint at pect + offset + arg: none. */ + + case ETIR__C_STC_BOH_PS: + + /* 214 Store-conditional NOP, BSR or HINT at psect + offset + arg: none. */ + case ETIR__C_STC_NBH_PS: + (*_bfd_error_handler) ("%s: not supported", + _bfd_vms_etir_name (cmd)); + return FALSE; + break; + + /* Det relocation base: pop stack, set image location counter + arg: none. */ + case ETIR__C_CTL_SETRB: + _bfd_vms_pop (abfd, &op1, &rel1); + if (!(rel1 & RELC_SEC_BASE)) + abort (); + image_set_ptr (abfd, op1, rel1 & RELC_MASK, info); + break; + + /* Augment relocation base: increment image location counter by offset + arg: lw offset value. */ + case ETIR__C_CTL_AUGRB: + op1 = bfd_getl32 (ptr); + image_inc_ptr (abfd, op1); + break; + + /* Define location: pop index, save location counter under index + arg: none. */ + case ETIR__C_CTL_DFLOC: + _bfd_vms_pop (abfd, &op1, &rel1); + if (rel1 != RELC_NONE) + goto bad_context; + dst_define_location (abfd, op1); + break; + + /* Set location: pop index, restore location counter from index + arg: none. */ + case ETIR__C_CTL_STLOC: + _bfd_vms_pop (abfd, &op1, &rel1); + if (rel1 != RELC_NONE) + goto bad_context; + dst_restore_location (abfd, op1); + break; + + /* Stack defined location: pop index, push location counter from index + arg: none. */ + case ETIR__C_CTL_STKDL: + _bfd_vms_pop (abfd, &op1, &rel1); + if (rel1 != RELC_NONE) + goto bad_context; + _bfd_vms_push (abfd, dst_retrieve_location (abfd, op1), RELC_NONE); + break; + + case ETIR__C_OPR_NOP: /* No-op. */ + break; + + case ETIR__C_OPR_ADD: /* Add. */ + _bfd_vms_pop (abfd, &op1, &rel1); + _bfd_vms_pop (abfd, &op2, &rel2); + if (rel1 == RELC_NONE && rel2 != RELC_NONE) + rel1 = rel2; + else if (rel1 != RELC_NONE && rel2 != RELC_NONE) + goto bad_context; + _bfd_vms_push (abfd, op1 + op2, rel1); + break; + + case ETIR__C_OPR_SUB: /* Subtract. */ + _bfd_vms_pop (abfd, &op1, &rel1); + _bfd_vms_pop (abfd, &op2, &rel2); + if (rel1 == RELC_NONE && rel2 != RELC_NONE) + rel1 = rel2; + else if ((rel1 & RELC_SEC_BASE) && (rel2 & RELC_SEC_BASE)) + { + op1 = alpha_vms_fix_sec_rel (abfd, info, rel1, op1); + op2 = alpha_vms_fix_sec_rel (abfd, info, rel2, op2); + rel1 = RELC_NONE; + } + else if (rel1 != RELC_NONE && rel2 != RELC_NONE) + goto bad_context; + _bfd_vms_push (abfd, op2 - op1, rel1); + break; + + case ETIR__C_OPR_MUL: /* Multiply. */ + _bfd_vms_pop (abfd, &op1, &rel1); + _bfd_vms_pop (abfd, &op2, &rel2); + if (rel1 != RELC_NONE || rel2 != RELC_NONE) + goto bad_context; + _bfd_vms_push (abfd, op1 * op2, RELC_NONE); + break; + + case ETIR__C_OPR_DIV: /* Divide. */ + _bfd_vms_pop (abfd, &op1, &rel1); + _bfd_vms_pop (abfd, &op2, &rel2); + if (rel1 != RELC_NONE || rel2 != RELC_NONE) + goto bad_context; + if (op2 == 0) + _bfd_vms_push (abfd, 0, RELC_NONE); + else + _bfd_vms_push (abfd, op2 / op1, RELC_NONE); + break; + + case ETIR__C_OPR_AND: /* Logical AND. */ + _bfd_vms_pop (abfd, &op1, &rel1); + _bfd_vms_pop (abfd, &op2, &rel2); + if (rel1 != RELC_NONE || rel2 != RELC_NONE) + goto bad_context; + _bfd_vms_push (abfd, op1 & op2, RELC_NONE); + break; + + case ETIR__C_OPR_IOR: /* Logical inclusive OR. */ + _bfd_vms_pop (abfd, &op1, &rel1); + _bfd_vms_pop (abfd, &op2, &rel2); + if (rel1 != RELC_NONE || rel2 != RELC_NONE) + goto bad_context; + _bfd_vms_push (abfd, op1 | op2, RELC_NONE); + break; + + case ETIR__C_OPR_EOR: /* Logical exclusive OR. */ + _bfd_vms_pop (abfd, &op1, &rel1); + _bfd_vms_pop (abfd, &op2, &rel2); + if (rel1 != RELC_NONE || rel2 != RELC_NONE) + goto bad_context; + _bfd_vms_push (abfd, op1 ^ op2, RELC_NONE); + break; + + case ETIR__C_OPR_NEG: /* Negate. */ + _bfd_vms_pop (abfd, &op1, &rel1); + if (rel1 != RELC_NONE) + goto bad_context; + _bfd_vms_push (abfd, -op1, RELC_NONE); + break; + + case ETIR__C_OPR_COM: /* Complement. */ + _bfd_vms_pop (abfd, &op1, &rel1); + if (rel1 != RELC_NONE) + goto bad_context; + _bfd_vms_push (abfd, ~op1, RELC_NONE); + break; + + case ETIR__C_OPR_ASH: /* Arithmetic shift. */ + _bfd_vms_pop (abfd, &op1, &rel1); + _bfd_vms_pop (abfd, &op2, &rel2); + if (rel1 != RELC_NONE || rel2 != RELC_NONE) + { + bad_context: + (*_bfd_error_handler) (_("invalid use of %s with contexts"), + _bfd_vms_etir_name (cmd)); + return FALSE; + } + if ((int)op2 < 0) /* Shift right. */ + op1 >>= -(int)op2; + else /* Shift left. */ + op1 <<= (int)op2; + _bfd_vms_push (abfd, op1, RELC_NONE); /* FIXME: sym. */ + break; + + case ETIR__C_OPR_INSV: /* Insert field. */ + case ETIR__C_OPR_USH: /* Unsigned shift. */ + case ETIR__C_OPR_ROT: /* Rotate. */ + case ETIR__C_OPR_REDEF: /* Redefine symbol to current location. */ + case ETIR__C_OPR_DFLIT: /* Define a literal. */ + (*_bfd_error_handler) (_("%s: not supported"), + _bfd_vms_etir_name (cmd)); + return FALSE; + break; + + case ETIR__C_OPR_SEL: /* Select. */ + _bfd_vms_pop (abfd, &op1, &rel1); + if (op1 & 0x01L) + _bfd_vms_pop (abfd, &op1, &rel1); + else + { + _bfd_vms_pop (abfd, &op1, &rel1); + _bfd_vms_pop (abfd, &op2, &rel2); + _bfd_vms_push (abfd, op1, rel1); + } + break; + + default: + (*_bfd_error_handler) (_("reserved cmd %d"), cmd); + return FALSE; + break; + } + + ptr += cmd_length - 4; + } + + return TRUE; +} + +/* Process EDBG/ETBT record. + Return TRUE on success, FALSE on error */ + +static bfd_boolean +vms_slurp_debug (bfd *abfd) +{ + asection *section = PRIV (dst_section); + + if (section == NULL) + { + /* We have no way to find out beforehand how much debug info there + is in an object file, so pick an initial amount and grow it as + needed later. */ + flagword flags = SEC_HAS_CONTENTS | SEC_DEBUGGING | SEC_RELOC + | SEC_IN_MEMORY; + + section = bfd_make_section (abfd, "$DST$"); + if (!section) + return FALSE; + if (!bfd_set_section_flags (abfd, section, flags)) + return FALSE; + PRIV (dst_section) = section; + } + + PRIV (image_section) = section; + PRIV (image_offset) = section->size; + PRIV (image_autoextend) = FALSE; + + if (!_bfd_vms_slurp_etir (abfd, NULL)) + return FALSE; + + return TRUE; +} + +/* Process EDBG record. + Return TRUE on success, FALSE on error. */ + +static bfd_boolean +_bfd_vms_slurp_edbg (bfd *abfd) +{ + vms_debug2 ((2, "EDBG\n")); + + abfd->flags |= (HAS_DEBUG | HAS_LINENO); + + return vms_slurp_debug (abfd); +} + +/* Process ETBT record. + Return TRUE on success, FALSE on error. */ + +static bfd_boolean +_bfd_vms_slurp_etbt (bfd *abfd) +{ + vms_debug2 ((2, "ETBT\n")); + + abfd->flags |= HAS_LINENO; + + return vms_slurp_debug (abfd); +} + +/* Process EEOM record. + Return TRUE on success, FALSE on error. */ + +static bfd_boolean +_bfd_vms_slurp_eeom (bfd *abfd) +{ + struct vms_eeom *eeom = (struct vms_eeom *) PRIV (recrd.rec); + + vms_debug2 ((2, "EEOM\n")); + + PRIV (eom_data).eom_l_total_lps = bfd_getl32 (eeom->total_lps); + PRIV (eom_data).eom_w_comcod = bfd_getl16 (eeom->comcod); + if (PRIV (eom_data).eom_w_comcod > 1) + { + (*_bfd_error_handler) (_("Object module NOT error-free !\n")); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + PRIV (eom_data).eom_has_transfer = FALSE; + if (PRIV (recrd.rec_size) > 10) + { + PRIV (eom_data).eom_has_transfer = TRUE; + PRIV (eom_data).eom_b_tfrflg = eeom->tfrflg; + PRIV (eom_data).eom_l_psindx = bfd_getl32 (eeom->psindx); + PRIV (eom_data).eom_l_tfradr = bfd_getl32 (eeom->tfradr); + + abfd->start_address = PRIV (eom_data).eom_l_tfradr; + } + return TRUE; +} + +/* Slurp an ordered set of VMS object records. Return FALSE on error. */ + +static bfd_boolean +_bfd_vms_slurp_object_records (bfd * abfd) +{ + int err, new_type, type = -1; + + do + { + vms_debug2 ((7, "reading at %08lx\n", (unsigned long)bfd_tell (abfd))); + + new_type = _bfd_vms_get_object_record (abfd); + if (new_type < 0) + { + vms_debug2 ((2, "next_record failed\n")); + return FALSE; + } + + type = new_type; + + switch (type) + { + case EOBJ__C_EMH: + err = _bfd_vms_slurp_ehdr (abfd); + break; + case EOBJ__C_EEOM: + err = _bfd_vms_slurp_eeom (abfd); + break; + case EOBJ__C_EGSD: + err = _bfd_vms_slurp_egsd (abfd); + break; + case EOBJ__C_ETIR: + err = TRUE; /* _bfd_vms_slurp_etir (abfd); */ + break; + case EOBJ__C_EDBG: + err = _bfd_vms_slurp_edbg (abfd); + break; + case EOBJ__C_ETBT: + err = _bfd_vms_slurp_etbt (abfd); + break; + default: + err = FALSE; + } + if (err != TRUE) + { + vms_debug2 ((2, "slurp type %d failed\n", type)); + return FALSE; + } + } + while (type != EOBJ__C_EEOM); + + return TRUE; +} + +/* Initialize private data */ +static bfd_boolean +vms_initialize (bfd * abfd) +{ + bfd_size_type amt; + + amt = sizeof (struct vms_private_data_struct); + abfd->tdata.any = bfd_zalloc (abfd, amt); + if (abfd->tdata.any == NULL) + return FALSE; + + PRIV (recrd.file_format) = FF_UNKNOWN; + + amt = sizeof (struct stack_struct) * STACKSIZE; + PRIV (stack) = bfd_alloc (abfd, amt); + if (PRIV (stack) == NULL) + goto error_ret1; + + return TRUE; + + error_ret1: + bfd_release (abfd, abfd->tdata.any); + abfd->tdata.any = NULL; + return FALSE; +} + +/* Check the format for a file being read. + Return a (bfd_target *) if it's an object file or zero if not. */ + +static const struct bfd_target * +alpha_vms_object_p (bfd *abfd) +{ + PTR tdata_save = abfd->tdata.any; + unsigned int test_len; + unsigned char *buf; + + vms_debug2 ((1, "vms_object_p(%p)\n", abfd)); + + /* Allocate alpha-vms specific data. */ + if (!vms_initialize (abfd)) + goto error_ret; + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET)) + goto err_wrong_format; + + /* The first challenge with VMS is to discover the kind of the file. + + Image files (executable or shared images) are stored as a raw + stream of bytes (like on UNIX), but there is no magic number. + + Object files are written with RMS (record management service), ie + each records are preceeded by its length (on a word - 2 bytes), and + padded for word-alignment. That would be simple but when files + are transfered to a UNIX filesystem (using ftp), records are lost. + Only the raw content of the records are transfered. Fortunately, + the Alpha Object file format also store the length of the record + in the records. Is that clear ? */ + + /* Minimum is 6 bytes for objects (2 bytes size, 2 bytes record id, + 2 bytes size repeated) and 12 bytes for images (4 bytes major id, + 4 bytes minor id, 4 bytes length). */ + test_len = 12; + + /* Size the main buffer. */ + buf = (unsigned char *) bfd_malloc (test_len); + if (buf == NULL) + goto error_ret; + PRIV (recrd.buf) = buf; + PRIV (recrd.buf_size) = test_len; + + /* Initialize the record pointer. */ + PRIV (recrd.rec) = buf; + + if (bfd_bread (buf, test_len, abfd) != test_len) + { + bfd_set_error (bfd_error_file_truncated); + goto error_ret; + } + + /* Is it an image? */ + if ((bfd_getl32 (buf) == EIHD__K_MAJORID) + && (bfd_getl32 (buf + 4) == EIHD__K_MINORID)) + { + unsigned int to_read; + unsigned int read_so_far; + unsigned int remaining; + unsigned int eisd_offset, eihs_offset; + + /* Extract the header size. */ + PRIV (recrd.rec_size) = bfd_getl32 (buf + EIHD__L_SIZE); + + if (PRIV (recrd.rec_size) > PRIV (recrd.buf_size)) + { + buf = bfd_realloc_or_free (buf, PRIV (recrd.rec_size)); + + if (buf == NULL) + { + PRIV (recrd.buf) = NULL; + bfd_set_error (bfd_error_no_memory); + goto error_ret; + } + PRIV (recrd.buf) = buf; + PRIV (recrd.buf_size) = PRIV (recrd.rec_size); + } + + /* Read the remaining record. */ + remaining = PRIV (recrd.rec_size) - test_len; + to_read = MIN (VMS_BLOCK_SIZE - test_len, remaining); + read_so_far = test_len; + + while (remaining > 0) + { + if (bfd_bread (buf + read_so_far, to_read, abfd) != to_read) + { + bfd_set_error (bfd_error_file_truncated); + goto err_wrong_format; + } + + read_so_far += to_read; + remaining -= to_read; + + to_read = MIN (VMS_BLOCK_SIZE, remaining); + } + + /* Reset the record pointer. */ + PRIV (recrd.rec) = buf; + + vms_debug2 ((2, "file type is image\n")); + + if (_bfd_vms_slurp_eihd (abfd, &eisd_offset, &eihs_offset) != TRUE) + goto err_wrong_format; + + if (_bfd_vms_slurp_eisd (abfd, eisd_offset) != TRUE) + goto err_wrong_format; + + /* EIHS is optional. */ + if (eihs_offset != 0 && _bfd_vms_slurp_eihs (abfd, eihs_offset) != TRUE) + goto err_wrong_format; + } + else + { + int type; + + /* Assume it's a module and adjust record pointer if necessary. */ + maybe_adjust_record_pointer_for_object (abfd); + + /* But is it really a module? */ + if (bfd_getl16 (PRIV (recrd.rec)) <= EOBJ__C_MAXRECTYP + && bfd_getl16 (PRIV (recrd.rec) + 2) <= EOBJ__C_MAXRECSIZ) + { + if (vms_get_remaining_object_record (abfd, test_len) <= 0) + goto err_wrong_format; + + vms_debug2 ((2, "file type is module\n")); + + type = bfd_getl16 (PRIV (recrd.rec)); + if (type != EOBJ__C_EMH || _bfd_vms_slurp_ehdr (abfd) != TRUE) + goto err_wrong_format; + + if (_bfd_vms_slurp_object_records (abfd) != TRUE) + goto err_wrong_format; + } + else + goto err_wrong_format; + } + + /* Set arch_info to alpha. */ + + if (! bfd_default_set_arch_mach (abfd, bfd_arch_alpha, 0)) + goto err_wrong_format; + + return abfd->xvec; + + err_wrong_format: + bfd_set_error (bfd_error_wrong_format); + + error_ret: + if (PRIV (recrd.buf)) + free (PRIV (recrd.buf)); + if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL) + bfd_release (abfd, abfd->tdata.any); + abfd->tdata.any = tdata_save; + return NULL; +} + +/* Image write. */ + +static void +vector_grow1 (struct vector_type *vec, size_t elsz) +{ + if (vec->nbr_el + 1 < vec->max_el) + return; + + if (vec->max_el == 0) + { + vec->max_el = 16; + vec->els = bfd_malloc2 (vec->max_el, elsz); + } + else + { + vec->max_el *= 2; + vec->els = bfd_realloc2 (vec->els, vec->max_el, elsz); + } +} + +/* Bump ABFD file position to next block. */ + +static void +alpha_vms_file_position_block (bfd *abfd) +{ + /* Next block. */ + PRIV (file_pos) += VMS_BLOCK_SIZE - 1; + PRIV (file_pos) -= (PRIV (file_pos) % VMS_BLOCK_SIZE); +} + +static void +alpha_vms_swap_eisd_out (struct vms_internal_eisd_map *src, + struct vms_eisd *dst) +{ + bfd_putl32 (src->u.eisd.majorid, dst->majorid); + bfd_putl32 (src->u.eisd.minorid, dst->minorid); + bfd_putl32 (src->u.eisd.eisdsize, dst->eisdsize); + if (src->u.eisd.eisdsize <= EISD__K_LENEND) + return; + bfd_putl32 (src->u.eisd.secsize, dst->secsize); + bfd_putl64 (src->u.eisd.virt_addr, dst->virt_addr); + bfd_putl32 (src->u.eisd.flags, dst->flags); + bfd_putl32 (src->u.eisd.vbn, dst->vbn); + dst->pfc = src->u.eisd.pfc; + dst->matchctl = src->u.eisd.matchctl; + dst->type = src->u.eisd.type; + dst->fill_1 = 0; + if (src->u.eisd.flags & EISD__M_GBL) + { + bfd_putl32 (src->u.gbl_eisd.ident, dst->ident); + memcpy (dst->gblnam, src->u.gbl_eisd.gblnam, + src->u.gbl_eisd.gblnam[0] + 1); + } +} + +/* Append EISD to the list of extra eisd for ABFD. */ + +static void +alpha_vms_append_extra_eisd (bfd *abfd, struct vms_internal_eisd_map *eisd) +{ + eisd->next = NULL; + if (PRIV (gbl_eisd_head) == NULL) + PRIV (gbl_eisd_head) = eisd; + else + PRIV (gbl_eisd_tail)->next = eisd; + PRIV (gbl_eisd_tail) = eisd; +} + +static bfd_boolean +alpha_vms_create_eisd_for_shared (bfd *abfd, bfd *shrimg) +{ + struct vms_internal_eisd_map *eisd; + int namlen; + + namlen = strlen (PRIV2 (shrimg, hdr_data.hdr_t_name)); + if (namlen + 5 > EISD__K_GBLNAMLEN) + { + /* Won't fit. */ + return FALSE; + } + + eisd = bfd_alloc (abfd, sizeof (*eisd)); + if (eisd == NULL) + return FALSE; + + /* Fill the fields. */ + eisd->u.gbl_eisd.common.majorid = EISD__K_MAJORID; + eisd->u.gbl_eisd.common.minorid = EISD__K_MINORID; + eisd->u.gbl_eisd.common.eisdsize = (EISD__K_LEN + 4 + namlen + 5 + 3) & ~3; + eisd->u.gbl_eisd.common.secsize = VMS_BLOCK_SIZE; /* Must not be 0. */ + eisd->u.gbl_eisd.common.virt_addr = 0; + eisd->u.gbl_eisd.common.flags = EISD__M_GBL; + eisd->u.gbl_eisd.common.vbn = 0; + eisd->u.gbl_eisd.common.pfc = 0; + eisd->u.gbl_eisd.common.matchctl = PRIV2 (shrimg, matchctl); + eisd->u.gbl_eisd.common.type = EISD__K_SHRPIC; + + eisd->u.gbl_eisd.ident = PRIV2 (shrimg, ident); + eisd->u.gbl_eisd.gblnam[0] = namlen + 4; + memcpy (eisd->u.gbl_eisd.gblnam + 1, PRIV2 (shrimg, hdr_data.hdr_t_name), + namlen); + memcpy (eisd->u.gbl_eisd.gblnam + 1 + namlen, "_001", 4); + + /* Append it to the list. */ + alpha_vms_append_extra_eisd (abfd, eisd); + + return TRUE; +} + +static bfd_boolean +alpha_vms_create_eisd_for_section (bfd *abfd, asection *sec) +{ + struct vms_internal_eisd_map *eisd; + + /* Only for allocating section. */ + if (!(sec->flags & SEC_ALLOC)) + return TRUE; + + BFD_ASSERT (vms_section_data (sec)->eisd == NULL); + eisd = bfd_alloc (abfd, sizeof (*eisd)); + if (eisd == NULL) + return FALSE; + vms_section_data (sec)->eisd = eisd; + + /* Fill the fields. */ + eisd->u.eisd.majorid = EISD__K_MAJORID; + eisd->u.eisd.minorid = EISD__K_MINORID; + eisd->u.eisd.eisdsize = EISD__K_LEN; + eisd->u.eisd.secsize = + (sec->size + VMS_BLOCK_SIZE - 1) & ~(VMS_BLOCK_SIZE - 1); + eisd->u.eisd.virt_addr = sec->vma; + eisd->u.eisd.flags = 0; + eisd->u.eisd.vbn = 0; /* To be later defined. */ + eisd->u.eisd.pfc = 0; /* Default. */ + eisd->u.eisd.matchctl = EISD__K_MATALL; + eisd->u.eisd.type = EISD__K_NORMAL; + + if (sec->flags & SEC_CODE) + eisd->u.eisd.flags |= EISD__M_EXE; + if (!(sec->flags & SEC_READONLY)) + eisd->u.eisd.flags |= EISD__M_WRT | EISD__M_CRF; + + if (!(sec->flags & SEC_LOAD)) + { + eisd->u.eisd.flags |= EISD__M_DZRO; + eisd->u.eisd.flags &= ~EISD__M_CRF; + } + if (sec->flags & SEC_LINKER_CREATED) + { + if (strcmp (sec->name, "$FIXUP$") == 0) + eisd->u.eisd.flags |= EISD__M_FIXUPVEC; + } + + /* Append it to the list. */ + eisd->next = NULL; + if (PRIV (eisd_head) == NULL) + PRIV (eisd_head) = eisd; + else + PRIV (eisd_tail)->next = eisd; + PRIV (eisd_tail) = eisd; + + return TRUE; +} + +static bfd_boolean +alpha_vms_write_exec (bfd *abfd) +{ + struct vms_eihd eihd; + struct vms_eiha *eiha; + struct vms_eihi *eihi; + struct vms_eihs *eihs = NULL; + asection *sec; + struct vms_internal_eisd_map *first_eisd; + struct vms_internal_eisd_map *eisd; + asection *dst; + + PRIV (file_pos) = EIHD__C_LENGTH; + + memset (&eihd, 0, sizeof (eihd)); + memset (eihd.fill_2, 0xff, sizeof (eihd.fill_2)); + + bfd_putl32 (EIHD__K_MAJORID, eihd.majorid); + bfd_putl32 (EIHD__K_MINORID, eihd.minorid); + + bfd_putl32 (sizeof (eihd), eihd.size); + bfd_putl32 (0, eihd.isdoff); + bfd_putl32 (0, eihd.activoff); + bfd_putl32 (0, eihd.symdbgoff); + bfd_putl32 (0, eihd.imgidoff); + bfd_putl32 (0, eihd.patchoff); + bfd_putl64 (0, eihd.iafva); + bfd_putl32 (0, eihd.version_array_off); + + bfd_putl32 (EIHD__K_EXE, eihd.imgtype); + bfd_putl32 (0, eihd.subtype); + + bfd_putl32 (0, eihd.imgiocnt); + bfd_putl32 (-1, eihd.privreqs); + bfd_putl32 (-1, eihd.privreqs + 4); + + bfd_putl32 ((sizeof (eihd) + VMS_BLOCK_SIZE - 1) / VMS_BLOCK_SIZE, + eihd.hdrblkcnt); + bfd_putl32 (0, eihd.lnkflags); + bfd_putl32 (0, eihd.ident); + bfd_putl32 (0, eihd.sysver); + + eihd.matchctl = 0; + bfd_putl32 (0, eihd.symvect_size); + bfd_putl32 (16, eihd.virt_mem_block_size); + bfd_putl32 (0, eihd.ext_fixup_off); + bfd_putl32 (0, eihd.noopt_psect_off); + bfd_putl32 (-1, eihd.alias); + + /* Alloc EIHA. */ + eiha = (struct vms_eiha *)((char *) &eihd + PRIV (file_pos)); + bfd_putl32 (PRIV (file_pos), eihd.activoff); + PRIV (file_pos) += sizeof (struct vms_eiha); + + bfd_putl32 (sizeof (struct vms_eiha), eiha->size); + bfd_putl32 (0, eiha->spare); + bfd_putl32 (0x00000340, eiha->tfradr1); /* SYS$IMGACT */ + bfd_putl32 (0xffffffff, eiha->tfradr1_h); + bfd_putl64 (bfd_get_start_address (abfd), eiha->tfradr2); + bfd_putl64 (0, eiha->tfradr3); + bfd_putl64 (0, eiha->tfradr4); + bfd_putl64 (0, eiha->inishr); + + /* Alloc EIHI. */ + eihi = (struct vms_eihi *)((char *) &eihd + PRIV (file_pos)); + bfd_putl32 (PRIV (file_pos), eihd.imgidoff); + PRIV (file_pos) += sizeof (struct vms_eihi); + + bfd_putl32 (EIHI__K_MAJORID, eihi->majorid); + bfd_putl32 (EIHI__K_MINORID, eihi->minorid); + { + char *module; + unsigned int len; + + module = vms_get_module_name (bfd_get_filename (abfd), TRUE); + len = strlen (module); + if (len > sizeof (eihi->imgnam) - 1) + len = sizeof (eihi->imgnam) - 1; + eihi->imgnam[0] = len; + memcpy (eihi->imgnam + 1, module, len); + free (module); + } + bfd_putl32 (0, eihi->linktime + 0); + bfd_putl32 (0, eihi->linktime + 4); + eihi->imgid[0] = 0; + eihi->linkid[0] = 0; + eihi->imgbid[0] = 0; + + /* Alloc EIHS. */ + dst = bfd_get_section_by_name (abfd, "$DST$"); + if (dst == NULL || dst->size == 0) + dst = bfd_get_section_by_name (abfd, "$TBT$"); + if (dst != NULL && dst->size != 0) + { + eihs = (struct vms_eihs *)((char *) &eihd + PRIV (file_pos)); + bfd_putl32 (PRIV (file_pos), eihd.symdbgoff); + PRIV (file_pos) += sizeof (struct vms_eihs); + + bfd_putl32 (EIHS__K_MAJORID, eihs->majorid); + bfd_putl32 (EIHS__K_MINORID, eihs->minorid); + bfd_putl32 (0, eihs->dstvbn); + bfd_putl32 (0, eihs->dstsize); + bfd_putl32 (0, eihs->gstvbn); + bfd_putl32 (0, eihs->gstsize); + bfd_putl32 (0, eihs->dmtvbn); + bfd_putl32 (0, eihs->dmtsize); + } + + /* One per section. */ + for (sec = abfd->sections; sec; sec = sec->next) + { + if (!alpha_vms_create_eisd_for_section (abfd, sec)) + return FALSE; + } + + /* Merge section EIDS which extra ones. */ + if (PRIV (eisd_tail)) + PRIV (eisd_tail)->next = PRIV (gbl_eisd_head); + else + PRIV (eisd_head) = PRIV (gbl_eisd_head); + if (PRIV (gbl_eisd_tail)) + PRIV (eisd_tail) = PRIV (gbl_eisd_tail); + + first_eisd = PRIV (eisd_head); + + /* Add end of eisd. */ + if (first_eisd) + { + eisd = bfd_zalloc (abfd, sizeof (*eisd)); + if (eisd == NULL) + return FALSE; + eisd->u.eisd.majorid = 0; + eisd->u.eisd.minorid = 0; + eisd->u.eisd.eisdsize = 0; + alpha_vms_append_extra_eisd (abfd, eisd); + } + + /* Place EISD in the file. */ + for (eisd = first_eisd; eisd; eisd = eisd->next) + { + file_ptr room = VMS_BLOCK_SIZE - (PRIV (file_pos) % VMS_BLOCK_SIZE); + + /* First block is a little bit special: there is a word at the end. */ + if (PRIV (file_pos) < VMS_BLOCK_SIZE && room > 2) + room -= 2; + if (room < eisd->u.eisd.eisdsize + EISD__K_LENEND) + alpha_vms_file_position_block (abfd); + + eisd->file_pos = PRIV (file_pos); + PRIV (file_pos) += eisd->u.eisd.eisdsize; + + if (eisd->u.eisd.flags & EISD__M_FIXUPVEC) + bfd_putl64 (eisd->u.eisd.virt_addr, eihd.iafva); + } + + if (first_eisd != NULL) + { + bfd_putl32 (first_eisd->file_pos, eihd.isdoff); + /* Real size of end of eisd marker. */ + PRIV (file_pos) += EISD__K_LENEND; + } + + bfd_putl32 (PRIV (file_pos), eihd.size); + bfd_putl32 ((PRIV (file_pos) + VMS_BLOCK_SIZE - 1) / VMS_BLOCK_SIZE, + eihd.hdrblkcnt); + + /* Place sections. */ + for (sec = abfd->sections; sec; sec = sec->next) + { + if (!(sec->flags & SEC_HAS_CONTENTS)) + continue; + + eisd = vms_section_data (sec)->eisd; + + /* Align on a block. */ + alpha_vms_file_position_block (abfd); + sec->filepos = PRIV (file_pos); + + if (eisd != NULL) + eisd->u.eisd.vbn = (sec->filepos / VMS_BLOCK_SIZE) + 1; + + PRIV (file_pos) += sec->size; + } + + if (eihs != NULL && dst != NULL) + { + bfd_putl32 ((dst->filepos / VMS_BLOCK_SIZE) + 1, eihs->dstvbn); + bfd_putl32 (dst->size, eihs->dstsize); + } + + /* Write EISD in hdr. */ + for (eisd = first_eisd; eisd && eisd->file_pos < VMS_BLOCK_SIZE; + eisd = eisd->next) + alpha_vms_swap_eisd_out + (eisd, (struct vms_eisd *)((char *)&eihd + eisd->file_pos)); + + /* Write first block. */ + if (bfd_bwrite (&eihd, sizeof (eihd), abfd) != sizeof (eihd)) + return FALSE; + + /* Write remaining eisd. */ + if (eisd != NULL) + { + unsigned char blk[VMS_BLOCK_SIZE]; + struct vms_internal_eisd_map *next_eisd; + + memset (blk, 0xff, sizeof (blk)); + while (eisd != NULL) + { + alpha_vms_swap_eisd_out + (eisd, + (struct vms_eisd *)(blk + (eisd->file_pos % VMS_BLOCK_SIZE))); + + next_eisd = eisd->next; + if (next_eisd == NULL + || (next_eisd->file_pos / VMS_BLOCK_SIZE + != eisd->file_pos / VMS_BLOCK_SIZE)) + { + if (bfd_bwrite (blk, sizeof (blk), abfd) != sizeof (blk)) + return FALSE; + + memset (blk, 0xff, sizeof (blk)); + } + eisd = next_eisd; + } + } + + /* Write sections. */ + for (sec = abfd->sections; sec; sec = sec->next) + { + unsigned char blk[VMS_BLOCK_SIZE]; + bfd_size_type len; + + if (sec->size == 0 || !(sec->flags & SEC_HAS_CONTENTS)) + continue; + if (bfd_bwrite (sec->contents, sec->size, abfd) != sec->size) + return FALSE; + + /* Pad. */ + len = VMS_BLOCK_SIZE - sec->size % VMS_BLOCK_SIZE; + if (len != VMS_BLOCK_SIZE) + { + memset (blk, 0, len); + if (bfd_bwrite (blk, len, abfd) != len) + return FALSE; + } + } + + return TRUE; +} + +/* Object write. */ + +/* This hash routine borrowed from GNU-EMACS, and strengthened + slightly. ERY. */ + +static int +hash_string (const char *ptr) +{ + const unsigned char *p = (unsigned char *) ptr; + const unsigned char *end = p + strlen (ptr); + unsigned char c; + int hash = 0; + + while (p != end) + { + c = *p++; + hash = ((hash << 3) + (hash << 15) + (hash >> 28) + c); + } + return hash; +} + +/* Generate a length-hashed VMS symbol name (limited to maxlen chars). */ + +static char * +_bfd_vms_length_hash_symbol (bfd *abfd, const char *in, int maxlen) +{ + unsigned long result; + int in_len; + char *new_name; + const char *old_name; + int i; + static char outbuf[EOBJ__C_SYMSIZ + 1]; + char *out = outbuf; + +#if VMS_DEBUG + vms_debug (4, "_bfd_vms_length_hash_symbol \"%s\"\n", in); +#endif + + if (maxlen > EOBJ__C_SYMSIZ) + maxlen = EOBJ__C_SYMSIZ; + + /* Save this for later. */ + new_name = out; + + /* We may need to truncate the symbol, save the hash for later. */ + in_len = strlen (in); + + result = (in_len > maxlen) ? hash_string (in) : 0; + + old_name = in; + + /* Do the length checking. */ + if (in_len <= maxlen) + i = in_len; + else + { + if (PRIV (flag_hash_long_names)) + i = maxlen - 9; + else + i = maxlen; + } + + strncpy (out, in, (size_t) i); + in += i; + out += i; + + if ((in_len > maxlen) + && PRIV (flag_hash_long_names)) + sprintf (out, "_%08lx", result); + else + *out = 0; + +#if VMS_DEBUG + vms_debug (4, "--> [%d]\"%s\"\n", (int)strlen (outbuf), outbuf); +#endif + + if (in_len > maxlen + && PRIV (flag_hash_long_names) + && PRIV (flag_show_after_trunc)) + printf (_("Symbol %s replaced by %s\n"), old_name, new_name); + + return outbuf; +} + +/* Write section and symbol directory of bfd abfd. Return FALSE on error. */ + +static bfd_boolean +_bfd_vms_write_egsd (bfd *abfd) +{ + asection *section; + asymbol *symbol; + unsigned int symnum; + int last_index = -1; + char dummy_name[10]; + char *sname; + flagword new_flags, old_flags; + int abs_section_index = 0; + struct vms_rec_wr *recwr = &PRIV (recwr); + + vms_debug2 ((2, "vms_write_gsd\n")); + + /* Output sections. */ + section = abfd->sections; + vms_debug2 ((3, "%d sections found\n", abfd->section_count)); + + /* Egsd is quadword aligned. */ + _bfd_vms_output_alignment (recwr, 8); + + _bfd_vms_output_begin (recwr, EOBJ__C_EGSD); + _bfd_vms_output_long (recwr, 0); + + while (section != 0) + { + vms_debug2 ((3, "Section #%d %s, %d bytes\n", + section->index, section->name, (int)section->size)); + + /* Don't write out the VMS debug info section since it is in the + ETBT and EDBG sections in etir. */ + if (!strcmp (section->name, ".vmsdebug")) + goto done; + + /* 13 bytes egsd, max 31 chars name -> should be 44 bytes. */ + if (_bfd_vms_output_check (recwr, 64) < 0) + { + _bfd_vms_output_end (abfd, recwr); + _bfd_vms_output_begin (recwr, EOBJ__C_EGSD); + _bfd_vms_output_long (recwr, 0); + } + + /* Create dummy sections to keep consecutive indices. */ + while (section->index - last_index > 1) + { + vms_debug2 ((3, "index %d, last %d\n", section->index, last_index)); + _bfd_vms_output_begin_subrec (recwr, EGSD__C_PSC); + _bfd_vms_output_short (recwr, 0); + _bfd_vms_output_short (recwr, 0); + _bfd_vms_output_long (recwr, 0); + sprintf (dummy_name, ".DUMMY%02d", last_index); + _bfd_vms_output_counted (recwr, dummy_name); + _bfd_vms_output_end_subrec (recwr); + last_index++; + } + + /* Don't know if this is necessary for the linker but for now it keeps + vms_slurp_gsd happy */ + sname = (char *)section->name; + if (*sname == '.') + { + sname++; + if ((*sname == 't') && (strcmp (sname, "text") == 0)) + sname = EVAX_CODE_NAME; + else if ((*sname == 'd') && (strcmp (sname, "data") == 0)) + sname = EVAX_DATA_NAME; + else if ((*sname == 'b') && (strcmp (sname, "bss") == 0)) + sname = EVAX_BSS_NAME; + else if ((*sname == 'l') && (strcmp (sname, "link") == 0)) + sname = EVAX_LINK_NAME; + else if ((*sname == 'r') && (strcmp (sname, "rdata") == 0)) + sname = EVAX_READONLY_NAME; + else if ((*sname == 'l') && (strcmp (sname, "literal") == 0)) + sname = EVAX_LITERAL_NAME; + else if ((*sname == 'l') && (strcmp (sname, "literals") == 0)) + { + sname = EVAX_LITERALS_NAME; + abs_section_index = section->index; + } + else if ((*sname == 'c') && (strcmp (sname, "comm") == 0)) + sname = EVAX_COMMON_NAME; + else if ((*sname == 'l') && (strcmp (sname, "lcomm") == 0)) + sname = EVAX_LOCAL_NAME; + } + else + sname = _bfd_vms_length_hash_symbol (abfd, sname, EOBJ__C_SECSIZ); + + _bfd_vms_output_begin_subrec (recwr, EGSD__C_PSC); + _bfd_vms_output_short (recwr, section->alignment_power & 0xff); + + if (bfd_is_com_section (section)) + new_flags = (EGPS__V_OVR | EGPS__V_REL | EGPS__V_GBL | EGPS__V_RD + | EGPS__V_WRT | EGPS__V_NOMOD | EGPS__V_COM); + else + new_flags = vms_esecflag_by_name (evax_section_flags, sname, + section->size > 0); + + /* Modify them as directed. */ + if (section->flags & SEC_READONLY) + new_flags &= ~EGPS__V_WRT; + + new_flags &= ~vms_section_data (section)->no_flags; + new_flags |= vms_section_data (section)->flags; + + vms_debug2 ((3, "sec flags %x\n", section->flags)); + vms_debug2 ((3, "new_flags %x, _raw_size %lu\n", + new_flags, (unsigned long)section->size)); + + _bfd_vms_output_short (recwr, new_flags); + _bfd_vms_output_long (recwr, (unsigned long) section->size); + _bfd_vms_output_counted (recwr, sname); + _bfd_vms_output_end_subrec (recwr); + + last_index = section->index; +done: + section = section->next; + } + + /* Output symbols. */ + vms_debug2 ((3, "%d symbols found\n", abfd->symcount)); + + bfd_set_start_address (abfd, (bfd_vma) -1); + + for (symnum = 0; symnum < abfd->symcount; symnum++) + { + char *hash; + + symbol = abfd->outsymbols[symnum]; + if (*(symbol->name) == '_') + { + if (strcmp (symbol->name, "__main") == 0) + bfd_set_start_address (abfd, (bfd_vma)symbol->value); + } + old_flags = symbol->flags; + + if (old_flags & BSF_FILE) + continue; + + if ((old_flags & BSF_GLOBAL) == 0 /* Not xdef... */ + && !bfd_is_und_section (symbol->section) /* and not xref... */ + && !((old_flags & BSF_SECTION_SYM) != 0 /* and not LIB$INITIALIZE. */ + && strcmp (symbol->section->name, "LIB$INITIALIZE") == 0)) + continue; + + /* 13 bytes egsd, max 64 chars name -> should be 77 bytes. */ + if (_bfd_vms_output_check (recwr, 80) < 0) + { + _bfd_vms_output_end (abfd, recwr); + _bfd_vms_output_begin (recwr, EOBJ__C_EGSD); + _bfd_vms_output_long (recwr, 0); + } + + _bfd_vms_output_begin_subrec (recwr, EGSD__C_SYM); + + /* Data type, alignment. */ + _bfd_vms_output_short (recwr, 0); + + new_flags = 0; + + if (old_flags & BSF_WEAK) + new_flags |= EGSY__V_WEAK; + if (bfd_is_com_section (symbol->section)) /* .comm */ + new_flags |= (EGSY__V_WEAK | EGSY__V_COMM); + + if (old_flags & BSF_FUNCTION) + { + new_flags |= EGSY__V_NORM; + new_flags |= EGSY__V_REL; + } + if (old_flags & BSF_GLOBAL) + { + new_flags |= EGSY__V_DEF; + if (!bfd_is_abs_section (symbol->section)) + new_flags |= EGSY__V_REL; + } + _bfd_vms_output_short (recwr, new_flags); + + if (old_flags & BSF_GLOBAL) + { + /* Symbol definition. */ + bfd_vma code_address = 0; + unsigned long ca_psindx = 0; + unsigned long psindx; + + if ((old_flags & BSF_FUNCTION) && symbol->udata.p != NULL) + { + asymbol *sym; + + sym = ((struct evax_private_udata_struct *)symbol->udata.p)->enbsym; + code_address = sym->value; + ca_psindx = sym->section->index; + } + if (bfd_is_abs_section (symbol->section)) + psindx = abs_section_index; + else + psindx = symbol->section->index; + + _bfd_vms_output_quad (recwr, symbol->value); + _bfd_vms_output_quad (recwr, code_address); + _bfd_vms_output_long (recwr, ca_psindx); + _bfd_vms_output_long (recwr, psindx); + } + hash = _bfd_vms_length_hash_symbol (abfd, symbol->name, EOBJ__C_SYMSIZ); + _bfd_vms_output_counted (recwr, hash); + + _bfd_vms_output_end_subrec (recwr); + + } + + _bfd_vms_output_alignment (recwr, 8); + _bfd_vms_output_end (abfd, recwr); + + return TRUE; +} + +/* Write object header for bfd abfd. Return FALSE on error. */ + +static bfd_boolean +_bfd_vms_write_ehdr (bfd *abfd) +{ + asymbol *symbol; + unsigned int symnum; + int had_case = 0; + int had_file = 0; + char version [256]; + struct vms_rec_wr *recwr = &PRIV (recwr); + + vms_debug2 ((2, "vms_write_ehdr (%p)\n", abfd)); + + _bfd_vms_output_alignment (recwr, 2); + + /* EMH. */ + _bfd_vms_output_begin (recwr, EOBJ__C_EMH); + _bfd_vms_output_short (recwr, EMH__C_MHD); + _bfd_vms_output_short (recwr, EOBJ__C_STRLVL); + _bfd_vms_output_long (recwr, 0); + _bfd_vms_output_long (recwr, 0); + _bfd_vms_output_long (recwr, MAX_OUTREC_SIZE); + + /* Create module name from filename. */ + if (bfd_get_filename (abfd) != 0) + { + char *module = vms_get_module_name (bfd_get_filename (abfd), TRUE); + _bfd_vms_output_counted (recwr, module); + free (module); + } + else + _bfd_vms_output_counted (recwr, "NONAME"); + + _bfd_vms_output_counted (recwr, BFD_VERSION_STRING); + _bfd_vms_output_dump (recwr, get_vms_time_string (), EMH_DATE_LENGTH); + _bfd_vms_output_fill (recwr, 0, EMH_DATE_LENGTH); + _bfd_vms_output_end (abfd, recwr); + + /* LMN. */ + _bfd_vms_output_begin (recwr, EOBJ__C_EMH); + _bfd_vms_output_short (recwr, EMH__C_LNM); + snprintf (version, sizeof (version), "GAS BFD v%s", BFD_VERSION_STRING); + _bfd_vms_output_dump (recwr, (unsigned char *)version, strlen (version)); + _bfd_vms_output_end (abfd, recwr); + + /* SRC. */ + _bfd_vms_output_begin (recwr, EOBJ__C_EMH); + _bfd_vms_output_short (recwr, EMH__C_SRC); + + for (symnum = 0; symnum < abfd->symcount; symnum++) + { + symbol = abfd->outsymbols[symnum]; + + if (symbol->flags & BSF_FILE) + { + if (CONST_STRNEQ ((char *)symbol->name, "<CASE:")) + { + PRIV (flag_hash_long_names) = symbol->name[6] - '0'; + PRIV (flag_show_after_trunc) = symbol->name[7] - '0'; + + if (had_file) + break; + had_case = 1; + continue; + } + + _bfd_vms_output_dump (recwr, (unsigned char *) symbol->name, + (int) strlen (symbol->name)); + if (had_case) + break; + had_file = 1; + } + } + + if (symnum == abfd->symcount) + _bfd_vms_output_dump (recwr, (unsigned char *) STRING_COMMA_LEN ("noname")); + + _bfd_vms_output_end (abfd, recwr); + + /* TTL. */ + _bfd_vms_output_begin (recwr, EOBJ__C_EMH); + _bfd_vms_output_short (recwr, EMH__C_TTL); + _bfd_vms_output_dump (recwr, (unsigned char *) STRING_COMMA_LEN ("TTL")); + _bfd_vms_output_end (abfd, recwr); + + /* CPR. */ + _bfd_vms_output_begin (recwr, EOBJ__C_EMH); + _bfd_vms_output_short (recwr, EMH__C_CPR); + _bfd_vms_output_dump (recwr, + (unsigned char *)"GNU BFD ported by Klaus Kämpf 1994-1996", + 39); + _bfd_vms_output_end (abfd, recwr); + + return TRUE; +} + +/* Part 4.6, relocations. */ + + +/* WRITE ETIR SECTION + + This is still under construction and therefore not documented. */ + +/* Close the etir/etbt record. */ + +static void +end_etir_record (bfd * abfd) +{ + struct vms_rec_wr *recwr = &PRIV (recwr); + + _bfd_vms_output_end (abfd, recwr); +} + +static void +start_etir_or_etbt_record (bfd *abfd, asection *section, bfd_vma offset) +{ + struct vms_rec_wr *recwr = &PRIV (recwr); + + if (section->name[0] == '.' && section->name[1] == 'v' + && !strcmp (section->name, ".vmsdebug")) + { + _bfd_vms_output_begin (recwr, EOBJ__C_ETBT); + + if (offset == 0) + { + /* Push start offset. */ + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_LW); + _bfd_vms_output_long (recwr, (unsigned long) 0); + _bfd_vms_output_end_subrec (recwr); + + /* Set location. */ + _bfd_vms_output_begin_subrec (recwr, ETIR__C_CTL_DFLOC); + _bfd_vms_output_end_subrec (recwr); + } + } + else + { + _bfd_vms_output_begin (recwr, EOBJ__C_ETIR); + + if (offset == 0) + { + /* Push start offset. */ + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_PQ); + _bfd_vms_output_long (recwr, (unsigned long) section->index); + _bfd_vms_output_quad (recwr, offset); + _bfd_vms_output_end_subrec (recwr); + + /* Start = pop (). */ + _bfd_vms_output_begin_subrec (recwr, ETIR__C_CTL_SETRB); + _bfd_vms_output_end_subrec (recwr); + } + } +} + +/* Output a STO_IMM command for SSIZE bytes of data from CPR at virtual + address VADDR in section specified by SEC_INDEX and NAME. */ + +static void +sto_imm (bfd *abfd, asection *section, + bfd_size_type ssize, unsigned char *cptr, bfd_vma vaddr) +{ + bfd_size_type size; + struct vms_rec_wr *recwr = &PRIV (recwr); + +#if VMS_DEBUG + _bfd_vms_debug (8, "sto_imm %d bytes\n", (int) ssize); + _bfd_hexdump (9, cptr, (int) ssize, (int) vaddr); +#endif + + while (ssize > 0) + { + /* Try all the rest. */ + size = ssize; + + if (_bfd_vms_output_check (recwr, size) < 0) + { + /* Doesn't fit, split ! */ + end_etir_record (abfd); + + start_etir_or_etbt_record (abfd, section, vaddr); + + size = _bfd_vms_output_check (recwr, 0); /* get max size */ + if (size > ssize) /* more than what's left ? */ + size = ssize; + } + + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_IMM); + _bfd_vms_output_long (recwr, (unsigned long) (size)); + _bfd_vms_output_dump (recwr, cptr, size); + _bfd_vms_output_end_subrec (recwr); + +#if VMS_DEBUG + _bfd_vms_debug (10, "dumped %d bytes\n", (int) size); + _bfd_hexdump (10, cptr, (int) size, (int) vaddr); +#endif + + vaddr += size; + cptr += size; + ssize -= size; + } +} + +static void +etir_output_check (bfd *abfd, asection *section, bfd_vma vaddr, int checklen) +{ + if (_bfd_vms_output_check (&PRIV (recwr), checklen) < 0) + { + /* Not enough room in this record. Close it and open a new one. */ + end_etir_record (abfd); + start_etir_or_etbt_record (abfd, section, vaddr); + } +} + +/* Return whether RELOC must be deferred till the end. */ + +static bfd_boolean +defer_reloc_p (arelent *reloc) +{ + switch (reloc->howto->type) + { + case ALPHA_R_NOP: + case ALPHA_R_LDA: + case ALPHA_R_BSR: + case ALPHA_R_BOH: + return TRUE; + + default: + return FALSE; + } +} + +/* Write section contents for bfd abfd. Return FALSE on error. */ + +static bfd_boolean +_bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED) +{ + asection *section; + struct vms_rec_wr *recwr = &PRIV (recwr); + + vms_debug2 ((2, "vms_write_tir (%p, %d)\n", abfd, objtype)); + + _bfd_vms_output_alignment (recwr, 4); + + PRIV (vms_linkage_index) = 1; + + for (section = abfd->sections; section; section = section->next) + { + vms_debug2 ((4, "writing %d. section '%s' (%d bytes)\n", + section->index, section->name, (int) (section->size))); + + if (!(section->flags & SEC_HAS_CONTENTS) + || bfd_is_com_section (section)) + continue; + + if (!section->contents) + { + bfd_set_error (bfd_error_no_contents); + return FALSE; + } + + start_etir_or_etbt_record (abfd, section, 0); + + if (section->flags & SEC_RELOC) + { + bfd_vma curr_addr = 0; + unsigned char *curr_data = section->contents; + bfd_size_type size; + int pass2_needed = 0; + int pass2_in_progress = 0; + unsigned int irel; + + if (section->reloc_count <= 0) + (*_bfd_error_handler) + (_("SEC_RELOC with no relocs in section %s"), section->name); + +#if VMS_DEBUG + else + { + int i = section->reloc_count; + arelent **rptr = section->orelocation; + _bfd_vms_debug (4, "%d relocations:\n", i); + while (i-- > 0) + { + _bfd_vms_debug (4, "sym %s in sec %s, value %08lx, " + "addr %08lx, off %08lx, len %d: %s\n", + (*(*rptr)->sym_ptr_ptr)->name, + (*(*rptr)->sym_ptr_ptr)->section->name, + (long) (*(*rptr)->sym_ptr_ptr)->value, + (unsigned long)(*rptr)->address, + (unsigned long)(*rptr)->addend, + bfd_get_reloc_size ((*rptr)->howto), + ( *rptr)->howto->name); + rptr++; + } + } +#endif + + new_pass: + for (irel = 0; irel < section->reloc_count; irel++) + { + struct evax_private_udata_struct *udata; + arelent *rptr = section->orelocation [irel]; + bfd_vma addr = rptr->address; + asymbol *sym = *rptr->sym_ptr_ptr; + asection *sec = sym->section; + bfd_boolean defer = defer_reloc_p (rptr); + unsigned int slen; + char *hash; + + if (pass2_in_progress) + { + /* Non-deferred relocs have already been output. */ + if (!defer) + continue; + } + else + { + /* Deferred relocs must be output at the very end. */ + if (defer) + { + pass2_needed = 1; + continue; + } + + /* Regular relocs are intertwined with binary data. */ + if (curr_addr > addr) + (*_bfd_error_handler) (_("Size error in section %s"), + section->name); + size = addr - curr_addr; + sto_imm (abfd, section, size, curr_data, curr_addr); + curr_data += size; + curr_addr += size; + } + + size = bfd_get_reloc_size (rptr->howto); + + switch (rptr->howto->type) + { + case ALPHA_R_IGNORE: + break; + + case ALPHA_R_REFLONG: + if (bfd_is_und_section (sym->section)) + { + bfd_vma addend = rptr->addend; + slen = strlen ((char *) sym->name); + hash = _bfd_vms_length_hash_symbol + (abfd, sym->name, EOBJ__C_SYMSIZ); + etir_output_check (abfd, section, curr_addr, slen); + if (addend) + { + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_GBL); + _bfd_vms_output_counted (recwr, hash); + _bfd_vms_output_end_subrec (recwr); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_LW); + _bfd_vms_output_long (recwr, (unsigned long) addend); + _bfd_vms_output_end_subrec (recwr); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_OPR_ADD); + _bfd_vms_output_end_subrec (recwr); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_LW); + _bfd_vms_output_end_subrec (recwr); + } + else + { + _bfd_vms_output_begin_subrec + (recwr, ETIR__C_STO_GBL_LW); + _bfd_vms_output_counted (recwr, hash); + _bfd_vms_output_end_subrec (recwr); + } + } + else if (bfd_is_abs_section (sym->section)) + { + etir_output_check (abfd, section, curr_addr, 16); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_LW); + _bfd_vms_output_long (recwr, (unsigned long) sym->value); + _bfd_vms_output_end_subrec (recwr); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_LW); + _bfd_vms_output_end_subrec (recwr); + } + else + { + etir_output_check (abfd, section, curr_addr, 32); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_PQ); + _bfd_vms_output_long (recwr, (unsigned long) sec->index); + _bfd_vms_output_quad (recwr, rptr->addend + sym->value); + _bfd_vms_output_end_subrec (recwr); + /* ??? Table B-8 of the OpenVMS Linker Utilily Manual + says that we should have a ETIR__C_STO_OFF here. + But the relocation would not be BFD_RELOC_32 then. + This case is very likely unreachable. */ + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_LW); + _bfd_vms_output_end_subrec (recwr); + } + break; + + case ALPHA_R_REFQUAD: + if (bfd_is_und_section (sym->section)) + { + bfd_vma addend = rptr->addend; + slen = strlen ((char *) sym->name); + hash = _bfd_vms_length_hash_symbol + (abfd, sym->name, EOBJ__C_SYMSIZ); + etir_output_check (abfd, section, curr_addr, slen); + if (addend) + { + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_GBL); + _bfd_vms_output_counted (recwr, hash); + _bfd_vms_output_end_subrec (recwr); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_QW); + _bfd_vms_output_quad (recwr, addend); + _bfd_vms_output_end_subrec (recwr); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_OPR_ADD); + _bfd_vms_output_end_subrec (recwr); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_QW); + _bfd_vms_output_end_subrec (recwr); + } + else + { + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_GBL); + _bfd_vms_output_counted (recwr, hash); + _bfd_vms_output_end_subrec (recwr); + } + } + else if (bfd_is_abs_section (sym->section)) + { + etir_output_check (abfd, section, curr_addr, 16); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_QW); + _bfd_vms_output_quad (recwr, sym->value); + _bfd_vms_output_end_subrec (recwr); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_QW); + _bfd_vms_output_end_subrec (recwr); + } + else + { + etir_output_check (abfd, section, curr_addr, 32); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_PQ); + _bfd_vms_output_long (recwr, (unsigned long) sec->index); + _bfd_vms_output_quad (recwr, rptr->addend + sym->value); + _bfd_vms_output_end_subrec (recwr); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_OFF); + _bfd_vms_output_end_subrec (recwr); + } + break; + + case ALPHA_R_HINT: + sto_imm (abfd, section, size, curr_data, curr_addr); + break; + + case ALPHA_R_LINKAGE: + etir_output_check (abfd, section, curr_addr, 64); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STC_LP_PSB); + _bfd_vms_output_long + (recwr, (unsigned long) PRIV (vms_linkage_index)); + PRIV (vms_linkage_index) += 2; + hash = _bfd_vms_length_hash_symbol + (abfd, sym->name, EOBJ__C_SYMSIZ); + _bfd_vms_output_counted (recwr, hash); + _bfd_vms_output_byte (recwr, 0); + _bfd_vms_output_end_subrec (recwr); + break; + + case ALPHA_R_CODEADDR: + slen = strlen ((char *) sym->name); + hash = _bfd_vms_length_hash_symbol + (abfd, sym->name, EOBJ__C_SYMSIZ); + etir_output_check (abfd, section, curr_addr, slen); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_CA); + _bfd_vms_output_counted (recwr, hash); + _bfd_vms_output_end_subrec (recwr); + break; + + case ALPHA_R_NOP: + udata + = (struct evax_private_udata_struct *) rptr->sym_ptr_ptr; + etir_output_check (abfd, section, curr_addr, + 32 + 1 + strlen (udata->origname)); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STC_NOP_GBL); + _bfd_vms_output_long (recwr, (unsigned long) udata->lkindex); + _bfd_vms_output_long + (recwr, (unsigned long) udata->enbsym->section->index); + _bfd_vms_output_quad (recwr, rptr->address); + _bfd_vms_output_long (recwr, (unsigned long) 0x47ff041f); + _bfd_vms_output_long + (recwr, (unsigned long) udata->enbsym->section->index); + _bfd_vms_output_quad (recwr, rptr->addend); + _bfd_vms_output_counted + (recwr, _bfd_vms_length_hash_symbol + (abfd, udata->origname, EOBJ__C_SYMSIZ)); + _bfd_vms_output_end_subrec (recwr); + break; + + case ALPHA_R_BSR: + (*_bfd_error_handler) (_("Spurious ALPHA_R_BSR reloc")); + break; + + case ALPHA_R_LDA: + udata + = (struct evax_private_udata_struct *) rptr->sym_ptr_ptr; + etir_output_check (abfd, section, curr_addr, + 32 + 1 + strlen (udata->origname)); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STC_LDA_GBL); + _bfd_vms_output_long + (recwr, (unsigned long) udata->lkindex + 1); + _bfd_vms_output_long + (recwr, (unsigned long) udata->enbsym->section->index); + _bfd_vms_output_quad (recwr, rptr->address); + _bfd_vms_output_long (recwr, (unsigned long) 0x237B0000); + _bfd_vms_output_long + (recwr, (unsigned long) udata->bsym->section->index); + _bfd_vms_output_quad (recwr, rptr->addend); + _bfd_vms_output_counted + (recwr, _bfd_vms_length_hash_symbol + (abfd, udata->origname, EOBJ__C_SYMSIZ)); + _bfd_vms_output_end_subrec (recwr); + break; + + case ALPHA_R_BOH: + udata + = (struct evax_private_udata_struct *) rptr->sym_ptr_ptr; + etir_output_check (abfd, section, curr_addr, + 32 + 1 + strlen (udata->origname)); + _bfd_vms_output_begin_subrec (recwr, ETIR__C_STC_BOH_GBL); + _bfd_vms_output_long (recwr, (unsigned long) udata->lkindex); + _bfd_vms_output_long + (recwr, (unsigned long) udata->enbsym->section->index); + _bfd_vms_output_quad (recwr, rptr->address); + _bfd_vms_output_long (recwr, (unsigned long) 0xD3400000); + _bfd_vms_output_long + (recwr, (unsigned long) udata->enbsym->section->index); + _bfd_vms_output_quad (recwr, rptr->addend); + _bfd_vms_output_counted + (recwr, _bfd_vms_length_hash_symbol + (abfd, udata->origname, EOBJ__C_SYMSIZ)); + _bfd_vms_output_end_subrec (recwr); + break; + + default: + (*_bfd_error_handler) (_("Unhandled relocation %s"), + rptr->howto->name); + break; + } + + curr_data += size; + curr_addr += size; + } /* End of relocs loop. */ + + if (!pass2_in_progress) + { + /* Output rest of section. */ + if (curr_addr > section->size) + (*_bfd_error_handler) (_("Size error in section %s"), + section->name); + size = section->size - curr_addr; + sto_imm (abfd, section, size, curr_data, curr_addr); + curr_data += size; + curr_addr += size; + + if (pass2_needed) + { + pass2_in_progress = 1; + goto new_pass; + } + } + } + + else /* (section->flags & SEC_RELOC) */ + sto_imm (abfd, section, section->size, section->contents, 0); + + end_etir_record (abfd); + } + + _bfd_vms_output_alignment (recwr, 2); + return TRUE; +} + +/* Write eom record for bfd abfd. Return FALSE on error. */ + +static bfd_boolean +_bfd_vms_write_eeom (bfd *abfd) +{ + struct vms_rec_wr *recwr = &PRIV (recwr); + + vms_debug2 ((2, "vms_write_eeom\n")); + + _bfd_vms_output_begin (recwr, EOBJ__C_EEOM); + _bfd_vms_output_long (recwr, (unsigned long) (PRIV (vms_linkage_index) >> 1)); + _bfd_vms_output_byte (recwr, 0); /* Completion code. */ + _bfd_vms_output_byte (recwr, 0); /* Fill byte. */ + + if (bfd_get_start_address (abfd) != (bfd_vma)-1) + { + asection *section; + + section = bfd_get_section_by_name (abfd, ".link"); + if (section == 0) + { + bfd_set_error (bfd_error_nonrepresentable_section); + return FALSE; + } + _bfd_vms_output_short (recwr, 0); + _bfd_vms_output_long (recwr, (unsigned long) (section->index)); + _bfd_vms_output_long (recwr, + (unsigned long) bfd_get_start_address (abfd)); + _bfd_vms_output_long (recwr, 0); + } + + _bfd_vms_output_end (abfd, recwr); + return TRUE; +} + +/* Write cached information into a file being written, at bfd_close. */ + +static bfd_boolean +alpha_vms_write_object_contents (bfd *abfd) +{ + vms_debug2 ((1, "vms_write_object_contents (%p)\n", abfd)); + + if (abfd->flags & (EXEC_P | DYNAMIC)) + { + return alpha_vms_write_exec (abfd); + } + else + { + if (abfd->section_count > 0) /* we have sections */ + { + if (_bfd_vms_write_ehdr (abfd) != TRUE) + return FALSE; + if (_bfd_vms_write_egsd (abfd) != TRUE) + return FALSE; + if (_bfd_vms_write_etir (abfd, EOBJ__C_ETIR) != TRUE) + return FALSE; + if (_bfd_vms_write_eeom (abfd) != TRUE) + return FALSE; + } + } + return TRUE; +} + +/* Debug stuff: nearest line. */ + +#define SET_MODULE_PARSED(m) \ + do { if ((m)->name == NULL) (m)->name = ""; } while (0) +#define IS_MODULE_PARSED(m) ((m)->name != NULL) + +/* Build a new module for the specified BFD. */ + +static struct module * +new_module (bfd *abfd) +{ + struct module *module + = (struct module *) bfd_zalloc (abfd, sizeof (struct module)); + module->file_table_count = 16; /* Arbitrary. */ + module->file_table + = bfd_malloc (module->file_table_count * sizeof (struct fileinfo)); + return module; +} + +/* Parse debug info for a module and internalize it. */ + +static void +parse_module (bfd *abfd, struct module *module, unsigned char *ptr, + int length) +{ + unsigned char *maxptr = ptr + length; + unsigned char *src_ptr, *pcl_ptr; + unsigned int prev_linum = 0, curr_linenum = 0; + bfd_vma prev_pc = 0, curr_pc = 0; + struct srecinfo *curr_srec, *srec; + struct lineinfo *curr_line, *line; + struct funcinfo *funcinfo; + + /* Initialize tables with zero element. */ + curr_srec = (struct srecinfo *) bfd_zalloc (abfd, sizeof (struct srecinfo)); + module->srec_table = curr_srec; + + curr_line = (struct lineinfo *) bfd_zalloc (abfd, sizeof (struct lineinfo)); + module->line_table = curr_line; + + while (length == -1 || ptr < maxptr) + { + /* The first byte is not counted in the recorded length. */ + int rec_length = bfd_getl16 (ptr) + 1; + int rec_type = bfd_getl16 (ptr + 2); + + vms_debug2 ((2, "DST record: leng %d, type %d\n", rec_length, rec_type)); + + if (length == -1 && rec_type == DST__K_MODEND) + break; + + switch (rec_type) + { + case DST__K_MODBEG: + module->name + = _bfd_vms_save_counted_string (ptr + DST_S_B_MODBEG_NAME); + + curr_pc = 0; + prev_pc = 0; + curr_linenum = 0; + prev_linum = 0; + + vms_debug2 ((3, "module: %s\n", module->name)); + break; + + case DST__K_MODEND: + break; + + case DST__K_RTNBEG: + funcinfo = (struct funcinfo *) + bfd_zalloc (abfd, sizeof (struct funcinfo)); + funcinfo->name + = _bfd_vms_save_counted_string (ptr + DST_S_B_RTNBEG_NAME); + funcinfo->low = bfd_getl32 (ptr + DST_S_L_RTNBEG_ADDRESS); + funcinfo->next = module->func_table; + module->func_table = funcinfo; + + vms_debug2 ((3, "routine: %s at 0x%lx\n", + funcinfo->name, (unsigned long) funcinfo->low)); + break; + + case DST__K_RTNEND: + module->func_table->high = module->func_table->low + + bfd_getl32 (ptr + DST_S_L_RTNEND_SIZE) - 1; + + if (module->func_table->high > module->high) + module->high = module->func_table->high; + + vms_debug2 ((3, "end routine\n")); + break; + + case DST__K_PROLOG: + vms_debug2 ((3, "prologue\n")); + break; + + case DST__K_EPILOG: + vms_debug2 ((3, "epilog\n")); + break; + + case DST__K_BLKBEG: + vms_debug2 ((3, "block\n")); + break; + + case DST__K_BLKEND: + vms_debug2 ((3, "end block\n")); + break; + + case DST__K_SOURCE: + src_ptr = ptr + DST_S_C_SOURCE_HEADER_SIZE; + + vms_debug2 ((3, "source info\n")); + + while (src_ptr < ptr + rec_length) + { + int cmd = src_ptr[0], cmd_length, data; + + switch (cmd) + { + case DST__K_SRC_DECLFILE: + { + unsigned int fileid + = bfd_getl16 (src_ptr + DST_S_W_SRC_DF_FILEID); + char *filename + = _bfd_vms_save_counted_string (src_ptr + + DST_S_B_SRC_DF_FILENAME); + + while (fileid >= module->file_table_count) + { + module->file_table_count *= 2; + module->file_table + = bfd_realloc (module->file_table, + module->file_table_count + * sizeof (struct fileinfo)); + } + + module->file_table [fileid].name = filename; + module->file_table [fileid].srec = 1; + cmd_length = src_ptr[DST_S_B_SRC_DF_LENGTH] + 2; + vms_debug2 ((4, "DST_S_C_SRC_DECLFILE: %d, %s\n", + fileid, module->file_table [fileid].name)); + } + break; + + case DST__K_SRC_DEFLINES_B: + /* Perform the association and set the next higher index + to the limit. */ + data = src_ptr[DST_S_B_SRC_UNSBYTE]; + srec = (struct srecinfo *) + bfd_zalloc (abfd, sizeof (struct srecinfo)); + srec->line = curr_srec->line + data; + srec->srec = curr_srec->srec + data; + srec->sfile = curr_srec->sfile; + curr_srec->next = srec; + curr_srec = srec; + cmd_length = 2; + vms_debug2 ((4, "DST_S_C_SRC_DEFLINES_B: %d\n", data)); + break; + + case DST__K_SRC_DEFLINES_W: + /* Perform the association and set the next higher index + to the limit. */ + data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD); + srec = (struct srecinfo *) + bfd_zalloc (abfd, sizeof (struct srecinfo)); + srec->line = curr_srec->line + data; + srec->srec = curr_srec->srec + data, + srec->sfile = curr_srec->sfile; + curr_srec->next = srec; + curr_srec = srec; + cmd_length = 3; + vms_debug2 ((4, "DST_S_C_SRC_DEFLINES_W: %d\n", data)); + break; + + case DST__K_SRC_INCRLNUM_B: + data = src_ptr[DST_S_B_SRC_UNSBYTE]; + curr_srec->line += data; + cmd_length = 2; + vms_debug2 ((4, "DST_S_C_SRC_INCRLNUM_B: %d\n", data)); + break; + + case DST__K_SRC_SETFILE: + data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD); + curr_srec->sfile = data; + curr_srec->srec = module->file_table[data].srec; + cmd_length = 3; + vms_debug2 ((4, "DST_S_C_SRC_SETFILE: %d\n", data)); + break; + + case DST__K_SRC_SETLNUM_L: + data = bfd_getl32 (src_ptr + DST_S_L_SRC_UNSLONG); + curr_srec->line = data; + cmd_length = 5; + vms_debug2 ((4, "DST_S_C_SRC_SETLNUM_L: %d\n", data)); + break; + + case DST__K_SRC_SETLNUM_W: + data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD); + curr_srec->line = data; + cmd_length = 3; + vms_debug2 ((4, "DST_S_C_SRC_SETLNUM_W: %d\n", data)); + break; + + case DST__K_SRC_SETREC_L: + data = bfd_getl32 (src_ptr + DST_S_L_SRC_UNSLONG); + curr_srec->srec = data; + module->file_table[curr_srec->sfile].srec = data; + cmd_length = 5; + vms_debug2 ((4, "DST_S_C_SRC_SETREC_L: %d\n", data)); + break; + + case DST__K_SRC_SETREC_W: + data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD); + curr_srec->srec = data; + module->file_table[curr_srec->sfile].srec = data; + cmd_length = 3; + vms_debug2 ((4, "DST_S_C_SRC_SETREC_W: %d\n", data)); + break; + + case DST__K_SRC_FORMFEED: + cmd_length = 1; + vms_debug2 ((4, "DST_S_C_SRC_FORMFEED\n")); + break; + + default: + (*_bfd_error_handler) (_("unknown source command %d"), + cmd); + cmd_length = 2; + break; + } + + src_ptr += cmd_length; + } + break; + + case DST__K_LINE_NUM: + pcl_ptr = ptr + DST_S_C_LINE_NUM_HEADER_SIZE; + + vms_debug2 ((3, "line info\n")); + + while (pcl_ptr < ptr + rec_length) + { + /* The command byte is signed so we must sign-extend it. */ + int cmd = ((signed char *)pcl_ptr)[0], cmd_length, data; + + switch (cmd) + { + case DST__K_DELTA_PC_W: + data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); + curr_pc += data; + curr_linenum += 1; + cmd_length = 3; + vms_debug2 ((4, "DST__K_DELTA_PC_W: %d\n", data)); + break; + + case DST__K_DELTA_PC_L: + data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); + curr_pc += data; + curr_linenum += 1; + cmd_length = 5; + vms_debug2 ((4, "DST__K_DELTA_PC_L: %d\n", data)); + break; + + case DST__K_INCR_LINUM: + data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE]; + curr_linenum += data; + cmd_length = 2; + vms_debug2 ((4, "DST__K_INCR_LINUM: %d\n", data)); + break; + + case DST__K_INCR_LINUM_W: + data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); + curr_linenum += data; + cmd_length = 3; + vms_debug2 ((4, "DST__K_INCR_LINUM_W: %d\n", data)); + break; + + case DST__K_INCR_LINUM_L: + data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); + curr_linenum += data; + cmd_length = 5; + vms_debug2 ((4, "DST__K_INCR_LINUM_L: %d\n", data)); + break; + + case DST__K_SET_LINUM_INCR: + (*_bfd_error_handler) + (_("DST__K_SET_LINUM_INCR not implemented")); + cmd_length = 2; + break; + + case DST__K_SET_LINUM_INCR_W: + (*_bfd_error_handler) + (_("DST__K_SET_LINUM_INCR_W not implemented")); + cmd_length = 3; + break; + + case DST__K_RESET_LINUM_INCR: + (*_bfd_error_handler) + (_("DST__K_RESET_LINUM_INCR not implemented")); + cmd_length = 1; + break; + + case DST__K_BEG_STMT_MODE: + (*_bfd_error_handler) + (_("DST__K_BEG_STMT_MODE not implemented")); + cmd_length = 1; + break; + + case DST__K_END_STMT_MODE: + (*_bfd_error_handler) + (_("DST__K_END_STMT_MODE not implemented")); + cmd_length = 1; + break; + + case DST__K_SET_LINUM_B: + data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE]; + curr_linenum = data; + cmd_length = 2; + vms_debug2 ((4, "DST__K_SET_LINUM_B: %d\n", data)); + break; + + case DST__K_SET_LINUM: + data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); + curr_linenum = data; + cmd_length = 3; + vms_debug2 ((4, "DST__K_SET_LINE_NUM: %d\n", data)); + break; + + case DST__K_SET_LINUM_L: + data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); + curr_linenum = data; + cmd_length = 5; + vms_debug2 ((4, "DST__K_SET_LINUM_L: %d\n", data)); + break; + + case DST__K_SET_PC: + (*_bfd_error_handler) + (_("DST__K_SET_PC not implemented")); + cmd_length = 2; + break; + + case DST__K_SET_PC_W: + (*_bfd_error_handler) + (_("DST__K_SET_PC_W not implemented")); + cmd_length = 3; + break; + + case DST__K_SET_PC_L: + (*_bfd_error_handler) + (_("DST__K_SET_PC_L not implemented")); + cmd_length = 5; + break; + + case DST__K_SET_STMTNUM: + (*_bfd_error_handler) + (_("DST__K_SET_STMTNUM not implemented")); + cmd_length = 2; + break; + + case DST__K_TERM: + data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE]; + curr_pc += data; + cmd_length = 2; + vms_debug2 ((4, "DST__K_TERM: %d\n", data)); + break; + + case DST__K_TERM_W: + data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); + curr_pc += data; + cmd_length = 3; + vms_debug2 ((4, "DST__K_TERM_W: %d\n", data)); + break; + + case DST__K_TERM_L: + data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); + curr_pc += data; + cmd_length = 5; + vms_debug2 ((4, "DST__K_TERM_L: %d\n", data)); + break; + + case DST__K_SET_ABS_PC: + data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); + curr_pc = data; + cmd_length = 5; + vms_debug2 ((4, "DST__K_SET_ABS_PC: 0x%x\n", data)); + break; + + default: + if (cmd <= 0) + { + curr_pc -= cmd; + curr_linenum += 1; + cmd_length = 1; + vms_debug2 ((4, "bump pc to 0x%lx and line to %d\n", + (unsigned long)curr_pc, curr_linenum)); + } + else + { + (*_bfd_error_handler) (_("unknown line command %d"), + cmd); + cmd_length = 2; + } + break; + } + + if ((curr_linenum != prev_linum && curr_pc != prev_pc) + || cmd <= 0 + || cmd == DST__K_DELTA_PC_L + || cmd == DST__K_DELTA_PC_W) + { + line = (struct lineinfo *) + bfd_zalloc (abfd, sizeof (struct lineinfo)); + line->address = curr_pc; + line->line = curr_linenum; + + curr_line->next = line; + curr_line = line; + + prev_linum = curr_linenum; + prev_pc = curr_pc; + vms_debug2 ((4, "-> correlate pc 0x%lx with line %d\n", + (unsigned long)curr_pc, curr_linenum)); + } + + pcl_ptr += cmd_length; + } + break; + + case 0x17: /* Undocumented type used by DEC C to declare equates. */ + vms_debug2 ((3, "undocumented type 0x17\n")); + break; + + default: + vms_debug2 ((3, "ignoring record\n")); + break; + + } + + ptr += rec_length; + } + + /* Finalize tables with EOL marker. */ + srec = (struct srecinfo *) bfd_zalloc (abfd, sizeof (struct srecinfo)); + srec->line = (unsigned int) -1; + srec->srec = (unsigned int) -1; + curr_srec->next = srec; + + line = (struct lineinfo *) bfd_zalloc (abfd, sizeof (struct lineinfo)); + line->line = (unsigned int) -1; + line->address = (bfd_vma) -1; + curr_line->next = line; + + /* Advertise that this module has been parsed. This is needed + because parsing can be either performed at module creation + or deferred until debug info is consumed. */ + SET_MODULE_PARSED (module); +} + +/* Build the list of modules for the specified BFD. */ + +static struct module * +build_module_list (bfd *abfd) +{ + struct module *module, *list = NULL; + asection *dmt; + + if ((dmt = bfd_get_section_by_name (abfd, "$DMT$"))) + { + /* We have a DMT section so this must be an image. Parse the + section and build the list of modules. This is sufficient + since we can compute the start address and the end address + of every module from the section contents. */ + bfd_size_type size = bfd_get_section_size (dmt); + unsigned char *ptr, *end; + + ptr = (unsigned char *) bfd_alloc (abfd, size); + if (! ptr) + return NULL; + + if (! bfd_get_section_contents (abfd, dmt, ptr, 0, size)) + return NULL; + + vms_debug2 ((2, "DMT\n")); + + end = ptr + size; + + while (ptr < end) + { + /* Each header declares a module with its start offset and size + of debug info in the DST section, as well as the count of + program sections (i.e. address spans) it contains. */ + int modbeg = bfd_getl32 (ptr + DBG_S_L_DMT_MODBEG); + int msize = bfd_getl32 (ptr + DBG_S_L_DST_SIZE); + int count = bfd_getl16 (ptr + DBG_S_W_DMT_PSECT_COUNT); + ptr += DBG_S_C_DMT_HEADER_SIZE; + + vms_debug2 ((3, "module: modbeg = %d, size = %d, count = %d\n", + modbeg, msize, count)); + + /* We create a 'module' structure for each program section since + we only support contiguous addresses in a 'module' structure. + As a consequence, the actual debug info in the DST section is + shared and can be parsed multiple times; that doesn't seem to + cause problems in practice. */ + while (count-- > 0) + { + int start = bfd_getl32 (ptr + DBG_S_L_DMT_PSECT_START); + int length = bfd_getl32 (ptr + DBG_S_L_DMT_PSECT_LENGTH); + module = new_module (abfd); + module->modbeg = modbeg; + module->size = msize; + module->low = start; + module->high = start + length; + module->next = list; + list = module; + ptr += DBG_S_C_DMT_PSECT_SIZE; + + vms_debug2 ((4, "section: start = 0x%x, length = %d\n", + start, length)); + } + } + } + else + { + /* We don't have a DMT section so this must be an object. Parse + the module right now in order to compute its start address and + end address. */ + module = new_module (abfd); + parse_module (abfd, module, PRIV (dst_section)->contents, -1); + list = module; + } + + return list; +} + +/* Calculate and return the name of the source file and the line nearest + to the wanted location in the specified module. */ + +static bfd_boolean +module_find_nearest_line (bfd *abfd, struct module *module, bfd_vma addr, + const char **file, const char **func, + unsigned int *line) +{ + struct funcinfo *funcinfo; + struct lineinfo *lineinfo; + struct srecinfo *srecinfo; + bfd_boolean ret = FALSE; + + /* Parse this module if that was not done at module creation. */ + if (! IS_MODULE_PARSED (module)) + { + unsigned int size = module->size; + unsigned int modbeg = PRIV (dst_section)->filepos + module->modbeg; + unsigned char *buffer = (unsigned char *) bfd_malloc (module->size); + + if (bfd_seek (abfd, modbeg, SEEK_SET) != 0 + || bfd_bread (buffer, size, abfd) != size) + { + bfd_set_error (bfd_error_no_debug_section); + return FALSE; + } + + parse_module (abfd, module, buffer, size); + free (buffer); + } + + /* Find out the function (if any) that contains the address. */ + for (funcinfo = module->func_table; funcinfo; funcinfo = funcinfo->next) + if (addr >= funcinfo->low && addr <= funcinfo->high) + { + *func = funcinfo->name; + ret = TRUE; + break; + } + + /* Find out the source file and the line nearest to the address. */ + for (lineinfo = module->line_table; lineinfo; lineinfo = lineinfo->next) + if (lineinfo->next && addr < lineinfo->next->address) + { + for (srecinfo = module->srec_table; srecinfo; srecinfo = srecinfo->next) + if (srecinfo->next && lineinfo->line < srecinfo->next->line) + { + if (srecinfo->sfile > 0) + { + *file = module->file_table[srecinfo->sfile].name; + *line = srecinfo->srec + lineinfo->line - srecinfo->line; + } + else + { + *file = module->name; + *line = lineinfo->line; + } + return TRUE; + } + + break; + } + + return ret; +} + +/* Provided a BFD, a section and an offset into the section, calculate and + return the name of the source file and the line nearest to the wanted + location. */ + +static bfd_boolean +_bfd_vms_find_nearest_dst_line (bfd *abfd, asection *section, + asymbol **symbols ATTRIBUTE_UNUSED, + bfd_vma offset, const char **file, + const char **func, unsigned int *line) +{ + struct module *module; + + /* What address are we looking for? */ + bfd_vma addr = section->vma + offset; + + *file = NULL; + *func = NULL; + *line = 0; + + if (PRIV (dst_section) == NULL || !(abfd->flags & (EXEC_P | DYNAMIC))) + return FALSE; + + if (PRIV (modules) == NULL) + { + PRIV (modules) = build_module_list (abfd); + if (PRIV (modules) == NULL) + return FALSE; + } + + for (module = PRIV (modules); module; module = module->next) + if (addr >= module->low && addr <= module->high) + return module_find_nearest_line (abfd, module, addr, file, func, line); + + return FALSE; +} + +/* Canonicalizations. */ +/* Set name, value, section and flags of SYM from E. */ + +static bfd_boolean +alpha_vms_convert_symbol (bfd *abfd, struct vms_symbol_entry *e, asymbol *sym) +{ + flagword flags; + symvalue value; + asection *sec; + const char *name; + + name = e->name; + value = 0; + flags = BSF_NO_FLAGS; + sec = NULL; + + switch (e->typ) + { + case EGSD__C_SYM: + if (e->flags & EGSY__V_WEAK) + flags |= BSF_WEAK; + + if (e->flags & EGSY__V_DEF) + { + /* Symbol definition. */ + flags |= BSF_GLOBAL; + if (e->flags & EGSY__V_NORM) + flags |= BSF_FUNCTION; + value = e->value; + sec = PRIV (sections)[e->section]; + } + else + { + /* Symbol reference. */ + sec = bfd_und_section_ptr; + } + break; + + case EGSD__C_SYMG: + /* A universal symbol is by definition global... */ + flags |= BSF_GLOBAL; + + /* ...and dynamic in shared libraries. */ + if (abfd->flags & DYNAMIC) + flags |= BSF_DYNAMIC; + + if (e->flags & EGSY__V_WEAK) + flags |= BSF_WEAK; + + if (!(e->flags & EGSY__V_DEF)) + abort (); + + if (e->flags & EGSY__V_NORM) + flags |= BSF_FUNCTION; + + value = e->symbol_vector; + + /* Adding this offset is necessary in order for GDB to + read the DWARF-2 debug info from shared libraries. */ + if ((abfd->flags & DYNAMIC) && strstr (name, "$DWARF2.DEBUG") != 0) + value += PRIV (symvva); + + sec = bfd_abs_section_ptr; +#if 0 + /* Find containing section. */ + { + bfd_vma sbase = 0; + asection *s; + + for (s = abfd->sections; s; s = s->next) + { + if (value >= s->vma + && s->vma > sbase + && !(s->flags & SEC_COFF_SHARED_LIBRARY) + && (s->size > 0 || !(e->flags & EGSY__V_REL))) + { + sbase = s->vma; + sec = s; + } + } + value -= sbase; + } +#endif + + break; + + default: + return FALSE; + } + + sym->name = name; + sym->section = sec; + sym->flags = flags; + sym->value = value; + return TRUE; +} + + +/* Return the number of bytes required to store a vector of pointers + to asymbols for all the symbols in the BFD abfd, including a + terminal NULL pointer. If there are no symbols in the BFD, + then return 0. If an error occurs, return -1. */ + +static long +alpha_vms_get_symtab_upper_bound (bfd *abfd) +{ + vms_debug2 ((1, "alpha_vms_get_symtab_upper_bound (%p), %d symbols\n", + abfd, PRIV (gsd_sym_count))); + + return (PRIV (gsd_sym_count) + 1) * sizeof (asymbol *); +} + +/* Read the symbols from the BFD abfd, and fills in the vector + location with pointers to the symbols and a trailing NULL. + + Return number of symbols read. */ + +static long +alpha_vms_canonicalize_symtab (bfd *abfd, asymbol **symbols) +{ + unsigned int i; + + vms_debug2 ((1, "alpha_vms_canonicalize_symtab (%p, <ret>)\n", abfd)); + + if (PRIV (csymbols) == NULL) + { + PRIV (csymbols) = (asymbol **) bfd_alloc + (abfd, PRIV (gsd_sym_count) * sizeof (asymbol *)); + + /* Traverse table and fill symbols vector. */ + for (i = 0; i < PRIV (gsd_sym_count); i++) + { + struct vms_symbol_entry *e = PRIV (syms)[i]; + asymbol *sym; + + sym = bfd_make_empty_symbol (abfd); + if (sym == NULL || !alpha_vms_convert_symbol (abfd, e, sym)) + { + bfd_release (abfd, PRIV (csymbols)); + PRIV (csymbols) = NULL; + return -1; + } + + PRIV (csymbols)[i] = sym; + } + } + + if (symbols != NULL) + { + for (i = 0; i < PRIV (gsd_sym_count); i++) + symbols[i] = PRIV (csymbols)[i]; + symbols[i] = NULL; + } + + return PRIV (gsd_sym_count); +} + +/* Read and convert relocations from ETIR. We do it once for all sections. */ + +static bfd_boolean +alpha_vms_slurp_relocs (bfd *abfd) +{ + int cur_psect = -1; + + vms_debug2 ((3, "alpha_vms_slurp_relocs\n")); + + /* We slurp relocs only once, for all sections. */ + if (PRIV (reloc_done)) + return TRUE; + PRIV (reloc_done) = TRUE; + + if (alpha_vms_canonicalize_symtab (abfd, NULL) < 0) + return FALSE; + + if (bfd_seek (abfd, 0, SEEK_SET) != 0) + return FALSE; + + while (1) + { + unsigned char *begin; + unsigned char *end; + unsigned char *ptr; + bfd_reloc_code_real_type reloc_code; + int type; + bfd_vma vaddr = 0; + + int length; + + bfd_vma cur_address; + int cur_psidx = -1; + unsigned char *cur_sym = NULL; + int prev_cmd = -1; + bfd_vma cur_addend = 0; + + /* Skip non-ETIR records. */ + type = _bfd_vms_get_object_record (abfd); + if (type == EOBJ__C_EEOM) + break; + if (type != EOBJ__C_ETIR) + continue; + + begin = PRIV (recrd.rec) + 4; + end = PRIV (recrd.rec) + PRIV (recrd.rec_size); + + for (ptr = begin; ptr < end; ptr += length) + { + int cmd; + + cmd = bfd_getl16 (ptr); + length = bfd_getl16 (ptr + 2); + + cur_address = vaddr; + + vms_debug2 ((4, "alpha_vms_slurp_relocs: etir %s\n", + _bfd_vms_etir_name (cmd))); + + switch (cmd) + { + case ETIR__C_STA_GBL: /* ALPHA_R_REFLONG und_section, step 1 */ + /* ALPHA_R_REFQUAD und_section, step 1 */ + cur_sym = ptr + 4; + prev_cmd = cmd; + continue; + + case ETIR__C_STA_PQ: /* ALPHA_R_REF{LONG|QUAD}, others part 1 */ + cur_psidx = bfd_getl32 (ptr + 4); + cur_addend = bfd_getl64 (ptr + 8); + prev_cmd = cmd; + continue; + + case ETIR__C_CTL_SETRB: + if (prev_cmd != ETIR__C_STA_PQ) + { + (*_bfd_error_handler) + (_("Unknown reloc %s + %s"), _bfd_vms_etir_name (prev_cmd), + _bfd_vms_etir_name (cmd)); + return FALSE; + } + cur_psect = cur_psidx; + vaddr = cur_addend; + cur_psidx = -1; + cur_addend = 0; + continue; + + case ETIR__C_STA_LW: /* ALPHA_R_REFLONG abs_section, step 1 */ + /* ALPHA_R_REFLONG und_section, step 2 */ + if (prev_cmd != -1) + { + if (prev_cmd != ETIR__C_STA_GBL) + { + (*_bfd_error_handler) + (_("Unknown reloc %s + %s"), _bfd_vms_etir_name (cmd), + _bfd_vms_etir_name (ETIR__C_STA_LW)); + return FALSE; + } + } + cur_addend = bfd_getl32 (ptr + 4); + prev_cmd = cmd; + continue; + + case ETIR__C_STA_QW: /* ALPHA_R_REFQUAD abs_section, step 1 */ + /* ALPHA_R_REFQUAD und_section, step 2 */ + if (prev_cmd != -1 && prev_cmd != ETIR__C_STA_GBL) + { + (*_bfd_error_handler) + (_("Unknown reloc %s + %s"), _bfd_vms_etir_name (cmd), + _bfd_vms_etir_name (ETIR__C_STA_QW)); + return FALSE; + } + cur_addend = bfd_getl64 (ptr + 4); + prev_cmd = cmd; + continue; + + case ETIR__C_STO_LW: /* ALPHA_R_REFLONG und_section, step 4 */ + /* ALPHA_R_REFLONG abs_section, step 2 */ + /* ALPHA_R_REFLONG others, step 2 */ + if (prev_cmd != ETIR__C_OPR_ADD + && prev_cmd != ETIR__C_STA_LW + && prev_cmd != ETIR__C_STA_PQ) + { + (*_bfd_error_handler) (_("Unknown reloc %s + %s"), + _bfd_vms_etir_name (prev_cmd), + _bfd_vms_etir_name (ETIR__C_STO_LW)); + return FALSE; + } + reloc_code = BFD_RELOC_32; + break; + + case ETIR__C_STO_QW: /* ALPHA_R_REFQUAD und_section, step 4 */ + /* ALPHA_R_REFQUAD abs_section, step 2 */ + if (prev_cmd != ETIR__C_OPR_ADD && prev_cmd != ETIR__C_STA_QW) + { + (*_bfd_error_handler) (_("Unknown reloc %s + %s"), + _bfd_vms_etir_name (prev_cmd), + _bfd_vms_etir_name (ETIR__C_STO_QW)); + return FALSE; + } + reloc_code = BFD_RELOC_64; + break; + + case ETIR__C_STO_OFF: /* ALPHA_R_REFQUAD others, step 2 */ + if (prev_cmd != ETIR__C_STA_PQ) + { + (*_bfd_error_handler) (_("Unknown reloc %s + %s"), + _bfd_vms_etir_name (prev_cmd), + _bfd_vms_etir_name (ETIR__C_STO_OFF)); + return FALSE; + } + reloc_code = BFD_RELOC_64; + break; + + case ETIR__C_OPR_ADD: /* ALPHA_R_REFLONG und_section, step 3 */ + /* ALPHA_R_REFQUAD und_section, step 3 */ + if (prev_cmd != ETIR__C_STA_LW && prev_cmd != ETIR__C_STA_QW) + { + (*_bfd_error_handler) (_("Unknown reloc %s + %s"), + _bfd_vms_etir_name (prev_cmd), + _bfd_vms_etir_name (ETIR__C_OPR_ADD)); + return FALSE; + } + prev_cmd = ETIR__C_OPR_ADD; + continue; + + case ETIR__C_STO_CA: /* ALPHA_R_CODEADDR */ + reloc_code = BFD_RELOC_ALPHA_CODEADDR; + cur_sym = ptr + 4; + break; + + case ETIR__C_STO_GBL: /* ALPHA_R_REFQUAD und_section */ + reloc_code = BFD_RELOC_64; + cur_sym = ptr + 4; + break; + + case ETIR__C_STO_GBL_LW: /* ALPHA_R_REFLONG und_section */ + reloc_code = BFD_RELOC_32; + cur_sym = ptr + 4; + break; + + case ETIR__C_STC_LP_PSB: /* ALPHA_R_LINKAGE */ + reloc_code = BFD_RELOC_ALPHA_LINKAGE; + cur_sym = ptr + 8; + break; + + case ETIR__C_STC_NOP_GBL: /* ALPHA_R_NOP */ + reloc_code = BFD_RELOC_ALPHA_NOP; + goto call_reloc; + + case ETIR__C_STC_BSR_GBL: /* ALPHA_R_BSR */ + reloc_code = BFD_RELOC_ALPHA_BSR; + goto call_reloc; + + case ETIR__C_STC_LDA_GBL: /* ALPHA_R_LDA */ + reloc_code = BFD_RELOC_ALPHA_LDA; + goto call_reloc; + + case ETIR__C_STC_BOH_GBL: /* ALPHA_R_BOH */ + reloc_code = BFD_RELOC_ALPHA_BOH; + goto call_reloc; + + call_reloc: + cur_sym = ptr + 4 + 32; + cur_address = bfd_getl64 (ptr + 4 + 8); + cur_addend = bfd_getl64 (ptr + 4 + 24); + break; + + case ETIR__C_STO_IMM: + vaddr += bfd_getl32 (ptr + 4); + continue; + + default: + (*_bfd_error_handler) (_("Unknown reloc %s"), + _bfd_vms_etir_name (cmd)); + return FALSE; + } + + { + asection *sec; + struct vms_section_data_struct *vms_sec; + arelent *reloc; + + /* Get section to which the relocation applies. */ + if (cur_psect < 0 || cur_psect > (int)PRIV (section_count)) + { + (*_bfd_error_handler) (_("Invalid section index in ETIR")); + return FALSE; + } + sec = PRIV (sections)[cur_psect]; + vms_sec = vms_section_data (sec); + + /* Allocate a reloc entry. */ + if (sec->reloc_count >= vms_sec->reloc_max) + { + if (vms_sec->reloc_max == 0) + { + vms_sec->reloc_max = 64; + sec->relocation = bfd_zmalloc + (vms_sec->reloc_max * sizeof (arelent)); + } + else + { + vms_sec->reloc_max *= 2; + sec->relocation = bfd_realloc + (sec->relocation, vms_sec->reloc_max * sizeof (arelent)); + } + } + reloc = &sec->relocation[sec->reloc_count]; + sec->reloc_count++; + + reloc->howto = bfd_reloc_type_lookup (abfd, reloc_code); + + if (cur_sym != NULL) + { + unsigned int j; + unsigned int symlen = *cur_sym; + asymbol **sym; + + /* Linear search. */ + symlen = *cur_sym; + cur_sym++; + sym = NULL; + + for (j = 0; j < PRIV (gsd_sym_count); j++) + if (PRIV (syms)[j]->namelen == symlen + && memcmp (PRIV (syms)[j]->name, cur_sym, symlen) == 0) + { + sym = &PRIV (csymbols)[j]; + break; + } + if (sym == NULL) + { + (*_bfd_error_handler) (_("Unknown symbol in command %s"), + _bfd_vms_etir_name (cmd)); + reloc->sym_ptr_ptr = NULL; + } + else + reloc->sym_ptr_ptr = sym; + } + else if (cur_psidx >= 0) + reloc->sym_ptr_ptr = + PRIV (sections)[cur_psidx]->symbol_ptr_ptr; + else + reloc->sym_ptr_ptr = NULL; + + reloc->address = cur_address; + reloc->addend = cur_addend; + + vaddr += bfd_get_reloc_size (reloc->howto); + } + + cur_addend = 0; + prev_cmd = -1; + cur_sym = NULL; + cur_psidx = -1; + } + } + vms_debug2 ((3, "alpha_vms_slurp_relocs: result = TRUE\n")); + + return TRUE; +} + +/* Return the number of bytes required to store the relocation + information associated with the given section. */ + +static long +alpha_vms_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *section) +{ + alpha_vms_slurp_relocs (abfd); + + return (section->reloc_count + 1) * sizeof (arelent *); +} + +/* Convert relocations from VMS (external) form into BFD internal + form. Return the number of relocations. */ + +static long +alpha_vms_canonicalize_reloc (bfd *abfd, asection *section, arelent **relptr, + asymbol **symbols ATTRIBUTE_UNUSED) +{ + arelent *tblptr; + int count; + + if (!alpha_vms_slurp_relocs (abfd)) + return -1; + + count = section->reloc_count; + tblptr = section->relocation; + + while (count--) + *relptr++ = tblptr++; + + *relptr = (arelent *) NULL; + return section->reloc_count; +} + +/* This is just copied from ecoff-alpha, needs to be fixed probably. */ + +/* How to process the various reloc types. */ + +static bfd_reloc_status_type +reloc_nil (bfd * abfd ATTRIBUTE_UNUSED, + arelent *reloc ATTRIBUTE_UNUSED, + asymbol *sym ATTRIBUTE_UNUSED, + void * data ATTRIBUTE_UNUSED, + asection *sec ATTRIBUTE_UNUSED, + bfd *output_bfd ATTRIBUTE_UNUSED, + char **error_message ATTRIBUTE_UNUSED) +{ +#if VMS_DEBUG + vms_debug (1, "reloc_nil (abfd %p, output_bfd %p)\n", abfd, output_bfd); + vms_debug (2, "In section %s, symbol %s\n", + sec->name, sym->name); + vms_debug (2, "reloc sym %s, addr %08lx, addend %08lx, reloc is a %s\n", + reloc->sym_ptr_ptr[0]->name, + (unsigned long)reloc->address, + (unsigned long)reloc->addend, reloc->howto->name); + vms_debug (2, "data at %p\n", data); + /* _bfd_hexdump (2, data, bfd_get_reloc_size (reloc->howto), 0); */ +#endif + + return bfd_reloc_ok; +} + +/* In case we're on a 32-bit machine, construct a 64-bit "-1" value + from smaller values. Start with zero, widen, *then* decrement. */ +#define MINUS_ONE (((bfd_vma)0) - 1) + +static reloc_howto_type alpha_howto_table[] = +{ + HOWTO (ALPHA_R_IGNORE, /* Type. */ + 0, /* Rightshift. */ + 0, /* Size (0 = byte, 1 = short, 2 = long). */ + 8, /* Bitsize. */ + TRUE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_dont,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "IGNORE", /* Name. */ + TRUE, /* Partial_inplace. */ + 0, /* Source mask */ + 0, /* Dest mask. */ + TRUE), /* PC rel offset. */ + + /* A 64 bit reference to a symbol. */ + HOWTO (ALPHA_R_REFQUAD, /* Type. */ + 0, /* Rightshift. */ + 4, /* Size (0 = byte, 1 = short, 2 = long). */ + 64, /* Bitsize. */ + FALSE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_bitfield, /* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "REFQUAD", /* Name. */ + TRUE, /* Partial_inplace. */ + MINUS_ONE, /* Source mask. */ + MINUS_ONE, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* A 21 bit branch. The native assembler generates these for + branches within the text segment, and also fills in the PC + relative offset in the instruction. */ + HOWTO (ALPHA_R_BRADDR, /* Type. */ + 2, /* Rightshift. */ + 2, /* Size (0 = byte, 1 = short, 2 = long). */ + 21, /* Bitsize. */ + TRUE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_signed, /* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "BRADDR", /* Name. */ + TRUE, /* Partial_inplace. */ + 0x1fffff, /* Source mask. */ + 0x1fffff, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* A hint for a jump to a register. */ + HOWTO (ALPHA_R_HINT, /* Type. */ + 2, /* Rightshift. */ + 1, /* Size (0 = byte, 1 = short, 2 = long). */ + 14, /* Bitsize. */ + TRUE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_dont,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "HINT", /* Name. */ + TRUE, /* Partial_inplace. */ + 0x3fff, /* Source mask. */ + 0x3fff, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* 16 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL16, /* Type. */ + 0, /* Rightshift. */ + 1, /* Size (0 = byte, 1 = short, 2 = long). */ + 16, /* Bitsize. */ + TRUE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_signed, /* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "SREL16", /* Name. */ + TRUE, /* Partial_inplace. */ + 0xffff, /* Source mask. */ + 0xffff, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* 32 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL32, /* Type. */ + 0, /* Rightshift. */ + 2, /* Size (0 = byte, 1 = short, 2 = long). */ + 32, /* Bitsize. */ + TRUE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_signed, /* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "SREL32", /* Name. */ + TRUE, /* Partial_inplace. */ + 0xffffffff, /* Source mask. */ + 0xffffffff, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* A 64 bit PC relative offset. */ + HOWTO (ALPHA_R_SREL64, /* Type. */ + 0, /* Rightshift. */ + 4, /* Size (0 = byte, 1 = short, 2 = long). */ + 64, /* Bitsize. */ + TRUE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_signed, /* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "SREL64", /* Name. */ + TRUE, /* Partial_inplace. */ + MINUS_ONE, /* Source mask. */ + MINUS_ONE, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* Push a value on the reloc evaluation stack. */ + HOWTO (ALPHA_R_OP_PUSH, /* Type. */ + 0, /* Rightshift. */ + 0, /* Size (0 = byte, 1 = short, 2 = long). */ + 0, /* Bitsize. */ + FALSE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_dont,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "OP_PUSH", /* Name. */ + FALSE, /* Partial_inplace. */ + 0, /* Source mask. */ + 0, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* Store the value from the stack at the given address. Store it in + a bitfield of size r_size starting at bit position r_offset. */ + HOWTO (ALPHA_R_OP_STORE, /* Type. */ + 0, /* Rightshift. */ + 4, /* Size (0 = byte, 1 = short, 2 = long). */ + 64, /* Bitsize. */ + FALSE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_dont,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "OP_STORE", /* Name. */ + FALSE, /* Partial_inplace. */ + 0, /* Source mask. */ + MINUS_ONE, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* Subtract the reloc address from the value on the top of the + relocation stack. */ + HOWTO (ALPHA_R_OP_PSUB, /* Type. */ + 0, /* Rightshift. */ + 0, /* Size (0 = byte, 1 = short, 2 = long). */ + 0, /* Bitsize. */ + FALSE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_dont,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "OP_PSUB", /* Name. */ + FALSE, /* Partial_inplace. */ + 0, /* Source mask. */ + 0, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* Shift the value on the top of the relocation stack right by the + given value. */ + HOWTO (ALPHA_R_OP_PRSHIFT, /* Type. */ + 0, /* Rightshift. */ + 0, /* Size (0 = byte, 1 = short, 2 = long). */ + 0, /* Bitsize. */ + FALSE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_dont,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "OP_PRSHIFT", /* Name. */ + FALSE, /* Partial_inplace. */ + 0, /* Source mask. */ + 0, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* Hack. Linkage is done by linker. */ + HOWTO (ALPHA_R_LINKAGE, /* Type. */ + 0, /* Rightshift. */ + 8, /* Size (0 = byte, 1 = short, 2 = long). */ + 256, /* Bitsize. */ + FALSE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_dont,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "LINKAGE", /* Name. */ + FALSE, /* Partial_inplace. */ + 0, /* Source mask. */ + 0, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* A 32 bit reference to a symbol. */ + HOWTO (ALPHA_R_REFLONG, /* Type. */ + 0, /* Rightshift. */ + 2, /* Size (0 = byte, 1 = short, 2 = long). */ + 32, /* Bitsize. */ + FALSE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_bitfield, /* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "REFLONG", /* Name. */ + TRUE, /* Partial_inplace. */ + 0xffffffff, /* Source mask. */ + 0xffffffff, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + /* A 64 bit reference to a procedure, written as 32 bit value. */ + HOWTO (ALPHA_R_CODEADDR, /* Type. */ + 0, /* Rightshift. */ + 4, /* Size (0 = byte, 1 = short, 2 = long). */ + 64, /* Bitsize. */ + FALSE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_signed,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "CODEADDR", /* Name. */ + FALSE, /* Partial_inplace. */ + 0xffffffff, /* Source mask. */ + 0xffffffff, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + HOWTO (ALPHA_R_NOP, /* Type. */ + 0, /* Rightshift. */ + 3, /* Size (0 = byte, 1 = short, 2 = long). */ + 0, /* Bitsize. */ + /* The following value must match that of ALPHA_R_BSR/ALPHA_R_BOH + because the calculations for the 3 relocations are the same. + See B.4.5.2 of the OpenVMS Linker Utility Manual. */ + TRUE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_dont,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "NOP", /* Name. */ + FALSE, /* Partial_inplace. */ + 0xffffffff, /* Source mask. */ + 0xffffffff, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + HOWTO (ALPHA_R_BSR, /* Type. */ + 0, /* Rightshift. */ + 3, /* Size (0 = byte, 1 = short, 2 = long). */ + 0, /* Bitsize. */ + TRUE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_dont,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "BSR", /* Name. */ + FALSE, /* Partial_inplace. */ + 0xffffffff, /* Source mask. */ + 0xffffffff, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + HOWTO (ALPHA_R_LDA, /* Type. */ + 0, /* Rightshift. */ + 3, /* Size (0 = byte, 1 = short, 2 = long). */ + 0, /* Bitsize. */ + FALSE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_dont,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "LDA", /* Name. */ + FALSE, /* Partial_inplace. */ + 0xffffffff, /* Source mask. */ + 0xffffffff, /* Dest mask. */ + FALSE), /* PC rel offset. */ + + HOWTO (ALPHA_R_BOH, /* Type. */ + 0, /* Rightshift. */ + 3, /* Size (0 = byte, 1 = short, 2 = long, 3 = nil). */ + 0, /* Bitsize. */ + TRUE, /* PC relative. */ + 0, /* Bitpos. */ + complain_overflow_dont,/* Complain_on_overflow. */ + reloc_nil, /* Special_function. */ + "BOH", /* Name. */ + FALSE, /* Partial_inplace. */ + 0xffffffff, /* Source mask. */ + 0xffffffff, /* Dest mask. */ + FALSE), /* PC rel offset. */ +}; + +/* Return a pointer to a howto structure which, when invoked, will perform + the relocation code on data from the architecture noted. */ + +static const struct reloc_howto_struct * +alpha_vms_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + int alpha_type; + + vms_debug2 ((1, "vms_bfd_reloc_type_lookup (%p, %d)\t", abfd, code)); + + switch (code) + { + case BFD_RELOC_16: alpha_type = ALPHA_R_SREL16; break; + case BFD_RELOC_32: alpha_type = ALPHA_R_REFLONG; break; + case BFD_RELOC_64: alpha_type = ALPHA_R_REFQUAD; break; + case BFD_RELOC_CTOR: alpha_type = ALPHA_R_REFQUAD; break; + case BFD_RELOC_23_PCREL_S2: alpha_type = ALPHA_R_BRADDR; break; + case BFD_RELOC_ALPHA_HINT: alpha_type = ALPHA_R_HINT; break; + case BFD_RELOC_16_PCREL: alpha_type = ALPHA_R_SREL16; break; + case BFD_RELOC_32_PCREL: alpha_type = ALPHA_R_SREL32; break; + case BFD_RELOC_64_PCREL: alpha_type = ALPHA_R_SREL64; break; + case BFD_RELOC_ALPHA_LINKAGE: alpha_type = ALPHA_R_LINKAGE; break; + case BFD_RELOC_ALPHA_CODEADDR: alpha_type = ALPHA_R_CODEADDR; break; + case BFD_RELOC_ALPHA_NOP: alpha_type = ALPHA_R_NOP; break; + case BFD_RELOC_ALPHA_BSR: alpha_type = ALPHA_R_BSR; break; + case BFD_RELOC_ALPHA_LDA: alpha_type = ALPHA_R_LDA; break; + case BFD_RELOC_ALPHA_BOH: alpha_type = ALPHA_R_BOH; break; + default: + (*_bfd_error_handler) ("reloc (%d) is *UNKNOWN*", code); + return NULL; + } + vms_debug2 ((2, "reloc is %s\n", alpha_howto_table[alpha_type].name)); + return & alpha_howto_table[alpha_type]; +} + +static reloc_howto_type * +alpha_vms_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; + i < sizeof (alpha_howto_table) / sizeof (alpha_howto_table[0]); + i++) + if (alpha_howto_table[i].name != NULL + && strcasecmp (alpha_howto_table[i].name, r_name) == 0) + return &alpha_howto_table[i]; + + return NULL; +} + +static long +alpha_vms_get_synthetic_symtab (bfd *abfd, + long symcount ATTRIBUTE_UNUSED, + asymbol **usyms ATTRIBUTE_UNUSED, + long dynsymcount ATTRIBUTE_UNUSED, + asymbol **dynsyms ATTRIBUTE_UNUSED, + asymbol **ret) +{ + asymbol *syms; + unsigned int i; + unsigned int n = 0; + + syms = (asymbol *) bfd_malloc (PRIV (norm_sym_count) * sizeof (asymbol)); + *ret = syms; + if (syms == NULL) + return -1; + + for (i = 0; i < PRIV (gsd_sym_count); i++) + { + struct vms_symbol_entry *e = PRIV (syms)[i]; + asymbol *sym; + flagword flags; + symvalue value; + asection *sec; + const char *name; + char *sname; + int l; + + name = e->name; + value = 0; + flags = BSF_LOCAL | BSF_SYNTHETIC; + sec = NULL; + + switch (e->typ) + { + case EGSD__C_SYM: + if ((e->flags & EGSY__V_DEF) && (e->flags & EGSY__V_NORM)) + { + value = e->code_value; + sec = PRIV (sections)[e->code_section]; + } + else + continue; + break; + + case EGSD__C_SYMG: + if ((e->flags & EGSY__V_DEF) && (e->flags & EGSY__V_NORM)) + { + bfd_vma sbase = 0; + asection *s; + + value = e->code_value; + + /* Find containing section. */ + for (s = abfd->sections; s; s = s->next) + { + if (value >= s->vma + && s->vma > sbase + && !(s->flags & SEC_COFF_SHARED_LIBRARY) + && (s->size > 0 || !(e->flags & EGSY__V_REL))) + { + sbase = s->vma; + sec = s; + } + } + value -= sbase; + } + else + continue; + break; + + default: + abort (); + } + + l = strlen (name); + sname = bfd_alloc (abfd, l + 5); + if (sname == NULL) + return FALSE; + memcpy (sname, name, l); + memcpy (sname + l, "..en", 5); + + sym = &syms[n++]; + sym->name = sname; + sym->section = sec; + sym->flags = flags; + sym->value = value; + sym->udata.p = NULL; + } + + return n; +} + +/* Private dump. */ + +static const char * +vms_time_to_str (unsigned char *buf) +{ + time_t t = vms_rawtime_to_time_t (buf); + char *res = ctime (&t); + + if (!res) + res = "*invalid time*"; + else + res[24] = 0; + return res; +} + +static void +evax_bfd_print_emh (FILE *file, unsigned char *rec, unsigned int rec_len) +{ + struct vms_emh_common *emh = (struct vms_emh_common *)rec; + unsigned int subtype; + + subtype = (unsigned)bfd_getl16 (emh->subtyp); + + fprintf (file, _(" EMH %u (len=%u): "), subtype, rec_len); + + switch (subtype) + { + case EMH__C_MHD: + { + struct vms_emh_mhd *mhd = (struct vms_emh_mhd *)rec; + const char *name; + + fprintf (file, _("Module header\n")); + fprintf (file, _(" structure level: %u\n"), mhd->strlvl); + fprintf (file, _(" max record size: %u\n"), + (unsigned)bfd_getl32 (mhd->recsiz)); + name = (char *)(mhd + 1); + fprintf (file, _(" module name : %.*s\n"), name[0], name + 1); + name += name[0] + 1; + fprintf (file, _(" module version : %.*s\n"), name[0], name + 1); + name += name[0] + 1; + fprintf (file, _(" compile date : %.17s\n"), name); + } + break; + case EMH__C_LNM: + { + fprintf (file, _("Language Processor Name\n")); + fprintf (file, _(" language name: %.*s\n"), + (int)(rec_len - sizeof (struct vms_emh_common)), + (char *)rec + sizeof (struct vms_emh_common)); + } + break; + case EMH__C_SRC: + { + fprintf (file, _("Source Files Header\n")); + fprintf (file, _(" file: %.*s\n"), + (int)(rec_len - sizeof (struct vms_emh_common)), + (char *)rec + sizeof (struct vms_emh_common)); + } + break; + case EMH__C_TTL: + { + fprintf (file, _("Title Text Header\n")); + fprintf (file, _(" title: %.*s\n"), + (int)(rec_len - sizeof (struct vms_emh_common)), + (char *)rec + sizeof (struct vms_emh_common)); + } + break; + case EMH__C_CPR: + { + fprintf (file, _("Copyright Header\n")); + fprintf (file, _(" copyright: %.*s\n"), + (int)(rec_len - sizeof (struct vms_emh_common)), + (char *)rec + sizeof (struct vms_emh_common)); + } + break; + default: + fprintf (file, _("unhandled emh subtype %u\n"), subtype); + break; + } +} + +static void +evax_bfd_print_eeom (FILE *file, unsigned char *rec, unsigned int rec_len) +{ + struct vms_eeom *eeom = (struct vms_eeom *)rec; + + fprintf (file, _(" EEOM (len=%u):\n"), rec_len); + fprintf (file, _(" number of cond linkage pairs: %u\n"), + (unsigned)bfd_getl32 (eeom->total_lps)); + fprintf (file, _(" completion code: %u\n"), + (unsigned)bfd_getl16 (eeom->comcod)); + if (rec_len > 10) + { + fprintf (file, _(" transfer addr flags: 0x%02x\n"), eeom->tfrflg); + fprintf (file, _(" transfer addr psect: %u\n"), + (unsigned)bfd_getl32 (eeom->psindx)); + fprintf (file, _(" transfer address : 0x%08x\n"), + (unsigned)bfd_getl32 (eeom->tfradr)); + } +} + +static void +exav_bfd_print_egsy_flags (unsigned int flags, FILE *file) +{ + if (flags & EGSY__V_WEAK) + fputs (_(" WEAK"), file); + if (flags & EGSY__V_DEF) + fputs (_(" DEF"), file); + if (flags & EGSY__V_UNI) + fputs (_(" UNI"), file); + if (flags & EGSY__V_REL) + fputs (_(" REL"), file); + if (flags & EGSY__V_COMM) + fputs (_(" COMM"), file); + if (flags & EGSY__V_VECEP) + fputs (_(" VECEP"), file); + if (flags & EGSY__V_NORM) + fputs (_(" NORM"), file); + if (flags & EGSY__V_QUAD_VAL) + fputs (_(" QVAL"), file); +} + +static void +evax_bfd_print_egsd (FILE *file, unsigned char *rec, unsigned int rec_len) +{ + unsigned int off = sizeof (struct vms_egsd); + unsigned int n; + + fprintf (file, _(" EGSD (len=%u):\n"), rec_len); + + n = 0; + for (off = sizeof (struct vms_egsd); off < rec_len; ) + { + struct vms_egsd_entry *e = (struct vms_egsd_entry *)(rec + off); + unsigned int type; + unsigned int len; + + type = (unsigned)bfd_getl16 (e->gsdtyp); + len = (unsigned)bfd_getl16 (e->gsdsiz); + + fprintf (file, _(" EGSD entry %2u (type: %u, len: %u): "), + n, type, len); + n++; + + switch (type) + { + case EGSD__C_PSC: + { + struct vms_egps *egps = (struct vms_egps *)e; + unsigned int flags = bfd_getl16 (egps->flags); + unsigned int l; + + fprintf (file, _("PSC - Program section definition\n")); + fprintf (file, _(" alignment : 2**%u\n"), egps->align); + fprintf (file, _(" flags : 0x%04x"), flags); + if (flags & EGPS__V_PIC) + fputs (_(" PIC"), file); + if (flags & EGPS__V_LIB) + fputs (_(" LIB"), file); + if (flags & EGPS__V_OVR) + fputs (_(" OVR"), file); + if (flags & EGPS__V_REL) + fputs (_(" REL"), file); + if (flags & EGPS__V_GBL) + fputs (_(" GBL"), file); + if (flags & EGPS__V_SHR) + fputs (_(" SHR"), file); + if (flags & EGPS__V_EXE) + fputs (_(" EXE"), file); + if (flags & EGPS__V_RD) + fputs (_(" RD"), file); + if (flags & EGPS__V_WRT) + fputs (_(" WRT"), file); + if (flags & EGPS__V_VEC) + fputs (_(" VEC"), file); + if (flags & EGPS__V_NOMOD) + fputs (_(" NOMOD"), file); + if (flags & EGPS__V_COM) + fputs (_(" COM"), file); + if (flags & EGPS__V_ALLOC_64BIT) + fputs (_(" 64B"), file); + fputc ('\n', file); + l = bfd_getl32 (egps->alloc); + fprintf (file, _(" alloc (len): %u (0x%08x)\n"), l, l); + fprintf (file, _(" name : %.*s\n"), + egps->namlng, egps->name); + } + break; + case EGSD__C_SYM: + { + struct vms_egsy *egsy = (struct vms_egsy *)e; + unsigned int flags = bfd_getl16 (egsy->flags); + + if (flags & EGSY__V_DEF) + { + struct vms_esdf *esdf = (struct vms_esdf *)e; + + fprintf (file, _("SYM - Global symbol definition\n")); + fprintf (file, _(" flags: 0x%04x"), flags); + exav_bfd_print_egsy_flags (flags, file); + fputc ('\n', file); + fprintf (file, _(" psect offset: 0x%08x\n"), + (unsigned)bfd_getl32 (esdf->value)); + if (flags & EGSY__V_NORM) + { + fprintf (file, _(" code address: 0x%08x\n"), + (unsigned)bfd_getl32 (esdf->code_address)); + fprintf (file, _(" psect index for entry point : %u\n"), + (unsigned)bfd_getl32 (esdf->ca_psindx)); + } + fprintf (file, _(" psect index : %u\n"), + (unsigned)bfd_getl32 (esdf->psindx)); + fprintf (file, _(" name : %.*s\n"), + esdf->namlng, esdf->name); + } + else + { + struct vms_esrf *esrf = (struct vms_esrf *)e; + + fprintf (file, _("SYM - Global symbol reference\n")); + fprintf (file, _(" name : %.*s\n"), + esrf->namlng, esrf->name); + } + } + break; + case EGSD__C_SYMG: + { + struct vms_egst *egst = (struct vms_egst *)e; + unsigned int flags = bfd_getl16 (egst->header.flags); + + fprintf (file, _("SYMG - Universal symbol definition\n")); + fprintf (file, _(" flags: 0x%04x"), flags); + exav_bfd_print_egsy_flags (flags, file); + fputc ('\n', file); + fprintf (file, _(" symbol vector offset: 0x%08x\n"), + (unsigned)bfd_getl32 (egst->value)); + fprintf (file, _(" entry point: 0x%08x\n"), + (unsigned)bfd_getl32 (egst->lp_1)); + fprintf (file, _(" proc descr : 0x%08x\n"), + (unsigned)bfd_getl32 (egst->lp_2)); + fprintf (file, _(" psect index: %u\n"), + (unsigned)bfd_getl32 (egst->psindx)); + fprintf (file, _(" name : %.*s\n"), + egst->namlng, egst->name); + } + break; + case EGSD__C_SYMV: + { + struct vms_esdfv *esdfv = (struct vms_esdfv *)e; + unsigned int flags = bfd_getl16 (esdfv->flags); + + fprintf (file, _("SYMV - Vectored symbol definition\n")); + fprintf (file, _(" flags: 0x%04x"), flags); + exav_bfd_print_egsy_flags (flags, file); + fputc ('\n', file); + fprintf (file, _(" vector : 0x%08x\n"), + (unsigned)bfd_getl32 (esdfv->vector)); + fprintf (file, _(" psect offset: %u\n"), + (unsigned)bfd_getl32 (esdfv->value)); + fprintf (file, _(" psect index : %u\n"), + (unsigned)bfd_getl32 (esdfv->psindx)); + fprintf (file, _(" name : %.*s\n"), + esdfv->namlng, esdfv->name); + } + break; + case EGSD__C_SYMM: + { + struct vms_esdfm *esdfm = (struct vms_esdfm *)e; + unsigned int flags = bfd_getl16 (esdfm->flags); + + fprintf (file, _("SYMM - Global symbol definition with version\n")); + fprintf (file, _(" flags: 0x%04x"), flags); + exav_bfd_print_egsy_flags (flags, file); + fputc ('\n', file); + fprintf (file, _(" version mask: 0x%08x\n"), + (unsigned)bfd_getl32 (esdfm->version_mask)); + fprintf (file, _(" psect offset: %u\n"), + (unsigned)bfd_getl32 (esdfm->value)); + fprintf (file, _(" psect index : %u\n"), + (unsigned)bfd_getl32 (esdfm->psindx)); + fprintf (file, _(" name : %.*s\n"), + esdfm->namlng, esdfm->name); + } + break; + default: + fprintf (file, _("unhandled egsd entry type %u\n"), type); + break; + } + off += len; + } +} + +static void +evax_bfd_print_hex (FILE *file, const char *pfx, + const unsigned char *buf, unsigned int len) +{ + unsigned int i; + unsigned int n; + + n = 0; + for (i = 0; i < len; i++) + { + if (n == 0) + fputs (pfx, file); + fprintf (file, " %02x", buf[i]); + n++; + if (n == 16) + { + n = 0; + fputc ('\n', file); + } + } + if (n != 0) + fputc ('\n', file); +} + +static void +evax_bfd_print_etir_stc_ir (FILE *file, const unsigned char *buf, int is_ps) +{ + fprintf (file, _(" linkage index: %u, replacement insn: 0x%08x\n"), + (unsigned)bfd_getl32 (buf), + (unsigned)bfd_getl32 (buf + 16)); + fprintf (file, _(" psect idx 1: %u, offset 1: 0x%08x %08x\n"), + (unsigned)bfd_getl32 (buf + 4), + (unsigned)bfd_getl32 (buf + 12), + (unsigned)bfd_getl32 (buf + 8)); + fprintf (file, _(" psect idx 2: %u, offset 2: 0x%08x %08x\n"), + (unsigned)bfd_getl32 (buf + 20), + (unsigned)bfd_getl32 (buf + 28), + (unsigned)bfd_getl32 (buf + 24)); + if (is_ps) + fprintf (file, _(" psect idx 3: %u, offset 3: 0x%08x %08x\n"), + (unsigned)bfd_getl32 (buf + 32), + (unsigned)bfd_getl32 (buf + 40), + (unsigned)bfd_getl32 (buf + 36)); + else + fprintf (file, _(" global name: %.*s\n"), buf[32], buf + 33); +} + +static void +evax_bfd_print_etir (FILE *file, const char *name, + unsigned char *rec, unsigned int rec_len) +{ + unsigned int off = sizeof (struct vms_egsd); + unsigned int sec_len; + + fprintf (file, _(" %s (len=%u+%u):\n"), name, + (unsigned)(rec_len - sizeof (struct vms_eobjrec)), + (unsigned)sizeof (struct vms_eobjrec)); + + for (off = sizeof (struct vms_eobjrec); off < rec_len; ) + { + struct vms_etir *etir = (struct vms_etir *)(rec + off); + unsigned char *buf; + unsigned int type; + unsigned int size; + + type = bfd_getl16 (etir->rectyp); + size = bfd_getl16 (etir->size); + buf = rec + off + sizeof (struct vms_etir); + + fprintf (file, _(" (type: %3u, size: 4+%3u): "), type, size - 4); + switch (type) + { + case ETIR__C_STA_GBL: + fprintf (file, _("STA_GBL (stack global) %.*s\n"), + buf[0], buf + 1); + break; + case ETIR__C_STA_LW: + fprintf (file, _("STA_LW (stack longword) 0x%08x\n"), + (unsigned)bfd_getl32 (buf)); + break; + case ETIR__C_STA_QW: + fprintf (file, _("STA_QW (stack quadword) 0x%08x %08x\n"), + (unsigned)bfd_getl32 (buf + 4), + (unsigned)bfd_getl32 (buf + 0)); + break; + case ETIR__C_STA_PQ: + fprintf (file, _("STA_PQ (stack psect base + offset)\n")); + fprintf (file, _(" psect: %u, offset: 0x%08x %08x\n"), + (unsigned)bfd_getl32 (buf + 0), + (unsigned)bfd_getl32 (buf + 8), + (unsigned)bfd_getl32 (buf + 4)); + break; + case ETIR__C_STA_LI: + fprintf (file, _("STA_LI (stack literal)\n")); + break; + case ETIR__C_STA_MOD: + fprintf (file, _("STA_MOD (stack module)\n")); + break; + case ETIR__C_STA_CKARG: + fprintf (file, _("STA_CKARG (compare procedure argument)\n")); + break; + + case ETIR__C_STO_B: + fprintf (file, _("STO_B (store byte)\n")); + break; + case ETIR__C_STO_W: + fprintf (file, _("STO_W (store word)\n")); + break; + case ETIR__C_STO_LW: + fprintf (file, _("STO_LW (store longword)\n")); + break; + case ETIR__C_STO_QW: + fprintf (file, _("STO_QW (store quadword)\n")); + break; + case ETIR__C_STO_IMMR: + { + unsigned int len = bfd_getl32 (buf); + fprintf (file, + _("STO_IMMR (store immediate repeat) %u bytes\n"), + len); + evax_bfd_print_hex (file, " ", buf + 4, len); + sec_len += len; + } + break; + case ETIR__C_STO_GBL: + fprintf (file, _("STO_GBL (store global) %.*s\n"), + buf[0], buf + 1); + break; + case ETIR__C_STO_CA: + fprintf (file, _("STO_CA (store code address) %.*s\n"), + buf[0], buf + 1); + break; + case ETIR__C_STO_RB: + fprintf (file, _("STO_RB (store relative branch)\n")); + break; + case ETIR__C_STO_AB: + fprintf (file, _("STO_AB (store absolute branch)\n")); + break; + case ETIR__C_STO_OFF: + fprintf (file, _("STO_OFF (store offset to psect)\n")); + break; + case ETIR__C_STO_IMM: + { + unsigned int len = bfd_getl32 (buf); + fprintf (file, + _("STO_IMM (store immediate) %u bytes\n"), + len); + evax_bfd_print_hex (file, " ", buf + 4, len); + sec_len += len; + } + break; + case ETIR__C_STO_LP_PSB: + fprintf (file, _("STO_OFF (store LP with procedure signature)\n")); + break; + case ETIR__C_STO_HINT_GBL: + fprintf (file, _("STO_BR_GBL (store branch global) *todo*\n")); + break; + case ETIR__C_STO_HINT_PS: + fprintf (file, _("STO_BR_PS (store branch psect + offset) *todo*\n")); + break; + + case ETIR__C_OPR_NOP: + fprintf (file, _("OPR_NOP (no-operation)\n")); + break; + case ETIR__C_OPR_ADD: + fprintf (file, _("OPR_ADD (add)\n")); + break; + case ETIR__C_OPR_SUB: + fprintf (file, _("OPR_SUB (substract)\n")); + break; + case ETIR__C_OPR_MUL: + fprintf (file, _("OPR_MUL (multiply)\n")); + break; + case ETIR__C_OPR_DIV: + fprintf (file, _("OPR_DIV (divide)\n")); + break; + case ETIR__C_OPR_AND: + fprintf (file, _("OPR_AND (logical and)\n")); + break; + case ETIR__C_OPR_IOR: + fprintf (file, _("OPR_IOR (logical inclusive or)\n")); + break; + case ETIR__C_OPR_EOR: + fprintf (file, _("OPR_EOR (logical exclusive or)\n")); + break; + case ETIR__C_OPR_NEG: + fprintf (file, _("OPR_NEG (negate)\n")); + break; + case ETIR__C_OPR_COM: + fprintf (file, _("OPR_COM (complement)\n")); + break; + case ETIR__C_OPR_INSV: + fprintf (file, _("OPR_INSV (insert field)\n")); + break; + case ETIR__C_OPR_ASH: + fprintf (file, _("OPR_ASH (arithmetic shift)\n")); + break; + case ETIR__C_OPR_USH: + fprintf (file, _("OPR_USH (unsigned shift)\n")); + break; + case ETIR__C_OPR_ROT: + fprintf (file, _("OPR_ROT (rotate)\n")); + break; + case ETIR__C_OPR_SEL: + fprintf (file, _("OPR_SEL (select)\n")); + break; + case ETIR__C_OPR_REDEF: + fprintf (file, _("OPR_REDEF (redefine symbol to curr location)\n")); + break; + case ETIR__C_OPR_DFLIT: + fprintf (file, _("OPR_REDEF (define a literal)\n")); + break; + + case ETIR__C_STC_LP: + fprintf (file, _("STC_LP (store cond linkage pair)\n")); + break; + case ETIR__C_STC_LP_PSB: + fprintf (file, + _("STC_LP_PSB (store cond linkage pair + signature)\n")); + fprintf (file, _(" linkage index: %u, procedure: %.*s\n"), + (unsigned)bfd_getl32 (buf), buf[4], buf + 5); + buf += 4 + 1 + buf[4]; + fprintf (file, _(" signature: %.*s\n"), buf[0], buf + 1); + break; + case ETIR__C_STC_GBL: + fprintf (file, _("STC_GBL (store cond global)\n")); + fprintf (file, _(" linkage index: %u, global: %.*s\n"), + (unsigned)bfd_getl32 (buf), buf[4], buf + 5); + break; + case ETIR__C_STC_GCA: + fprintf (file, _("STC_GCA (store cond code address)\n")); + fprintf (file, _(" linkage index: %u, procedure name: %.*s\n"), + (unsigned)bfd_getl32 (buf), buf[4], buf + 5); + break; + case ETIR__C_STC_PS: + fprintf (file, _("STC_PS (store cond psect + offset)\n")); + fprintf (file, + _(" linkage index: %u, psect: %u, offset: 0x%08x %08x\n"), + (unsigned)bfd_getl32 (buf), + (unsigned)bfd_getl32 (buf + 4), + (unsigned)bfd_getl32 (buf + 12), + (unsigned)bfd_getl32 (buf + 8)); + break; + case ETIR__C_STC_NOP_GBL: + fprintf (file, _("STC_NOP_GBL (store cond NOP at global addr)\n")); + evax_bfd_print_etir_stc_ir (file, buf, 0); + break; + case ETIR__C_STC_NOP_PS: + fprintf (file, _("STC_NOP_PS (store cond NOP at psect + offset)\n")); + evax_bfd_print_etir_stc_ir (file, buf, 1); + break; + case ETIR__C_STC_BSR_GBL: + fprintf (file, _("STC_BSR_GBL (store cond BSR at global addr)\n")); + evax_bfd_print_etir_stc_ir (file, buf, 0); + break; + case ETIR__C_STC_BSR_PS: + fprintf (file, _("STC_BSR_PS (store cond BSR at psect + offset)\n")); + evax_bfd_print_etir_stc_ir (file, buf, 1); + break; + case ETIR__C_STC_LDA_GBL: + fprintf (file, _("STC_LDA_GBL (store cond LDA at global addr)\n")); + evax_bfd_print_etir_stc_ir (file, buf, 0); + break; + case ETIR__C_STC_LDA_PS: + fprintf (file, _("STC_LDA_PS (store cond LDA at psect + offset)\n")); + evax_bfd_print_etir_stc_ir (file, buf, 1); + break; + case ETIR__C_STC_BOH_GBL: + fprintf (file, _("STC_BOH_GBL (store cond BOH at global addr)\n")); + evax_bfd_print_etir_stc_ir (file, buf, 0); + break; + case ETIR__C_STC_BOH_PS: + fprintf (file, _("STC_BOH_PS (store cond BOH at psect + offset)\n")); + evax_bfd_print_etir_stc_ir (file, buf, 1); + break; + case ETIR__C_STC_NBH_GBL: + fprintf (file, + _("STC_NBH_GBL (store cond or hint at global addr)\n")); + break; + case ETIR__C_STC_NBH_PS: + fprintf (file, + _("STC_NBH_PS (store cond or hint at psect + offset)\n")); + break; + + case ETIR__C_CTL_SETRB: + fprintf (file, _("CTL_SETRB (set relocation base)\n")); + sec_len += 4; + break; + case ETIR__C_CTL_AUGRB: + { + unsigned int val = bfd_getl32 (buf); + fprintf (file, _("CTL_AUGRB (augment relocation base) %u\n"), val); + } + break; + case ETIR__C_CTL_DFLOC: + fprintf (file, _("CTL_DFLOC (define location)\n")); + break; + case ETIR__C_CTL_STLOC: + fprintf (file, _("CTL_STLOC (set location)\n")); + break; + case ETIR__C_CTL_STKDL: + fprintf (file, _("CTL_STKDL (stack defined location)\n")); + break; + default: + fprintf (file, _("*unhandled*\n")); + break; + } + off += size; + } +} + +static void +evax_bfd_print_eobj (struct bfd *abfd, FILE *file) +{ + bfd_boolean is_first = TRUE; + bfd_boolean has_records = FALSE; + + while (1) + { + unsigned int rec_len; + unsigned int pad_len; + unsigned char *rec; + unsigned int hdr_size; + unsigned int type; + + if (is_first) + { + unsigned char buf[6]; + + is_first = FALSE; + + /* Read 6 bytes. */ + if (bfd_bread (buf, sizeof (buf), abfd) != sizeof (buf)) + { + fprintf (file, _("cannot read GST record length\n")); + return; + } + rec_len = bfd_getl16 (buf + 0); + if (rec_len == bfd_getl16 (buf + 4) + && bfd_getl16 (buf + 2) == EOBJ__C_EMH) + { + /* The format is raw: record-size, type, record-size. */ + has_records = TRUE; + pad_len = (rec_len + 1) & ~1U; + hdr_size = 4; + } + else if (rec_len == EOBJ__C_EMH) + { + has_records = FALSE; + pad_len = bfd_getl16 (buf + 2); + hdr_size = 6; + } + else + { + /* Ill-formed. */ + fprintf (file, _("cannot find EMH in first GST record\n")); + return; + } + rec = bfd_malloc (pad_len); + memcpy (rec, buf + sizeof (buf) - hdr_size, hdr_size); + } + else + { + unsigned int rec_len2 = 0; + unsigned char hdr[4]; + + if (has_records) + { + unsigned char buf_len[2]; + + if (bfd_bread (buf_len, sizeof (buf_len), abfd) + != sizeof (buf_len)) + { + fprintf (file, _("cannot read GST record length\n")); + return; + } + rec_len2 = (unsigned)bfd_getl16 (buf_len); + } + + if (bfd_bread (hdr, sizeof (hdr), abfd) != sizeof (hdr)) + { + fprintf (file, _("cannot read GST record header\n")); + return; + } + rec_len = (unsigned)bfd_getl16 (hdr + 2); + if (has_records) + pad_len = (rec_len + 1) & ~1U; + else + pad_len = rec_len; + rec = bfd_malloc (pad_len); + memcpy (rec, hdr, sizeof (hdr)); + hdr_size = sizeof (hdr); + if (has_records && rec_len2 != rec_len) + { + fprintf (file, _(" corrupted GST\n")); + break; + } + } + + if (bfd_bread (rec + hdr_size, pad_len - hdr_size, abfd) + != pad_len - hdr_size) + { + fprintf (file, _("cannot read GST record\n")); + return; + } + + type = (unsigned)bfd_getl16 (rec); + + switch (type) + { + case EOBJ__C_EMH: + evax_bfd_print_emh (file, rec, rec_len); + break; + case EOBJ__C_EGSD: + evax_bfd_print_egsd (file, rec, rec_len); + break; + case EOBJ__C_EEOM: + evax_bfd_print_eeom (file, rec, rec_len); + free (rec); + return; + break; + case EOBJ__C_ETIR: + evax_bfd_print_etir (file, "ETIR", rec, rec_len); + break; + case EOBJ__C_EDBG: + evax_bfd_print_etir (file, "EDBG", rec, rec_len); + break; + case EOBJ__C_ETBT: + evax_bfd_print_etir (file, "ETBT", rec, rec_len); + break; + default: + fprintf (file, _(" unhandled EOBJ record type %u\n"), type); + break; + } + free (rec); + } +} + +static void +evax_bfd_print_relocation_records (FILE *file, const unsigned char *rel, + unsigned int stride) +{ + while (1) + { + unsigned int base; + unsigned int count; + unsigned int j; + + count = bfd_getl32 (rel + 0); + + if (count == 0) + break; + base = bfd_getl32 (rel + 4); + + fprintf (file, _(" bitcount: %u, base addr: 0x%08x\n"), + count, base); + + rel += 8; + for (j = 0; count > 0; j += 4, count -= 32) + { + unsigned int k; + unsigned int n = 0; + unsigned int val; + + val = bfd_getl32 (rel); + rel += 4; + + fprintf (file, _(" bitmap: 0x%08x (count: %u):\n"), val, count); + + for (k = 0; k < 32; k++) + if (val & (1 << k)) + { + if (n == 0) + fputs (" ", file); + fprintf (file, _(" %08x"), base + (j * 8 + k) * stride); + n++; + if (n == 8) + { + fputs ("\n", file); + n = 0; + } + } + if (n) + fputs ("\n", file); + } + } +} + +static void +evax_bfd_print_address_fixups (FILE *file, const unsigned char *rel) +{ + while (1) + { + unsigned int j; + unsigned int count; + + count = bfd_getl32 (rel + 0); + if (count == 0) + return; + fprintf (file, _(" image %u (%u entries)\n"), + (unsigned)bfd_getl32 (rel + 4), count); + rel += 8; + for (j = 0; j < count; j++) + { + fprintf (file, _(" offset: 0x%08x, val: 0x%08x\n"), + (unsigned)bfd_getl32 (rel + 0), + (unsigned)bfd_getl32 (rel + 4)); + rel += 8; + } + } +} + +static void +evax_bfd_print_reference_fixups (FILE *file, const unsigned char *rel) +{ + unsigned int count; + + while (1) + { + unsigned int j; + unsigned int n = 0; + + count = bfd_getl32 (rel + 0); + if (count == 0) + break; + fprintf (file, _(" image %u (%u entries), offsets:\n"), + (unsigned)bfd_getl32 (rel + 4), count); + rel += 8; + for (j = 0; j < count; j++) + { + if (n == 0) + fputs (" ", file); + fprintf (file, _(" 0x%08x"), (unsigned)bfd_getl32 (rel)); + n++; + if (n == 7) + { + fputs ("\n", file); + n = 0; + } + rel += 4; + } + if (n) + fputs ("\n", file); + } +} + +static void +evax_bfd_print_indent (int indent, FILE *file) +{ + for (; indent; indent--) + fputc (' ', file); +} + +static const char * +evax_bfd_get_dsc_name (unsigned int v) +{ + switch (v) + { + case DSC__K_DTYPE_Z: + return "Z (Unspecified)"; + case DSC__K_DTYPE_V: + return "V (Bit)"; + case DSC__K_DTYPE_BU: + return "BU (Byte logical)"; + case DSC__K_DTYPE_WU: + return "WU (Word logical)"; + case DSC__K_DTYPE_LU: + return "LU (Longword logical)"; + case DSC__K_DTYPE_QU: + return "QU (Quadword logical)"; + case DSC__K_DTYPE_B: + return "B (Byte integer)"; + case DSC__K_DTYPE_W: + return "W (Word integer)"; + case DSC__K_DTYPE_L: + return "L (Longword integer)"; + case DSC__K_DTYPE_Q: + return "Q (Quadword integer)"; + case DSC__K_DTYPE_F: + return "F (Single-precision floating)"; + case DSC__K_DTYPE_D: + return "D (Double-precision floating)"; + case DSC__K_DTYPE_FC: + return "FC (Complex)"; + case DSC__K_DTYPE_DC: + return "DC (Double-precision Complex)"; + case DSC__K_DTYPE_T: + return "T (ASCII text string)"; + case DSC__K_DTYPE_NU: + return "NU (Numeric string, unsigned)"; + case DSC__K_DTYPE_NL: + return "NL (Numeric string, left separate sign)"; + case DSC__K_DTYPE_NLO: + return "NLO (Numeric string, left overpunched sign)"; + case DSC__K_DTYPE_NR: + return "NR (Numeric string, right separate sign)"; + case DSC__K_DTYPE_NRO: + return "NRO (Numeric string, right overpunched sig)"; + case DSC__K_DTYPE_NZ: + return "NZ (Numeric string, zoned sign)"; + case DSC__K_DTYPE_P: + return "P (Packed decimal string)"; + case DSC__K_DTYPE_ZI: + return "ZI (Sequence of instructions)"; + case DSC__K_DTYPE_ZEM: + return "ZEM (Procedure entry mask)"; + case DSC__K_DTYPE_DSC: + return "DSC (Descriptor, used for arrays of dyn strings)"; + case DSC__K_DTYPE_OU: + return "OU (Octaword logical)"; + case DSC__K_DTYPE_O: + return "O (Octaword integer)"; + case DSC__K_DTYPE_G: + return "G (Double precision G floating, 64 bit)"; + case DSC__K_DTYPE_H: + return "H (Quadruple precision floating, 128 bit)"; + case DSC__K_DTYPE_GC: + return "GC (Double precision complex, G floating)"; + case DSC__K_DTYPE_HC: + return "HC (Quadruple precision complex, H floating)"; + case DSC__K_DTYPE_CIT: + return "CIT (COBOL intermediate temporary)"; + case DSC__K_DTYPE_BPV: + return "BPV (Bound Procedure Value)"; + case DSC__K_DTYPE_BLV: + return "BLV (Bound Label Value)"; + case DSC__K_DTYPE_VU: + return "VU (Bit Unaligned)"; + case DSC__K_DTYPE_ADT: + return "ADT (Absolute Date-Time)"; + case DSC__K_DTYPE_VT: + return "VT (Varying Text)"; + case DSC__K_DTYPE_T2: + return "T2 (16-bit char)"; + case DSC__K_DTYPE_VT2: + return "VT2 (16-bit varying char)"; + default: + return "?? (unknown)"; + } +} + +static void +evax_bfd_print_desc (const unsigned char *buf, int indent, FILE *file) +{ + unsigned char bclass = buf[3]; + unsigned char dtype = buf[2]; + unsigned int len = (unsigned)bfd_getl16 (buf); + unsigned int pointer = (unsigned)bfd_getl32 (buf + 4); + + evax_bfd_print_indent (indent, file); + + if (len == 1 && pointer == 0xffffffffUL) + { + /* 64 bits. */ + fprintf (file, _("64 bits *unhandled*\n")); + } + else + { + fprintf (file, _("class: %u, dtype: %u, length: %u, pointer: 0x%08x\n"), + bclass, dtype, len, pointer); + switch (bclass) + { + case DSC__K_CLASS_NCA: + { + const struct vms_dsc_nca *dsc = (const void *)buf; + unsigned int i; + const unsigned char *b; + + evax_bfd_print_indent (indent, file); + fprintf (file, _("non-contiguous array of %s\n"), + evax_bfd_get_dsc_name (dsc->dtype)); + evax_bfd_print_indent (indent + 1, file); + fprintf (file, + _("dimct: %u, aflags: 0x%02x, digits: %u, scale: %u\n"), + dsc->dimct, dsc->aflags, dsc->digits, dsc->scale); + evax_bfd_print_indent (indent + 1, file); + fprintf (file, + _("arsize: %u, a0: 0x%08x\n"), + (unsigned)bfd_getl32 (dsc->arsize), + (unsigned)bfd_getl32 (dsc->a0)); + evax_bfd_print_indent (indent + 1, file); + fprintf (file, _("Strides:\n")); + b = buf + sizeof (*dsc); + for (i = 0; i < dsc->dimct; i++) + { + evax_bfd_print_indent (indent + 2, file); + fprintf (file, _("[%u]: %u\n"), i + 1, + (unsigned)bfd_getl32 (b)); + b += 4; + } + evax_bfd_print_indent (indent + 1, file); + fprintf (file, _("Bounds:\n")); + b = buf + sizeof (*dsc); + for (i = 0; i < dsc->dimct; i++) + { + evax_bfd_print_indent (indent + 2, file); + fprintf (file, _("[%u]: Lower: %u, upper: %u\n"), i + 1, + (unsigned)bfd_getl32 (b + 0), + (unsigned)bfd_getl32 (b + 4)); + b += 8; + } + } + break; + case DSC__K_CLASS_UBS: + { + const struct vms_dsc_ubs *ubs = (const void *)buf; + + evax_bfd_print_indent (indent, file); + fprintf (file, _("unaligned bit-string of %s\n"), + evax_bfd_get_dsc_name (ubs->dtype)); + evax_bfd_print_indent (indent + 1, file); + fprintf (file, + _("base: %u, pos: %u\n"), + (unsigned)bfd_getl32 (ubs->base), + (unsigned)bfd_getl32 (ubs->pos)); + } + break; + default: + fprintf (file, _("*unhandled*\n")); + break; + } + } +} + +static unsigned int +evax_bfd_print_valspec (const unsigned char *buf, int indent, FILE *file) +{ + unsigned int vflags = buf[0]; + unsigned int value = (unsigned)bfd_getl32 (buf + 1); + unsigned int len = 5; + + evax_bfd_print_indent (indent, file); + fprintf (file, _("vflags: 0x%02x, value: 0x%08x "), vflags, value); + buf += 5; + + switch (vflags) + { + case DST__K_VFLAGS_NOVAL: + fprintf (file, _("(no value)\n")); + break; + case DST__K_VFLAGS_NOTACTIVE: + fprintf (file, _("(not active)\n")); + break; + case DST__K_VFLAGS_UNALLOC: + fprintf (file, _("(not allocated)\n")); + break; + case DST__K_VFLAGS_DSC: + fprintf (file, _("(descriptor)\n")); + evax_bfd_print_desc (buf + value, indent + 1, file); + break; + case DST__K_VFLAGS_TVS: + fprintf (file, _("(trailing value)\n")); + break; + case DST__K_VS_FOLLOWS: + fprintf (file, _("(value spec follows)\n")); + break; + case DST__K_VFLAGS_BITOFFS: + fprintf (file, _("(at bit offset %u)\n"), value); + break; + default: + fprintf (file, _("(reg: %u, disp: %u, indir: %u, kind: "), + (vflags & DST__K_REGNUM_MASK) >> DST__K_REGNUM_SHIFT, + vflags & DST__K_DISP ? 1 : 0, + vflags & DST__K_INDIR ? 1 : 0); + switch (vflags & DST__K_VALKIND_MASK) + { + case DST__K_VALKIND_LITERAL: + fputs (_("literal"), file); + break; + case DST__K_VALKIND_ADDR: + fputs (_("address"), file); + break; + case DST__K_VALKIND_DESC: + fputs (_("desc"), file); + break; + case DST__K_VALKIND_REG: + fputs (_("reg"), file); + break; + } + fputs (")\n", file); + break; + } + return len; +} + +static void +evax_bfd_print_typspec (const unsigned char *buf, int indent, FILE *file) +{ + unsigned char kind = buf[2]; + unsigned int len = (unsigned)bfd_getl16 (buf); + + evax_bfd_print_indent (indent, file); + fprintf (file, ("len: %2u, kind: %2u "), len, kind); + buf += 3; + switch (kind) + { + case DST__K_TS_ATOM: + fprintf (file, ("atomic, type=0x%02x %s\n"), + buf[0], evax_bfd_get_dsc_name (buf[0])); + break; + case DST__K_TS_IND: + fprintf (file, ("indirect, defined at 0x%08x\n"), + (unsigned)bfd_getl32 (buf)); + break; + case DST__K_TS_TPTR: + fprintf (file, ("typed pointer\n")); + evax_bfd_print_typspec (buf, indent + 1, file); + break; + case DST__K_TS_PTR: + fprintf (file, ("pointer\n")); + break; + case DST__K_TS_ARRAY: + { + const unsigned char *vs; + unsigned int vec_len; + unsigned int i; + + fprintf (file, ("array, dim: %u, bitmap: "), buf[0]); + vec_len = (buf[0] + 1 + 7) / 8; + for (i = 0; i < vec_len; i++) + fprintf (file, " %02x", buf[i + 1]); + fputc ('\n', file); + vs = buf + 1 + vec_len; + evax_bfd_print_indent (indent, file); + fprintf (file, ("array descriptor:\n")); + vs += evax_bfd_print_valspec (vs, indent + 1, file); + for (i = 0; i < buf[0] + 1U; i++) + if (buf[1 + i / 8] & (1 << (i % 8))) + { + evax_bfd_print_indent (indent, file); + if (i == 0) + fprintf (file, ("type spec for element:\n")); + else + fprintf (file, ("type spec for subscript %u:\n"), i); + evax_bfd_print_typspec (vs, indent + 1, file); + vs += bfd_getl16 (vs); + } + } + break; + default: + fprintf (file, ("*unhandled*\n")); + } +} + +static void +evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) +{ + unsigned int off = 0; + unsigned int pc = 0; + unsigned int line = 0; + + fprintf (file, _("Debug symbol table:\n")); + + while (dst_size > 0) + { + struct vms_dst_header dsth; + unsigned int len; + unsigned int type; + unsigned char *buf; + + if (bfd_bread (&dsth, sizeof (dsth), abfd) != sizeof (dsth)) + { + fprintf (file, _("cannot read DST header\n")); + return; + } + len = bfd_getl16 (dsth.length); + type = bfd_getl16 (dsth.type); + fprintf (file, _(" type: %3u, len: %3u (at 0x%08x): "), + type, len, off); + if (len == 0) + { + fputc ('\n', file); + break; + } + len++; + dst_size -= len; + off += len; + len -= sizeof (dsth); + buf = bfd_malloc (len); + if (bfd_bread (buf, len, abfd) != len) + { + fprintf (file, _("cannot read DST symbol\n")); + return; + } + switch (type) + { + case DSC__K_DTYPE_V: + case DSC__K_DTYPE_BU: + case DSC__K_DTYPE_WU: + case DSC__K_DTYPE_LU: + case DSC__K_DTYPE_QU: + case DSC__K_DTYPE_B: + case DSC__K_DTYPE_W: + case DSC__K_DTYPE_L: + case DSC__K_DTYPE_Q: + case DSC__K_DTYPE_F: + case DSC__K_DTYPE_D: + case DSC__K_DTYPE_FC: + case DSC__K_DTYPE_DC: + case DSC__K_DTYPE_T: + case DSC__K_DTYPE_NU: + case DSC__K_DTYPE_NL: + case DSC__K_DTYPE_NLO: + case DSC__K_DTYPE_NR: + case DSC__K_DTYPE_NRO: + case DSC__K_DTYPE_NZ: + case DSC__K_DTYPE_P: + case DSC__K_DTYPE_ZI: + case DSC__K_DTYPE_ZEM: + case DSC__K_DTYPE_DSC: + case DSC__K_DTYPE_OU: + case DSC__K_DTYPE_O: + case DSC__K_DTYPE_G: + case DSC__K_DTYPE_H: + case DSC__K_DTYPE_GC: + case DSC__K_DTYPE_HC: + case DSC__K_DTYPE_CIT: + case DSC__K_DTYPE_BPV: + case DSC__K_DTYPE_BLV: + case DSC__K_DTYPE_VU: + case DSC__K_DTYPE_ADT: + case DSC__K_DTYPE_VT: + case DSC__K_DTYPE_T2: + case DSC__K_DTYPE_VT2: + fprintf (file, _("standard data: %s\n"), + evax_bfd_get_dsc_name (type)); + evax_bfd_print_valspec (buf, 4, file); + fprintf (file, _(" name: %.*s\n"), buf[5], buf + 6); + break; + case DST__K_MODBEG: + { + struct vms_dst_modbeg *dst = (void *)buf; + const char *name = (const char *)buf + sizeof (*dst); + + fprintf (file, _("modbeg\n")); + fprintf (file, _(" flags: %d, language: %u, " + "major: %u, minor: %u\n"), + dst->flags, + (unsigned)bfd_getl32 (dst->language), + (unsigned)bfd_getl16 (dst->major), + (unsigned)bfd_getl16 (dst->minor)); + fprintf (file, _(" module name: %.*s\n"), + name[0], name + 1); + name += name[0] + 1; + fprintf (file, _(" compiler : %.*s\n"), + name[0], name + 1); + } + break; + case DST__K_MODEND: + fprintf (file, _("modend\n")); + break; + case DST__K_RTNBEG: + { + struct vms_dst_rtnbeg *dst = (void *)buf; + const char *name = (const char *)buf + sizeof (*dst); + + fputs (_("rtnbeg\n"), file); + fprintf (file, _(" flags: %u, address: 0x%08x, " + "pd-address: 0x%08x\n"), + dst->flags, + (unsigned)bfd_getl32 (dst->address), + (unsigned)bfd_getl32 (dst->pd_address)); + fprintf (file, _(" routine name: %.*s\n"), + name[0], name + 1); + } + break; + case DST__K_RTNEND: + { + struct vms_dst_rtnend *dst = (void *)buf; + + fprintf (file, _("rtnend: size 0x%08x\n"), + (unsigned)bfd_getl32 (dst->size)); + } + break; + case DST__K_PROLOG: + { + struct vms_dst_prolog *dst = (void *)buf; + + fprintf (file, _("prolog: bkpt address 0x%08x\n"), + (unsigned)bfd_getl32 (dst->bkpt_addr)); + } + break; + case DST__K_EPILOG: + { + struct vms_dst_epilog *dst = (void *)buf; + + fprintf (file, _("epilog: flags: %u, count: %u\n"), + dst->flags, (unsigned)bfd_getl32 (dst->count)); + } + break; + case DST__K_BLKBEG: + { + struct vms_dst_blkbeg *dst = (void *)buf; + const char *name = (const char *)buf + sizeof (*dst); + + fprintf (file, _("blkbeg: address: 0x%08x, name: %.*s\n"), + (unsigned)bfd_getl32 (dst->address), + name[0], name + 1); + } + break; + case DST__K_BLKEND: + { + struct vms_dst_blkend *dst = (void *)buf; + + fprintf (file, _("blkend: size: 0x%08x\n"), + (unsigned)bfd_getl32 (dst->size)); + } + break; + case DST__K_TYPSPEC: + { + fprintf (file, _("typspec (len: %u)\n"), len); + fprintf (file, _(" name: %.*s\n"), buf[0], buf + 1); + evax_bfd_print_typspec (buf + 1 + buf[0], 5, file); + } + break; + case DST__K_SEPTYP: + { + fprintf (file, _("septyp, name: %.*s\n"), buf[5], buf + 6); + evax_bfd_print_valspec (buf, 4, file); + } + break; + case DST__K_RECBEG: + { + struct vms_dst_recbeg *recbeg = (void *)buf; + const char *name = (const char *)buf + sizeof (*recbeg); + + fprintf (file, _("recbeg: name: %.*s\n"), name[0], name + 1); + evax_bfd_print_valspec (buf, 4, file); + fprintf (file, (" len: %u bits\n"), + (unsigned)bfd_getl32 (name + 1 + name[0])); + } + break; + case DST__K_RECEND: + fprintf (file, _("recend\n")); + break; + case DST__K_ENUMBEG: + fprintf (file, _("enumbeg, len: %u, name: %.*s\n"), + buf[0], buf[1], buf + 2); + break; + case DST__K_ENUMELT: + fprintf (file, _("enumelt, name: %.*s\n"), buf[5], buf + 6); + evax_bfd_print_valspec (buf, 4, file); + break; + case DST__K_ENUMEND: + fprintf (file, _("enumend\n")); + break; + case DST__K_LABEL: + { + struct vms_dst_label *lab = (void *)buf; + fprintf (file, ("label, name: %.*s\n"), + lab->name[0], lab->name + 1); + fprintf (file, (" address: 0x%08x\n"), + (unsigned)bfd_getl32 (lab->value)); + } + break; + case DST__K_DIS_RANGE: + { + unsigned int cnt = bfd_getl32 (buf); + unsigned char *rng = buf + 4; + unsigned int i; + + fprintf (file, _("discontiguous range (nbr: %u)\n"), cnt); + for (i = 0; i < cnt; i++, rng += 8) + fprintf (file, _(" address: 0x%08x, size: %u\n"), + (unsigned)bfd_getl32 (rng), + (unsigned)bfd_getl32 (rng + 4)); + + } + break; + case DST__K_LINE_NUM: + { + unsigned char *buf_orig = buf; + + fprintf (file, _("line num (len: %u)\n"), len); + + while (len > 0) + { + signed char cmd; + unsigned char cmdlen; + unsigned int val; + + cmd = buf[0]; + cmdlen = 0; + + fputs (" ", file); + + switch (cmd) + { + case DST__K_DELTA_PC_W: + val = bfd_getl16 (buf + 1); + fprintf (file, _("delta_pc_w %u\n"), val); + pc += val; + line++; + cmdlen = 3; + break; + case DST__K_INCR_LINUM: + val = buf[1]; + fprintf (file, _("incr_linum: +%u\n"), val); + line += val; + cmdlen = 2; + break; + case DST__K_INCR_LINUM_W: + val = bfd_getl16 (buf + 1); + fprintf (file, _("incr_linum: +%u\n"), val); + line += val; + cmdlen = 3; + break; + case DST__K_SET_LINUM: + line = (unsigned)bfd_getl16 (buf + 1); + fprintf (file, _("set_line_num %u\n"), line); + cmdlen = 3; + break; + case DST__K_SET_LINUM_B: + line = buf[1]; + fprintf (file, _("set_line_num_b %u\n"), line); + cmdlen = 2; + break; + case DST__K_SET_LINUM_L: + line = (unsigned)bfd_getl32 (buf + 1); + fprintf (file, _("set_line_num_l %u\n"), line); + cmdlen = 5; + break; + case DST__K_SET_ABS_PC: + pc = (unsigned)bfd_getl32 (buf + 1); + fprintf (file, _("set_abs_pc: 0x%08x\n"), pc); + cmdlen = 5; + break; + case DST__K_DELTA_PC_L: + fprintf (file, _("delta_pc_l: +0x%08x\n"), + (unsigned)bfd_getl32 (buf + 1)); + cmdlen = 5; + break; + case DST__K_TERM: + fprintf (file, _("term: 0x%02x"), buf[1]); + pc += buf[1]; + fprintf (file, _(" pc: 0x%08x\n"), pc); + cmdlen = 2; + break; + case DST__K_TERM_W: + val = bfd_getl16 (buf + 1); + fprintf (file, _("term_w: 0x%04x"), val); + pc += val; + fprintf (file, _(" pc: 0x%08x\n"), pc); + cmdlen = 3; + break; + default: + if (cmd <= 0) + { + fprintf (file, _("delta pc +%-4d"), -cmd); + line++; /* FIXME: curr increment. */ + pc += -cmd; + fprintf (file, _(" pc: 0x%08x line: %5u\n"), + pc, line); + cmdlen = 1; + } + else + fprintf (file, _(" *unhandled* cmd %u\n"), cmd); + break; + } + if (cmdlen == 0) + break; + len -= cmdlen; + buf += cmdlen; + } + buf = buf_orig; + } + break; + case DST__K_SOURCE: + { + unsigned char *buf_orig = buf; + + fprintf (file, _("source (len: %u)\n"), len); + + while (len > 0) + { + signed char cmd = buf[0]; + unsigned char cmdlen = 0; + + switch (cmd) + { + case DST__K_SRC_DECLFILE: + { + struct vms_dst_src_decl_src *src = (void *)(buf + 1); + const char *name; + + fprintf (file, _(" declfile: len: %u, flags: %u, " + "fileid: %u\n"), + src->length, src->flags, + (unsigned)bfd_getl16 (src->fileid)); + fprintf (file, _(" rms: cdt: 0x%08x %08x, " + "ebk: 0x%08x, ffb: 0x%04x, " + "rfo: %u\n"), + (unsigned)bfd_getl32 (src->rms_cdt + 4), + (unsigned)bfd_getl32 (src->rms_cdt + 0), + (unsigned)bfd_getl32 (src->rms_ebk), + (unsigned)bfd_getl16 (src->rms_ffb), + src->rms_rfo); + name = (const char *)buf + 1 + sizeof (*src); + fprintf (file, _(" filename : %.*s\n"), + name[0], name + 1); + name += name[0] + 1; + fprintf (file, _(" module name: %.*s\n"), + name[0], name + 1); + cmdlen = 2 + src->length; + } + break; + case DST__K_SRC_SETFILE: + fprintf (file, _(" setfile %u\n"), + (unsigned)bfd_getl16 (buf + 1)); + cmdlen = 3; + break; + case DST__K_SRC_SETREC_W: + fprintf (file, _(" setrec %u\n"), + (unsigned)bfd_getl16 (buf + 1)); + cmdlen = 3; + break; + case DST__K_SRC_SETREC_L: + fprintf (file, _(" setrec %u\n"), + (unsigned)bfd_getl32 (buf + 1)); + cmdlen = 5; + break; + case DST__K_SRC_SETLNUM_W: + fprintf (file, _(" setlnum %u\n"), + (unsigned)bfd_getl16 (buf + 1)); + cmdlen = 3; + break; + case DST__K_SRC_SETLNUM_L: + fprintf (file, _(" setlnum %u\n"), + (unsigned)bfd_getl32 (buf + 1)); + cmdlen = 5; + break; + case DST__K_SRC_DEFLINES_W: + fprintf (file, _(" deflines %u\n"), + (unsigned)bfd_getl16 (buf + 1)); + cmdlen = 3; + break; + case DST__K_SRC_DEFLINES_B: + fprintf (file, _(" deflines %u\n"), buf[1]); + cmdlen = 2; + break; + case DST__K_SRC_FORMFEED: + fprintf (file, _(" formfeed\n")); + cmdlen = 1; + break; + default: + fprintf (file, _(" *unhandled* cmd %u\n"), cmd); + break; + } + if (cmdlen == 0) + break; + len -= cmdlen; + buf += cmdlen; + } + buf = buf_orig; + } + break; + default: + fprintf (file, _("*unhandled* dst type %u\n"), type); + break; + } + free (buf); + } +} + +static void +evax_bfd_print_image (bfd *abfd, FILE *file) +{ + struct vms_eihd eihd; + const char *name; + unsigned int val; + unsigned int eiha_off; + unsigned int eihi_off; + unsigned int eihs_off; + unsigned int eisd_off; + unsigned int eihef_off = 0; + unsigned int eihnp_off = 0; + unsigned int dmt_vbn = 0; + unsigned int dmt_size = 0; + unsigned int dst_vbn = 0; + unsigned int dst_size = 0; + unsigned int gst_vbn = 0; + unsigned int gst_size = 0; + unsigned int eiaf_vbn = 0; + unsigned int eiaf_size = 0; + unsigned int eihvn_off; + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) + || bfd_bread (&eihd, sizeof (eihd), abfd) != sizeof (eihd)) + { + fprintf (file, _("cannot read EIHD\n")); + return; + } + fprintf (file, _("EIHD: (size: %u, nbr blocks: %u)\n"), + (unsigned)bfd_getl32 (eihd.size), + (unsigned)bfd_getl32 (eihd.hdrblkcnt)); + fprintf (file, _(" majorid: %u, minorid: %u\n"), + (unsigned)bfd_getl32 (eihd.majorid), + (unsigned)bfd_getl32 (eihd.minorid)); + + val = (unsigned)bfd_getl32 (eihd.imgtype); + switch (val) + { + case EIHD__K_EXE: + name = _("executable"); + break; + case EIHD__K_LIM: + name = _("linkable image"); + break; + default: + name = _("unknown"); + break; + } + fprintf (file, _(" image type: %u (%s)"), val, name); + + val = (unsigned)bfd_getl32 (eihd.subtype); + switch (val) + { + case EIHD__C_NATIVE: + name = _("native"); + break; + case EIHD__C_CLI: + name = _("CLI"); + break; + default: + name = _("unknown"); + break; + } + fprintf (file, _(", subtype: %u (%s)\n"), val, name); + + eisd_off = bfd_getl32 (eihd.isdoff); + eiha_off = bfd_getl32 (eihd.activoff); + eihi_off = bfd_getl32 (eihd.imgidoff); + eihs_off = bfd_getl32 (eihd.symdbgoff); + fprintf (file, _(" offsets: isd: %u, activ: %u, symdbg: %u, " + "imgid: %u, patch: %u\n"), + eisd_off, eiha_off, eihs_off, eihi_off, + (unsigned)bfd_getl32 (eihd.patchoff)); + fprintf (file, _(" fixup info rva: ")); + bfd_fprintf_vma (abfd, file, bfd_getl64 (eihd.iafva)); + fprintf (file, _(", symbol vector rva: ")); + bfd_fprintf_vma (abfd, file, bfd_getl64 (eihd.symvva)); + eihvn_off = bfd_getl32 (eihd.version_array_off); + fprintf (file, _("\n" + " version array off: %u\n"), + eihvn_off); + fprintf (file, + _(" img I/O count: %u, nbr channels: %u, req pri: %08x%08x\n"), + (unsigned)bfd_getl32 (eihd.imgiocnt), + (unsigned)bfd_getl32 (eihd.iochancnt), + (unsigned)bfd_getl32 (eihd.privreqs + 4), + (unsigned)bfd_getl32 (eihd.privreqs + 0)); + val = (unsigned)bfd_getl32 (eihd.lnkflags); + fprintf (file, _(" linker flags: %08x:"), val); + if (val & EIHD__M_LNKDEBUG) + fprintf (file, " LNKDEBUG"); + if (val & EIHD__M_LNKNOTFR) + fprintf (file, " LNKNOTFR"); + if (val & EIHD__M_NOP0BUFS) + fprintf (file, " NOP0BUFS"); + if (val & EIHD__M_PICIMG) + fprintf (file, " PICIMG"); + if (val & EIHD__M_P0IMAGE) + fprintf (file, " P0IMAGE"); + if (val & EIHD__M_DBGDMT) + fprintf (file, " DBGDMT"); + if (val & EIHD__M_INISHR) + fprintf (file, " INISHR"); + if (val & EIHD__M_XLATED) + fprintf (file, " XLATED"); + if (val & EIHD__M_BIND_CODE_SEC) + fprintf (file, " BIND_CODE_SEC"); + if (val & EIHD__M_BIND_DATA_SEC) + fprintf (file, " BIND_DATA_SEC"); + if (val & EIHD__M_MKTHREADS) + fprintf (file, " MKTHREADS"); + if (val & EIHD__M_UPCALLS) + fprintf (file, " UPCALLS"); + if (val & EIHD__M_OMV_READY) + fprintf (file, " OMV_READY"); + if (val & EIHD__M_EXT_BIND_SECT) + fprintf (file, " EXT_BIND_SECT"); + fprintf (file, "\n"); + fprintf (file, _(" ident: 0x%08x, sysver: 0x%08x, " + "match ctrl: %u, symvect_size: %u\n"), + (unsigned)bfd_getl32 (eihd.ident), + (unsigned)bfd_getl32 (eihd.sysver), + eihd.matchctl, + (unsigned)bfd_getl32 (eihd.symvect_size)); + fprintf (file, _(" BPAGE: %u"), + (unsigned)bfd_getl32 (eihd.virt_mem_block_size)); + if (val & (EIHD__M_OMV_READY | EIHD__M_EXT_BIND_SECT)) + { + eihef_off = bfd_getl32 (eihd.ext_fixup_off); + eihnp_off = bfd_getl32 (eihd.noopt_psect_off); + fprintf (file, _(", ext fixup offset: %u, no_opt psect off: %u"), + eihef_off, eihnp_off); + } + fprintf (file, _(", alias: %u\n"), (unsigned)bfd_getl16 (eihd.alias)); + + if (eihvn_off != 0) + { + struct vms_eihvn eihvn; + unsigned int mask; + unsigned int j; + + fprintf (file, _("system version array information:\n")); + if (bfd_seek (abfd, (file_ptr) eihvn_off, SEEK_SET) + || bfd_bread (&eihvn, sizeof (eihvn), abfd) != sizeof (eihvn)) + { + fprintf (file, _("cannot read EIHVN header\n")); + return; + } + mask = bfd_getl32 (eihvn.subsystem_mask); + for (j = 0; j < 32; j++) + if (mask & (1 << j)) + { + struct vms_eihvn_subversion ver; + if (bfd_bread (&ver, sizeof (ver), abfd) != sizeof (ver)) + { + fprintf (file, _("cannot read EIHVN version\n")); + return; + } + fprintf (file, _(" %02u "), j); + switch (j) + { + case EIHVN__BASE_IMAGE_BIT: + fputs (_("BASE_IMAGE "), file); + break; + case EIHVN__MEMORY_MANAGEMENT_BIT: + fputs (_("MEMORY_MANAGEMENT"), file); + break; + case EIHVN__IO_BIT: + fputs (_("IO "), file); + break; + case EIHVN__FILES_VOLUMES_BIT: + fputs (_("FILES_VOLUMES "), file); + break; + case EIHVN__PROCESS_SCHED_BIT: + fputs (_("PROCESS_SCHED "), file); + break; + case EIHVN__SYSGEN_BIT: + fputs (_("SYSGEN "), file); + break; + case EIHVN__CLUSTERS_LOCKMGR_BIT: + fputs (_("CLUSTERS_LOCKMGR "), file); + break; + case EIHVN__LOGICAL_NAMES_BIT: + fputs (_("LOGICAL_NAMES "), file); + break; + case EIHVN__SECURITY_BIT: + fputs (_("SECURITY "), file); + break; + case EIHVN__IMAGE_ACTIVATOR_BIT: + fputs (_("IMAGE_ACTIVATOR "), file); + break; + case EIHVN__NETWORKS_BIT: + fputs (_("NETWORKS "), file); + break; + case EIHVN__COUNTERS_BIT: + fputs (_("COUNTERS "), file); + break; + case EIHVN__STABLE_BIT: + fputs (_("STABLE "), file); + break; + case EIHVN__MISC_BIT: + fputs (_("MISC "), file); + break; + case EIHVN__CPU_BIT: + fputs (_("CPU "), file); + break; + case EIHVN__VOLATILE_BIT: + fputs (_("VOLATILE "), file); + break; + case EIHVN__SHELL_BIT: + fputs (_("SHELL "), file); + break; + case EIHVN__POSIX_BIT: + fputs (_("POSIX "), file); + break; + case EIHVN__MULTI_PROCESSING_BIT: + fputs (_("MULTI_PROCESSING "), file); + break; + case EIHVN__GALAXY_BIT: + fputs (_("GALAXY "), file); + break; + default: + fputs (_("*unknown* "), file); + break; + } + fprintf (file, _(": %u.%u\n"), + (unsigned)bfd_getl16 (ver.major), + (unsigned)bfd_getl16 (ver.minor)); + } + } + + if (eiha_off != 0) + { + struct vms_eiha eiha; + + if (bfd_seek (abfd, (file_ptr) eiha_off, SEEK_SET) + || bfd_bread (&eiha, sizeof (eiha), abfd) != sizeof (eiha)) + { + fprintf (file, _("cannot read EIHA\n")); + return; + } + fprintf (file, _("Image activation: (size=%u)\n"), + (unsigned)bfd_getl32 (eiha.size)); + fprintf (file, _(" First address : 0x%08x 0x%08x\n"), + (unsigned)bfd_getl32 (eiha.tfradr1_h), + (unsigned)bfd_getl32 (eiha.tfradr1)); + fprintf (file, _(" Second address: 0x%08x 0x%08x\n"), + (unsigned)bfd_getl32 (eiha.tfradr2_h), + (unsigned)bfd_getl32 (eiha.tfradr2)); + fprintf (file, _(" Third address : 0x%08x 0x%08x\n"), + (unsigned)bfd_getl32 (eiha.tfradr3_h), + (unsigned)bfd_getl32 (eiha.tfradr3)); + fprintf (file, _(" Fourth address: 0x%08x 0x%08x\n"), + (unsigned)bfd_getl32 (eiha.tfradr4_h), + (unsigned)bfd_getl32 (eiha.tfradr4)); + fprintf (file, _(" Shared image : 0x%08x 0x%08x\n"), + (unsigned)bfd_getl32 (eiha.inishr_h), + (unsigned)bfd_getl32 (eiha.inishr)); + } + if (eihi_off != 0) + { + struct vms_eihi eihi; + + if (bfd_seek (abfd, (file_ptr) eihi_off, SEEK_SET) + || bfd_bread (&eihi, sizeof (eihi), abfd) != sizeof (eihi)) + { + fprintf (file, _("cannot read EIHI\n")); + return; + } + fprintf (file, _("Image identification: (major: %u, minor: %u)\n"), + (unsigned)bfd_getl32 (eihi.majorid), + (unsigned)bfd_getl32 (eihi.minorid)); + fprintf (file, _(" image name : %.*s\n"), + eihi.imgnam[0], eihi.imgnam + 1); + fprintf (file, _(" link time : %s\n"), + vms_time_to_str (eihi.linktime)); + fprintf (file, _(" image ident : %.*s\n"), + eihi.imgid[0], eihi.imgid + 1); + fprintf (file, _(" linker ident : %.*s\n"), + eihi.linkid[0], eihi.linkid + 1); + fprintf (file, _(" image build ident: %.*s\n"), + eihi.imgbid[0], eihi.imgbid + 1); + } + if (eihs_off != 0) + { + struct vms_eihs eihs; + + if (bfd_seek (abfd, (file_ptr) eihs_off, SEEK_SET) + || bfd_bread (&eihs, sizeof (eihs), abfd) != sizeof (eihs)) + { + fprintf (file, _("cannot read EIHS\n")); + return; + } + fprintf (file, _("Image symbol & debug table: (major: %u, minor: %u)\n"), + (unsigned)bfd_getl32 (eihs.majorid), + (unsigned)bfd_getl32 (eihs.minorid)); + dst_vbn = bfd_getl32 (eihs.dstvbn); + dst_size = bfd_getl32 (eihs.dstsize); + fprintf (file, _(" debug symbol table : vbn: %u, size: %u\n"), + dst_vbn, dst_size); + gst_vbn = bfd_getl32 (eihs.gstvbn); + gst_size = bfd_getl32 (eihs.gstsize); + fprintf (file, _(" global symbol table: vbn: %u, records: %u\n"), + gst_vbn, gst_size); + dmt_vbn = bfd_getl32 (eihs.dmtvbn); + dmt_size = bfd_getl32 (eihs.dmtsize); + fprintf (file, _(" debug module table : vbn: %u, size: %u\n"), + dmt_vbn, dmt_size); + } + while (eisd_off != 0) + { + struct vms_eisd eisd; + unsigned int len; + + while (1) + { + if (bfd_seek (abfd, (file_ptr) eisd_off, SEEK_SET) + || bfd_bread (&eisd, sizeof (eisd), abfd) != sizeof (eisd)) + { + fprintf (file, _("cannot read EISD\n")); + return; + } + len = (unsigned)bfd_getl32 (eisd.eisdsize); + if (len != (unsigned)-1) + break; + + /* Next block. */ + eisd_off = (eisd_off + VMS_BLOCK_SIZE) & ~(VMS_BLOCK_SIZE - 1); + } + fprintf (file, _("Image section descriptor: (major: %u, minor: %u, " + "size: %u, offset: %u)\n"), + (unsigned)bfd_getl32 (eisd.majorid), + (unsigned)bfd_getl32 (eisd.minorid), + len, eisd_off); + if (len == 0) + break; + fprintf (file, _(" section: base: 0x%08x%08x size: 0x%08x\n"), + (unsigned)bfd_getl32 (eisd.virt_addr + 4), + (unsigned)bfd_getl32 (eisd.virt_addr + 0), + (unsigned)bfd_getl32 (eisd.secsize)); + val = (unsigned)bfd_getl32 (eisd.flags); + fprintf (file, _(" flags: 0x%04x"), val); + if (val & EISD__M_GBL) + fprintf (file, " GBL"); + if (val & EISD__M_CRF) + fprintf (file, " CRF"); + if (val & EISD__M_DZRO) + fprintf (file, " DZRO"); + if (val & EISD__M_WRT) + fprintf (file, " WRT"); + if (val & EISD__M_INITALCODE) + fprintf (file, " INITALCODE"); + if (val & EISD__M_BASED) + fprintf (file, " BASED"); + if (val & EISD__M_FIXUPVEC) + fprintf (file, " FIXUPVEC"); + if (val & EISD__M_RESIDENT) + fprintf (file, " RESIDENT"); + if (val & EISD__M_VECTOR) + fprintf (file, " VECTOR"); + if (val & EISD__M_PROTECT) + fprintf (file, " PROTECT"); + if (val & EISD__M_LASTCLU) + fprintf (file, " LASTCLU"); + if (val & EISD__M_EXE) + fprintf (file, " EXE"); + if (val & EISD__M_NONSHRADR) + fprintf (file, " NONSHRADR"); + if (val & EISD__M_QUAD_LENGTH) + fprintf (file, " QUAD_LENGTH"); + if (val & EISD__M_ALLOC_64BIT) + fprintf (file, " ALLOC_64BIT"); + fprintf (file, "\n"); + if (val & EISD__M_FIXUPVEC) + { + eiaf_vbn = bfd_getl32 (eisd.vbn); + eiaf_size = bfd_getl32 (eisd.secsize); + } + fprintf (file, _(" vbn: %u, pfc: %u, matchctl: %u type: %u ("), + (unsigned)bfd_getl32 (eisd.vbn), + eisd.pfc, eisd.matchctl, eisd.type); + switch (eisd.type) + { + case EISD__K_NORMAL: + fputs (_("NORMAL"), file); + break; + case EISD__K_SHRFXD: + fputs (_("SHRFXD"), file); + break; + case EISD__K_PRVFXD: + fputs (_("PRVFXD"), file); + break; + case EISD__K_SHRPIC: + fputs (_("SHRPIC"), file); + break; + case EISD__K_PRVPIC: + fputs (_("PRVPIC"), file); + break; + case EISD__K_USRSTACK: + fputs (_("USRSTACK"), file); + break; + default: + fputs (_("*unknown*"), file); + break; + } + fputs (_(")\n"), file); + if (val & EISD__M_GBL) + fprintf (file, _(" ident: 0x%08x, name: %.*s\n"), + (unsigned)bfd_getl32 (eisd.ident), + eisd.gblnam[0], eisd.gblnam + 1); + eisd_off += len; + } + + if (dmt_vbn != 0) + { + if (bfd_seek (abfd, (file_ptr) (dmt_vbn - 1) * VMS_BLOCK_SIZE, SEEK_SET)) + { + fprintf (file, _("cannot read DMT\n")); + return; + } + + fprintf (file, _("Debug module table:\n")); + + while (dmt_size > 0) + { + struct vms_dmt_header dmth; + unsigned int count; + + if (bfd_bread (&dmth, sizeof (dmth), abfd) != sizeof (dmth)) + { + fprintf (file, _("cannot read DMT header\n")); + return; + } + count = bfd_getl16 (dmth.psect_count); + fprintf (file, + _(" module address: 0x%08x, size: 0x%08x, (%u psect)\n"), + (unsigned)bfd_getl32 (dmth.modbeg), + (unsigned)bfd_getl32 (dmth.size), count); + dmt_size -= sizeof (dmth); + while (count > 0) + { + struct vms_dmt_psect dmtp; + + if (bfd_bread (&dmtp, sizeof (dmtp), abfd) != sizeof (dmtp)) + { + fprintf (file, _("cannot read DMT psect\n")); + return; + } + fprintf (file, _(" psect start: 0x%08x, length: %u\n"), + (unsigned)bfd_getl32 (dmtp.start), + (unsigned)bfd_getl32 (dmtp.length)); + count--; + dmt_size -= sizeof (dmtp); + } + } + } + + if (dst_vbn != 0) + { + if (bfd_seek (abfd, (file_ptr) (dst_vbn - 1) * VMS_BLOCK_SIZE, SEEK_SET)) + { + fprintf (file, _("cannot read DST\n")); + return; + } + + evax_bfd_print_dst (abfd, dst_size, file); + } + if (gst_vbn != 0) + { + if (bfd_seek (abfd, (file_ptr) (gst_vbn - 1) * VMS_BLOCK_SIZE, SEEK_SET)) + { + fprintf (file, _("cannot read GST\n")); + return; + } + + fprintf (file, _("Global symbol table:\n")); + evax_bfd_print_eobj (abfd, file); + } + if (eiaf_vbn != 0) + { + unsigned char *buf; + struct vms_eiaf *eiaf; + unsigned int qrelfixoff; + unsigned int lrelfixoff; + unsigned int qdotadroff; + unsigned int ldotadroff; + unsigned int shrimgcnt; + unsigned int shlstoff; + unsigned int codeadroff; + unsigned int lpfixoff; + unsigned int chgprtoff; + + buf = bfd_malloc (eiaf_size); + + if (bfd_seek (abfd, (file_ptr) (eiaf_vbn - 1) * VMS_BLOCK_SIZE, SEEK_SET) + || bfd_bread (buf, eiaf_size, abfd) != eiaf_size) + { + fprintf (file, _("cannot read EIHA\n")); + free (buf); + return; + } + eiaf = (struct vms_eiaf *)buf; + fprintf (file, + _("Image activator fixup: (major: %u, minor: %u)\n"), + (unsigned)bfd_getl32 (eiaf->majorid), + (unsigned)bfd_getl32 (eiaf->minorid)); + fprintf (file, _(" iaflink : 0x%08x %08x\n"), + (unsigned)bfd_getl32 (eiaf->iaflink + 0), + (unsigned)bfd_getl32 (eiaf->iaflink + 4)); + fprintf (file, _(" fixuplnk: 0x%08x %08x\n"), + (unsigned)bfd_getl32 (eiaf->fixuplnk + 0), + (unsigned)bfd_getl32 (eiaf->fixuplnk + 4)); + fprintf (file, _(" size : %u\n"), + (unsigned)bfd_getl32 (eiaf->size)); + fprintf (file, _(" flags: 0x%08x\n"), + (unsigned)bfd_getl32 (eiaf->flags)); + qrelfixoff = bfd_getl32 (eiaf->qrelfixoff); + lrelfixoff = bfd_getl32 (eiaf->lrelfixoff); + fprintf (file, _(" qrelfixoff: %5u, lrelfixoff: %5u\n"), + qrelfixoff, lrelfixoff); + qdotadroff = bfd_getl32 (eiaf->qdotadroff); + ldotadroff = bfd_getl32 (eiaf->ldotadroff); + fprintf (file, _(" qdotadroff: %5u, ldotadroff: %5u\n"), + qdotadroff, ldotadroff); + codeadroff = bfd_getl32 (eiaf->codeadroff); + lpfixoff = bfd_getl32 (eiaf->lpfixoff); + fprintf (file, _(" codeadroff: %5u, lpfixoff : %5u\n"), + codeadroff, lpfixoff); + chgprtoff = bfd_getl32 (eiaf->chgprtoff); + fprintf (file, _(" chgprtoff : %5u\n"), chgprtoff); + shrimgcnt = bfd_getl32 (eiaf->shrimgcnt); + shlstoff = bfd_getl32 (eiaf->shlstoff); + fprintf (file, _(" shlstoff : %5u, shrimgcnt : %5u\n"), + shlstoff, shrimgcnt); + fprintf (file, _(" shlextra : %5u, permctx : %5u\n"), + (unsigned)bfd_getl32 (eiaf->shlextra), + (unsigned)bfd_getl32 (eiaf->permctx)); + fprintf (file, _(" base_va : 0x%08x\n"), + (unsigned)bfd_getl32 (eiaf->base_va)); + fprintf (file, _(" lppsbfixoff: %5u\n"), + (unsigned)bfd_getl32 (eiaf->lppsbfixoff)); + + if (shlstoff) + { + struct vms_shl *shl = (struct vms_shl *)(buf + shlstoff); + unsigned int j; + + fprintf (file, _(" Shareable images:\n")); + for (j = 0; j < shrimgcnt; j++, shl++) + { + fprintf (file, + _(" %u: size: %u, flags: 0x%02x, name: %.*s\n"), + j, shl->size, shl->flags, + shl->imgnam[0], shl->imgnam + 1); + } + } + if (qrelfixoff != 0) + { + fprintf (file, _(" quad-word relocation fixups:\n")); + evax_bfd_print_relocation_records (file, buf + qrelfixoff, 8); + } + if (lrelfixoff != 0) + { + fprintf (file, _(" long-word relocation fixups:\n")); + evax_bfd_print_relocation_records (file, buf + lrelfixoff, 4); + } + if (qdotadroff != 0) + { + fprintf (file, _(" quad-word .address reference fixups:\n")); + evax_bfd_print_address_fixups (file, buf + qdotadroff); + } + if (ldotadroff != 0) + { + fprintf (file, _(" long-word .address reference fixups:\n")); + evax_bfd_print_address_fixups (file, buf + ldotadroff); + } + if (codeadroff != 0) + { + fprintf (file, _(" Code Address Reference Fixups:\n")); + evax_bfd_print_reference_fixups (file, buf + codeadroff); + } + if (lpfixoff != 0) + { + fprintf (file, _(" Linkage Pairs Referece Fixups:\n")); + evax_bfd_print_reference_fixups (file, buf + lpfixoff); + } + if (chgprtoff) + { + unsigned int count = (unsigned)bfd_getl32 (buf + chgprtoff); + struct vms_eicp *eicp = (struct vms_eicp *)(buf + chgprtoff + 4); + unsigned int j; + + fprintf (file, _(" Change Protection (%u entries):\n"), count); + for (j = 0; j < count; j++, eicp++) + { + unsigned int prot = bfd_getl32 (eicp->newprt); + fprintf (file, + _(" base: 0x%08x %08x, size: 0x%08x, prot: 0x%08x "), + (unsigned)bfd_getl32 (eicp->baseva + 4), + (unsigned)bfd_getl32 (eicp->baseva + 0), + (unsigned)bfd_getl32 (eicp->size), + (unsigned)bfd_getl32 (eicp->newprt)); + switch (prot) + { + case PRT__C_NA: + fprintf (file, "NA"); + break; + case PRT__C_RESERVED: + fprintf (file, "RES"); + break; + case PRT__C_KW: + fprintf (file, "KW"); + break; + case PRT__C_KR: + fprintf (file, "KR"); + break; + case PRT__C_UW: + fprintf (file, "UW"); + break; + case PRT__C_EW: + fprintf (file, "EW"); + break; + case PRT__C_ERKW: + fprintf (file, "ERKW"); + break; + case PRT__C_ER: + fprintf (file, "ER"); + break; + case PRT__C_SW: + fprintf (file, "SW"); + break; + case PRT__C_SREW: + fprintf (file, "SREW"); + break; + case PRT__C_SRKW: + fprintf (file, "SRKW"); + break; + case PRT__C_SR: + fprintf (file, "SR"); + break; + case PRT__C_URSW: + fprintf (file, "URSW"); + break; + case PRT__C_UREW: + fprintf (file, "UREW"); + break; + case PRT__C_URKW: + fprintf (file, "URKW"); + break; + case PRT__C_UR: + fprintf (file, "UR"); + break; + default: + fputs ("??", file); + break; + } + fputc ('\n', file); + } + } + free (buf); + } +} + +static bfd_boolean +vms_bfd_print_private_bfd_data (bfd *abfd, void *ptr) +{ + FILE *file = (FILE *)ptr; + + if (bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC)) + evax_bfd_print_image (abfd, file); + else + { + if (bfd_seek (abfd, 0, SEEK_SET)) + return FALSE; + evax_bfd_print_eobj (abfd, file); + } + return TRUE; +} + +/* Linking. */ + +/* Slurp an ordered set of VMS object records. */ + +static bfd_boolean +alpha_vms_read_sections_content (bfd *abfd, struct bfd_link_info *info) +{ + asection *cur_section; + file_ptr cur_offset; + asection *dst_section; + file_ptr dst_offset; + + if (bfd_seek (abfd, 0, SEEK_SET) != 0) + return FALSE; + + PRIV (image_autoextend) = FALSE; + + cur_section = NULL; + cur_offset = 0; + + dst_section = PRIV (dst_section); + dst_offset = 0; + if (info) + { + if (info->strip == strip_all || info->strip == strip_debugger) + { + dst_offset = 0; + dst_section = NULL; + } + else if (dst_section) + { + dst_offset = dst_section->output_offset; + dst_section = dst_section->output_section; + } + } + + while (1) + { + int type; + bfd_boolean res; + + type = _bfd_vms_get_object_record (abfd); + if (type < 0) + { + vms_debug2 ((2, "next_record failed\n")); + return FALSE; + } + switch (type) + { + case EOBJ__C_ETIR: + PRIV (image_section) = cur_section; + PRIV (image_offset) = cur_offset; + res = _bfd_vms_slurp_etir (abfd, info); + cur_section = PRIV (image_section); + cur_offset = PRIV (image_offset); + break; + case EOBJ__C_EDBG: + case EOBJ__C_ETBT: + if (dst_section == NULL) + continue; + PRIV (image_section) = dst_section; + PRIV (image_offset) = dst_offset; + PRIV (image_autoextend) = TRUE; + res = _bfd_vms_slurp_etir (abfd, info); + PRIV (image_autoextend) = FALSE; + dst_offset = PRIV (image_offset); + break; + case EOBJ__C_EEOM: + return TRUE; + default: + continue; + } + if (!res) + { + vms_debug2 ((2, "slurp eobj type %d failed\n", type)); + return FALSE; + } + } +} + +static int +alpha_vms_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + return 0; +} + +/* Add a linkage pair fixup at address SECT + OFFSET to SHLIB. */ + +static void +alpha_vms_add_fixup_lp (struct bfd_link_info *info, bfd *src, bfd *shlib) +{ + struct alpha_vms_shlib_el *sl; + asection *sect = PRIV2 (src, image_section); + file_ptr offset = PRIV2 (src, image_offset); + + sl = &VEC_EL (alpha_vms_link_hash (info)->shrlibs, + struct alpha_vms_shlib_el, PRIV2 (shlib, shr_index)); + sl->has_fixups = TRUE; + VEC_APPEND_EL (sl->lp, bfd_vma, + sect->output_section->vma + sect->output_offset + offset); +} + +static void +alpha_vms_add_fixup_ca (struct bfd_link_info *info, bfd *src, bfd *shlib) +{ + struct alpha_vms_shlib_el *sl; + asection *sect = PRIV2 (src, image_section); + file_ptr offset = PRIV2 (src, image_offset); + + sl = &VEC_EL (alpha_vms_link_hash (info)->shrlibs, + struct alpha_vms_shlib_el, PRIV2 (shlib, shr_index)); + sl->has_fixups = TRUE; + VEC_APPEND_EL (sl->ca, bfd_vma, + sect->output_section->vma + sect->output_offset + offset); +} + +static void +alpha_vms_add_fixup_qr (struct bfd_link_info *info, bfd *src, + bfd *shlib, bfd_vma vec) +{ + struct alpha_vms_shlib_el *sl; + struct alpha_vms_vma_ref *r; + asection *sect = PRIV2 (src, image_section); + file_ptr offset = PRIV2 (src, image_offset); + + sl = &VEC_EL (alpha_vms_link_hash (info)->shrlibs, + struct alpha_vms_shlib_el, PRIV2 (shlib, shr_index)); + sl->has_fixups = TRUE; + r = VEC_APPEND (sl->qr, struct alpha_vms_vma_ref); + r->vma = sect->output_section->vma + sect->output_offset + offset; + r->ref = vec; +} + +static void +alpha_vms_add_lw_fixup (struct bfd_link_info *info ATTRIBUTE_UNUSED, + unsigned int shr ATTRIBUTE_UNUSED, + bfd_vma vec ATTRIBUTE_UNUSED) +{ + abort (); +} + +#if 0 +static void +alpha_vms_add_qw_fixup (struct bfd_link_info *info ATTRIBUTE_UNUSED, + unsigned int shr ATTRIBUTE_UNUSED, + bfd_vma vec ATTRIBUTE_UNUSED) +{ + abort (); +} +#endif + +static void +alpha_vms_add_lw_reloc (struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ +} + +static void +alpha_vms_add_qw_reloc (struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ +} + +static struct bfd_hash_entry * +alpha_vms_link_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) +{ + struct alpha_vms_link_hash_entry *ret = + (struct alpha_vms_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == NULL) + ret = ((struct alpha_vms_link_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct alpha_vms_link_hash_entry))); + if (ret == NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct alpha_vms_link_hash_entry *) + _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + + ret->sym = NULL; + + return (struct bfd_hash_entry *) ret; +} + +/* Create an Alpha/VMS link hash table. */ + +static struct bfd_link_hash_table * +alpha_vms_bfd_link_hash_table_create (bfd *abfd) +{ + struct alpha_vms_link_hash_table *ret; + bfd_size_type amt = sizeof (struct alpha_vms_link_hash_table); + + ret = (struct alpha_vms_link_hash_table *) bfd_malloc (amt); + if (ret == NULL) + return NULL; + if (!_bfd_link_hash_table_init (&ret->root, abfd, + alpha_vms_link_hash_newfunc, + sizeof (struct alpha_vms_link_hash_entry))) + { + free (ret); + return NULL; + } + + VEC_INIT (ret->shrlibs); + ret->fixup = NULL; + + return &ret->root; +} + +static bfd_boolean +alpha_vms_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) +{ + unsigned int i; + + for (i = 0; i < PRIV (gsd_sym_count); i++) + { + struct vms_symbol_entry *e = PRIV (syms)[i]; + struct alpha_vms_link_hash_entry *h; + asymbol sym; + + if (!alpha_vms_convert_symbol (abfd, e, &sym)) + return FALSE; + + if ((e->flags & EGSY__V_DEF) && abfd->selective_search) + { + /* In selective_search mode, only add definition that are + required. */ + h = (struct alpha_vms_link_hash_entry *)bfd_link_hash_lookup + (info->hash, sym.name, FALSE, FALSE, FALSE); + if (h == NULL || h->root.type != bfd_link_hash_undefined) + continue; + } + else + h = NULL; + + if (_bfd_generic_link_add_one_symbol + (info, abfd, sym.name, sym.flags, sym.section, sym.value, + NULL, FALSE, FALSE, (struct bfd_link_hash_entry **)&h) == FALSE) + return FALSE; + + if ((e->flags & EGSY__V_DEF) + && h->sym == NULL + && abfd->xvec == info->output_bfd->xvec) + h->sym = e; + } + + if (abfd->flags & DYNAMIC) + { + struct alpha_vms_shlib_el *shlib; + + /* We do not want to include any of the sections in a dynamic + object in the output file. See comment in elflink.c. */ + bfd_section_list_clear (abfd); + + shlib = VEC_APPEND (alpha_vms_link_hash (info)->shrlibs, + struct alpha_vms_shlib_el); + shlib->abfd = abfd; + VEC_INIT (shlib->ca); + VEC_INIT (shlib->lp); + VEC_INIT (shlib->qr); + PRIV (shr_index) = VEC_COUNT (alpha_vms_link_hash (info)->shrlibs) - 1; + } + + return TRUE; +} + +static bfd_boolean +alpha_vms_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) +{ + int pass; + struct bfd_link_hash_entry **pundef; + struct bfd_link_hash_entry **next_pundef; + + /* We only accept VMS libraries. */ + if (info->output_bfd->xvec != abfd->xvec) + { + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + /* The archive_pass field in the archive itself is used to + initialize PASS, since we may search the same archive multiple + times. */ + pass = ++abfd->archive_pass; + + /* Look through the list of undefined symbols. */ + for (pundef = &info->hash->undefs; *pundef != NULL; pundef = next_pundef) + { + struct bfd_link_hash_entry *h; + file_ptr file_offset; + bfd *element; + bfd *orig_element; + + h = *pundef; + next_pundef = &(*pundef)->u.undef.next; + + /* 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. */ + if (*pundef != info->hash->undefs_tail) + { + *pundef = *next_pundef; + next_pundef = pundef; + } + continue; + } + + /* Look for this symbol in the archive hash table. */ + file_offset = _bfd_vms_lib_find_symbol (abfd, h->root.string); + if (file_offset == 0) + { + /* Nothing in this slot. */ + continue; + } + + element = bfd_get_elt_at_index (abfd, file_offset); + if (element == NULL) + return FALSE; + + if (element->archive_pass == -1 || element->archive_pass == pass) + continue; + + if (! bfd_check_format (element, bfd_object)) + { + element->archive_pass = -1; + return FALSE; + } + + orig_element = element; + if (bfd_is_thin_archive (abfd)) + { + element = _bfd_vms_lib_get_imagelib_file (element); + if (element == NULL || !bfd_check_format (element, bfd_object)) + { + orig_element->archive_pass = -1; + return FALSE; + } + } + + /* Unlike the generic linker, we know that this element provides + a definition for an undefined symbol and we know that we want + to include it. We don't need to check anything. */ + if (! (*info->callbacks->add_archive_element) (info, element, + h->root.string)) + return FALSE; + if (! alpha_vms_link_add_object_symbols (element, info)) + return FALSE; + + orig_element->archive_pass = pass; + } + + return TRUE; +} + +static bfd_boolean +alpha_vms_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info) +{ + switch (bfd_get_format (abfd)) + { + case bfd_object: + vms_debug2 ((2, "vms_link_add_symbols for object %s\n", + abfd->filename)); + return alpha_vms_link_add_object_symbols (abfd, info); + break; + case bfd_archive: + vms_debug2 ((2, "vms_link_add_symbols for archive %s\n", + abfd->filename)); + return alpha_vms_link_add_archive_symbols (abfd, info); + break; + default: + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } +} + +static bfd_boolean +alpha_vms_build_fixups (struct bfd_link_info *info) +{ + struct alpha_vms_link_hash_table *t = alpha_vms_link_hash (info); + unsigned char *content; + unsigned int i; + unsigned int sz = 0; + unsigned int lp_sz = 0; + unsigned int ca_sz = 0; + unsigned int qr_sz = 0; + unsigned int shrimg_cnt = 0; + struct vms_eiaf *eiaf; + unsigned int off; + asection *sec; + + /* Shared libraries. */ + for (i = 0; i < VEC_COUNT (t->shrlibs); i++) + { + struct alpha_vms_shlib_el *shlib; + + shlib = &VEC_EL (t->shrlibs, struct alpha_vms_shlib_el, i); + + if (!shlib->has_fixups) + continue; + + shrimg_cnt++; + + if (VEC_COUNT (shlib->ca) > 0) + { + /* Header + entries. */ + ca_sz += 8; + ca_sz += VEC_COUNT (shlib->ca) * 4; + } + if (VEC_COUNT (shlib->lp) > 0) + { + /* Header + entries. */ + lp_sz += 8; + lp_sz += VEC_COUNT (shlib->lp) * 4; + } + if (VEC_COUNT (shlib->qr) > 0) + { + /* Header + entries. */ + qr_sz += 8; + qr_sz += VEC_COUNT (shlib->qr) * 8; + } + } + /* Add markers. */ + if (ca_sz > 0) + ca_sz += 8; + if (lp_sz > 0) + lp_sz += 8; + if (qr_sz > 0) + qr_sz += 8; + + /* Finish now if there is no content. */ + if (ca_sz + lp_sz + qr_sz == 0) + return TRUE; + + /* Allocate section content (round-up size) */ + sz = sizeof (struct vms_eiaf) + shrimg_cnt * sizeof (struct vms_shl) + + ca_sz + lp_sz + qr_sz; + sz = (sz + VMS_BLOCK_SIZE - 1) & ~(VMS_BLOCK_SIZE - 1); + content = bfd_zalloc (info->output_bfd, sz); + if (content == NULL) + return FALSE; + + sec = alpha_vms_link_hash (info)->fixup; + sec->contents = content; + sec->size = sz; + + eiaf = (struct vms_eiaf *)content; + off = sizeof (struct vms_eiaf); + bfd_putl32 (0, eiaf->majorid); + bfd_putl32 (0, eiaf->minorid); + bfd_putl32 (0, eiaf->iaflink); + bfd_putl32 (0, eiaf->fixuplnk); + bfd_putl32 (sizeof (struct vms_eiaf), eiaf->size); + bfd_putl32 (0, eiaf->flags); + bfd_putl32 (0, eiaf->qrelfixoff); + bfd_putl32 (0, eiaf->lrelfixoff); + bfd_putl32 (0, eiaf->qdotadroff); + bfd_putl32 (0, eiaf->ldotadroff); + bfd_putl32 (0, eiaf->codeadroff); + bfd_putl32 (0, eiaf->lpfixoff); + bfd_putl32 (0, eiaf->chgprtoff); + bfd_putl32 (shrimg_cnt ? off : 0, eiaf->shlstoff); + bfd_putl32 (shrimg_cnt, eiaf->shrimgcnt); + bfd_putl32 (0, eiaf->shlextra); + bfd_putl32 (0, eiaf->permctx); + bfd_putl32 (0, eiaf->base_va); + bfd_putl32 (0, eiaf->lppsbfixoff); + + if (shrimg_cnt) + { + shrimg_cnt = 0; + + /* Write shl. */ + for (i = 0; i < VEC_COUNT (t->shrlibs); i++) + { + struct alpha_vms_shlib_el *shlib; + struct vms_shl *shl; + + shlib = &VEC_EL (t->shrlibs, struct alpha_vms_shlib_el, i); + + if (!shlib->has_fixups) + continue; + + /* Renumber shared images. */ + PRIV2 (shlib->abfd, shr_index) = shrimg_cnt++; + + shl = (struct vms_shl *)(content + off); + bfd_putl32 (0, shl->baseva); + bfd_putl32 (0, shl->shlptr); + bfd_putl32 (0, shl->ident); + bfd_putl32 (0, shl->permctx); + shl->size = sizeof (struct vms_shl); + bfd_putl16 (0, shl->fill_1); + shl->flags = 0; + bfd_putl32 (0, shl->icb); + shl->imgnam[0] = strlen (PRIV2 (shlib->abfd, hdr_data.hdr_t_name)); + memcpy (shl->imgnam + 1, PRIV2 (shlib->abfd, hdr_data.hdr_t_name), + shl->imgnam[0]); + + off += sizeof (struct vms_shl); + } + + /* CA fixups. */ + if (ca_sz != 0) + { + bfd_putl32 (off, eiaf->codeadroff); + + for (i = 0; i < VEC_COUNT (t->shrlibs); i++) + { + struct alpha_vms_shlib_el *shlib; + unsigned int j; + + shlib = &VEC_EL (t->shrlibs, struct alpha_vms_shlib_el, i); + + if (VEC_COUNT (shlib->ca) == 0) + continue; + + bfd_putl32 (VEC_COUNT (shlib->ca), content + off); + bfd_putl32 (PRIV2 (shlib->abfd, shr_index), content + off + 4); + off += 8; + + for (j = 0; j < VEC_COUNT (shlib->ca); j++) + { + bfd_putl32 (VEC_EL (shlib->ca, bfd_vma, j) - t->base_addr, + content + off); + off += 4; + } + } + + bfd_putl32 (0, content + off); + bfd_putl32 (0, content + off + 4); + off += 8; + } + + /* LP fixups. */ + if (lp_sz != 0) + { + bfd_putl32 (off, eiaf->lpfixoff); + + for (i = 0; i < VEC_COUNT (t->shrlibs); i++) + { + struct alpha_vms_shlib_el *shlib; + unsigned int j; + + shlib = &VEC_EL (t->shrlibs, struct alpha_vms_shlib_el, i); + + if (VEC_COUNT (shlib->lp) == 0) + continue; + + bfd_putl32 (VEC_COUNT (shlib->lp), content + off); + bfd_putl32 (PRIV2 (shlib->abfd, shr_index), content + off + 4); + off += 8; + + for (j = 0; j < VEC_COUNT (shlib->lp); j++) + { + bfd_putl32 (VEC_EL (shlib->lp, bfd_vma, j) - t->base_addr, + content + off); + off += 4; + } + } + + bfd_putl32 (0, content + off); + bfd_putl32 (0, content + off + 4); + off += 8; + } + + /* QR fixups. */ + if (qr_sz != 0) + { + bfd_putl32 (off, eiaf->qdotadroff); + + for (i = 0; i < VEC_COUNT (t->shrlibs); i++) + { + struct alpha_vms_shlib_el *shlib; + unsigned int j; + + shlib = &VEC_EL (t->shrlibs, struct alpha_vms_shlib_el, i); + + if (VEC_COUNT (shlib->qr) == 0) + continue; + + bfd_putl32 (VEC_COUNT (shlib->qr), content + off); + bfd_putl32 (PRIV2 (shlib->abfd, shr_index), content + off + 4); + off += 8; + + for (j = 0; j < VEC_COUNT (shlib->qr); j++) + { + struct alpha_vms_vma_ref *r; + r = &VEC_EL (shlib->qr, struct alpha_vms_vma_ref, j); + bfd_putl32 (r->vma - t->base_addr, content + off); + bfd_putl32 (r->ref, content + off + 4); + off += 8; + } + } + + bfd_putl32 (0, content + off); + bfd_putl32 (0, content + off + 4); + off += 8; + } + + /* CA fixups. */ + } + + return TRUE; +} + +static bfd_boolean +alpha_vms_bfd_final_link (bfd *abfd, struct bfd_link_info *info) +{ + asection *o; + struct bfd_link_order *p; + bfd *sub; + asection *fixupsec; + bfd_vma base_addr; + bfd_vma last_addr; + + bfd_get_outsymbols (abfd) = NULL; + bfd_get_symcount (abfd) = 0; + + /* Mark all sections which will be included in the output file. */ + for (o = abfd->sections; o != NULL; o = o->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) + if (p->type == bfd_indirect_link_order) + p->u.indirect.section->linker_mark = TRUE; + +#if 0 + /* Handle all the link order information for the sections. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + printf ("For section %s (at 0x%08x, flags=0x%08x):\n", + o->name, (unsigned)o->vma, (unsigned)o->flags); + + for (p = o->map_head.link_order; p != NULL; p = p->next) + { + printf (" at 0x%08x - 0x%08x: ", + (unsigned)p->offset, (unsigned)(p->offset + p->size - 1)); + switch (p->type) + { + case bfd_section_reloc_link_order: + case bfd_symbol_reloc_link_order: + printf (" section/symbol reloc\n"); + break; + case bfd_indirect_link_order: + printf (" section %s of %s\n", + p->u.indirect.section->name, + p->u.indirect.section->owner->filename); + break; + case bfd_data_link_order: + printf (" explicit data\n"); + break; + default: + printf (" *unknown* type %u\n", p->type); + break; + } + } + } +#endif + + /* Find entry point. */ + if (bfd_get_start_address (abfd) == 0) + { + bfd *startbfd = NULL; + + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + /* Consider only VMS object files. */ + if (sub->xvec != abfd->xvec) + continue; + + if (!PRIV2 (sub, eom_data).eom_has_transfer) + continue; + if ((PRIV2 (sub, eom_data).eom_b_tfrflg & EEOM__M_WKTFR) && startbfd) + continue; + if (startbfd != NULL + && !(PRIV2 (sub, eom_data).eom_b_tfrflg & EEOM__M_WKTFR)) + { + (*info->callbacks->einfo) + (_("%P: multiple entry points: in modules %B and %B\n"), + startbfd, sub); + continue; + } + startbfd = sub; + } + + if (startbfd) + { + unsigned int ps_idx = PRIV2 (startbfd, eom_data).eom_l_psindx; + bfd_vma tfradr = PRIV2 (startbfd, eom_data).eom_l_tfradr; + asection *sec; + + sec = PRIV2 (startbfd, sections)[ps_idx]; + + bfd_set_start_address + (abfd, sec->output_section->vma + sec->output_offset + tfradr); + } + } + + /* Allocate content. */ + base_addr = (bfd_vma)-1; + last_addr = 0; + for (o = abfd->sections; o != NULL; o = o->next) + { + if (o->flags & SEC_HAS_CONTENTS) + { + o->contents = bfd_alloc (abfd, o->size); + if (o->contents == NULL) + return FALSE; + } + if (o->flags & SEC_LOAD) + { + if (o->vma < base_addr) + base_addr = o->vma; + if (o->vma + o->size > last_addr) + last_addr = o->vma + o->size; + } + } + + fixupsec = bfd_make_section_anyway_with_flags + (info->output_bfd, "$FIXUP$", + SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_LINKER_CREATED); + if (fixupsec == NULL) + return FALSE; + last_addr = (last_addr + 0xffff) & ~0xffff; + fixupsec->vma = last_addr; + + alpha_vms_link_hash (info)->fixup = fixupsec; + alpha_vms_link_hash (info)->base_addr = base_addr; + + /* Read all sections from the inputs. */ + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + if (sub->flags & DYNAMIC) + { + alpha_vms_create_eisd_for_shared (abfd, sub); + continue; + } + + if (!alpha_vms_read_sections_content (sub, info)) + return FALSE; + } + + /* Handle all the link order information for the sections. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + for (p = o->map_head.link_order; p != NULL; p = p->next) + { + switch (p->type) + { + case bfd_section_reloc_link_order: + case bfd_symbol_reloc_link_order: + abort (); + return FALSE; + case bfd_indirect_link_order: + /* Already done. */ + break; + default: + if (! _bfd_default_link_order (abfd, info, o, p)) + return FALSE; + break; + } + } + } + + /* Compute fixups. */ + if (!alpha_vms_build_fixups (info)) + return FALSE; + + return TRUE; +} + +/* Read the contents of a section. + buf points to a buffer of buf_size bytes to be filled with + section data (starting at offset into section) */ + +static bfd_boolean +alpha_vms_get_section_contents (bfd *abfd, asection *section, + void *buf, file_ptr offset, + bfd_size_type count) +{ + asection *sec; + + /* Image are easy. */ + if (bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC)) + return _bfd_generic_get_section_contents (abfd, section, + buf, offset, count); + + /* Safety check. */ + if (offset + count < count + || offset + count > section->size) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + /* Alloc in memory and read ETIRs. */ + BFD_ASSERT (section->contents == NULL); + + for (sec = abfd->sections; sec; sec = sec->next) + { + BFD_ASSERT (sec->contents == NULL); + + if (sec->size != 0 && (sec->flags & SEC_HAS_CONTENTS)) + { + sec->contents = bfd_alloc (abfd, sec->size); + if (sec->contents == NULL) + return FALSE; + } + } + if (!alpha_vms_read_sections_content (abfd, NULL)) + return FALSE; + for (sec = abfd->sections; sec; sec = sec->next) + if (section->contents) + section->flags |= SEC_IN_MEMORY; + memcpy (buf, section->contents + offset, count); + return TRUE; +} + + +/* Set the format of a file being written. */ + +static bfd_boolean +alpha_vms_mkobject (bfd * abfd) +{ + const bfd_arch_info_type *arch; + + vms_debug2 ((1, "alpha_vms_mkobject (%p)\n", abfd)); + + if (!vms_initialize (abfd)) + return FALSE; + + PRIV (recwr.buf) = bfd_alloc (abfd, MAX_OUTREC_SIZE); + if (PRIV (recwr.buf) == NULL) + return FALSE; + + arch = bfd_scan_arch ("alpha"); + + if (arch == 0) + { + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + abfd->arch_info = arch; + return TRUE; +} + + +/* 4.1, generic. */ + +/* Called when the BFD is being closed to do any necessary cleanup. */ + +static bfd_boolean +vms_close_and_cleanup (bfd * abfd) +{ + vms_debug2 ((1, "vms_close_and_cleanup (%p)\n", abfd)); + + if (abfd == NULL || abfd->tdata.any == NULL) + return TRUE; + + if (abfd->format == bfd_archive) + { + bfd_release (abfd, abfd->tdata.any); + abfd->tdata.any = NULL; + return TRUE; + } + + if (PRIV (recrd.buf) != NULL) + free (PRIV (recrd.buf)); + + if (PRIV (sections) != NULL) + free (PRIV (sections)); + + bfd_release (abfd, abfd->tdata.any); + abfd->tdata.any = NULL; + +#ifdef VMS + if (abfd->direction == write_direction) + { + /* Last step on VMS is to convert the file to variable record length + format. */ + if (bfd_cache_close (abfd) != TRUE) + return FALSE; + if (vms_convert_to_var_unix_filename (abfd->filename) != TRUE) + return FALSE; + } +#endif + + return TRUE; +} + +/* Called when a new section is created. */ + +static bfd_boolean +vms_new_section_hook (bfd * abfd, asection *section) +{ + bfd_size_type amt; + + /* Count hasn't been incremented yet. */ + unsigned int section_count = abfd->section_count + 1; + + vms_debug2 ((1, "vms_new_section_hook (%p, [%d]%s), count %d\n", + abfd, section->index, section->name, section_count)); + + bfd_set_section_alignment (abfd, section, 0); + + if (section_count > PRIV (section_count)) + { + amt = section_count; + amt *= sizeof (asection *); + PRIV (sections) = bfd_realloc_or_free (PRIV (sections), amt); + if (PRIV (sections) == NULL) + return FALSE; + PRIV (section_count) = section_count; + } + + vms_debug2 ((6, "section_count: %d\n", PRIV (section_count))); + + PRIV (sections)[section->index] = section; + + vms_debug2 ((7, "%d: %s\n", section->index, section->name)); + + amt = sizeof (struct vms_section_data_struct); + section->used_by_bfd = (PTR) bfd_zalloc (abfd, amt); + if (section->used_by_bfd == NULL) + return FALSE; + + if (strcmp (bfd_get_section_name (abfd, section), "$DST$") == 0) + PRIV (dst_section) = section; + + /* Create the section symbol. */ + return _bfd_generic_new_section_hook (abfd, section); +} + +/* Part 4.5, symbols. */ + +/* Print symbol to file according to how. how is one of + bfd_print_symbol_name just print the name + bfd_print_symbol_more print more (???) + bfd_print_symbol_all print all we know, which is not much right now :-). */ + +static void +vms_print_symbol (bfd * abfd, + void * file, + asymbol *symbol, + bfd_print_symbol_type how) +{ + vms_debug2 ((1, "vms_print_symbol (%p, %p, %p, %d)\n", + abfd, file, symbol, how)); + + switch (how) + { + case bfd_print_symbol_name: + case bfd_print_symbol_more: + fprintf ((FILE *)file," %s", symbol->name); + break; + + case bfd_print_symbol_all: + { + const char *section_name = symbol->section->name; + + bfd_print_symbol_vandf (abfd, file, symbol); + + fprintf ((FILE *) file," %-8s %s", section_name, symbol->name); + } + break; + } +} + +/* Return information about symbol in ret. + + fill type, value and name + type: + A absolute + B bss segment symbol + C common symbol + D data segment symbol + f filename + t a static function symbol + T text segment symbol + U undefined + - debug. */ + +static void +vms_get_symbol_info (bfd * abfd ATTRIBUTE_UNUSED, + asymbol *symbol, + symbol_info *ret) +{ + asection *sec; + + vms_debug2 ((1, "vms_get_symbol_info (%p, %p, %p)\n", abfd, symbol, ret)); + + sec = symbol->section; + + if (ret == NULL) + return; + + if (sec == 0) + ret->type = 'U'; + else if (bfd_is_com_section (sec)) + ret->type = 'C'; + else if (bfd_is_abs_section (sec)) + ret->type = 'A'; + else if (bfd_is_und_section (sec)) + ret->type = 'U'; + else if (bfd_is_ind_section (sec)) + ret->type = 'I'; + else if (bfd_get_section_flags (abfd, sec) & SEC_CODE) + ret->type = 'T'; + else if (bfd_get_section_flags (abfd, sec) & SEC_DATA) + ret->type = 'D'; + else if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) + ret->type = 'B'; + else + ret->type = '-'; + + if (ret->type != 'U') + ret->value = symbol->value + symbol->section->vma; + else + ret->value = 0; + ret->name = symbol->name; +} + +/* Return TRUE if the given symbol sym in the BFD abfd is + a compiler generated local label, else return FALSE. */ + +static bfd_boolean +vms_bfd_is_local_label_name (bfd * abfd ATTRIBUTE_UNUSED, + const char *name) +{ + vms_debug2 ((1, "vms_bfd_is_local_label_name (%p, %s)\n", abfd, name)); + return name[0] == '$'; +} + +/* Part 4.7, writing an object file. */ + +/* Sets the contents of the section section in BFD abfd to the data starting + in memory at LOCATION. The data is written to the output section starting + at offset offset for count bytes. + + Normally TRUE is returned, else FALSE. Possible error returns are: + o bfd_error_no_contents - The output section does not have the + SEC_HAS_CONTENTS attribute, so nothing can be written to it. + o and some more too */ + +static bfd_boolean +_bfd_vms_set_section_contents (bfd * abfd, + asection *section, + const void * location, + file_ptr offset, + bfd_size_type count) +{ + if (section->contents == NULL) + { + section->contents = bfd_alloc (abfd, section->size); + if (section->contents == NULL) + return FALSE; + + memcpy (section->contents + offset, location, (size_t) count); + } + + return TRUE; +} + +/* Set the architecture and machine type in BFD abfd to arch and mach. + Find the correct pointer to a structure and insert it into the arch_info + pointer. */ + +static bfd_boolean +alpha_vms_set_arch_mach (bfd *abfd, + enum bfd_architecture arch, unsigned long mach) +{ + if (arch != bfd_arch_alpha + && arch != bfd_arch_unknown) + return FALSE; + + return bfd_default_set_arch_mach (abfd, arch, mach); +} + +/* Set section VMS flags. Clear NO_FLAGS and set FLAGS. */ + +void +bfd_vms_set_section_flags (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, flagword no_flags, flagword flags) +{ + vms_section_data (sec)->no_flags = no_flags; + vms_section_data (sec)->flags = flags; +} + +struct vms_private_data_struct * +bfd_vms_get_data (bfd *abfd) +{ + return (struct vms_private_data_struct *)abfd->tdata.any; +} + +#define vms_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) +#define vms_bfd_link_just_syms _bfd_generic_link_just_syms +#define vms_bfd_copy_link_hash_symbol_type \ + _bfd_generic_copy_link_hash_symbol_type +#define vms_bfd_is_group_section bfd_generic_is_group_section +#define vms_bfd_discard_group bfd_generic_discard_group +#define vms_section_already_linked _bfd_generic_section_already_linked +#define vms_bfd_define_common_symbol bfd_generic_define_common_symbol +#define vms_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data + +#define vms_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data +#define vms_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define vms_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data +#define vms_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data +#define vms_bfd_set_private_flags _bfd_generic_bfd_set_private_flags +#define vms_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data + +/* Symbols table. */ +#define alpha_vms_make_empty_symbol _bfd_generic_make_empty_symbol +#define alpha_vms_bfd_is_target_special_symbol \ + ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) +#define alpha_vms_print_symbol vms_print_symbol +#define alpha_vms_get_symbol_info vms_get_symbol_info +#define alpha_vms_read_minisymbols _bfd_generic_read_minisymbols +#define alpha_vms_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol +#define alpha_vms_get_lineno _bfd_nosymbols_get_lineno +#define alpha_vms_find_inliner_info _bfd_nosymbols_find_inliner_info +#define alpha_vms_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define alpha_vms_find_nearest_line _bfd_vms_find_nearest_dst_line +#define alpha_vms_bfd_is_local_label_name vms_bfd_is_local_label_name + +/* Generic table. */ +#define alpha_vms_close_and_cleanup vms_close_and_cleanup +#define alpha_vms_bfd_free_cached_info vms_bfd_free_cached_info +#define alpha_vms_new_section_hook vms_new_section_hook +#define alpha_vms_set_section_contents _bfd_vms_set_section_contents +#define alpha_vms_get_section_contents_in_window _bfd_generic_get_section_contents_in_window + +#define alpha_vms_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents + +#define alpha_vms_bfd_relax_section bfd_generic_relax_section +#define alpha_vms_bfd_gc_sections bfd_generic_gc_sections +#define alpha_vms_bfd_merge_sections bfd_generic_merge_sections +#define alpha_vms_bfd_is_group_section bfd_generic_is_group_section +#define alpha_vms_bfd_discard_group bfd_generic_discard_group +#define alpha_vms_section_already_linked \ + _bfd_generic_section_already_linked + +#define alpha_vms_bfd_define_common_symbol bfd_generic_define_common_symbol +#define alpha_vms_bfd_link_hash_table_free _bfd_generic_link_hash_table_free +#define alpha_vms_bfd_link_just_syms _bfd_generic_link_just_syms +#define alpha_vms_bfd_copy_link_hash_symbol_type \ + _bfd_generic_copy_link_hash_symbol_type + +#define alpha_vms_bfd_link_split_section _bfd_generic_link_split_section + +#define alpha_vms_get_dynamic_symtab_upper_bound \ + _bfd_nodynamic_get_dynamic_symtab_upper_bound +#define alpha_vms_canonicalize_dynamic_symtab \ + _bfd_nodynamic_canonicalize_dynamic_symtab +#define alpha_vms_get_dynamic_reloc_upper_bound \ + _bfd_nodynamic_get_dynamic_reloc_upper_bound +#define alpha_vms_canonicalize_dynamic_reloc \ + _bfd_nodynamic_canonicalize_dynamic_reloc + +const bfd_target vms_alpha_vec = +{ + "vms-alpha", /* Name. */ + bfd_target_evax_flavour, + BFD_ENDIAN_LITTLE, /* Data byte order is little. */ + BFD_ENDIAN_LITTLE, /* Header byte order is little. */ + + (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS + | WP_TEXT | D_PAGED), /* Object flags. */ + (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_READONLY | SEC_CODE | SEC_DATA + | SEC_HAS_CONTENTS | SEC_IN_MEMORY), /* Sect flags. */ + 0, /* symbol_leading_char. */ + ' ', /* ar_pad_char. */ + 15, /* ar_max_namelen. */ + 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_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, + + {_bfd_dummy_target, alpha_vms_object_p, /* bfd_check_format. */ + _bfd_vms_lib_alpha_archive_p, _bfd_dummy_target}, + {bfd_false, alpha_vms_mkobject, /* bfd_set_format. */ + _bfd_vms_lib_mkarchive, bfd_false}, + {bfd_false, alpha_vms_write_object_contents, /* bfd_write_contents. */ + _bfd_vms_lib_write_archive_contents, bfd_false}, + + BFD_JUMP_TABLE_GENERIC (alpha_vms), + BFD_JUMP_TABLE_COPY (vms), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_vms_lib), + BFD_JUMP_TABLE_SYMBOLS (alpha_vms), + BFD_JUMP_TABLE_RELOCS (alpha_vms), + BFD_JUMP_TABLE_WRITE (alpha_vms), + BFD_JUMP_TABLE_LINK (alpha_vms), + BFD_JUMP_TABLE_DYNAMIC (alpha_vms), + + NULL, + + (PTR) 0 +}; diff --git a/bfd/vms-gsd.c b/bfd/vms-gsd.c deleted file mode 100644 index d0ffd78..0000000 --- a/bfd/vms-gsd.c +++ /dev/null @@ -1,1082 +0,0 @@ -/* vms-gsd.c -- BFD back-end for VAX (openVMS/VAX) and - EVAX (openVMS/Alpha) files. - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2007, 2009 Free Software Foundation, Inc. - - GSD record handling functions - EGSD record handling functions - - Go and read the openVMS linker manual (esp. appendix B) - if you don't know what's going on here :-) - - Written by Klaus K"ampf (kkaempf@rmi.de) - - 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 3 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., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" - -#include "vms.h" - -/* Typical sections for vax object files. */ - -#define VAX_CODE_NAME "$CODE" -#define VAX_DATA_NAME "$DATA" -#define VAX_ADDRESS_DATA_NAME "$ADDRESS_DATA" - -/* Typical sections for evax object files. */ - -#define EVAX_ABS_NAME "$ABS$" -#define EVAX_CODE_NAME "$CODE$" -#define EVAX_LINK_NAME "$LINK$" -#define EVAX_DATA_NAME "$DATA$" -#define EVAX_BSS_NAME "$BSS$" -#define EVAX_READONLYADDR_NAME "$READONLY_ADDR$" -#define EVAX_READONLY_NAME "$READONLY$" -#define EVAX_LITERAL_NAME "$LITERAL$" -#define EVAX_LITERALS_NAME "$LITERALS" -#define EVAX_COMMON_NAME "$COMMON$" -#define EVAX_LOCAL_NAME "$LOCAL$" - -struct sec_flags_struct -{ - char *name; /* Name of section. */ - int vflags_always; - flagword flags_always; /* Flags we set always. */ - int vflags_hassize; - flagword flags_hassize; /* Flags we set if the section has a size > 0. */ -}; - -/* These flags are deccrtl/vaxcrtl (openVMS 6.2 VAX) compatible. */ - -static struct sec_flags_struct vax_section_flags[] = - { - { VAX_CODE_NAME, - (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_SHR | GPS_S_M_EXE | GPS_S_M_RD), - (SEC_CODE), - (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_SHR | GPS_S_M_EXE | GPS_S_M_RD), - (SEC_IN_MEMORY | SEC_CODE | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, - { VAX_DATA_NAME, - (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_RD | GPS_S_M_WRT), - (SEC_DATA), - (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_RD | GPS_S_M_WRT), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, - { VAX_ADDRESS_DATA_NAME, - (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_RD), - (SEC_DATA | SEC_READONLY), - (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_RD), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, - { NULL, - (GPS_S_M_PIC | GPS_S_M_OVR | GPS_S_M_REL | GPS_S_M_GBL | GPS_S_M_RD | GPS_S_M_WRT), - (SEC_DATA), - (GPS_S_M_PIC | GPS_S_M_OVR | GPS_S_M_REL | GPS_S_M_GBL | GPS_S_M_RD | GPS_S_M_WRT), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) } - }; - -/* These flags are deccrtl/vaxcrtl (openVMS 6.2 Alpha) compatible. */ - -static struct sec_flags_struct evax_section_flags[] = - { - { EVAX_ABS_NAME, - (EGPS_S_V_SHR), - (SEC_DATA), - (EGPS_S_V_SHR), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, - { EVAX_CODE_NAME, - (EGPS_S_V_PIC | EGPS_S_V_REL | EGPS_S_V_SHR | EGPS_S_V_EXE), - (SEC_CODE), - (EGPS_S_V_PIC | EGPS_S_V_REL | EGPS_S_V_SHR | EGPS_S_V_EXE), - (SEC_IN_MEMORY | SEC_CODE | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, - { EVAX_LITERAL_NAME, - (EGPS_S_V_PIC | EGPS_S_V_REL | EGPS_S_V_SHR | EGPS_S_V_RD | EGPS_S_V_NOMOD), - (SEC_DATA | SEC_READONLY), - (EGPS_S_V_PIC | EGPS_S_V_REL | EGPS_S_V_SHR | EGPS_S_V_RD), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, - { EVAX_LINK_NAME, - (EGPS_S_V_REL | EGPS_S_V_RD), - (SEC_DATA | SEC_READONLY), - (EGPS_S_V_REL | EGPS_S_V_RD), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, - { EVAX_DATA_NAME, - (EGPS_S_V_REL | EGPS_S_V_RD | EGPS_S_V_WRT | EGPS_S_V_NOMOD), - (SEC_DATA), - (EGPS_S_V_REL | EGPS_S_V_RD | EGPS_S_V_WRT), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, - { EVAX_BSS_NAME, - (EGPS_S_V_REL | EGPS_S_V_RD | EGPS_S_V_WRT | EGPS_S_V_NOMOD), - (SEC_NO_FLAGS), - (EGPS_S_V_REL | EGPS_S_V_RD | EGPS_S_V_WRT | EGPS_S_V_NOMOD), - (SEC_IN_MEMORY | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, - { EVAX_READONLYADDR_NAME, - (EGPS_S_V_PIC | EGPS_S_V_REL | EGPS_S_V_RD), - (SEC_DATA | SEC_READONLY), - (EGPS_S_V_PIC | EGPS_S_V_REL | EGPS_S_V_RD), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, - { EVAX_READONLY_NAME, - (EGPS_S_V_PIC | EGPS_S_V_REL | EGPS_S_V_SHR | EGPS_S_V_RD | EGPS_S_V_NOMOD), - (SEC_DATA | SEC_READONLY), - (EGPS_S_V_PIC | EGPS_S_V_REL | EGPS_S_V_SHR | EGPS_S_V_RD), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, - { EVAX_LOCAL_NAME, - (EGPS_S_V_REL | EGPS_S_V_RD | EGPS_S_V_WRT), - (SEC_DATA), - (EGPS_S_V_REL | EGPS_S_V_RD | EGPS_S_V_WRT), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, - { EVAX_LITERALS_NAME, - (EGPS_S_V_PIC | EGPS_S_V_OVR), - (SEC_DATA | SEC_READONLY), - (EGPS_S_V_PIC | EGPS_S_V_OVR), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, - { NULL, - (EGPS_S_V_REL | EGPS_S_V_RD | EGPS_S_V_WRT), - (SEC_DATA), - (EGPS_S_V_REL | EGPS_S_V_RD | EGPS_S_V_WRT), - (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) } - }; - -/* Retrieve bfd section flags by name and size. */ - -static flagword -vms_secflag_by_name (bfd *abfd, - struct sec_flags_struct *section_flags, - char *name, - int hassize) -{ - int i = 0; - - while (section_flags[i].name != NULL) - { - if ((PRIV (is_vax)? - strcasecmp (name, section_flags[i].name): - strcmp (name, section_flags[i].name)) == 0) - { - if (hassize) - return section_flags[i].flags_hassize; - else - return section_flags[i].flags_always; - } - i++; - } - if (hassize) - return section_flags[i].flags_hassize; - return section_flags[i].flags_always; -} - -/* Retrieve vms section flags by name and size. */ - -static flagword -vms_esecflag_by_name (struct sec_flags_struct *section_flags, - char *name, - int hassize) -{ - int i = 0; - - while (section_flags[i].name != NULL) - { - if (strcmp (name, section_flags[i].name) == 0) - { - if (hassize) - return section_flags[i].vflags_hassize; - else - return section_flags[i].vflags_always; - } - i++; - } - if (hassize) - return section_flags[i].vflags_hassize; - return section_flags[i].vflags_always; -} - -#if VMS_DEBUG - -struct flagdescstruct { const char *name; flagword value; }; - -static const struct flagdescstruct gpsflagdesc[] = -{ - { "PIC", GPS_S_M_PIC }, - { "LIB", GPS_S_M_LIB }, - { "OVR", GPS_S_M_OVR }, - { "REL", GPS_S_M_REL }, - { "GBL", GPS_S_M_GBL }, - { "SHR", GPS_S_M_SHR }, - { "EXE", GPS_S_M_EXE }, - { "RD", GPS_S_M_RD }, - { "WRT", GPS_S_M_WRT }, - { "VEC", GPS_S_M_VEC }, - { "NOMOD", EGPS_S_V_NOMOD }, - { "COM", EGPS_S_V_COM }, - { NULL, 0 } -}; - -static const struct flagdescstruct gsyflagdesc[] = -{ - { "WEAK", GSY_S_M_WEAK }, - { "DEF", GSY_S_M_DEF }, - { "UNI", GSY_S_M_UNI }, - { "REL", GSY_S_M_REL }, - { "COMM", EGSY_S_V_COMM }, - { "VECEP", EGSY_S_V_VECEP }, - { "NORM", EGSY_S_V_NORM }, - { NULL, 0 } -}; - -static char *flag2str (struct flagdescstruct *, flagword); - -/* Convert flag to printable string. */ - -static char * -flag2str (struct flagdescstruct * flagdesc, flagword flags) -{ - static char res[64]; - int next = 0; - - res[0] = 0; - while (flagdesc->name != NULL) - { - if ((flags & flagdesc->value) != 0) - { - if (next) - strcat (res, ","); - else - next = 1; - strcat (res, flagdesc->name); - } - flagdesc++; - } - return res; -} -#endif - -/* Input routines. */ - -static int register_universal_symbol (bfd *abfd, asymbol *symbol, - int vms_flags); - -/* Process GSD/EGSD record - return 0 on success, -1 on error. */ - -int -_bfd_vms_slurp_gsd (bfd * abfd, int objtype) -{ - int gsd_type, gsd_size; - asection *section; - unsigned char *vms_rec; - flagword new_flags, old_flags; - char *name; - asymbol *symbol; - vms_symbol_entry *entry; - unsigned long base_addr; - unsigned long align_addr; - static unsigned int psect_idx = 0; - -#if VMS_DEBUG - vms_debug (2, "GSD/EGSD (%d/%x)\n", objtype, objtype); -#endif - - switch (objtype) - { - case EOBJ_S_C_EGSD: - PRIV (vms_rec) += 8; /* Skip type, size, l_temp. */ - PRIV (rec_size) -= 8; - break; - case OBJ_S_C_GSD: - PRIV (vms_rec) += 1; - PRIV (rec_size) -= 1; - break; - default: - return -1; - } - - /* Calculate base address for each section. */ - base_addr = 0L; - - abfd->symcount = 0; - - while (PRIV (rec_size) > 0) - { - vms_rec = PRIV (vms_rec); - - if (objtype == OBJ_S_C_GSD) - gsd_type = vms_rec[0]; - else - { - _bfd_vms_get_header_values (abfd, vms_rec, &gsd_type, &gsd_size); - gsd_type += EVAX_OFFSET; - } - -#if VMS_DEBUG - vms_debug (3, "gsd_type %d\n", gsd_type); -#endif - - switch (gsd_type) - { - case GSD_S_C_PSC: - { - /* Program section definition. */ - asection *old_section = 0; - -#if VMS_DEBUG - vms_debug (4, "GSD_S_C_PSC\n"); -#endif - /* If this section isn't a bfd section. */ - if (PRIV (is_vax) && (psect_idx < (abfd->section_count - 1))) - { - /* Check for temporary section from TIR record. */ - if (psect_idx < PRIV (section_count)) - old_section = PRIV (sections)[psect_idx]; - else - old_section = 0; - } - - name = _bfd_vms_save_counted_string (vms_rec + 8); - section = bfd_make_section (abfd, name); - if (!section) - { - (*_bfd_error_handler) (_("bfd_make_section (%s) failed"), - name); - return -1; - } - old_flags = bfd_getl16 (vms_rec + 2); - section->size = bfd_getl32 (vms_rec + 4); /* allocation */ - new_flags = vms_secflag_by_name (abfd, vax_section_flags, name, - section->size > 0); - if (old_flags & EGPS_S_V_REL) - new_flags |= SEC_RELOC; - if (old_flags & GPS_S_M_OVR) - new_flags |= SEC_IS_COMMON; - if (!bfd_set_section_flags (abfd, section, new_flags)) - { - (*_bfd_error_handler) - (_("bfd_set_section_flags (%s, %x) failed"), - name, new_flags); - return -1; - } - section->alignment_power = vms_rec[1]; - align_addr = (1 << section->alignment_power); - if ((base_addr % align_addr) != 0) - base_addr += (align_addr - (base_addr % align_addr)); - section->vma = (bfd_vma)base_addr; - base_addr += section->size; - - /* Global section is common symbol. */ - if (old_flags & GPS_S_M_GBL) - { - entry = _bfd_vms_enter_symbol (abfd, name); - if (entry == NULL) - { - bfd_set_error (bfd_error_no_memory); - return -1; - } - symbol = entry->symbol; - - symbol->value = 0; - symbol->section = section; - symbol->flags = (BSF_GLOBAL | BSF_SECTION_SYM | BSF_OLD_COMMON); - } - - /* Copy saved contents if old_section set. */ - if (old_section != 0) - { - section->contents = old_section->contents; - if (section->size < old_section->size) - { - (*_bfd_error_handler) - (_("Size mismatch section %s=%lx, %s=%lx"), - old_section->name, - (unsigned long) old_section->size, - section->name, - (unsigned long) section->size); - return -1; - } - else if (section->size > old_section->size) - { - section->contents = bfd_realloc (old_section->contents, - section->size); - if (section->contents == NULL) - { - bfd_set_error (bfd_error_no_memory); - return -1; - } - } - } - else - { - section->contents = bfd_zmalloc (section->size); - if (section->contents == NULL) - { - bfd_set_error (bfd_error_no_memory); - return -1; - } - } -#if VMS_DEBUG - vms_debug (4, "gsd psc %d (%s, flags %04x=%s) ", - section->index, name, old_flags, flag2str (gpsflagdesc, old_flags)); - vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n", - section->size, section->vma, section->contents); -#endif - - gsd_size = vms_rec[8] + 9; - - psect_idx++; - } - break; - - case GSD_S_C_EPM: - case GSD_S_C_EPMW: -#if VMS_DEBUG - vms_debug (4, "gsd epm\n"); -#endif - /* Fall through. */ - case GSD_S_C_SYM: - case GSD_S_C_SYMW: - { - int name_offset = 0, value_offset = 0; - - /* Symbol specification (definition or reference). */ -#if VMS_DEBUG - vms_debug (4, "GSD_S_C_SYM(W)\n"); -#endif - old_flags = bfd_getl16 (vms_rec + 2); - new_flags = BSF_NO_FLAGS; - - if (old_flags & GSY_S_M_WEAK) - new_flags |= BSF_WEAK; - - switch (gsd_type) - { - case GSD_S_C_EPM: - name_offset = 11; - value_offset = 5; - new_flags |= BSF_FUNCTION; - break; - case GSD_S_C_EPMW: - name_offset = 12; - value_offset = 6; - new_flags |= BSF_FUNCTION; - break; - case GSD_S_C_SYM: - if (old_flags & GSY_S_M_DEF) /* Symbol definition. */ - name_offset = 9; - else - name_offset = 4; - value_offset = 5; - break; - case GSD_S_C_SYMW: - if (old_flags & GSY_S_M_DEF) /* Symbol definition. */ - name_offset = 10; - else - name_offset = 5; - value_offset = 6; - break; - } - - /* Save symbol in vms_symbol_table. */ - entry = _bfd_vms_enter_symbol - (abfd, _bfd_vms_save_counted_string (vms_rec + name_offset)); - if (entry == NULL) - { - bfd_set_error (bfd_error_no_memory); - return -1; - } - symbol = entry->symbol; - - if (old_flags & GSY_S_M_DEF) - { - /* Symbol definition. */ - int psect; - - symbol->value = bfd_getl32 (vms_rec + value_offset); - if ((gsd_type == GSD_S_C_SYMW) - || (gsd_type == GSD_S_C_EPMW)) - psect = bfd_getl16 (vms_rec + value_offset - 2); - else - psect = vms_rec[value_offset-1]; - - symbol->section = (asection *)(unsigned long)psect; -#if VMS_DEBUG - vms_debug (4, "gsd sym def #%d (%s, %ld, %04x=%s)\n", abfd->symcount, - symbol->name, (long)symbol->section, old_flags, flag2str(gsyflagdesc, old_flags)); -#endif - } - else - { - /* Symbol reference. */ -#if VMS_DEBUG - vms_debug (4, "gsd sym ref #%d (%s, %04x=%s)\n", abfd->symcount, - symbol->name, old_flags, flag2str (gsyflagdesc, old_flags)); -#endif - symbol->section = (asection *)(unsigned long)-1; - } - - gsd_size = vms_rec[name_offset] + name_offset + 1; - symbol->flags = new_flags; - } - - break; - - case GSD_S_C_PRO: - case GSD_S_C_PROW: -#if VMS_DEBUG - vms_debug (4, "gsd pro\n"); -#endif - break; - case GSD_S_C_IDC: -#if VMS_DEBUG - vms_debug (4, "gsd idc\n"); -#endif - break; - case GSD_S_C_ENV: -#if VMS_DEBUG - vms_debug (4, "gsd env\n"); -#endif - break; - case GSD_S_C_LSY: -#if VMS_DEBUG - vms_debug (4, "gsd lsy\n"); -#endif - break; - case GSD_S_C_LEPM: -#if VMS_DEBUG - vms_debug (4, "gsd lepm\n"); -#endif - break; - case GSD_S_C_LPRO: -#if VMS_DEBUG - vms_debug (4, "gsd lpro\n"); -#endif - break; - case GSD_S_C_SPSC: -#if VMS_DEBUG - vms_debug (4, "gsd spsc\n"); -#endif - break; - case GSD_S_C_SYMV: -#if VMS_DEBUG - vms_debug (4, "gsd symv\n"); -#endif - break; - case GSD_S_C_EPMV: -#if VMS_DEBUG - vms_debug (4, "gsd epmv\n"); -#endif - break; - case GSD_S_C_PROV: -#if VMS_DEBUG - vms_debug (4, "gsd prov\n"); -#endif - break; - - case EGSD_S_C_PSC + EVAX_OFFSET: - { - /* Program section definition. */ - name = _bfd_vms_save_counted_string (vms_rec + EGPS_S_B_NAMLNG); - section = bfd_make_section (abfd, name); - if (!section) - return -1; - old_flags = bfd_getl16 (vms_rec + EGPS_S_W_FLAGS); - section->size = bfd_getl32 (vms_rec + EGPS_S_L_ALLOC); - new_flags = vms_secflag_by_name (abfd, evax_section_flags, name, - section->size > 0); - if (old_flags & EGPS_S_V_REL) - new_flags |= SEC_RELOC; - if (!bfd_set_section_flags (abfd, section, new_flags)) - return -1; - section->alignment_power = vms_rec[EGPS_S_B_ALIGN]; - align_addr = (1 << section->alignment_power); - if ((base_addr % align_addr) != 0) - base_addr += (align_addr - (base_addr % align_addr)); - section->vma = (bfd_vma)base_addr; - base_addr += section->size; - section->contents = bfd_zmalloc (section->size); - if (section->contents == NULL) - return -1; - section->filepos = (unsigned int)-1; -#if VMS_DEBUG - vms_debug (4, "EGSD P-section %d (%s, flags %04x=%s) ", - section->index, name, old_flags, flag2str(gpsflagdesc, old_flags)); - vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n", - section->size, section->vma, section->contents); -#endif - } - break; - - case EGSD_S_C_SYM + EVAX_OFFSET: - { - /* Global symbol specification (definition or reference). */ - symbol = bfd_make_empty_symbol (abfd); - if (symbol == 0) - return -1; - - old_flags = bfd_getl16 (vms_rec + EGSY_S_W_FLAGS); - new_flags = BSF_NO_FLAGS; - - if (old_flags & EGSY_S_V_WEAK) - new_flags |= BSF_WEAK; - - if (old_flags & EGSY_S_V_DEF) - { - /* Symbol definition. */ - if (old_flags & EGSY_S_V_NORM) - new_flags |= BSF_FUNCTION; - symbol->name = - _bfd_vms_save_counted_string (vms_rec + ESDF_S_B_NAMLNG); - symbol->value = bfd_getl64 (vms_rec + ESDF_S_L_VALUE); - symbol->section = - (asection *)(unsigned long) bfd_getl32 (vms_rec + ESDF_S_L_PSINDX); -#if VMS_DEBUG - vms_debug (4, "EGSD sym def #%d (%s, %ld, %04x=%s)\n", - abfd->symcount, symbol->name, (long)symbol->section, - old_flags, flag2str (gsyflagdesc, old_flags)); -#endif - } - else - { - /* Symbol reference. */ - symbol->name = - _bfd_vms_save_counted_string (vms_rec + ESRF_S_B_NAMLNG); -#if VMS_DEBUG - vms_debug (4, "EGSD sym ref #%d (%s, %04x=%s)\n", - abfd->symcount, symbol->name, old_flags, - flag2str (gsyflagdesc, old_flags)); -#endif - symbol->section = (asection *)(unsigned long)-1; - } - - symbol->flags = new_flags; - - /* Register symbol in VMS symbol table. */ - entry = (vms_symbol_entry *) bfd_hash_lookup - (PRIV (vms_symbol_table), symbol->name, TRUE, FALSE); - - if (entry == NULL) - { - bfd_set_error (bfd_error_no_memory); - return -1; - } - - if (entry->symbol != NULL) - { - /* FIXME ?, DEC C generates this. */ -#if VMS_DEBUG - vms_debug (4, "EGSD_S_C_SYM: duplicate \"%s\"\n", symbol->name); -#endif - } - else - { - entry->symbol = symbol; - PRIV (gsd_sym_count)++; - abfd->symcount++; - } - } - break; - - case EGSD_S_C_SYMG + EVAX_OFFSET: - { - /* Universal symbol specification (definition). */ - symbol = bfd_make_empty_symbol (abfd); - if (symbol == 0) - return -1; - - old_flags = bfd_getl16 (vms_rec + EGST_S_W_FLAGS); - new_flags = BSF_NO_FLAGS; - - if (old_flags & EGSY_S_V_WEAK) - new_flags |= BSF_WEAK; - - if (old_flags & EGSY_S_V_DEF) /* symbol definition */ - { - if (old_flags & EGSY_S_V_NORM) - new_flags |= BSF_FUNCTION; - - symbol->name = - _bfd_vms_save_counted_string (vms_rec + EGST_S_B_NAMLNG); - - /* For BSF_FUNCTION symbols, the entry point is in LP_1 - and the descriptor in LP_2. For other symbols, the - unique value is in LP_2. */ - symbol->value = bfd_getl64 (vms_rec + EGST_S_Q_LP_2); - - /* Adding this offset is necessary in order for GDB to - read the DWARF-2 debug info from shared libraries. */ - if (abfd->flags & DYNAMIC - && strstr (symbol->name, "$DWARF2.DEBUG") != 0) - symbol->value += PRIV (symvva); - } - else /* symbol reference */ - (*_bfd_error_handler) ("Invalid EGST reference"); - - symbol->flags = new_flags; - - if (register_universal_symbol (abfd, symbol, old_flags) < 0) - return -1; - - /* Make a second symbol for the entry point. */ - if (symbol->flags & BSF_FUNCTION) - { - asymbol *en_sym; - - name = bfd_alloc (abfd, strlen (symbol->name) + 5); - - en_sym = bfd_make_empty_symbol (abfd); - if (en_sym == 0) - return -1; - - strcpy (name, symbol->name); - strcat (name, "..en"); - - en_sym->name = name; - en_sym->value = bfd_getl64 (vms_rec + EGST_S_Q_LP_1); - - if (register_universal_symbol (abfd, en_sym, old_flags) < 0) - return -1; - } - } - break; - - case EGSD_S_C_IDC + EVAX_OFFSET: - break; - - default: - (*_bfd_error_handler) (_("Unknown GSD/EGSD subtype %d"), gsd_type); - bfd_set_error (bfd_error_bad_value); - return -1; - } - - PRIV (rec_size) -= gsd_size; - PRIV (vms_rec) += gsd_size; - } - - if (abfd->symcount > 0) - abfd->flags |= HAS_SYMS; - - return 0; -} - -/* Register a universal symbol in the VMS symbol table. */ - -static int -register_universal_symbol (bfd *abfd, asymbol *symbol, int vms_flags) -{ - bfd_vma sbase = 0; - asection *s, *sec = NULL; - vms_symbol_entry *entry; - - /* A universal symbol is by definition global... */ - symbol->flags |= BSF_GLOBAL; - - /* ...and dynamic in shared libraries. */ - if (abfd->flags & DYNAMIC) - symbol->flags |= BSF_DYNAMIC; - - /* Find containing section. */ - for (s = abfd->sections; s; s = s->next) - { - if (symbol->value >= s->vma - && s->vma > sbase - && !(s->flags & SEC_COFF_SHARED_LIBRARY) - && (s->size > 0 || !(vms_flags & EGSY_S_V_REL))) - { - sbase = s->vma; - sec = s; - } - } - - symbol->value -= sbase; - symbol->section = sec; - -#if VMS_DEBUG - vms_debug (4, "EGST sym def #%d (%s, 0x%llx => 0x%llx, %04x=%s)\n", - abfd->symcount, symbol->name, symbol->value + sbase, - symbol->value, vms_flags, - flag2str(gsyflagdesc, vms_flags)); -#endif - - entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table), - symbol->name, - TRUE, FALSE); - - if (entry == NULL) - { - bfd_set_error (bfd_error_no_memory); - return -1; - } - - if (entry->symbol) /* FIXME: DEC C generates this */ - { -#if VMS_DEBUG - vms_debug (4, "EGSD_S_C_SYMG: duplicate \"%s\"\n", symbol->name); -#endif - } - else - { - entry->symbol = symbol; - PRIV (gsd_sym_count)++; - abfd->symcount++; - } - - return 0; -} - -/* Set section VMS flags. */ - -void -bfd_vms_set_section_flags (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, flagword flags) -{ - vms_section_data (sec)->vflags = flags; -} - -/* Write section and symbol directory of bfd abfd. */ - -int -_bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED) -{ - asection *section; - asymbol *symbol; - unsigned int symnum; - int last_index = -1; - char dummy_name[10]; - char *sname; - flagword new_flags, old_flags; - int abs_section_index = 0; - -#if VMS_DEBUG - vms_debug (2, "vms_write_gsd (%p, %d)\n", abfd, objtype); -#endif - - /* Output sections. */ - section = abfd->sections; -#if VMS_DEBUG - vms_debug (3, "%d sections found\n", abfd->section_count); -#endif - - /* Egsd is quadword aligned. */ - _bfd_vms_output_alignment (abfd, 8); - - _bfd_vms_output_begin (abfd, EOBJ_S_C_EGSD, -1); - _bfd_vms_output_long (abfd, 0); - /* Prepare output for subrecords. */ - _bfd_vms_output_push (abfd); - - while (section != 0) - { -#if VMS_DEBUG - vms_debug (3, "Section #%d %s, %d bytes\n", section->index, section->name, (int)section->size); -#endif - - /* Don't write out the VMS debug info section since it is in the - ETBT and EDBG sections in etir. */ - if (!strcmp (section->name, ".vmsdebug")) - goto done; - - /* 13 bytes egsd, max 31 chars name -> should be 44 bytes. */ - if (_bfd_vms_output_check (abfd, 64) < 0) - { - _bfd_vms_output_pop (abfd); - _bfd_vms_output_end (abfd); - _bfd_vms_output_begin (abfd, EOBJ_S_C_EGSD, -1); - _bfd_vms_output_long (abfd, 0); - /* Prepare output for subrecords. */ - _bfd_vms_output_push (abfd); - } - - /* Create dummy sections to keep consecutive indices. */ - while (section->index - last_index > 1) - { -#if VMS_DEBUG - vms_debug (3, "index %d, last %d\n", section->index, last_index); -#endif - _bfd_vms_output_begin (abfd, EGSD_S_C_PSC, -1); - _bfd_vms_output_short (abfd, 0); - _bfd_vms_output_short (abfd, 0); - _bfd_vms_output_long (abfd, 0); - sprintf (dummy_name, ".DUMMY%02d", last_index); - _bfd_vms_output_counted (abfd, dummy_name); - _bfd_vms_output_flush (abfd); - last_index++; - } - - /* Don't know if this is necessary for the linker but for now it keeps - vms_slurp_gsd happy */ - sname = (char *)section->name; - if (*sname == '.') - { - sname++; - if ((*sname == 't') && (strcmp (sname, "text") == 0)) - sname = PRIV (is_vax)?VAX_CODE_NAME:EVAX_CODE_NAME; - else if ((*sname == 'd') && (strcmp (sname, "data") == 0)) - sname = PRIV (is_vax)?VAX_DATA_NAME:EVAX_DATA_NAME; - else if ((*sname == 'b') && (strcmp (sname, "bss") == 0)) - sname = EVAX_BSS_NAME; - else if ((*sname == 'l') && (strcmp (sname, "link") == 0)) - sname = EVAX_LINK_NAME; - else if ((*sname == 'r') && (strcmp (sname, "rdata") == 0)) - sname = EVAX_READONLY_NAME; - else if ((*sname == 'l') && (strcmp (sname, "literal") == 0)) - sname = EVAX_LITERAL_NAME; - else if ((*sname == 'l') && (strcmp (sname, "literals") == 0)) - { - sname = EVAX_LITERALS_NAME; - abs_section_index = section->index; - } - else if ((*sname == 'c') && (strcmp (sname, "comm") == 0)) - sname = EVAX_COMMON_NAME; - else if ((*sname == 'l') && (strcmp (sname, "lcomm") == 0)) - sname = EVAX_LOCAL_NAME; - } - else - sname = _bfd_vms_length_hash_symbol (abfd, sname, EOBJ_S_C_SECSIZ); - - _bfd_vms_output_begin (abfd, EGSD_S_C_PSC, -1); - _bfd_vms_output_short (abfd, section->alignment_power & 0xff); - - if (bfd_is_com_section (section)) - new_flags = (EGPS_S_V_OVR | EGPS_S_V_REL | EGPS_S_V_GBL | EGPS_S_V_RD - | EGPS_S_V_WRT | EGPS_S_V_NOMOD | EGPS_S_V_COM); - else - new_flags = vms_esecflag_by_name (evax_section_flags, sname, - section->size > 0); - - /* Modify them as directed. */ - if (section->flags & SEC_READONLY) - new_flags &= ~EGPS_S_V_WRT; - - new_flags |= vms_section_data (section)->vflags & 0xffff; - new_flags &= - ~((vms_section_data (section)->vflags >> EGPS_S_V_NO_SHIFT) & 0xffff); - -#if VMS_DEBUG - vms_debug (3, "sec flags %x\n", section->flags); - vms_debug (3, "new_flags %x, _raw_size %d\n", new_flags, section->size); -#endif - - _bfd_vms_output_short (abfd, new_flags); - _bfd_vms_output_long (abfd, (unsigned long) section->size); - _bfd_vms_output_counted (abfd, sname); - _bfd_vms_output_flush (abfd); - - last_index = section->index; -done: - section = section->next; - } - - /* Output symbols. */ -#if VMS_DEBUG - vms_debug (3, "%d symbols found\n", abfd->symcount); -#endif - - bfd_set_start_address (abfd, (bfd_vma) -1); - - for (symnum = 0; symnum < abfd->symcount; symnum++) - { - char *hash; - - symbol = abfd->outsymbols[symnum]; - if (*(symbol->name) == '_') - { - if (strcmp (symbol->name, "__main") == 0) - bfd_set_start_address (abfd, (bfd_vma)symbol->value); - } - old_flags = symbol->flags; - - if (old_flags & BSF_FILE) - continue; - - if ((old_flags & BSF_GLOBAL) == 0 /* Not xdef... */ - && !bfd_is_und_section (symbol->section) /* and not xref... */ - && !((old_flags & BSF_SECTION_SYM) != 0 /* and not LIB$INITIALIZE. */ - && strcmp (symbol->section->name, "LIB$INITIALIZE") == 0)) - continue; - - /* 13 bytes egsd, max 64 chars name -> should be 77 bytes. */ - if (_bfd_vms_output_check (abfd, 80) < 0) - { - _bfd_vms_output_pop (abfd); - _bfd_vms_output_end (abfd); - _bfd_vms_output_begin (abfd, EOBJ_S_C_EGSD, -1); - _bfd_vms_output_long (abfd, 0); - /* Prepare output for subrecords. */ - _bfd_vms_output_push (abfd); - } - - _bfd_vms_output_begin (abfd, EGSD_S_C_SYM, -1); - - /* Data type, alignment. */ - _bfd_vms_output_short (abfd, 0); - - new_flags = 0; - - if (old_flags & BSF_WEAK) - new_flags |= EGSY_S_V_WEAK; - if (bfd_is_com_section (symbol->section)) /* .comm */ - new_flags |= (EGSY_S_V_WEAK | EGSY_S_V_COMM); - - if (old_flags & BSF_FUNCTION) - { - new_flags |= EGSY_S_V_NORM; - new_flags |= EGSY_S_V_REL; - } - if (old_flags & BSF_GLOBAL) - { - new_flags |= EGSY_S_V_DEF; - if (!bfd_is_abs_section (symbol->section)) - new_flags |= EGSY_S_V_REL; - } - _bfd_vms_output_short (abfd, new_flags); - - if (old_flags & BSF_GLOBAL) - { - /* Symbol definition. */ - uquad code_address = 0; - unsigned long ca_psindx = 0; - unsigned long psindx; - - if ((old_flags & BSF_FUNCTION) && symbol->udata.p != NULL) - { - asymbol *sym; - - if (bfd_get_flavour (abfd) == bfd_target_evax_flavour) - sym = ((struct evax_private_udata_struct *)symbol->udata.p)->enbsym; - else - sym = (asymbol *)symbol->udata.p; - code_address = sym->value; - ca_psindx = sym->section->index; - } - if (bfd_is_abs_section (symbol->section)) - psindx = abs_section_index; - else - psindx = symbol->section->index; - - _bfd_vms_output_quad (abfd, symbol->value); - _bfd_vms_output_quad (abfd, code_address); - _bfd_vms_output_long (abfd, ca_psindx); - _bfd_vms_output_long (abfd, psindx); - } - hash = _bfd_vms_length_hash_symbol (abfd, symbol->name, EOBJ_S_C_SYMSIZ); - _bfd_vms_output_counted (abfd, hash); - - _bfd_vms_output_flush (abfd); - - } - - _bfd_vms_output_alignment (abfd, 8); - _bfd_vms_output_pop (abfd); - _bfd_vms_output_end (abfd); - - return 0; -} diff --git a/bfd/vms-hdr.c b/bfd/vms-hdr.c deleted file mode 100644 index 343f53e..0000000 --- a/bfd/vms-hdr.c +++ /dev/null @@ -1,1382 +0,0 @@ -/* vms-hdr.c -- BFD back-end for VMS/VAX (openVMS/VAX) and - EVAX (openVMS/Alpha) files. - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, - 2007, 2008, 2009 Free Software Foundation, Inc. - - HDR record handling functions - EMH record handling functions - - EOM record handling functions - EEOM record handling functions - - IHD record handling functions - EIHD record handling functions - - ISD record handling functions - EISD record handling functions - - IHS record handling functions - EIHS record handling functions - - DBG record handling functions - EDBG record handling functions - - TBT record handling functions - ETBT record handling functions - - DST/DMT section handling functions - - Written by Klaus K"ampf (kkaempf@rmi.de) - - 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 3 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., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdver.h" -#include "bfdlink.h" -#include "safe-ctype.h" -#include "libbfd.h" - -#include "vms.h" - -static struct module *new_module (bfd *); -static void parse_module - (bfd *, struct module *, unsigned char *, unsigned int); -static struct module *build_module_list (bfd *); -static bfd_boolean module_find_nearest_line - (bfd *, struct module *, bfd_vma, const char **, const char **, - unsigned int *); -static int vms_slurp_debug (bfd *); - -#define SET_MODULE_PARSED(m) \ - do { if ((m)->name == NULL) (m)->name = ""; } while (0) -#define IS_MODULE_PARSED(m) ((m)->name != NULL) - - -/* Read & process emh record - return 0 on success, -1 on error. */ - -int -_bfd_vms_slurp_hdr (bfd *abfd, int objtype) -{ - unsigned char *ptr; - unsigned char *vms_rec; - int subtype; - - vms_rec = PRIV(vms_rec); - -#if VMS_DEBUG - vms_debug(2, "HDR/EMH\n"); -#endif - - switch (objtype) - { - case OBJ_S_C_HDR: - subtype = vms_rec[1]; - break; - case EOBJ_S_C_EMH: - subtype = bfd_getl16 (vms_rec + 4) + EVAX_OFFSET; - break; - default: - subtype = -1; - } - -#if VMS_DEBUG - vms_debug(3, "subtype %d\n", subtype); -#endif - - switch (subtype) - { - case MHD_S_C_MHD: - /* Module header. */ - PRIV (hdr_data).hdr_b_strlvl = vms_rec[2]; - PRIV (hdr_data).hdr_l_recsiz = bfd_getl16 (vms_rec + 3); - PRIV (hdr_data).hdr_t_name = _bfd_vms_save_counted_string (vms_rec + 5); - ptr = vms_rec + 5 + vms_rec[5] + 1; - PRIV (hdr_data).hdr_t_version = _bfd_vms_save_counted_string (ptr); - ptr += *ptr + 1; - PRIV (hdr_data).hdr_t_date = _bfd_vms_save_sized_string (ptr, 17); - break; - - case MHD_S_C_LNM: - PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 2)); - break; - - case MHD_S_C_SRC: - PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 2)); - break; - - case MHD_S_C_TTL: - PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 2)); - break; - - case EMH_S_C_MHD + EVAX_OFFSET: - /* Module header. */ - PRIV (hdr_data).hdr_b_strlvl = vms_rec[6]; - PRIV (hdr_data).hdr_l_arch1 = bfd_getl32 (vms_rec + 8); - PRIV (hdr_data).hdr_l_arch2 = bfd_getl32 (vms_rec + 12); - PRIV (hdr_data).hdr_l_recsiz = bfd_getl32 (vms_rec + 16); - PRIV (hdr_data).hdr_t_name = _bfd_vms_save_counted_string (vms_rec + 20); - ptr = vms_rec + 20 + vms_rec[20] + 1; - PRIV (hdr_data).hdr_t_version =_bfd_vms_save_counted_string (ptr); - ptr += *ptr + 1; - PRIV (hdr_data).hdr_t_date = _bfd_vms_save_sized_string (ptr, 17); - break; - - case EMH_S_C_LNM + EVAX_OFFSET: - PRIV (hdr_data).hdr_c_lnm = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 6)); - break; - - case EMH_S_C_SRC + EVAX_OFFSET: - PRIV (hdr_data).hdr_c_src = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 6)); - break; - - case EMH_S_C_TTL + EVAX_OFFSET: - PRIV (hdr_data).hdr_c_ttl = _bfd_vms_save_sized_string (vms_rec, PRIV (rec_size - 6)); - break; - - case MHD_S_C_CPR: - case MHD_S_C_MTC: - case MHD_S_C_GTX: - case EMH_S_C_CPR + EVAX_OFFSET: - case EMH_S_C_MTC + EVAX_OFFSET: - case EMH_S_C_GTX + EVAX_OFFSET: - break; - - default: - bfd_set_error (bfd_error_wrong_format); - return -1; - } - - return 0; -} - -/* Output routines. */ - -/* Manufacture a VMS like time on a unix based system. - stolen from obj-vms.c. */ - -static unsigned char * -get_vms_time_string (void) -{ - static unsigned char tbuf[18]; -#ifndef VMS -#include <time.h> - - char *pnt; - time_t timeb; - - time (& timeb); - pnt = ctime (&timeb); - pnt[3] = 0; - pnt[7] = 0; - pnt[10] = 0; - pnt[16] = 0; - pnt[24] = 0; - sprintf ((char *) tbuf, "%2s-%3s-%s %s", - pnt + 8, pnt + 4, pnt + 20, pnt + 11); -#else -#include <starlet.h> - struct - { - int Size; - unsigned char *Ptr; - } Descriptor; - Descriptor.Size = 17; - Descriptor.Ptr = tbuf; - SYS$ASCTIM (0, &Descriptor, 0, 0); -#endif /* not VMS */ - -#if VMS_DEBUG - vms_debug (6, "vmstimestring:'%s'\n", tbuf); -#endif - - return tbuf; -} - -/* Write object header for bfd abfd. */ - -int -_bfd_vms_write_hdr (bfd *abfd, int objtype) -{ - asymbol *symbol; - unsigned int symnum; - int had_case = 0; - int had_file = 0; - char version [256]; - -#if VMS_DEBUG - vms_debug (2, "vms_write_hdr (%p)\n", abfd); -#endif - - _bfd_vms_output_alignment (abfd, 2); - - /* MHD. */ - if (objtype != OBJ_S_C_HDR) - { - _bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_MHD); - _bfd_vms_output_short (abfd, EOBJ_S_C_STRLVL); - _bfd_vms_output_long (abfd, 0); - _bfd_vms_output_long (abfd, 0); - _bfd_vms_output_long (abfd, MAX_OUTREC_SIZE); - } - - /* Create module name from filename. */ - if (bfd_get_filename (abfd) != 0) - { - char *module = vms_get_module_name (bfd_get_filename (abfd), TRUE); - _bfd_vms_output_counted (abfd, module); - free (module); - } - else - _bfd_vms_output_counted (abfd, "NONAME"); - - _bfd_vms_output_counted (abfd, BFD_VERSION_STRING); - _bfd_vms_output_dump (abfd, get_vms_time_string (), EMH_DATE_LENGTH); - _bfd_vms_output_fill (abfd, 0, EMH_DATE_LENGTH); - _bfd_vms_output_flush (abfd); - - /* LMN. */ - _bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_LNM); - snprintf (version, sizeof (version), "GAS BFD v%s", BFD_VERSION_STRING); - _bfd_vms_output_dump (abfd, (unsigned char *)version, strlen (version)); - _bfd_vms_output_flush (abfd); - - /* SRC. */ - _bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_SRC); - - for (symnum = 0; symnum < abfd->symcount; symnum++) - { - symbol = abfd->outsymbols[symnum]; - - if (symbol->flags & BSF_FILE) - { - if (CONST_STRNEQ ((char *)symbol->name, "<CASE:")) - { - PRIV (flag_hash_long_names) = symbol->name[6] - '0'; - PRIV (flag_show_after_trunc) = symbol->name[7] - '0'; - - if (had_file) - break; - had_case = 1; - continue; - } - - _bfd_vms_output_dump (abfd, (unsigned char *) symbol->name, - (int) strlen (symbol->name)); - if (had_case) - break; - had_file = 1; - } - } - - if (symnum == abfd->symcount) - _bfd_vms_output_dump (abfd, (unsigned char *) STRING_COMMA_LEN ("noname")); - - _bfd_vms_output_flush (abfd); - - /* TTL. */ - _bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_TTL); - _bfd_vms_output_dump (abfd, (unsigned char *) STRING_COMMA_LEN ("TTL")); - _bfd_vms_output_flush (abfd); - - /* CPR. */ - _bfd_vms_output_begin (abfd, EOBJ_S_C_EMH, EMH_S_C_CPR); - _bfd_vms_output_dump (abfd, - (unsigned char *)"GNU BFD ported by Klaus Kämpf 1994-1996", - 39); - _bfd_vms_output_flush (abfd); - - return 0; -} - -/* Process EOM/EEOM record - return 0 on success, -1 on error. */ - -int -_bfd_vms_slurp_eom (bfd *abfd, int objtype) -{ - unsigned char *vms_rec; - -#if VMS_DEBUG - vms_debug(2, "EOM/EEOM\n"); -#endif - - vms_rec = PRIV (vms_rec); - - if ((objtype == OBJ_S_C_EOM) - || (objtype == OBJ_S_C_EOMW)) - { - } - else - { - PRIV (eom_data).eom_l_total_lps - = bfd_getl32 (vms_rec + EEOM_S_L_TOTAL_LPS); - PRIV (eom_data).eom_w_comcod = bfd_getl16 (vms_rec + EEOM_S_W_COMCOD); - if (PRIV (eom_data).eom_w_comcod > 1) - { - (*_bfd_error_handler) (_("Object module NOT error-free !\n")); - bfd_set_error (bfd_error_bad_value); - return -1; - } - PRIV (eom_data).eom_has_transfer = FALSE; - if (PRIV (rec_size) > 10) - { - PRIV (eom_data).eom_has_transfer = TRUE; - PRIV (eom_data).eom_b_tfrflg = vms_rec[EEOM_S_B_TFRFLG]; - PRIV (eom_data).eom_l_psindx - = bfd_getl32 (vms_rec + EEOM_S_L_PSINDX); - PRIV (eom_data).eom_l_tfradr - = bfd_getl32 (vms_rec + EEOM_S_L_TFRADR); - - abfd->start_address = PRIV (eom_data).eom_l_tfradr; - } - } - return 0; -} - -/* Write eom record for bfd abfd. */ - -int -_bfd_vms_write_eom (bfd *abfd, int objtype) -{ -#if VMS_DEBUG - vms_debug (2, "vms_write_eom (%p, %d)\n", abfd, objtype); -#endif - - _bfd_vms_output_begin (abfd, objtype, -1); - _bfd_vms_output_long (abfd, (unsigned long) (PRIV (vms_linkage_index) >> 1)); - _bfd_vms_output_byte (abfd, 0); /* Completion code. */ - _bfd_vms_output_byte (abfd, 0); /* Fill byte. */ - - if (bfd_get_start_address (abfd) != (bfd_vma)-1) - { - asection *section; - - section = bfd_get_section_by_name (abfd, ".link"); - if (section == 0) - { - bfd_set_error (bfd_error_nonrepresentable_section); - return -1; - } - _bfd_vms_output_short (abfd, 0); - _bfd_vms_output_long (abfd, (unsigned long) (section->index)); - _bfd_vms_output_long (abfd, - (unsigned long) bfd_get_start_address (abfd)); - _bfd_vms_output_long (abfd, 0); - } - - _bfd_vms_output_end (abfd); - return 0; -} - -/* Read & process IHD/EIHD record. - Return 0 on success, -1 on error */ -int -_bfd_vms_slurp_ihd (bfd *abfd, unsigned int *isd_offset, - unsigned int *ihs_offset) -{ - unsigned int imgtype, size; - bfd_vma symvva; - -#if VMS_DEBUG - vms_debug (8, "_bfd_vms_slurp_ihd\n"); -#endif - - size = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_SIZE); - imgtype = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_IMGTYPE); - - if (imgtype == EIHD_S_K_EXE) - abfd->flags |= EXEC_P; - - symvva = bfd_getl64 (PRIV (vms_rec) + EIHD_S_Q_SYMVVA); - if (symvva != 0) - { - PRIV (symvva) = symvva; - abfd->flags |= DYNAMIC; - } - - *isd_offset = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_ISDOFF); - *ihs_offset = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_SYMDBGOFF); - -#if VMS_DEBUG - vms_debug (4, "EIHD record size %d imgtype %d symvva 0x%llx isd %d ihs %d\n", - size, imgtype, symvva, *isd_offset, *ihs_offset); -#endif - - return 0; -} - -/* Read & process ISD/EISD record - return 0 on success, -1 on error */ - -int -_bfd_vms_slurp_isd (bfd *abfd, unsigned int offset) -{ - int section_count = 0; - unsigned char *p; - unsigned int rec_size; - -#if VMS_DEBUG - vms_debug (8, "_bfd_vms_slurp_isd\n"); -#endif - - for (p = PRIV (vms_rec) + offset; - (rec_size = bfd_getl32 (p + EISD_S_L_EISDSIZE)) != 0; - p += rec_size) - { - unsigned long long vaddr = bfd_getl64 (p + EISD_S_Q_VIR_ADDR); - unsigned int size = bfd_getl32 (p + EISD_S_L_SECSIZE); - unsigned int flags = bfd_getl32 (p + EISD_S_L_FLAGS); - unsigned int vbn = bfd_getl32 (p + EISD_S_L_VBN); - char *name = NULL; - asection *section; - flagword bfd_flags; - -#if VMS_DEBUG - vms_debug (4, "EISD record at 0x%x size 0x%x addr 0x%x bfd_flags 0x%x block %d\n", - p - PRIV (vms_rec), size, vaddr, flags, vbn); -#endif - - /* VMS combines psects from .obj files into isects in the .exe. This - process doesn't preserve enough information to reliably determine - what's in each section without examining the data. This is - especially true of DWARF debug sections. */ - bfd_flags = SEC_ALLOC; - - if (flags & EISD_S_M_EXE) - bfd_flags |= SEC_CODE | SEC_HAS_CONTENTS | SEC_LOAD; - - if (flags & EISD_S_M_NONSHRADR) - bfd_flags |= SEC_DATA | SEC_HAS_CONTENTS | SEC_LOAD; - - if (!(flags & EISD_S_M_WRT)) - bfd_flags |= SEC_READONLY; - - if (flags & EISD_S_M_DZRO) - bfd_flags |= SEC_DATA; - - if (flags & EISD_S_M_FIXUPVEC) - bfd_flags |= SEC_DATA | SEC_HAS_CONTENTS | SEC_LOAD; - - if (flags & EISD_S_M_CRF) - bfd_flags |= SEC_HAS_CONTENTS | SEC_LOAD; - - if (flags & EISD_S_M_GBL) - { - name = _bfd_vms_save_counted_string (p + EISD_S_T_GBLNAM); - bfd_flags |= SEC_COFF_SHARED_LIBRARY; - bfd_flags &= ~(SEC_ALLOC | SEC_LOAD); - } - else - { - name = (char*) bfd_alloc (abfd, 32); - sprintf (name, "$LOCAL_%03d$", section_count++); - } - - section = bfd_make_section (abfd, name); - - if (!section) - return -1; - - section->filepos = vbn ? VMS_BLOCK_SIZE * (vbn - 1) : (unsigned int)-1; - section->size = size; - section->vma = vaddr; - - if (!bfd_set_section_flags (abfd, section, bfd_flags)) - return -1; - } - - return 0; -} - -/* Read & process IHS/EIHS record - return 0 on success, -1 on error */ -int -_bfd_vms_slurp_ihs (bfd *abfd, unsigned int offset) -{ - unsigned char *p = PRIV (vms_rec) + offset; - unsigned int gstvbn = bfd_getl32 (p + EIHS_S_L_GSTVBN); - unsigned int gstsize ATTRIBUTE_UNUSED = bfd_getl32 (p + EIHS_S_L_GSTSIZE); - unsigned int dstvbn = bfd_getl32 (p + EIHS_S_L_DSTVBN); - unsigned int dstsize = bfd_getl32 (p + EIHS_S_L_DSTSIZE); - unsigned int dmtvbn = bfd_getl32 (p + EIHS_S_L_DMTVBN); - unsigned int dmtbytes = bfd_getl32 (p + EIHS_S_L_DMTBYTES); - asection *section; - -#if VMS_DEBUG - vms_debug (8, "_bfd_vms_slurp_ihs\n"); - vms_debug (4, "EIHS record gstvbn %d gstsize %d dstvbn %d dstsize %d dmtvbn %d dmtbytes %d\n", - gstvbn, gstsize, dstvbn, dstsize, dmtvbn, dmtbytes); -#endif - - if (dstvbn) - { - flagword bfd_flags = SEC_HAS_CONTENTS | SEC_DEBUGGING; - - section = bfd_make_section (abfd, "$DST$"); - if (!section) - return -1; - - section->size = dstsize; - section->filepos = VMS_BLOCK_SIZE * (dstvbn - 1); - - if (!bfd_set_section_flags (abfd, section, bfd_flags)) - return -1; - - PRIV (dst_section) = section; - abfd->flags |= (HAS_DEBUG | HAS_LINENO); - } - - if (dmtvbn) - { - flagword bfd_flags = SEC_HAS_CONTENTS | SEC_DEBUGGING; - - section = bfd_make_section (abfd, "$DMT$"); - if (!section) - return -1; - - section->size = dmtbytes; - section->filepos = VMS_BLOCK_SIZE * (dmtvbn - 1); - - if (!bfd_set_section_flags (abfd, section, bfd_flags)) - return -1; - } - - if (gstvbn) - { - flagword bfd_flags = SEC_HAS_CONTENTS; - - section = bfd_make_section (abfd, "$GST$"); - if (!section) - return -1; - - if (bfd_seek (abfd, VMS_BLOCK_SIZE * (gstvbn - 1), SEEK_SET)) - { - bfd_set_error (bfd_error_file_truncated); - return -1; - } - - if (_bfd_vms_slurp_object_records (abfd) != 0) - return -1; - - section->filepos = VMS_BLOCK_SIZE * (gstvbn - 1); - section->size = bfd_tell (abfd) - section->filepos; - - if (!bfd_set_section_flags (abfd, section, bfd_flags)) - return -1; - - abfd->flags |= HAS_SYMS; - } - - return 0; -} - -/* Build a new module for the specified BFD. */ - -static struct module * -new_module (bfd *abfd) -{ - struct module *module - = (struct module *) bfd_zalloc (abfd, sizeof (struct module)); - module->file_table_count = 16; /* Arbitrary. */ - module->file_table - = bfd_malloc (module->file_table_count * sizeof (struct fileinfo)); - return module; -} - -/* Parse debug info for a module and internalize it. */ - -static void -parse_module (bfd *abfd, struct module *module, unsigned char *ptr, - unsigned int length) -{ - unsigned char *maxptr = ptr + length, *src_ptr, *pcl_ptr; - unsigned int prev_linum = 0, curr_linenum = 0; - bfd_vma prev_pc = 0, curr_pc = 0; - struct srecinfo *curr_srec, *srec; - struct lineinfo *curr_line, *line; - struct funcinfo *funcinfo; - - /* Initialize tables with zero element. */ - curr_srec = (struct srecinfo *) bfd_zalloc (abfd, sizeof (struct srecinfo)); - module->srec_table = curr_srec; - - curr_line = (struct lineinfo *) bfd_zalloc (abfd, sizeof (struct lineinfo)); - module->line_table = curr_line; - - while (ptr < maxptr) - { - /* The first byte is not counted in the recorded length. */ - int rec_length = bfd_getl16 (ptr) + 1; - int rec_type = bfd_getl16 (ptr + 2); - -#if VMS_DEBUG - _bfd_vms_debug (2, "DST record: length %d, type %d\n", - rec_length, rec_type); -#endif - - switch (rec_type) - { - case DST_S_C_MODBEG: - module->name - = _bfd_vms_save_counted_string (ptr + DST_S_B_MODBEG_NAME); - - curr_pc = 0; - prev_pc = 0; - curr_linenum = 0; - prev_linum = 0; - -#if VMS_DEBUG - _bfd_vms_debug (3, "module: %s\n", module->name); -#endif - break; - - case DST_S_C_MODEND: -#if VMS_DEBUG - _bfd_vms_debug (3, "end module\n"); -#endif - break; - - case DST_S_C_RTNBEG: - funcinfo = (struct funcinfo *) - bfd_zalloc (abfd, sizeof (struct funcinfo)); - funcinfo->name - = _bfd_vms_save_counted_string (ptr + DST_S_B_RTNBEG_NAME); - funcinfo->low = bfd_getl32 (ptr + DST_S_L_RTNBEG_ADDRESS); - funcinfo->next = module->func_table; - module->func_table = funcinfo; - -#if VMS_DEBUG - _bfd_vms_debug (3, "routine: %s at 0x%x\n", - funcinfo->name, funcinfo->low); -#endif - break; - - case DST_S_C_RTNEND: - module->func_table->high = module->func_table->low - + bfd_getl32 (ptr + DST_S_L_RTNEND_SIZE) - 1; - - if (module->func_table->high > module->high) - module->high = module->func_table->high; - -#if VMS_DEBUG - _bfd_vms_debug (3, "end routine\n"); -#endif - break; - - case DST_S_C_PROLOG: -#if VMS_DEBUG - _bfd_vms_debug (3, "prologue\n"); -#endif - break; - - case DST_S_C_EPILOG: -#if VMS_DEBUG - _bfd_vms_debug (3, "epilog\n"); -#endif - break; - - case DST_S_C_BLKBEG: -#if VMS_DEBUG - _bfd_vms_debug (3, "block\n"); -#endif - break; - - case DST_S_C_BLKEND: -#if VMS_DEBUG - _bfd_vms_debug (3, "end block\n"); -#endif - break; - - case DST_S_C_SOURCE: - src_ptr = ptr + DST_S_C_SOURCE_HEADER_SIZE; - -#if VMS_DEBUG - _bfd_vms_debug (3, "source info\n"); -#endif - - while (src_ptr < ptr + rec_length) - { - int cmd = src_ptr[0], cmd_length, data; - - switch (cmd) - { - case DST_S_C_SRC_DECLFILE: - { - unsigned int fileid - = bfd_getl16 (src_ptr + DST_S_W_SRC_DF_FILEID); - char *filename - = _bfd_vms_save_counted_string (src_ptr - + DST_S_B_SRC_DF_FILENAME); - - while (fileid >= module->file_table_count) - { - module->file_table_count *= 2; - module->file_table - = bfd_realloc (module->file_table, - module->file_table_count - * sizeof (struct fileinfo)); - } - - module->file_table [fileid].name = filename; - module->file_table [fileid].srec = 1; - cmd_length = src_ptr[DST_S_B_SRC_DF_LENGTH] + 2; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SRC_DECLFILE: %d, %s\n", - fileid, - module->file_table [fileid].name); -#endif - } - break; - - case DST_S_C_SRC_DEFLINES_B: - /* Perform the association and set the next higher index - to the limit. */ - data = src_ptr[DST_S_B_SRC_UNSBYTE]; - srec = (struct srecinfo *) - bfd_zalloc (abfd, sizeof (struct srecinfo)); - srec->line = curr_srec->line + data; - srec->srec = curr_srec->srec + data; - srec->sfile = curr_srec->sfile; - curr_srec->next = srec; - curr_srec = srec; - cmd_length = 2; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SRC_DEFLINES_B: %d\n", data); -#endif - break; - - case DST_S_C_SRC_DEFLINES_W: - /* Perform the association and set the next higher index - to the limit. */ - data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD); - srec = (struct srecinfo *) - bfd_zalloc (abfd, sizeof (struct srecinfo)); - srec->line = curr_srec->line + data; - srec->srec = curr_srec->srec + data, - srec->sfile = curr_srec->sfile; - curr_srec->next = srec; - curr_srec = srec; - cmd_length = 3; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SRC_DEFLINES_W: %d\n", data); -#endif - break; - - case DST_S_C_SRC_INCRLNUM_B: - data = src_ptr[DST_S_B_SRC_UNSBYTE]; - curr_srec->line += data; - cmd_length = 2; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SRC_INCRLNUM_B: %d\n", data); -#endif - break; - - case DST_S_C_SRC_SETFILE: - data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD); - curr_srec->sfile = data; - curr_srec->srec = module->file_table[data].srec; - cmd_length = 3; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SRC_SETFILE: %d\n", data); -#endif - break; - - case DST_S_C_SRC_SETLNUM_L: - data = bfd_getl32 (src_ptr + DST_S_L_SRC_UNSLONG); - curr_srec->line = data; - cmd_length = 5; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SRC_SETLNUM_L: %d\n", data); -#endif - break; - - case DST_S_C_SRC_SETLNUM_W: - data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD); - curr_srec->line = data; - cmd_length = 3; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SRC_SETLNUM_W: %d\n", data); -#endif - break; - - case DST_S_C_SRC_SETREC_L: - data = bfd_getl32 (src_ptr + DST_S_L_SRC_UNSLONG); - curr_srec->srec = data; - module->file_table[curr_srec->sfile].srec = data; - cmd_length = 5; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SRC_SETREC_L: %d\n", data); -#endif - break; - - case DST_S_C_SRC_SETREC_W: - data = bfd_getl16 (src_ptr + DST_S_W_SRC_UNSWORD); - curr_srec->srec = data; - module->file_table[curr_srec->sfile].srec = data; - cmd_length = 3; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SRC_SETREC_W: %d\n", data); -#endif - break; - - case DST_S_C_SRC_FORMFEED: - cmd_length = 1; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SRC_FORMFEED\n"); -#endif - break; - - default: - (*_bfd_error_handler) (_("unknown source command %d"), - cmd); - cmd_length = 2; - break; - } - - src_ptr += cmd_length; - } - break; - - case DST_S_C_LINE_NUM: - pcl_ptr = ptr + DST_S_C_LINE_NUM_HEADER_SIZE; - -#if VMS_DEBUG - _bfd_vms_debug (3, "line info\n"); -#endif - - while (pcl_ptr < ptr + rec_length) - { - /* The command byte is signed so we must sign-extend it. */ - int cmd = ((signed char *)pcl_ptr)[0], cmd_length, data; - - switch (cmd) - { - case DST_S_C_DELTA_PC_W: - data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); - curr_pc += data; - curr_linenum += 1; - cmd_length = 3; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_DELTA_PC_W: %d\n", data); -#endif - break; - - case DST_S_C_DELTA_PC_L: - data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); - curr_pc += data; - curr_linenum += 1; - cmd_length = 5; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_DELTA_PC_L: %d\n", data); -#endif - break; - - case DST_S_C_INCR_LINUM: - data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE]; - curr_linenum += data; - cmd_length = 2; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_INCR_LINUM: %d\n", data); -#endif - break; - - case DST_S_C_INCR_LINUM_W: - data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); - curr_linenum += data; - cmd_length = 3; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_INCR_LINUM_W: %d\n", data); -#endif - break; - - case DST_S_C_INCR_LINUM_L: - data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); - curr_linenum += data; - cmd_length = 5; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_INCR_LINUM_L: %d\n", data); -#endif - break; - - case DST_S_C_SET_LINUM_INCR: - (*_bfd_error_handler) - (_("DST_S_C_SET_LINUM_INCR not implemented")); - cmd_length = 2; - break; - - case DST_S_C_SET_LINUM_INCR_W: - (*_bfd_error_handler) - (_("DST_S_C_SET_LINUM_INCR_W not implemented")); - cmd_length = 3; - break; - - case DST_S_C_RESET_LINUM_INCR: - (*_bfd_error_handler) - (_("DST_S_C_RESET_LINUM_INCR not implemented")); - cmd_length = 1; - break; - - case DST_S_C_BEG_STMT_MODE: - (*_bfd_error_handler) - (_("DST_S_C_BEG_STMT_MODE not implemented")); - cmd_length = 1; - break; - - case DST_S_C_END_STMT_MODE: - (*_bfd_error_handler) - (_("DST_S_C_END_STMT_MODE not implemented")); - cmd_length = 1; - break; - - case DST_S_C_SET_LINUM_B: - data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE]; - curr_linenum = data; - cmd_length = 2; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SET_LINUM_B: %d\n", data); -#endif - break; - - case DST_S_C_SET_LINE_NUM: - data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); - curr_linenum = data; - cmd_length = 3; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SET_LINE_NUM: %d\n", data); -#endif - break; - - case DST_S_C_SET_LINUM_L: - data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); - curr_linenum = data; - cmd_length = 5; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SET_LINUM_L: %d\n", data); -#endif - break; - - case DST_S_C_SET_PC: - (*_bfd_error_handler) - (_("DST_S_C_SET_PC not implemented")); - cmd_length = 2; - break; - - case DST_S_C_SET_PC_W: - (*_bfd_error_handler) - (_("DST_S_C_SET_PC_W not implemented")); - cmd_length = 3; - break; - - case DST_S_C_SET_PC_L: - (*_bfd_error_handler) - (_("DST_S_C_SET_PC_L not implemented")); - cmd_length = 5; - break; - - case DST_S_C_SET_STMTNUM: - (*_bfd_error_handler) - (_("DST_S_C_SET_STMTNUM not implemented")); - cmd_length = 2; - break; - - case DST_S_C_TERM: - data = pcl_ptr[DST_S_B_PCLINE_UNSBYTE]; - curr_pc += data; - cmd_length = 2; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_TERM: %d\n", data); -#endif - break; - - case DST_S_C_TERM_W: - data = bfd_getl16 (pcl_ptr + DST_S_W_PCLINE_UNSWORD); - curr_pc += data; - cmd_length = 3; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_TERM_W: %d\n", data); -#endif - break; - - case DST_S_C_TERM_L: - data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); - curr_pc += data; - cmd_length = 5; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_TERM_L: %d\n", data); -#endif - break; - - case DST_S_C_SET_ABS_PC: - data = bfd_getl32 (pcl_ptr + DST_S_L_PCLINE_UNSLONG); - curr_pc = data; - cmd_length = 5; -#if VMS_DEBUG - _bfd_vms_debug (4, "DST_S_C_SET_ABS_PC: 0x%x\n", data); -#endif - break; - - default: - if (cmd <= 0) - { - curr_pc -= cmd; - curr_linenum += 1; - cmd_length = 1; -#if VMS_DEBUG - _bfd_vms_debug (4, "bump pc to 0x%llx and line to %d\n", - curr_pc, curr_linenum); -#endif - } - else - { - (*_bfd_error_handler) (_("unknown line command %d"), - cmd); - cmd_length = 2; - } - break; - } - - if ((curr_linenum != prev_linum && curr_pc != prev_pc) - || cmd <= 0 - || cmd == DST_S_C_DELTA_PC_L - || cmd == DST_S_C_DELTA_PC_W) - { - line = (struct lineinfo *) - bfd_zalloc (abfd, sizeof (struct lineinfo)); - line->address = curr_pc; - line->line = curr_linenum; - - curr_line->next = line; - curr_line = line; - - prev_linum = curr_linenum; - prev_pc = curr_pc; -#if VMS_DEBUG - _bfd_vms_debug (4, "-> correlate pc 0x%llx with line %d\n", - curr_pc, curr_linenum); -#endif - } - - pcl_ptr += cmd_length; - } - break; - - case 0x17: /* Undocumented type used by DEC C to declare equates. */ -#if VMS_DEBUG - _bfd_vms_debug (3, "undocumented type 0x17\n"); -#endif - break; - - default: -#if VMS_DEBUG - _bfd_vms_debug (3, "ignoring record\n"); -#endif - break; - - } - - ptr += rec_length; - } - - /* Finalize tables with EOL marker. */ - srec = (struct srecinfo *) bfd_zalloc (abfd, sizeof (struct srecinfo)); - srec->line = (unsigned int) -1; - srec->srec = (unsigned int) -1; - curr_srec->next = srec; - - line = (struct lineinfo *) bfd_zalloc (abfd, sizeof (struct lineinfo)); - line->line = (unsigned int) -1; - line->address = (bfd_vma) -1; - curr_line->next = line; - - /* Advertise that this module has been parsed. This is needed - because parsing can be either performed at module creation - or deferred until debug info is consumed. */ - SET_MODULE_PARSED (module); -} - -/* Build the list of modules for the specified BFD. */ - -static struct module * -build_module_list (bfd *abfd) -{ - struct module *module, *list = NULL; - asection *dmt; - - if ((dmt = bfd_get_section_by_name (abfd, "$DMT$"))) - { - /* We have a DMT section so this must be an image. Parse the - section and build the list of modules. This is sufficient - since we can compute the start address and the end address - of every module from the section contents. */ - bfd_size_type size = bfd_get_section_size (dmt); - unsigned char *ptr, *end; - - ptr = (unsigned char *) bfd_alloc (abfd, size); - if (! ptr) - return NULL; - - if (! bfd_get_section_contents (abfd, dmt, ptr, 0, size)) - return NULL; - -#if VMS_DEBUG - _bfd_vms_debug (2, "DMT\n"); -#endif - - end = ptr + size; - - while (ptr < end) - { - /* Each header declares a module with its start offset and size - of debug info in the DST section, as well as the count of - program sections (i.e. address spans) it contains. */ - int modbeg = bfd_getl32 (ptr + DBG_S_L_DMT_MODBEG); - int msize = bfd_getl32 (ptr + DBG_S_L_DST_SIZE); - int count = bfd_getl16 (ptr + DBG_S_W_DMT_PSECT_COUNT); - ptr += DBG_S_C_DMT_HEADER_SIZE; - -#if VMS_DEBUG - _bfd_vms_debug (3, "module: modbeg = %d, size = %d, count = %d\n", - modbeg, msize, count); -#endif - - /* We create a 'module' structure for each program section since - we only support contiguous addresses in a 'module' structure. - As a consequence, the actual debug info in the DST section is - shared and can be parsed multiple times; that doesn't seem to - cause problems in practice. */ - while (count-- > 0) - { - int start = bfd_getl32 (ptr + DBG_S_L_DMT_PSECT_START); - int length = bfd_getl32 (ptr + DBG_S_L_DMT_PSECT_LENGTH); - module = new_module (abfd); - module->modbeg = modbeg; - module->size = msize; - module->low = start; - module->high = start + length; - module->next = list; - list = module; - ptr += DBG_S_C_DMT_PSECT_SIZE; - -#if VMS_DEBUG - _bfd_vms_debug (4, "section: start = 0x%x, length = %d\n", - start, length); -#endif - } - } - } - else - { - /* We don't have a DMT section so this must be an object. Parse - the module right now in order to compute its start address and - end address. */ - module = new_module (abfd); - parse_module (abfd, module, PRIV (dst_section)->contents, - PRIV (dst_ptr_end) - PRIV (dst_section)->contents); - list = module; - } - - return list; -} - -/* Calculate and return the name of the source file and the line nearest - to the wanted location in the specified module. */ - -static bfd_boolean -module_find_nearest_line (bfd *abfd, struct module *module, bfd_vma addr, - const char **file, const char **func, - unsigned int *line) -{ - struct funcinfo *funcinfo; - struct lineinfo *lineinfo; - struct srecinfo *srecinfo; - bfd_boolean ret = FALSE; - - /* Parse this module if that was not done at module creation. */ - if (! IS_MODULE_PARSED (module)) - { - unsigned int size = module->size; - unsigned int modbeg = PRIV (dst_section)->filepos + module->modbeg; - unsigned char *buffer = (unsigned char *) bfd_malloc (module->size); - - if (bfd_seek (abfd, modbeg, SEEK_SET) != 0 - || bfd_bread (buffer, size, abfd) != size) - { - bfd_set_error (bfd_error_no_debug_section); - return FALSE; - } - - parse_module (abfd, module, buffer, size); - free (buffer); - } - - /* Find out the function (if any) that contains the address. */ - for (funcinfo = module->func_table; funcinfo; funcinfo = funcinfo->next) - if (addr >= funcinfo->low && addr <= funcinfo->high) - { - *func = funcinfo->name; - ret = TRUE; - break; - } - - /* Find out the source file and the line nearest to the address. */ - for (lineinfo = module->line_table; lineinfo; lineinfo = lineinfo->next) - if (lineinfo->next && addr < lineinfo->next->address) - { - for (srecinfo = module->srec_table; srecinfo; srecinfo = srecinfo->next) - if (srecinfo->next && lineinfo->line < srecinfo->next->line) - { - if (srecinfo->sfile > 0) - { - *file = module->file_table[srecinfo->sfile].name; - *line = srecinfo->srec + lineinfo->line - srecinfo->line; - } - else - { - *file = module->name; - *line = lineinfo->line; - } - return TRUE; - } - - break; - } - - return ret; -} - -/* Provided a BFD, a section and an offset into the section, calculate and - return the name of the source file and the line nearest to the wanted - location. */ - -bfd_boolean -_bfd_vms_find_nearest_dst_line (bfd *abfd, asection *section, - asymbol **symbols ATTRIBUTE_UNUSED, - bfd_vma offset, const char **file, - const char **func, unsigned int *line) -{ - struct module *module; - - /* What address are we looking for? */ - bfd_vma addr = section->vma + offset; - - *file = NULL; - *func = NULL; - *line = 0; - - if (PRIV (dst_section) == NULL) - return FALSE; - - if (PRIV (modules) == NULL) - { - PRIV (modules) = build_module_list (abfd); - if (PRIV (modules) == NULL) - return FALSE; - } - - for (module = PRIV (modules); module; module = module->next) - if (addr >= module->low && addr <= module->high) - return module_find_nearest_line (abfd, module, addr, file, func, line); - - return FALSE; -} - -/* Process EDBG/ETBT record. - Return 0 on success, -1 on error */ - -static int -vms_slurp_debug (bfd *abfd) -{ - if (PRIV (dst_section) == NULL) - { - /* We have no way to find out beforehand how much debug info there - is in an object file, so pick an initial amount and grow it as - needed later. */ - flagword flags = SEC_HAS_CONTENTS | SEC_DEBUGGING | SEC_RELOC; - asection *section = bfd_make_section (abfd, "$DST$"); - if (!section) - return -1; - section->size = 1024; - if (!bfd_set_section_flags (abfd, section, flags)) - return -1; - section->contents = ((unsigned char *) - bfd_zmalloc (section->size)); - if (section->contents == NULL) - return -1; - section->filepos = (unsigned int)-1; - PRIV (dst_section) = section; - } - - PRIV (image_section) = PRIV (dst_section); - PRIV (image_ptr) = PRIV (dst_section)->contents; - - return _bfd_vms_slurp_tir (abfd, EOBJ_S_C_ETIR); -} - -/* Process DBG/EDBG record. - Return 0 on success, -1 on error. */ - -int -_bfd_vms_slurp_dbg (bfd *abfd, int objtype ATTRIBUTE_UNUSED) -{ -#if VMS_DEBUG - _bfd_vms_debug (2, "DBG/EDBG\n"); -#endif - - abfd->flags |= (HAS_DEBUG | HAS_LINENO); - - return vms_slurp_debug (abfd); -} - -/* Process TBT/ETBT record. - Return 0 on success, -1 on error. */ - -int -_bfd_vms_slurp_tbt (bfd *abfd, int objtype ATTRIBUTE_UNUSED) -{ -#if VMS_DEBUG - _bfd_vms_debug (2, "TBT/ETBT\n"); -#endif - - abfd->flags |= HAS_LINENO; - - return vms_slurp_debug (abfd); -} - -/* Write DBG/EDBG record. */ - -int -_bfd_vms_write_dbg (bfd *abfd ATTRIBUTE_UNUSED, int objtype ATTRIBUTE_UNUSED) -{ -#if VMS_DEBUG - _bfd_vms_debug (2, "vms_write_dbg (%p, %d)\n", abfd, objtype); -#endif - - return 0; -} - -/* Write TBT/ETBT record. */ - -int -_bfd_vms_write_tbt (bfd *abfd ATTRIBUTE_UNUSED, int objtype ATTRIBUTE_UNUSED) -{ -#if VMS_DEBUG - _bfd_vms_debug (2, "vms_write_tbt (%p, %d)\n", abfd, objtype); -#endif - - return 0; -} diff --git a/bfd/vms-misc.c b/bfd/vms-misc.c index 9646324..67cc25a 100644 --- a/bfd/vms-misc.c +++ b/bfd/vms-misc.c @@ -32,15 +32,17 @@ #include "libbfd.h" #include "safe-ctype.h" -#include "vms.h" - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#ifdef VMS +#include <rms.h> +#include <unixlib.h> +#include <starlet.h> +#define RME$C_SETRFM 0x00000001 +#include <unistd.h> +#endif +#include <time.h> -static int hash_string PARAMS ((const char *)); -static asymbol *new_symbol PARAMS ((bfd *, char *)); -static void maybe_adjust_record_pointer_for_object PARAMS ((bfd *)); -static int vms_get_remaining_object_record PARAMS ((bfd *, int )); -static int vms_get_remaining_image_record PARAMS ((bfd *, int )); +#include "vms.h" +#include "vms/emh.h" #if VMS_DEBUG /* Debug functions. */ @@ -82,7 +84,7 @@ _bfd_vms_debug (int level, char *format, ...) if (abslvl > min_level) return; - while (--level>0) + while (--level > 0) fprintf (output, " "); va_start (args, format); vfprintf (output, format, args); @@ -94,10 +96,7 @@ _bfd_vms_debug (int level, char *format, ...) hex dump 'size' bytes starting at 'ptr'. */ void -_bfd_hexdump (int level, - unsigned char *ptr, - int size, - int offset) +_bfd_hexdump (int level, unsigned char *ptr, int size, int offset) { unsigned char *lptr = ptr; int count = 0; @@ -105,445 +104,35 @@ _bfd_hexdump (int level, while (size-- > 0) { - if ((count%16) == 0) + if ((count % 16) == 0) vms_debug (level, "%08lx:", start); vms_debug (-level, " %02x", *ptr++); count++; start++; if (size == 0) { - while ((count%16) != 0) + while ((count % 16) != 0) { vms_debug (-level, " "); count++; } } - if ((count%16) == 0) + if ((count % 16) == 0) { vms_debug (-level, " "); while (lptr < ptr) { - vms_debug (-level, "%c", (*lptr < 32)?'.':*lptr); + vms_debug (-level, "%c", (*lptr < 32) ? '.' : *lptr); lptr++; } vms_debug (-level, "\n"); } } - if ((count%16) != 0) + if ((count % 16) != 0) vms_debug (-level, "\n"); } #endif -/* Hash functions - - These are needed when reading an object file. */ - -/* Allocate new vms_hash_entry - keep the symbol name and a pointer to the bfd symbol in the table. */ - -struct bfd_hash_entry * -_bfd_vms_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - vms_symbol_entry *ret; - -#if VMS_DEBUG - vms_debug (5, "_bfd_vms_hash_newfunc (%p, %p, %s)\n", entry, table, string); -#endif - - if (entry == NULL) - { - ret = (vms_symbol_entry *) - bfd_hash_allocate (table, sizeof (vms_symbol_entry)); - if (ret == NULL) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } - entry = (struct bfd_hash_entry *) ret; - } - - /* Call the allocation method of the base class. */ - ret = (vms_symbol_entry *) bfd_hash_newfunc (entry, table, string); -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_hash_newfunc ret %p\n", ret); -#endif - - ret->symbol = NULL; - - return (struct bfd_hash_entry *)ret; -} - -/* Object file input functions. */ - -/* Return type and size from record header (buf) on Alpha. */ - -void -_bfd_vms_get_header_values (bfd * abfd ATTRIBUTE_UNUSED, - unsigned char *buf, - int *type, - int *size) -{ - if (type) - *type = bfd_getl16 (buf); - - if (size) - *size = bfd_getl16 (buf+2); - -#if VMS_DEBUG - vms_debug (10, "_bfd_vms_get_header_values type %x, size %x\n", - type ? *type : 0, size ? *size : 0); -#endif -} - -/* Get next record from object file to vms_buf. - Set PRIV(buf_size) and return it - - This is a little tricky since it should be portable. - - The openVMS object file has 'variable length' which means that - read() returns data in chunks of (hopefully) correct and expected - size. The linker (and other tools on VMS) depend on that. Unix - doesn't know about 'formatted' files, so reading and writing such - an object file in a Unix environment is not trivial. - - With the tool 'file' (available on all VMS FTP sites), one - can view and change the attributes of a file. Changing from - 'variable length' to 'fixed length, 512 bytes' reveals the - record size at the first 2 bytes of every record. The same - may happen during the transfer of object files from VMS to Unix, - at least with UCX, the DEC implementation of TCP/IP. - - The VMS format repeats the size at bytes 2 & 3 of every record. - - On the first call (file_format == FF_UNKNOWN) we check if - the first and the third byte pair (!) of the record match. - If they do it's an object file in an Unix environment or with - wrong attributes (FF_FOREIGN), else we should be in a VMS - environment where read() returns the record size (FF_NATIVE). - - Reading is always done in 2 steps: - 1. first just the record header is read and the size extracted, - 2. then the read buffer is adjusted and the remaining bytes are - read in. - - All file I/O is done on even file positions. */ - -#define VMS_OBJECT_ADJUSTMENT 2 - -static void -maybe_adjust_record_pointer_for_object (bfd *abfd) -{ - /* Set the file format once for all on the first invocation. */ - if (PRIV (file_format) == FF_UNKNOWN) - { - if (PRIV (vms_rec)[0] == PRIV (vms_rec)[4] - && PRIV (vms_rec)[1] == PRIV (vms_rec)[5]) - PRIV (file_format) = FF_FOREIGN; - else - PRIV (file_format) = FF_NATIVE; - } - - /* The adjustment is needed only in an Unix environment. */ - if (PRIV (file_format) == FF_FOREIGN) - PRIV (vms_rec) += VMS_OBJECT_ADJUSTMENT; -} - -/* Get first record from file and return the file type. */ - -int -_bfd_vms_get_first_record (bfd *abfd) -{ - unsigned int test_len; - -#if VMS_DEBUG - vms_debug (8, "_bfd_vms_get_first_record\n"); -#endif - - if (PRIV (is_vax)) - test_len = 0; - else - /* Minimum is 6 bytes for objects (2 bytes size, 2 bytes record id, - 2 bytes size repeated) and 12 bytes for images (4 bytes major id, - 4 bytes minor id, 4 bytes length). */ - test_len = 12; - - /* Size the main buffer. */ - if (PRIV (buf_size) == 0) - { - /* On VAX there's no size information in the record, so - start with OBJ_S_C_MAXRECSIZ. */ - bfd_size_type amt = (test_len ? test_len : OBJ_S_C_MAXRECSIZ); - PRIV (vms_buf) = (unsigned char *) bfd_malloc (amt); - PRIV (buf_size) = amt; - } - - /* Initialize the record pointer. */ - PRIV (vms_rec) = PRIV (vms_buf); - - /* We only support modules on VAX. */ - if (PRIV (is_vax)) - { - if (vms_get_remaining_object_record (abfd, test_len) <= 0) - return FT_UNKNOWN; - -#if VMS_DEBUG - vms_debug (2, "file type is VAX module\n"); -#endif - - return FT_MODULE; - } - - if (bfd_bread (PRIV (vms_buf), test_len, abfd) != test_len) - { - bfd_set_error (bfd_error_file_truncated); - return FT_UNKNOWN; - } - - /* Is it an image? */ - if ((bfd_getl32 (PRIV (vms_rec)) == EIHD_S_K_MAJORID) - && (bfd_getl32 (PRIV (vms_rec) + 4) == EIHD_S_K_MINORID)) - { - if (vms_get_remaining_image_record (abfd, test_len) <= 0) - return FT_UNKNOWN; - -#if VMS_DEBUG - vms_debug (2, "file type is image\n"); -#endif - - return FT_IMAGE; - } - - /* Assume it's a module and adjust record pointer if necessary. */ - maybe_adjust_record_pointer_for_object (abfd); - - /* But is it really a module? */ - if (bfd_getl16 (PRIV (vms_rec)) <= EOBJ_S_C_MAXRECTYP - && bfd_getl16 (PRIV (vms_rec) + 2) <= EOBJ_S_C_MAXRECSIZ) - { - if (vms_get_remaining_object_record (abfd, test_len) <= 0) - return FT_UNKNOWN; - -#if VMS_DEBUG - vms_debug (2, "file type is module\n"); -#endif - - return FT_MODULE; - } - -#if VMS_DEBUG - vms_debug (2, "file type is unknown\n"); -#endif - - return FT_UNKNOWN; -} - -/* Implement step #1 of the object record reading procedure. - Return the record type or -1 on failure. */ - -int -_bfd_vms_get_object_record (bfd *abfd) -{ - unsigned int test_len; - int type; - -#if VMS_DEBUG - vms_debug (8, "_bfd_vms_get_obj_record\n"); -#endif - - if (PRIV (is_vax)) - test_len = 0; - else - { - int off = 0; - - /* See _bfd_vms_get_first_record. */ - test_len = 6; - - /* Skip odd alignment byte. */ - if (bfd_tell (abfd) & 1) - { - if (bfd_bread (PRIV (vms_buf), 1, abfd) != 1) - { - bfd_set_error (bfd_error_file_truncated); - return -1; - } - /* Alignment byte may be present or not. This is not easy to - detect but all object record types are not 0 (on Alpha VMS). - We also hope that pad byte is 0. */ - if (PRIV (vms_buf)[0]) - off = 1; - } - - /* Read the record header */ - if (bfd_bread (PRIV (vms_buf) + off, test_len - off, abfd) - != test_len - off) - { - bfd_set_error (bfd_error_file_truncated); - return -1; - } - - /* Reset the record pointer. */ - PRIV (vms_rec) = PRIV (vms_buf); - maybe_adjust_record_pointer_for_object (abfd); - } - - if (vms_get_remaining_object_record (abfd, test_len) <= 0) - return -1; - - if (PRIV (is_vax)) - type = PRIV (vms_rec) [0]; - else - type = bfd_getl16 (PRIV (vms_rec)); - -#if VMS_DEBUG - vms_debug (8, "_bfd_vms_get_obj_record: rec %p, size %d, type %d\n", - PRIV (vms_rec), PRIV (rec_size), type); -#endif - - return type; -} - -/* Implement step #2 of the object record reading procedure. - Return the size of the record or 0 on failure. */ - -static int -vms_get_remaining_object_record (bfd *abfd, int read_so_far) -{ -#if VMS_DEBUG - vms_debug (8, "vms_get_remaining_obj_record\n"); -#endif - - if (PRIV (is_vax)) - { - if (read_so_far != 0) - abort (); - - PRIV (rec_size) = bfd_bread (PRIV (vms_buf), PRIV (buf_size), abfd); - - if (PRIV (rec_size) <= 0) - { - bfd_set_error (bfd_error_file_truncated); - return 0; - } - - /* Reset the record pointer. */ - PRIV (vms_rec) = PRIV (vms_buf); - } - else - { - unsigned int to_read; - - /* Extract record size. */ - PRIV (rec_size) = bfd_getl16 (PRIV (vms_rec) + 2); - - if (PRIV (rec_size) <= 0) - { - bfd_set_error (bfd_error_file_truncated); - return 0; - } - - /* That's what the linker manual says. */ - if (PRIV (rec_size) > EOBJ_S_C_MAXRECSIZ) - { - bfd_set_error (bfd_error_file_truncated); - return 0; - } - - /* Take into account object adjustment. */ - to_read = PRIV (rec_size); - if (PRIV (file_format) == FF_FOREIGN) - to_read += VMS_OBJECT_ADJUSTMENT; - - /* Adjust the buffer. */ - if (to_read > PRIV (buf_size)) - { - PRIV (vms_buf) - = (unsigned char *) bfd_realloc (PRIV (vms_buf), to_read); - if (PRIV (vms_buf) == NULL) - return 0; - PRIV (buf_size) = to_read; - } - - /* Read the remaining record. */ - to_read -= read_so_far; - -#if VMS_DEBUG - vms_debug (8, "vms_get_remaining_obj_record: to_read %d\n", to_read); -#endif - - if (bfd_bread (PRIV (vms_buf) + read_so_far, to_read, abfd) != to_read) - { - bfd_set_error (bfd_error_file_truncated); - return 0; - } - - /* Reset the record pointer. */ - PRIV (vms_rec) = PRIV (vms_buf); - maybe_adjust_record_pointer_for_object (abfd); - } - -#if VMS_DEBUG - vms_debug (8, "vms_get_remaining_obj_record: size %d\n", PRIV (rec_size)); -#endif - - return PRIV (rec_size); -} - -/* Implement step #2 of the record reading procedure for images. - Return the size of the record or 0 on failure. */ - -static int -vms_get_remaining_image_record (bfd *abfd, int read_so_far) -{ - unsigned int to_read; - int remaining; - - /* Extract record size. */ - PRIV (rec_size) = bfd_getl32 (PRIV (vms_rec) + EIHD_S_L_SIZE); - - if (PRIV (rec_size) > PRIV (buf_size)) - { - PRIV (vms_buf) = bfd_realloc (PRIV (vms_buf), PRIV (rec_size)); - - if (PRIV (vms_buf) == NULL) - { - bfd_set_error (bfd_error_no_memory); - return 0; - } - - PRIV (buf_size) = PRIV (rec_size); - } - - /* Read the remaining record. */ - remaining = PRIV (rec_size) - read_so_far; - to_read = MIN (VMS_BLOCK_SIZE - read_so_far, remaining); - - while (remaining > 0) - { - if (bfd_bread (PRIV (vms_buf) + read_so_far, to_read, abfd) != to_read) - { - bfd_set_error (bfd_error_file_truncated); - return 0; - } - - read_so_far += to_read; - remaining -= to_read; - - /* Eat trailing 0xff's. */ - if (remaining > 0) - while (PRIV (vms_buf) [read_so_far - 1] == 0xff) - read_so_far--; - - to_read = MIN (VMS_BLOCK_SIZE, remaining); - } - - /* Reset the record pointer. */ - PRIV (vms_rec) = PRIV (vms_buf); - - return PRIV (rec_size); -} /* Copy sized string (string with fixed size) to new allocated area size is string size (size of record) */ @@ -555,7 +144,7 @@ _bfd_vms_save_sized_string (unsigned char *str, int size) if (newstr == NULL) return NULL; - strncpy (newstr, (char *) str, (size_t) size); + memcpy (newstr, (char *) str, (size_t) size); newstr[size] = 0; return newstr; @@ -572,280 +161,196 @@ _bfd_vms_save_counted_string (unsigned char *ptr) return _bfd_vms_save_sized_string (ptr, len); } -/* Stack routines for vms ETIR commands. */ +/* Object output routines. */ -/* Push value and section index. */ +/* Begin new record. + Write 2 bytes rectype and 2 bytes record length. */ void -_bfd_vms_push (bfd * abfd, uquad val, int psect) +_bfd_vms_output_begin (struct vms_rec_wr *recwr, int rectype) { - static int last_psect; + vms_debug2 ((6, "_bfd_vms_output_begin (type %d)\n", rectype)); -#if VMS_DEBUG - vms_debug (4, "<push %016lx (%d) at %d>\n", val, psect, PRIV (stackptr)); -#endif - - if (psect >= 0) - last_psect = psect; + /* Record must have been closed. */ + BFD_ASSERT (recwr->size == 0); - PRIV (stack[PRIV (stackptr)]).value = val; - PRIV (stack[PRIV (stackptr)]).psect = last_psect; - PRIV (stackptr)++; - if (PRIV (stackptr) >= STACKSIZE) - { - bfd_set_error (bfd_error_bad_value); - (*_bfd_error_handler) (_("Stack overflow (%d) in _bfd_vms_push"), PRIV (stackptr)); - exit (1); - } -} + _bfd_vms_output_short (recwr, (unsigned int) rectype); -/* Pop value and section index. */ - -uquad -_bfd_vms_pop (bfd * abfd, int *psect) -{ - uquad value; - - if (PRIV (stackptr) == 0) - { - bfd_set_error (bfd_error_bad_value); - (*_bfd_error_handler) (_("Stack underflow in _bfd_vms_pop")); - exit (1); - } - PRIV (stackptr)--; - value = PRIV (stack[PRIV (stackptr)]).value; - if ((psect != NULL) && (PRIV (stack[PRIV (stackptr)]).psect >= 0)) - *psect = PRIV (stack[PRIV (stackptr)]).psect; - -#if VMS_DEBUG - vms_debug (4, "<pop %016lx(%d)>\n", value, PRIV (stack[PRIV (stackptr)]).psect); -#endif - - return value; + /* Placeholder for length. */ + _bfd_vms_output_short (recwr, 0); } - -/* Object output routines. */ -/* Begin new record or record header - write 2 bytes rectype - write 2 bytes record length (filled in at flush) - write 2 bytes header type (ommitted if rechead == -1). */ +/* Begin new sub-record. + Write 2 bytes rectype, and 2 bytes record length. */ void -_bfd_vms_output_begin (bfd * abfd, int rectype, int rechead) +_bfd_vms_output_begin_subrec (struct vms_rec_wr *recwr, int rectype) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_begin (type %d, head %d)\n", rectype, - rechead); -#endif + vms_debug2 ((6, "_bfd_vms_output_begin_subrec (type %d)\n", rectype)); - _bfd_vms_output_short (abfd, (unsigned int) rectype); + /* Subrecord must have been closed. */ + BFD_ASSERT (recwr->subrec_offset == 0); - /* Save current output position to fill in length later. */ + /* Save start of subrecord offset. */ + recwr->subrec_offset = recwr->size; - if (PRIV (push_level) > 0) - PRIV (length_pos) = PRIV (output_size); - -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_begin: length_pos = %d\n", - PRIV (length_pos)); -#endif + /* Subrecord type. */ + _bfd_vms_output_short (recwr, (unsigned int) rectype); /* Placeholder for length. */ - _bfd_vms_output_short (abfd, 0); - - if (rechead != -1) - _bfd_vms_output_short (abfd, (unsigned int) rechead); + _bfd_vms_output_short (recwr, 0); } /* Set record/subrecord alignment. */ void -_bfd_vms_output_alignment (bfd * abfd, int alignto) +_bfd_vms_output_alignment (struct vms_rec_wr *recwr, int alignto) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_alignment (%d)\n", alignto); -#endif - - PRIV (output_alignment) = alignto; + vms_debug2 ((6, "_bfd_vms_output_alignment (%d)\n", alignto)); + recwr->align = alignto; } -/* Prepare for subrecord fields. */ - -void -_bfd_vms_output_push (bfd * abfd) -{ -#if VMS_DEBUG - vms_debug (6, "vms_output_push (pushed_size = %d)\n", PRIV (output_size)); -#endif +/* Align the size of the current record (whose length is LENGTH). + Warning: this obviously changes the record (and the possible subrecord) + length. */ - PRIV (push_level)++; - PRIV (pushed_size) = PRIV (output_size); -} - -/* End of subrecord fields. */ - -void -_bfd_vms_output_pop (bfd * abfd) +static void +_bfd_vms_output_align (struct vms_rec_wr *recwr, unsigned int length) { -#if VMS_DEBUG - vms_debug (6, "vms_output_pop (pushed_size = %d)\n", PRIV (pushed_size)); -#endif - - _bfd_vms_output_flush (abfd); - PRIV (length_pos) = 2; + unsigned int real_size = recwr->size; + unsigned int aligncount; -#if VMS_DEBUG - vms_debug (6, "vms_output_pop: length_pos = %d\n", PRIV (length_pos)); -#endif + /* Pad with 0 if alignment is required. */ + aligncount = (recwr->align - (length % recwr->align)) % recwr->align; + vms_debug2 ((6, "align: adding %d bytes\n", aligncount)); + while (aligncount-- > 0) + recwr->buf[real_size++] = 0; - PRIV (pushed_size) = 0; - PRIV (push_level)--; + recwr->size = real_size; } -/* Flush unwritten output, ends current record. */ +/* Ends current sub-record. Set length field. */ void -_bfd_vms_output_flush (bfd * abfd) +_bfd_vms_output_end_subrec (struct vms_rec_wr *recwr) { - int real_size = PRIV (output_size); - int aligncount; + int real_size = recwr->size; int length; -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_flush (real_size = %d, pushed_size %d at lenpos %d)\n", - real_size, PRIV (pushed_size), PRIV (length_pos)); -#endif + /* Subrecord must be open. */ + BFD_ASSERT (recwr->subrec_offset != 0); - if (PRIV (push_level) > 0) - length = real_size - PRIV (pushed_size); - else - length = real_size; + length = real_size - recwr->subrec_offset; if (length == 0) return; - aligncount = (PRIV (output_alignment) - - (length % PRIV (output_alignment))) % PRIV (output_alignment); - -#if VMS_DEBUG - vms_debug (6, "align: adding %d bytes\n", aligncount); -#endif - while (aligncount-- > 0) - { - PRIV (output_buf)[real_size++] = 0; - length++; - } + _bfd_vms_output_align (recwr, length); /* Put length to buffer. */ - PRIV (output_size) = PRIV (length_pos); - _bfd_vms_output_short (abfd, (unsigned int) length); + bfd_putl16 ((bfd_vma) (recwr->size - recwr->subrec_offset), + recwr->buf + recwr->subrec_offset + 2); - if (PRIV (push_level) == 0) - { - /* File is open in undefined (UDF) format on VMS, but ultimately will be - converted to variable length (VAR) format. VAR format has a length - word first which must be explicitly output in UDF format. */ - bfd_bwrite (PRIV (output_buf) + 2, 2, abfd); - bfd_bwrite (PRIV (output_buf), (size_t) real_size, abfd); - PRIV (output_size) = 0; - } - else - { - PRIV (output_size) = real_size; - PRIV (pushed_size) = PRIV (output_size); - } + /* Close the subrecord. */ + recwr->subrec_offset = 0; } -/* End record output. */ +/* Ends current record (and write it). */ void -_bfd_vms_output_end (bfd * abfd) +_bfd_vms_output_end (bfd *abfd, struct vms_rec_wr *recwr) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_end\n"); -#endif + vms_debug2 ((6, "_bfd_vms_output_end (size %u)\n", recwr->size)); - _bfd_vms_output_flush (abfd); -} + /* Subrecord must have been closed. */ + BFD_ASSERT (recwr->subrec_offset == 0); + + if (recwr->size == 0) + return; -/* Check remaining buffer size + _bfd_vms_output_align (recwr, recwr->size); - Return what's left. */ + /* Write the length word. */ + bfd_putl16 ((bfd_vma) recwr->size, recwr->buf + 2); + + /* File is open in undefined (UDF) format on VMS, but ultimately will be + converted to variable length (VAR) format. VAR format has a length + word first which must be explicitly output in UDF format. */ + /* So, first the length word. */ + bfd_bwrite (recwr->buf + 2, 2, abfd); + + /* Align. */ + if (recwr->size & 1) + recwr->buf[recwr->size++] = 0; + + /* Then the record. */ + bfd_bwrite (recwr->buf, (size_t) recwr->size, abfd); + + recwr->size = 0; +} + +/* Check remaining buffer size. Return what's left. */ int -_bfd_vms_output_check (bfd * abfd, int size) +_bfd_vms_output_check (struct vms_rec_wr *recwr, int size) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_check (%d)\n", size); -#endif + vms_debug2 ((6, "_bfd_vms_output_check (%d)\n", size)); - return (MAX_OUTREC_SIZE - (PRIV (output_size) + size + MIN_OUTREC_LUFT)); + return (MAX_OUTREC_SIZE - (recwr->size + size + MIN_OUTREC_LUFT)); } /* Output byte (8 bit) value. */ void -_bfd_vms_output_byte (bfd * abfd, unsigned int value) +_bfd_vms_output_byte (struct vms_rec_wr *recwr, unsigned int value) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_byte (%02x)\n", value); -#endif + vms_debug2 ((6, "_bfd_vms_output_byte (%02x)\n", value)); - bfd_put_8 (abfd, value & 0xff, PRIV (output_buf) + PRIV (output_size)); - PRIV (output_size) += 1; + *(recwr->buf + recwr->size) = value; + recwr->size += 1; } /* Output short (16 bit) value. */ void -_bfd_vms_output_short (bfd * abfd, unsigned int value) +_bfd_vms_output_short (struct vms_rec_wr *recwr, unsigned int value) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_short (%04x)\n", value); -#endif + vms_debug2 ((6, "_bfd_vms_output_short (%04x)\n", value)); - bfd_put_16 (abfd, (bfd_vma) value & 0xffff, - PRIV (output_buf) + PRIV (output_size)); - PRIV (output_size) += 2; + bfd_putl16 ((bfd_vma) value & 0xffff, recwr->buf + recwr->size); + recwr->size += 2; } /* Output long (32 bit) value. */ void -_bfd_vms_output_long (bfd * abfd, unsigned long value) +_bfd_vms_output_long (struct vms_rec_wr *recwr, unsigned long value) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_long (%08lx)\n", value); -#endif + vms_debug2 ((6, "_bfd_vms_output_long (%08lx)\n", value)); - bfd_put_32 (abfd, (bfd_vma) value, PRIV (output_buf) + PRIV (output_size)); - PRIV (output_size) += 4; + bfd_putl32 ((bfd_vma) value, recwr->buf + recwr->size); + recwr->size += 4; } /* Output quad (64 bit) value. */ void -_bfd_vms_output_quad (bfd * abfd, uquad value) +_bfd_vms_output_quad (struct vms_rec_wr *recwr, bfd_vma value) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_quad (%016lx)\n", value); -#endif + vms_debug2 ((6, "_bfd_vms_output_quad (%08lx)\n", (unsigned long)value)); - bfd_put_64(abfd, value, PRIV (output_buf) + PRIV (output_size)); - PRIV (output_size) += 8; + bfd_putl64 (value, recwr->buf + recwr->size); + recwr->size += 8; } /* Output c-string as counted string. */ void -_bfd_vms_output_counted (bfd * abfd, char *value) +_bfd_vms_output_counted (struct vms_rec_wr *recwr, char *value) { int len; -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_counted (%s)\n", value); -#endif + vms_debug2 ((6, "_bfd_vms_output_counted (%s)\n", value)); len = strlen (value); if (len == 0) @@ -858,193 +363,117 @@ _bfd_vms_output_counted (bfd * abfd, char *value) (*_bfd_error_handler) (_("_bfd_vms_output_counted called with too many bytes")); return; } - _bfd_vms_output_byte (abfd, (unsigned int) len & 0xff); - _bfd_vms_output_dump (abfd, (unsigned char *) value, len); + _bfd_vms_output_byte (recwr, (unsigned int) len & 0xff); + _bfd_vms_output_dump (recwr, (unsigned char *) value, len); } /* Output character area. */ void -_bfd_vms_output_dump (bfd * abfd, - unsigned char *data, - int length) +_bfd_vms_output_dump (struct vms_rec_wr *recwr, unsigned char *data, int len) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_dump (%d)\n", length); -#endif + vms_debug2 ((6, "_bfd_vms_output_dump (%d)\n", len)); - if (length == 0) + if (len == 0) return; - memcpy (PRIV (output_buf) + PRIV (output_size), data, (size_t) length); - PRIV (output_size) += length; + memcpy (recwr->buf + recwr->size, data, (size_t) len); + recwr->size += len; } /* Output count bytes of value. */ void -_bfd_vms_output_fill (bfd * abfd, - int value, - int count) +_bfd_vms_output_fill (struct vms_rec_wr *recwr, int value, int count) { -#if VMS_DEBUG - vms_debug (6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count); -#endif + vms_debug2 ((6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count)); if (count == 0) return; - memset (PRIV (output_buf) + PRIV (output_size), value, (size_t) count); - PRIV (output_size) += count; -} - -/* This hash routine borrowed from GNU-EMACS, and strengthened slightly. ERY. */ - -static int -hash_string (const char *ptr) -{ - const unsigned char *p = (unsigned char *) ptr; - const unsigned char *end = p + strlen (ptr); - unsigned char c; - int hash = 0; - - while (p != end) - { - c = *p++; - hash = ((hash << 3) + (hash << 15) + (hash >> 28) + c); - } - return hash; + memset (recwr->buf + recwr->size, value, (size_t) count); + recwr->size += count; } -/* Generate a length-hashed VMS symbol name (limited to maxlen chars). */ +#ifdef VMS +/* Convert the file to variable record length format. This is done + using undocumented system call sys$modify(). + Pure VMS version. */ -char * -_bfd_vms_length_hash_symbol (bfd * abfd, const char *in, int maxlen) +static void +vms_convert_to_var (char *vms_filename) { - unsigned long result; - int in_len; - char *new_name; - const char *old_name; - int i; - static char outbuf[EOBJ_S_C_SYMSIZ+1]; - char *out = outbuf; - -#if VMS_DEBUG - vms_debug (4, "_bfd_vms_length_hash_symbol \"%s\"\n", in); -#endif - - if (maxlen > EOBJ_S_C_SYMSIZ) - maxlen = EOBJ_S_C_SYMSIZ; - - /* Save this for later. */ - new_name = out; - - /* We may need to truncate the symbol, save the hash for later. */ - in_len = strlen (in); + struct FAB fab = cc$rms_fab; - result = (in_len > maxlen) ? hash_string (in) : 0; + fab.fab$l_fna = vms_filename; + fab.fab$b_fns = strlen (vms_filename); + fab.fab$b_fac = FAB$M_PUT; + fab.fab$l_fop = FAB$M_ESC; + fab.fab$l_ctx = RME$C_SETRFM; - old_name = in; + sys$open (&fab); - /* Do the length checking. */ - if (in_len <= maxlen) - i = in_len; - else - { - if (PRIV (flag_hash_long_names)) - i = maxlen-9; - else - i = maxlen; - } - - strncpy (out, in, (size_t) i); - in += i; - out += i; - - if ((in_len > maxlen) - && PRIV (flag_hash_long_names)) - sprintf (out, "_%08lx", result); - else - *out = 0; - -#if VMS_DEBUG - vms_debug (4, "--> [%d]\"%s\"\n", strlen (outbuf), outbuf); -#endif - - if (in_len > maxlen - && PRIV (flag_hash_long_names) - && PRIV (flag_show_after_trunc)) - printf (_("Symbol %s replaced by %s\n"), old_name, new_name); + fab.fab$b_rfm = FAB$C_VAR; - return outbuf; + sys$modify (&fab); + sys$close (&fab); } -/* Allocate and initialize a new symbol. */ - -static asymbol * -new_symbol (bfd * abfd, char *name) +static int +vms_convert_to_var_1 (char *filename, int type) { - asymbol *symbol; - -#if VMS_DEBUG - _bfd_vms_debug (7, "new_symbol %s\n", name); -#endif - - symbol = bfd_make_empty_symbol (abfd); - if (symbol == 0) - return symbol; - symbol->name = name; - symbol->section = (asection *)(unsigned long)-1; - - return symbol; + if (type != DECC$K_FILE) + return FALSE; + vms_convert_to_var (filename); + return TRUE; } -/* Allocate and enter a new private symbol. */ +/* Convert the file to variable record length format. This is done + using undocumented system call sys$modify(). + Unix filename version. */ -vms_symbol_entry * -_bfd_vms_enter_symbol (bfd * abfd, char *name) -{ - vms_symbol_entry *entry; - -#if VMS_DEBUG - _bfd_vms_debug (6, "_bfd_vms_enter_symbol %s\n", name); -#endif - - entry = (vms_symbol_entry *) - bfd_hash_lookup (PRIV (vms_symbol_table), name, FALSE, FALSE); - if (entry == 0) - { -#if VMS_DEBUG - _bfd_vms_debug (8, "creating hash entry for %s\n", name); -#endif - entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table), - name, TRUE, FALSE); - if (entry != 0) - { - asymbol *symbol; - symbol = new_symbol (abfd, name); - if (symbol != 0) - { - entry->symbol = symbol; - PRIV (gsd_sym_count)++; - abfd->symcount++; - } - else - entry = 0; - } - else - (*_bfd_error_handler) (_("failed to enter %s"), name); - } - else - { -#if VMS_DEBUG - _bfd_vms_debug (8, "found hash entry for %s\n", name); -#endif - } - -#if VMS_DEBUG - _bfd_vms_debug (7, "-> entry %p, entry->symbol %p\n", entry, entry->symbol); -#endif - return entry; +static int +vms_convert_to_var_unix_filename (const char *unix_filename) +{ + if (decc$to_vms (unix_filename, &vms_convert_to_var_1, 0, 1) != 1) + return FALSE; + return TRUE; +} +#endif /* VMS */ + +/* Manufacture a VMS like time on a unix based system. + stolen from obj-vms.c. */ + +unsigned char * +get_vms_time_string (void) +{ + static unsigned char tbuf[18]; +#ifndef VMS + char *pnt; + time_t timeb; + + time (& timeb); + pnt = ctime (&timeb); + pnt[3] = 0; + pnt[7] = 0; + pnt[10] = 0; + pnt[16] = 0; + pnt[24] = 0; + sprintf ((char *) tbuf, "%2s-%3s-%s %s", + pnt + 8, pnt + 4, pnt + 20, pnt + 11); +#else + struct + { + int Size; + unsigned char *Ptr; + } Descriptor; + Descriptor.Size = 17; + Descriptor.Ptr = tbuf; + SYS$ASCTIM (0, &Descriptor, 0, 0); +#endif /* not VMS */ + + vms_debug2 ((6, "vmstimestring:'%s'\n", tbuf)); + + return tbuf; } /* Create module name from filename (ie, extract the basename and convert it diff --git a/bfd/vms-tir.c b/bfd/vms-tir.c deleted file mode 100644 index 1ecb151..0000000 --- a/bfd/vms-tir.c +++ /dev/null @@ -1,2808 +0,0 @@ -/* vms-tir.c -- BFD back-end for VAX (openVMS/VAX) and - EVAX (openVMS/Alpha) files. - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2007, - 2008, 2009 Free Software Foundation, Inc. - - TIR record handling functions - ETIR record handling functions - - Go and read the openVMS linker manual (esp. appendix B) - if you don't know what's going on here :-) - - Written by Klaus K"ampf (kkaempf@rmi.de) - - 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 3 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., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* The following type abbreviations are used: - - cs counted string (ascii string with length byte) - by byte (1 byte) - sh short (2 byte, 16 bit) - lw longword (4 byte, 32 bit) - qw quadword (8 byte, 64 bit) - da data stream */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "vms.h" - -static int check_section (bfd *, int); -static void image_set_ptr (bfd *abfd, int psect, uquad offset); -static void image_inc_ptr (bfd *abfd, uquad offset); -static void dst_define_location (bfd *abfd, uquad loc); -static void dst_restore_location (bfd *abfd, uquad loc); -static unsigned int dst_retrieve_location (bfd *abfd, uquad loc); -static void dst_check_allocation (bfd *abfd, unsigned int size); -static void image_dump (bfd *abfd, unsigned char *ptr, int size, int offset); -static void image_write_b (bfd *abfd, unsigned int value); -static void image_write_w (bfd *abfd, unsigned int value); -static void image_write_l (bfd *abfd, unsigned long value); -static void image_write_q (bfd *abfd, uquad value); -static bfd_boolean etir_sta (bfd *, int, unsigned char *, int *); -static bfd_boolean etir_sto (bfd *, int, unsigned char *, int *); -static bfd_boolean etir_opr (bfd *, int, unsigned char *, int *); -static bfd_boolean etir_ctl (bfd *, int, unsigned char *, int *); -static bfd_boolean etir_stc (bfd *, int, unsigned char *, int *); -static asection *new_section (bfd *, int); -static int alloc_section (bfd *, unsigned int); -static int etir_cmd (bfd *, int, unsigned char *, int *); -static int analyze_tir (bfd *, unsigned char *, unsigned int); -static int analyze_etir (bfd *, unsigned char *, unsigned int); -static unsigned char *tir_opr (bfd *, unsigned char *); -static const char *tir_cmd_name (int); -static const char *cmd_name (int); - - -static int -check_section (bfd * abfd, int size) -{ - bfd_size_type offset; - - offset = PRIV (image_ptr) - PRIV (image_section)->contents; - if (offset + size > PRIV (image_section)->size) - { - PRIV (image_section)->contents - = bfd_realloc_or_free (PRIV (image_section)->contents, offset + size); - if (PRIV (image_section)->contents == NULL) - { - (*_bfd_error_handler) (_("No Mem !")); - return -1; - } - PRIV (image_section)->size = offset + size; - PRIV (image_ptr) = PRIV (image_section)->contents + offset; - } - - return 0; -} - -/* Routines to fill sections contents during tir/etir read. */ - -/* Initialize image buffer pointer to be filled. */ - -static void -image_set_ptr (bfd * abfd, int psect, uquad offset) -{ -#if VMS_DEBUG - _bfd_vms_debug (4, "image_set_ptr (%d=%s, %d)\n", - psect, PRIV (sections)[psect]->name, offset); -#endif - - PRIV (image_ptr) = PRIV (sections)[psect]->contents + offset; - PRIV (image_section) = PRIV (sections)[psect]; -} - -/* Increment image buffer pointer by offset. */ - -static void -image_inc_ptr (bfd * abfd, uquad offset) -{ -#if VMS_DEBUG - _bfd_vms_debug (4, "image_inc_ptr (%d)\n", offset); -#endif - - PRIV (image_ptr) += offset; -} - -/* Save current DST location counter under specified index. */ - -static void -dst_define_location (bfd *abfd, uquad loc) -{ - asection *dst_section = PRIV (dst_section); - -#if VMS_DEBUG - _bfd_vms_debug (4, "dst_define_location (%d)\n", (int)loc); -#endif - - /* Grow the ptr offset table if necessary. */ - if (loc + 1 > PRIV (dst_ptr_offsets_count)) - { - PRIV (dst_ptr_offsets) = bfd_realloc (PRIV (dst_ptr_offsets), - (loc + 1) * sizeof (unsigned int)); - PRIV (dst_ptr_offsets_count) = loc + 1; - } - - PRIV (dst_ptr_offsets)[loc] = PRIV (image_ptr) - dst_section->contents; -} - -/* Restore saved DST location counter from specified index. */ - -static void -dst_restore_location (bfd *abfd, uquad loc) -{ - asection *dst_section = PRIV (dst_section); - -#if VMS_DEBUG - _bfd_vms_debug (4, "dst_restore_location (%d)\n", (int)loc); -#endif - - PRIV (image_ptr) = dst_section->contents + PRIV (dst_ptr_offsets)[loc]; -} - -/* Retrieve saved DST location counter from specified index. */ - -static unsigned int -dst_retrieve_location (bfd *abfd, uquad loc) -{ -#if VMS_DEBUG - _bfd_vms_debug (4, "dst_retrieve_location (%d)\n", (int)loc); -#endif - - return PRIV (dst_ptr_offsets)[loc]; -} - -/* Check that the DST section is big enough for the specified - amount of bytes. */ - -static void -dst_check_allocation (bfd *abfd, unsigned int size) -{ - asection *dst_section = PRIV (dst_section); - - bfd_size_type used = PRIV (image_ptr) - dst_section->contents; - bfd_size_type left = dst_section->size - used; - - /* Grow the DST section as necessary */ - if (size > left) - { - dst_section->size *= 2; - dst_section->contents - = bfd_realloc (dst_section->contents, dst_section->size); - PRIV (image_ptr) = dst_section->contents + used; - - dst_check_allocation (abfd, size); - } -} - -/* Dump multiple bytes to section image. */ - -static void -image_dump (bfd * abfd, - unsigned char *ptr, - int size, - int offset ATTRIBUTE_UNUSED) -{ -#if VMS_DEBUG - _bfd_vms_debug (8, "image_dump from (%p, %d) to (%p)\n", ptr, size, - PRIV (image_ptr)); - _bfd_hexdump (9, ptr, size, offset); -#endif - - if (PRIV (is_vax) && check_section (abfd, size)) - return; - - if (PRIV (dst_section)) - dst_check_allocation (abfd, size); - - while (size-- > 0) - *PRIV (image_ptr)++ = *ptr++; -} - -/* Write byte to section image. */ - -static void -image_write_b (bfd * abfd, unsigned int value) -{ -#if VMS_DEBUG - _bfd_vms_debug (6, "image_write_b (%02x)\n", (int) value); -#endif - - if (PRIV (is_vax) && check_section (abfd, 1)) - return; - - if (PRIV (dst_section)) - dst_check_allocation (abfd, 1); - - *PRIV (image_ptr)++ = (value & 0xff); -} - -/* Write 2-byte word to image. */ - -static void -image_write_w (bfd * abfd, unsigned int value) -{ -#if VMS_DEBUG - _bfd_vms_debug (6, "image_write_w (%04x)\n", (int) value); -#endif - - if (PRIV (is_vax) && check_section (abfd, 2)) - return; - - if (PRIV (dst_section)) - dst_check_allocation (abfd, 2); - - bfd_putl16 ((bfd_vma) value, PRIV (image_ptr)); - PRIV (image_ptr) += 2; -} - -/* Write 4-byte long to image. */ - -static void -image_write_l (bfd * abfd, unsigned long value) -{ -#if VMS_DEBUG - _bfd_vms_debug (6, "image_write_l (%08lx)\n", value); -#endif - - if (PRIV (is_vax) && check_section (abfd, 4)) - return; - - if (PRIV (dst_section)) - dst_check_allocation (abfd, 4); - - bfd_putl32 ((bfd_vma) value, PRIV (image_ptr)); - PRIV (image_ptr) += 4; -} - -/* Write 8-byte quad to image. */ - -static void -image_write_q (bfd * abfd, uquad value) -{ -#if VMS_DEBUG - _bfd_vms_debug (6, "image_write_q (%016lx)\n", value); -#endif - - if (PRIV (is_vax) && check_section (abfd, 8)) - return; - - if (PRIV (dst_section)) - dst_check_allocation (abfd, 8); - - bfd_putl64 (value, PRIV (image_ptr)); - PRIV (image_ptr) += 8; -} - -static const char * -cmd_name (int cmd) -{ - switch (cmd) - { - case ETIR_S_C_STA_GBL: return "ETIR_S_C_STA_GBL"; - case ETIR_S_C_STA_LW: return "ETIR_S_C_STA_LW"; - case ETIR_S_C_STA_QW: return "ETIR_S_C_STA_QW"; - case ETIR_S_C_STA_PQ: return "ETIR_S_C_STA_PQ"; - case ETIR_S_C_STA_LI: return "ETIR_S_C_STA_LI"; - case ETIR_S_C_STA_MOD: return "ETIR_S_C_STA_MOD"; - case ETIR_S_C_STA_CKARG: return "ETIR_S_C_STA_CKARG"; - case ETIR_S_C_STO_B: return "ETIR_S_C_STO_B"; - case ETIR_S_C_STO_W: return "ETIR_S_C_STO_W"; - case ETIR_S_C_STO_GBL: return "ETIR_S_C_STO_GBL"; - case ETIR_S_C_STO_CA: return "ETIR_S_C_STO_CA"; - case ETIR_S_C_STO_RB: return "ETIR_S_C_STO_RB"; - case ETIR_S_C_STO_AB: return "ETIR_S_C_STO_AB"; - case ETIR_S_C_STO_OFF: return "ETIR_S_C_STO_OFF"; - case ETIR_S_C_STO_IMM: return "ETIR_S_C_STO_IMM"; - case ETIR_S_C_STO_IMMR: return "ETIR_S_C_STO_IMMR"; - case ETIR_S_C_STO_LW: return "ETIR_S_C_STO_LW"; - case ETIR_S_C_STO_QW: return "ETIR_S_C_STO_QW"; - case ETIR_S_C_STO_GBL_LW: return "ETIR_S_C_STO_GBL_LW"; - case ETIR_S_C_STO_LP_PSB: return "ETIR_S_C_STO_LP_PSB"; - case ETIR_S_C_STO_HINT_GBL: return "ETIR_S_C_STO_HINT_GBL"; - case ETIR_S_C_STO_HINT_PS: return "ETIR_S_C_STO_HINT_PS"; - case ETIR_S_C_OPR_ADD: return "ETIR_S_C_OPR_ADD"; - case ETIR_S_C_OPR_INSV: return "ETIR_S_C_OPR_INSV"; - case ETIR_S_C_OPR_USH: return "ETIR_S_C_OPR_USH"; - case ETIR_S_C_OPR_ROT: return "ETIR_S_C_OPR_ROT"; - case ETIR_S_C_OPR_REDEF: return "ETIR_S_C_OPR_REDEF"; - case ETIR_S_C_OPR_DFLIT: return "ETIR_S_C_OPR_DFLIT"; - case ETIR_S_C_STC_LP: return "ETIR_S_C_STC_LP"; - case ETIR_S_C_STC_GBL: return "ETIR_S_C_STC_GBL"; - case ETIR_S_C_STC_GCA: return "ETIR_S_C_STC_GCA"; - case ETIR_S_C_STC_PS: return "ETIR_S_C_STC_PS"; - case ETIR_S_C_STC_NBH_PS: return "ETIR_S_C_STC_NBH_PS"; - case ETIR_S_C_STC_NOP_GBL: return "ETIR_S_C_STC_NOP_GBL"; - case ETIR_S_C_STC_NOP_PS: return "ETIR_S_C_STC_NOP_PS"; - case ETIR_S_C_STC_BSR_GBL: return "ETIR_S_C_STC_BSR_GBL"; - case ETIR_S_C_STC_BSR_PS: return "ETIR_S_C_STC_BSR_PS"; - case ETIR_S_C_STC_LDA_GBL: return "ETIR_S_C_STC_LDA_GBL"; - case ETIR_S_C_STC_LDA_PS: return "ETIR_S_C_STC_LDA_PS"; - case ETIR_S_C_STC_BOH_GBL: return "ETIR_S_C_STC_BOH_GBL"; - case ETIR_S_C_STC_BOH_PS: return "ETIR_S_C_STC_BOH_PS"; - case ETIR_S_C_STC_NBH_GBL: return "ETIR_S_C_STC_NBH_GBL"; - case ETIR_S_C_CTL_SETRB: return "ETIR_S_C_CTL_SETRB"; - case ETIR_S_C_STC_LP_PSB: return "ETIR_S_C_STC_LP_PSB"; - case ETIR_S_C_CTL_DFLOC: return "ETIR_S_C_CTL_DFLOC"; - case ETIR_S_C_CTL_STLOC: return "ETIR_S_C_CTL_STLOC"; - case ETIR_S_C_CTL_STKDL: return "ETIR_S_C_CTL_STKDL"; - - default: - /* These names have not yet been added to this switch statement. */ - (*_bfd_error_handler) (_("unknown ETIR command %d"), cmd); - } - - return NULL; -} -#define HIGHBIT(op) ((op & 0x80000000L) == 0x80000000L) - -/* etir_sta - - Vms stack commands. - - Handle sta_xxx commands in etir section, - ptr points to data area in record. - - See table B-8 of the openVMS linker manual. */ - -static bfd_boolean -etir_sta (bfd *abfd, int cmd, unsigned char *ptr, int *quarter_relocs) -{ -#if VMS_DEBUG - _bfd_vms_debug (5, "etir_sta %d/%x\n", cmd, cmd); - _bfd_hexdump (8, ptr, 16, (long) ptr); -#endif - - switch (cmd) - { - /* Stack global - arg: cs symbol name - - stack 32 bit value of symbol (high bits set to 0). */ - case ETIR_S_C_STA_GBL: - { - char *name; - vms_symbol_entry *entry; - - name = _bfd_vms_save_counted_string (ptr); - entry = (vms_symbol_entry *) - bfd_hash_lookup (PRIV (vms_symbol_table), name, FALSE, FALSE); - if (entry == NULL) - { -#if VMS_DEBUG - _bfd_vms_debug (3, "%s: no symbol \"%s\"\n", - cmd_name (cmd), name); -#endif - _bfd_vms_push (abfd, (uquad) 0, -1); - } - else - _bfd_vms_push (abfd, (uquad) (entry->symbol->value), -1); - } - *quarter_relocs = 1; - break; - - /* Stack longword - arg: lw value - - stack 32 bit value, sign extend to 64 bit. */ - case ETIR_S_C_STA_LW: - _bfd_vms_push (abfd, (uquad) bfd_getl32 (ptr), -1); - /* This one is special as it is both part of the section header - and of the ALPHA_R_REFLONG relocation. */ - if (bfd_getl16 (ptr - 4 + bfd_getl16 (ptr - 2)) == ETIR_S_C_CTL_DFLOC) - *quarter_relocs = 0; - else if (*quarter_relocs) - *quarter_relocs += 1; - else - *quarter_relocs = 2; - break; - - /* Stack quadword - arg: qw value - - stack 64 bit value of symbol. */ - case ETIR_S_C_STA_QW: - _bfd_vms_push (abfd, (uquad) bfd_getl64 (ptr), -1); - if (*quarter_relocs) - *quarter_relocs += 1; - else - *quarter_relocs = 2; - break; - - /* Stack psect base plus quadword offset - arg: lw section index - qw signed quadword offset (low 32 bits) - - Stack qw argument and section index - (see ETIR_S_C_STO_OFF, ETIR_S_C_CTL_SETRB). */ - case ETIR_S_C_STA_PQ: - { - uquad dummy; - int psect; - - psect = bfd_getl32 (ptr); - if ((unsigned int) psect >= PRIV (section_count)) - { - (*_bfd_error_handler) (_("bad section index in %s"), - cmd_name (cmd)); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - dummy = bfd_getl64 (ptr + 4); - _bfd_vms_push (abfd, dummy, (int) psect); - } - /* This one is special as it is both part of the section header - and of the ALPHA_R_REFLONG and ALPHA_R_REFQUAD relocations. */ - if (bfd_getl16 (ptr - 4 + bfd_getl16 (ptr - 2)) == ETIR_S_C_CTL_SETRB) - *quarter_relocs = 0; - else - *quarter_relocs = 2; - break; - - case ETIR_S_C_STA_LI: - case ETIR_S_C_STA_MOD: - case ETIR_S_C_STA_CKARG: - (*_bfd_error_handler) (_("unsupported STA cmd %s"), cmd_name (cmd)); - *quarter_relocs = 0; - return FALSE; - - default: - (*_bfd_error_handler) (_("reserved STA cmd %d"), cmd); - *quarter_relocs = 0; - return FALSE; - } - -#if VMS_DEBUG - _bfd_vms_debug (5, "etir_sta true\n"); -#endif - - return TRUE; -} - -/* etir_sto - - vms store commands - - handle sto_xxx commands in etir section - ptr points to data area in record - - see table B-9 of the openVMS linker manual. */ - -static bfd_boolean -etir_sto (bfd *abfd, int cmd, unsigned char *ptr, int *quarter_relocs) -{ - uquad dummy; - int psect; - -#if VMS_DEBUG - _bfd_vms_debug (5, "etir_sto %d/%x\n", cmd, cmd); - _bfd_hexdump (8, ptr, 16, (long) ptr); -#endif - - switch (cmd) - { - /* Store byte: pop stack, write byte - arg: -. */ - case ETIR_S_C_STO_B: - dummy = _bfd_vms_pop (abfd, &psect); - /* FIXME: check top bits. */ - image_write_b (abfd, (unsigned int) dummy & 0xff); - *quarter_relocs = 0; - break; - - /* Store word: pop stack, write word - arg: -. */ - case ETIR_S_C_STO_W: - dummy = _bfd_vms_pop (abfd, &psect); - /* FIXME: check top bits */ - image_write_w (abfd, (unsigned int) dummy & 0xffff); - *quarter_relocs = 0; - break; - - /* Store longword: pop stack, write longword - arg: -. */ - case ETIR_S_C_STO_LW: - dummy = _bfd_vms_pop (abfd, &psect); - dummy += (PRIV (sections)[psect])->vma; - /* FIXME: check top bits. */ - image_write_l (abfd, (unsigned int) dummy & 0xffffffff); - if (*quarter_relocs == 2) - *quarter_relocs = 4; - else - *quarter_relocs += 1; - break; - - /* Store quadword: pop stack, write quadword - arg: -. */ - case ETIR_S_C_STO_QW: - dummy = _bfd_vms_pop (abfd, &psect); - dummy += (PRIV (sections)[psect])->vma; - /* FIXME: check top bits. */ - image_write_q (abfd, dummy); - if (*quarter_relocs == 2) - *quarter_relocs = 4; - else - *quarter_relocs += 1; - break; - - /* Store immediate repeated: pop stack for repeat count - arg: lw byte count - da data. */ - case ETIR_S_C_STO_IMMR: - { - int size; - - size = bfd_getl32 (ptr); - dummy = (unsigned long) _bfd_vms_pop (abfd, NULL); - while (dummy-- > 0) - image_dump (abfd, ptr+4, size, 0); - } - *quarter_relocs = 0; - break; - - /* Store global: write symbol value - arg: cs global symbol name. */ - case ETIR_S_C_STO_GBL: - { - vms_symbol_entry *entry; - char *name; - - name = _bfd_vms_save_counted_string (ptr); - entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table), - name, FALSE, FALSE); - if (entry == NULL) - /* FIXME, reloc. */ - image_write_q (abfd, (uquad) (0)); - else - /* FIXME, reloc. */ - image_write_q (abfd, (uquad) (entry->symbol->value)); - } - *quarter_relocs = 4; - break; - - /* Store code address: write address of entry point - arg: cs global symbol name (procedure). */ - case ETIR_S_C_STO_CA: - { - vms_symbol_entry *entry; - char *name; - - name = _bfd_vms_save_counted_string (ptr); - entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table), - name, FALSE, FALSE); - if (entry == NULL) - /* FIXME, reloc. */ - image_write_q (abfd, (uquad) (0)); - else - /* FIXME, reloc. */ - image_write_q (abfd, (uquad) (entry->symbol->value)); - } - *quarter_relocs = 4; - break; - - /* Store offset to psect: pop stack, add low 32 bits to base of psect - arg: none. */ - case ETIR_S_C_STO_OFF: - { - uquad q; - int psect1; - - q = _bfd_vms_pop (abfd, & psect1); - q += (PRIV (sections)[psect1])->vma; - image_write_q (abfd, q); - } - *quarter_relocs += 2; - break; - - /* Store immediate - arg: lw count of bytes - da data. */ - case ETIR_S_C_STO_IMM: - { - int size; - - size = bfd_getl32 (ptr); - image_dump (abfd, ptr+4, size, 0); - } - *quarter_relocs = 0; - break; - - /* This code is 'reserved to digital' according to the openVMS - linker manual, however it is generated by the DEC C compiler - and defined in the include file. - FIXME, since the following is just a guess - store global longword: store 32bit value of symbol - arg: cs symbol name. */ - case ETIR_S_C_STO_GBL_LW: - { - vms_symbol_entry *entry; - char *name; - - name = _bfd_vms_save_counted_string (ptr); - entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table), - name, FALSE, FALSE); - if (entry == NULL) - { -#if VMS_DEBUG - _bfd_vms_debug (3, "%s: no symbol \"%s\"\n", cmd_name (cmd), name); -#endif - image_write_l (abfd, (unsigned long) 0); /* FIXME, reloc */ - } - else - /* FIXME, reloc. */ - image_write_l (abfd, (unsigned long) (entry->symbol->value)); - } - *quarter_relocs = 4; - break; - - case ETIR_S_C_STO_RB: - case ETIR_S_C_STO_AB: - case ETIR_S_C_STO_LP_PSB: - (*_bfd_error_handler) (_("%s: not supported"), cmd_name (cmd)); - *quarter_relocs = 0; - return FALSE; - - case ETIR_S_C_STO_HINT_GBL: - case ETIR_S_C_STO_HINT_PS: - (*_bfd_error_handler) (_("%s: not implemented"), cmd_name (cmd)); - *quarter_relocs = 0; - return FALSE; - - default: - (*_bfd_error_handler) (_("reserved STO cmd %d"), cmd); - *quarter_relocs = 0; - return FALSE; - } - - return TRUE; -} - -/* Stack operator commands - all 32 bit signed arithmetic - all word just like a stack calculator - arguments are popped from stack, results are pushed on stack - - see table B-10 of the openVMS linker manual. */ - -static bfd_boolean -etir_opr (bfd *abfd, int cmd, unsigned char *ptr ATTRIBUTE_UNUSED, - int *quarter_relocs) -{ - long op1, op2; - -#if VMS_DEBUG - _bfd_vms_debug (5, "etir_opr %d/%x\n", cmd, cmd); - _bfd_hexdump (8, ptr, 16, (long) ptr); -#endif - - /* No relocation uses OPR commands except ETIR_S_C_OPR_ADD. */ - if (cmd == ETIR_S_C_OPR_ADD) - *quarter_relocs += 1; - else - *quarter_relocs = 0; - - switch (cmd) - { - case ETIR_S_C_OPR_NOP: /* No-op. */ - break; - - case ETIR_S_C_OPR_ADD: /* Add. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 + op2), -1); - break; - - case ETIR_S_C_OPR_SUB: /* Subtract. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op2 - op1), -1); - break; - - case ETIR_S_C_OPR_MUL: /* Multiply. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 * op2), -1); - break; - - case ETIR_S_C_OPR_DIV: /* Divide. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - if (op2 == 0) - _bfd_vms_push (abfd, (uquad) 0, -1); - else - _bfd_vms_push (abfd, (uquad) (op2 / op1), -1); - break; - - case ETIR_S_C_OPR_AND: /* Logical AND. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 & op2), -1); - break; - - case ETIR_S_C_OPR_IOR: /* Logical inclusive OR. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 | op2), -1); - break; - - case ETIR_S_C_OPR_EOR: /* Logical exclusive OR. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 ^ op2), -1); - break; - - case ETIR_S_C_OPR_NEG: /* Negate. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (-op1), -1); - break; - - case ETIR_S_C_OPR_COM: /* Complement. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 ^ -1L), -1); - break; - - case ETIR_S_C_OPR_ASH: /* Arithmetic shift. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - if (op2 < 0) /* Shift right. */ - op1 >>= -op2; - else /* Shift left. */ - op1 <<= op2; - _bfd_vms_push (abfd, (uquad) op1, -1); - break; - - case ETIR_S_C_OPR_INSV: /* Insert field. */ - (void) _bfd_vms_pop (abfd, NULL); - case ETIR_S_C_OPR_USH: /* Unsigned shift. */ - case ETIR_S_C_OPR_ROT: /* Rotate. */ - case ETIR_S_C_OPR_REDEF: /* Redefine symbol to current location. */ - case ETIR_S_C_OPR_DFLIT: /* Define a literal. */ - (*_bfd_error_handler) (_("%s: not supported"), cmd_name (cmd)); - return FALSE; - - case ETIR_S_C_OPR_SEL: /* Select. */ - if ((long) _bfd_vms_pop (abfd, NULL) & 0x01L) - (void) _bfd_vms_pop (abfd, NULL); - else - { - op1 = (long) _bfd_vms_pop (abfd, NULL); - (void) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) op1, -1); - } - break; - - default: - (*_bfd_error_handler) (_("reserved OPR cmd %d"), cmd); - return FALSE; - } - - return TRUE; -} - -/* Control commands. - - See table B-11 of the openVMS linker manual. */ - -static bfd_boolean -etir_ctl (bfd *abfd, int cmd, unsigned char *ptr, int *quarter_relocs) -{ - uquad dummy; - int psect; - -#if VMS_DEBUG - _bfd_vms_debug (5, "etir_ctl %d/%x\n", cmd, cmd); - _bfd_hexdump (8, ptr, 16, (long) ptr); -#endif - - /* No relocation uses CTL commands. */ - *quarter_relocs = 0; - - switch (cmd) - { - /* Det relocation base: pop stack, set image location counter - arg: none. */ - case ETIR_S_C_CTL_SETRB: - dummy = _bfd_vms_pop (abfd, &psect); - image_set_ptr (abfd, psect, dummy); - break; - - /* Augment relocation base: increment image location counter by offset - arg: lw offset value. */ - case ETIR_S_C_CTL_AUGRB: - dummy = bfd_getl32 (ptr); - image_inc_ptr (abfd, dummy); - break; - - /* Define location: pop index, save location counter under index - arg: none. */ - case ETIR_S_C_CTL_DFLOC: - dummy = _bfd_vms_pop (abfd, NULL); - dst_define_location (abfd, dummy); - break; - - /* Set location: pop index, restore location counter from index - arg: none. */ - case ETIR_S_C_CTL_STLOC: - dummy = _bfd_vms_pop (abfd, NULL); - dst_restore_location (abfd, dummy); - break; - - /* Stack defined location: pop index, push location counter from index - arg: none. */ - case ETIR_S_C_CTL_STKDL: - dummy = _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, dst_retrieve_location (abfd, dummy), -1); - break; - - default: - (*_bfd_error_handler) (_("reserved CTL cmd %d"), cmd); - return FALSE; - } - - return TRUE; -} - -/* Store conditional commands - - See table B-12 and B-13 of the openVMS linker manual. */ - -static bfd_boolean -etir_stc (bfd *abfd, int cmd, unsigned char *ptr ATTRIBUTE_UNUSED, - int *quarter_relocs) -{ -#if VMS_DEBUG - _bfd_vms_debug (5, "etir_stc %d/%x\n", cmd, cmd); - _bfd_hexdump (8, ptr, 16, (long) ptr); -#endif - - switch (cmd) - { - /* 200 Store-conditional Linkage Pair - arg: none. */ - case ETIR_S_C_STC_LP: - - /* 202 Store-conditional Address at global address - arg: lw linkage index - cs global name. */ - - case ETIR_S_C_STC_GBL: - - /* 203 Store-conditional Code Address at global address - arg: lw linkage index - cs procedure name. */ - case ETIR_S_C_STC_GCA: - - /* 204 Store-conditional Address at psect + offset - arg: lw linkage index - lw psect index - qw offset. */ - case ETIR_S_C_STC_PS: - (*_bfd_error_handler) (_("%s: not supported"), cmd_name (cmd)); - *quarter_relocs = 0; - return FALSE; - - /* 201 Store-conditional Linkage Pair with Procedure Signature - arg: lw linkage index - cs procedure name - by signature length - da signature. */ - - case ETIR_S_C_STC_LP_PSB: - image_inc_ptr (abfd, (uquad) 16); /* skip entry,procval */ - *quarter_relocs = 4; - break; - - /* 205 Store-conditional NOP at address of global - arg: none. */ - case ETIR_S_C_STC_NOP_GBL: - /* ALPHA_R_NOP */ - - /* 207 Store-conditional BSR at global address - arg: none. */ - - case ETIR_S_C_STC_BSR_GBL: - /* ALPHA_R_BSR */ - - /* 209 Store-conditional LDA at global address - arg: none. */ - - case ETIR_S_C_STC_LDA_GBL: - /* ALPHA_R_LDA */ - - /* 211 Store-conditional BSR or Hint at global address - arg: none. */ - - case ETIR_S_C_STC_BOH_GBL: - *quarter_relocs = 4; - break; - - /* 213 Store-conditional NOP,BSR or HINT at global address - arg: none. */ - - case ETIR_S_C_STC_NBH_GBL: - - /* 206 Store-conditional NOP at pect + offset - arg: none. */ - - case ETIR_S_C_STC_NOP_PS: - - /* 208 Store-conditional BSR at pect + offset - arg: none. */ - - case ETIR_S_C_STC_BSR_PS: - - /* 210 Store-conditional LDA at psect + offset - arg: none. */ - - case ETIR_S_C_STC_LDA_PS: - - /* 212 Store-conditional BSR or Hint at pect + offset - arg: none. */ - - case ETIR_S_C_STC_BOH_PS: - - /* 214 Store-conditional NOP, BSR or HINT at psect + offset - arg: none. */ - case ETIR_S_C_STC_NBH_PS: - (*_bfd_error_handler) ("%s: not supported", cmd_name (cmd)); - *quarter_relocs = 0; - return FALSE; - - default: - (*_bfd_error_handler) (_("reserved STC cmd %d"), cmd); - *quarter_relocs = 0; - return FALSE; - } - - return TRUE; -} - -static asection * -new_section (bfd * abfd ATTRIBUTE_UNUSED, int idx) -{ - asection *section; - char sname[16]; - char *name; - -#if VMS_DEBUG - _bfd_vms_debug (5, "new_section %d\n", idx); -#endif - sprintf (sname, SECTION_NAME_TEMPLATE, idx); - - name = bfd_malloc ((bfd_size_type) strlen (sname) + 1); - if (name == 0) - return NULL; - strcpy (name, sname); - - section = bfd_malloc ((bfd_size_type) sizeof (asection)); - if (section == 0) - { -#if VMS_DEBUG - _bfd_vms_debug (6, "new_section (%s) failed", name); -#endif - return NULL; - } - - section->size = 0; - section->vma = 0; - section->contents = 0; - section->name = name; - section->index = idx; - - return section; -} - -static int -alloc_section (bfd * abfd, unsigned int idx) -{ - bfd_size_type amt; - -#if VMS_DEBUG - _bfd_vms_debug (4, "alloc_section %d\n", idx); -#endif - - amt = idx + 1; - amt *= sizeof (asection *); - PRIV (sections) = bfd_realloc_or_free (PRIV (sections), amt); - if (PRIV (sections) == NULL) - return -1; - - while (PRIV (section_count) <= idx) - { - PRIV (sections)[PRIV (section_count)] - = new_section (abfd, (int) PRIV (section_count)); - if (PRIV (sections)[PRIV (section_count)] == 0) - return -1; - PRIV (section_count)++; - } - - return 0; -} - -/* tir_sta - - Vax stack commands. - - Handle sta_xxx commands in tir section, - ptr points to data area in record. - - See table 7-3 of the VAX/VMS linker manual. */ - -static unsigned char * -tir_sta (bfd * abfd, unsigned char *ptr) -{ - int cmd = *ptr++; - -#if VMS_DEBUG - _bfd_vms_debug (5, "tir_sta %d\n", cmd); -#endif - - switch (cmd) - { - /* stack */ - case TIR_S_C_STA_GBL: - /* stack global - arg: cs symbol name - - stack 32 bit value of symbol (high bits set to 0). */ - { - char *name; - vms_symbol_entry *entry; - - name = _bfd_vms_save_counted_string (ptr); - - entry = _bfd_vms_enter_symbol (abfd, name); - if (entry == NULL) - return NULL; - - _bfd_vms_push (abfd, (uquad) (entry->symbol->value), -1); - ptr += *ptr + 1; - } - break; - - case TIR_S_C_STA_SB: - /* stack signed byte - arg: by value - - stack byte value, sign extend to 32 bit. */ - _bfd_vms_push (abfd, (uquad) *ptr++, -1); - break; - - case TIR_S_C_STA_SW: - /* stack signed short word - arg: sh value - - stack 16 bit value, sign extend to 32 bit. */ - _bfd_vms_push (abfd, (uquad) bfd_getl16 (ptr), -1); - ptr += 2; - break; - - case TIR_S_C_STA_LW: - /* stack signed longword - arg: lw value - - stack 32 bit value. */ - _bfd_vms_push (abfd, (uquad) bfd_getl32 (ptr), -1); - ptr += 4; - break; - - case TIR_S_C_STA_PB: - case TIR_S_C_STA_WPB: - /* stack psect base plus byte offset (word index) - arg: by section index - (sh section index) - by signed byte offset. */ - { - unsigned long dummy; - int psect; - - if (cmd == TIR_S_C_STA_PB) - psect = *ptr++; - else - { - psect = bfd_getl16 (ptr); - ptr += 2; - } - - if ((unsigned int) psect >= PRIV (section_count)) - alloc_section (abfd, psect); - - dummy = (long) *ptr++; - dummy += (PRIV (sections)[psect])->vma; - _bfd_vms_push (abfd, (uquad) dummy, psect); - } - break; - - case TIR_S_C_STA_PW: - case TIR_S_C_STA_WPW: - /* stack psect base plus word offset (word index) - arg: by section index - (sh section index) - sh signed short offset. */ - { - unsigned long dummy; - int psect; - - if (cmd == TIR_S_C_STA_PW) - psect = *ptr++; - else - { - psect = bfd_getl16 (ptr); - ptr += 2; - } - - if ((unsigned int) psect >= PRIV (section_count)) - alloc_section (abfd, psect); - - dummy = bfd_getl16 (ptr); ptr+=2; - dummy += (PRIV (sections)[psect])->vma; - _bfd_vms_push (abfd, (uquad) dummy, psect); - } - break; - - case TIR_S_C_STA_PL: - case TIR_S_C_STA_WPL: - /* stack psect base plus long offset (word index) - arg: by section index - (sh section index) - lw signed longword offset. */ - { - unsigned long dummy; - int psect; - - if (cmd == TIR_S_C_STA_PL) - psect = *ptr++; - else - { - psect = bfd_getl16 (ptr); - ptr += 2; - } - - if ((unsigned int) psect >= PRIV (section_count)) - alloc_section (abfd, psect); - - dummy = bfd_getl32 (ptr); ptr += 4; - dummy += (PRIV (sections)[psect])->vma; - _bfd_vms_push (abfd, (uquad) dummy, psect); - } - break; - - case TIR_S_C_STA_UB: - /* stack unsigned byte - arg: by value - - stack byte value. */ - _bfd_vms_push (abfd, (uquad) *ptr++, -1); - break; - - case TIR_S_C_STA_UW: - /* stack unsigned short word - arg: sh value - - stack 16 bit value. */ - _bfd_vms_push (abfd, (uquad) bfd_getl16 (ptr), -1); - ptr += 2; - break; - - case TIR_S_C_STA_BFI: - /* stack byte from image - arg: none. */ - /* FALLTHRU */ - case TIR_S_C_STA_WFI: - /* stack byte from image - arg: none. */ - /* FALLTHRU */ - case TIR_S_C_STA_LFI: - /* stack byte from image - arg: none. */ - (*_bfd_error_handler) (_("stack-from-image not implemented")); - return NULL; - - case TIR_S_C_STA_EPM: - /* stack entry point mask - arg: cs symbol name - - stack (unsigned) entry point mask of symbol - err if symbol is no entry point. */ - { - char *name; - vms_symbol_entry *entry; - - name = _bfd_vms_save_counted_string (ptr); - entry = _bfd_vms_enter_symbol (abfd, name); - if (entry == NULL) - return NULL; - - (*_bfd_error_handler) (_("stack-entry-mask not fully implemented")); - _bfd_vms_push (abfd, (uquad) 0, -1); - ptr += *ptr + 1; - } - break; - - case TIR_S_C_STA_CKARG: - /* compare procedure argument - arg: cs symbol name - by argument index - da argument descriptor - - compare argument descriptor with symbol argument (ARG$V_PASSMECH) - and stack TRUE (args match) or FALSE (args dont match) value. */ - (*_bfd_error_handler) (_("PASSMECH not fully implemented")); - _bfd_vms_push (abfd, (uquad) 1, -1); - break; - - case TIR_S_C_STA_LSY: - /* stack local symbol value - arg: sh environment index - cs symbol name. */ - { - int envidx; - char *name; - vms_symbol_entry *entry; - - envidx = bfd_getl16 (ptr); - ptr += 2; - name = _bfd_vms_save_counted_string (ptr); - entry = _bfd_vms_enter_symbol (abfd, name); - if (entry == NULL) - return NULL; - (*_bfd_error_handler) (_("stack-local-symbol not fully implemented")); - _bfd_vms_push (abfd, (uquad) 0, -1); - ptr += *ptr + 1; - } - break; - - case TIR_S_C_STA_LIT: - /* stack literal - arg: by literal index - - stack literal. */ - ptr++; - _bfd_vms_push (abfd, (uquad) 0, -1); - (*_bfd_error_handler) (_("stack-literal not fully implemented")); - break; - - case TIR_S_C_STA_LEPM: - /* stack local symbol entry point mask - arg: sh environment index - cs symbol name - - stack (unsigned) entry point mask of symbol - err if symbol is no entry point. */ - { - int envidx; - char *name; - vms_symbol_entry *entry; - - envidx = bfd_getl16 (ptr); - ptr += 2; - name = _bfd_vms_save_counted_string (ptr); - entry = _bfd_vms_enter_symbol (abfd, name); - if (entry == NULL) - return NULL; - (*_bfd_error_handler) (_("stack-local-symbol-entry-point-mask not fully implemented")); - _bfd_vms_push (abfd, (uquad) 0, -1); - ptr += *ptr + 1; - } - break; - - default: - (*_bfd_error_handler) (_("reserved STA cmd %d"), ptr[-1]); - return NULL; - break; - } - - return ptr; -} - -static const char * -tir_cmd_name (int cmd) -{ - switch (cmd) - { - case TIR_S_C_STO_RSB: return "TIR_S_C_STO_RSB"; - case TIR_S_C_STO_RSW: return "TIR_S_C_STO_RSW"; - case TIR_S_C_STO_RL: return "TIR_S_C_STO_RL"; - case TIR_S_C_STO_VPS: return "TIR_S_C_STO_VPS"; - case TIR_S_C_STO_USB: return "TIR_S_C_STO_USB"; - case TIR_S_C_STO_USW: return "TIR_S_C_STO_USW"; - case TIR_S_C_STO_RUB: return "TIR_S_C_STO_RUB"; - case TIR_S_C_STO_RUW: return "TIR_S_C_STO_RUW"; - case TIR_S_C_STO_PIRR: return "TIR_S_C_STO_PIRR"; - case TIR_S_C_OPR_INSV: return "TIR_S_C_OPR_INSV"; - case TIR_S_C_OPR_DFLIT: return "TIR_S_C_OPR_DFLIT"; - case TIR_S_C_OPR_REDEF: return "TIR_S_C_OPR_REDEF"; - case TIR_S_C_OPR_ROT: return "TIR_S_C_OPR_ROT"; - case TIR_S_C_OPR_USH: return "TIR_S_C_OPR_USH"; - case TIR_S_C_OPR_ASH: return "TIR_S_C_OPR_ASH"; - case TIR_S_C_CTL_DFLOC: return "TIR_S_C_CTL_DFLOC"; - case TIR_S_C_CTL_STLOC: return "TIR_S_C_CTL_STLOC"; - case TIR_S_C_CTL_STKDL: return "TIR_S_C_CTL_STKDL"; - - default: - /* These strings have not been added yet. */ - abort (); - } -} - -/* tir_sto - - vax store commands - - handle sto_xxx commands in tir section - ptr points to data area in record - - See table 7-4 of the VAX/VMS linker manual. */ - -static unsigned char * -tir_sto (bfd * abfd, unsigned char *ptr) -{ - unsigned long dummy; - int size; - int psect; - -#if VMS_DEBUG - _bfd_vms_debug (5, "tir_sto %d\n", *ptr); -#endif - - switch (*ptr++) - { - case TIR_S_C_STO_SB: - /* Store signed byte: pop stack, write byte - arg: none. */ - dummy = _bfd_vms_pop (abfd, &psect); - image_write_b (abfd, dummy & 0xff); /* FIXME: check top bits */ - break; - - case TIR_S_C_STO_SW: - /* Store signed word: pop stack, write word - arg: none. */ - dummy = _bfd_vms_pop (abfd, &psect); - image_write_w (abfd, dummy & 0xffff); /* FIXME: check top bits */ - break; - - case TIR_S_C_STO_LW: - /* Store longword: pop stack, write longword - arg: none. */ - dummy = _bfd_vms_pop (abfd, &psect); - image_write_l (abfd, dummy & 0xffffffff); /* FIXME: check top bits */ - break; - - case TIR_S_C_STO_BD: - /* Store byte displaced: pop stack, sub lc+1, write byte - arg: none. */ - dummy = _bfd_vms_pop (abfd, &psect); - dummy -= ((PRIV (sections)[psect])->vma + 1); - image_write_b (abfd, dummy & 0xff);/* FIXME: check top bits */ - break; - - case TIR_S_C_STO_WD: - /* Store word displaced: pop stack, sub lc+2, write word - arg: none. */ - dummy = _bfd_vms_pop (abfd, &psect); - dummy -= ((PRIV (sections)[psect])->vma + 2); - image_write_w (abfd, dummy & 0xffff);/* FIXME: check top bits */ - break; - - case TIR_S_C_STO_LD: - /* Store long displaced: pop stack, sub lc+4, write long - arg: none. */ - dummy = _bfd_vms_pop (abfd, &psect); - dummy -= ((PRIV (sections)[psect])->vma + 4); - image_write_l (abfd, dummy & 0xffffffff);/* FIXME: check top bits */ - break; - - case TIR_S_C_STO_LI: - /* Store short literal: pop stack, write byte - arg: none. */ - dummy = _bfd_vms_pop (abfd, &psect); - image_write_b (abfd, dummy & 0xff);/* FIXME: check top bits */ - break; - - case TIR_S_C_STO_PIDR: - /* Store position independent data reference: pop stack, write longword - arg: none. - FIXME: incomplete ! */ - dummy = _bfd_vms_pop (abfd, &psect); - image_write_l (abfd, dummy & 0xffffffff); - break; - - case TIR_S_C_STO_PICR: - /* Store position independent code reference: pop stack, write longword - arg: none. - FIXME: incomplete ! */ - dummy = _bfd_vms_pop (abfd, &psect); - image_write_b (abfd, 0x9f); - image_write_l (abfd, dummy & 0xffffffff); - break; - - case TIR_S_C_STO_RIVB: - /* Store repeated immediate variable bytes - 1-byte count n field followed by n bytes of data - pop stack, write n bytes <stack> times. */ - size = *ptr++; - dummy = (unsigned long) _bfd_vms_pop (abfd, NULL); - while (dummy-- > 0L) - image_dump (abfd, ptr, size, 0); - ptr += size; - break; - - case TIR_S_C_STO_B: - /* Store byte from top longword. */ - dummy = (unsigned long) _bfd_vms_pop (abfd, NULL); - image_write_b (abfd, dummy & 0xff); - break; - - case TIR_S_C_STO_W: - /* Store word from top longword. */ - dummy = (unsigned long) _bfd_vms_pop (abfd, NULL); - image_write_w (abfd, dummy & 0xffff); - break; - - case TIR_S_C_STO_RB: - /* Store repeated byte from top longword. */ - size = (unsigned long) _bfd_vms_pop (abfd, NULL); - dummy = (unsigned long) _bfd_vms_pop (abfd, NULL); - while (size-- > 0) - image_write_b (abfd, dummy & 0xff); - break; - - case TIR_S_C_STO_RW: - /* Store repeated word from top longword. */ - size = (unsigned long) _bfd_vms_pop (abfd, NULL); - dummy = (unsigned long) _bfd_vms_pop (abfd, NULL); - while (size-- > 0) - image_write_w (abfd, dummy & 0xffff); - break; - - case TIR_S_C_STO_RSB: - case TIR_S_C_STO_RSW: - case TIR_S_C_STO_RL: - case TIR_S_C_STO_VPS: - case TIR_S_C_STO_USB: - case TIR_S_C_STO_USW: - case TIR_S_C_STO_RUB: - case TIR_S_C_STO_RUW: - case TIR_S_C_STO_PIRR: - (*_bfd_error_handler) (_("%s: not implemented"), tir_cmd_name (ptr[-1])); - break; - - default: - (*_bfd_error_handler) (_("reserved STO cmd %d"), ptr[-1]); - break; - } - - return ptr; -} - -/* Stack operator commands - All 32 bit signed arithmetic - All word just like a stack calculator - Arguments are popped from stack, results are pushed on stack - - See table 7-5 of the VAX/VMS linker manual. */ - -static unsigned char * -tir_opr (bfd * abfd, unsigned char *ptr) -{ - long op1, op2; - -#if VMS_DEBUG - _bfd_vms_debug (5, "tir_opr %d\n", *ptr); -#endif - - /* Operation. */ - switch (*ptr++) - { - case TIR_S_C_OPR_NOP: /* No-op. */ - break; - - case TIR_S_C_OPR_ADD: /* Add. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 + op2), -1); - break; - - case TIR_S_C_OPR_SUB: /* Subtract. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op2 - op1), -1); - break; - - case TIR_S_C_OPR_MUL: /* Multiply. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 * op2), -1); - break; - - case TIR_S_C_OPR_DIV: /* Divide. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - if (op2 == 0) - _bfd_vms_push (abfd, (uquad) 0, -1); - else - _bfd_vms_push (abfd, (uquad) (op2 / op1), -1); - break; - - case TIR_S_C_OPR_AND: /* Logical AND. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 & op2), -1); - break; - - case TIR_S_C_OPR_IOR: /* Logical inclusive OR. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 | op2), -1); - break; - - case TIR_S_C_OPR_EOR: /* Logical exclusive OR. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 ^ op2), -1); - break; - - case TIR_S_C_OPR_NEG: /* Negate. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (-op1), -1); - break; - - case TIR_S_C_OPR_COM: /* Complement. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) (op1 ^ -1L), -1); - break; - - case TIR_S_C_OPR_INSV: /* Insert field. */ - (void) _bfd_vms_pop (abfd, NULL); - (*_bfd_error_handler) (_("%s: not fully implemented"), - tir_cmd_name (ptr[-1])); - break; - - case TIR_S_C_OPR_ASH: /* Arithmetic shift. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - if (HIGHBIT (op1)) /* Shift right. */ - op2 >>= op1; - else /* Shift left. */ - op2 <<= op1; - _bfd_vms_push (abfd, (uquad) op2, -1); - (*_bfd_error_handler) (_("%s: not fully implemented"), - tir_cmd_name (ptr[-1])); - break; - - case TIR_S_C_OPR_USH: /* Unsigned shift. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - if (HIGHBIT (op1)) /* Shift right. */ - op2 >>= op1; - else /* Shift left. */ - op2 <<= op1; - _bfd_vms_push (abfd, (uquad) op2, -1); - (*_bfd_error_handler) (_("%s: not fully implemented"), - tir_cmd_name (ptr[-1])); - break; - - case TIR_S_C_OPR_ROT: /* Rotate. */ - op1 = (long) _bfd_vms_pop (abfd, NULL); - op2 = (long) _bfd_vms_pop (abfd, NULL); - if (HIGHBIT (0)) /* Shift right. */ - op2 >>= op1; - else /* Shift left. */ - op2 <<= op1; - _bfd_vms_push (abfd, (uquad) op2, -1); - (*_bfd_error_handler) (_("%s: not fully implemented"), - tir_cmd_name (ptr[-1])); - break; - - case TIR_S_C_OPR_SEL: /* Select. */ - if ((long) _bfd_vms_pop (abfd, NULL) & 0x01L) - (void) _bfd_vms_pop (abfd, NULL); - else - { - op1 = (long) _bfd_vms_pop (abfd, NULL); - (void) _bfd_vms_pop (abfd, NULL); - _bfd_vms_push (abfd, (uquad) op1, -1); - } - break; - - case TIR_S_C_OPR_REDEF: /* Redefine symbol to current location. */ - case TIR_S_C_OPR_DFLIT: /* Define a literal. */ - (*_bfd_error_handler) (_("%s: not supported"), - tir_cmd_name (ptr[-1])); - break; - - default: - (*_bfd_error_handler) (_("reserved OPR cmd %d"), ptr[-1]); - break; - } - - return ptr; -} - -/* Control commands - - See table 7-6 of the VAX/VMS linker manual. */ - -static unsigned char * -tir_ctl (bfd * abfd, unsigned char *ptr) -{ - unsigned long dummy; - int psect; - -#if VMS_DEBUG - _bfd_vms_debug (5, "tir_ctl %d\n", *ptr); -#endif - - switch (*ptr++) - { - case TIR_S_C_CTL_SETRB: - /* Set relocation base: pop stack, set image location counter - arg: none. */ - dummy = _bfd_vms_pop (abfd, &psect); - if ((unsigned int) psect >= PRIV (section_count)) - alloc_section (abfd, psect); - image_set_ptr (abfd, psect, (uquad) dummy); - break; - - case TIR_S_C_CTL_AUGRB: - /* Augment relocation base: increment image location counter by offset - arg: lw offset value. */ - dummy = bfd_getl32 (ptr); - image_inc_ptr (abfd, (uquad) dummy); - break; - - case TIR_S_C_CTL_DFLOC: - /* Define location: pop index, save location counter under index - arg: none. */ - dummy = _bfd_vms_pop (abfd, NULL); - (*_bfd_error_handler) (_("%s: not fully implemented"), - tir_cmd_name (ptr[-1])); - break; - - case TIR_S_C_CTL_STLOC: - /* Set location: pop index, restore location counter from index - arg: none. */ - dummy = _bfd_vms_pop (abfd, &psect); - (*_bfd_error_handler) (_("%s: not fully implemented"), - tir_cmd_name (ptr[-1])); - break; - - case TIR_S_C_CTL_STKDL: - /* Stack defined location: pop index, push location counter from index - arg: none. */ - dummy = _bfd_vms_pop (abfd, &psect); - (*_bfd_error_handler) (_("%s: not fully implemented"), - tir_cmd_name (ptr[-1])); - break; - - default: - (*_bfd_error_handler) (_("reserved CTL cmd %d"), ptr[-1]); - break; - } - return ptr; -} - -/* Handle command from TIR section. */ - -static unsigned char * -tir_cmd (bfd * abfd, unsigned char *ptr) -{ - static const struct - { - int mincod; - int maxcod; - unsigned char * (*explain) (bfd *, unsigned char *); - } - tir_table[] = - { - { 0, TIR_S_C_MAXSTACOD, tir_sta }, - { TIR_S_C_MINSTOCOD, TIR_S_C_MAXSTOCOD, tir_sto }, - { TIR_S_C_MINOPRCOD, TIR_S_C_MAXOPRCOD, tir_opr }, - { TIR_S_C_MINCTLCOD, TIR_S_C_MAXCTLCOD, tir_ctl }, - { -1, -1, NULL } - }; - int i = 0; - -#if VMS_DEBUG - _bfd_vms_debug (4, "tir_cmd %d/%x\n", *ptr, *ptr); - _bfd_hexdump (8, ptr, 16, (long) ptr); -#endif - - if (*ptr & 0x80) - { - /* Store immediate. */ - i = 128 - (*ptr++ & 0x7f); - image_dump (abfd, ptr, i, 0); - ptr += i; - } - else - { - while (tir_table[i].mincod >= 0) - { - if ( (tir_table[i].mincod <= *ptr) - && (*ptr <= tir_table[i].maxcod)) - { - ptr = tir_table[i].explain (abfd, ptr); - break; - } - i++; - } - if (tir_table[i].mincod < 0) - { - (*_bfd_error_handler) (_("obj code %d not found"), *ptr); - ptr = 0; - } - } - - return ptr; -} - -/* Handle command from ETIR section. */ - -static int -etir_cmd (bfd *abfd, int cmd, unsigned char *ptr, int *quarter_relocs) -{ - static const struct - { - int mincod; - int maxcod; - bfd_boolean (*explain) (bfd *, int, unsigned char *, int *); - } - etir_table[] = - { - { ETIR_S_C_MINSTACOD, ETIR_S_C_MAXSTACOD, etir_sta }, - { ETIR_S_C_MINSTOCOD, ETIR_S_C_MAXSTOCOD, etir_sto }, - { ETIR_S_C_MINOPRCOD, ETIR_S_C_MAXOPRCOD, etir_opr }, - { ETIR_S_C_MINCTLCOD, ETIR_S_C_MAXCTLCOD, etir_ctl }, - { ETIR_S_C_MINSTCCOD, ETIR_S_C_MAXSTCCOD, etir_stc }, - { -1, -1, NULL } - }; - - int i = 0; - -#if VMS_DEBUG - _bfd_vms_debug (4, "etir_cmd: %s(%d)\n", cmd_name (cmd), cmd); - _bfd_hexdump (8, ptr, 16, (long) ptr); -#endif - - while (etir_table[i].mincod >= 0) - { - if ( (etir_table[i].mincod <= cmd) - && (cmd <= etir_table[i].maxcod)) - { - if (!etir_table[i].explain (abfd, cmd, ptr, quarter_relocs)) - return -1; - break; - } - i++; - } - -#if VMS_DEBUG - _bfd_vms_debug (4, "etir_cmd: result = 0\n"); -#endif - return 0; -} - -/* Text Information and Relocation Records (OBJ$C_TIR) - handle tir record. */ - -static int -analyze_tir (bfd * abfd, unsigned char *ptr, unsigned int length) -{ - unsigned char *maxptr; - -#if VMS_DEBUG - _bfd_vms_debug (3, "analyze_tir: %d bytes\n", length); -#endif - - maxptr = ptr + length; - - while (ptr < maxptr) - { - ptr = tir_cmd (abfd, ptr); - if (ptr == 0) - return -1; - } - - return 0; -} - -/* Text Information and Relocation Records (EOBJ$C_ETIR) - handle etir record. */ - -static int -analyze_etir (bfd * abfd, unsigned char *ptr, unsigned int length) -{ - unsigned char *maxptr = ptr + length; - /* Relocations are made of 1, 2 or 4 ETIR commands. - We therefore count them using quarters. */ - int quarter_relocs = 0; - int result = 0; - -#if VMS_DEBUG - _bfd_vms_debug (3, "analyze_etir: %d bytes\n", length); -#endif - - while (ptr < maxptr) - { - int cmd = bfd_getl16 (ptr); - int cmd_length = bfd_getl16 (ptr + 2); - result = etir_cmd (abfd, cmd, ptr + 4, &quarter_relocs); - if (result != 0) - break; - - /* If we have a relocation, we record its length to size - future buffers and bump the reloc count of the section. */ - if (quarter_relocs) - { - vms_section_data (PRIV (image_section))->reloc_size += cmd_length; - abfd->flags |= HAS_RELOC; - - if (quarter_relocs == 4) - { - PRIV (image_section)->reloc_count++; - -#if VMS_DEBUG - _bfd_vms_debug (4, "-> reloc %d at 0x%x\n", - PRIV (image_section)->reloc_count-1, - ptr - (maxptr - length)); -#endif - - quarter_relocs = 0; - } - else if (quarter_relocs > 4) - { - -#if VMS_DEBUG - _bfd_vms_debug (4, "Reloc count error (%d) in section %s\n", - PRIV (image_section)->reloc_count, - PRIV (image_section)->name); -#endif - - quarter_relocs = 0; - } - } - - /* If we have a Store Immediate, we reserve space for the - count argument. */ - else if (cmd == ETIR_S_C_STO_IMM) - vms_section_data (PRIV (image_section))->reloc_size - += ETIR_S_C_HEADER_SIZE + 4; - - ptr += cmd_length; - } - -#if VMS_DEBUG - _bfd_vms_debug (3, "analyze_etir: result = %d\n", result); -#endif - - return result; -} - -/* Process ETIR record - Return 0 on success, -1 on error. */ - -int -_bfd_vms_slurp_tir (bfd * abfd, int objtype) -{ - int result; - -#if VMS_DEBUG - _bfd_vms_debug (2, "TIR/ETIR\n"); -#endif - - switch (objtype) - { - case EOBJ_S_C_ETIR: - PRIV (vms_rec) += ETIR_S_C_HEADER_SIZE; - PRIV (rec_size) -= ETIR_S_C_HEADER_SIZE; - result = analyze_etir (abfd, PRIV (vms_rec), (unsigned) PRIV (rec_size)); - break; - case OBJ_S_C_TIR: - PRIV (vms_rec) += 1; /* Skip type. */ - PRIV (rec_size) -= 1; - result = analyze_tir (abfd, PRIV (vms_rec), (unsigned) PRIV (rec_size)); - break; - default: - result = -1; - break; - } - - return result; -} - - /* Slurp relocs from ETIR sections and (temporarily) save them - in the per-section reloc buffer. */ - -int -_bfd_vms_slurp_relocs (bfd *abfd) -{ - struct vms_section_data_struct *vsd; - unsigned char *begin = PRIV (vms_rec) + 4; - unsigned char *end = PRIV (vms_rec) + PRIV (rec_size); - unsigned char *ptr; - int cmd, length, slurped_length; - -#if VMS_DEBUG - _bfd_vms_debug (3, "_bfd_vms_slurp_relocs: %d bytes\n", PRIV (rec_size)); -#endif - - for (ptr = begin; ptr < end; ptr += length) - { - cmd = bfd_getl16 (ptr); - length = bfd_getl16 (ptr + 2); - slurped_length = length; - - switch (cmd) - { - case ETIR_S_C_STA_PQ: /* ALPHA_R_REF{LONG|QUAD}, others part 1 */ - /* This one is special as it is both part of the section header - and of the ALPHA_R_REFLONG and ALPHA_R_REFQUAD relocations. */ - if (bfd_getl16 (ptr + length) == ETIR_S_C_CTL_SETRB) - { - int psect = bfd_getl32 (ptr + ETIR_S_C_HEADER_SIZE); - PRIV (image_section) = PRIV (sections)[psect]; - continue; - } - - case ETIR_S_C_STA_GBL: /* ALPHA_R_REFLONG und_section, step 1 */ - /* ALPHA_R_REFQUAD und_section, step 1 */ - break; - - case ETIR_S_C_STA_LW: /* ALPHA_R_REFLONG und_section, step 2 */ - /* ALPHA_R_REFLONG abs_section, step 1 */ - /* This one is special as it is both part of the section header - and of the ALPHA_R_REFLONG relocation. */ - if (bfd_getl16 (ptr + length) == ETIR_S_C_CTL_DFLOC) - { - PRIV (image_section) = PRIV (dst_section); - continue; - } - - case ETIR_S_C_STA_QW: /* ALPHA_R_REFQUAD und_section, step 2 */ - /* ALPHA_R_REFQUAD abs_section, step 1 */ - - case ETIR_S_C_STO_LW: /* ALPHA_R_REFLONG und_section, step 4 */ - /* ALPHA_R_REFLONG abs_section, step 2 */ - /* ALPHA_R_REFLONG others, step 2 */ - - case ETIR_S_C_STO_QW: /* ALPHA_R_REFQUAD und_section, step 4 */ - /* ALPHA_R_REFQUAD abs_section, step 2 */ - - case ETIR_S_C_STO_OFF: /* ALPHA_R_REFQUAD others, step 2 */ - - case ETIR_S_C_OPR_ADD: /* ALPHA_R_REFLONG und_section, step 3 */ - /* ALPHA_R_REFQUAD und_section, step 3 */ - - case ETIR_S_C_STO_CA: /* ALPHA_R_CODEADDR */ - case ETIR_S_C_STO_GBL: /* ALPHA_R_REFQUAD und_section */ - case ETIR_S_C_STO_GBL_LW: /* ALPHA_R_REFLONG und_section */ - case ETIR_S_C_STC_LP_PSB: /* ALPHA_R_LINKAGE */ - case ETIR_S_C_STC_NOP_GBL: /* ALPHA_R_NOP */ - case ETIR_S_C_STC_BSR_GBL: /* ALPHA_R_BSR */ - case ETIR_S_C_STC_LDA_GBL: /* ALPHA_R_LDA */ - case ETIR_S_C_STC_BOH_GBL: /* ALPHA_R_BOH */ - break; - - case ETIR_S_C_STO_IMM: - if (PRIV (image_section)->reloc_count == 0) - continue; - /* This is not a relocation, but we nevertheless slurp the - count argument. We'll use it to compute the addresses - of the relocations. */ - slurped_length = ETIR_S_C_HEADER_SIZE + 4; - break; - - default: - continue; - } - - vsd = vms_section_data (PRIV (image_section)); - memcpy (vsd->reloc_stream + vsd->reloc_offset, ptr, slurped_length); - vsd->reloc_offset += slurped_length; - if (vsd->reloc_offset > vsd->reloc_size) - { - (*_bfd_error_handler) (_("Reloc size error in section %s"), - PRIV (image_section)->name); - return -1; - } - } - -#if VMS_DEBUG - _bfd_vms_debug (3, "_bfd_vms_slurp_relocs: result = 0\n"); -#endif - - return 0; -} - -/* Decode relocs from the reloc buffer of the specified section - and internalize them in the specified buffer. */ - -int -_bfd_vms_decode_relocs (bfd *abfd, arelent *relocs, asection *section, - asymbol **symbols ATTRIBUTE_UNUSED) -{ - int saved_cmd, saved_sym_offset, saved_sec_offset, saved_addend_offset; - int cmd, sym_offset, sec_offset, address_offset, addend_offset; - struct vms_section_data_struct *vsd = vms_section_data (section); - bfd_reloc_code_real_type reloc_code; - vms_symbol_entry *entry; - bfd_vma vaddr = 0; - unsigned char *begin = vsd->reloc_stream; - unsigned char *end = vsd->reloc_stream + vsd->reloc_size; - unsigned char *ptr, *arg_ptr; - const char *name; - int length; - -#if VMS_DEBUG - _bfd_vms_debug (3, "_bfd_vms_decode_relocs: %d bytes\n", vsd->reloc_size); -#endif - - #define PUSH_CMD() \ - { \ - saved_cmd = cmd; \ - saved_sym_offset = sym_offset - length; \ - saved_sec_offset = sec_offset - length; \ - saved_addend_offset = addend_offset - length; \ - continue; \ - } - - #define POP_CMD() \ - { \ - cmd = saved_cmd; \ - saved_cmd = ETIR_S_C_MAXSTCCOD + 1; \ - sym_offset = saved_sym_offset; \ - sec_offset = saved_sec_offset; \ - addend_offset= saved_addend_offset; \ - } - - #define CMD_PUSHED (saved_cmd != ETIR_S_C_MAXSTCCOD + 1) - - #define NO_OFFSET -128 - - saved_cmd = ETIR_S_C_MAXSTCCOD + 1; - saved_sym_offset = NO_OFFSET; - saved_sec_offset = NO_OFFSET; - saved_addend_offset = NO_OFFSET; - - for (ptr = begin; ptr < end; ptr += length) - { - cmd = bfd_getl16 (ptr); - length = bfd_getl16 (ptr + 2); - - arg_ptr = ptr + ETIR_S_C_HEADER_SIZE; - sym_offset = NO_OFFSET; - sec_offset = NO_OFFSET; - address_offset = NO_OFFSET; - addend_offset = NO_OFFSET; - - switch (cmd) - { - case ETIR_S_C_STA_GBL: /* ALPHA_R_REFLONG und_section, step 1 */ - /* ALPHA_R_REFQUAD und_section, step 1 */ - sym_offset = 0; - PUSH_CMD () - - case ETIR_S_C_STA_PQ: /* ALPHA_R_REF{LONG|QUAD}, others part 1 */ - sec_offset = 0; - addend_offset = 4; - PUSH_CMD () - - case ETIR_S_C_STA_LW: /* ALPHA_R_REFLONG abs_section, step 1 */ - /* ALPHA_R_REFLONG und_section, step 2 */ - if (CMD_PUSHED) - { - POP_CMD () - if (cmd != ETIR_S_C_STA_GBL) - { - (*_bfd_error_handler) (_("Unknown reloc %s + %s"), - cmd_name (cmd), - cmd_name (ETIR_S_C_STA_LW)); - return 0; - } - cmd = ETIR_S_C_STA_LW; - } - addend_offset = 0; - PUSH_CMD () - - case ETIR_S_C_STA_QW: /* ALPHA_R_REFQUAD abs_section, step 1 */ - /* ALPHA_R_REFQUAD und_section, step 2 */ - if (CMD_PUSHED) - { - POP_CMD () - if (cmd != ETIR_S_C_STA_GBL) - { - (*_bfd_error_handler) (_("Unknown reloc %s + %s"), - cmd_name (cmd), - cmd_name (ETIR_S_C_STA_QW)); - return 0; - } - cmd = ETIR_S_C_STA_QW; - } - addend_offset = 0; - PUSH_CMD () - - case ETIR_S_C_STO_LW: /* ALPHA_R_REFLONG und_section, step 4 */ - /* ALPHA_R_REFLONG abs_section, step 2 */ - /* ALPHA_R_REFLONG others, step 2 */ - POP_CMD () - if (cmd != ETIR_S_C_OPR_ADD - && cmd != ETIR_S_C_STA_LW - && cmd != ETIR_S_C_STA_PQ) - { - (*_bfd_error_handler) (_("Unknown reloc %s + %s"), - cmd_name (cmd), cmd_name (ETIR_S_C_STO_LW)); - return 0; - } - reloc_code = BFD_RELOC_32; - break; - - case ETIR_S_C_STO_QW: /* ALPHA_R_REFQUAD und_section, step 4 */ - /* ALPHA_R_REFQUAD abs_section, step 2 */ - POP_CMD () - if (cmd != ETIR_S_C_OPR_ADD && cmd != ETIR_S_C_STA_QW) - { - (*_bfd_error_handler) (_("Unknown reloc %s + %s"), - cmd_name (cmd), cmd_name (ETIR_S_C_STO_QW)); - return 0; - } - reloc_code = BFD_RELOC_64; - break; - - case ETIR_S_C_STO_OFF: /* ALPHA_R_REFQUAD others, step 2 */ - POP_CMD () - if (cmd != ETIR_S_C_STA_PQ) - { - (*_bfd_error_handler) (_("Unknown reloc %s + %s"), - cmd_name (cmd), cmd_name (ETIR_S_C_STO_OFF)); - return 0; - } - reloc_code = BFD_RELOC_64; - break; - - case ETIR_S_C_OPR_ADD: /* ALPHA_R_REFLONG und_section, step 3 */ - /* ALPHA_R_REFQUAD und_section, step 3 */ - POP_CMD () - if (cmd != ETIR_S_C_STA_LW && cmd != ETIR_S_C_STA_QW) - { - (*_bfd_error_handler) (_("Unknown reloc %s + %s"), - cmd_name (cmd), cmd_name (ETIR_S_C_OPR_ADD)); - return 0; - } - cmd = ETIR_S_C_OPR_ADD; - PUSH_CMD () - - case ETIR_S_C_STO_CA: /* ALPHA_R_CODEADDR */ - reloc_code = BFD_RELOC_ALPHA_CODEADDR; - sym_offset = 0; - break; - - case ETIR_S_C_STO_GBL: /* ALPHA_R_REFQUAD und_section */ - reloc_code = BFD_RELOC_64; - sym_offset = 0; - break; - - case ETIR_S_C_STO_GBL_LW: /* ALPHA_R_REFLONG und_section */ - reloc_code = BFD_RELOC_32; - sym_offset = 0; - break; - - case ETIR_S_C_STC_LP_PSB: /* ALPHA_R_LINKAGE */ - reloc_code = BFD_RELOC_ALPHA_LINKAGE; - sym_offset = 4; - break; - - case ETIR_S_C_STC_NOP_GBL: /* ALPHA_R_NOP */ - reloc_code = BFD_RELOC_ALPHA_NOP; - goto call_reloc; - - case ETIR_S_C_STC_BSR_GBL: /* ALPHA_R_BSR */ - reloc_code = BFD_RELOC_ALPHA_BSR; - goto call_reloc; - - case ETIR_S_C_STC_LDA_GBL: /* ALPHA_R_LDA */ - reloc_code = BFD_RELOC_ALPHA_LDA; - goto call_reloc; - - case ETIR_S_C_STC_BOH_GBL: /* ALPHA_R_BOH */ - reloc_code = BFD_RELOC_ALPHA_BOH; - goto call_reloc; - - call_reloc: - sym_offset = 32; - address_offset = 8; - addend_offset = 24; - break; - - case ETIR_S_C_STO_IMM: - vaddr += bfd_getl32 (arg_ptr); - length = ETIR_S_C_HEADER_SIZE + 4; - continue; - - default: - continue; - } - - relocs->howto = bfd_reloc_type_lookup (abfd, reloc_code); - - if (sym_offset > NO_OFFSET) - { - name = _bfd_vms_save_counted_string (arg_ptr + sym_offset); - entry = (vms_symbol_entry *) - bfd_hash_lookup (PRIV (vms_symbol_table), name, FALSE, FALSE); - if (entry == NULL) - { - (*_bfd_error_handler) (_("Unknown symbol %s in command %s"), - name, cmd_name (cmd)); - relocs->sym_ptr_ptr = NULL; - } - else - /* ??? This is a hack. We should point in 'symbols'. */ - relocs->sym_ptr_ptr = &entry->symbol; - } - else if (sec_offset > NO_OFFSET) - relocs->sym_ptr_ptr - = PRIV (sections)[bfd_getl32 (arg_ptr + sec_offset)]->symbol_ptr_ptr; - else - relocs->sym_ptr_ptr = NULL; - - if (address_offset > NO_OFFSET) - relocs->address = bfd_getl64 (arg_ptr + address_offset); - else - relocs->address = vaddr; - - if (addend_offset > NO_OFFSET) - relocs->addend = bfd_getl64 (arg_ptr + addend_offset); - else - relocs->addend = 0; - - vaddr += bfd_get_reloc_size (relocs->howto); - relocs++; - } - - #undef PUSH_CMD - #undef POP_CMD - #undef NO_OFFSET - -#if VMS_DEBUG - _bfd_vms_debug (3, "_bfd_vms_decode_relocs: result = 0\n"); -#endif - - return 0; -} - -/* Process LNK record - Return 0 on success, -1 on error - - Not implemented yet. */ - -int -_bfd_vms_slurp_lnk (bfd * abfd ATTRIBUTE_UNUSED, - int objtype ATTRIBUTE_UNUSED) -{ -#if VMS_DEBUG - _bfd_vms_debug (2, "LNK\n"); -#endif - - return 0; -} - -/* WRITE ETIR SECTION - - This is still under construction and therefore not documented. */ - -static void start_etir_record (bfd *abfd, int sec_index, uquad offset, - bfd_boolean justoffset); -static void start_first_etbt_record (bfd *abfd); -static void start_another_etbt_record (bfd *abfd); -static void sto_imm (bfd *abfd, bfd_size_type, unsigned char *, bfd_vma vaddr, - int sec_index, const char *name); -static void end_etir_record (bfd *abfd); -static void etir_output_check (bfd *abfd, asection *section, bfd_vma vaddr, - int checklen); - -/* Start ETIR record for section #index at virtual addr offset. */ - -static void -start_etir_record (bfd * abfd, int sec_index, uquad offset, bfd_boolean justoffset) -{ - if (!justoffset) - { - /* One ETIR per section. */ - _bfd_vms_output_begin (abfd, EOBJ_S_C_ETIR, -1); - _bfd_vms_output_push (abfd); - } - - /* Push start offset. */ - _bfd_vms_output_begin (abfd, ETIR_S_C_STA_PQ, -1); - _bfd_vms_output_long (abfd, (unsigned long) sec_index); - _bfd_vms_output_quad (abfd, (uquad) offset); - _bfd_vms_output_flush (abfd); - - /* Start = pop (). */ - _bfd_vms_output_begin (abfd, ETIR_S_C_CTL_SETRB, -1); - _bfd_vms_output_flush (abfd); -} - -static void -end_etir_record (bfd * abfd) -{ - _bfd_vms_output_pop (abfd); - _bfd_vms_output_end (abfd); -} - -/* Output a STO_IMM command for SSIZE bytes of data from CPR at virtual - address VADDR in section specified by SEC_INDEX and NAME. */ - -static void -sto_imm (bfd *abfd, bfd_size_type ssize, unsigned char *cptr, bfd_vma vaddr, - int sec_index, const char *name) -{ - bfd_size_type size; - -#if VMS_DEBUG - _bfd_vms_debug (8, "sto_imm %d bytes\n", ssize); - _bfd_hexdump (9, cptr, (int) ssize, (int) vaddr); -#endif - - while (ssize > 0) - { - /* Try all the rest. */ - size = ssize; - - if (_bfd_vms_output_check (abfd, size) < 0) - { - /* Doesn't fit, split ! */ - end_etir_record (abfd); - - if (name [0] && name[1] == 'v' && !strcmp (name, ".vmsdebug")) - start_another_etbt_record (abfd); - else - start_etir_record (abfd, sec_index, vaddr, FALSE); - - size = _bfd_vms_output_check (abfd, 0); /* get max size */ - if (size > ssize) /* more than what's left ? */ - size = ssize; - } - - _bfd_vms_output_begin (abfd, ETIR_S_C_STO_IMM, -1); - _bfd_vms_output_long (abfd, (unsigned long) (size)); - _bfd_vms_output_dump (abfd, cptr, size); - _bfd_vms_output_flush (abfd); - -#if VMS_DEBUG - _bfd_vms_debug (10, "dumped %d bytes\n", size); - _bfd_hexdump (10, cptr, (int) size, (int) vaddr); -#endif - - vaddr += size; - cptr += size; - ssize -= size; - } -} - -/* Start ETBT record for section #index at virtual addr offset. */ - -static void -start_first_etbt_record (bfd *abfd) -{ - _bfd_vms_output_begin (abfd, EOBJ_S_C_ETBT, -1); - _bfd_vms_output_push (abfd); - - _bfd_vms_output_begin (abfd, ETIR_S_C_STA_LW, -1); /* push start offset */ - _bfd_vms_output_long (abfd, (unsigned long) 0); - _bfd_vms_output_flush (abfd); - - _bfd_vms_output_begin (abfd, ETIR_S_C_CTL_DFLOC, -1); /* start = pop() */ - _bfd_vms_output_flush (abfd); -} - -static void -start_another_etbt_record (bfd *abfd) -{ - _bfd_vms_output_begin (abfd, EOBJ_S_C_ETBT, -1); - _bfd_vms_output_push (abfd); -} - -static void -etir_output_check (bfd *abfd, asection *section, bfd_vma vaddr, int checklen) -{ - if (_bfd_vms_output_check (abfd, checklen) < 0) - { - end_etir_record (abfd); - if (section->name[0] && section->name[1] == 'v' - && !strcmp (section->name, ".vmsdebug")) - start_another_etbt_record (abfd); - else - start_etir_record (abfd, section->index, vaddr, FALSE); - } -} - -/* Return whether RELOC must be deferred till the end. */ - -static int -defer_reloc_p (arelent *reloc) -{ - switch (reloc->howto->type) - { - case ALPHA_R_NOP: - case ALPHA_R_LDA: - case ALPHA_R_BSR: - case ALPHA_R_BOH: - return 1; - - default: - return 0; - } -} - -/* Write section contents for bfd abfd. */ - -int -_bfd_vms_write_tir (bfd * abfd, int objtype ATTRIBUTE_UNUSED) -{ - asection *section; - -#if VMS_DEBUG - _bfd_vms_debug (2, "vms_write_tir (%p, %d)\n", abfd, objtype); -#endif - - _bfd_vms_output_alignment (abfd, 4); - - PRIV (vms_linkage_index) = 1; - - for (section = abfd->sections; section; section = section->next) - { -#if VMS_DEBUG - _bfd_vms_debug (4, "writing %d. section '%s' (%d bytes)\n", - section->index, section->name, - (int) (section->size)); -#endif - - if (!(section->flags & SEC_HAS_CONTENTS) - || bfd_is_com_section (section)) - continue; - - if (!section->contents) - { - bfd_set_error (bfd_error_no_contents); - return -1; - } - - if (section->name[0] - && section->name[1] == 'v' - && !strcmp (section->name, ".vmsdebug")) - start_first_etbt_record (abfd); - else - start_etir_record (abfd, section->index, 0, FALSE); - - if (section->flags & SEC_RELOC) - { - bfd_vma curr_addr = 0; - unsigned char *curr_data = section->contents; - bfd_size_type size; - int pass2_needed = 0; - int pass2_in_progress = 0; - unsigned int irel; - - if (section->reloc_count <= 0) - (*_bfd_error_handler) - (_("SEC_RELOC with no relocs in section %s"), section->name); - -#if VMS_DEBUG - else - { - int i = section->reloc_count; - arelent **rptr = section->orelocation; - _bfd_vms_debug (4, "%d relocations:\n", i); - while (i-- > 0) - { - _bfd_vms_debug (4, "sym %s in sec %s, value %08lx, " - "addr %08lx, off %08lx, len %d: %s\n", - (*(*rptr)->sym_ptr_ptr)->name, - (*(*rptr)->sym_ptr_ptr)->section->name, - (long) (*(*rptr)->sym_ptr_ptr)->value, - (*rptr)->address, (*rptr)->addend, - bfd_get_reloc_size ((*rptr)->howto), - ( *rptr)->howto->name); - rptr++; - } - } -#endif - - new_pass: - for (irel = 0; irel < section->reloc_count; irel++) - { - struct evax_private_udata_struct *udata; - arelent *rptr = section->orelocation [irel]; - bfd_vma addr = rptr->address; - asymbol *sym = *rptr->sym_ptr_ptr; - asection *sec = sym->section; - int defer = defer_reloc_p (rptr); - unsigned int slen; - char *hash; - - if (pass2_in_progress) - { - /* Non-deferred relocs have already been output. */ - if (!defer) - continue; - } - else - { - /* Deferred relocs must be output at the very end. */ - if (defer) - { - pass2_needed = 1; - continue; - } - - /* Regular relocs are intertwined with binary data. */ - if (curr_addr > addr) - (*_bfd_error_handler) (_("Size error in section %s"), - section->name); - size = addr - curr_addr; - sto_imm (abfd, size, curr_data, curr_addr, - section->index, section->name); - curr_data += size; - curr_addr += size; - } - - size = bfd_get_reloc_size (rptr->howto); - - switch (rptr->howto->type) - { - case ALPHA_R_IGNORE: - break; - - case ALPHA_R_REFLONG: - if (bfd_is_und_section (sym->section)) - { - bfd_vma addend = rptr->addend; - slen = strlen ((char *) sym->name); - hash = _bfd_vms_length_hash_symbol - (abfd, sym->name, EOBJ_S_C_SYMSIZ); - etir_output_check (abfd, section, curr_addr, slen); - if (addend) - { - _bfd_vms_output_begin (abfd, ETIR_S_C_STA_GBL, -1); - _bfd_vms_output_counted (abfd, hash); - _bfd_vms_output_flush (abfd); - _bfd_vms_output_begin (abfd, ETIR_S_C_STA_LW, -1); - _bfd_vms_output_long (abfd, (unsigned long) addend); - _bfd_vms_output_flush (abfd); - _bfd_vms_output_begin (abfd, ETIR_S_C_OPR_ADD, -1); - _bfd_vms_output_flush (abfd); - _bfd_vms_output_begin (abfd, ETIR_S_C_STO_LW, -1); - _bfd_vms_output_flush (abfd); - } - else - { - _bfd_vms_output_begin (abfd, ETIR_S_C_STO_GBL_LW, -1); - _bfd_vms_output_counted (abfd, hash); - _bfd_vms_output_flush (abfd); - } - } - else if (bfd_is_abs_section (sym->section)) - { - etir_output_check (abfd, section, curr_addr, 16); - _bfd_vms_output_begin (abfd, ETIR_S_C_STA_LW, -1); - _bfd_vms_output_long (abfd, (unsigned long) sym->value); - _bfd_vms_output_flush (abfd); - _bfd_vms_output_begin (abfd, ETIR_S_C_STO_LW, -1); - _bfd_vms_output_flush (abfd); - } - else - { - etir_output_check (abfd, section, curr_addr, 32); - _bfd_vms_output_begin (abfd, ETIR_S_C_STA_PQ, -1); - _bfd_vms_output_long (abfd, (unsigned long) sec->index); - _bfd_vms_output_quad (abfd, (uquad) rptr->addend - + (uquad) sym->value); - _bfd_vms_output_flush (abfd); - /* ??? Table B-8 of the OpenVMS Linker Utilily Manual - says that we should have a ETIR_S_C_STO_OFF here. - But the relocation would not be BFD_RELOC_32 then. - This case is very likely unreachable. */ - _bfd_vms_output_begin (abfd, ETIR_S_C_STO_LW, -1); - _bfd_vms_output_flush (abfd); - } - break; - - case ALPHA_R_REFQUAD: - if (bfd_is_und_section (sym->section)) - { - bfd_vma addend = rptr->addend; - slen = strlen ((char *) sym->name); - hash = _bfd_vms_length_hash_symbol - (abfd, sym->name, EOBJ_S_C_SYMSIZ); - etir_output_check (abfd, section, curr_addr, slen); - if (addend) - { - _bfd_vms_output_begin (abfd, ETIR_S_C_STA_GBL, -1); - _bfd_vms_output_counted (abfd, hash); - _bfd_vms_output_flush (abfd); - _bfd_vms_output_begin (abfd, ETIR_S_C_STA_QW, -1); - _bfd_vms_output_quad (abfd, (uquad) addend); - _bfd_vms_output_flush (abfd); - _bfd_vms_output_begin (abfd, ETIR_S_C_OPR_ADD, -1); - _bfd_vms_output_flush (abfd); - _bfd_vms_output_begin (abfd, ETIR_S_C_STO_QW, -1); - _bfd_vms_output_flush (abfd); - } - else - { - _bfd_vms_output_begin (abfd, ETIR_S_C_STO_GBL, -1); - _bfd_vms_output_counted (abfd, hash); - _bfd_vms_output_flush (abfd); - } - } - else if (bfd_is_abs_section (sym->section)) - { - etir_output_check (abfd, section, curr_addr, 16); - _bfd_vms_output_begin (abfd, ETIR_S_C_STA_QW, -1); - _bfd_vms_output_quad (abfd, (uquad) sym->value); - _bfd_vms_output_flush (abfd); - _bfd_vms_output_begin (abfd, ETIR_S_C_STO_QW, -1); - _bfd_vms_output_flush (abfd); - } - else - { - etir_output_check (abfd, section, curr_addr, 32); - _bfd_vms_output_begin (abfd, ETIR_S_C_STA_PQ, -1); - _bfd_vms_output_long (abfd, (unsigned long) sec->index); - _bfd_vms_output_quad (abfd, (uquad) rptr->addend - + (uquad) sym->value); - _bfd_vms_output_flush (abfd); - _bfd_vms_output_begin (abfd, ETIR_S_C_STO_OFF, -1); - _bfd_vms_output_flush (abfd); - } - break; - - case ALPHA_R_HINT: - sto_imm (abfd, size, curr_data, curr_addr, - section->index, section->name); - break; - - case ALPHA_R_LINKAGE: - etir_output_check (abfd, section, curr_addr, 64); - _bfd_vms_output_begin (abfd, ETIR_S_C_STC_LP_PSB, -1); - _bfd_vms_output_long - (abfd, (unsigned long) PRIV (vms_linkage_index)); - PRIV (vms_linkage_index) += 2; - hash = _bfd_vms_length_hash_symbol - (abfd, sym->name, EOBJ_S_C_SYMSIZ); - _bfd_vms_output_counted (abfd, hash); - _bfd_vms_output_byte (abfd, 0); - _bfd_vms_output_flush (abfd); - break; - - case ALPHA_R_CODEADDR: - slen = strlen ((char *) sym->name); - hash = _bfd_vms_length_hash_symbol - (abfd, sym->name, EOBJ_S_C_SYMSIZ); - etir_output_check (abfd, section, curr_addr, slen); - _bfd_vms_output_begin (abfd, ETIR_S_C_STO_CA, -1); - _bfd_vms_output_counted (abfd, hash); - _bfd_vms_output_flush (abfd); - break; - - case ALPHA_R_NOP: - udata - = (struct evax_private_udata_struct *) rptr->sym_ptr_ptr; - etir_output_check (abfd, section, curr_addr, - 32 + 1 + strlen (udata->origname)); - _bfd_vms_output_begin (abfd, ETIR_S_C_STC_NOP_GBL, -1); - _bfd_vms_output_long (abfd, (unsigned long) udata->lkindex); - _bfd_vms_output_long - (abfd, (unsigned long) udata->enbsym->section->index); - _bfd_vms_output_quad (abfd, (uquad) rptr->address); - _bfd_vms_output_long (abfd, (unsigned long) 0x47ff041f); - _bfd_vms_output_long - (abfd, (unsigned long) udata->enbsym->section->index); - _bfd_vms_output_quad (abfd, (uquad) rptr->addend); - _bfd_vms_output_counted - (abfd, _bfd_vms_length_hash_symbol - (abfd, udata->origname, EOBJ_S_C_SYMSIZ)); - _bfd_vms_output_flush (abfd); - break; - - case ALPHA_R_BSR: - (*_bfd_error_handler) (_("Spurious ALPHA_R_BSR reloc")); - break; - - case ALPHA_R_LDA: - udata - = (struct evax_private_udata_struct *) rptr->sym_ptr_ptr; - etir_output_check (abfd, section, curr_addr, - 32 + 1 + strlen (udata->origname)); - _bfd_vms_output_begin (abfd, ETIR_S_C_STC_LDA_GBL, -1); - _bfd_vms_output_long - (abfd, (unsigned long) udata->lkindex + 1); - _bfd_vms_output_long - (abfd, (unsigned long) udata->enbsym->section->index); - _bfd_vms_output_quad (abfd, (uquad) rptr->address); - _bfd_vms_output_long (abfd, (unsigned long) 0x237B0000); - _bfd_vms_output_long - (abfd, (unsigned long) udata->bsym->section->index); - _bfd_vms_output_quad (abfd, (uquad) rptr->addend); - _bfd_vms_output_counted - (abfd, _bfd_vms_length_hash_symbol - (abfd, udata->origname, EOBJ_S_C_SYMSIZ)); - _bfd_vms_output_flush (abfd); - break; - - case ALPHA_R_BOH: - udata - = (struct evax_private_udata_struct *) rptr->sym_ptr_ptr; - etir_output_check (abfd, section, curr_addr, - 32 + 1 + strlen (udata->origname)); - _bfd_vms_output_begin (abfd, ETIR_S_C_STC_BOH_GBL, -1); - _bfd_vms_output_long (abfd, (unsigned long) udata->lkindex); - _bfd_vms_output_long - (abfd, (unsigned long) udata->enbsym->section->index); - _bfd_vms_output_quad (abfd, (uquad) rptr->address); - _bfd_vms_output_long (abfd, (unsigned long) 0xD3400000); - _bfd_vms_output_long - (abfd, (unsigned long) udata->enbsym->section->index); - _bfd_vms_output_quad (abfd, (uquad) rptr->addend); - _bfd_vms_output_counted - (abfd, _bfd_vms_length_hash_symbol - (abfd, udata->origname, EOBJ_S_C_SYMSIZ)); - _bfd_vms_output_flush (abfd); - break; - - default: - (*_bfd_error_handler) (_("Unhandled relocation %s"), - rptr->howto->name); - break; - } - - curr_data += size; - curr_addr += size; - } /* End of relocs loop. */ - - if (!pass2_in_progress) - { - /* Output rest of section. */ - if (curr_addr > section->size) - (*_bfd_error_handler) (_("Size error in section %s"), - section->name); - size = section->size - curr_addr; - sto_imm (abfd, size, curr_data, curr_addr, - section->index, section->name); - curr_data += size; - curr_addr += size; - - if (pass2_needed) - { - pass2_in_progress = 1; - goto new_pass; - } - } - } - - else /* (section->flags & SEC_RELOC) */ - sto_imm (abfd, section->size, section->contents, 0, - section->index, section->name); - - end_etir_record (abfd); - } - - _bfd_vms_output_alignment (abfd, 2); - return 0; -} diff --git a/bfd/vms.c b/bfd/vms.c deleted file mode 100644 index c63e175..0000000 --- a/bfd/vms.c +++ /dev/null @@ -1,1518 +0,0 @@ -/* vms.c -- BFD back-end for VAX (openVMS/VAX) and - EVAX (openVMS/Alpha) files. - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2007, 2008, 2009 Free Software Foundation, Inc. - - Main file. - - Written by Klaus K"ampf (kkaempf@rmi.de) - - 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 3 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., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifdef VMS -#include <rms.h> -#include <unixlib.h> -#include <starlet.h> -#define RME$C_SETRFM 0x00000001 -#include <unistd.h> -#endif - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" - -#include "vms.h" - -static bfd_boolean vms_initialize (bfd *); -static bfd_boolean fill_section_ptr (struct bfd_hash_entry *, PTR); -static bfd_boolean vms_fixup_sections (bfd *); -static bfd_boolean copy_symbols (struct bfd_hash_entry *, PTR); -static bfd_reloc_status_type reloc_nil (bfd *, arelent *, asymbol *, PTR, - asection *, bfd *, char **); -static int vms_slurp_module (bfd *abfd); -static int vms_slurp_image (bfd *abfd); -static const struct bfd_target *vms_object_p (bfd *abfd); -static bfd_boolean vms_mkobject (bfd *abfd); -static bfd_boolean vms_write_object_contents (bfd *abfd); -static void free_reloc_stream (bfd *abfd, asection *section, void *data); -static bfd_boolean vms_close_and_cleanup (bfd *abfd); -static bfd_boolean vms_new_section_hook (bfd *abfd, asection *section); -static bfd_boolean vms_get_section_contents - (bfd *abfd, asection *section, PTR x1, file_ptr x2, bfd_size_type x3); -static long vms_get_symtab_upper_bound (bfd *abfd); -static long vms_canonicalize_symtab (bfd *abfd, asymbol **symbols); -static void vms_print_symbol (bfd *abfd, PTR file, asymbol *symbol, - bfd_print_symbol_type how); -static void vms_get_symbol_info (bfd *abfd, asymbol *symbol, symbol_info *ret); -static bfd_boolean vms_bfd_is_local_label_name (bfd *abfd, const char *); -static bfd_boolean vms_find_nearest_line - (bfd *abfd, asection *section, asymbol **symbols, bfd_vma offset, - const char **file, const char **func, unsigned int *line); -static void alloc_reloc_stream (bfd *abfd, asection *section, - void *alloc_error); -static bfd_boolean vms_slurp_reloc_table (bfd *abfd, asection *section, - asymbol **symbols); -static long vms_get_reloc_upper_bound (bfd *abfd, asection *sect); -static long vms_canonicalize_reloc (bfd *abfd, asection *srcsec, - arelent **location, asymbol **symbols); -static const struct reloc_howto_struct *vms_bfd_reloc_type_lookup - (bfd *abfd, bfd_reloc_code_real_type code); -static bfd_boolean vms_set_arch_mach - (bfd *abfd, enum bfd_architecture arch, unsigned long mach); -static bfd_boolean vms_set_section_contents - (bfd *abfd, asection *section, const PTR location, file_ptr offset, - bfd_size_type count); - -#define vms_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) -#define vms_make_empty_symbol _bfd_generic_make_empty_symbol -#define vms_bfd_link_just_syms _bfd_generic_link_just_syms -#define vms_bfd_copy_link_hash_symbol_type \ - _bfd_generic_copy_link_hash_symbol_type -#define vms_bfd_is_group_section bfd_generic_is_group_section -#define vms_bfd_discard_group bfd_generic_discard_group -#define vms_section_already_linked _bfd_generic_section_already_linked -#define vms_bfd_define_common_symbol bfd_generic_define_common_symbol -#define vms_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data -#define vms_get_synthetic_symtab _bfd_nodynamic_get_synthetic_symtab - -#define vms_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data -#define vms_bfd_free_cached_info _bfd_generic_bfd_free_cached_info -#define vms_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data -#define vms_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data -#define vms_bfd_set_private_flags _bfd_generic_bfd_set_private_flags -#define vms_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data -#define vms_get_section_contents_in_window _bfd_generic_get_section_contents_in_window -#define vms_read_minisymbols _bfd_generic_read_minisymbols -#define vms_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol -#define vms_get_lineno _bfd_nosymbols_get_lineno -#define vms_find_inliner_info _bfd_nosymbols_find_inliner_info -#define vms_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol - -#ifdef VMS_DEBUG -/* Cause debug info to be emitted for the structure. */ -struct vms_private_data_struct _vms_private_data_struct_dummy; -struct vms_section_data_struct _vms_section_data_struct_dummy; -#endif - -extern const bfd_target vms_vax_vec; -extern const bfd_target vms_alpha_vec; - -/* Initialize private data */ -static bfd_boolean -vms_initialize (bfd * abfd) -{ - bfd_size_type amt; - - bfd_set_start_address (abfd, (bfd_vma) -1); - - amt = sizeof (struct vms_private_data_struct); - abfd->tdata.any = bfd_zalloc (abfd, amt); - if (abfd->tdata.any == NULL) - return FALSE; - - if (bfd_get_flavour (abfd) == bfd_target_ovax_flavour) - PRIV (is_vax) = TRUE; - - PRIV (file_format) = FF_UNKNOWN; - - amt = sizeof (struct stack_struct) * STACKSIZE; - PRIV (stack) = bfd_alloc (abfd, amt); - if (PRIV (stack) == NULL) - goto error_ret1; - - amt = sizeof (struct bfd_hash_table); - PRIV (vms_symbol_table) = bfd_alloc (abfd, amt); - if (PRIV (vms_symbol_table) == NULL) - goto error_ret1; - - if (!bfd_hash_table_init (PRIV (vms_symbol_table), _bfd_vms_hash_newfunc, - sizeof (vms_symbol_entry))) - goto error_ret1; - - amt = MAX_OUTREC_SIZE; - PRIV (output_buf) = bfd_alloc (abfd, amt); - if (PRIV (output_buf) == NULL) - goto error_ret2; - - PRIV (length_pos) = 2; - - return TRUE; - - error_ret2: - bfd_hash_table_free (PRIV (vms_symbol_table)); - error_ret1: - bfd_release (abfd, abfd->tdata.any); - abfd->tdata.any = NULL; - return FALSE; -} - -struct pair -{ - unsigned int section_count; - asection **sections; -}; - -/* Fill symbol->section with section pointer. - - symbol->section is filled with the section index for defined symbols - during reading the GSD/EGSD section. But we need the pointer to the - bfd section later. - - It has the correct value for referenced (undefined section) symbols. - - Called from bfd_hash_traverse in vms_fixup_sections. */ - -static bfd_boolean -fill_section_ptr (struct bfd_hash_entry *entry, void *sections) -{ - asymbol *sym = ((vms_symbol_entry *)entry)->symbol; - struct pair *data = (struct pair *)sections; - unsigned long sec = (unsigned long)sym->section; - - vms_debug2 ((6, "fill_section_ptr: sym %p, sec %lu\n", sym, sec)); - - if (sec < data->section_count) - { - sym->section = data->sections[sec]; - - if (strcmp (sym->name, sym->section->name) == 0) - sym->flags |= BSF_SECTION_SYM; - } - else if (sec == (unsigned long)-1) - sym->section = &bfd_und_section; - - return TRUE; -} - -/* Fixup section pointers in symbols. */ -static bfd_boolean -vms_fixup_sections (bfd * abfd) -{ - struct pair data; - - if (PRIV (fixup_done)) - return TRUE; - - data.section_count = PRIV (section_count); - data.sections = PRIV (sections); - bfd_hash_traverse (PRIV (vms_symbol_table), fill_section_ptr, &data); - - PRIV (fixup_done) = TRUE; - return TRUE; -} - -/* Slurp an ordered set of VMS object records. */ -int -_bfd_vms_slurp_object_records (bfd * abfd) -{ - int err, new_type, type = -1; - - do - { - vms_debug2 ((7, "reading at %08lx\n", bfd_tell (abfd))); - - new_type = _bfd_vms_get_object_record (abfd); - if (new_type < 0) - { - vms_debug2 ((2, "next_record failed\n")); - return -1; - } - - if (type == EOBJ_S_C_EGSD && new_type != EOBJ_S_C_EGSD) - { - if (! vms_fixup_sections (abfd)) - { - vms_debug2 ((2, "vms_fixup_sections failed\n")); - return -1; - } - } - - type = new_type; - - switch (type) - { - case OBJ_S_C_HDR: - case EOBJ_S_C_EMH: - err = _bfd_vms_slurp_hdr (abfd, type); - break; - case OBJ_S_C_EOM: - case OBJ_S_C_EOMW: - case EOBJ_S_C_EEOM: - err = _bfd_vms_slurp_eom (abfd, type); - break; - case OBJ_S_C_GSD: - case EOBJ_S_C_EGSD: - err = _bfd_vms_slurp_gsd (abfd, type); - break; - case OBJ_S_C_TIR: - case EOBJ_S_C_ETIR: - err = _bfd_vms_slurp_tir (abfd, type); - break; - case OBJ_S_C_DBG: - case EOBJ_S_C_EDBG: - err = _bfd_vms_slurp_dbg (abfd, type); - PRIV (dst_ptr_end) = PRIV (image_ptr); - break; - case OBJ_S_C_TBT: - case EOBJ_S_C_ETBT: - err = _bfd_vms_slurp_tbt (abfd, type); - PRIV (dst_ptr_end) = PRIV (image_ptr); - break; - case OBJ_S_C_LNK: - err = _bfd_vms_slurp_lnk (abfd, type); - break; - default: - err = -1; - } - if (err != 0) - { - vms_debug2 ((2, "slurp type %d failed with %d\n", type, err)); - return err; - } - } - while (type != EOBJ_S_C_EEOM && type != OBJ_S_C_EOM && type != OBJ_S_C_EOMW); - - return 0; -} - -/* Slurp a VMS module and return an error status. */ - -static int -vms_slurp_module (bfd *abfd) -{ - int type, err; - - if (PRIV (is_vax)) - type = PRIV (vms_rec)[0]; - else - type = bfd_getl16 (PRIV (vms_rec)); - - err = _bfd_vms_slurp_hdr (abfd, type); - if (err != 0) - { - bfd_set_error (bfd_error_wrong_format); - return err; - } - - return _bfd_vms_slurp_object_records (abfd); -} - -/* Slurp a VMS image and return an error status. */ - -static int -vms_slurp_image (bfd *abfd) -{ - unsigned int isd_offset, ihs_offset; - int err; - - err = _bfd_vms_slurp_ihd (abfd, &isd_offset, &ihs_offset); - if (err != 0) - { - bfd_set_error (bfd_error_wrong_format); - return err; - } - - err = _bfd_vms_slurp_isd (abfd, isd_offset); - if (err != 0) - { - bfd_set_error (bfd_error_wrong_format); - return err; - } - - return _bfd_vms_slurp_ihs (abfd, ihs_offset); -} - -/* Check the format for a file being read. - Return a (bfd_target *) if it's an object file or zero if not. */ - -static const struct bfd_target * -vms_object_p (bfd *abfd) -{ - const struct bfd_target *target_vector; - const bfd_arch_info_type *arch; - PTR tdata_save = abfd->tdata.any; - bfd_vma saddr_save = bfd_get_start_address (abfd); - int err = 0; - - vms_debug2 ((1, "vms_object_p(%p)\n", abfd)); - - if (!vms_initialize (abfd)) - goto error_ret; - - if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET)) - goto err_wrong_format; - - switch (_bfd_vms_get_first_record (abfd)) - { - case FT_UNKNOWN: - default: - err = -1; - break; - - case FT_MODULE: - err = vms_slurp_module (abfd); - break; - - case FT_IMAGE: - err = vms_slurp_image (abfd); - break; - } - - if (err != 0) - goto err_wrong_format; - - if (PRIV (is_vax)) - { - if (! vms_fixup_sections (abfd)) - { - vms_debug2 ((2, "vms_fixup_sections failed\n")); - goto err_wrong_format; - } - - target_vector = &vms_vax_vec; - arch = bfd_scan_arch ("vax"); - - vms_debug2 ((2, "arch is vax\n")); - } - else - { - /* Set arch_info to alpha. */ - target_vector = &vms_alpha_vec; - arch = bfd_scan_arch ("alpha"); - vms_debug2 ((2, "arch is alpha\n")); - } - - abfd->arch_info = arch; - return target_vector; - - err_wrong_format: - bfd_set_error (bfd_error_wrong_format); - - error_ret: - if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL) - bfd_release (abfd, abfd->tdata.any); - abfd->tdata.any = tdata_save; - bfd_set_start_address (abfd, saddr_save); - return NULL; -} - -/* Set the format of a file being written. */ - -static bfd_boolean -vms_mkobject (bfd * abfd) -{ - const bfd_arch_info_type *arch; - - vms_debug2 ((1, "vms_mkobject (%p)\n", abfd)); - - if (!vms_initialize (abfd)) - return FALSE; - - if (PRIV (is_vax)) - arch = bfd_scan_arch ("vax"); - else - arch = bfd_scan_arch ("alpha"); - - if (arch == 0) - { - bfd_set_error(bfd_error_wrong_format); - return FALSE; - } - - abfd->arch_info = arch; - return TRUE; -} - -/* Write cached information into a file being written, at bfd_close. */ - -static bfd_boolean -vms_write_object_contents (bfd * abfd) -{ - vms_debug2 ((1, "vms_write_object_contents (%p)\n", abfd)); - - if (abfd->section_count > 0) /* we have sections */ - { - if (PRIV (is_vax)) - { - if (_bfd_vms_write_hdr (abfd, OBJ_S_C_HDR) != 0) - return FALSE; - if (_bfd_vms_write_gsd (abfd, OBJ_S_C_GSD) != 0) - return FALSE; - if (_bfd_vms_write_tir (abfd, OBJ_S_C_TIR) != 0) - return FALSE; - if (_bfd_vms_write_tbt (abfd, OBJ_S_C_TBT) != 0) - return FALSE; - if (_bfd_vms_write_dbg (abfd, OBJ_S_C_DBG) != 0) - return FALSE; - if (abfd->section_count > 255) - { - if (_bfd_vms_write_eom (abfd, OBJ_S_C_EOMW) != 0) - return FALSE; - } - else - { - if (_bfd_vms_write_eom (abfd, OBJ_S_C_EOM) != 0) - return FALSE; - } - } - else - { - if (_bfd_vms_write_hdr (abfd, EOBJ_S_C_EMH) != 0) - return FALSE; - if (_bfd_vms_write_gsd (abfd, EOBJ_S_C_EGSD) != 0) - return FALSE; - if (_bfd_vms_write_tir (abfd, EOBJ_S_C_ETIR) != 0) - return FALSE; - if (_bfd_vms_write_tbt (abfd, EOBJ_S_C_ETBT) != 0) - return FALSE; - if (_bfd_vms_write_dbg (abfd, EOBJ_S_C_EDBG) != 0) - return FALSE; - if (_bfd_vms_write_eom (abfd, EOBJ_S_C_EEOM) != 0) - return FALSE; - } - } - return TRUE; -} - -/* 4.1, generic. */ - -/* Free the reloc buffer for the specified section. */ - -static void -free_reloc_stream (bfd *abfd ATTRIBUTE_UNUSED, asection *section, - void *data ATTRIBUTE_UNUSED) -{ - if (vms_section_data (section)->reloc_stream) - free (vms_section_data (section)->reloc_stream); -} - -#ifdef VMS -/* Convert the file to variable record length format. This is done - using undocumented system call sys$modify(). - Pure VMS version. */ - -static void -vms_convert_to_var (char *vms_filename) -{ - struct FAB fab = cc$rms_fab; - - fab.fab$l_fna = vms_filename; - fab.fab$b_fns = strlen (vms_filename); - fab.fab$b_fac = FAB$M_PUT; - fab.fab$l_fop = FAB$M_ESC; - fab.fab$l_ctx = RME$C_SETRFM; - - sys$open (&fab); - - fab.fab$b_rfm = FAB$C_VAR; - - sys$modify (&fab); - sys$close (&fab); -} - -static int -vms_convert_to_var_1 (char *filename, int type) -{ - if (type != DECC$K_FILE) - return FALSE; - vms_convert_to_var (filename); - return TRUE; -} - -/* Convert the file to variable record length format. This is done - using undocumented system call sys$modify(). - Unix filename version. */ - -static int -vms_convert_to_var_unix_filename (const char *unix_filename) -{ - if (decc$to_vms (unix_filename, &vms_convert_to_var_1, 0, 1) != 1) - return FALSE; - return TRUE; -} -#endif /* VMS */ - -/* Called when the BFD is being closed to do any necessary cleanup. */ - -static bfd_boolean -vms_close_and_cleanup (bfd * abfd) -{ - vms_debug2 ((1, "vms_close_and_cleanup (%p)\n", abfd)); - - if (abfd == NULL || abfd->tdata.any == NULL) - return TRUE; - - if (PRIV (vms_buf) != NULL) - free (PRIV (vms_buf)); - - if (PRIV (sections) != NULL) - free (PRIV (sections)); - - if (PRIV (vms_symbol_table)) - bfd_hash_table_free (PRIV (vms_symbol_table)); - - bfd_map_over_sections (abfd, free_reloc_stream, NULL); - - bfd_release (abfd, abfd->tdata.any); - abfd->tdata.any = NULL; - -#ifdef VMS - if (abfd->direction == write_direction) - { - /* Last step on VMS is to convert the file to variable record length - format. */ - if (bfd_cache_close (abfd) != TRUE) - return FALSE; - if (vms_convert_to_var_unix_filename (abfd->filename) != TRUE) - return FALSE; - } -#endif - - return TRUE; -} - -/* Called when a new section is created. */ - -static bfd_boolean -vms_new_section_hook (bfd * abfd, asection *section) -{ - bfd_size_type amt; - - /* Count hasn't been incremented yet. */ - unsigned int section_count = abfd->section_count + 1; - - vms_debug2 ((1, "vms_new_section_hook (%p, [%d]%s), count %d\n", - abfd, section->index, section->name, section_count)); - - bfd_set_section_alignment (abfd, section, 0); - - if (section_count > PRIV (section_count)) - { - amt = section_count; - amt *= sizeof (asection *); - PRIV (sections) = bfd_realloc_or_free (PRIV (sections), amt); - if (PRIV (sections) == NULL) - return FALSE; - PRIV (section_count) = section_count; - } - - vms_debug2 ((6, "section_count: %d\n", PRIV (section_count))); - - PRIV (sections)[section->index] = section; - - vms_debug2 ((7, "%d: %s\n", section->index, section->name)); - - amt = sizeof (struct vms_section_data_struct); - section->used_by_bfd = (PTR) bfd_zalloc (abfd, amt); - if (section->used_by_bfd == NULL) - return FALSE; - - return _bfd_generic_new_section_hook (abfd, section); -} - -/* Read the contents of a section. - buf points to a buffer of buf_size bytes to be filled with - section data (starting at offset into section) */ - -static bfd_boolean -vms_get_section_contents (bfd * abfd ATTRIBUTE_UNUSED, - asection *section ATTRIBUTE_UNUSED, - void * buf ATTRIBUTE_UNUSED, - file_ptr offset ATTRIBUTE_UNUSED, - bfd_size_type buf_size ATTRIBUTE_UNUSED) -{ - bfd_size_type size = section->size; - - vms_debug2 ((1, "vms_get_section_contents (%p, %s, %p, off %ld, size %d)\n", - abfd, section->name, buf, offset, (int)buf_size)); - - if (section->contents) - abort (); - - section->contents = (unsigned char *) bfd_malloc (size); - - if (section->contents == NULL) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - - if (bfd_seek (abfd, section->filepos, SEEK_SET)) - { - bfd_set_error (bfd_error_file_truncated); - return FALSE; - } - - if (bfd_bread (section->contents, size, abfd) != size) - { - bfd_set_error (bfd_error_file_truncated); - return FALSE; - } - - section->flags |= SEC_IN_MEMORY; - - if (buf) - memcpy (buf, section->contents + offset, (size_t) buf_size); - - return TRUE; -} - -/* Part 4.5, symbols. */ - -/* Return the number of bytes required to store a vector of pointers - to asymbols for all the symbols in the BFD abfd, including a - terminal NULL pointer. If there are no symbols in the BFD, - then return 0. If an error occurs, return -1. */ - -static long -vms_get_symtab_upper_bound (bfd * abfd) -{ - vms_debug2 ((1, "vms_get_symtab_upper_bound (%p), %d symbols\n", - abfd, PRIV (gsd_sym_count))); - - return (PRIV (gsd_sym_count) + 1) * sizeof (asymbol *); -} - -/* Copy symbols from hash table to symbol vector - - called from bfd_hash_traverse in vms_canonicalize_symtab - init counter to 0 if entry == 0. */ - -static bfd_boolean -copy_symbols (struct bfd_hash_entry *entry, void * arg) -{ - bfd * abfd = (bfd *) arg; - - if (entry == NULL) /* Init counter. */ - PRIV (symnum) = 0; - else /* Fill vector, inc counter. */ - PRIV (symcache)[PRIV (symnum)++] = ((vms_symbol_entry *)entry)->symbol; - - return TRUE; -} - -/* Read the symbols from the BFD abfd, and fills in the vector - location with pointers to the symbols and a trailing NULL. - - Return number of symbols read. */ - -static long -vms_canonicalize_symtab (bfd * abfd, asymbol **symbols) -{ - vms_debug2 ((1, "vms_canonicalize_symtab (%p, <ret>)\n", abfd)); - - /* Init counter. */ - copy_symbols (NULL, abfd); - - /* Traverse table and fill symbols vector. */ - PRIV (symcache) = symbols; - bfd_hash_traverse (PRIV (vms_symbol_table), copy_symbols, abfd); - - symbols[PRIV (gsd_sym_count)] = NULL; - - return PRIV (gsd_sym_count); -} - -/* Print symbol to file according to how. how is one of - bfd_print_symbol_name just print the name - bfd_print_symbol_more print more (???) - bfd_print_symbol_all print all we know, which is not much right now :-). */ - -static void -vms_print_symbol (bfd * abfd, - void * file, - asymbol *symbol, - bfd_print_symbol_type how) -{ - vms_debug2 ((1, "vms_print_symbol (%p, %p, %p, %d)\n", - abfd, file, symbol, how)); - - switch (how) - { - case bfd_print_symbol_name: - case bfd_print_symbol_more: - fprintf ((FILE *)file," %s", symbol->name); - break; - - case bfd_print_symbol_all: - { - const char *section_name = symbol->section->name; - - bfd_print_symbol_vandf (abfd, file, symbol); - - fprintf ((FILE *) file," %-8s %s", section_name, symbol->name); - } - break; - } -} - -/* Return information about symbol in ret. - - fill type, value and name - type: - A absolute - B bss segment symbol - C common symbol - D data segment symbol - f filename - t a static function symbol - T text segment symbol - U undefined - - debug. */ - -static void -vms_get_symbol_info (bfd * abfd ATTRIBUTE_UNUSED, - asymbol *symbol, - symbol_info *ret) -{ - asection *sec; - - vms_debug2 ((1, "vms_get_symbol_info (%p, %p, %p)\n", abfd, symbol, ret)); - - sec = symbol->section; - - if (ret == NULL) - return; - - if (sec == 0) - ret->type = 'U'; - else if (bfd_is_com_section (sec)) - ret->type = 'C'; - else if (bfd_is_abs_section (sec)) - ret->type = 'A'; - else if (bfd_is_und_section (sec)) - ret->type = 'U'; - else if (bfd_is_ind_section (sec)) - ret->type = 'I'; - else if (bfd_get_section_flags (abfd, sec) & SEC_CODE) - ret->type = 'T'; - else if (bfd_get_section_flags (abfd, sec) & SEC_DATA) - ret->type = 'D'; - else if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) - ret->type = 'B'; - else - ret->type = '-'; - - if (ret->type != 'U') - ret->value = symbol->value + symbol->section->vma; - else - ret->value = 0; - ret->name = symbol->name; -} - -/* Return TRUE if the given symbol sym in the BFD abfd is - a compiler generated local label, else return FALSE. */ - -static bfd_boolean -vms_bfd_is_local_label_name (bfd * abfd ATTRIBUTE_UNUSED, - const char *name) -{ - vms_debug2 ((1, "vms_bfd_is_local_label_name (%p, %s)\n", abfd, name)); - return name[0] == '$'; -} - -/* Provided a BFD, a section and an offset into the section, calculate and - return the name of the source file and the line nearest to the wanted - location. */ - -static bfd_boolean -vms_find_nearest_line (bfd * abfd ATTRIBUTE_UNUSED, - asection *section ATTRIBUTE_UNUSED, - asymbol **symbols ATTRIBUTE_UNUSED, - bfd_vma offset ATTRIBUTE_UNUSED, - const char **file ATTRIBUTE_UNUSED, - const char **func ATTRIBUTE_UNUSED, - unsigned int *line ATTRIBUTE_UNUSED) -{ - vms_debug2 ((1, "vms_find_nearest_line (%p, %s, %p, %ld, ...)\n", - abfd, section->name, symbols, (long int)offset)); - return _bfd_vms_find_nearest_dst_line (abfd, section, symbols, offset, file, func, line); -} - -/* Part 4.6, relocations. */ - -/* Allocate the reloc buffer for the specified section. */ - -static void -alloc_reloc_stream (bfd *abfd ATTRIBUTE_UNUSED, asection *section, - void *alloc_error) -{ - unsigned char *ptr; - - /* If there were no relocations, there is nothing to do. */ - if (section->reloc_count == 0) - return; - - ptr = bfd_malloc (vms_section_data (section)->reloc_size); - if (ptr == NULL) - { - *(bfd_boolean *)alloc_error = TRUE; - return; - } - - vms_section_data (section)->reloc_stream = ptr; -} - -/* Read in the relocs for the specified section and internalize them. - - The implementation is loosely based on the SOM code and made up - of 3 distinct phases: - - 1. When the VMS object is opened and parsed, the number and the size - of the relocations are computed for all sections. This makes it - possible to know upfront both which sections have no relocs and - the size of the reloc buffers for the other sections, at virtually - no cost for consumers that don't care about relocs at all. - - 2. When vms_slurp_reloc_table is invoked for the first time on a section - with relocs, the object is traversed and all the reloc information - is saved in per-section reloc buffers. It would be very inefficient - to scan the whole file on each invocation, so we slurp for all the - sections at once. - - 3. On subsequent invocations of vms_slurp_reloc_table, the relocs for the - specified section are fetched from the buffer, decoded and internalized. - The buffer is then freed since the internalized relocs are attached to - the section, turning additional invocations of vms_slurp_reloc_table - on the same section into no-ops. - - Since VMS objects have very few sections, it could be profitable to merge - phase #2 and phase #3, i.e. to decode and internalize the relocs for all - the sections at once. The current implementation is more elegant. */ - -static bfd_boolean -vms_slurp_reloc_table (bfd *abfd, asection *section, asymbol **symbols) -{ - arelent *internal_relocs; - bfd_size_type amt; - int err; - - /* If there were no relocations, there is nothing to do. */ - if (section->reloc_count == 0) - return TRUE; - - /* Return saved information about the relocations if it is available. */ - if (section->relocation != NULL) - return TRUE; - - /* If the relocation stream has not been slurped, do it now. */ - if (vms_section_data (section)->reloc_stream == NULL) - { - bfd_boolean alloc_error = FALSE; - int type; - - /* Size the reloc buffer for each section. */ - bfd_map_over_sections (abfd, alloc_reloc_stream, &alloc_error); - if (alloc_error) - return FALSE; - - if (bfd_seek (abfd, 0, SEEK_SET) != 0) - return FALSE; - - /* Reset section pointer. */ - PRIV (image_section) = NULL; - - do - { - type = _bfd_vms_get_object_record (abfd); - if (type != EOBJ_S_C_ETIR - && type != EOBJ_S_C_EDBG - && type != EOBJ_S_C_ETBT) - continue; - err = _bfd_vms_slurp_relocs (abfd); - if (err != 0) - { - vms_debug2 ((2, "slurp relocs failed with %d\n", err)); - return FALSE; - } - } - while (type != EOBJ_S_C_EEOM); - } - - amt = section->reloc_count * sizeof (arelent); - internal_relocs = (arelent *) bfd_zalloc (abfd, amt); - if (internal_relocs == NULL) - return FALSE; - - /* Decode and internalize the relocations. */ - err = _bfd_vms_decode_relocs (abfd, internal_relocs, section, symbols); - if (err != 0) - { - vms_debug2 ((2, "decode relocs failed with %d\n", err)); - return FALSE; - } - - /* We're done with the external relocations. Free them. */ - free (vms_section_data (section)->reloc_stream); - vms_section_data (section)->reloc_stream = NULL; - - /* Save our results and return success. */ - section->relocation = internal_relocs; - return TRUE; -} - -/* Return the number of bytes required to store the relocation - information associated with the given section. */ - -static long -vms_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *section) -{ - return (section->reloc_count + 1) * sizeof (arelent *); -} - -/* Convert relocations from VMS (external) form into BFD internal - form. Return the number of relocations. */ - -static long -vms_canonicalize_reloc (bfd *abfd, asection *section, arelent **relptr, - asymbol **symbols) -{ - arelent *tblptr; - int count; - - if (! vms_slurp_reloc_table (abfd, section, symbols)) - return -1; - - count = section->reloc_count; - tblptr = section->relocation; - - while (count--) - *relptr++ = tblptr++; - - *relptr = (arelent *) NULL; - return section->reloc_count; -} - -/* This is just copied from ecoff-alpha, needs to be fixed probably. */ - -/* How to process the various reloc types. */ - -static bfd_reloc_status_type -reloc_nil (bfd * abfd ATTRIBUTE_UNUSED, - arelent *reloc ATTRIBUTE_UNUSED, - asymbol *sym ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *sec ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ -#if VMS_DEBUG - vms_debug (1, "reloc_nil (abfd %p, output_bfd %p)\n", abfd, output_bfd); - vms_debug (2, "In section %s, symbol %s\n", - sec->name, sym->name); - vms_debug (2, "reloc sym %s, addr %08lx, addend %08lx, reloc is a %s\n", - reloc->sym_ptr_ptr[0]->name, - (unsigned long)reloc->address, - (unsigned long)reloc->addend, reloc->howto->name); - vms_debug (2, "data at %p\n", data); - /* _bfd_hexdump (2, data, bfd_get_reloc_size (reloc->howto), 0); */ -#endif - - return bfd_reloc_ok; -} - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value - from smaller values. Start with zero, widen, *then* decrement. */ -#define MINUS_ONE (((bfd_vma)0) - 1) - -static reloc_howto_type alpha_howto_table[] = -{ - HOWTO (ALPHA_R_IGNORE, /* Type. */ - 0, /* Rightshift. */ - 0, /* Size (0 = byte, 1 = short, 2 = long). */ - 8, /* Bitsize. */ - TRUE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "IGNORE", /* Name. */ - TRUE, /* Partial_inplace. */ - 0, /* Source mask */ - 0, /* Dest mask. */ - TRUE), /* PC rel offset. */ - - /* A 64 bit reference to a symbol. */ - HOWTO (ALPHA_R_REFQUAD, /* Type. */ - 0, /* Rightshift. */ - 4, /* Size (0 = byte, 1 = short, 2 = long). */ - 64, /* Bitsize. */ - FALSE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "REFQUAD", /* Name. */ - TRUE, /* Partial_inplace. */ - MINUS_ONE, /* Source mask. */ - MINUS_ONE, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* A 21 bit branch. The native assembler generates these for - branches within the text segment, and also fills in the PC - relative offset in the instruction. */ - HOWTO (ALPHA_R_BRADDR, /* Type. */ - 2, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 21, /* Bitsize. */ - TRUE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "BRADDR", /* Name. */ - TRUE, /* Partial_inplace. */ - 0x1fffff, /* Source mask. */ - 0x1fffff, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* A hint for a jump to a register. */ - HOWTO (ALPHA_R_HINT, /* Type. */ - 2, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 14, /* Bitsize. */ - TRUE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "HINT", /* Name. */ - TRUE, /* Partial_inplace. */ - 0x3fff, /* Source mask. */ - 0x3fff, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* 16 bit PC relative offset. */ - HOWTO (ALPHA_R_SREL16, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "SREL16", /* Name. */ - TRUE, /* Partial_inplace. */ - 0xffff, /* Source mask. */ - 0xffff, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* 32 bit PC relative offset. */ - HOWTO (ALPHA_R_SREL32, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - TRUE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "SREL32", /* Name. */ - TRUE, /* Partial_inplace. */ - 0xffffffff, /* Source mask. */ - 0xffffffff, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* A 64 bit PC relative offset. */ - HOWTO (ALPHA_R_SREL64, /* Type. */ - 0, /* Rightshift. */ - 4, /* Size (0 = byte, 1 = short, 2 = long). */ - 64, /* Bitsize. */ - TRUE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "SREL64", /* Name. */ - TRUE, /* Partial_inplace. */ - MINUS_ONE, /* Source mask. */ - MINUS_ONE, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* Push a value on the reloc evaluation stack. */ - HOWTO (ALPHA_R_OP_PUSH, /* Type. */ - 0, /* Rightshift. */ - 0, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - FALSE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "OP_PUSH", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Source mask. */ - 0, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* Store the value from the stack at the given address. Store it in - a bitfield of size r_size starting at bit position r_offset. */ - HOWTO (ALPHA_R_OP_STORE, /* Type. */ - 0, /* Rightshift. */ - 4, /* Size (0 = byte, 1 = short, 2 = long). */ - 64, /* Bitsize. */ - FALSE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "OP_STORE", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Source mask. */ - MINUS_ONE, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* Subtract the reloc address from the value on the top of the - relocation stack. */ - HOWTO (ALPHA_R_OP_PSUB, /* Type. */ - 0, /* Rightshift. */ - 0, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - FALSE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "OP_PSUB", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Source mask. */ - 0, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* Shift the value on the top of the relocation stack right by the - given value. */ - HOWTO (ALPHA_R_OP_PRSHIFT, /* Type. */ - 0, /* Rightshift. */ - 0, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - FALSE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "OP_PRSHIFT", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Source mask. */ - 0, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* Hack. Linkage is done by linker. */ - HOWTO (ALPHA_R_LINKAGE, /* Type. */ - 0, /* Rightshift. */ - 8, /* Size (0 = byte, 1 = short, 2 = long). */ - 256, /* Bitsize. */ - FALSE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "LINKAGE", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Source mask. */ - 0, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* A 32 bit reference to a symbol. */ - HOWTO (ALPHA_R_REFLONG, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - FALSE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "REFLONG", /* Name. */ - TRUE, /* Partial_inplace. */ - 0xffffffff, /* Source mask. */ - 0xffffffff, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - /* A 64 bit reference to a procedure, written as 32 bit value. */ - HOWTO (ALPHA_R_CODEADDR, /* Type. */ - 0, /* Rightshift. */ - 4, /* Size (0 = byte, 1 = short, 2 = long). */ - 64, /* Bitsize. */ - FALSE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_signed,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "CODEADDR", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffffffff, /* Source mask. */ - 0xffffffff, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - HOWTO (ALPHA_R_NOP, /* Type. */ - 0, /* Rightshift. */ - 3, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - /* The following value must match that of ALPHA_R_BSR/ALPHA_R_BOH - because the calculations for the 3 relocations are the same. - See B.4.5.2 of the OpenVMS Linker Utility Manual. */ - TRUE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "NOP", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffffffff, /* Source mask. */ - 0xffffffff, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - HOWTO (ALPHA_R_BSR, /* Type. */ - 0, /* Rightshift. */ - 3, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - TRUE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "BSR", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffffffff, /* Source mask. */ - 0xffffffff, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - HOWTO (ALPHA_R_LDA, /* Type. */ - 0, /* Rightshift. */ - 3, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - FALSE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "LDA", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffffffff, /* Source mask. */ - 0xffffffff, /* Dest mask. */ - FALSE), /* PC rel offset. */ - - HOWTO (ALPHA_R_BOH, /* Type. */ - 0, /* Rightshift. */ - 3, /* Size (0 = byte, 1 = short, 2 = long, 3 = nil). */ - 0, /* Bitsize. */ - TRUE, /* PC relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - reloc_nil, /* Special_function. */ - "BOH", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffffffff, /* Source mask. */ - 0xffffffff, /* Dest mask. */ - FALSE), /* PC rel offset. */ -}; - -/* Return a pointer to a howto structure which, when invoked, will perform - the relocation code on data from the architecture noted. */ - -static const struct reloc_howto_struct * -vms_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - int alpha_type; - - vms_debug2 ((1, "vms_bfd_reloc_type_lookup (%p, %d)\t", abfd, code)); - - switch (code) - { - case BFD_RELOC_16: alpha_type = ALPHA_R_SREL16; break; - case BFD_RELOC_32: alpha_type = ALPHA_R_REFLONG; break; - case BFD_RELOC_64: alpha_type = ALPHA_R_REFQUAD; break; - case BFD_RELOC_CTOR: alpha_type = ALPHA_R_REFQUAD; break; - case BFD_RELOC_23_PCREL_S2: alpha_type = ALPHA_R_BRADDR; break; - case BFD_RELOC_ALPHA_HINT: alpha_type = ALPHA_R_HINT; break; - case BFD_RELOC_16_PCREL: alpha_type = ALPHA_R_SREL16; break; - case BFD_RELOC_32_PCREL: alpha_type = ALPHA_R_SREL32; break; - case BFD_RELOC_64_PCREL: alpha_type = ALPHA_R_SREL64; break; - case BFD_RELOC_ALPHA_LINKAGE: alpha_type = ALPHA_R_LINKAGE; break; - case BFD_RELOC_ALPHA_CODEADDR: alpha_type = ALPHA_R_CODEADDR; break; - case BFD_RELOC_ALPHA_NOP: alpha_type = ALPHA_R_NOP; break; - case BFD_RELOC_ALPHA_BSR: alpha_type = ALPHA_R_BSR; break; - case BFD_RELOC_ALPHA_LDA: alpha_type = ALPHA_R_LDA; break; - case BFD_RELOC_ALPHA_BOH: alpha_type = ALPHA_R_BOH; break; - default: - (*_bfd_error_handler) ("reloc (%d) is *UNKNOWN*", code); - return NULL; - } - vms_debug2 ((2, "reloc is %s\n", alpha_howto_table[alpha_type].name)); - return & alpha_howto_table[alpha_type]; -} - -static reloc_howto_type * -vms_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (alpha_howto_table) / sizeof (alpha_howto_table[0]); - i++) - if (alpha_howto_table[i].name != NULL - && strcasecmp (alpha_howto_table[i].name, r_name) == 0) - return &alpha_howto_table[i]; - - return NULL; -} - -/* Part 4.7, writing an object file. */ - -/* Set the architecture and machine type in BFD abfd to arch and mach. - Find the correct pointer to a structure and insert it into the arch_info - pointer. */ - -static bfd_boolean -vms_set_arch_mach (bfd * abfd, - enum bfd_architecture arch ATTRIBUTE_UNUSED, - unsigned long mach ATTRIBUTE_UNUSED) -{ - vms_debug2 ((1, "vms_set_arch_mach (%p, %d, %ld)\n", abfd, arch, mach)); - - if (arch != bfd_arch_alpha - && arch != bfd_arch_vax - && arch != bfd_arch_unknown) - return FALSE; - - return bfd_default_set_arch_mach (abfd, arch, mach); -} - -/* Sets the contents of the section section in BFD abfd to the data starting - in memory at LOCATION. The data is written to the output section starting - at offset offset for count bytes. - - Normally TRUE is returned, else FALSE. Possible error returns are: - o bfd_error_no_contents - The output section does not have the - SEC_HAS_CONTENTS attribute, so nothing can be written to it. - o and some more too */ - -static bfd_boolean -vms_set_section_contents (bfd * abfd, - asection *section, - const void * location, - file_ptr offset, - bfd_size_type count) -{ -#if VMS_DEBUG - vms_debug (1, "vms_set_section_contents (%p, sec %s, loc %p, off %ld, count %d)\n", - abfd, section->name, location, (long int)offset, (int)count); - vms_debug (2, "size %d\n", (int) section->size); -#endif - if (count == (bfd_size_type)0) - return TRUE; - - if (section->contents == NULL) - section->contents = bfd_alloc (abfd, section->size); - if (section->contents == NULL) - return FALSE; - - memcpy (section->contents + offset, location, (size_t) count); - return TRUE; -} - -static bfd_boolean -vms_bfd_print_private_bfd_data (bfd *abfd, void *ptr) -{ - FILE *file = (FILE *)ptr; - - fprintf (file, _("structure level: %d\n"), PRIV(hdr_data.hdr_b_strlvl)); - fprintf (file, _("module name : %s\n"), PRIV(hdr_data.hdr_t_name)); - fprintf (file, _("module version : %s\n"), PRIV(hdr_data.hdr_t_version)); - fprintf (file, _("module date : %s\n"), PRIV(hdr_data.hdr_t_date)); - fprintf (file, _("language name : %s\n"), PRIV(hdr_data.hdr_c_lnm)); - fprintf (file, _("source files : %s\n"), PRIV(hdr_data.hdr_c_src)); - fprintf (file, _("title : %s\n"), PRIV(hdr_data.hdr_c_ttl)); - - return TRUE; -} - -const bfd_target vms_alpha_vec = -{ - "vms-alpha", /* Name. */ - bfd_target_evax_flavour, - BFD_ENDIAN_LITTLE, /* Data byte order is little. */ - BFD_ENDIAN_LITTLE, /* Header byte order is little. */ - - (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS - | WP_TEXT | D_PAGED), /* Object flags. */ - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_CODE | SEC_DATA - | SEC_HAS_CONTENTS | SEC_IN_MEMORY), /* Sect flags. */ - 0, /* symbol_leading_char. */ - ' ', /* ar_pad_char. */ - 15, /* ar_max_namelen. */ - 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_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, - - {_bfd_dummy_target, vms_object_p, /* bfd_check_format. */ - _bfd_vms_lib_alpha_archive_p, _bfd_dummy_target}, - {bfd_false, vms_mkobject, /* bfd_set_format. */ - _bfd_vms_lib_mkarchive, bfd_false}, - {bfd_false, vms_write_object_contents, /* bfd_write_contents. */ - _bfd_vms_lib_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (vms), - BFD_JUMP_TABLE_COPY (vms), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_vms_lib), - BFD_JUMP_TABLE_SYMBOLS (vms), - BFD_JUMP_TABLE_RELOCS (vms), - BFD_JUMP_TABLE_WRITE (vms), - BFD_JUMP_TABLE_LINK (_bfd_nolink), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - NULL, - - (PTR) 0 -}; - -const bfd_target vms_vax_vec = -{ - "vms-vax", /* Name. */ - bfd_target_ovax_flavour, - BFD_ENDIAN_LITTLE, /* Data byte order is little. */ - BFD_ENDIAN_LITTLE, /* Header byte order is little. */ - - (HAS_RELOC | HAS_SYMS /* Object flags. */ - | WP_TEXT | D_PAGED - | HAS_LINENO | HAS_DEBUG | HAS_LOCALS), - - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_CODE | SEC_DATA - | SEC_HAS_CONTENTS | SEC_IN_MEMORY), /* Sect flags. */ - 0, /* symbol_leading_char */ - ' ', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 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. */ - - {_bfd_dummy_target, vms_object_p, /* bfd_check_format. */ - _bfd_dummy_target, _bfd_dummy_target}, - {bfd_false, vms_mkobject, /* bfd_set_format. */ - bfd_false, bfd_false}, - {bfd_false, vms_write_object_contents, /* bfd_write_contents. */ - bfd_false, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (vms), - BFD_JUMP_TABLE_COPY (vms), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), - BFD_JUMP_TABLE_SYMBOLS (vms), - BFD_JUMP_TABLE_RELOCS (vms), - BFD_JUMP_TABLE_WRITE (vms), - BFD_JUMP_TABLE_LINK (_bfd_nolink), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - NULL, - - (PTR) 0 -}; @@ -23,665 +23,23 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -#include <time.h> - #undef vms #ifndef VMS_H #define VMS_H -/* Constants starting with 'Exxx_' are for openVMS/Alpha (EVAX object - language). */ - -#define VMS_BLOCK_SIZE 512 - -/* VMS Text Information and Relocation Records (TIR/ETIR). */ - -#define TIR_S_C_STA_GBL 0 -#define TIR_S_C_STA_SB 1 -#define TIR_S_C_STA_SW 2 -#define TIR_S_C_STA_LW 3 -#define TIR_S_C_STA_PB 4 -#define TIR_S_C_STA_PW 5 -#define TIR_S_C_STA_PL 6 -#define TIR_S_C_STA_UB 7 -#define TIR_S_C_STA_UW 8 -#define TIR_S_C_STA_BFI 9 -#define TIR_S_C_STA_WFI 10 -#define TIR_S_C_STA_LFI 11 -#define TIR_S_C_STA_EPM 12 -#define TIR_S_C_STA_CKARG 13 -#define TIR_S_C_STA_WPB 14 -#define TIR_S_C_STA_WPW 15 -#define TIR_S_C_STA_WPL 16 -#define TIR_S_C_STA_LSY 17 -#define TIR_S_C_STA_LIT 18 -#define TIR_S_C_STA_LEPM 19 -#define TIR_S_C_MAXSTACOD 19 -#define TIR_S_C_MINSTOCOD 20 -#define TIR_S_C_STO_SB 20 -#define TIR_S_C_STO_SW 21 -#define TIR_S_C_STO_L 22 -#define TIR_S_C_STO_LW 22 -#define TIR_S_C_STO_BD 23 -#define TIR_S_C_STO_WD 24 -#define TIR_S_C_STO_LD 25 -#define TIR_S_C_STO_LI 26 -#define TIR_S_C_STO_PIDR 27 -#define TIR_S_C_STO_PICR 28 -#define TIR_S_C_STO_RSB 29 -#define TIR_S_C_STO_RSW 30 -#define TIR_S_C_STO_RL 31 -#define TIR_S_C_STO_VPS 32 -#define TIR_S_C_STO_USB 33 -#define TIR_S_C_STO_USW 34 -#define TIR_S_C_STO_RUB 35 -#define TIR_S_C_STO_RUW 36 -#define TIR_S_C_STO_B 37 -#define TIR_S_C_STO_W 38 -#define TIR_S_C_STO_RB 39 -#define TIR_S_C_STO_RW 40 -#define TIR_S_C_STO_RIVB 41 -#define TIR_S_C_STO_PIRR 42 -#define TIR_S_C_MAXSTOCOD 42 -#define TIR_S_C_MINOPRCOD 50 -#define TIR_S_C_OPR_NOP 50 -#define TIR_S_C_OPR_ADD 51 -#define TIR_S_C_OPR_SUB 52 -#define TIR_S_C_OPR_MUL 53 -#define TIR_S_C_OPR_DIV 54 -#define TIR_S_C_OPR_AND 55 -#define TIR_S_C_OPR_IOR 56 -#define TIR_S_C_OPR_EOR 57 -#define TIR_S_C_OPR_NEG 58 -#define TIR_S_C_OPR_COM 59 -#define TIR_S_C_OPR_INSV 60 -#define TIR_S_C_OPR_ASH 61 -#define TIR_S_C_OPR_USH 62 -#define TIR_S_C_OPR_ROT 63 -#define TIR_S_C_OPR_SEL 64 -#define TIR_S_C_OPR_REDEF 65 -#define TIR_S_C_OPR_DFLIT 66 -#define TIR_S_C_MAXOPRCOD 66 -#define TIR_S_C_MINCTLCOD 80 -#define TIR_S_C_CTL_SETRB 80 -#define TIR_S_C_CTL_AUGRB 81 -#define TIR_S_C_CTL_DFLOC 82 -#define TIR_S_C_CTL_STLOC 83 -#define TIR_S_C_CTL_STKDL 84 -#define TIR_S_C_MAXCTLCOD 84 - -#define ETIR_S_C_MINSTACOD 0 /* Minimum store code. */ -#define ETIR_S_C_STA_GBL 0 /* Stack global symbol value. */ -#define ETIR_S_C_STA_LW 1 /* Stack longword. */ -#define ETIR_S_C_STA_QW 2 /* Stack quadword. */ -#define ETIR_S_C_STA_PQ 3 /* Stack psect base + quadword off. */ -#define ETIR_S_C_STA_LI 4 /* Stack literal. */ -#define ETIR_S_C_STA_MOD 5 /* Stack module. */ -#define ETIR_S_C_STA_CKARG 6 /* Check Arguments. */ -#define ETIR_S_C_MAXSTACOD 6 /* Maximum stack code. */ -#define ETIR_S_C_MINSTOCOD 50 /* Minimum store code. */ -#define ETIR_S_C_STO_B 50 /* Store byte. */ -#define ETIR_S_C_STO_W 51 /* Store word. */ -#define ETIR_S_C_STO_LW 52 /* Store longword. */ -#define ETIR_S_C_STO_QW 53 /* Store quadword. */ -#define ETIR_S_C_STO_IMMR 54 /* Store immediate Repeated. */ -#define ETIR_S_C_STO_GBL 55 /* Store global. */ -#define ETIR_S_C_STO_CA 56 /* Store code address. */ -#define ETIR_S_C_STO_RB 57 /* Store relative branch. */ -#define ETIR_S_C_STO_AB 58 /* Store absolute branch. */ -#define ETIR_S_C_STO_OFF 59 /* Store offset within psect. */ -#define ETIR_S_C_STO_IMM 61 /* Store immediate. */ -#define ETIR_S_C_STO_GBL_LW 62 /* Store global Longword. */ -#define ETIR_S_C_STO_LP_PSB 63 /* STO_LP_PSB not valid in level 2 use STC_LP_PSB. */ -#define ETIR_S_C_STO_HINT_GBL 64 /* Store 14 bit HINT at global address. */ -#define ETIR_S_C_STO_HINT_PS 65 /* Store 14 bit HINT at psect + offset */ -#define ETIR_S_C_MAXSTOCOD 65 /* Maximum store code. */ -#define ETIR_S_C_MINOPRCOD 100 /* Minimum operate code. */ -#define ETIR_S_C_OPR_NOP 100 /* No-op. */ -#define ETIR_S_C_OPR_ADD 101 /* Add. */ -#define ETIR_S_C_OPR_SUB 102 /* Subtract. */ -#define ETIR_S_C_OPR_MUL 103 /* Multiply. */ -#define ETIR_S_C_OPR_DIV 104 /* Divide. */ -#define ETIR_S_C_OPR_AND 105 /* Logical AND. */ -#define ETIR_S_C_OPR_IOR 106 /* Logical inclusive OR. */ -#define ETIR_S_C_OPR_EOR 107 /* Logical exclusive OR. */ -#define ETIR_S_C_OPR_NEG 108 /* Negate. */ -#define ETIR_S_C_OPR_COM 109 /* Complement. */ -#define ETIR_S_C_OPR_INSV 110 /* Insert bit field. */ -#define ETIR_S_C_OPR_ASH 111 /* Arithmetic shift. */ -#define ETIR_S_C_OPR_USH 112 /* Unsigned shift. */ -#define ETIR_S_C_OPR_ROT 113 /* Rotate. */ -#define ETIR_S_C_OPR_SEL 114 /* Select one of three longwords on top of stack. */ -#define ETIR_S_C_OPR_REDEF 115 /* Redefine this symbol after pass 2. */ -#define ETIR_S_C_OPR_DFLIT 116 /* Define a literal. */ -#define ETIR_S_C_MAXOPRCOD 116 /* Maximum operate code. */ -#define ETIR_S_C_MINCTLCOD 150 /* Minimum control code. */ -#define ETIR_S_C_CTL_SETRB 150 /* Set relocation base. */ -#define ETIR_S_C_CTL_AUGRB 151 /* Augment relocation base. */ -#define ETIR_S_C_CTL_DFLOC 152 /* Define debug location. */ -#define ETIR_S_C_CTL_STLOC 153 /* Set debug location. */ -#define ETIR_S_C_CTL_STKDL 154 /* Stack debug location. */ -#define ETIR_S_C_MAXCTLCOD 154 /* Maximum control code. */ -#define ETIR_S_C_MINSTCCOD 200 /* Minimum store-conditional code. */ -#define ETIR_S_C_STC_LP 200 /* Store-conditional Linkage Pair. */ -#define ETIR_S_C_STC_LP_PSB 201 /* Store-conditional Linkage Pair with Procedure Signature. */ -#define ETIR_S_C_STC_GBL 202 /* Store-conditional Address at global address. */ -#define ETIR_S_C_STC_GCA 203 /* Store-conditional Code Address at global address. */ -#define ETIR_S_C_STC_PS 204 /* Store-conditional Address at psect + offset. */ -#define ETIR_S_C_STC_NOP_GBL 205 /* Store-conditional NOP at address of global. */ -#define ETIR_S_C_STC_NOP_PS 206 /* Store-conditional NOP at pect + offset. */ -#define ETIR_S_C_STC_BSR_GBL 207 /* Store-conditional BSR at global address. */ -#define ETIR_S_C_STC_BSR_PS 208 /* Store-conditional BSR at pect + offset. */ -#define ETIR_S_C_STC_LDA_GBL 209 /* Store-conditional LDA at global address. */ -#define ETIR_S_C_STC_LDA_PS 210 /* Store-conditional LDA at psect + offset. */ -#define ETIR_S_C_STC_BOH_GBL 211 /* Store-conditional BSR or Hint at global address. */ -#define ETIR_S_C_STC_BOH_PS 212 /* Store-conditional BSR or Hint at pect + offset. */ -#define ETIR_S_C_STC_NBH_GBL 213 /* Store-conditional NOP,BSR or HINT at global address. */ -#define ETIR_S_C_STC_NBH_PS 214 /* Store-conditional NOP,BSR or HINT at psect + offset. */ -#define ETIR_S_C_MAXSTCCOD 214 /* Maximum store-conditional code. */ - -#define ETIR_S_C_HEADER_SIZE 4 /* Size of the header of a command */ - -/* VMS Global Symbol Directory Records (GSD/EGSD). */ - -#define GSD_S_K_ENTRIES 1 -#define GSD_S_C_ENTRIES 1 -#define GSD_S_C_PSC 0 -#define GSD_S_C_SYM 1 -#define GSD_S_C_EPM 2 -#define GSD_S_C_PRO 3 -#define GSD_S_C_SYMW 4 -#define GSD_S_C_EPMW 5 -#define GSD_S_C_PROW 6 -#define GSD_S_C_IDC 7 -#define GSD_S_C_ENV 8 -#define GSD_S_C_LSY 9 -#define GSD_S_C_LEPM 10 -#define GSD_S_C_LPRO 11 -#define GSD_S_C_SPSC 12 -#define GSD_S_C_SYMV 13 -#define GSD_S_C_EPMV 14 -#define GSD_S_C_PROV 15 -#define GSD_S_C_MAXRECTYP 15 - -#define EGSD_S_K_ENTRIES 2 /* Offset to first entry in record. */ -#define EGSD_S_C_ENTRIES 2 /* Offset to first entry in record. */ -#define EGSD_S_C_PSC 0 /* Psect definition. */ -#define EGSD_S_C_SYM 1 /* Symbol specification. */ -#define EGSD_S_C_IDC 2 /* Random entity check. */ -#define EGSD_S_C_SPSC 5 /* Shareable image psect definition. */ -#define EGSD_S_C_SYMV 6 /* Vectored (dual-valued) versions of SYM. */ -#define EGSD_S_C_SYMM 7 /* Masked versions of SYM. */ -#define EGSD_S_C_SYMG 8 /* EGST - gst version of SYM. */ -#define EGSD_S_C_MAXRECTYP 8 /* Maximum entry type defined. */ - -/* Program Section Definition. */ -#define GPS_S_M_PIC 1 -#define GPS_S_M_LIB 2 -#define GPS_S_M_OVR 4 -#define GPS_S_M_REL 8 -#define GPS_S_M_GBL 16 -#define GPS_S_M_SHR 32 -#define GPS_S_M_EXE 64 -#define GPS_S_M_RD 128 -#define GPS_S_M_WRT 256 -#define GPS_S_M_VEC 512 -#define GPS_S_K_NAME 9 -#define GPS_S_C_NAME 9 - -#define EGPS_S_B_ALIGN 4 -#define EGPS_S_W_FLAGS 6 -#define EGPS_S_L_ALLOC 8 -#define EGPS_S_B_NAMLNG 12 - -#define EGPS_S_V_PIC 0x0001 -#define EGPS_S_V_LIB 0x0002 -#define EGPS_S_V_OVR 0x0004 -#define EGPS_S_V_REL 0x0008 -#define EGPS_S_V_GBL 0x0010 -#define EGPS_S_V_SHR 0x0020 -#define EGPS_S_V_EXE 0x0040 -#define EGPS_S_V_RD 0x0080 -#define EGPS_S_V_WRT 0x0100 -#define EGPS_S_V_VEC 0x0200 -#define EGPS_S_V_NOMOD 0x0400 -#define EGPS_S_V_COM 0x0800 -#define EGPS_S_V_ALLOC_64BIT 0x1000 - -/* Symbol Defintion or Reference. */ -#define GSY_S_M_WEAK 1 -#define GSY_S_M_DEF 2 -#define GSY_S_M_UNI 4 -#define GSY_S_M_REL 8 - -#define EGSY_S_W_FLAGS 6 - -#define EGSY_S_V_WEAK 0x0001 -#define EGSY_S_V_DEF 0x0002 -#define EGSY_S_V_UNI 0x0004 -#define EGSY_S_V_REL 0x0008 -#define EGSY_S_V_COMM 0x0010 -#define EGSY_S_V_VECEP 0x0020 -#define EGSY_S_V_NORM 0x0040 -#define EGSY_S_V_QUAD_VAL 0x0080 - -#define LSY_S_M_DEF 2 -#define LSY_S_M_REL 8 - -#define ENV_S_M_DEF 1 -#define ENV_S_M_NESTED 2 - -/* Symbol Definition. */ -#define ESDF_S_L_VALUE 8 -#define ESDF_S_L_PSINDX 28 -#define ESDF_S_B_NAMLNG 32 - -/* Universal Symbol Definition. */ -#define EGST_S_W_FLAGS 6 -#define EGST_S_Q_LP_1 16 -#define EGST_S_Q_LP_2 24 -#define EGST_S_L_PSINDX 32 -#define EGST_S_B_NAMLNG 36 - -/* Symbol Reference. */ -#define ESRF_S_B_NAMLNG 8 - -/* Debugger symbol definitions: These are done by hand, - as no machine-readable version seems to be available. */ -#define DST_S_C_C 7 /* Language == "C". */ -#define DST_S_C_CXX 15 /* Language == "C++". */ -#define DST_S_C_EPILOG 127 -#define DST_S_C_VERSION 153 -#define DST_S_C_SOURCE 155 /* Source file. */ -#define DST_S_C_PROLOG 162 -#define DST_S_C_BLKBEG 176 /* Beginning of block. */ -#define DST_S_C_BLKEND 177 /* End of block. */ -#define DST_S_C_ENTRY 181 -#define DST_S_C_PSECT 184 -#define DST_S_C_LINE_NUM 185 /* Line Number. */ -#define DST_S_C_LBLORLIT 186 -#define DST_S_C_LABEL 187 -#define DST_S_C_MODBEG 188 /* Beginning of module. */ -#define DST_S_C_MODEND 189 /* End of module. */ -#define DST_S_C_RTNBEG 190 /* Beginning of routine.*/ -#define DST_S_C_RTNEND 191 /* End of routine. */ - -/* These are used with DST_S_C_LINE_NUM. */ -#define DST_S_C_LINE_NUM_HEADER_SIZE 4 - -#define DST_S_C_DELTA_PC_W 1 /* Incr PC. */ -#define DST_S_C_INCR_LINUM 2 /* Incr Line #. */ -#define DST_S_C_INCR_LINUM_W 3 /* Incr Line #. */ -#define DST_S_C_SET_LINUM_INCR 4 -#define DST_S_C_SET_LINUM_INCR_W 5 -#define DST_S_C_RESET_LINUM_INCR 6 -#define DST_S_C_BEG_STMT_MODE 7 -#define DST_S_C_END_STMT_MODE 8 -#define DST_S_C_SET_LINE_NUM 9 /* Set Line #. */ -#define DST_S_C_SET_PC 10 -#define DST_S_C_SET_PC_W 11 -#define DST_S_C_SET_PC_L 12 -#define DST_S_C_SET_STMTNUM 13 -#define DST_S_C_TERM 14 /* End of lines. */ -#define DST_S_C_TERM_W 15 /* End of lines. */ -#define DST_S_C_SET_ABS_PC 16 /* Set PC. */ -#define DST_S_C_DELTA_PC_L 17 /* Incr PC. */ -#define DST_S_C_INCR_LINUM_L 18 /* Incr Line #. */ -#define DST_S_C_SET_LINUM_B 19 /* Set Line #. */ -#define DST_S_C_SET_LINUM_L 20 /* Set Line #. */ -#define DST_S_C_TERM_L 21 /* End of lines. */ -/* These are used with DST_S_C_SOURCE */ -#define DST_S_C_SRC_DECLFILE 1 /* Declare source file. */ -#define DST_S_C_SRC_SETFILE 2 /* Set source file. */ -#define DST_S_C_SRC_SETREC_L 3 /* Set record, longword value. */ -#define DST_S_C_SRC_SETREC_W 4 /* Set record, word value. */ -#define DST_S_C_SRC_SETLNUM_L 5 /* Set line, longword value. */ -#define DST_S_C_SRC_SETLNUM_W 6 /* Set line, word value. */ -#define DST_S_C_SRC_INCRLNUM_B 7 /* Increment line. */ -#define DST_S_C_SRC_DEFLINES_W 10 /* # of line, word counter. */ -#define DST_S_C_SRC_DEFLINES_B 11 /* # of line, byte counter. */ -#define DST_S_C_SRC_FORMFEED 16 /* ^L counts as a record. */ - -#define DST_S_B_PCLINE_UNSBYTE 1 -#define DST_S_W_PCLINE_UNSWORD 1 -#define DST_S_L_PCLINE_UNSLONG 1 - -#define DST_S_B_MODBEG_NAME 14 -#define DST_S_L_RTNBEG_ADDRESS 5 -#define DST_S_B_RTNBEG_NAME 13 -#define DST_S_L_RTNEND_SIZE 5 - -/* These are used with DST_S_C_SOURCE. */ -#define DST_S_C_SOURCE_HEADER_SIZE 4 - -#define DST_S_B_SRC_DF_LENGTH 1 -#define DST_S_W_SRC_DF_FILEID 3 -#define DST_S_B_SRC_DF_FILENAME 20 -#define DST_S_B_SRC_UNSBYTE 1 -#define DST_S_W_SRC_UNSWORD 1 -#define DST_S_L_SRC_UNSLONG 1 - -/* The following are the codes for the various data types. Anything not on - the list is included under 'advanced_type'. */ -#define DBG_S_C_UCHAR 0x02 -#define DBG_S_C_USINT 0x03 -#define DBG_S_C_ULINT 0x04 -#define DBG_S_C_UQUAD 0x05 -#define DBG_S_C_SCHAR 0x06 -#define DBG_S_C_SSINT 0x07 -#define DBG_S_C_SLINT 0x08 -#define DBG_S_C_SQUAD 0x09 -#define DBG_S_C_REAL4 0x0a -#define DBG_S_C_REAL8 0x0b /* D_float double. */ -#define DBG_S_C_COMPLX4 0x0c /* 2xF_float complex float. */ -#define DBG_S_C_COMPLX8 0x0d /* 2xD_float complex double. */ -#define DBG_S_C_REAL8_G 0x1b /* G_float double. */ -#define DBG_S_C_COMPLX8_G 0x1d /* 2xG_float complex double. */ -#define DBG_S_C_FUNCTION_ADDR 0x17 -#define DBG_S_C_ADVANCED_TYPE 0xa3 -/* Some of these are just for future reference. [pr]. */ -#define DBG_S_C_UBITA 0x01 /* Unsigned, aligned bit field. */ -#define DBG_S_C_UBITU 0x22 /* Unsigned, unaligned bit field. */ -#define DBG_S_C_SBITA 0x29 /* Signed, aligned bit field. */ -#define DBG_S_C_SBITU 0x2a /* Signed, unaligned bit field. */ -#define DBG_S_C_CSTRING 0x2e /* Asciz ('\0' terminated) string. */ -#define DBG_S_C_WCHAR 0x38 /* Wchar_t. */ -/* These are descriptor class codes. */ -#define DSC_K_CLASS_S 0x01 /* Static (fixed length). */ -#define DSC_K_CLASS_D 0x02 /* Dynamic string (not via malloc!). */ -#define DSC_K_CLASS_A 0x04 /* Array. */ -#define DSC_K_CLASS_UBS 0x0d /* Unaligned bit string. */ - -/* These are the codes that are used to generate the definitions of struct - union and enum records. */ -#define DBG_S_C_ENUM_ITEM 0xa4 -#define DBG_S_C_ENUM_START 0xa5 -#define DBG_S_C_ENUM_END 0xa6 -#define DBG_S_C_STRUCT_ITEM DST_K_VFLAGS_BITOFFS /* 0xff */ -#define DBG_S_C_STRUCT_START 0xab -#define DBG_S_C_STRUCT_END 0xac -#define DST_K_TYPSPEC 0xaf /* Type specification. */ -/* These codes are used in the generation of the symbol definition records. */ -#define DST_K_VFLAGS_NOVAL 0x80 /* Struct definition only. */ -#define DST_K_VFLAGS_DSC 0xfa /* Descriptor used. */ -#define DST_K_VFLAGS_TVS 0xfb /* Trailing value specified. */ -#define DST_K_VS_FOLLOWS 0xfd /* Value spec follows. */ -#define DST_K_VFLAGS_BITOFFS 0xff /* Value contains bit offset. */ -#define DST_K_VALKIND_LITERAL 0 -#define DST_K_VALKIND_ADDR 1 -#define DST_K_VALKIND_DESC 2 -#define DST_K_VALKIND_REG 3 -#define DST_K_REG_VAX_AP 0x0c /* R12. */ -#define DST_K_REG_VAX_FP 0x0d /* R13. */ -#define DST_K_REG_VAX_SP 0x0e /* R14. */ -#define DST_V_VALKIND 0 /* Offset of valkind field. */ -#define DST_V_INDIRECT 2 /* Offset to indirect bit. */ -#define DST_V_DISP 3 /* Offset to displacement bit. */ -#define DST_V_REGNUM 4 /* Offset to register number. */ -#define DST_M_INDIRECT (1<<DST_V_INDIRECT) -#define DST_M_DISP (1<<DST_V_DISP) -#define DBG_C_FUNCTION_PARAM /* 0xc9 */ \ - (DST_K_VALKIND_ADDR|DST_M_DISP|(DST_K_REG_VAX_AP<<DST_V_REGNUM)) -#define DBG_C_LOCAL_SYM /* 0xd9 */ \ - (DST_K_VALKIND_ADDR|DST_M_DISP|(DST_K_REG_VAX_FP<<DST_V_REGNUM)) -/* Kinds of value specifications. */ -#define DST_K_VS_ALLOC_SPLIT 3 /* Split lifetime. */ -/* Kinds of type specifications. */ -#define DST_K_TS_ATOM 0x01 /* Atomic type specification. */ -#define DST_K_TS_DSC 0x02 /* Descriptor type spec. */ -#define DST_K_TS_IND 0x03 /* Indirect type specification. */ -#define DST_K_TS_TPTR 0x04 /* Typed pointer type spec. */ -#define DST_K_TS_PTR 0x05 /* Pointer type spec. */ -#define DST_K_TS_ARRAY 0x07 /* Array type spec. */ -#define DST_K_TS_NOV_LENG 0x0e /* Novel length type spec. */ -/* These are the codes that are used in the suffix records to determine the - actual data type. */ -#define DBG_S_C_BASIC DST_K_TS_ATOM -#define DBG_S_C_BASIC_ARRAY DST_K_TS_DSC -#define DBG_S_C_STRUCT DST_K_TS_IND -#define DBG_S_C_POINTER DST_K_TS_TPTR -#define DBG_S_C_VOID DST_K_TS_PTR -#define DBG_S_C_COMPLEX_ARRAY DST_K_TS_ARRAY - -/* VMS Module Header Records (MHD/EMH). */ - -#define MHD_S_C_MHD 0 -#define MHD_S_C_LNM 1 -#define MHD_S_C_SRC 2 -#define MHD_S_C_TTL 3 -#define MHD_S_C_CPR 4 -#define MHD_S_C_MTC 5 -#define MHD_S_C_GTX 6 -#define MHD_S_C_MAXHDRTYP 6 - -#define EMH_S_C_MHD 0 /* Main header record. */ -#define EMH_S_C_LNM 1 /* Language name and version. */ -#define EMH_S_C_SRC 2 /* Source file specification. */ -#define EMH_S_C_TTL 3 /* Title text of module. */ -#define EMH_S_C_CPR 4 /* Copyright notice. */ -#define EMH_S_C_MTC 5 /* Maintenance status. */ -#define EMH_S_C_GTX 6 /* General text. */ -#define EMH_S_C_MAXHDRTYP 6 /* Maximum allowable type. */ - -/* vms.c. */ - -extern asymbol *_bfd_vms_make_empty_symbol (bfd *); -extern int _bfd_vms_slurp_object_records (bfd *abfd); - -/* vms-gsd.c. */ - -extern int _bfd_vms_slurp_gsd (bfd *abfd, int objtype); -extern int _bfd_vms_write_gsd (bfd *abfd, int objtype); -extern int _bfd_vms_slurp_dbg (bfd *abfd, int objtype); -extern int _bfd_vms_write_dbg (bfd *abfd, int objtype); -extern int _bfd_vms_slurp_tbt (bfd *abfd, int objtype); -extern int _bfd_vms_write_tbt (bfd *abfd, int objtype); - -/* vms-misc.c. */ - -extern int _bfd_vms_get_object_record (bfd *abfd); -extern int _bfd_vms_get_first_record (bfd *abfd); +#include <time.h> -extern char *vms_get_module_name (const char *filename, bfd_boolean); -extern time_t vms_time_to_time_t (unsigned int hi, unsigned int lo); -extern time_t vms_rawtime_to_time_t (unsigned char *buf); +/* Size of a VMS block on disk. */ -/* vms-hdr.c. */ - -extern int _bfd_vms_slurp_hdr (bfd *abfd, int objtype); -extern int _bfd_vms_write_hdr (bfd *abfd, int objtype); -extern int _bfd_vms_slurp_eom (bfd *abfd, int objtype); -extern int _bfd_vms_write_eom (bfd *abfd, int objtype); -extern bfd_boolean _bfd_vms_find_nearest_dst_line - (bfd *abfd, asection *section, asymbol **symbols, bfd_vma offset, - const char **file, const char **func, unsigned int *line); -extern int _bfd_vms_slurp_ihd - (bfd *abfd, unsigned int *isd_offset, unsigned int *ihs_offset); -extern int _bfd_vms_slurp_isd (bfd *abfd, unsigned int offset); -extern int _bfd_vms_slurp_ihs (bfd *abfd, unsigned int offset); - -/* vms-tir.c. */ - -extern int _bfd_vms_slurp_tir (bfd *abfd, int objtype); -extern int _bfd_vms_write_tir (bfd *abfd, int objtype); -extern int _bfd_vms_slurp_lnk (bfd *abfd, int objtype); - -extern int _bfd_vms_slurp_relocs (bfd *abfd); -extern int _bfd_vms_decode_relocs - (bfd *abfd, arelent *relocs, asection *section, asymbol **symbols); - -/* The r_type field in a reloc is one of the following values. */ -#define ALPHA_R_IGNORE 0 -#define ALPHA_R_REFQUAD 1 -#define ALPHA_R_BRADDR 2 -#define ALPHA_R_HINT 3 -#define ALPHA_R_SREL16 4 -#define ALPHA_R_SREL32 5 -#define ALPHA_R_SREL64 6 -#define ALPHA_R_OP_PUSH 7 -#define ALPHA_R_OP_STORE 8 -#define ALPHA_R_OP_PSUB 9 -#define ALPHA_R_OP_PRSHIFT 10 -#define ALPHA_R_LINKAGE 11 -#define ALPHA_R_REFLONG 12 -#define ALPHA_R_CODEADDR 13 -#define ALPHA_R_NOP 14 -#define ALPHA_R_BSR 15 -#define ALPHA_R_LDA 16 -#define ALPHA_R_BOH 17 - -/* VMS Object Language (OBJ/EOBJ). */ - -#define OBJ_S_C_HDR 0 /* VAX moule header record. */ -#define OBJ_S_C_GSD 1 /* VAX glbal symbol definition record. */ -#define OBJ_S_C_TIR 2 /* VAX tet information record. */ -#define OBJ_S_C_EOM 3 /* VAX en of module record. */ -#define OBJ_S_C_DBG 4 /* VAX Deugger information record. */ -#define OBJ_S_C_TBT 5 /* VAX Trceback information record. */ -#define OBJ_S_C_LNK 6 /* VAX liker options record. */ -#define OBJ_S_C_EOMW 7 /* VAX en of module word-psect record. */ -#define OBJ_S_C_MAXRECTYP 7 /* VAX Lat assigned record type. */ - -#define EOBJ_S_C_EMH 8 /* EVAX mdule header record. */ -#define EOBJ_S_C_EEOM 9 /* EVAX ed of module record. */ -#define EOBJ_S_C_EGSD 10 /* EVAX gobal symbol definition record. */ -#define EOBJ_S_C_ETIR 11 /* EVAX txt information record. */ -#define EOBJ_S_C_EDBG 12 /* EVAX Dbugger information record. */ -#define EOBJ_S_C_ETBT 13 /* EVAX Taceback information record. */ -#define EOBJ_S_C_MAXRECTYP 13 /* EVAX Lst assigned record type. */ - -#define OBJ_S_K_SUBTYP 1 -#define OBJ_S_C_SUBTYP 1 -#define EOBJ_S_K_SUBTYP 4 -#define EOBJ_S_C_SUBTYP 4 -#define OBJ_S_C_MAXRECSIZ 2048 /* Maximu legal record size. */ -#define EOBJ_S_C_MAXRECSIZ 8192 /* Maximu legal record size. */ -#define OBJ_S_C_STRLVL 0 /* Structre level. */ -#define EOBJ_S_C_STRLVL 2 /* Structre level. */ -#define OBJ_S_C_SYMSIZ 31 /* Maximu symbol length. */ -#define EOBJ_S_C_SYMSIZ 64 /* Maximu symbol length. */ -#define EOBJ_S_C_SECSIZ 31 /* Maximu section name length. */ -#define OBJ_S_C_STOREPLIM -1 /* Maximu repeat count on store commands. */ -#define EOBJ_S_C_STOREPLIM -1 /* Maximu repeat count on store commands. */ -#define OBJ_S_C_PSCALILIM 9 /* Maximu p-sect alignment. */ -#define EOBJ_S_C_PSCALILIM 16 /* Maximu p-sect alignment. */ - -#define EVAX_OFFSET 256 /* Type ofset for EVAX codes in switch. */ +#define VMS_BLOCK_SIZE 512 /* Miscellaneous definitions. */ -#if __GNUC__ -typedef unsigned long long uquad; -#else -typedef unsigned long uquad; -#endif - #define MAX_OUTREC_SIZE 4096 #define MIN_OUTREC_LUFT 64 -/* VMS module header. */ - -struct hdr_struct -{ - char hdr_b_strlvl; - int hdr_l_arch1; - int hdr_l_arch2; - int hdr_l_recsiz; - char *hdr_t_name; - char *hdr_t_version; - char *hdr_t_date; - char *hdr_c_lnm; - char *hdr_c_src; - char *hdr_c_ttl; -}; - -#define EMH_S_W_HDRTYP 4 -#define EMH_S_B_STRLVL 6 -#define EMH_S_L_ARCH1 8 -#define EMH_S_L_ARCH2 12 -#define EH_S_L_RECSIZ 16 -#define EMH_S_B_NAMLNG 20 - -#define EMH_DATE_LENGTH 17 - -/* VMS End-Of-Module records (EOM/EEOM). */ - -struct eom_struct -{ - int eom_l_total_lps; - short eom_w_comcod; - bfd_boolean eom_has_transfer; - char eom_b_tfrflg; - int eom_l_psindx; - int eom_l_tfradr; -}; - -#define EEOM_S_L_TOTAL_LPS 4 -#define EEOM_S_W_COMCOD 8 -#define EEOM_S_B_TFRFLG 10 -#define EEOM_S_L_PSINDX 12 -#define EEOM_S_L_TFRADR 16 - -/* VMS Image Header Records (IHD/EIHD). */ - -#define EIHD_S_K_MAJORID 3 /* Major id constant */ -#define EIHD_S_K_MINORID 0 /* Minor id constant */ -#define EIHD_S_K_EXE 1 /* Executable image */ - -#define EIHD_S_L_SIZE 8 -#define EIHD_S_L_ISDOFF 12 -#define EIHD_S_L_SYMDBGOFF 20 -#define EIHD_S_Q_SYMVVA 40 -#define EIHD_S_L_IMGTYPE 52 - -/* VMS Image Section Description Records (ISD/EISD). */ - -#define EISD_S_L_EISDSIZE 8 -#define EISD_S_L_SECSIZE 12 -#define EISD_S_Q_VIR_ADDR 16 -#define EISD_S_L_FLAGS 24 -#define EISD_S_L_VBN 28 -#define EISD_S_R_CONTROL 32 -#define EISD_S_L_IDENT 36 -#define EISD_S_T_GBLNAM 40 - -#define EISD_S_M_GBL 0x0001 -#define EISD_S_M_CRF 0x0002 -#define EISD_S_M_DZRO 0x0004 -#define EISD_S_M_WRT 0x0008 -#define EISD_S_M_INITALCODE 0x0010 -#define EISD_S_M_BASED 0x0020 -#define EISD_S_M_FIXUPVEC 0x0040 -#define EISD_S_M_RESIDENT 0x0080 -#define EISD_S_M_VECTOR 0x0100 -#define EISD_S_M_PROTECT 0x0200 -#define EISD_S_M_LASTCLU 0x0400 -#define EISD_S_M_EXE 0x0800 -#define EISD_S_M_NONSHRADR 0x1000 -#define EISD_S_M_QUAD_LENGTH 0x2000 -#define EISD_S_M_ALLOC_64BIT 0x4000 - -/* VMS Image Header Symbol Records (IHS/EIHS). */ - -#define EIHS_S_L_DSTVBN 8 -#define EIHS_S_L_DSTSIZE 12 -#define EIHS_S_L_GSTVBN 16 -#define EIHS_S_L_GSTSIZE 20 -#define EIHS_S_L_DMTVBN 24 -#define EIHS_S_L_DMTBYTES 28 - -/* Debugger symbol definitions. */ - -#define DBG_S_L_DMT_MODBEG 0 -#define DBG_S_L_DST_SIZE 4 -#define DBG_S_W_DMT_PSECT_COUNT 8 -#define DBG_S_C_DMT_HEADER_SIZE 12 - -#define DBG_S_L_DMT_PSECT_START 0 -#define DBG_S_L_DMT_PSECT_LENGTH 4 -#define DBG_S_C_DMT_PSECT_SIZE 8 - /* File format. */ + enum file_format_enum { /* Not yet known. */ @@ -697,169 +55,40 @@ enum file_format_enum FF_NATIVE }; -enum file_type_enum { FT_UNKNOWN, FT_MODULE, FT_IMAGE }; - -typedef struct vms_symbol_struct -{ - struct bfd_hash_entry bfd_hash; - asymbol *symbol; -} vms_symbol_entry; - -/* Stack value for push/pop commands. */ - -struct stack_struct -{ - uquad value; - int psect; -}; - -#define STACKSIZE 8192 - -/* A minimal decoding of DST compilation units. We only decode - what's needed to get to the line number information. */ - -struct fileinfo -{ - char *name; - unsigned int srec; -}; - -struct srecinfo -{ - struct srecinfo *next; - unsigned int line; - unsigned int sfile; - unsigned int srec; -}; - -struct lineinfo -{ - struct lineinfo *next; - bfd_vma address; - unsigned int line; -}; - -struct funcinfo -{ - struct funcinfo *next; - char *name; - bfd_vma low; - bfd_vma high; -}; +/* VMS records input buffer. */ -struct module +struct vms_rec_rd { - /* Chain the previously read compilation unit. */ - struct module *next; - - /* The module name. */ - char *name; + /* Buffer and its size. */ + unsigned char *buf; + unsigned int buf_size; - /* The start offset and size of debug info in the DST section. */ - unsigned int modbeg; - unsigned int size; + /* Current record and its size. */ + unsigned char *rec; + unsigned int rec_size; - /* The lowest and highest addresses contained in this compilation - unit as specified in the compilation unit header. */ - bfd_vma low; - bfd_vma high; - - /* The listing line table. */ - struct lineinfo *line_table; - - /* The source record table. */ - struct srecinfo *srec_table; - - /* A list of the functions found in this module. */ - struct funcinfo *func_table; - - /* Current allocation of file_table. */ - unsigned int file_table_count; - - /* An array of the files making up this module. */ - struct fileinfo *file_table; -}; - -struct vms_private_data_struct -{ - bfd_boolean is_vax; - bfd_boolean fixup_done; /* Flag to indicate if all - section pointers and PRIV(sections) - are set up correctly. */ - unsigned char *vms_buf; /* record buffer */ - unsigned int buf_size; /* size of record buffer */ - unsigned char *vms_rec; /* record pointer in record buffer */ - unsigned int rec_size; /* record size */ + /* Input file format. */ enum file_format_enum file_format; - - struct hdr_struct hdr_data; /* data from HDR/EMH record */ - struct eom_struct eom_data; /* data from EOM/EEOM record */ - unsigned int section_count; /* # of sections in following array */ - asection **sections; /* array of GSD/EGSD sections */ - unsigned int gsd_sym_count; /* # of GSD/EGSD symbols */ - asymbol **symbols; /* vector of GSD/EGSD symbols */ - struct proc_value *procedure; - - struct stack_struct *stack; - int stackptr; - - struct bfd_hash_table *vms_symbol_table; - struct bfd_symbol **symcache; - int symnum; - - asection *image_section; /* section for image_ptr */ - unsigned char *image_ptr; /* a pointer to section->contents */ - - unsigned char pdsc[8]; /* procedure descriptor */ - - struct module *modules; /* list of all compilation units */ - - struct dst_info *dst_info; - asection *dst_section; - unsigned char *dst_ptr_end; - unsigned int dst_ptr_offsets_count; /* # of offsets in following array */ - unsigned int *dst_ptr_offsets; /* array of saved image_ptr offsets */ - - /* Shared library support */ - bfd_vma symvva; /* relative virtual address of symbol vector */ - - /* Output routine storage */ - unsigned char *output_buf; /* output data */ - int push_level; - int pushed_size; - int length_pos; - int output_size; - int output_alignment; - - /* linkage index counter used by conditional store commands */ - int vms_linkage_index; - - /* see tc-alpha.c of gas for a description. */ - int flag_hash_long_names; /* -+, hash instead of truncate */ - int flag_show_after_trunc; /* -H, show hashing/truncation */ }; -#define PRIV(name) ((struct vms_private_data_struct *)abfd->tdata.any)->name +/* VMS records output buffer. */ -/* Used to keep extra VMS specific information for a given section. +struct vms_rec_wr +{ + /* Output buffer. */ + unsigned char *buf; - reloc_size holds the size of the relocation stream, note this - is very different from the number of relocations as VMS relocations - are variable length. + /* Current length of the record. */ + unsigned short int size; - reloc_stream is the actual stream of relocation entries. */ + /* Sub-record start offset. */ + unsigned short int subrec_offset; -struct vms_section_data_struct -{ - bfd_size_type reloc_size; - unsigned char *reloc_stream; - bfd_size_type reloc_offset; - flagword vflags; + /* Some records must have a size that is a multiple of the alignment. + Mustn't be 0. */ + unsigned short int align; }; -#define vms_section_data(sec) \ - ((struct vms_section_data_struct *)sec->used_by_bfd) - struct evax_private_udata_struct { asymbol *bsym; @@ -868,7 +97,9 @@ struct evax_private_udata_struct int lkindex; }; -#define SECTION_NAME_TEMPLATE "__SEC__%d" +/* vms-misc.c. */ + +#define VMS_DEBUG 1 #if VMS_DEBUG extern void _bfd_vms_debug (int, char *, ...) ATTRIBUTE_PRINTF_2; @@ -880,32 +111,29 @@ extern void _bfd_hexdump (int, unsigned char *, int, int); #define vms_debug2(X) #endif -extern struct bfd_hash_entry * _bfd_vms_hash_newfunc (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); -extern void _bfd_vms_get_header_values (bfd *, unsigned char *, int *, int *); -extern int _bfd_vms_get_record (bfd *abf); -extern int _bfd_vms_next_record (bfd *abf); -extern char * _bfd_vms_save_sized_string (unsigned char *, int); -extern char * _bfd_vms_save_counted_string (unsigned char *); -extern void _bfd_vms_push (bfd *, uquad, int); -extern uquad _bfd_vms_pop (bfd *, int *); -extern void _bfd_vms_output_begin (bfd *, int, int); -extern void _bfd_vms_output_alignment (bfd *, int); -extern void _bfd_vms_output_push (bfd *); -extern void _bfd_vms_output_pop (bfd *); -extern void _bfd_vms_output_flush (bfd *); -extern void _bfd_vms_output_end (bfd *); -extern int _bfd_vms_output_check (bfd *, int); -extern void _bfd_vms_output_byte (bfd *, unsigned); -extern void _bfd_vms_output_short (bfd *, unsigned); -extern void _bfd_vms_output_long (bfd *, unsigned long); -extern void _bfd_vms_output_quad (bfd *, uquad); -extern void _bfd_vms_output_counted (bfd *, char *); -extern void _bfd_vms_output_dump (bfd *, unsigned char *, int); -extern void _bfd_vms_output_fill (bfd *, int, int); -extern char * _bfd_vms_length_hash_symbol (bfd *, const char *, int); -extern vms_symbol_entry * _bfd_vms_enter_symbol (bfd *, char *); - -#define EGPS_S_V_NO_SHIFT 16 - -extern void bfd_vms_set_section_flags (bfd *, asection *, flagword); +extern char *vms_get_module_name (const char *filename, bfd_boolean); +extern unsigned char *get_vms_time_string (void); +extern time_t vms_time_to_time_t (unsigned int hi, unsigned int lo); +extern time_t vms_rawtime_to_time_t (unsigned char *buf); + +extern char *_bfd_vms_save_sized_string (unsigned char *, int); +extern char *_bfd_vms_save_counted_string (unsigned char *); +extern void _bfd_vms_output_begin (struct vms_rec_wr *, int); +extern void _bfd_vms_output_alignment (struct vms_rec_wr *, int); +extern void _bfd_vms_output_begin_subrec (struct vms_rec_wr *, int); +extern void _bfd_vms_output_end_subrec (struct vms_rec_wr *); +extern void _bfd_vms_output_end (bfd *, struct vms_rec_wr *); +extern int _bfd_vms_output_check (struct vms_rec_wr *, int); +extern void _bfd_vms_output_byte (struct vms_rec_wr *, unsigned); +extern void _bfd_vms_output_short (struct vms_rec_wr *, unsigned); +extern void _bfd_vms_output_long (struct vms_rec_wr *, unsigned long); +extern void _bfd_vms_output_quad (struct vms_rec_wr *, bfd_vma); +extern void _bfd_vms_output_counted (struct vms_rec_wr *, char *); +extern void _bfd_vms_output_dump (struct vms_rec_wr *, unsigned char *, int); +extern void _bfd_vms_output_fill (struct vms_rec_wr *, int, int); + +/* vms-alpha.c */ + +extern void bfd_vms_set_section_flags (bfd *, asection *, flagword, flagword); + #endif /* VMS_H */ |