OSDN Git Service

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