OSDN Git Service

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