BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.bin / gas / grot / vms.c
CommitLineData
089a3e50
C
1/* vms.c -- Write out a VAX/VMS object file
2 Copyright (C) 1987, 1988 Free Software Foundation, Inc.
3
4This file is part of GAS, the GNU Assembler.
5
6GAS is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GAS is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GAS; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20/* Written by David L. Kashtan */
21#include <ctype.h>
22#include <stdio.h>
23#include "as.h"
24#include "md.h"
25#include "subsegs.h"
26#include "obstack.h"
27#include "struc-symbol.h"
28#include "write.h"
29#include "symbols.h"
30
31#ifdef VMS /* THIS MODULE IS FOR VMS ONLY */
32
33#include <stab.h>
34#include "objrecdef.h" /* Define VMS Object record lang. */
35#include <vms/fabdef.h> /* Define File Access Block */
36#include <vms/namdef.h> /* Define NAM Block */
37#include <vms/xabdef.h> /* Define XAB */
38#include <vms/xabdatdef.h> /* Define Date XAB */
39#include <vms/xabfhcdef.h> /* Define File Header XAB */
40
41/*
42 * Version string of the compiler that produced the code we are
43 * assembling. (And this assembler, if we do not have compiler info.)
44 */
45extern char version_string[];
46char *compiler_version_string;
47
48extern char *myname;
49static symbolS *Entry_Point_Symbol = 0; /* Pointer to "_main" */
50
51/*
52 * We augment the "gas" symbol structure with this
53 */
54struct VMS_Symbol {
55 struct VMS_Symbol *Next;
56 struct symbol *Symbol;
57 int Size;
58 int Psect_Index;
59 int Psect_Offset;
60 };
61struct VMS_Symbol *VMS_Symbols = 0;
62
63/* we need this to keep track of the various input files, so that we can
64 * give the debugger the correct source line
65 */
66
67struct input_file{
68 struct input_file* next;
69 struct input_file* same_file_fpnt;
70 int file_number;
71 int max_line;
72 int min_line;
73 int offset;
74 char flag;
75 char * name;
76 symbolS * spnt;
77 };
78
79static struct input_file * file_root = (struct input_file*)NULL;
80
81struct input_file * find_file(symbolS *);
82
83\f
84/*
85 * If the procedure "main()" exists we have to add the instruction
86 * "jsb c$main_args" at the beginning to be compatible with VAX-11 "C".
87 */
88VMS_Check_For_Main()
89{
90 register symbolS *symbolP;
91#ifdef HACK_DEC_C_STARTUP /* JF */
92 register struct frchain *frchainP;
93 register fragS *fragP;
94 register fragS **prev_fragPP;
95 register struct fix *fixP;
96 register fragS *New_Frag;
97 int i;
98#endif HACK_DEC_C_STARTUP
99
100 symbolP = (struct symbol *)symbol_find("_main");
101 if (symbolP && (symbolP->sy_nlist.n_type == (N_TEXT | N_EXT))) {
102#ifdef HACK_DEC_C_STARTUP
103 if( !flagseen['+']) {
104#endif
105 /*
106 * Remember the entry point symbol
107 */
108 Entry_Point_Symbol = symbolP;
109#ifdef HACK_DEC_C_STARTUP
110 } else {
111 /*
112 * Scan all the fragment chains for the one with "_main"
113 * (Actually we know the fragment from the symbol, but we need
114 * the previous fragment so we can change its pointer)
115 */
116 frchainP = frchain_root;
117 while(frchainP) {
118 /*
119 * Scan all the fragments in this chain, remembering
120 * the "previous fragment"
121 */
122 prev_fragPP = &frchainP->frch_root;
123 fragP = frchainP->frch_root;
124 while(fragP && (fragP != frchainP->frch_last)) {
125 /*
126 * Is this the fragment?
127 */
128 if (fragP == symbolP->sy_frag) {
129 /*
130 * Yes: Modify the fragment by replacing
131 * it with a new fragment.
132 */
133 New_Frag = (fragS *)
134 xmalloc(sizeof(*New_Frag) +
135 fragP->fr_fix +
136 fragP->fr_var +
137 5);
138 /*
139 * The fragments are the same except
140 * that the "fixed" area is larger
141 */
142 *New_Frag = *fragP;
143 New_Frag->fr_fix += 6;
144 /*
145 * Copy the literal data opening a hole
146 * 2 bytes after "_main" (i.e. just after
147 * the entry mask). Into which we place
148 * the JSB instruction.
149 */
150 New_Frag->fr_literal[0] = fragP->fr_literal[0];
151 New_Frag->fr_literal[1] = fragP->fr_literal[1];
152 New_Frag->fr_literal[2] = 0x16; /* Jsb */
153 New_Frag->fr_literal[3] = 0xef;
154 New_Frag->fr_literal[4] = 0;
155 New_Frag->fr_literal[5] = 0;
156 New_Frag->fr_literal[6] = 0;
157 New_Frag->fr_literal[7] = 0;
158 for(i = 2; i < fragP->fr_fix + fragP->fr_var; i++)
159 New_Frag->fr_literal[i+6] =
160 fragP->fr_literal[i];
161 /*
162 * Now replace the old fragment with the
163 * newly generated one.
164 */
165 *prev_fragPP = New_Frag;
166 /*
167 * Remember the entry point symbol
168 */
169 Entry_Point_Symbol = symbolP;
170 /*
171 * Scan the text area fixup structures
172 * as offsets in the fragment may have
173 * changed
174 */
175 for(fixP = text_fix_root; fixP; fixP = fixP->fx_next) {
176 /*
177 * Look for references to this
178 * fragment.
179 */
180 if (fixP->fx_frag == fragP) {
181 /*
182 * Change the fragment
183 * pointer
184 */
185 fixP->fx_frag = New_Frag;
186 /*
187 * If the offset is after
188 * the entry mask we need
189 * to account for the JSB
190 * instruction we just
191 * inserted.
192 */
193 if (fixP->fx_where >= 2)
194 fixP->fx_where += 6;
195 }
196 }
197 /*
198 * Scan the symbols as offsets in the
199 * fragment may have changed
200 */
201 for(symbolP = symbol_rootP;
202 symbolP;
203 symbolP = symbolP->sy_next) {
204 /*
205 * Look for references to this
206 * fragment.
207 */
208 if (symbolP->sy_frag == fragP) {
209 /*
210 * Change the fragment
211 * pointer
212 */
213 symbolP->sy_frag = New_Frag;
214 /*
215 * If the offset is after
216 * the entry mask we need
217 * to account for the JSB
218 * instruction we just
219 * inserted.
220 */
221 if (symbolP->sy_nlist.n_value >= 2)
222 symbolP->sy_nlist.n_value += 6;
223 }
224 }
225 /*
226 * Make a symbol reference to
227 * "_c$main_args" so we can get
228 * its address inserted into the
229 * JSB instruction.
230 */
231 symbolP = (symbolS *)xmalloc(sizeof(*symbolP));
232 symbolP->sy_nlist.n_un.n_name = "_c$main_args";
233 symbolP->sy_nlist.n_type = N_UNDF;
234 symbolP->sy_nlist.n_other = 0;
235 symbolP->sy_nlist.n_desc = 0;
236 symbolP->sy_nlist.n_value = 0;
237 symbolP->sy_name_offset = 0;
238 symbolP->sy_number = 0;
239 symbolP->sy_frag = New_Frag;
240 symbolP->sy_forward = 0;
241 symbolP->sy_next = symbol_rootP;
242 symbol_rootP = symbolP;
243 /*
244 * Generate a text fixup structure
245 * to get "_c$main_args" stored into the
246 * JSB instruction.
247 */
248 fixP = (struct fix *)xmalloc(sizeof(*fixP));
249 fixP->fx_frag = New_Frag;
250 fixP->fx_where = 4;
251 fixP->fx_addsy = symbolP;
252 fixP->fx_subsy = 0;
253 fixP->fx_offset = 0;
254 fixP->fx_size = sizeof(long);
255 fixP->fx_pcrel = 1;
256 fixP->fx_next = text_fix_root;
257 text_fix_root = fixP;
258 /*
259 * Now make sure we exit from the loop
260 */
261 frchainP = 0;
262 break;
263 }
264 /*
265 * Try the next fragment
266 */
267 prev_fragPP = &fragP->fr_next;
268 fragP = fragP->fr_next;
269 }
270 /*
271 * Try the next fragment chain
272 */
273 if (frchainP) frchainP=frchainP->frch_next;
274 }
275 }
276#endif /* HACK_DEC_C_STARTUP */
277 }
278}
279\f
280/*
281 * Write a VAX/VMS object file (everything else has been done!)
282 */
283VMS_write_object_file(text_siz, data_siz, text_frag_root, data_frag_root)
284unsigned text_siz;
285unsigned data_siz;
286struct frag *text_frag_root;
287struct frag *data_frag_root;
288{
289 register fragS * fragP;
290 register symbolS * symbolP;
291 register symbolS * sp;
292 register struct fix * fixP;
293 register struct VMS_Symbol * vsp;
294 int Local_Initialized_Data_Size = 0;
295 int Psect_Number = 0; /* Psect Index Number */
296 int Text_Psect = -1; /* Text Psect Index */
297 int Data_Psect = -2; /* Data Psect Index JF: Was -1 */
298 int Bss_Psect = -3; /* Bss Psect Index JF: Was -1 */
299
300 /*
301 * Create the VMS object file
302 */
303 Create_VMS_Object_File();
304 /*
305 * Write the module header records
306 */
307 Write_VMS_MHD_Records();
308\f
309 /*
310 * Generate the VMS object file records
311 * 1st GSD then TIR records
312 */
313
314 /******* Global Symbol Dictionary *******/
315 /*
316 * Define the Text Psect
317 */
318 if (text_siz > 0) {
319 Text_Psect = Psect_Number++;
320 VMS_Psect_Spec("$code",text_siz,"TEXT");
321 }
322 /*
323 * Define the BSS Psect
324 */
325 if (local_bss_counter > 0) {
326 Bss_Psect = Psect_Number++;
327 VMS_Psect_Spec("$uninitialized_data",local_bss_counter,"DATA");
328 }
329 /*
330 * Now scan the symbols and emit the appropriate GSD records
331 */
332 for (sp = symbol_rootP; sp; sp = sp->sy_next) {
333 /*
334 * Dispatch on symbol type
335 */
336 switch(sp->sy_type) {
337 /*
338 * Global uninitialized data
339 */
340 case N_UNDF | N_EXT:
341 /*
342 * Make a VMS data symbol entry
343 */
344 vsp = (struct VMS_Symbol *)
345 xmalloc(sizeof(*vsp));
346 vsp->Symbol = sp;
347 vsp->Size = sp->sy_nlist.n_value;
348 vsp->Psect_Index = Psect_Number++;
349 vsp->Psect_Offset = 0;
350 vsp->Next = VMS_Symbols;
351 VMS_Symbols = vsp;
352 sp->sy_number = (int)vsp;
353 /*
354 * Make the psect for this data
355 */
356 if(sp->sy_nlist.n_other)
357 VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
358 vsp->Size,
359 "CONST");
360 else
361 VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
362 vsp->Size,
363 "COMMON");
364#ifdef NOT_VAX_11_C_COMPATIBLE
365 /*
366 * Place a global symbol at the
367 * beginning of the Psect
368 */
369 VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name,
370 vsp->Psect_Index,
371 0,
372 1);
373#endif NOT_VAX_11_C_COMPATIBLE
374 break;
375 /*
376 * Local uninitialized data
377 */
378 case N_BSS:
379 /*
380 * Make a VMS data symbol entry
381 */
382 vsp = (struct VMS_Symbol *)
383 xmalloc(sizeof(*vsp));
384 vsp->Symbol = sp;
385 vsp->Size = 0;
386 vsp->Psect_Index = Bss_Psect;
387 vsp->Psect_Offset =
388 sp->sy_nlist.n_value -
389 bss_address_frag . fr_address;
390 vsp->Next = VMS_Symbols;
391 VMS_Symbols = vsp;
392 sp->sy_number = (int)vsp;
393 break;
394 /*
395 * Global initialized data
396 */
397 case N_DATA | N_EXT:
398 /*
399 * Make a VMS data symbol entry
400 */
401 vsp = (struct VMS_Symbol *)
402 xmalloc(sizeof(*vsp));
403 vsp->Symbol = sp;
404 vsp->Size = VMS_Initialized_Data_Size(sp,
405 text_siz + data_siz);
406 vsp->Psect_Index = Psect_Number++;
407 vsp->Psect_Offset = 0;
408 vsp->Next = VMS_Symbols;
409 VMS_Symbols = vsp;
410 sp->sy_number = (int)vsp;
411 /*
412 * Make its psect
413 */
414 if(sp->sy_nlist.n_other)
415 VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
416 vsp->Size,
417 "CONST");
418 else
419 VMS_Psect_Spec(sp->sy_nlist.n_un.n_name,
420 vsp->Size,
421 "COMMON");
422#ifdef NOT_VAX_11_C_COMPATIBLE
423 /*
424 * Place a global symbol at the
425 * beginning of the Psect
426 */
427 VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name,
428 vsp->Psect_Index,
429 0,
430 1);
431#endif NOT_VAX_11_C_COMPATIBLE
432 break;
433 /*
434 * Local initialized data
435 */
436 case N_DATA:
437 /*
438 * Make a VMS data symbol entry
439 */
440 vsp = (struct VMS_Symbol *)
441 xmalloc(sizeof(*vsp));
442 vsp->Symbol = sp;
443 vsp->Size =
444 VMS_Initialized_Data_Size(sp,
445 text_siz + data_siz);
446 vsp->Psect_Index = Data_Psect;
447 vsp->Psect_Offset =
448 Local_Initialized_Data_Size;
449 Local_Initialized_Data_Size += vsp->Size;
450 vsp->Next = VMS_Symbols;
451 VMS_Symbols = vsp;
452 sp->sy_number = (int)vsp;
453 break;
454 /*
455 * Global Text definition
456 */
457 case N_TEXT | N_EXT: {
458 unsigned short Entry_Mask;
459
460 /*
461 * Get the entry mask
462 */
463 fragP = sp->sy_frag;
464 Entry_Mask = (fragP->fr_literal[0] & 0xff) +
465 ((fragP->fr_literal[1] & 0xff)
466 << 8);
467 /*
468 * Define the Procedure entry pt.
469 */
470 VMS_Procedure_Entry_Pt(sp->sy_nlist.n_un.n_name,
471 Text_Psect,
472 sp->sy_nlist.n_value,
473 Entry_Mask);
474 break;
475 }
476 /*
477 * Local Text definition
478 */
479 case N_TEXT:
480 /*
481 * Make a VMS data symbol entry
482 */
483 if(Text_Psect != -1) {
484 vsp = (struct VMS_Symbol *)
485 xmalloc(sizeof(*vsp));
486 vsp->Symbol = sp;
487 vsp->Size = 0;
488 vsp->Psect_Index = Text_Psect;
489 vsp->Psect_Offset = sp->sy_nlist.n_value;
490 vsp->Next = VMS_Symbols;
491 VMS_Symbols = vsp;
492 sp->sy_number = (int)vsp;
493 }
494 break;
495 /*
496 * Global Reference
497 */
498 case N_UNDF:
499 /*
500 * Make a GSD global symbol reference
501 * record.
502 */
503 VMS_Global_Symbol_Spec(sp->sy_nlist.n_un.n_name,
504 0,
505 0,
506 0);
507 break;
508 /*
509 * Anything else
510 */
511 default:
512 /*
513 * Ignore STAB symbols
514 * Including .stabs emitted by g++
515 */
516 if ((sp->sy_type & N_STAB) != 0 || sp->sy_nlist.n_type==22)
517 break;
518 /*
519 * Error
520 */
521 if(sp->sy_nlist.n_type !=22)
522 printf(" ERROR, unknown type (%d)\n",
523 sp->sy_nlist.n_type);
524 break;
525 }
526 }
527 /*
528 * Define the Data Psect
529 */
530 if ((data_siz > 0) && (Local_Initialized_Data_Size > 0)) {
531 /*
532 * Do it
533 */
534 Data_Psect = Psect_Number++;
535 VMS_Psect_Spec("$data",
536 Local_Initialized_Data_Size,
537 "DATA");
538 /*
539 * Scan the VMS symbols and fill in the data psect
540 */
541 for (vsp = VMS_Symbols; vsp; vsp = vsp->Next) {
542 /*
543 * Only look for undefined psects
544 */
545 if (vsp->Psect_Index < 0) {
546 /*
547 * And only initialized data
548 */
549 if (vsp->Symbol->sy_nlist.n_type == N_DATA)
550 vsp->Psect_Index = Data_Psect;
551 }
552 }
553 }
554\f
555 /******* Text Information and Relocation Records *******/
556 /*
557 * Write the text segment data
558 */
559 if (text_siz > 0) {
560 /*
561 * Scan the text fragments
562 */
563 for(fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
564 /*
565 * Stop if we get to the data fragments
566 */
567 if (fragP == data_frag_root) break;
568 /*
569 * Ignore fragments with no data
570 */
571 if ((fragP->fr_fix == 0) && (fragP->fr_var == 0))
572 continue;
573 /*
574 * Go the the appropriate offset in the
575 * Text Psect.
576 */
577 VMS_Set_Psect(Text_Psect,fragP->fr_address,OBJ$C_TIR);
578 /*
579 * Store the "fixed" part
580 */
581 if (fragP->fr_fix)
582 VMS_Store_Immediate_Data(fragP->fr_literal,
583 fragP->fr_fix,
584 OBJ$C_TIR);
585 /*
586 * Store the "variable" part
587 */
588 if (fragP->fr_var && fragP->fr_offset)
589 VMS_Store_Repeated_Data(fragP->fr_offset,
590 fragP->fr_literal+
591 fragP->fr_fix,
592 fragP->fr_var,
593 OBJ$C_TIR);
594 }
595 /*
596 * Now we go through the text segment fixups and
597 * generate TIR records to fix up addresses within
598 * the Text Psect
599 */
600 for(fixP = text_fix_root; fixP; fixP = fixP->fx_next) {
601 /*
602 * We DO handle the case of "Symbol - Symbol" as
603 * long as it is in the same segment.
604 */
605 if (fixP->fx_subsy && fixP->fx_addsy) {
606 int i;
607
608 /*
609 * They need to be in the same segment
610 */
611 if (fixP->fx_subsy->sy_type !=
612 fixP->fx_addsy->sy_type)
613 error("Fixup data addsy and subsy didn't have the same type");
614 /*
615 * And they need to be in one that we
616 * can check the psect on
617 */
618 if (((fixP->fx_addsy->sy_type & ~N_EXT) != N_DATA) &&
619 ((fixP->fx_addsy->sy_type & ~N_EXT) != N_TEXT))
620 error("Fixup data addsy and subsy didn't have an appropriate type");
621 /*
622 * This had better not be PC relative!
623 */
624 if (fixP->fx_pcrel)
625 error("Fixup data was erroneously \"pcrel\"");
626 /*
627 * Subtract their values to get the
628 * difference.
629 */
630 i = fixP->fx_addsy->sy_value -
631 fixP->fx_subsy->sy_value;
632 /*
633 * Now generate the fixup object records
634 * Set the psect and store the data
635 */
636 VMS_Set_Psect(Text_Psect,
637 fixP->fx_where +
638 fixP->fx_frag->fr_address,
639 OBJ$C_TIR);
640 VMS_Store_Immediate_Data(&i,
641 fixP->fx_size,
642 OBJ$C_TIR);
643 /*
644 * Done
645 */
646 continue;
647 }
648 /*
649 * Size will HAVE to be "long"
650 */
651 if (fixP->fx_size != sizeof(long))
652 error("Fixup datum was not a longword");
653 /*
654 * Symbol must be "added" (if it is ever
655 * subtracted we can
656 * fix this assumption)
657 */
658 if (fixP->fx_addsy == 0)
659 error("Fixup datum was not \"fixP->fx_addsy\"");
660 /*
661 * Store the symbol value in a PIC fashion
662 */
663 VMS_Store_PIC_Symbol_Reference(fixP->fx_addsy,
664 fixP->fx_offset,
665 fixP->fx_pcrel,
666 Text_Psect,
667 fixP->fx_where +
668 fixP->fx_frag->fr_address,
669 OBJ$C_TIR);
670 /*
671 * Check for indirect address reference,
672 * which has to be fixed up (as the linker
673 * will screw it up with TIR$C_STO_PICR).
674 */
675 if (fixP->fx_pcrel)
676 VMS_Fix_Indirect_Reference(Text_Psect,
677 fixP->fx_where +
678 fixP->fx_frag->fr_address,
679 fixP->fx_frag,
680 text_frag_root);
681 }
682 }
683 /*
684 * Store the Data segment:
685 *
686 * Since this is REALLY hard to do any other way,
687 * we actually manufacture the data segment and
688 * the store the appropriate values out of it.
689 */
690 if (data_siz > 0) {
691 char *Data_Segment;
692
693 /*
694 * Allocate the data segment
695 */
696 Data_Segment = (char *)xmalloc(data_siz);
697 /*
698 * Run through the data fragments, filling in the segment
699 */
700 for(fragP = data_frag_root; fragP; fragP = fragP->fr_next) {
701 register long int count;
702 register char * fill_literal;
703 register long int fill_size;
704 int i;
705
706 i = fragP->fr_address - text_siz;
707 if (fragP->fr_fix)
708 bcopy(fragP->fr_literal,
709 Data_Segment + i,
710 fragP->fr_fix);
711 i += fragP->fr_fix;
712
713 fill_literal= fragP -> fr_literal + fragP -> fr_fix;
714 fill_size = fragP -> fr_var;
715 for (count = fragP -> fr_offset; count; count --) {
716 if (fill_size)
717 bcopy(fill_literal,
718 Data_Segment + i,
719 fill_size);
720 i += fill_size;
721 }
722 }
723 /*
724 * Now we can run through all the data symbols
725 * and store the data
726 */
727 for(vsp = VMS_Symbols; vsp; vsp = vsp->Next) {
728 /*
729 * Ignore anything other than data symbols
730 */
731 if ((vsp->Symbol->sy_nlist.n_type & ~N_EXT) != N_DATA)
732 continue;
733 /*
734 * Set the Psect + Offset
735 */
736 VMS_Set_Psect(vsp->Psect_Index,
737 vsp->Psect_Offset,
738 OBJ$C_TIR);
739 /*
740 * Store the data
741 */
742 VMS_Store_Immediate_Data(Data_Segment +
743 vsp->Symbol->sy_nlist.n_value -
744 text_siz,
745 vsp->Size,
746 OBJ$C_TIR);
747 }
748 /*
749 * Now we go through the data segment fixups and
750 * generate TIR records to fix up addresses within
751 * the Data Psects
752 */
753 for(fixP = data_fix_root; fixP; fixP = fixP->fx_next) {
754 /*
755 * Find the symbol for the containing datum
756 */
757 for(vsp = VMS_Symbols; vsp; vsp = vsp->Next) {
758 /*
759 * Only bother with Data symbols
760 */
761 sp = vsp->Symbol;
762 if ((sp->sy_nlist.n_type & ~N_EXT) != N_DATA)
763 continue;
764 /*
765 * Ignore symbol if After fixup
766 */
767 if (sp->sy_nlist.n_value >
768 (fixP->fx_where +
769 fixP->fx_frag->fr_address))
770 continue;
771 /*
772 * See if the datum is here
773 */
774 if ((sp->sy_nlist.n_value + vsp->Size) <=
775 (fixP->fx_where +
776 fixP->fx_frag->fr_address))
777 continue;
778 /*
779 * We DO handle the case of "Symbol - Symbol" as
780 * long as it is in the same segment.
781 */
782 if (fixP->fx_subsy && fixP->fx_addsy) {
783 int i;
784
785 /*
786 * They need to be in the same segment
787 */
788 if (fixP->fx_subsy->sy_type !=
789 fixP->fx_addsy->sy_type)
790 error("Fixup data addsy and subsy didn't have the same type");
791 /*
792 * And they need to be in one that we
793 * can check the psect on
794 */
795 if (((fixP->fx_addsy->sy_type & ~N_EXT) != N_DATA) &&
796 ((fixP->fx_addsy->sy_type & ~N_EXT) != N_TEXT))
797 error("Fixup data addsy and subsy didn't have an appropriate type");
798 /*
799 * This had better not be PC relative!
800 */
801 if (fixP->fx_pcrel)
802 error("Fixup data was erroneously \"pcrel\"");
803 /*
804 * Subtract their values to get the
805 * difference.
806 */
807 i = fixP->fx_addsy->sy_value -
808 fixP->fx_subsy->sy_value;
809 /*
810 * Now generate the fixup object records
811 * Set the psect and store the data
812 */
813 VMS_Set_Psect(vsp->Psect_Index,
814 fixP->fx_frag->fr_address +
815 fixP->fx_where -
816 vsp->Symbol->sy_value +
817 vsp->Psect_Offset,
818 OBJ$C_TIR);
819 VMS_Store_Immediate_Data(&i,
820 fixP->fx_size,
821 OBJ$C_TIR);
822 /*
823 * Done
824 */
825 break;
826 }
827 /*
828 * Size will HAVE to be "long"
829 */
830 if (fixP->fx_size != sizeof(long))
831 error("Fixup datum was not a longword");
832 /*
833 * Symbol must be "added" (if it is ever
834 * subtracted we can
835 * fix this assumption)
836 */
837 if (fixP->fx_addsy == 0)
838 error("Fixup datum was not \"fixP->fx_addsy\"");
839 /*
840 * Store the symbol value in a PIC fashion
841 */
842 VMS_Store_PIC_Symbol_Reference(
843 fixP->fx_addsy,
844 fixP->fx_offset,
845 fixP->fx_pcrel,
846 vsp->Psect_Index,
847 fixP->fx_frag->fr_address +
848 fixP->fx_where -
849 vsp->Symbol->sy_value +
850 vsp->Psect_Offset,
851 OBJ$C_TIR);
852 /*
853 * Done
854 */
855 break;
856 }
857
858 }
859 }
860\f
861 /*
862 * Write the Traceback Begin Module record
863 */
864 VMS_TBT_Module_Begin();
865 /*
866 * Scan the symbols and write out the routines
867 * (this makes the assumption that symbols are in
868 * order of ascending text segment offset)
869 */
870 {
871 struct symbol *Current_Routine = 0;
872 int Current_Line_Number = 0;
873 int Current_Offset = -1;
874 struct input_file * Current_File;
875
876/* Output debugging info for global variables and static variables that are not
877 * specific to one routine. We also need to examine all stabs directives, to
878 * find the definitions to all of the advanced data types, and this is done by
879 * VMS_LSYM_Parse. This needs to be done before any definitions are output to
880 * the object file, since there can be forward references in the stabs
881 * directives. When through with parsing, the text of the stabs directive
882 * is altered, with the definitions removed, so that later passes will see
883 * directives as they would be written if the type were already defined.
884 *
885 * We also look for files and include files, and make a list of them. We
886 * examine the source file numbers to establish the actual lines that code was
887 * generated from, and then generate offsets.
888 */
889 VMS_LSYM_Parse();
890 for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next) {
891 /*
892 * Deal with STAB symbols
893 */
894 if ((symbolP->sy_nlist.n_type & N_STAB) != 0) {
895 /*
896 * Dispatch on STAB type
897 */
898 switch((unsigned char)symbolP->sy_nlist.n_type) {
899 case N_SLINE:
900 if(symbolP->sy_nlist.n_desc > Current_File->max_line)
901 Current_File->max_line = symbolP->sy_nlist.n_desc;
902 if(symbolP->sy_nlist.n_desc < Current_File->min_line)
903 Current_File->min_line = symbolP->sy_nlist.n_desc;
904 break;
905 case N_SO:
906 Current_File =find_file(symbolP);
907 Current_File->flag = 1;
908 Current_File->min_line = 1;
909 break;
910 case N_SOL:
911 Current_File = find_file(symbolP);
912 break;
913 case N_GSYM:
914 VMS_GSYM_Parse(symbolP,Text_Psect);
915 break;
916 case N_LCSYM:
917 VMS_LCSYM_Parse(symbolP,Text_Psect);
918 break;
919 case N_FUN: /* For static constant symbols */
920 case N_STSYM:
921 VMS_STSYM_Parse(symbolP,Text_Psect);
922 break;
923 }
924 }
925 }
926
927 /* now we take a quick sweep through the files and assign offsets
928 to each one. This will essentially be the starting line number to the
929 debugger for each file. Output the info for the debugger to specify the
930 files, and then tell it how many lines to use */
931 {
932 int File_Number = 0;
933 int Debugger_Offset = 0;
934 int file_available;
935 Current_File = file_root;
936 for(Current_File = file_root; Current_File; Current_File = Current_File->next){
937 if(Current_File == (struct input_file*) NULL) break;
938 if(Current_File->max_line == 0) continue;
939 if((strncmp(Current_File->name,"GNU_GXX_INCLUDE:",16) == 0) &&
940 !flagseen['D']) continue;
941 if((strncmp(Current_File->name,"GNU_CC_INCLUDE:",15) == 0) &&
942 !flagseen['D']) continue;
943/* show a few extra lines at the start of the region selected */
944 if(Current_File->min_line > 2) Current_File->min_line -= 2;
945 Current_File->offset = Debugger_Offset - Current_File->min_line + 1;
946 Debugger_Offset += Current_File->max_line - Current_File->min_line + 1;
947 if(Current_File->same_file_fpnt != (struct input_file *) NULL)
948 Current_File->file_number =Current_File->same_file_fpnt->file_number;
949 else {
950 Current_File->file_number = ++File_Number;
951 file_available = VMS_TBT_Source_File(Current_File->name,
952 Current_File->file_number);
953 if(!file_available) {Current_File->file_number = 0;
954 File_Number--;
955 continue;};
956 };
957 VMS_TBT_Source_Lines(Current_File->file_number,
958 Current_File->min_line,
959 Current_File->max_line-Current_File->min_line+1);
960 }; /* for */
961 }; /* scope */
962 Current_File = (struct input_file*) NULL;
963
964 for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next) {
965 /*
966 * Deal with text symbols
967 */
968 if ((symbolP->sy_nlist.n_type & ~N_EXT) == N_TEXT) {
969 /*
970 * Ignore symbols starting with "L",
971 * as they are local symbols
972 */
973 if (symbolP->sy_nlist.n_un.n_name[0] == 'L') continue;
974 /*
975 * If there is a routine start defined,
976 * terminate it.
977 */
978 if (Current_Routine) {
979 /*
980 * End the routine
981 */
982 VMS_TBT_Routine_End(text_siz,Current_Routine);
983 }
984 /*
985 * Store the routine begin traceback info
986 */
987 if(Text_Psect != -1) {
988 VMS_TBT_Routine_Begin(symbolP,Text_Psect);
989 Current_Routine = symbolP;
990 }
991/* Output local symbols, i.e. all symbols that are associated with a specific
992 * routine. We output them now so the debugger recognizes them as local to
993 * this routine.
994 */
995 { symbolS * symbolP1;
996 char* pnt;
997 char* pnt1;
998 for(symbolP1 = Current_Routine; symbolP1; symbolP1 = symbolP1->sy_next) {
999 if ((symbolP1->sy_nlist.n_type & N_STAB) == 0) continue;
1000 if (symbolP1->sy_nlist.n_type != N_FUN) continue;
1001 pnt=symbolP->sy_nlist.n_un.n_name;
1002 pnt1=symbolP1->sy_nlist.n_un.n_name;
1003 if(*pnt++ != '_') continue;
1004 while(*pnt++ == *pnt1++) {};
1005 if((*(--pnt) == '\0') && (*(--pnt1) == ':')) break;
1006 };
1007 if(symbolP1 != (symbolS *) NULL)
1008 VMS_DBG_Define_Routine(symbolP1,Current_Routine,Text_Psect);
1009 } /* local symbol block */
1010 /*
1011 * Done
1012 */
1013 continue;
1014 }
1015 /*
1016 * Deal with STAB symbols
1017 */
1018 if ((symbolP->sy_nlist.n_type & N_STAB) != 0) {
1019 /*
1020 * Dispatch on STAB type
1021 */
1022 switch((unsigned char)symbolP->sy_nlist.n_type) {
1023 /*
1024 * Line number
1025 */
1026 case N_SLINE:
1027 /* Offset the line into the correct portion
1028 * of the file */
1029 if(Current_File->file_number == 0) break;
1030 /* Sometimes the same offset gets several source
1031 * lines assigned to it.
1032 * We should be selective about which lines
1033 * we allow, we should prefer lines that are
1034 * in the main source file when debugging
1035 * inline functions. */
1036 if((Current_File->file_number != 1) &&
1037 symbolP->sy_nlist.n_value ==
1038 Current_Offset) break;
1039 /* calculate actual debugger source line */
1040 symbolP->sy_nlist.n_desc
1041 += Current_File->offset;
1042 /*
1043 * If this is the 1st N_SLINE, setup
1044 * PC/Line correlation. Otherwise
1045 * do the delta PC/Line. If the offset
1046 * for the line number is not +ve we need
1047 * to do another PC/Line correlation
1048 * setup
1049 */
1050 if (Current_Offset == -1) {
1051 VMS_TBT_Line_PC_Correlation(
1052 symbolP->sy_nlist.n_desc,
1053 symbolP->sy_nlist.n_value,
1054 Text_Psect,
1055 0);
1056 } else {
1057 if ((symbolP->sy_nlist.n_desc -
1058 Current_Line_Number) <= 0) {
1059 /*
1060 * Line delta is not +ve, we
1061 * need to close the line and
1062 * start a new PC/Line
1063 * correlation.
1064 */
1065 VMS_TBT_Line_PC_Correlation(0,
1066 symbolP->sy_nlist.n_value -
1067 Current_Offset,
1068 0,
1069 -1);
1070 VMS_TBT_Line_PC_Correlation(
1071 symbolP->sy_nlist.n_desc,
1072 symbolP->sy_nlist.n_value,
1073 Text_Psect,
1074 0);
1075 } else {
1076 /*
1077 * Line delta is +ve, all is well
1078 */
1079 VMS_TBT_Line_PC_Correlation(
1080 symbolP->sy_nlist.n_desc -
1081 Current_Line_Number,
1082 symbolP->sy_nlist.n_value -
1083 Current_Offset,
1084 0,
1085 1);
1086 }
1087 }
1088 /*
1089 * Update the current line/PC
1090 */
1091 Current_Line_Number = symbolP->sy_nlist.n_desc;
1092 Current_Offset = symbolP->sy_nlist.n_value;
1093 /*
1094 * Done
1095 */
1096 break;
1097 /*
1098 * Source file
1099 */
1100 case N_SO:
1101 /*
1102 * Remember that we had a source file
1103 * and emit the source file debugger
1104 * record
1105 */
1106 Current_File =
1107 find_file(symbolP);
1108 break;
1109/* We need to make sure that we are really in the actual source file when
1110 * we compute the maximum line number. Otherwise the debugger gets really
1111 * confused */
1112 case N_SOL:
1113 Current_File =
1114 find_file(symbolP);
1115 break;
1116 }
1117 }
1118 }
1119 /*
1120 * If there is a routine start defined,
1121 * terminate it (and the line numbers)
1122 */
1123 if (Current_Routine) {
1124 /*
1125 * Terminate the line numbers
1126 */
1127 VMS_TBT_Line_PC_Correlation(0,
1128 text_siz - Current_Routine->sy_nlist.n_value,
1129 0,
1130 -1);
1131 /*
1132 * Terminate the routine
1133 */
1134 VMS_TBT_Routine_End(text_siz,Current_Routine);
1135 }
1136 }
1137 /*
1138 * Write the Traceback End Module TBT record
1139 */
1140 VMS_TBT_Module_End();
1141\f
1142 /*
1143 * Write the End Of Module record
1144 */
1145 if (Entry_Point_Symbol == 0)
1146 Write_VMS_EOM_Record(-1,0);
1147 else
1148 Write_VMS_EOM_Record(Text_Psect,
1149 Entry_Point_Symbol->sy_nlist.n_value);
1150\f
1151 /*
1152 * All done, close the object file
1153 */
1154 Close_VMS_Object_File();
1155}
1156
1157\f
1158 /****** VMS OBJECT FILE HACKING ROUTINES *******/
1159
1160
1161/*
1162 * Global data (Object records limited to 512 bytes by VAX-11 "C" runtime)
1163 */
1164static int VMS_Object_File_FD; /* File Descriptor for object file */
1165static char Object_Record_Buffer[512]; /* Buffer for object file records */
1166static int Object_Record_Offset; /* Offset to end of data */
1167static int Current_Object_Record_Type; /* Type of record in above */
1168
1169/*
1170 * Macros for placing data into the object record buffer
1171 */
1172#define PUT_LONG(val) *((long *)(Object_Record_Buffer + \
1173 Object_Record_Offset)) = val; \
1174 Object_Record_Offset += sizeof(long)
1175
1176#define PUT_SHORT(val) *((short *)(Object_Record_Buffer + \
1177 Object_Record_Offset)) = val; \
1178 Object_Record_Offset += sizeof(short)
1179
1180#define PUT_CHAR(val) Object_Record_Buffer[Object_Record_Offset++] = val
1181
1182#define PUT_COUNTED_STRING(cp) {\
1183 register char *p = cp; \
1184 PUT_CHAR(strlen(p)); \
1185 while(*p) PUT_CHAR(*p++);}
1186
1187/*
1188 * Macro for determining if a Name has psect attributes attached
1189 * to it.
1190 */
1191#define PSECT_ATTRIBUTES_STRING "$$PsectAttributes_"
1192#define PSECT_ATTRIBUTES_STRING_LENGTH 18
1193
1194#define HAS_PSECT_ATTRIBUTES(Name) \
1195 (strncmp((Name[0] == '_' ? Name + 1 : Name), \
1196 PSECT_ATTRIBUTES_STRING, \
1197 PSECT_ATTRIBUTES_STRING_LENGTH) == 0)
1198
1199\f
1200/*
1201 * Create the VMS object file
1202 */
1203Create_VMS_Object_File()
1204{
1205#ifdef eunice
1206 VMS_Object_File_FD = creat(out_file_name, 0777, "var");
1207#else eunice
1208 VMS_Object_File_FD = creat(out_file_name, 0, "rfm=var");
1209#endif eunice
1210 /*
1211 * Deal with errors
1212 */
1213 if (VMS_Object_File_FD < 0) {
1214 char Error_Line[256];
1215
1216 sprintf(Error_Line,"Couldn't create VMS object file \"%s\"",
1217 out_file_name);
1218 error(Error_Line);
1219 }
1220 /*
1221 * Initialize object file hacking variables
1222 */
1223 Object_Record_Offset = 0;
1224 Current_Object_Record_Type = -1;
1225}
1226
1227\f
1228/*
1229 * Declare a particular type of object file record
1230 */
1231Set_VMS_Object_File_Record(Type)
1232int Type;
1233{
1234 /*
1235 * If the type matches, we are done
1236 */
1237 if (Type == Current_Object_Record_Type) return;
1238 /*
1239 * Otherwise: flush the buffer
1240 */
1241 Flush_VMS_Object_Record_Buffer();
1242 /*
1243 * Set the new type
1244 */
1245 Current_Object_Record_Type = Type;
1246}
1247
1248\f
1249/*
1250 * Flush the object record buffer to the object file
1251 */
1252Flush_VMS_Object_Record_Buffer()
1253{
1254 int i;
1255
1256 /*
1257 * If the buffer is empty, we are done
1258 */
1259 if (Object_Record_Offset == 0) return;
1260 /*
1261 * Write the data to the file
1262 */
1263 i= write(VMS_Object_File_FD,
1264 Object_Record_Buffer,
1265 Object_Record_Offset);
1266 if (i != Object_Record_Offset)
1267 error("I/O error writing VMS object file");
1268 /*
1269 * The buffer is now empty
1270 */
1271 Object_Record_Offset = 0;
1272}
1273
1274\f
1275/*
1276 * Close the VMS Object file
1277 */
1278Close_VMS_Object_File()
1279{
1280 close(VMS_Object_File_FD);
1281}
1282
1283\f
1284/*
1285 * Write the MHD (Module Header) records
1286 */
1287Write_VMS_MHD_Records()
1288{
1289 register char *cp,*cp1;
1290 register int i;
1291 struct {int Size; char *Ptr;} Descriptor;
1292 char Module_Name[256];
1293 char Now[17];
1294
1295 /*
1296 * We are writing a module header record
1297 */
1298 Set_VMS_Object_File_Record(OBJ$C_HDR);
1299 /*
1300 * ***************************
1301 * *MAIN MODULE HEADER RECORD*
1302 * ***************************
1303 *
1304 * Store record type and header type
1305 */
1306 PUT_CHAR(OBJ$C_HDR);
1307 PUT_CHAR(MHD$C_MHD);
1308 /*
1309 * Structure level is 0
1310 */
1311 PUT_CHAR(OBJ$C_STRLVL);
1312 /*
1313 * Maximum record size is size of the object record buffer
1314 */
1315 PUT_SHORT(sizeof(Object_Record_Buffer));
1316 /*
1317 * Get module name (the FILENAME part of the object file)
1318 */
1319 cp = out_file_name;
1320 cp1 = Module_Name;
1321 while(*cp) {
1322 if ((*cp == ']') || (*cp == '>') ||
1323 (*cp == ':') || (*cp == '/')) {
1324 cp1 = Module_Name;
1325 cp++;
1326 continue;
1327 }
1328 *cp1++ = islower(*cp) ? toupper(*cp++) : *cp++;
1329 }
1330 *cp1 = 0;
1331 /*
1332 * Limit it to 31 characters and store in the object record
1333 */
1334 while(--cp1 >= Module_Name)
1335 if (*cp1 == '.') *cp1 = 0;
1336 if (strlen(Module_Name) > 31) {
1337 if(flagseen['+'])
1338 printf("%s: Module name truncated: %s\n", myname, Module_Name);
1339 Module_Name[31] = 0;
1340 }
1341 PUT_COUNTED_STRING(Module_Name);
1342 /*
1343 * Module Version is "V1.0"
1344 */
1345 PUT_COUNTED_STRING("V1.0");
1346 /*
1347 * Creation time is "now" (17 chars of time string)
1348 */
1349 Descriptor.Size = 17;
1350 Descriptor.Ptr = Now;
1351 sys$asctim(0,&Descriptor,0,0);
1352 for(i = 0; i < 17; i++) PUT_CHAR(Now[i]);
1353 /*
1354 * Patch time is "never" (17 zeros)
1355 */
1356 for(i = 0; i < 17; i++) PUT_CHAR(0);
1357 /*
1358 * Flush the record
1359 */
1360 Flush_VMS_Object_Record_Buffer();
1361 /*
1362 * *************************
1363 * *LANGUAGE PROCESSOR NAME*
1364 * *************************
1365 *
1366 * Store record type and header type
1367 */
1368 PUT_CHAR(OBJ$C_HDR);
1369 PUT_CHAR(MHD$C_LNM);
1370 /*
1371 * Store language processor name and version
1372 * (not a counted string!)
1373 */
1374 cp = compiler_version_string;
1375 if (cp == 0) {
1376 cp ="GNU AS V";
1377 while(*cp) PUT_CHAR(*cp++);
1378 cp = strchr(&version_string,'.');
1379 while(*cp != ' ') cp--; cp++;
1380 };
1381 while(*cp >= 32) PUT_CHAR(*cp++);
1382 /*
1383 * Flush the record
1384 */
1385 Flush_VMS_Object_Record_Buffer();
1386}
1387
1388\f
1389/*
1390 * Write the EOM (End Of Module) record
1391 */
1392Write_VMS_EOM_Record(Psect, Offset)
1393int Psect;
1394int Offset;
1395{
1396 /*
1397 * We are writing an end-of-module record
1398 */
1399 Set_VMS_Object_File_Record(OBJ$C_EOM);
1400 /*
1401 * Store record Type
1402 */
1403 PUT_CHAR(OBJ$C_EOM);
1404 /*
1405 * Store the error severity (0)
1406 */
1407 PUT_CHAR(0);
1408 /*
1409 * Store the entry point, if it exists
1410 */
1411 if (Psect >= 0) {
1412 /*
1413 * Store the entry point Psect
1414 */
1415 PUT_CHAR(Psect);
1416 /*
1417 * Store the entry point Psect offset
1418 */
1419 PUT_LONG(Offset);
1420 }
1421 /*
1422 * Flush the record
1423 */
1424 Flush_VMS_Object_Record_Buffer();
1425}
1426
1427\f
1428/* this hash routine borrowed from GNU-EMACS, and strengthened slightly ERY*/
1429
1430static int
1431hash_string (ptr)
1432 unsigned char *ptr;
1433{
1434 register unsigned char *p = ptr;
1435 register unsigned char *end = p + strlen(ptr);
1436 register unsigned char c;
1437 register int hash = 0;
1438
1439 while (p != end)
1440 {
1441 c = *p++;
1442 hash = ((hash<<3) + (hash<<15) + (hash>>28) + c);
1443 }
1444 return hash;
1445}
1446
1447/*
1448 * Generate a Case-Hacked VMS symbol name (limited to 31 chars)
1449 */
1450VMS_Case_Hack_Symbol(In,Out)
1451register char *In;
1452register char *Out;
1453{
1454 long int init = 0;
1455 long int result;
1456 char *pnt;
1457 char *new_name;
1458 char *old_name;
1459 register int i;
1460 int destructor = 0; /*hack to allow for case sens in a destructor*/
1461 int truncate = 0;
1462 int Case_Hack_Bits = 0;
1463 int Saw_Dollar = 0;
1464 static char Hex_Table[16] =
1465 {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
1466
1467 /*
1468 * Kill any leading "_"
1469 */
1470 if (*In == '_') In++;
1471
1472 new_name=Out; /* save this for later*/
1473
1474 if((In[0]=='_')&&(In[1]=='$')&&(In[2]=='_'))
1475 destructor=1;
1476
1477 /* We may need to truncate the symbol, save the hash for later*/
1478 if(strlen(In)>23) result = hash_string(In);
1479 /*
1480 * Is there a Psect Attribute to skip??
1481 */
1482 if (HAS_PSECT_ATTRIBUTES(In)) {
1483 /*
1484 * Yes: Skip it
1485 */
1486 In += PSECT_ATTRIBUTES_STRING_LENGTH;
1487 while(*In) {
1488 if ((In[0] == '$') && (In[1] == '$')) {
1489 In += 2;
1490 break;
1491 }
1492 In++;
1493 }
1494 }
1495
1496 old_name=In;
1497/* if(strlen(In) > 31 && flagseen['+'])
1498 printf("%s: Symbol name truncated: %s\n",myname,In);*/
1499 /*
1500 * Do the case conversion
1501 */
1502 i = 23; /* Maximum of 23 chars */
1503 while(*In && (--i >= 0)) {
1504 Case_Hack_Bits <<= 1;
1505 if (*In == '$') Saw_Dollar = 1;
1506 if ((destructor==1)&&(i==21)) Saw_Dollar = 0;
1507 if (isupper(*In)) {
1508 *Out++ = *In++;
1509 Case_Hack_Bits |= 1;
1510 } else {
1511 *Out++ = islower(*In) ? toupper(*In++) : *In++;
1512 }
1513 }
1514 /*
1515 * If we saw a dollar sign, we don't do case hacking
1516 */
1517 if(flagseen['h'] || Saw_Dollar)
1518 Case_Hack_Bits = 0;
1519
1520 /*
1521 * If we have more than 23 characters and everything is lowercase
1522 * we can insert the full 31 characters
1523 */
1524 if (*In) {
1525 /*
1526 * We have more than 23 characters
1527 * If we must add the case hack, then we have truncated the str
1528 */
1529 pnt=Out;
1530 truncate=1;
1531 if (Case_Hack_Bits == 0) {
1532 /*
1533 * And so far they are all lower case:
1534 * Check up to 8 more characters
1535 * and ensure that they are lowercase
1536 */
1537 if(flagseen['h'])
1538 i=8;
1539 else
1540 for(i = 0; (In[i] != 0) && (i < 8); i++)
1541 if (isupper(In[i]) && !Saw_Dollar)
1542 break;
1543 if(In[i]==0)
1544 truncate=0;
1545
1546 if ((i >= 8) || (In[i] == 0)) {
1547 /*
1548 * They are: Copy up to 31 characters
1549 * to the output string
1550 */
1551 i = 8;
1552 while((--i >= 0) && (*In))
1553 *Out++ = islower(*In) ?
1554 toupper(*In++) :
1555 *In++;
1556 }
1557 }
1558 }
1559 /*
1560 * If there were any uppercase characters in the name we
1561 * take on the case hacking string
1562 */
1563
1564 /* Old behavior for regular GNU-C compiler */
1565 if (!flagseen['+'])
1566 truncate=0;
1567 if ((Case_Hack_Bits != 0)||(truncate==1)) {
1568 if(truncate==0) {
1569 *Out++ = '_';
1570 for(i = 0; i < 6; i++) {
1571 *Out++ = Hex_Table[Case_Hack_Bits & 0xf];
1572 Case_Hack_Bits >>= 4;
1573 }
1574 *Out++ = 'X';
1575 } else {
1576 Out=pnt; /*Cut back to 23 characters maximum */
1577 *Out++ = '_';
1578 for( i=0; i < 7; i++) {
1579 init = result & 0x01f;
1580 if (init < 10)
1581 *Out++='0'+init;
1582 else
1583 *Out++ = 'A'+init-10;
1584 result = result >> 5;
1585 }
1586 }
1587 } /*Case Hack */
1588 /*
1589 * Done
1590 */
1591 *Out = 0;
1592 if( truncate==1 && flagseen['+'] && flagseen['H'])
1593 printf("%s: Symbol %s replaced by %s\n",myname,old_name,new_name);
1594}
1595
1596\f
1597/*
1598 * Scan a symbol name for a psect attribute specification
1599 */
1600VMS_Modify_Psect_Attributes(Name, Attribute_Pointer)
1601char *Name;
1602int *Attribute_Pointer;
1603{
1604 register int i;
1605 register char *cp;
1606 int Negate;
1607 static struct {
1608 char *Name;
1609 int Value;
1610 } Attributes[] = {
1611 {"PIC", GPS$M_PIC},
1612 {"LIB", GPS$M_LIB},
1613 {"OVR", GPS$M_OVR},
1614 {"REL", GPS$M_REL},
1615 {"GBL", GPS$M_GBL},
1616 {"SHR", GPS$M_SHR},
1617 {"EXE", GPS$M_EXE},
1618 {"RD", GPS$M_RD},
1619 {"WRT", GPS$M_WRT},
1620 {"VEC", GPS$M_VEC},
1621 {0, 0}};
1622
1623 /*
1624 * Kill leading "_"
1625 */
1626 if (*Name == '_') Name++;
1627 /*
1628 * Check for a PSECT attribute list
1629 */
1630 if (!HAS_PSECT_ATTRIBUTES(Name)) return; /* If not, return */
1631 /*
1632 * Skip the attribute list indicator
1633 */
1634 Name += PSECT_ATTRIBUTES_STRING_LENGTH;
1635 /*
1636 * Process the attributes ("_" separated, "$" terminated)
1637 */
1638 while(*Name != '$') {
1639 /*
1640 * Assume not negating
1641 */
1642 Negate = 0;
1643 /*
1644 * Check for "NO"
1645 */
1646 if ((Name[0] == 'N') && (Name[1] == 'O')) {
1647 /*
1648 * We are negating (and skip the NO)
1649 */
1650 Negate = 1;
1651 Name += 2;
1652 }
1653 /*
1654 * Find the token delimiter
1655 */
1656 cp = Name;
1657 while(*cp && (*cp != '_') && (*cp != '$')) cp++;
1658 /*
1659 * Look for the token in the attribute list
1660 */
1661 for(i = 0; Attributes[i].Name; i++) {
1662 /*
1663 * If the strings match, set/clear the attr.
1664 */
1665 if (strncmp(Name, Attributes[i].Name, cp - Name) == 0) {
1666 /*
1667 * Set or clear
1668 */
1669 if (Negate)
1670 *Attribute_Pointer &=
1671 ~Attributes[i].Value;
1672 else
1673 *Attribute_Pointer |=
1674 Attributes[i].Value;
1675 /*
1676 * Done
1677 */
1678 break;
1679 }
1680 }
1681 /*
1682 * Now skip the attribute
1683 */
1684 Name = cp;
1685 if (*Name == '_') Name++;
1686 }
1687 /*
1688 * Done
1689 */
1690 return;
1691}
1692
1693\f
1694/*
1695 * Define a psect
1696 */
1697VMS_Psect_Spec(Name, Size, Type)
1698char *Name;
1699int Size;
1700char *Type;
1701{
1702 char Local[32];
1703 int Psect_Attributes;
1704
1705 /*
1706 * We are writing a GSD record
1707 */
1708 Set_VMS_Object_File_Record(OBJ$C_GSD);
1709 /*
1710 * If the buffer is empty we must insert the GSD record type
1711 */
1712 if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD);
1713 /*
1714 * We are writing a PSECT definition subrecord
1715 */
1716 PUT_CHAR(GSD$C_PSC);
1717 /*
1718 * Psects are always LONGWORD aligned
1719 */
1720 PUT_CHAR(2);
1721 /*
1722 * Generate the appropriate PSECT flags given the PSECT type
1723 */
1724 if (strcmp(Type,"COMMON") == 0) {
1725 /*
1726 * Common block psects are: PIC,OVR,REL,GBL,SHR,RD,WRT
1727 */
1728 Psect_Attributes = (GPS$M_PIC|GPS$M_OVR|GPS$M_REL|GPS$M_GBL|
1729 GPS$M_SHR|GPS$M_RD|GPS$M_WRT);
1730 } else if (strcmp(Type,"CONST") == 0) {
1731 /*
1732 * Common block psects are: PIC,OVR,REL,GBL,SHR,RD
1733 */
1734 Psect_Attributes = (GPS$M_PIC|GPS$M_OVR|GPS$M_REL|GPS$M_GBL|
1735 GPS$M_SHR|GPS$M_RD);
1736 } else if (strcmp(Type,"DATA") == 0) {
1737 /*
1738 * The Data psects are PIC,REL,RD,WRT
1739 */
1740 Psect_Attributes =
1741 (GPS$M_PIC|GPS$M_REL|GPS$M_RD|GPS$M_WRT);
1742 } else if (strcmp(Type,"TEXT") == 0) {
1743 /*
1744 * The Text psects are PIC,REL,SHR,EXE,RD
1745 */
1746 Psect_Attributes =
1747 (GPS$M_PIC|GPS$M_REL|GPS$M_SHR|
1748 GPS$M_EXE|GPS$M_RD);
1749 } else {
1750 /*
1751 * Error: Unknown psect type
1752 */
1753 error("Unknown VMS psect type");
1754 }
1755 /*
1756 * Modify the psect attributes according to any attribute string
1757 */
1758 if (HAS_PSECT_ATTRIBUTES(Name))
1759 VMS_Modify_Psect_Attributes(Name,&Psect_Attributes);
1760 /*
1761 * Specify the psect attributes
1762 */
1763 PUT_SHORT(Psect_Attributes);
1764 /*
1765 * Specify the allocation
1766 */
1767 PUT_LONG(Size);
1768 /*
1769 * Finally, the psect name
1770 */
1771 VMS_Case_Hack_Symbol(Name,Local);
1772 PUT_COUNTED_STRING(Local);
1773 /*
1774 * Flush the buffer if it is more than 75% full
1775 */
1776 if (Object_Record_Offset >
1777 (sizeof(Object_Record_Buffer)*3/4))
1778 Flush_VMS_Object_Record_Buffer();
1779}
1780
1781\f
1782/*
1783 * Define a global symbol
1784 */
1785VMS_Global_Symbol_Spec(Name, Psect_Number, Psect_Offset, Defined)
1786char *Name;
1787int Psect_Number;
1788int Psect_Offset;
1789{
1790 char Local[32];
1791
1792 /*
1793 * We are writing a GSD record
1794 */
1795 Set_VMS_Object_File_Record(OBJ$C_GSD);
1796 /*
1797 * If the buffer is empty we must insert the GSD record type
1798 */
1799 if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD);
1800 /*
1801 * We are writing a Global symbol definition subrecord
1802 */
1803 if (Psect_Number <= 255) {
1804 PUT_CHAR(GSD$C_SYM);
1805 } else {
1806 PUT_CHAR(GSD$C_SYMW);
1807 }
1808 /*
1809 * Data type is undefined
1810 */
1811 PUT_CHAR(0);
1812 /*
1813 * Switch on Definition/Reference
1814 */
1815 if (Defined) {
1816 /*
1817 * Definition:
1818 * Flags = "RELOCATABLE" and "DEFINED"
1819 */
1820 PUT_SHORT(GSY$M_DEF|GSY$M_REL);
1821 /*
1822 * Psect Number
1823 */
1824 if (Psect_Number <= 255) {
1825 PUT_CHAR(Psect_Number);
1826 } else {
1827 PUT_SHORT(Psect_Number);
1828 }
1829 /*
1830 * Offset
1831 */
1832 PUT_LONG(Psect_Offset);
1833 } else {
1834 /*
1835 * Reference:
1836 * Flags = "RELOCATABLE"
1837 */
1838 PUT_SHORT(GSY$M_REL);
1839 }
1840 /*
1841 * Finally, the global symbol name
1842 */
1843 VMS_Case_Hack_Symbol(Name,Local);
1844 PUT_COUNTED_STRING(Local);
1845 /*
1846 * Flush the buffer if it is more than 75% full
1847 */
1848 if (Object_Record_Offset >
1849 (sizeof(Object_Record_Buffer)*3/4))
1850 Flush_VMS_Object_Record_Buffer();
1851}
1852
1853\f
1854/*
1855 * Define a procedure entry pt/mask
1856 */
1857VMS_Procedure_Entry_Pt(Name, Psect_Number, Psect_Offset, Entry_Mask)
1858char *Name;
1859int Psect_Number;
1860int Psect_Offset;
1861int Entry_Mask;
1862{
1863 char Local[32];
1864
1865 /*
1866 * We are writing a GSD record
1867 */
1868 Set_VMS_Object_File_Record(OBJ$C_GSD);
1869 /*
1870 * If the buffer is empty we must insert the GSD record type
1871 */
1872 if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_GSD);
1873 /*
1874 * We are writing a Procedure Entry Pt/Mask subrecord
1875 */
1876 if (Psect_Number <= 255) {
1877 PUT_CHAR(GSD$C_EPM);
1878 } else {
1879 PUT_CHAR(GSD$C_EPMW);
1880 }
1881 /*
1882 * Data type is undefined
1883 */
1884 PUT_CHAR(0);
1885 /*
1886 * Flags = "RELOCATABLE" and "DEFINED"
1887 */
1888 PUT_SHORT(GSY$M_DEF|GSY$M_REL);
1889 /*
1890 * Psect Number
1891 */
1892 if (Psect_Number <= 255) {
1893 PUT_CHAR(Psect_Number);
1894 } else {
1895 PUT_SHORT(Psect_Number);
1896 }
1897 /*
1898 * Offset
1899 */
1900 PUT_LONG(Psect_Offset);
1901 /*
1902 * Entry mask
1903 */
1904 PUT_SHORT(Entry_Mask);
1905 /*
1906 * Finally, the global symbol name
1907 */
1908 VMS_Case_Hack_Symbol(Name,Local);
1909 PUT_COUNTED_STRING(Local);
1910 /*
1911 * Flush the buffer if it is more than 75% full
1912 */
1913 if (Object_Record_Offset >
1914 (sizeof(Object_Record_Buffer)*3/4))
1915 Flush_VMS_Object_Record_Buffer();
1916}
1917
1918\f
1919/*
1920 * Set the current location counter to a particular Psect and Offset
1921 */
1922VMS_Set_Psect(Psect_Index, Offset, Record_Type)
1923int Psect_Index;
1924int Offset;
1925int Record_Type;
1926{
1927 /*
1928 * We are writing a "Record_Type" record
1929 */
1930 Set_VMS_Object_File_Record(Record_Type);
1931 /*
1932 * If the buffer is empty we must insert the record type
1933 */
1934 if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
1935 /*
1936 * Stack the Psect base + Longword Offset
1937 */
1938 if (Psect_Index < 255) {
1939 PUT_CHAR(TIR$C_STA_PL);
1940 PUT_CHAR(Psect_Index);
1941 } else {
1942 PUT_CHAR(TIR$C_STA_WPL);
1943 PUT_SHORT(Psect_Index);
1944 }
1945 PUT_LONG(Offset);
1946 /*
1947 * Set relocation base
1948 */
1949 PUT_CHAR(TIR$C_CTL_SETRB);
1950 /*
1951 * Flush the buffer if it is more than 75% full
1952 */
1953 if (Object_Record_Offset >
1954 (sizeof(Object_Record_Buffer)*3/4))
1955 Flush_VMS_Object_Record_Buffer();
1956}
1957
1958/*
1959 * Make a data reference
1960 */
1961VMS_Set_Data(Psect_Index, Offset, Record_Type,Force)
1962int Psect_Index;
1963int Offset;
1964int Record_Type;
1965int Force;
1966{
1967 /*
1968 * We are writing a "Record_Type" record
1969 */
1970 Set_VMS_Object_File_Record(Record_Type);
1971 /*
1972 * If the buffer is empty we must insert the record type
1973 */
1974 if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
1975 /*
1976 * Stack the Psect base + Longword Offset
1977 */
1978 if(Force==1){
1979 if(Psect_Index>127){
1980 PUT_CHAR(TIR$C_STA_WPL);
1981 PUT_SHORT(Psect_Index);
1982 PUT_LONG(Offset);}
1983 else {
1984 PUT_CHAR(TIR$C_STA_PL);
1985 PUT_CHAR(Psect_Index);
1986 PUT_LONG(Offset);}
1987 } else {if(Offset>32767){
1988 PUT_CHAR(TIR$C_STA_WPL);
1989 PUT_SHORT(Psect_Index);
1990 PUT_LONG(Offset);}
1991 else if(Offset>127){
1992 PUT_CHAR(TIR$C_STA_WPW);
1993 PUT_SHORT(Psect_Index);
1994 PUT_SHORT(Offset);}
1995 else{
1996 PUT_CHAR(TIR$C_STA_WPB);
1997 PUT_SHORT(Psect_Index);
1998 PUT_CHAR(Offset);};};
1999 /*
2000 * Set relocation base
2001 */
2002 PUT_CHAR(TIR$C_STO_PIDR);
2003 /*
2004 * Flush the buffer if it is more than 75% full
2005 */
2006 if (Object_Record_Offset >
2007 (sizeof(Object_Record_Buffer)*3/4))
2008 Flush_VMS_Object_Record_Buffer();
2009}
2010
2011/*
2012 * Make a debugger reference to a struct, union or enum.
2013 */
2014VMS_Store_Struct(int Struct_Index)
2015{
2016 /*
2017 * We are writing a "OBJ$C_DBG" record
2018 */
2019 Set_VMS_Object_File_Record(OBJ$C_DBG);
2020 /*
2021 * If the buffer is empty we must insert the record type
2022 */
2023 if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
2024 PUT_CHAR(TIR$C_STA_UW);
2025 PUT_SHORT(Struct_Index);
2026 PUT_CHAR(TIR$C_CTL_STKDL);
2027 PUT_CHAR(TIR$C_STO_L);
2028 /*
2029 * Flush the buffer if it is more than 75% full
2030 */
2031 if (Object_Record_Offset >
2032 (sizeof(Object_Record_Buffer)*3/4))
2033 Flush_VMS_Object_Record_Buffer();
2034}
2035
2036/*
2037 * Make a debugger reference to partially define a struct, union or enum.
2038 */
2039VMS_Def_Struct(int Struct_Index)
2040{
2041 /*
2042 * We are writing a "OBJ$C_DBG" record
2043 */
2044 Set_VMS_Object_File_Record(OBJ$C_DBG);
2045 /*
2046 * If the buffer is empty we must insert the record type
2047 */
2048 if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
2049 PUT_CHAR(TIR$C_STA_UW);
2050 PUT_SHORT(Struct_Index);
2051 PUT_CHAR(TIR$C_CTL_DFLOC);
2052 /*
2053 * Flush the buffer if it is more than 75% full
2054 */
2055 if (Object_Record_Offset >
2056 (sizeof(Object_Record_Buffer)*3/4))
2057 Flush_VMS_Object_Record_Buffer();
2058}
2059
2060VMS_Set_Struct(int Struct_Index)
2061{/* see previous functions for comments */
2062 Set_VMS_Object_File_Record(OBJ$C_DBG);
2063 if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
2064 PUT_CHAR(TIR$C_STA_UW);
2065 PUT_SHORT(Struct_Index);
2066 PUT_CHAR(TIR$C_CTL_STLOC);
2067 if (Object_Record_Offset >
2068 (sizeof(Object_Record_Buffer)*3/4))
2069 Flush_VMS_Object_Record_Buffer();
2070}
2071\f
2072/*
2073 * Store immediate data in current Psect
2074 */
2075VMS_Store_Immediate_Data(Pointer, Size, Record_Type)
2076register char *Pointer;
2077int Size;
2078int Record_Type;
2079{
2080 register int i;
2081
2082 /*
2083 * We are writing a "Record_Type" record
2084 */
2085 Set_VMS_Object_File_Record(Record_Type);
2086 /*
2087 * We can only store 128 bytes at a time
2088 */
2089 while(Size > 0) {
2090 /*
2091 * Store a maximum of 128 bytes
2092 */
2093 i = (Size > 128) ? 128 : Size;
2094 Size -= i;
2095 /*
2096 * If we cannot accommodate this record, flush the
2097 * buffer.
2098 */
2099 if ((Object_Record_Offset + i + 1) >=
2100 sizeof(Object_Record_Buffer))
2101 Flush_VMS_Object_Record_Buffer();
2102 /*
2103 * If the buffer is empty we must insert record type
2104 */
2105 if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
2106 /*
2107 * Store the count
2108 */
2109 PUT_CHAR(-i & 0xff);
2110 /*
2111 * Store the data
2112 */
2113 while(--i >= 0) PUT_CHAR(*Pointer++);
2114 /*
2115 * Flush the buffer if it is more than 75% full
2116 */
2117 if (Object_Record_Offset >
2118 (sizeof(Object_Record_Buffer)*3/4))
2119 Flush_VMS_Object_Record_Buffer();
2120 }
2121}
2122
2123\f
2124/*
2125 * Store repeated immediate data in current Psect
2126 */
2127VMS_Store_Repeated_Data(Repeat_Count,Pointer, Size, Record_Type)
2128int Repeat_Count;
2129register char *Pointer;
2130int Size;
2131int Record_Type;
2132{
2133
2134 /*
2135 * Ignore zero bytes/words/longwords
2136 */
2137 if ((Size == sizeof(char)) && (*Pointer == 0)) return;
2138 if ((Size == sizeof(short)) && (*(short *)Pointer == 0)) return;
2139 if ((Size == sizeof(long)) && (*(long *)Pointer == 0)) return;
2140 /*
2141 * If the data is too big for a TIR$C_STO_RIVB sub-record
2142 * then we do it manually
2143 */
2144 if (Size > 255) {
2145 while(--Repeat_Count >= 0)
2146 VMS_Store_Immediate_Data(Pointer,Size,Record_Type);
2147 return;
2148 }
2149 /*
2150 * We are writing a "Record_Type" record
2151 */
2152 Set_VMS_Object_File_Record(Record_Type);
2153 /*
2154 * If the buffer is empty we must insert record type
2155 */
2156 if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
2157 /*
2158 * Stack the repeat count
2159 */
2160 PUT_CHAR(TIR$C_STA_LW);
2161 PUT_LONG(Repeat_Count);
2162 /*
2163 * And now the command and its data
2164 */
2165 PUT_CHAR(TIR$C_STO_RIVB);
2166 PUT_CHAR(Size);
2167 while(--Size >= 0) PUT_CHAR(*Pointer++);
2168 /*
2169 * Flush the buffer if it is more than 75% full
2170 */
2171 if (Object_Record_Offset >
2172 (sizeof(Object_Record_Buffer)*3/4))
2173 Flush_VMS_Object_Record_Buffer();
2174}
2175
2176\f
2177/*
2178 * Store a Position Independent Reference
2179 */
2180VMS_Store_PIC_Symbol_Reference(Symbol, Offset, PC_Relative,
2181 Psect, Psect_Offset, Record_Type)
2182struct symbol *Symbol;
2183int Offset;
2184int PC_Relative;
2185int Psect;
2186int Psect_Offset;
2187int Record_Type;
2188{
2189 register struct VMS_Symbol *vsp =
2190 (struct VMS_Symbol *)(Symbol->sy_number);
2191 char Local[32];
2192
2193 /*
2194 * We are writing a "Record_Type" record
2195 */
2196 Set_VMS_Object_File_Record(Record_Type);
2197 /*
2198 * If the buffer is empty we must insert record type
2199 */
2200 if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
2201 /*
2202 * Set to the appropriate offset in the Psect
2203 */
2204 if (PC_Relative) {
2205 /*
2206 * For a Code reference we need to fix the operand
2207 * specifier as well (so back up 1 byte)
2208 */
2209 VMS_Set_Psect(Psect, Psect_Offset - 1, Record_Type);
2210 } else {
2211 /*
2212 * For a Data reference we just store HERE
2213 */
2214 VMS_Set_Psect(Psect, Psect_Offset, Record_Type);
2215 }
2216 /*
2217 * Make sure we are still generating a "Record Type" record
2218 */
2219 if (Object_Record_Offset == 0) PUT_CHAR(Record_Type);
2220 /*
2221 * Dispatch on symbol type (so we can stack its value)
2222 */
2223 switch(Symbol->sy_nlist.n_type) {
2224 /*
2225 * Global symbol
2226 */
2227#ifdef NOT_VAX_11_C_COMPATIBLE
2228 case N_UNDF | N_EXT:
2229 case N_DATA | N_EXT:
2230#endif NOT_VAX_11_C_COMPATIBLE
2231 case N_UNDF:
2232 case N_TEXT | N_EXT:
2233 /*
2234 * Get the symbol name (case hacked)
2235 */
2236 VMS_Case_Hack_Symbol(Symbol->sy_nlist.n_un.n_name,Local);
2237 /*
2238 * Stack the global symbol value
2239 */
2240 PUT_CHAR(TIR$C_STA_GBL);
2241 PUT_COUNTED_STRING(Local);
2242 if (Offset) {
2243 /*
2244 * Stack the longword offset
2245 */
2246 PUT_CHAR(TIR$C_STA_LW);
2247 PUT_LONG(Offset);
2248 /*
2249 * Add the two, leaving the result on the stack
2250 */
2251 PUT_CHAR(TIR$C_OPR_ADD);
2252 }
2253 break;
2254 /*
2255 * Uninitialized local data
2256 */
2257 case N_BSS:
2258 /*
2259 * Stack the Psect (+offset)
2260 */
2261 if (vsp->Psect_Index < 255) {
2262 PUT_CHAR(TIR$C_STA_PL);
2263 PUT_CHAR(vsp->Psect_Index);
2264 } else {
2265 PUT_CHAR(TIR$C_STA_WPL);
2266 PUT_SHORT(vsp->Psect_Index);
2267 }
2268 PUT_LONG(vsp->Psect_Offset + Offset);
2269 break;
2270 /*
2271 * Local text
2272 */
2273 case N_TEXT:
2274 /*
2275 * Stack the Psect (+offset)
2276 */
2277 if (vsp->Psect_Index < 255) {
2278 PUT_CHAR(TIR$C_STA_PL);
2279 PUT_CHAR(vsp->Psect_Index);
2280 } else {
2281 PUT_CHAR(TIR$C_STA_WPL);
2282 PUT_SHORT(vsp->Psect_Index);
2283 }
2284 PUT_LONG(Symbol->sy_nlist.n_value);
2285 break;
2286 /*
2287 * Initialized local or global data
2288 */
2289 case N_DATA:
2290#ifndef NOT_VAX_11_C_COMPATIBLE
2291 case N_UNDF | N_EXT:
2292 case N_DATA | N_EXT:
2293#endif NOT_VAX_11_C_COMPATIBLE
2294 /*
2295 * Stack the Psect (+offset)
2296 */
2297 if (vsp->Psect_Index < 255) {
2298 PUT_CHAR(TIR$C_STA_PL);
2299 PUT_CHAR(vsp->Psect_Index);
2300 } else {
2301 PUT_CHAR(TIR$C_STA_WPL);
2302 PUT_SHORT(vsp->Psect_Index);
2303 }
2304 PUT_LONG(vsp->Psect_Offset + Offset);
2305 break;
2306 }
2307 /*
2308 * Store either a code or data reference
2309 */
2310 PUT_CHAR(PC_Relative ? TIR$C_STO_PICR : TIR$C_STO_PIDR);
2311 /*
2312 * Flush the buffer if it is more than 75% full
2313 */
2314 if (Object_Record_Offset >
2315 (sizeof(Object_Record_Buffer)*3/4))
2316 Flush_VMS_Object_Record_Buffer();
2317}
2318
2319\f
2320/*
2321 * Check in the text area for an indirect pc-relative reference
2322 * and fix it up with addressing mode 0xff [PC indirect]
2323 *
2324 * THIS SHOULD BE REPLACED BY THE USE OF TIR$C_STO_PIRR IN THE
2325 * PIC CODE GENERATING FIXUP ROUTINE.
2326 */
2327VMS_Fix_Indirect_Reference(Text_Psect, Offset, fragP, text_frag_root)
2328int Text_Psect;
2329int Offset;
2330register fragS *fragP;
2331struct frag *text_frag_root;
2332{
2333 /*
2334 * The addressing mode byte is 1 byte before the address
2335 */
2336 Offset--;
2337 /*
2338 * Is it in THIS frag??
2339 */
2340 if ((Offset < fragP->fr_address) ||
2341 (Offset >= (fragP->fr_address + fragP->fr_fix))) {
2342 /*
2343 * We need to search for the fragment containing this
2344 * Offset
2345 */
2346 for(fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
2347 if ((Offset >= fragP->fr_address) &&
2348 (Offset < (fragP->fr_address + fragP->fr_fix)))
2349 break;
2350 }
2351 /*
2352 * If we couldn't find the frag, things are BAD!!
2353 */
2354 if (fragP == 0)
2355 error("Couldn't find fixup fragment when checking for indirect reference");
2356 }
2357 /*
2358 * Check for indirect PC relative addressing mode
2359 */
2360 if (fragP->fr_literal[Offset - fragP->fr_address] == (char)0xff) {
2361 static char Address_Mode = 0xff;
2362
2363 /*
2364 * Yes: Store the indirect mode back into the image
2365 * to fix up the damage done by STO_PICR
2366 */
2367 VMS_Set_Psect(Text_Psect,Offset,OBJ$C_TIR);
2368 VMS_Store_Immediate_Data(&Address_Mode,1,OBJ$C_TIR);
2369 }
2370}
2371
2372\f
2373/*
2374 * Write the Traceback Module Begin record
2375 */
2376VMS_TBT_Module_Begin()
2377{
2378 register char *cp,*cp1;
2379 int Size;
2380 char Module_Name[256];
2381 char Local[256];
2382
2383 /*
2384 * Get module name (the FILENAME part of the object file)
2385 */
2386 cp = out_file_name;
2387 cp1 = Module_Name;
2388 while(*cp) {
2389 if ((*cp == ']') || (*cp == '>') ||
2390 (*cp == ':') || (*cp == '/')) {
2391 cp1 = Module_Name;
2392 cp++;
2393 continue;
2394 }
2395 *cp1++ = islower(*cp) ? toupper(*cp++) : *cp++;
2396 }
2397 *cp1 = 0;
2398 /*
2399 * Limit it to 31 characters
2400 */
2401 while(--cp1 >= Module_Name)
2402 if (*cp1 == '.') *cp1 = 0;
2403 if (strlen(Module_Name) > 31) {
2404 if(flagseen['+'])
2405 printf("%s: Module name truncated: %s\n",myname, Module_Name);
2406 Module_Name[31] = 0;
2407 }
2408 /*
2409 * Arrange to store the data locally (leave room for size byte)
2410 */
2411 cp = Local+1;
2412 /*
2413 * Begin module
2414 */
2415 *cp++ = DST$C_MODBEG;
2416 /*
2417 * Unused
2418 */
2419 *cp++ = 0;
2420 /*
2421 * Language type == "C"
2422 */
2423 *(long *)cp = DST$C_C;
2424 cp += sizeof(long);
2425 /*
2426 * Store the module name
2427 */
2428 *cp++ = strlen(Module_Name);
2429 cp1 = Module_Name;
2430 while(*cp1) *cp++ = *cp1++;
2431 /*
2432 * Now we can store the record size
2433 */
2434 Size = (cp - Local);
2435 Local[0] = Size-1;
2436 /*
2437 * Put it into the object record
2438 */
2439 VMS_Store_Immediate_Data(Local, Size, OBJ$C_TBT);
2440}
2441
2442\f
2443/*
2444 * Write the Traceback Module End record
2445*/
2446VMS_TBT_Module_End()
2447{
2448 char Local[2];
2449
2450 /*
2451 * End module
2452 */
2453 Local[0] = 1;
2454 Local[1] = DST$C_MODEND;
2455 /*
2456 * Put it into the object record
2457 */
2458 VMS_Store_Immediate_Data(Local, 2, OBJ$C_TBT);
2459}
2460
2461\f
2462/*
2463 * Write the Traceback Routine Begin record
2464 */
2465VMS_TBT_Routine_Begin(symbolP, Psect)
2466struct symbol *symbolP;
2467int Psect;
2468{
2469 register char *cp,*cp1;
2470 char *Name;
2471 int Offset;
2472 int Size;
2473 char Local[512];
2474
2475 /*
2476 * Strip the leading "_" from the name
2477 */
2478 Name = symbolP->sy_nlist.n_un.n_name;
2479 if (*Name == '_') Name++;
2480 /*
2481 * Get the text psect offset
2482 */
2483 Offset = symbolP->sy_nlist.n_value;
2484 /*
2485 * Calculate the record size
2486 */
2487 Size = 1+1+4+1+strlen(Name);
2488 /*
2489 * Record Size
2490 */
2491 Local[0] = Size;
2492 /*
2493 * Begin Routine
2494 */
2495 Local[1] = DST$C_RTNBEG;
2496 /*
2497 * Uses CallS/CallG
2498 */
2499 Local[2] = 0;
2500 /*
2501 * Store the data so far
2502 */
2503 VMS_Store_Immediate_Data(Local, 3, OBJ$C_TBT);
2504 /*
2505 * Make sure we are still generating a OBJ$C_TBT record
2506 */
2507 if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_TBT);
2508 /*
2509 * Now get the symbol address
2510 */
2511 PUT_CHAR(TIR$C_STA_WPL);
2512 PUT_SHORT(Psect);
2513 PUT_LONG(Offset);
2514 /*
2515 * Store the data reference
2516 */
2517 PUT_CHAR(TIR$C_STO_PIDR);
2518 /*
2519 * Store the counted string as data
2520 */
2521 cp = Local;
2522 cp1 = Name;
2523 Size = strlen(cp1) + 1;
2524 *cp++ = Size - 1;
2525 while(*cp1) *cp++ = *cp1++;
2526 VMS_Store_Immediate_Data(Local, Size, OBJ$C_TBT);
2527}
2528
2529\f
2530/*
2531 * Write the Traceback Routine End record
2532 * We *must* search the symbol table to find the next routine, since
2533 * the assember has a way of reassembling the symbol table OUT OF ORDER
2534 * Thus the next routine in the symbol list is not necessarily the
2535 * next one in memory. For debugging to work correctly we must know the
2536 * size of the routine.
2537 */
2538VMS_TBT_Routine_End(Max_Size,sp)
2539int Max_Size;
2540symbolS *sp;
2541{
2542 symbolS *symbolP;
2543 int Size = 0x7fffffff;
2544 char Local[16];
2545
2546
2547 for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next) {
2548 if ((symbolP->sy_nlist.n_type & ~N_EXT) == N_TEXT) {
2549 if (symbolP->sy_nlist.n_un.n_name[0] == 'L') continue;
2550 if((symbolP->sy_nlist.n_value > sp->sy_nlist.n_value) &&
2551 (symbolP->sy_nlist.n_value < Size ))
2552 Size = symbolP->sy_nlist.n_value;
2553 /* check if gcc_compiled. has size of zero */
2554 if((symbolP->sy_nlist.n_value == sp->sy_nlist.n_value) &&
2555 sp != symbolP &&
2556 !strcmp(sp->sy_nlist.n_un.n_name,"gcc_compiled."))
2557 Size = symbolP->sy_nlist.n_value;
2558
2559 };
2560 };
2561 if(Size == 0x7fffffff) Size = Max_Size;
2562 Size -= sp->sy_nlist.n_value; /* and get the size of the routine */
2563 /*
2564 * Record Size
2565 */
2566 Local[0] = 6;
2567 /*
2568 * End of Routine
2569 */
2570 Local[1] = DST$C_RTNEND;
2571 /*
2572 * Unused
2573 */
2574 Local[2] = 0;
2575 /*
2576 * Size of routine
2577 */
2578 *((long *)(Local+3)) = Size;
2579 /*
2580 * Store the record
2581 */
2582 VMS_Store_Immediate_Data(Local,7, OBJ$C_TBT);
2583}
2584/*
2585 * Write the Traceback Block End record
2586 */
2587VMS_TBT_Block_Begin(symbolP, Psect, Name)
2588struct symbol *symbolP;
2589int Psect;
2590char* Name;
2591{
2592 register char *cp,*cp1;
2593 int Offset;
2594 int Size;
2595 char Local[512];
2596 /*
2597 * Begin block
2598 */
2599 Size = 1+1+4+1+strlen(Name);
2600 /*
2601 * Record Size
2602 */
2603 Local[0] = Size;
2604 /*
2605 * Begin Block - We simulate with a phony routine
2606 */
2607 Local[1] = DST$C_BLKBEG;
2608 /*
2609 * Uses CallS/CallG
2610 */
2611 Local[2] = 0;
2612 /*
2613 * Store the data so far
2614 */
2615 VMS_Store_Immediate_Data(Local, 3, OBJ$C_DBG);
2616 /*
2617 * Make sure we are still generating a OBJ$C_DBG record
2618 */
2619 if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_DBG);
2620 /*
2621 * Now get the symbol address
2622 */
2623 PUT_CHAR(TIR$C_STA_WPL);
2624 PUT_SHORT(Psect);
2625 /*
2626 * Get the text psect offset
2627 */
2628 Offset = symbolP->sy_nlist.n_value;
2629 PUT_LONG(Offset);
2630 /*
2631 * Store the data reference
2632 */
2633 PUT_CHAR(TIR$C_STO_PIDR);
2634 /*
2635 * Store the counted string as data
2636 */
2637 cp = Local;
2638 cp1 = Name;
2639 Size = strlen(cp1) + 1;
2640 *cp++ = Size - 1;
2641 while(*cp1) *cp++ = *cp1++;
2642 VMS_Store_Immediate_Data(Local, Size, OBJ$C_DBG);
2643}
2644
2645\f
2646/*
2647 * Write the Traceback Block End record
2648 */
2649VMS_TBT_Block_End(int Size)
2650{
2651 char Local[16];
2652
2653 /*
2654 * End block - simulate with a phony end routine
2655 */
2656 Local[0] = 6;
2657 Local[1] = DST$C_BLKEND;
2658 *((long *)(Local+3)) = Size;
2659 /*
2660 * Unused
2661 */
2662 Local[2] = 0;
2663 VMS_Store_Immediate_Data(Local,7, OBJ$C_DBG);
2664}
2665
2666
2667\f
2668/*
2669 * Write a Line number / PC correlation record
2670 */
2671VMS_TBT_Line_PC_Correlation(Line_Number, Offset, Psect, Do_Delta)
2672int Line_Number;
2673int Offset;
2674int Psect;
2675int Do_Delta;
2676{
2677 register char *cp;
2678 char Local[64];
2679
2680 /*
2681* If not delta, set our PC/Line number correlation
2682*/
2683 if (Do_Delta == 0) {
2684 /*
2685 * Size
2686 */
2687 Local[0] = 1+1+2+1+4;
2688 /*
2689 * Line Number/PC correlation
2690 */
2691 Local[1] = DST$C_LINE_NUM;
2692 /*
2693 * Set Line number
2694 */
2695 Local[2] = DST$C_SET_LINE_NUM;
2696 *((unsigned short *)(Local+3)) = Line_Number-1;
2697 /*
2698 * Set PC
2699 */
2700 Local[5] = DST$C_SET_ABS_PC;
2701 VMS_Store_Immediate_Data(Local, 6, OBJ$C_TBT);
2702 /*
2703 * Make sure we are still generating a OBJ$C_TBT record
2704 */
2705 if (Object_Record_Offset == 0) PUT_CHAR(OBJ$C_TBT);
2706 if (Psect < 255) {
2707 PUT_CHAR(TIR$C_STA_PL);
2708 PUT_CHAR(Psect);
2709 } else {
2710 PUT_CHAR(TIR$C_STA_WPL);
2711 PUT_SHORT(Psect);
2712 }
2713 PUT_LONG(Offset);
2714 PUT_CHAR(TIR$C_STO_PIDR);
2715 /*
2716 * Do a PC offset of 0 to register the line number
2717 */
2718 Local[0] = 2;
2719 Local[1] = DST$C_LINE_NUM;
2720 Local[2] = 0; /* Increment PC by 0 and register line # */
2721 VMS_Store_Immediate_Data(Local, 3, OBJ$C_TBT);
2722 } else {
2723 /*
2724 * If Delta is negative, terminate the line numbers
2725 */
2726 if (Do_Delta < 0) {
2727 Local[0] = 1+1+4;
2728 Local[1] = DST$C_LINE_NUM;
2729 Local[2] = DST$C_TERM_L;
2730 *((long *)(Local+3)) = Offset;
2731 VMS_Store_Immediate_Data(Local, 7, OBJ$C_TBT);
2732 /*
2733 * Done
2734 */
2735 return;
2736 }
2737 /*
2738 * Do a PC/Line delta
2739 */
2740 cp = Local+1;
2741 *cp++ = DST$C_LINE_NUM;
2742 if (Line_Number > 1) {
2743 /*
2744 * We need to increment the line number
2745 */
2746 if (Line_Number-1 <= 255) {
2747 *cp++ = DST$C_INCR_LINUM;
2748 *cp++ = Line_Number-1;
2749 } else {
2750 *cp++ = DST$C_INCR_LINUM_W;
2751 *(short *)cp = Line_Number-1;
2752 cp += sizeof(short);
2753 }
2754 }
2755 /*
2756 * Increment the PC
2757 */
2758 if (Offset <= 128) {
2759 *cp++ = -Offset;
2760 } else {
2761 if (Offset < 0x10000) {
2762 *cp++ = DST$C_DELTA_PC_W;
2763 *(short *)cp = Offset;
2764 cp += sizeof(short);
2765 } else {
2766 *cp++ = DST$C_DELTA_PC_L;
2767 *(long *)cp = Offset;
2768 cp += sizeof(long);
2769 }
2770 }
2771 Local[0] = cp - (Local+1);
2772 VMS_Store_Immediate_Data(Local,cp - Local, OBJ$C_TBT);
2773 }
2774}
2775
2776\f
2777/*
2778 * Describe a source file to the debugger
2779 */
2780VMS_TBT_Source_File(Filename, ID_Number)
2781char *Filename;
2782int ID_Number;
2783{
2784 register char *cp,*cp1;
2785 int Status,i;
2786 char Local[512];
2787 static struct FAB Fab;
2788 static struct NAM Nam;
2789 static struct XABDAT Date_Xab;
2790 static struct XABFHC File_Header_Xab;
2791 char Es_String[255],Rs_String[255];
2792
2793 /*
2794 * Setup the Fab
2795 */
2796 Fab.fab$b_bid = FAB$C_BID;
2797 Fab.fab$b_bln = sizeof(Fab);
2798 Fab.fab$l_nam = (&Nam);
2799 Fab.fab$l_xab = (struct XAB *)&Date_Xab;
2800 /*
2801 * Setup the Nam block so we can find out the FULL name
2802 * of the source file.
2803 */
2804 Nam.nam$b_bid = NAM$C_BID;
2805 Nam.nam$b_bln = sizeof(Nam);
2806 Nam.nam$l_rsa = Rs_String;
2807 Nam.nam$b_rss = sizeof(Rs_String);
2808 Nam.nam$l_esa = Es_String;
2809 Nam.nam$b_ess = sizeof(Es_String);
2810 /*
2811 * Setup the Date and File Header Xabs
2812 */
2813 Date_Xab.xab$b_cod = XAB$C_DAT;
2814 Date_Xab.xab$b_bln = sizeof(Date_Xab);
2815 Date_Xab.xab$l_nxt = (char *)&File_Header_Xab;
2816 File_Header_Xab.xab$b_cod = XAB$C_FHC;
2817 File_Header_Xab.xab$b_bln = sizeof(File_Header_Xab);
2818/* ((struct XAB *)&Date_Xab)->xab$b_cod = XAB$C_DAT; */
2819/* ((struct XAB *)&Date_Xab)->xab$b_bln = sizeof(Date_Xab); */
2820/* ((struct XAB *)&Date_Xab)->xab$l_nxt = (struct XAB *)&File_Header_Xab; */
2821/* ((struct XAB *)&File_Header_Xab)->xab$b_cod = XAB$C_FHC; */
2822/* ((struct XAB *)&File_Header_Xab)->xab$b_bln = sizeof(File_Header_Xab); */
2823 /*
2824 * Get the file information
2825 */
2826 Fab.fab$l_fna = Filename;
2827 Fab.fab$b_fns = strlen(Filename);
2828 Status = sys$open(&Fab);
2829 if (!(Status & 1)) {
2830 printf("gas: Couldn't find source file \"%s\", Error = %%X%x\n",
2831 Filename, Status);
2832 return(0);
2833 }
2834 sys$close(&Fab);
2835 /*
2836 * Calculate the size of the resultant string
2837 */
2838 i = Nam.nam$b_rsl;
2839 /*
2840 * Size of record
2841 */
2842 Local[0] = 1+1+1+1+1+2+8+4+2+1+1+i+1;
2843 /*
2844 * Source declaration
2845 */
2846 Local[1] = DST$C_SOURCE;
2847 /*
2848 * Make formfeeds count as source records
2849 */
2850 Local[2] = DST$C_SRC_FORMFEED;
2851 /*
2852 * Declare source file
2853 */
2854 Local[3] = DST$C_SRC_DECLFILE;
2855 Local[4] = 1+2+8+4+2+1+1+i+1;
2856 cp = Local+5;
2857 /*
2858 * Flags
2859 */
2860 *cp++ = 0;
2861 /*
2862 * File ID
2863 */
2864 *(short *)cp = ID_Number;
2865 cp += sizeof(short);
2866 /*
2867 * Creation Date
2868 */
2869 *(long *)cp = ((long *) &Date_Xab.xab$q_cdt)[0];
2870 cp += sizeof(long);
2871 *(long *)cp = ((long *) &Date_Xab.xab$q_cdt)[1];
2872 cp += sizeof(long);
2873 /*
2874 * End of file block
2875 */
2876 *(long *)cp = File_Header_Xab.xab$l_ebk;
2877 cp += sizeof(long);
2878 /*
2879 * First free byte
2880 */
2881 *(short *)cp = File_Header_Xab.xab$w_ffb;
2882 cp += sizeof(short);
2883 /*
2884 * Record format
2885 */
2886 *cp++ = File_Header_Xab.xab$b_rfo;
2887 /*
2888 * Filename
2889 */
2890 *cp++ = i;
2891 cp1 = Rs_String;
2892 while(--i >= 0) *cp++ = *cp1++;
2893 /*
2894 * Library module name (none)
2895 */
2896 *cp++ = 0;
2897 /*
2898 * Done
2899 */
2900 VMS_Store_Immediate_Data(Local,cp - Local, OBJ$C_TBT);
2901}
2902
2903\f
2904/*
2905 * Give the number of source lines to the debugger
2906 */
2907VMS_TBT_Source_Lines(ID_Number,Starting_Line_Number,Number_Of_Lines)
2908int ID_Number;
2909int Starting_Line_Number;
2910int Number_Of_Lines;
2911{
2912 char *cp,*cp1;
2913 char Local[16];
2914
2915 /*
2916 * Size of record
2917 */
2918 Local[0] = 1+1+2+1+4+1+2;
2919 /*
2920 * Source declaration
2921 */
2922 Local[1] = DST$C_SOURCE;
2923 /*
2924 * Set Source File
2925 */
2926 cp = Local+2;
2927 *cp++ = DST$C_SRC_SETFILE;
2928 /*
2929 * File ID Number
2930 */
2931 *(short *)cp = ID_Number;
2932 cp += sizeof(short);
2933 /*
2934 * Set record number
2935 */
2936 *cp++ = DST$C_SRC_SETREC_L;
2937 *(long *)cp = Starting_Line_Number;
2938 cp += sizeof(long);
2939 /*
2940 * Define lines
2941 */
2942 *cp++ = DST$C_SRC_DEFLINES_W;
2943 *(short *)cp = Number_Of_Lines;
2944 cp += sizeof(short);
2945 /*
2946 * Done
2947 */
2948 VMS_Store_Immediate_Data(Local, cp-Local, OBJ$C_TBT);
2949}
2950
2951\f
2952/*
2953 * Given the pointer to a symbol we calculate how big the data at the
2954 * symbol is. We do this by looking for the next symbol (local or
2955 * global) which will indicate the start of another datum.
2956 */
2957int VMS_Initialized_Data_Size(sp, End_Of_Data)
2958register struct symbol *sp;
2959int End_Of_Data;
2960{
2961 register struct symbol *sp1,*Next_Symbol;
2962
2963 /*
2964 * Find the next symbol
2965 * it delimits this datum
2966 */
2967 Next_Symbol = 0;
2968 for (sp1 = symbol_rootP; sp1; sp1 = sp1->sy_next) {
2969 /*
2970 * The data type must match
2971 */
2972 if ((sp1->sy_nlist.n_type & ~N_EXT) != N_DATA) continue;
2973 /*
2974 * The symbol must be AFTER this symbol
2975 */
2976 if (sp1->sy_nlist.n_value <= sp->sy_nlist.n_value) continue;
2977 /*
2978 * We ignore THIS symbol
2979 */
2980 if (sp1 == sp) continue;
2981 /*
2982 * If there is already a candidate selected for the
2983 * next symbol, see if we are a better candidate
2984 */
2985 if (Next_Symbol) {
2986 /*
2987 * We are a better candidate if we are "closer"
2988 * to the symbol
2989 */
2990 if (sp1->sy_nlist.n_value >
2991 Next_Symbol->sy_nlist.n_value)
2992 continue;
2993 /*
2994 * Win: Make this the candidate
2995 */
2996 Next_Symbol = sp1;
2997 } else {
2998 /*
2999 * This is the 1st candidate
3000 */
3001 Next_Symbol = sp1;
3002 }
3003 }
3004 /*
3005 * Calculate its size
3006 */
3007 return(Next_Symbol ?
3008 (Next_Symbol->sy_nlist.n_value -
3009 sp->sy_nlist.n_value) :
3010 (End_Of_Data - sp->sy_nlist.n_value));
3011}
3012
3013\f
3014
3015/* this routine locates a file in the list of files. If an entry does not
3016 * exist, one is created. For include files, a new entry is always created
3017 * such that inline functions can be properly debugged */
3018struct input_file *
3019find_file(sp)
3020symbolS * sp;
3021{
3022 struct input_file * same_file;
3023 struct input_file * fpnt;
3024 same_file = (struct input_file*) NULL;
3025 for(fpnt = file_root; fpnt; fpnt = fpnt->next){
3026 if(fpnt == (struct input_file*) NULL) break;
3027 if(fpnt->spnt == sp) return fpnt;
3028 };
3029 for(fpnt = file_root; fpnt; fpnt = fpnt->next){
3030 if(fpnt == (struct input_file*) NULL) break;
3031 if (strcmp(sp->sy_nlist.n_un.n_name,fpnt->name) == 0){
3032 if(fpnt->flag == 1)return fpnt;
3033 same_file = fpnt;
3034 break;
3035 };
3036 };
3037 fpnt = (struct input_file*) malloc(sizeof(struct input_file));
3038 if(file_root == (struct input_file*) NULL) file_root = fpnt;
3039 else {
3040 struct input_file * fpnt1;
3041 for(fpnt1 = file_root; fpnt1->next; fpnt1 = fpnt1->next);
3042 fpnt1->next = fpnt;
3043 };
3044 fpnt->next = (struct input_file*) NULL;
3045 fpnt->name = sp->sy_nlist.n_un.n_name;
3046 fpnt->min_line = 0x7fffffff;
3047 fpnt->max_line = 0;
3048 fpnt->offset = 0;
3049 fpnt->flag = 0;
3050 fpnt->file_number = 0;
3051 fpnt->spnt = sp;
3052 fpnt->same_file_fpnt = same_file;
3053 return fpnt;
3054}
3055
3056\f
3057/*
3058 * This is a hacked _doprnt() for VAX-11 "C". It understands that
3059 * it is ONLY called by as_fatal(Format, Args) with a pointer to the
3060 * "Args" argument. From this we can make it all work right!
3061 */
3062#ifndef eunice
3063_doprnt(Format, a, f)
3064char *Format;
3065FILE *f;
3066char **a;
3067{
3068 int Nargs = ((int *)a)[-2]; /* This understands as_fatal() */
3069
3070 switch(Nargs) {
3071 default: fprintf(f,"_doprnt error on \"%s\"!!",Format); break;
3072 case 1: fprintf(f,Format); break;
3073 case 2: fprintf(f,Format,a[0]); break;
3074 case 3: fprintf(f,Format,a[0],a[1]); break;
3075 case 4: fprintf(f,Format,a[0],a[1],a[2]); break;
3076 case 5: fprintf(f,Format,a[0],a[1],a[2],a[3]); break;
3077 case 6: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4]); break;
3078 case 7: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5]); break;
3079 case 8: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6]); break;
3080 case 9: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]); break;
3081 case 10: fprintf(f,Format,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]); break;
3082 }
3083}
3084
3085#endif /* eunice */
3086
3087#endif /* VMS */