xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/vmsdbgout.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* Output VMS debug format symbol table information from GCC.
2    Copyright (C) 1987-2015 Free Software Foundation, Inc.
3    Contributed by Douglas B. Rupp (rupp@gnat.com).
4    Updated by Bernard W. Giroud (bgiroud@users.sourceforge.net).
5 
6 This file is part of GCC.
7 
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
12 
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3.  If not see
20 <http://www.gnu.org/licenses/>.  */
21 
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 
27 #ifdef VMS_DEBUGGING_INFO
28 #include "hash-set.h"
29 #include "machmode.h"
30 #include "vec.h"
31 #include "double-int.h"
32 #include "input.h"
33 #include "alias.h"
34 #include "symtab.h"
35 #include "wide-int.h"
36 #include "inchash.h"
37 #include "tree.h"
38 #include "varasm.h"
39 #include "version.h"
40 #include "flags.h"
41 #include "rtl.h"
42 #include "output.h"
43 #include "vmsdbg.h"
44 #include "debug.h"
45 #include "langhooks.h"
46 #include "hard-reg-set.h"
47 #include "input.h"
48 #include "function.h"
49 #include "target.h"
50 
51 /* Difference in seconds between the VMS Epoch and the Unix Epoch */
52 static const long long vms_epoch_offset = 3506716800ll;
53 
54 int vms_file_stats_name (const char *, long long *, long *, char *, int *);
55 
56 /* NOTE: In the comments in this file, many references are made to "Debug
57    Symbol Table".  This term is abbreviated as `DST' throughout the remainder
58    of this file.  */
59 
60 typedef struct dst_line_info_struct *dst_line_info_ref;
61 
62 /* Each entry in the line_info_table maintains the file and
63    line number associated with the label generated for that
64    entry.  The label gives the PC value associated with
65    the line number entry.  */
66 typedef struct dst_line_info_struct
67 {
68   unsigned long dst_file_num;
69   unsigned long dst_line_num;
70 }
71 dst_line_info_entry;
72 
73 typedef struct dst_file_info_struct *dst_file_info_ref;
74 
75 typedef struct dst_file_info_struct
76 {
77   char *file_name;
78   unsigned int max_line;
79   unsigned int listing_line_start;
80   long long cdt;
81   long ebk;
82   short ffb;
83   char rfo;
84 }
85 dst_file_info_entry;
86 
87 /* Maximum size (in bytes) of an artificially generated label.  */
88 #define MAX_ARTIFICIAL_LABEL_BYTES	30
89 
90 /* Make sure we know the sizes of the various types debug can describe. These
91    are only defaults.  If the sizes are different for your target, you should
92    override these values by defining the appropriate symbols in your tm.h
93    file.  */
94 #ifndef PTR_SIZE
95 #define PTR_SIZE 4 /* Must be 32 bits for VMS debug info */
96 #endif
97 
98 /* Pointer to a structure of filenames referenced by this compilation unit.  */
99 static dst_file_info_ref file_info_table;
100 
101 /* Total number of entries in the table (i.e. array) pointed to by
102    `file_info_table'.  This is the *total* and includes both used and unused
103    slots.  */
104 static unsigned int file_info_table_allocated;
105 
106 /* Number of entries in the file_info_table which are actually in use.  */
107 static unsigned int file_info_table_in_use;
108 
109 /* Size (in elements) of increments by which we may expand the filename
110    table.  */
111 #define FILE_TABLE_INCREMENT 64
112 
113 typedef char *char_p;
114 
115 static vec<char_p> funcnam_table;
116 static vec<unsigned> funcnum_table;
117 #define FUNC_TABLE_INITIAL 256
118 
119 /* Local pointer to the name of the main input file.  Initialized in
120    vmsdbgout_init.  */
121 static const char *primary_filename;
122 
123 static char *module_producer;
124 static unsigned int module_language;
125 
126 /* A pointer to the base of a table that contains line information
127    for each source code line in .text in the compilation unit.  */
128 static dst_line_info_ref line_info_table;
129 
130 /* Number of elements currently allocated for line_info_table.  */
131 static unsigned int line_info_table_allocated;
132 
133 /* Number of elements in line_info_table currently in use.  */
134 static unsigned int line_info_table_in_use;
135 
136 /* Size (in elements) of increments by which we may expand line_info_table.  */
137 #define LINE_INFO_TABLE_INCREMENT 1024
138 
139 /* Forward declarations for functions defined in this file.  */
140 static char *full_name (const char *);
141 static unsigned int lookup_filename (const char *);
142 static int write_debug_header (DST_HEADER *, const char *, int);
143 static int write_debug_addr (const char *, const char *, int);
144 static int write_debug_data1 (unsigned int, const char *, int);
145 static int write_debug_data2 (unsigned int, const char *, int);
146 static int write_debug_data4 (unsigned long, const char *, int);
147 static int write_debug_data8 (unsigned long long, const char *, int);
148 static int write_debug_delta4 (const char *, const char *, const char *, int);
149 static int write_debug_string (const char *, const char *, int);
150 static int write_modbeg (int);
151 static int write_modend (int);
152 static int write_rtnbeg (int, int);
153 static int write_rtnend (int, int);
154 static int write_pclines (int);
155 static int write_srccorr (int, dst_file_info_entry, int);
156 static int write_srccorrs (int);
157 
158 static void vmsdbgout_init (const char *);
159 static void vmsdbgout_finish (const char *);
160 static void vmsdbgout_assembly_start (void);
161 static void vmsdbgout_define (unsigned int, const char *);
162 static void vmsdbgout_undef (unsigned int, const char *);
163 static void vmsdbgout_start_source_file (unsigned int, const char *);
164 static void vmsdbgout_end_source_file (unsigned int);
165 static void vmsdbgout_begin_block (unsigned int, unsigned int);
166 static void vmsdbgout_end_block (unsigned int, unsigned int);
167 static bool vmsdbgout_ignore_block (const_tree);
168 static void vmsdbgout_source_line (unsigned int, const char *, int, bool);
169 static void vmsdbgout_write_source_line (unsigned, const char *, int , bool);
170 static void vmsdbgout_begin_prologue (unsigned int, const char *);
171 static void vmsdbgout_end_prologue (unsigned int, const char *);
172 static void vmsdbgout_end_function (unsigned int);
173 static void vmsdbgout_begin_epilogue (unsigned int, const char *);
174 static void vmsdbgout_end_epilogue (unsigned int, const char *);
175 static void vmsdbgout_begin_function (tree);
176 static void vmsdbgout_decl (tree);
177 static void vmsdbgout_global_decl (tree);
178 static void vmsdbgout_type_decl (tree, int);
179 static void vmsdbgout_abstract_function (tree);
180 
181 /* The debug hooks structure.  */
182 
183 const struct gcc_debug_hooks vmsdbg_debug_hooks
184 = {vmsdbgout_init,
185    vmsdbgout_finish,
186    vmsdbgout_assembly_start,
187    vmsdbgout_define,
188    vmsdbgout_undef,
189    vmsdbgout_start_source_file,
190    vmsdbgout_end_source_file,
191    vmsdbgout_begin_block,
192    vmsdbgout_end_block,
193    vmsdbgout_ignore_block,
194    vmsdbgout_source_line,
195    vmsdbgout_begin_prologue,
196    vmsdbgout_end_prologue,
197    vmsdbgout_begin_epilogue,
198    vmsdbgout_end_epilogue,
199    vmsdbgout_begin_function,
200    vmsdbgout_end_function,
201    debug_nothing_tree,		  /* register_main_translation_unit */
202    vmsdbgout_decl,
203    vmsdbgout_global_decl,
204    vmsdbgout_type_decl,		  /* type_decl */
205    debug_nothing_tree_tree_tree_bool, /* imported_module_or_decl */
206    debug_nothing_tree,		  /* deferred_inline_function */
207    vmsdbgout_abstract_function,
208    debug_nothing_rtx_code_label,  /* label */
209    debug_nothing_int,		  /* handle_pch */
210    debug_nothing_rtx_insn,	  /* var_location */
211    debug_nothing_void,            /* switch_text_section */
212    debug_nothing_tree_tree,	  /* set_name */
213    0,                             /* start_end_main_source_file */
214    TYPE_SYMTAB_IS_ADDRESS         /* tree_type_symtab_field */
215 };
216 
217 /* Definitions of defaults for assembler-dependent names of various
218    pseudo-ops and section names.  */
219 #define VMS_UNALIGNED_SHORT_ASM_OP	".word"
220 #define VMS_UNALIGNED_INT_ASM_OP	".long"
221 #define VMS_UNALIGNED_LONG_ASM_OP	".long"
222 #define VMS_UNALIGNED_DOUBLE_INT_ASM_OP	".quad"
223 
224 #define VMS_ASM_BYTE_OP	".byte"
225 
226 #define NUMBYTES(I) ((I) < 256 ? 1 : (I) < 65536 ? 2 : 4)
227 
228 #define NUMBYTES0(I) ((I) < 128 ? 0 : (I) < 65536 ? 2 : 4)
229 
230 #ifndef UNALIGNED_PTR_ASM_OP
231 #define UNALIGNED_PTR_ASM_OP \
232   (PTR_SIZE == 8 ? VMS_UNALIGNED_DOUBLE_INT_ASM_OP : VMS_UNALIGNED_INT_ASM_OP)
233 #endif
234 
235 #ifndef UNALIGNED_OFFSET_ASM_OP
236 #define UNALIGNED_OFFSET_ASM_OP(OFFSET) \
237   (NUMBYTES (OFFSET) == 4 \
238    ? VMS_UNALIGNED_LONG_ASM_OP \
239    : (NUMBYTES (OFFSET) == 2 ? VMS_UNALIGNED_SHORT_ASM_OP : VMS_ASM_BYTE_OP))
240 #endif
241 
242 /* Definitions of defaults for formats and names of various special
243    (artificial) labels which may be generated within this file (when the -g
244    options is used and VMS_DEBUGGING_INFO is in effect.  If necessary, these
245    may be overridden from within the tm.h file, but typically, overriding these
246    defaults is unnecessary.  */
247 
248 static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
249 
250 #ifndef TEXT_END_LABEL
251 #define TEXT_END_LABEL		"Lvetext"
252 #endif
253 #ifndef FUNC_BEGIN_LABEL
254 #define FUNC_BEGIN_LABEL	"LVFB"
255 #endif
256 #ifndef FUNC_PROLOG_LABEL
257 #define FUNC_PROLOG_LABEL	"LVFP"
258 #endif
259 #ifndef FUNC_EPILOG_LABEL
260 #define FUNC_EPILOG_LABEL	"LVEB"
261 #endif
262 #ifndef FUNC_END_LABEL
263 #define FUNC_END_LABEL		"LVFE"
264 #endif
265 #ifndef BLOCK_BEGIN_LABEL
266 #define BLOCK_BEGIN_LABEL	"LVBB"
267 #endif
268 #ifndef BLOCK_END_LABEL
269 #define BLOCK_END_LABEL		"LVBE"
270 #endif
271 #ifndef LINE_CODE_LABEL
272 #define LINE_CODE_LABEL		"LVM"
273 #endif
274 
275 #ifndef ASM_OUTPUT_DEBUG_DELTA2
276 #define ASM_OUTPUT_DEBUG_DELTA2(FILE,LABEL1,LABEL2)			 \
277   do									 \
278     {									 \
279       fprintf ((FILE), "\t%s\t", VMS_UNALIGNED_SHORT_ASM_OP);		 \
280       assemble_name (FILE, LABEL1);					 \
281       fprintf (FILE, "-");						 \
282       assemble_name (FILE, LABEL2);					 \
283     }									 \
284   while (0)
285 #endif
286 
287 #ifndef ASM_OUTPUT_DEBUG_DELTA4
288 #define ASM_OUTPUT_DEBUG_DELTA4(FILE,LABEL1,LABEL2)			 \
289   do									 \
290     {									 \
291       fprintf ((FILE), "\t%s\t", VMS_UNALIGNED_INT_ASM_OP);		 \
292       assemble_name (FILE, LABEL1);					 \
293       fprintf (FILE, "-");						 \
294       assemble_name (FILE, LABEL2);					 \
295     }									 \
296   while (0)
297 #endif
298 
299 #ifndef ASM_OUTPUT_DEBUG_ADDR_DELTA
300 #define ASM_OUTPUT_DEBUG_ADDR_DELTA(FILE,LABEL1,LABEL2)			 \
301   do									 \
302     {									 \
303       fprintf ((FILE), "\t%s\t", UNALIGNED_PTR_ASM_OP);			 \
304       assemble_name (FILE, LABEL1);					 \
305       fprintf (FILE, "-");						 \
306       assemble_name (FILE, LABEL2);					 \
307     }									 \
308   while (0)
309 #endif
310 
311 #ifndef ASM_OUTPUT_DEBUG_ADDR
312 #define ASM_OUTPUT_DEBUG_ADDR(FILE,LABEL)				 \
313   do									 \
314     {									 \
315       fprintf ((FILE), "\t%s\t", UNALIGNED_PTR_ASM_OP);			 \
316       assemble_name (FILE, LABEL);					 \
317     }									 \
318   while (0)
319 #endif
320 
321 #ifndef ASM_OUTPUT_DEBUG_ADDR_CONST
322 #define ASM_OUTPUT_DEBUG_ADDR_CONST(FILE,ADDR)				\
323   fprintf ((FILE), "\t%s\t%s", UNALIGNED_PTR_ASM_OP, (ADDR))
324 #endif
325 
326 #ifndef ASM_OUTPUT_DEBUG_DATA1
327 #define ASM_OUTPUT_DEBUG_DATA1(FILE,VALUE) \
328   fprintf ((FILE), "\t%s\t%#x", VMS_ASM_BYTE_OP, (unsigned char) VALUE)
329 #endif
330 
331 #ifndef ASM_OUTPUT_DEBUG_DATA2
332 #define ASM_OUTPUT_DEBUG_DATA2(FILE,VALUE) \
333   fprintf ((FILE), "\t%s\t%#x", VMS_UNALIGNED_SHORT_ASM_OP, \
334 	   (unsigned short) VALUE)
335 #endif
336 
337 #ifndef ASM_OUTPUT_DEBUG_DATA4
338 #define ASM_OUTPUT_DEBUG_DATA4(FILE,VALUE) \
339   fprintf ((FILE), "\t%s\t%#lx", VMS_UNALIGNED_INT_ASM_OP, \
340 	   (unsigned long) VALUE)
341 #endif
342 
343 #ifndef ASM_OUTPUT_DEBUG_DATA
344 #define ASM_OUTPUT_DEBUG_DATA(FILE,VALUE) \
345   fprintf ((FILE), "\t%s\t%#lx", UNALIGNED_OFFSET_ASM_OP (VALUE), VALUE)
346 #endif
347 
348 #ifndef ASM_OUTPUT_DEBUG_ADDR_DATA
349 #define ASM_OUTPUT_DEBUG_ADDR_DATA(FILE,VALUE) \
350   fprintf ((FILE), "\t%s\t%#lx", UNALIGNED_PTR_ASM_OP, \
351 	   (unsigned long) VALUE)
352 #endif
353 
354 #ifndef ASM_OUTPUT_DEBUG_DATA8
355 #define ASM_OUTPUT_DEBUG_DATA8(FILE,VALUE) \
356   fprintf ((FILE), "\t%s\t%#llx", VMS_UNALIGNED_DOUBLE_INT_ASM_OP, \
357                                  (unsigned long long) VALUE)
358 #endif
359 
360 /* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing
361    newline is produced.  When flag_verbose_asm is asserted, we add commentary
362    at the end of the line, so we must avoid output of a newline here.  */
363 #ifndef ASM_OUTPUT_DEBUG_STRING
364 #define ASM_OUTPUT_DEBUG_STRING(FILE,P)		\
365   do						\
366     {						\
367       register int slen = strlen (P);		\
368       register const char *p = (P);		\
369       register int i;				\
370       fprintf (FILE, "\t.ascii \"");		\
371       for (i = 0; i < slen; i++)		\
372 	{					\
373 	  register int c = p[i];		\
374 	  if (c == '\"' || c == '\\')		\
375 	    putc ('\\', FILE);			\
376 	  if (c >= ' ' && c < 0177)		\
377 	    putc (c, FILE);			\
378 	  else					\
379 	    fprintf (FILE, "\\%o", c);		\
380 	}					\
381       fprintf (FILE, "\"");			\
382     }						\
383   while (0)
384 #endif
385 
386 /* Convert a reference to the assembler name of a C-level name.  This
387    macro has the same effect as ASM_OUTPUT_LABELREF, but copies to
388    a string rather than writing to a file.  */
389 #ifndef ASM_NAME_TO_STRING
390 #define ASM_NAME_TO_STRING(STR, NAME)		\
391   do						\
392     {						\
393       if ((NAME)[0] == '*')			\
394 	strcpy (STR, NAME+1);			\
395       else					\
396 	strcpy (STR, NAME);			\
397     }						\
398   while (0)
399 #endif
400 
401 
402 /* Output the debug header HEADER.  Also output COMMENT if flag_verbose_asm is
403    set.  Return the header size.  Just return the size if DOSIZEONLY is
404    nonzero.  */
405 
406 static int
407 write_debug_header (DST_HEADER *header, const char *comment, int dosizeonly)
408 {
409   if (!dosizeonly)
410     {
411       ASM_OUTPUT_DEBUG_DATA2 (asm_out_file,
412 			      header->dst__header_length.dst_w_length);
413 
414       if (flag_verbose_asm)
415 	fprintf (asm_out_file, "\t%s record length", ASM_COMMENT_START);
416       fputc ('\n', asm_out_file);
417 
418       ASM_OUTPUT_DEBUG_DATA2 (asm_out_file,
419 			      header->dst__header_type.dst_w_type);
420 
421       if (flag_verbose_asm)
422 	fprintf (asm_out_file, "\t%s record type (%s)", ASM_COMMENT_START,
423 		 comment);
424 
425       fputc ('\n', asm_out_file);
426     }
427 
428   return 4;
429 }
430 
431 /* Output the address of SYMBOL.  Also output COMMENT if flag_verbose_asm is
432    set.  Return the address size.  Just return the size if DOSIZEONLY is
433    nonzero.  */
434 
435 static int
436 write_debug_addr (const char *symbol, const char *comment, int dosizeonly)
437 {
438   if (!dosizeonly)
439     {
440       ASM_OUTPUT_DEBUG_ADDR (asm_out_file, symbol);
441       if (flag_verbose_asm)
442 	fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, comment);
443       fputc ('\n', asm_out_file);
444     }
445 
446   return PTR_SIZE;
447 }
448 
449 /* Output the single byte DATA1.  Also output COMMENT if flag_verbose_asm is
450    set.  Return the data size.  Just return the size if DOSIZEONLY is
451    nonzero.  */
452 
453 static int
454 write_debug_data1 (unsigned int data1, const char *comment, int dosizeonly)
455 {
456   if (!dosizeonly)
457     {
458       ASM_OUTPUT_DEBUG_DATA1 (asm_out_file, data1);
459       if (flag_verbose_asm)
460 	fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, comment);
461       fputc ('\n', asm_out_file);
462     }
463 
464   return 1;
465 }
466 
467 /* Output the single word DATA2.  Also output COMMENT if flag_verbose_asm is
468    set.  Return the data size.  Just return the size if DOSIZEONLY is
469    nonzero.  */
470 
471 static int
472 write_debug_data2 (unsigned int data2, const char *comment, int dosizeonly)
473 {
474   if (!dosizeonly)
475     {
476       ASM_OUTPUT_DEBUG_DATA2 (asm_out_file, data2);
477       if (flag_verbose_asm)
478 	fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, comment);
479       fputc ('\n', asm_out_file);
480     }
481 
482   return 2;
483 }
484 
485 /* Output double word DATA4.  Also output COMMENT if flag_verbose_asm is set.
486    Return the data size.  Just return the size if DOSIZEONLY is nonzero.  */
487 
488 static int
489 write_debug_data4 (unsigned long data4, const char *comment, int dosizeonly)
490 {
491   if (!dosizeonly)
492     {
493       ASM_OUTPUT_DEBUG_DATA4 (asm_out_file, data4);
494       if (flag_verbose_asm)
495 	fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, comment);
496       fputc ('\n', asm_out_file);
497     }
498 
499   return 4;
500 }
501 
502 /* Output quad word DATA8.  Also output COMMENT if flag_verbose_asm is set.
503    Return the data size.  Just return the size if DOSIZEONLY is nonzero.  */
504 
505 static int
506 write_debug_data8 (unsigned long long data8, const char *comment,
507 		   int dosizeonly)
508 {
509   if (!dosizeonly)
510     {
511       ASM_OUTPUT_DEBUG_DATA8 (asm_out_file, data8);
512       if (flag_verbose_asm)
513 	fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, comment);
514       fputc ('\n', asm_out_file);
515     }
516 
517   return 8;
518 }
519 
520 /* Output the difference between LABEL1 and LABEL2.  Also output COMMENT if
521    flag_verbose_asm is set.  Return the data size.  Just return the size if
522    DOSIZEONLY is nonzero.  */
523 
524 static int
525 write_debug_delta4 (const char *label1, const char *label2,
526 		    const char *comment, int dosizeonly)
527 {
528   if (!dosizeonly)
529     {
530       ASM_OUTPUT_DEBUG_DELTA4 (asm_out_file, label1, label2);
531       if (flag_verbose_asm)
532 	fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, comment);
533       fputc ('\n', asm_out_file);
534     }
535 
536   return 4;
537 }
538 
539 /* Output a character string STRING.  Also write COMMENT if flag_verbose_asm is
540    set.  Return the string length.  Just return the length if DOSIZEONLY is
541    nonzero.  */
542 
543 static int
544 write_debug_string (const char *string, const char *comment, int dosizeonly)
545 {
546   if (!dosizeonly)
547     {
548       ASM_OUTPUT_DEBUG_STRING (asm_out_file, string);
549       if (flag_verbose_asm)
550 	fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, comment);
551       fputc ('\n', asm_out_file);
552     }
553 
554   return strlen (string);
555 }
556 
557 /* Output a module begin header and return the header size.  Just return the
558    size if DOSIZEONLY is nonzero.  */
559 
560 static int
561 write_modbeg (int dosizeonly)
562 {
563   DST_MODULE_BEGIN modbeg;
564   DST_MB_TRLR mb_trlr;
565   int i;
566   char *module_name, *m;
567   int modnamelen;
568   int prodnamelen;
569   int totsize = 0;
570 
571   /* Assumes primary filename has Unix syntax file spec.  */
572   module_name = xstrdup (lbasename (primary_filename));
573 
574   m = strrchr (module_name, '.');
575   if (m)
576     *m = 0;
577 
578   modnamelen = strlen (module_name);
579   for (i = 0; i < modnamelen; i++)
580     module_name[i] = TOUPPER (module_name[i]);
581 
582   prodnamelen = strlen (module_producer);
583 
584   modbeg.dst_a_modbeg_header.dst__header_length.dst_w_length
585     = DST_K_MODBEG_SIZE + modnamelen + DST_K_MB_TRLR_SIZE + prodnamelen - 1;
586   modbeg.dst_a_modbeg_header.dst__header_type.dst_w_type = DST_K_MODBEG;
587   modbeg.dst_b_modbeg_flags.dst_v_modbeg_hide = 0;
588   modbeg.dst_b_modbeg_flags.dst_v_modbeg_version = 1;
589   modbeg.dst_b_modbeg_flags.dst_v_modbeg_unused = 0;
590   modbeg.dst_b_modbeg_unused = 0;
591   modbeg.dst_l_modbeg_language = (DST_LANGUAGE) module_language;
592   modbeg.dst_w_version_major = DST_K_VERSION_MAJOR;
593   modbeg.dst_w_version_minor = DST_K_VERSION_MINOR;
594   modbeg.dst_b_modbeg_name = strlen (module_name);
595 
596   mb_trlr.dst_b_compiler = strlen (module_producer);
597 
598   totsize += write_debug_header (&modbeg.dst_a_modbeg_header,
599 				 "modbeg", dosizeonly);
600   totsize += write_debug_data1 (*((char *) &modbeg.dst_b_modbeg_flags),
601 				"flags", dosizeonly);
602   totsize += write_debug_data1 (modbeg.dst_b_modbeg_unused,
603 				"unused", dosizeonly);
604   totsize += write_debug_data4 (modbeg.dst_l_modbeg_language,
605 				"language", dosizeonly);
606   totsize += write_debug_data2 (modbeg.dst_w_version_major,
607 				"DST major version", dosizeonly);
608   totsize += write_debug_data2 (modbeg.dst_w_version_minor,
609 				"DST minor version", dosizeonly);
610   totsize += write_debug_data1 (modbeg.dst_b_modbeg_name,
611 				"length of module name", dosizeonly);
612   totsize += write_debug_string (module_name, "module name", dosizeonly);
613   totsize += write_debug_data1 (mb_trlr.dst_b_compiler,
614 				"length of compiler name", dosizeonly);
615   totsize += write_debug_string (module_producer, "compiler name", dosizeonly);
616 
617   return totsize;
618 }
619 
620 /* Output a module end trailer and return the trailer size.   Just return
621    the size if DOSIZEONLY is nonzero.  */
622 
623 static int
624 write_modend (int dosizeonly)
625 {
626   DST_MODULE_END modend;
627   int totsize = 0;
628 
629   modend.dst_a_modend_header.dst__header_length.dst_w_length
630    = DST_K_MODEND_SIZE - 1;
631   modend.dst_a_modend_header.dst__header_type.dst_w_type = DST_K_MODEND;
632 
633   totsize += write_debug_header (&modend.dst_a_modend_header, "modend",
634 				 dosizeonly);
635 
636   return totsize;
637 }
638 
639 /* Output a routine begin header routine RTNNUM and return the header size.
640    Just return the size if DOSIZEONLY is nonzero.  */
641 
642 static int
643 write_rtnbeg (int rtnnum, int dosizeonly)
644 {
645   const char *rtnname;
646   int rtnnamelen;
647   char *rtnentryname;
648   int totsize = 0;
649   char label[MAX_ARTIFICIAL_LABEL_BYTES];
650   DST_ROUTINE_BEGIN rtnbeg;
651   DST_PROLOG prolog;
652 
653   rtnname = funcnam_table[rtnnum];
654   rtnnamelen = strlen (rtnname);
655   rtnentryname = concat (rtnname, "..en", NULL);
656 
657   if (!strcmp (rtnname, "main"))
658     {
659       DST_HEADER header;
660       const char *go = "TRANSFER$BREAK$GO";
661 
662       /* This command isn't documented in DSTRECORDS, so it's made to
663 	 look like what DEC C does */
664 
665       /* header size - 1st byte + flag byte + STO_LW size
666 	 + string count byte + string length */
667       header.dst__header_length.dst_w_length
668 	= DST_K_DST_HEADER_SIZE - 1 + 1 + 4 + 1 + strlen (go);
669       header.dst__header_type.dst_w_type = DST_K_TBG;
670 
671       totsize += write_debug_header (&header, "transfer", dosizeonly);
672 
673       /* I think this is a flag byte, but I don't know what this flag means */
674       totsize += write_debug_data1 (0x1, "flags ???", dosizeonly);
675 
676       /* Routine Begin PD Address */
677       totsize += write_debug_addr (rtnname, "main procedure descriptor",
678 				   dosizeonly);
679       totsize += write_debug_data1 (strlen (go), "length of main_name",
680 				    dosizeonly);
681       totsize += write_debug_string (go, "main name", dosizeonly);
682     }
683 
684   /* The header length never includes the length byte.  */
685   rtnbeg.dst_a_rtnbeg_header.dst__header_length.dst_w_length
686    = DST_K_RTNBEG_SIZE + rtnnamelen - 1;
687   rtnbeg.dst_a_rtnbeg_header.dst__header_type.dst_w_type = DST_K_RTNBEG;
688   rtnbeg.dst_b_rtnbeg_flags.dst_v_rtnbeg_unused = 0;
689   rtnbeg.dst_b_rtnbeg_flags.dst_v_rtnbeg_unalloc = 0;
690   rtnbeg.dst_b_rtnbeg_flags.dst_v_rtnbeg_prototype = 0;
691   rtnbeg.dst_b_rtnbeg_flags.dst_v_rtnbeg_inlined = 0;
692   rtnbeg.dst_b_rtnbeg_flags.dst_v_rtnbeg_no_call = 1;
693   rtnbeg.dst_b_rtnbeg_name = rtnnamelen;
694 
695   totsize += write_debug_header (&rtnbeg.dst_a_rtnbeg_header, "rtnbeg",
696 				 dosizeonly);
697   totsize += write_debug_data1 (*((char *) &rtnbeg.dst_b_rtnbeg_flags),
698 				"flags", dosizeonly);
699 
700   /* Routine Begin Address */
701   totsize += write_debug_addr (rtnentryname, "routine entry name", dosizeonly);
702 
703   /* Routine Begin PD Address */
704   totsize += write_debug_addr (rtnname, "routine procedure descriptor",
705 			       dosizeonly);
706 
707   /* Routine Begin Name */
708   totsize += write_debug_data1 (rtnbeg.dst_b_rtnbeg_name,
709 				"length of routine name", dosizeonly);
710 
711   totsize += write_debug_string (rtnname, "routine name", dosizeonly);
712 
713   free (rtnentryname);
714 
715   if (debug_info_level > DINFO_LEVEL_TERSE)
716     {
717       prolog.dst_a_prolog_header.dst__header_length.dst_w_length
718 	= DST_K_PROLOG_SIZE - 1;
719       prolog.dst_a_prolog_header.dst__header_type.dst_w_type = DST_K_PROLOG;
720 
721       totsize += write_debug_header (&prolog.dst_a_prolog_header, "prolog",
722 				     dosizeonly);
723 
724       ASM_GENERATE_INTERNAL_LABEL
725         (label, FUNC_PROLOG_LABEL,
726 	 funcnum_table[rtnnum]);
727       totsize += write_debug_addr (label, "prolog breakpoint addr",
728 				   dosizeonly);
729     }
730 
731   return totsize;
732 }
733 
734 /* Output a routine end trailer for routine RTNNUM and return the header size.
735    Just return the size if DOSIZEONLY is nonzero.  */
736 
737 static int
738 write_rtnend (int rtnnum, int dosizeonly)
739 {
740   DST_ROUTINE_END rtnend;
741   char label1[MAX_ARTIFICIAL_LABEL_BYTES];
742   char label2[MAX_ARTIFICIAL_LABEL_BYTES];
743   int totsize;
744 
745   totsize = 0;
746 
747   rtnend.dst_a_rtnend_header.dst__header_length.dst_w_length
748    = DST_K_RTNEND_SIZE - 1;
749   rtnend.dst_a_rtnend_header.dst__header_type.dst_w_type = DST_K_RTNEND;
750   rtnend.dst_b_rtnend_unused = 0;
751   rtnend.dst_l_rtnend_size = 0; /* Calculated below.  */
752 
753   totsize += write_debug_header (&rtnend.dst_a_rtnend_header, "rtnend",
754 				 dosizeonly);
755   totsize += write_debug_data1 (rtnend.dst_b_rtnend_unused, "unused",
756 				dosizeonly);
757 
758   ASM_GENERATE_INTERNAL_LABEL
759    (label1, FUNC_BEGIN_LABEL,
760     funcnum_table[rtnnum]);
761   ASM_GENERATE_INTERNAL_LABEL
762    (label2, FUNC_END_LABEL,
763     funcnum_table[rtnnum]);
764   totsize += write_debug_delta4 (label2, label1, "routine size", dosizeonly);
765 
766   return totsize;
767 }
768 
769 #define K_DELTA_PC(I) \
770  ((I) < 128 ? -(I) : (I) < 65536 ? DST_K_DELTA_PC_W : DST_K_DELTA_PC_L)
771 
772 #define K_SET_LINUM(I) \
773  ((I) < 256 ? DST_K_SET_LINUM_B \
774   : (I) < 65536 ? DST_K_SET_LINUM : DST_K_SET_LINUM_L)
775 
776 #define K_INCR_LINUM(I) \
777  ((I) < 256 ? DST_K_INCR_LINUM \
778   : (I) < 65536 ? DST_K_INCR_LINUM_W : DST_K_INCR_LINUM_L)
779 
780 /* Output the PC to line number correlations and return the size.  Just return
781    the size if DOSIZEONLY is nonzero */
782 
783 static int
784 write_pclines (int dosizeonly)
785 {
786   unsigned i;
787   int fn;
788   int ln, lastln;
789   int linestart = 0;
790   int max_line;
791   DST_LINE_NUM_HEADER line_num;
792   DST_PCLINE_COMMANDS pcline;
793   char label[MAX_ARTIFICIAL_LABEL_BYTES];
794   char lastlabel[MAX_ARTIFICIAL_LABEL_BYTES];
795   int totsize = 0;
796   char buff[256];
797 
798   max_line = file_info_table[1].max_line;
799   file_info_table[1].listing_line_start = linestart;
800   linestart = linestart + ((max_line / 100000) + 1) * 100000;
801 
802   for (i = 2; i < file_info_table_in_use; i++)
803     {
804       max_line = file_info_table[i].max_line;
805       file_info_table[i].listing_line_start = linestart;
806       linestart = linestart + ((max_line / 10000) + 1) * 10000;
807     }
808 
809   /* Set starting address to beginning of text section.  */
810   line_num.dst_a_line_num_header.dst__header_length.dst_w_length = 8;
811   line_num.dst_a_line_num_header.dst__header_type.dst_w_type = DST_K_LINE_NUM;
812   pcline.dst_b_pcline_command = DST_K_SET_ABS_PC;
813 
814   totsize += write_debug_header (&line_num.dst_a_line_num_header,
815 				 "line_num", dosizeonly);
816   totsize += write_debug_data1 (pcline.dst_b_pcline_command,
817 				"line_num (SET ABS PC)", dosizeonly);
818 
819   if (dosizeonly)
820     totsize += 4;
821   else
822     {
823       ASM_OUTPUT_DEBUG_ADDR (asm_out_file, TEXT_SECTION_ASM_OP);
824       if (flag_verbose_asm)
825 	fprintf (asm_out_file, "\t%s line_num", ASM_COMMENT_START);
826       fputc ('\n', asm_out_file);
827     }
828 
829   fn = line_info_table[1].dst_file_num;
830   ln = (file_info_table[fn].listing_line_start
831 	+ line_info_table[1].dst_line_num);
832   line_num.dst_a_line_num_header.dst__header_length.dst_w_length = 4 + 4;
833   pcline.dst_b_pcline_command = DST_K_SET_LINUM_L;
834 
835   totsize += write_debug_header (&line_num.dst_a_line_num_header,
836 				 "line_num", dosizeonly);
837   totsize += write_debug_data1 (pcline.dst_b_pcline_command,
838 				"line_num (SET LINUM LONG)", dosizeonly);
839 
840   sprintf (buff, "line_num (%d)", ln ? ln - 1 : 0);
841   totsize += write_debug_data4 (ln ? ln - 1 : 0, buff, dosizeonly);
842 
843   lastln = ln;
844   strcpy (lastlabel, TEXT_SECTION_ASM_OP);
845   for (i = 1; i < line_info_table_in_use; i++)
846     {
847       int extrabytes;
848 
849       fn = line_info_table[i].dst_file_num;
850       ln = (file_info_table[fn].listing_line_start
851 	    + line_info_table[i].dst_line_num);
852 
853       if (ln - lastln > 1)
854 	extrabytes = 5; /* NUMBYTES (ln - lastln - 1) + 1; */
855       else if (ln <= lastln)
856 	extrabytes = 5; /* NUMBYTES (ln - 1) + 1; */
857       else
858 	extrabytes = 0;
859 
860       line_num.dst_a_line_num_header.dst__header_length.dst_w_length
861 	= 8 + extrabytes;
862 
863       totsize += write_debug_header
864 	(&line_num.dst_a_line_num_header, "line_num", dosizeonly);
865 
866       if (ln - lastln > 1)
867 	{
868 	  int lndif = ln - lastln - 1;
869 
870 	  /* K_INCR_LINUM (lndif); */
871 	  pcline.dst_b_pcline_command = DST_K_INCR_LINUM_L;
872 
873 	  totsize += write_debug_data1 (pcline.dst_b_pcline_command,
874 					"line_num (INCR LINUM LONG)",
875 					dosizeonly);
876 
877 	  sprintf (buff, "line_num (%d)", lndif);
878 	  totsize += write_debug_data4 (lndif, buff, dosizeonly);
879 	}
880       else if (ln <= lastln)
881 	{
882 	  /* K_SET_LINUM (ln-1); */
883 	  pcline.dst_b_pcline_command = DST_K_SET_LINUM_L;
884 
885 	  totsize += write_debug_data1 (pcline.dst_b_pcline_command,
886 					"line_num (SET LINUM LONG)",
887 					dosizeonly);
888 
889 	  sprintf (buff, "line_num (%d)", ln - 1);
890 	  totsize += write_debug_data4 (ln - 1, buff, dosizeonly);
891 	}
892 
893       pcline.dst_b_pcline_command = DST_K_DELTA_PC_L;
894 
895       totsize += write_debug_data1 (pcline.dst_b_pcline_command,
896 				    "line_num (DELTA PC LONG)", dosizeonly);
897 
898       ASM_GENERATE_INTERNAL_LABEL (label, LINE_CODE_LABEL, i);
899       totsize += write_debug_delta4 (label, lastlabel, "increment line_num",
900 				     dosizeonly);
901 
902       lastln = ln;
903       strcpy (lastlabel, label);
904     }
905 
906   return totsize;
907 }
908 
909 /* Output a source correlation for file FILEID using information saved in
910    FILE_INFO_ENTRY and return the size.  Just return the size if DOSIZEONLY is
911    nonzero.  */
912 
913 static int
914 write_srccorr (int fileid, dst_file_info_entry file_info_entry,
915 	       int dosizeonly)
916 {
917   int src_command_size;
918   int linesleft = file_info_entry.max_line;
919   int linestart = file_info_entry.listing_line_start;
920   int flen = strlen (file_info_entry.file_name);
921   int linestodo = 0;
922   DST_SOURCE_CORR src_header;
923   DST_SRC_COMMAND src_command;
924   DST_SRC_COMMAND src_command_sf;
925   DST_SRC_COMMAND src_command_sl;
926   DST_SRC_COMMAND src_command_sr;
927   DST_SRC_COMMAND src_command_dl;
928   DST_SRC_CMDTRLR src_cmdtrlr;
929   char buff[256];
930   int totsize = 0;
931 
932   if (fileid == 1)
933     {
934       src_header.dst_a_source_corr_header.dst__header_length.dst_w_length
935 	= DST_K_SOURCE_CORR_HEADER_SIZE + 1 - 1;
936       src_header.dst_a_source_corr_header.dst__header_type.dst_w_type
937 	= DST_K_SOURCE;
938       src_command.dst_b_src_command = DST_K_SRC_FORMFEED;
939 
940       totsize += write_debug_header (&src_header.dst_a_source_corr_header,
941 				     "source corr", dosizeonly);
942 
943       totsize += write_debug_data1 (src_command.dst_b_src_command,
944 				    "source_corr (SRC FORMFEED)",
945 				    dosizeonly);
946     }
947 
948   src_command_size
949     = DST_K_SRC_COMMAND_SIZE + flen + DST_K_SRC_CMDTRLR_SIZE;
950   src_command.dst_b_src_command = DST_K_SRC_DECLFILE;
951   src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_length
952     = src_command_size - 2;
953   src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_flags = 0;
954   src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_w_src_df_fileid
955     = fileid;
956   src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_q_src_df_rms_cdt
957     = file_info_entry.cdt;
958   src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_l_src_df_rms_ebk
959     = file_info_entry.ebk;
960   src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_w_src_df_rms_ffb
961     = file_info_entry.ffb;
962   src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_rms_rfo
963     = file_info_entry.rfo;
964   src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_filename
965     = flen;
966 
967   src_header.dst_a_source_corr_header.dst__header_length.dst_w_length
968     = DST_K_SOURCE_CORR_HEADER_SIZE + src_command_size - 1;
969   src_header.dst_a_source_corr_header.dst__header_type.dst_w_type
970     = DST_K_SOURCE;
971 
972   src_cmdtrlr.dst_b_src_df_libmodname = 0;
973 
974   totsize += write_debug_header (&src_header.dst_a_source_corr_header,
975 				 "source corr", dosizeonly);
976   totsize += write_debug_data1 (src_command.dst_b_src_command,
977 				"source_corr (DECL SRC FILE)", dosizeonly);
978   totsize += write_debug_data1
979     (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_length,
980      "source_corr (length)", dosizeonly);
981 
982   totsize += write_debug_data1
983     (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_flags,
984      "source_corr (flags)", dosizeonly);
985 
986   totsize += write_debug_data2
987     (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_w_src_df_fileid,
988      "source_corr (fileid)", dosizeonly);
989 
990   totsize += write_debug_data8
991     (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_q_src_df_rms_cdt,
992      "source_corr (creation date)", dosizeonly);
993 
994   totsize += write_debug_data4
995     (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_l_src_df_rms_ebk,
996      "source_corr (EOF block number)", dosizeonly);
997 
998   totsize += write_debug_data2
999     (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_w_src_df_rms_ffb,
1000      "source_corr (first free byte)", dosizeonly);
1001 
1002   totsize += write_debug_data1
1003     (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_rms_rfo,
1004      "source_corr (record and file organization)", dosizeonly);
1005 
1006   totsize += write_debug_data1
1007     (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_filename,
1008      "source_corr (filename length)", dosizeonly);
1009 
1010   totsize += write_debug_string (remap_debug_filename (
1011 				    file_info_entry.file_name),
1012 				 "source file name", dosizeonly);
1013   totsize += write_debug_data1 (src_cmdtrlr.dst_b_src_df_libmodname,
1014 				"source_corr (libmodname)", dosizeonly);
1015 
1016   src_command_sf.dst_b_src_command = DST_K_SRC_SETFILE;
1017   src_command_sf.dst_a_src_cmd_fields.dst_w_src_unsword = fileid;
1018 
1019   src_command_sr.dst_b_src_command = DST_K_SRC_SETREC_W;
1020   src_command_sr.dst_a_src_cmd_fields.dst_w_src_unsword = 1;
1021 
1022   src_command_sl.dst_b_src_command = DST_K_SRC_SETLNUM_L;
1023   src_command_sl.dst_a_src_cmd_fields.dst_l_src_unslong = linestart + 1;
1024 
1025   src_command_dl.dst_b_src_command = DST_K_SRC_DEFLINES_W;
1026 
1027   if (linesleft > 65534)
1028     linesleft = linesleft - 65534, linestodo = 65534;
1029   else
1030     linestodo = linesleft, linesleft = 0;
1031 
1032   src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword = linestodo;
1033 
1034   src_header.dst_a_source_corr_header.dst__header_length.dst_w_length
1035     = DST_K_SOURCE_CORR_HEADER_SIZE + 3 + 3 + 5 + 3 - 1;
1036   src_header.dst_a_source_corr_header.dst__header_type.dst_w_type
1037     = DST_K_SOURCE;
1038 
1039   if (src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword)
1040     {
1041       totsize += write_debug_header (&src_header.dst_a_source_corr_header,
1042 				     "source corr", dosizeonly);
1043 
1044       totsize += write_debug_data1 (src_command_sf.dst_b_src_command,
1045 				    "source_corr (src setfile)", dosizeonly);
1046 
1047       totsize += write_debug_data2
1048 	(src_command_sf.dst_a_src_cmd_fields.dst_w_src_unsword,
1049 	 "source_corr (fileid)", dosizeonly);
1050 
1051       totsize += write_debug_data1 (src_command_sr.dst_b_src_command,
1052 				    "source_corr (setrec)", dosizeonly);
1053 
1054       totsize += write_debug_data2
1055 	(src_command_sr.dst_a_src_cmd_fields.dst_w_src_unsword,
1056 	 "source_corr (recnum)", dosizeonly);
1057 
1058       totsize += write_debug_data1 (src_command_sl.dst_b_src_command,
1059 				    "source_corr (setlnum)", dosizeonly);
1060 
1061       totsize += write_debug_data4
1062 	(src_command_sl.dst_a_src_cmd_fields.dst_l_src_unslong,
1063 	 "source_corr (linenum)", dosizeonly);
1064 
1065       totsize += write_debug_data1 (src_command_dl.dst_b_src_command,
1066 				    "source_corr (deflines)", dosizeonly);
1067 
1068       sprintf (buff, "source_corr (%d)",
1069 	       src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword);
1070       totsize += write_debug_data2
1071 	(src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword,
1072 	 buff, dosizeonly);
1073 
1074       while (linesleft > 0)
1075 	{
1076 	  src_header.dst_a_source_corr_header.dst__header_length.dst_w_length
1077 	    = DST_K_SOURCE_CORR_HEADER_SIZE + 3 - 1;
1078 	  src_header.dst_a_source_corr_header.dst__header_type.dst_w_type
1079 	    = DST_K_SOURCE;
1080 	  src_command_dl.dst_b_src_command = DST_K_SRC_DEFLINES_W;
1081 
1082 	  if (linesleft > 65534)
1083 	    linesleft = linesleft - 65534, linestodo = 65534;
1084 	  else
1085 	    linestodo = linesleft, linesleft = 0;
1086 
1087 	  src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword = linestodo;
1088 
1089 	  totsize += write_debug_header (&src_header.dst_a_source_corr_header,
1090 					 "source corr", dosizeonly);
1091 	  totsize += write_debug_data1 (src_command_dl.dst_b_src_command,
1092 					"source_corr (deflines)", dosizeonly);
1093 	  sprintf (buff, "source_corr (%d)",
1094 		   src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword);
1095 	  totsize += write_debug_data2
1096 	    (src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword,
1097 	     buff, dosizeonly);
1098 	}
1099     }
1100 
1101   return totsize;
1102 }
1103 
1104 /* Output all the source correlation entries and return the size.  Just return
1105    the size if DOSIZEONLY is nonzero.  */
1106 
1107 static int
1108 write_srccorrs (int dosizeonly)
1109 {
1110   unsigned int i;
1111   int totsize = 0;
1112 
1113   for (i = 1; i < file_info_table_in_use; i++)
1114     totsize += write_srccorr (i, file_info_table[i], dosizeonly);
1115 
1116   return totsize;
1117 }
1118 
1119 /* Output a marker (i.e. a label) for the beginning of a function, before
1120    the prologue.  */
1121 
1122 static void
1123 vmsdbgout_begin_prologue (unsigned int line, const char *file)
1124 {
1125   char label[MAX_ARTIFICIAL_LABEL_BYTES];
1126 
1127   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1128     (*dwarf2_debug_hooks.begin_prologue) (line, file);
1129 
1130   if (debug_info_level > DINFO_LEVEL_NONE)
1131     {
1132       ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
1133 				   current_function_funcdef_no);
1134       ASM_OUTPUT_LABEL (asm_out_file, label);
1135     }
1136 }
1137 
1138 /* Output a marker (i.e. a label) for the beginning of a function, after
1139    the prologue.  */
1140 
1141 static void
1142 vmsdbgout_end_prologue (unsigned int line, const char *file)
1143 {
1144   char label[MAX_ARTIFICIAL_LABEL_BYTES];
1145 
1146   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1147     (*dwarf2_debug_hooks.end_prologue) (line, file);
1148 
1149   if (debug_info_level > DINFO_LEVEL_TERSE)
1150     {
1151       ASM_GENERATE_INTERNAL_LABEL (label, FUNC_PROLOG_LABEL,
1152 				   current_function_funcdef_no);
1153       ASM_OUTPUT_LABEL (asm_out_file, label);
1154 
1155       /* VMS PCA expects every PC range to correlate to some line and file.  */
1156       vmsdbgout_write_source_line (line, file, 0, true);
1157     }
1158 }
1159 
1160 /* No output for VMS debug, but make obligatory call to Dwarf2 debug */
1161 
1162 static void
1163 vmsdbgout_end_function (unsigned int line)
1164 {
1165   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1166     (*dwarf2_debug_hooks.end_function) (line);
1167 }
1168 
1169 /* Output a marker (i.e. a label) for the beginning of the epilogue.
1170    This gets called *before* the epilogue code has been generated.  */
1171 
1172 static void
1173 vmsdbgout_begin_epilogue (unsigned int line, const char *file)
1174 {
1175   char label[MAX_ARTIFICIAL_LABEL_BYTES];
1176   static int save_current_function_funcdef_no = -1;
1177 
1178   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1179     (*dwarf2_debug_hooks.begin_epilogue) (line, file);
1180 
1181   if (debug_info_level > DINFO_LEVEL_NONE)
1182     {
1183       if (save_current_function_funcdef_no != current_function_funcdef_no)
1184 	{
1185 	  /* Output a label to mark the endpoint of the code generated for this
1186 	     function.  */
1187 	  ASM_GENERATE_INTERNAL_LABEL (label, FUNC_EPILOG_LABEL,
1188 				       current_function_funcdef_no);
1189 
1190 	  ASM_OUTPUT_LABEL (asm_out_file, label);
1191 
1192 	  save_current_function_funcdef_no = current_function_funcdef_no;
1193 
1194 	  /* VMS PCA expects every PC range to correlate to some line and
1195 	     file.  */
1196 	  vmsdbgout_write_source_line (line, file, 0, true);
1197 	}
1198     }
1199 }
1200 
1201 /* Output a marker (i.e. a label) for the absolute end of the generated code
1202    for a function definition.  This gets called *after* the epilogue code has
1203    been generated.  */
1204 
1205 static void
1206 vmsdbgout_end_epilogue (unsigned int line, const char *file)
1207 {
1208   char label[MAX_ARTIFICIAL_LABEL_BYTES];
1209 
1210   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1211     (*dwarf2_debug_hooks.end_epilogue) (line, file);
1212 
1213   if (debug_info_level > DINFO_LEVEL_NONE)
1214     {
1215       /* Output a label to mark the endpoint of the code generated for this
1216          function.  */
1217       ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL,
1218 				   current_function_funcdef_no);
1219       ASM_OUTPUT_LABEL (asm_out_file, label);
1220 
1221       /* VMS PCA expects every PC range to correlate to some line and file.  */
1222       vmsdbgout_write_source_line (line, file, 0, true);
1223     }
1224 }
1225 
1226 /* Output a marker (i.e. a label) for the beginning of the generated code for
1227    a lexical block.  */
1228 
1229 static void
1230 vmsdbgout_begin_block (register unsigned line, register unsigned blocknum)
1231 {
1232   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1233     (*dwarf2_debug_hooks.begin_block) (line, blocknum);
1234 
1235   if (debug_info_level > DINFO_LEVEL_TERSE)
1236     targetm.asm_out.internal_label (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
1237 }
1238 
1239 /* Output a marker (i.e. a label) for the end of the generated code for a
1240    lexical block.  */
1241 
1242 static void
1243 vmsdbgout_end_block (register unsigned line, register unsigned blocknum)
1244 {
1245   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1246     (*dwarf2_debug_hooks.end_block) (line, blocknum);
1247 
1248   if (debug_info_level > DINFO_LEVEL_TERSE)
1249     targetm.asm_out.internal_label (asm_out_file, BLOCK_END_LABEL, blocknum);
1250 }
1251 
1252 /* Not implemented in VMS Debug.  */
1253 
1254 static bool
1255 vmsdbgout_ignore_block (const_tree block)
1256 {
1257   bool retval = 0;
1258 
1259   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1260     retval = (*dwarf2_debug_hooks.ignore_block) (block);
1261 
1262   return retval;
1263 }
1264 
1265 /* Add an entry for function DECL into the funcnam_table.  */
1266 
1267 static void
1268 vmsdbgout_begin_function (tree decl)
1269 {
1270   const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1271 
1272   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1273     (*dwarf2_debug_hooks.begin_function) (decl);
1274 
1275   /* Add the new entry to the end of the function name table.  */
1276   funcnam_table.safe_push (xstrdup (name));
1277   funcnum_table.safe_push (current_function_funcdef_no);
1278 }
1279 
1280 static char fullname_buff [4096];
1281 
1282 /* Return the full file specification for FILENAME.  The specification must be
1283    in VMS syntax in order to be processed by VMS Debug.  */
1284 
1285 static char *
1286 full_name (const char *filename)
1287 {
1288 #ifdef VMS
1289   FILE *fp = fopen (filename, "r");
1290 
1291   fgetname (fp, fullname_buff, 1);
1292   fclose (fp);
1293 #else
1294   /* Unix paths really mess up VMS debug. Better to just output the
1295      base filename.  */
1296   strcpy (fullname_buff, filename);
1297 #endif
1298 
1299   return fullname_buff;
1300 }
1301 
1302 /* Lookup a filename (in the list of filenames that we know about here in
1303    vmsdbgout.c) and return its "index".  The index of each (known) filename is
1304    just a unique number which is associated with only that one filename.  We
1305    need such numbers for the sake of generating labels  and references
1306    to those files numbers.  If the filename given as an argument is not
1307    found in our current list, add it to the list and assign it the next
1308    available unique index number.  In order to speed up searches, we remember
1309    the index of the filename was looked up last.  This handles the majority of
1310    all searches.  */
1311 
1312 static unsigned int
1313 lookup_filename (const char *file_name)
1314 {
1315   static unsigned int last_file_lookup_index = 0;
1316   register char *fn;
1317   register unsigned i;
1318   const char *fnam;
1319   long long cdt = 0;
1320   long ebk = 0;
1321   short ffb = 0;
1322   char rfo = 0;
1323   long siz = 0;
1324   int ver = 0;
1325 
1326   fnam = full_name (file_name);
1327 
1328   /* Check to see if the file name that was searched on the previous call
1329      matches this file name. If so, return the index.  */
1330   if (last_file_lookup_index != 0)
1331     {
1332       fn = file_info_table[last_file_lookup_index].file_name;
1333       if (strcmp (fnam, fn) == 0)
1334 	return last_file_lookup_index;
1335     }
1336 
1337   /* Didn't match the previous lookup, search the table */
1338   for (i = 1; i < file_info_table_in_use; ++i)
1339     {
1340       fn = file_info_table[i].file_name;
1341       if (strcmp (fnam, fn) == 0)
1342 	{
1343 	  last_file_lookup_index = i;
1344 	  return i;
1345 	}
1346     }
1347 
1348   /* Prepare to add a new table entry by making sure there is enough space in
1349      the table to do so.  If not, expand the current table.  */
1350   if (file_info_table_in_use == file_info_table_allocated)
1351     {
1352 
1353       file_info_table_allocated += FILE_TABLE_INCREMENT;
1354       file_info_table = XRESIZEVEC (dst_file_info_entry, file_info_table,
1355 				    file_info_table_allocated);
1356     }
1357 
1358   if (vms_file_stats_name (file_name, &cdt, &siz, &rfo, &ver) == 0)
1359     {
1360       ebk = siz / 512 + 1;
1361       ffb = siz - ((siz / 512) * 512);
1362     }
1363 
1364   /* Add the new entry to the end of the filename table.  */
1365   file_info_table[file_info_table_in_use].file_name = xstrdup (fnam);
1366   file_info_table[file_info_table_in_use].max_line = 0;
1367   file_info_table[file_info_table_in_use].cdt = cdt;
1368   file_info_table[file_info_table_in_use].ebk = ebk;
1369   file_info_table[file_info_table_in_use].ffb = ffb;
1370   file_info_table[file_info_table_in_use].rfo = rfo;
1371 
1372   last_file_lookup_index = file_info_table_in_use++;
1373   return last_file_lookup_index;
1374 }
1375 
1376 /* Output a label to mark the beginning of a source code line entry
1377    and record information relating to this source line, in
1378    'line_info_table' for later output of the .debug_line section.  */
1379 
1380 static void
1381 vmsdbgout_write_source_line (unsigned line, const char *filename,
1382                              int /* discriminator */, bool /* is_stmt */)
1383 {
1384   dst_line_info_ref line_info;
1385 
1386   targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL,
1387                                   line_info_table_in_use);
1388 
1389   /* Expand the line info table if necessary.  */
1390   if (line_info_table_in_use == line_info_table_allocated)
1391     {
1392       line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
1393       line_info_table = XRESIZEVEC (dst_line_info_entry, line_info_table,
1394                                     line_info_table_allocated);
1395     }
1396 
1397   /* Add the new entry at the end of the line_info_table.  */
1398   line_info = &line_info_table[line_info_table_in_use++];
1399   line_info->dst_file_num = lookup_filename (filename);
1400   line_info->dst_line_num = line;
1401   if (line > file_info_table[line_info->dst_file_num].max_line)
1402     file_info_table[line_info->dst_file_num].max_line = line;
1403 }
1404 
1405 static void
1406 vmsdbgout_source_line (register unsigned line, register const char *filename,
1407                        int discriminator, bool is_stmt)
1408 {
1409   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1410     (*dwarf2_debug_hooks.source_line) (line, filename, discriminator, is_stmt);
1411 
1412   if (debug_info_level >= DINFO_LEVEL_TERSE)
1413     vmsdbgout_write_source_line (line, filename, discriminator, is_stmt);
1414 }
1415 
1416 /* Record the beginning of a new source file, for later output.
1417    At present, unimplemented.  */
1418 
1419 static void
1420 vmsdbgout_start_source_file (unsigned int lineno, const char *filename)
1421 {
1422   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1423     (*dwarf2_debug_hooks.start_source_file) (lineno, filename);
1424 }
1425 
1426 /* Record the end of a source file, for later output.
1427    At present, unimplemented.  */
1428 
1429 static void
1430 vmsdbgout_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED)
1431 {
1432   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1433     (*dwarf2_debug_hooks.end_source_file) (lineno);
1434 }
1435 
1436 /* Set up for Debug output at the start of compilation.  */
1437 
1438 static void
1439 vmsdbgout_init (const char *filename)
1440 {
1441   const char *language_string = lang_hooks.name;
1442 
1443   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1444     (*dwarf2_debug_hooks.init) (filename);
1445 
1446   if (debug_info_level == DINFO_LEVEL_NONE)
1447     return;
1448 
1449   /* Remember the name of the primary input file.  */
1450   primary_filename = filename;
1451 
1452   /* Allocate the initial hunk of the file_info_table.  */
1453   file_info_table = XCNEWVEC (dst_file_info_entry, FILE_TABLE_INCREMENT);
1454   file_info_table_allocated = FILE_TABLE_INCREMENT;
1455   /* Skip the first entry - file numbers begin at 1.  */
1456   file_info_table_in_use = 1;
1457 
1458   funcnam_table.create (FUNC_TABLE_INITIAL);
1459   funcnum_table.create (FUNC_TABLE_INITIAL);
1460 
1461   /* Allocate the initial hunk of the line_info_table.  */
1462   line_info_table = XCNEWVEC (dst_line_info_entry, LINE_INFO_TABLE_INCREMENT);
1463   line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
1464   /* zero-th entry is allocated, but unused */
1465   line_info_table_in_use = 1;
1466 
1467   lookup_filename (primary_filename);
1468 
1469   if (lang_GNU_C ())
1470     module_language = DST_K_C;
1471   else if (lang_GNU_CXX ())
1472     module_language = DST_K_CXX;
1473   else if (!strcmp (language_string, "GNU Ada"))
1474     module_language = DST_K_ADA;
1475   else if (!strcmp (language_string, "GNU F77"))
1476     module_language = DST_K_FORTRAN;
1477   else
1478     module_language = DST_K_UNKNOWN;
1479 
1480   module_producer = concat (language_string, " ", version_string, NULL);
1481 
1482   ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
1483 
1484 }
1485 
1486 /* Not implemented in VMS Debug.  */
1487 
1488 static void
1489 vmsdbgout_assembly_start (void)
1490 {
1491   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1492     (*dwarf2_debug_hooks.assembly_start) ();
1493 }
1494 
1495 /* Not implemented in VMS Debug.  */
1496 
1497 static void
1498 vmsdbgout_define (unsigned int lineno, const char *buffer)
1499 {
1500   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1501     (*dwarf2_debug_hooks.define) (lineno, buffer);
1502 }
1503 
1504 /* Not implemented in VMS Debug.  */
1505 
1506 static void
1507 vmsdbgout_undef (unsigned int lineno, const char *buffer)
1508 {
1509   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1510     (*dwarf2_debug_hooks.undef) (lineno, buffer);
1511 }
1512 
1513 /* Not implemented in VMS Debug.  */
1514 
1515 static void
1516 vmsdbgout_decl (tree decl)
1517 {
1518   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1519     (*dwarf2_debug_hooks.function_decl) (decl);
1520 }
1521 
1522 /* Not implemented in VMS Debug.  */
1523 
1524 static void
1525 vmsdbgout_global_decl (tree decl)
1526 {
1527   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1528     (*dwarf2_debug_hooks.global_decl) (decl);
1529 }
1530 
1531 /* Not implemented in VMS Debug.  */
1532 
1533 static void
1534 vmsdbgout_type_decl (tree decl, int local)
1535 {
1536   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1537     (*dwarf2_debug_hooks.type_decl) (decl, local);
1538 }
1539 
1540 /* Not implemented in VMS Debug.  */
1541 
1542 static void
1543 vmsdbgout_abstract_function (tree decl)
1544 {
1545   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1546     (*dwarf2_debug_hooks.outlining_inline_function) (decl);
1547 }
1548 
1549 /* Output stuff that Debug requires at the end of every file and generate the
1550    VMS Debug debugging info.  */
1551 
1552 static void
1553 vmsdbgout_finish (const char *filename ATTRIBUTE_UNUSED)
1554 {
1555   unsigned int i, ifunc;
1556   int totsize;
1557 
1558   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1559     (*dwarf2_debug_hooks.finish) (filename);
1560 
1561   if (debug_info_level == DINFO_LEVEL_NONE)
1562     return;
1563 
1564   /* Output a terminator label for the .text section.  */
1565   switch_to_section (text_section);
1566   targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
1567 
1568   /* Output debugging information.
1569      Warning! Do not change the name of the .vmsdebug section without
1570      changing it in the assembler also.  */
1571   switch_to_section (get_named_section (NULL, ".vmsdebug", 0));
1572   ASM_OUTPUT_ALIGN (asm_out_file, 0);
1573 
1574   totsize = write_modbeg (1);
1575   FOR_EACH_VEC_ELT (funcnum_table, i, ifunc)
1576     {
1577       totsize += write_rtnbeg (i, 1);
1578       totsize += write_rtnend (i, 1);
1579     }
1580   totsize += write_pclines (1);
1581 
1582   write_modbeg (0);
1583   FOR_EACH_VEC_ELT (funcnum_table, i, ifunc)
1584     {
1585       write_rtnbeg (i, 0);
1586       write_rtnend (i, 0);
1587     }
1588   write_pclines (0);
1589 
1590   if (debug_info_level > DINFO_LEVEL_TERSE)
1591     {
1592       totsize = write_srccorrs (1);
1593       write_srccorrs (0);
1594     }
1595 
1596   totsize = write_modend (1);
1597   write_modend (0);
1598 }
1599 
1600 /* Need for both Dwarf2 on IVMS and VMS Debug on AVMS */
1601 
1602 #ifdef VMS
1603 #define __NEW_STARLET 1
1604 #include <vms/rms.h>
1605 #include <vms/atrdef.h>
1606 #include <vms/fibdef.h>
1607 #include <vms/stsdef.h>
1608 #include <vms/iodef.h>
1609 #include <vms/fatdef.h>
1610 #include <vms/descrip.h>
1611 #include <unixlib.h>
1612 
1613 #define MAXPATH 256
1614 
1615 /* descrip.h doesn't have everything ...  */
1616 typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) ));
1617 struct dsc$descriptor_fib
1618 {
1619   unsigned int fib$l_len;
1620   __fibdef_ptr32 fib$l_addr;
1621 };
1622 
1623 /* I/O Status Block.  */
1624 struct IOSB
1625 {
1626   unsigned short status, count;
1627   unsigned int devdep;
1628 };
1629 
1630 static char *tryfile;
1631 
1632 /* Variable length string.  */
1633 struct vstring
1634 {
1635   short length;
1636   char string[NAM$C_MAXRSS+1];
1637 };
1638 
1639 static char filename_buff [MAXPATH];
1640 static char vms_filespec [MAXPATH];
1641 
1642 /* Callback function for filespec style conversion.  */
1643 
1644 static int
1645 translate_unix (char *name, int type ATTRIBUTE_UNUSED)
1646 {
1647   strncpy (filename_buff, name, MAXPATH);
1648   filename_buff [MAXPATH - 1] = (char) 0;
1649   return 0;
1650 }
1651 
1652 /* Wrapper for DECC function that converts a Unix filespec
1653    to VMS style filespec.  */
1654 
1655 static char *
1656 to_vms_file_spec (char *filespec)
1657 {
1658   strncpy (vms_filespec, "", MAXPATH);
1659   decc$to_vms (filespec, translate_unix, 1, 1);
1660   strncpy (vms_filespec, filename_buff, MAXPATH);
1661 
1662   vms_filespec [MAXPATH - 1] = (char) 0;
1663 
1664   return vms_filespec;
1665 }
1666 
1667 #else
1668 #define VMS_EPOCH_OFFSET 35067168000000000LL
1669 #define VMS_GRANULARITY_FACTOR 10000000
1670 #endif
1671 
1672 /* Return VMS file date, size, format, version given a name.  */
1673 
1674 int
1675 vms_file_stats_name (const char *filename, long long *cdt, long *siz, char *rfo,
1676 		     int *ver)
1677 {
1678 #ifdef VMS
1679   struct FAB fab;
1680   struct NAM nam;
1681 
1682   unsigned long long create;
1683   FAT recattr;
1684   char ascnamebuff [256];
1685 
1686   ATRDEF atrlst[]
1687     = {
1688       { ATR$S_CREDATE,  ATR$C_CREDATE,  &create },
1689       { ATR$S_RECATTR,  ATR$C_RECATTR,  &recattr },
1690       { ATR$S_ASCNAME,  ATR$C_ASCNAME,  &ascnamebuff },
1691       { 0, 0, 0}
1692     };
1693 
1694   FIBDEF fib;
1695   struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1696 
1697   struct IOSB iosb;
1698 
1699   long status;
1700   unsigned short chan;
1701 
1702   struct vstring file;
1703   struct dsc$descriptor_s filedsc
1704     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1705   struct vstring device;
1706   struct dsc$descriptor_s devicedsc
1707     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1708   struct vstring result;
1709   struct dsc$descriptor_s resultdsc
1710     = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1711 
1712   if (strcmp (filename, "<internal>") == 0
1713       || strcmp (filename, "<built-in>") == 0)
1714     {
1715       if (cdt)
1716 	*cdt = 0;
1717 
1718       if (siz)
1719 	*siz = 0;
1720 
1721       if (rfo)
1722 	*rfo = 0;
1723 
1724       if (ver)
1725         *ver = 0;
1726 
1727       return 0;
1728     }
1729 
1730   tryfile = to_vms_file_spec (filename);
1731 
1732   /* Allocate and initialize a FAB and NAM structures.  */
1733   fab = cc$rms_fab;
1734   nam = cc$rms_nam;
1735 
1736   nam.nam$l_esa = file.string;
1737   nam.nam$b_ess = NAM$C_MAXRSS;
1738   nam.nam$l_rsa = result.string;
1739   nam.nam$b_rss = NAM$C_MAXRSS;
1740   fab.fab$l_fna = tryfile;
1741   fab.fab$b_fns = strlen (tryfile);
1742   fab.fab$l_nam = &nam;
1743 
1744   /* Validate filespec syntax and device existence.  */
1745   status = SYS$PARSE (&fab, 0, 0);
1746   if ((status & 1) != 1)
1747     return 1;
1748 
1749   file.string[nam.nam$b_esl] = 0;
1750 
1751   /* Find matching filespec.  */
1752   status = SYS$SEARCH (&fab, 0, 0);
1753   if ((status & 1) != 1)
1754     return 1;
1755 
1756   file.string[nam.nam$b_esl] = 0;
1757   result.string[result.length=nam.nam$b_rsl] = 0;
1758 
1759   /* Get the device name and assign an IO channel.  */
1760   strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1761   devicedsc.dsc$w_length  = nam.nam$b_dev;
1762   chan = 0;
1763   status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1764   if ((status & 1) != 1)
1765     return 1;
1766 
1767   /* Initialize the FIB and fill in the directory id field.  */
1768   memset (&fib, 0, sizeof (fib));
1769   fib.fib$w_did[0]  = nam.nam$w_did[0];
1770   fib.fib$w_did[1]  = nam.nam$w_did[1];
1771   fib.fib$w_did[2]  = nam.nam$w_did[2];
1772   fib.fib$l_acctl = 0;
1773   fib.fib$l_wcc = 0;
1774   strcpy (file.string, (strrchr (result.string, ']') + 1));
1775   filedsc.dsc$w_length = strlen (file.string);
1776   result.string[result.length = 0] = 0;
1777 
1778   /* Open and close the file to fill in the attributes.  */
1779   status
1780     = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1781 		&fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1782   if ((status & 1) != 1)
1783     return 1;
1784   if ((iosb.status & 1) != 1)
1785     return 1;
1786 
1787   result.string[result.length] = 0;
1788   status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1789 		     &atrlst, 0);
1790   if ((status & 1) != 1)
1791     return 1;
1792   if ((iosb.status & 1) != 1)
1793     return 1;
1794 
1795   /* Deassign the channel and exit.  */
1796   status = SYS$DASSGN (chan);
1797   if ((status & 1) != 1)
1798     return 1;
1799 
1800   if (cdt) *cdt = create;
1801   if (siz) *siz = (512 * 65536 * recattr.fat$w_efblkh) +
1802                   (512 * (recattr.fat$w_efblkl - 1)) +
1803                   recattr.fat$w_ffbyte;
1804   if (rfo) *rfo = recattr.fat$v_rtype;
1805   if (ver) *ver = strtol (strrchr (ascnamebuff, ';')+1, 0, 10);
1806 
1807   return 0;
1808 #else
1809   struct stat buff;
1810 
1811   if ((stat (filename, &buff)) != 0)
1812      return 1;
1813 
1814   if (cdt)
1815     *cdt = (long long) (buff.st_mtime * VMS_GRANULARITY_FACTOR)
1816                         + VMS_EPOCH_OFFSET;
1817 
1818   if (siz)
1819     *siz = buff.st_size;
1820 
1821   if (rfo)
1822     *rfo = 2; /* Stream LF format */
1823 
1824   if (ver)
1825     *ver = 1;
1826 
1827   return 0;
1828 #endif
1829 }
1830 #endif
1831