aboutsummaryrefslogtreecommitdiff
path: root/gas/config/vms
diff options
context:
space:
mode:
authorK. Richard Pixley <rich@cygnus>1991-04-04 18:19:56 +0000
committerK. Richard Pixley <rich@cygnus>1991-04-04 18:19:56 +0000
commit0e39a8bbfe9e77100c9f0672415b2ae32df54d29 (patch)
tree50d89163c44d492bf99d7db29f54cd141c08a233 /gas/config/vms
parent3c0c9328b9c299580bcf8cb6fdb3b71d5a0525ff (diff)
downloadgdb-0e39a8bbfe9e77100c9f0672415b2ae32df54d29.zip
gdb-0e39a8bbfe9e77100c9f0672415b2ae32df54d29.tar.gz
gdb-0e39a8bbfe9e77100c9f0672415b2ae32df54d29.tar.bz2
new gas main line
Diffstat (limited to 'gas/config/vms')
-rw-r--r--gas/config/vms/objrecdef.h255
-rw-r--r--gas/config/vms/vms-dbg.c1125
-rw-r--r--gas/config/vms/vms.c3741
3 files changed, 5121 insertions, 0 deletions
diff --git a/gas/config/vms/objrecdef.h b/gas/config/vms/objrecdef.h
new file mode 100644
index 0000000..fca8af4
--- /dev/null
+++ b/gas/config/vms/objrecdef.h
@@ -0,0 +1,255 @@
+/*
+ *
+ * $OBJRECDEF
+ * Generated automatically by "vms_struct Version 1.00"
+ * Created from VMS definition file "objrecdef.mar"
+ * Mon Oct 14 14:01:29 1985
+ *
+ */
+struct OBJREC {
+ unsigned char obj$b_rectyp;
+ unsigned char obj$b_subtyp;
+ unsigned char obj$b_mhd_strlv;
+ unsigned char obj$b_mhd_recsz[2];
+ unsigned char obj$t_mhd_name[1];
+ };
+
+#define OBJ$C_HDR 0
+#define OBJ$C_HDR_MHD 0
+#define OBJ$C_HDR_LNM 1
+#define OBJ$C_HDR_SRC 2
+#define OBJ$C_HDR_TTL 3
+#define OBJ$C_HDR_CPR 4
+#define OBJ$C_HDR_MTC 5
+#define OBJ$C_HDR_GTX 6
+#define OBJ$C_GSD 1
+#define OBJ$C_GSD_PSC 0
+#define OBJ$C_GSD_SYM 1
+#define OBJ$C_GSD_EPM 2
+#define OBJ$C_GSD_PRO 3
+#define OBJ$C_GSD_SYMW 4
+#define OBJ$C_GSD_EPMW 5
+#define OBJ$C_GSD_PROW 6
+#define OBJ$C_GSD_IDC 7
+#define OBJ$C_GSD_ENV 8
+#define OBJ$C_GSD_LSY 9
+#define OBJ$C_GSD_LEPM 10
+#define OBJ$C_GSD_LPRO 11
+#define OBJ$C_GSD_SPSC 12
+#define OBJ$C_TIR 2
+#define OBJ$C_EOM 3
+#define OBJ$C_DBG 4
+#define OBJ$C_TBT 5
+#define OBJ$C_LNK 6
+#define OBJ$C_EOMW 7
+#define OBJ$C_MAXRECTYP 7
+#define OBJ$K_SUBTYP 1
+#define OBJ$C_SUBTYP 1
+#define OBJ$C_MAXRECSIZ 2048
+#define OBJ$C_STRLVL 0
+#define OBJ$C_SYMSIZ 31
+#define OBJ$C_STOREPLIM -1
+#define OBJ$C_PSCALILIM 9
+
+#define MHD$C_MHD 0
+#define MHD$C_LNM 1
+#define MHD$C_SRC 2
+#define MHD$C_TTL 3
+#define MHD$C_CPR 4
+#define MHD$C_MTC 5
+#define MHD$C_GTX 6
+#define MHD$C_MAXHDRTYP 6
+
+#define GSD$K_ENTRIES 1
+#define GSD$C_ENTRIES 1
+#define GSD$C_PSC 0
+#define GSD$C_SYM 1
+#define GSD$C_EPM 2
+#define GSD$C_PRO 3
+#define GSD$C_SYMW 4
+#define GSD$C_EPMW 5
+#define GSD$C_PROW 6
+#define GSD$C_IDC 7
+#define GSD$C_ENV 8
+#define GSD$C_LSY 9
+#define GSD$C_LEPM 10
+#define GSD$C_LPRO 11
+#define GSD$C_SPSC 12
+#define GSD$C_SYMV 13
+#define GSD$C_EPMV 14
+#define GSD$C_PROV 15
+#define GSD$C_MAXRECTYP 15
+
+#define GSY$M_WEAK 1
+#define GSY$M_DEF 2
+#define GSY$M_UNI 4
+#define GSY$M_REL 8
+
+#define GPS$M_PIC 1
+#define GPS$M_LIB 2
+#define GPS$M_OVR 4
+#define GPS$M_REL 8
+#define GPS$M_GBL 16
+#define GPS$M_SHR 32
+#define GPS$M_EXE 64
+#define GPS$M_RD 128
+#define GPS$M_WRT 256
+#define GPS$M_VEC 512
+#define GPS$K_NAME 9
+#define GPS$C_NAME 9
+
+#define TIR$C_STA_GBL 0
+#define TIR$C_STA_SB 1
+#define TIR$C_STA_SW 2
+#define TIR$C_STA_LW 3
+#define TIR$C_STA_PB 4
+#define TIR$C_STA_PW 5
+#define TIR$C_STA_PL 6
+#define TIR$C_STA_UB 7
+#define TIR$C_STA_UW 8
+#define TIR$C_STA_BFI 9
+#define TIR$C_STA_WFI 10
+#define TIR$C_STA_LFI 11
+#define TIR$C_STA_EPM 12
+#define TIR$C_STA_CKARG 13
+#define TIR$C_STA_WPB 14
+#define TIR$C_STA_WPW 15
+#define TIR$C_STA_WPL 16
+#define TIR$C_STA_LSY 17
+#define TIR$C_STA_LIT 18
+#define TIR$C_STA_LEPM 19
+#define TIR$C_MAXSTACOD 19
+#define TIR$C_MINSTOCOD 20
+#define TIR$C_STO_SB 20
+#define TIR$C_STO_SW 21
+#define TIR$C_STO_L 22
+#define TIR$C_STO_BD 23
+#define TIR$C_STO_WD 24
+#define TIR$C_STO_LD 25
+#define TIR$C_STO_LI 26
+#define TIR$C_STO_PIDR 27
+#define TIR$C_STO_PICR 28
+#define TIR$C_STO_RSB 29
+#define TIR$C_STO_RSW 30
+#define TIR$C_STO_RL 31
+#define TIR$C_STO_VPS 32
+#define TIR$C_STO_USB 33
+#define TIR$C_STO_USW 34
+#define TIR$C_STO_RUB 35
+#define TIR$C_STO_RUW 36
+#define TIR$C_STO_B 37
+#define TIR$C_STO_W 38
+#define TIR$C_STO_RB 39
+#define TIR$C_STO_RW 40
+#define TIR$C_STO_RIVB 41
+#define TIR$C_STO_PIRR 42
+#define TIR$C_MAXSTOCOD 42
+#define TIR$C_MINOPRCOD 50
+#define TIR$C_OPR_NOP 50
+#define TIR$C_OPR_ADD 51
+#define TIR$C_OPR_SUB 52
+#define TIR$C_OPR_MUL 53
+#define TIR$C_OPR_DIV 54
+#define TIR$C_OPR_AND 55
+#define TIR$C_OPR_IOR 56
+#define TIR$C_OPR_EOR 57
+#define TIR$C_OPR_NEG 58
+#define TIR$C_OPR_COM 59
+#define TIR$C_OPR_INSV 60
+#define TIR$C_OPR_ASH 61
+#define TIR$C_OPR_USH 62
+#define TIR$C_OPR_ROT 63
+#define TIR$C_OPR_SEL 64
+#define TIR$C_OPR_REDEF 65
+#define TIR$C_OPR_DFLIT 66
+#define TIR$C_MAXOPRCOD 66
+#define TIR$C_MINCTLCOD 80
+#define TIR$C_CTL_SETRB 80
+#define TIR$C_CTL_AUGRB 81
+#define TIR$C_CTL_DFLOC 82
+#define TIR$C_CTL_STLOC 83
+#define TIR$C_CTL_STKDL 84
+#define TIR$C_MAXCTLCOD 84
+
+/*
+ * Debugger symbol definitions: These are done by hand, as no
+ * machine-readable version seems
+ * to be available.
+ */
+#define DST$C_C 7 /* Language == "C" */
+#define DST$C_VERSION 153
+#define DST$C_SOURCE 155 /* Source file */
+#define DST$C_PROLOG 162
+#define DST$C_BLKBEG 176 /* Beginning of block */
+#define DST$C_BLKEND 177 /* End of block */
+#define DST$C_ENTRY 181
+#define DST$C_PSECT 184
+#define DST$C_LINE_NUM 185 /* Line Number */
+#define DST$C_LBLORLIT 186
+#define DST$C_LABEL 187
+#define DST$C_MODBEG 188 /* Beginning of module */
+#define DST$C_MODEND 189 /* End of module */
+#define DST$C_RTNBEG 190 /* Beginning of routine */
+#define DST$C_RTNEND 191 /* End of routine */
+#define DST$C_DELTA_PC_W 1 /* Incr PC */
+#define DST$C_INCR_LINUM 2 /* Incr Line # */
+#define DST$C_INCR_LINUM_W 3 /* Incr Line # */
+#define DST$C_SET_LINUM_INCR 4
+#define DST$C_SET_LINUM_INCR_W 5
+#define DST$C_RESET_LINUM_INCR 6
+#define DST$C_BEG_STMT_MODE 7
+#define DST$C_END_STMT_MODE 8
+#define DST$C_SET_LINE_NUM 9 /* Set Line # */
+#define DST$C_SET_PC 10
+#define DST$C_SET_PC_W 11
+#define DST$C_SET_PC_L 12
+#define DST$C_SET_STMTNUM 13
+#define DST$C_TERM 14 /* End of lines */
+#define DST$C_TERM_W 15 /* End of lines */
+#define DST$C_SET_ABS_PC 16 /* Set PC */
+#define DST$C_DELTA_PC_L 17 /* Incr PC */
+#define DST$C_INCR_LINUM_L 18 /* Incr Line # */
+#define DST$C_SET_LINUM_B 19 /* Set Line # */
+#define DST$C_SET_LINUM_L 20 /* Set Line # */
+#define DST$C_TERM_L 21 /* End of lines */
+/* these are used with DST$C_SOURCE */
+#define DST$C_SRC_FORMFEED 16 /* ^L counts */
+#define DST$C_SRC_DECLFILE 1 /* Declare file */
+#define DST$C_SRC_SETFILE 2 /* Set file */
+#define DST$C_SRC_SETREC_L 3 /* Set record */
+#define DST$C_SRC_DEFLINES_W 10 /* # of line */
+/* the following are the codes for the various data types. Anything not on
+ * the list is included under 'advanced_type'
+ */
+#define DBG$C_UCHAR 0x02
+#define DBG$C_USINT 0x03
+#define DBG$C_ULINT 0x04
+#define DBG$C_SCHAR 0x06
+#define DBG$C_SSINT 0x07
+#define DBG$C_SLINT 0x08
+#define DBG$C_REAL4 0x0a
+#define DBG$C_REAL8 0x0b
+#define DBG$C_FUNCTION_ADDR 0x17
+#define DBG$C_ADVANCED_TYPE 0xa3
+/* These are the codes that are used to generate the definitions of struct
+ * union and enum records
+ */
+#define DBG$C_ENUM_ITEM 0xa4
+#define DBG$C_ENUM_START 0xa5
+#define DBG$C_ENUM_END 0xa6
+#define DBG$C_STRUCT_START 0xab
+#define DBG$C_STRUCT_ITEM 0xff
+#define DBG$C_STRUCT_END 0xac
+/* These are the codes that are used in the suffix records to determine the
+ * actual data type
+ */
+#define DBG$C_BASIC 0x01
+#define DBG$C_BASIC_ARRAY 0x02
+#define DBG$C_STRUCT 0x03
+#define DBG$C_POINTER 0x04
+#define DBG$C_VOID 0x05
+#define DBG$C_COMPLEX_ARRAY 0x07
+/* These codes are used in the generation of the symbol definition records
+ */
+#define DBG$C_FUNCTION_PARAMETER 0xc9
+#define DBG$C_LOCAL_SYM 0xd9
diff --git a/gas/config/vms/vms-dbg.c b/gas/config/vms/vms-dbg.c
new file mode 100644
index 0000000..19c6c93
--- /dev/null
+++ b/gas/config/vms/vms-dbg.c
@@ -0,0 +1,1125 @@
+#include <stdio.h>
+#include "as.h"
+#include "struc-symbol.h"
+#include "symbols.h"
+#include "objrecdef.h"
+#include <stab.h>
+
+/* 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.
+ */
+
+/* We need this info to cross correlate between the stabs def for a symbol and
+ * the actual symbol def. The actual symbol def contains the psect number and
+ * offset, which is needed to declare a variable to the debugger for global
+ * and static variables
+ */
+struct VMS_Symbol {
+ struct VMS_Symbol *Next;
+ struct symbol *Symbol;
+ int Size;
+ int Psect_Index;
+ int Psect_Offset;
+ };
+extern struct VMS_Symbol *VMS_Symbols;
+
+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};
+
+static char * symbol_name;
+static structure_count=0;
+
+/* 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(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
+ */
+static fix_name(char* pnt){
+ for( ;*pnt != 0; pnt++){
+ if(*pnt == '.') *pnt = '$';
+ };
+}
+
+/* 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 )
+
+/* 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(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(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;
+}
+
+
+/* Many good programmers cringe when they see a fixed size array - since I am
+ * using this to generate the various descriptors for the data types present,
+ * you might argue that the descriptor could overflow the array for a
+ * complicated variable, and then I am in deep doo-doo. My answer to this is
+ * that the debugger records that we write have all sorts of length bytes
+ * stored in them all over the place, and if we exceed 127 bytes (since the top
+ * bit indicates data, rather than a command), we are dead anyhow. So I figure
+ * why not do this the easy way. Besides, to get 128 bytes, you need something
+ * like an array with 10 indicies, or something like
+ * char **************************************** var;
+ * Lets get real. If some idiot writes programs like that he/she gets what
+ * they deserve. (It is possible to overflow the record with a somewhat
+ * simpler example, like: int (*(*(*(*(*(* sarr6)[1])[1])[2])[3])[4])[5];
+ * but still...). And if someone in the peanut gallery wants to know "What
+ * does VAX-C do with something like this?", I will tell you. It crashes.
+ * At least this code has the good sense to convert it to *void.
+ * In practice, I do not think that this presents too much of a problem, since
+ * struct/union/enum all use defined types, which sort of terminate the
+ * definition. It occurs to me that we could possibly do the same thing with
+ * arrays and pointers, but I don't know quite how it would be coded.
+ *
+ * And now back to the regularly scheduled program...
+ */
+#define MAX_DEBUG_RECORD 128
+static char Local[MAX_DEBUG_RECORD]; /* buffer for variable descriptor */
+static int Lpnt; /* index into Local */
+static char Asuffix[MAX_DEBUG_RECORD]; /* buffer for array descriptor */
+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*/
+static int struct_number; /* counter used to assign indexes to struct
+ unions and enums */
+
+/* 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
+ */
+push(int value, int 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(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(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(struct VMS_DBG_Symbol * spnt,int array_suffix_len){
+ struct VMS_DBG_Symbol * spnt1;
+ int i;
+ switch(spnt->advanced){
+ case VOID:
+ push(DBG$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$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$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$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$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(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$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$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$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$C_DBG);Lpnt=0;
+ };
+ i=0;
+ while(i<Apoint) Local[Lpnt++] = Asuffix[i++];
+ if(Lpnt != 0)
+ VMS_Store_Immediate_Data(Local, Lpnt, OBJ$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).
+ */
+VMS_DBG_record(struct VMS_DBG_Symbol* spnt,int Psect,int Offset, char* Name)
+{
+ char* pnt;
+ int j;
+ int maxlen;
+ int i=0;
+ if(Psect < 0) { /* this is a local variable, referenced to SP */
+ maxlen=7+strlen(Name);
+ Local[i++] = maxlen;
+ Local[i++]=spnt->VMS_type;
+ if(Offset > 0) Local[i++] = DBG$C_FUNCTION_PARAMETER;
+ else Local[i++] = DBG$C_LOCAL_SYM;
+ pnt=(char*) &Offset;
+ for(j=0;j<4;j++) Local[i++]=*pnt++; /* copy the offset */
+ } else {
+ maxlen=7+strlen(Name); /* symbols fixed in memory */
+ Local[i++]=7+strlen(Name);
+ Local[i++]=spnt->VMS_type;
+ Local[i++]=1;
+ VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0;
+ VMS_Set_Data(Psect,Offset,OBJ$C_DBG,0);
+ }
+ Local[i++]=strlen(Name);
+ pnt=Name;
+ fix_name(pnt); /* if there are bad characters in name, convert them */
+ while(*pnt!='\0') Local[i++]=*pnt++;
+ VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG);
+ if(spnt->VMS_type == DBG$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
+ */
+int VMS_local_stab_Parse(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=sp->sy_nlist.n_un.n_name;
+ 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 ((sp1->sy_nlist.n_type & N_STAB) == 0) continue;
+ if((unsigned char)sp1->sy_nlist.n_type == N_FUN) break;
+ if((unsigned char)sp1->sy_nlist.n_type != N_RSYM) continue;
+ str1=sp1->sy_nlist.n_un.n_name; /* 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,sp->sy_nlist.n_value,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 gave_compiler_message = 0;
+
+static int VMS_stab_parse(symbolS * sp,char expected_type,
+ int type1,int type2,int 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=sp->sy_nlist.n_un.n_name;
+ 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=vsp->Symbol->sy_nlist.n_un.n_name;
+ 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)
+ && ((vsp->Symbol->sy_type == type1) ||
+ (vsp->Symbol->sy_type == 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(sp1->sy_type != (N_TEXT | N_EXT) && sp1->sy_type!=N_TEXT)
+ continue;
+ pnt = sp1->sy_nlist.n_un.n_name;
+ 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,
+ sp1->sy_nlist.n_value,
+ str);
+ *pnt1=':';
+ *(sp1->sy_nlist.n_un.n_name) = 'L';
+ /* fool assembler to not output this
+ * as a routine in the TBT */
+ return 1;};
+ };
+ };
+ *pnt1=':'; /* and restore the string */
+ return 0;
+}
+
+
+VMS_GSYM_Parse(symbolS * sp,int Text_Psect){ /* Global variables */
+ VMS_stab_parse(sp,'G',(N_UNDF | N_EXT),(N_DATA | N_EXT),Text_Psect);
+}
+
+
+VMS_LCSYM_Parse(symbolS * sp,int Text_Psect){/* Static symbols - uninitialized */
+ VMS_stab_parse(sp,'S',N_BSS,-1,Text_Psect);
+}
+
+VMS_STSYM_Parse(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.
+ */
+VMS_RSYM_Parse(symbolS * sp,symbolS * 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((unsigned char)symbolP->sy_type) {
+ case N_LBRAC:
+ if(bcnt++==0) Min_Offset = symbolP->sy_nlist.n_value;
+ break;
+ case N_RBRAC:
+ if(--bcnt==0) Max_Offset =
+ symbolP->sy_nlist.n_value-1;
+ break;
+ }
+ if((Min_Offset != -1) && (bcnt == 0)) break;
+ if((unsigned char)symbolP->sy_type == N_FUN) 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 = sp->sy_nlist.n_value;
+ for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ /*
+ * Dispatch on STAB type
+ */
+ This_Offset = symbolP->sy_nlist.n_value;
+ switch(symbolP->sy_type) {
+ 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=sp->sy_nlist.n_un.n_name;
+ 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';
+ maxlen=25+strlen(sp->sy_nlist.n_un.n_name);
+ Local[i++]=maxlen;
+ Local[i++]=spnt->VMS_type;
+ Local[i++]=0xfb;
+ Local[i++]=strlen(sp->sy_nlist.n_un.n_name)+1;
+ Local[i++]=0x00;
+ Local[i++]=0x00;
+ Local[i++]=0x00;
+ Local[i++]=strlen(sp->sy_nlist.n_un.n_name);
+ pnt=sp->sy_nlist.n_un.n_name;
+ fix_name(pnt); /* if there are bad characters in name, convert them */
+ 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$C_DBG); i=0;
+ VMS_Set_Data(Text_Psect,Min_Offset,OBJ$C_DBG,1);
+ VMS_Set_Data(Text_Psect,Max_Offset,OBJ$C_DBG,1);
+ Local[i++]=0x03;
+ Local[i++]=sp->sy_nlist.n_value;
+ Local[i++]=0x00;
+ Local[i++]=0x00;
+ Local[i++]=0x00;
+ VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG);
+ *pnt1=':';
+ if(spnt->VMS_type == DBG$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(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(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;};
+ 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$C_SLINT; spnt->data_size=4;}
+ else if(type_check("long int")) {
+ spnt->VMS_type=DBG$C_SLINT; spnt->data_size=4;}
+ else if(type_check("unsigned int")) {
+ spnt->VMS_type=DBG$C_ULINT; spnt->data_size = 4;}
+ else if(type_check("long unsigned int")) {
+ spnt->VMS_type=DBG$C_ULINT; spnt->data_size = 4;}
+ else if(type_check("short int")) {
+ spnt->VMS_type=DBG$C_SSINT; spnt->data_size = 2;}
+ else if(type_check("short unsigned int")) {
+ spnt->VMS_type=DBG$C_USINT; spnt->data_size = 2;}
+ else if(type_check("char")) {
+ spnt->VMS_type=DBG$C_SCHAR; spnt->data_size = 1;}
+ else if(type_check("signed char")) {
+ spnt->VMS_type=DBG$C_SCHAR; spnt->data_size = 1;}
+ else if(type_check("unsigned char")) {
+ spnt->VMS_type=DBG$C_UCHAR; spnt->data_size = 1;}
+ else if(type_check("float")) {
+ spnt->VMS_type=DBG$C_REAL4; spnt->data_size = 4;}
+ else if(type_check("double")) {
+ spnt->VMS_type=DBG$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$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$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$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$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$C_ADVANCED_TYPE;
+ Local[i++] = DBG$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$C_DBG); i=0;
+ if(spnt1 == (struct VMS_DBG_Symbol*) NULL)
+ generate_suffix(spnt1,dtype);
+ else if(spnt1->VMS_type == DBG$C_ADVANCED_TYPE)
+ generate_suffix(spnt1,0);
+ };
+ };
+ pnt1++;
+ Local[i++] = 0x01; /* length byte */
+ Local[i++] = DBG$C_STRUCT_END;
+ VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0;
+ break;
+ case 'e':
+ spnt->advanced= ENUM;
+ spnt->VMS_type = DBG$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$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$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$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$C_DBG); i=0;
+ pnt= pnt1; /* Skip final semicolon */
+ };
+ Local[i++] = 0x01; /* len byte */
+ Local[i++] = DBG$C_ENUM_END;
+ VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0;
+ pnt1=pnt + 1;
+ break;
+ case 'a':
+ spnt->advanced= ARRAY;
+ spnt->VMS_type = DBG$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$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$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.
+ */
+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 ((sp->sy_nlist.n_type & N_STAB) != 0) {
+ /*
+ * Dispatch on STAB type
+ */
+ switch((unsigned char)sp->sy_nlist.n_type) {
+ 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=sp->sy_nlist.n_un.n_name;
+ 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 symbolS* Current_Routine;
+static int Text_Psect;
+
+static Define_Local_Symbols(symbolS* s1,symbolS* s2){
+ symbolS * symbolP1;
+ for(symbolP1 = symbol_next(s1); symbolP1 != s2; symbolP1 = symbol_next(symbolP1)) {
+ if (symbolP1 == (symbolS *)NULL) return;
+ if (symbolP1->sy_nlist.n_type == N_FUN) return;
+ /*
+ * Deal with STAB symbols
+ */
+ if ((symbolP1->sy_nlist.n_type & N_STAB) != 0) {
+ /*
+ * Dispatch on STAB type
+ */
+ switch((unsigned char)symbolP1->sy_nlist.n_type) {
+ 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 */
+}
+
+static symbolS* Define_Routine(symbolS* symbolP,int Level){
+ symbolS * sstart;
+ symbolS * symbolP1;
+ char str[10];
+ char * pnt;
+ int rcount = 0;
+ int Offset;
+ sstart = symbolP;
+ for(symbolP1 = symbol_next(symbolP); symbolP1; symbolP1 = symbol_next(symbolP1)) {
+ if (symbolP1->sy_nlist.n_type == N_FUN) break;
+ /*
+ * Deal with STAB symbols
+ */
+ if ((symbolP1->sy_nlist.n_type & N_STAB) != 0) {
+ /*
+ * Dispatch on STAB type
+ */
+ if((unsigned char)symbolP1->sy_nlist.n_type == N_FUN) break;
+ switch((unsigned char)symbolP1->sy_nlist.n_type) {
+ case N_LBRAC:
+ if(Level != 0) {
+ pnt = str +sprintf(str,"$%d",rcount++);
+ *pnt = '\0';
+ VMS_TBT_Block_Begin(symbolP1,Text_Psect,str);
+ };
+ Offset = symbolP1->sy_nlist.n_value;
+ Define_Local_Symbols(sstart,symbolP1);
+ symbolP1 =
+ Define_Routine(symbolP1,Level+1);
+ if(Level != 0)
+ VMS_TBT_Block_End(symbolP1->sy_nlist.n_value -
+ 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);
+}
+
+VMS_DBG_Define_Routine(symbolS* symbolP,symbolS* Curr_Routine,int Txt_Psect){
+ Current_Routine = Curr_Routine;
+ Text_Psect = Txt_Psect;
+ Define_Routine(symbolP,0);
+}
diff --git a/gas/config/vms/vms.c b/gas/config/vms/vms.c
new file mode 100644
index 0000000..cd3bb59
--- /dev/null
+++ b/gas/config/vms/vms.c
@@ -0,0 +1,3741 @@
+/* vms.c -- Write out a VAX/VMS object file
+ Copyright (C) 1987, 1988 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 1, 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 */
+#include <ctype.h>
+#include <stdio.h>
+
+#include "as.h"
+#include "subsegs.h"
+#include "obstack.h"
+#include "struc-symbol.h"
+#include "write.h"
+#include "symbols.h"
+
+#ifdef VMS /* THIS MODULE IS FOR VMS ONLY */
+
+#include <stab.h>
+#include "objrecdef.h" /* Define VMS Object record lang. */
+#include <vms/fabdef.h> /* Define File Access Block */
+#include <vms/namdef.h> /* Define NAM Block */
+#include <vms/xabdef.h> /* Define XAB */
+#include <vms/xabdatdef.h> /* Define Date XAB */
+#include <vms/xabfhcdef.h> /* Define File Header XAB */
+
+const pseudo_typeS obj_pseudo_table[] = {
+ { "const", s_const, 0 },
+
+}; /* obj_pseudo_table */
+
+/*
+ * Version string of the compiler that produced the code we are
+ * assembling. (And this assembler, if we do not have compiler info.)
+ */
+extern char version_string[];
+char *compiler_version_string;
+
+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;
+
+struct input_file * find_file(symbolS *);
+
+
+/*
+ * 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 && (symbolP->sy_nlist.n_type == (N_TEXT | N_EXT))) {
+#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 (symbolP->sy_nlist.n_value >= 2)
+ symbolP->sy_nlist.n_value += 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));
+ symbolP->sy_nlist.n_un.n_name = "_c$main_args";
+ symbolP->sy_nlist.n_type = N_UNDF;
+ symbolP->sy_nlist.n_other = 0;
+ symbolP->sy_nlist.n_desc = 0;
+ symbolP->sy_nlist.n_value = 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;
+ int Local_Initialized_Data_Size = 0;
+ 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();
+
+ /*
+ * Generate the VMS object file records
+ * 1st GSD then TIR records
+ */
+
+ /******* Global Symbol Dictionary *******/
+ /*
+ * Define the Text Psect
+ */
+ if (text_siz > 0) {
+ Text_Psect = Psect_Number++;
+ VMS_Psect_Spec("$code",text_siz,"TEXT");
+ }
+ /*
+ * Define the BSS Psect
+ */
+ if (local_bss_counter > 0) {
+ Bss_Psect = Psect_Number++;
+ VMS_Psect_Spec("$uninitialized_data",local_bss_counter,"DATA");
+ }
+ /*
+ * Now scan the symbols and emit the appropriate GSD records
+ */
+ for (sp = symbol_rootP; sp; sp = symbol_next(sp)) {
+ /*
+ * Dispatch on symbol type
+ */
+ switch(sp->sy_type) {
+ /*
+ * 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 = sp->sy_nlist.n_value;
+ 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(sp->sy_nlist.n_other)
+ VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
+ vsp->Size,
+ "CONST");
+ else
+ VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
+ vsp->Size,
+ "COMMON");
+#ifdef NOT_VAX_11_C_COMPATIBLE
+ /*
+ * Place a global symbol at the
+ * beginning of the Psect
+ */
+ VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name,
+ 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 =
+ sp->sy_nlist.n_value -
+ 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(sp->sy_nlist.n_other)
+ VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
+ vsp->Size,
+ "CONST");
+ else
+ VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
+ vsp->Size,
+ "COMMON");
+#ifdef NOT_VAX_11_C_COMPATIBLE
+ /*
+ * Place a global symbol at the
+ * beginning of the Psect
+ */
+ VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name,
+ 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(sp->sy_nlist.n_un.n_name,
+ Text_Psect,
+ sp->sy_nlist.n_value,
+ 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 = sp->sy_nlist.n_value;
+ 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(sp->sy_nlist.n_un.n_name,
+ 0,
+ 0,
+ 0);
+ break;
+ /*
+ * Anything else
+ */
+ default:
+ /*
+ * Ignore STAB symbols
+ * Including .stabs emitted by g++
+ */
+ if ((sp->sy_type & N_STAB) != 0 || sp->sy_nlist.n_type==22)
+ break;
+ /*
+ * Error
+ */
+ if(sp->sy_nlist.n_type !=22)
+ printf(" ERROR, unknown type (%d)\n",
+ sp->sy_nlist.n_type);
+ 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");
+ /*
+ * 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 (vsp->Symbol->sy_nlist.n_type == N_DATA)
+ 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$C_TIR);
+ /*
+ * Store the "fixed" part
+ */
+ if (fragP->fr_fix)
+ VMS_Store_Immediate_Data(fragP->fr_literal,
+ fragP->fr_fix,
+ OBJ$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$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 (fixP->fx_subsy->sy_type !=
+ fixP->fx_addsy->sy_type)
+ 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 (((fixP->fx_addsy->sy_type & ~N_EXT) != N_DATA) &&
+ ((fixP->fx_addsy->sy_type & ~N_EXT) != 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 = fixP->fx_addsy->sy_value -
+ fixP->fx_subsy->sy_value;
+ /*
+ * 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$C_TIR);
+ VMS_Store_Immediate_Data(&i,
+ fixP->fx_size,
+ OBJ$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$C_TIR);
+ /*
+ * Check for indirect address reference,
+ * which has to be fixed up (as the linker
+ * will screw it up with TIR$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.
+ */
+ if (data_siz > 0) {
+ char *Data_Segment;
+
+ /*
+ * 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)
+ bcopy(fragP->fr_literal,
+ Data_Segment + i,
+ 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)
+ bcopy(fill_literal,
+ Data_Segment + i,
+ fill_size);
+ i += fill_size;
+ }
+ }
+ /*
+ * 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 ((vsp->Symbol->sy_nlist.n_type & ~N_EXT) != N_DATA)
+ continue;
+ /*
+ * Set the Psect + Offset
+ */
+ VMS_Set_Psect(vsp->Psect_Index,
+ vsp->Psect_Offset,
+ OBJ$C_TIR);
+ /*
+ * Store the data
+ */
+ VMS_Store_Immediate_Data(Data_Segment +
+ vsp->Symbol->sy_nlist.n_value -
+ text_siz,
+ vsp->Size,
+ OBJ$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 ((sp->sy_nlist.n_type & ~N_EXT) != N_DATA)
+ continue;
+ /*
+ * Ignore symbol if After fixup
+ */
+ if (sp->sy_nlist.n_value >
+ (fixP->fx_where +
+ fixP->fx_frag->fr_address))
+ continue;
+ /*
+ * See if the datum is here
+ */
+ if ((sp->sy_nlist.n_value + 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 (fixP->fx_subsy->sy_type !=
+ fixP->fx_addsy->sy_type)
+ 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 (((fixP->fx_addsy->sy_type & ~N_EXT) != N_DATA) &&
+ ((fixP->fx_addsy->sy_type & ~N_EXT) != 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 = fixP->fx_addsy->sy_value -
+ fixP->fx_subsy->sy_value;
+ /*
+ * 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 -
+ vsp->Symbol->sy_value +
+ vsp->Psect_Offset,
+ OBJ$C_TIR);
+ VMS_Store_Immediate_Data(&i,
+ fixP->fx_size,
+ OBJ$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 -
+ vsp->Symbol->sy_value +
+ vsp->Psect_Offset,
+ OBJ$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 ((symbolP->sy_nlist.n_type & N_STAB) != 0) {
+ /*
+ * Dispatch on STAB type
+ */
+ switch((unsigned char)symbolP->sy_nlist.n_type) {
+ case N_SLINE:
+ if(symbolP->sy_nlist.n_desc > Current_File->max_line)
+ Current_File->max_line = symbolP->sy_nlist.n_desc;
+ if(symbolP->sy_nlist.n_desc < Current_File->min_line)
+ Current_File->min_line = symbolP->sy_nlist.n_desc;
+ 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 ((symbolP->sy_nlist.n_type & ~N_EXT) == N_TEXT) {
+ /*
+ * Ignore symbols starting with "L",
+ * as they are local symbols
+ */
+ if (symbolP->sy_nlist.n_un.n_name[0] == '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 ((symbolP1->sy_nlist.n_type & N_STAB) == 0) continue;
+ if (symbolP1->sy_nlist.n_type != N_FUN) continue;
+ pnt=symbolP->sy_nlist.n_un.n_name;
+ pnt1=symbolP1->sy_nlist.n_un.n_name;
+ if(*pnt++ != '_') continue;
+ while(*pnt++ == *pnt1++) {};
+ 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 ((symbolP->sy_nlist.n_type & N_STAB) != 0) {
+ /*
+ * Dispatch on STAB type
+ */
+ switch((unsigned char)symbolP->sy_nlist.n_type) {
+ /*
+ * 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) &&
+ symbolP->sy_nlist.n_value ==
+ Current_Offset) break;
+ /* calculate actual debugger source line */
+ symbolP->sy_nlist.n_desc
+ += 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(
+ symbolP->sy_nlist.n_desc,
+ symbolP->sy_nlist.n_value,
+ Text_Psect,
+ 0);
+ } else {
+ if ((symbolP->sy_nlist.n_desc -
+ 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,
+ symbolP->sy_nlist.n_value -
+ Current_Offset,
+ 0,
+ -1);
+ VMS_TBT_Line_PC_Correlation(
+ symbolP->sy_nlist.n_desc,
+ symbolP->sy_nlist.n_value,
+ Text_Psect,
+ 0);
+ } else {
+ /*
+ * Line delta is +ve, all is well
+ */
+ VMS_TBT_Line_PC_Correlation(
+ symbolP->sy_nlist.n_desc -
+ Current_Line_Number,
+ symbolP->sy_nlist.n_value -
+ Current_Offset,
+ 0,
+ 1);
+ }
+ }
+ /*
+ * Update the current line/PC
+ */
+ Current_Line_Number = symbolP->sy_nlist.n_desc;
+ Current_Offset = symbolP->sy_nlist.n_value;
+ /*
+ * 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 - Current_Routine->sy_nlist.n_value,
+ 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,
+ Entry_Point_Symbol->sy_nlist.n_value);
+
+ /*
+ * All done, close the object file
+ */
+ Close_VMS_Object_File();
+}
+
+
+ /****** VMS OBJECT FILE HACKING ROUTINES *******/
+
+
+/*
+ * 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) *((long *)(Object_Record_Buffer + \
+ Object_Record_Offset)) = val; \
+ Object_Record_Offset += sizeof(long)
+
+#define PUT_SHORT(val) *((short *)(Object_Record_Buffer + \
+ Object_Record_Offset)) = val; \
+ Object_Record_Offset += sizeof(short)
+
+#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)
+
+
+/*
+ * Create the VMS object file
+ */
+Create_VMS_Object_File()
+{
+#ifdef eunice
+ VMS_Object_File_FD = creat(out_file_name, 0777, "var");
+#else eunice
+ VMS_Object_File_FD = creat(out_file_name, 0, "rfm=var");
+#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;
+}
+
+
+/*
+ * Declare a particular type of object file record
+ */
+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;
+}
+
+
+/*
+ * Flush the object record buffer to the object file
+ */
+Flush_VMS_Object_Record_Buffer()
+{
+ int i;
+
+ /*
+ * If the buffer is empty, we are done
+ */
+ if (Object_Record_Offset == 0) return;
+ /*
+ * Write the data to the file
+ */
+ 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");
+ /*
+ * The buffer is now empty
+ */
+ Object_Record_Offset = 0;
+}
+
+
+/*
+ * Close the VMS Object file
+ */
+Close_VMS_Object_File()
+{
+ close(VMS_Object_File_FD);
+}
+
+
+/*
+ * Write the MHD (Module Header) records
+ */
+Write_VMS_MHD_Records()
+{
+ register char *cp,*cp1;
+ register int i;
+ struct {int Size; char *Ptr;} Descriptor;
+ char Module_Name[256];
+ char Now[17];
+
+ /*
+ * We are writing a module header record
+ */
+ Set_VMS_Object_File_Record(OBJ$C_HDR);
+ /*
+ * ***************************
+ * *MAIN MODULE HEADER RECORD*
+ * ***************************
+ *
+ * Store record type and header type
+ */
+ PUT_CHAR(OBJ$C_HDR);
+ PUT_CHAR(MHD$C_MHD);
+ /*
+ * Structure level is 0
+ */
+ PUT_CHAR(OBJ$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)
+ */
+ Descriptor.Size = 17;
+ Descriptor.Ptr = Now;
+ sys$asctim(0,&Descriptor,0,0);
+ 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$C_HDR);
+ PUT_CHAR(MHD$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
+ */
+Write_VMS_EOM_Record(Psect, Offset)
+int Psect;
+int Offset;
+{
+ /*
+ * We are writing an end-of-module record
+ */
+ Set_VMS_Object_File_Record(OBJ$C_EOM);
+ /*
+ * Store record Type
+ */
+ PUT_CHAR(OBJ$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)
+ */
+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 == '_') In++;
+
+ new_name=Out; /* save this for later*/
+
+ if((In[0]=='_')&&(In[1]=='$')&&(In[2]=='_'))
+ destructor=1;
+
+ /* 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;
+ if (isupper(*In)) {
+ *Out++ = *In++;
+ Case_Hack_Bits |= 1;
+ } else {
+ *Out++ = islower(*In) ? toupper(*In++) : *In++;
+ }
+ }
+ /*
+ * 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
+ */
+ if(flagseen['h'])
+ i=8;
+ else
+ for(i = 0; (In[i] != 0) && (i < 8); i++)
+ if (isupper(In[i]) && !Saw_Dollar)
+ 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))
+ *Out++ = islower(*In) ?
+ toupper(*In++) :
+ *In++;
+ }
+ }
+ }
+ /*
+ * 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
+ */
+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$M_PIC},
+ {"LIB", GPS$M_LIB},
+ {"OVR", GPS$M_OVR},
+ {"REL", GPS$M_REL},
+ {"GBL", GPS$M_GBL},
+ {"SHR", GPS$M_SHR},
+ {"EXE", GPS$M_EXE},
+ {"RD", GPS$M_RD},
+ {"WRT", GPS$M_WRT},
+ {"VEC", GPS$M_VEC},
+ {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 psect
+ */
+VMS_Psect_Spec(Name, Size, Type)
+char *Name;
+int Size;
+char *Type;
+{
+ char Local[32];
+ int Psect_Attributes;
+
+ /*
+ * We are writing a GSD record
+ */
+ Set_VMS_Object_File_Record(OBJ$C_GSD);
+ /*
+ * If the buffer is empty we must insert the GSD record type
+ */
+ if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD);
+ /*
+ * We are writing a PSECT definition subrecord
+ */
+ PUT_CHAR(GSD$C_PSC);
+ /*
+ * Psects are always LONGWORD aligned
+ */
+ PUT_CHAR(2);
+ /*
+ * 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$M_PIC|GPS$M_OVR|GPS$M_REL|GPS$M_GBL|
+ GPS$M_SHR|GPS$M_RD|GPS$M_WRT);
+ } else if (strcmp(Type,"CONST") == 0) {
+ /*
+ * Common block psects are: PIC,OVR,REL,GBL,SHR,RD
+ */
+ Psect_Attributes = (GPS$M_PIC|GPS$M_OVR|GPS$M_REL|GPS$M_GBL|
+ GPS$M_SHR|GPS$M_RD);
+ } else if (strcmp(Type,"DATA") == 0) {
+ /*
+ * The Data psects are PIC,REL,RD,WRT
+ */
+ Psect_Attributes =
+ (GPS$M_PIC|GPS$M_REL|GPS$M_RD|GPS$M_WRT);
+ } else if (strcmp(Type,"TEXT") == 0) {
+ /*
+ * The Text psects are PIC,REL,SHR,EXE,RD
+ */
+ Psect_Attributes =
+ (GPS$M_PIC|GPS$M_REL|GPS$M_SHR|
+ GPS$M_EXE|GPS$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);
+ /*
+ * 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();
+}
+
+
+/*
+ * Define a global symbol
+ */
+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$C_GSD);
+ /*
+ * If the buffer is empty we must insert the GSD record type
+ */
+ if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD);
+ /*
+ * We are writing a Global symbol definition subrecord
+ */
+ if (Psect_Number <= 255) {
+ PUT_CHAR(GSD$C_SYM);
+ } else {
+ PUT_CHAR(GSD$C_SYMW);
+ }
+ /*
+ * Data type is undefined
+ */
+ PUT_CHAR(0);
+ /*
+ * Switch on Definition/Reference
+ */
+ if (Defined) {
+ /*
+ * Definition:
+ * Flags = "RELOCATABLE" and "DEFINED"
+ */
+ PUT_SHORT(GSY$M_DEF|GSY$M_REL);
+ /*
+ * Psect Number
+ */
+ if (Psect_Number <= 255) {
+ PUT_CHAR(Psect_Number);
+ } else {
+ PUT_SHORT(Psect_Number);
+ }
+ /*
+ * Offset
+ */
+ PUT_LONG(Psect_Offset);
+ } else {
+ /*
+ * Reference:
+ * Flags = "RELOCATABLE"
+ */
+ PUT_SHORT(GSY$M_REL);
+ }
+ /*
+ * 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 procedure entry pt/mask
+ */
+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$C_GSD);
+ /*
+ * If the buffer is empty we must insert the GSD record type
+ */
+ if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD);
+ /*
+ * We are writing a Procedure Entry Pt/Mask subrecord
+ */
+ if (Psect_Number <= 255) {
+ PUT_CHAR(GSD$C_EPM);
+ } else {
+ PUT_CHAR(GSD$C_EPMW);
+ }
+ /*
+ * Data type is undefined
+ */
+ PUT_CHAR(0);
+ /*
+ * Flags = "RELOCATABLE" and "DEFINED"
+ */
+ PUT_SHORT(GSY$M_DEF|GSY$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
+ */
+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$C_STA_PL);
+ PUT_CHAR(Psect_Index);
+ } else {
+ PUT_CHAR(TIR$C_STA_WPL);
+ PUT_SHORT(Psect_Index);
+ }
+ PUT_LONG(Offset);
+ /*
+ * Set relocation base
+ */
+ PUT_CHAR(TIR$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();
+}
+
+/*
+ * Make a data reference
+ */
+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$C_STA_WPL);
+ PUT_SHORT(Psect_Index);
+ PUT_LONG(Offset);}
+ else {
+ PUT_CHAR(TIR$C_STA_PL);
+ PUT_CHAR(Psect_Index);
+ PUT_LONG(Offset);}
+ } else {if(Offset>32767){
+ PUT_CHAR(TIR$C_STA_WPL);
+ PUT_SHORT(Psect_Index);
+ PUT_LONG(Offset);}
+ else if(Offset>127){
+ PUT_CHAR(TIR$C_STA_WPW);
+ PUT_SHORT(Psect_Index);
+ PUT_SHORT(Offset);}
+ else{
+ PUT_CHAR(TIR$C_STA_WPB);
+ PUT_SHORT(Psect_Index);
+ PUT_CHAR(Offset);};};
+ /*
+ * Set relocation base
+ */
+ PUT_CHAR(TIR$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.
+ */
+VMS_Store_Struct(int Struct_Index)
+{
+ /*
+ * We are writing a "OBJ$C_DBG" record
+ */
+ Set_VMS_Object_File_Record(OBJ$C_DBG);
+ /*
+ * If the buffer is empty we must insert the record type
+ */
+ if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
+ PUT_CHAR(TIR$C_STA_UW);
+ PUT_SHORT(Struct_Index);
+ PUT_CHAR(TIR$C_CTL_STKDL);
+ PUT_CHAR(TIR$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.
+ */
+VMS_Def_Struct(int Struct_Index)
+{
+ /*
+ * We are writing a "OBJ$C_DBG" record
+ */
+ Set_VMS_Object_File_Record(OBJ$C_DBG);
+ /*
+ * If the buffer is empty we must insert the record type
+ */
+ if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
+ PUT_CHAR(TIR$C_STA_UW);
+ PUT_SHORT(Struct_Index);
+ PUT_CHAR(TIR$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();
+}
+
+VMS_Set_Struct(int Struct_Index)
+{/* see previous functions for comments */
+ Set_VMS_Object_File_Record(OBJ$C_DBG);
+ if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
+ PUT_CHAR(TIR$C_STA_UW);
+ PUT_SHORT(Struct_Index);
+ PUT_CHAR(TIR$C_CTL_STLOC);
+ if (Object_Record_Offset >
+ (sizeof(Object_Record_Buffer)*3/4))
+ Flush_VMS_Object_Record_Buffer();
+}
+
+/*
+ * Store immediate data in current Psect
+ */
+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();
+ }
+}
+
+
+/*
+ * Store repeated immediate data in current Psect
+ */
+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$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$C_STA_LW);
+ PUT_LONG(Repeat_Count);
+ /*
+ * And now the command and its data
+ */
+ PUT_CHAR(TIR$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
+ */
+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(Symbol->sy_nlist.n_type) {
+ /*
+ * 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(Symbol->sy_nlist.n_un.n_name,Local);
+ /*
+ * Stack the global symbol value
+ */
+ PUT_CHAR(TIR$C_STA_GBL);
+ PUT_COUNTED_STRING(Local);
+ if (Offset) {
+ /*
+ * Stack the longword offset
+ */
+ PUT_CHAR(TIR$C_STA_LW);
+ PUT_LONG(Offset);
+ /*
+ * Add the two, leaving the result on the stack
+ */
+ PUT_CHAR(TIR$C_OPR_ADD);
+ }
+ break;
+ /*
+ * Uninitialized local data
+ */
+ case N_BSS:
+ /*
+ * Stack the Psect (+offset)
+ */
+ if (vsp->Psect_Index < 255) {
+ PUT_CHAR(TIR$C_STA_PL);
+ PUT_CHAR(vsp->Psect_Index);
+ } else {
+ PUT_CHAR(TIR$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$C_STA_PL);
+ PUT_CHAR(vsp->Psect_Index);
+ } else {
+ PUT_CHAR(TIR$C_STA_WPL);
+ PUT_SHORT(vsp->Psect_Index);
+ }
+ PUT_LONG(Symbol->sy_nlist.n_value);
+ 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$C_STA_PL);
+ PUT_CHAR(vsp->Psect_Index);
+ } else {
+ PUT_CHAR(TIR$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$C_STO_PICR : TIR$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$C_STO_PIRR IN THE
+ * PIC CODE GENERATING FIXUP ROUTINE.
+ */
+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$C_TIR);
+ VMS_Store_Immediate_Data(&Address_Mode,1,OBJ$C_TIR);
+ }
+}
+
+
+/*
+ * Write the Traceback Module Begin record
+ */
+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$C_MODBEG;
+ /*
+ * Unused
+ */
+ *cp++ = 0;
+ /*
+ * Language type == "C"
+ */
+ *(long *)cp = DST$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$C_TBT);
+}
+
+
+/*
+ * Write the Traceback Module End record
+*/
+VMS_TBT_Module_End()
+{
+ char Local[2];
+
+ /*
+ * End module
+ */
+ Local[0] = 1;
+ Local[1] = DST$C_MODEND;
+ /*
+ * Put it into the object record
+ */
+ VMS_Store_Immediate_Data(Local, 2, OBJ$C_TBT);
+}
+
+
+/*
+ * Write the Traceback Routine Begin record
+ */
+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 = symbolP->sy_nlist.n_un.n_name;
+ if (*Name == '_') Name++;
+ /*
+ * Get the text psect offset
+ */
+ Offset = symbolP->sy_nlist.n_value;
+ /*
+ * Calculate the record size
+ */
+ Size = 1+1+4+1+strlen(Name);
+ /*
+ * Record Size
+ */
+ Local[0] = Size;
+ /*
+ * Begin Routine
+ */
+ Local[1] = DST$C_RTNBEG;
+ /*
+ * Uses CallS/CallG
+ */
+ Local[2] = 0;
+ /*
+ * Store the data so far
+ */
+ VMS_Store_Immediate_Data(Local, 3, OBJ$C_TBT);
+ /*
+ * Make sure we are still generating a OBJ$C_TBT record
+ */
+ if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_TBT);
+ /*
+ * Now get the symbol address
+ */
+ PUT_CHAR(TIR$C_STA_WPL);
+ PUT_SHORT(Psect);
+ PUT_LONG(Offset);
+ /*
+ * Store the data reference
+ */
+ PUT_CHAR(TIR$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$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.
+ */
+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 ((symbolP->sy_nlist.n_type & ~N_EXT) == N_TEXT) {
+ if (symbolP->sy_nlist.n_un.n_name[0] == 'L') continue;
+ if((symbolP->sy_nlist.n_value > sp->sy_nlist.n_value) &&
+ (symbolP->sy_nlist.n_value < Size ))
+ Size = symbolP->sy_nlist.n_value;
+ /* check if gcc_compiled. has size of zero */
+ if((symbolP->sy_nlist.n_value == sp->sy_nlist.n_value) &&
+ sp != symbolP &&
+ !strcmp(sp->sy_nlist.n_un.n_name,"gcc_compiled."))
+ Size = symbolP->sy_nlist.n_value;
+
+ };
+ };
+ if(Size == 0x7fffffff) Size = Max_Size;
+ Size -= sp->sy_nlist.n_value; /* and get the size of the routine */
+ /*
+ * Record Size
+ */
+ Local[0] = 6;
+ /*
+ * End of Routine
+ */
+ Local[1] = DST$C_RTNEND;
+ /*
+ * Unused
+ */
+ Local[2] = 0;
+ /*
+ * Size of routine
+ */
+ *((long *)(Local+3)) = Size;
+ /*
+ * Store the record
+ */
+ VMS_Store_Immediate_Data(Local,7, OBJ$C_TBT);
+}
+/*
+ * Write the Traceback Block End record
+ */
+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$C_BLKBEG;
+ /*
+ * Uses CallS/CallG
+ */
+ Local[2] = 0;
+ /*
+ * Store the data so far
+ */
+ VMS_Store_Immediate_Data(Local, 3, OBJ$C_DBG);
+ /*
+ * Make sure we are still generating a OBJ$C_DBG record
+ */
+ if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
+ /*
+ * Now get the symbol address
+ */
+ PUT_CHAR(TIR$C_STA_WPL);
+ PUT_SHORT(Psect);
+ /*
+ * Get the text psect offset
+ */
+ Offset = symbolP->sy_nlist.n_value;
+ PUT_LONG(Offset);
+ /*
+ * Store the data reference
+ */
+ PUT_CHAR(TIR$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$C_DBG);
+}
+
+
+/*
+ * Write the Traceback Block End record
+ */
+VMS_TBT_Block_End(int Size)
+{
+ char Local[16];
+
+ /*
+ * End block - simulate with a phony end routine
+ */
+ Local[0] = 6;
+ Local[1] = DST$C_BLKEND;
+ *((long *)(Local+3)) = Size;
+ /*
+ * Unused
+ */
+ Local[2] = 0;
+ VMS_Store_Immediate_Data(Local,7, OBJ$C_DBG);
+}
+
+
+
+/*
+ * Write a Line number / PC correlation record
+ */
+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$C_LINE_NUM;
+ /*
+ * Set Line number
+ */
+ Local[2] = DST$C_SET_LINE_NUM;
+ *((unsigned short *)(Local+3)) = Line_Number-1;
+ /*
+ * Set PC
+ */
+ Local[5] = DST$C_SET_ABS_PC;
+ VMS_Store_Immediate_Data(Local, 6, OBJ$C_TBT);
+ /*
+ * Make sure we are still generating a OBJ$C_TBT record
+ */
+ if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_TBT);
+ if (Psect < 255) {
+ PUT_CHAR(TIR$C_STA_PL);
+ PUT_CHAR(Psect);
+ } else {
+ PUT_CHAR(TIR$C_STA_WPL);
+ PUT_SHORT(Psect);
+ }
+ PUT_LONG(Offset);
+ PUT_CHAR(TIR$C_STO_PIDR);
+ /*
+ * Do a PC offset of 0 to register the line number
+ */
+ Local[0] = 2;
+ Local[1] = DST$C_LINE_NUM;
+ Local[2] = 0; /* Increment PC by 0 and register line # */
+ VMS_Store_Immediate_Data(Local, 3, OBJ$C_TBT);
+ } else {
+ /*
+ * If Delta is negative, terminate the line numbers
+ */
+ if (Do_Delta < 0) {
+ Local[0] = 1+1+4;
+ Local[1] = DST$C_LINE_NUM;
+ Local[2] = DST$C_TERM_L;
+ *((long *)(Local+3)) = Offset;
+ VMS_Store_Immediate_Data(Local, 7, OBJ$C_TBT);
+ /*
+ * Done
+ */
+ return;
+ }
+ /*
+ * Do a PC/Line delta
+ */
+ cp = Local+1;
+ *cp++ = DST$C_LINE_NUM;
+ if (Line_Number > 1) {
+ /*
+ * We need to increment the line number
+ */
+ if (Line_Number-1 <= 255) {
+ *cp++ = DST$C_INCR_LINUM;
+ *cp++ = Line_Number-1;
+ } else {
+ *cp++ = DST$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$C_DELTA_PC_W;
+ *(short *)cp = Offset;
+ cp += sizeof(short);
+ } else {
+ *cp++ = DST$C_DELTA_PC_L;
+ *(long *)cp = Offset;
+ cp += sizeof(long);
+ }
+ }
+ Local[0] = cp - (Local+1);
+ VMS_Store_Immediate_Data(Local,cp - Local, OBJ$C_TBT);
+ }
+}
+
+
+/*
+ * Describe a source file to the debugger
+ */
+VMS_TBT_Source_File(Filename, ID_Number)
+char *Filename;
+int ID_Number;
+{
+ register char *cp,*cp1;
+ int Status,i;
+ char Local[512];
+ 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 = (struct XAB *)&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);
+/* ((struct XAB *)&Date_Xab)->xab$b_cod = XAB$C_DAT; */
+/* ((struct XAB *)&Date_Xab)->xab$b_bln = sizeof(Date_Xab); */
+/* ((struct XAB *)&Date_Xab)->xab$l_nxt = (struct XAB *)&File_Header_Xab; */
+/* ((struct XAB *)&File_Header_Xab)->xab$b_cod = XAB$C_FHC; */
+/* ((struct XAB *)&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;
+ /*
+ * Size of record
+ */
+ Local[0] = 1+1+1+1+1+2+8+4+2+1+1+i+1;
+ /*
+ * Source declaration
+ */
+ Local[1] = DST$C_SOURCE;
+ /*
+ * Make formfeeds count as source records
+ */
+ Local[2] = DST$C_SRC_FORMFEED;
+ /*
+ * Declare source file
+ */
+ Local[3] = DST$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);
+ /*
+ * 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;
+ while(--i >= 0) *cp++ = *cp1++;
+ /*
+ * Library module name (none)
+ */
+ *cp++ = 0;
+ /*
+ * Done
+ */
+ VMS_Store_Immediate_Data(Local,cp - Local, OBJ$C_TBT);
+}
+
+
+/*
+ * Give the number of source lines to the debugger
+ */
+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$C_SOURCE;
+ /*
+ * Set Source File
+ */
+ cp = Local+2;
+ *cp++ = DST$C_SRC_SETFILE;
+ /*
+ * File ID Number
+ */
+ *(short *)cp = ID_Number;
+ cp += sizeof(short);
+ /*
+ * Set record number
+ */
+ *cp++ = DST$C_SRC_SETREC_L;
+ *(long *)cp = Starting_Line_Number;
+ cp += sizeof(long);
+ /*
+ * Define lines
+ */
+ *cp++ = DST$C_SRC_DEFLINES_W;
+ *(short *)cp = Number_Of_Lines;
+ cp += sizeof(short);
+ /*
+ * Done
+ */
+ VMS_Store_Immediate_Data(Local, cp-Local, OBJ$C_TBT);
+}
+
+
+/*
+ * 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.
+ */
+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 ((sp1->sy_nlist.n_type & ~N_EXT) != N_DATA) continue;
+ /*
+ * The symbol must be AFTER this symbol
+ */
+ if (sp1->sy_nlist.n_value <= sp->sy_nlist.n_value) 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 (sp1->sy_nlist.n_value >
+ Next_Symbol->sy_nlist.n_value)
+ continue;
+ /*
+ * Win: Make this the candidate
+ */
+ Next_Symbol = sp1;
+ } else {
+ /*
+ * This is the 1st candidate
+ */
+ Next_Symbol = sp1;
+ }
+ }
+ /*
+ * Calculate its size
+ */
+ return(Next_Symbol ?
+ (Next_Symbol->sy_nlist.n_value -
+ sp->sy_nlist.n_value) :
+ (End_Of_Data - sp->sy_nlist.n_value));
+}
+
+
+
+/* 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 */
+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(sp->sy_nlist.n_un.n_name,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 = sp->sy_nlist.n_un.n_name;
+ fpnt->min_line = 0x7fffffff;
+ fpnt->max_line = 0;
+ fpnt->offset = 0;
+ fpnt->flag = 0;
+ fpnt->file_number = 0;
+ fpnt->spnt = sp;
+ fpnt->same_file_fpnt = same_file;
+ return fpnt;
+}
+
+
+/*
+ * This 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!
+ */
+#ifndef eunice
+_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 */
+
+#endif /* VMS */
+
+char const_flag = 0;
+void s_const();
+
+void
+s_const()
+{
+ register int temp;
+
+ temp = get_absolute_expression ();
+ subseg_new (SEG_DATA, (subsegT)temp);
+ const_flag = 1;
+ demand_empty_rest_of_line();
+}
+
+obj_crawl_symbol_chain() {
+ /* JF deal with forward references first. . . */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ if (symbolP->sy_forward) {
+ symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address;
+#ifdef OBJ_COFF
+ if(SF_GET_GET_SEGMENT(symbolP) &&
+ S_GET_SEGMENT(symbolP) == SEG_UNKNOWN)
+ S_SET_SEGMENT(symbolP, S_GET_SEGMENT(symbolP->sy_forward));
+#endif /* OBJ_COFF */
+ symbolP->sy_forward=0;
+ } /* if it has a forward reference */
+ } /* walk the symbol chain */
+
+ { /* crawl symbol table */
+ register int symbol_number = 0;
+
+#if defined(OBJ_COFF)
+ { /* OBJ_COFF version */
+ lineno* lineP;
+ symbolS* symbol_externP = (symbolS*)0;
+ symbolS* symbol_extern_lastP = (symbolS*)0;
+
+ /* The symbol list should be ordered according to the following sequence
+ * order :
+ * . .file symbol
+ * . debug entries for functions
+ * . fake symbols for .text .data and .bss
+ * . defined symbols
+ * . undefined symbols
+ * But this is not mandatory. The only important point is to put the
+ * undefined symbols at the end of the list.
+ */
+
+ if (symbol_rootP == NULL
+ || S_GET_STORAGE_CLASS(symbol_rootP) != C_FILE) {
+ c_dot_file_symbol("fake");
+ } /* Is there a .file symbol ? If not insert one at the beginning. */
+
+ /*
+ * Build up static symbols for .text, .data and .bss
+ */
+ dot_text_symbol = (symbolS*)
+ c_section_symbol(".text",
+ 0,
+ H_GET_TEXT_SIZE(&headers),
+ 0/*text_relocation_number*/,
+ 0/*text_lineno_number*/);
+
+ dot_data_symbol = (symbolS*)
+ c_section_symbol(".data",
+ H_GET_TEXT_SIZE(&headers),
+ H_GET_DATA_SIZE(&headers),
+ 0/*data_relocation_number*/,
+ 0); /* There are no data lineno
+ entries */
+
+ dot_bss_symbol = (symbolS*)
+ c_section_symbol(".bss",
+ H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers),
+ H_GET_BSS_SIZE(&headers),
+ 0, /* No relocation for a bss section. */
+ 0); /* There are no bss lineno entries */
+
+ /* FIXME late night before delivery, I don't know why the chain is
+ broken, but I can guess. So! Let's force them to be knit properly
+ at this point. */
+
+/* as john pointed out, this wasn't right. Instead, we'll check here to
+ make sure that the list is doubly linked. */
+
+#if defined(DEBUG) && defined(SYMBOLS_NEED_BACKPOINTERS)
+ for (symbolP = symbol_rootP; symbol_next(symbolP); symbolP = symbol_next(symbolP)) {
+ know(symbolP->sy_next->sy_previous == symbolP);
+ } /* walk the symbol chain */
+#endif /* DEBUG and SYMBOLS_NEED_BACKPOINTERS */
+ symbolP = symbol_rootP;
+
+ if (symbolP) {
+ while(symbolP) {
+ /* If the symbol has a tagndx entry, resolve it */
+ if(SF_GET_TAGGED(symbolP)) {
+ SA_SET_SYM_TAGNDX(symbolP,
+ ((symbolS*)SA_GET_SYM_TAGNDX(symbolP))->sy_number);
+ }
+ /* Debug symbol do not need all this rubbish */
+ if(!SF_GET_DEBUG(symbolP)) {
+ symbolS* real_symbolP;
+ /* L* and C_EFCN symbols never merge. */
+ if(!SF_GET_LOCAL(symbolP) &&
+ (real_symbolP =
+ symbol_find_base(S_GET_NAME(symbolP), DO_NOT_STRIP)) &&
+ real_symbolP != symbolP) {
+ /* FIXME where do dups come from? xoxorich. */
+ /* Move the debug data from the debug symbol to the
+ real symbol. Do NOT do the oposite (i.e. move from
+ real symbol to symbol and remove real symbol from the
+ list.) Because some pointers refer to the real symbol
+ whereas no pointers refer to the symbol. */
+ c_symbol_merge(symbolP, real_symbolP);
+ /* Replace the current symbol by the real one */
+ /* The symbols will never be the last or the first
+ because : 1st symbol is .file and 3 last symbols are
+ .text, .data, .bss */
+ symbol_remove(real_symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_insert(real_symbolP, symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_remove(symbolP, &symbol_rootP, &symbol_lastP);
+ symbolP = real_symbolP;
+ }
+ if(flagseen['R'] && S_IS_DATA(symbolP))
+ S_SET_TEXT(symbolP);
+
+ symbolP->sy_value += symbolP->sy_frag->fr_address;
+
+ if(!S_IS_DEFINED(symbolP))
+ S_SET_EXTERNAL(symbolP);
+ else if(S_GET_STORAGE_CLASS(symbolP) == C_NULL)
+ S_SET_STORAGE_CLASS(symbolP, C_STAT);
+
+ /* Mainly to speed up if not -g */
+ if(SF_GET_PROCESS(symbolP)) {
+ /* Handle the nested blocks auxiliary info. */
+ if(S_GET_STORAGE_CLASS(symbolP) == C_BLOCK) {
+ if(!strcmp(S_GET_NAME(symbolP), ".bb"))
+ stack_push(block_stack, (char *) &symbolP);
+ else { /* .eb */
+ register symbolS* begin_symbolP;
+ begin_symbolP = *(symbolS**)stack_pop(block_stack);
+ if(begin_symbolP == (symbolS*)0)
+ as_warn("mismatched .eb");
+ else
+ SA_SET_SYM_ENDNDX(begin_symbolP, symbol_number);
+ }
+ }
+ /* If we are able to identify the type of a function, and we
+ are out of a function (last_functionP == 0) then, the
+ function symbol will be associated with an auxiliary
+ entry. */
+ if(last_functionP == (symbolS*)0 &&
+ SF_GET_FUNCTION(symbolP)) {
+ last_functionP = symbolP;
+ S_SET_NUMBER_AUXILIARY(symbolP, 1);
+ /* Clobber possible stale .dim information. */
+ memset(&symbolP->sy_auxent[0], '\0', sizeof(union auxent));
+ }
+ /* The C_FCN doesn't need any additional information.
+ I don't even know if this is needed for sdb. But the
+ standard assembler generates it, so...
+ */
+ if(S_GET_STORAGE_CLASS(symbolP) == C_EFCN) {
+ if(last_functionP == (symbolS*)0)
+ as_fatal("C_EFCN symbol out of scope");
+ SA_SET_SYM_FSIZE(last_functionP,
+ (long)(symbolP->sy_value -
+ last_functionP->sy_value));
+ SA_SET_SYM_ENDNDX(last_functionP, symbol_number);
+ last_functionP = (symbolS*)0;
+ }
+ }
+ } else {
+ /* First descriptor of a structure must point to the next
+ slot outside the structure description. */
+ if(SF_GET_TAG(symbolP))
+ last_tagP = symbolP;
+ else if(S_GET_STORAGE_CLASS(symbolP) == C_EOS)
+ /* +2 take in account the current symbol */
+ SA_SET_SYM_ENDNDX(last_tagP, symbol_number+2);
+ }
+
+ /* We must put the external symbols apart. The loader
+ does not bomb if we do not. But the references in
+ the endndx field for a .bb symbol are not corrected
+ if an external symbol is removed between .bb and .be.
+ I.e in the following case :
+ [20] .bb endndx = 22
+ [21] foo external
+ [22] .be
+ ld will move the symbol 21 to the end of the list but
+ endndx will still be 22 instead of 21. */
+ {
+ register symbolS* thisP = symbolP;
+
+ symbolP = symbol_next(thisP);
+ /* remove C_EFCN and LOCAL (L...) symbols */
+ if (SF_GET_LOCAL(thisP)) {
+ symbol_remove(thisP, &symbol_rootP, &symbol_lastP);
+ } else {
+ if(S_GET_STORAGE_CLASS(thisP) == C_EXT &&
+ !SF_GET_FUNCTION(thisP)) {
+ /* Remove from the list */
+ symbol_remove(thisP, &symbol_rootP, &symbol_lastP);
+ symbol_clear_list_pointers(thisP);
+ /* Move at the end of the list */
+ if (symbol_extern_lastP == (symbolS*)0)
+ symbol_externP = thisP;
+ else
+ symbol_append(thisP, symbol_extern_lastP);
+ symbol_extern_lastP = thisP;
+ } else {
+ if(SF_GET_STRING(thisP)) {
+ thisP->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(thisP)) + 1;
+ } else
+ thisP->sy_name_offset = 0;
+ thisP->sy_number = symbol_number;
+ symbol_number += 1 + S_GET_NUMBER_AUXILIARY(thisP);
+ }
+ }
+ }
+ }
+
+ /* this actually appends the entire extern chain */
+ symbol_append(symbol_externP, symbol_lastP);
+ symbolP = symbol_externP;
+ while(symbolP) {
+ if(SF_GET_STRING(symbolP)) {
+ symbolP->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(symbolP)) + 1;
+ } else
+ symbolP->sy_name_offset = 0;
+ symbolP->sy_number = symbol_number;
+ symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP);
+ symbolP = symbol_next(symbolP);
+ }
+ }
+
+ /* FIXME I'm counting line no's here so we know what to put in the section
+ headers, and I'm resolving the addresses since I'm not sure how to
+ do it later. I am NOT resolving the linno's representing functions.
+ Their symbols need a fileptr pointing to this linno when emitted.
+ Thus, I resolve them on emit. xoxorich. */
+
+ for (lineP = lineno_rootP; lineP; lineP = lineP->next) {
+ if (lineP->line.l_lnno) {
+ lineP->line.l_addr.l_paddr += ((fragS*)lineP->frag)->fr_address;
+ } else {
+ ;
+ }
+ text_lineno_number++;
+ } /* for each line number */
+ } /* OBJ_COFF version */
+#elif defined(OBJ_AOUT) | defined(OBJ_BOUT)
+ { /* OBJ_AOUT version */
+ symbolPP = & symbol_rootP; /* -> last symbol chain link. */
+ while ((symbolP = *symbolPP) != NULL)
+ {
+ if (flagseen['R'] && S_IS_DATA(symbolP)) {
+ S_SET_TEXT(symbolP);
+ } /* if pusing data into text */
+
+ symbolP -> sy_value += 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 (1
+ && !S_IS_REGISTER(symbolP)
+#ifndef VMS /* Under VMS we need to keep local symbols */
+ && ( !S_GET_NAME(symbolP)
+ || S_IS_DEBUG(symbolP)
+#ifdef TC_I960
+ /* FIXME this ifdef seems highly dubious to me. xoxorich. */
+ || !S_IS_DEFINED(symbolP)
+ || S_IS_EXTERNAL(symbolP)
+#endif /* TC_I960 */
+ || (S_GET_NAME(symbolP)[0] != '\001' && (flagseen ['L'] || ! S_LOCAL_NAME(symbolP))))
+#endif /* not VMS */
+ )
+ {
+#ifndef VMS
+ symbolP->sy_number = symbol_number++;
+
+ /* The + 1 after strlen account for the \0 at the
+ end of each string */
+ if (!S_IS_STABD(symbolP)) {
+ /* Ordinary case. */
+ symbolP->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(symbolP)) + 1;
+ }
+ else /* .Stabd case. */
+#endif /* not VMS */
+ 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", name);
+ } /* oops. */
+
+#ifndef VMS
+ /* Unhook it from the chain */
+ *symbolPP = symbol_next(symbolP);
+#endif /* VMS */
+ } /* if this symbol should be in the output */
+ } /* for each symbol */
+ } /* OBJ_AOUT version */
+#else
+ cant_crawl_symbol_table();
+#endif
+ H_SET_STRING_SIZE(&headers,string_byte_count);
+ H_SET_SYMBOL_TABLE_SIZE(&headers, symbol_number);
+ } /* crawl symbol table */
+
+ /* JF deal with forward references first. . . */
+ for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) {
+ if (symbolP->sy_forward) {
+ symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address;
+#ifdef OBJ_COFF
+ if(SF_GET_GET_SEGMENT(symbolP) &&
+ S_GET_SEGMENT(symbolP) == SEG_UNKNOWN)
+ S_SET_SEGMENT(symbolP, S_GET_SEGMENT(symbolP->sy_forward));
+#endif /* OBJ_COFF */
+ symbolP->sy_forward=0;
+ } /* if it has a forward reference */
+ } /* walk the symbol chain */
+
+ { /* crawl symbol table */
+ register int symbol_number = 0;
+
+#if defined(OBJ_COFF)
+ { /* OBJ_COFF version */
+ lineno* lineP;
+ symbolS* symbol_externP = (symbolS*)0;
+ symbolS* symbol_extern_lastP = (symbolS*)0;
+
+ /* The symbol list should be ordered according to the following sequence
+ * order :
+ * . .file symbol
+ * . debug entries for functions
+ * . fake symbols for .text .data and .bss
+ * . defined symbols
+ * . undefined symbols
+ * But this is not mandatory. The only important point is to put the
+ * undefined symbols at the end of the list.
+ */
+
+ if (symbol_rootP == NULL
+ || S_GET_STORAGE_CLASS(symbol_rootP) != C_FILE) {
+ c_dot_file_symbol("fake");
+ } /* Is there a .file symbol ? If not insert one at the beginning. */
+
+ /*
+ * Build up static symbols for .text, .data and .bss
+ */
+ dot_text_symbol = (symbolS*)
+ c_section_symbol(".text",
+ 0,
+ H_GET_TEXT_SIZE(&headers),
+ 0/*text_relocation_number*/,
+ 0/*text_lineno_number*/);
+
+ dot_data_symbol = (symbolS*)
+ c_section_symbol(".data",
+ H_GET_TEXT_SIZE(&headers),
+ H_GET_DATA_SIZE(&headers),
+ 0/*data_relocation_number*/,
+ 0); /* There are no data lineno
+ entries */
+
+ dot_bss_symbol = (symbolS*)
+ c_section_symbol(".bss",
+ H_GET_TEXT_SIZE(&headers) + H_GET_DATA_SIZE(&headers),
+ H_GET_BSS_SIZE(&headers),
+ 0, /* No relocation for a bss section. */
+ 0); /* There are no bss lineno entries */
+
+ /* FIXME late night before delivery, I don't know why the chain is
+ broken, but I can guess. So! Let's force them to be knit properly
+ at this point. */
+
+/* as john pointed out, this wasn't right. Instead, we'll check here to
+ make sure that the list is doubly linked. */
+
+#if defined(DEBUG) && defined(SYMBOLS_NEED_BACKPOINTERS)
+ for (symbolP = symbol_rootP; symbol_next(symbolP); symbolP = symbol_next(symbolP)) {
+ know(symbolP->sy_next->sy_previous == symbolP);
+ } /* walk the symbol chain */
+#endif /* DEBUG and SYMBOLS_NEED_BACKPOINTERS */
+ symbolP = symbol_rootP;
+
+ if (symbolP) {
+ while(symbolP) {
+ /* If the symbol has a tagndx entry, resolve it */
+ if(SF_GET_TAGGED(symbolP)) {
+ SA_SET_SYM_TAGNDX(symbolP,
+ ((symbolS*)SA_GET_SYM_TAGNDX(symbolP))->sy_number);
+ }
+ /* Debug symbol do not need all this rubbish */
+ if(!SF_GET_DEBUG(symbolP)) {
+ symbolS* real_symbolP;
+ /* L* and C_EFCN symbols never merge. */
+ if(!SF_GET_LOCAL(symbolP) &&
+ (real_symbolP =
+ symbol_find_base(S_GET_NAME(symbolP), DO_NOT_STRIP)) &&
+ real_symbolP != symbolP) {
+ /* FIXME where do dups come from? xoxorich. */
+ /* Move the debug data from the debug symbol to the
+ real symbol. Do NOT do the oposite (i.e. move from
+ real symbol to symbol and remove real symbol from the
+ list.) Because some pointers refer to the real symbol
+ whereas no pointers refer to the symbol. */
+ c_symbol_merge(symbolP, real_symbolP);
+ /* Replace the current symbol by the real one */
+ /* The symbols will never be the last or the first
+ because : 1st symbol is .file and 3 last symbols are
+ .text, .data, .bss */
+ symbol_remove(real_symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_insert(real_symbolP, symbolP, &symbol_rootP, &symbol_lastP);
+ symbol_remove(symbolP, &symbol_rootP, &symbol_lastP);
+ symbolP = real_symbolP;
+ }
+ if(flagseen['R'] && S_IS_DATA(symbolP))
+ S_SET_TEXT(symbolP);
+
+ symbolP->sy_value += symbolP->sy_frag->fr_address;
+
+ if(!S_IS_DEFINED(symbolP))
+ S_SET_EXTERNAL(symbolP);
+ else if(S_GET_STORAGE_CLASS(symbolP) == C_NULL)
+ S_SET_STORAGE_CLASS(symbolP, C_STAT);
+
+ /* Mainly to speed up if not -g */
+ if(SF_GET_PROCESS(symbolP)) {
+ /* Handle the nested blocks auxiliary info. */
+ if(S_GET_STORAGE_CLASS(symbolP) == C_BLOCK) {
+ if(!strcmp(S_GET_NAME(symbolP), ".bb"))
+ stack_push(block_stack, (char *) &symbolP);
+ else { /* .eb */
+ register symbolS* begin_symbolP;
+ begin_symbolP = *(symbolS**)stack_pop(block_stack);
+ if(begin_symbolP == (symbolS*)0)
+ as_warn("mismatched .eb");
+ else
+ SA_SET_SYM_ENDNDX(begin_symbolP, symbol_number);
+ }
+ }
+ /* If we are able to identify the type of a function, and we
+ are out of a function (last_functionP == 0) then, the
+ function symbol will be associated with an auxiliary
+ entry. */
+ if(last_functionP == (symbolS*)0 &&
+ SF_GET_FUNCTION(symbolP)) {
+ last_functionP = symbolP;
+ S_SET_NUMBER_AUXILIARY(symbolP, 1);
+ /* Clobber possible stale .dim information. */
+ memset(&symbolP->sy_auxent[0], '\0', sizeof(union auxent));
+ }
+ /* The C_FCN doesn't need any additional information.
+ I don't even know if this is needed for sdb. But the
+ standard assembler generates it, so...
+ */
+ if(S_GET_STORAGE_CLASS(symbolP) == C_EFCN) {
+ if(last_functionP == (symbolS*)0)
+ as_fatal("C_EFCN symbol out of scope");
+ SA_SET_SYM_FSIZE(last_functionP,
+ (long)(symbolP->sy_value -
+ last_functionP->sy_value));
+ SA_SET_SYM_ENDNDX(last_functionP, symbol_number);
+ last_functionP = (symbolS*)0;
+ }
+ }
+ } else {
+ /* First descriptor of a structure must point to the next
+ slot outside the structure description. */
+ if(SF_GET_TAG(symbolP))
+ last_tagP = symbolP;
+ else if(S_GET_STORAGE_CLASS(symbolP) == C_EOS)
+ /* +2 take in account the current symbol */
+ SA_SET_SYM_ENDNDX(last_tagP, symbol_number+2);
+ }
+
+ /* We must put the external symbols apart. The loader
+ does not bomb if we do not. But the references in
+ the endndx field for a .bb symbol are not corrected
+ if an external symbol is removed between .bb and .be.
+ I.e in the following case :
+ [20] .bb endndx = 22
+ [21] foo external
+ [22] .be
+ ld will move the symbol 21 to the end of the list but
+ endndx will still be 22 instead of 21. */
+ {
+ register symbolS* thisP = symbolP;
+
+ symbolP = symbol_next(thisP);
+ /* remove C_EFCN and LOCAL (L...) symbols */
+ if (SF_GET_LOCAL(thisP)) {
+ symbol_remove(thisP, &symbol_rootP, &symbol_lastP);
+ } else {
+ if(S_GET_STORAGE_CLASS(thisP) == C_EXT &&
+ !SF_GET_FUNCTION(thisP)) {
+ /* Remove from the list */
+ symbol_remove(thisP, &symbol_rootP, &symbol_lastP);
+ symbol_clear_list_pointers(thisP);
+ /* Move at the end of the list */
+ if (symbol_extern_lastP == (symbolS*)0)
+ symbol_externP = thisP;
+ else
+ symbol_append(thisP, symbol_extern_lastP);
+ symbol_extern_lastP = thisP;
+ } else {
+ if(SF_GET_STRING(thisP)) {
+ thisP->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(thisP)) + 1;
+ } else
+ thisP->sy_name_offset = 0;
+ thisP->sy_number = symbol_number;
+ symbol_number += 1 + S_GET_NUMBER_AUXILIARY(thisP);
+ }
+ }
+ }
+ }
+
+ /* this actually appends the entire extern chain */
+ symbol_append(symbol_externP, symbol_lastP);
+ symbolP = symbol_externP;
+ while(symbolP) {
+ if(SF_GET_STRING(symbolP)) {
+ symbolP->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(symbolP)) + 1;
+ } else
+ symbolP->sy_name_offset = 0;
+ symbolP->sy_number = symbol_number;
+ symbol_number += 1 + S_GET_NUMBER_AUXILIARY(symbolP);
+ symbolP = symbol_next(symbolP);
+ }
+ }
+
+ /* FIXME I'm counting line no's here so we know what to put in the section
+ headers, and I'm resolving the addresses since I'm not sure how to
+ do it later. I am NOT resolving the linno's representing functions.
+ Their symbols need a fileptr pointing to this linno when emitted.
+ Thus, I resolve them on emit. xoxorich. */
+
+ for (lineP = lineno_rootP; lineP; lineP = lineP->next) {
+ if (lineP->line.l_lnno) {
+ lineP->line.l_addr.l_paddr += ((fragS*)lineP->frag)->fr_address;
+ } else {
+ ;
+ }
+ text_lineno_number++;
+ } /* for each line number */
+ } /* OBJ_COFF version */
+#elif defined(OBJ_AOUT) | defined(OBJ_BOUT)
+ { /* OBJ_AOUT version */
+ symbolPP = & symbol_rootP; /* -> last symbol chain link. */
+ while ((symbolP = *symbolPP) != NULL)
+ {
+ if (flagseen['R'] && S_IS_DATA(symbolP)) {
+ S_SET_TEXT(symbolP);
+ } /* if pusing data into text */
+
+ symbolP -> sy_value += 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 (1
+ && !S_IS_REGISTER(symbolP)
+#ifndef VMS /* Under VMS we need to keep local symbols */
+ && ( !S_GET_NAME(symbolP)
+ || S_IS_DEBUG(symbolP)
+#ifdef TC_I960
+ /* FIXME this ifdef seems highly dubious to me. xoxorich. */
+ || !S_IS_DEFINED(symbolP)
+ || S_IS_EXTERNAL(symbolP)
+#endif /* TC_I960 */
+ || (S_GET_NAME(symbolP)[0] != '\001' && (flagseen ['L'] || ! S_LOCAL_NAME(symbolP))))
+#endif /* not VMS */
+ )
+ {
+#ifndef VMS
+ symbolP->sy_number = symbol_number++;
+
+ /* The + 1 after strlen account for the \0 at the
+ end of each string */
+ if (!S_IS_STABD(symbolP)) {
+ /* Ordinary case. */
+ symbolP->sy_name_offset = string_byte_count;
+ string_byte_count += strlen(S_GET_NAME(symbolP)) + 1;
+ }
+ else /* .Stabd case. */
+#endif /* not VMS */
+ 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", name);
+ } /* oops. */
+
+#ifndef VMS
+ /* Unhook it from the chain */
+ *symbolPP = symbol_next(symbolP);
+#endif /* VMS */
+ } /* if this symbol should be in the output */
+ } /* for each symbol */
+ } /* OBJ_AOUT version */
+#else
+ cant_crawl_symbol_table();
+#endif
+ H_SET_STRING_SIZE(&headers,string_byte_count);
+ H_SET_SYMBOL_TABLE_SIZE(&headers, symbol_number);
+ } /* crawl symbol table */
+
+} /* obj_crawl_symbol_chain() */
+
+/* end of obj-vms.c */