📄 vms-dbg.c
字号:
#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 128static 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -