summaryrefslogtreecommitdiff
path: root/gas/config/obj-vms.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/config/obj-vms.c')
-rw-r--r--gas/config/obj-vms.c5549
1 files changed, 5549 insertions, 0 deletions
diff --git a/gas/config/obj-vms.c b/gas/config/obj-vms.c
new file mode 100644
index 0000000000..0f08f8eb3f
--- /dev/null
+++ b/gas/config/obj-vms.c
@@ -0,0 +1,5549 @@
+/* vms.c -- Write out a VAX/VMS object file
+ Copyright (C) 1987, 88, 92, 94, 95, 97, 1998 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler.
+
+GAS is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GAS 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 GAS; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+/* Written by David L. Kashtan */
+/* Modified by Eric Youngdale to write VMS debug records for program
+ variables */
+
+/* Want all of obj-vms.h (as obj-format.h, via targ-env.h, via as.h). */
+#define WANT_VMS_OBJ_DEFS
+
+#include "as.h"
+#include "config.h"
+#include "subsegs.h"
+#include "obstack.h"
+
+/* What we do if there is a goof. */
+#define error as_fatal
+
+#ifdef VMS /* These are of no use if we are cross assembling. */
+#include <fab.h> /* Define File Access Block */
+#include <nam.h> /* Define NAM Block */
+#include <xab.h> /* Define XAB - all different types*/
+extern int sys$open(), sys$close(), sys$asctim();
+#endif
+
+/*
+ * Version string of the compiler that produced the code we are
+ * assembling. (And this assembler, if we do not have compiler info.)
+ */
+char *compiler_version_string;
+
+extern int flag_hash_long_names; /* -+ */
+extern int flag_one; /* -1; compatibility with gcc 1.x */
+extern int flag_show_after_trunc; /* -H */
+extern int flag_no_hash_mixed_case; /* -h NUM */
+
+/* Flag that determines how we map names. This takes several values, and
+ * is set with the -h switch. A value of zero implies names should be
+ * upper case, and the presence of the -h switch inhibits the case hack.
+ * No -h switch at all sets vms_name_mapping to 0, and allows case hacking.
+ * A value of 2 (set with -h2) implies names should be
+ * all lower case, with no case hack. A value of 3 (set with -h3) implies
+ * that case should be preserved. */
+
+/* If the -+ switch is given, then the hash is appended to any name that is
+ * longer than 31 characters, regardless of the setting of the -h switch.
+ */
+
+char vms_name_mapping = 0;
+
+static symbolS *Entry_Point_Symbol = 0; /* Pointer to "_main" */
+
+/*
+ * We augment the "gas" symbol structure with this
+ */
+struct VMS_Symbol
+{
+ struct VMS_Symbol *Next;
+ symbolS *Symbol;
+ int Size;
+ int Psect_Index;
+ int Psect_Offset;
+};
+
+struct VMS_Symbol *VMS_Symbols = 0;
+struct VMS_Symbol *Ctors_Symbols = 0;
+struct VMS_Symbol *Dtors_Symbols = 0;
+
+/* We need this to keep track of the various input files, so that we can
+ * give the debugger the correct source line.
+ */
+
+struct input_file
+{
+ struct input_file *next;
+ struct input_file *same_file_fpnt;
+ int file_number;
+ int max_line;
+ int min_line;
+ int offset;
+ char flag;
+ char *name;
+ symbolS *spnt;
+};
+
+static struct input_file *file_root = (struct input_file *) NULL;
+
+
+/*
+ * Styles of PSECTS (program sections) that we generate; just shorthand
+ * to avoid lists of section attributes. Used by VMS_Psect_Spec().
+ */
+enum ps_type
+{
+ ps_TEXT, ps_DATA, ps_COMMON, ps_CONST, ps_CTORS, ps_DTORS
+};
+
+/*
+ * This enum is used to keep track of the various types of variables that
+ * may be present.
+ */
+
+enum advanced_type
+{
+ BASIC, POINTER, ARRAY, ENUM, STRUCT, UNION, FUNCTION, VOID, ALIAS, UNKNOWN
+};
+
+/*
+ * This structure contains the information from the stabs directives, and the
+ * information is filled in by VMS_typedef_parse. Everything that is needed
+ * to generate the debugging record for a given symbol is present here.
+ * This could be done more efficiently, using nested struct/unions, but for now
+ * I am happy that it works.
+ */
+struct VMS_DBG_Symbol
+{
+ struct VMS_DBG_Symbol *next;
+ /* description of what this is */
+ enum advanced_type advanced;
+ /* this record is for this type */
+ int dbx_type;
+ /* For advanced types this is the type referred to. I.e., the type
+ a pointer points to, or the type of object that makes up an
+ array. */
+ int type2;
+ /* Use this type when generating a variable def */
+ int VMS_type;
+ /* used for arrays - this will be present for all */
+ int index_min;
+ /* entries, but will be meaningless for non-arrays */
+ int index_max;
+ /* Size in bytes of the data type. For an array, this is the size
+ of one element in the array */
+ int data_size;
+ /* Number of the structure/union/enum - used for ref */
+ int struc_numb;
+};
+
+#define SYMTYPLST_SIZE (1<<4) /* 16; must be power of two */
+#define SYMTYP_HASH(x) ((unsigned)(x) & (SYMTYPLST_SIZE-1))
+struct VMS_DBG_Symbol *VMS_Symbol_type_list[SYMTYPLST_SIZE];
+
+/*
+ * We need this structure to keep track of forward references to
+ * struct/union/enum that have not been defined yet. When they are ultimately
+ * defined, then we can go back and generate the TIR commands to make a back
+ * reference.
+ */
+
+struct forward_ref
+{
+ struct forward_ref *next;
+ int dbx_type;
+ int struc_numb;
+ char resolved;
+};
+
+struct forward_ref *f_ref_root = (struct forward_ref *) NULL;
+
+/*
+ * This routine is used to compare the names of certain types to various
+ * fixed types that are known by the debugger.
+ */
+#define type_check(X) !strcmp (symbol_name, X)
+
+/*
+ * This variable is used to keep track of the name of the symbol we are
+ * working on while we are parsing the stabs directives.
+ */
+static const char *symbol_name;
+
+/* We use this counter to assign numbers to all of the structures, unions
+ * and enums that we define. When we actually declare a variable to the
+ * debugger, we can simply do it by number, rather than describing the
+ * whole thing each time.
+ */
+
+static structure_count = 0;
+
+/* This variable is used to indicate that we are making the last attempt to
+ parse the stabs, and that we should define as much as we can, and ignore
+ the rest */
+
+static int final_pass;
+
+/* This variable is used to keep track of the current structure number
+ * for a given variable. If this is < 0, that means that the structure
+ * has not yet been defined to the debugger. This is still cool, since
+ * the VMS object language has ways of fixing things up after the fact,
+ * so we just make a note of this, and generate fixups at the end.
+ */
+static int struct_number;
+
+/* This is used to distinguish between D_float and G_float for telling
+ the debugger about doubles. gcc outputs the same .stabs regardless
+ of whether -mg is used to select alternate doubles. */
+
+static int vax_g_doubles = 0;
+
+/* Local symbol references (used to handle N_ABS symbols; gcc does not
+ generate those, but they're possible with hand-coded assembler input)
+ are always made relative to some particular environment. If the current
+ input has any such symbols, then we expect this to get incremented
+ exactly once and end up having all of them be in environment #0. */
+
+static int Current_Environment = -1;
+
+/* Every object file must specify an module name, which is also used by
+ traceback records. Set in Write_VMS_MHD_Records(). */
+
+static char Module_Name[255+1];
+
+/*
+ * Variable descriptors are used tell the debugger the data types of certain
+ * more complicated variables (basically anything involving a structure,
+ * union, enum, array or pointer). Some non-pointer variables of the
+ * basic types that the debugger knows about do not require a variable
+ * descriptor.
+ *
+ * Since it is impossible to have a variable descriptor longer than 128
+ * bytes by virtue of the way that the VMS object language is set up,
+ * it makes not sense to make the arrays any longer than this, or worrying
+ * about dynamic sizing of the array.
+ *
+ * These are the arrays and counters that we use to build a variable
+ * descriptor.
+ */
+
+#define MAX_DEBUG_RECORD 128
+static char Local[MAX_DEBUG_RECORD]; /* buffer for variable descriptor */
+static char Asuffix[MAX_DEBUG_RECORD]; /* buffer for array descriptor */
+static int Lpnt; /* index into Local */
+static int Apoint; /* index into Asuffix */
+static char overflow; /* flag to indicate we have written too much*/
+static int total_len; /* used to calculate the total length of variable
+ descriptor plus array descriptor - used for len byte*/
+
+/* Flag if we have told user about finding global constants in the text
+ section. */
+static int gave_compiler_message = 0;
+
+
+/*
+ * Global data (Object records limited to 512 bytes by VAX-11 "C" runtime)
+ */
+static int VMS_Object_File_FD; /* File Descriptor for object file */
+static char Object_Record_Buffer[512]; /* Buffer for object file records */
+static int Object_Record_Offset;/* Offset to end of data */
+static int Current_Object_Record_Type; /* Type of record in above */
+
+/*
+ * Macros for moving data around. Must work on big-endian systems.
+ */
+#ifdef VMS /* These are more efficient for VMS->VMS systems */
+#define COPY_LONG(dest,val) ( *(long *)(dest) = (val) )
+#define COPY_SHORT(dest,val) ( *(short *)(dest) = (val) )
+#else
+#define COPY_LONG(dest,val) md_number_to_chars ((dest), (val), 4)
+#define COPY_SHORT(dest,val) md_number_to_chars ((dest), (val), 2)
+#endif
+/*
+ * Macros for placing data into the object record buffer.
+ */
+#define PUT_LONG(val) \
+ ( COPY_LONG (&Object_Record_Buffer[Object_Record_Offset], (val)), \
+ Object_Record_Offset += 4 )
+
+#define PUT_SHORT(val) \
+ ( COPY_SHORT (&Object_Record_Buffer[Object_Record_Offset], (val)), \
+ Object_Record_Offset += 2 )
+
+#define PUT_CHAR(val) ( Object_Record_Buffer[Object_Record_Offset++] = (val) )
+
+#define PUT_COUNTED_STRING(cp) do { \
+ register const char *p = (cp); \
+ PUT_CHAR ((char) strlen (p)); \
+ while (*p) PUT_CHAR (*p++); } while (0)
+
+/*
+ * Macro for determining if a Name has psect attributes attached
+ * to it.
+ */
+#define PSECT_ATTRIBUTES_STRING "$$PsectAttributes_"
+#define PSECT_ATTRIBUTES_STRING_LENGTH 18
+
+#define HAS_PSECT_ATTRIBUTES(Name) \
+ (strncmp ((*Name == '_' ? Name + 1 : Name), \
+ PSECT_ATTRIBUTES_STRING, \
+ PSECT_ATTRIBUTES_STRING_LENGTH) == 0)
+
+
+ /* in: segT out: N_TYPE bits */
+const short seg_N_TYPE[] =
+{
+ N_ABS,
+ N_TEXT,
+ N_DATA,
+ N_BSS,
+ N_UNDF, /* unknown */
+ N_UNDF, /* error */
+ N_UNDF, /* expression */
+ N_UNDF, /* debug */
+ N_UNDF, /* ntv */
+ N_UNDF, /* ptv */
+ N_REGISTER, /* register */
+};
+
+const segT N_TYPE_seg[N_TYPE + 2] =
+{ /* N_TYPE == 0x1E = 32-2 */
+ SEG_UNKNOWN, /* N_UNDF == 0 */
+ SEG_GOOF,
+ SEG_ABSOLUTE, /* N_ABS == 2 */
+ SEG_GOOF,
+ SEG_TEXT, /* N_TEXT == 4 */
+ SEG_GOOF,
+ SEG_DATA, /* N_DATA == 6 */
+ SEG_GOOF,
+ SEG_BSS, /* N_BSS == 8 */
+ SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
+ SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */
+ SEG_GOOF,
+};
+
+
+/* Local support routines which return a value. */
+
+static struct input_file *find_file PARAMS ((symbolS *));
+static struct VMS_DBG_Symbol *find_symbol PARAMS ((int));
+static symbolS *Define_Routine PARAMS ((symbolS *,int,symbolS *,int));
+
+static char *cvt_integer PARAMS ((char *,int *));
+static char *fix_name PARAMS ((char *));
+static char *get_struct_name PARAMS ((char *));
+
+static offsetT VMS_Initialized_Data_Size PARAMS ((symbolS *,unsigned));
+
+static int VMS_TBT_Source_File PARAMS ((char *,int));
+static int gen1 PARAMS ((struct VMS_DBG_Symbol *,int));
+static int forward_reference PARAMS ((char *));
+static int final_forward_reference PARAMS ((struct VMS_DBG_Symbol *));
+static int VMS_typedef_parse PARAMS ((char *));
+static int hash_string PARAMS ((const char *));
+static int VMS_Psect_Spec PARAMS ((const char *,int,enum ps_type,
+ struct VMS_Symbol *));
+
+/* Local support routines which don't directly return any value. */
+
+static void s_const PARAMS ((int));
+static void Create_VMS_Object_File PARAMS ((void));
+static void Flush_VMS_Object_Record_Buffer PARAMS ((void));
+static void Set_VMS_Object_File_Record PARAMS ((int));
+static void Close_VMS_Object_File PARAMS ((void));
+static void vms_tir_stack_psect PARAMS ((int,int,int));
+static void VMS_Store_Immediate_Data PARAMS ((const char *,int,int));
+static void VMS_Set_Data PARAMS ((int,int,int,int));
+static void VMS_Store_Struct PARAMS ((int));
+static void VMS_Def_Struct PARAMS ((int));
+static void VMS_Set_Struct PARAMS ((int));
+static void VMS_TBT_Module_Begin PARAMS ((void));
+static void VMS_TBT_Module_End PARAMS ((void));
+static void VMS_TBT_Routine_Begin PARAMS ((symbolS *,int));
+static void VMS_TBT_Routine_End PARAMS ((int,symbolS *));
+static void VMS_TBT_Block_Begin PARAMS ((symbolS *,int,char *));
+static void VMS_TBT_Block_End PARAMS ((valueT));
+static void VMS_TBT_Line_PC_Correlation PARAMS ((int,int,int,int));
+static void VMS_TBT_Source_Lines PARAMS ((int,int,int));
+static void fpush PARAMS ((int,int));
+static void rpush PARAMS ((int,int));
+static void array_suffix PARAMS ((struct VMS_DBG_Symbol *));
+static void new_forward_ref PARAMS ((int));
+static void generate_suffix PARAMS ((struct VMS_DBG_Symbol *,int));
+static void bitfield_suffix PARAMS ((struct VMS_DBG_Symbol *,int));
+static void setup_basic_type PARAMS ((struct VMS_DBG_Symbol *));
+static void VMS_DBG_record PARAMS ((struct VMS_DBG_Symbol *,int,int,char *));
+static void VMS_local_stab_Parse PARAMS ((symbolS *));
+static void VMS_stab_parse PARAMS ((symbolS *,int,int,int,int));
+static void VMS_GSYM_Parse PARAMS ((symbolS *,int));
+static void VMS_LCSYM_Parse PARAMS ((symbolS *,int));
+static void VMS_STSYM_Parse PARAMS ((symbolS *,int));
+static void VMS_RSYM_Parse PARAMS ((symbolS *,symbolS *,int));
+static void VMS_LSYM_Parse PARAMS ((void));
+static void Define_Local_Symbols PARAMS ((symbolS *,symbolS *,symbolS *,int));
+static void Write_VMS_MHD_Records PARAMS ((void));
+static void Write_VMS_EOM_Record PARAMS ((int,valueT));
+static void VMS_Case_Hack_Symbol PARAMS ((const char *,char *));
+static void VMS_Modify_Psect_Attributes PARAMS ((const char *,int *));
+static void VMS_Global_Symbol_Spec PARAMS ((const char *,int,int,int));
+static void VMS_Local_Environment_Setup PARAMS ((const char *));
+static void VMS_Emit_Globalvalues PARAMS ((unsigned,unsigned,char *));
+static void VMS_Procedure_Entry_Pt PARAMS ((char *,int,int,int));
+static void VMS_Set_Psect PARAMS ((int,int,int));
+static void VMS_Store_Repeated_Data PARAMS ((int,char *,int,int));
+static void VMS_Store_PIC_Symbol_Reference PARAMS ((symbolS *,int,
+ int,int,int,int));
+static void VMS_Fix_Indirect_Reference PARAMS ((int,int,fragS *,fragS *));
+
+/* Support code which used to be inline within vms_write_object_file. */
+static void vms_fixup_text_section PARAMS ((unsigned,struct frag *,struct frag *));
+static void synthesize_data_segment PARAMS ((unsigned,unsigned,struct frag *));
+static void vms_fixup_data_section PARAMS ((unsigned,unsigned));
+static void global_symbol_directory PARAMS ((unsigned,unsigned));
+static void local_symbols_DST PARAMS ((symbolS *,symbolS *));
+static void vms_build_DST PARAMS ((unsigned));
+static void vms_fixup_xtors_section PARAMS ((struct VMS_Symbol *, int));
+
+
+/* The following code defines the special types of pseudo-ops that we
+ use with VMS. */
+
+unsigned char const_flag = IN_DEFAULT_SECTION;
+
+static void
+s_const (arg)
+ int arg; /* 3rd field from obj_pseudo_table[]; not needed here */
+{
+ /* Since we don't need `arg', use it as our scratch variable so that
+ we won't get any "not used" warnings about it. */
+ arg = get_absolute_expression ();
+ subseg_set (SEG_DATA, (subsegT) arg);
+ const_flag = 1;
+ demand_empty_rest_of_line ();
+}
+
+const pseudo_typeS obj_pseudo_table[] =
+{
+ {"const", s_const, 0},
+ {0, 0, 0},
+}; /* obj_pseudo_table */
+
+
+/* Routine to perform RESOLVE_SYMBOL_REDEFINITION(). */
+
+int
+vms_resolve_symbol_redef (sym)
+ symbolS *sym;
+{
+ /*
+ * If the new symbol is .comm AND it has a size of zero,
+ * we ignore it (i.e. the old symbol overrides it)
+ */
+ if (SEGMENT_TO_SYMBOL_TYPE ((int) now_seg) == (N_UNDF | N_EXT)
+ && frag_now_fix () == 0)
+ {
+ as_warn (_("compiler emitted zero-size common symbol `%s' already defined"),
+ S_GET_NAME (sym));
+ return 1;
+ }
+ /*
+ * If the old symbol is .comm and it has a size of zero,
+ * we override it with the new symbol value.
+ */
+ if (S_IS_EXTERNAL (sym) && S_IS_DEFINED (sym) && S_GET_VALUE (sym) == 0)
+ {
+ as_warn (_("compiler redefined zero-size common symbol `%s'"),
+ S_GET_NAME (sym));
+ sym->sy_frag = frag_now;
+ S_SET_OTHER (sym, const_flag);
+ S_SET_VALUE (sym, frag_now_fix ());
+ /* Keep N_EXT bit. */
+ sym->sy_symbol.n_type |= SEGMENT_TO_SYMBOL_TYPE ((int) now_seg);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* `tc_frob_label' handler for colon(symbols.c), used to examine the
+ dummy label(s) gcc inserts at the beginning of each file it generates.
+ gcc 1.x put "gcc_compiled."; gcc 2.x (as of 2.7) puts "gcc2_compiled."
+ and "__gnu_language_<name>" and possibly "__vax_<type>_doubles". */
+
+void
+vms_check_for_special_label (symbolP)
+symbolS *symbolP;
+{
+ /* Special labels only occur prior to explicit section directives. */
+ if ((const_flag & IN_DEFAULT_SECTION) != 0)
+ {
+ char *sym_name = S_GET_NAME (symbolP);
+
+ if (*sym_name == '_')
+ ++sym_name;
+
+ if (!strcmp (sym_name, "__vax_g_doubles"))
+ vax_g_doubles = 1;
+#if 0 /* not necessary */
+ else if (!strcmp (sym_name, "__vax_d_doubles"))
+ vax_g_doubles = 0;
+#endif
+#if 0 /* these are potential alternatives to tc-vax.c's md_parse_options() */
+ else if (!strcmp (sym_name, "gcc_compiled."))
+ flag_one = 1;
+ else if (!strcmp (sym_name, "__gnu_language_cplusplus"))
+ flag_hash_long_names = 1;
+#endif
+ }
+ return;
+}
+
+
+void
+obj_read_begin_hook ()
+{
+ return;
+}
+
+
+void
+obj_crawl_symbol_chain (headers)
+ object_headers *headers;
+{
+ symbolS *symbolP;
+ symbolS **symbolPP;
+ int symbol_number = 0;
+
+ symbolPP = &symbol_rootP; /* -> last symbol chain link. */
+ while ((symbolP = *symbolPP) != NULL)
+ {
+ resolve_symbol_value (symbolP, 1);
+
+ /* OK, here is how we decide which symbols go out into the
+ brave new symtab. Symbols that do are:
+
+ * symbols with no name (stabd's?)
+ * symbols with debug info in their N_TYPE
+ * symbols with \1 as their 3rd character (numeric labels)
+ * "local labels" needed for PIC fixups
+
+ Symbols that don't are:
+ * symbols that are registers
+
+ All other symbols are output. We complain if a deleted
+ symbol was marked external. */
+
+ if (!S_IS_REGISTER (symbolP))
+ {
+ symbolP->sy_number = symbol_number++;
+ symbolP->sy_name_offset = 0;
+ symbolPP = &(symbol_next (symbolP));
+ }
+ else
+ {
+ if (S_IS_EXTERNAL (symbolP) || !S_IS_DEFINED (symbolP))
+ {
+ as_bad (_("Local symbol %s never defined"), S_GET_NAME (symbolP));
+ } /* oops. */
+
+ /* Unhook it from the chain. */
+ *symbolPP = symbol_next (symbolP);
+ } /* if this symbol should be in the output */
+
+ } /* for each symbol */
+
+ H_SET_STRING_SIZE (headers, string_byte_count);
+ H_SET_SYMBOL_TABLE_SIZE (headers, symbol_number);
+} /* obj_crawl_symbol_chain() */
+
+
+ /****** VMS OBJECT FILE HACKING ROUTINES *******/
+
+
+/* Create the VMS object file. */
+
+static void
+Create_VMS_Object_File ()
+{
+#if defined(eunice) || !defined(VMS)
+ VMS_Object_File_FD = creat (out_file_name, 0777, "var");
+#else /* eunice */
+ VMS_Object_File_FD = creat (out_file_name, 0, "rfm=var",
+ "ctx=bin", "mbc=16", "deq=64", "fop=tef",
+ "shr=nil");
+#endif /* eunice */
+ /* Deal with errors. */
+ if (VMS_Object_File_FD < 0)
+ as_fatal (_("Couldn't create VMS object file \"%s\""), out_file_name);
+ /* Initialize object file hacking variables. */
+ Object_Record_Offset = 0;
+ Current_Object_Record_Type = -1;
+}
+
+
+/* Flush the object record buffer to the object file. */
+
+static void
+Flush_VMS_Object_Record_Buffer ()
+{
+ /* If the buffer is empty, there's nothing to do. */
+ if (Object_Record_Offset == 0)
+ return;
+
+#ifndef VMS /* For cross-assembly purposes. */
+ {
+ char RecLen[2];
+
+ /* "Variable-length record" files have a two byte length field
+ prepended to each record. It's normally out-of-band, and native
+ VMS output will insert it automatically for this type of file.
+ When cross-assembling, we must write it explicitly. */
+ md_number_to_chars (RecLen, Object_Record_Offset, 2);
+ if (write (VMS_Object_File_FD, RecLen, 2) != 2)
+ error (_("I/O error writing VMS object file (length prefix)"));
+ /* We also need to force the actual record to be an even number of
+ bytes. For native output, that's automatic; when cross-assembling,
+ pad with a NUL byte if length is odd. Do so _after_ writing the
+ pre-padded length. Since our buffer is defined with even size,
+ an odd offset implies that it has some room left. */
+ if ((Object_Record_Offset & 1) != 0)
+ Object_Record_Buffer[Object_Record_Offset++] = '\0';
+ }
+#endif /* not VMS */
+
+ /* Write the data to the file. */
+ if (write (VMS_Object_File_FD, Object_Record_Buffer, Object_Record_Offset)
+ != Object_Record_Offset)
+ error (_("I/O error writing VMS object file"));
+
+ /* The buffer is now empty. */
+ Object_Record_Offset = 0;
+}
+
+
+/* Declare a particular type of object file record. */
+
+static void
+Set_VMS_Object_File_Record (Type)
+ int Type;
+{
+ /* If the type matches, we are done. */
+ if (Type == Current_Object_Record_Type)
+ return;
+ /* Otherwise: flush the buffer. */
+ Flush_VMS_Object_Record_Buffer ();
+ /* Remember the new type. */
+ Current_Object_Record_Type = Type;
+}
+
+
+/* Close the VMS Object file. */
+
+static void
+Close_VMS_Object_File ()
+{
+ /* Flush (should never be necessary) and reset saved record-type context. */
+ Set_VMS_Object_File_Record (-1);
+
+#ifndef VMS /* For cross-assembly purposes. */
+ {
+ char RecLen[2];
+ int minus_one = -1;
+
+ /* Write a 2 byte record-length field of -1 into the file, which
+ means end-of-block when read, hence end-of-file when occurring
+ in the file's last block. It is only needed for variable-length
+ record files transferred to VMS as fixed-length record files
+ (typical for binary FTP; NFS shouldn't need it, but it won't hurt). */
+ md_number_to_chars (RecLen, minus_one, 2);
+ write (VMS_Object_File_FD, RecLen, 2);
+ }
+#else
+ /* When written on a VMS system, the file header (cf inode) will record
+ the actual end-of-file position and no inline marker is needed. */
+#endif
+
+ close (VMS_Object_File_FD);
+}
+
+
+ /****** Text Information and Relocation routines ******/
+
+
+/* Stack Psect base followed by signed, varying-sized offset.
+ Common to several object records. */
+
+static void
+vms_tir_stack_psect (Psect_Index, Offset, Force)
+ int Psect_Index;
+ int Offset;
+ int Force;
+{
+ int psect_width, offset_width;
+
+ psect_width = ((unsigned) Psect_Index > 255) ? 2 : 1;
+ offset_width = (Force || Offset > 32767 || Offset < -32768) ? 4
+ : (Offset > 127 || Offset < -128) ? 2 : 1;
+#define Sta_P(p,o) (((o)<<1) | ((p)-1))
+ /* byte or word psect; byte, word, or longword offset */
+ switch (Sta_P(psect_width,offset_width))
+ {
+ case Sta_P(1,1): PUT_CHAR (TIR_S_C_STA_PB);
+ PUT_CHAR ((char)(unsigned char) Psect_Index);
+ PUT_CHAR ((char) Offset);
+ break;
+ case Sta_P(1,2): PUT_CHAR (TIR_S_C_STA_PW);
+ PUT_CHAR ((char)(unsigned char) Psect_Index);
+ PUT_SHORT (Offset);
+ break;
+ case Sta_P(1,4): PUT_CHAR (TIR_S_C_STA_PL);
+ PUT_CHAR ((char)(unsigned char) Psect_Index);
+ PUT_LONG (Offset);
+ break;
+ case Sta_P(2,1): PUT_CHAR (TIR_S_C_STA_WPB);
+ PUT_SHORT (Psect_Index);
+ PUT_CHAR ((char) Offset);
+ break;
+ case Sta_P(2,2): PUT_CHAR (TIR_S_C_STA_WPW);
+ PUT_SHORT (Psect_Index);
+ PUT_SHORT (Offset);
+ break;
+ case Sta_P(2,4): PUT_CHAR (TIR_S_C_STA_WPL);
+ PUT_SHORT (Psect_Index);
+ PUT_LONG (Offset);
+ break;
+ }
+#undef Sta_P
+}
+
+
+/* Store immediate data in current Psect. */
+
+static void
+VMS_Store_Immediate_Data (Pointer, Size, Record_Type)
+ const char *Pointer;
+ int Size;
+ int Record_Type;
+{
+ register int i;
+
+ Set_VMS_Object_File_Record (Record_Type);
+ /* We can only store as most 128 bytes at a time due to the way that
+ TIR commands are encoded. */
+ while (Size > 0)
+ {
+ i = (Size > 128) ? 128 : Size;
+ Size -= i;
+ /* If we cannot accommodate this record, flush the buffer. */
+ if ((Object_Record_Offset + i + 1) >= sizeof Object_Record_Buffer)
+ Flush_VMS_Object_Record_Buffer ();
+ /* If the buffer is empty we must insert record type. */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /* Store the count. The Store Immediate TIR command is implied by
+ a negative command byte, and the length of the immediate data
+ is abs(command_byte). So, we write the negated length value. */
+ PUT_CHAR ((char) (-i & 0xff));
+ /* Now store the data. */
+ while (--i >= 0)
+ PUT_CHAR (*Pointer++);
+ }
+ /* Flush the buffer if it is more than 75% full. */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/* Make a data reference. */
+
+static void
+VMS_Set_Data (Psect_Index, Offset, Record_Type, Force)
+ int Psect_Index;
+ int Offset;
+ int Record_Type;
+ int Force;
+{
+ Set_VMS_Object_File_Record (Record_Type);
+ /* If the buffer is empty we must insert the record type. */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /* Stack the Psect base with its offset. */
+ vms_tir_stack_psect (Psect_Index, Offset, Force);
+ /* Set relocation base. */
+ PUT_CHAR (TIR_S_C_STO_PIDR);
+ /* Flush the buffer if it is more than 75% full. */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/* Make a debugger reference to a struct, union or enum. */
+
+static void
+VMS_Store_Struct (Struct_Index)
+ int Struct_Index;
+{
+ /* We are writing a debug record. */
+ Set_VMS_Object_File_Record (OBJ_S_C_DBG);
+ /* If the buffer is empty we must insert the record type. */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_DBG);
+ PUT_CHAR (TIR_S_C_STA_UW);
+ PUT_SHORT (Struct_Index);
+ PUT_CHAR (TIR_S_C_CTL_STKDL);
+ PUT_CHAR (TIR_S_C_STO_L);
+ /* Flush the buffer if it is more than 75% full. */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/* Make a debugger reference to partially define a struct, union or enum. */
+
+static void
+VMS_Def_Struct (Struct_Index)
+ int Struct_Index;
+{
+ /* We are writing a debug record. */
+ Set_VMS_Object_File_Record (OBJ_S_C_DBG);
+ /* If the buffer is empty we must insert the record type. */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_DBG);
+ PUT_CHAR (TIR_S_C_STA_UW);
+ PUT_SHORT (Struct_Index);
+ PUT_CHAR (TIR_S_C_CTL_DFLOC);
+ /* Flush the buffer if it is more than 75% full. */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+static void
+VMS_Set_Struct (Struct_Index)
+ int Struct_Index;
+{ /* see previous functions for comments */
+ Set_VMS_Object_File_Record (OBJ_S_C_DBG);
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_DBG);
+ PUT_CHAR (TIR_S_C_STA_UW);
+ PUT_SHORT (Struct_Index);
+ PUT_CHAR (TIR_S_C_CTL_STLOC);
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+ /****** Traceback Information routines ******/
+
+
+/* Write the Traceback Module Begin record. */
+
+static void
+VMS_TBT_Module_Begin ()
+{
+ register char *cp, *cp1;
+ int Size;
+ char Local[256];
+
+ /* Arrange to store the data locally (leave room for size byte). */
+ cp = &Local[1];
+ /* Begin module. */
+ *cp++ = DST_S_C_MODBEG;
+ *cp++ = 0; /* flags; not used */
+ /*
+ * Language type == "C"
+ *
+ * (FIXME: this should be based on the input...)
+ */
+ COPY_LONG (cp, DST_S_C_C);
+ cp += 4;
+ /* Store the module name. */
+ *cp++ = (char) strlen (Module_Name);
+ cp1 = Module_Name;
+ while (*cp1)
+ *cp++ = *cp1++;
+ /* Now we can store the record size. */
+ Size = (cp - Local);
+ Local[0] = Size - 1;
+ /* Put it into the object record. */
+ VMS_Store_Immediate_Data (Local, Size, OBJ_S_C_TBT);
+}
+
+
+/* Write the Traceback Module End record. */
+
+static void
+VMS_TBT_Module_End ()
+{
+ char Local[2];
+
+ /* End module. */
+ Local[0] = 1;
+ Local[1] = DST_S_C_MODEND;
+ /* Put it into the object record. */
+ VMS_Store_Immediate_Data (Local, 2, OBJ_S_C_TBT);
+}
+
+
+/* Write a Traceback Routine Begin record. */
+
+static void
+VMS_TBT_Routine_Begin (symbolP, Psect)
+ symbolS *symbolP;
+ int Psect;
+{
+ register char *cp, *cp1;
+ char *Name;
+ int Offset;
+ int Size;
+ char Local[512];
+
+ /* Strip the leading "_" from the name. */
+ Name = S_GET_NAME (symbolP);
+ if (*Name == '_')
+ Name++;
+ /* Get the text psect offset. */
+ Offset = S_GET_VALUE (symbolP);
+ /* Set the record size. */
+ Size = 1 + 1 + 4 + 1 + strlen (Name);
+ Local[0] = Size;
+ /* DST type "routine begin". */
+ Local[1] = DST_S_C_RTNBEG;
+ /* Uses CallS/CallG. */
+ Local[2] = 0;
+ /* Store the data so far. */
+ VMS_Store_Immediate_Data (Local, 3, OBJ_S_C_TBT);
+ /* Make sure we are still generating a OBJ_S_C_TBT record. */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_TBT);
+ /* Stack the address. */
+ vms_tir_stack_psect (Psect, Offset, 0);
+ /* Store the data reference. */
+ PUT_CHAR (TIR_S_C_STO_PIDR);
+ /* Store the counted string as data. */
+ cp = Local;
+ cp1 = Name;
+ Size = strlen (cp1) + 1;
+ *cp++ = Size - 1;
+ while (*cp1)
+ *cp++ = *cp1++;
+ VMS_Store_Immediate_Data (Local, Size, OBJ_S_C_TBT);
+}
+
+
+/* Write a Traceback Routine End record.
+
+ We *must* search the symbol table to find the next routine, since the
+ assember has a way of reassembling the symbol table OUT OF ORDER Thus
+ the next routine in the symbol list is not necessarily the next one in
+ memory. For debugging to work correctly we must know the size of the
+ routine. */
+
+static void
+VMS_TBT_Routine_End (Max_Size, sp)
+ int Max_Size;
+ symbolS *sp;
+{
+ symbolS *symbolP;
+ int Size = 0x7fffffff;
+ char Local[16];
+ valueT sym_value, sp_value = S_GET_VALUE (sp);
+
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
+ {
+ if (!S_IS_DEBUG (symbolP) && S_GET_TYPE (symbolP) == N_TEXT)
+ {
+ if (*S_GET_NAME (symbolP) == 'L')
+ continue;
+ sym_value = S_GET_VALUE (symbolP);
+ if (sym_value > sp_value && sym_value < Size)
+ Size = sym_value;
+
+ /*
+ * Dummy labels like "gcc_compiled." should no longer reach here.
+ */
+#if 0
+ else
+ /* check if gcc_compiled. has size of zero */
+ if (sym_value == sp_value &&
+ sp != symbolP &&
+ (!strcmp (S_GET_NAME (sp), "gcc_compiled.") ||
+ !strcmp (S_GET_NAME (sp), "gcc2_compiled.")))
+ Size = sym_value;
+#endif
+ }
+ }
+ if (Size == 0x7fffffff)
+ Size = Max_Size;
+ Size -= sp_value; /* and get the size of the routine */
+ /* Record Size. */
+ Local[0] = 6;
+ /* DST type is "routine end". */
+ Local[1] = DST_S_C_RTNEND;
+ Local[2] = 0; /* unused */
+ /* Size of routine. */
+ COPY_LONG (&Local[3], Size);
+ /* Store the record. */
+ VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_TBT);
+}
+
+
+/* Write a Traceback Block Begin record. */
+
+static void
+VMS_TBT_Block_Begin (symbolP, Psect, Name)
+ symbolS *symbolP;
+ int Psect;
+ char *Name;
+{
+ register char *cp, *cp1;
+ int Offset;
+ int Size;
+ char Local[512];
+
+ /* Set the record size. */
+ Size = 1 + 1 + 4 + 1 + strlen (Name);
+ Local[0] = Size;
+ /* DST type is "begin block"; we simulate with a phony routine. */
+ Local[1] = DST_S_C_BLKBEG;
+ /* Uses CallS/CallG. */
+ Local[2] = 0;
+ /* Store the data so far. */
+ VMS_Store_Immediate_Data (Local, 3, OBJ_S_C_DBG);
+ /* Make sure we are still generating a debug record. */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_DBG);
+ /* Now get the symbol address. */
+ PUT_CHAR (TIR_S_C_STA_WPL);
+ PUT_SHORT (Psect);
+ /* Get the text psect offset. */
+ Offset = S_GET_VALUE (symbolP);
+ PUT_LONG (Offset);
+ /* Store the data reference. */
+ PUT_CHAR (TIR_S_C_STO_PIDR);
+ /* Store the counted string as data. */
+ cp = Local;
+ cp1 = Name;
+ Size = strlen (cp1) + 1;
+ *cp++ = Size - 1;
+ while (*cp1)
+ *cp++ = *cp1++;
+ VMS_Store_Immediate_Data (Local, Size, OBJ_S_C_DBG);
+}
+
+
+/* Write a Traceback Block End record. */
+
+static void
+VMS_TBT_Block_End (Size)
+ valueT Size;
+{
+ char Local[16];
+
+ Local[0] = 6; /* record length */
+ /* DST type is "block end"; simulate with a phony end routine. */
+ Local[1] = DST_S_C_BLKEND;
+ Local[2] = 0; /* unused, must be zero */
+ COPY_LONG (&Local[3], Size);
+ VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_DBG);
+}
+
+
+/* Write a Line number <-> Program Counter correlation record. */
+
+static void
+VMS_TBT_Line_PC_Correlation (Line_Number, Offset, Psect, Do_Delta)
+ int Line_Number;
+ int Offset;
+ int Psect;
+ int Do_Delta;
+{
+ register char *cp;
+ char Local[64];
+
+ if (Do_Delta == 0)
+ {
+ /*
+ * If not delta, set our PC/Line number correlation.
+ */
+ cp = &Local[1]; /* Put size in Local[0] later. */
+ /* DST type is "Line Number/PC correlation". */
+ *cp++ = DST_S_C_LINE_NUM;
+ /* Set Line number. */
+ if (Line_Number - 1 <= 255)
+ {
+ *cp++ = DST_S_C_SET_LINUM_B;
+ *cp++ = (char) (Line_Number - 1);
+ }
+ else if (Line_Number - 1 <= 65535)
+ {
+ *cp++ = DST_S_C_SET_LINE_NUM;
+ COPY_SHORT (cp, Line_Number - 1), cp += 2;
+ }
+ else
+ {
+ *cp++ = DST_S_C_SET_LINUM_L;
+ COPY_LONG (cp, Line_Number - 1), cp += 4;
+ }
+ /* Set PC. */
+ *cp++ = DST_S_C_SET_ABS_PC;
+ /* Store size now that we know it, then output the data. */
+ Local[0] = cp - &Local[1];
+ /* Account for the space that TIR_S_C_STO_PIDR will use for the PC. */
+ Local[0] += 4; /* size includes length of another longword */
+ VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT);
+ /* Make sure we are still generating a OBJ_S_C_TBT record. */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_TBT);
+ vms_tir_stack_psect (Psect, Offset, 0);
+ PUT_CHAR (TIR_S_C_STO_PIDR);
+ /* Do a PC offset of 0 to register the line number. */
+ Local[0] = 2;
+ Local[1] = DST_S_C_LINE_NUM;
+ Local[2] = 0; /* Increment PC by 0 and register line # */
+ VMS_Store_Immediate_Data (Local, 3, OBJ_S_C_TBT);
+ }
+ else
+ {
+ if (Do_Delta < 0)
+ {
+ /*
+ * When delta is negative, terminate the line numbers.
+ */
+ Local[0] = 1 + 1 + 4;
+ Local[1] = DST_S_C_LINE_NUM;
+ Local[2] = DST_S_C_TERM_L;
+ COPY_LONG (&Local[3], Offset);
+ VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_TBT);
+ return;
+ }
+ /*
+ * Do a PC/Line delta.
+ */
+ cp = &Local[1];
+ *cp++ = DST_S_C_LINE_NUM;
+ if (Line_Number > 1)
+ {
+ /* We need to increment the line number. */
+ if (Line_Number - 1 <= 255)
+ {
+ *cp++ = DST_S_C_INCR_LINUM;
+ *cp++ = Line_Number - 1;
+ }
+ else if (Line_Number - 1 <= 65535)
+ {
+ *cp++ = DST_S_C_INCR_LINUM_W;
+ COPY_SHORT (cp, Line_Number - 1), cp += 2;
+ }
+ else
+ {
+ *cp++ = DST_S_C_INCR_LINUM_L;
+ COPY_LONG (cp, Line_Number - 1), cp += 4;
+ }
+ }
+ /*
+ * Increment the PC
+ */
+ if (Offset <= 128)
+ {
+ /* Small offsets are encoded as negative numbers, rather than the
+ usual non-negative type code followed by another data field. */
+ *cp++ = (char) -Offset;
+ }
+ else if (Offset <= 65535)
+ {
+ *cp++ = DST_S_C_DELTA_PC_W;
+ COPY_SHORT (cp, Offset), cp += 2;
+ }
+ else
+ {
+ *cp++ = DST_S_C_DELTA_PC_L;
+ COPY_LONG (cp, Offset), cp += 4;
+ }
+ /* Set size now that be know it, then output the data. */
+ Local[0] = cp - &Local[1];
+ VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT);
+ }
+}
+
+
+/* Describe a source file to the debugger. */
+
+static int
+VMS_TBT_Source_File (Filename, ID_Number)
+ char *Filename;
+ int ID_Number;
+{
+ register char *cp;
+ int len, rfo, ffb, ebk;
+ char cdt[8];
+ char Local[512];
+#ifdef VMS /* Used for native assembly */
+ unsigned Status;
+ struct FAB fab; /* RMS file access block */
+ struct NAM nam; /* file name information */
+ struct XABDAT xabdat; /* date+time fields */
+ struct XABFHC xabfhc; /* file header characteristics */
+ char resultant_string_buffer[255 + 1];
+
+ /*
+ * Set up RMS structures:
+ */
+ /* FAB -- file access block */
+ memset ((char *) &fab, 0, sizeof fab);
+ fab.fab$b_bid = FAB$C_BID;
+ fab.fab$b_bln = (unsigned char) sizeof fab;
+ fab.fab$l_fna = Filename;
+ fab.fab$b_fns = (unsigned char) strlen (Filename);
+ fab.fab$l_nam = (char *) &nam;
+ fab.fab$l_xab = (char *) &xabdat;
+ /* NAM -- file name block */
+ memset ((char *) &nam, 0, sizeof nam);
+ nam.nam$b_bid = NAM$C_BID;
+ nam.nam$b_bln = (unsigned char) sizeof nam;
+ nam.nam$l_rsa = resultant_string_buffer;
+ nam.nam$b_rss = (unsigned char) (sizeof resultant_string_buffer - 1);
+ /* XABs -- extended attributes blocks */
+ memset ((char *) &xabdat, 0, sizeof xabdat);
+ xabdat.xab$b_cod = XAB$C_DAT;
+ xabdat.xab$b_bln = (unsigned char) sizeof xabdat;
+ xabdat.xab$l_nxt = (char *) &xabfhc;
+ memset ((char *) &xabfhc, 0, sizeof xabfhc);
+ xabfhc.xab$b_cod = XAB$C_FHC;
+ xabfhc.xab$b_bln = (unsigned char) sizeof xabfhc;
+ xabfhc.xab$l_nxt = 0;
+ /*
+ * Get the file information
+ */
+ Status = sys$open (&fab);
+ if (!(Status & 1))
+ {
+ as_tsktsk (_("Couldn't find source file \"%s\", status=%%X%x"),
+ Filename, Status);
+ return 0;
+ }
+ sys$close (&fab);
+ /* Now extract fields of interest. */
+ memcpy (cdt, (char *) &xabdat.xab$q_cdt, 8); /* creation date */
+ ebk = xabfhc.xab$l_ebk; /* end-of-file block */
+ ffb = xabfhc.xab$w_ffb; /* first free byte of last block */
+ rfo = xabfhc.xab$b_rfo; /* record format */
+ len = nam.nam$b_rsl; /* length of Filename */
+ resultant_string_buffer[len] = '\0';
+ Filename = resultant_string_buffer; /* full filename */
+#else /* Cross-assembly */
+ /* [Perhaps we ought to use actual values derived from stat() here?] */
+ memset (cdt, 0, 8); /* null VMS quadword binary time */
+ ebk = ffb = rfo = 0;
+ len = strlen (Filename);
+ if (len > 255) /* a single byte is used as count prefix */
+ {
+ Filename += (len - 255); /* tail end is more significant */
+ len = 255;
+ }
+#endif /* VMS */
+
+ cp = &Local[1]; /* fill in record length later */
+ *cp++ = DST_S_C_SOURCE; /* DST type is "source file" */
+ *cp++ = DST_S_C_SRC_FORMFEED; /* formfeeds count as source records */
+ *cp++ = DST_S_C_SRC_DECLFILE; /* declare source file */
+ know (cp == &Local[4]);
+ *cp++ = 0; /* fill in this length below */
+ *cp++ = 0; /* flags; must be zero */
+ COPY_SHORT (cp, ID_Number), cp += 2; /* file ID number */
+ memcpy (cp, cdt, 8), cp += 8; /* creation date+time */
+ COPY_LONG (cp, ebk), cp += 4; /* end-of-file block */
+ COPY_SHORT (cp, ffb), cp += 2; /* first free byte of last block */
+ *cp++ = (char) rfo; /* RMS record format */
+ /* Filename. */
+ *cp++ = (char) len;
+ while (--len >= 0)
+ *cp++ = *Filename++;
+ /* Library module name (none). */
+ *cp++ = 0;
+ /* Now that size is known, fill it in and write out the record. */
+ Local[4] = cp - &Local[5]; /* source file declaration size */
+ Local[0] = cp - &Local[1]; /* TBT record size */
+ VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT);
+ return 1;
+}
+
+
+/* Traceback information is described in terms of lines from compiler
+ listing files, not lines from source files. We need to set up the
+ correlation between listing line numbers and source line numbers.
+ Since gcc's .stabn directives refer to the source lines, we just
+ need to describe a one-to-one correspondence. */
+
+static void
+VMS_TBT_Source_Lines (ID_Number, Starting_Line_Number, Number_Of_Lines)
+ int ID_Number;
+ int Starting_Line_Number;
+ int Number_Of_Lines;
+{
+ char *cp;
+ int chunk_limit;
+ char Local[128]; /* room enough to describe 1310700 lines... */
+
+ cp = &Local[1]; /* Put size in Local[0] later. */
+ *cp++ = DST_S_C_SOURCE; /* DST type is "source file". */
+ *cp++ = DST_S_C_SRC_SETFILE; /* Set Source File. */
+ COPY_SHORT (cp, ID_Number), cp += 2; /* File ID Number. */
+ /* Set record number and define lines. Since no longword form of
+ SRC_DEFLINES is available, we need to be able to cope with any huge
+ files a chunk at a time. It doesn't matter for tracebacks, since
+ unspecified lines are mapped one-to-one and work out right, but it
+ does matter within the debugger. Without this explicit mapping,
+ it will complain about lines not existing in the module. */
+ chunk_limit = (sizeof Local - 5) / 6;
+ if (Number_Of_Lines > 65535 * chunk_limit) /* avoid buffer overflow */
+ Number_Of_Lines = 65535 * chunk_limit;
+ while (Number_Of_Lines > 65535)
+ {
+ *cp++ = DST_S_C_SRC_SETREC_L;
+ COPY_LONG (cp, Starting_Line_Number), cp += 4;
+ *cp++ = DST_S_C_SRC_DEFLINES_W;
+ COPY_SHORT (cp, 65535), cp += 2;
+ Starting_Line_Number += 65535;
+ Number_Of_Lines -= 65535;
+ }
+ /* Set record number and define lines, normal case. */
+ if (Starting_Line_Number <= 65535)
+ {
+ *cp++ = DST_S_C_SRC_SETREC_W;
+ COPY_SHORT (cp, Starting_Line_Number), cp += 2;
+ }
+ else
+ {
+ *cp++ = DST_S_C_SRC_SETREC_L;
+ COPY_LONG (cp, Starting_Line_Number), cp += 4;
+ }
+ *cp++ = DST_S_C_SRC_DEFLINES_W;
+ COPY_SHORT (cp, Number_Of_Lines), cp += 2;
+ /* Set size now that be know it, then output the data. */
+ Local[0] = cp - &Local[1];
+ VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT);
+}
+
+
+ /****** Debugger Information support routines ******/
+
+
+/* This routine locates a file in the list of files. If an entry does
+ not exist, one is created. For include files, a new entry is always
+ created such that inline functions can be properly debugged. */
+
+static struct input_file *
+find_file (sp)
+ symbolS *sp;
+{
+ struct input_file *same_file = 0;
+ struct input_file *fpnt, *last = 0;
+ char *sp_name;
+
+ for (fpnt = file_root; fpnt; fpnt = fpnt->next)
+ {
+ if (fpnt->spnt == sp)
+ return fpnt;
+ last = fpnt;
+ }
+ sp_name = S_GET_NAME (sp);
+ for (fpnt = file_root; fpnt; fpnt = fpnt->next)
+ {
+ if (strcmp (sp_name, fpnt->name) == 0)
+ {
+ if (fpnt->flag == 1)
+ return fpnt;
+ same_file = fpnt;
+ break;
+ }
+ }
+ fpnt = (struct input_file *) xmalloc (sizeof (struct input_file));
+ if (!file_root)
+ file_root = fpnt;
+ else
+ last->next = fpnt;
+ fpnt->next = 0;
+ fpnt->name = sp_name;
+ fpnt->min_line = 0x7fffffff;
+ fpnt->max_line = 0;
+ fpnt->offset = 0;
+ fpnt->flag = 0;
+ fpnt->file_number = 0;
+ fpnt->spnt = sp;
+ fpnt->same_file_fpnt = same_file;
+ return fpnt;
+}
+
+
+/* This routine converts a number string into an integer, and stops when
+ it sees an invalid character. The return value is the address of the
+ character just past the last character read. No error is generated. */
+
+static char *
+cvt_integer (str, rtn)
+ char *str;
+ int *rtn;
+{
+ int ival = 0, sgn = 1;
+
+ if (*str == '-')
+ sgn = -1, ++str;
+ while (*str >= '0' && *str <= '9')
+ ival = 10 * ival + *str++ - '0';
+ *rtn = sgn * ival;
+ return str;
+}
+
+
+/*
+ * The following functions and definitions are used to generate object
+ * records that will describe program variables to the VMS debugger.
+ *
+ * This file contains many of the routines needed to output debugging info
+ * into the object file that the VMS debugger needs to understand symbols.
+ * These routines are called very late in the assembly process, and thus
+ * we can be fairly lax about changing things, since the GSD and the TIR
+ * sections have already been output.
+ */
+
+
+/* This routine fixes the names that are generated by C++, ".this" is a good
+ example. The period does not work for the debugger, since it looks like
+ the syntax for a structure element, and thus it gets mightily confused.
+
+ We also use this to strip the PsectAttribute hack from the name before we
+ write a debugger record. */
+
+static char *
+fix_name (pnt)
+ char *pnt;
+{
+ char *pnt1;
+
+ /* Kill any leading "_". */
+ if (*pnt == '_')
+ pnt++;
+
+ /* Is there a Psect Attribute to skip?? */
+ if (HAS_PSECT_ATTRIBUTES (pnt))
+ {
+ /* Yes: Skip it. */
+ pnt += PSECT_ATTRIBUTES_STRING_LENGTH;
+ while (*pnt)
+ {
+ if ((pnt[0] == '$') && (pnt[1] == '$'))
+ {
+ pnt += 2;
+ break;
+ }
+ pnt++;
+ }
+ }
+
+ /* Here we fix the .this -> $this conversion. */
+ for (pnt1 = pnt; *pnt1 != 0; pnt1++)
+ if (*pnt1 == '.')
+ *pnt1 = '$';
+
+ return pnt;
+}
+
+
+/* When defining a structure, this routine is called to find the name of
+ the actual structure. It is assumed that str points to the equal sign
+ in the definition, and it moves backward until it finds the start of the
+ name. If it finds a 0, then it knows that this structure def is in the
+ outermost level, and thus symbol_name points to the symbol name. */
+
+static char *
+get_struct_name (str)
+ char *str;
+{
+ char *pnt;
+ pnt = str;
+ while ((*pnt != ':') && (*pnt != '\0'))
+ pnt--;
+ if (*pnt == '\0')
+ return (char *) symbol_name;
+ *pnt-- = '\0';
+ while ((*pnt != ';') && (*pnt != '='))
+ pnt--;
+ if (*pnt == ';')
+ return pnt + 1;
+ while ((*pnt < '0') || (*pnt > '9'))
+ pnt++;
+ while ((*pnt >= '0') && (*pnt <= '9'))
+ pnt++;
+ return pnt;
+}
+
+
+/* Search symbol list for type number dbx_type.
+ Return a pointer to struct. */
+
+static struct VMS_DBG_Symbol *
+find_symbol (dbx_type)
+ int dbx_type;
+{
+ struct VMS_DBG_Symbol *spnt;
+
+ spnt = VMS_Symbol_type_list[SYMTYP_HASH (dbx_type)];
+ while (spnt)
+ {
+ if (spnt->dbx_type == dbx_type)
+ break;
+ spnt = spnt->next;
+ }
+ if (!spnt || spnt->advanced != ALIAS)
+ return spnt;
+ return find_symbol (spnt->type2);
+}
+
+
+#if 0 /* obsolete */
+/* this routine puts info into either Local or Asuffix, depending on the sign
+ * of size. The reason is that it is easier to build the variable descriptor
+ * backwards, while the array descriptor is best built forwards. In the end
+ * they get put together, if there is not a struct/union/enum along the way
+ */
+static void
+push (value, size1)
+ int value, size1;
+{
+ if (size1 < 0)
+ {
+ size1 = -size1;
+ if (Lpnt < size1)
+ {
+ overflow = 1;
+ Lpnt = 1;
+ return;
+ }
+ Lpnt -= size1;
+ md_number_to_chars (&Local[Lpnt + 1], value, size1);
+ }
+ else
+ {
+ if (Apoint + size1 >= MAX_DEBUG_RECORD)
+ {
+ overflow = 1;
+ Apoint = MAX_DEBUG_RECORD - 1;
+ return;
+ }
+ md_number_to_chars (&Asuffix[Apoint], value, size1);
+ Apoint += size1;
+ }
+}
+#endif
+
+
+static void
+fpush (value, size)
+ int value, size;
+{
+ if (Apoint + size >= MAX_DEBUG_RECORD)
+ {
+ overflow = 1;
+ Apoint = MAX_DEBUG_RECORD - 1;
+ return;
+ }
+ if (size == 1)
+ Asuffix[Apoint++] = (char) value;
+ else
+ {
+ md_number_to_chars (&Asuffix[Apoint], value, size);
+ Apoint += size;
+ }
+}
+
+static void
+rpush (value, size)
+ int value, size;
+{
+ if (Lpnt < size)
+ {
+ overflow = 1;
+ Lpnt = 1;
+ return;
+ }
+ if (size == 1)
+ Local[Lpnt--] = (char) value;
+ else
+ {
+ Lpnt -= size;
+ md_number_to_chars (&Local[Lpnt + 1], value, size);
+ }
+}
+
+
+/* This routine generates the array descriptor for a given array. */
+
+static void
+array_suffix (spnt2)
+ struct VMS_DBG_Symbol *spnt2;
+{
+ struct VMS_DBG_Symbol *spnt;
+ struct VMS_DBG_Symbol *spnt1;
+ int rank;
+ int total_size;
+
+ rank = 0;
+ spnt = spnt2;
+ while (spnt->advanced != ARRAY)
+ {
+ spnt = find_symbol (spnt->type2);
+ if (!spnt)
+ return;
+ }
+ spnt1 = spnt;
+ total_size = 1;
+ while (spnt1->advanced == ARRAY)
+ {
+ rank++;
+ total_size *= (spnt1->index_max - spnt1->index_min + 1);
+ spnt1 = find_symbol (spnt1->type2);
+ }
+ total_size = total_size * spnt1->data_size;
+ fpush (spnt1->data_size, 2); /* element size */
+ if (spnt1->VMS_type == DBG_S_C_ADVANCED_TYPE)
+ fpush (0, 1);
+ else
+ fpush (spnt1->VMS_type, 1); /* element type */
+ fpush (DSC_K_CLASS_A, 1); /* descriptor class */
+ fpush (0, 4); /* base address */
+ fpush (0, 1); /* scale factor -- not applicable */
+ fpush (0, 1); /* digit count -- not applicable */
+ fpush (0xc0, 1); /* flags: multiplier block & bounds present */
+ fpush (rank, 1); /* number of dimensions */
+ fpush (total_size, 4);
+ fpush (0, 4); /* pointer to element [0][0]...[0] */
+ spnt1 = spnt;
+ while (spnt1->advanced == ARRAY)
+ {
+ fpush (spnt1->index_max - spnt1->index_min + 1, 4);
+ spnt1 = find_symbol (spnt1->type2);
+ }
+ spnt1 = spnt;
+ while (spnt1->advanced == ARRAY)
+ {
+ fpush (spnt1->index_min, 4);
+ fpush (spnt1->index_max, 4);
+ spnt1 = find_symbol (spnt1->type2);
+ }
+}
+
+
+/* This routine generates the start of a variable descriptor based upon
+ a struct/union/enum that has yet to be defined. We define this spot as
+ a new location, and save four bytes for the address. When the struct is
+ finally defined, then we can go back and plug in the correct address. */
+
+static void
+new_forward_ref (dbx_type)
+ int dbx_type;
+{
+ struct forward_ref *fpnt;
+ fpnt = (struct forward_ref *) xmalloc (sizeof (struct forward_ref));
+ fpnt->next = f_ref_root;
+ f_ref_root = fpnt;
+ fpnt->dbx_type = dbx_type;
+ fpnt->struc_numb = ++structure_count;
+ fpnt->resolved = 'N';
+ rpush (DST_K_TS_IND, 1); /* indirect type specification */
+ total_len = 5;
+ rpush (total_len, 2);
+ struct_number = -fpnt->struc_numb;
+}
+
+
+/* This routine generates the variable descriptor used to describe non-basic
+ variables. It calls itself recursively until it gets to the bottom of it
+ all, and then builds the descriptor backwards. It is easiest to do it
+ this way since we must periodically write length bytes, and it is easiest
+ if we know the value when it is time to write it. */
+
+static int
+gen1 (spnt, array_suffix_len)
+ struct VMS_DBG_Symbol *spnt;
+ int array_suffix_len;
+{
+ struct VMS_DBG_Symbol *spnt1;
+ int i;
+
+ switch (spnt->advanced)
+ {
+ case VOID:
+ rpush (DBG_S_C_VOID, 1);
+ total_len += 1;
+ rpush (total_len, 2);
+ return 0;
+ case BASIC:
+ case FUNCTION:
+ if (array_suffix_len == 0)
+ {
+ rpush (spnt->VMS_type, 1);
+ rpush (DBG_S_C_BASIC, 1);
+ total_len = 2;
+ rpush (total_len, 2);
+ return 1;
+ }
+ rpush (0, 4);
+ rpush (DST_K_VFLAGS_DSC, 1);
+ rpush (DST_K_TS_DSC, 1); /* descriptor type specification */
+ total_len = -2;
+ return 1;
+ case STRUCT:
+ case UNION:
+ case ENUM:
+ struct_number = spnt->struc_numb;
+ if (struct_number < 0)
+ {
+ new_forward_ref (spnt->dbx_type);
+ return 1;
+ }
+ rpush (DBG_S_C_STRUCT, 1);
+ total_len = 5;
+ rpush (total_len, 2);
+ return 1;
+ case POINTER:
+ spnt1 = find_symbol (spnt->type2);
+ i = 1;
+ if (!spnt1)
+ new_forward_ref (spnt->type2);
+ else
+ i = gen1 (spnt1, 0);
+ if (i)
+ { /* (*void) is a special case, do not put pointer suffix */
+ rpush (DBG_S_C_POINTER, 1);
+ total_len += 3;
+ rpush (total_len, 2);
+ }
+ return 1;
+ case ARRAY:
+ spnt1 = spnt;
+ while (spnt1->advanced == ARRAY)
+ {
+ spnt1 = find_symbol (spnt1->type2);
+ if (!spnt1)
+ {
+ as_tsktsk (_("debugger forward reference error, dbx type %d"),
+ spnt->type2);
+ return 0;
+ }
+ }
+/* It is too late to generate forward references, so the user gets a message.
+ * This should only happen on a compiler error */
+ (void) gen1 (spnt1, 1);
+ i = Apoint;
+ array_suffix (spnt);
+ array_suffix_len = Apoint - i;
+ switch (spnt1->advanced)
+ {
+ case BASIC:
+ case FUNCTION:
+ break;
+ default:
+ rpush (0, 2);
+ total_len += 2;
+ rpush (total_len, 2);
+ rpush (DST_K_VFLAGS_DSC, 1);
+ rpush (1, 1); /* flags: element value spec included */
+ rpush (1, 1); /* one dimension */
+ rpush (DBG_S_C_COMPLEX_ARRAY, 1);
+ }
+ total_len += array_suffix_len + 8;
+ rpush (total_len, 2);
+ break;
+ default: /* lint suppression */
+ break;
+ }
+ return 0;
+}
+
+
+/* This generates a suffix for a variable. If it is not a defined type yet,
+ then dbx_type contains the type we are expecting so we can generate a
+ forward reference. This calls gen1 to build most of the descriptor, and
+ then it puts the icing on at the end. It then dumps whatever is needed
+ to get a complete descriptor (i.e. struct reference, array suffix). */
+
+static void
+generate_suffix (spnt, dbx_type)
+ struct VMS_DBG_Symbol *spnt;
+ int dbx_type;
+{
+ static const char pvoid[6] = {
+ 5, /* record.length == 5 */
+ DST_K_TYPSPEC, /* record.type == 1 (type specification) */
+ 0, /* name.length == 0, no name follows */
+ 1, 0, /* type.length == 1 {2 bytes, little endian} */
+ DBG_S_C_VOID /* type.type == 5 (pointer to unspecified) */
+ };
+ int i;
+
+ Apoint = 0;
+ Lpnt = MAX_DEBUG_RECORD - 1;
+ total_len = 0;
+ struct_number = 0;
+ overflow = 0;
+ if (!spnt)
+ new_forward_ref (dbx_type);
+ else
+ {
+ if (spnt->VMS_type != DBG_S_C_ADVANCED_TYPE)
+ return; /* no suffix needed */
+ gen1 (spnt, 0);
+ }
+ rpush (0, 1); /* no name (len==0) */
+ rpush (DST_K_TYPSPEC, 1);
+ total_len += 4;
+ rpush (total_len, 1);
+ /* If the variable descriptor overflows the record, output a descriptor
+ for a pointer to void. */
+ if ((total_len >= MAX_DEBUG_RECORD) || overflow)
+ {
+ as_warn (_("Variable descriptor %d too complicated. Defined as `void *'."),
+ spnt->dbx_type);
+ VMS_Store_Immediate_Data (pvoid, 6, OBJ_S_C_DBG);
+ return;
+ }
+ i = 0;
+ while (Lpnt < MAX_DEBUG_RECORD - 1)
+ Local[i++] = Local[++Lpnt];
+ Lpnt = i;
+ /* we use this for reference to structure that has already been defined */
+ if (struct_number > 0)
+ {
+ VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG);
+ Lpnt = 0;
+ VMS_Store_Struct (struct_number);
+ }
+ /* We use this for a forward reference to a structure that has yet to
+ be defined. We store four bytes of zero to make room for the actual
+ address once it is known. */
+ if (struct_number < 0)
+ {
+ struct_number = -struct_number;
+ VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG);
+ Lpnt = 0;
+ VMS_Def_Struct (struct_number);
+ COPY_LONG (&Local[Lpnt], 0L);
+ Lpnt += 4;
+ VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG);
+ Lpnt = 0;
+ }
+ i = 0;
+ while (i < Apoint)
+ Local[Lpnt++] = Asuffix[i++];
+ if (Lpnt != 0)
+ VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG);
+ Lpnt = 0;
+}
+
+
+ /* "novel length" type doesn't work for simple atomic types */
+#define USE_BITSTRING_DESCRIPTOR(t) ((t)->advanced == BASIC)
+#undef SETUP_BASIC_TYPES
+
+/* This routine generates a type description for a bitfield. */
+
+static void
+bitfield_suffix (spnt, width)
+ struct VMS_DBG_Symbol *spnt;
+ int width;
+{
+ Local[Lpnt++] = 13; /* rec.len==13 */
+ Local[Lpnt++] = DST_K_TYPSPEC; /* a type specification record */
+ Local[Lpnt++] = 0; /* not named */
+ COPY_SHORT (&Local[Lpnt], 9); /* typ.len==9 */
+ Lpnt += 2;
+ Local[Lpnt++] = DST_K_TS_NOV_LENG; /* This type is a "novel length"
+ incarnation of some other type. */
+ COPY_LONG (&Local[Lpnt], width); /* size in bits == novel length */
+ Lpnt += 4;
+ VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG);
+ Lpnt = 0;
+ /* assert( spnt->struc_numb > 0 ); */
+ VMS_Store_Struct (spnt->struc_numb); /* output 4 more bytes */
+}
+
+
+/* Formally define a builtin type, so that it can serve as the target of
+ an indirect reference. It makes bitfield_suffix() easier by avoiding
+ the need to use a forward reference for the first occurrence of each
+ type used in a bitfield. */
+
+static void
+setup_basic_type (spnt)
+ struct VMS_DBG_Symbol *spnt;
+{
+#ifdef SETUP_BASIC_TYPES
+ /* This would be very useful if "novel length" fields actually worked
+ with basic types like they do with enumerated types. However,
+ they do not, so this isn't worth doing just so that you can use
+ EXAMINE/TYPE=(__long_long_int) instead of EXAMINE/QUAD. */
+ char *p;
+#ifndef SETUP_SYNONYM_TYPES
+ /* This determines whether compatible things like `int' and `long int'
+ ought to have distinct type records rather than sharing one. */
+ struct VMS_DBG_Symbol *spnt2;
+
+ /* first check whether this type has already been seen by another name */
+ for (spnt2 = VMS_Symbol_type_list[SYMTYP_HASH (spnt->VMS_type)];
+ spnt2;
+ spnt2 = spnt2->next)
+ if (spnt2 != spnt && spnt2->VMS_type == spnt->VMS_type)
+ {
+ spnt->struc_numb = spnt2->struc_numb;
+ return;
+ }
+#endif
+
+ /* `structure number' doesn't really mean `structure'; it means an index
+ into a linker maintained set of saved locations which can be referenced
+ again later. */
+ spnt->struc_numb = ++structure_count;
+ VMS_Def_Struct (spnt->struc_numb); /* remember where this type lives */
+ /* define the simple scalar type */
+ Local[Lpnt++] = 6 + strlen (symbol_name) + 2; /* rec.len */
+ Local[Lpnt++] = DST_K_TYPSPEC; /* rec.typ==type specification */
+ Local[Lpnt++] = strlen (symbol_name) + 2;
+ Local[Lpnt++] = '_'; /* prefix name with "__" */
+ Local[Lpnt++] = '_';
+ for (p = symbol_name; *p; p++)
+ Local[Lpnt++] = *p == ' ' ? '_' : *p;
+ COPY_SHORT (&Local[Lpnt], 2); /* typ.len==2 */
+ Lpnt += 2;
+ Local[Lpnt++] = DST_K_TS_ATOM; /* typ.kind is simple type */
+ Local[Lpnt++] = spnt->VMS_type; /* typ.type */
+ VMS_Store_Immediate_Data (Local, Lpnt, OBJ_S_C_DBG);
+ Lpnt = 0;
+#endif /* SETUP_BASIC_TYPES */
+ return;
+}
+
+
+/* This routine generates a symbol definition for a C symbol for the debugger.
+ It takes a psect and offset for global symbols; if psect < 0, then this is
+ a local variable and the offset is relative to FP. In this case it can
+ be either a variable (Offset < 0) or a parameter (Offset > 0). */
+
+static void
+VMS_DBG_record (spnt, Psect, Offset, Name)
+ struct VMS_DBG_Symbol *spnt;
+ int Psect;
+ int Offset;
+ char *Name;
+{
+ char *Name_pnt;
+ int len;
+ int i = 0;
+
+ /* if there are bad characters in name, convert them */
+ Name_pnt = fix_name (Name);
+
+ len = strlen (Name_pnt);
+ if (Psect < 0)
+ { /* this is a local variable, referenced to SP */
+ Local[i++] = 7 + len;
+ Local[i++] = spnt->VMS_type;
+ Local[i++] = (Offset > 0) ? DBG_C_FUNCTION_PARAM : DBG_C_LOCAL_SYM;
+ COPY_LONG (&Local[i], Offset);
+ i += 4;
+ }
+ else
+ {
+ Local[i++] = 7 + len;
+ Local[i++] = spnt->VMS_type;
+ Local[i++] = DST_K_VALKIND_ADDR;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ VMS_Set_Data (Psect, Offset, OBJ_S_C_DBG, 0);
+ }
+ Local[i++] = len;
+ while (*Name_pnt != '\0')
+ Local[i++] = *Name_pnt++;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ if (spnt->VMS_type == DBG_S_C_ADVANCED_TYPE)
+ generate_suffix (spnt, 0);
+}
+
+
+/* This routine parses the stabs entries in order to make the definition
+ for the debugger of local symbols and function parameters. */
+
+static void
+VMS_local_stab_Parse (sp)
+ symbolS *sp;
+{
+ struct VMS_DBG_Symbol *spnt;
+ char *pnt;
+ char *pnt1;
+ char *str;
+ int dbx_type;
+
+ dbx_type = 0;
+ str = S_GET_NAME (sp);
+ pnt = (char *) strchr (str, ':');
+ if (!pnt)
+ return; /* no colon present */
+ pnt1 = pnt++; /* save this for later, and skip colon */
+ if (*pnt == 'c')
+ return; /* ignore static constants */
+
+/* there is one little catch that we must be aware of. Sometimes function
+ * parameters are optimized into registers, and the compiler, in its infiite
+ * wisdom outputs stabs records for *both*. In general we want to use the
+ * register if it is present, so we must search the rest of the symbols for
+ * this function to see if this parameter is assigned to a register.
+ */
+ {
+ symbolS *sp1;
+ char *str1;
+ char *pnt2;
+
+ if (*pnt == 'p')
+ {
+ for (sp1 = symbol_next (sp); sp1; sp1 = symbol_next (sp1))
+ {
+ if (!S_IS_DEBUG (sp1))
+ continue;
+ if (S_GET_RAW_TYPE (sp1) == N_FUN)
+ {
+ pnt2 = (char *) strchr (S_GET_NAME (sp1), ':') + 1;
+ if (*pnt2 == 'F' || *pnt2 == 'f')
+ break;
+ }
+ if (S_GET_RAW_TYPE (sp1) != N_RSYM)
+ continue;
+ str1 = S_GET_NAME (sp1); /* and get the name */
+ pnt2 = str;
+ while (*pnt2 != ':')
+ {
+ if (*pnt2 != *str1)
+ break;
+ pnt2++;
+ str1++;
+ }
+ if (*str1 == ':' && *pnt2 == ':')
+ return; /* they are the same! lets skip this one */
+ } /* for */
+ pnt++; /* skip p in case no register */
+ } /* if */
+ } /* p block */
+
+ pnt = cvt_integer (pnt, &dbx_type);
+ spnt = find_symbol (dbx_type);
+ if (!spnt)
+ return; /*Dunno what this is*/
+ *pnt1 = '\0';
+ VMS_DBG_record (spnt, -1, S_GET_VALUE (sp), str);
+ *pnt1 = ':'; /* and restore the string */
+ return;
+}
+
+
+/* This routine parses a stabs entry to find the information required
+ to define a variable. It is used for global and static variables.
+ Basically we need to know the address of the symbol. With older
+ versions of the compiler, const symbols are treated differently, in
+ that if they are global they are written into the text psect. The
+ global symbol entry for such a const is actually written as a program
+ entry point (Yuk!!), so if we cannot find a symbol in the list of
+ psects, we must search the entry points as well. static consts are
+ even harder, since they are never assigned a memory address. The
+ compiler passes a stab to tell us the value, but I am not sure what
+ to do with it. */
+
+static void
+VMS_stab_parse (sp, expected_type, type1, type2, Text_Psect)
+ symbolS *sp;
+ int expected_type; /* char */
+ int type1, type2, Text_Psect;
+{
+ char *pnt;
+ char *pnt1;
+ char *str;
+ symbolS *sp1;
+ struct VMS_DBG_Symbol *spnt;
+ struct VMS_Symbol *vsp;
+ int dbx_type;
+
+ dbx_type = 0;
+ str = S_GET_NAME (sp);
+ pnt = (char *) strchr (str, ':');
+ if (!pnt)
+ return; /* no colon present */
+ pnt1 = pnt; /* save this for later*/
+ pnt++;
+ if (*pnt == expected_type)
+ {
+ pnt = cvt_integer (pnt + 1, &dbx_type);
+ spnt = find_symbol (dbx_type);
+ if (!spnt)
+ return; /*Dunno what this is*/
+ /*
+ * Now we need to search the symbol table to find the psect and
+ * offset for this variable.
+ */
+ *pnt1 = '\0';
+ vsp = VMS_Symbols;
+ while (vsp)
+ {
+ pnt = S_GET_NAME (vsp->Symbol);
+ if (pnt && *pnt++ == '_'
+ /* make sure name is the same and symbol type matches */
+ && strcmp (pnt, str) == 0
+ && (S_GET_RAW_TYPE (vsp->Symbol) == type1
+ || S_GET_RAW_TYPE (vsp->Symbol) == type2))
+ break;
+ vsp = vsp->Next;
+ }
+ if (vsp)
+ {
+ VMS_DBG_record (spnt, vsp->Psect_Index, vsp->Psect_Offset, str);
+ *pnt1 = ':'; /* and restore the string */
+ return;
+ }
+ /* The symbol was not in the symbol list, but it may be an
+ "entry point" if it was a constant. */
+ for (sp1 = symbol_rootP; sp1; sp1 = symbol_next (sp1))
+ {
+ /*
+ * Dispatch on STAB type
+ */
+ if (S_IS_DEBUG (sp1) || (S_GET_TYPE (sp1) != N_TEXT))
+ continue;
+ pnt = S_GET_NAME (sp1);
+ if (*pnt == '_')
+ pnt++;
+ if (strcmp (pnt, str) == 0)
+ {
+ if (!gave_compiler_message && expected_type == 'G')
+ {
+ char *long_const_msg = _("\
+***Warning - the assembly code generated by the compiler has placed \n\
+ global constant(s) in the text psect. These will not be available to \n\
+ other modules, since this is not the correct way to handle this. You \n\
+ have two options: 1) get a patched compiler that does not put global \n\
+ constants in the text psect, or 2) remove the 'const' keyword from \n\
+ definitions of global variables in your source module(s). Don't say \n\
+ I didn't warn you! \n");
+
+ as_tsktsk (long_const_msg);
+ gave_compiler_message = 1;
+ }
+ VMS_DBG_record (spnt,
+ Text_Psect,
+ S_GET_VALUE (sp1),
+ str);
+ *pnt1 = ':';
+ /* fool assembler to not output this as a routine in the TBT */
+ pnt1 = S_GET_NAME (sp1);
+ *pnt1 = 'L';
+ S_SET_NAME (sp1, pnt1);
+ return;
+ }
+ }
+ }
+ *pnt1 = ':'; /* and restore the string */
+ return;
+}
+
+
+/* Simpler interfaces into VMS_stab_parse(). */
+
+static void
+VMS_GSYM_Parse (sp, Text_Psect)
+ symbolS *sp;
+ int Text_Psect;
+{ /* Global variables */
+ VMS_stab_parse (sp, 'G', (N_UNDF | N_EXT), (N_DATA | N_EXT), Text_Psect);
+}
+
+static void
+VMS_LCSYM_Parse (sp, Text_Psect)
+ symbolS *sp;
+ int Text_Psect;
+{ /* Static symbols - uninitialized */
+ VMS_stab_parse (sp, 'S', N_BSS, -1, Text_Psect);
+}
+
+static void
+VMS_STSYM_Parse (sp, Text_Psect)
+ symbolS *sp;
+ int Text_Psect;
+{ /* Static symbols - initialized */
+ VMS_stab_parse (sp, 'S', N_DATA, -1, Text_Psect);
+}
+
+
+/* For register symbols, we must figure out what range of addresses
+ within the psect are valid. We will use the brackets in the stab
+ directives to give us guidance as to the PC range that this variable
+ is in scope. I am still not completely comfortable with this but
+ as I learn more, I seem to get a better handle on what is going on.
+ Caveat Emptor. */
+
+static void
+VMS_RSYM_Parse (sp, Current_Routine, Text_Psect)
+ symbolS *sp, *Current_Routine;
+ int Text_Psect;
+{
+ symbolS *symbolP;
+ struct VMS_DBG_Symbol *spnt;
+ char *pnt;
+ char *pnt1;
+ char *str;
+ int dbx_type;
+ int len;
+ int i = 0;
+ int bcnt = 0;
+ int Min_Offset = -1; /* min PC of validity */
+ int Max_Offset = 0; /* max PC of validity */
+
+ for (symbolP = sp; symbolP; symbolP = symbol_next (symbolP))
+ {
+ /*
+ * Dispatch on STAB type
+ */
+ switch (S_GET_RAW_TYPE (symbolP))
+ {
+ case N_LBRAC:
+ if (bcnt++ == 0)
+ Min_Offset = S_GET_VALUE (symbolP);
+ break;
+ case N_RBRAC:
+ if (--bcnt == 0)
+ Max_Offset = S_GET_VALUE (symbolP) - 1;
+ break;
+ }
+ if ((Min_Offset != -1) && (bcnt == 0))
+ break;
+ if (S_GET_RAW_TYPE (symbolP) == N_FUN)
+ {
+ pnt = (char *) strchr (S_GET_NAME (symbolP), ':') + 1;
+ if (*pnt == 'F' || *pnt == 'f') break;
+ }
+ }
+
+ /* Check to see that the addresses were defined. If not, then there
+ were no brackets in the function, and we must try to search for
+ the next function. Since functions can be in any order, we should
+ search all of the symbol list to find the correct ending address. */
+ if (Min_Offset == -1)
+ {
+ int Max_Source_Offset;
+ int This_Offset;
+
+ Min_Offset = S_GET_VALUE (sp);
+ Max_Source_Offset = Min_Offset; /* just in case no N_SLINEs found */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
+ switch (S_GET_RAW_TYPE (symbolP))
+ {
+ case N_TEXT | N_EXT:
+ This_Offset = S_GET_VALUE (symbolP);
+ if (This_Offset > Min_Offset && This_Offset < Max_Offset)
+ Max_Offset = This_Offset;
+ break;
+ case N_SLINE:
+ This_Offset = S_GET_VALUE (symbolP);
+ if (This_Offset > Max_Source_Offset)
+ Max_Source_Offset = This_Offset;
+ break;
+ }
+ /* If this is the last routine, then we use the PC of the last source
+ line as a marker of the max PC for which this reg is valid. */
+ if (Max_Offset == 0x7fffffff)
+ Max_Offset = Max_Source_Offset;
+ }
+
+ dbx_type = 0;
+ str = S_GET_NAME (sp);
+ if ((pnt = (char *) strchr (str, ':')) == 0)
+ return; /* no colon present */
+ pnt1 = pnt; /* save this for later*/
+ pnt++;
+ if (*pnt != 'r')
+ return;
+ pnt = cvt_integer (pnt + 1, &dbx_type);
+ spnt = find_symbol (dbx_type);
+ if (!spnt)
+ return; /*Dunno what this is yet*/
+ *pnt1 = '\0';
+ pnt = fix_name (S_GET_NAME (sp)); /* if there are bad characters in name, convert them */
+ len = strlen (pnt);
+ Local[i++] = 25 + len;
+ Local[i++] = spnt->VMS_type;
+ Local[i++] = DST_K_VFLAGS_TVS; /* trailing value specified */
+ COPY_LONG (&Local[i], 1 + len); /* relative offset, beyond name */
+ i += 4;
+ Local[i++] = len; /* name length (ascic prefix) */
+ while (*pnt != '\0')
+ Local[i++] = *pnt++;
+ Local[i++] = DST_K_VS_FOLLOWS; /* value specification follows */
+ COPY_SHORT (&Local[i], 15); /* length of rest of record */
+ i += 2;
+ Local[i++] = DST_K_VS_ALLOC_SPLIT; /* split lifetime */
+ Local[i++] = 1; /* one binding follows */
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ VMS_Set_Data (Text_Psect, Min_Offset, OBJ_S_C_DBG, 1);
+ VMS_Set_Data (Text_Psect, Max_Offset, OBJ_S_C_DBG, 1);
+ Local[i++] = DST_K_VALKIND_REG; /* nested value spec */
+ COPY_LONG (&Local[i], S_GET_VALUE (sp));
+ i += 4;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ *pnt1 = ':';
+ if (spnt->VMS_type == DBG_S_C_ADVANCED_TYPE)
+ generate_suffix (spnt, 0);
+}
+
+
+/* This function examines a structure definition, checking all of the elements
+ to make sure that all of them are fully defined. The only thing that we
+ kick out are arrays of undefined structs, since we do not know how big
+ they are. All others we can handle with a normal forward reference. */
+
+static int
+forward_reference (pnt)
+ char *pnt;
+{
+ struct VMS_DBG_Symbol *spnt, *spnt1;
+ int i;
+
+ pnt = cvt_integer (pnt + 1, &i);
+ if (*pnt == ';')
+ return 0; /* no forward references */
+ do
+ {
+ pnt = (char *) strchr (pnt, ':');
+ pnt = cvt_integer (pnt + 1, &i);
+ spnt = find_symbol (i);
+ while (spnt && (spnt->advanced == POINTER || spnt->advanced == ARRAY))
+ {
+ spnt1 = find_symbol (spnt->type2);
+ if (spnt->advanced == ARRAY && !spnt1)
+ return 1;
+ spnt = spnt1;
+ }
+ pnt = cvt_integer (pnt + 1, &i);
+ pnt = cvt_integer (pnt + 1, &i);
+ } while (*++pnt != ';');
+ return 0; /* no forward refences found */
+}
+
+
+/* Used to check a single element of a structure on the final pass. */
+
+static int
+final_forward_reference (spnt)
+ struct VMS_DBG_Symbol *spnt;
+{
+ struct VMS_DBG_Symbol *spnt1;
+
+ while (spnt && (spnt->advanced == POINTER || spnt->advanced == ARRAY))
+ {
+ spnt1 = find_symbol (spnt->type2);
+ if (spnt->advanced == ARRAY && !spnt1)
+ return 1;
+ spnt = spnt1;
+ }
+ return 0; /* no forward refences found */
+}
+
+
+/* This routine parses the stabs directives to find any definitions of dbx
+ type numbers. It makes a note of all of them, creating a structure
+ element of VMS_DBG_Symbol that describes it. This also generates the
+ info for the debugger that describes the struct/union/enum, so that
+ further references to these data types will be by number
+
+ We have to process pointers right away, since there can be references
+ to them later in the same stabs directive. We cannot have forward
+ references to pointers, (but we can have a forward reference to a
+ pointer to a structure/enum/union) and this is why we process them
+ immediately. After we process the pointer, then we search for defs
+ that are nested even deeper.
+
+ 8/15/92: We have to process arrays right away too, because there can
+ be multiple references to identical array types in one structure
+ definition, and only the first one has the definition. */
+
+static int
+VMS_typedef_parse (str)
+ char *str;
+{
+ char *pnt;
+ char *pnt1;
+ const char *pnt2;
+ int i;
+ int dtype;
+ struct forward_ref *fpnt;
+ int i1, i2, i3, len;
+ struct VMS_DBG_Symbol *spnt;
+ struct VMS_DBG_Symbol *spnt1;
+
+ /* check for any nested def's */
+ pnt = (char *) strchr (str + 1, '=');
+ if (pnt && str[1] != '*' && (str[1] != 'a' || str[2] != 'r')
+ && VMS_typedef_parse (pnt) == 1)
+ return 1;
+ /* now find dbx_type of entry */
+ pnt = str - 1;
+ if (*pnt == 'c')
+ { /* check for static constants */
+ *str = '\0'; /* for now we ignore them */
+ return 0;
+ }
+ while ((*pnt <= '9') && (*pnt >= '0'))
+ pnt--;
+ pnt++; /* and get back to the number */
+ cvt_integer (pnt, &i1);
+ spnt = find_symbol (i1);
+ /* first see if this has been defined already, due to forward reference */
+ if (!spnt)
+ {
+ i2 = SYMTYP_HASH (i1);
+ spnt = (struct VMS_DBG_Symbol *) xmalloc (sizeof (struct VMS_DBG_Symbol));
+ spnt->next = VMS_Symbol_type_list[i2];
+ VMS_Symbol_type_list[i2] = spnt;
+ spnt->dbx_type = i1; /* and save the type */
+ spnt->type2 = spnt->VMS_type = spnt->data_size = 0;
+ spnt->index_min = spnt->index_max = spnt->struc_numb = 0;
+ }
+ /*
+ * For structs and unions, do a partial parse, otherwise we sometimes get
+ * circular definitions that are impossible to resolve. We read enough
+ * info so that any reference to this type has enough info to be resolved.
+ */
+ pnt = str + 1; /* point to character past equal sign */
+ if (*pnt >= '0' && *pnt <= '9')
+ {
+ if (type_check ("void"))
+ { /* this is the void symbol */
+ *str = '\0';
+ spnt->advanced = VOID;
+ return 0;
+ }
+ if (type_check ("unknown type"))
+ {
+ *str = '\0';
+ spnt->advanced = UNKNOWN;
+ return 0;
+ }
+ pnt1 = cvt_integer (pnt, &i1);
+ if (i1 != spnt->dbx_type)
+ {
+ spnt->advanced = ALIAS;
+ spnt->type2 = i1;
+ strcpy (str, pnt1);
+ return 0;
+ }
+ as_tsktsk (_("debugginer output: %d is an unknown untyped variable."),
+ spnt->dbx_type);
+ return 1; /* do not know what this is */
+ }
+
+ pnt = str + 1; /* point to character past equal sign */
+ switch (*pnt)
+ {
+ case 'r':
+ spnt->advanced = BASIC;
+ if (type_check ("int"))
+ {
+ spnt->VMS_type = DBG_S_C_SLINT;
+ spnt->data_size = 4;
+ }
+ else if (type_check ("long int"))
+ {
+ spnt->VMS_type = DBG_S_C_SLINT;
+ spnt->data_size = 4;
+ }
+ else if (type_check ("unsigned int"))
+ {
+ spnt->VMS_type = DBG_S_C_ULINT;
+ spnt->data_size = 4;
+ }
+ else if (type_check ("long unsigned int"))
+ {
+ spnt->VMS_type = DBG_S_C_ULINT;
+ spnt->data_size = 4;
+ }
+ else if (type_check ("short int"))
+ {
+ spnt->VMS_type = DBG_S_C_SSINT;
+ spnt->data_size = 2;
+ }
+ else if (type_check ("short unsigned int"))
+ {
+ spnt->VMS_type = DBG_S_C_USINT;
+ spnt->data_size = 2;
+ }
+ else if (type_check ("char"))
+ {
+ spnt->VMS_type = DBG_S_C_SCHAR;
+ spnt->data_size = 1;
+ }
+ else if (type_check ("signed char"))
+ {
+ spnt->VMS_type = DBG_S_C_SCHAR;
+ spnt->data_size = 1;
+ }
+ else if (type_check ("unsigned char"))
+ {
+ spnt->VMS_type = DBG_S_C_UCHAR;
+ spnt->data_size = 1;
+ }
+ else if (type_check ("float"))
+ {
+ spnt->VMS_type = DBG_S_C_REAL4;
+ spnt->data_size = 4;
+ }
+ else if (type_check ("double"))
+ {
+ spnt->VMS_type = vax_g_doubles ? DBG_S_C_REAL8_G : DBG_S_C_REAL8;
+ spnt->data_size = 8;
+ }
+ else if (type_check ("long double"))
+ {
+ /* same as double, at least for now */
+ spnt->VMS_type = vax_g_doubles ? DBG_S_C_REAL8_G : DBG_S_C_REAL8;
+ spnt->data_size = 8;
+ }
+ else if (type_check ("long long int"))
+ {
+ spnt->VMS_type = DBG_S_C_SQUAD; /* signed quadword */
+ spnt->data_size = 8;
+ }
+ else if (type_check ("long long unsigned int"))
+ {
+ spnt->VMS_type = DBG_S_C_UQUAD; /* unsigned quadword */
+ spnt->data_size = 8;
+ }
+ else if (type_check ("complex float"))
+ {
+ spnt->VMS_type = DBG_S_C_COMPLX4;
+ spnt->data_size = 2 * 4;
+ }
+ else if (type_check ("complex double"))
+ {
+ spnt->VMS_type = vax_g_doubles ? DBG_S_C_COMPLX8_G : DBG_S_C_COMPLX8;
+ spnt->data_size = 2 * 8;
+ }
+ else if (type_check ("complex long double"))
+ {
+ /* same as complex double, at least for now */
+ spnt->VMS_type = vax_g_doubles ? DBG_S_C_COMPLX8_G : DBG_S_C_COMPLX8;
+ spnt->data_size = 2 * 8;
+ }
+ else
+ {
+ /* [pr]
+ * Shouldn't get here, but if we do, something
+ * more substantial ought to be done...
+ */
+ spnt->VMS_type = 0;
+ spnt->data_size = 0;
+ }
+ if (spnt->VMS_type != 0)
+ setup_basic_type (spnt);
+ pnt1 = (char *) strchr (str, ';') + 1;
+ break;
+ case 's':
+ case 'u':
+ spnt->advanced = (*pnt == 's') ? STRUCT : UNION;
+ spnt->VMS_type = DBG_S_C_ADVANCED_TYPE;
+ pnt1 = cvt_integer (pnt + 1, &spnt->data_size);
+ if (!final_pass && forward_reference (pnt))
+ {
+ spnt->struc_numb = -1;
+ return 1;
+ }
+ spnt->struc_numb = ++structure_count;
+ pnt1--;
+ pnt = get_struct_name (str);
+ VMS_Def_Struct (spnt->struc_numb);
+ i = 0;
+ for (fpnt = f_ref_root; fpnt; fpnt = fpnt->next)
+ if (fpnt->dbx_type == spnt->dbx_type)
+ {
+ fpnt->resolved = 'Y';
+ VMS_Set_Struct (fpnt->struc_numb);
+ VMS_Store_Struct (spnt->struc_numb);
+ i++;
+ }
+ if (i > 0)
+ VMS_Set_Struct (spnt->struc_numb);
+ i = 0;
+ Local[i++] = 11 + strlen (pnt);
+ Local[i++] = DBG_S_C_STRUCT_START;
+ Local[i++] = DST_K_VFLAGS_NOVAL; /* structure definition only */
+ COPY_LONG (&Local[i], 0L); /* hence value is unused */
+ i += 4;
+ Local[i++] = strlen (pnt);
+ pnt2 = pnt;
+ while (*pnt2 != '\0')
+ Local[i++] = *pnt2++;
+ i2 = spnt->data_size * 8; /* number of bits */
+ COPY_LONG (&Local[i], i2);
+ i += 4;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ if (pnt != symbol_name)
+ {
+ pnt += strlen (pnt);
+ *pnt = ':';
+ } /* replace colon for later */
+ while (*++pnt1 != ';')
+ {
+ pnt = (char *) strchr (pnt1, ':');
+ *pnt = '\0';
+ pnt2 = pnt1;
+ pnt1 = cvt_integer (pnt + 1, &dtype);
+ pnt1 = cvt_integer (pnt1 + 1, &i2);
+ pnt1 = cvt_integer (pnt1 + 1, &i3);
+ spnt1 = find_symbol (dtype);
+ len = strlen (pnt2);
+ if (spnt1 && (spnt1->advanced == BASIC || spnt1->advanced == ENUM)
+ && ((i3 != spnt1->data_size * 8) || (i2 % 8 != 0)))
+ { /* bitfield */
+ if (USE_BITSTRING_DESCRIPTOR (spnt1))
+ {
+ /* This uses a type descriptor, which doesn't work if
+ the enclosing structure has been placed in a register.
+ Also, enum bitfields degenerate to simple integers. */
+ int unsigned_type = (spnt1->VMS_type == DBG_S_C_ULINT
+ || spnt1->VMS_type == DBG_S_C_USINT
+ || spnt1->VMS_type == DBG_S_C_UCHAR
+ || spnt1->VMS_type == DBG_S_C_UQUAD
+ || spnt1->advanced == ENUM); /* (approximate) */
+ Apoint = 0;
+ fpush (19 + len, 1);
+ fpush (unsigned_type ? DBG_S_C_UBITU : DBG_S_C_SBITU, 1);
+ fpush (DST_K_VFLAGS_DSC, 1); /* specified by descriptor */
+ fpush (1 + len, 4); /* relative offset to descriptor */
+ fpush (len, 1); /* length byte (ascic prefix) */
+ while (*pnt2 != '\0') /* name bytes */
+ fpush (*pnt2++, 1);
+ fpush (i3, 2); /* dsc length == size of bitfield */
+ /* dsc type == un?signed bitfield */
+ fpush (unsigned_type ? DBG_S_C_UBITU : DBG_S_C_SBITU, 1);
+ fpush (DSC_K_CLASS_UBS, 1); /* dsc class == unaligned bitstring */
+ fpush (0x00, 4); /* dsc pointer == zeroes */
+ fpush (i2, 4); /* start position */
+ VMS_Store_Immediate_Data (Asuffix, Apoint, OBJ_S_C_DBG);
+ Apoint = 0;
+ }
+ else
+ {
+ /* Use a "novel length" type specification, which works
+ right for register structures and for enum bitfields
+ but results in larger object modules. */
+ Local[i++] = 7 + len;
+ Local[i++] = DBG_S_C_ADVANCED_TYPE; /* type spec follows */
+ Local[i++] = DBG_S_C_STRUCT_ITEM; /* value is a bit offset */
+ COPY_LONG (&Local[i], i2); /* bit offset */
+ i += 4;
+ Local[i++] = strlen (pnt2);
+ while (*pnt2 != '\0')
+ Local[i++] = *pnt2++;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ bitfield_suffix (spnt1, i3);
+ }
+ }
+ else
+ { /* not a bitfield */
+ /* check if this is a forward reference */
+ if (final_pass && final_forward_reference (spnt1))
+ {
+ as_tsktsk (_("debugger output: structure element `%s' has undefined type"),
+ pnt2);
+ continue;
+ }
+ Local[i++] = 7 + len;
+ Local[i++] = spnt1 ? spnt1->VMS_type : DBG_S_C_ADVANCED_TYPE;
+ Local[i++] = DBG_S_C_STRUCT_ITEM;
+ COPY_LONG (&Local[i], i2); /* bit offset */
+ i += 4;
+ Local[i++] = strlen (pnt2);
+ while (*pnt2 != '\0')
+ Local[i++] = *pnt2++;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ if (!spnt1)
+ generate_suffix (spnt1, dtype);
+ else if (spnt1->VMS_type == DBG_S_C_ADVANCED_TYPE)
+ generate_suffix (spnt1, 0);
+ }
+ }
+ pnt1++;
+ Local[i++] = 0x01; /* length byte */
+ Local[i++] = DBG_S_C_STRUCT_END;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ break;
+ case 'e':
+ spnt->advanced = ENUM;
+ spnt->VMS_type = DBG_S_C_ADVANCED_TYPE;
+ spnt->struc_numb = ++structure_count;
+ spnt->data_size = 4;
+ VMS_Def_Struct (spnt->struc_numb);
+ i = 0;
+ for (fpnt = f_ref_root; fpnt; fpnt = fpnt->next)
+ if (fpnt->dbx_type == spnt->dbx_type)
+ {
+ fpnt->resolved = 'Y';
+ VMS_Set_Struct (fpnt->struc_numb);
+ VMS_Store_Struct (spnt->struc_numb);
+ i++;
+ }
+ if (i > 0)
+ VMS_Set_Struct (spnt->struc_numb);
+ i = 0;
+ len = strlen (symbol_name);
+ Local[i++] = 3 + len;
+ Local[i++] = DBG_S_C_ENUM_START;
+ Local[i++] = 4 * 8; /* enum values are 32 bits */
+ Local[i++] = len;
+ pnt2 = symbol_name;
+ while (*pnt2 != '\0')
+ Local[i++] = *pnt2++;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ while (*++pnt != ';')
+ {
+ pnt1 = (char *) strchr (pnt, ':');
+ *pnt1++ = '\0';
+ pnt1 = cvt_integer (pnt1, &i1);
+ len = strlen (pnt);
+ Local[i++] = 7 + len;
+ Local[i++] = DBG_S_C_ENUM_ITEM;
+ Local[i++] = DST_K_VALKIND_LITERAL;
+ COPY_LONG (&Local[i], i1);
+ i += 4;
+ Local[i++] = len;
+ pnt2 = pnt;
+ while (*pnt != '\0')
+ Local[i++] = *pnt++;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ pnt = pnt1; /* Skip final semicolon */
+ }
+ Local[i++] = 0x01; /* len byte */
+ Local[i++] = DBG_S_C_ENUM_END;
+ VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG);
+ i = 0;
+ pnt1 = pnt + 1;
+ break;
+ case 'a':
+ spnt->advanced = ARRAY;
+ spnt->VMS_type = DBG_S_C_ADVANCED_TYPE;
+ pnt = (char *) strchr (pnt, ';');
+ if (!pnt)
+ return 1;
+ pnt1 = cvt_integer (pnt + 1, &spnt->index_min);
+ pnt1 = cvt_integer (pnt1 + 1, &spnt->index_max);
+ pnt1 = cvt_integer (pnt1 + 1, &spnt->type2);
+ pnt = (char *) strchr (str + 1, '=');
+ if (pnt && VMS_typedef_parse (pnt) == 1)
+ return 1;
+ break;
+ case 'f':
+ spnt->advanced = FUNCTION;
+ spnt->VMS_type = DBG_S_C_FUNCTION_ADDR;
+ /* this masquerades as a basic type*/
+ spnt->data_size = 4;
+ pnt1 = cvt_integer (pnt + 1, &spnt->type2);
+ break;
+ case '*':
+ spnt->advanced = POINTER;
+ spnt->VMS_type = DBG_S_C_ADVANCED_TYPE;
+ spnt->data_size = 4;
+ pnt1 = cvt_integer (pnt + 1, &spnt->type2);
+ pnt = (char *) strchr (str + 1, '=');
+ if (pnt && VMS_typedef_parse (pnt) == 1)
+ return 1;
+ break;
+ default:
+ spnt->advanced = UNKNOWN;
+ spnt->VMS_type = 0;
+ as_tsktsk (_("debugger output: %d is an unknown type of variable."),
+ spnt->dbx_type);
+ return 1; /* unable to decipher */
+ }
+ /* This removes the evidence of the definition so that the outer levels
+ of parsing do not have to worry about it. */
+ pnt = str;
+ while (*pnt1 != '\0')
+ *pnt++ = *pnt1++;
+ *pnt = '\0';
+ return 0;
+}
+
+
+/* This is the root routine that parses the stabs entries for definitions.
+ it calls VMS_typedef_parse, which can in turn call itself. We need to
+ be careful, since sometimes there are forward references to other symbol
+ types, and these cannot be resolved until we have completed the parse.
+
+ Also check and see if we are using continuation stabs, if we are, then
+ paste together the entire contents of the stab before we pass it to
+ VMS_typedef_parse. */
+
+static void
+VMS_LSYM_Parse ()
+{
+ char *pnt;
+ char *pnt1;
+ char *pnt2;
+ char *str;
+ char *parse_buffer = 0;
+ char fixit[10];
+ int incomplete, pass, incom1;
+ struct forward_ref *fpnt;
+ symbolS *sp;
+
+ pass = 0;
+ final_pass = 0;
+ incomplete = 0;
+ do
+ {
+ incom1 = incomplete;
+ incomplete = 0;
+ for (sp = symbol_rootP; sp; sp = symbol_next (sp))
+ {
+ /*
+ * Deal with STAB symbols
+ */
+ if (S_IS_DEBUG (sp))
+ {
+ /*
+ * Dispatch on STAB type
+ */
+ switch (S_GET_RAW_TYPE (sp))
+ {
+ case N_GSYM:
+ case N_LCSYM:
+ case N_STSYM:
+ case N_PSYM:
+ case N_RSYM:
+ case N_LSYM:
+ case N_FUN: /*sometimes these contain typedefs*/
+ str = S_GET_NAME (sp);
+ symbol_name = str;
+ pnt = str + strlen (str) - 1;
+ if (*pnt == '?') /* Continuation stab. */
+ {
+ symbolS *spnext;
+ int tlen = 0;
+
+ spnext = sp;
+ do {
+ tlen += strlen (str) - 1;
+ spnext = symbol_next (spnext);
+ str = S_GET_NAME (spnext);
+ pnt = str + strlen (str) - 1;
+ } while (*pnt == '?');
+ tlen += strlen (str);
+ parse_buffer = (char *) xmalloc (tlen + 1);
+ strcpy (parse_buffer, S_GET_NAME (sp));
+ pnt2 = parse_buffer + strlen (parse_buffer) - 1;
+ *pnt2 = '\0';
+ spnext = sp;
+ do {
+ spnext = symbol_next (spnext);
+ str = S_GET_NAME (spnext);
+ strcat (pnt2, str);
+ pnt2 += strlen (str) - 1;
+ *str = '\0'; /* Erase this string */
+ /* S_SET_NAME (spnext, str); */
+ if (*pnt2 != '?') break;
+ *pnt2 = '\0';
+ } while (1);
+ str = parse_buffer;
+ symbol_name = str;
+ }
+ if ((pnt = (char *) strchr (str, ':')) != 0)
+ {
+ *pnt = '\0';
+ pnt1 = pnt + 1;
+ if ((pnt2 = (char *) strchr (pnt1, '=')) != 0)
+ incomplete += VMS_typedef_parse (pnt2);
+ if (parse_buffer)
+ {
+ /* At this point the parse buffer should just
+ contain name:nn. If it does not, then we
+ are in real trouble. Anyway, this is always
+ shorter than the original line. */
+ pnt2 = S_GET_NAME (sp);
+ strcpy (pnt2, parse_buffer);
+ /* S_SET_NAME (sp, pnt2); */
+ free (parse_buffer), parse_buffer = 0;
+ }
+ *pnt = ':'; /* put back colon to restore dbx_type */
+ }
+ break;
+ } /*switch*/
+ } /* if */
+ } /*for*/
+ pass++;
+ /*
+ * Make one last pass, if needed, and define whatever we can
+ * that is left.
+ */
+ if (final_pass == 0 && incomplete == incom1)
+ {
+ final_pass = 1;
+ incom1++; /* Force one last pass through */
+ }
+ } while (incomplete != 0 && incomplete != incom1);
+ /* repeat until all refs resolved if possible */
+/* if (pass > 1) printf (" Required %d passes\n", pass); */
+ if (incomplete != 0)
+ {
+ as_tsktsk (_("debugger output: Unable to resolve %d circular references."),
+ incomplete);
+ }
+ fpnt = f_ref_root;
+ symbol_name = "\0";
+ while (fpnt)
+ {
+ if (fpnt->resolved != 'Y')
+ {
+ if (find_symbol (fpnt->dbx_type))
+ {
+ as_tsktsk (_("debugger forward reference error, dbx type %d"),
+ fpnt->dbx_type);
+ break;
+ }
+ fixit[0] = 0;
+ sprintf (&fixit[1], "%d=s4;", fpnt->dbx_type);
+ pnt2 = (char *) strchr (&fixit[1], '=');
+ VMS_typedef_parse (pnt2);
+ }
+ fpnt = fpnt->next;
+ }
+}
+
+
+static void
+Define_Local_Symbols (s0P, s2P, Current_Routine, Text_Psect)
+ symbolS *s0P, *s2P;
+ symbolS *Current_Routine;
+ int Text_Psect;
+{
+ symbolS *s1P; /* each symbol from s0P .. s2P (exclusive) */
+
+ for (s1P = symbol_next (s0P); s1P != s2P; s1P = symbol_next (s1P))
+ {
+ if (!s1P)
+ break; /* and return */
+ if (S_GET_RAW_TYPE (s1P) == N_FUN)
+ {
+ char *pnt = (char *) strchr (S_GET_NAME (s1P), ':') + 1;
+ if (*pnt == 'F' || *pnt == 'f') break;
+ }
+ if (!S_IS_DEBUG (s1P))
+ continue;
+ /*
+ * Dispatch on STAB type
+ */
+ switch (S_GET_RAW_TYPE (s1P))
+ {
+ default:
+ continue; /* not left or right brace */
+
+ case N_LSYM:
+ case N_PSYM:
+ VMS_local_stab_Parse (s1P);
+ break;
+
+ case N_RSYM:
+ VMS_RSYM_Parse (s1P, Current_Routine, Text_Psect);
+ break;
+ } /*switch*/
+ } /* for */
+}
+
+
+/* This function crawls the symbol chain searching for local symbols that
+ need to be described to the debugger. When we enter a new scope with
+ a "{", it creates a new "block", which helps the debugger keep track
+ of which scope we are currently in. */
+
+static symbolS *
+Define_Routine (s0P, Level, Current_Routine, Text_Psect)
+ symbolS *s0P;
+ int Level;
+ symbolS *Current_Routine;
+ int Text_Psect;
+{
+ symbolS *s1P;
+ valueT Offset;
+ int rcount = 0;
+
+ for (s1P = symbol_next (s0P); s1P != 0; s1P = symbol_next (s1P))
+ {
+ if (S_GET_RAW_TYPE (s1P) == N_FUN)
+ {
+ char *pnt = (char *) strchr (S_GET_NAME (s1P), ':') + 1;
+ if (*pnt == 'F' || *pnt == 'f') break;
+ }
+ if (!S_IS_DEBUG (s1P))
+ continue;
+ /*
+ * Dispatch on STAB type
+ */
+ switch (S_GET_RAW_TYPE (s1P))
+ {
+ default:
+ continue; /* not left or right brace */
+
+ case N_LBRAC:
+ if (Level != 0)
+ {
+ char str[10];
+ sprintf (str, "$%d", rcount++);
+ VMS_TBT_Block_Begin (s1P, Text_Psect, str);
+ }
+ Offset = S_GET_VALUE (s1P); /* side-effect: fully resolve symbol */
+ Define_Local_Symbols (s0P, s1P, Current_Routine, Text_Psect);
+ s1P = Define_Routine (s1P, Level + 1, Current_Routine, Text_Psect);
+ if (Level != 0)
+ VMS_TBT_Block_End (S_GET_VALUE (s1P) - Offset);
+ s0P = s1P;
+ break;
+
+ case N_RBRAC:
+ return s1P;
+ } /*switch*/
+ } /* for */
+
+ /* We end up here if there were no brackets in this function.
+ Define everything. */
+ Define_Local_Symbols (s0P, (symbolS *)0, Current_Routine, Text_Psect);
+ return s1P;
+}
+
+
+#ifndef VMS
+#include <sys/types.h>
+#include <time.h>
+static void get_VMS_time_on_unix PARAMS ((char *));
+
+/* Manufacture a VMS-like time string on a Unix based system. */
+static void
+get_VMS_time_on_unix (Now)
+ char *Now;
+{
+ 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 (Now, "%2s-%3s-%s %s", pnt + 8, pnt + 4, pnt + 20, pnt + 11);
+}
+#endif /* not VMS */
+
+
+/* Write the MHD (Module Header) records. */
+
+static void
+Write_VMS_MHD_Records ()
+{
+ register const char *cp;
+ register char *cp1;
+ register int i;
+#ifdef VMS
+ struct { unsigned short len, mbz; char *ptr; } Descriptor;
+#endif
+ char Now[17+1];
+
+ /* We are writing a module header record. */
+ Set_VMS_Object_File_Record (OBJ_S_C_HDR);
+ /*
+ * ***************************
+ * *MAIN MODULE HEADER RECORD*
+ * ***************************
+ */
+ /* Store record type and header type. */
+ PUT_CHAR (OBJ_S_C_HDR);
+ PUT_CHAR (MHD_S_C_MHD);
+ /* Structure level is 0. */
+ PUT_CHAR (OBJ_S_C_STRLVL);
+ /* Maximum record size is size of the object record buffer. */
+ PUT_SHORT (sizeof (Object_Record_Buffer));
+
+ /*
+ * FIXME: module name and version should be user
+ * specifiable via `.ident' and/or `#pragma ident'.
+ */
+
+ /* Get module name (the FILENAME part of the object file). */
+ cp = out_file_name;
+ cp1 = Module_Name;
+ while (*cp)
+ {
+ if (*cp == ']' || *cp == '>' || *cp == ':' || *cp == '/')
+ {
+ cp1 = Module_Name;
+ cp++;
+ continue;
+ }
+ *cp1++ = islower (*cp) ? toupper (*cp++) : *cp++;
+ }
+ *cp1 = '\0';
+
+ /* Limit it to 31 characters and store in the object record. */
+ while (--cp1 >= Module_Name)
+ if (*cp1 == '.')
+ *cp1 = '\0';
+ if (strlen (Module_Name) > 31)
+ {
+ if (flag_hash_long_names)
+ as_tsktsk (_("Module name truncated: %s\n"), Module_Name);
+ Module_Name[31] = '\0';
+ }
+ PUT_COUNTED_STRING (Module_Name);
+ /* Module Version is "V1.0". */
+ PUT_COUNTED_STRING ("V1.0");
+ /* Creation time is "now" (17 chars of time string): "dd-MMM-yyyy hh:mm". */
+#ifndef VMS
+ get_VMS_time_on_unix (Now);
+#else /* VMS */
+ Descriptor.len = sizeof Now - 1;
+ Descriptor.mbz = 0; /* type & class unspecified */
+ Descriptor.ptr = Now;
+ (void) sys$asctim ((unsigned short *)0, &Descriptor, (long *)0, 0);
+#endif /* VMS */
+ for (i = 0; i < 17; i++)
+ PUT_CHAR (Now[i]);
+ /* Patch time is "never" (17 zeros). */
+ for (i = 0; i < 17; i++)
+ PUT_CHAR (0);
+ /* Force this to be a separate output record. */
+ Flush_VMS_Object_Record_Buffer ();
+
+ /*
+ * *************************
+ * *LANGUAGE PROCESSOR NAME*
+ * *************************
+ */
+ /* Store record type and header type. */
+ PUT_CHAR (OBJ_S_C_HDR);
+ PUT_CHAR (MHD_S_C_LNM);
+ /*
+ * Store language processor name and version (not a counted string!).
+ *
+ * This is normally supplied by the gcc driver for the command line
+ * which invokes gas. If absent, we fall back to gas's version.
+ */
+ cp = compiler_version_string;
+ if (cp == 0)
+ {
+ cp = "GNU AS V";
+ while (*cp)
+ PUT_CHAR (*cp++);
+ cp = VERSION;
+ }
+ while (*cp >= ' ')
+ PUT_CHAR (*cp++);
+ /* Force this to be a separate output record. */
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/* Write the EOM (End Of Module) record. */
+
+static void
+Write_VMS_EOM_Record (Psect, Offset)
+ int Psect;
+ valueT Offset;
+{
+ /*
+ * We are writing an end-of-module record
+ * (this assumes that the entry point will always be in a psect
+ * represented by a single byte, which is the case for code in
+ * Text_Psect==0)
+ */
+ Set_VMS_Object_File_Record (OBJ_S_C_EOM);
+ PUT_CHAR (OBJ_S_C_EOM); /* Record type. */
+ PUT_CHAR (0); /* Error severity level (we ignore it). */
+ /*
+ * Store the entry point, if it exists
+ */
+ if (Psect >= 0)
+ {
+ PUT_CHAR (Psect);
+ PUT_LONG (Offset);
+ }
+ /* Flush the record; this will be our final output. */
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/* this hash routine borrowed from GNU-EMACS, and strengthened slightly ERY*/
+
+static int
+hash_string (ptr)
+ const char *ptr;
+{
+ register const unsigned char *p = (unsigned char *) ptr;
+ register const unsigned char *end = p + strlen (ptr);
+ register unsigned char c;
+ register int hash = 0;
+
+ while (p != end)
+ {
+ c = *p++;
+ hash = ((hash << 3) + (hash << 15) + (hash >> 28) + c);
+ }
+ return hash;
+}
+
+/*
+ * Generate a Case-Hacked VMS symbol name (limited to 31 chars)
+ */
+static void
+VMS_Case_Hack_Symbol (In, Out)
+ register const char *In;
+ register char *Out;
+{
+ long int init;
+ long int result;
+ char *pnt = 0;
+ char *new_name;
+ const char *old_name;
+ register int i;
+ int destructor = 0; /*hack to allow for case sens in a destructor*/
+ int truncate = 0;
+ int Case_Hack_Bits = 0;
+ int Saw_Dollar = 0;
+ static char Hex_Table[16] =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ /*
+ * Kill any leading "_"
+ */
+ if ((In[0] == '_') && ((In[1] > '9') || (In[1] < '0')))
+ In++;
+
+ new_name = Out; /* save this for later*/
+
+#if barfoo /* Dead code */
+ if ((In[0] == '_') && (In[1] == '$') && (In[2] == '_'))
+ destructor = 1;
+#endif
+
+ /* We may need to truncate the symbol, save the hash for later*/
+ result = (strlen (In) > 23) ? hash_string (In) : 0;
+ /*
+ * Is there a Psect Attribute to skip??
+ */
+ if (HAS_PSECT_ATTRIBUTES (In))
+ {
+ /*
+ * Yes: Skip it
+ */
+ In += PSECT_ATTRIBUTES_STRING_LENGTH;
+ while (*In)
+ {
+ if ((In[0] == '$') && (In[1] == '$'))
+ {
+ In += 2;
+ break;
+ }
+ In++;
+ }
+ }
+
+ old_name = In;
+/* if (strlen (In) > 31 && flag_hash_long_names)
+ as_tsktsk ("Symbol name truncated: %s\n", In); */
+ /*
+ * Do the case conversion
+ */
+ i = 23; /* Maximum of 23 chars */
+ while (*In && (--i >= 0))
+ {
+ Case_Hack_Bits <<= 1;
+ if (*In == '$')
+ Saw_Dollar = 1;
+ if ((destructor == 1) && (i == 21))
+ Saw_Dollar = 0;
+ switch (vms_name_mapping)
+ {
+ case 0:
+ if (isupper (*In)) {
+ *Out++ = *In++;
+ Case_Hack_Bits |= 1;
+ } else {
+ *Out++ = islower (*In) ? toupper (*In++) : *In++;
+ }
+ break;
+ case 3: *Out++ = *In++;
+ break;
+ case 2:
+ if (islower (*In)) {
+ *Out++ = *In++;
+ } else {
+ *Out++ = isupper (*In) ? tolower (*In++) : *In++;
+ }
+ break;
+ }
+ }
+ /*
+ * If we saw a dollar sign, we don't do case hacking
+ */
+ if (flag_no_hash_mixed_case || Saw_Dollar)
+ Case_Hack_Bits = 0;
+
+ /*
+ * If we have more than 23 characters and everything is lowercase
+ * we can insert the full 31 characters
+ */
+ if (*In)
+ {
+ /*
+ * We have more than 23 characters
+ * If we must add the case hack, then we have truncated the str
+ */
+ pnt = Out;
+ truncate = 1;
+ if (Case_Hack_Bits == 0)
+ {
+ /*
+ * And so far they are all lower case:
+ * Check up to 8 more characters
+ * and ensure that they are lowercase
+ */
+ for (i = 0; (In[i] != 0) && (i < 8); i++)
+ if (isupper (In[i]) && !Saw_Dollar && !flag_no_hash_mixed_case)
+ break;
+
+ if (In[i] == 0)
+ truncate = 0;
+
+ if ((i == 8) || (In[i] == 0))
+ {
+ /*
+ * They are: Copy up to 31 characters
+ * to the output string
+ */
+ i = 8;
+ while ((--i >= 0) && (*In))
+ switch (vms_name_mapping){
+ case 0: *Out++ = islower (*In) ? toupper (*In++) : *In++;
+ break;
+ case 3: *Out++ = *In++;
+ break;
+ case 2: *Out++ = isupper (*In) ? tolower (*In++) : *In++;
+ break;
+ }
+ }
+ }
+ }
+ /*
+ * If there were any uppercase characters in the name we
+ * take on the case hacking string
+ */
+
+ /* Old behavior for regular GNU-C compiler */
+ if (!flag_hash_long_names)
+ truncate = 0;
+ if ((Case_Hack_Bits != 0) || (truncate == 1))
+ {
+ if (truncate == 0)
+ {
+ *Out++ = '_';
+ for (i = 0; i < 6; i++)
+ {
+ *Out++ = Hex_Table[Case_Hack_Bits & 0xf];
+ Case_Hack_Bits >>= 4;
+ }
+ *Out++ = 'X';
+ }
+ else
+ {
+ Out = pnt; /*Cut back to 23 characters maximum */
+ *Out++ = '_';
+ for (i = 0; i < 7; i++)
+ {
+ init = result & 0x01f;
+ *Out++ = (init < 10) ? ('0' + init) : ('A' + init - 10);
+ result = result >> 5;
+ }
+ }
+ } /*Case Hack */
+ /*
+ * Done
+ */
+ *Out = 0;
+ if (truncate == 1 && flag_hash_long_names && flag_show_after_trunc)
+ as_tsktsk (_("Symbol %s replaced by %s\n"), old_name, new_name);
+}
+
+
+/*
+ * Scan a symbol name for a psect attribute specification
+ */
+#define GLOBALSYMBOL_BIT 0x10000
+#define GLOBALVALUE_BIT 0x20000
+
+
+static void
+VMS_Modify_Psect_Attributes (Name, Attribute_Pointer)
+ const char *Name;
+ int *Attribute_Pointer;
+{
+ register int i;
+ register const char *cp;
+ int Negate;
+ static const struct
+ {
+ const char *Name;
+ int Value;
+ } Attributes[] =
+ {
+ {"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},
+ {"GLOBALSYMBOL", GLOBALSYMBOL_BIT},
+ {"GLOBALVALUE", GLOBALVALUE_BIT},
+ {0, 0}
+ };
+
+ /*
+ * Kill leading "_"
+ */
+ if (*Name == '_')
+ Name++;
+ /*
+ * Check for a PSECT attribute list
+ */
+ if (!HAS_PSECT_ATTRIBUTES (Name))
+ return; /* If not, return */
+ /*
+ * Skip the attribute list indicator
+ */
+ Name += PSECT_ATTRIBUTES_STRING_LENGTH;
+ /*
+ * Process the attributes ("_" separated, "$" terminated)
+ */
+ while (*Name != '$')
+ {
+ /*
+ * Assume not negating
+ */
+ Negate = 0;
+ /*
+ * Check for "NO"
+ */
+ if ((Name[0] == 'N') && (Name[1] == 'O'))
+ {
+ /*
+ * We are negating (and skip the NO)
+ */
+ Negate = 1;
+ Name += 2;
+ }
+ /*
+ * Find the token delimiter
+ */
+ cp = Name;
+ while (*cp && (*cp != '_') && (*cp != '$'))
+ cp++;
+ /*
+ * Look for the token in the attribute list
+ */
+ for (i = 0; Attributes[i].Name; i++)
+ {
+ /*
+ * If the strings match, set/clear the attr.
+ */
+ if (strncmp (Name, Attributes[i].Name, cp - Name) == 0)
+ {
+ /*
+ * Set or clear
+ */
+ if (Negate)
+ *Attribute_Pointer &=
+ ~Attributes[i].Value;
+ else
+ *Attribute_Pointer |=
+ Attributes[i].Value;
+ /*
+ * Done
+ */
+ break;
+ }
+ }
+ /*
+ * Now skip the attribute
+ */
+ Name = cp;
+ if (*Name == '_')
+ Name++;
+ }
+}
+
+
+#define GBLSYM_REF 0
+#define GBLSYM_DEF 1
+#define GBLSYM_VAL 2
+#define GBLSYM_LCL 4 /* not GBL after all... */
+#define GBLSYM_WEAK 8
+
+/*
+ * Define a global symbol (or possibly a local one).
+ */
+static void
+VMS_Global_Symbol_Spec (Name, Psect_Number, Psect_Offset, Flags)
+ const char *Name;
+ int Psect_Number;
+ int Psect_Offset;
+ int Flags;
+{
+ char Local[32];
+
+ /*
+ * We are writing a GSD record
+ */
+ Set_VMS_Object_File_Record (OBJ_S_C_GSD);
+ /*
+ * If the buffer is empty we must insert the GSD record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_GSD);
+ /*
+ * We are writing a Global (or local) symbol definition subrecord.
+ */
+ PUT_CHAR ((Flags & GBLSYM_LCL) != 0 ? GSD_S_C_LSY :
+ ((unsigned) Psect_Number <= 255) ? GSD_S_C_SYM : GSD_S_C_SYMW);
+ /*
+ * Data type is undefined
+ */
+ PUT_CHAR (0);
+ /*
+ * Switch on Definition/Reference
+ */
+ if ((Flags & GBLSYM_DEF) == 0)
+ {
+ /*
+ * Reference
+ */
+ PUT_SHORT (((Flags & GBLSYM_VAL) == 0) ? GSY_S_M_REL : 0);
+ if ((Flags & GBLSYM_LCL) != 0) /* local symbols have extra field */
+ PUT_SHORT (Current_Environment);
+ }
+ else
+ {
+ int sym_flags;
+
+ /*
+ * Definition
+ *[ assert (LSY_S_M_DEF == GSY_S_M_DEF && LSY_S_M_REL == GSY_S_M_REL); ]
+ */
+ sym_flags = GSY_S_M_DEF;
+ if (Flags & GBLSYM_WEAK)
+ sym_flags |= GSY_S_M_WEAK;
+ if ((Flags & GBLSYM_VAL) == 0)
+ sym_flags |= GSY_S_M_REL;
+ PUT_SHORT (sym_flags);
+ if ((Flags & GBLSYM_LCL) != 0) /* local symbols have extra field */
+ PUT_SHORT (Current_Environment);
+ /*
+ * Psect Number
+ */
+ if ((Flags & GBLSYM_LCL) == 0 && (unsigned) Psect_Number <= 255)
+ PUT_CHAR (Psect_Number);
+ else
+ PUT_SHORT (Psect_Number);
+ /*
+ * Offset
+ */
+ PUT_LONG (Psect_Offset);
+ }
+ /*
+ * Finally, the global symbol name
+ */
+ VMS_Case_Hack_Symbol (Name, Local);
+ PUT_COUNTED_STRING (Local);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+/*
+ * Define an environment to support local symbol references.
+ * This is just to mollify the linker; we don't actually do
+ * anything useful with it.
+ */
+static void
+VMS_Local_Environment_Setup (Env_Name)
+ const char *Env_Name;
+{
+ /* We are writing a GSD record. */
+ Set_VMS_Object_File_Record (OBJ_S_C_GSD);
+ /* If the buffer is empty we must insert the GSD record type. */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_GSD);
+ /* We are writing an ENV subrecord. */
+ PUT_CHAR (GSD_S_C_ENV);
+
+ ++Current_Environment; /* index of environment being defined */
+
+ /* ENV$W_FLAGS: we are defining the next environment. It's not nested. */
+ PUT_SHORT (ENV_S_M_DEF);
+ /* ENV$W_ENVINDX: index is always 0 for non-nested definitions. */
+ PUT_SHORT (0);
+
+ /* ENV$B_NAMLNG + ENV$T_NAME: environment name in ASCIC format. */
+ if (!Env_Name) Env_Name = "";
+ PUT_COUNTED_STRING ((char *)Env_Name);
+
+ /* Flush the buffer if it is more than 75% full. */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/*
+ * Define a psect
+ */
+static int
+VMS_Psect_Spec (Name, Size, Type, vsp)
+ const char *Name;
+ int Size;
+ enum ps_type Type;
+ struct VMS_Symbol *vsp;
+{
+ char Local[32];
+ int Psect_Attributes;
+
+ /*
+ * Generate the appropriate PSECT flags given the PSECT type
+ */
+ switch (Type)
+ {
+ case ps_TEXT:
+ /* Text psects are PIC,noOVR,REL,noGBL,SHR,EXE,RD,noWRT. */
+ Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_SHR|GPS_S_M_EXE
+ |GPS_S_M_RD);
+ break;
+ case ps_DATA:
+ /* Data psects are PIC,noOVR,REL,noGBL,noSHR,noEXE,RD,WRT. */
+ Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_RD|GPS_S_M_WRT);
+ break;
+ case ps_COMMON:
+ /* Common block psects are: PIC,OVR,REL,GBL,noSHR,noEXE,RD,WRT. */
+ Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_OVR|GPS_S_M_REL|GPS_S_M_GBL
+ |GPS_S_M_RD|GPS_S_M_WRT);
+ break;
+ case ps_CONST:
+ /* Const data psects are: PIC,OVR,REL,GBL,noSHR,noEXE,RD,noWRT. */
+ Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_OVR|GPS_S_M_REL|GPS_S_M_GBL
+ |GPS_S_M_RD);
+ break;
+ case ps_CTORS:
+ /* Ctor psects are PIC,noOVR,REL,GBL,noSHR,noEXE,RD,noWRT. */
+ Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_GBL|GPS_S_M_RD);
+ break;
+ case ps_DTORS:
+ /* Dtor psects are PIC,noOVR,REL,GBL,noSHR,noEXE,RD,noWRT. */
+ Psect_Attributes = (GPS_S_M_PIC|GPS_S_M_REL|GPS_S_M_GBL|GPS_S_M_RD);
+ break;
+ default:
+ /* impossible */
+ error (_("Unknown VMS psect type (%ld)"), (long) Type);
+ break;
+ }
+ /*
+ * Modify the psect attributes according to any attribute string
+ */
+ if (vsp && S_GET_TYPE (vsp->Symbol) == N_ABS)
+ Psect_Attributes |= GLOBALVALUE_BIT;
+ else if (HAS_PSECT_ATTRIBUTES (Name))
+ VMS_Modify_Psect_Attributes (Name, &Psect_Attributes);
+ /*
+ * Check for globalref/def/val.
+ */
+ if ((Psect_Attributes & GLOBALVALUE_BIT) != 0)
+ {
+ /*
+ * globalvalue symbols were generated before. This code
+ * prevents unsightly psect buildup, and makes sure that
+ * fixup references are emitted correctly.
+ */
+ vsp->Psect_Index = -1; /* to catch errors */
+ S_SET_TYPE (vsp->Symbol, N_UNDF); /* make refs work */
+ return 1; /* decrement psect counter */
+ }
+
+ if ((Psect_Attributes & GLOBALSYMBOL_BIT) != 0)
+ {
+ switch (S_GET_RAW_TYPE (vsp->Symbol))
+ {
+ case N_UNDF | N_EXT:
+ VMS_Global_Symbol_Spec (Name, vsp->Psect_Index,
+ vsp->Psect_Offset, GBLSYM_REF);
+ vsp->Psect_Index = -1;
+ S_SET_TYPE (vsp->Symbol, N_UNDF);
+ return 1; /* return and indicate no psect */
+ case N_DATA | N_EXT:
+ VMS_Global_Symbol_Spec (Name, vsp->Psect_Index,
+ vsp->Psect_Offset, GBLSYM_DEF);
+ /* In this case we still generate the psect */
+ break;
+ default:
+ as_fatal (_("Globalsymbol attribute for symbol %s was unexpected."),
+ Name);
+ break;
+ } /* switch */
+ }
+
+ Psect_Attributes &= 0xffff; /* clear out the globalref/def stuff */
+ /*
+ * We are writing a GSD record
+ */
+ Set_VMS_Object_File_Record (OBJ_S_C_GSD);
+ /*
+ * If the buffer is empty we must insert the GSD record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_GSD);
+ /*
+ * We are writing a PSECT definition subrecord
+ */
+ PUT_CHAR (GSD_S_C_PSC);
+ /*
+ * Psects are always LONGWORD aligned
+ */
+ PUT_CHAR (2);
+ /*
+ * Specify the psect attributes
+ */
+ PUT_SHORT (Psect_Attributes);
+ /*
+ * Specify the allocation
+ */
+ PUT_LONG (Size);
+ /*
+ * Finally, the psect name
+ */
+ VMS_Case_Hack_Symbol (Name, Local);
+ PUT_COUNTED_STRING (Local);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+ return 0;
+}
+
+
+/* Given the pointer to a symbol we calculate how big the data at the
+ symbol is. We do this by looking for the next symbol (local or global)
+ which will indicate the start of another datum. */
+
+static offsetT
+VMS_Initialized_Data_Size (s0P, End_Of_Data)
+ register symbolS *s0P;
+ unsigned End_Of_Data;
+{
+ symbolS *s1P;
+ valueT s0P_val = S_GET_VALUE (s0P), s1P_val,
+ nearest_val = (valueT) End_Of_Data;
+
+ /* Find the nearest symbol what follows this one. */
+ for (s1P = symbol_rootP; s1P; s1P = symbol_next (s1P))
+ {
+ /* The data type must match. */
+ if (S_GET_TYPE (s1P) != N_DATA)
+ continue;
+ s1P_val = S_GET_VALUE (s1P);
+ if (s1P_val > s0P_val && s1P_val < nearest_val)
+ nearest_val = s1P_val;
+ }
+ /* Calculate its size. */
+ return (offsetT) (nearest_val - s0P_val);
+}
+
+
+/* Check symbol names for the Psect hack with a globalvalue, and then
+ generate globalvalues for those that have it. */
+
+static void
+VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment)
+ unsigned text_siz;
+ unsigned data_siz;
+ char *Data_Segment;
+{
+ register symbolS *sp;
+ char *stripped_name, *Name;
+ int Size;
+ int Psect_Attributes;
+ int globalvalue;
+ int typ, abstyp;
+
+ /*
+ * Scan the symbol table for globalvalues, and emit def/ref when
+ * required. These will be caught again later and converted to
+ * N_UNDF
+ */
+ for (sp = symbol_rootP; sp; sp = sp->sy_next)
+ {
+ typ = S_GET_RAW_TYPE (sp);
+ abstyp = ((typ & ~N_EXT) == N_ABS);
+ /*
+ * See if this is something we want to look at.
+ */
+ if (!abstyp &&
+ typ != (N_DATA | N_EXT) &&
+ typ != (N_UNDF | N_EXT))
+ continue;
+ /*
+ * See if this has globalvalue specification.
+ */
+ Name = S_GET_NAME (sp);
+
+ if (abstyp)
+ {
+ stripped_name = 0;
+ Psect_Attributes = GLOBALVALUE_BIT;
+ }
+ else if (HAS_PSECT_ATTRIBUTES (Name))
+ {
+ stripped_name = (char *) xmalloc (strlen (Name) + 1);
+ strcpy (stripped_name, Name);
+ Psect_Attributes = 0;
+ VMS_Modify_Psect_Attributes (stripped_name, &Psect_Attributes);
+ }
+ else
+ continue;
+
+ if ((Psect_Attributes & GLOBALVALUE_BIT) != 0)
+ {
+ switch (typ)
+ {
+ case N_ABS:
+ /* Local symbol references will want
+ to have an environment defined. */
+ if (Current_Environment < 0)
+ VMS_Local_Environment_Setup (".N_ABS");
+ VMS_Global_Symbol_Spec (Name, 0,
+ S_GET_VALUE (sp),
+ GBLSYM_DEF|GBLSYM_VAL|GBLSYM_LCL);
+ break;
+ case N_ABS | N_EXT:
+ VMS_Global_Symbol_Spec (Name, 0,
+ S_GET_VALUE (sp),
+ GBLSYM_DEF|GBLSYM_VAL);
+ break;
+ case N_UNDF | N_EXT:
+ VMS_Global_Symbol_Spec (stripped_name, 0, 0, GBLSYM_VAL);
+ break;
+ case N_DATA | N_EXT:
+ Size = VMS_Initialized_Data_Size (sp, text_siz + data_siz);
+ if (Size > 4)
+ error (_("Invalid data type for globalvalue"));
+ globalvalue = md_chars_to_number (Data_Segment +
+ S_GET_VALUE (sp) - text_siz , Size);
+ /* Three times for good luck. The linker seems to get confused
+ if there are fewer than three */
+ VMS_Global_Symbol_Spec (stripped_name, 0, 0, GBLSYM_VAL);
+ VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue,
+ GBLSYM_DEF|GBLSYM_VAL);
+ VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue,
+ GBLSYM_DEF|GBLSYM_VAL);
+ break;
+ default:
+ as_warn (_("Invalid globalvalue of %s"), stripped_name);
+ break;
+ } /* switch */
+ } /* if */
+ if (stripped_name) free (stripped_name); /* clean up */
+ } /* for */
+
+}
+
+
+/*
+ * Define a procedure entry pt/mask
+ */
+static void
+VMS_Procedure_Entry_Pt (Name, Psect_Number, Psect_Offset, Entry_Mask)
+ char *Name;
+ int Psect_Number;
+ int Psect_Offset;
+ int Entry_Mask;
+{
+ char Local[32];
+
+ /*
+ * We are writing a GSD record
+ */
+ Set_VMS_Object_File_Record (OBJ_S_C_GSD);
+ /*
+ * If the buffer is empty we must insert the GSD record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (OBJ_S_C_GSD);
+ /*
+ * We are writing a Procedure Entry Pt/Mask subrecord
+ */
+ PUT_CHAR (((unsigned) Psect_Number <= 255) ? GSD_S_C_EPM : GSD_S_C_EPMW);
+ /*
+ * Data type is undefined
+ */
+ PUT_CHAR (0);
+ /*
+ * Flags = "RELOCATABLE" and "DEFINED"
+ */
+ PUT_SHORT (GSY_S_M_DEF | GSY_S_M_REL);
+ /*
+ * Psect Number
+ */
+ if ((unsigned) Psect_Number <= 255)
+ PUT_CHAR (Psect_Number);
+ else
+ PUT_SHORT (Psect_Number);
+ /*
+ * Offset
+ */
+ PUT_LONG (Psect_Offset);
+ /*
+ * Entry mask
+ */
+ PUT_SHORT (Entry_Mask);
+ /*
+ * Finally, the global symbol name
+ */
+ VMS_Case_Hack_Symbol (Name, Local);
+ PUT_COUNTED_STRING (Local);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/*
+ * Set the current location counter to a particular Psect and Offset
+ */
+static void
+VMS_Set_Psect (Psect_Index, Offset, Record_Type)
+ int Psect_Index;
+ int Offset;
+ int Record_Type;
+{
+ /*
+ * We are writing a "Record_Type" record
+ */
+ Set_VMS_Object_File_Record (Record_Type);
+ /*
+ * If the buffer is empty we must insert the record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /*
+ * Stack the Psect base + Offset
+ */
+ vms_tir_stack_psect (Psect_Index, Offset, 0);
+ /*
+ * Set relocation base
+ */
+ PUT_CHAR (TIR_S_C_CTL_SETRB);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/*
+ * Store repeated immediate data in current Psect
+ */
+static void
+VMS_Store_Repeated_Data (Repeat_Count, Pointer, Size, Record_Type)
+ int Repeat_Count;
+ register char *Pointer;
+ int Size;
+ int Record_Type;
+{
+
+ /*
+ * Ignore zero bytes/words/longwords
+ */
+ switch (Size)
+ {
+ case 4:
+ if (Pointer[3] != 0 || Pointer[2] != 0) break;
+ /* else FALLTHRU */
+ case 2:
+ if (Pointer[1] != 0) break;
+ /* else FALLTHRU */
+ case 1:
+ if (Pointer[0] != 0) break;
+ /* zero value */
+ return;
+ default:
+ break;
+ }
+ /*
+ * If the data is too big for a TIR_S_C_STO_RIVB sub-record
+ * then we do it manually
+ */
+ if (Size > 255)
+ {
+ while (--Repeat_Count >= 0)
+ VMS_Store_Immediate_Data (Pointer, Size, Record_Type);
+ return;
+ }
+ /*
+ * We are writing a "Record_Type" record
+ */
+ Set_VMS_Object_File_Record (Record_Type);
+ /*
+ * If the buffer is empty we must insert record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /*
+ * Stack the repeat count
+ */
+ PUT_CHAR (TIR_S_C_STA_LW);
+ PUT_LONG (Repeat_Count);
+ /*
+ * And now the command and its data
+ */
+ PUT_CHAR (TIR_S_C_STO_RIVB);
+ PUT_CHAR (Size);
+ while (--Size >= 0)
+ PUT_CHAR (*Pointer++);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/*
+ * Store a Position Independent Reference
+ */
+static void
+VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative,
+ Psect, Psect_Offset, Record_Type)
+ symbolS *Symbol;
+ int Offset;
+ int PC_Relative;
+ int Psect;
+ int Psect_Offset;
+ int Record_Type;
+{
+ register struct VMS_Symbol *vsp = Symbol->sy_obj;
+ char Local[32];
+ int local_sym = 0;
+
+ /*
+ * We are writing a "Record_Type" record
+ */
+ Set_VMS_Object_File_Record (Record_Type);
+ /*
+ * If the buffer is empty we must insert record type
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /*
+ * Set to the appropriate offset in the Psect.
+ * For a Code reference we need to fix the operand
+ * specifier as well, so back up 1 byte;
+ * for a Data reference we just store HERE.
+ */
+ VMS_Set_Psect (Psect,
+ PC_Relative ? Psect_Offset - 1 : Psect_Offset,
+ Record_Type);
+ /*
+ * Make sure we are still generating a "Record Type" record
+ */
+ if (Object_Record_Offset == 0)
+ PUT_CHAR (Record_Type);
+ /*
+ * Dispatch on symbol type (so we can stack its value)
+ */
+ switch (S_GET_RAW_TYPE (Symbol))
+ {
+ /*
+ * Global symbol
+ */
+ case N_ABS:
+ local_sym = 1;
+ /*FALLTHRU*/
+ case N_ABS | N_EXT:
+#ifdef NOT_VAX_11_C_COMPATIBLE
+ case N_UNDF | N_EXT:
+ case N_DATA | N_EXT:
+#endif /* NOT_VAX_11_C_COMPATIBLE */
+ case N_UNDF:
+ case N_TEXT | N_EXT:
+ /*
+ * Get the symbol name (case hacked)
+ */
+ VMS_Case_Hack_Symbol (S_GET_NAME (Symbol), Local);
+ /*
+ * Stack the global symbol value
+ */
+ if (!local_sym)
+ {
+ PUT_CHAR (TIR_S_C_STA_GBL);
+ }
+ else
+ {
+ /* Local symbols have an extra field. */
+ PUT_CHAR (TIR_S_C_STA_LSY);
+ PUT_SHORT (Current_Environment);
+ }
+ PUT_COUNTED_STRING (Local);
+ if (Offset)
+ {
+ /*
+ * Stack the longword offset
+ */
+ PUT_CHAR (TIR_S_C_STA_LW);
+ PUT_LONG (Offset);
+ /*
+ * Add the two, leaving the result on the stack
+ */
+ PUT_CHAR (TIR_S_C_OPR_ADD);
+ }
+ break;
+ /*
+ * Uninitialized local data
+ */
+ case N_BSS:
+ /*
+ * Stack the Psect (+offset)
+ */
+ vms_tir_stack_psect (vsp->Psect_Index,
+ vsp->Psect_Offset + Offset,
+ 0);
+ break;
+ /*
+ * Local text
+ */
+ case N_TEXT:
+ /*
+ * Stack the Psect (+offset)
+ */
+ vms_tir_stack_psect (vsp->Psect_Index,
+ S_GET_VALUE (Symbol) + Offset,
+ 0);
+ break;
+ /*
+ * Initialized local or global data
+ */
+ case N_DATA:
+#ifndef NOT_VAX_11_C_COMPATIBLE
+ case N_UNDF | N_EXT:
+ case N_DATA | N_EXT:
+#endif /* NOT_VAX_11_C_COMPATIBLE */
+ /*
+ * Stack the Psect (+offset)
+ */
+ vms_tir_stack_psect (vsp->Psect_Index,
+ vsp->Psect_Offset + Offset,
+ 0);
+ break;
+ }
+ /*
+ * Store either a code or data reference
+ */
+ PUT_CHAR (PC_Relative ? TIR_S_C_STO_PICR : TIR_S_C_STO_PIDR);
+ /*
+ * Flush the buffer if it is more than 75% full
+ */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+}
+
+
+/*
+ * Check in the text area for an indirect pc-relative reference
+ * and fix it up with addressing mode 0xff [PC indirect]
+ *
+ * THIS SHOULD BE REPLACED BY THE USE OF TIR_S_C_STO_PIRR IN THE
+ * PIC CODE GENERATING FIXUP ROUTINE.
+ */
+static void
+VMS_Fix_Indirect_Reference (Text_Psect, Offset, fragP, text_frag_root)
+ int Text_Psect;
+ int Offset;
+ register fragS *fragP;
+ fragS *text_frag_root;
+{
+ /*
+ * The addressing mode byte is 1 byte before the address
+ */
+ Offset--;
+ /*
+ * Is it in THIS frag??
+ */
+ if ((Offset < fragP->fr_address) ||
+ (Offset >= (fragP->fr_address + fragP->fr_fix)))
+ {
+ /*
+ * We need to search for the fragment containing this
+ * Offset
+ */
+ for (fragP = text_frag_root; fragP; fragP = fragP->fr_next)
+ {
+ if ((Offset >= fragP->fr_address) &&
+ (Offset < (fragP->fr_address + fragP->fr_fix)))
+ break;
+ }
+ /*
+ * If we couldn't find the frag, things are BAD!!
+ */
+ if (fragP == 0)
+ error (_("Couldn't find fixup fragment when checking for indirect reference"));
+ }
+ /*
+ * Check for indirect PC relative addressing mode
+ */
+ if (fragP->fr_literal[Offset - fragP->fr_address] == (char) 0xff)
+ {
+ static char Address_Mode = (char) 0xff;
+
+ /*
+ * Yes: Store the indirect mode back into the image
+ * to fix up the damage done by STO_PICR
+ */
+ VMS_Set_Psect (Text_Psect, Offset, OBJ_S_C_TIR);
+ VMS_Store_Immediate_Data (&Address_Mode, 1, OBJ_S_C_TIR);
+ }
+}
+
+
+/*
+ * If the procedure "main()" exists we have to add the instruction
+ * "jsb c$main_args" at the beginning to be compatible with VAX-11 "C".
+ *
+ * FIXME: the macro name `HACK_DEC_C_STARTUP' should be renamed
+ * to `HACK_VAXCRTL_STARTUP' because Digital's compiler
+ * named "DEC C" uses run-time library "DECC$SHR", but this
+ * startup code is for "VAXCRTL", the library for Digital's
+ * older "VAX C". Also, this extra code isn't needed for
+ * supporting gcc because it already generates the VAXCRTL
+ * startup call when compiling main(). The reference to
+ * `flag_hash_long_names' looks very suspicious too;
+ * probably an old-style command line option was inadvertently
+ * overloaded here, then blindly converted into the new one.
+ */
+void
+vms_check_for_main ()
+{
+ register symbolS *symbolP;
+#ifdef HACK_DEC_C_STARTUP /* JF */
+ register struct frchain *frchainP;
+ register fragS *fragP;
+ register fragS **prev_fragPP;
+ register struct fix *fixP;
+ register fragS *New_Frag;
+ int i;
+#endif /* HACK_DEC_C_STARTUP */
+
+ symbolP = (symbolS *) symbol_find ("_main");
+ if (symbolP && !S_IS_DEBUG (symbolP) &&
+ S_IS_EXTERNAL (symbolP) && (S_GET_TYPE (symbolP) == N_TEXT))
+ {
+#ifdef HACK_DEC_C_STARTUP
+ if (!flag_hash_long_names)
+ {
+#endif
+ /*
+ * Remember the entry point symbol
+ */
+ Entry_Point_Symbol = symbolP;
+#ifdef HACK_DEC_C_STARTUP
+ }
+ else
+ {
+ /*
+ * Scan all the fragment chains for the one with "_main"
+ * (Actually we know the fragment from the symbol, but we need
+ * the previous fragment so we can change its pointer)
+ */
+ frchainP = frchain_root;
+ while (frchainP)
+ {
+ /*
+ * Scan all the fragments in this chain, remembering
+ * the "previous fragment"
+ */
+ prev_fragPP = &frchainP->frch_root;
+ fragP = frchainP->frch_root;
+ while (fragP && (fragP != frchainP->frch_last))
+ {
+ /*
+ * Is this the fragment?
+ */
+ if (fragP == symbolP->sy_frag)
+ {
+ /*
+ * Yes: Modify the fragment by replacing
+ * it with a new fragment.
+ */
+ New_Frag = (fragS *)
+ xmalloc (sizeof (*New_Frag) +
+ fragP->fr_fix +
+ fragP->fr_var +
+ 5);
+ /*
+ * The fragments are the same except
+ * that the "fixed" area is larger
+ */
+ *New_Frag = *fragP;
+ New_Frag->fr_fix += 6;
+ /*
+ * Copy the literal data opening a hole
+ * 2 bytes after "_main" (i.e. just after
+ * the entry mask). Into which we place
+ * the JSB instruction.
+ */
+ New_Frag->fr_literal[0] = fragP->fr_literal[0];
+ New_Frag->fr_literal[1] = fragP->fr_literal[1];
+ New_Frag->fr_literal[2] = 0x16; /* Jsb */
+ New_Frag->fr_literal[3] = 0xef;
+ New_Frag->fr_literal[4] = 0;
+ New_Frag->fr_literal[5] = 0;
+ New_Frag->fr_literal[6] = 0;
+ New_Frag->fr_literal[7] = 0;
+ for (i = 2; i < fragP->fr_fix + fragP->fr_var; i++)
+ New_Frag->fr_literal[i + 6] =
+ fragP->fr_literal[i];
+ /*
+ * Now replace the old fragment with the
+ * newly generated one.
+ */
+ *prev_fragPP = New_Frag;
+ /*
+ * Remember the entry point symbol
+ */
+ Entry_Point_Symbol = symbolP;
+ /*
+ * Scan the text area fixup structures
+ * as offsets in the fragment may have
+ * changed
+ */
+ for (fixP = text_fix_root; fixP; fixP = fixP->fx_next)
+ {
+ /*
+ * Look for references to this
+ * fragment.
+ */
+ if (fixP->fx_frag == fragP)
+ {
+ /*
+ * Change the fragment
+ * pointer
+ */
+ fixP->fx_frag = New_Frag;
+ /*
+ * If the offset is after
+ * the entry mask we need
+ * to account for the JSB
+ * instruction we just
+ * inserted.
+ */
+ if (fixP->fx_where >= 2)
+ fixP->fx_where += 6;
+ }
+ }
+ /*
+ * Scan the symbols as offsets in the
+ * fragment may have changed
+ */
+ for (symbolP = symbol_rootP;
+ symbolP;
+ symbolP = symbol_next (symbolP))
+ {
+ /*
+ * Look for references to this
+ * fragment.
+ */
+ if (symbolP->sy_frag == fragP)
+ {
+ /*
+ * Change the fragment
+ * pointer
+ */
+ symbolP->sy_frag = New_Frag;
+ /*
+ * If the offset is after
+ * the entry mask we need
+ * to account for the JSB
+ * instruction we just
+ * inserted.
+ */
+ if (S_GET_VALUE (symbolP) >= 2)
+ S_SET_VALUE (symbolP,
+ S_GET_VALUE (symbolP) + 6);
+ }
+ }
+ /*
+ * Make a symbol reference to
+ * "_c$main_args" so we can get
+ * its address inserted into the
+ * JSB instruction.
+ */
+ symbolP = (symbolS *) xmalloc (sizeof (*symbolP));
+ S_SET_NAME (symbolP, "_C$MAIN_ARGS");
+ S_SET_TYPE (symbolP, N_UNDF);
+ S_SET_OTHER (symbolP, 0);
+ S_SET_DESC (symbolP, 0);
+ S_SET_VALUE (symbolP, 0);
+ symbolP->sy_name_offset = 0;
+ symbolP->sy_number = 0;
+ symbolP->sy_obj = 0;
+ symbolP->sy_frag = New_Frag;
+ symbolP->sy_resolved = 0;
+ symbolP->sy_resolving = 0;
+ /* this actually inserts at the beginning of the list */
+ symbol_append (symbol_rootP, symbolP,
+ &symbol_rootP, &symbol_lastP);
+
+ symbol_rootP = symbolP;
+ /*
+ * Generate a text fixup structure
+ * to get "_c$main_args" stored into the
+ * JSB instruction.
+ */
+ fixP = (struct fix *) xmalloc (sizeof (*fixP));
+ fixP->fx_frag = New_Frag;
+ fixP->fx_where = 4;
+ fixP->fx_addsy = symbolP;
+ fixP->fx_subsy = 0;
+ fixP->fx_offset = 0;
+ fixP->fx_size = 4;
+ fixP->fx_pcrel = 1;
+ fixP->fx_next = text_fix_root;
+ text_fix_root = fixP;
+ /*
+ * Now make sure we exit from the loop
+ */
+ frchainP = 0;
+ break;
+ }
+ /*
+ * Try the next fragment
+ */
+ prev_fragPP = &fragP->fr_next;
+ fragP = fragP->fr_next;
+ }
+ /*
+ * Try the next fragment chain
+ */
+ if (frchainP)
+ frchainP = frchainP->frch_next;
+ }
+ }
+#endif /* HACK_DEC_C_STARTUP */
+ }
+}
+
+
+/*
+ * Beginning of vms_write_object_file().
+ */
+
+static
+struct vms_obj_state {
+
+ /* Next program section index to use. */
+ int psect_number;
+
+ /* Psect index for code. Always ends up #0. */
+ int text_psect;
+
+ /* Psect index for initialized static variables. */
+ int data_psect;
+
+ /* Psect index for uninitialized static variables. */
+ int bss_psect;
+
+ /* Psect index for static constructors. */
+ int ctors_psect;
+
+ /* Psect index for static destructors. */
+ int dtors_psect;
+
+ /* Number of bytes used for local symbol data. */
+ int local_initd_data_size;
+
+ /* Dynamic buffer for initialized data. */
+ char *data_segment;
+
+} vms_obj_state;
+
+#define Psect_Number vms_obj_state.psect_number
+#define Text_Psect vms_obj_state.text_psect
+#define Data_Psect vms_obj_state.data_psect
+#define Bss_Psect vms_obj_state.bss_psect
+#define Ctors_Psect vms_obj_state.ctors_psect
+#define Dtors_Psect vms_obj_state.dtors_psect
+#define Local_Initd_Data_Size vms_obj_state.local_initd_data_size
+#define Data_Segment vms_obj_state.data_segment
+
+
+#define IS_GXX_VTABLE(symP) (strncmp (S_GET_NAME (symP), "__vt.", 5) == 0)
+#define IS_GXX_XTOR(symP) (strncmp (S_GET_NAME (symP), "__GLOBAL_.", 10) == 0)
+#define XTOR_SIZE 4
+
+
+/* Perform text segment fixups. */
+
+static void
+vms_fixup_text_section (text_siz, text_frag_root, data_frag_root)
+ unsigned text_siz;
+ struct frag *text_frag_root;
+ struct frag *data_frag_root;
+{
+ register fragS *fragP;
+ register struct fix *fixP;
+ offsetT dif;
+
+ /* Scan the text fragments. */
+ for (fragP = text_frag_root; fragP; fragP = fragP->fr_next)
+ {
+ /* Stop if we get to the data fragments. */
+ if (fragP == data_frag_root)
+ break;
+ /* Ignore fragments with no data. */
+ if ((fragP->fr_fix == 0) && (fragP->fr_var == 0))
+ continue;
+ /* Go the the appropriate offset in the Text Psect. */
+ VMS_Set_Psect (Text_Psect, fragP->fr_address, OBJ_S_C_TIR);
+ /* Store the "fixed" part. */
+ if (fragP->fr_fix)
+ VMS_Store_Immediate_Data (fragP->fr_literal,
+ fragP->fr_fix,
+ OBJ_S_C_TIR);
+ /* Store the "variable" part. */
+ if (fragP->fr_var && fragP->fr_offset)
+ VMS_Store_Repeated_Data (fragP->fr_offset,
+ fragP->fr_literal + fragP->fr_fix,
+ fragP->fr_var,
+ OBJ_S_C_TIR);
+ } /* text frag loop */
+
+ /*
+ * Now we go through the text segment fixups and generate
+ * TIR records to fix up addresses within the Text Psect.
+ */
+ for (fixP = text_fix_root; fixP; fixP = fixP->fx_next)
+ {
+ /* We DO handle the case of "Symbol - Symbol" as
+ long as it is in the same segment. */
+ if (fixP->fx_subsy && fixP->fx_addsy)
+ {
+ /* They need to be in the same segment. */
+ if (S_GET_RAW_TYPE (fixP->fx_subsy) !=
+ S_GET_RAW_TYPE (fixP->fx_addsy))
+ error (_("Fixup data addsy and subsy don't have the same type"));
+ /* And they need to be in one that we can check the psect on. */
+ if ((S_GET_TYPE (fixP->fx_addsy) != N_DATA) &&
+ (S_GET_TYPE (fixP->fx_addsy) != N_TEXT))
+ error (_("Fixup data addsy and subsy don't have an appropriate type"));
+ /* This had better not be PC relative! */
+ if (fixP->fx_pcrel)
+ error (_("Fixup data is erroneously \"pcrel\""));
+ /* Subtract their values to get the difference. */
+ dif = S_GET_VALUE (fixP->fx_addsy) - S_GET_VALUE (fixP->fx_subsy);
+ md_number_to_chars (Local, (valueT)dif, fixP->fx_size);
+ /* Now generate the fixup object records;
+ set the psect and store the data. */
+ VMS_Set_Psect (Text_Psect,
+ fixP->fx_where + fixP->fx_frag->fr_address,
+ OBJ_S_C_TIR);
+ VMS_Store_Immediate_Data (Local,
+ fixP->fx_size,
+ OBJ_S_C_TIR);
+ continue; /* done with this fixup */
+ } /* if fx_subsy && fx_addsy */
+ /* Size will HAVE to be "long". */
+ if (fixP->fx_size != 4)
+ error (_("Fixup datum is not a longword"));
+ /* Symbol must be "added" (if it is ever
+ subtracted we can fix this assumption). */
+ if (fixP->fx_addsy == 0)
+ error (_("Fixup datum is not \"fixP->fx_addsy\""));
+ /* Store the symbol value in a PIC fashion. */
+ VMS_Store_PIC_Symbol_Reference (fixP->fx_addsy,
+ fixP->fx_offset,
+ fixP->fx_pcrel,
+ Text_Psect,
+ fixP->fx_where + fixP->fx_frag->fr_address,
+ OBJ_S_C_TIR);
+ /*
+ * Check for indirect address reference, which has to be fixed up
+ * (as the linker will screw it up with TIR_S_C_STO_PICR)...
+ */
+ if (fixP->fx_pcrel)
+ VMS_Fix_Indirect_Reference (Text_Psect,
+ fixP->fx_where + fixP->fx_frag->fr_address,
+ fixP->fx_frag,
+ text_frag_root);
+ } /* text fix loop */
+}
+
+
+/* Create a buffer holding the data segment. */
+
+static void
+synthesize_data_segment (data_siz, text_siz, data_frag_root)
+ unsigned data_siz, text_siz;
+ struct frag *data_frag_root;
+{
+ register fragS *fragP;
+ char *fill_literal;
+ long fill_size, count, i;
+
+ /* Allocate the data segment. */
+ Data_Segment = (char *) xmalloc (data_siz);
+ /* Run through the data fragments, filling in the segment. */
+ for (fragP = data_frag_root; fragP; fragP = fragP->fr_next)
+ {
+ i = fragP->fr_address - text_siz;
+ if (fragP->fr_fix)
+ memcpy (Data_Segment + i, fragP->fr_literal, fragP->fr_fix);
+ i += fragP->fr_fix;
+
+ if ((fill_size = fragP->fr_var) != 0)
+ {
+ fill_literal = fragP->fr_literal + fragP->fr_fix;
+ for (count = fragP->fr_offset; count; count--)
+ {
+ memcpy (Data_Segment + i, fill_literal, fill_size);
+ i += fill_size;
+ }
+ }
+ } /* data frag loop */
+
+ return;
+}
+
+
+/* Perform data segment fixups. */
+
+static void
+vms_fixup_data_section (data_siz, text_siz)
+ unsigned data_siz, text_siz;
+{
+ register struct VMS_Symbol *vsp;
+ register struct fix *fixP;
+ register symbolS *sp;
+ addressT fr_address;
+ offsetT dif;
+ valueT val;
+
+ /* Run through all the data symbols and store the data. */
+ for (vsp = VMS_Symbols; vsp; vsp = vsp->Next)
+ {
+ /* Ignore anything other than data symbols. */
+ if (S_GET_TYPE (vsp->Symbol) != N_DATA)
+ continue;
+ /* Set the Psect + Offset. */
+ VMS_Set_Psect (vsp->Psect_Index,
+ vsp->Psect_Offset,
+ OBJ_S_C_TIR);
+ /* Store the data. */
+ val = S_GET_VALUE (vsp->Symbol);
+ VMS_Store_Immediate_Data (Data_Segment + val - text_siz,
+ vsp->Size,
+ OBJ_S_C_TIR);
+ } /* N_DATA symbol loop */
+
+ /*
+ * Now we go through the data segment fixups and generate
+ * TIR records to fix up addresses within the Data Psects.
+ */
+ for (fixP = data_fix_root; fixP; fixP = fixP->fx_next)
+ {
+ /* Find the symbol for the containing datum. */
+ for (vsp = VMS_Symbols; vsp; vsp = vsp->Next)
+ {
+ /* Only bother with Data symbols. */
+ sp = vsp->Symbol;
+ if (S_GET_TYPE (sp) != N_DATA)
+ continue;
+ /* Ignore symbol if After fixup. */
+ val = S_GET_VALUE (sp);
+ fr_address = fixP->fx_frag->fr_address;
+ if (val > fixP->fx_where + fr_address)
+ continue;
+ /* See if the datum is here. */
+ if (val + vsp->Size <= fixP->fx_where + fr_address)
+ continue;
+ /* We DO handle the case of "Symbol - Symbol" as
+ long as it is in the same segment. */
+ if (fixP->fx_subsy && fixP->fx_addsy)
+ {
+ /* They need to be in the same segment. */
+ if (S_GET_RAW_TYPE (fixP->fx_subsy) !=
+ S_GET_RAW_TYPE (fixP->fx_addsy))
+ error (_("Fixup data addsy and subsy don't have the same type"));
+ /* And they need to be in one that we can check the psect on. */
+ if ((S_GET_TYPE (fixP->fx_addsy) != N_DATA) &&
+ (S_GET_TYPE (fixP->fx_addsy) != N_TEXT))
+ error (_("Fixup data addsy and subsy don't have an appropriate type"));
+ /* This had better not be PC relative! */
+ if (fixP->fx_pcrel)
+ error (_("Fixup data is erroneously \"pcrel\""));
+ /* Subtract their values to get the difference. */
+ dif = S_GET_VALUE (fixP->fx_addsy) - S_GET_VALUE (fixP->fx_subsy);
+ md_number_to_chars (Local, (valueT)dif, fixP->fx_size);
+ /*
+ * Now generate the fixup object records;
+ * set the psect and store the data.
+ */
+ VMS_Set_Psect (vsp->Psect_Index,
+ fr_address + fixP->fx_where
+ - val + vsp->Psect_Offset,
+ OBJ_S_C_TIR);
+ VMS_Store_Immediate_Data (Local,
+ fixP->fx_size,
+ OBJ_S_C_TIR);
+ break; /* done with this fixup */
+ }
+ /* Size will HAVE to be "long". */
+ if (fixP->fx_size != 4)
+ error (_("Fixup datum is not a longword"));
+ /* Symbol must be "added" (if it is ever
+ subtracted we can fix this assumption). */
+ if (fixP->fx_addsy == 0)
+ error (_("Fixup datum is not \"fixP->fx_addsy\""));
+ /* Store the symbol value in a PIC fashion. */
+ VMS_Store_PIC_Symbol_Reference (fixP->fx_addsy,
+ fixP->fx_offset,
+ fixP->fx_pcrel,
+ vsp->Psect_Index,
+ fr_address + fixP->fx_where
+ - val + vsp->Psect_Offset,
+ OBJ_S_C_TIR);
+ /* Done with this fixup. */
+ break;
+ } /* vms_symbol loop */
+
+ } /* data fix loop */
+}
+
+/* Perform ctors/dtors segment fixups. */
+
+static void
+vms_fixup_xtors_section (symbols, sect_no)
+ struct VMS_Symbol *symbols;
+ int sect_no;
+{
+ register struct VMS_Symbol *vsp;
+
+ /* Run through all the symbols and store the data. */
+ for (vsp = symbols; vsp; vsp = vsp->Next)
+ {
+ register symbolS *sp;
+
+ /* Set relocation base. */
+ VMS_Set_Psect (vsp->Psect_Index, vsp->Psect_Offset, OBJ_S_C_TIR);
+
+ sp = vsp->Symbol;
+ /* Stack the Psect base with its offset. */
+ VMS_Set_Data (Text_Psect, S_GET_VALUE (sp), OBJ_S_C_TIR, 0);
+ }
+ /* Flush the buffer if it is more than 75% full. */
+ if (Object_Record_Offset > (sizeof (Object_Record_Buffer) * 3 / 4))
+ Flush_VMS_Object_Record_Buffer ();
+
+ return;
+}
+
+
+/* Define symbols for the linker. */
+
+static void
+global_symbol_directory (text_siz, data_siz)
+ unsigned text_siz, data_siz;
+{
+ register fragS *fragP;
+ register symbolS *sp;
+ register struct VMS_Symbol *vsp;
+ int Globalref, define_as_global_symbol;
+
+#if 0
+ /* The g++ compiler does not write out external references to
+ vtables correctly. Check for this and holler if we see it
+ happening. If that compiler bug is ever fixed we can remove
+ this.
+
+ (Jun'95: gcc 2.7.0's cc1plus still exhibits this behavior.)
+
+ This was reportedly fixed as of June 2, 1998. */
+
+ for (sp = symbol_rootP; sp; sp = symbol_next (sp))
+ if (S_GET_RAW_TYPE (sp) == N_UNDF && IS_GXX_VTABLE (sp))
+ {
+ S_SET_TYPE (sp, N_UNDF | N_EXT);
+ S_SET_OTHER (sp, 1);
+ as_warn (_("g++ wrote an extern reference to `%s' as a routine.\nI will fix it, but I hope that it was note really a routine."),
+ S_GET_NAME (sp));
+ }
+#endif
+
+ /*
+ * Now scan the symbols and emit the appropriate GSD records
+ */
+ for (sp = symbol_rootP; sp; sp = symbol_next (sp))
+ {
+ define_as_global_symbol = 0;
+ vsp = 0;
+ /* Dispatch on symbol type. */
+ switch (S_GET_RAW_TYPE (sp))
+ {
+
+ /* Global uninitialized data. */
+ case N_UNDF | N_EXT:
+ /* Make a VMS data symbol entry. */
+ vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp);
+ vsp->Symbol = sp;
+ vsp->Size = S_GET_VALUE (sp);
+ vsp->Psect_Index = Psect_Number++;
+ vsp->Psect_Offset = 0;
+ vsp->Next = VMS_Symbols;
+ VMS_Symbols = vsp;
+ sp->sy_obj = vsp;
+ /* Make the psect for this data. */
+ Globalref = VMS_Psect_Spec (S_GET_NAME (sp),
+ vsp->Size,
+ S_GET_OTHER (sp) ? ps_CONST : ps_COMMON,
+ vsp);
+ if (Globalref)
+ Psect_Number--;
+#ifdef NOT_VAX_11_C_COMPATIBLE
+ define_as_global_symbol = 1;
+#else
+ /* See if this is an external vtable. We want to help the
+ linker find these things in libraries, so we make a symbol
+ reference. This is not compatible with VAX-C usage for
+ variables, but since vtables are only used internally by
+ g++, we can get away with this hack. */
+ define_as_global_symbol = IS_GXX_VTABLE (sp);
+#endif
+ break;
+
+ /* Local uninitialized data. */
+ case N_BSS:
+ /* Make a VMS data symbol entry. */
+ vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp);
+ vsp->Symbol = sp;
+ vsp->Size = 0;
+ vsp->Psect_Index = Bss_Psect;
+ vsp->Psect_Offset = S_GET_VALUE (sp) - bss_address_frag.fr_address;
+ vsp->Next = VMS_Symbols;
+ VMS_Symbols = vsp;
+ sp->sy_obj = vsp;
+ break;
+
+ /* Global initialized data. */
+ case N_DATA | N_EXT:
+ /* Make a VMS data symbol entry. */
+ vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp);
+ vsp->Symbol = sp;
+ vsp->Size = VMS_Initialized_Data_Size (sp, text_siz + data_siz);
+ vsp->Psect_Index = Psect_Number++;
+ vsp->Psect_Offset = 0;
+ vsp->Next = VMS_Symbols;
+ VMS_Symbols = vsp;
+ sp->sy_obj = vsp;
+ /* Make its psect. */
+ Globalref = VMS_Psect_Spec (S_GET_NAME (sp),
+ vsp->Size,
+ S_GET_OTHER (sp) ? ps_CONST : ps_COMMON,
+ vsp);
+ if (Globalref)
+ Psect_Number--;
+#ifdef NOT_VAX_11_C_COMPATIBLE
+ define_as_global_symbol = 1;
+#else
+ /* See N_UNDF|N_EXT above for explanation. */
+ define_as_global_symbol = IS_GXX_VTABLE (sp);
+#endif
+ break;
+
+ /* Local initialized data. */
+ case N_DATA:
+ {
+ char *sym_name = S_GET_NAME (sp);
+
+ /* Always suppress local numeric labels. */
+ if (sym_name && strcmp (sym_name, FAKE_LABEL_NAME) == 0)
+ break;
+
+ /* Make a VMS data symbol entry. */
+ vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp);
+ vsp->Symbol = sp;
+ vsp->Size = VMS_Initialized_Data_Size (sp, text_siz + data_siz);
+ vsp->Psect_Index = Data_Psect;
+ vsp->Psect_Offset = Local_Initd_Data_Size;
+ Local_Initd_Data_Size += vsp->Size;
+ vsp->Next = VMS_Symbols;
+ VMS_Symbols = vsp;
+ sp->sy_obj = vsp;
+ }
+ break;
+
+ /* Global Text definition. */
+ case N_TEXT | N_EXT:
+ {
+
+ if (IS_GXX_XTOR (sp))
+ {
+ vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp);
+ vsp->Symbol = sp;
+ vsp->Size = XTOR_SIZE;
+ sp->sy_obj = vsp;
+ switch ((S_GET_NAME (sp))[10])
+ {
+ case 'I':
+ vsp->Psect_Index = Ctors_Psect;
+ vsp->Psect_Offset = (Ctors_Symbols==0)?0:(Ctors_Symbols->Psect_Offset+XTOR_SIZE);
+ vsp->Next = Ctors_Symbols;
+ Ctors_Symbols = vsp;
+ break;
+ case 'D':
+ vsp->Psect_Index = Dtors_Psect;
+ vsp->Psect_Offset = (Dtors_Symbols==0)?0:(Dtors_Symbols->Psect_Offset+XTOR_SIZE);
+ vsp->Next = Dtors_Symbols;
+ Dtors_Symbols = vsp;
+ break;
+ case 'G':
+ as_warn (_("Can't handle global xtors symbols yet."));
+ break;
+ default:
+ as_warn (_("Unknown %s"), S_GET_NAME (sp));
+ break;
+ }
+ }
+ else
+ {
+ unsigned short Entry_Mask;
+
+ /* Get the entry mask. */
+ fragP = sp->sy_frag;
+ /* First frag might be empty if we're generating listings.
+ So skip empty rs_fill frags. */
+ while (fragP && fragP->fr_type == rs_fill && fragP->fr_fix == 0)
+ fragP = fragP->fr_next;
+
+ /* If first frag doesn't contain the data, what do we do?
+ If it's possibly smaller than two bytes, that would
+ imply that the entry mask is not stored where we're
+ expecting it.
+
+ If you can find a test case that triggers this, report
+ it (and tell me what the entry mask field ought to be),
+ and I'll try to fix it. KR */
+ if (fragP->fr_fix < 2)
+ abort ();
+
+ Entry_Mask = (fragP->fr_literal[0] & 0x00ff) |
+ ((fragP->fr_literal[1] & 0x00ff) << 8);
+ /* Define the procedure entry point. */
+ VMS_Procedure_Entry_Pt (S_GET_NAME (sp),
+ Text_Psect,
+ S_GET_VALUE (sp),
+ Entry_Mask);
+ }
+ break;
+ }
+
+ /* Local Text definition. */
+ case N_TEXT:
+ /* Make a VMS data symbol entry. */
+ if (Text_Psect != -1)
+ {
+ vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp);
+ vsp->Symbol = sp;
+ vsp->Size = 0;
+ vsp->Psect_Index = Text_Psect;
+ vsp->Psect_Offset = S_GET_VALUE (sp);
+ vsp->Next = VMS_Symbols;
+ VMS_Symbols = vsp;
+ sp->sy_obj = vsp;
+ }
+ break;
+
+ /* Global Reference. */
+ case N_UNDF:
+ /* Make a GSD global symbol reference record. */
+ VMS_Global_Symbol_Spec (S_GET_NAME (sp),
+ 0,
+ 0,
+ GBLSYM_REF);
+ break;
+
+ /* Absolute symbol. */
+ case N_ABS:
+ case N_ABS | N_EXT:
+ /* gcc doesn't generate these;
+ VMS_Emit_Globalvalue handles them though. */
+ vsp = (struct VMS_Symbol *) xmalloc (sizeof *vsp);
+ vsp->Symbol = sp;
+ vsp->Size = 4; /* always assume 32 bits */
+ vsp->Psect_Index = 0;
+ vsp->Psect_Offset = S_GET_VALUE (sp);
+ vsp->Next = VMS_Symbols;
+ VMS_Symbols = vsp;
+ sp->sy_obj = vsp;
+ break;
+
+ /* Anything else. */
+ default:
+ /* Ignore STAB symbols, including .stabs emitted by g++. */
+ if (S_IS_DEBUG (sp) || (S_GET_TYPE (sp) == 22))
+ break;
+ /*
+ * Error otherwise.
+ */
+ as_tsktsk (_("unhandled stab type %d"), S_GET_TYPE (sp));
+ break;
+ }
+
+ /* Global symbols have different linkage than external variables. */
+ if (define_as_global_symbol)
+ VMS_Global_Symbol_Spec (S_GET_NAME (sp),
+ vsp->Psect_Index,
+ 0,
+ GBLSYM_DEF);
+ }
+
+ return;
+}
+
+
+/* Output debugger symbol table information for symbols which
+ are local to a specific routine. */
+
+static void
+local_symbols_DST (s0P, Current_Routine)
+ symbolS *s0P, *Current_Routine;
+{
+ symbolS *s1P;
+ char *s0P_name, *pnt0, *pnt1;
+
+ s0P_name = S_GET_NAME (s0P);
+ if (*s0P_name++ != '_')
+ return;
+
+ for (s1P = Current_Routine; s1P; s1P = symbol_next (s1P))
+ {
+#if 0 /* redundant; RAW_TYPE != N_FUN suffices */
+ if (!S_IS_DEBUG (s1P))
+ continue;
+#endif
+ if (S_GET_RAW_TYPE (s1P) != N_FUN)
+ continue;
+ pnt0 = s0P_name;
+ pnt1 = S_GET_NAME (s1P);
+ /* We assume the two strings are never exactly equal... */
+ while (*pnt0++ == *pnt1++)
+ {
+ }
+ /* Found it if s0P name is exhausted and s1P name has ":F" or ":f" next.
+ Note: both pointers have advanced one past the non-matching char. */
+ if ((*pnt1 == 'F' || *pnt1 == 'f') && *--pnt1 == ':' && *--pnt0 == '\0')
+ {
+ Define_Routine (s1P, 0, Current_Routine, Text_Psect);
+ return;
+ }
+ }
+}
+
+
+/* Construct and output the debug symbol table. */
+
+static void
+vms_build_DST (text_siz)
+ unsigned text_siz;
+{
+ register symbolS *symbolP;
+ symbolS *Current_Routine = 0;
+ struct input_file *Cur_File = 0;
+ offsetT Cur_Offset = -1;
+ int Cur_Line_Number = 0;
+ int File_Number = 0;
+ int Debugger_Offset = 0;
+ int file_available;
+ int dsc;
+ offsetT val;
+
+ /* Write the Traceback Begin Module record. */
+ VMS_TBT_Module_Begin ();
+
+ /*
+ * Output debugging info for global variables and static variables
+ * that are not specific to one routine. We also need to examine
+ * all stabs directives, to find the definitions to all of the
+ * advanced data types, and this is done by VMS_LSYM_Parse. This
+ * needs to be done before any definitions are output to the object
+ * file, since there can be forward references in the stabs
+ * directives. When through with parsing, the text of the stabs
+ * directive is altered, with the definitions removed, so that later
+ * passes will see directives as they would be written if the type
+ * were already defined.
+ *
+ * We also look for files and include files, and make a list of
+ * them. We examine the source file numbers to establish the actual
+ * lines that code was generated from, and then generate offsets.
+ */
+ VMS_LSYM_Parse ();
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
+ {
+ /* Only deal with STAB symbols here. */
+ if (!S_IS_DEBUG (symbolP))
+ continue;
+ /*
+ * Dispatch on STAB type.
+ */
+ switch (S_GET_RAW_TYPE (symbolP))
+ {
+ case N_SLINE:
+ dsc = S_GET_DESC (symbolP);
+ if (dsc > Cur_File->max_line)
+ Cur_File->max_line = dsc;
+ if (dsc < Cur_File->min_line)
+ Cur_File->min_line = dsc;
+ break;
+ case N_SO:
+ Cur_File = find_file (symbolP);
+ Cur_File->flag = 1;
+ Cur_File->min_line = 1;
+ break;
+ case N_SOL:
+ Cur_File = find_file (symbolP);
+ break;
+ case N_GSYM:
+ VMS_GSYM_Parse (symbolP, Text_Psect);
+ break;
+ case N_LCSYM:
+ VMS_LCSYM_Parse (symbolP, Text_Psect);
+ break;
+ case N_FUN: /* For static constant symbols */
+ case N_STSYM:
+ VMS_STSYM_Parse (symbolP, Text_Psect);
+ break;
+ default:
+ break;
+ } /* switch */
+ } /* for */
+
+ /*
+ * Now we take a quick sweep through the files and assign offsets
+ * to each one. This will essentially be the starting line number to
+ * the debugger for each file. Output the info for the debugger to
+ * specify the files, and then tell it how many lines to use.
+ */
+ for (Cur_File = file_root; Cur_File; Cur_File = Cur_File->next)
+ {
+ if (Cur_File->max_line == 0)
+ continue;
+ if ((strncmp (Cur_File->name, "GNU_GXX_INCLUDE:", 16) == 0) &&
+ !flag_debug)
+ continue;
+ if ((strncmp (Cur_File->name, "GNU_CC_INCLUDE:", 15) == 0) &&
+ !flag_debug)
+ continue;
+ /* show a few extra lines at the start of the region selected */
+ if (Cur_File->min_line > 2)
+ Cur_File->min_line -= 2;
+ Cur_File->offset = Debugger_Offset - Cur_File->min_line + 1;
+ Debugger_Offset += Cur_File->max_line - Cur_File->min_line + 1;
+ if (Cur_File->same_file_fpnt)
+ {
+ Cur_File->file_number = Cur_File->same_file_fpnt->file_number;
+ }
+ else
+ {
+ Cur_File->file_number = ++File_Number;
+ file_available = VMS_TBT_Source_File (Cur_File->name,
+ Cur_File->file_number);
+ if (!file_available)
+ {
+ Cur_File->file_number = 0;
+ File_Number--;
+ continue;
+ }
+ }
+ VMS_TBT_Source_Lines (Cur_File->file_number,
+ Cur_File->min_line,
+ Cur_File->max_line - Cur_File->min_line + 1);
+ } /* for */
+ Cur_File = (struct input_file *) NULL;
+
+ /*
+ * Scan the symbols and write out the routines
+ * (this makes the assumption that symbols are in
+ * order of ascending text segment offset)
+ */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
+ {
+ /*
+ * Deal with text symbols.
+ */
+ if (!S_IS_DEBUG (symbolP) && S_GET_TYPE (symbolP) == N_TEXT)
+ {
+ /*
+ * Ignore symbols starting with "L", as they are local symbols.
+ */
+ if (*S_GET_NAME (symbolP) == 'L')
+ continue;
+ /*
+ * If there is a routine start defined, terminate it.
+ */
+ if (Current_Routine)
+ VMS_TBT_Routine_End (text_siz, Current_Routine);
+
+ /*
+ * Check for & skip dummy labels like "gcc_compiled.".
+ * They're identified by the IN_DEFAULT_SECTION flag.
+ */
+ if ((S_GET_OTHER (symbolP) & IN_DEFAULT_SECTION) != 0 &&
+ S_GET_VALUE (symbolP) == 0)
+ continue;
+ /*
+ * Store the routine begin traceback info.
+ */
+ VMS_TBT_Routine_Begin (symbolP, Text_Psect);
+ Current_Routine = symbolP;
+ /*
+ * Define symbols local to this routine.
+ */
+ local_symbols_DST (symbolP, Current_Routine);
+ /*
+ * Done
+ */
+ continue;
+
+ }
+ /*
+ * Deal with STAB symbols.
+ */
+ else if (S_IS_DEBUG (symbolP))
+ {
+ /*
+ * Dispatch on STAB type.
+ */
+ switch (S_GET_RAW_TYPE (symbolP))
+ {
+ /*
+ * Line number
+ */
+ case N_SLINE:
+ /* Offset the line into the correct portion of the file. */
+ if (Cur_File->file_number == 0)
+ break;
+ val = S_GET_VALUE (symbolP);
+ /* Sometimes the same offset gets several source lines
+ assigned to it. We should be selective about which
+ lines we allow, we should prefer lines that are in
+ the main source file when debugging inline functions. */
+ if (val == Cur_Offset && Cur_File->file_number != 1)
+ break;
+
+ /* calculate actual debugger source line */
+ dsc = S_GET_DESC (symbolP) + Cur_File->offset;
+ S_SET_DESC (symbolP, dsc);
+ /*
+ * Define PC/Line correlation.
+ */
+ if (Cur_Offset == -1)
+ {
+ /*
+ * First N_SLINE; set up initial correlation.
+ */
+ VMS_TBT_Line_PC_Correlation (dsc,
+ val,
+ Text_Psect,
+ 0);
+ }
+ else if ((dsc - Cur_Line_Number) <= 0)
+ {
+ /*
+ * Line delta is not +ve, we need to close the line and
+ * start a new PC/Line correlation.
+ */
+ VMS_TBT_Line_PC_Correlation (0,
+ val - Cur_Offset,
+ 0,
+ -1);
+ VMS_TBT_Line_PC_Correlation (dsc,
+ val,
+ Text_Psect,
+ 0);
+ }
+ else
+ {
+ /*
+ * Line delta is +ve, all is well.
+ */
+ VMS_TBT_Line_PC_Correlation (dsc - Cur_Line_Number,
+ val - Cur_Offset,
+ 0,
+ 1);
+ }
+ /* Update the current line/PC info. */
+ Cur_Line_Number = dsc;
+ Cur_Offset = val;
+ break;
+
+ /*
+ * Source file
+ */
+ case N_SO:
+ /* Remember that we had a source file and emit
+ the source file debugger record. */
+ Cur_File = find_file (symbolP);
+ break;
+
+ case N_SOL:
+ /* We need to make sure that we are really in the actual
+ source file when we compute the maximum line number.
+ Otherwise the debugger gets really confused. */
+ Cur_File = find_file (symbolP);
+ break;
+
+ default:
+ break;
+ } /* switch */
+ } /* if (IS_DEBUG) */
+ } /* for */
+
+ /*
+ * If there is a routine start defined, terminate it
+ * (and the line numbers).
+ */
+ if (Current_Routine)
+ {
+ /* Terminate the line numbers. */
+ VMS_TBT_Line_PC_Correlation (0,
+ text_siz - S_GET_VALUE (Current_Routine),
+ 0,
+ -1);
+ /* Terminate the routine. */
+ VMS_TBT_Routine_End (text_siz, Current_Routine);
+ }
+
+ /* Write the Traceback End Module TBT record. */
+ VMS_TBT_Module_End ();
+}
+
+
+/* Write a VAX/VMS object file (everything else has been done!). */
+
+void
+vms_write_object_file (text_siz, data_siz, bss_siz, text_frag_root,
+ data_frag_root)
+ unsigned text_siz;
+ unsigned data_siz;
+ unsigned bss_siz;
+ fragS *text_frag_root;
+ fragS *data_frag_root;
+{
+ register struct VMS_Symbol *vsp;
+
+ /*
+ * Initialize program section indices; values get updated later.
+ */
+ Psect_Number = 0; /* next Psect Index to use */
+ Text_Psect = -1; /* Text Psect Index */
+ Data_Psect = -2; /* Data Psect Index JF: Was -1 */
+ Bss_Psect = -3; /* Bss Psect Index JF: Was -1 */
+ Ctors_Psect = -4; /* Ctors Psect Index */
+ Dtors_Psect = -5; /* Dtors Psect Index */
+ /* Initialize other state variables. */
+ Data_Segment = 0;
+ Local_Initd_Data_Size = 0;
+
+ /*
+ * Create the actual output file and populate it with required
+ * "module header" information.
+ */
+ Create_VMS_Object_File ();
+ Write_VMS_MHD_Records ();
+
+ /*
+ * Create the Data segment:
+ *
+ * Since this is REALLY hard to do any other way,
+ * we actually manufacture the data segment and
+ * then store the appropriate values out of it.
+ * We need to generate this early, so that globalvalues
+ * can be properly emitted.
+ */
+ if (data_siz > 0)
+ synthesize_data_segment (data_siz, text_siz, data_frag_root);
+
+
+ /******* Global Symbol Directory *******/
+
+ /*
+ * Emit globalvalues now. We must do this before the text psect is
+ * defined, or we will get linker warnings about multiply defined
+ * symbols. All of the globalvalues "reference" psect 0, although
+ * it really does not have anything to do with it.
+ */
+ VMS_Emit_Globalvalues (text_siz, data_siz, Data_Segment);
+ /*
+ * Define the Text Psect
+ */
+ Text_Psect = Psect_Number++;
+ VMS_Psect_Spec ("$code", text_siz, ps_TEXT, 0);
+ /*
+ * Define the BSS Psect
+ */
+ if (bss_siz > 0)
+ {
+ Bss_Psect = Psect_Number++;
+ VMS_Psect_Spec ("$uninitialized_data", bss_siz, ps_DATA, 0);
+ }
+ /*
+ * Define symbols to the linker.
+ */
+ global_symbol_directory (text_siz, data_siz);
+ /*
+ * Define the Data Psect
+ */
+ if (data_siz > 0 && Local_Initd_Data_Size > 0)
+ {
+ Data_Psect = Psect_Number++;
+ VMS_Psect_Spec ("$data", Local_Initd_Data_Size, ps_DATA, 0);
+ /*
+ * Local initialized data (N_DATA) symbols need to be updated to the
+ * proper value of Data_Psect now that it's actually been defined.
+ * (A dummy value was used in global_symbol_directory() above.)
+ */
+ for (vsp = VMS_Symbols; vsp; vsp = vsp->Next)
+ if (vsp->Psect_Index < 0 && S_GET_RAW_TYPE (vsp->Symbol) == N_DATA)
+ vsp->Psect_Index = Data_Psect;
+ }
+
+
+ if (Ctors_Symbols != 0)
+ {
+ char *ps_name = "$ctors";
+ Ctors_Psect = Psect_Number++;
+ VMS_Psect_Spec (ps_name, Ctors_Symbols->Psect_Offset + XTOR_SIZE,
+ ps_CTORS, 0);
+ VMS_Global_Symbol_Spec (ps_name, Ctors_Psect,
+ 0, GBLSYM_DEF|GBLSYM_WEAK);
+ for (vsp = Ctors_Symbols; vsp; vsp = vsp->Next)
+ vsp->Psect_Index = Ctors_Psect;
+ }
+
+ if (Dtors_Symbols != 0)
+ {
+ char *ps_name = "$dtors";
+ Dtors_Psect = Psect_Number++;
+ VMS_Psect_Spec (ps_name, Dtors_Symbols->Psect_Offset + XTOR_SIZE,
+ ps_DTORS, 0);
+ VMS_Global_Symbol_Spec (ps_name, Dtors_Psect,
+ 0, GBLSYM_DEF|GBLSYM_WEAK);
+ for (vsp = Dtors_Symbols; vsp; vsp = vsp->Next)
+ vsp->Psect_Index = Dtors_Psect;
+ }
+
+ /******* Text Information and Relocation Records *******/
+
+ /*
+ * Write the text segment data
+ */
+ if (text_siz > 0)
+ vms_fixup_text_section (text_siz, text_frag_root, data_frag_root);
+ /*
+ * Write the data segment data, then discard it.
+ */
+ if (data_siz > 0)
+ {
+ vms_fixup_data_section (data_siz, text_siz);
+ free (Data_Segment), Data_Segment = 0;
+ }
+
+ if (Ctors_Symbols != 0)
+ {
+ vms_fixup_xtors_section (Ctors_Symbols, Ctors_Psect);
+ }
+
+ if (Dtors_Symbols != 0)
+ {
+ vms_fixup_xtors_section (Dtors_Symbols, Dtors_Psect);
+ }
+
+
+ /******* Debugger Symbol Table Records *******/
+
+ vms_build_DST (text_siz);
+
+
+ /******* Wrap things up *******/
+
+ /*
+ * Write the End Of Module record
+ */
+ if (Entry_Point_Symbol)
+ Write_VMS_EOM_Record (Text_Psect, S_GET_VALUE (Entry_Point_Symbol));
+ else
+ Write_VMS_EOM_Record (-1, (valueT) 0);
+
+ /*
+ * All done, close the object file
+ */
+ Close_VMS_Object_File ();
+}
+
+/* end of obj-vms.c */