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