OSDN Git Service

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