OSDN Git Service

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