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