aboutsummaryrefslogtreecommitdiff
path: root/gas/config/vms/vms-dbg.c
blob: 75cc4c81584db0b679da5503a0fb8f5fef3d851d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
#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 */