Commit | Line | Data |
---|---|---|
01170860 RP |
1 | /* This file is vms-dbg.c |
2 | ||
3 | Copyright (C) 1987-1992 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GAS, the GNU Assembler. | |
6 | ||
7 | GAS is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GAS is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GAS; see the file COPYING. If not, write to | |
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
0e39a8bb RP |
21 | #include <stdio.h> |
22 | #include "as.h" | |
23 | #include "struc-symbol.h" | |
24 | #include "symbols.h" | |
25 | #include "objrecdef.h" | |
26 | #include <stab.h> | |
27 | ||
28 | /* This file contains many of the routines needed to output debugging info into | |
29 | * the object file that the VMS debugger needs to understand symbols. These | |
30 | * routines are called very late in the assembly process, and thus we can be | |
31 | * fairly lax about changing things, since the GSD and the TIR sections have | |
32 | * already been output. | |
33 | */ | |
34 | ||
35 | /* We need this info to cross correlate between the stabs def for a symbol and | |
36 | * the actual symbol def. The actual symbol def contains the psect number and | |
37 | * offset, which is needed to declare a variable to the debugger for global | |
38 | * and static variables | |
39 | */ | |
40 | struct VMS_Symbol { | |
8b228fe9 RP |
41 | struct VMS_Symbol *Next; |
42 | struct symbol *Symbol; | |
43 | int Size; | |
44 | int Psect_Index; | |
45 | int Psect_Offset; | |
46 | }; | |
0e39a8bb RP |
47 | extern struct VMS_Symbol *VMS_Symbols; |
48 | ||
49 | enum advanced_type {BASIC,POINTER,ARRAY,ENUM,STRUCT,UNION,FUNCTION,VOID,UNKNOWN}; | |
50 | ||
51 | /* this structure contains the information from the stabs directives, and the | |
52 | * information is filled in by VMS_typedef_parse. Everything that is needed | |
53 | * to generate the debugging record for a given symbol is present here. | |
54 | * This could be done more efficiently, using nested struct/unions, but for now | |
55 | * I am happy that it works. | |
56 | */ | |
57 | struct VMS_DBG_Symbol{ | |
8b228fe9 RP |
58 | struct VMS_DBG_Symbol * next; |
59 | enum advanced_type advanced; /* description of what this is */ | |
60 | int dbx_type; /* this record is for this type */ | |
61 | int type2; /* For advanced types this is the type referred to. | |
62 | i.e. the type a pointer points to, or the type | |
63 | of object that makes up an array */ | |
64 | int VMS_type; /* Use this type when generating a variable def */ | |
65 | int index_min; /* used for arrays - this will be present for all */ | |
66 | int index_max; /* entries, but will be meaningless for non-arrays */ | |
67 | int data_size; /* size in bytes of the data type. For an array, this | |
0e39a8bb | 68 | is the size of one element in the array */ |
8b228fe9 | 69 | int struc_numb; /* Number of the structure/union/enum - used for ref */ |
0e39a8bb RP |
70 | }; |
71 | ||
72 | struct VMS_DBG_Symbol *VMS_Symbol_type_list={(struct VMS_DBG_Symbol*) NULL}; | |
8b228fe9 RP |
73 | |
74 | /* we need this structure to keep track of forward references to | |
75 | * struct/union/enum that have not been defined yet. When they are ultimately | |
76 | * defined, then we can go back and generate the TIR commands to make a back | |
77 | * reference. | |
78 | */ | |
79 | ||
80 | struct forward_ref{ | |
0e39a8bb RP |
81 | struct forward_ref * next; |
82 | int dbx_type; | |
83 | int struc_numb; | |
84 | char resolved; | |
8b228fe9 RP |
85 | }; |
86 | ||
87 | struct forward_ref * f_ref_root={(struct forward_ref*) NULL}; | |
88 | ||
89 | static char * symbol_name; | |
90 | static structure_count=0; | |
91 | ||
92 | /* this routine converts a number string into an integer, and stops when it | |
93 | * sees an invalid character the return value is the address of the character | |
94 | * just past the last character read. No error is generated. | |
95 | */ | |
96 | static char * cvt_integer(char* str,int * rtn){ | |
0e39a8bb | 97 | int ival, neg; |
8b228fe9 RP |
98 | neg = *str == '-' ? ++str, -1 : 1; |
99 | ival=0; /* first get the number of the type for dbx */ | |
100 | while((*str <= '9') && (*str >= '0')) | |
101 | ival = 10*ival + *str++ -'0'; | |
0e39a8bb RP |
102 | *rtn = neg*ival; |
103 | return str; | |
8b228fe9 RP |
104 | } |
105 | ||
106 | /* this routine fixes the names that are generated by C++, ".this" is a good | |
107 | * example. The period does not work for the debugger, since it looks like | |
108 | * the syntax for a structure element, and thus it gets mightily confused | |
109 | */ | |
110 | static fix_name(char* pnt){ | |
0e39a8bb | 111 | for( ;*pnt != 0; pnt++){ |
8b228fe9 | 112 | if(*pnt == '.') *pnt = '$'; |
0e39a8bb | 113 | }; |
8b228fe9 RP |
114 | } |
115 | ||
116 | /* this routine is used to compare the names of certain types to various | |
117 | * fixed types that are known by the debugger. | |
118 | */ | |
0e39a8bb | 119 | #define type_check(x) !strcmp( symbol_name , x ) |
8b228fe9 RP |
120 | |
121 | /* When defining a structure, this routine is called to find the name of | |
122 | * the actual structure. It is assumed that str points to the equal sign | |
123 | * in the definition, and it moves backward until it finds the start of the | |
124 | * name. If it finds a 0, then it knows that this structure def is in the | |
125 | * outermost level, and thus symbol_name points to the symbol name. | |
126 | */ | |
127 | static char* get_struct_name(char* str){ | |
0e39a8bb RP |
128 | char* pnt; |
129 | pnt=str; | |
130 | while((*pnt != ':') && (*pnt != '\0')) pnt--; | |
131 | if(*pnt == '\0') return symbol_name; | |
132 | *pnt-- = '\0'; | |
133 | while((*pnt != ';') && (*pnt != '=')) pnt--; | |
134 | if(*pnt == ';') return pnt+1; | |
135 | while((*pnt < '0') || (*pnt > '9')) pnt++; | |
136 | while((*pnt >= '0') && (*pnt <= '9')) pnt++; | |
137 | return pnt; | |
8b228fe9 RP |
138 | } |
139 | /* search symbol list for type number dbx_type. Return a pointer to struct */ | |
140 | static struct VMS_DBG_Symbol* find_symbol(int dbx_type){ | |
0e39a8bb RP |
141 | struct VMS_DBG_Symbol* spnt; |
142 | spnt=VMS_Symbol_type_list; | |
143 | while (spnt!=(struct VMS_DBG_Symbol*) NULL){ | |
8b228fe9 RP |
144 | if(spnt->dbx_type==dbx_type) break; |
145 | spnt=spnt->next;}; | |
0e39a8bb RP |
146 | if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is*/ |
147 | return spnt; | |
8b228fe9 RP |
148 | } |
149 | ||
150 | ||
151 | /* Many good programmers cringe when they see a fixed size array - since I am | |
152 | * using this to generate the various descriptors for the data types present, | |
153 | * you might argue that the descriptor could overflow the array for a | |
154 | * complicated variable, and then I am in deep doo-doo. My answer to this is | |
155 | * that the debugger records that we write have all sorts of length bytes | |
156 | * stored in them all over the place, and if we exceed 127 bytes (since the top | |
157 | * bit indicates data, rather than a command), we are dead anyhow. So I figure | |
158 | * why not do this the easy way. Besides, to get 128 bytes, you need something | |
159 | * like an array with 10 indicies, or something like | |
160 | * char **************************************** var; | |
161 | * Lets get real. If some idiot writes programs like that he/she gets what | |
162 | * they deserve. (It is possible to overflow the record with a somewhat | |
163 | * simpler example, like: int (*(*(*(*(*(* sarr6)[1])[1])[2])[3])[4])[5]; | |
164 | * but still...). And if someone in the peanut gallery wants to know "What | |
165 | * does VAX-C do with something like this?", I will tell you. It crashes. | |
166 | * At least this code has the good sense to convert it to *void. | |
167 | * In practice, I do not think that this presents too much of a problem, since | |
168 | * struct/union/enum all use defined types, which sort of terminate the | |
169 | * definition. It occurs to me that we could possibly do the same thing with | |
170 | * arrays and pointers, but I don't know quite how it would be coded. | |
171 | * | |
172 | * And now back to the regularly scheduled program... | |
173 | */ | |
0e39a8bb | 174 | #define MAX_DEBUG_RECORD 128 |
8b228fe9 RP |
175 | static char Local[MAX_DEBUG_RECORD]; /* buffer for variable descriptor */ |
176 | static int Lpnt; /* index into Local */ | |
177 | static char Asuffix[MAX_DEBUG_RECORD]; /* buffer for array descriptor */ | |
178 | static int Apoint; /* index into Asuffix */ | |
179 | static char overflow; /* flag to indicate we have written too much*/ | |
180 | static int total_len; /* used to calculate the total length of variable | |
181 | descriptor plus array descriptor - used for len byte*/ | |
182 | static int struct_number; /* counter used to assign indexes to struct | |
183 | unions and enums */ | |
184 | ||
185 | /* this routine puts info into either Local or Asuffix, depending on the sign | |
186 | * of size. The reason is that it is easier to build the variable descriptor | |
187 | * backwards, while the array descriptor is best built forwards. In the end | |
188 | * they get put together, if there is not a struct/union/enum along the way | |
189 | */ | |
190 | push(int value, int size){ | |
0e39a8bb RP |
191 | char * pnt; |
192 | int i; | |
193 | int size1; | |
194 | long int val; | |
195 | val=value; | |
196 | pnt=(char*) &val; | |
197 | size1 = size; | |
198 | if (size < 0) {size1 = -size; pnt += size1-1;}; | |
199 | if(size < 0) | |
8b228fe9 | 200 | for(i=0;i<size1;i++) { |
0e39a8bb RP |
201 | Local[Lpnt--] = *pnt--; |
202 | if(Lpnt < 0) {overflow = 1; Lpnt = 1;};} | |
203 | else for(i=0;i<size1;i++){ | |
8b228fe9 RP |
204 | Asuffix[Apoint++] = *pnt++; |
205 | if(Apoint >= MAX_DEBUG_RECORD) | |
206 | {overflow = 1; Apoint =MAX_DEBUG_RECORD-1;};} | |
207 | } | |
208 | ||
209 | /* this routine generates the array descriptor for a given array */ | |
210 | static array_suffix(struct VMS_DBG_Symbol* spnt2){ | |
0e39a8bb RP |
211 | struct VMS_DBG_Symbol * spnt; |
212 | struct VMS_DBG_Symbol * spnt1; | |
213 | int rank; | |
214 | int total_size; | |
215 | int i; | |
216 | rank=0; | |
217 | spnt=spnt2; | |
218 | while(spnt->advanced != ARRAY) { | |
8b228fe9 RP |
219 | spnt=find_symbol(spnt->type2); |
220 | if(spnt == (struct VMS_DBG_Symbol *) NULL) return;}; | |
0e39a8bb RP |
221 | spnt1=spnt; |
222 | spnt1=spnt; | |
223 | total_size= 1; | |
224 | while(spnt1->advanced == ARRAY) {rank++; | |
8b228fe9 RP |
225 | total_size *= (spnt1->index_max - spnt1->index_min +1); |
226 | spnt1=find_symbol(spnt1->type2);}; | |
0e39a8bb RP |
227 | total_size = total_size * spnt1->data_size; |
228 | push(spnt1->data_size,2); | |
229 | if(spnt1->VMS_type == 0xa3) push(0,1); | |
8b228fe9 | 230 | else push(spnt1->VMS_type,1); |
0e39a8bb RP |
231 | push(4,1); |
232 | for(i=0;i<6;i++) push(0,1); | |
233 | push(0xc0,1); | |
234 | push(rank,1); | |
235 | push(total_size,4); | |
236 | push(0,4); | |
237 | spnt1=spnt; | |
238 | while(spnt1->advanced == ARRAY) { | |
8b228fe9 RP |
239 | push(spnt1->index_max - spnt1->index_min+1,4); |
240 | spnt1=find_symbol(spnt1->type2);}; | |
0e39a8bb RP |
241 | spnt1=spnt; |
242 | while(spnt1->advanced == ARRAY) { | |
8b228fe9 RP |
243 | push(spnt1->index_min,4); |
244 | push(spnt1->index_max,4); | |
245 | spnt1=find_symbol(spnt1->type2);}; | |
246 | } | |
247 | ||
248 | /* this routine generates the start of a variable descriptor based upon | |
249 | * a struct/union/enum that has yet to be defined. We define this spot as | |
250 | * a new location, and save four bytes for the address. When the struct is | |
251 | * finally defined, then we can go back and plug in the correct address | |
252 | */ | |
253 | static new_forward_ref(int dbx_type){ | |
0e39a8bb RP |
254 | struct forward_ref* fpnt; |
255 | fpnt = (struct forward_ref*) malloc(sizeof(struct forward_ref)); | |
256 | fpnt->next = f_ref_root; | |
257 | f_ref_root = fpnt; | |
258 | fpnt->dbx_type = dbx_type; | |
259 | fpnt->struc_numb = ++structure_count; | |
260 | fpnt->resolved = 'N'; | |
261 | push(3,-1); | |
262 | total_len = 5; | |
263 | push(total_len,-2); | |
264 | struct_number = - fpnt->struc_numb; | |
8b228fe9 RP |
265 | } |
266 | ||
267 | /* this routine generates the variable descriptor used to describe non-basic | |
268 | * variables. It calls itself recursively until it gets to the bottom of it | |
269 | * all, and then builds the descriptor backwards. It is easiest to do it this | |
270 | *way since we must periodically write length bytes, and it is easiest if we know | |
271 | *the value when it is time to write it. | |
272 | */ | |
273 | static int gen1(struct VMS_DBG_Symbol * spnt,int array_suffix_len){ | |
0e39a8bb RP |
274 | struct VMS_DBG_Symbol * spnt1; |
275 | int i; | |
276 | switch(spnt->advanced){ | |
277 | case VOID: | |
8b228fe9 RP |
278 | push(DBG$C_VOID,-1); |
279 | total_len += 1; | |
280 | push(total_len,-2); | |
281 | return 0; | |
0e39a8bb RP |
282 | case BASIC: |
283 | case FUNCTION: | |
8b228fe9 RP |
284 | if(array_suffix_len == 0) { |
285 | push(spnt->VMS_type,-1); | |
286 | push(DBG$C_BASIC,-1); | |
287 | total_len = 2; | |
288 | push(total_len,-2); | |
289 | return 1;}; | |
290 | push(0,-4); | |
291 | push(0xfa02,-2); | |
292 | total_len = -2; | |
293 | return 1; | |
0e39a8bb RP |
294 | case STRUCT: |
295 | case UNION: | |
296 | case ENUM: | |
8b228fe9 RP |
297 | struct_number=spnt->struc_numb; |
298 | if(struct_number < 0) { | |
299 | new_forward_ref(spnt->dbx_type); | |
0e39a8bb | 300 | return 1; |
8b228fe9 RP |
301 | } |
302 | push(DBG$C_STRUCT,-1); | |
303 | total_len = 5; | |
304 | push(total_len,-2); | |
305 | return 1; | |
0e39a8bb | 306 | case POINTER: |
8b228fe9 RP |
307 | spnt1=find_symbol(spnt->type2); |
308 | i=1; | |
309 | if(spnt1 == (struct VMS_DBG_Symbol *) NULL) | |
310 | new_forward_ref(spnt->type2); | |
311 | else i=gen1(spnt1,0); | |
312 | if(i){ /* (*void) is a special case, do not put pointer suffix*/ | |
313 | push(DBG$C_POINTER,-1); | |
314 | total_len += 3; | |
315 | push(total_len,-2); | |
316 | }; | |
317 | return 1; | |
0e39a8bb | 318 | case ARRAY: |
8b228fe9 RP |
319 | spnt1=spnt; |
320 | while(spnt1->advanced == ARRAY) | |
321 | {spnt1 = find_symbol(spnt1->type2); | |
322 | if(spnt1 == (struct VMS_DBG_Symbol *) NULL) { | |
323 | printf("gcc-as warning(debugger output):"); | |
324 | printf("Forward reference error, dbx type %d\n", | |
325 | spnt->type2); | |
326 | return;} | |
327 | }; | |
328 | /* It is too late to generate forward references, so the user gets a message. | |
329 | * This should only happen on a compiler error */ | |
330 | i=gen1(spnt1,1); | |
331 | i=Apoint; | |
332 | array_suffix(spnt); | |
333 | array_suffix_len = Apoint - i; | |
334 | switch(spnt1->advanced){ | |
335 | case BASIC: | |
336 | case FUNCTION: | |
337 | break; | |
338 | default: | |
339 | push(0,-2); | |
340 | total_len += 2; | |
341 | push(total_len,-2); | |
342 | push(0xfa,-1); | |
343 | push(0x0101,-2); | |
344 | push(DBG$C_COMPLEX_ARRAY,-1); | |
345 | }; | |
346 | total_len += array_suffix_len + 8; | |
347 | push(total_len,-2); | |
0e39a8bb | 348 | }; |
8b228fe9 RP |
349 | } |
350 | ||
351 | /* this generates a suffix for a variable. If it is not a defined type yet, | |
352 | * then dbx_type contains the type we are expecting so we can generate a | |
353 | * forward reference. This calls gen1 to build most of the descriptor, and | |
354 | * then it puts the icing on at the end. It then dumps whatever is needed | |
355 | * to get a complete descriptor (i.e. struct reference, array suffix ). | |
356 | */ | |
357 | static generate_suffix(struct VMS_DBG_Symbol * spnt,int dbx_type){ | |
0e39a8bb RP |
358 | int ilen; |
359 | int i; | |
360 | char pvoid[6] = {5,0xaf,0,1,0,5}; | |
361 | struct VMS_DBG_Symbol * spnt1; | |
362 | Apoint=0; | |
363 | Lpnt =MAX_DEBUG_RECORD-1; | |
364 | total_len=0; | |
365 | struct_number = 0; | |
366 | overflow = 0; | |
367 | if(spnt == (struct VMS_DBG_Symbol*) NULL) | |
8b228fe9 | 368 | new_forward_ref(dbx_type); |
0e39a8bb | 369 | else{ |
8b228fe9 RP |
370 | if(spnt->VMS_type != 0xa3) return 0; /* no suffix needed */ |
371 | gen1(spnt,0); | |
0e39a8bb RP |
372 | }; |
373 | push(0x00af,-2); | |
374 | total_len += 4; | |
375 | push(total_len,-1); | |
8b228fe9 RP |
376 | /* if the variable descriptor overflows the record, output a descriptor for |
377 | * a pointer to void. | |
378 | */ | |
0e39a8bb | 379 | if((total_len >= MAX_DEBUG_RECORD) || overflow) { |
8b228fe9 RP |
380 | printf(" Variable descriptor %d too complicated. Defined as *void ",spnt->dbx_type); |
381 | VMS_Store_Immediate_Data(pvoid, 6, OBJ$C_DBG); | |
382 | return; | |
383 | }; | |
0e39a8bb RP |
384 | i=0; |
385 | while(Lpnt < MAX_DEBUG_RECORD-1) Local[i++] = Local[++Lpnt]; | |
386 | Lpnt = i; | |
8b228fe9 | 387 | /* we use this for a reference to a structure that has already been defined */ |
0e39a8bb | 388 | if(struct_number > 0){ |
8b228fe9 RP |
389 | VMS_Store_Immediate_Data(Local, Lpnt, OBJ$C_DBG);Lpnt=0; |
390 | VMS_Store_Struct(struct_number);}; | |
391 | /* we use this for a forward reference to a structure that has yet to be | |
392 | *defined. We store four bytes of zero to make room for the actual address once | |
393 | * it is known | |
394 | */ | |
0e39a8bb | 395 | if(struct_number < 0){ |
8b228fe9 RP |
396 | struct_number = -struct_number; |
397 | VMS_Store_Immediate_Data(Local, Lpnt,OBJ$C_DBG);Lpnt=0; | |
398 | VMS_Def_Struct(struct_number); | |
399 | for(i=0;i<4;i++) Local[Lpnt++] = 0; | |
400 | VMS_Store_Immediate_Data(Local, Lpnt, OBJ$C_DBG);Lpnt=0; | |
401 | }; | |
0e39a8bb RP |
402 | i=0; |
403 | while(i<Apoint) Local[Lpnt++] = Asuffix[i++]; | |
404 | if(Lpnt != 0) | |
8b228fe9 | 405 | VMS_Store_Immediate_Data(Local, Lpnt, OBJ$C_DBG); |
0e39a8bb | 406 | Lpnt=0; |
8b228fe9 RP |
407 | } |
408 | ||
409 | /* This routine generates a symbol definition for a C sybmol for the debugger. | |
410 | * It takes a psect and offset for global symbols - if psect < 0, then this is | |
411 | * a local variable and the offset is relative to FP. In this case it can | |
412 | * be either a variable (Offset < 0) or a parameter (Offset > 0). | |
413 | */ | |
414 | VMS_DBG_record(struct VMS_DBG_Symbol* spnt,int Psect,int Offset, char* Name) | |
0e39a8bb | 415 | { |
8b228fe9 RP |
416 | char* pnt; |
417 | int j; | |
418 | int maxlen; | |
419 | int i=0; | |
420 | if(Psect < 0) { /* this is a local variable, referenced to SP */ | |
421 | maxlen=7+strlen(Name); | |
422 | Local[i++] = maxlen; | |
423 | Local[i++]=spnt->VMS_type; | |
424 | if(Offset > 0) Local[i++] = DBG$C_FUNCTION_PARAMETER; | |
425 | else Local[i++] = DBG$C_LOCAL_SYM; | |
426 | pnt=(char*) &Offset; | |
427 | for(j=0;j<4;j++) Local[i++]=*pnt++; /* copy the offset */ | |
428 | } else { | |
429 | maxlen=7+strlen(Name); /* symbols fixed in memory */ | |
430 | Local[i++]=7+strlen(Name); | |
431 | Local[i++]=spnt->VMS_type; | |
432 | Local[i++]=1; | |
433 | VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; | |
434 | VMS_Set_Data(Psect,Offset,OBJ$C_DBG,0); | |
435 | } | |
436 | Local[i++]=strlen(Name); | |
437 | pnt=Name; | |
438 | fix_name(pnt); /* if there are bad characters in name, convert them */ | |
439 | while(*pnt!='\0') Local[i++]=*pnt++; | |
440 | VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); | |
441 | if(spnt->VMS_type == DBG$C_ADVANCED_TYPE) generate_suffix(spnt,0); | |
0e39a8bb RP |
442 | } |
443 | ||
444 | ||
445 | /* This routine parses the stabs entries in order to make the definition | |
446 | * for the debugger of local symbols and function parameters | |
447 | */ | |
448 | int VMS_local_stab_Parse(symbolS * sp){ | |
8b228fe9 RP |
449 | char *pnt; |
450 | char *pnt1; | |
451 | char *str; | |
452 | struct VMS_DBG_Symbol* spnt; | |
453 | struct VMS_Symbol * vsp; | |
454 | int dbx_type; | |
455 | int VMS_type; | |
456 | dbx_type=0; | |
457 | str=sp->sy_nlist.n_un.n_name; | |
458 | pnt=(char*) strchr(str,':'); | |
459 | if(pnt==(char*) NULL) return; /* no colon present */ | |
460 | pnt1=pnt++; /* save this for later, and skip colon */ | |
461 | if(*pnt == 'c') return 0; /* ignore static constants */ | |
462 | /* there is one little catch that we must be aware of. Sometimes function | |
463 | * parameters are optimized into registers, and the compiler, in its infiite | |
464 | * wisdom outputs stabs records for *both*. In general we want to use the | |
465 | * register if it is present, so we must search the rest of the symbols for | |
466 | * this function to see if this parameter is assigned to a register. | |
467 | */ | |
468 | { | |
469 | char *str1; | |
470 | char *pnt2; | |
471 | symbolS * sp1; | |
472 | if(*pnt == 'p'){ | |
473 | for(sp1 = symbol_next(sp); sp1; sp1 = symbol_next(sp1)) { | |
0e39a8bb RP |
474 | if ((sp1->sy_nlist.n_type & N_STAB) == 0) continue; |
475 | if((unsigned char)sp1->sy_nlist.n_type == N_FUN) break; | |
476 | if((unsigned char)sp1->sy_nlist.n_type != N_RSYM) continue; | |
477 | str1=sp1->sy_nlist.n_un.n_name; /* and get the name */ | |
478 | pnt2=str; | |
479 | while(*pnt2 != ':') { | |
480 | if(*pnt2 != *str1) break; | |
481 | pnt2++; str1++;}; | |
482 | if((*str1 != ':') || (*pnt2 != ':') ) continue; | |
483 | return; /* they are the same! lets skip this one */ | |
8b228fe9 RP |
484 | }; /* for */ |
485 | /* first find the dbx symbol type from list, and then find VMS type */ | |
486 | pnt++; /* skip p in case no register */ | |
487 | };/* if */ }; /* p block */ | |
488 | pnt = cvt_integer( pnt, &dbx_type); | |
489 | spnt = find_symbol(dbx_type); | |
490 | if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is*/ | |
491 | *pnt1='\0'; | |
492 | VMS_DBG_record(spnt,-1,sp->sy_nlist.n_value,str); | |
493 | *pnt1=':'; /* and restore the string */ | |
494 | return 1; | |
0e39a8bb RP |
495 | } |
496 | ||
497 | /* this routine parses a stabs entry to find the information required to define | |
498 | * a variable. It is used for global and static variables. | |
499 | * Basically we need to know the address of the symbol. With older versions | |
500 | * of the compiler, const symbols are | |
501 | * treated differently, in that if they are global they are written into the | |
502 | * text psect. The global symbol entry for such a const is actually written | |
503 | * as a program entry point (Yuk!!), so if we cannot find a symbol in the list | |
504 | * of psects, we must search the entry points as well. static consts are even | |
505 | * harder, since they are never assigned a memory address. The compiler passes | |
506 | * a stab to tell us the value, but I am not sure what to do with it. | |
507 | */ | |
508 | static gave_compiler_message = 0; | |
509 | ||
510 | static int VMS_stab_parse(symbolS * sp,char expected_type, | |
8b228fe9 | 511 | int type1,int type2,int Text_Psect){ |
0e39a8bb | 512 | char *pnt; |
8b228fe9 RP |
513 | char *pnt1; |
514 | char *str; | |
515 | symbolS * sp1; | |
516 | struct VMS_DBG_Symbol* spnt; | |
517 | struct VMS_Symbol * vsp; | |
518 | int dbx_type; | |
519 | int VMS_type; | |
520 | dbx_type=0; | |
521 | str=sp->sy_nlist.n_un.n_name; | |
522 | pnt=(char*) strchr(str,':'); | |
523 | if(pnt==(char*) NULL) return; /* no colon present */ | |
524 | pnt1=pnt; /* save this for later*/ | |
525 | pnt++; | |
526 | if(*pnt==expected_type){ | |
527 | pnt = cvt_integer(pnt+1,&dbx_type); | |
528 | spnt = find_symbol(dbx_type); | |
529 | if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is*/ | |
530 | /* now we need to search the symbol table to find the psect and offset for | |
531 | * this variable. | |
532 | */ | |
0e39a8bb RP |
533 | *pnt1='\0'; |
534 | vsp=VMS_Symbols; | |
535 | while(vsp != (struct VMS_Symbol*) NULL) | |
8b228fe9 RP |
536 | {pnt=vsp->Symbol->sy_nlist.n_un.n_name; |
537 | if(pnt!=(char*) NULL) if(*pnt++ == '_') | |
538 | /* make sure name is the same, and make sure correct symbol type */ | |
539 | if((strlen(pnt) == strlen(str)) && (strcmp(pnt,str)==0) | |
0e39a8bb | 540 | && ((vsp->Symbol->sy_type == type1) || |
8b228fe9 RP |
541 | (vsp->Symbol->sy_type == type2))) break; |
542 | vsp=vsp->Next;}; | |
543 | if(vsp != (struct VMS_Symbol*) NULL){ | |
0e39a8bb | 544 | VMS_DBG_record(spnt,vsp->Psect_Index,vsp->Psect_Offset,str); |
8b228fe9 RP |
545 | *pnt1=':'; /* and restore the string */ |
546 | return 1;}; | |
547 | /* the symbol was not in the symbol list, but it may be an "entry point" | |
548 | if it was a constant */ | |
549 | for(sp1 = symbol_rootP; sp1; sp1 = symbol_next(sp1)) { | |
550 | /* | |
551 | * Dispatch on STAB type | |
552 | */ | |
553 | if(sp1->sy_type != (N_TEXT | N_EXT) && sp1->sy_type!=N_TEXT) | |
554 | continue; | |
555 | pnt = sp1->sy_nlist.n_un.n_name; | |
556 | if(*pnt == '_') pnt++; | |
557 | if(strcmp(pnt,str) == 0){ | |
558 | if(!gave_compiler_message && expected_type=='G'){ | |
559 | printf("***Warning - the assembly code generated by the compiler has placed\n"); | |
560 | printf("global constant(s) in the text psect. These will not be available to\n"); | |
561 | printf("other modules, since this is not the correct way to handle this. You\n"); | |
562 | printf("have two options: 1) get a patched compiler that does not put global\n"); | |
563 | printf("constants in the text psect, or 2) remove the 'const' keyword from\n"); | |
564 | printf("definitions of global variables in your source module(s). Don't say\n"); | |
565 | printf("I didn't warn you!"); | |
566 | gave_compiler_message = 1;}; | |
567 | VMS_DBG_record(spnt, | |
568 | Text_Psect, | |
569 | sp1->sy_nlist.n_value, | |
570 | str); | |
571 | *pnt1=':'; | |
572 | *(sp1->sy_nlist.n_un.n_name) = 'L'; | |
573 | /* fool assembler to not output this | |
574 | * as a routine in the TBT */ | |
0e39a8bb | 575 | return 1;}; |
0e39a8bb | 576 | }; |
8b228fe9 RP |
577 | }; |
578 | *pnt1=':'; /* and restore the string */ | |
579 | return 0; | |
0e39a8bb RP |
580 | } |
581 | ||
582 | ||
583 | VMS_GSYM_Parse(symbolS * sp,int Text_Psect){ /* Global variables */ | |
584 | VMS_stab_parse(sp,'G',(N_UNDF | N_EXT),(N_DATA | N_EXT),Text_Psect); | |
585 | } | |
586 | ||
587 | ||
588 | VMS_LCSYM_Parse(symbolS * sp,int Text_Psect){/* Static symbols - uninitialized */ | |
589 | VMS_stab_parse(sp,'S',N_BSS,-1,Text_Psect); | |
590 | } | |
591 | ||
592 | VMS_STSYM_Parse(symbolS * sp,int Text_Psect){ /*Static symbols - initialized */ | |
593 | VMS_stab_parse(sp,'S',N_DATA,-1,Text_Psect); | |
594 | } | |
595 | ||
596 | ||
597 | /* for register symbols, we must figure out what range of addresses within the | |
598 | * psect are valid. We will use the brackets in the stab directives to give us | |
599 | * guidance as to the PC range that this variable is in scope. I am still not | |
600 | * completely comfortable with this but as I learn more, I seem to get a better | |
601 | * handle on what is going on. | |
602 | * Caveat Emptor. | |
603 | */ | |
604 | VMS_RSYM_Parse(symbolS * sp,symbolS * Current_Routine,int Text_Psect){ | |
605 | char* pnt; | |
8b228fe9 RP |
606 | char* pnt1; |
607 | char* str; | |
608 | int dbx_type; | |
609 | struct VMS_DBG_Symbol* spnt; | |
610 | int j; | |
611 | int maxlen; | |
612 | int i=0; | |
613 | int bcnt=0; | |
614 | int Min_Offset=-1; /* min PC of validity */ | |
615 | int Max_Offset=0; /* max PC of validity */ | |
616 | symbolS * symbolP; | |
617 | for(symbolP = sp; symbolP; symbolP = symbol_next(symbolP)) { | |
618 | /* | |
619 | * Dispatch on STAB type | |
620 | */ | |
621 | switch((unsigned char)symbolP->sy_type) { | |
622 | case N_LBRAC: | |
623 | if(bcnt++==0) Min_Offset = symbolP->sy_nlist.n_value; | |
624 | break; | |
625 | case N_RBRAC: | |
626 | if(--bcnt==0) Max_Offset = | |
627 | symbolP->sy_nlist.n_value-1; | |
628 | break; | |
629 | } | |
630 | if((Min_Offset != -1) && (bcnt == 0)) break; | |
631 | if((unsigned char)symbolP->sy_type == N_FUN) break; | |
632 | } | |
633 | /* check to see that the addresses were defined. If not, then there were no | |
634 | * brackets in the function, and we must try to search for the next function | |
635 | * Since functions can be in any order, we should search all of the symbol list | |
636 | * to find the correct ending address. */ | |
637 | if(Min_Offset == -1){ | |
638 | int Max_Source_Offset; | |
639 | int This_Offset; | |
640 | Min_Offset = sp->sy_nlist.n_value; | |
641 | for(symbolP = symbol_rootP; symbolP; symbolP = symbol_next(symbolP)) { | |
642 | /* | |
643 | * Dispatch on STAB type | |
644 | */ | |
645 | This_Offset = symbolP->sy_nlist.n_value; | |
646 | switch(symbolP->sy_type) { | |
647 | case N_TEXT | N_EXT: | |
648 | if((This_Offset > Min_Offset) && (This_Offset < Max_Offset)) | |
649 | Max_Offset = This_Offset; | |
650 | break; | |
651 | case N_SLINE: | |
652 | if(This_Offset > Max_Source_Offset) | |
653 | Max_Source_Offset=This_Offset; | |
654 | } | |
655 | } | |
656 | /* if this is the last routine, then we use the PC of the last source line | |
657 | * as a marker of the max PC for which this reg is valid */ | |
658 | if(Max_Offset == 0x7fffffff) Max_Offset = Max_Source_Offset; | |
659 | }; | |
660 | dbx_type=0; | |
661 | str=sp->sy_nlist.n_un.n_name; | |
662 | pnt=(char*) strchr(str,':'); | |
663 | if(pnt==(char*) NULL) return; /* no colon present */ | |
664 | pnt1=pnt; /* save this for later*/ | |
665 | pnt++; | |
666 | if(*pnt!='r') return 0; | |
667 | pnt = cvt_integer( pnt+1, &dbx_type); | |
668 | spnt = find_symbol(dbx_type); | |
669 | if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is yet*/ | |
670 | *pnt1='\0'; | |
671 | maxlen=25+strlen(sp->sy_nlist.n_un.n_name); | |
672 | Local[i++]=maxlen; | |
673 | Local[i++]=spnt->VMS_type; | |
674 | Local[i++]=0xfb; | |
675 | Local[i++]=strlen(sp->sy_nlist.n_un.n_name)+1; | |
676 | Local[i++]=0x00; | |
677 | Local[i++]=0x00; | |
678 | Local[i++]=0x00; | |
679 | Local[i++]=strlen(sp->sy_nlist.n_un.n_name); | |
680 | pnt=sp->sy_nlist.n_un.n_name; | |
681 | fix_name(pnt); /* if there are bad characters in name, convert them */ | |
682 | while(*pnt!='\0') Local[i++]=*pnt++; | |
683 | Local[i++]=0xfd; | |
684 | Local[i++]=0x0f; | |
685 | Local[i++]=0x00; | |
686 | Local[i++]=0x03; | |
687 | Local[i++]=0x01; | |
688 | VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; | |
689 | VMS_Set_Data(Text_Psect,Min_Offset,OBJ$C_DBG,1); | |
690 | VMS_Set_Data(Text_Psect,Max_Offset,OBJ$C_DBG,1); | |
691 | Local[i++]=0x03; | |
692 | Local[i++]=sp->sy_nlist.n_value; | |
693 | Local[i++]=0x00; | |
694 | Local[i++]=0x00; | |
695 | Local[i++]=0x00; | |
696 | VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); | |
697 | *pnt1=':'; | |
698 | if(spnt->VMS_type == DBG$C_ADVANCED_TYPE) generate_suffix(spnt,0); | |
0e39a8bb RP |
699 | } |
700 | ||
701 | /* this function examines a structure definition, checking all of the elements | |
702 | * to make sure that all of them are fully defined. The only thing that we | |
703 | * kick out are arrays of undefined structs, since we do not know how big | |
704 | * they are. All others we can handle with a normal forward reference. | |
705 | */ | |
706 | static int forward_reference(char* pnt){ | |
707 | int i; | |
8b228fe9 RP |
708 | struct VMS_DBG_Symbol * spnt; |
709 | struct VMS_DBG_Symbol * spnt1; | |
710 | pnt = cvt_integer(pnt+1,&i); | |
711 | if(*pnt == ';') return 0; /* no forward references */ | |
712 | do{ | |
713 | pnt=(char*) strchr(pnt,':'); | |
0e39a8bb | 714 | pnt = cvt_integer(pnt+1,&i); |
8b228fe9 RP |
715 | spnt = find_symbol(i); |
716 | if(spnt == (struct VMS_DBG_Symbol*) NULL) return 0; | |
717 | while((spnt->advanced == POINTER) || (spnt->advanced == ARRAY)){ | |
718 | i=spnt->type2; | |
719 | spnt1 = find_symbol(spnt->type2); | |
720 | if((spnt->advanced == ARRAY) && | |
721 | (spnt1 == (struct VMS_DBG_Symbol*) NULL))return 1; | |
722 | if(spnt1 == (struct VMS_DBG_Symbol*) NULL) break; | |
723 | spnt=spnt1; | |
724 | }; | |
725 | pnt = cvt_integer(pnt+1,&i); | |
726 | pnt = cvt_integer(pnt+1,&i); | |
727 | }while(*++pnt != ';'); | |
728 | return 0; /* no forward refences found */ | |
0e39a8bb RP |
729 | } |
730 | ||
731 | /* This routine parses the stabs directives to find any definitions of dbx type | |
732 | * numbers. It makes a note of all of them, creating a structure element | |
733 | * of VMS_DBG_Symbol that describes it. This also generates the info for the | |
734 | * debugger that describes the struct/union/enum, so that further references | |
735 | * to these data types will be by number | |
736 | * We have to process pointers right away, since there can be references | |
737 | * to them later in the same stabs directive. We cannot have forward | |
738 | * references to pointers, (but we can have a forward reference to a pointer to | |
739 | * a structure/enum/union) and this is why we process them immediately. | |
740 | * After we process the pointer, then we search for defs that are nested even | |
741 | * deeper. | |
742 | */ | |
743 | static int VMS_typedef_parse(char* str){ | |
744 | char* pnt; | |
8b228fe9 RP |
745 | char* pnt1; |
746 | char* pnt2; | |
747 | int i; | |
748 | int dtype; | |
749 | struct forward_ref * fpnt; | |
750 | int i1,i2,i3; | |
751 | int convert_integer; | |
752 | struct VMS_DBG_Symbol* spnt; | |
753 | struct VMS_DBG_Symbol* spnt1; | |
754 | /* check for any nested def's */ | |
755 | pnt=(char*)strchr(str+1,'='); | |
756 | if((pnt != (char*) NULL) && (*(str+1) != '*')) | |
757 | if(VMS_typedef_parse(pnt) == 1 ) return 1; | |
758 | /* now find dbx_type of entry */ | |
759 | pnt=str-1; | |
760 | if(*pnt == 'c'){ /* check for static constants */ | |
761 | *str = '\0'; /* for now we ignore them */ | |
762 | return 0;}; | |
763 | while((*pnt <= '9')&& (*pnt >= '0')) pnt--; | |
764 | pnt++; /* and get back to the number */ | |
765 | cvt_integer(pnt,&i1); | |
766 | spnt = find_symbol(i1); | |
767 | /* first we see if this has been defined already, due to a forward reference*/ | |
768 | if(spnt == (struct VMS_DBG_Symbol*) NULL) { | |
769 | if(VMS_Symbol_type_list==(struct VMS_DBG_Symbol*) NULL) | |
770 | {spnt=(struct VMS_DBG_Symbol*) malloc(sizeof(struct VMS_DBG_Symbol)); | |
771 | spnt->next = (struct VMS_DBG_Symbol*) NULL; | |
772 | VMS_Symbol_type_list=spnt;} | |
773 | else | |
774 | {spnt=(struct VMS_DBG_Symbol*) malloc(sizeof(struct VMS_DBG_Symbol)); | |
775 | spnt->next=VMS_Symbol_type_list; | |
776 | VMS_Symbol_type_list = spnt;}; | |
777 | spnt->dbx_type = i1; /* and save the type */ | |
778 | }; | |
779 | /* for structs and unions, do a partial parse, otherwise we sometimes get | |
780 | * circular definitions that are impossible to resolve. We read enough info | |
781 | * so that any reference to this type has enough info to be resolved | |
782 | */ | |
783 | pnt=str + 1; /* point to character past equal sign */ | |
784 | if((*pnt == 'u') || (*pnt == 's')){ | |
785 | }; | |
786 | if((*pnt <= '9') && (*pnt >= '0')){ | |
787 | if(type_check("void")){ /* this is the void symbol */ | |
788 | *str='\0'; | |
789 | spnt->advanced = VOID; | |
790 | return 0;}; | |
791 | printf("gcc-as warning(debugger output):"); | |
792 | printf(" %d is an unknown untyped variable.\n",spnt->dbx_type); | |
793 | return 1; /* do not know what this is */ | |
794 | }; | |
795 | /* now define this module*/ | |
796 | pnt=str + 1; /* point to character past equal sign */ | |
797 | switch (*pnt){ | |
798 | case 'r': | |
799 | spnt->advanced= BASIC; | |
800 | if(type_check("int")) { | |
801 | spnt->VMS_type=DBG$C_SLINT; spnt->data_size=4;} | |
802 | else if(type_check("long int")) { | |
803 | spnt->VMS_type=DBG$C_SLINT; spnt->data_size=4;} | |
804 | else if(type_check("unsigned int")) { | |
805 | spnt->VMS_type=DBG$C_ULINT; spnt->data_size = 4;} | |
806 | else if(type_check("long unsigned int")) { | |
807 | spnt->VMS_type=DBG$C_ULINT; spnt->data_size = 4;} | |
808 | else if(type_check("short int")) { | |
809 | spnt->VMS_type=DBG$C_SSINT; spnt->data_size = 2;} | |
810 | else if(type_check("short unsigned int")) { | |
811 | spnt->VMS_type=DBG$C_USINT; spnt->data_size = 2;} | |
812 | else if(type_check("char")) { | |
813 | spnt->VMS_type=DBG$C_SCHAR; spnt->data_size = 1;} | |
814 | else if(type_check("signed char")) { | |
815 | spnt->VMS_type=DBG$C_SCHAR; spnt->data_size = 1;} | |
816 | else if(type_check("unsigned char")) { | |
817 | spnt->VMS_type=DBG$C_UCHAR; spnt->data_size = 1;} | |
818 | else if(type_check("float")) { | |
819 | spnt->VMS_type=DBG$C_REAL4; spnt->data_size = 4;} | |
820 | else if(type_check("double")) { | |
821 | spnt->VMS_type=DBG$C_REAL8; spnt->data_size = 8;} | |
822 | pnt1=(char*) strchr(str,';')+1; | |
823 | break; | |
824 | case 's': | |
825 | case 'u': | |
826 | if(*pnt == 's') spnt->advanced= STRUCT; | |
827 | else spnt->advanced= UNION; | |
828 | spnt->VMS_type = DBG$C_ADVANCED_TYPE; | |
829 | pnt1 = cvt_integer(pnt+1,&spnt->data_size); | |
830 | if(forward_reference(pnt)) { | |
831 | spnt->struc_numb = -1; | |
832 | return 1; | |
833 | } | |
834 | spnt->struc_numb = ++structure_count; | |
835 | pnt1--; | |
836 | pnt=get_struct_name(str); | |
837 | VMS_Def_Struct(spnt->struc_numb); | |
838 | fpnt = f_ref_root; | |
839 | while(fpnt != (struct forward_ref*) NULL){ | |
840 | if(fpnt->dbx_type == spnt->dbx_type) { | |
841 | fpnt->resolved = 'Y'; | |
842 | VMS_Set_Struct(fpnt->struc_numb); | |
843 | VMS_Store_Struct(spnt->struc_numb);}; | |
844 | fpnt = fpnt->next;}; | |
845 | VMS_Set_Struct(spnt->struc_numb); | |
846 | i=0; | |
847 | Local[i++] = 11+strlen(pnt); | |
848 | Local[i++] = DBG$C_STRUCT_START; | |
849 | Local[i++] = 0x80; | |
850 | for(i1=0;i1<4;i1++) Local[i++] = 0x00; | |
851 | Local[i++] = strlen(pnt); | |
852 | pnt2=pnt; | |
853 | while(*pnt2 != '\0') Local[i++] = *pnt2++; | |
854 | i2=spnt->data_size * 8; /* number of bits */ | |
855 | pnt2=(char*) &i2; | |
856 | for(i1=0;i1<4;i1++) Local[i++] = *pnt2++; | |
857 | VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; | |
858 | if(pnt != symbol_name) { | |
859 | pnt += strlen(pnt); | |
860 | *pnt=':';}; /* replace colon for later */ | |
861 | while(*++pnt1 != ';'){ | |
862 | pnt=(char*) strchr(pnt1,':'); | |
863 | *pnt='\0'; | |
864 | pnt2=pnt1; | |
865 | pnt1 = cvt_integer(pnt+1,&dtype); | |
866 | pnt1 = cvt_integer(pnt1+1,&i2); | |
867 | pnt1 = cvt_integer(pnt1+1,&i3); | |
868 | if((dtype == 1) && (i3 != 32)) { /* bitfield */ | |
869 | Apoint = 0; | |
870 | push(19+strlen(pnt2),1); | |
871 | push(0xfa22,2); | |
872 | push(1+strlen(pnt2),4); | |
873 | push(strlen(pnt2),1); | |
874 | while(*pnt2 != '\0') push(*pnt2++,1); | |
875 | push(i3,2); /* size of bitfield */ | |
876 | push(0x0d22,2); | |
877 | push(0x00,4); | |
878 | push(i2,4); /* start position */ | |
879 | VMS_Store_Immediate_Data(Asuffix,Apoint,OBJ$C_DBG); | |
880 | Apoint=0; | |
881 | }else{ | |
882 | Local[i++] = 7+strlen(pnt2); | |
883 | spnt1 = find_symbol(dtype); | |
0e39a8bb | 884 | /* check if this is a forward reference */ |
8b228fe9 RP |
885 | if(spnt1 != (struct VMS_DBG_Symbol*) NULL) |
886 | Local[i++] = spnt1->VMS_type; | |
887 | else | |
888 | Local[i++] = DBG$C_ADVANCED_TYPE; | |
889 | Local[i++] = DBG$C_STRUCT_ITEM; | |
890 | pnt=(char*) &i2; | |
891 | for(i1=0;i1<4;i1++) Local[i++] = *pnt++; | |
892 | Local[i++] = strlen(pnt2); | |
0e39a8bb RP |
893 | while(*pnt2 != '\0') Local[i++] = *pnt2++; |
894 | VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; | |
8b228fe9 RP |
895 | if(spnt1 == (struct VMS_DBG_Symbol*) NULL) |
896 | generate_suffix(spnt1,dtype); | |
897 | else if(spnt1->VMS_type == DBG$C_ADVANCED_TYPE) | |
898 | generate_suffix(spnt1,0); | |
899 | }; | |
0e39a8bb | 900 | }; |
8b228fe9 RP |
901 | pnt1++; |
902 | Local[i++] = 0x01; /* length byte */ | |
903 | Local[i++] = DBG$C_STRUCT_END; | |
904 | VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; | |
905 | break; | |
906 | case 'e': | |
907 | spnt->advanced= ENUM; | |
908 | spnt->VMS_type = DBG$C_ADVANCED_TYPE; | |
909 | spnt->struc_numb = ++structure_count; | |
910 | spnt->data_size=4; | |
911 | VMS_Def_Struct(spnt->struc_numb); | |
912 | fpnt = f_ref_root; | |
913 | while(fpnt != (struct forward_ref*) NULL){ | |
914 | if(fpnt->dbx_type == spnt->dbx_type) { | |
915 | fpnt->resolved = 'Y'; | |
916 | VMS_Set_Struct(fpnt->struc_numb); | |
917 | VMS_Store_Struct(spnt->struc_numb);}; | |
918 | fpnt = fpnt->next;}; | |
919 | VMS_Set_Struct(spnt->struc_numb); | |
920 | i=0; | |
921 | Local[i++] = 3+strlen(symbol_name); | |
922 | Local[i++] = DBG$C_ENUM_START; | |
923 | Local[i++] = 0x20; | |
924 | Local[i++] = strlen(symbol_name); | |
925 | pnt2=symbol_name; | |
926 | while(*pnt2 != '\0') Local[i++] = *pnt2++; | |
927 | VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; | |
928 | while(*++pnt != ';') { | |
929 | pnt1=(char*) strchr(pnt,':'); | |
930 | *pnt1++='\0'; | |
931 | pnt1 = cvt_integer(pnt1,&i1); | |
932 | Local[i++] = 7+strlen(pnt); | |
933 | Local[i++] = DBG$C_ENUM_ITEM; | |
934 | Local[i++] = 0x00; | |
935 | pnt2=(char*) &i1; | |
936 | for(i2=0;i2<4;i2++) Local[i++] = *pnt2++; | |
937 | Local[i++] = strlen(pnt); | |
938 | pnt2=pnt; | |
939 | while(*pnt != '\0') Local[i++] = *pnt++; | |
940 | VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; | |
941 | pnt= pnt1; /* Skip final semicolon */ | |
942 | }; | |
943 | Local[i++] = 0x01; /* len byte */ | |
944 | Local[i++] = DBG$C_ENUM_END; | |
945 | VMS_Store_Immediate_Data(Local, i, OBJ$C_DBG); i=0; | |
946 | pnt1=pnt + 1; | |
947 | break; | |
948 | case 'a': | |
949 | spnt->advanced= ARRAY; | |
950 | spnt->VMS_type = DBG$C_ADVANCED_TYPE; | |
951 | pnt=(char*)strchr(pnt,';'); if (pnt == (char*) NULL) return 1; | |
952 | pnt1 = cvt_integer(pnt+1,&spnt->index_min); | |
953 | pnt1 = cvt_integer(pnt1+1,&spnt->index_max); | |
954 | pnt1 = cvt_integer(pnt1+1,&spnt->type2); | |
955 | break; | |
956 | case 'f': | |
957 | spnt->advanced= FUNCTION; | |
958 | spnt->VMS_type = DBG$C_FUNCTION_ADDR; | |
959 | /* this masquerades as a basic type*/ | |
960 | spnt->data_size=4; | |
961 | pnt1 = cvt_integer(pnt+1,&spnt->type2); | |
962 | break; | |
963 | case '*': | |
964 | spnt->advanced= POINTER; | |
965 | spnt->VMS_type = DBG$C_ADVANCED_TYPE; | |
966 | spnt->data_size=4; | |
967 | pnt1 = cvt_integer(pnt+1,&spnt->type2); | |
968 | pnt=(char*)strchr(str+1,'='); | |
969 | if((pnt != (char*) NULL)) | |
970 | if(VMS_typedef_parse(pnt) == 1 ) return 1; | |
971 | break; | |
972 | default: | |
973 | spnt->advanced= UNKNOWN; | |
974 | spnt->VMS_type = 0; | |
975 | printf("gcc-as warning(debugger output):"); | |
976 | printf(" %d is an unknown type of variable.\n",spnt->dbx_type); | |
977 | return 1; /* unable to decipher */ | |
978 | }; | |
979 | /* this removes the evidence of the definition so that the outer levels of | |
980 | parsing do not have to worry about it */ | |
981 | pnt=str; | |
982 | while (*pnt1 != '\0') *pnt++ = *pnt1++; | |
983 | *pnt = '\0'; | |
984 | return 0; | |
0e39a8bb RP |
985 | } |
986 | ||
987 | ||
988 | /* | |
989 | * This is the root routine that parses the stabs entries for definitions. | |
990 | * it calls VMS_typedef_parse, which can in turn call itself. | |
991 | * We need to be careful, since sometimes there are forward references to | |
992 | * other symbol types, and these cannot be resolved until we have completed | |
993 | * the parse. | |
994 | */ | |
995 | int VMS_LSYM_Parse(){ | |
996 | char *pnt; | |
8b228fe9 RP |
997 | char *pnt1; |
998 | char *pnt2; | |
999 | char *str; | |
1000 | char fixit[10]; | |
1001 | int incomplete,i,pass,incom1; | |
1002 | struct VMS_DBG_Symbol* spnt; | |
1003 | struct VMS_Symbol * vsp; | |
1004 | struct forward_ref * fpnt; | |
1005 | symbolS * sp; | |
1006 | pass=0; | |
1007 | incomplete = 0; | |
1008 | do{ | |
1009 | incom1=incomplete; | |
0e39a8bb | 1010 | incomplete = 0; |
8b228fe9 RP |
1011 | for(sp = symbol_rootP; sp; sp = symbol_next(sp)) { |
1012 | /* | |
1013 | * Deal with STAB symbols | |
1014 | */ | |
1015 | if ((sp->sy_nlist.n_type & N_STAB) != 0) { | |
0e39a8bb | 1016 | /* |
8b228fe9 | 1017 | * Dispatch on STAB type |
0e39a8bb | 1018 | */ |
8b228fe9 RP |
1019 | switch((unsigned char)sp->sy_nlist.n_type) { |
1020 | case N_GSYM: | |
1021 | case N_LCSYM: | |
1022 | case N_STSYM: | |
1023 | case N_PSYM: | |
1024 | case N_RSYM: | |
1025 | case N_LSYM: | |
1026 | case N_FUN: /*sometimes these contain typedefs*/ | |
1027 | str=sp->sy_nlist.n_un.n_name; | |
1028 | symbol_name = str; | |
1029 | pnt=(char*)strchr(str,':'); | |
1030 | if(pnt== (char*) NULL) break; | |
1031 | *pnt='\0'; | |
1032 | pnt1=pnt+1; | |
1033 | pnt2=(char*)strchr(pnt1,'='); | |
1034 | if(pnt2 == (char*) NULL){ | |
1035 | *pnt=':'; /* replace colon */ | |
1036 | break;}; /* no symbol here */ | |
1037 | incomplete += VMS_typedef_parse(pnt2); | |
1038 | *pnt=':'; /* put back colon so variable def code finds dbx_type*/ | |
1039 | break; | |
1040 | } /*switch*/ | |
1041 | } /* if */ | |
1042 | } /*for*/ | |
0e39a8bb | 1043 | pass++; |
8b228fe9 RP |
1044 | } while((incomplete != 0) && (incomplete != incom1 )); |
1045 | /* repeat until all refs resolved if possible */ | |
1046 | /* if(pass > 1) printf(" Required %d passes\n",pass);*/ | |
1047 | if(incomplete != 0){ | |
1048 | printf("gcc-as warning(debugger output):"); | |
1049 | printf("Unable to resolve %d circular references.\n",incomplete); | |
1050 | }; | |
1051 | fpnt = f_ref_root; | |
1052 | symbol_name="\0"; | |
1053 | while(fpnt != (struct forward_ref*) NULL){ | |
1054 | if(fpnt->resolved != 'Y') { | |
1055 | if( find_symbol(fpnt->dbx_type) != | |
1056 | (struct VMS_DBG_Symbol*) NULL){ | |
0e39a8bb | 1057 | printf("gcc-as warning(debugger output):"); |
8b228fe9 RP |
1058 | printf("Forward reference error, dbx type %d\n", |
1059 | fpnt->dbx_type); | |
1060 | break;}; | |
1061 | fixit[0]=0; | |
1062 | sprintf(&fixit[1],"%d=s4;",fpnt->dbx_type); | |
1063 | pnt2=(char*)strchr(&fixit[1],'='); | |
1064 | VMS_typedef_parse(pnt2); | |
1065 | }; | |
1066 | fpnt = fpnt->next;}; | |
0e39a8bb RP |
1067 | } |
1068 | ||
1069 | static symbolS* Current_Routine; | |
1070 | static int Text_Psect; | |
1071 | ||
1072 | static Define_Local_Symbols(symbolS* s1,symbolS* s2){ | |
1073 | symbolS * symbolP1; | |
8b228fe9 RP |
1074 | for(symbolP1 = symbol_next(s1); symbolP1 != s2; symbolP1 = symbol_next(symbolP1)) { |
1075 | if (symbolP1 == (symbolS *)NULL) return; | |
1076 | if (symbolP1->sy_nlist.n_type == N_FUN) return; | |
1077 | /* | |
1078 | * Deal with STAB symbols | |
1079 | */ | |
1080 | if ((symbolP1->sy_nlist.n_type & N_STAB) != 0) { | |
1081 | /* | |
1082 | * Dispatch on STAB type | |
1083 | */ | |
1084 | switch((unsigned char)symbolP1->sy_nlist.n_type) { | |
1085 | case N_LSYM: | |
1086 | case N_PSYM: | |
1087 | VMS_local_stab_Parse(symbolP1); | |
1088 | break; | |
1089 | case N_RSYM: | |
1090 | VMS_RSYM_Parse(symbolP1,Current_Routine,Text_Psect); | |
1091 | break; | |
1092 | } /*switch*/ | |
1093 | } /* if */ | |
1094 | } /* for */ | |
0e39a8bb RP |
1095 | } |
1096 | ||
1097 | static symbolS* Define_Routine(symbolS* symbolP,int Level){ | |
1098 | symbolS * sstart; | |
8b228fe9 RP |
1099 | symbolS * symbolP1; |
1100 | char str[10]; | |
1101 | char * pnt; | |
1102 | int rcount = 0; | |
1103 | int Offset; | |
1104 | sstart = symbolP; | |
1105 | for(symbolP1 = symbol_next(symbolP); symbolP1; symbolP1 = symbol_next(symbolP1)) { | |
1106 | if (symbolP1->sy_nlist.n_type == N_FUN) break; | |
1107 | /* | |
1108 | * Deal with STAB symbols | |
1109 | */ | |
1110 | if ((symbolP1->sy_nlist.n_type & N_STAB) != 0) { | |
1111 | /* | |
1112 | * Dispatch on STAB type | |
1113 | */ | |
1114 | if((unsigned char)symbolP1->sy_nlist.n_type == N_FUN) break; | |
1115 | switch((unsigned char)symbolP1->sy_nlist.n_type) { | |
1116 | case N_LBRAC: | |
1117 | if(Level != 0) { | |
1118 | pnt = str +sprintf(str,"$%d",rcount++); | |
1119 | *pnt = '\0'; | |
1120 | VMS_TBT_Block_Begin(symbolP1,Text_Psect,str); | |
1121 | }; | |
1122 | Offset = symbolP1->sy_nlist.n_value; | |
1123 | Define_Local_Symbols(sstart,symbolP1); | |
1124 | symbolP1 = | |
1125 | Define_Routine(symbolP1,Level+1); | |
1126 | if(Level != 0) | |
1127 | VMS_TBT_Block_End(symbolP1->sy_nlist.n_value - | |
1128 | Offset); | |
1129 | sstart=symbolP1; | |
1130 | break; | |
1131 | case N_RBRAC: | |
1132 | return symbolP1; | |
1133 | } /*switch*/ | |
1134 | } /* if */ | |
1135 | } /* for */ | |
1136 | /* we end up here if there were no brackets in this function. Define | |
1137 | everything */ | |
1138 | Define_Local_Symbols(sstart,(symbolS *) 0); | |
0e39a8bb RP |
1139 | } |
1140 | ||
1141 | VMS_DBG_Define_Routine(symbolS* symbolP,symbolS* Curr_Routine,int Txt_Psect){ | |
1142 | Current_Routine = Curr_Routine; | |
8b228fe9 RP |
1143 | Text_Psect = Txt_Psect; |
1144 | Define_Routine(symbolP,0); | |
0e39a8bb | 1145 | } |
8b228fe9 RP |
1146 | |
1147 | /* end of vms-dbg.c */ |