diff options
Diffstat (limited to 'gas/config/obj-vms.c')
-rw-r--r-- | gas/config/obj-vms.c | 5549 |
1 files changed, 0 insertions, 5549 deletions
diff --git a/gas/config/obj-vms.c b/gas/config/obj-vms.c deleted file mode 100644 index 0f08f8eb3f3..00000000000 --- a/gas/config/obj-vms.c +++ /dev/null @@ -1,5549 +0,0 @@ -/* 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 */ |