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