OSDN Git Service

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