OSDN Git Service

2010-09-18 Kai Tietz <kai.tietz@onevision.com>
[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   /* Unix paths really mess up VMS debug. Better to just output the
1314      base filename.  */
1315   strcpy (fullname_buff, filename);
1316 #endif
1317
1318   return fullname_buff;
1319 }
1320
1321 /* Lookup a filename (in the list of filenames that we know about here in
1322    vmsdbgout.c) and return its "index".  The index of each (known) filename is
1323    just a unique number which is associated with only that one filename.  We
1324    need such numbers for the sake of generating labels  and references
1325    to those files numbers.  If the filename given as an argument is not
1326    found in our current list, add it to the list and assign it the next
1327    available unique index number.  In order to speed up searches, we remember
1328    the index of the filename was looked up last.  This handles the majority of
1329    all searches.  */
1330
1331 static unsigned int
1332 lookup_filename (const char *file_name)
1333 {
1334   static unsigned int last_file_lookup_index = 0;
1335   register char *fn;
1336   register unsigned i;
1337   const char *fnam;
1338   char flen;
1339   long long cdt = 0;
1340   long ebk = 0;
1341   short ffb = 0;
1342   char rfo = 0;
1343   long siz = 0;
1344   int ver = 0;
1345
1346   fnam = full_name (file_name);
1347   flen = strlen (fnam);
1348
1349   /* Check to see if the file name that was searched on the previous call
1350      matches this file name. If so, return the index.  */
1351   if (last_file_lookup_index != 0)
1352     {
1353       fn = file_info_table[last_file_lookup_index].file_name;
1354       if (strcmp (fnam, fn) == 0)
1355         return last_file_lookup_index;
1356     }
1357
1358   /* Didn't match the previous lookup, search the table */
1359   for (i = 1; i < file_info_table_in_use; ++i)
1360     {
1361       fn = file_info_table[i].file_name;
1362       if (strcmp (fnam, fn) == 0)
1363         {
1364           last_file_lookup_index = i;
1365           return i;
1366         }
1367     }
1368
1369   /* Prepare to add a new table entry by making sure there is enough space in
1370      the table to do so.  If not, expand the current table.  */
1371   if (file_info_table_in_use == file_info_table_allocated)
1372     {
1373
1374       file_info_table_allocated += FILE_TABLE_INCREMENT;
1375       file_info_table = XRESIZEVEC (dst_file_info_entry, file_info_table,
1376                                     file_info_table_allocated);
1377     }
1378
1379   if (vms_file_stats_name (file_name, &cdt, &siz, &rfo, &ver) == 0)
1380     {
1381       ebk = siz / 512 + 1;
1382       ffb = siz - ((siz / 512) * 512);
1383     }
1384
1385   /* Add the new entry to the end of the filename table.  */
1386   file_info_table[file_info_table_in_use].file_name = xstrdup (fnam);
1387   file_info_table[file_info_table_in_use].max_line = 0;
1388   file_info_table[file_info_table_in_use].cdt = cdt;
1389   file_info_table[file_info_table_in_use].ebk = ebk;
1390   file_info_table[file_info_table_in_use].ffb = ffb;
1391   file_info_table[file_info_table_in_use].rfo = rfo;
1392   file_info_table[file_info_table_in_use].flen = flen;
1393
1394   last_file_lookup_index = file_info_table_in_use++;
1395   return last_file_lookup_index;
1396 }
1397
1398 /* Output a label to mark the beginning of a source code line entry
1399    and record information relating to this source line, in
1400    'line_info_table' for later output of the .debug_line section.  */
1401
1402 static void
1403 vmsdbgout_source_line (register unsigned line, register const char *filename,
1404                        int discriminator, bool is_stmt)
1405 {
1406   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1407     (*dwarf2_debug_hooks.source_line) (line, filename, discriminator, is_stmt);
1408
1409   if (debug_info_level >= DINFO_LEVEL_TERSE)
1410     {
1411       dst_line_info_ref line_info;
1412
1413       targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL,
1414                                       line_info_table_in_use);
1415
1416       /* Expand the line info table if necessary.  */
1417       if (line_info_table_in_use == line_info_table_allocated)
1418         {
1419           line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
1420           line_info_table = XRESIZEVEC (dst_line_info_entry, line_info_table,
1421                                         line_info_table_allocated);
1422         }
1423
1424       /* Add the new entry at the end of the line_info_table.  */
1425       line_info = &line_info_table[line_info_table_in_use++];
1426       line_info->dst_file_num = lookup_filename (filename);
1427       line_info->dst_line_num = line;
1428       if (line > file_info_table[line_info->dst_file_num].max_line)
1429         file_info_table[line_info->dst_file_num].max_line = line;
1430     }
1431 }
1432
1433 /* Record the beginning of a new source file, for later output.
1434    At present, unimplemented.  */
1435
1436 static void
1437 vmsdbgout_start_source_file (unsigned int lineno, const char *filename)
1438 {
1439   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1440     (*dwarf2_debug_hooks.start_source_file) (lineno, filename);
1441 }
1442
1443 /* Record the end of a source file, for later output.
1444    At present, unimplemented.  */
1445
1446 static void
1447 vmsdbgout_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED)
1448 {
1449   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1450     (*dwarf2_debug_hooks.end_source_file) (lineno);
1451 }
1452
1453 /* Set up for Debug output at the start of compilation.  */
1454
1455 static void
1456 vmsdbgout_init (const char *main_input_filename)
1457 {
1458   const char *language_string = lang_hooks.name;
1459
1460   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1461     (*dwarf2_debug_hooks.init) (main_input_filename);
1462
1463   if (debug_info_level == DINFO_LEVEL_NONE)
1464     return;
1465
1466   /* Remember the name of the primary input file.  */
1467   primary_filename = main_input_filename;
1468
1469   /* Allocate the initial hunk of the file_info_table.  */
1470   file_info_table = XCNEWVEC (dst_file_info_entry, FILE_TABLE_INCREMENT);
1471   file_info_table_allocated = FILE_TABLE_INCREMENT;
1472   /* Skip the first entry - file numbers begin at 1.  */
1473   file_info_table_in_use = 1;
1474
1475   funcnam_table = VEC_alloc (char_p, heap, FUNC_TABLE_INITIAL);
1476   funcnum_table = VEC_alloc (unsigned, heap, FUNC_TABLE_INITIAL);
1477
1478   /* Allocate the initial hunk of the line_info_table.  */
1479   line_info_table = XCNEWVEC (dst_line_info_entry, LINE_INFO_TABLE_INCREMENT);
1480   line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
1481   /* zero-th entry is allocated, but unused */
1482   line_info_table_in_use = 1;
1483
1484   lookup_filename (primary_filename);
1485
1486   if (!strcmp (language_string, "GNU C"))
1487     module_language = DST_K_C;
1488   else if (!strcmp (language_string, "GNU C++"))
1489     module_language = DST_K_CXX;
1490   else if (!strcmp (language_string, "GNU Ada"))
1491     module_language = DST_K_ADA;
1492   else if (!strcmp (language_string, "GNU F77"))
1493     module_language = DST_K_FORTRAN;
1494   else
1495     module_language = DST_K_UNKNOWN;
1496
1497   module_producer = concat (language_string, " ", version_string, NULL);
1498
1499   ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
1500
1501 }
1502
1503 /* Not implemented in VMS Debug.  */
1504
1505 static void
1506 vmsdbgout_assembly_start (void)
1507 {
1508   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1509     (*dwarf2_debug_hooks.assembly_start) ();
1510 }
1511
1512 /* Not implemented in VMS Debug.  */
1513
1514 static void
1515 vmsdbgout_define (unsigned int lineno, const char *buffer)
1516 {
1517   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1518     (*dwarf2_debug_hooks.define) (lineno, buffer);
1519 }
1520
1521 /* Not implemented in VMS Debug.  */
1522
1523 static void
1524 vmsdbgout_undef (unsigned int lineno, const char *buffer)
1525 {
1526   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1527     (*dwarf2_debug_hooks.undef) (lineno, buffer);
1528 }
1529
1530 /* Not implemented in VMS Debug.  */
1531
1532 static void
1533 vmsdbgout_decl (tree decl)
1534 {
1535   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1536     (*dwarf2_debug_hooks.function_decl) (decl);
1537 }
1538
1539 /* Not implemented in VMS Debug.  */
1540
1541 static void
1542 vmsdbgout_global_decl (tree decl)
1543 {
1544   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1545     (*dwarf2_debug_hooks.global_decl) (decl);
1546 }
1547
1548 /* Not implemented in VMS Debug.  */
1549
1550 static void
1551 vmsdbgout_type_decl (tree decl, int local)
1552 {
1553   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1554     (*dwarf2_debug_hooks.type_decl) (decl, local);
1555 }
1556
1557 /* Not implemented in VMS Debug.  */
1558
1559 static void
1560 vmsdbgout_abstract_function (tree decl)
1561 {
1562   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1563     (*dwarf2_debug_hooks.outlining_inline_function) (decl);
1564 }
1565
1566 /* Output stuff that Debug requires at the end of every file and generate the
1567    VMS Debug debugging info.  */
1568
1569 static void
1570 vmsdbgout_finish (const char *main_input_filename ATTRIBUTE_UNUSED)
1571 {
1572   unsigned int i, ifunc;
1573   int totsize;
1574
1575   if (write_symbols == VMS_AND_DWARF2_DEBUG)
1576     (*dwarf2_debug_hooks.finish) (main_input_filename);
1577
1578   if (debug_info_level == DINFO_LEVEL_NONE)
1579     return;
1580
1581   /* Output a terminator label for the .text section.  */
1582   switch_to_section (text_section);
1583   targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
1584
1585   /* Output debugging information.
1586      Warning! Do not change the name of the .vmsdebug section without
1587      changing it in the assembler also.  */
1588   switch_to_section (get_named_section (NULL, ".vmsdebug", 0));
1589   ASM_OUTPUT_ALIGN (asm_out_file, 0);
1590
1591   totsize = write_modbeg (1);
1592   FOR_EACH_VEC_ELT (unsigned, funcnum_table, i, ifunc)
1593     {
1594       totsize += write_rtnbeg (i, 1);
1595       totsize += write_rtnend (i, 1);
1596     }
1597   totsize += write_pclines (1);
1598
1599   write_modbeg (0);
1600   FOR_EACH_VEC_ELT (unsigned, funcnum_table, i, ifunc)
1601     {
1602       write_rtnbeg (i, 0);
1603       write_rtnend (i, 0);
1604     }
1605   write_pclines (0);
1606
1607   if (debug_info_level > DINFO_LEVEL_TERSE)
1608     {
1609       totsize = write_srccorrs (1);
1610       write_srccorrs (0);
1611     }
1612
1613   totsize = write_modend (1);
1614   write_modend (0);
1615 }
1616
1617 /* Need for both Dwarf2 on IVMS and VMS Debug on AVMS */
1618
1619 #ifdef VMS
1620 #define __NEW_STARLET 1
1621 #include <vms/rms.h>
1622 #include <vms/atrdef.h>
1623 #include <vms/fibdef.h>
1624 #include <vms/stsdef.h>
1625 #include <vms/iodef.h>
1626 #include <vms/fatdef.h>
1627 #include <errno.h>
1628 #include <vms/descrip.h>
1629 #include <string.h>
1630 #include <unixlib.h>
1631
1632 #define MAXPATH 256
1633
1634 /* descrip.h doesn't have everything ...  */
1635 typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) ));
1636 struct dsc$descriptor_fib
1637 {
1638   unsigned int fib$l_len;
1639   __fibdef_ptr32 fib$l_addr;
1640 };
1641
1642 /* I/O Status Block.  */
1643 struct IOSB
1644 {
1645   unsigned short status, count;
1646   unsigned int devdep;
1647 };
1648
1649 static char *tryfile;
1650
1651 /* Variable length string.  */
1652 struct vstring
1653 {
1654   short length;
1655   char string[NAM$C_MAXRSS+1];
1656 };
1657
1658 static char filename_buff [MAXPATH];
1659 static char vms_filespec [MAXPATH];
1660
1661 /* Callback function for filespec style conversion.  */
1662
1663 static int
1664 translate_unix (char *name, int type ATTRIBUTE_UNUSED)
1665 {
1666   strncpy (filename_buff, name, MAXPATH);
1667   filename_buff [MAXPATH - 1] = (char) 0;
1668   return 0;
1669 }
1670
1671 /* Wrapper for DECC function that converts a Unix filespec
1672    to VMS style filespec.  */
1673
1674 static char *
1675 to_vms_file_spec (char *filespec)
1676 {
1677   strncpy (vms_filespec, "", MAXPATH);
1678   decc$to_vms (filespec, translate_unix, 1, 1);
1679   strncpy (vms_filespec, filename_buff, MAXPATH);
1680
1681   vms_filespec [MAXPATH - 1] = (char) 0;
1682
1683   return vms_filespec;
1684 }
1685
1686 #else
1687 #define VMS_EPOCH_OFFSET 35067168000000000
1688 #define VMS_GRANULARITY_FACTOR 10000000
1689 #endif
1690
1691 /* Return VMS file date, size, format, version given a name.  */
1692
1693 int
1694 vms_file_stats_name (const char *filename, long long *cdt, long *siz, char *rfo,
1695                      int *ver)
1696 {
1697 #ifdef VMS
1698   struct FAB fab;
1699   struct NAM nam;
1700
1701   unsigned long long create;
1702   FAT recattr;
1703   char ascnamebuff [256];
1704
1705   ATRDEF atrlst[]
1706     = {
1707       { ATR$S_CREDATE,  ATR$C_CREDATE,  &create },
1708       { ATR$S_RECATTR,  ATR$C_RECATTR,  &recattr },
1709       { ATR$S_ASCNAME,  ATR$C_ASCNAME,  &ascnamebuff },
1710       { 0, 0, 0}
1711     };
1712
1713   FIBDEF fib;
1714   struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib};
1715
1716   struct IOSB iosb;
1717
1718   long status;
1719   unsigned short chan;
1720
1721   struct vstring file;
1722   struct dsc$descriptor_s filedsc
1723     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string};
1724   struct vstring device;
1725   struct dsc$descriptor_s devicedsc
1726     = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string};
1727   struct vstring result;
1728   struct dsc$descriptor_s resultdsc
1729     = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string};
1730
1731   if (strcmp (filename, "<internal>") == 0
1732       || strcmp (filename, "<built-in>") == 0)
1733     {
1734       if (cdt)
1735         *cdt = 0;
1736
1737       if (siz)
1738         *siz = 0;
1739
1740       if (rfo)
1741         *rfo = 0;
1742
1743       if (ver)
1744         *ver = 0;
1745
1746       return 0;
1747     }
1748
1749   tryfile = to_vms_file_spec (filename);
1750
1751   /* Allocate and initialize a FAB and NAM structures.  */
1752   fab = cc$rms_fab;
1753   nam = cc$rms_nam;
1754
1755   nam.nam$l_esa = file.string;
1756   nam.nam$b_ess = NAM$C_MAXRSS;
1757   nam.nam$l_rsa = result.string;
1758   nam.nam$b_rss = NAM$C_MAXRSS;
1759   fab.fab$l_fna = tryfile;
1760   fab.fab$b_fns = strlen (tryfile);
1761   fab.fab$l_nam = &nam;
1762
1763   /* Validate filespec syntax and device existence.  */
1764   status = SYS$PARSE (&fab, 0, 0);
1765   if ((status & 1) != 1)
1766     return 1;
1767
1768   file.string[nam.nam$b_esl] = 0;
1769
1770   /* Find matching filespec.  */
1771   status = SYS$SEARCH (&fab, 0, 0);
1772   if ((status & 1) != 1)
1773     return 1;
1774
1775   file.string[nam.nam$b_esl] = 0;
1776   result.string[result.length=nam.nam$b_rsl] = 0;
1777
1778   /* Get the device name and assign an IO channel.  */
1779   strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev);
1780   devicedsc.dsc$w_length  = nam.nam$b_dev;
1781   chan = 0;
1782   status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0);
1783   if ((status & 1) != 1)
1784     return 1;
1785
1786   /* Initialize the FIB and fill in the directory id field.  */
1787   memset (&fib, 0, sizeof (fib));
1788   fib.fib$w_did[0]  = nam.nam$w_did[0];
1789   fib.fib$w_did[1]  = nam.nam$w_did[1];
1790   fib.fib$w_did[2]  = nam.nam$w_did[2];
1791   fib.fib$l_acctl = 0;
1792   fib.fib$l_wcc = 0;
1793   strcpy (file.string, (strrchr (result.string, ']') + 1));
1794   filedsc.dsc$w_length = strlen (file.string);
1795   result.string[result.length = 0] = 0;
1796
1797   /* Open and close the file to fill in the attributes.  */
1798   status
1799     = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0,
1800                 &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0);
1801   if ((status & 1) != 1)
1802     return 1;
1803   if ((iosb.status & 1) != 1)
1804     return 1;
1805
1806   result.string[result.length] = 0;
1807   status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0,
1808                      &atrlst, 0);
1809   if ((status & 1) != 1)
1810     return 1;
1811   if ((iosb.status & 1) != 1)
1812     return 1;
1813
1814   /* Deassign the channel and exit.  */
1815   status = SYS$DASSGN (chan);
1816   if ((status & 1) != 1)
1817     return 1;
1818
1819   if (cdt) *cdt = create;
1820   if (siz) *siz = (512 * 65536 * recattr.fat$w_efblkh) +
1821                   (512 * (recattr.fat$w_efblkl - 1)) +
1822                   recattr.fat$w_ffbyte;
1823   if (rfo) *rfo = recattr.fat$v_rtype;
1824   if (ver) *ver = strtol (strrchr (ascnamebuff, ';')+1, 0, 10);
1825
1826   return 0;
1827 #else
1828   struct stat buff;
1829
1830   if ((stat (filename, &buff)) != 0)
1831      return 1;
1832
1833   if (cdt)
1834     *cdt = (long long) (buff.st_mtime * VMS_GRANULARITY_FACTOR)
1835                         + VMS_EPOCH_OFFSET;
1836
1837   if (siz)
1838     *siz = buff.st_size;
1839
1840   if (rfo)
1841     *rfo = 2; /* Stream LF format */
1842
1843   if (ver)
1844     *ver = 1;
1845
1846   return 0;
1847 #endif
1848 }
1849 #endif