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