OSDN Git Service

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