diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /gnu/usr.bin/gas/config/obj-vms.c |
initial import of NetBSD tree
Diffstat (limited to 'gnu/usr.bin/gas/config/obj-vms.c')
-rw-r--r-- | gnu/usr.bin/gas/config/obj-vms.c | 5484 |
1 files changed, 5484 insertions, 0 deletions
diff --git a/gnu/usr.bin/gas/config/obj-vms.c b/gnu/usr.bin/gas/config/obj-vms.c new file mode 100644 index 00000000000..5d12387e30d --- /dev/null +++ b/gnu/usr.bin/gas/config/obj-vms.c @@ -0,0 +1,5484 @@ +/* vms.c -- Write out a VAX/VMS object file + Copyright (C) 1987, 1988, 1992 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Written by David L. Kashtan */ +/* Modified by Eric Youngdale to write VMS debug records for program + variables */ +#include "as.h" +#include "subsegs.h" +#include "obstack.h" + +/* What we do if there is a goof. */ +#define error as_fatal + +#ifdef HO_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*/ +#endif +/* + * Version string of the compiler that produced the code we are + * assembling. (And this assembler, if we do not have compiler info.) + */ +extern const char version_string[]; +char *compiler_version_string; + +/* 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, irregardless of the setting of the -h switch. + */ + +char vms_name_mapping = 0; + + +extern char *strchr (); +extern char *myname; +static symbolS *Entry_Point_Symbol = 0; /* Pointer to "_main" */ + +/* + * We augment the "gas" symbol structure with this + */ +struct VMS_Symbol +{ + struct VMS_Symbol *Next; + struct symbol *Symbol; + int Size; + int Psect_Index; + int Psect_Offset; +}; +struct VMS_Symbol *VMS_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; + + +static struct input_file *find_file (symbolS *); + +/* + * 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, 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; + enum advanced_type advanced; /* description of what this is */ + int dbx_type; /* this record is for this type */ + int type2; /* 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 VMS_type; /* Use this type when generating a variable def */ + int index_min; /* used for arrays - this will be present for all */ + int index_max; /* entries, but will be meaningless for non-arrays */ + int data_size; /* size in bytes of the data type. For an array, this + is the size of one element in the array */ + int struc_numb; /* Number of the structure/union/enum - used for ref */ +}; + +struct VMS_DBG_Symbol *VMS_Symbol_type_list = +{(struct VMS_DBG_Symbol *) NULL}; + +/* + * 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 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 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; + + +/* + * 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 gave_compiler_message = 0; + +/* A pointer to the current routine that we are working on. */ + +static symbolS *Current_Routine; + +/* The psect number for $code a.k.a. the text section. */ + +static int Text_Psect; + + +/* + * 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 placing data into the object record buffer + */ + +#define PUT_LONG(val) \ +{ md_number_to_chars(Object_Record_Buffer + \ + Object_Record_Offset, val, 4); \ + Object_Record_Offset += 4; } + +#define PUT_SHORT(val) \ +{ md_number_to_chars(Object_Record_Buffer + \ + Object_Record_Offset, val, 2); \ + Object_Record_Offset += 2; } + +#define PUT_CHAR(val) Object_Record_Buffer[Object_Record_Offset++] = val + +#define PUT_COUNTED_STRING(cp) {\ + register char *p = cp; \ + PUT_CHAR(strlen(p)); \ + while (*p) PUT_CHAR(*p++);} + +/* + * 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[0] == '_' ? 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, /* absent */ + N_UNDF, /* pass1 */ + N_UNDF, /* error */ + N_UNDF, /* bignum/flonum */ + N_UNDF, /* difference */ + 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, +}; + + +/* The following code defines the special types of pseudo-ops that we + * use with VMS. + */ + +char const_flag = 0; + +void +s_const () +{ + register int temp; + + temp = get_absolute_expression (); + subseg_new (SEG_DATA, (subsegT) temp); + const_flag = 1; + demand_empty_rest_of_line (); +} + +/* + * stab() + * + * Handle .stabX directives, which used to be open-coded. + * So much creeping featurism overloaded the semantics that we decided + * to put all .stabX thinking in one place. Here. + * + * We try to make any .stabX directive legal. Other people's AS will often + * do assembly-time consistency checks: eg assigning meaning to n_type bits + * and "protecting" you from setting them to certain values. (They also zero + * certain bits before emitting symbols. Tut tut.) + * + * If an expression is not absolute we either gripe or use the relocation + * information. Other people's assemblers silently forget information they + * don't need and invent information they need that you didn't supply. + * + * .stabX directives always make a symbol table entry. It may be junk if + * the rest of your .stabX directive is malformed. + */ +static void +obj_aout_stab (what) + int what; +{ + register symbolS *symbolP = 0; + register char *string; + int saved_type = 0; + int length; + int goof; /* TRUE if we have aborted. */ + long longint; + +/* + * Enter with input_line_pointer pointing past .stabX and any following + * whitespace. + */ + goof = 0; /* JF who forgot this?? */ + if (what == 's') + { + string = demand_copy_C_string (&length); + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + input_line_pointer++; + else + { + as_bad ("I need a comma after symbol's name"); + goof = 1; + } + } + else + string = ""; + +/* + * Input_line_pointer->after ','. String->symbol name. + */ + if (!goof) + { + symbolP = symbol_new (string, + SEG_UNKNOWN, + 0, + (struct frag *) 0); + switch (what) + { + case 'd': + S_SET_NAME (symbolP, NULL); /* .stabd feature. */ + S_SET_VALUE (symbolP, obstack_next_free (&frags) - frag_now->fr_literal); + symbolP->sy_frag = frag_now; + break; + + case 'n': + symbolP->sy_frag = &zero_address_frag; + break; + + case 's': + symbolP->sy_frag = &zero_address_frag; + break; + + default: + BAD_CASE (what); + break; + } + + if (get_absolute_expression_and_terminator (&longint) == ',') + symbolP->sy_symbol.n_type = saved_type = longint; + else + { + as_bad ("I want a comma after the n_type expression"); + goof = 1; + input_line_pointer--; /* Backup over a non-',' char. */ + } + } + + if (!goof) + { + if (get_absolute_expression_and_terminator (&longint) == ',') + S_SET_OTHER (symbolP, longint); + else + { + as_bad ("I want a comma after the n_other expression"); + goof = 1; + input_line_pointer--; /* Backup over a non-',' char. */ + } + } + + if (!goof) + { + S_SET_DESC (symbolP, get_absolute_expression ()); + if (what == 's' || what == 'n') + { + if (*input_line_pointer != ',') + { + as_bad ("I want a comma after the n_desc expression"); + goof = 1; + } + else + { + input_line_pointer++; + } + } + } + + if ((!goof) && (what == 's' || what == 'n')) + { + pseudo_set (symbolP); + symbolP->sy_symbol.n_type = saved_type; + } + + if (goof) + ignore_rest_of_line (); + else + demand_empty_rest_of_line (); +} /* obj_aout_stab() */ + +const pseudo_typeS obj_pseudo_table[] = +{ + {"stabd", obj_aout_stab, 'd'},/* stabs */ + {"stabn", obj_aout_stab, 'n'},/* stabs */ + {"stabs", obj_aout_stab, 's'},/* stabs */ + {"const", s_const, 0}, + {0, 0, 0}, + +}; /* obj_pseudo_table */ + +void +obj_read_begin_hook () +{ + return; +} /* obj_read_begin_hook() */ + +void +obj_crawl_symbol_chain (headers) + object_headers *headers; +{ + symbolS *symbolP; + symbolS **symbolPP; + int symbol_number = 0; + + /* JF deal with forward references first... */ + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) + { + if (symbolP->sy_forward) + { + S_SET_VALUE (symbolP, S_GET_VALUE (symbolP) + + S_GET_VALUE (symbolP->sy_forward) + + symbolP->sy_forward->sy_frag->fr_address); + symbolP->sy_forward = 0; + } /* if it has a forward reference */ + } /* walk the symbol chain */ + + { /* crawl symbol table */ + register int symbol_number = 0; + + { + symbolPP = &symbol_rootP; /* -> last symbol chain link. */ + while ((symbolP = *symbolPP) != NULL) + { + S_GET_VALUE (symbolP) += symbolP->sy_frag->fr_address; + + /* 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 that don't are: + * symbols that are registers + * symbols with \1 as their 3rd character (numeric labels) + * "local labels" as defined by S_LOCAL_NAME(name) + if the -L switch was passed to gas. + + All other symbols are output. We complain if a deleted + symbol was marked external. */ + + + if (!S_IS_REGISTER (symbolP)) + { + 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. */ + + } /* 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); + } /* crawl symbol table */ + +} /* obj_crawl_symbol_chain() */ + + + /****** VMS OBJECT FILE HACKING ROUTINES *******/ + + +/* + * Create the VMS object file + */ +static +Create_VMS_Object_File () +{ +#if defined(eunice) || !defined(HO_VMS) + VMS_Object_File_FD = creat (out_file_name, 0777, "var"); +#else /* eunice */ + VMS_Object_File_FD = creat (out_file_name, 0, "rfm=var", + "mbc=16", "deq=64", "fop=tef", "shr=nil"); +#endif /* eunice */ + /* + * Deal with errors + */ + if (VMS_Object_File_FD < 0) + { + char Error_Line[256]; + + sprintf (Error_Line, "Couldn't create VMS object file \"%s\"", + out_file_name); + error (Error_Line); + } + /* + * Initialize object file hacking variables + */ + Object_Record_Offset = 0; + Current_Object_Record_Type = -1; +} + + +/* + * Flush the object record buffer to the object file + */ +static +Flush_VMS_Object_Record_Buffer () +{ + int i; + short int zero; + /* + * If the buffer is empty, we are done + */ + if (Object_Record_Offset == 0) + return; + /* + * Write the data to the file + */ +#ifndef HO_VMS /* For cross-assembly purposes. */ + i = write (VMS_Object_File_FD, &Object_Record_Offset, 2); +#endif /* not HO_VMS */ + i = write (VMS_Object_File_FD, + Object_Record_Buffer, + Object_Record_Offset); + if (i != Object_Record_Offset) + error ("I/O error writing VMS object file"); +#ifndef HO_VMS /* When cross-assembling, we need to pad the record to an even + number of bytes. */ + /* pad it if needed */ + zero = 0; + if (Object_Record_Offset & 1 != 0) + write (VMS_Object_File_FD, &zero, 1); +#endif /* not HO_VMS */ + /* + * The buffer is now empty + */ + Object_Record_Offset = 0; +} + + +/* + * Declare a particular type of object file record + */ +static +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 (); + /* + * Set the new type + */ + Current_Object_Record_Type = Type; +} + + + +/* + * Close the VMS Object file + */ +static +Close_VMS_Object_File () +{ + short int m_one = -1; +#ifndef HO_VMS /* For cross-assembly purposes. */ +/* Write a 0xffff into the file, which means "End of File" */ + write (VMS_Object_File_FD, &m_one, 2); +#endif /* not HO_VMS */ + close (VMS_Object_File_FD); +} + + +/* + * Store immediate data in current Psect + */ +static +VMS_Store_Immediate_Data (Pointer, Size, Record_Type) + register char *Pointer; + int Size; + int Record_Type; +{ + register int i; + + /* + * We are writing a "Record_Type" record + */ + Set_VMS_Object_File_Record (Record_Type); + /* + * We can only store 128 bytes at a time + */ + while (Size > 0) + { + /* + * Store a maximum of 128 bytes + */ + 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 + */ + PUT_CHAR (-i & 0xff); + /* + * 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 +VMS_Set_Data (Psect_Index, Offset, Record_Type, Force) + int Psect_Index; + int Offset; + int Record_Type; + int Force; +{ + /* + * 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 + Longword Offset + */ + if (Force == 1) + { + if (Psect_Index > 127) + { + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (Psect_Index); + PUT_LONG (Offset); + } + else + { + PUT_CHAR (TIR_S_C_STA_PL); + PUT_CHAR (Psect_Index); + PUT_LONG (Offset); + } + } + else + { + if (Offset > 32767) + { + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (Psect_Index); + PUT_LONG (Offset); + } + else if (Offset > 127) + { + PUT_CHAR (TIR_S_C_STA_WPW); + PUT_SHORT (Psect_Index); + PUT_SHORT (Offset); + } + else + { + PUT_CHAR (TIR_S_C_STA_WPB); + PUT_SHORT (Psect_Index); + PUT_CHAR (Offset); + }; + }; + /* + * 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 +VMS_Store_Struct (int Struct_Index) +{ + /* + * We are writing a "OBJ_S_C_DBG" 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 +VMS_Def_Struct (int Struct_Index) +{ + /* + * We are writing a "OBJ_S_C_DBG" 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 +VMS_Set_Struct (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 (); +} + +/* + * Write the Traceback Module Begin record + */ +static +VMS_TBT_Module_Begin () +{ + register char *cp, *cp1; + int Size; + char Module_Name[256]; + char Local[256]; + + /* + * 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 + */ + while (--cp1 >= Module_Name) + if (*cp1 == '.') + *cp1 = 0; + if (strlen (Module_Name) > 31) + { + if (flagseen['+']) + printf ("%s: Module name truncated: %s\n", myname, Module_Name); + Module_Name[31] = 0; + } + /* + * Arrange to store the data locally (leave room for size byte) + */ + cp = Local + 1; + /* + * Begin module + */ + *cp++ = DST_S_C_MODBEG; + /* + * Unused + */ + *cp++ = 0; + /* + * Language type == "C" + */ + *(long *) cp = DST_S_C_C; + cp += sizeof (long); + /* + * Store the module name + */ + *cp++ = 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 +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 the Traceback Routine Begin record + */ +static +VMS_TBT_Routine_Begin (symbolP, Psect) + struct symbol *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); + /* + * Calculate the record size + */ + Size = 1 + 1 + 4 + 1 + strlen (Name); + /* + * Record Size + */ + Local[0] = Size; + /* + * Begin Routine + */ + 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); + /* + * Now get the symbol address + */ + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (Psect); + 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_TBT); +} + + +/* + * Write the 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 +VMS_TBT_Routine_End (Max_Size, sp) + int Max_Size; + symbolS *sp; +{ + symbolS *symbolP; + int Size = 0x7fffffff; + char Local[16]; + + + 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; + if ((S_GET_VALUE (symbolP) > S_GET_VALUE (sp)) && + (S_GET_VALUE (symbolP) < Size)) + Size = S_GET_VALUE (symbolP); + /* check if gcc_compiled. has size of zero */ + if ((S_GET_VALUE (symbolP) == S_GET_VALUE (sp)) && + sp != symbolP && + (!strcmp (S_GET_NAME (sp), "gcc_compiled.") || + !strcmp (S_GET_NAME (sp), "gcc2_compiled."))) + Size = S_GET_VALUE (symbolP); + + }; + }; + if (Size == 0x7fffffff) + Size = Max_Size; + Size -= S_GET_VALUE (sp); /* and get the size of the routine */ + /* + * Record Size + */ + Local[0] = 6; + /* + * End of Routine + */ + Local[1] = DST_S_C_RTNEND; + /* + * Unused + */ + Local[2] = 0; + /* + * Size of routine + */ + *((long *) (Local + 3)) = Size; + /* + * Store the record + */ + VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_TBT); +} + +/* + * Write the Traceback Block End record + */ +static +VMS_TBT_Block_Begin (symbolP, Psect, Name) + struct symbol *symbolP; + int Psect; + char *Name; +{ + register char *cp, *cp1; + int Offset; + int Size; + char Local[512]; + /* + * Begin block + */ + Size = 1 + 1 + 4 + 1 + strlen (Name); + /* + * Record Size + */ + Local[0] = Size; + /* + * 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 OBJ_S_C_DBG 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 the Traceback Block End record + */ +static +VMS_TBT_Block_End (int Size) +{ + char Local[16]; + + /* + * End block - simulate with a phony end routine + */ + Local[0] = 6; + Local[1] = DST_S_C_BLKEND; + *((long *) (Local + 3)) = Size; + /* + * Unused + */ + Local[2] = 0; + VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_DBG); +} + + + +/* + * Write a Line number / PC correlation record + */ +static +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 not delta, set our PC/Line number correlation +*/ + if (Do_Delta == 0) + { + /* + * Size + */ + Local[0] = 1 + 1 + 2 + 1 + 4; + /* + * Line Number/PC correlation + */ + Local[1] = DST_S_C_LINE_NUM; + /* + * Set Line number + */ + Local[2] = DST_S_C_SET_LINE_NUM; + *((unsigned short *) (Local + 3)) = Line_Number - 1; + /* + * Set PC + */ + Local[5] = DST_S_C_SET_ABS_PC; + VMS_Store_Immediate_Data (Local, 6, 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); + if (Psect < 255) + { + PUT_CHAR (TIR_S_C_STA_PL); + PUT_CHAR (Psect); + } + else + { + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (Psect); + } + PUT_LONG (Offset); + 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 Delta is negative, terminate the line numbers + */ + if (Do_Delta < 0) + { + Local[0] = 1 + 1 + 4; + Local[1] = DST_S_C_LINE_NUM; + Local[2] = DST_S_C_TERM_L; + *((long *) (Local + 3)) = Offset; + VMS_Store_Immediate_Data (Local, 7, OBJ_S_C_TBT); + /* + * Done + */ + 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 + { + *cp++ = DST_S_C_INCR_LINUM_W; + *(short *) cp = Line_Number - 1; + cp += sizeof (short); + } + } + /* + * Increment the PC + */ + if (Offset <= 128) + { + *cp++ = -Offset; + } + else + { + if (Offset < 0x10000) + { + *cp++ = DST_S_C_DELTA_PC_W; + *(short *) cp = Offset; + cp += sizeof (short); + } + else + { + *cp++ = DST_S_C_DELTA_PC_L; + *(long *) cp = Offset; + cp += sizeof (long); + } + } + Local[0] = cp - (Local + 1); + VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT); + } +} + + +/* + * Describe a source file to the debugger + */ +static +VMS_TBT_Source_File (Filename, ID_Number) + char *Filename; + int ID_Number; +{ + register char *cp, *cp1; + int Status, i; + char Local[512]; +#ifndef HO_VMS /* Used for cross-assembly */ + i = strlen (Filename); +#else /* HO_VMS */ + static struct FAB Fab; + static struct NAM Nam; + static struct XABDAT Date_Xab; + static struct XABFHC File_Header_Xab; + char Es_String[255], Rs_String[255]; + + /* + * Setup the Fab + */ + Fab.fab$b_bid = FAB$C_BID; + Fab.fab$b_bln = sizeof (Fab); + Fab.fab$l_nam = (&Nam); + Fab.fab$l_xab = (char *) &Date_Xab; + /* + * Setup the Nam block so we can find out the FULL name + * of the source file. + */ + Nam.nam$b_bid = NAM$C_BID; + Nam.nam$b_bln = sizeof (Nam); + Nam.nam$l_rsa = Rs_String; + Nam.nam$b_rss = sizeof (Rs_String); + Nam.nam$l_esa = Es_String; + Nam.nam$b_ess = sizeof (Es_String); + /* + * Setup the Date and File Header Xabs + */ + Date_Xab.xab$b_cod = XAB$C_DAT; + Date_Xab.xab$b_bln = sizeof (Date_Xab); + Date_Xab.xab$l_nxt = (char *) &File_Header_Xab; + File_Header_Xab.xab$b_cod = XAB$C_FHC; + File_Header_Xab.xab$b_bln = sizeof (File_Header_Xab); + /* + * Get the file information + */ + Fab.fab$l_fna = Filename; + Fab.fab$b_fns = strlen (Filename); + Status = sys$open (&Fab); + if (!(Status & 1)) + { + printf ("gas: Couldn't find source file \"%s\", Error = %%X%x\n", + Filename, Status); + return (0); + } + sys$close (&Fab); + /* + * Calculate the size of the resultant string + */ + i = Nam.nam$b_rsl; +#endif /* HO_VMS */ + /* + * Size of record + */ + Local[0] = 1 + 1 + 1 + 1 + 1 + 2 + 8 + 4 + 2 + 1 + 1 + i + 1; + /* + * Source declaration + */ + Local[1] = DST_S_C_SOURCE; + /* + * Make formfeeds count as source records + */ + Local[2] = DST_S_C_SRC_FORMFEED; + /* + * Declare source file + */ + Local[3] = DST_S_C_SRC_DECLFILE; + Local[4] = 1 + 2 + 8 + 4 + 2 + 1 + 1 + i + 1; + cp = Local + 5; + /* + * Flags + */ + *cp++ = 0; + /* + * File ID + */ + *(short *) cp = ID_Number; + cp += sizeof (short); +#ifndef HO_VMS + /* + * Creation Date. Unknown, so we fill with zeroes. + */ + *(long *) cp = 0; + cp += sizeof (long); + *(long *) cp = 0; + cp += sizeof (long); + /* + * End of file block + */ + *(long *) cp = 0; + cp += sizeof (long); + /* + * First free byte + */ + *(short *) cp = 0; + cp += sizeof (short); + /* + * Record format + */ + *cp++ = 0; + /* + * Filename + */ + *cp++ = i; + cp1 = Filename; +#else /* Use this code when assembling for VMS on a VMS system */ + /* + * Creation Date + */ + *(long *) cp = ((long *) &Date_Xab.xab$q_cdt)[0]; + cp += sizeof (long); + *(long *) cp = ((long *) &Date_Xab.xab$q_cdt)[1]; + cp += sizeof (long); + /* + * End of file block + */ + *(long *) cp = File_Header_Xab.xab$l_ebk; + cp += sizeof (long); + /* + * First free byte + */ + *(short *) cp = File_Header_Xab.xab$w_ffb; + cp += sizeof (short); + /* + * Record format + */ + *cp++ = File_Header_Xab.xab$b_rfo; + /* + * Filename + */ + *cp++ = i; + cp1 = Rs_String; +#endif /* HO_VMS */ + while (--i >= 0) + *cp++ = *cp1++; + /* + * Library module name (none) + */ + *cp++ = 0; + /* + * Done + */ + VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT); + return 1; +} + + +/* + * Give the number of source lines to the debugger + */ +static +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, *cp1; + char Local[16]; + + /* + * Size of record + */ + Local[0] = 1 + 1 + 2 + 1 + 4 + 1 + 2; + /* + * Source declaration + */ + Local[1] = DST_S_C_SOURCE; + /* + * Set Source File + */ + cp = Local + 2; + *cp++ = DST_S_C_SRC_SETFILE; + /* + * File ID Number + */ + *(short *) cp = ID_Number; + cp += sizeof (short); + /* + * Set record number + */ + *cp++ = DST_S_C_SRC_SETREC_L; + *(long *) cp = Starting_Line_Number; + cp += sizeof (long); + /* + * Define lines + */ + *cp++ = DST_S_C_SRC_DEFLINES_W; + *(short *) cp = Number_Of_Lines; + cp += sizeof (short); + /* + * Done + */ + VMS_Store_Immediate_Data (Local, cp - Local, OBJ_S_C_TBT); +} + + + + +/* 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; + struct input_file *fpnt; + same_file = (struct input_file *) NULL; + for (fpnt = file_root; fpnt; fpnt = fpnt->next) + { + if (fpnt == (struct input_file *) NULL) + break; + if (fpnt->spnt == sp) + return fpnt; + }; + for (fpnt = file_root; fpnt; fpnt = fpnt->next) + { + if (fpnt == (struct input_file *) NULL) + break; + if (strcmp (S_GET_NAME (sp), fpnt->name) == 0) + { + if (fpnt->flag == 1) + return fpnt; + same_file = fpnt; + break; + }; + }; + fpnt = (struct input_file *) malloc (sizeof (struct input_file)); + if (file_root == (struct input_file *) NULL) + file_root = fpnt; + else + { + struct input_file *fpnt1; + for (fpnt1 = file_root; fpnt1->next; fpnt1 = fpnt1->next) ; + fpnt1->next = fpnt; + }; + fpnt->next = (struct input_file *) NULL; + fpnt->name = S_GET_NAME (sp); + 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; +} + +/* + * 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 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, neg; + neg = *str == '-' ? ++str, -1 : 1; + ival = 0; /* first get the number of the type for dbx */ + while ((*str <= '9') && (*str >= '0')) + ival = 10 * ival + *str++ - '0'; + *rtn = neg * ival; + return str; +} + +/* 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 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; + while (spnt != (struct VMS_DBG_Symbol *) NULL) + { + if (spnt->dbx_type == dbx_type) + break; + spnt = spnt->next; + }; + if (spnt == (struct VMS_DBG_Symbol *) NULL) + return 0; /*Dunno what this is*/ + return spnt; +} + + +/* 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 +push (value, size) + int value, size; +{ + char *pnt; + int i; + int size1; + long int val; + val = value; + pnt = (char *) &val; + size1 = size; + if (size < 0) + { + size1 = -size; + pnt += size1 - 1; + }; + if (size < 0) + for (i = 0; i < size1; i++) + { + Local[Lpnt--] = *pnt--; + if (Lpnt < 0) + { + overflow = 1; + Lpnt = 1; + }; + } + else + for (i = 0; i < size1; i++) + { + Asuffix[Apoint++] = *pnt++; + if (Apoint >= MAX_DEBUG_RECORD) + { + overflow = 1; + Apoint = MAX_DEBUG_RECORD - 1; + }; + } +} + +/* this routine generates the array descriptor for a given array */ +static +array_suffix (spnt2) + struct VMS_DBG_Symbol *spnt2; +{ + struct VMS_DBG_Symbol *spnt; + struct VMS_DBG_Symbol *spnt1; + int rank; + int total_size; + int i; + rank = 0; + spnt = spnt2; + while (spnt->advanced != ARRAY) + { + spnt = find_symbol (spnt->type2); + if (spnt == (struct VMS_DBG_Symbol *) NULL) + return; + }; + spnt1 = spnt; + 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; + push (spnt1->data_size, 2); + if (spnt1->VMS_type == 0xa3) + push (0, 1); + else + push (spnt1->VMS_type, 1); + push (4, 1); + for (i = 0; i < 6; i++) + push (0, 1); + push (0xc0, 1); + push (rank, 1); + push (total_size, 4); + push (0, 4); + spnt1 = spnt; + while (spnt1->advanced == ARRAY) + { + push (spnt1->index_max - spnt1->index_min + 1, 4); + spnt1 = find_symbol (spnt1->type2); + }; + spnt1 = spnt; + while (spnt1->advanced == ARRAY) + { + push (spnt1->index_min, 4); + push (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 +new_forward_ref (dbx_type) + int dbx_type; +{ + struct forward_ref *fpnt; + fpnt = (struct forward_ref *) malloc (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'; + push (3, -1); + total_len = 5; + push (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: + push (DBG_S_C_VOID, -1); + total_len += 1; + push (total_len, -2); + return 0; + case BASIC: + case FUNCTION: + if (array_suffix_len == 0) + { + push (spnt->VMS_type, -1); + push (DBG_S_C_BASIC, -1); + total_len = 2; + push (total_len, -2); + return 1; + }; + push (0, -4); + push (0xfa02, -2); + 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; + } + push (DBG_S_C_STRUCT, -1); + total_len = 5; + push (total_len, -2); + return 1; + case POINTER: + spnt1 = find_symbol (spnt->type2); + i = 1; + if (spnt1 == (struct VMS_DBG_Symbol *) NULL) + new_forward_ref (spnt->type2); + else + i = gen1 (spnt1, 0); + if (i) + { /* (*void) is a special case, do not put pointer suffix*/ + push (DBG_S_C_POINTER, -1); + total_len += 3; + push (total_len, -2); + }; + return 1; + case ARRAY: + spnt1 = spnt; + while (spnt1->advanced == ARRAY) + { + spnt1 = find_symbol (spnt1->type2); + if (spnt1 == (struct VMS_DBG_Symbol *) NULL) + { + printf ("gcc-as warning(debugger output):"); + printf ("Forward reference error, dbx type %d\n", + spnt->type2); + return; + } + }; +/* It is too late to generate forward references, so the user gets a message. + * This should only happen on a compiler error */ + i = gen1 (spnt1, 1); + i = Apoint; + array_suffix (spnt); + array_suffix_len = Apoint - i; + switch (spnt1->advanced) + { + case BASIC: + case FUNCTION: + break; + default: + push (0, -2); + total_len += 2; + push (total_len, -2); + push (0xfa, -1); + push (0x0101, -2); + push (DBG_S_C_COMPLEX_ARRAY, -1); + }; + total_len += array_suffix_len + 8; + push (total_len, -2); + }; +} + +/* 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 +generate_suffix (spnt, dbx_type) + struct VMS_DBG_Symbol *spnt; + int dbx_type; +{ + int ilen; + int i; + char pvoid[6] = + {5, 0xaf, 0, 1, 0, 5}; + struct VMS_DBG_Symbol *spnt1; + Apoint = 0; + Lpnt = MAX_DEBUG_RECORD - 1; + total_len = 0; + struct_number = 0; + overflow = 0; + if (spnt == (struct VMS_DBG_Symbol *) NULL) + new_forward_ref (dbx_type); + else + { + if (spnt->VMS_type != 0xa3) + return 0; /* no suffix needed */ + gen1 (spnt, 0); + }; + push (0x00af, -2); + total_len += 4; + push (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) + { + printf (" 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 a reference to a 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); + for (i = 0; i < 4; i++) + Local[Lpnt++] = 0; + 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; +} + +/* This routine generates a symbol definition for a C sybmol 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 +VMS_DBG_record (spnt, Psect, Offset, Name) + struct VMS_DBG_Symbol *spnt; + int Psect; + int Offset; + char *Name; +{ + char *pnt; + char *Name_pnt; + int j; + int maxlen; + int i = 0; + Name_pnt = fix_name (Name); /* if there are bad characters in name, convert them */ + if (Psect < 0) + { /* this is a local variable, referenced to SP */ + maxlen = 7 + strlen (Name_pnt); + Local[i++] = maxlen; + Local[i++] = spnt->VMS_type; + if (Offset > 0) + Local[i++] = DBG_S_C_FUNCTION_PARAMETER; + else + Local[i++] = DBG_S_C_LOCAL_SYM; + pnt = (char *) &Offset; + for (j = 0; j < 4; j++) + Local[i++] = *pnt++; /* copy the offset */ + } + else + { + maxlen = 7 + strlen (Name_pnt); /* symbols fixed in memory */ + Local[i++] = 7 + strlen (Name_pnt); + Local[i++] = spnt->VMS_type; + Local[i++] = 1; + VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); + i = 0; + VMS_Set_Data (Psect, Offset, OBJ_S_C_DBG, 0); + } + Local[i++] = strlen (Name_pnt); + 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 int +VMS_local_stab_Parse (sp) + symbolS *sp; +{ + char *pnt; + char *pnt1; + char *str; + struct VMS_DBG_Symbol *spnt; + struct VMS_Symbol *vsp; + int dbx_type; + int VMS_type; + dbx_type = 0; + str = S_GET_NAME (sp); + pnt = (char *) strchr (str, ':'); + if (pnt == (char *) NULL) + return; /* no colon present */ + pnt1 = pnt++; /* save this for later, and skip colon */ + if (*pnt == 'c') + return 0; /* 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. + */ + { + char *str1; + char *pnt2; + symbolS *sp1; + 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) + { + char * pnt3=(char*) strchr (S_GET_NAME (sp1), ':') + 1; + if (*pnt3 == 'F' || *pnt3 == '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 != ':')) + continue; + return; /* they are the same! lets skip this one */ + }; /* for */ +/* first find the dbx symbol type from list, and then find VMS type */ + pnt++; /* skip p in case no register */ + }; /* if */ + }; /* p block */ + pnt = cvt_integer (pnt, &dbx_type); + spnt = find_symbol (dbx_type); + if (spnt == (struct VMS_DBG_Symbol *) NULL) + return 0; /*Dunno what this is*/ + *pnt1 = '\0'; + VMS_DBG_record (spnt, -1, S_GET_VALUE (sp), str); + *pnt1 = ':'; /* and restore the string */ + return 1; +} + +/* 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 +VMS_stab_parse (sp, expected_type, type1, type2, Text_Psect) + symbolS *sp; + char expected_type; + 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; + int VMS_type; + dbx_type = 0; + str = S_GET_NAME (sp); + pnt = (char *) strchr (str, ':'); + if (pnt == (char *) NULL) + 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 == (struct VMS_DBG_Symbol *) NULL) + return 0; /*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 != (struct VMS_Symbol *) NULL) + { + pnt = S_GET_NAME (vsp->Symbol); + if (pnt != (char *) NULL) + if (*pnt++ == '_') +/* make sure name is the same, and make sure correct symbol type */ + if ((strlen (pnt) == strlen (str)) && (strcmp (pnt, str) == 0) + && ((S_GET_RAW_TYPE (vsp->Symbol) == type1) || + (S_GET_RAW_TYPE (vsp->Symbol) == type2))) + break; + vsp = vsp->Next; + }; + if (vsp != (struct VMS_Symbol *) NULL) + { + VMS_DBG_record (spnt, vsp->Psect_Index, vsp->Psect_Offset, str); + *pnt1 = ':'; /* and restore the string */ + return 1; + }; +/* 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') + { + printf ("***Warning - the assembly code generated by the compiler has placed\n"); + printf ("global constant(s) in the text psect. These will not be available to\n"); + printf ("other modules, since this is not the correct way to handle this. You\n"); + printf ("have two options: 1) get a patched compiler that does not put global\n"); + printf ("constants in the text psect, or 2) remove the 'const' keyword from\n"); + printf ("definitions of global variables in your source module(s). Don't say\n"); + printf ("I didn't warn you!"); + gave_compiler_message = 1; + }; + VMS_DBG_record (spnt, + Text_Psect, + S_GET_VALUE (sp1), + str); + *pnt1 = ':'; + *S_GET_NAME (sp1) = 'L'; + /* fool assembler to not output this + * as a routine in the TBT */ + return 1; + }; + }; + }; + *pnt1 = ':'; /* and restore the string */ + return 0; +} + +static +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 +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 +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 +VMS_RSYM_Parse (sp, Current_Routine, Text_Psect) + symbolS *sp, *Current_Routine; + int Text_Psect; +{ + char *pnt; + char *pnt1; + char *str; + int dbx_type; + struct VMS_DBG_Symbol *spnt; + int j; + int maxlen; + int i = 0; + int bcnt = 0; + int Min_Offset = -1; /* min PC of validity */ + int Max_Offset = 0; /* max PC of validity */ + symbolS *symbolP; + 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); + for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) + { + /* + * Dispatch on STAB type + */ + This_Offset = S_GET_VALUE (symbolP); + switch (S_GET_RAW_TYPE (symbolP)) + { + case N_TEXT | N_EXT: + if ((This_Offset > Min_Offset) && (This_Offset < Max_Offset)) + Max_Offset = This_Offset; + break; + case N_SLINE: + if (This_Offset > Max_Source_Offset) + Max_Source_Offset = This_Offset; + } + } +/* 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); + pnt = (char *) strchr (str, ':'); + if (pnt == (char *) NULL) + return; /* no colon present */ + pnt1 = pnt; /* save this for later*/ + pnt++; + if (*pnt != 'r') + return 0; + pnt = cvt_integer (pnt + 1, &dbx_type); + spnt = find_symbol (dbx_type); + if (spnt == (struct VMS_DBG_Symbol *) NULL) + return 0; /*Dunno what this is yet*/ + *pnt1 = '\0'; + pnt = fix_name (S_GET_NAME (sp)); /* if there are bad characters in name, convert them */ + maxlen = 25 + strlen (pnt); + Local[i++] = maxlen; + Local[i++] = spnt->VMS_type; + Local[i++] = 0xfb; + Local[i++] = strlen (pnt) + 1; + Local[i++] = 0x00; + Local[i++] = 0x00; + Local[i++] = 0x00; + Local[i++] = strlen (pnt); + while (*pnt != '\0') + Local[i++] = *pnt++; + Local[i++] = 0xfd; + Local[i++] = 0x0f; + Local[i++] = 0x00; + Local[i++] = 0x03; + Local[i++] = 0x01; + 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++] = 0x03; + Local[i++] = S_GET_VALUE (sp); + Local[i++] = 0x00; + Local[i++] = 0x00; + Local[i++] = 0x00; + 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; +{ + int i; + struct VMS_DBG_Symbol *spnt; + struct VMS_DBG_Symbol *spnt1; + 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); + if (spnt == (struct VMS_DBG_Symbol *) NULL) + return 0; + while ((spnt->advanced == POINTER) || (spnt->advanced == ARRAY)) + { + i = spnt->type2; + spnt1 = find_symbol (spnt->type2); + if ((spnt->advanced == ARRAY) && + (spnt1 == (struct VMS_DBG_Symbol *) NULL)) + return 1; + if (spnt1 == (struct VMS_DBG_Symbol *) NULL) + break; + spnt = spnt1; + }; + pnt = cvt_integer (pnt + 1, &i); + pnt = cvt_integer (pnt + 1, &i); + } while (*++pnt != ';'); + 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. + */ +static int +VMS_typedef_parse (str) + char *str; +{ + char *pnt; + char *pnt1; + char *pnt2; + int i; + int dtype; + struct forward_ref *fpnt; + int i1, i2, i3; + int convert_integer; + struct VMS_DBG_Symbol *spnt; + struct VMS_DBG_Symbol *spnt1; +/* check for any nested def's */ + pnt = (char *) strchr (str + 1, '='); + if ((pnt != (char *) NULL) && (*(str + 1) != '*')) + if (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 we see if this has been defined already, due to a forward reference*/ + if (spnt == (struct VMS_DBG_Symbol *) NULL) + { + if (VMS_Symbol_type_list == (struct VMS_DBG_Symbol *) NULL) + { + spnt = (struct VMS_DBG_Symbol *) malloc (sizeof (struct VMS_DBG_Symbol)); + spnt->next = (struct VMS_DBG_Symbol *) NULL; + VMS_Symbol_type_list = spnt; + } + else + { + spnt = (struct VMS_DBG_Symbol *) malloc (sizeof (struct VMS_DBG_Symbol)); + spnt->next = VMS_Symbol_type_list; + VMS_Symbol_type_list = spnt; + }; + spnt->dbx_type = i1; /* and save the type */ + }; +/* 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 == 'u') || (*pnt == 's')) + { + }; + if ((*pnt <= '9') && (*pnt >= '0')) + { + if (type_check ("void")) + { /* this is the void symbol */ + *str = '\0'; + spnt->advanced = VOID; + return 0; + }; + if (type_check ("unknown type")) + { /* this is the void symbol */ + *str = '\0'; + spnt->advanced = UNKNOWN; + return 0; + }; + printf ("gcc-as warning(debugger output):"); + printf (" %d is an unknown untyped variable.\n", spnt->dbx_type); + return 1; /* do not know what this is */ + }; +/* now define this module*/ + 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 = DBG_S_C_REAL8; + spnt->data_size = 8; + } + pnt1 = (char *) strchr (str, ';') + 1; + break; + case 's': + case 'u': + if (*pnt == 's') + spnt->advanced = STRUCT; + else + spnt->advanced = UNION; + spnt->VMS_type = DBG_S_C_ADVANCED_TYPE; + pnt1 = cvt_integer (pnt + 1, &spnt->data_size); + if (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); + fpnt = f_ref_root; + while (fpnt != (struct forward_ref *) NULL) + { + if (fpnt->dbx_type == spnt->dbx_type) + { + fpnt->resolved = 'Y'; + VMS_Set_Struct (fpnt->struc_numb); + VMS_Store_Struct (spnt->struc_numb); + }; + fpnt = fpnt->next; + }; + VMS_Set_Struct (spnt->struc_numb); + i = 0; + Local[i++] = 11 + strlen (pnt); + Local[i++] = DBG_S_C_STRUCT_START; + Local[i++] = 0x80; + for (i1 = 0; i1 < 4; i1++) + Local[i++] = 0x00; + Local[i++] = strlen (pnt); + pnt2 = pnt; + while (*pnt2 != '\0') + Local[i++] = *pnt2++; + i2 = spnt->data_size * 8; /* number of bits */ + pnt2 = (char *) &i2; + for (i1 = 0; i1 < 4; i1++) + Local[i++] = *pnt2++; + 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); + if ((dtype == 1) && (i3 != 32)) + { /* bitfield */ + Apoint = 0; + push (19 + strlen (pnt2), 1); + push (0xfa22, 2); + push (1 + strlen (pnt2), 4); + push (strlen (pnt2), 1); + while (*pnt2 != '\0') + push (*pnt2++, 1); + push (i3, 2); /* size of bitfield */ + push (0x0d22, 2); + push (0x00, 4); + push (i2, 4); /* start position */ + VMS_Store_Immediate_Data (Asuffix, Apoint, OBJ_S_C_DBG); + Apoint = 0; + } + else + { + Local[i++] = 7 + strlen (pnt2); + spnt1 = find_symbol (dtype); + /* check if this is a forward reference */ + if (spnt1 != (struct VMS_DBG_Symbol *) NULL) + Local[i++] = spnt1->VMS_type; + else + Local[i++] = DBG_S_C_ADVANCED_TYPE; + Local[i++] = DBG_S_C_STRUCT_ITEM; + pnt = (char *) &i2; + for (i1 = 0; i1 < 4; i1++) + Local[i++] = *pnt++; + Local[i++] = strlen (pnt2); + while (*pnt2 != '\0') + Local[i++] = *pnt2++; + VMS_Store_Immediate_Data (Local, i, OBJ_S_C_DBG); + i = 0; + if (spnt1 == (struct VMS_DBG_Symbol *) NULL) + 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); + fpnt = f_ref_root; + while (fpnt != (struct forward_ref *) NULL) + { + if (fpnt->dbx_type == spnt->dbx_type) + { + fpnt->resolved = 'Y'; + VMS_Set_Struct (fpnt->struc_numb); + VMS_Store_Struct (spnt->struc_numb); + }; + fpnt = fpnt->next; + }; + VMS_Set_Struct (spnt->struc_numb); + i = 0; + Local[i++] = 3 + strlen (symbol_name); + Local[i++] = DBG_S_C_ENUM_START; + Local[i++] = 0x20; + Local[i++] = strlen (symbol_name); + 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); + Local[i++] = 7 + strlen (pnt); + Local[i++] = DBG_S_C_ENUM_ITEM; + Local[i++] = 0x00; + pnt2 = (char *) &i1; + for (i2 = 0; i2 < 4; i2++) + Local[i++] = *pnt2++; + Local[i++] = strlen (pnt); + 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 == (char *) NULL) + 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); + 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 != (char *) NULL)) + if (VMS_typedef_parse (pnt) == 1) + return 1; + break; + default: + spnt->advanced = UNKNOWN; + spnt->VMS_type = 0; + printf ("gcc-as warning(debugger output):"); + printf (" %d is an unknown type of variable.\n", 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. + */ +static int +VMS_LSYM_Parse () +{ + char *pnt; + char *pnt1; + char *pnt2; + char *str; + char fixit[10]; + int incomplete, i, pass, incom1; + struct VMS_DBG_Symbol *spnt; + struct VMS_Symbol *vsp; + struct forward_ref *fpnt; + symbolS *sp; + 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 = (char *) strchr (str, ':'); + if (pnt == (char *) NULL) + break; + *pnt = '\0'; + pnt1 = pnt + 1; + pnt2 = (char *) strchr (pnt1, '='); + if (pnt2 == (char *) NULL) + { + *pnt = ':'; /* replace colon */ + break; + }; /* no symbol here */ + incomplete += VMS_typedef_parse (pnt2); + *pnt = ':'; /* put back colon so variable def code finds dbx_type*/ + break; + } /*switch*/ + } /* if */ + } /*for*/ + pass++; + } while ((incomplete != 0) && (incomplete != incom1)); + /* repeat until all refs resolved if possible */ +/* if (pass > 1) printf(" Required %d passes\n",pass);*/ + if (incomplete != 0) + { + printf ("gcc-as warning(debugger output):"); + printf ("Unable to resolve %d circular references.\n", incomplete); + }; + fpnt = f_ref_root; + symbol_name = "\0"; + while (fpnt != (struct forward_ref *) NULL) + { + if (fpnt->resolved != 'Y') + { + if (find_symbol (fpnt->dbx_type) != + (struct VMS_DBG_Symbol *) NULL) + { + printf ("gcc-as warning(debugger output):"); + printf ("Forward reference error, dbx type %d\n", + 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 +Define_Local_Symbols (s1, s2) + symbolS *s1, *s2; +{ + symbolS *symbolP1; + for (symbolP1 = symbol_next (s1); symbolP1 != s2; symbolP1 = symbol_next (symbolP1)) + { + if (symbolP1 == (symbolS *) NULL) + return; + if (S_GET_RAW_TYPE (symbolP1) == N_FUN) + { + char * pnt=(char*) strchr (S_GET_NAME (symbolP1), ':') + 1; + if (*pnt == 'F' || *pnt == 'f') break; + }; + /* + * Deal with STAB symbols + */ + if (S_IS_DEBUG (symbolP1)) + { + /* + * Dispatch on STAB type + */ + switch (S_GET_RAW_TYPE (symbolP1)) + { + case N_LSYM: + case N_PSYM: + VMS_local_stab_Parse (symbolP1); + break; + case N_RSYM: + VMS_RSYM_Parse (symbolP1, Current_Routine, Text_Psect); + break; + } /*switch*/ + } /* if */ + } /* 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 (symbolP, Level) + symbolS *symbolP; + int Level; +{ + symbolS *sstart; + symbolS *symbolP1; + char str[10]; + int rcount = 0; + int Offset; + sstart = symbolP; + for (symbolP1 = symbol_next (symbolP); symbolP1; symbolP1 = symbol_next (symbolP1)) + { + if (S_GET_RAW_TYPE (symbolP1) == N_FUN) + { + char * pnt=(char*) strchr (S_GET_NAME (symbolP1), ':') + 1; + if (*pnt == 'F' || *pnt == 'f') break; + }; + /* + * Deal with STAB symbols + */ + if (S_IS_DEBUG (symbolP1)) + { + /* + * Dispatch on STAB type + */ + switch (S_GET_RAW_TYPE (symbolP1)) + { + case N_LBRAC: + if (Level != 0) + { + sprintf (str, "$%d", rcount++); + VMS_TBT_Block_Begin (symbolP1, Text_Psect, str); + }; + Offset = S_GET_VALUE (symbolP1); + Define_Local_Symbols (sstart, symbolP1); + symbolP1 = + Define_Routine (symbolP1, Level + 1); + if (Level != 0) + VMS_TBT_Block_End (S_GET_VALUE (symbolP1) - + Offset); + sstart = symbolP1; + break; + case N_RBRAC: + return symbolP1; + } /*switch*/ + } /* if */ + } /* for */ + /* we end up here if there were no brackets in this function. Define +everything */ + Define_Local_Symbols (sstart, (symbolS *) 0); + return symbolP1; +} + + +static +VMS_DBG_Define_Routine (symbolP, Curr_Routine, Txt_Psect) + symbolS *symbolP; + symbolS *Curr_Routine; + int Txt_Psect; +{ + Current_Routine = Curr_Routine; + Text_Psect = Txt_Psect; + Define_Routine (symbolP, 0); +} + + + + +#ifndef HO_VMS +#include <sys/types.h> +#include <time.h> + +/* Manufacure a VMS like time on a unix based system. */ +get_VMS_time_on_unix (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 HO_VMS */ +/* + * Write the MHD (Module Header) records + */ +static +Write_VMS_MHD_Records () +{ + register char *cp, *cp1; + register int i; + struct + { + int Size; + char *Ptr; + } Descriptor; + char Module_Name[256]; + char Now[18]; + + /* + * 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)); + /* + * 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 (flagseen['+']) + printf ("%s: Module name truncated: %s\n", myname, 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) + */ +#ifndef HO_VMS + get_VMS_time_on_unix (&Now[0]); +#else /* HO_VMS */ + Descriptor.Size = 17; + Descriptor.Ptr = Now; + sys$asctim (0, &Descriptor, 0, 0); +#endif /* HO_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); + /* + * Flush the 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!) + */ + cp = compiler_version_string; + if (cp == 0) + { + cp = "GNU AS V"; + while (*cp) + PUT_CHAR (*cp++); + cp = strchr (&version_string, '.'); + while (*cp != ' ') + cp--; + cp++; + }; + while (*cp >= 32) + PUT_CHAR (*cp++); + /* + * Flush the record + */ + Flush_VMS_Object_Record_Buffer (); +} + + +/* + * Write the EOM (End Of Module) record + */ +static +Write_VMS_EOM_Record (Psect, Offset) + int Psect; + int Offset; +{ + /* + * We are writing an end-of-module record + */ + Set_VMS_Object_File_Record (OBJ_S_C_EOM); + /* + * Store record Type + */ + PUT_CHAR (OBJ_S_C_EOM); + /* + * Store the error severity (0) + */ + PUT_CHAR (0); + /* + * Store the entry point, if it exists + */ + if (Psect >= 0) + { + /* + * Store the entry point Psect + */ + PUT_CHAR (Psect); + /* + * Store the entry point Psect offset + */ + PUT_LONG (Offset); + } + /* + * Flush the record + */ + Flush_VMS_Object_Record_Buffer (); +} + + +/* this hash routine borrowed from GNU-EMACS, and strengthened slightly ERY*/ + +static int +hash_string (ptr) + unsigned char *ptr; +{ + register unsigned char *p = ptr; + register 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 +VMS_Case_Hack_Symbol (In, Out) + register char *In; + register char *Out; +{ + long int init = 0; + long int result; + char *pnt; + char *new_name; + 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*/ + if (strlen (In) > 23) + result = hash_string (In); + /* + * 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 && flagseen['+']) + printf("%s: Symbol name truncated: %s\n",myname,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 (flagseen['h'] || 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 && !flagseen['h']) + 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 (!flagseen['+']) + 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; + if (init < 10) + *Out++ = '0' + init; + else + *Out++ = 'A' + init - 10; + result = result >> 5; + } + } + } /*Case Hack */ + /* + * Done + */ + *Out = 0; + if (truncate == 1 && flagseen['+'] && flagseen['H']) + printf ("%s: Symbol %s replaced by %s\n", myname, old_name, new_name); +} + + +/* + * Scan a symbol name for a psect attribute specification + */ +#define GLOBALSYMBOL_BIT 0x10000 +#define GLOBALVALUE_BIT 0x20000 + + +static +VMS_Modify_Psect_Attributes (Name, Attribute_Pointer) + char *Name; + int *Attribute_Pointer; +{ + register int i; + register char *cp; + int Negate; + static struct + { + 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++; + } + /* + * Done + */ + return; +} + + +/* + * Define a global symbol + */ +static +VMS_Global_Symbol_Spec (Name, Psect_Number, Psect_Offset, Defined) + char *Name; + int Psect_Number; + int Psect_Offset; +{ + 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 symbol definition subrecord + */ + if (Psect_Number <= 255) + { + PUT_CHAR (GSD_S_C_SYM); + } + else + { + PUT_CHAR (GSD_S_C_SYMW); + } + /* + * Data type is undefined + */ + PUT_CHAR (0); + /* + * Switch on Definition/Reference + */ + if ((Defined & 1) != 0) + { + /* + * Definition: + * Flags = "RELOCATABLE" and "DEFINED" for regular symbol + * = "DEFINED" for globalvalue (Defined & 2 == 1) + */ + if ((Defined & 2) == 0) + { + PUT_SHORT (GSY_S_M_DEF | GSY_S_M_REL); + } + else + { + PUT_SHORT (GSY_S_M_DEF); + }; + /* + * Psect Number + */ + if (Psect_Number <= 255) + { + PUT_CHAR (Psect_Number); + } + else + { + PUT_SHORT (Psect_Number); + } + /* + * Offset + */ + PUT_LONG (Psect_Offset); + } + else + { + /* + * Reference: + * Flags = "RELOCATABLE" for regular symbol, + * = "" for globalvalue (Defined & 2 == 1) + */ + if ((Defined & 2) == 0) + { + PUT_SHORT (GSY_S_M_REL); + } + else + { + PUT_SHORT (0); + }; + } + /* + * 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 a psect + */ +static int +VMS_Psect_Spec (Name, Size, Type, vsp) + char *Name; + int Size; + char *Type; + struct VMS_Symbol *vsp; +{ + char Local[32]; + int Psect_Attributes; + + /* + * Generate the appropriate PSECT flags given the PSECT type + */ + if (strcmp (Type, "COMMON") == 0) + { + /* + * Common block psects are: PIC,OVR,REL,GBL,SHR,RD,WRT + */ + Psect_Attributes = (GPS_S_M_PIC | GPS_S_M_OVR | GPS_S_M_REL | GPS_S_M_GBL | + GPS_S_M_SHR | GPS_S_M_RD | GPS_S_M_WRT); + } + else if (strcmp (Type, "CONST") == 0) + { + /* + * Common block psects are: PIC,OVR,REL,GBL,SHR,RD + */ + Psect_Attributes = (GPS_S_M_PIC | GPS_S_M_OVR | GPS_S_M_REL | GPS_S_M_GBL | + GPS_S_M_SHR | GPS_S_M_RD); + } + else if (strcmp (Type, "DATA") == 0) + { + /* + * The Data psects are PIC,REL,RD,WRT + */ + Psect_Attributes = + (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_RD | GPS_S_M_WRT); + } + else if (strcmp (Type, "TEXT") == 0) + { + /* + * The Text psects are PIC,REL,SHR,EXE,RD + */ + Psect_Attributes = + (GPS_S_M_PIC | GPS_S_M_REL | GPS_S_M_SHR | + GPS_S_M_EXE | GPS_S_M_RD); + } + else + { + /* + * Error: Unknown psect type + */ + error ("Unknown VMS psect type"); + } + /* + * Modify the psect attributes according to any attribute string + */ + 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_GET_RAW_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, 0); + vsp->Psect_Index = -1; + S_GET_RAW_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, 1); + /* In this case we still generate the psect */ + break; + default: + { + char Error_Line[256]; + sprintf (Error_Line, "Globalsymbol attribute for" + " symbol %s was unexpected.\n", Name); + error (Error_Line); + 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 int +VMS_Initialized_Data_Size (sp, End_Of_Data) + register struct symbol *sp; + int End_Of_Data; +{ + register struct symbol *sp1, *Next_Symbol; + + /* + * Find the next symbol + * it delimits this datum + */ + Next_Symbol = 0; + for (sp1 = symbol_rootP; sp1; sp1 = symbol_next (sp1)) + { + /* + * The data type must match + */ + if (S_GET_TYPE (sp1) != N_DATA) + continue; + /* + * The symbol must be AFTER this symbol + */ + if (S_GET_VALUE (sp1) <= S_GET_VALUE (sp)) + continue; + /* + * We ignore THIS symbol + */ + if (sp1 == sp) + continue; + /* + * If there is already a candidate selected for the + * next symbol, see if we are a better candidate + */ + if (Next_Symbol) + { + /* + * We are a better candidate if we are "closer" + * to the symbol + */ + if (S_GET_VALUE (sp1) > + S_GET_VALUE (Next_Symbol)) + continue; + /* + * Win: Make this the candidate + */ + Next_Symbol = sp1; + } + else + { + /* + * This is the 1st candidate + */ + Next_Symbol = sp1; + } + } + /* + * Calculate its size + */ + return (Next_Symbol ? + (S_GET_VALUE (Next_Symbol) - + S_GET_VALUE (sp)) : + (End_Of_Data - S_GET_VALUE (sp))); +} + +/* + * Check symbol names for the Psect hack with a globalvalue, and then + * generate globalvalues for those that have it. + */ +static +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; + + /* + * 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) + { + /* + * See if this is something we want to look at. + */ + if ((S_GET_RAW_TYPE (sp) != (N_DATA | N_EXT)) && + (S_GET_RAW_TYPE (sp) != (N_UNDF | N_EXT))) + continue; + /* + * See if this has globalvalue specification. + */ + Name = S_GET_NAME (sp); + + if (!HAS_PSECT_ATTRIBUTES (Name)) + continue; + + stripped_name = (char *) malloc (strlen (Name) + 1); + strcpy (stripped_name, Name); + Psect_Attributes = 0; + VMS_Modify_Psect_Attributes (stripped_name, &Psect_Attributes); + + if ((Psect_Attributes & GLOBALVALUE_BIT) != 0) + { + switch (S_GET_RAW_TYPE (sp)) + { + case N_UNDF | N_EXT: + VMS_Global_Symbol_Spec (stripped_name, 0, 0, 2); + 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 = 0; + + memcpy (&globalvalue, 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, 2); + VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue, 3); + VMS_Global_Symbol_Spec (stripped_name, 0, globalvalue, 3); + break; + default: + printf (" Invalid globalvalue of %s\n", stripped_name); + break; + }; /* switch */ + }; /* if */ + free (stripped_name); /* clean up */ + }; /* for */ + +} + + +/* + * Define a procedure entry pt/mask + */ +static +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 + */ + if (Psect_Number <= 255) + { + PUT_CHAR (GSD_S_C_EPM); + } + else + { + PUT_CHAR (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 (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 +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 + Longword Offset + */ + if (Psect_Index < 255) + { + PUT_CHAR (TIR_S_C_STA_PL); + PUT_CHAR (Psect_Index); + } + else + { + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (Psect_Index); + } + PUT_LONG (Offset); + /* + * 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 +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 + */ + if ((Size == sizeof (char)) && (*Pointer == 0)) + return; + if ((Size == sizeof (short)) && (*(short *) Pointer == 0)) + return; + if ((Size == sizeof (long)) && (*(long *) Pointer == 0)) + return; + /* + * 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 +VMS_Store_PIC_Symbol_Reference (Symbol, Offset, PC_Relative, + Psect, Psect_Offset, Record_Type) + struct symbol *Symbol; + int Offset; + int PC_Relative; + int Psect; + int Psect_Offset; + int Record_Type; +{ + register struct VMS_Symbol *vsp = + (struct VMS_Symbol *) (Symbol->sy_number); + char Local[32]; + + /* + * 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 + */ + if (PC_Relative) + { + /* + * For a Code reference we need to fix the operand + * specifier as well (so back up 1 byte) + */ + VMS_Set_Psect (Psect, Psect_Offset - 1, Record_Type); + } + else + { + /* + * For a Data reference we just store HERE + */ + VMS_Set_Psect (Psect, 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 + */ +#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 + */ + PUT_CHAR (TIR_S_C_STA_GBL); + 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) + */ + if (vsp->Psect_Index < 255) + { + PUT_CHAR (TIR_S_C_STA_PL); + PUT_CHAR (vsp->Psect_Index); + } + else + { + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (vsp->Psect_Index); + } + PUT_LONG (vsp->Psect_Offset + Offset); + break; + /* + * Local text + */ + case N_TEXT: + /* + * Stack the Psect (+offset) + */ + if (vsp->Psect_Index < 255) + { + PUT_CHAR (TIR_S_C_STA_PL); + PUT_CHAR (vsp->Psect_Index); + } + else + { + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (vsp->Psect_Index); + } + PUT_LONG (S_GET_VALUE (Symbol) + Offset); + 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) + */ + if (vsp->Psect_Index < 255) + { + PUT_CHAR (TIR_S_C_STA_PL); + PUT_CHAR (vsp->Psect_Index); + } + else + { + PUT_CHAR (TIR_S_C_STA_WPL); + PUT_SHORT (vsp->Psect_Index); + } + PUT_LONG (vsp->Psect_Offset + Offset); + 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 +VMS_Fix_Indirect_Reference (Text_Psect, Offset, fragP, text_frag_root) + int Text_Psect; + int Offset; + register fragS *fragP; + struct frag *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 = 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); + } +} + + + +/* + * This is a hacked _doprnt() for VAX-11 "C". It understands that + * it is ONLY called by as_fatal(Format, Args) with a pointer to the + * "Args" argument. From this we can make it all work right! + */ +#if !defined(eunice) && defined(HO_VMS) +_doprnt (Format, a, f) + char *Format; + FILE *f; + char **a; +{ + int Nargs = ((int *) a)[-2]; /* This understands as_fatal() */ + + switch (Nargs) + { + default: + fprintf (f, "_doprnt error on \"%s\"!!", Format); + break; + case 1: + fprintf (f, Format); + break; + case 2: + fprintf (f, Format, a[0]); + break; + case 3: + fprintf (f, Format, a[0], a[1]); + break; + case 4: + fprintf (f, Format, a[0], a[1], a[2]); + break; + case 5: + fprintf (f, Format, a[0], a[1], a[2], a[3]); + break; + case 6: + fprintf (f, Format, a[0], a[1], a[2], a[3], a[4]); + break; + case 7: + fprintf (f, Format, a[0], a[1], a[2], a[3], a[4], a[5]); + break; + case 8: + fprintf (f, Format, a[0], a[1], a[2], a[3], a[4], a[5], a[6]); + break; + case 9: + fprintf (f, Format, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); + break; + case 10: + fprintf (f, Format, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); + break; + } +} + +#endif /* eunice */ + + +/* + * 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". + */ +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 = (struct symbol *) 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 (!flagseen['+']) + { +#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_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_GET_NAME (symbolP) = "_c$main_args"; + S_SET_TYPE (symbolP, N_UNDF); + S_GET_OTHER (symbolP) = 0; + S_GET_DESC (symbolP) = 0; + S_GET_VALUE (symbolP) = 0; + symbolP->sy_name_offset = 0; + symbolP->sy_number = 0; + symbolP->sy_frag = New_Frag; + symbolP->sy_forward = 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 = sizeof (long); + 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 */ + } +} + +/* + * Write a VAX/VMS object file (everything else has been done!) + */ +VMS_write_object_file (text_siz, data_siz, text_frag_root, data_frag_root) + unsigned text_siz; + unsigned data_siz; + struct frag *text_frag_root; + struct frag *data_frag_root; +{ + register fragS *fragP; + register symbolS *symbolP; + register symbolS *sp; + register struct fix *fixP; + register struct VMS_Symbol *vsp; + char *Data_Segment; + int Local_Initialized_Data_Size = 0; + int Globalref; + int Psect_Number = 0; /* Psect Index Number */ + int Text_Psect = -1; /* Text Psect Index */ + int Data_Psect = -2; /* Data Psect Index JF: Was -1 */ + int Bss_Psect = -3; /* Bss Psect Index JF: Was -1 */ + + /* + * Create the VMS object file + */ + Create_VMS_Object_File (); + /* + * Write the module header records + */ + Write_VMS_MHD_Records (); + + /* + * Store the Data segment: + * + * Since this is REALLY hard to do any other way, + * we actually manufacture the data segment and + * the store the appropriate values out of it. + * We need to generate this early, so that globalvalues + * can be properly emitted. + */ + if (data_siz > 0) + { + /* + * 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) + { + register long int count; + register char *fill_literal; + register long int fill_size; + int i; + + i = fragP->fr_address - text_siz; + if (fragP->fr_fix) + memcpy (Data_Segment + i, + fragP->fr_literal, + fragP->fr_fix); + i += fragP->fr_fix; + + fill_literal = fragP->fr_literal + fragP->fr_fix; + fill_size = fragP->fr_var; + for (count = fragP->fr_offset; count; count--) + { + if (fill_size) + memcpy (Data_Segment + i, fill_literal, fill_size); + i += fill_size; + } + } + } + + + /* + * Generate the VMS object file records + * 1st GSD then TIR records + */ + + /******* Global Symbol Dictionary *******/ + /* + * 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, "TEXT", 0); + /* + * Define the BSS Psect + */ + if (local_bss_counter > 0) + { + Bss_Psect = Psect_Number++; + VMS_Psect_Spec ("$uninitialized_data", local_bss_counter, "DATA", + 0); + } +#ifndef gxx_bug_fixed + /* + * 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. + */ + for (sp = symbol_rootP; sp; sp = symbol_next (sp)) + { + /* + * Dispatch on symbol type + */ + switch (S_GET_RAW_TYPE (sp)) { + /* + * Global Reference + */ + case N_UNDF: + /* + * Make a GSD global symbol reference + * record. + */ + if (strncmp (S_GET_NAME (sp),"__vt.",5) == 0) + { + S_GET_RAW_TYPE (sp) = N_UNDF | N_EXT; + as_warn("g++ wrote an extern reference to %s as a routine.", + S_GET_NAME (sp)); + as_warn("I will fix it, but I hope that it was not really a routine"); + }; + break; + default: + break; + } + } +#endif /* gxx_bug_fixed */ + /* + * Now scan the symbols and emit the appropriate GSD records + */ + for (sp = symbol_rootP; sp; sp = symbol_next (sp)) + { + /* + * 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_number = (int) vsp; + /* + * Make the psect for this data + */ + if (S_GET_OTHER (sp)) + Globalref = VMS_Psect_Spec ( + S_GET_NAME (sp), + vsp->Size, + "CONST", + vsp); + else + Globalref = VMS_Psect_Spec ( + S_GET_NAME (sp), + vsp->Size, + "COMMON", + vsp); + if (Globalref) + Psect_Number--; +#ifdef NOT_VAX_11_C_COMPATIBLE + /* + * Place a global symbol at the + * beginning of the Psect + */ + VMS_Global_Symbol_Spec (S_GET_NAME (sp), + vsp->Psect_Index, + 0, + 1); +#endif /* NOT_VAX_11_C_COMPATIBLE */ + 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_number = (int) 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_number = (int) vsp; + /* + * Make its psect + */ + if (S_GET_OTHER (sp)) + Globalref = VMS_Psect_Spec ( + S_GET_NAME (sp), + vsp->Size, + "CONST", + vsp); + else + Globalref = VMS_Psect_Spec ( + S_GET_NAME (sp), + vsp->Size, + "COMMON", + vsp); + if (Globalref) + Psect_Number--; +#ifdef NOT_VAX_11_C_COMPATIBLE + /* + * Place a global symbol at the + * beginning of the Psect + */ + VMS_Global_Symbol_Spec (S_GET_NAME (sp), + vsp->Psect_Index, + 0, + 1); +#endif /* NOT_VAX_11_C_COMPATIBLE */ + break; + /* + * Local initialized data + */ + case N_DATA: + /* + * 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_Initialized_Data_Size; + Local_Initialized_Data_Size += vsp->Size; + vsp->Next = VMS_Symbols; + VMS_Symbols = vsp; + sp->sy_number = (int) vsp; + break; + /* + * Global Text definition + */ + case N_TEXT | N_EXT: + { + unsigned short Entry_Mask; + + /* + * Get the entry mask + */ + fragP = sp->sy_frag; + Entry_Mask = (fragP->fr_literal[0] & 0xff) + + ((fragP->fr_literal[1] & 0xff) + << 8); + /* + * Define the Procedure entry pt. + */ + 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_number = (int) vsp; + } + break; + /* + * Global Reference + */ + case N_UNDF: + /* + * Make a GSD global symbol reference + * record. + */ + VMS_Global_Symbol_Spec (S_GET_NAME (sp), + 0, + 0, + 0); + break; + /* + * Anything else + */ + default: + /* + * Ignore STAB symbols + * Including .stabs emitted by g++ + */ + if (S_IS_DEBUG (sp) || (S_GET_TYPE (sp) == 22)) + break; + /* + * Error + */ + if (S_GET_TYPE (sp) != 22) + printf (" ERROR, unknown type (%d)\n", + S_GET_TYPE (sp)); + break; + } + } + /* + * Define the Data Psect + */ + if ((data_siz > 0) && (Local_Initialized_Data_Size > 0)) + { + /* + * Do it + */ + Data_Psect = Psect_Number++; + VMS_Psect_Spec ("$data", + Local_Initialized_Data_Size, + "DATA", 0); + /* + * Scan the VMS symbols and fill in the data psect + */ + for (vsp = VMS_Symbols; vsp; vsp = vsp->Next) + { + /* + * Only look for undefined psects + */ + if (vsp->Psect_Index < 0) + { + /* + * And only initialized data + */ + if ((S_GET_TYPE (vsp->Symbol) == N_DATA) && !S_IS_EXTERNAL (vsp->Symbol)) + vsp->Psect_Index = Data_Psect; + } + } + } + + /******* Text Information and Relocation Records *******/ + /* + * Write the text segment data + */ + if (text_siz > 0) + { + /* + * 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); + } + /* + * 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) + { + int i; + + /* + * 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 didn'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 didn't have an appropriate type"); + /* + * This had better not be PC relative! + */ + if (fixP->fx_pcrel) + error ("Fixup data was erroneously \"pcrel\""); + /* + * Subtract their values to get the + * difference. + */ + i = S_GET_VALUE (fixP->fx_addsy) - + S_GET_VALUE (fixP->fx_subsy); + /* + * 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 (&i, + fixP->fx_size, + OBJ_S_C_TIR); + /* + * Done + */ + continue; + } + /* + * Size will HAVE to be "long" + */ + if (fixP->fx_size != sizeof (long)) + error ("Fixup datum was 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 was 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); + } + } + /* + * Store the Data segment: + * + * Since this is REALLY hard to do any other way, + * we actually manufacture the data segment and + * the store the appropriate values out of it. + * The segment was manufactured before, now we just + * dump it into the appropriate psects. + */ + if (data_siz > 0) + { + + /* + * Now we can 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 + */ + VMS_Store_Immediate_Data (Data_Segment + + S_GET_VALUE (vsp->Symbol) - + text_siz, + vsp->Size, + OBJ_S_C_TIR); + } + /* + * 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 + */ + if (S_GET_VALUE (sp) > + (fixP->fx_where + + fixP->fx_frag->fr_address)) + continue; + /* + * See if the datum is here + */ + if ((S_GET_VALUE (sp) + vsp->Size) <= + (fixP->fx_where + + fixP->fx_frag->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) + { + int i; + + /* + * 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 didn'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 didn't have an appropriate type"); + /* + * This had better not be PC relative! + */ + if (fixP->fx_pcrel) + error ("Fixup data was erroneously \"pcrel\""); + /* + * Subtract their values to get the + * difference. + */ + i = S_GET_VALUE (fixP->fx_addsy) - + S_GET_VALUE (fixP->fx_subsy); + /* + * Now generate the fixup object records + * Set the psect and store the data + */ + VMS_Set_Psect (vsp->Psect_Index, + fixP->fx_frag->fr_address + + fixP->fx_where - + S_GET_VALUE (vsp->Symbol) + + vsp->Psect_Offset, + OBJ_S_C_TIR); + VMS_Store_Immediate_Data (&i, + fixP->fx_size, + OBJ_S_C_TIR); + /* + * Done + */ + break; + } + /* + * Size will HAVE to be "long" + */ + if (fixP->fx_size != sizeof (long)) + error ("Fixup datum was 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 was 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, + fixP->fx_frag->fr_address + + fixP->fx_where - + S_GET_VALUE (vsp->Symbol) + + vsp->Psect_Offset, + OBJ_S_C_TIR); + /* + * Done + */ + break; + } + + } + } + + /* + * Write the Traceback Begin Module record + */ + VMS_TBT_Module_Begin (); + /* + * Scan the symbols and write out the routines + * (this makes the assumption that symbols are in + * order of ascending text segment offset) + */ + { + struct symbol *Current_Routine = 0; + int Current_Line_Number = 0; + int Current_Offset = -1; + struct input_file *Current_File; + +/* 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)) + { + /* + * Deal with STAB symbols + */ + if (S_IS_DEBUG (symbolP)) + { + /* + * Dispatch on STAB type + */ + switch ((unsigned char) S_GET_RAW_TYPE (symbolP)) + { + case N_SLINE: + if (S_GET_DESC (symbolP) > Current_File->max_line) + Current_File->max_line = S_GET_DESC (symbolP); + if (S_GET_DESC (symbolP) < Current_File->min_line) + Current_File->min_line = S_GET_DESC (symbolP); + break; + case N_SO: + Current_File = find_file (symbolP); + Current_File->flag = 1; + Current_File->min_line = 1; + break; + case N_SOL: + Current_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; + } + } + } + + /* 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 */ + { + int File_Number = 0; + int Debugger_Offset = 0; + int file_available; + Current_File = file_root; + for (Current_File = file_root; Current_File; Current_File = Current_File->next) + { + if (Current_File == (struct input_file *) NULL) + break; + if (Current_File->max_line == 0) + continue; + if ((strncmp (Current_File->name, "GNU_GXX_INCLUDE:", 16) == 0) && + !flagseen['D']) + continue; + if ((strncmp (Current_File->name, "GNU_CC_INCLUDE:", 15) == 0) && + !flagseen['D']) + continue; +/* show a few extra lines at the start of the region selected */ + if (Current_File->min_line > 2) + Current_File->min_line -= 2; + Current_File->offset = Debugger_Offset - Current_File->min_line + 1; + Debugger_Offset += Current_File->max_line - Current_File->min_line + 1; + if (Current_File->same_file_fpnt != (struct input_file *) NULL) + Current_File->file_number = Current_File->same_file_fpnt->file_number; + else + { + Current_File->file_number = ++File_Number; + file_available = VMS_TBT_Source_File (Current_File->name, + Current_File->file_number); + if (!file_available) + { + Current_File->file_number = 0; + File_Number--; + continue; + }; + }; + VMS_TBT_Source_Lines (Current_File->file_number, + Current_File->min_line, + Current_File->max_line - Current_File->min_line + 1); + }; /* for */ + }; /* scope */ + Current_File = (struct input_file *) NULL; + + 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) + { + /* + * End the routine + */ + VMS_TBT_Routine_End (text_siz, Current_Routine); + } + /* + * Store the routine begin traceback info + */ + if (Text_Psect != -1) + { + VMS_TBT_Routine_Begin (symbolP, Text_Psect); + Current_Routine = symbolP; + } +/* Output local symbols, i.e. all symbols that are associated with a specific + * routine. We output them now so the debugger recognizes them as local to + * this routine. + */ + { + symbolS *symbolP1; + char *pnt; + char *pnt1; + for (symbolP1 = Current_Routine; symbolP1; symbolP1 = symbol_next (symbolP1)) + { + if (!S_IS_DEBUG (symbolP1)) + continue; + if (S_GET_RAW_TYPE (symbolP1) != N_FUN) + continue; + pnt = S_GET_NAME (symbolP); + pnt1 = S_GET_NAME (symbolP1); + if (*pnt++ != '_') + continue; + while (*pnt++ == *pnt1++) + { + }; + if (*pnt1 != 'F' && *pnt1 != 'f') continue; + if ((*(--pnt) == '\0') && (*(--pnt1) == ':')) + break; + }; + if (symbolP1 != (symbolS *) NULL) + VMS_DBG_Define_Routine (symbolP1, Current_Routine, Text_Psect); + } /* local symbol block */ + /* + * Done + */ + continue; + } + /* + * Deal with STAB symbols + */ + if (S_IS_DEBUG (symbolP)) + { + /* + * Dispatch on STAB type + */ + switch ((unsigned char) S_GET_RAW_TYPE (symbolP)) + { + /* + * Line number + */ + case N_SLINE: + /* Offset the line into the correct portion + * of the file */ + if (Current_File->file_number == 0) + break; + /* 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 ((Current_File->file_number != 1) && + S_GET_VALUE (symbolP) == + Current_Offset) + break; + /* calculate actual debugger source line */ + S_GET_DESC (symbolP) + += Current_File->offset; + /* + * If this is the 1st N_SLINE, setup + * PC/Line correlation. Otherwise + * do the delta PC/Line. If the offset + * for the line number is not +ve we need + * to do another PC/Line correlation + * setup + */ + if (Current_Offset == -1) + { + VMS_TBT_Line_PC_Correlation ( + S_GET_DESC (symbolP), + S_GET_VALUE (symbolP), + Text_Psect, + 0); + } + else + { + if ((S_GET_DESC (symbolP) - + Current_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, + S_GET_VALUE (symbolP) - + Current_Offset, + 0, + -1); + VMS_TBT_Line_PC_Correlation ( + S_GET_DESC (symbolP), + S_GET_VALUE (symbolP), + Text_Psect, + 0); + } + else + { + /* + * Line delta is +ve, all is well + */ + VMS_TBT_Line_PC_Correlation ( + S_GET_DESC (symbolP) - + Current_Line_Number, + S_GET_VALUE (symbolP) - + Current_Offset, + 0, + 1); + } + } + /* + * Update the current line/PC + */ + Current_Line_Number = S_GET_DESC (symbolP); + Current_Offset = S_GET_VALUE (symbolP); + /* + * Done + */ + break; + /* + * Source file + */ + case N_SO: + /* + * Remember that we had a source file + * and emit the source file debugger + * record + */ + Current_File = + find_file (symbolP); + break; +/* 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 */ + case N_SOL: + Current_File = + find_file (symbolP); + break; + } + } + } + /* + * 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 the End Of Module record + */ + if (Entry_Point_Symbol == 0) + Write_VMS_EOM_Record (-1, 0); + else + Write_VMS_EOM_Record (Text_Psect, + S_GET_VALUE (Entry_Point_Symbol)); + + /* + * All done, close the object file + */ + Close_VMS_Object_File (); +} + +/* end of obj-vms.c */ |