0117086004
copylefted 1992.
1147 lines
39 KiB
C
1147 lines
39 KiB
C
/* This file is vms-dbg.c
|
|
|
|
Copyright (C) 1987-1992 Free Software Foundation, Inc.
|
|
|
|
This file is part of GAS, the GNU Assembler.
|
|
|
|
GAS is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
GAS is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GAS; see the file COPYING. If not, write to
|
|
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
#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);
|
|
}
|
|
|
|
/* end of vms-dbg.c */
|