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