OSDN Git Service

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