Update gcc-50 to SVN version 225979 (gcc-5-branch)
[dragonfly.git] / contrib / gcc-5.0 / gcc / vmsdbgout.c
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 \f
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 \f
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