dwarf2out.c revision 50397
150397Sobrien/* Output Dwarf2 format symbol table information from the GNU C compiler.
250397Sobrien   Copyright (C) 1992, 93, 95, 96, 97, 1998 Free Software Foundation, Inc.
350397Sobrien   Contributed by Gary Funck (gary@intrepid.com).
450397Sobrien   Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
550397Sobrien   Extensively modified by Jason Merrill (jason@cygnus.com).
650397Sobrien
750397SobrienThis file is part of GNU CC.
850397Sobrien
950397SobrienGNU CC is free software; you can redistribute it and/or modify
1050397Sobrienit under the terms of the GNU General Public License as published by
1150397Sobrienthe Free Software Foundation; either version 2, or (at your option)
1250397Sobrienany later version.
1350397Sobrien
1450397SobrienGNU CC is distributed in the hope that it will be useful,
1550397Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1650397SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1750397SobrienGNU General Public License for more details.
1850397Sobrien
1950397SobrienYou should have received a copy of the GNU General Public License
2050397Sobrienalong with GNU CC; see the file COPYING.  If not, write to
2150397Sobrienthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
2250397Sobrien
2350397Sobrien/* The first part of this file deals with the DWARF 2 frame unwind
2450397Sobrien   information, which is also used by the GCC efficient exception handling
2550397Sobrien   mechanism.  The second part, controlled only by an #ifdef
2650397Sobrien   DWARF2_DEBUGGING_INFO, deals with the other DWARF 2 debugging
2750397Sobrien   information.  */
2850397Sobrien
2950397Sobrien#include "config.h"
3050397Sobrien#include "system.h"
3150397Sobrien#include "defaults.h"
3250397Sobrien#include "tree.h"
3350397Sobrien#include "flags.h"
3450397Sobrien#include "rtl.h"
3550397Sobrien#include "hard-reg-set.h"
3650397Sobrien#include "regs.h"
3750397Sobrien#include "insn-config.h"
3850397Sobrien#include "reload.h"
3950397Sobrien#include "output.h"
4050397Sobrien#include "expr.h"
4150397Sobrien#include "except.h"
4250397Sobrien#include "dwarf2.h"
4350397Sobrien#include "dwarf2out.h"
4450397Sobrien#include "toplev.h"
4550397Sobrien#include "dyn-string.h"
4650397Sobrien
4750397Sobrien/* We cannot use <assert.h> in GCC source, since that would include
4850397Sobrien   GCC's assert.h, which may not be compatible with the host compiler.  */
4950397Sobrien#undef assert
5050397Sobrien#ifdef NDEBUG
5150397Sobrien# define assert(e)
5250397Sobrien#else
5350397Sobrien# define assert(e) do { if (! (e)) abort (); } while (0)
5450397Sobrien#endif
5550397Sobrien
5650397Sobrien/* Decide whether we want to emit frame unwind information for the current
5750397Sobrien   translation unit.  */
5850397Sobrien
5950397Sobrienint
6050397Sobriendwarf2out_do_frame ()
6150397Sobrien{
6250397Sobrien  return (write_symbols == DWARF2_DEBUG
6350397Sobrien#ifdef DWARF2_FRAME_INFO
6450397Sobrien          || DWARF2_FRAME_INFO
6550397Sobrien#endif
6650397Sobrien#ifdef DWARF2_UNWIND_INFO
6750397Sobrien	  || (flag_exceptions && ! exceptions_via_longjmp)
6850397Sobrien#endif
6950397Sobrien	  );
7050397Sobrien}
7150397Sobrien
7250397Sobrien#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
7350397Sobrien
7450397Sobrien#ifndef __GNUC__
7550397Sobrien#define inline
7650397Sobrien#endif
7750397Sobrien
7850397Sobrien/* How to start an assembler comment.  */
7950397Sobrien#ifndef ASM_COMMENT_START
8050397Sobrien#define ASM_COMMENT_START ";#"
8150397Sobrien#endif
8250397Sobrien
8350397Sobrientypedef struct dw_cfi_struct *dw_cfi_ref;
8450397Sobrientypedef struct dw_fde_struct *dw_fde_ref;
8550397Sobrientypedef union  dw_cfi_oprnd_struct *dw_cfi_oprnd_ref;
8650397Sobrien
8750397Sobrien/* Call frames are described using a sequence of Call Frame
8850397Sobrien   Information instructions.  The register number, offset
8950397Sobrien   and address fields are provided as possible operands;
9050397Sobrien   their use is selected by the opcode field.  */
9150397Sobrien
9250397Sobrientypedef union dw_cfi_oprnd_struct
9350397Sobrien{
9450397Sobrien  unsigned long dw_cfi_reg_num;
9550397Sobrien  long int dw_cfi_offset;
9650397Sobrien  char *dw_cfi_addr;
9750397Sobrien}
9850397Sobriendw_cfi_oprnd;
9950397Sobrien
10050397Sobrientypedef struct dw_cfi_struct
10150397Sobrien{
10250397Sobrien  dw_cfi_ref dw_cfi_next;
10350397Sobrien  enum dwarf_call_frame_info dw_cfi_opc;
10450397Sobrien  dw_cfi_oprnd dw_cfi_oprnd1;
10550397Sobrien  dw_cfi_oprnd dw_cfi_oprnd2;
10650397Sobrien}
10750397Sobriendw_cfi_node;
10850397Sobrien
10950397Sobrien/* All call frame descriptions (FDE's) in the GCC generated DWARF
11050397Sobrien   refer to a single Common Information Entry (CIE), defined at
11150397Sobrien   the beginning of the .debug_frame section.  This used of a single
11250397Sobrien   CIE obviates the need to keep track of multiple CIE's
11350397Sobrien   in the DWARF generation routines below.  */
11450397Sobrien
11550397Sobrientypedef struct dw_fde_struct
11650397Sobrien{
11750397Sobrien  char *dw_fde_begin;
11850397Sobrien  char *dw_fde_current_label;
11950397Sobrien  char *dw_fde_end;
12050397Sobrien  dw_cfi_ref dw_fde_cfi;
12150397Sobrien}
12250397Sobriendw_fde_node;
12350397Sobrien
12450397Sobrien/* Maximum size (in bytes) of an artificially generated label.   */
12550397Sobrien#define MAX_ARTIFICIAL_LABEL_BYTES	30
12650397Sobrien
12750397Sobrien/* Make sure we know the sizes of the various types dwarf can describe. These
12850397Sobrien   are only defaults.  If the sizes are different for your target, you should
12950397Sobrien   override these values by defining the appropriate symbols in your tm.h
13050397Sobrien   file.  */
13150397Sobrien
13250397Sobrien#ifndef CHAR_TYPE_SIZE
13350397Sobrien#define CHAR_TYPE_SIZE BITS_PER_UNIT
13450397Sobrien#endif
13550397Sobrien#ifndef PTR_SIZE
13650397Sobrien#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
13750397Sobrien#endif
13850397Sobrien
13950397Sobrien/* The size in bytes of a DWARF field indicating an offset or length
14050397Sobrien   relative to a debug info section, specified to be 4 bytes in the DWARF-2
14150397Sobrien   specification.  The SGI/MIPS ABI defines it to be the same as PTR_SIZE.  */
14250397Sobrien
14350397Sobrien#ifndef DWARF_OFFSET_SIZE
14450397Sobrien#define DWARF_OFFSET_SIZE 4
14550397Sobrien#endif
14650397Sobrien
14750397Sobrien#define DWARF_VERSION 2
14850397Sobrien
14950397Sobrien/* Round SIZE up to the nearest BOUNDARY.  */
15050397Sobrien#define DWARF_ROUND(SIZE,BOUNDARY) \
15150397Sobrien  (((SIZE) + (BOUNDARY) - 1) & ~((BOUNDARY) - 1))
15250397Sobrien
15350397Sobrien/* Offsets recorded in opcodes are a multiple of this alignment factor.  */
15450397Sobrien#ifdef STACK_GROWS_DOWNWARD
15550397Sobrien#define DWARF_CIE_DATA_ALIGNMENT (-UNITS_PER_WORD)
15650397Sobrien#else
15750397Sobrien#define DWARF_CIE_DATA_ALIGNMENT UNITS_PER_WORD
15850397Sobrien#endif
15950397Sobrien
16050397Sobrien/* A pointer to the base of a table that contains frame description
16150397Sobrien   information for each routine.  */
16250397Sobrienstatic dw_fde_ref fde_table;
16350397Sobrien
16450397Sobrien/* Number of elements currently allocated for fde_table.  */
16550397Sobrienstatic unsigned fde_table_allocated;
16650397Sobrien
16750397Sobrien/* Number of elements in fde_table currently in use.  */
16850397Sobrienstatic unsigned fde_table_in_use;
16950397Sobrien
17050397Sobrien/* Size (in elements) of increments by which we may expand the
17150397Sobrien   fde_table.  */
17250397Sobrien#define FDE_TABLE_INCREMENT 256
17350397Sobrien
17450397Sobrien/* A list of call frame insns for the CIE.  */
17550397Sobrienstatic dw_cfi_ref cie_cfi_head;
17650397Sobrien
17750397Sobrien/* The number of the current function definition for which debugging
17850397Sobrien   information is being generated.  These numbers range from 1 up to the
17950397Sobrien   maximum number of function definitions contained within the current
18050397Sobrien   compilation unit.  These numbers are used to create unique label id's
18150397Sobrien   unique to each function definition.  */
18250397Sobrienstatic unsigned current_funcdef_number = 0;
18350397Sobrien
18450397Sobrien/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram
18550397Sobrien   attribute that accelerates the lookup of the FDE associated
18650397Sobrien   with the subprogram.  This variable holds the table index of the FDE
18750397Sobrien   associated with the current function (body) definition.  */
18850397Sobrienstatic unsigned current_funcdef_fde;
18950397Sobrien
19050397Sobrien/* Forward declarations for functions defined in this file.  */
19150397Sobrien
19250397Sobrienstatic char *stripattributes		PROTO((char *));
19350397Sobrienstatic char *dwarf_cfi_name		PROTO((unsigned));
19450397Sobrienstatic dw_cfi_ref new_cfi		PROTO((void));
19550397Sobrienstatic void add_cfi			PROTO((dw_cfi_ref *, dw_cfi_ref));
19650397Sobrienstatic unsigned long size_of_uleb128	PROTO((unsigned long));
19750397Sobrienstatic unsigned long size_of_sleb128	PROTO((long));
19850397Sobrienstatic void output_uleb128		PROTO((unsigned long));
19950397Sobrienstatic void output_sleb128		PROTO((long));
20050397Sobrienstatic void add_fde_cfi			PROTO((char *, dw_cfi_ref));
20150397Sobrienstatic void lookup_cfa_1		PROTO((dw_cfi_ref, unsigned long *,
20250397Sobrien					       long *));
20350397Sobrienstatic void lookup_cfa			PROTO((unsigned long *, long *));
20450397Sobrienstatic void reg_save			PROTO((char *, unsigned, unsigned,
20550397Sobrien					       long));
20650397Sobrienstatic void initial_return_save		PROTO((rtx));
20750397Sobrienstatic void output_cfi			PROTO((dw_cfi_ref, dw_fde_ref));
20850397Sobrienstatic void output_call_frame_info	PROTO((int));
20950397Sobrienstatic unsigned reg_number		PROTO((rtx));
21050397Sobrienstatic void dwarf2out_stack_adjust	PROTO((rtx));
21150397Sobrien
21250397Sobrien/* Definitions of defaults for assembler-dependent names of various
21350397Sobrien   pseudo-ops and section names.
21450397Sobrien   Theses may be overridden in the tm.h file (if necessary) for a particular
21550397Sobrien   assembler.  */
21650397Sobrien
21750397Sobrien#ifdef OBJECT_FORMAT_ELF
21850397Sobrien#ifndef UNALIGNED_SHORT_ASM_OP
21950397Sobrien#define UNALIGNED_SHORT_ASM_OP	".2byte"
22050397Sobrien#endif
22150397Sobrien#ifndef UNALIGNED_INT_ASM_OP
22250397Sobrien#define UNALIGNED_INT_ASM_OP	".4byte"
22350397Sobrien#endif
22450397Sobrien#ifndef UNALIGNED_DOUBLE_INT_ASM_OP
22550397Sobrien#define UNALIGNED_DOUBLE_INT_ASM_OP	".8byte"
22650397Sobrien#endif
22750397Sobrien#endif /* OBJECT_FORMAT_ELF */
22850397Sobrien
22950397Sobrien#ifndef ASM_BYTE_OP
23050397Sobrien#define ASM_BYTE_OP		".byte"
23150397Sobrien#endif
23250397Sobrien
23350397Sobrien/* Data and reference forms for relocatable data.  */
23450397Sobrien#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4)
23550397Sobrien#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4)
23650397Sobrien
23750397Sobrien/* Pseudo-op for defining a new section.  */
23850397Sobrien#ifndef SECTION_ASM_OP
23950397Sobrien#define SECTION_ASM_OP	".section"
24050397Sobrien#endif
24150397Sobrien
24250397Sobrien/* The default format used by the ASM_OUTPUT_SECTION macro (see below) to
24350397Sobrien   print the SECTION_ASM_OP and the section name.  The default here works for
24450397Sobrien   almost all svr4 assemblers, except for the sparc, where the section name
24550397Sobrien   must be enclosed in double quotes.  (See sparcv4.h).  */
24650397Sobrien#ifndef SECTION_FORMAT
24750397Sobrien#ifdef PUSHSECTION_FORMAT
24850397Sobrien#define SECTION_FORMAT PUSHSECTION_FORMAT
24950397Sobrien#else
25050397Sobrien#define SECTION_FORMAT		"\t%s\t%s\n"
25150397Sobrien#endif
25250397Sobrien#endif
25350397Sobrien
25450397Sobrien#ifndef FRAME_SECTION
25550397Sobrien#define FRAME_SECTION		".debug_frame"
25650397Sobrien#endif
25750397Sobrien
25850397Sobrien#ifndef FUNC_BEGIN_LABEL
25950397Sobrien#define FUNC_BEGIN_LABEL	"LFB"
26050397Sobrien#endif
26150397Sobrien#ifndef FUNC_END_LABEL
26250397Sobrien#define FUNC_END_LABEL		"LFE"
26350397Sobrien#endif
26450397Sobrien#define CIE_AFTER_SIZE_LABEL	"LSCIE"
26550397Sobrien#define CIE_END_LABEL		"LECIE"
26650397Sobrien#define CIE_LENGTH_LABEL	"LLCIE"
26750397Sobrien#define FDE_AFTER_SIZE_LABEL	"LSFDE"
26850397Sobrien#define FDE_END_LABEL		"LEFDE"
26950397Sobrien#define FDE_LENGTH_LABEL	"LLFDE"
27050397Sobrien
27150397Sobrien/* Definitions of defaults for various types of primitive assembly language
27250397Sobrien   output operations.  These may be overridden from within the tm.h file,
27350397Sobrien   but typically, that is unnecessary.  */
27450397Sobrien
27550397Sobrien#ifndef ASM_OUTPUT_SECTION
27650397Sobrien#define ASM_OUTPUT_SECTION(FILE, SECTION) \
27750397Sobrien  fprintf ((FILE), SECTION_FORMAT, SECTION_ASM_OP, SECTION)
27850397Sobrien#endif
27950397Sobrien
28050397Sobrien#ifndef ASM_OUTPUT_DWARF_DATA1
28150397Sobrien#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \
28250397Sobrien  fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) (VALUE))
28350397Sobrien#endif
28450397Sobrien
28550397Sobrien#ifndef ASM_OUTPUT_DWARF_DELTA1
28650397Sobrien#define ASM_OUTPUT_DWARF_DELTA1(FILE,LABEL1,LABEL2)			\
28750397Sobrien do {	fprintf ((FILE), "\t%s\t", ASM_BYTE_OP);			\
28850397Sobrien	assemble_name (FILE, LABEL1);					\
28950397Sobrien	fprintf (FILE, "-");						\
29050397Sobrien	assemble_name (FILE, LABEL2);					\
29150397Sobrien  } while (0)
29250397Sobrien#endif
29350397Sobrien
29450397Sobrien#ifdef UNALIGNED_INT_ASM_OP
29550397Sobrien
29650397Sobrien#ifndef UNALIGNED_OFFSET_ASM_OP
29750397Sobrien#define UNALIGNED_OFFSET_ASM_OP \
29850397Sobrien  (DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
29950397Sobrien#endif
30050397Sobrien
30150397Sobrien#ifndef UNALIGNED_WORD_ASM_OP
30250397Sobrien#define UNALIGNED_WORD_ASM_OP \
30350397Sobrien  (PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
30450397Sobrien#endif
30550397Sobrien
30650397Sobrien#ifndef ASM_OUTPUT_DWARF_DELTA2
30750397Sobrien#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2)			\
30850397Sobrien do {	fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP);		\
30950397Sobrien	assemble_name (FILE, LABEL1);					\
31050397Sobrien	fprintf (FILE, "-");						\
31150397Sobrien	assemble_name (FILE, LABEL2);					\
31250397Sobrien  } while (0)
31350397Sobrien#endif
31450397Sobrien
31550397Sobrien#ifndef ASM_OUTPUT_DWARF_DELTA4
31650397Sobrien#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2)			\
31750397Sobrien do {	fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP);		\
31850397Sobrien	assemble_name (FILE, LABEL1);					\
31950397Sobrien	fprintf (FILE, "-");						\
32050397Sobrien	assemble_name (FILE, LABEL2);					\
32150397Sobrien  } while (0)
32250397Sobrien#endif
32350397Sobrien
32450397Sobrien#ifndef ASM_OUTPUT_DWARF_DELTA
32550397Sobrien#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2)			\
32650397Sobrien do {	fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP);		\
32750397Sobrien	assemble_name (FILE, LABEL1);					\
32850397Sobrien	fprintf (FILE, "-");						\
32950397Sobrien	assemble_name (FILE, LABEL2);					\
33050397Sobrien  } while (0)
33150397Sobrien#endif
33250397Sobrien
33350397Sobrien#ifndef ASM_OUTPUT_DWARF_ADDR_DELTA
33450397Sobrien#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2)			\
33550397Sobrien do {	fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP);		\
33650397Sobrien	assemble_name (FILE, LABEL1);					\
33750397Sobrien	fprintf (FILE, "-");						\
33850397Sobrien	assemble_name (FILE, LABEL2);					\
33950397Sobrien  } while (0)
34050397Sobrien#endif
34150397Sobrien
34250397Sobrien#ifndef ASM_OUTPUT_DWARF_ADDR
34350397Sobrien#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL)				\
34450397Sobrien do {	fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP);		\
34550397Sobrien	assemble_name (FILE, LABEL);					\
34650397Sobrien  } while (0)
34750397Sobrien#endif
34850397Sobrien
34950397Sobrien#ifndef ASM_OUTPUT_DWARF_ADDR_CONST
35050397Sobrien#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,ADDR)				\
35150397Sobrien  fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, (ADDR))
35250397Sobrien#endif
35350397Sobrien
35450397Sobrien#ifndef ASM_OUTPUT_DWARF_OFFSET4
35550397Sobrien#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \
35650397Sobrien do {	fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP);		\
35750397Sobrien	assemble_name (FILE, LABEL);					\
35850397Sobrien  } while (0)
35950397Sobrien#endif
36050397Sobrien
36150397Sobrien#ifndef ASM_OUTPUT_DWARF_OFFSET
36250397Sobrien#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL)				\
36350397Sobrien do {	fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP);		\
36450397Sobrien	assemble_name (FILE, LABEL);					\
36550397Sobrien  } while (0)
36650397Sobrien#endif
36750397Sobrien
36850397Sobrien#ifndef ASM_OUTPUT_DWARF_DATA2
36950397Sobrien#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \
37050397Sobrien  fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, (unsigned) (VALUE))
37150397Sobrien#endif
37250397Sobrien
37350397Sobrien#ifndef ASM_OUTPUT_DWARF_DATA4
37450397Sobrien#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \
37550397Sobrien  fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_INT_ASM_OP, (unsigned) (VALUE))
37650397Sobrien#endif
37750397Sobrien
37850397Sobrien#ifndef ASM_OUTPUT_DWARF_DATA
37950397Sobrien#define ASM_OUTPUT_DWARF_DATA(FILE,VALUE) \
38050397Sobrien  fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_OFFSET_ASM_OP, \
38150397Sobrien	   (unsigned long) (VALUE))
38250397Sobrien#endif
38350397Sobrien
38450397Sobrien#ifndef ASM_OUTPUT_DWARF_ADDR_DATA
38550397Sobrien#define ASM_OUTPUT_DWARF_ADDR_DATA(FILE,VALUE) \
38650397Sobrien  fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_WORD_ASM_OP, \
38750397Sobrien	   (unsigned long) (VALUE))
38850397Sobrien#endif
38950397Sobrien
39050397Sobrien#ifndef ASM_OUTPUT_DWARF_DATA8
39150397Sobrien#define ASM_OUTPUT_DWARF_DATA8(FILE,HIGH_VALUE,LOW_VALUE)		\
39250397Sobrien  do {									\
39350397Sobrien    if (WORDS_BIG_ENDIAN)						\
39450397Sobrien      {									\
39550397Sobrien	fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (HIGH_VALUE));\
39650397Sobrien	fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (LOW_VALUE));\
39750397Sobrien      }									\
39850397Sobrien    else								\
39950397Sobrien      {									\
40050397Sobrien	fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (LOW_VALUE)); \
40150397Sobrien	fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (HIGH_VALUE)); \
40250397Sobrien      }									\
40350397Sobrien  } while (0)
40450397Sobrien#endif
40550397Sobrien
40650397Sobrien#else /* UNALIGNED_INT_ASM_OP */
40750397Sobrien
40850397Sobrien/* We don't have unaligned support, let's hope the normal output works for
40950397Sobrien   .debug_frame.  */
41050397Sobrien
41150397Sobrien#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \
41250397Sobrien  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, LABEL), PTR_SIZE, 1)
41350397Sobrien
41450397Sobrien#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \
41550397Sobrien  assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1)
41650397Sobrien
41750397Sobrien#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \
41850397Sobrien  assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1)
41950397Sobrien
42050397Sobrien#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2)			\
42150397Sobrien  assemble_integer (gen_rtx_MINUS (HImode,			      	\
42250397Sobrien			     gen_rtx_SYMBOL_REF (Pmode, LABEL1),   	\
42350397Sobrien			     gen_rtx_SYMBOL_REF (Pmode, LABEL2)),	\
42450397Sobrien		    2, 1)
42550397Sobrien
42650397Sobrien#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2)			\
42750397Sobrien  assemble_integer (gen_rtx_MINUS (SImode,			      	\
42850397Sobrien			     gen_rtx_SYMBOL_REF (Pmode, LABEL1),   	\
42950397Sobrien			     gen_rtx_SYMBOL_REF (Pmode, LABEL2)),	\
43050397Sobrien		    4, 1)
43150397Sobrien
43250397Sobrien#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2)			\
43350397Sobrien  assemble_integer (gen_rtx_MINUS (Pmode,				\
43450397Sobrien			     gen_rtx_SYMBOL_REF (Pmode, LABEL1),	\
43550397Sobrien			     gen_rtx_SYMBOL_REF (Pmode, LABEL2)),	\
43650397Sobrien		    PTR_SIZE, 1)
43750397Sobrien
43850397Sobrien#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \
43950397Sobrien  ASM_OUTPUT_DWARF_DELTA4 (FILE,LABEL1,LABEL2)
44050397Sobrien
44150397Sobrien#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \
44250397Sobrien  assemble_integer (GEN_INT (VALUE), 4, 1)
44350397Sobrien
44450397Sobrien#endif /* UNALIGNED_INT_ASM_OP */
44550397Sobrien
44650397Sobrien#ifdef SET_ASM_OP
44750397Sobrien#ifndef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
44850397Sobrien#define ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL(FILE, SY, HI, LO)    	\
44950397Sobrien do {									\
45050397Sobrien  fprintf (FILE, "\t%s\t", SET_ASM_OP);					\
45150397Sobrien  assemble_name (FILE, SY);						\
45250397Sobrien  fputc (',', FILE);							\
45350397Sobrien  assemble_name (FILE, HI);						\
45450397Sobrien  fputc ('-', FILE);							\
45550397Sobrien  assemble_name (FILE, LO);						\
45650397Sobrien } while (0)
45750397Sobrien#endif
45850397Sobrien#endif /* SET_ASM_OP */
45950397Sobrien
46050397Sobrien/* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing
46150397Sobrien   newline is produced.  When flag_debug_asm is asserted, we add commentary
46250397Sobrien   at the end of the line, so we must avoid output of a newline here.  */
46350397Sobrien#ifndef ASM_OUTPUT_DWARF_STRING
46450397Sobrien#define ASM_OUTPUT_DWARF_STRING(FILE,P) \
46550397Sobrien  do {									      \
46650397Sobrien    register int slen = strlen(P);                                            \
46750397Sobrien    register char *p = (P);  	                                              \
46850397Sobrien    register int i;					                      \
46950397Sobrien    fprintf (FILE, "\t.ascii \"");				              \
47050397Sobrien    for (i = 0; i < slen; i++)					              \
47150397Sobrien      {								              \
47250397Sobrien	  register int c = p[i];					      \
47350397Sobrien	  if (c == '\"' || c == '\\')					      \
47450397Sobrien	    putc ('\\', FILE);					              \
47550397Sobrien	  if (c >= ' ' && c < 0177)					      \
47650397Sobrien	    putc (c, FILE);					              \
47750397Sobrien	  else								      \
47850397Sobrien	    {								      \
47950397Sobrien	      fprintf (FILE, "\\%o", c);			              \
48050397Sobrien	    }							 	      \
48150397Sobrien      }								              \
48250397Sobrien    fprintf (FILE, "\\0\"");					              \
48350397Sobrien  }									      \
48450397Sobrien  while (0)
48550397Sobrien#endif
48650397Sobrien
48750397Sobrien/* The DWARF 2 CFA column which tracks the return address.  Normally this
48850397Sobrien   is the column for PC, or the first column after all of the hard
48950397Sobrien   registers.  */
49050397Sobrien#ifndef DWARF_FRAME_RETURN_COLUMN
49150397Sobrien#ifdef PC_REGNUM
49250397Sobrien#define DWARF_FRAME_RETURN_COLUMN 	DWARF_FRAME_REGNUM (PC_REGNUM)
49350397Sobrien#else
49450397Sobrien#define DWARF_FRAME_RETURN_COLUMN 	FIRST_PSEUDO_REGISTER
49550397Sobrien#endif
49650397Sobrien#endif
49750397Sobrien
49850397Sobrien/* The mapping from gcc register number to DWARF 2 CFA column number.  By
49950397Sobrien   default, we just provide columns for all registers.  */
50050397Sobrien#ifndef DWARF_FRAME_REGNUM
50150397Sobrien#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
50250397Sobrien#endif
50350397Sobrien
50450397Sobrien/* Hook used by __throw.  */
50550397Sobrien
50650397Sobrienrtx
50750397Sobrienexpand_builtin_dwarf_fp_regnum ()
50850397Sobrien{
50950397Sobrien  return GEN_INT (DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM));
51050397Sobrien}
51150397Sobrien
51250397Sobrien/* The offset from the incoming value of %sp to the top of the stack frame
51350397Sobrien   for the current function.  */
51450397Sobrien#ifndef INCOMING_FRAME_SP_OFFSET
51550397Sobrien#define INCOMING_FRAME_SP_OFFSET 0
51650397Sobrien#endif
51750397Sobrien
51850397Sobrien/* Return a pointer to a copy of the section string name S with all
51950397Sobrien   attributes stripped off, and an asterisk prepended (for assemble_name).  */
52050397Sobrien
52150397Sobrienstatic inline char *
52250397Sobrienstripattributes (s)
52350397Sobrien     char *s;
52450397Sobrien{
52550397Sobrien  char *stripped = xmalloc (strlen (s) + 2);
52650397Sobrien  char *p = stripped;
52750397Sobrien
52850397Sobrien  *p++ = '*';
52950397Sobrien
53050397Sobrien  while (*s && *s != ',')
53150397Sobrien    *p++ = *s++;
53250397Sobrien
53350397Sobrien  *p = '\0';
53450397Sobrien  return stripped;
53550397Sobrien}
53650397Sobrien
53750397Sobrien/* Return the register number described by a given RTL node.  */
53850397Sobrien
53950397Sobrienstatic unsigned
54050397Sobrienreg_number (rtl)
54150397Sobrien     register rtx rtl;
54250397Sobrien{
54350397Sobrien  register unsigned regno = REGNO (rtl);
54450397Sobrien
54550397Sobrien  if (regno >= FIRST_PSEUDO_REGISTER)
54650397Sobrien    {
54750397Sobrien      warning ("internal regno botch: regno = %d\n", regno);
54850397Sobrien      regno = 0;
54950397Sobrien    }
55050397Sobrien
55150397Sobrien  regno = DBX_REGISTER_NUMBER (regno);
55250397Sobrien  return regno;
55350397Sobrien}
55450397Sobrien
55550397Sobrienstruct reg_size_range
55650397Sobrien{
55750397Sobrien  int beg;
55850397Sobrien  int end;
55950397Sobrien  int size;
56050397Sobrien};
56150397Sobrien
56250397Sobrien/* Given a register number in REG_TREE, return an rtx for its size in bytes.
56350397Sobrien   We do this in kind of a roundabout way, by building up a list of
56450397Sobrien   register size ranges and seeing where our register falls in one of those
56550397Sobrien   ranges.  We need to do it this way because REG_TREE is not a constant,
56650397Sobrien   and the target macros were not designed to make this task easy.  */
56750397Sobrien
56850397Sobrienrtx
56950397Sobrienexpand_builtin_dwarf_reg_size (reg_tree, target)
57050397Sobrien     tree reg_tree;
57150397Sobrien     rtx target;
57250397Sobrien{
57350397Sobrien  enum machine_mode mode;
57450397Sobrien  int size;
57550397Sobrien  struct reg_size_range ranges[5];
57650397Sobrien  tree t, t2;
57750397Sobrien
57850397Sobrien  int i = 0;
57950397Sobrien  int n_ranges = 0;
58050397Sobrien  int last_size = -1;
58150397Sobrien
58250397Sobrien  for (; i < FIRST_PSEUDO_REGISTER; ++i)
58350397Sobrien    {
58450397Sobrien      /* The return address is out of order on the MIPS, and we don't use
58550397Sobrien	 copy_reg for it anyway, so we don't care here how large it is.  */
58650397Sobrien      if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN)
58750397Sobrien	continue;
58850397Sobrien
58950397Sobrien      mode = reg_raw_mode[i];
59050397Sobrien
59150397Sobrien      /* CCmode is arbitrarily given a size of 4 bytes.  It is more useful
59250397Sobrien	 to use the same size as word_mode, since that reduces the number
59350397Sobrien	 of ranges we need.  It should not matter, since the result should
59450397Sobrien	 never be used for a condition code register anyways.  */
59550397Sobrien      if (GET_MODE_CLASS (mode) == MODE_CC)
59650397Sobrien	mode = word_mode;
59750397Sobrien
59850397Sobrien      size = GET_MODE_SIZE (mode);
59950397Sobrien
60050397Sobrien      /* If this register is not valid in the specified mode and
60150397Sobrien	 we have a previous size, use that for the size of this
60250397Sobrien	 register to avoid making junk tiny ranges.  */
60350397Sobrien      if (! HARD_REGNO_MODE_OK (i, mode) && last_size != -1)
60450397Sobrien	size = last_size;
60550397Sobrien
60650397Sobrien      if (size != last_size)
60750397Sobrien	{
60850397Sobrien	  ranges[n_ranges].beg = i;
60950397Sobrien	  ranges[n_ranges].size = last_size = size;
61050397Sobrien	  ++n_ranges;
61150397Sobrien	  if (n_ranges >= 5)
61250397Sobrien	    abort ();
61350397Sobrien	}
61450397Sobrien      ranges[n_ranges-1].end = i;
61550397Sobrien    }
61650397Sobrien
61750397Sobrien  /* The usual case: fp regs surrounded by general regs.  */
61850397Sobrien  if (n_ranges == 3 && ranges[0].size == ranges[2].size)
61950397Sobrien    {
62050397Sobrien      if ((DWARF_FRAME_REGNUM (ranges[1].end)
62150397Sobrien	   - DWARF_FRAME_REGNUM (ranges[1].beg))
62250397Sobrien	  != ranges[1].end - ranges[1].beg)
62350397Sobrien	abort ();
62450397Sobrien      t  = fold (build (GE_EXPR, integer_type_node, reg_tree,
62550397Sobrien			build_int_2 (DWARF_FRAME_REGNUM (ranges[1].beg), 0)));
62650397Sobrien      t2 = fold (build (LE_EXPR, integer_type_node, reg_tree,
62750397Sobrien			build_int_2 (DWARF_FRAME_REGNUM (ranges[1].end), 0)));
62850397Sobrien      t = fold (build (TRUTH_ANDIF_EXPR, integer_type_node, t, t2));
62950397Sobrien      t = fold (build (COND_EXPR, integer_type_node, t,
63050397Sobrien		       build_int_2 (ranges[1].size, 0),
63150397Sobrien		       build_int_2 (ranges[0].size, 0)));
63250397Sobrien    }
63350397Sobrien  else
63450397Sobrien    {
63550397Sobrien      --n_ranges;
63650397Sobrien      t = build_int_2 (ranges[n_ranges].size, 0);
63750397Sobrien      size = DWARF_FRAME_REGNUM (ranges[n_ranges].beg);
63850397Sobrien      for (; n_ranges--; )
63950397Sobrien	{
64050397Sobrien	  if ((DWARF_FRAME_REGNUM (ranges[n_ranges].end)
64150397Sobrien	       - DWARF_FRAME_REGNUM (ranges[n_ranges].beg))
64250397Sobrien	      != ranges[n_ranges].end - ranges[n_ranges].beg)
64350397Sobrien	    abort ();
64450397Sobrien	  if (DWARF_FRAME_REGNUM (ranges[n_ranges].beg) >= size)
64550397Sobrien	    abort ();
64650397Sobrien	  size = DWARF_FRAME_REGNUM (ranges[n_ranges].beg);
64750397Sobrien	  t2 = fold (build (LE_EXPR, integer_type_node, reg_tree,
64850397Sobrien			    build_int_2 (DWARF_FRAME_REGNUM
64950397Sobrien					 (ranges[n_ranges].end), 0)));
65050397Sobrien	  t = fold (build (COND_EXPR, integer_type_node, t2,
65150397Sobrien			   build_int_2 (ranges[n_ranges].size, 0), t));
65250397Sobrien	}
65350397Sobrien    }
65450397Sobrien  return expand_expr (t, target, Pmode, 0);
65550397Sobrien}
65650397Sobrien
65750397Sobrien/* Convert a DWARF call frame info. operation to its string name */
65850397Sobrien
65950397Sobrienstatic char *
66050397Sobriendwarf_cfi_name (cfi_opc)
66150397Sobrien     register unsigned cfi_opc;
66250397Sobrien{
66350397Sobrien  switch (cfi_opc)
66450397Sobrien    {
66550397Sobrien    case DW_CFA_advance_loc:
66650397Sobrien      return "DW_CFA_advance_loc";
66750397Sobrien    case DW_CFA_offset:
66850397Sobrien      return "DW_CFA_offset";
66950397Sobrien    case DW_CFA_restore:
67050397Sobrien      return "DW_CFA_restore";
67150397Sobrien    case DW_CFA_nop:
67250397Sobrien      return "DW_CFA_nop";
67350397Sobrien    case DW_CFA_set_loc:
67450397Sobrien      return "DW_CFA_set_loc";
67550397Sobrien    case DW_CFA_advance_loc1:
67650397Sobrien      return "DW_CFA_advance_loc1";
67750397Sobrien    case DW_CFA_advance_loc2:
67850397Sobrien      return "DW_CFA_advance_loc2";
67950397Sobrien    case DW_CFA_advance_loc4:
68050397Sobrien      return "DW_CFA_advance_loc4";
68150397Sobrien    case DW_CFA_offset_extended:
68250397Sobrien      return "DW_CFA_offset_extended";
68350397Sobrien    case DW_CFA_restore_extended:
68450397Sobrien      return "DW_CFA_restore_extended";
68550397Sobrien    case DW_CFA_undefined:
68650397Sobrien      return "DW_CFA_undefined";
68750397Sobrien    case DW_CFA_same_value:
68850397Sobrien      return "DW_CFA_same_value";
68950397Sobrien    case DW_CFA_register:
69050397Sobrien      return "DW_CFA_register";
69150397Sobrien    case DW_CFA_remember_state:
69250397Sobrien      return "DW_CFA_remember_state";
69350397Sobrien    case DW_CFA_restore_state:
69450397Sobrien      return "DW_CFA_restore_state";
69550397Sobrien    case DW_CFA_def_cfa:
69650397Sobrien      return "DW_CFA_def_cfa";
69750397Sobrien    case DW_CFA_def_cfa_register:
69850397Sobrien      return "DW_CFA_def_cfa_register";
69950397Sobrien    case DW_CFA_def_cfa_offset:
70050397Sobrien      return "DW_CFA_def_cfa_offset";
70150397Sobrien
70250397Sobrien    /* SGI/MIPS specific */
70350397Sobrien    case DW_CFA_MIPS_advance_loc8:
70450397Sobrien      return "DW_CFA_MIPS_advance_loc8";
70550397Sobrien
70650397Sobrien    /* GNU extensions */
70750397Sobrien    case DW_CFA_GNU_window_save:
70850397Sobrien      return "DW_CFA_GNU_window_save";
70950397Sobrien    case DW_CFA_GNU_args_size:
71050397Sobrien      return "DW_CFA_GNU_args_size";
71150397Sobrien
71250397Sobrien    default:
71350397Sobrien      return "DW_CFA_<unknown>";
71450397Sobrien    }
71550397Sobrien}
71650397Sobrien
71750397Sobrien/* Return a pointer to a newly allocated Call Frame Instruction.  */
71850397Sobrien
71950397Sobrienstatic inline dw_cfi_ref
72050397Sobriennew_cfi ()
72150397Sobrien{
72250397Sobrien  register dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (sizeof (dw_cfi_node));
72350397Sobrien
72450397Sobrien  cfi->dw_cfi_next = NULL;
72550397Sobrien  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0;
72650397Sobrien  cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0;
72750397Sobrien
72850397Sobrien  return cfi;
72950397Sobrien}
73050397Sobrien
73150397Sobrien/* Add a Call Frame Instruction to list of instructions.  */
73250397Sobrien
73350397Sobrienstatic inline void
73450397Sobrienadd_cfi (list_head, cfi)
73550397Sobrien     register dw_cfi_ref *list_head;
73650397Sobrien     register dw_cfi_ref cfi;
73750397Sobrien{
73850397Sobrien  register dw_cfi_ref *p;
73950397Sobrien
74050397Sobrien  /* Find the end of the chain.  */
74150397Sobrien  for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next)
74250397Sobrien    ;
74350397Sobrien
74450397Sobrien  *p = cfi;
74550397Sobrien}
74650397Sobrien
74750397Sobrien/* Generate a new label for the CFI info to refer to.  */
74850397Sobrien
74950397Sobrienchar *
75050397Sobriendwarf2out_cfi_label ()
75150397Sobrien{
75250397Sobrien  static char label[20];
75350397Sobrien  static unsigned long label_num = 0;
75450397Sobrien
75550397Sobrien  ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", label_num++);
75650397Sobrien  ASM_OUTPUT_LABEL (asm_out_file, label);
75750397Sobrien
75850397Sobrien  return label;
75950397Sobrien}
76050397Sobrien
76150397Sobrien/* Add CFI to the current fde at the PC value indicated by LABEL if specified,
76250397Sobrien   or to the CIE if LABEL is NULL.  */
76350397Sobrien
76450397Sobrienstatic void
76550397Sobrienadd_fde_cfi (label, cfi)
76650397Sobrien     register char *label;
76750397Sobrien     register dw_cfi_ref cfi;
76850397Sobrien{
76950397Sobrien  if (label)
77050397Sobrien    {
77150397Sobrien      register dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
77250397Sobrien
77350397Sobrien      if (*label == 0)
77450397Sobrien	label = dwarf2out_cfi_label ();
77550397Sobrien
77650397Sobrien      if (fde->dw_fde_current_label == NULL
77750397Sobrien	  || strcmp (label, fde->dw_fde_current_label) != 0)
77850397Sobrien	{
77950397Sobrien	  register dw_cfi_ref xcfi;
78050397Sobrien
78150397Sobrien	  fde->dw_fde_current_label = label = xstrdup (label);
78250397Sobrien
78350397Sobrien	  /* Set the location counter to the new label.  */
78450397Sobrien	  xcfi = new_cfi ();
78550397Sobrien	  xcfi->dw_cfi_opc = DW_CFA_advance_loc4;
78650397Sobrien	  xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
78750397Sobrien	  add_cfi (&fde->dw_fde_cfi, xcfi);
78850397Sobrien	}
78950397Sobrien
79050397Sobrien      add_cfi (&fde->dw_fde_cfi, cfi);
79150397Sobrien    }
79250397Sobrien
79350397Sobrien  else
79450397Sobrien    add_cfi (&cie_cfi_head, cfi);
79550397Sobrien}
79650397Sobrien
79750397Sobrien/* Subroutine of lookup_cfa.  */
79850397Sobrien
79950397Sobrienstatic inline void
80050397Sobrienlookup_cfa_1 (cfi, regp, offsetp)
80150397Sobrien     register dw_cfi_ref cfi;
80250397Sobrien     register unsigned long *regp;
80350397Sobrien     register long *offsetp;
80450397Sobrien{
80550397Sobrien  switch (cfi->dw_cfi_opc)
80650397Sobrien    {
80750397Sobrien    case DW_CFA_def_cfa_offset:
80850397Sobrien      *offsetp = cfi->dw_cfi_oprnd1.dw_cfi_offset;
80950397Sobrien      break;
81050397Sobrien    case DW_CFA_def_cfa_register:
81150397Sobrien      *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
81250397Sobrien      break;
81350397Sobrien    case DW_CFA_def_cfa:
81450397Sobrien      *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
81550397Sobrien      *offsetp = cfi->dw_cfi_oprnd2.dw_cfi_offset;
81650397Sobrien      break;
81750397Sobrien    default:
81850397Sobrien      break;
81950397Sobrien    }
82050397Sobrien}
82150397Sobrien
82250397Sobrien/* Find the previous value for the CFA.  */
82350397Sobrien
82450397Sobrienstatic void
82550397Sobrienlookup_cfa (regp, offsetp)
82650397Sobrien     register unsigned long *regp;
82750397Sobrien     register long *offsetp;
82850397Sobrien{
82950397Sobrien  register dw_cfi_ref cfi;
83050397Sobrien
83150397Sobrien  *regp = (unsigned long) -1;
83250397Sobrien  *offsetp = 0;
83350397Sobrien
83450397Sobrien  for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
83550397Sobrien    lookup_cfa_1 (cfi, regp, offsetp);
83650397Sobrien
83750397Sobrien  if (fde_table_in_use)
83850397Sobrien    {
83950397Sobrien      register dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
84050397Sobrien      for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
84150397Sobrien	lookup_cfa_1 (cfi, regp, offsetp);
84250397Sobrien    }
84350397Sobrien}
84450397Sobrien
84550397Sobrien/* The current rule for calculating the DWARF2 canonical frame address.  */
84650397Sobrienstatic unsigned long cfa_reg;
84750397Sobrienstatic long cfa_offset;
84850397Sobrien
84950397Sobrien/* The register used for saving registers to the stack, and its offset
85050397Sobrien   from the CFA.  */
85150397Sobrienstatic unsigned cfa_store_reg;
85250397Sobrienstatic long cfa_store_offset;
85350397Sobrien
85450397Sobrien/* The running total of the size of arguments pushed onto the stack.  */
85550397Sobrienstatic long args_size;
85650397Sobrien
85750397Sobrien/* The last args_size we actually output.  */
85850397Sobrienstatic long old_args_size;
85950397Sobrien
86050397Sobrien/* Entry point to update the canonical frame address (CFA).
86150397Sobrien   LABEL is passed to add_fde_cfi.  The value of CFA is now to be
86250397Sobrien   calculated from REG+OFFSET.  */
86350397Sobrien
86450397Sobrienvoid
86550397Sobriendwarf2out_def_cfa (label, reg, offset)
86650397Sobrien     register char *label;
86750397Sobrien     register unsigned reg;
86850397Sobrien     register long offset;
86950397Sobrien{
87050397Sobrien  register dw_cfi_ref cfi;
87150397Sobrien  unsigned long old_reg;
87250397Sobrien  long old_offset;
87350397Sobrien
87450397Sobrien  cfa_reg = reg;
87550397Sobrien  cfa_offset = offset;
87650397Sobrien  if (cfa_store_reg == reg)
87750397Sobrien    cfa_store_offset = offset;
87850397Sobrien
87950397Sobrien  reg = DWARF_FRAME_REGNUM (reg);
88050397Sobrien  lookup_cfa (&old_reg, &old_offset);
88150397Sobrien
88250397Sobrien  if (reg == old_reg && offset == old_offset)
88350397Sobrien    return;
88450397Sobrien
88550397Sobrien  cfi = new_cfi ();
88650397Sobrien
88750397Sobrien  if (reg == old_reg)
88850397Sobrien    {
88950397Sobrien      cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
89050397Sobrien      cfi->dw_cfi_oprnd1.dw_cfi_offset = offset;
89150397Sobrien    }
89250397Sobrien
89350397Sobrien#ifndef MIPS_DEBUGGING_INFO  /* SGI dbx thinks this means no offset.  */
89450397Sobrien  else if (offset == old_offset && old_reg != (unsigned long) -1)
89550397Sobrien    {
89650397Sobrien      cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
89750397Sobrien      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
89850397Sobrien    }
89950397Sobrien#endif
90050397Sobrien
90150397Sobrien  else
90250397Sobrien    {
90350397Sobrien      cfi->dw_cfi_opc = DW_CFA_def_cfa;
90450397Sobrien      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
90550397Sobrien      cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
90650397Sobrien    }
90750397Sobrien
90850397Sobrien  add_fde_cfi (label, cfi);
90950397Sobrien}
91050397Sobrien
91150397Sobrien/* Add the CFI for saving a register.  REG is the CFA column number.
91250397Sobrien   LABEL is passed to add_fde_cfi.
91350397Sobrien   If SREG is -1, the register is saved at OFFSET from the CFA;
91450397Sobrien   otherwise it is saved in SREG.  */
91550397Sobrien
91650397Sobrienstatic void
91750397Sobrienreg_save (label, reg, sreg, offset)
91850397Sobrien     register char * label;
91950397Sobrien     register unsigned reg;
92050397Sobrien     register unsigned sreg;
92150397Sobrien     register long offset;
92250397Sobrien{
92350397Sobrien  register dw_cfi_ref cfi = new_cfi ();
92450397Sobrien
92550397Sobrien  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
92650397Sobrien
92750397Sobrien  /* The following comparison is correct. -1 is used to indicate that
92850397Sobrien     the value isn't a register number.  */
92950397Sobrien  if (sreg == (unsigned int) -1)
93050397Sobrien    {
93150397Sobrien      if (reg & ~0x3f)
93250397Sobrien	/* The register number won't fit in 6 bits, so we have to use
93350397Sobrien	   the long form.  */
93450397Sobrien	cfi->dw_cfi_opc = DW_CFA_offset_extended;
93550397Sobrien      else
93650397Sobrien	cfi->dw_cfi_opc = DW_CFA_offset;
93750397Sobrien
93850397Sobrien      offset /= DWARF_CIE_DATA_ALIGNMENT;
93950397Sobrien      if (offset < 0)
94050397Sobrien	abort ();
94150397Sobrien      cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
94250397Sobrien    }
94350397Sobrien  else
94450397Sobrien    {
94550397Sobrien      cfi->dw_cfi_opc = DW_CFA_register;
94650397Sobrien      cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
94750397Sobrien    }
94850397Sobrien
94950397Sobrien  add_fde_cfi (label, cfi);
95050397Sobrien}
95150397Sobrien
95250397Sobrien/* Add the CFI for saving a register window.  LABEL is passed to reg_save.
95350397Sobrien   This CFI tells the unwinder that it needs to restore the window registers
95450397Sobrien   from the previous frame's window save area.
95550397Sobrien
95650397Sobrien   ??? Perhaps we should note in the CIE where windows are saved (instead of
95750397Sobrien   assuming 0(cfa)) and what registers are in the window.  */
95850397Sobrien
95950397Sobrienvoid
96050397Sobriendwarf2out_window_save (label)
96150397Sobrien     register char * label;
96250397Sobrien{
96350397Sobrien  register dw_cfi_ref cfi = new_cfi ();
96450397Sobrien  cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
96550397Sobrien  add_fde_cfi (label, cfi);
96650397Sobrien}
96750397Sobrien
96850397Sobrien/* Add a CFI to update the running total of the size of arguments
96950397Sobrien   pushed onto the stack.  */
97050397Sobrien
97150397Sobrienvoid
97250397Sobriendwarf2out_args_size (label, size)
97350397Sobrien     char *label;
97450397Sobrien     long size;
97550397Sobrien{
97650397Sobrien  register dw_cfi_ref cfi;
97750397Sobrien
97850397Sobrien  if (size == old_args_size)
97950397Sobrien    return;
98050397Sobrien  old_args_size = size;
98150397Sobrien
98250397Sobrien  cfi = new_cfi ();
98350397Sobrien  cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
98450397Sobrien  cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
98550397Sobrien  add_fde_cfi (label, cfi);
98650397Sobrien}
98750397Sobrien
98850397Sobrien/* Entry point for saving a register to the stack.  REG is the GCC register
98950397Sobrien   number.  LABEL and OFFSET are passed to reg_save.  */
99050397Sobrien
99150397Sobrienvoid
99250397Sobriendwarf2out_reg_save (label, reg, offset)
99350397Sobrien     register char * label;
99450397Sobrien     register unsigned reg;
99550397Sobrien     register long offset;
99650397Sobrien{
99750397Sobrien  reg_save (label, DWARF_FRAME_REGNUM (reg), -1, offset);
99850397Sobrien}
99950397Sobrien
100050397Sobrien/* Entry point for saving the return address in the stack.
100150397Sobrien   LABEL and OFFSET are passed to reg_save.  */
100250397Sobrien
100350397Sobrienvoid
100450397Sobriendwarf2out_return_save (label, offset)
100550397Sobrien     register char * label;
100650397Sobrien     register long offset;
100750397Sobrien{
100850397Sobrien  reg_save (label, DWARF_FRAME_RETURN_COLUMN, -1, offset);
100950397Sobrien}
101050397Sobrien
101150397Sobrien/* Entry point for saving the return address in a register.
101250397Sobrien   LABEL and SREG are passed to reg_save.  */
101350397Sobrien
101450397Sobrienvoid
101550397Sobriendwarf2out_return_reg (label, sreg)
101650397Sobrien     register char * label;
101750397Sobrien     register unsigned sreg;
101850397Sobrien{
101950397Sobrien  reg_save (label, DWARF_FRAME_RETURN_COLUMN, sreg, 0);
102050397Sobrien}
102150397Sobrien
102250397Sobrien/* Record the initial position of the return address.  RTL is
102350397Sobrien   INCOMING_RETURN_ADDR_RTX.  */
102450397Sobrien
102550397Sobrienstatic void
102650397Sobrieninitial_return_save (rtl)
102750397Sobrien     register rtx rtl;
102850397Sobrien{
102950397Sobrien  unsigned reg = -1;
103050397Sobrien  long offset = 0;
103150397Sobrien
103250397Sobrien  switch (GET_CODE (rtl))
103350397Sobrien    {
103450397Sobrien    case REG:
103550397Sobrien      /* RA is in a register.  */
103650397Sobrien      reg = reg_number (rtl);
103750397Sobrien      break;
103850397Sobrien    case MEM:
103950397Sobrien      /* RA is on the stack.  */
104050397Sobrien      rtl = XEXP (rtl, 0);
104150397Sobrien      switch (GET_CODE (rtl))
104250397Sobrien	{
104350397Sobrien	case REG:
104450397Sobrien	  if (REGNO (rtl) != STACK_POINTER_REGNUM)
104550397Sobrien	    abort ();
104650397Sobrien	  offset = 0;
104750397Sobrien	  break;
104850397Sobrien	case PLUS:
104950397Sobrien	  if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM)
105050397Sobrien	    abort ();
105150397Sobrien	  offset = INTVAL (XEXP (rtl, 1));
105250397Sobrien	  break;
105350397Sobrien	case MINUS:
105450397Sobrien	  if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM)
105550397Sobrien	    abort ();
105650397Sobrien	  offset = -INTVAL (XEXP (rtl, 1));
105750397Sobrien	  break;
105850397Sobrien	default:
105950397Sobrien	  abort ();
106050397Sobrien	}
106150397Sobrien      break;
106250397Sobrien    case PLUS:
106350397Sobrien      /* The return address is at some offset from any value we can
106450397Sobrien	 actually load.  For instance, on the SPARC it is in %i7+8. Just
106550397Sobrien	 ignore the offset for now; it doesn't matter for unwinding frames.  */
106650397Sobrien      if (GET_CODE (XEXP (rtl, 1)) != CONST_INT)
106750397Sobrien	abort ();
106850397Sobrien      initial_return_save (XEXP (rtl, 0));
106950397Sobrien      return;
107050397Sobrien    default:
107150397Sobrien      abort ();
107250397Sobrien    }
107350397Sobrien
107450397Sobrien  reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa_offset);
107550397Sobrien}
107650397Sobrien
107750397Sobrien/* Check INSN to see if it looks like a push or a stack adjustment, and
107850397Sobrien   make a note of it if it does.  EH uses this information to find out how
107950397Sobrien   much extra space it needs to pop off the stack.  */
108050397Sobrien
108150397Sobrienstatic void
108250397Sobriendwarf2out_stack_adjust (insn)
108350397Sobrien     rtx insn;
108450397Sobrien{
108550397Sobrien  long offset;
108650397Sobrien  char *label;
108750397Sobrien
108850397Sobrien  if (! asynchronous_exceptions && GET_CODE (insn) == CALL_INSN)
108950397Sobrien    {
109050397Sobrien      /* Extract the size of the args from the CALL rtx itself.  */
109150397Sobrien
109250397Sobrien      insn = PATTERN (insn);
109350397Sobrien      if (GET_CODE (insn) == PARALLEL)
109450397Sobrien	insn = XVECEXP (insn, 0, 0);
109550397Sobrien      if (GET_CODE (insn) == SET)
109650397Sobrien	insn = SET_SRC (insn);
109750397Sobrien      assert (GET_CODE (insn) == CALL);
109850397Sobrien      dwarf2out_args_size ("", INTVAL (XEXP (insn, 1)));
109950397Sobrien      return;
110050397Sobrien    }
110150397Sobrien
110250397Sobrien  /* If only calls can throw, and we have a frame pointer,
110350397Sobrien     save up adjustments until we see the CALL_INSN.  */
110450397Sobrien  else if (! asynchronous_exceptions
110550397Sobrien	   && cfa_reg != STACK_POINTER_REGNUM)
110650397Sobrien    return;
110750397Sobrien
110850397Sobrien  if (GET_CODE (insn) == BARRIER)
110950397Sobrien    {
111050397Sobrien      /* When we see a BARRIER, we know to reset args_size to 0.  Usually
111150397Sobrien	 the compiler will have already emitted a stack adjustment, but
111250397Sobrien	 doesn't bother for calls to noreturn functions.  */
111350397Sobrien#ifdef STACK_GROWS_DOWNWARD
111450397Sobrien      offset = -args_size;
111550397Sobrien#else
111650397Sobrien      offset = args_size;
111750397Sobrien#endif
111850397Sobrien    }
111950397Sobrien  else if (GET_CODE (PATTERN (insn)) == SET)
112050397Sobrien    {
112150397Sobrien      rtx src, dest;
112250397Sobrien      enum rtx_code code;
112350397Sobrien
112450397Sobrien      insn = PATTERN (insn);
112550397Sobrien      src = SET_SRC (insn);
112650397Sobrien      dest = SET_DEST (insn);
112750397Sobrien
112850397Sobrien      if (dest == stack_pointer_rtx)
112950397Sobrien	{
113050397Sobrien	  /* (set (reg sp) (plus (reg sp) (const_int))) */
113150397Sobrien	  code = GET_CODE (src);
113250397Sobrien	  if (! (code == PLUS || code == MINUS)
113350397Sobrien	      || XEXP (src, 0) != stack_pointer_rtx
113450397Sobrien	      || GET_CODE (XEXP (src, 1)) != CONST_INT)
113550397Sobrien	    return;
113650397Sobrien
113750397Sobrien	  offset = INTVAL (XEXP (src, 1));
113850397Sobrien	}
113950397Sobrien      else if (GET_CODE (dest) == MEM)
114050397Sobrien	{
114150397Sobrien	  /* (set (mem (pre_dec (reg sp))) (foo)) */
114250397Sobrien	  src = XEXP (dest, 0);
114350397Sobrien	  code = GET_CODE (src);
114450397Sobrien
114550397Sobrien	  if (! (code == PRE_DEC || code == PRE_INC)
114650397Sobrien	      || XEXP (src, 0) != stack_pointer_rtx)
114750397Sobrien	    return;
114850397Sobrien
114950397Sobrien	  offset = GET_MODE_SIZE (GET_MODE (dest));
115050397Sobrien	}
115150397Sobrien      else
115250397Sobrien	return;
115350397Sobrien
115450397Sobrien      if (code == PLUS || code == PRE_INC)
115550397Sobrien	offset = -offset;
115650397Sobrien    }
115750397Sobrien  else
115850397Sobrien    return;
115950397Sobrien
116050397Sobrien  if (offset == 0)
116150397Sobrien    return;
116250397Sobrien
116350397Sobrien  if (cfa_reg == STACK_POINTER_REGNUM)
116450397Sobrien    cfa_offset += offset;
116550397Sobrien
116650397Sobrien#ifndef STACK_GROWS_DOWNWARD
116750397Sobrien  offset = -offset;
116850397Sobrien#endif
116950397Sobrien  args_size += offset;
117050397Sobrien  if (args_size < 0)
117150397Sobrien    args_size = 0;
117250397Sobrien
117350397Sobrien  label = dwarf2out_cfi_label ();
117450397Sobrien  dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
117550397Sobrien  dwarf2out_args_size (label, args_size);
117650397Sobrien}
117750397Sobrien
117850397Sobrien/* Record call frame debugging information for INSN, which either
117950397Sobrien   sets SP or FP (adjusting how we calculate the frame address) or saves a
118050397Sobrien   register to the stack.  If INSN is NULL_RTX, initialize our state.  */
118150397Sobrien
118250397Sobrienvoid
118350397Sobriendwarf2out_frame_debug (insn)
118450397Sobrien     rtx insn;
118550397Sobrien{
118650397Sobrien  char *label;
118750397Sobrien  rtx src, dest;
118850397Sobrien  long offset;
118950397Sobrien
119050397Sobrien  /* A temporary register used in adjusting SP or setting up the store_reg.  */
119150397Sobrien  static unsigned cfa_temp_reg;
119250397Sobrien  static long cfa_temp_value;
119350397Sobrien
119450397Sobrien  if (insn == NULL_RTX)
119550397Sobrien    {
119650397Sobrien      /* Set up state for generating call frame debug info.  */
119750397Sobrien      lookup_cfa (&cfa_reg, &cfa_offset);
119850397Sobrien      if (cfa_reg != DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM))
119950397Sobrien	abort ();
120050397Sobrien      cfa_reg = STACK_POINTER_REGNUM;
120150397Sobrien      cfa_store_reg = cfa_reg;
120250397Sobrien      cfa_store_offset = cfa_offset;
120350397Sobrien      cfa_temp_reg = -1;
120450397Sobrien      cfa_temp_value = 0;
120550397Sobrien      return;
120650397Sobrien    }
120750397Sobrien
120850397Sobrien  if (! RTX_FRAME_RELATED_P (insn))
120950397Sobrien    {
121050397Sobrien      dwarf2out_stack_adjust (insn);
121150397Sobrien      return;
121250397Sobrien    }
121350397Sobrien
121450397Sobrien  label = dwarf2out_cfi_label ();
121550397Sobrien
121650397Sobrien  insn = PATTERN (insn);
121750397Sobrien  /* Assume that in a PARALLEL prologue insn, only the first elt is
121850397Sobrien     significant.  Currently this is true.  */
121950397Sobrien  if (GET_CODE (insn) == PARALLEL)
122050397Sobrien    insn = XVECEXP (insn, 0, 0);
122150397Sobrien  if (GET_CODE (insn) != SET)
122250397Sobrien    abort ();
122350397Sobrien
122450397Sobrien  src = SET_SRC (insn);
122550397Sobrien  dest = SET_DEST (insn);
122650397Sobrien
122750397Sobrien  switch (GET_CODE (dest))
122850397Sobrien    {
122950397Sobrien    case REG:
123050397Sobrien      /* Update the CFA rule wrt SP or FP.  Make sure src is
123150397Sobrien	 relative to the current CFA register.  */
123250397Sobrien      switch (GET_CODE (src))
123350397Sobrien	{
123450397Sobrien	  /* Setting FP from SP.  */
123550397Sobrien	case REG:
123650397Sobrien	  if (cfa_reg != REGNO (src))
123750397Sobrien	    abort ();
123850397Sobrien	  if (REGNO (dest) != STACK_POINTER_REGNUM
123950397Sobrien	      && !(frame_pointer_needed
124050397Sobrien		   && REGNO (dest) == HARD_FRAME_POINTER_REGNUM))
124150397Sobrien	    abort ();
124250397Sobrien	  cfa_reg = REGNO (dest);
124350397Sobrien	  break;
124450397Sobrien
124550397Sobrien	case PLUS:
124650397Sobrien	case MINUS:
124750397Sobrien	  if (dest == stack_pointer_rtx)
124850397Sobrien	    {
124950397Sobrien	      /* Adjusting SP.  */
125050397Sobrien	      switch (GET_CODE (XEXP (src, 1)))
125150397Sobrien		{
125250397Sobrien		case CONST_INT:
125350397Sobrien		  offset = INTVAL (XEXP (src, 1));
125450397Sobrien		  break;
125550397Sobrien		case REG:
125650397Sobrien		  if (REGNO (XEXP (src, 1)) != cfa_temp_reg)
125750397Sobrien		    abort ();
125850397Sobrien		  offset = cfa_temp_value;
125950397Sobrien		  break;
126050397Sobrien		default:
126150397Sobrien		  abort ();
126250397Sobrien		}
126350397Sobrien
126450397Sobrien	      if (XEXP (src, 0) == hard_frame_pointer_rtx)
126550397Sobrien		{
126650397Sobrien		  /* Restoring SP from FP in the epilogue.  */
126750397Sobrien		  if (cfa_reg != HARD_FRAME_POINTER_REGNUM)
126850397Sobrien		    abort ();
126950397Sobrien		  cfa_reg = STACK_POINTER_REGNUM;
127050397Sobrien		}
127150397Sobrien	      else if (XEXP (src, 0) != stack_pointer_rtx)
127250397Sobrien		abort ();
127350397Sobrien
127450397Sobrien	      if (GET_CODE (src) == PLUS)
127550397Sobrien		offset = -offset;
127650397Sobrien	      if (cfa_reg == STACK_POINTER_REGNUM)
127750397Sobrien		cfa_offset += offset;
127850397Sobrien	      if (cfa_store_reg == STACK_POINTER_REGNUM)
127950397Sobrien		cfa_store_offset += offset;
128050397Sobrien	    }
128150397Sobrien          else if (dest == hard_frame_pointer_rtx)
128250397Sobrien            {
128350397Sobrien              /* Either setting the FP from an offset of the SP,
128450397Sobrien                 or adjusting the FP */
128550397Sobrien	      if (! frame_pointer_needed
128650397Sobrien		  || REGNO (dest) != HARD_FRAME_POINTER_REGNUM)
128750397Sobrien		abort ();
128850397Sobrien
128950397Sobrien              if (XEXP (src, 0) == stack_pointer_rtx
129050397Sobrien                  && GET_CODE (XEXP (src, 1)) == CONST_INT)
129150397Sobrien                {
129250397Sobrien		  if (cfa_reg != STACK_POINTER_REGNUM)
129350397Sobrien		    abort ();
129450397Sobrien                  offset = INTVAL (XEXP (src, 1));
129550397Sobrien                  if (GET_CODE (src) == PLUS)
129650397Sobrien                    offset = -offset;
129750397Sobrien                  cfa_offset += offset;
129850397Sobrien                  cfa_reg = HARD_FRAME_POINTER_REGNUM;
129950397Sobrien                }
130050397Sobrien              else if (XEXP (src, 0) == hard_frame_pointer_rtx
130150397Sobrien                       && GET_CODE (XEXP (src, 1)) == CONST_INT)
130250397Sobrien                {
130350397Sobrien		  if (cfa_reg != HARD_FRAME_POINTER_REGNUM)
130450397Sobrien		    abort ();
130550397Sobrien                  offset = INTVAL (XEXP (src, 1));
130650397Sobrien                  if (GET_CODE (src) == PLUS)
130750397Sobrien                    offset = -offset;
130850397Sobrien                  cfa_offset += offset;
130950397Sobrien                }
131050397Sobrien
131150397Sobrien              else
131250397Sobrien                abort();
131350397Sobrien            }
131450397Sobrien	  else
131550397Sobrien	    {
131650397Sobrien	      if (GET_CODE (src) != PLUS
131750397Sobrien		  || XEXP (src, 1) != stack_pointer_rtx)
131850397Sobrien		abort ();
131950397Sobrien	      if (GET_CODE (XEXP (src, 0)) != REG
132050397Sobrien		  || REGNO (XEXP (src, 0)) != cfa_temp_reg)
132150397Sobrien		abort ();
132250397Sobrien	      if (cfa_reg != STACK_POINTER_REGNUM)
132350397Sobrien		abort ();
132450397Sobrien	      cfa_store_reg = REGNO (dest);
132550397Sobrien	      cfa_store_offset = cfa_offset - cfa_temp_value;
132650397Sobrien	    }
132750397Sobrien	  break;
132850397Sobrien
132950397Sobrien	case CONST_INT:
133050397Sobrien	  cfa_temp_reg = REGNO (dest);
133150397Sobrien	  cfa_temp_value = INTVAL (src);
133250397Sobrien	  break;
133350397Sobrien
133450397Sobrien	case IOR:
133550397Sobrien	  if (GET_CODE (XEXP (src, 0)) != REG
133650397Sobrien	      || REGNO (XEXP (src, 0)) != cfa_temp_reg
133750397Sobrien	      || REGNO (dest) != cfa_temp_reg
133850397Sobrien	      || GET_CODE (XEXP (src, 1)) != CONST_INT)
133950397Sobrien	    abort ();
134050397Sobrien	  cfa_temp_value |= INTVAL (XEXP (src, 1));
134150397Sobrien	  break;
134250397Sobrien
134350397Sobrien	default:
134450397Sobrien	  abort ();
134550397Sobrien	}
134650397Sobrien      dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
134750397Sobrien      break;
134850397Sobrien
134950397Sobrien    case MEM:
135050397Sobrien      /* Saving a register to the stack.  Make sure dest is relative to the
135150397Sobrien         CFA register.  */
135250397Sobrien      if (GET_CODE (src) != REG)
135350397Sobrien	abort ();
135450397Sobrien      switch (GET_CODE (XEXP (dest, 0)))
135550397Sobrien	{
135650397Sobrien	  /* With a push.  */
135750397Sobrien	case PRE_INC:
135850397Sobrien	case PRE_DEC:
135950397Sobrien	  offset = GET_MODE_SIZE (GET_MODE (dest));
136050397Sobrien	  if (GET_CODE (XEXP (dest, 0)) == PRE_INC)
136150397Sobrien	    offset = -offset;
136250397Sobrien
136350397Sobrien	  if (REGNO (XEXP (XEXP (dest, 0), 0)) != STACK_POINTER_REGNUM
136450397Sobrien	      || cfa_store_reg != STACK_POINTER_REGNUM)
136550397Sobrien	    abort ();
136650397Sobrien	  cfa_store_offset += offset;
136750397Sobrien	  if (cfa_reg == STACK_POINTER_REGNUM)
136850397Sobrien	    cfa_offset = cfa_store_offset;
136950397Sobrien
137050397Sobrien	  offset = -cfa_store_offset;
137150397Sobrien	  break;
137250397Sobrien
137350397Sobrien	  /* With an offset.  */
137450397Sobrien	case PLUS:
137550397Sobrien	case MINUS:
137650397Sobrien	  offset = INTVAL (XEXP (XEXP (dest, 0), 1));
137750397Sobrien	  if (GET_CODE (src) == MINUS)
137850397Sobrien	    offset = -offset;
137950397Sobrien
138050397Sobrien	  if (cfa_store_reg != REGNO (XEXP (XEXP (dest, 0), 0)))
138150397Sobrien	    abort ();
138250397Sobrien	  offset -= cfa_store_offset;
138350397Sobrien	  break;
138450397Sobrien
138550397Sobrien	default:
138650397Sobrien	  abort ();
138750397Sobrien	}
138850397Sobrien      dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
138950397Sobrien      dwarf2out_reg_save (label, REGNO (src), offset);
139050397Sobrien      break;
139150397Sobrien
139250397Sobrien    default:
139350397Sobrien      abort ();
139450397Sobrien    }
139550397Sobrien}
139650397Sobrien
139750397Sobrien/* Return the size of an unsigned LEB128 quantity.  */
139850397Sobrien
139950397Sobrienstatic inline unsigned long
140050397Sobriensize_of_uleb128 (value)
140150397Sobrien     register unsigned long value;
140250397Sobrien{
140350397Sobrien  register unsigned long size = 0;
140450397Sobrien  register unsigned byte;
140550397Sobrien
140650397Sobrien  do
140750397Sobrien    {
140850397Sobrien      byte = (value & 0x7f);
140950397Sobrien      value >>= 7;
141050397Sobrien      size += 1;
141150397Sobrien    }
141250397Sobrien  while (value != 0);
141350397Sobrien
141450397Sobrien  return size;
141550397Sobrien}
141650397Sobrien
141750397Sobrien/* Return the size of a signed LEB128 quantity.  */
141850397Sobrien
141950397Sobrienstatic inline unsigned long
142050397Sobriensize_of_sleb128 (value)
142150397Sobrien     register long value;
142250397Sobrien{
142350397Sobrien  register unsigned long size = 0;
142450397Sobrien  register unsigned byte;
142550397Sobrien
142650397Sobrien  do
142750397Sobrien    {
142850397Sobrien      byte = (value & 0x7f);
142950397Sobrien      value >>= 7;
143050397Sobrien      size += 1;
143150397Sobrien    }
143250397Sobrien  while (!(((value == 0) && ((byte & 0x40) == 0))
143350397Sobrien	   || ((value == -1) && ((byte & 0x40) != 0))));
143450397Sobrien
143550397Sobrien  return size;
143650397Sobrien}
143750397Sobrien
143850397Sobrien/* Output an unsigned LEB128 quantity.  */
143950397Sobrien
144050397Sobrienstatic void
144150397Sobrienoutput_uleb128 (value)
144250397Sobrien     register unsigned long value;
144350397Sobrien{
144450397Sobrien  unsigned long save_value = value;
144550397Sobrien
144650397Sobrien  fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP);
144750397Sobrien  do
144850397Sobrien    {
144950397Sobrien      register unsigned byte = (value & 0x7f);
145050397Sobrien      value >>= 7;
145150397Sobrien      if (value != 0)
145250397Sobrien	/* More bytes to follow.  */
145350397Sobrien	byte |= 0x80;
145450397Sobrien
145550397Sobrien      fprintf (asm_out_file, "0x%x", byte);
145650397Sobrien      if (value != 0)
145750397Sobrien	fprintf (asm_out_file, ",");
145850397Sobrien    }
145950397Sobrien  while (value != 0);
146050397Sobrien
146150397Sobrien  if (flag_debug_asm)
146250397Sobrien    fprintf (asm_out_file, "\t%s ULEB128 0x%lx", ASM_COMMENT_START, save_value);
146350397Sobrien}
146450397Sobrien
146550397Sobrien/* Output an signed LEB128 quantity.  */
146650397Sobrien
146750397Sobrienstatic void
146850397Sobrienoutput_sleb128 (value)
146950397Sobrien     register long value;
147050397Sobrien{
147150397Sobrien  register int more;
147250397Sobrien  register unsigned byte;
147350397Sobrien  long save_value = value;
147450397Sobrien
147550397Sobrien  fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP);
147650397Sobrien  do
147750397Sobrien    {
147850397Sobrien      byte = (value & 0x7f);
147950397Sobrien      /* arithmetic shift */
148050397Sobrien      value >>= 7;
148150397Sobrien      more = !((((value == 0) && ((byte & 0x40) == 0))
148250397Sobrien		|| ((value == -1) && ((byte & 0x40) != 0))));
148350397Sobrien      if (more)
148450397Sobrien	byte |= 0x80;
148550397Sobrien
148650397Sobrien      fprintf (asm_out_file, "0x%x", byte);
148750397Sobrien      if (more)
148850397Sobrien	fprintf (asm_out_file, ",");
148950397Sobrien    }
149050397Sobrien
149150397Sobrien  while (more);
149250397Sobrien  if (flag_debug_asm)
149350397Sobrien    fprintf (asm_out_file, "\t%s SLEB128 %ld", ASM_COMMENT_START, save_value);
149450397Sobrien}
149550397Sobrien
149650397Sobrien/* Output a Call Frame Information opcode and its operand(s).  */
149750397Sobrien
149850397Sobrienstatic void
149950397Sobrienoutput_cfi (cfi, fde)
150050397Sobrien     register dw_cfi_ref cfi;
150150397Sobrien     register dw_fde_ref fde;
150250397Sobrien{
150350397Sobrien  if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
150450397Sobrien    {
150550397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
150650397Sobrien			      cfi->dw_cfi_opc
150750397Sobrien			      | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f));
150850397Sobrien      if (flag_debug_asm)
150950397Sobrien	fprintf (asm_out_file, "\t%s DW_CFA_advance_loc 0x%lx",
151050397Sobrien		 ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset);
151150397Sobrien      fputc ('\n', asm_out_file);
151250397Sobrien    }
151350397Sobrien
151450397Sobrien  else if (cfi->dw_cfi_opc == DW_CFA_offset)
151550397Sobrien    {
151650397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
151750397Sobrien			      cfi->dw_cfi_opc
151850397Sobrien			      | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f));
151950397Sobrien      if (flag_debug_asm)
152050397Sobrien	fprintf (asm_out_file, "\t%s DW_CFA_offset, column 0x%lx",
152150397Sobrien		 ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
152250397Sobrien
152350397Sobrien      fputc ('\n', asm_out_file);
152450397Sobrien      output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
152550397Sobrien      fputc ('\n', asm_out_file);
152650397Sobrien    }
152750397Sobrien  else if (cfi->dw_cfi_opc == DW_CFA_restore)
152850397Sobrien    {
152950397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
153050397Sobrien			      cfi->dw_cfi_opc
153150397Sobrien			      | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f));
153250397Sobrien      if (flag_debug_asm)
153350397Sobrien	fprintf (asm_out_file, "\t%s DW_CFA_restore, column 0x%lx",
153450397Sobrien		 ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
153550397Sobrien
153650397Sobrien      fputc ('\n', asm_out_file);
153750397Sobrien    }
153850397Sobrien  else
153950397Sobrien    {
154050397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, cfi->dw_cfi_opc);
154150397Sobrien      if (flag_debug_asm)
154250397Sobrien	fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START,
154350397Sobrien		 dwarf_cfi_name (cfi->dw_cfi_opc));
154450397Sobrien
154550397Sobrien      fputc ('\n', asm_out_file);
154650397Sobrien      switch (cfi->dw_cfi_opc)
154750397Sobrien	{
154850397Sobrien	case DW_CFA_set_loc:
154950397Sobrien          ASM_OUTPUT_DWARF_ADDR (asm_out_file, cfi->dw_cfi_oprnd1.dw_cfi_addr);
155050397Sobrien          fputc ('\n', asm_out_file);
155150397Sobrien	  break;
155250397Sobrien	case DW_CFA_advance_loc1:
155350397Sobrien	  ASM_OUTPUT_DWARF_DELTA1 (asm_out_file,
155450397Sobrien				   cfi->dw_cfi_oprnd1.dw_cfi_addr,
155550397Sobrien				   fde->dw_fde_current_label);
155650397Sobrien	  fputc ('\n', asm_out_file);
155750397Sobrien	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
155850397Sobrien	  break;
155950397Sobrien	case DW_CFA_advance_loc2:
156050397Sobrien          ASM_OUTPUT_DWARF_DELTA2 (asm_out_file,
156150397Sobrien				   cfi->dw_cfi_oprnd1.dw_cfi_addr,
156250397Sobrien				   fde->dw_fde_current_label);
156350397Sobrien          fputc ('\n', asm_out_file);
156450397Sobrien	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
156550397Sobrien	  break;
156650397Sobrien	case DW_CFA_advance_loc4:
156750397Sobrien          ASM_OUTPUT_DWARF_DELTA4 (asm_out_file,
156850397Sobrien				   cfi->dw_cfi_oprnd1.dw_cfi_addr,
156950397Sobrien				   fde->dw_fde_current_label);
157050397Sobrien          fputc ('\n', asm_out_file);
157150397Sobrien	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
157250397Sobrien	  break;
157350397Sobrien#ifdef MIPS_DEBUGGING_INFO
157450397Sobrien	case DW_CFA_MIPS_advance_loc8:
157550397Sobrien	  /* TODO: not currently implemented.  */
157650397Sobrien	  abort ();
157750397Sobrien	  break;
157850397Sobrien#endif
157950397Sobrien	case DW_CFA_offset_extended:
158050397Sobrien	case DW_CFA_def_cfa:
158150397Sobrien	  output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
158250397Sobrien          fputc ('\n', asm_out_file);
158350397Sobrien	  output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
158450397Sobrien          fputc ('\n', asm_out_file);
158550397Sobrien	  break;
158650397Sobrien	case DW_CFA_restore_extended:
158750397Sobrien	case DW_CFA_undefined:
158850397Sobrien	  output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
158950397Sobrien          fputc ('\n', asm_out_file);
159050397Sobrien	  break;
159150397Sobrien	case DW_CFA_same_value:
159250397Sobrien	case DW_CFA_def_cfa_register:
159350397Sobrien	  output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
159450397Sobrien          fputc ('\n', asm_out_file);
159550397Sobrien	  break;
159650397Sobrien	case DW_CFA_register:
159750397Sobrien	  output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
159850397Sobrien          fputc ('\n', asm_out_file);
159950397Sobrien	  output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num);
160050397Sobrien          fputc ('\n', asm_out_file);
160150397Sobrien	  break;
160250397Sobrien	case DW_CFA_def_cfa_offset:
160350397Sobrien	  output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
160450397Sobrien          fputc ('\n', asm_out_file);
160550397Sobrien	  break;
160650397Sobrien	case DW_CFA_GNU_window_save:
160750397Sobrien	  break;
160850397Sobrien	case DW_CFA_GNU_args_size:
160950397Sobrien	  output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
161050397Sobrien          fputc ('\n', asm_out_file);
161150397Sobrien	  break;
161250397Sobrien	default:
161350397Sobrien	  break;
161450397Sobrien	}
161550397Sobrien     }
161650397Sobrien}
161750397Sobrien
161850397Sobrien#if !defined (EH_FRAME_SECTION)
161950397Sobrien#if defined (EH_FRAME_SECTION_ASM_OP)
162050397Sobrien#define EH_FRAME_SECTION() eh_frame_section();
162150397Sobrien#else
162250397Sobrien#if defined (ASM_OUTPUT_SECTION_NAME)
162350397Sobrien#define EH_FRAME_SECTION()				\
162450397Sobrien  do {							\
162550397Sobrien      named_section (NULL_TREE, ".eh_frame", 0);	\
162650397Sobrien  } while (0)
162750397Sobrien#endif
162850397Sobrien#endif
162950397Sobrien#endif
163050397Sobrien
163150397Sobrien/* If we aren't using crtstuff to run ctors, don't use it for EH.  */
163250397Sobrien#if !defined (HAS_INIT_SECTION) && !defined (INIT_SECTION_ASM_OP)
163350397Sobrien#undef EH_FRAME_SECTION
163450397Sobrien#endif
163550397Sobrien
163650397Sobrien/* Output the call frame information used to used to record information
163750397Sobrien   that relates to calculating the frame pointer, and records the
163850397Sobrien   location of saved registers.  */
163950397Sobrien
164050397Sobrienstatic void
164150397Sobrienoutput_call_frame_info (for_eh)
164250397Sobrien     int for_eh;
164350397Sobrien{
164450397Sobrien  register unsigned long i;
164550397Sobrien  register dw_fde_ref fde;
164650397Sobrien  register dw_cfi_ref cfi;
164750397Sobrien  char l1[20], l2[20];
164850397Sobrien#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
164950397Sobrien  char ld[20];
165050397Sobrien#endif
165150397Sobrien
165250397Sobrien  /* Do we want to include a pointer to the exception table?  */
165350397Sobrien  int eh_ptr = for_eh && exception_table_p ();
165450397Sobrien
165550397Sobrien  fputc ('\n', asm_out_file);
165650397Sobrien
165750397Sobrien  /* We're going to be generating comments, so turn on app.  */
165850397Sobrien  if (flag_debug_asm)
165950397Sobrien    app_enable ();
166050397Sobrien
166150397Sobrien  if (for_eh)
166250397Sobrien    {
166350397Sobrien#ifdef EH_FRAME_SECTION
166450397Sobrien      EH_FRAME_SECTION ();
166550397Sobrien#else
166650397Sobrien      tree label = get_file_function_name ('F');
166750397Sobrien
166850397Sobrien      data_section ();
166950397Sobrien      ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
167050397Sobrien      ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
167150397Sobrien      ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
167250397Sobrien#endif
167350397Sobrien      assemble_label ("__FRAME_BEGIN__");
167450397Sobrien    }
167550397Sobrien  else
167650397Sobrien    ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
167750397Sobrien
167850397Sobrien  /* Output the CIE. */
167950397Sobrien  ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
168050397Sobrien  ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
168150397Sobrien#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
168250397Sobrien  ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, for_eh);
168350397Sobrien  if (for_eh)
168450397Sobrien    ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
168550397Sobrien  else
168650397Sobrien    ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
168750397Sobrien#else
168850397Sobrien  if (for_eh)
168950397Sobrien    ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
169050397Sobrien  else
169150397Sobrien    ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
169250397Sobrien#endif
169350397Sobrien  if (flag_debug_asm)
169450397Sobrien    fprintf (asm_out_file, "\t%s Length of Common Information Entry",
169550397Sobrien	     ASM_COMMENT_START);
169650397Sobrien
169750397Sobrien  fputc ('\n', asm_out_file);
169850397Sobrien  ASM_OUTPUT_LABEL (asm_out_file, l1);
169950397Sobrien
170050397Sobrien  if (for_eh)
170150397Sobrien    /* Now that the CIE pointer is PC-relative for EH,
170250397Sobrien       use 0 to identify the CIE.  */
170350397Sobrien    ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
170450397Sobrien  else
170550397Sobrien    ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
170650397Sobrien
170750397Sobrien  if (flag_debug_asm)
170850397Sobrien    fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START);
170950397Sobrien
171050397Sobrien  fputc ('\n', asm_out_file);
171150397Sobrien  if (! for_eh && DWARF_OFFSET_SIZE == 8)
171250397Sobrien    {
171350397Sobrien      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
171450397Sobrien      fputc ('\n', asm_out_file);
171550397Sobrien    }
171650397Sobrien
171750397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION);
171850397Sobrien  if (flag_debug_asm)
171950397Sobrien    fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START);
172050397Sobrien
172150397Sobrien  fputc ('\n', asm_out_file);
172250397Sobrien  if (eh_ptr)
172350397Sobrien    {
172450397Sobrien      /* The CIE contains a pointer to the exception region info for the
172550397Sobrien         frame.  Make the augmentation string three bytes (including the
172650397Sobrien         trailing null) so the pointer is 4-byte aligned.  The Solaris ld
172750397Sobrien         can't handle unaligned relocs.  */
172850397Sobrien      if (flag_debug_asm)
172950397Sobrien	{
173050397Sobrien	  ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh");
173150397Sobrien	  fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START);
173250397Sobrien	}
173350397Sobrien      else
173450397Sobrien	{
173550397Sobrien	  ASM_OUTPUT_ASCII (asm_out_file, "eh", 3);
173650397Sobrien	}
173750397Sobrien      fputc ('\n', asm_out_file);
173850397Sobrien
173950397Sobrien      ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__");
174050397Sobrien      if (flag_debug_asm)
174150397Sobrien	fprintf (asm_out_file, "\t%s pointer to exception region info",
174250397Sobrien		 ASM_COMMENT_START);
174350397Sobrien    }
174450397Sobrien  else
174550397Sobrien    {
174650397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
174750397Sobrien      if (flag_debug_asm)
174850397Sobrien	fprintf (asm_out_file, "\t%s CIE Augmentation (none)",
174950397Sobrien		 ASM_COMMENT_START);
175050397Sobrien    }
175150397Sobrien
175250397Sobrien  fputc ('\n', asm_out_file);
175350397Sobrien  output_uleb128 (1);
175450397Sobrien  if (flag_debug_asm)
175550397Sobrien    fprintf (asm_out_file, " (CIE Code Alignment Factor)");
175650397Sobrien
175750397Sobrien  fputc ('\n', asm_out_file);
175850397Sobrien  output_sleb128 (DWARF_CIE_DATA_ALIGNMENT);
175950397Sobrien  if (flag_debug_asm)
176050397Sobrien    fprintf (asm_out_file, " (CIE Data Alignment Factor)");
176150397Sobrien
176250397Sobrien  fputc ('\n', asm_out_file);
176350397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN);
176450397Sobrien  if (flag_debug_asm)
176550397Sobrien    fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
176650397Sobrien
176750397Sobrien  fputc ('\n', asm_out_file);
176850397Sobrien
176950397Sobrien  for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
177050397Sobrien    output_cfi (cfi, NULL);
177150397Sobrien
177250397Sobrien  /* Pad the CIE out to an address sized boundary.  */
177350397Sobrien  ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
177450397Sobrien  ASM_OUTPUT_LABEL (asm_out_file, l2);
177550397Sobrien#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
177650397Sobrien  ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
177750397Sobrien  if (flag_debug_asm)
177850397Sobrien    fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START);
177950397Sobrien  fputc ('\n', asm_out_file);
178050397Sobrien#endif
178150397Sobrien
178250397Sobrien  /* Loop through all of the FDE's.  */
178350397Sobrien  for (i = 0; i < fde_table_in_use; ++i)
178450397Sobrien    {
178550397Sobrien      fde = &fde_table[i];
178650397Sobrien
178750397Sobrien      ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i*2);
178850397Sobrien      ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i*2);
178950397Sobrien#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
179050397Sobrien      ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i*2);
179150397Sobrien      if (for_eh)
179250397Sobrien	ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
179350397Sobrien      else
179450397Sobrien	ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
179550397Sobrien#else
179650397Sobrien      if (for_eh)
179750397Sobrien	ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
179850397Sobrien      else
179950397Sobrien	ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
180050397Sobrien#endif
180150397Sobrien      if (flag_debug_asm)
180250397Sobrien	fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START);
180350397Sobrien      fputc ('\n', asm_out_file);
180450397Sobrien      ASM_OUTPUT_LABEL (asm_out_file, l1);
180550397Sobrien
180650397Sobrien      if (for_eh)
180750397Sobrien	ASM_OUTPUT_DWARF_DELTA (asm_out_file, l1, "__FRAME_BEGIN__");
180850397Sobrien      else
180950397Sobrien	ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (FRAME_SECTION));
181050397Sobrien      if (flag_debug_asm)
181150397Sobrien	fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START);
181250397Sobrien
181350397Sobrien      fputc ('\n', asm_out_file);
181450397Sobrien      ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin);
181550397Sobrien      if (flag_debug_asm)
181650397Sobrien	fprintf (asm_out_file, "\t%s FDE initial location", ASM_COMMENT_START);
181750397Sobrien
181850397Sobrien      fputc ('\n', asm_out_file);
181950397Sobrien      ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file,
182050397Sobrien				   fde->dw_fde_end, fde->dw_fde_begin);
182150397Sobrien      if (flag_debug_asm)
182250397Sobrien	fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START);
182350397Sobrien
182450397Sobrien      fputc ('\n', asm_out_file);
182550397Sobrien
182650397Sobrien      /* Loop through the Call Frame Instructions associated with
182750397Sobrien	 this FDE.  */
182850397Sobrien      fde->dw_fde_current_label = fde->dw_fde_begin;
182950397Sobrien      for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
183050397Sobrien	output_cfi (cfi, fde);
183150397Sobrien
183250397Sobrien      /* Pad the FDE out to an address sized boundary.  */
183350397Sobrien      ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
183450397Sobrien      ASM_OUTPUT_LABEL (asm_out_file, l2);
183550397Sobrien#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
183650397Sobrien      ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
183750397Sobrien      if (flag_debug_asm)
183850397Sobrien	fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START);
183950397Sobrien      fputc ('\n', asm_out_file);
184050397Sobrien#endif
184150397Sobrien    }
184250397Sobrien#ifndef EH_FRAME_SECTION
184350397Sobrien  if (for_eh)
184450397Sobrien    {
184550397Sobrien      /* Emit terminating zero for table.  */
184650397Sobrien      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
184750397Sobrien      fputc ('\n', asm_out_file);
184850397Sobrien    }
184950397Sobrien#endif
185050397Sobrien#ifdef MIPS_DEBUGGING_INFO
185150397Sobrien  /* Work around Irix 6 assembler bug whereby labels at the end of a section
185250397Sobrien     get a value of 0.  Putting .align 0 after the label fixes it.  */
185350397Sobrien  ASM_OUTPUT_ALIGN (asm_out_file, 0);
185450397Sobrien#endif
185550397Sobrien
185650397Sobrien  /* Turn off app to make assembly quicker.  */
185750397Sobrien  if (flag_debug_asm)
185850397Sobrien    app_disable ();
185950397Sobrien}
186050397Sobrien
186150397Sobrien/* Output a marker (i.e. a label) for the beginning of a function, before
186250397Sobrien   the prologue.  */
186350397Sobrien
186450397Sobrienvoid
186550397Sobriendwarf2out_begin_prologue ()
186650397Sobrien{
186750397Sobrien  char label[MAX_ARTIFICIAL_LABEL_BYTES];
186850397Sobrien  register dw_fde_ref fde;
186950397Sobrien
187050397Sobrien  ++current_funcdef_number;
187150397Sobrien
187250397Sobrien  function_section (current_function_decl);
187350397Sobrien  ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
187450397Sobrien			       current_funcdef_number);
187550397Sobrien  ASM_OUTPUT_LABEL (asm_out_file, label);
187650397Sobrien
187750397Sobrien  /* Expand the fde table if necessary.  */
187850397Sobrien  if (fde_table_in_use == fde_table_allocated)
187950397Sobrien    {
188050397Sobrien      fde_table_allocated += FDE_TABLE_INCREMENT;
188150397Sobrien      fde_table
188250397Sobrien	= (dw_fde_ref) xrealloc (fde_table,
188350397Sobrien				 fde_table_allocated * sizeof (dw_fde_node));
188450397Sobrien    }
188550397Sobrien
188650397Sobrien  /* Record the FDE associated with this function.  */
188750397Sobrien  current_funcdef_fde = fde_table_in_use;
188850397Sobrien
188950397Sobrien  /* Add the new FDE at the end of the fde_table.  */
189050397Sobrien  fde = &fde_table[fde_table_in_use++];
189150397Sobrien  fde->dw_fde_begin = xstrdup (label);
189250397Sobrien  fde->dw_fde_current_label = NULL;
189350397Sobrien  fde->dw_fde_end = NULL;
189450397Sobrien  fde->dw_fde_cfi = NULL;
189550397Sobrien
189650397Sobrien  args_size = old_args_size = 0;
189750397Sobrien}
189850397Sobrien
189950397Sobrien/* Output a marker (i.e. a label) for the absolute end of the generated code
190050397Sobrien   for a function definition.  This gets called *after* the epilogue code has
190150397Sobrien   been generated.  */
190250397Sobrien
190350397Sobrienvoid
190450397Sobriendwarf2out_end_epilogue ()
190550397Sobrien{
190650397Sobrien  dw_fde_ref fde;
190750397Sobrien  char label[MAX_ARTIFICIAL_LABEL_BYTES];
190850397Sobrien
190950397Sobrien  /* Output a label to mark the endpoint of the code generated for this
191050397Sobrien     function.        */
191150397Sobrien  ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number);
191250397Sobrien  ASM_OUTPUT_LABEL (asm_out_file, label);
191350397Sobrien  fde = &fde_table[fde_table_in_use - 1];
191450397Sobrien  fde->dw_fde_end = xstrdup (label);
191550397Sobrien}
191650397Sobrien
191750397Sobrienvoid
191850397Sobriendwarf2out_frame_init ()
191950397Sobrien{
192050397Sobrien  /* Allocate the initial hunk of the fde_table.  */
192150397Sobrien  fde_table
192250397Sobrien    = (dw_fde_ref) xmalloc (FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
192350397Sobrien  bzero ((char *) fde_table, FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
192450397Sobrien  fde_table_allocated = FDE_TABLE_INCREMENT;
192550397Sobrien  fde_table_in_use = 0;
192650397Sobrien
192750397Sobrien  /* Generate the CFA instructions common to all FDE's.  Do it now for the
192850397Sobrien     sake of lookup_cfa.  */
192950397Sobrien
193050397Sobrien#ifdef DWARF2_UNWIND_INFO
193150397Sobrien  /* On entry, the Canonical Frame Address is at SP.  */
193250397Sobrien  dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
193350397Sobrien  initial_return_save (INCOMING_RETURN_ADDR_RTX);
193450397Sobrien#endif
193550397Sobrien}
193650397Sobrien
193750397Sobrienvoid
193850397Sobriendwarf2out_frame_finish ()
193950397Sobrien{
194050397Sobrien  /* Output call frame information.  */
194150397Sobrien#ifdef MIPS_DEBUGGING_INFO
194250397Sobrien  if (write_symbols == DWARF2_DEBUG)
194350397Sobrien    output_call_frame_info (0);
194450397Sobrien  if (flag_exceptions && ! exceptions_via_longjmp)
194550397Sobrien    output_call_frame_info (1);
194650397Sobrien#else
194750397Sobrien  if (write_symbols == DWARF2_DEBUG
194850397Sobrien      || (flag_exceptions && ! exceptions_via_longjmp))
194950397Sobrien    output_call_frame_info (1);
195050397Sobrien#endif
195150397Sobrien}
195250397Sobrien
195350397Sobrien#endif /* .debug_frame support */
195450397Sobrien
195550397Sobrien/* And now, the support for symbolic debugging information.  */
195650397Sobrien#ifdef DWARF2_DEBUGGING_INFO
195750397Sobrien
195850397Sobrienextern char *getpwd PROTO((void));
195950397Sobrien
196050397Sobrien/* NOTE: In the comments in this file, many references are made to
196150397Sobrien   "Debugging Information Entries".  This term is abbreviated as `DIE'
196250397Sobrien   throughout the remainder of this file.  */
196350397Sobrien
196450397Sobrien/* An internal representation of the DWARF output is built, and then
196550397Sobrien   walked to generate the DWARF debugging info.  The walk of the internal
196650397Sobrien   representation is done after the entire program has been compiled.
196750397Sobrien   The types below are used to describe the internal representation.  */
196850397Sobrien
196950397Sobrien/* Each DIE may have a series of attribute/value pairs.  Values
197050397Sobrien   can take on several forms.  The forms that are used in this
197150397Sobrien   implementation are listed below.  */
197250397Sobrien
197350397Sobrientypedef enum
197450397Sobrien{
197550397Sobrien  dw_val_class_addr,
197650397Sobrien  dw_val_class_loc,
197750397Sobrien  dw_val_class_const,
197850397Sobrien  dw_val_class_unsigned_const,
197950397Sobrien  dw_val_class_long_long,
198050397Sobrien  dw_val_class_float,
198150397Sobrien  dw_val_class_flag,
198250397Sobrien  dw_val_class_die_ref,
198350397Sobrien  dw_val_class_fde_ref,
198450397Sobrien  dw_val_class_lbl_id,
198550397Sobrien  dw_val_class_section_offset,
198650397Sobrien  dw_val_class_str
198750397Sobrien}
198850397Sobriendw_val_class;
198950397Sobrien
199050397Sobrien/* Various DIE's use offsets relative to the beginning of the
199150397Sobrien   .debug_info section to refer to each other.  */
199250397Sobrien
199350397Sobrientypedef long int dw_offset;
199450397Sobrien
199550397Sobrien/* Define typedefs here to avoid circular dependencies.  */
199650397Sobrien
199750397Sobrientypedef struct die_struct *dw_die_ref;
199850397Sobrientypedef struct dw_attr_struct *dw_attr_ref;
199950397Sobrientypedef struct dw_val_struct *dw_val_ref;
200050397Sobrientypedef struct dw_line_info_struct *dw_line_info_ref;
200150397Sobrientypedef struct dw_separate_line_info_struct *dw_separate_line_info_ref;
200250397Sobrientypedef struct dw_loc_descr_struct *dw_loc_descr_ref;
200350397Sobrientypedef struct pubname_struct *pubname_ref;
200450397Sobrientypedef dw_die_ref *arange_ref;
200550397Sobrien
200650397Sobrien/* Describe a double word constant value.  */
200750397Sobrien
200850397Sobrientypedef struct dw_long_long_struct
200950397Sobrien{
201050397Sobrien  unsigned long hi;
201150397Sobrien  unsigned long low;
201250397Sobrien}
201350397Sobriendw_long_long_const;
201450397Sobrien
201550397Sobrien/* Describe a floating point constant value.  */
201650397Sobrien
201750397Sobrientypedef struct dw_fp_struct
201850397Sobrien{
201950397Sobrien  long *array;
202050397Sobrien  unsigned length;
202150397Sobrien}
202250397Sobriendw_float_const;
202350397Sobrien
202450397Sobrien/* Each entry in the line_info_table maintains the file and
202550397Sobrien   line number associated with the label generated for that
202650397Sobrien   entry.  The label gives the PC value associated with
202750397Sobrien   the line number entry.  */
202850397Sobrien
202950397Sobrientypedef struct dw_line_info_struct
203050397Sobrien{
203150397Sobrien  unsigned long dw_file_num;
203250397Sobrien  unsigned long dw_line_num;
203350397Sobrien}
203450397Sobriendw_line_info_entry;
203550397Sobrien
203650397Sobrien/* Line information for functions in separate sections; each one gets its
203750397Sobrien   own sequence.  */
203850397Sobrientypedef struct dw_separate_line_info_struct
203950397Sobrien{
204050397Sobrien  unsigned long dw_file_num;
204150397Sobrien  unsigned long dw_line_num;
204250397Sobrien  unsigned long function;
204350397Sobrien}
204450397Sobriendw_separate_line_info_entry;
204550397Sobrien
204650397Sobrien/* The dw_val_node describes an attribute's value, as it is
204750397Sobrien   represented internally.  */
204850397Sobrien
204950397Sobrientypedef struct dw_val_struct
205050397Sobrien{
205150397Sobrien  dw_val_class val_class;
205250397Sobrien  union
205350397Sobrien    {
205450397Sobrien      char *val_addr;
205550397Sobrien      dw_loc_descr_ref val_loc;
205650397Sobrien      long int val_int;
205750397Sobrien      long unsigned val_unsigned;
205850397Sobrien      dw_long_long_const val_long_long;
205950397Sobrien      dw_float_const val_float;
206050397Sobrien      dw_die_ref val_die_ref;
206150397Sobrien      unsigned val_fde_index;
206250397Sobrien      char *val_str;
206350397Sobrien      char *val_lbl_id;
206450397Sobrien      char *val_section;
206550397Sobrien      unsigned char val_flag;
206650397Sobrien    }
206750397Sobrien  v;
206850397Sobrien}
206950397Sobriendw_val_node;
207050397Sobrien
207150397Sobrien/* Locations in memory are described using a sequence of stack machine
207250397Sobrien   operations.  */
207350397Sobrien
207450397Sobrientypedef struct dw_loc_descr_struct
207550397Sobrien{
207650397Sobrien  dw_loc_descr_ref dw_loc_next;
207750397Sobrien  enum dwarf_location_atom dw_loc_opc;
207850397Sobrien  dw_val_node dw_loc_oprnd1;
207950397Sobrien  dw_val_node dw_loc_oprnd2;
208050397Sobrien}
208150397Sobriendw_loc_descr_node;
208250397Sobrien
208350397Sobrien/* Each DIE attribute has a field specifying the attribute kind,
208450397Sobrien   a link to the next attribute in the chain, and an attribute value.
208550397Sobrien   Attributes are typically linked below the DIE they modify.  */
208650397Sobrien
208750397Sobrientypedef struct dw_attr_struct
208850397Sobrien{
208950397Sobrien  enum dwarf_attribute dw_attr;
209050397Sobrien  dw_attr_ref dw_attr_next;
209150397Sobrien  dw_val_node dw_attr_val;
209250397Sobrien}
209350397Sobriendw_attr_node;
209450397Sobrien
209550397Sobrien/* The Debugging Information Entry (DIE) structure */
209650397Sobrien
209750397Sobrientypedef struct die_struct
209850397Sobrien{
209950397Sobrien  enum dwarf_tag die_tag;
210050397Sobrien  dw_attr_ref die_attr;
210150397Sobrien  dw_attr_ref die_attr_last;
210250397Sobrien  dw_die_ref die_parent;
210350397Sobrien  dw_die_ref die_child;
210450397Sobrien  dw_die_ref die_child_last;
210550397Sobrien  dw_die_ref die_sib;
210650397Sobrien  dw_offset die_offset;
210750397Sobrien  unsigned long die_abbrev;
210850397Sobrien}
210950397Sobriendie_node;
211050397Sobrien
211150397Sobrien/* The pubname structure */
211250397Sobrien
211350397Sobrientypedef struct pubname_struct
211450397Sobrien{
211550397Sobrien  dw_die_ref die;
211650397Sobrien  char * name;
211750397Sobrien}
211850397Sobrienpubname_entry;
211950397Sobrien
212050397Sobrien/* The limbo die list structure.  */
212150397Sobrientypedef struct limbo_die_struct
212250397Sobrien{
212350397Sobrien  dw_die_ref die;
212450397Sobrien  struct limbo_die_struct *next;
212550397Sobrien}
212650397Sobrienlimbo_die_node;
212750397Sobrien
212850397Sobrien/* How to start an assembler comment.  */
212950397Sobrien#ifndef ASM_COMMENT_START
213050397Sobrien#define ASM_COMMENT_START ";#"
213150397Sobrien#endif
213250397Sobrien
213350397Sobrien/* Define a macro which returns non-zero for a TYPE_DECL which was
213450397Sobrien   implicitly generated for a tagged type.
213550397Sobrien
213650397Sobrien   Note that unlike the gcc front end (which generates a NULL named
213750397Sobrien   TYPE_DECL node for each complete tagged type, each array type, and
213850397Sobrien   each function type node created) the g++ front end generates a
213950397Sobrien   _named_ TYPE_DECL node for each tagged type node created.
214050397Sobrien   These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to
214150397Sobrien   generate a DW_TAG_typedef DIE for them.  */
214250397Sobrien
214350397Sobrien#define TYPE_DECL_IS_STUB(decl)				\
214450397Sobrien  (DECL_NAME (decl) == NULL_TREE			\
214550397Sobrien   || (DECL_ARTIFICIAL (decl)				\
214650397Sobrien       && is_tagged_type (TREE_TYPE (decl))		\
214750397Sobrien       && ((decl == TYPE_STUB_DECL (TREE_TYPE (decl)))	\
214850397Sobrien	   /* This is necessary for stub decls that	\
214950397Sobrien	      appear in nested inline functions.  */	\
215050397Sobrien	   || (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE	\
215150397Sobrien	       && (decl_ultimate_origin (decl)		\
215250397Sobrien		   == TYPE_STUB_DECL (TREE_TYPE (decl)))))))
215350397Sobrien
215450397Sobrien/* Information concerning the compilation unit's programming
215550397Sobrien   language, and compiler version.  */
215650397Sobrien
215750397Sobrienextern int flag_traditional;
215850397Sobrienextern char *version_string;
215950397Sobrienextern char *language_string;
216050397Sobrien
216150397Sobrien/* Fixed size portion of the DWARF compilation unit header.  */
216250397Sobrien#define DWARF_COMPILE_UNIT_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 3)
216350397Sobrien
216450397Sobrien/* Fixed size portion of debugging line information prolog.  */
216550397Sobrien#define DWARF_LINE_PROLOG_HEADER_SIZE 5
216650397Sobrien
216750397Sobrien/* Fixed size portion of public names info.  */
216850397Sobrien#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
216950397Sobrien
217050397Sobrien/* Fixed size portion of the address range info.  */
217150397Sobrien#define DWARF_ARANGES_HEADER_SIZE \
217250397Sobrien  (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, PTR_SIZE * 2) - DWARF_OFFSET_SIZE)
217350397Sobrien
217450397Sobrien/* Define the architecture-dependent minimum instruction length (in bytes).
217550397Sobrien   In this implementation of DWARF, this field is used for information
217650397Sobrien   purposes only.  Since GCC generates assembly language, we have
217750397Sobrien   no a priori knowledge of how many instruction bytes are generated
217850397Sobrien   for each source line, and therefore can use only the  DW_LNE_set_address
217950397Sobrien   and DW_LNS_fixed_advance_pc line information commands.  */
218050397Sobrien
218150397Sobrien#ifndef DWARF_LINE_MIN_INSTR_LENGTH
218250397Sobrien#define DWARF_LINE_MIN_INSTR_LENGTH 4
218350397Sobrien#endif
218450397Sobrien
218550397Sobrien/* Minimum line offset in a special line info. opcode.
218650397Sobrien   This value was chosen to give a reasonable range of values.  */
218750397Sobrien#define DWARF_LINE_BASE  -10
218850397Sobrien
218950397Sobrien/* First special line opcde - leave room for the standard opcodes.  */
219050397Sobrien#define DWARF_LINE_OPCODE_BASE  10
219150397Sobrien
219250397Sobrien/* Range of line offsets in a special line info. opcode.  */
219350397Sobrien#define DWARF_LINE_RANGE  (254-DWARF_LINE_OPCODE_BASE+1)
219450397Sobrien
219550397Sobrien/* Flag that indicates the initial value of the is_stmt_start flag.
219650397Sobrien   In the present implementation, we do not mark any lines as
219750397Sobrien   the beginning of a source statement, because that information
219850397Sobrien   is not made available by the GCC front-end.  */
219950397Sobrien#define	DWARF_LINE_DEFAULT_IS_STMT_START 1
220050397Sobrien
220150397Sobrien/* This location is used by calc_die_sizes() to keep track
220250397Sobrien   the offset of each DIE within the .debug_info section.  */
220350397Sobrienstatic unsigned long next_die_offset;
220450397Sobrien
220550397Sobrien/* Record the root of the DIE's built for the current compilation unit.  */
220650397Sobrienstatic dw_die_ref comp_unit_die;
220750397Sobrien
220850397Sobrien/* A list of DIEs with a NULL parent waiting to be relocated.  */
220950397Sobrienstatic limbo_die_node *limbo_die_list = 0;
221050397Sobrien
221150397Sobrien/* Pointer to an array of filenames referenced by this compilation unit.  */
221250397Sobrienstatic char **file_table;
221350397Sobrien
221450397Sobrien/* Total number of entries in the table (i.e. array) pointed to by
221550397Sobrien   `file_table'.  This is the *total* and includes both used and unused
221650397Sobrien   slots.  */
221750397Sobrienstatic unsigned file_table_allocated;
221850397Sobrien
221950397Sobrien/* Number of entries in the file_table which are actually in use.  */
222050397Sobrienstatic unsigned file_table_in_use;
222150397Sobrien
222250397Sobrien/* Size (in elements) of increments by which we may expand the filename
222350397Sobrien   table.  */
222450397Sobrien#define FILE_TABLE_INCREMENT 64
222550397Sobrien
222650397Sobrien/* Local pointer to the name of the main input file.  Initialized in
222750397Sobrien   dwarf2out_init.  */
222850397Sobrienstatic char *primary_filename;
222950397Sobrien
223050397Sobrien/* For Dwarf output, we must assign lexical-blocks id numbers in the order in
223150397Sobrien   which their beginnings are encountered. We output Dwarf debugging info
223250397Sobrien   that refers to the beginnings and ends of the ranges of code for each
223350397Sobrien   lexical block.  The labels themselves are generated in final.c, which
223450397Sobrien   assigns numbers to the blocks in the same way.  */
223550397Sobrienstatic unsigned next_block_number = 2;
223650397Sobrien
223750397Sobrien/* A pointer to the base of a table of references to DIE's that describe
223850397Sobrien   declarations.  The table is indexed by DECL_UID() which is a unique
223950397Sobrien   number identifying each decl.  */
224050397Sobrienstatic dw_die_ref *decl_die_table;
224150397Sobrien
224250397Sobrien/* Number of elements currently allocated for the decl_die_table.  */
224350397Sobrienstatic unsigned decl_die_table_allocated;
224450397Sobrien
224550397Sobrien/* Number of elements in decl_die_table currently in use.  */
224650397Sobrienstatic unsigned decl_die_table_in_use;
224750397Sobrien
224850397Sobrien/* Size (in elements) of increments by which we may expand the
224950397Sobrien   decl_die_table.  */
225050397Sobrien#define DECL_DIE_TABLE_INCREMENT 256
225150397Sobrien
225250397Sobrien/* Structure used for the decl_scope table.  scope is the current declaration
225350397Sobrien   scope, and previous is the entry that is the parent of this scope.  This
225450397Sobrien   is usually but not always the immediately preceeding entry.  */
225550397Sobrien
225650397Sobrientypedef struct decl_scope_struct
225750397Sobrien{
225850397Sobrien  tree scope;
225950397Sobrien  int previous;
226050397Sobrien}
226150397Sobriendecl_scope_node;
226250397Sobrien
226350397Sobrien/* A pointer to the base of a table of references to declaration
226450397Sobrien   scopes.  This table is a display which tracks the nesting
226550397Sobrien   of declaration scopes at the current scope and containing
226650397Sobrien   scopes.  This table is used to find the proper place to
226750397Sobrien   define type declaration DIE's.  */
226850397Sobrienstatic decl_scope_node *decl_scope_table;
226950397Sobrien
227050397Sobrien/* Number of elements currently allocated for the decl_scope_table.  */
227150397Sobrienstatic int decl_scope_table_allocated;
227250397Sobrien
227350397Sobrien/* Current level of nesting of declaration scopes.  */
227450397Sobrienstatic int decl_scope_depth;
227550397Sobrien
227650397Sobrien/* Size (in elements) of increments by which we may expand the
227750397Sobrien   decl_scope_table.  */
227850397Sobrien#define DECL_SCOPE_TABLE_INCREMENT 64
227950397Sobrien
228050397Sobrien/* A pointer to the base of a list of references to DIE's that
228150397Sobrien   are uniquely identified by their tag, presence/absence of
228250397Sobrien   children DIE's, and list of attribute/value pairs.  */
228350397Sobrienstatic dw_die_ref *abbrev_die_table;
228450397Sobrien
228550397Sobrien/* Number of elements currently allocated for abbrev_die_table.  */
228650397Sobrienstatic unsigned abbrev_die_table_allocated;
228750397Sobrien
228850397Sobrien/* Number of elements in type_die_table currently in use.  */
228950397Sobrienstatic unsigned abbrev_die_table_in_use;
229050397Sobrien
229150397Sobrien/* Size (in elements) of increments by which we may expand the
229250397Sobrien   abbrev_die_table.  */
229350397Sobrien#define ABBREV_DIE_TABLE_INCREMENT 256
229450397Sobrien
229550397Sobrien/* A pointer to the base of a table that contains line information
229650397Sobrien   for each source code line in .text in the compilation unit.  */
229750397Sobrienstatic dw_line_info_ref line_info_table;
229850397Sobrien
229950397Sobrien/* Number of elements currently allocated for line_info_table.  */
230050397Sobrienstatic unsigned line_info_table_allocated;
230150397Sobrien
230250397Sobrien/* Number of elements in separate_line_info_table currently in use.  */
230350397Sobrienstatic unsigned separate_line_info_table_in_use;
230450397Sobrien
230550397Sobrien/* A pointer to the base of a table that contains line information
230650397Sobrien   for each source code line outside of .text in the compilation unit.  */
230750397Sobrienstatic dw_separate_line_info_ref separate_line_info_table;
230850397Sobrien
230950397Sobrien/* Number of elements currently allocated for separate_line_info_table.  */
231050397Sobrienstatic unsigned separate_line_info_table_allocated;
231150397Sobrien
231250397Sobrien/* Number of elements in line_info_table currently in use.  */
231350397Sobrienstatic unsigned line_info_table_in_use;
231450397Sobrien
231550397Sobrien/* Size (in elements) of increments by which we may expand the
231650397Sobrien   line_info_table.  */
231750397Sobrien#define LINE_INFO_TABLE_INCREMENT 1024
231850397Sobrien
231950397Sobrien/* A pointer to the base of a table that contains a list of publicly
232050397Sobrien   accessible names.  */
232150397Sobrienstatic pubname_ref pubname_table;
232250397Sobrien
232350397Sobrien/* Number of elements currently allocated for pubname_table.  */
232450397Sobrienstatic unsigned pubname_table_allocated;
232550397Sobrien
232650397Sobrien/* Number of elements in pubname_table currently in use.  */
232750397Sobrienstatic unsigned pubname_table_in_use;
232850397Sobrien
232950397Sobrien/* Size (in elements) of increments by which we may expand the
233050397Sobrien   pubname_table.  */
233150397Sobrien#define PUBNAME_TABLE_INCREMENT 64
233250397Sobrien
233350397Sobrien/* A pointer to the base of a table that contains a list of publicly
233450397Sobrien   accessible names.  */
233550397Sobrienstatic arange_ref arange_table;
233650397Sobrien
233750397Sobrien/* Number of elements currently allocated for arange_table.  */
233850397Sobrienstatic unsigned arange_table_allocated;
233950397Sobrien
234050397Sobrien/* Number of elements in arange_table currently in use.  */
234150397Sobrienstatic unsigned arange_table_in_use;
234250397Sobrien
234350397Sobrien/* Size (in elements) of increments by which we may expand the
234450397Sobrien   arange_table.  */
234550397Sobrien#define ARANGE_TABLE_INCREMENT 64
234650397Sobrien
234750397Sobrien/* A pointer to the base of a list of pending types which we haven't
234850397Sobrien   generated DIEs for yet, but which we will have to come back to
234950397Sobrien   later on.  */
235050397Sobrien
235150397Sobrienstatic tree *pending_types_list;
235250397Sobrien
235350397Sobrien/* Number of elements currently allocated for the pending_types_list.  */
235450397Sobrienstatic unsigned pending_types_allocated;
235550397Sobrien
235650397Sobrien/* Number of elements of pending_types_list currently in use.  */
235750397Sobrienstatic unsigned pending_types;
235850397Sobrien
235950397Sobrien/* Size (in elements) of increments by which we may expand the pending
236050397Sobrien   types list.  Actually, a single hunk of space of this size should
236150397Sobrien   be enough for most typical programs.	 */
236250397Sobrien#define PENDING_TYPES_INCREMENT 64
236350397Sobrien
236450397Sobrien/* Record whether the function being analyzed contains inlined functions.  */
236550397Sobrienstatic int current_function_has_inlines;
236650397Sobrien#if 0 && defined (MIPS_DEBUGGING_INFO)
236750397Sobrienstatic int comp_unit_has_inlines;
236850397Sobrien#endif
236950397Sobrien
237050397Sobrien/* A pointer to the ..._DECL node which we have most recently been working
237150397Sobrien   on.  We keep this around just in case something about it looks screwy and
237250397Sobrien   we want to tell the user what the source coordinates for the actual
237350397Sobrien   declaration are.  */
237450397Sobrienstatic tree dwarf_last_decl;
237550397Sobrien
237650397Sobrien/* Forward declarations for functions defined in this file.  */
237750397Sobrien
237850397Sobrienstatic void addr_const_to_string	PROTO((dyn_string_t, rtx));
237950397Sobrienstatic char *addr_to_string		PROTO((rtx));
238050397Sobrienstatic int is_pseudo_reg		PROTO((rtx));
238150397Sobrienstatic tree type_main_variant		PROTO((tree));
238250397Sobrienstatic int is_tagged_type		PROTO((tree));
238350397Sobrienstatic char *dwarf_tag_name		PROTO((unsigned));
238450397Sobrienstatic char *dwarf_attr_name		PROTO((unsigned));
238550397Sobrienstatic char *dwarf_form_name		PROTO((unsigned));
238650397Sobrienstatic char *dwarf_stack_op_name	PROTO((unsigned));
238750397Sobrien#if 0
238850397Sobrienstatic char *dwarf_type_encoding_name	PROTO((unsigned));
238950397Sobrien#endif
239050397Sobrienstatic tree decl_ultimate_origin	PROTO((tree));
239150397Sobrienstatic tree block_ultimate_origin	PROTO((tree));
239250397Sobrienstatic tree decl_class_context		PROTO((tree));
239350397Sobrienstatic void add_dwarf_attr		PROTO((dw_die_ref, dw_attr_ref));
239450397Sobrienstatic void add_AT_flag			PROTO((dw_die_ref,
239550397Sobrien					       enum dwarf_attribute,
239650397Sobrien					       unsigned));
239750397Sobrienstatic void add_AT_int			PROTO((dw_die_ref,
239850397Sobrien					       enum dwarf_attribute, long));
239950397Sobrienstatic void add_AT_unsigned		PROTO((dw_die_ref,
240050397Sobrien					       enum dwarf_attribute,
240150397Sobrien					       unsigned long));
240250397Sobrienstatic void add_AT_long_long		PROTO((dw_die_ref,
240350397Sobrien					       enum dwarf_attribute,
240450397Sobrien					       unsigned long, unsigned long));
240550397Sobrienstatic void add_AT_float		PROTO((dw_die_ref,
240650397Sobrien					       enum dwarf_attribute,
240750397Sobrien					       unsigned, long *));
240850397Sobrienstatic void add_AT_string		PROTO((dw_die_ref,
240950397Sobrien					       enum dwarf_attribute, char *));
241050397Sobrienstatic void add_AT_die_ref		PROTO((dw_die_ref,
241150397Sobrien					       enum dwarf_attribute,
241250397Sobrien					       dw_die_ref));
241350397Sobrienstatic void add_AT_fde_ref		PROTO((dw_die_ref,
241450397Sobrien					       enum dwarf_attribute,
241550397Sobrien					       unsigned));
241650397Sobrienstatic void add_AT_loc			PROTO((dw_die_ref,
241750397Sobrien					       enum dwarf_attribute,
241850397Sobrien					       dw_loc_descr_ref));
241950397Sobrienstatic void add_AT_addr			PROTO((dw_die_ref,
242050397Sobrien					       enum dwarf_attribute, char *));
242150397Sobrienstatic void add_AT_lbl_id		PROTO((dw_die_ref,
242250397Sobrien					       enum dwarf_attribute, char *));
242350397Sobrienstatic void add_AT_section_offset	PROTO((dw_die_ref,
242450397Sobrien					       enum dwarf_attribute, char *));
242550397Sobrienstatic int is_extern_subr_die		PROTO((dw_die_ref));
242650397Sobrienstatic dw_attr_ref get_AT		PROTO((dw_die_ref,
242750397Sobrien					       enum dwarf_attribute));
242850397Sobrienstatic char *get_AT_low_pc		PROTO((dw_die_ref));
242950397Sobrienstatic char *get_AT_hi_pc		PROTO((dw_die_ref));
243050397Sobrienstatic char *get_AT_string		PROTO((dw_die_ref,
243150397Sobrien					       enum dwarf_attribute));
243250397Sobrienstatic int get_AT_flag			PROTO((dw_die_ref,
243350397Sobrien					       enum dwarf_attribute));
243450397Sobrienstatic unsigned get_AT_unsigned		PROTO((dw_die_ref,
243550397Sobrien					       enum dwarf_attribute));
243650397Sobrienstatic int is_c_family			PROTO((void));
243750397Sobrienstatic int is_fortran			PROTO((void));
243850397Sobrienstatic void remove_AT			PROTO((dw_die_ref,
243950397Sobrien					       enum dwarf_attribute));
244050397Sobrienstatic void remove_children		PROTO((dw_die_ref));
244150397Sobrienstatic void add_child_die		PROTO((dw_die_ref, dw_die_ref));
244250397Sobrienstatic dw_die_ref new_die		PROTO((enum dwarf_tag, dw_die_ref));
244350397Sobrienstatic dw_die_ref lookup_type_die	PROTO((tree));
244450397Sobrienstatic void equate_type_number_to_die	PROTO((tree, dw_die_ref));
244550397Sobrienstatic dw_die_ref lookup_decl_die	PROTO((tree));
244650397Sobrienstatic void equate_decl_number_to_die	PROTO((tree, dw_die_ref));
244750397Sobrienstatic dw_loc_descr_ref new_loc_descr	PROTO((enum dwarf_location_atom,
244850397Sobrien					       unsigned long, unsigned long));
244950397Sobrienstatic void add_loc_descr		PROTO((dw_loc_descr_ref *,
245050397Sobrien					       dw_loc_descr_ref));
245150397Sobrienstatic void print_spaces		PROTO((FILE *));
245250397Sobrienstatic void print_die			PROTO((dw_die_ref, FILE *));
245350397Sobrienstatic void print_dwarf_line_table	PROTO((FILE *));
245450397Sobrienstatic void add_sibling_attributes	PROTO((dw_die_ref));
245550397Sobrienstatic void build_abbrev_table		PROTO((dw_die_ref));
245650397Sobrienstatic unsigned long size_of_string	PROTO((char *));
245750397Sobrienstatic unsigned long size_of_loc_descr	PROTO((dw_loc_descr_ref));
245850397Sobrienstatic unsigned long size_of_locs	PROTO((dw_loc_descr_ref));
245950397Sobrienstatic int constant_size		PROTO((long unsigned));
246050397Sobrienstatic unsigned long size_of_die	PROTO((dw_die_ref));
246150397Sobrienstatic void calc_die_sizes		PROTO((dw_die_ref));
246250397Sobrienstatic unsigned long size_of_line_prolog	PROTO((void));
246350397Sobrienstatic unsigned long size_of_line_info	PROTO((void));
246450397Sobrienstatic unsigned long size_of_pubnames	PROTO((void));
246550397Sobrienstatic unsigned long size_of_aranges	PROTO((void));
246650397Sobrienstatic enum dwarf_form value_format	PROTO((dw_val_ref));
246750397Sobrienstatic void output_value_format		PROTO((dw_val_ref));
246850397Sobrienstatic void output_abbrev_section	PROTO((void));
246950397Sobrienstatic void output_loc_operands		PROTO((dw_loc_descr_ref));
247050397Sobrienstatic unsigned long sibling_offset	PROTO((dw_die_ref));
247150397Sobrienstatic void output_die			PROTO((dw_die_ref));
247250397Sobrienstatic void output_compilation_unit_header PROTO((void));
247350397Sobrienstatic char *dwarf2_name		PROTO((tree, int));
247450397Sobrienstatic void add_pubname			PROTO((tree, dw_die_ref));
247550397Sobrienstatic void output_pubnames		PROTO((void));
247650397Sobrienstatic void add_arange			PROTO((tree, dw_die_ref));
247750397Sobrienstatic void output_aranges		PROTO((void));
247850397Sobrienstatic void output_line_info		PROTO((void));
247950397Sobrienstatic int is_body_block		PROTO((tree));
248050397Sobrienstatic dw_die_ref base_type_die		PROTO((tree));
248150397Sobrienstatic tree root_type			PROTO((tree));
248250397Sobrienstatic int is_base_type			PROTO((tree));
248350397Sobrienstatic dw_die_ref modified_type_die	PROTO((tree, int, int, dw_die_ref));
248450397Sobrienstatic int type_is_enum			PROTO((tree));
248550397Sobrienstatic dw_loc_descr_ref reg_loc_descriptor PROTO((rtx));
248650397Sobrienstatic dw_loc_descr_ref based_loc_descr	PROTO((unsigned, long));
248750397Sobrienstatic int is_based_loc			PROTO((rtx));
248850397Sobrienstatic dw_loc_descr_ref mem_loc_descriptor PROTO((rtx));
248950397Sobrienstatic dw_loc_descr_ref concat_loc_descriptor PROTO((rtx, rtx));
249050397Sobrienstatic dw_loc_descr_ref loc_descriptor	PROTO((rtx));
249150397Sobrienstatic unsigned ceiling			PROTO((unsigned, unsigned));
249250397Sobrienstatic tree field_type			PROTO((tree));
249350397Sobrienstatic unsigned simple_type_align_in_bits PROTO((tree));
249450397Sobrienstatic unsigned simple_type_size_in_bits PROTO((tree));
249550397Sobrienstatic unsigned field_byte_offset		PROTO((tree));
249650397Sobrienstatic void add_AT_location_description	PROTO((dw_die_ref,
249750397Sobrien					       enum dwarf_attribute, rtx));
249850397Sobrienstatic void add_data_member_location_attribute PROTO((dw_die_ref, tree));
249950397Sobrienstatic void add_const_value_attribute	PROTO((dw_die_ref, rtx));
250050397Sobrienstatic void add_location_or_const_value_attribute PROTO((dw_die_ref, tree));
250150397Sobrienstatic void add_name_attribute		PROTO((dw_die_ref, char *));
250250397Sobrienstatic void add_bound_info		PROTO((dw_die_ref,
250350397Sobrien					       enum dwarf_attribute, tree));
250450397Sobrienstatic void add_subscript_info		PROTO((dw_die_ref, tree));
250550397Sobrienstatic void add_byte_size_attribute	PROTO((dw_die_ref, tree));
250650397Sobrienstatic void add_bit_offset_attribute	PROTO((dw_die_ref, tree));
250750397Sobrienstatic void add_bit_size_attribute	PROTO((dw_die_ref, tree));
250850397Sobrienstatic void add_prototyped_attribute	PROTO((dw_die_ref, tree));
250950397Sobrienstatic void add_abstract_origin_attribute PROTO((dw_die_ref, tree));
251050397Sobrienstatic void add_pure_or_virtual_attribute PROTO((dw_die_ref, tree));
251150397Sobrienstatic void add_src_coords_attributes	PROTO((dw_die_ref, tree));
251250397Sobrienstatic void add_name_and_src_coords_attributes PROTO((dw_die_ref, tree));
251350397Sobrienstatic void push_decl_scope		PROTO((tree));
251450397Sobrienstatic dw_die_ref scope_die_for		PROTO((tree, dw_die_ref));
251550397Sobrienstatic void pop_decl_scope		PROTO((void));
251650397Sobrienstatic void add_type_attribute		PROTO((dw_die_ref, tree, int, int,
251750397Sobrien					       dw_die_ref));
251850397Sobrienstatic char *type_tag			PROTO((tree));
251950397Sobrienstatic tree member_declared_type	PROTO((tree));
252050397Sobrien#if 0
252150397Sobrienstatic char *decl_start_label		PROTO((tree));
252250397Sobrien#endif
252350397Sobrienstatic void gen_array_type_die		PROTO((tree, dw_die_ref));
252450397Sobrienstatic void gen_set_type_die		PROTO((tree, dw_die_ref));
252550397Sobrien#if 0
252650397Sobrienstatic void gen_entry_point_die		PROTO((tree, dw_die_ref));
252750397Sobrien#endif
252850397Sobrienstatic void pend_type			PROTO((tree));
252950397Sobrienstatic void output_pending_types_for_scope PROTO((dw_die_ref));
253050397Sobrienstatic void gen_inlined_enumeration_type_die PROTO((tree, dw_die_ref));
253150397Sobrienstatic void gen_inlined_structure_type_die PROTO((tree, dw_die_ref));
253250397Sobrienstatic void gen_inlined_union_type_die	PROTO((tree, dw_die_ref));
253350397Sobrienstatic void gen_enumeration_type_die	PROTO((tree, dw_die_ref));
253450397Sobrienstatic dw_die_ref gen_formal_parameter_die PROTO((tree, dw_die_ref));
253550397Sobrienstatic void gen_unspecified_parameters_die PROTO((tree, dw_die_ref));
253650397Sobrienstatic void gen_formal_types_die	PROTO((tree, dw_die_ref));
253750397Sobrienstatic void gen_subprogram_die		PROTO((tree, dw_die_ref));
253850397Sobrienstatic void gen_variable_die		PROTO((tree, dw_die_ref));
253950397Sobrienstatic void gen_label_die		PROTO((tree, dw_die_ref));
254050397Sobrienstatic void gen_lexical_block_die	PROTO((tree, dw_die_ref, int));
254150397Sobrienstatic void gen_inlined_subroutine_die	PROTO((tree, dw_die_ref, int));
254250397Sobrienstatic void gen_field_die		PROTO((tree, dw_die_ref));
254350397Sobrienstatic void gen_ptr_to_mbr_type_die	PROTO((tree, dw_die_ref));
254450397Sobrienstatic void gen_compile_unit_die	PROTO((char *));
254550397Sobrienstatic void gen_string_type_die		PROTO((tree, dw_die_ref));
254650397Sobrienstatic void gen_inheritance_die		PROTO((tree, dw_die_ref));
254750397Sobrienstatic void gen_member_die		PROTO((tree, dw_die_ref));
254850397Sobrienstatic void gen_struct_or_union_type_die PROTO((tree, dw_die_ref));
254950397Sobrienstatic void gen_subroutine_type_die	PROTO((tree, dw_die_ref));
255050397Sobrienstatic void gen_typedef_die		PROTO((tree, dw_die_ref));
255150397Sobrienstatic void gen_type_die		PROTO((tree, dw_die_ref));
255250397Sobrienstatic void gen_tagged_type_instantiation_die PROTO((tree, dw_die_ref));
255350397Sobrienstatic void gen_block_die		PROTO((tree, dw_die_ref, int));
255450397Sobrienstatic void decls_for_scope		PROTO((tree, dw_die_ref, int));
255550397Sobrienstatic int is_redundant_typedef		PROTO((tree));
255650397Sobrienstatic void gen_decl_die		PROTO((tree, dw_die_ref));
255750397Sobrienstatic unsigned lookup_filename		PROTO((char *));
255850397Sobrien
255950397Sobrien/* Section names used to hold DWARF debugging information.  */
256050397Sobrien#ifndef DEBUG_INFO_SECTION
256150397Sobrien#define DEBUG_INFO_SECTION	".debug_info"
256250397Sobrien#endif
256350397Sobrien#ifndef ABBREV_SECTION
256450397Sobrien#define ABBREV_SECTION		".debug_abbrev"
256550397Sobrien#endif
256650397Sobrien#ifndef ARANGES_SECTION
256750397Sobrien#define ARANGES_SECTION		".debug_aranges"
256850397Sobrien#endif
256950397Sobrien#ifndef DW_MACINFO_SECTION
257050397Sobrien#define DW_MACINFO_SECTION	".debug_macinfo"
257150397Sobrien#endif
257250397Sobrien#ifndef DEBUG_LINE_SECTION
257350397Sobrien#define DEBUG_LINE_SECTION	".debug_line"
257450397Sobrien#endif
257550397Sobrien#ifndef LOC_SECTION
257650397Sobrien#define LOC_SECTION		".debug_loc"
257750397Sobrien#endif
257850397Sobrien#ifndef PUBNAMES_SECTION
257950397Sobrien#define PUBNAMES_SECTION	".debug_pubnames"
258050397Sobrien#endif
258150397Sobrien#ifndef STR_SECTION
258250397Sobrien#define STR_SECTION		".debug_str"
258350397Sobrien#endif
258450397Sobrien
258550397Sobrien/* Standard ELF section names for compiled code and data.  */
258650397Sobrien#ifndef TEXT_SECTION
258750397Sobrien#define TEXT_SECTION		".text"
258850397Sobrien#endif
258950397Sobrien#ifndef DATA_SECTION
259050397Sobrien#define DATA_SECTION		".data"
259150397Sobrien#endif
259250397Sobrien#ifndef BSS_SECTION
259350397Sobrien#define BSS_SECTION		".bss"
259450397Sobrien#endif
259550397Sobrien
259650397Sobrien
259750397Sobrien/* Definitions of defaults for formats and names of various special
259850397Sobrien   (artificial) labels which may be generated within this file (when the -g
259950397Sobrien   options is used and DWARF_DEBUGGING_INFO is in effect.
260050397Sobrien   If necessary, these may be overridden from within the tm.h file, but
260150397Sobrien   typically, overriding these defaults is unnecessary.  */
260250397Sobrien
260350397Sobrienstatic char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
260450397Sobrien
260550397Sobrien#ifndef TEXT_END_LABEL
260650397Sobrien#define TEXT_END_LABEL		"Letext"
260750397Sobrien#endif
260850397Sobrien#ifndef DATA_END_LABEL
260950397Sobrien#define DATA_END_LABEL		"Ledata"
261050397Sobrien#endif
261150397Sobrien#ifndef BSS_END_LABEL
261250397Sobrien#define BSS_END_LABEL           "Lebss"
261350397Sobrien#endif
261450397Sobrien#ifndef INSN_LABEL_FMT
261550397Sobrien#define INSN_LABEL_FMT		"LI%u_"
261650397Sobrien#endif
261750397Sobrien#ifndef BLOCK_BEGIN_LABEL
261850397Sobrien#define BLOCK_BEGIN_LABEL	"LBB"
261950397Sobrien#endif
262050397Sobrien#ifndef BLOCK_END_LABEL
262150397Sobrien#define BLOCK_END_LABEL		"LBE"
262250397Sobrien#endif
262350397Sobrien#ifndef BODY_BEGIN_LABEL
262450397Sobrien#define BODY_BEGIN_LABEL	"Lbb"
262550397Sobrien#endif
262650397Sobrien#ifndef BODY_END_LABEL
262750397Sobrien#define BODY_END_LABEL		"Lbe"
262850397Sobrien#endif
262950397Sobrien#ifndef LINE_CODE_LABEL
263050397Sobrien#define LINE_CODE_LABEL		"LM"
263150397Sobrien#endif
263250397Sobrien#ifndef SEPARATE_LINE_CODE_LABEL
263350397Sobrien#define SEPARATE_LINE_CODE_LABEL	"LSM"
263450397Sobrien#endif
263550397Sobrien
263650397Sobrien/* Convert a reference to the assembler name of a C-level name.  This
263750397Sobrien   macro has the same effect as ASM_OUTPUT_LABELREF, but copies to
263850397Sobrien   a string rather than writing to a file.  */
263950397Sobrien#ifndef ASM_NAME_TO_STRING
264050397Sobrien#define ASM_NAME_TO_STRING(STR, NAME) \
264150397Sobrien  do {									      \
264250397Sobrien      if ((NAME)[0] == '*')						      \
264350397Sobrien	dyn_string_append (STR, NAME + 1);				      \
264450397Sobrien      else								      \
264550397Sobrien	dyn_string_append (STR, NAME);                                        \
264650397Sobrien  }                                                                           \
264750397Sobrien  while (0)
264850397Sobrien#endif
264950397Sobrien
265050397Sobrien/* Convert an integer constant expression into assembler syntax.  Addition
265150397Sobrien   and subtraction are the only arithmetic that may appear in these
265250397Sobrien   expressions.   This is an adaptation of output_addr_const in final.c.
265350397Sobrien   Here, the target of the conversion is a string buffer.  We can't use
265450397Sobrien   output_addr_const directly, because it writes to a file.  */
265550397Sobrien
265650397Sobrienstatic void
265750397Sobrienaddr_const_to_string (str, x)
265850397Sobrien     dyn_string_t str;
265950397Sobrien     rtx x;
266050397Sobrien{
266150397Sobrien  char buf1[256];
266250397Sobrien
266350397Sobrienrestart:
266450397Sobrien  switch (GET_CODE (x))
266550397Sobrien    {
266650397Sobrien    case PC:
266750397Sobrien      if (flag_pic)
266850397Sobrien	dyn_string_append (str, ",");
266950397Sobrien      else
267050397Sobrien	abort ();
267150397Sobrien      break;
267250397Sobrien
267350397Sobrien    case SYMBOL_REF:
267450397Sobrien      ASM_NAME_TO_STRING (str, XSTR (x, 0));
267550397Sobrien      break;
267650397Sobrien
267750397Sobrien    case LABEL_REF:
267850397Sobrien      ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
267950397Sobrien      ASM_NAME_TO_STRING (str, buf1);
268050397Sobrien      break;
268150397Sobrien
268250397Sobrien    case CODE_LABEL:
268350397Sobrien      ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (x));
268450397Sobrien      ASM_NAME_TO_STRING (str, buf1);
268550397Sobrien      break;
268650397Sobrien
268750397Sobrien    case CONST_INT:
268850397Sobrien      sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
268950397Sobrien      dyn_string_append (str, buf1);
269050397Sobrien      break;
269150397Sobrien
269250397Sobrien    case CONST:
269350397Sobrien      /* This used to output parentheses around the expression, but that does
269450397Sobrien         not work on the 386 (either ATT or BSD assembler).  */
269550397Sobrien      addr_const_to_string (str, XEXP (x, 0));
269650397Sobrien      break;
269750397Sobrien
269850397Sobrien    case CONST_DOUBLE:
269950397Sobrien      if (GET_MODE (x) == VOIDmode)
270050397Sobrien	{
270150397Sobrien	  /* We can use %d if the number is one word and positive.  */
270250397Sobrien	  if (CONST_DOUBLE_HIGH (x))
270350397Sobrien	    sprintf (buf1, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
270450397Sobrien		     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
270550397Sobrien	  else if (CONST_DOUBLE_LOW (x) < 0)
270650397Sobrien	    sprintf (buf1, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
270750397Sobrien	  else
270850397Sobrien	    sprintf (buf1, HOST_WIDE_INT_PRINT_DEC,
270950397Sobrien		     CONST_DOUBLE_LOW (x));
271050397Sobrien	  dyn_string_append (str, buf1);
271150397Sobrien	}
271250397Sobrien      else
271350397Sobrien	/* We can't handle floating point constants; PRINT_OPERAND must
271450397Sobrien	   handle them.  */
271550397Sobrien	output_operand_lossage ("floating constant misused");
271650397Sobrien      break;
271750397Sobrien
271850397Sobrien    case PLUS:
271950397Sobrien      /* Some assemblers need integer constants to appear last (eg masm).  */
272050397Sobrien      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
272150397Sobrien	{
272250397Sobrien	  addr_const_to_string (str, XEXP (x, 1));
272350397Sobrien	  if (INTVAL (XEXP (x, 0)) >= 0)
272450397Sobrien	    dyn_string_append (str, "+");
272550397Sobrien
272650397Sobrien	  addr_const_to_string (str, XEXP (x, 0));
272750397Sobrien	}
272850397Sobrien      else
272950397Sobrien	{
273050397Sobrien	  addr_const_to_string (str, XEXP (x, 0));
273150397Sobrien	  if (INTVAL (XEXP (x, 1)) >= 0)
273250397Sobrien	    dyn_string_append (str, "+");
273350397Sobrien
273450397Sobrien	  addr_const_to_string (str, XEXP (x, 1));
273550397Sobrien	}
273650397Sobrien      break;
273750397Sobrien
273850397Sobrien    case MINUS:
273950397Sobrien      /* Avoid outputting things like x-x or x+5-x, since some assemblers
274050397Sobrien         can't handle that.  */
274150397Sobrien      x = simplify_subtraction (x);
274250397Sobrien      if (GET_CODE (x) != MINUS)
274350397Sobrien	goto restart;
274450397Sobrien
274550397Sobrien      addr_const_to_string (str, XEXP (x, 0));
274650397Sobrien      dyn_string_append (str, "-");
274750397Sobrien      if (GET_CODE (XEXP (x, 1)) == CONST_INT
274850397Sobrien	  && INTVAL (XEXP (x, 1)) < 0)
274950397Sobrien	{
275050397Sobrien	  dyn_string_append (str, ASM_OPEN_PAREN);
275150397Sobrien	  addr_const_to_string (str, XEXP (x, 1));
275250397Sobrien	  dyn_string_append (str, ASM_CLOSE_PAREN);
275350397Sobrien	}
275450397Sobrien      else
275550397Sobrien	addr_const_to_string (str, XEXP (x, 1));
275650397Sobrien      break;
275750397Sobrien
275850397Sobrien    case ZERO_EXTEND:
275950397Sobrien    case SIGN_EXTEND:
276050397Sobrien      addr_const_to_string (str, XEXP (x, 0));
276150397Sobrien      break;
276250397Sobrien
276350397Sobrien    default:
276450397Sobrien      output_operand_lossage ("invalid expression as operand");
276550397Sobrien    }
276650397Sobrien}
276750397Sobrien
276850397Sobrien/* Convert an address constant to a string, and return a pointer to
276950397Sobrien   a copy of the result, located on the heap.  */
277050397Sobrien
277150397Sobrienstatic char *
277250397Sobrienaddr_to_string (x)
277350397Sobrien     rtx x;
277450397Sobrien{
277550397Sobrien  dyn_string_t ds = dyn_string_new (256);
277650397Sobrien  char *s;
277750397Sobrien
277850397Sobrien  addr_const_to_string (ds, x);
277950397Sobrien
278050397Sobrien  /* Return the dynamically allocated string, but free the
278150397Sobrien     dyn_string_t itself.  */
278250397Sobrien  s = ds->s;
278350397Sobrien  free (ds);
278450397Sobrien  return s;
278550397Sobrien}
278650397Sobrien
278750397Sobrien/* Test if rtl node points to a pseudo register.  */
278850397Sobrien
278950397Sobrienstatic inline int
279050397Sobrienis_pseudo_reg (rtl)
279150397Sobrien     register rtx rtl;
279250397Sobrien{
279350397Sobrien  return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER))
279450397Sobrien	  || ((GET_CODE (rtl) == SUBREG)
279550397Sobrien	      && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER)));
279650397Sobrien}
279750397Sobrien
279850397Sobrien/* Return a reference to a type, with its const and volatile qualifiers
279950397Sobrien   removed.  */
280050397Sobrien
280150397Sobrienstatic inline tree
280250397Sobrientype_main_variant (type)
280350397Sobrien     register tree type;
280450397Sobrien{
280550397Sobrien  type = TYPE_MAIN_VARIANT (type);
280650397Sobrien
280750397Sobrien  /* There really should be only one main variant among any group of variants
280850397Sobrien     of a given type (and all of the MAIN_VARIANT values for all members of
280950397Sobrien     the group should point to that one type) but sometimes the C front-end
281050397Sobrien     messes this up for array types, so we work around that bug here.  */
281150397Sobrien
281250397Sobrien  if (TREE_CODE (type) == ARRAY_TYPE)
281350397Sobrien    while (type != TYPE_MAIN_VARIANT (type))
281450397Sobrien      type = TYPE_MAIN_VARIANT (type);
281550397Sobrien
281650397Sobrien  return type;
281750397Sobrien}
281850397Sobrien
281950397Sobrien/* Return non-zero if the given type node represents a tagged type.  */
282050397Sobrien
282150397Sobrienstatic inline int
282250397Sobrienis_tagged_type (type)
282350397Sobrien     register tree type;
282450397Sobrien{
282550397Sobrien  register enum tree_code code = TREE_CODE (type);
282650397Sobrien
282750397Sobrien  return (code == RECORD_TYPE || code == UNION_TYPE
282850397Sobrien	  || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
282950397Sobrien}
283050397Sobrien
283150397Sobrien/* Convert a DIE tag into its string name.  */
283250397Sobrien
283350397Sobrienstatic char *
283450397Sobriendwarf_tag_name (tag)
283550397Sobrien     register unsigned tag;
283650397Sobrien{
283750397Sobrien  switch (tag)
283850397Sobrien    {
283950397Sobrien    case DW_TAG_padding:
284050397Sobrien      return "DW_TAG_padding";
284150397Sobrien    case DW_TAG_array_type:
284250397Sobrien      return "DW_TAG_array_type";
284350397Sobrien    case DW_TAG_class_type:
284450397Sobrien      return "DW_TAG_class_type";
284550397Sobrien    case DW_TAG_entry_point:
284650397Sobrien      return "DW_TAG_entry_point";
284750397Sobrien    case DW_TAG_enumeration_type:
284850397Sobrien      return "DW_TAG_enumeration_type";
284950397Sobrien    case DW_TAG_formal_parameter:
285050397Sobrien      return "DW_TAG_formal_parameter";
285150397Sobrien    case DW_TAG_imported_declaration:
285250397Sobrien      return "DW_TAG_imported_declaration";
285350397Sobrien    case DW_TAG_label:
285450397Sobrien      return "DW_TAG_label";
285550397Sobrien    case DW_TAG_lexical_block:
285650397Sobrien      return "DW_TAG_lexical_block";
285750397Sobrien    case DW_TAG_member:
285850397Sobrien      return "DW_TAG_member";
285950397Sobrien    case DW_TAG_pointer_type:
286050397Sobrien      return "DW_TAG_pointer_type";
286150397Sobrien    case DW_TAG_reference_type:
286250397Sobrien      return "DW_TAG_reference_type";
286350397Sobrien    case DW_TAG_compile_unit:
286450397Sobrien      return "DW_TAG_compile_unit";
286550397Sobrien    case DW_TAG_string_type:
286650397Sobrien      return "DW_TAG_string_type";
286750397Sobrien    case DW_TAG_structure_type:
286850397Sobrien      return "DW_TAG_structure_type";
286950397Sobrien    case DW_TAG_subroutine_type:
287050397Sobrien      return "DW_TAG_subroutine_type";
287150397Sobrien    case DW_TAG_typedef:
287250397Sobrien      return "DW_TAG_typedef";
287350397Sobrien    case DW_TAG_union_type:
287450397Sobrien      return "DW_TAG_union_type";
287550397Sobrien    case DW_TAG_unspecified_parameters:
287650397Sobrien      return "DW_TAG_unspecified_parameters";
287750397Sobrien    case DW_TAG_variant:
287850397Sobrien      return "DW_TAG_variant";
287950397Sobrien    case DW_TAG_common_block:
288050397Sobrien      return "DW_TAG_common_block";
288150397Sobrien    case DW_TAG_common_inclusion:
288250397Sobrien      return "DW_TAG_common_inclusion";
288350397Sobrien    case DW_TAG_inheritance:
288450397Sobrien      return "DW_TAG_inheritance";
288550397Sobrien    case DW_TAG_inlined_subroutine:
288650397Sobrien      return "DW_TAG_inlined_subroutine";
288750397Sobrien    case DW_TAG_module:
288850397Sobrien      return "DW_TAG_module";
288950397Sobrien    case DW_TAG_ptr_to_member_type:
289050397Sobrien      return "DW_TAG_ptr_to_member_type";
289150397Sobrien    case DW_TAG_set_type:
289250397Sobrien      return "DW_TAG_set_type";
289350397Sobrien    case DW_TAG_subrange_type:
289450397Sobrien      return "DW_TAG_subrange_type";
289550397Sobrien    case DW_TAG_with_stmt:
289650397Sobrien      return "DW_TAG_with_stmt";
289750397Sobrien    case DW_TAG_access_declaration:
289850397Sobrien      return "DW_TAG_access_declaration";
289950397Sobrien    case DW_TAG_base_type:
290050397Sobrien      return "DW_TAG_base_type";
290150397Sobrien    case DW_TAG_catch_block:
290250397Sobrien      return "DW_TAG_catch_block";
290350397Sobrien    case DW_TAG_const_type:
290450397Sobrien      return "DW_TAG_const_type";
290550397Sobrien    case DW_TAG_constant:
290650397Sobrien      return "DW_TAG_constant";
290750397Sobrien    case DW_TAG_enumerator:
290850397Sobrien      return "DW_TAG_enumerator";
290950397Sobrien    case DW_TAG_file_type:
291050397Sobrien      return "DW_TAG_file_type";
291150397Sobrien    case DW_TAG_friend:
291250397Sobrien      return "DW_TAG_friend";
291350397Sobrien    case DW_TAG_namelist:
291450397Sobrien      return "DW_TAG_namelist";
291550397Sobrien    case DW_TAG_namelist_item:
291650397Sobrien      return "DW_TAG_namelist_item";
291750397Sobrien    case DW_TAG_packed_type:
291850397Sobrien      return "DW_TAG_packed_type";
291950397Sobrien    case DW_TAG_subprogram:
292050397Sobrien      return "DW_TAG_subprogram";
292150397Sobrien    case DW_TAG_template_type_param:
292250397Sobrien      return "DW_TAG_template_type_param";
292350397Sobrien    case DW_TAG_template_value_param:
292450397Sobrien      return "DW_TAG_template_value_param";
292550397Sobrien    case DW_TAG_thrown_type:
292650397Sobrien      return "DW_TAG_thrown_type";
292750397Sobrien    case DW_TAG_try_block:
292850397Sobrien      return "DW_TAG_try_block";
292950397Sobrien    case DW_TAG_variant_part:
293050397Sobrien      return "DW_TAG_variant_part";
293150397Sobrien    case DW_TAG_variable:
293250397Sobrien      return "DW_TAG_variable";
293350397Sobrien    case DW_TAG_volatile_type:
293450397Sobrien      return "DW_TAG_volatile_type";
293550397Sobrien    case DW_TAG_MIPS_loop:
293650397Sobrien      return "DW_TAG_MIPS_loop";
293750397Sobrien    case DW_TAG_format_label:
293850397Sobrien      return "DW_TAG_format_label";
293950397Sobrien    case DW_TAG_function_template:
294050397Sobrien      return "DW_TAG_function_template";
294150397Sobrien    case DW_TAG_class_template:
294250397Sobrien      return "DW_TAG_class_template";
294350397Sobrien    default:
294450397Sobrien      return "DW_TAG_<unknown>";
294550397Sobrien    }
294650397Sobrien}
294750397Sobrien
294850397Sobrien/* Convert a DWARF attribute code into its string name.  */
294950397Sobrien
295050397Sobrienstatic char *
295150397Sobriendwarf_attr_name (attr)
295250397Sobrien     register unsigned attr;
295350397Sobrien{
295450397Sobrien  switch (attr)
295550397Sobrien    {
295650397Sobrien    case DW_AT_sibling:
295750397Sobrien      return "DW_AT_sibling";
295850397Sobrien    case DW_AT_location:
295950397Sobrien      return "DW_AT_location";
296050397Sobrien    case DW_AT_name:
296150397Sobrien      return "DW_AT_name";
296250397Sobrien    case DW_AT_ordering:
296350397Sobrien      return "DW_AT_ordering";
296450397Sobrien    case DW_AT_subscr_data:
296550397Sobrien      return "DW_AT_subscr_data";
296650397Sobrien    case DW_AT_byte_size:
296750397Sobrien      return "DW_AT_byte_size";
296850397Sobrien    case DW_AT_bit_offset:
296950397Sobrien      return "DW_AT_bit_offset";
297050397Sobrien    case DW_AT_bit_size:
297150397Sobrien      return "DW_AT_bit_size";
297250397Sobrien    case DW_AT_element_list:
297350397Sobrien      return "DW_AT_element_list";
297450397Sobrien    case DW_AT_stmt_list:
297550397Sobrien      return "DW_AT_stmt_list";
297650397Sobrien    case DW_AT_low_pc:
297750397Sobrien      return "DW_AT_low_pc";
297850397Sobrien    case DW_AT_high_pc:
297950397Sobrien      return "DW_AT_high_pc";
298050397Sobrien    case DW_AT_language:
298150397Sobrien      return "DW_AT_language";
298250397Sobrien    case DW_AT_member:
298350397Sobrien      return "DW_AT_member";
298450397Sobrien    case DW_AT_discr:
298550397Sobrien      return "DW_AT_discr";
298650397Sobrien    case DW_AT_discr_value:
298750397Sobrien      return "DW_AT_discr_value";
298850397Sobrien    case DW_AT_visibility:
298950397Sobrien      return "DW_AT_visibility";
299050397Sobrien    case DW_AT_import:
299150397Sobrien      return "DW_AT_import";
299250397Sobrien    case DW_AT_string_length:
299350397Sobrien      return "DW_AT_string_length";
299450397Sobrien    case DW_AT_common_reference:
299550397Sobrien      return "DW_AT_common_reference";
299650397Sobrien    case DW_AT_comp_dir:
299750397Sobrien      return "DW_AT_comp_dir";
299850397Sobrien    case DW_AT_const_value:
299950397Sobrien      return "DW_AT_const_value";
300050397Sobrien    case DW_AT_containing_type:
300150397Sobrien      return "DW_AT_containing_type";
300250397Sobrien    case DW_AT_default_value:
300350397Sobrien      return "DW_AT_default_value";
300450397Sobrien    case DW_AT_inline:
300550397Sobrien      return "DW_AT_inline";
300650397Sobrien    case DW_AT_is_optional:
300750397Sobrien      return "DW_AT_is_optional";
300850397Sobrien    case DW_AT_lower_bound:
300950397Sobrien      return "DW_AT_lower_bound";
301050397Sobrien    case DW_AT_producer:
301150397Sobrien      return "DW_AT_producer";
301250397Sobrien    case DW_AT_prototyped:
301350397Sobrien      return "DW_AT_prototyped";
301450397Sobrien    case DW_AT_return_addr:
301550397Sobrien      return "DW_AT_return_addr";
301650397Sobrien    case DW_AT_start_scope:
301750397Sobrien      return "DW_AT_start_scope";
301850397Sobrien    case DW_AT_stride_size:
301950397Sobrien      return "DW_AT_stride_size";
302050397Sobrien    case DW_AT_upper_bound:
302150397Sobrien      return "DW_AT_upper_bound";
302250397Sobrien    case DW_AT_abstract_origin:
302350397Sobrien      return "DW_AT_abstract_origin";
302450397Sobrien    case DW_AT_accessibility:
302550397Sobrien      return "DW_AT_accessibility";
302650397Sobrien    case DW_AT_address_class:
302750397Sobrien      return "DW_AT_address_class";
302850397Sobrien    case DW_AT_artificial:
302950397Sobrien      return "DW_AT_artificial";
303050397Sobrien    case DW_AT_base_types:
303150397Sobrien      return "DW_AT_base_types";
303250397Sobrien    case DW_AT_calling_convention:
303350397Sobrien      return "DW_AT_calling_convention";
303450397Sobrien    case DW_AT_count:
303550397Sobrien      return "DW_AT_count";
303650397Sobrien    case DW_AT_data_member_location:
303750397Sobrien      return "DW_AT_data_member_location";
303850397Sobrien    case DW_AT_decl_column:
303950397Sobrien      return "DW_AT_decl_column";
304050397Sobrien    case DW_AT_decl_file:
304150397Sobrien      return "DW_AT_decl_file";
304250397Sobrien    case DW_AT_decl_line:
304350397Sobrien      return "DW_AT_decl_line";
304450397Sobrien    case DW_AT_declaration:
304550397Sobrien      return "DW_AT_declaration";
304650397Sobrien    case DW_AT_discr_list:
304750397Sobrien      return "DW_AT_discr_list";
304850397Sobrien    case DW_AT_encoding:
304950397Sobrien      return "DW_AT_encoding";
305050397Sobrien    case DW_AT_external:
305150397Sobrien      return "DW_AT_external";
305250397Sobrien    case DW_AT_frame_base:
305350397Sobrien      return "DW_AT_frame_base";
305450397Sobrien    case DW_AT_friend:
305550397Sobrien      return "DW_AT_friend";
305650397Sobrien    case DW_AT_identifier_case:
305750397Sobrien      return "DW_AT_identifier_case";
305850397Sobrien    case DW_AT_macro_info:
305950397Sobrien      return "DW_AT_macro_info";
306050397Sobrien    case DW_AT_namelist_items:
306150397Sobrien      return "DW_AT_namelist_items";
306250397Sobrien    case DW_AT_priority:
306350397Sobrien      return "DW_AT_priority";
306450397Sobrien    case DW_AT_segment:
306550397Sobrien      return "DW_AT_segment";
306650397Sobrien    case DW_AT_specification:
306750397Sobrien      return "DW_AT_specification";
306850397Sobrien    case DW_AT_static_link:
306950397Sobrien      return "DW_AT_static_link";
307050397Sobrien    case DW_AT_type:
307150397Sobrien      return "DW_AT_type";
307250397Sobrien    case DW_AT_use_location:
307350397Sobrien      return "DW_AT_use_location";
307450397Sobrien    case DW_AT_variable_parameter:
307550397Sobrien      return "DW_AT_variable_parameter";
307650397Sobrien    case DW_AT_virtuality:
307750397Sobrien      return "DW_AT_virtuality";
307850397Sobrien    case DW_AT_vtable_elem_location:
307950397Sobrien      return "DW_AT_vtable_elem_location";
308050397Sobrien
308150397Sobrien    case DW_AT_MIPS_fde:
308250397Sobrien      return "DW_AT_MIPS_fde";
308350397Sobrien    case DW_AT_MIPS_loop_begin:
308450397Sobrien      return "DW_AT_MIPS_loop_begin";
308550397Sobrien    case DW_AT_MIPS_tail_loop_begin:
308650397Sobrien      return "DW_AT_MIPS_tail_loop_begin";
308750397Sobrien    case DW_AT_MIPS_epilog_begin:
308850397Sobrien      return "DW_AT_MIPS_epilog_begin";
308950397Sobrien    case DW_AT_MIPS_loop_unroll_factor:
309050397Sobrien      return "DW_AT_MIPS_loop_unroll_factor";
309150397Sobrien    case DW_AT_MIPS_software_pipeline_depth:
309250397Sobrien      return "DW_AT_MIPS_software_pipeline_depth";
309350397Sobrien    case DW_AT_MIPS_linkage_name:
309450397Sobrien      return "DW_AT_MIPS_linkage_name";
309550397Sobrien    case DW_AT_MIPS_stride:
309650397Sobrien      return "DW_AT_MIPS_stride";
309750397Sobrien    case DW_AT_MIPS_abstract_name:
309850397Sobrien      return "DW_AT_MIPS_abstract_name";
309950397Sobrien    case DW_AT_MIPS_clone_origin:
310050397Sobrien      return "DW_AT_MIPS_clone_origin";
310150397Sobrien    case DW_AT_MIPS_has_inlines:
310250397Sobrien      return "DW_AT_MIPS_has_inlines";
310350397Sobrien
310450397Sobrien    case DW_AT_sf_names:
310550397Sobrien      return "DW_AT_sf_names";
310650397Sobrien    case DW_AT_src_info:
310750397Sobrien      return "DW_AT_src_info";
310850397Sobrien    case DW_AT_mac_info:
310950397Sobrien      return "DW_AT_mac_info";
311050397Sobrien    case DW_AT_src_coords:
311150397Sobrien      return "DW_AT_src_coords";
311250397Sobrien    case DW_AT_body_begin:
311350397Sobrien      return "DW_AT_body_begin";
311450397Sobrien    case DW_AT_body_end:
311550397Sobrien      return "DW_AT_body_end";
311650397Sobrien    default:
311750397Sobrien      return "DW_AT_<unknown>";
311850397Sobrien    }
311950397Sobrien}
312050397Sobrien
312150397Sobrien/* Convert a DWARF value form code into its string name.  */
312250397Sobrien
312350397Sobrienstatic char *
312450397Sobriendwarf_form_name (form)
312550397Sobrien     register unsigned form;
312650397Sobrien{
312750397Sobrien  switch (form)
312850397Sobrien    {
312950397Sobrien    case DW_FORM_addr:
313050397Sobrien      return "DW_FORM_addr";
313150397Sobrien    case DW_FORM_block2:
313250397Sobrien      return "DW_FORM_block2";
313350397Sobrien    case DW_FORM_block4:
313450397Sobrien      return "DW_FORM_block4";
313550397Sobrien    case DW_FORM_data2:
313650397Sobrien      return "DW_FORM_data2";
313750397Sobrien    case DW_FORM_data4:
313850397Sobrien      return "DW_FORM_data4";
313950397Sobrien    case DW_FORM_data8:
314050397Sobrien      return "DW_FORM_data8";
314150397Sobrien    case DW_FORM_string:
314250397Sobrien      return "DW_FORM_string";
314350397Sobrien    case DW_FORM_block:
314450397Sobrien      return "DW_FORM_block";
314550397Sobrien    case DW_FORM_block1:
314650397Sobrien      return "DW_FORM_block1";
314750397Sobrien    case DW_FORM_data1:
314850397Sobrien      return "DW_FORM_data1";
314950397Sobrien    case DW_FORM_flag:
315050397Sobrien      return "DW_FORM_flag";
315150397Sobrien    case DW_FORM_sdata:
315250397Sobrien      return "DW_FORM_sdata";
315350397Sobrien    case DW_FORM_strp:
315450397Sobrien      return "DW_FORM_strp";
315550397Sobrien    case DW_FORM_udata:
315650397Sobrien      return "DW_FORM_udata";
315750397Sobrien    case DW_FORM_ref_addr:
315850397Sobrien      return "DW_FORM_ref_addr";
315950397Sobrien    case DW_FORM_ref1:
316050397Sobrien      return "DW_FORM_ref1";
316150397Sobrien    case DW_FORM_ref2:
316250397Sobrien      return "DW_FORM_ref2";
316350397Sobrien    case DW_FORM_ref4:
316450397Sobrien      return "DW_FORM_ref4";
316550397Sobrien    case DW_FORM_ref8:
316650397Sobrien      return "DW_FORM_ref8";
316750397Sobrien    case DW_FORM_ref_udata:
316850397Sobrien      return "DW_FORM_ref_udata";
316950397Sobrien    case DW_FORM_indirect:
317050397Sobrien      return "DW_FORM_indirect";
317150397Sobrien    default:
317250397Sobrien      return "DW_FORM_<unknown>";
317350397Sobrien    }
317450397Sobrien}
317550397Sobrien
317650397Sobrien/* Convert a DWARF stack opcode into its string name.  */
317750397Sobrien
317850397Sobrienstatic char *
317950397Sobriendwarf_stack_op_name (op)
318050397Sobrien     register unsigned op;
318150397Sobrien{
318250397Sobrien  switch (op)
318350397Sobrien    {
318450397Sobrien    case DW_OP_addr:
318550397Sobrien      return "DW_OP_addr";
318650397Sobrien    case DW_OP_deref:
318750397Sobrien      return "DW_OP_deref";
318850397Sobrien    case DW_OP_const1u:
318950397Sobrien      return "DW_OP_const1u";
319050397Sobrien    case DW_OP_const1s:
319150397Sobrien      return "DW_OP_const1s";
319250397Sobrien    case DW_OP_const2u:
319350397Sobrien      return "DW_OP_const2u";
319450397Sobrien    case DW_OP_const2s:
319550397Sobrien      return "DW_OP_const2s";
319650397Sobrien    case DW_OP_const4u:
319750397Sobrien      return "DW_OP_const4u";
319850397Sobrien    case DW_OP_const4s:
319950397Sobrien      return "DW_OP_const4s";
320050397Sobrien    case DW_OP_const8u:
320150397Sobrien      return "DW_OP_const8u";
320250397Sobrien    case DW_OP_const8s:
320350397Sobrien      return "DW_OP_const8s";
320450397Sobrien    case DW_OP_constu:
320550397Sobrien      return "DW_OP_constu";
320650397Sobrien    case DW_OP_consts:
320750397Sobrien      return "DW_OP_consts";
320850397Sobrien    case DW_OP_dup:
320950397Sobrien      return "DW_OP_dup";
321050397Sobrien    case DW_OP_drop:
321150397Sobrien      return "DW_OP_drop";
321250397Sobrien    case DW_OP_over:
321350397Sobrien      return "DW_OP_over";
321450397Sobrien    case DW_OP_pick:
321550397Sobrien      return "DW_OP_pick";
321650397Sobrien    case DW_OP_swap:
321750397Sobrien      return "DW_OP_swap";
321850397Sobrien    case DW_OP_rot:
321950397Sobrien      return "DW_OP_rot";
322050397Sobrien    case DW_OP_xderef:
322150397Sobrien      return "DW_OP_xderef";
322250397Sobrien    case DW_OP_abs:
322350397Sobrien      return "DW_OP_abs";
322450397Sobrien    case DW_OP_and:
322550397Sobrien      return "DW_OP_and";
322650397Sobrien    case DW_OP_div:
322750397Sobrien      return "DW_OP_div";
322850397Sobrien    case DW_OP_minus:
322950397Sobrien      return "DW_OP_minus";
323050397Sobrien    case DW_OP_mod:
323150397Sobrien      return "DW_OP_mod";
323250397Sobrien    case DW_OP_mul:
323350397Sobrien      return "DW_OP_mul";
323450397Sobrien    case DW_OP_neg:
323550397Sobrien      return "DW_OP_neg";
323650397Sobrien    case DW_OP_not:
323750397Sobrien      return "DW_OP_not";
323850397Sobrien    case DW_OP_or:
323950397Sobrien      return "DW_OP_or";
324050397Sobrien    case DW_OP_plus:
324150397Sobrien      return "DW_OP_plus";
324250397Sobrien    case DW_OP_plus_uconst:
324350397Sobrien      return "DW_OP_plus_uconst";
324450397Sobrien    case DW_OP_shl:
324550397Sobrien      return "DW_OP_shl";
324650397Sobrien    case DW_OP_shr:
324750397Sobrien      return "DW_OP_shr";
324850397Sobrien    case DW_OP_shra:
324950397Sobrien      return "DW_OP_shra";
325050397Sobrien    case DW_OP_xor:
325150397Sobrien      return "DW_OP_xor";
325250397Sobrien    case DW_OP_bra:
325350397Sobrien      return "DW_OP_bra";
325450397Sobrien    case DW_OP_eq:
325550397Sobrien      return "DW_OP_eq";
325650397Sobrien    case DW_OP_ge:
325750397Sobrien      return "DW_OP_ge";
325850397Sobrien    case DW_OP_gt:
325950397Sobrien      return "DW_OP_gt";
326050397Sobrien    case DW_OP_le:
326150397Sobrien      return "DW_OP_le";
326250397Sobrien    case DW_OP_lt:
326350397Sobrien      return "DW_OP_lt";
326450397Sobrien    case DW_OP_ne:
326550397Sobrien      return "DW_OP_ne";
326650397Sobrien    case DW_OP_skip:
326750397Sobrien      return "DW_OP_skip";
326850397Sobrien    case DW_OP_lit0:
326950397Sobrien      return "DW_OP_lit0";
327050397Sobrien    case DW_OP_lit1:
327150397Sobrien      return "DW_OP_lit1";
327250397Sobrien    case DW_OP_lit2:
327350397Sobrien      return "DW_OP_lit2";
327450397Sobrien    case DW_OP_lit3:
327550397Sobrien      return "DW_OP_lit3";
327650397Sobrien    case DW_OP_lit4:
327750397Sobrien      return "DW_OP_lit4";
327850397Sobrien    case DW_OP_lit5:
327950397Sobrien      return "DW_OP_lit5";
328050397Sobrien    case DW_OP_lit6:
328150397Sobrien      return "DW_OP_lit6";
328250397Sobrien    case DW_OP_lit7:
328350397Sobrien      return "DW_OP_lit7";
328450397Sobrien    case DW_OP_lit8:
328550397Sobrien      return "DW_OP_lit8";
328650397Sobrien    case DW_OP_lit9:
328750397Sobrien      return "DW_OP_lit9";
328850397Sobrien    case DW_OP_lit10:
328950397Sobrien      return "DW_OP_lit10";
329050397Sobrien    case DW_OP_lit11:
329150397Sobrien      return "DW_OP_lit11";
329250397Sobrien    case DW_OP_lit12:
329350397Sobrien      return "DW_OP_lit12";
329450397Sobrien    case DW_OP_lit13:
329550397Sobrien      return "DW_OP_lit13";
329650397Sobrien    case DW_OP_lit14:
329750397Sobrien      return "DW_OP_lit14";
329850397Sobrien    case DW_OP_lit15:
329950397Sobrien      return "DW_OP_lit15";
330050397Sobrien    case DW_OP_lit16:
330150397Sobrien      return "DW_OP_lit16";
330250397Sobrien    case DW_OP_lit17:
330350397Sobrien      return "DW_OP_lit17";
330450397Sobrien    case DW_OP_lit18:
330550397Sobrien      return "DW_OP_lit18";
330650397Sobrien    case DW_OP_lit19:
330750397Sobrien      return "DW_OP_lit19";
330850397Sobrien    case DW_OP_lit20:
330950397Sobrien      return "DW_OP_lit20";
331050397Sobrien    case DW_OP_lit21:
331150397Sobrien      return "DW_OP_lit21";
331250397Sobrien    case DW_OP_lit22:
331350397Sobrien      return "DW_OP_lit22";
331450397Sobrien    case DW_OP_lit23:
331550397Sobrien      return "DW_OP_lit23";
331650397Sobrien    case DW_OP_lit24:
331750397Sobrien      return "DW_OP_lit24";
331850397Sobrien    case DW_OP_lit25:
331950397Sobrien      return "DW_OP_lit25";
332050397Sobrien    case DW_OP_lit26:
332150397Sobrien      return "DW_OP_lit26";
332250397Sobrien    case DW_OP_lit27:
332350397Sobrien      return "DW_OP_lit27";
332450397Sobrien    case DW_OP_lit28:
332550397Sobrien      return "DW_OP_lit28";
332650397Sobrien    case DW_OP_lit29:
332750397Sobrien      return "DW_OP_lit29";
332850397Sobrien    case DW_OP_lit30:
332950397Sobrien      return "DW_OP_lit30";
333050397Sobrien    case DW_OP_lit31:
333150397Sobrien      return "DW_OP_lit31";
333250397Sobrien    case DW_OP_reg0:
333350397Sobrien      return "DW_OP_reg0";
333450397Sobrien    case DW_OP_reg1:
333550397Sobrien      return "DW_OP_reg1";
333650397Sobrien    case DW_OP_reg2:
333750397Sobrien      return "DW_OP_reg2";
333850397Sobrien    case DW_OP_reg3:
333950397Sobrien      return "DW_OP_reg3";
334050397Sobrien    case DW_OP_reg4:
334150397Sobrien      return "DW_OP_reg4";
334250397Sobrien    case DW_OP_reg5:
334350397Sobrien      return "DW_OP_reg5";
334450397Sobrien    case DW_OP_reg6:
334550397Sobrien      return "DW_OP_reg6";
334650397Sobrien    case DW_OP_reg7:
334750397Sobrien      return "DW_OP_reg7";
334850397Sobrien    case DW_OP_reg8:
334950397Sobrien      return "DW_OP_reg8";
335050397Sobrien    case DW_OP_reg9:
335150397Sobrien      return "DW_OP_reg9";
335250397Sobrien    case DW_OP_reg10:
335350397Sobrien      return "DW_OP_reg10";
335450397Sobrien    case DW_OP_reg11:
335550397Sobrien      return "DW_OP_reg11";
335650397Sobrien    case DW_OP_reg12:
335750397Sobrien      return "DW_OP_reg12";
335850397Sobrien    case DW_OP_reg13:
335950397Sobrien      return "DW_OP_reg13";
336050397Sobrien    case DW_OP_reg14:
336150397Sobrien      return "DW_OP_reg14";
336250397Sobrien    case DW_OP_reg15:
336350397Sobrien      return "DW_OP_reg15";
336450397Sobrien    case DW_OP_reg16:
336550397Sobrien      return "DW_OP_reg16";
336650397Sobrien    case DW_OP_reg17:
336750397Sobrien      return "DW_OP_reg17";
336850397Sobrien    case DW_OP_reg18:
336950397Sobrien      return "DW_OP_reg18";
337050397Sobrien    case DW_OP_reg19:
337150397Sobrien      return "DW_OP_reg19";
337250397Sobrien    case DW_OP_reg20:
337350397Sobrien      return "DW_OP_reg20";
337450397Sobrien    case DW_OP_reg21:
337550397Sobrien      return "DW_OP_reg21";
337650397Sobrien    case DW_OP_reg22:
337750397Sobrien      return "DW_OP_reg22";
337850397Sobrien    case DW_OP_reg23:
337950397Sobrien      return "DW_OP_reg23";
338050397Sobrien    case DW_OP_reg24:
338150397Sobrien      return "DW_OP_reg24";
338250397Sobrien    case DW_OP_reg25:
338350397Sobrien      return "DW_OP_reg25";
338450397Sobrien    case DW_OP_reg26:
338550397Sobrien      return "DW_OP_reg26";
338650397Sobrien    case DW_OP_reg27:
338750397Sobrien      return "DW_OP_reg27";
338850397Sobrien    case DW_OP_reg28:
338950397Sobrien      return "DW_OP_reg28";
339050397Sobrien    case DW_OP_reg29:
339150397Sobrien      return "DW_OP_reg29";
339250397Sobrien    case DW_OP_reg30:
339350397Sobrien      return "DW_OP_reg30";
339450397Sobrien    case DW_OP_reg31:
339550397Sobrien      return "DW_OP_reg31";
339650397Sobrien    case DW_OP_breg0:
339750397Sobrien      return "DW_OP_breg0";
339850397Sobrien    case DW_OP_breg1:
339950397Sobrien      return "DW_OP_breg1";
340050397Sobrien    case DW_OP_breg2:
340150397Sobrien      return "DW_OP_breg2";
340250397Sobrien    case DW_OP_breg3:
340350397Sobrien      return "DW_OP_breg3";
340450397Sobrien    case DW_OP_breg4:
340550397Sobrien      return "DW_OP_breg4";
340650397Sobrien    case DW_OP_breg5:
340750397Sobrien      return "DW_OP_breg5";
340850397Sobrien    case DW_OP_breg6:
340950397Sobrien      return "DW_OP_breg6";
341050397Sobrien    case DW_OP_breg7:
341150397Sobrien      return "DW_OP_breg7";
341250397Sobrien    case DW_OP_breg8:
341350397Sobrien      return "DW_OP_breg8";
341450397Sobrien    case DW_OP_breg9:
341550397Sobrien      return "DW_OP_breg9";
341650397Sobrien    case DW_OP_breg10:
341750397Sobrien      return "DW_OP_breg10";
341850397Sobrien    case DW_OP_breg11:
341950397Sobrien      return "DW_OP_breg11";
342050397Sobrien    case DW_OP_breg12:
342150397Sobrien      return "DW_OP_breg12";
342250397Sobrien    case DW_OP_breg13:
342350397Sobrien      return "DW_OP_breg13";
342450397Sobrien    case DW_OP_breg14:
342550397Sobrien      return "DW_OP_breg14";
342650397Sobrien    case DW_OP_breg15:
342750397Sobrien      return "DW_OP_breg15";
342850397Sobrien    case DW_OP_breg16:
342950397Sobrien      return "DW_OP_breg16";
343050397Sobrien    case DW_OP_breg17:
343150397Sobrien      return "DW_OP_breg17";
343250397Sobrien    case DW_OP_breg18:
343350397Sobrien      return "DW_OP_breg18";
343450397Sobrien    case DW_OP_breg19:
343550397Sobrien      return "DW_OP_breg19";
343650397Sobrien    case DW_OP_breg20:
343750397Sobrien      return "DW_OP_breg20";
343850397Sobrien    case DW_OP_breg21:
343950397Sobrien      return "DW_OP_breg21";
344050397Sobrien    case DW_OP_breg22:
344150397Sobrien      return "DW_OP_breg22";
344250397Sobrien    case DW_OP_breg23:
344350397Sobrien      return "DW_OP_breg23";
344450397Sobrien    case DW_OP_breg24:
344550397Sobrien      return "DW_OP_breg24";
344650397Sobrien    case DW_OP_breg25:
344750397Sobrien      return "DW_OP_breg25";
344850397Sobrien    case DW_OP_breg26:
344950397Sobrien      return "DW_OP_breg26";
345050397Sobrien    case DW_OP_breg27:
345150397Sobrien      return "DW_OP_breg27";
345250397Sobrien    case DW_OP_breg28:
345350397Sobrien      return "DW_OP_breg28";
345450397Sobrien    case DW_OP_breg29:
345550397Sobrien      return "DW_OP_breg29";
345650397Sobrien    case DW_OP_breg30:
345750397Sobrien      return "DW_OP_breg30";
345850397Sobrien    case DW_OP_breg31:
345950397Sobrien      return "DW_OP_breg31";
346050397Sobrien    case DW_OP_regx:
346150397Sobrien      return "DW_OP_regx";
346250397Sobrien    case DW_OP_fbreg:
346350397Sobrien      return "DW_OP_fbreg";
346450397Sobrien    case DW_OP_bregx:
346550397Sobrien      return "DW_OP_bregx";
346650397Sobrien    case DW_OP_piece:
346750397Sobrien      return "DW_OP_piece";
346850397Sobrien    case DW_OP_deref_size:
346950397Sobrien      return "DW_OP_deref_size";
347050397Sobrien    case DW_OP_xderef_size:
347150397Sobrien      return "DW_OP_xderef_size";
347250397Sobrien    case DW_OP_nop:
347350397Sobrien      return "DW_OP_nop";
347450397Sobrien    default:
347550397Sobrien      return "OP_<unknown>";
347650397Sobrien    }
347750397Sobrien}
347850397Sobrien
347950397Sobrien/* Convert a DWARF type code into its string name.  */
348050397Sobrien
348150397Sobrien#if 0
348250397Sobrienstatic char *
348350397Sobriendwarf_type_encoding_name (enc)
348450397Sobrien     register unsigned enc;
348550397Sobrien{
348650397Sobrien  switch (enc)
348750397Sobrien    {
348850397Sobrien    case DW_ATE_address:
348950397Sobrien      return "DW_ATE_address";
349050397Sobrien    case DW_ATE_boolean:
349150397Sobrien      return "DW_ATE_boolean";
349250397Sobrien    case DW_ATE_complex_float:
349350397Sobrien      return "DW_ATE_complex_float";
349450397Sobrien    case DW_ATE_float:
349550397Sobrien      return "DW_ATE_float";
349650397Sobrien    case DW_ATE_signed:
349750397Sobrien      return "DW_ATE_signed";
349850397Sobrien    case DW_ATE_signed_char:
349950397Sobrien      return "DW_ATE_signed_char";
350050397Sobrien    case DW_ATE_unsigned:
350150397Sobrien      return "DW_ATE_unsigned";
350250397Sobrien    case DW_ATE_unsigned_char:
350350397Sobrien      return "DW_ATE_unsigned_char";
350450397Sobrien    default:
350550397Sobrien      return "DW_ATE_<unknown>";
350650397Sobrien    }
350750397Sobrien}
350850397Sobrien#endif
350950397Sobrien
351050397Sobrien/* Determine the "ultimate origin" of a decl.  The decl may be an inlined
351150397Sobrien   instance of an inlined instance of a decl which is local to an inline
351250397Sobrien   function, so we have to trace all of the way back through the origin chain
351350397Sobrien   to find out what sort of node actually served as the original seed for the
351450397Sobrien   given block.  */
351550397Sobrien
351650397Sobrienstatic tree
351750397Sobriendecl_ultimate_origin (decl)
351850397Sobrien     register tree decl;
351950397Sobrien{
352050397Sobrien  register tree immediate_origin = DECL_ABSTRACT_ORIGIN (decl);
352150397Sobrien
352250397Sobrien  if (immediate_origin == NULL_TREE)
352350397Sobrien    return NULL_TREE;
352450397Sobrien  else
352550397Sobrien    {
352650397Sobrien      register tree ret_val;
352750397Sobrien      register tree lookahead = immediate_origin;
352850397Sobrien
352950397Sobrien      do
353050397Sobrien	{
353150397Sobrien	  ret_val = lookahead;
353250397Sobrien	  lookahead = DECL_ABSTRACT_ORIGIN (ret_val);
353350397Sobrien	}
353450397Sobrien      while (lookahead != NULL && lookahead != ret_val);
353550397Sobrien
353650397Sobrien      return ret_val;
353750397Sobrien    }
353850397Sobrien}
353950397Sobrien
354050397Sobrien/* Determine the "ultimate origin" of a block.  The block may be an inlined
354150397Sobrien   instance of an inlined instance of a block which is local to an inline
354250397Sobrien   function, so we have to trace all of the way back through the origin chain
354350397Sobrien   to find out what sort of node actually served as the original seed for the
354450397Sobrien   given block.  */
354550397Sobrien
354650397Sobrienstatic tree
354750397Sobrienblock_ultimate_origin (block)
354850397Sobrien     register tree block;
354950397Sobrien{
355050397Sobrien  register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
355150397Sobrien
355250397Sobrien  if (immediate_origin == NULL_TREE)
355350397Sobrien    return NULL_TREE;
355450397Sobrien  else
355550397Sobrien    {
355650397Sobrien      register tree ret_val;
355750397Sobrien      register tree lookahead = immediate_origin;
355850397Sobrien
355950397Sobrien      do
356050397Sobrien	{
356150397Sobrien	  ret_val = lookahead;
356250397Sobrien	  lookahead = (TREE_CODE (ret_val) == BLOCK)
356350397Sobrien	    ? BLOCK_ABSTRACT_ORIGIN (ret_val)
356450397Sobrien	    : NULL;
356550397Sobrien	}
356650397Sobrien      while (lookahead != NULL && lookahead != ret_val);
356750397Sobrien
356850397Sobrien      return ret_val;
356950397Sobrien    }
357050397Sobrien}
357150397Sobrien
357250397Sobrien/* Get the class to which DECL belongs, if any.  In g++, the DECL_CONTEXT
357350397Sobrien   of a virtual function may refer to a base class, so we check the 'this'
357450397Sobrien   parameter.  */
357550397Sobrien
357650397Sobrienstatic tree
357750397Sobriendecl_class_context (decl)
357850397Sobrien     tree decl;
357950397Sobrien{
358050397Sobrien  tree context = NULL_TREE;
358150397Sobrien
358250397Sobrien  if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl))
358350397Sobrien    context = DECL_CONTEXT (decl);
358450397Sobrien  else
358550397Sobrien    context = TYPE_MAIN_VARIANT
358650397Sobrien      (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
358750397Sobrien
358850397Sobrien  if (context && TREE_CODE_CLASS (TREE_CODE (context)) != 't')
358950397Sobrien    context = NULL_TREE;
359050397Sobrien
359150397Sobrien  return context;
359250397Sobrien}
359350397Sobrien
359450397Sobrien/* Add an attribute/value pair to a DIE */
359550397Sobrien
359650397Sobrienstatic inline void
359750397Sobrienadd_dwarf_attr (die, attr)
359850397Sobrien     register dw_die_ref die;
359950397Sobrien     register dw_attr_ref attr;
360050397Sobrien{
360150397Sobrien  if (die != NULL && attr != NULL)
360250397Sobrien    {
360350397Sobrien      if (die->die_attr == NULL)
360450397Sobrien	{
360550397Sobrien	  die->die_attr = attr;
360650397Sobrien	  die->die_attr_last = attr;
360750397Sobrien	}
360850397Sobrien      else
360950397Sobrien	{
361050397Sobrien	  die->die_attr_last->dw_attr_next = attr;
361150397Sobrien	  die->die_attr_last = attr;
361250397Sobrien	}
361350397Sobrien    }
361450397Sobrien}
361550397Sobrien
361650397Sobrien/* Add a flag value attribute to a DIE.  */
361750397Sobrien
361850397Sobrienstatic inline void
361950397Sobrienadd_AT_flag (die, attr_kind, flag)
362050397Sobrien     register dw_die_ref die;
362150397Sobrien     register enum dwarf_attribute attr_kind;
362250397Sobrien     register unsigned flag;
362350397Sobrien{
362450397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
362550397Sobrien
362650397Sobrien  attr->dw_attr_next = NULL;
362750397Sobrien  attr->dw_attr = attr_kind;
362850397Sobrien  attr->dw_attr_val.val_class = dw_val_class_flag;
362950397Sobrien  attr->dw_attr_val.v.val_flag = flag;
363050397Sobrien  add_dwarf_attr (die, attr);
363150397Sobrien}
363250397Sobrien
363350397Sobrien/* Add a signed integer attribute value to a DIE.  */
363450397Sobrien
363550397Sobrienstatic inline void
363650397Sobrienadd_AT_int (die, attr_kind, int_val)
363750397Sobrien     register dw_die_ref die;
363850397Sobrien     register enum dwarf_attribute attr_kind;
363950397Sobrien     register long int int_val;
364050397Sobrien{
364150397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
364250397Sobrien
364350397Sobrien  attr->dw_attr_next = NULL;
364450397Sobrien  attr->dw_attr = attr_kind;
364550397Sobrien  attr->dw_attr_val.val_class = dw_val_class_const;
364650397Sobrien  attr->dw_attr_val.v.val_int = int_val;
364750397Sobrien  add_dwarf_attr (die, attr);
364850397Sobrien}
364950397Sobrien
365050397Sobrien/* Add an unsigned integer attribute value to a DIE.  */
365150397Sobrien
365250397Sobrienstatic inline void
365350397Sobrienadd_AT_unsigned (die, attr_kind, unsigned_val)
365450397Sobrien     register dw_die_ref die;
365550397Sobrien     register enum dwarf_attribute attr_kind;
365650397Sobrien     register unsigned long unsigned_val;
365750397Sobrien{
365850397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
365950397Sobrien
366050397Sobrien  attr->dw_attr_next = NULL;
366150397Sobrien  attr->dw_attr = attr_kind;
366250397Sobrien  attr->dw_attr_val.val_class = dw_val_class_unsigned_const;
366350397Sobrien  attr->dw_attr_val.v.val_unsigned = unsigned_val;
366450397Sobrien  add_dwarf_attr (die, attr);
366550397Sobrien}
366650397Sobrien
366750397Sobrien/* Add an unsigned double integer attribute value to a DIE.  */
366850397Sobrien
366950397Sobrienstatic inline void
367050397Sobrienadd_AT_long_long (die, attr_kind, val_hi, val_low)
367150397Sobrien     register dw_die_ref die;
367250397Sobrien     register enum dwarf_attribute attr_kind;
367350397Sobrien     register unsigned long val_hi;
367450397Sobrien     register unsigned long val_low;
367550397Sobrien{
367650397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
367750397Sobrien
367850397Sobrien  attr->dw_attr_next = NULL;
367950397Sobrien  attr->dw_attr = attr_kind;
368050397Sobrien  attr->dw_attr_val.val_class = dw_val_class_long_long;
368150397Sobrien  attr->dw_attr_val.v.val_long_long.hi = val_hi;
368250397Sobrien  attr->dw_attr_val.v.val_long_long.low = val_low;
368350397Sobrien  add_dwarf_attr (die, attr);
368450397Sobrien}
368550397Sobrien
368650397Sobrien/* Add a floating point attribute value to a DIE and return it.  */
368750397Sobrien
368850397Sobrienstatic inline void
368950397Sobrienadd_AT_float (die, attr_kind, length, array)
369050397Sobrien     register dw_die_ref die;
369150397Sobrien     register enum dwarf_attribute attr_kind;
369250397Sobrien     register unsigned length;
369350397Sobrien     register long *array;
369450397Sobrien{
369550397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
369650397Sobrien
369750397Sobrien  attr->dw_attr_next = NULL;
369850397Sobrien  attr->dw_attr = attr_kind;
369950397Sobrien  attr->dw_attr_val.val_class = dw_val_class_float;
370050397Sobrien  attr->dw_attr_val.v.val_float.length = length;
370150397Sobrien  attr->dw_attr_val.v.val_float.array = array;
370250397Sobrien  add_dwarf_attr (die, attr);
370350397Sobrien}
370450397Sobrien
370550397Sobrien/* Add a string attribute value to a DIE.  */
370650397Sobrien
370750397Sobrienstatic inline void
370850397Sobrienadd_AT_string (die, attr_kind, str)
370950397Sobrien     register dw_die_ref die;
371050397Sobrien     register enum dwarf_attribute attr_kind;
371150397Sobrien     register char *str;
371250397Sobrien{
371350397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
371450397Sobrien
371550397Sobrien  attr->dw_attr_next = NULL;
371650397Sobrien  attr->dw_attr = attr_kind;
371750397Sobrien  attr->dw_attr_val.val_class = dw_val_class_str;
371850397Sobrien  attr->dw_attr_val.v.val_str = xstrdup (str);
371950397Sobrien  add_dwarf_attr (die, attr);
372050397Sobrien}
372150397Sobrien
372250397Sobrien/* Add a DIE reference attribute value to a DIE.  */
372350397Sobrien
372450397Sobrienstatic inline void
372550397Sobrienadd_AT_die_ref (die, attr_kind, targ_die)
372650397Sobrien     register dw_die_ref die;
372750397Sobrien     register enum dwarf_attribute attr_kind;
372850397Sobrien     register dw_die_ref targ_die;
372950397Sobrien{
373050397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
373150397Sobrien
373250397Sobrien  attr->dw_attr_next = NULL;
373350397Sobrien  attr->dw_attr = attr_kind;
373450397Sobrien  attr->dw_attr_val.val_class = dw_val_class_die_ref;
373550397Sobrien  attr->dw_attr_val.v.val_die_ref = targ_die;
373650397Sobrien  add_dwarf_attr (die, attr);
373750397Sobrien}
373850397Sobrien
373950397Sobrien/* Add an FDE reference attribute value to a DIE.  */
374050397Sobrien
374150397Sobrienstatic inline void
374250397Sobrienadd_AT_fde_ref (die, attr_kind, targ_fde)
374350397Sobrien     register dw_die_ref die;
374450397Sobrien     register enum dwarf_attribute attr_kind;
374550397Sobrien     register unsigned targ_fde;
374650397Sobrien{
374750397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
374850397Sobrien
374950397Sobrien  attr->dw_attr_next = NULL;
375050397Sobrien  attr->dw_attr = attr_kind;
375150397Sobrien  attr->dw_attr_val.val_class = dw_val_class_fde_ref;
375250397Sobrien  attr->dw_attr_val.v.val_fde_index = targ_fde;
375350397Sobrien  add_dwarf_attr (die, attr);
375450397Sobrien}
375550397Sobrien
375650397Sobrien/* Add a location description attribute value to a DIE.  */
375750397Sobrien
375850397Sobrienstatic inline void
375950397Sobrienadd_AT_loc (die, attr_kind, loc)
376050397Sobrien     register dw_die_ref die;
376150397Sobrien     register enum dwarf_attribute attr_kind;
376250397Sobrien     register dw_loc_descr_ref loc;
376350397Sobrien{
376450397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
376550397Sobrien
376650397Sobrien  attr->dw_attr_next = NULL;
376750397Sobrien  attr->dw_attr = attr_kind;
376850397Sobrien  attr->dw_attr_val.val_class = dw_val_class_loc;
376950397Sobrien  attr->dw_attr_val.v.val_loc = loc;
377050397Sobrien  add_dwarf_attr (die, attr);
377150397Sobrien}
377250397Sobrien
377350397Sobrien/* Add an address constant attribute value to a DIE.  */
377450397Sobrien
377550397Sobrienstatic inline void
377650397Sobrienadd_AT_addr (die, attr_kind, addr)
377750397Sobrien     register dw_die_ref die;
377850397Sobrien     register enum dwarf_attribute attr_kind;
377950397Sobrien     char *addr;
378050397Sobrien{
378150397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
378250397Sobrien
378350397Sobrien  attr->dw_attr_next = NULL;
378450397Sobrien  attr->dw_attr = attr_kind;
378550397Sobrien  attr->dw_attr_val.val_class = dw_val_class_addr;
378650397Sobrien  attr->dw_attr_val.v.val_addr = addr;
378750397Sobrien  add_dwarf_attr (die, attr);
378850397Sobrien}
378950397Sobrien
379050397Sobrien/* Add a label identifier attribute value to a DIE.  */
379150397Sobrien
379250397Sobrienstatic inline void
379350397Sobrienadd_AT_lbl_id (die, attr_kind, lbl_id)
379450397Sobrien     register dw_die_ref die;
379550397Sobrien     register enum dwarf_attribute attr_kind;
379650397Sobrien     register char *lbl_id;
379750397Sobrien{
379850397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
379950397Sobrien
380050397Sobrien  attr->dw_attr_next = NULL;
380150397Sobrien  attr->dw_attr = attr_kind;
380250397Sobrien  attr->dw_attr_val.val_class = dw_val_class_lbl_id;
380350397Sobrien  attr->dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
380450397Sobrien  add_dwarf_attr (die, attr);
380550397Sobrien}
380650397Sobrien
380750397Sobrien/* Add a section offset attribute value to a DIE.  */
380850397Sobrien
380950397Sobrienstatic inline void
381050397Sobrienadd_AT_section_offset (die, attr_kind, section)
381150397Sobrien     register dw_die_ref die;
381250397Sobrien     register enum dwarf_attribute attr_kind;
381350397Sobrien     register char *section;
381450397Sobrien{
381550397Sobrien  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
381650397Sobrien
381750397Sobrien  attr->dw_attr_next = NULL;
381850397Sobrien  attr->dw_attr = attr_kind;
381950397Sobrien  attr->dw_attr_val.val_class = dw_val_class_section_offset;
382050397Sobrien  attr->dw_attr_val.v.val_section = section;
382150397Sobrien  add_dwarf_attr (die, attr);
382250397Sobrien
382350397Sobrien}
382450397Sobrien
382550397Sobrien/* Test if die refers to an external subroutine.  */
382650397Sobrien
382750397Sobrienstatic inline int
382850397Sobrienis_extern_subr_die (die)
382950397Sobrien     register dw_die_ref die;
383050397Sobrien{
383150397Sobrien  register dw_attr_ref a;
383250397Sobrien  register int is_subr = FALSE;
383350397Sobrien  register int is_extern = FALSE;
383450397Sobrien
383550397Sobrien  if (die != NULL && die->die_tag == DW_TAG_subprogram)
383650397Sobrien    {
383750397Sobrien      is_subr = TRUE;
383850397Sobrien      for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
383950397Sobrien	{
384050397Sobrien	  if (a->dw_attr == DW_AT_external
384150397Sobrien	      && a->dw_attr_val.val_class == dw_val_class_flag
384250397Sobrien	      && a->dw_attr_val.v.val_flag != 0)
384350397Sobrien	    {
384450397Sobrien	      is_extern = TRUE;
384550397Sobrien	      break;
384650397Sobrien	    }
384750397Sobrien	}
384850397Sobrien    }
384950397Sobrien
385050397Sobrien  return is_subr && is_extern;
385150397Sobrien}
385250397Sobrien
385350397Sobrien/* Get the attribute of type attr_kind.  */
385450397Sobrien
385550397Sobrienstatic inline dw_attr_ref
385650397Sobrienget_AT (die, attr_kind)
385750397Sobrien     register dw_die_ref die;
385850397Sobrien     register enum dwarf_attribute attr_kind;
385950397Sobrien{
386050397Sobrien  register dw_attr_ref a;
386150397Sobrien  register dw_die_ref spec = NULL;
386250397Sobrien
386350397Sobrien  if (die != NULL)
386450397Sobrien    {
386550397Sobrien      for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
386650397Sobrien	{
386750397Sobrien	  if (a->dw_attr == attr_kind)
386850397Sobrien	    return a;
386950397Sobrien
387050397Sobrien	  if (a->dw_attr == DW_AT_specification
387150397Sobrien	      || a->dw_attr == DW_AT_abstract_origin)
387250397Sobrien	    spec = a->dw_attr_val.v.val_die_ref;
387350397Sobrien	}
387450397Sobrien
387550397Sobrien      if (spec)
387650397Sobrien	return get_AT (spec, attr_kind);
387750397Sobrien    }
387850397Sobrien
387950397Sobrien  return NULL;
388050397Sobrien}
388150397Sobrien
388250397Sobrien/* Return the "low pc" attribute value, typically associated with
388350397Sobrien   a subprogram DIE.  Return null if the "low pc" attribute is
388450397Sobrien   either not prsent, or if it cannot be represented as an
388550397Sobrien   assembler label identifier.  */
388650397Sobrien
388750397Sobrienstatic inline char *
388850397Sobrienget_AT_low_pc (die)
388950397Sobrien     register dw_die_ref die;
389050397Sobrien{
389150397Sobrien  register dw_attr_ref a = get_AT (die, DW_AT_low_pc);
389250397Sobrien
389350397Sobrien  if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id)
389450397Sobrien    return a->dw_attr_val.v.val_lbl_id;
389550397Sobrien
389650397Sobrien  return NULL;
389750397Sobrien}
389850397Sobrien
389950397Sobrien/* Return the "high pc" attribute value, typically associated with
390050397Sobrien   a subprogram DIE.  Return null if the "high pc" attribute is
390150397Sobrien   either not prsent, or if it cannot be represented as an
390250397Sobrien   assembler label identifier.  */
390350397Sobrien
390450397Sobrienstatic inline char *
390550397Sobrienget_AT_hi_pc (die)
390650397Sobrien     register dw_die_ref die;
390750397Sobrien{
390850397Sobrien  register dw_attr_ref a = get_AT (die, DW_AT_high_pc);
390950397Sobrien
391050397Sobrien  if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id)
391150397Sobrien    return a->dw_attr_val.v.val_lbl_id;
391250397Sobrien
391350397Sobrien  return NULL;
391450397Sobrien}
391550397Sobrien
391650397Sobrien/* Return the value of the string attribute designated by ATTR_KIND, or
391750397Sobrien   NULL if it is not present.  */
391850397Sobrien
391950397Sobrienstatic inline char *
392050397Sobrienget_AT_string (die, attr_kind)
392150397Sobrien     register dw_die_ref die;
392250397Sobrien     register enum dwarf_attribute attr_kind;
392350397Sobrien{
392450397Sobrien  register dw_attr_ref a = get_AT (die, attr_kind);
392550397Sobrien
392650397Sobrien  if (a && a->dw_attr_val.val_class == dw_val_class_str)
392750397Sobrien    return a->dw_attr_val.v.val_str;
392850397Sobrien
392950397Sobrien  return NULL;
393050397Sobrien}
393150397Sobrien
393250397Sobrien/* Return the value of the flag attribute designated by ATTR_KIND, or -1
393350397Sobrien   if it is not present.  */
393450397Sobrien
393550397Sobrienstatic inline int
393650397Sobrienget_AT_flag (die, attr_kind)
393750397Sobrien     register dw_die_ref die;
393850397Sobrien     register enum dwarf_attribute attr_kind;
393950397Sobrien{
394050397Sobrien  register dw_attr_ref a = get_AT (die, attr_kind);
394150397Sobrien
394250397Sobrien  if (a && a->dw_attr_val.val_class == dw_val_class_flag)
394350397Sobrien    return a->dw_attr_val.v.val_flag;
394450397Sobrien
394550397Sobrien  return -1;
394650397Sobrien}
394750397Sobrien
394850397Sobrien/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0
394950397Sobrien   if it is not present.  */
395050397Sobrien
395150397Sobrienstatic inline unsigned
395250397Sobrienget_AT_unsigned (die, attr_kind)
395350397Sobrien     register dw_die_ref die;
395450397Sobrien     register enum dwarf_attribute attr_kind;
395550397Sobrien{
395650397Sobrien  register dw_attr_ref a = get_AT (die, attr_kind);
395750397Sobrien
395850397Sobrien  if (a && a->dw_attr_val.val_class == dw_val_class_unsigned_const)
395950397Sobrien    return a->dw_attr_val.v.val_unsigned;
396050397Sobrien
396150397Sobrien  return 0;
396250397Sobrien}
396350397Sobrien
396450397Sobrienstatic inline int
396550397Sobrienis_c_family ()
396650397Sobrien{
396750397Sobrien  register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
396850397Sobrien
396950397Sobrien  return (lang == DW_LANG_C || lang == DW_LANG_C89
397050397Sobrien	  || lang == DW_LANG_C_plus_plus);
397150397Sobrien}
397250397Sobrien
397350397Sobrienstatic inline int
397450397Sobrienis_fortran ()
397550397Sobrien{
397650397Sobrien  register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
397750397Sobrien
397850397Sobrien  return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90);
397950397Sobrien}
398050397Sobrien
398150397Sobrien/* Remove the specified attribute if present.  */
398250397Sobrien
398350397Sobrienstatic inline void
398450397Sobrienremove_AT (die, attr_kind)
398550397Sobrien     register dw_die_ref die;
398650397Sobrien     register enum dwarf_attribute attr_kind;
398750397Sobrien{
398850397Sobrien  register dw_attr_ref a;
398950397Sobrien  register dw_attr_ref removed = NULL;;
399050397Sobrien
399150397Sobrien  if (die != NULL)
399250397Sobrien    {
399350397Sobrien      if (die->die_attr->dw_attr == attr_kind)
399450397Sobrien	{
399550397Sobrien	  removed = die->die_attr;
399650397Sobrien	  if (die->die_attr_last == die->die_attr)
399750397Sobrien	    die->die_attr_last = NULL;
399850397Sobrien
399950397Sobrien	  die->die_attr = die->die_attr->dw_attr_next;
400050397Sobrien	}
400150397Sobrien
400250397Sobrien      else
400350397Sobrien	for (a = die->die_attr; a->dw_attr_next != NULL;
400450397Sobrien	     a = a->dw_attr_next)
400550397Sobrien	  if (a->dw_attr_next->dw_attr == attr_kind)
400650397Sobrien	    {
400750397Sobrien	      removed = a->dw_attr_next;
400850397Sobrien	      if (die->die_attr_last == a->dw_attr_next)
400950397Sobrien		die->die_attr_last = a;
401050397Sobrien
401150397Sobrien	      a->dw_attr_next = a->dw_attr_next->dw_attr_next;
401250397Sobrien	      break;
401350397Sobrien	    }
401450397Sobrien
401550397Sobrien      if (removed != 0)
401650397Sobrien	free (removed);
401750397Sobrien    }
401850397Sobrien}
401950397Sobrien
402050397Sobrien/* Discard the children of this DIE.  */
402150397Sobrien
402250397Sobrienstatic inline void
402350397Sobrienremove_children (die)
402450397Sobrien     register dw_die_ref die;
402550397Sobrien{
402650397Sobrien  register dw_die_ref child_die = die->die_child;
402750397Sobrien
402850397Sobrien  die->die_child = NULL;
402950397Sobrien  die->die_child_last = NULL;
403050397Sobrien
403150397Sobrien  while (child_die != NULL)
403250397Sobrien    {
403350397Sobrien      register dw_die_ref tmp_die = child_die;
403450397Sobrien      register dw_attr_ref a;
403550397Sobrien
403650397Sobrien      child_die = child_die->die_sib;
403750397Sobrien
403850397Sobrien      for (a = tmp_die->die_attr; a != NULL; )
403950397Sobrien	{
404050397Sobrien	  register dw_attr_ref tmp_a = a;
404150397Sobrien
404250397Sobrien	  a = a->dw_attr_next;
404350397Sobrien	  free (tmp_a);
404450397Sobrien	}
404550397Sobrien
404650397Sobrien      free (tmp_die);
404750397Sobrien    }
404850397Sobrien}
404950397Sobrien
405050397Sobrien/* Add a child DIE below its parent.  */
405150397Sobrien
405250397Sobrienstatic inline void
405350397Sobrienadd_child_die (die, child_die)
405450397Sobrien     register dw_die_ref die;
405550397Sobrien     register dw_die_ref child_die;
405650397Sobrien{
405750397Sobrien  if (die != NULL && child_die != NULL)
405850397Sobrien    {
405950397Sobrien      if (die == child_die)
406050397Sobrien	abort ();
406150397Sobrien      child_die->die_parent = die;
406250397Sobrien      child_die->die_sib = NULL;
406350397Sobrien
406450397Sobrien      if (die->die_child == NULL)
406550397Sobrien	{
406650397Sobrien	  die->die_child = child_die;
406750397Sobrien	  die->die_child_last = child_die;
406850397Sobrien	}
406950397Sobrien      else
407050397Sobrien	{
407150397Sobrien	  die->die_child_last->die_sib = child_die;
407250397Sobrien	  die->die_child_last = child_die;
407350397Sobrien	}
407450397Sobrien    }
407550397Sobrien}
407650397Sobrien
407750397Sobrien/* Return a pointer to a newly created DIE node.  */
407850397Sobrien
407950397Sobrienstatic inline dw_die_ref
408050397Sobriennew_die (tag_value, parent_die)
408150397Sobrien     register enum dwarf_tag tag_value;
408250397Sobrien     register dw_die_ref parent_die;
408350397Sobrien{
408450397Sobrien  register dw_die_ref die = (dw_die_ref) xmalloc (sizeof (die_node));
408550397Sobrien
408650397Sobrien  die->die_tag = tag_value;
408750397Sobrien  die->die_abbrev = 0;
408850397Sobrien  die->die_offset = 0;
408950397Sobrien  die->die_child = NULL;
409050397Sobrien  die->die_parent = NULL;
409150397Sobrien  die->die_sib = NULL;
409250397Sobrien  die->die_child_last = NULL;
409350397Sobrien  die->die_attr = NULL;
409450397Sobrien  die->die_attr_last = NULL;
409550397Sobrien
409650397Sobrien  if (parent_die != NULL)
409750397Sobrien    add_child_die (parent_die, die);
409850397Sobrien  else
409950397Sobrien    {
410050397Sobrien      limbo_die_node *limbo_node;
410150397Sobrien
410250397Sobrien      limbo_node = (limbo_die_node *) xmalloc (sizeof (limbo_die_node));
410350397Sobrien      limbo_node->die = die;
410450397Sobrien      limbo_node->next = limbo_die_list;
410550397Sobrien      limbo_die_list = limbo_node;
410650397Sobrien    }
410750397Sobrien
410850397Sobrien  return die;
410950397Sobrien}
411050397Sobrien
411150397Sobrien/* Return the DIE associated with the given type specifier.  */
411250397Sobrien
411350397Sobrienstatic inline dw_die_ref
411450397Sobrienlookup_type_die (type)
411550397Sobrien     register tree type;
411650397Sobrien{
411750397Sobrien  return (dw_die_ref) TYPE_SYMTAB_POINTER (type);
411850397Sobrien}
411950397Sobrien
412050397Sobrien/* Equate a DIE to a given type specifier.  */
412150397Sobrien
412250397Sobrienstatic void
412350397Sobrienequate_type_number_to_die (type, type_die)
412450397Sobrien     register tree type;
412550397Sobrien     register dw_die_ref type_die;
412650397Sobrien{
412750397Sobrien  TYPE_SYMTAB_POINTER (type) = (char *) type_die;
412850397Sobrien}
412950397Sobrien
413050397Sobrien/* Return the DIE associated with a given declaration.  */
413150397Sobrien
413250397Sobrienstatic inline dw_die_ref
413350397Sobrienlookup_decl_die (decl)
413450397Sobrien     register tree decl;
413550397Sobrien{
413650397Sobrien  register unsigned decl_id = DECL_UID (decl);
413750397Sobrien
413850397Sobrien  return (decl_id < decl_die_table_in_use
413950397Sobrien	  ? decl_die_table[decl_id] : NULL);
414050397Sobrien}
414150397Sobrien
414250397Sobrien/* Equate a DIE to a particular declaration.  */
414350397Sobrien
414450397Sobrienstatic void
414550397Sobrienequate_decl_number_to_die (decl, decl_die)
414650397Sobrien     register tree decl;
414750397Sobrien     register dw_die_ref decl_die;
414850397Sobrien{
414950397Sobrien  register unsigned decl_id = DECL_UID (decl);
415050397Sobrien  register unsigned num_allocated;
415150397Sobrien
415250397Sobrien  if (decl_id >= decl_die_table_allocated)
415350397Sobrien    {
415450397Sobrien      num_allocated
415550397Sobrien	= ((decl_id + 1 + DECL_DIE_TABLE_INCREMENT - 1)
415650397Sobrien	   / DECL_DIE_TABLE_INCREMENT)
415750397Sobrien	  * DECL_DIE_TABLE_INCREMENT;
415850397Sobrien
415950397Sobrien      decl_die_table
416050397Sobrien	= (dw_die_ref *) xrealloc (decl_die_table,
416150397Sobrien				   sizeof (dw_die_ref) * num_allocated);
416250397Sobrien
416350397Sobrien      bzero ((char *) &decl_die_table[decl_die_table_allocated],
416450397Sobrien	     (num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref));
416550397Sobrien      decl_die_table_allocated = num_allocated;
416650397Sobrien    }
416750397Sobrien
416850397Sobrien  if (decl_id >= decl_die_table_in_use)
416950397Sobrien    decl_die_table_in_use = (decl_id + 1);
417050397Sobrien
417150397Sobrien  decl_die_table[decl_id] = decl_die;
417250397Sobrien}
417350397Sobrien
417450397Sobrien/* Return a pointer to a newly allocated location description.  Location
417550397Sobrien   descriptions are simple expression terms that can be strung
417650397Sobrien   together to form more complicated location (address) descriptions.  */
417750397Sobrien
417850397Sobrienstatic inline dw_loc_descr_ref
417950397Sobriennew_loc_descr (op, oprnd1, oprnd2)
418050397Sobrien     register enum dwarf_location_atom op;
418150397Sobrien     register unsigned long oprnd1;
418250397Sobrien     register unsigned long oprnd2;
418350397Sobrien{
418450397Sobrien  register dw_loc_descr_ref descr
418550397Sobrien    = (dw_loc_descr_ref) xmalloc (sizeof (dw_loc_descr_node));
418650397Sobrien
418750397Sobrien  descr->dw_loc_next = NULL;
418850397Sobrien  descr->dw_loc_opc = op;
418950397Sobrien  descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
419050397Sobrien  descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
419150397Sobrien  descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
419250397Sobrien  descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
419350397Sobrien
419450397Sobrien  return descr;
419550397Sobrien}
419650397Sobrien
419750397Sobrien/* Add a location description term to a location description expression.  */
419850397Sobrien
419950397Sobrienstatic inline void
420050397Sobrienadd_loc_descr (list_head, descr)
420150397Sobrien     register dw_loc_descr_ref *list_head;
420250397Sobrien     register dw_loc_descr_ref descr;
420350397Sobrien{
420450397Sobrien  register dw_loc_descr_ref *d;
420550397Sobrien
420650397Sobrien  /* Find the end of the chain.  */
420750397Sobrien  for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
420850397Sobrien    ;
420950397Sobrien
421050397Sobrien  *d = descr;
421150397Sobrien}
421250397Sobrien
421350397Sobrien/* Keep track of the number of spaces used to indent the
421450397Sobrien   output of the debugging routines that print the structure of
421550397Sobrien   the DIE internal representation.  */
421650397Sobrienstatic int print_indent;
421750397Sobrien
421850397Sobrien/* Indent the line the number of spaces given by print_indent.  */
421950397Sobrien
422050397Sobrienstatic inline void
422150397Sobrienprint_spaces (outfile)
422250397Sobrien     FILE *outfile;
422350397Sobrien{
422450397Sobrien  fprintf (outfile, "%*s", print_indent, "");
422550397Sobrien}
422650397Sobrien
422750397Sobrien/* Print the information associated with a given DIE, and its children.
422850397Sobrien   This routine is a debugging aid only.  */
422950397Sobrien
423050397Sobrienstatic void
423150397Sobrienprint_die (die, outfile)
423250397Sobrien     dw_die_ref die;
423350397Sobrien     FILE *outfile;
423450397Sobrien{
423550397Sobrien  register dw_attr_ref a;
423650397Sobrien  register dw_die_ref c;
423750397Sobrien
423850397Sobrien  print_spaces (outfile);
423950397Sobrien  fprintf (outfile, "DIE %4lu: %s\n",
424050397Sobrien	   die->die_offset, dwarf_tag_name (die->die_tag));
424150397Sobrien  print_spaces (outfile);
424250397Sobrien  fprintf (outfile, "  abbrev id: %lu", die->die_abbrev);
424350397Sobrien  fprintf (outfile, " offset: %lu\n", die->die_offset);
424450397Sobrien
424550397Sobrien  for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
424650397Sobrien    {
424750397Sobrien      print_spaces (outfile);
424850397Sobrien      fprintf (outfile, "  %s: ", dwarf_attr_name (a->dw_attr));
424950397Sobrien
425050397Sobrien      switch (a->dw_attr_val.val_class)
425150397Sobrien	{
425250397Sobrien	case dw_val_class_addr:
425350397Sobrien	  fprintf (outfile, "address");
425450397Sobrien	  break;
425550397Sobrien	case dw_val_class_loc:
425650397Sobrien	  fprintf (outfile, "location descriptor");
425750397Sobrien	  break;
425850397Sobrien	case dw_val_class_const:
425950397Sobrien	  fprintf (outfile, "%ld", a->dw_attr_val.v.val_int);
426050397Sobrien	  break;
426150397Sobrien	case dw_val_class_unsigned_const:
426250397Sobrien	  fprintf (outfile, "%lu", a->dw_attr_val.v.val_unsigned);
426350397Sobrien	  break;
426450397Sobrien	case dw_val_class_long_long:
426550397Sobrien	  fprintf (outfile, "constant (%lu,%lu)",
426650397Sobrien		  a->dw_attr_val.v.val_long_long.hi,
426750397Sobrien		  a->dw_attr_val.v.val_long_long.low);
426850397Sobrien	  break;
426950397Sobrien	case dw_val_class_float:
427050397Sobrien	  fprintf (outfile, "floating-point constant");
427150397Sobrien	  break;
427250397Sobrien	case dw_val_class_flag:
427350397Sobrien	  fprintf (outfile, "%u", a->dw_attr_val.v.val_flag);
427450397Sobrien	  break;
427550397Sobrien	case dw_val_class_die_ref:
427650397Sobrien	  if (a->dw_attr_val.v.val_die_ref != NULL)
427750397Sobrien	    fprintf (outfile, "die -> %lu",
427850397Sobrien		     a->dw_attr_val.v.val_die_ref->die_offset);
427950397Sobrien	  else
428050397Sobrien	    fprintf (outfile, "die -> <null>");
428150397Sobrien	  break;
428250397Sobrien	case dw_val_class_lbl_id:
428350397Sobrien	  fprintf (outfile, "label: %s", a->dw_attr_val.v.val_lbl_id);
428450397Sobrien	  break;
428550397Sobrien	case dw_val_class_section_offset:
428650397Sobrien	  fprintf (outfile, "section: %s", a->dw_attr_val.v.val_section);
428750397Sobrien	  break;
428850397Sobrien	case dw_val_class_str:
428950397Sobrien	  if (a->dw_attr_val.v.val_str != NULL)
429050397Sobrien	    fprintf (outfile, "\"%s\"", a->dw_attr_val.v.val_str);
429150397Sobrien	  else
429250397Sobrien	    fprintf (outfile, "<null>");
429350397Sobrien	  break;
429450397Sobrien	default:
429550397Sobrien	  break;
429650397Sobrien	}
429750397Sobrien
429850397Sobrien      fprintf (outfile, "\n");
429950397Sobrien    }
430050397Sobrien
430150397Sobrien  if (die->die_child != NULL)
430250397Sobrien    {
430350397Sobrien      print_indent += 4;
430450397Sobrien      for (c = die->die_child; c != NULL; c = c->die_sib)
430550397Sobrien	print_die (c, outfile);
430650397Sobrien
430750397Sobrien      print_indent -= 4;
430850397Sobrien    }
430950397Sobrien}
431050397Sobrien
431150397Sobrien/* Print the contents of the source code line number correspondence table.
431250397Sobrien   This routine is a debugging aid only.  */
431350397Sobrien
431450397Sobrienstatic void
431550397Sobrienprint_dwarf_line_table (outfile)
431650397Sobrien     FILE *outfile;
431750397Sobrien{
431850397Sobrien  register unsigned i;
431950397Sobrien  register dw_line_info_ref line_info;
432050397Sobrien
432150397Sobrien  fprintf (outfile, "\n\nDWARF source line information\n");
432250397Sobrien  for (i = 1; i < line_info_table_in_use; ++i)
432350397Sobrien    {
432450397Sobrien      line_info = &line_info_table[i];
432550397Sobrien      fprintf (outfile, "%5d: ", i);
432650397Sobrien      fprintf (outfile, "%-20s", file_table[line_info->dw_file_num]);
432750397Sobrien      fprintf (outfile, "%6ld", line_info->dw_line_num);
432850397Sobrien      fprintf (outfile, "\n");
432950397Sobrien    }
433050397Sobrien
433150397Sobrien  fprintf (outfile, "\n\n");
433250397Sobrien}
433350397Sobrien
433450397Sobrien/* Print the information collected for a given DIE.  */
433550397Sobrien
433650397Sobrienvoid
433750397Sobriendebug_dwarf_die (die)
433850397Sobrien     dw_die_ref die;
433950397Sobrien{
434050397Sobrien  print_die (die, stderr);
434150397Sobrien}
434250397Sobrien
434350397Sobrien/* Print all DWARF information collected for the compilation unit.
434450397Sobrien   This routine is a debugging aid only.  */
434550397Sobrien
434650397Sobrienvoid
434750397Sobriendebug_dwarf ()
434850397Sobrien{
434950397Sobrien  print_indent = 0;
435050397Sobrien  print_die (comp_unit_die, stderr);
435150397Sobrien  print_dwarf_line_table (stderr);
435250397Sobrien}
435350397Sobrien
435450397Sobrien/* Traverse the DIE, and add a sibling attribute if it may have the
435550397Sobrien   effect of speeding up access to siblings.  To save some space,
435650397Sobrien   avoid generating sibling attributes for DIE's without children.  */
435750397Sobrien
435850397Sobrienstatic void
435950397Sobrienadd_sibling_attributes(die)
436050397Sobrien     register dw_die_ref die;
436150397Sobrien{
436250397Sobrien  register dw_die_ref c;
436350397Sobrien  register dw_attr_ref attr;
436450397Sobrien  if (die != comp_unit_die && die->die_child != NULL)
436550397Sobrien    {
436650397Sobrien      attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
436750397Sobrien      attr->dw_attr_next = NULL;
436850397Sobrien      attr->dw_attr = DW_AT_sibling;
436950397Sobrien      attr->dw_attr_val.val_class = dw_val_class_die_ref;
437050397Sobrien      attr->dw_attr_val.v.val_die_ref = die->die_sib;
437150397Sobrien
437250397Sobrien      /* Add the sibling link to the front of the attribute list.  */
437350397Sobrien      attr->dw_attr_next = die->die_attr;
437450397Sobrien      if (die->die_attr == NULL)
437550397Sobrien	die->die_attr_last = attr;
437650397Sobrien
437750397Sobrien      die->die_attr = attr;
437850397Sobrien    }
437950397Sobrien
438050397Sobrien  for (c = die->die_child; c != NULL; c = c->die_sib)
438150397Sobrien    add_sibling_attributes (c);
438250397Sobrien}
438350397Sobrien
438450397Sobrien/* The format of each DIE (and its attribute value pairs)
438550397Sobrien   is encoded in an abbreviation table.  This routine builds the
438650397Sobrien   abbreviation table and assigns a unique abbreviation id for
438750397Sobrien   each abbreviation entry.  The children of each die are visited
438850397Sobrien   recursively.  */
438950397Sobrien
439050397Sobrienstatic void
439150397Sobrienbuild_abbrev_table (die)
439250397Sobrien     register dw_die_ref die;
439350397Sobrien{
439450397Sobrien  register unsigned long abbrev_id;
439550397Sobrien  register unsigned long n_alloc;
439650397Sobrien  register dw_die_ref c;
439750397Sobrien  register dw_attr_ref d_attr, a_attr;
439850397Sobrien  for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
439950397Sobrien    {
440050397Sobrien      register dw_die_ref abbrev = abbrev_die_table[abbrev_id];
440150397Sobrien
440250397Sobrien      if (abbrev->die_tag == die->die_tag)
440350397Sobrien	{
440450397Sobrien	  if ((abbrev->die_child != NULL) == (die->die_child != NULL))
440550397Sobrien	    {
440650397Sobrien	      a_attr = abbrev->die_attr;
440750397Sobrien	      d_attr = die->die_attr;
440850397Sobrien
440950397Sobrien	      while (a_attr != NULL && d_attr != NULL)
441050397Sobrien		{
441150397Sobrien		  if ((a_attr->dw_attr != d_attr->dw_attr)
441250397Sobrien		      || (value_format (&a_attr->dw_attr_val)
441350397Sobrien			  != value_format (&d_attr->dw_attr_val)))
441450397Sobrien		    break;
441550397Sobrien
441650397Sobrien		  a_attr = a_attr->dw_attr_next;
441750397Sobrien		  d_attr = d_attr->dw_attr_next;
441850397Sobrien		}
441950397Sobrien
442050397Sobrien	      if (a_attr == NULL && d_attr == NULL)
442150397Sobrien		break;
442250397Sobrien	    }
442350397Sobrien	}
442450397Sobrien    }
442550397Sobrien
442650397Sobrien  if (abbrev_id >= abbrev_die_table_in_use)
442750397Sobrien    {
442850397Sobrien      if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
442950397Sobrien	{
443050397Sobrien	  n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
443150397Sobrien	  abbrev_die_table
443250397Sobrien	    = (dw_die_ref *) xrealloc (abbrev_die_table,
443350397Sobrien				       sizeof (dw_die_ref) * n_alloc);
443450397Sobrien
443550397Sobrien	  bzero ((char *) &abbrev_die_table[abbrev_die_table_allocated],
443650397Sobrien		 (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
443750397Sobrien	  abbrev_die_table_allocated = n_alloc;
443850397Sobrien	}
443950397Sobrien
444050397Sobrien      ++abbrev_die_table_in_use;
444150397Sobrien      abbrev_die_table[abbrev_id] = die;
444250397Sobrien    }
444350397Sobrien
444450397Sobrien  die->die_abbrev = abbrev_id;
444550397Sobrien  for (c = die->die_child; c != NULL; c = c->die_sib)
444650397Sobrien    build_abbrev_table (c);
444750397Sobrien}
444850397Sobrien
444950397Sobrien/* Return the size of a string, including the null byte.
445050397Sobrien
445150397Sobrien   This used to treat backslashes as escapes, and hence they were not included
445250397Sobrien   in the count.  However, that conflicts with what ASM_OUTPUT_ASCII does,
445350397Sobrien   which treats a backslash as a backslash, escaping it if necessary, and hence
445450397Sobrien   we must include them in the count.  */
445550397Sobrien
445650397Sobrienstatic unsigned long
445750397Sobriensize_of_string (str)
445850397Sobrien     register char *str;
445950397Sobrien{
446050397Sobrien  return strlen (str) + 1;
446150397Sobrien}
446250397Sobrien
446350397Sobrien/* Return the size of a location descriptor.  */
446450397Sobrien
446550397Sobrienstatic unsigned long
446650397Sobriensize_of_loc_descr (loc)
446750397Sobrien     register dw_loc_descr_ref loc;
446850397Sobrien{
446950397Sobrien  register unsigned long size = 1;
447050397Sobrien
447150397Sobrien  switch (loc->dw_loc_opc)
447250397Sobrien    {
447350397Sobrien    case DW_OP_addr:
447450397Sobrien      size += PTR_SIZE;
447550397Sobrien      break;
447650397Sobrien    case DW_OP_const1u:
447750397Sobrien    case DW_OP_const1s:
447850397Sobrien      size += 1;
447950397Sobrien      break;
448050397Sobrien    case DW_OP_const2u:
448150397Sobrien    case DW_OP_const2s:
448250397Sobrien      size += 2;
448350397Sobrien      break;
448450397Sobrien    case DW_OP_const4u:
448550397Sobrien    case DW_OP_const4s:
448650397Sobrien      size += 4;
448750397Sobrien      break;
448850397Sobrien    case DW_OP_const8u:
448950397Sobrien    case DW_OP_const8s:
449050397Sobrien      size += 8;
449150397Sobrien      break;
449250397Sobrien    case DW_OP_constu:
449350397Sobrien      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
449450397Sobrien      break;
449550397Sobrien    case DW_OP_consts:
449650397Sobrien      size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
449750397Sobrien      break;
449850397Sobrien    case DW_OP_pick:
449950397Sobrien      size += 1;
450050397Sobrien      break;
450150397Sobrien    case DW_OP_plus_uconst:
450250397Sobrien      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
450350397Sobrien      break;
450450397Sobrien    case DW_OP_skip:
450550397Sobrien    case DW_OP_bra:
450650397Sobrien      size += 2;
450750397Sobrien      break;
450850397Sobrien    case DW_OP_breg0:
450950397Sobrien    case DW_OP_breg1:
451050397Sobrien    case DW_OP_breg2:
451150397Sobrien    case DW_OP_breg3:
451250397Sobrien    case DW_OP_breg4:
451350397Sobrien    case DW_OP_breg5:
451450397Sobrien    case DW_OP_breg6:
451550397Sobrien    case DW_OP_breg7:
451650397Sobrien    case DW_OP_breg8:
451750397Sobrien    case DW_OP_breg9:
451850397Sobrien    case DW_OP_breg10:
451950397Sobrien    case DW_OP_breg11:
452050397Sobrien    case DW_OP_breg12:
452150397Sobrien    case DW_OP_breg13:
452250397Sobrien    case DW_OP_breg14:
452350397Sobrien    case DW_OP_breg15:
452450397Sobrien    case DW_OP_breg16:
452550397Sobrien    case DW_OP_breg17:
452650397Sobrien    case DW_OP_breg18:
452750397Sobrien    case DW_OP_breg19:
452850397Sobrien    case DW_OP_breg20:
452950397Sobrien    case DW_OP_breg21:
453050397Sobrien    case DW_OP_breg22:
453150397Sobrien    case DW_OP_breg23:
453250397Sobrien    case DW_OP_breg24:
453350397Sobrien    case DW_OP_breg25:
453450397Sobrien    case DW_OP_breg26:
453550397Sobrien    case DW_OP_breg27:
453650397Sobrien    case DW_OP_breg28:
453750397Sobrien    case DW_OP_breg29:
453850397Sobrien    case DW_OP_breg30:
453950397Sobrien    case DW_OP_breg31:
454050397Sobrien      size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
454150397Sobrien      break;
454250397Sobrien    case DW_OP_regx:
454350397Sobrien      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
454450397Sobrien      break;
454550397Sobrien    case DW_OP_fbreg:
454650397Sobrien      size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
454750397Sobrien      break;
454850397Sobrien    case DW_OP_bregx:
454950397Sobrien      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
455050397Sobrien      size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
455150397Sobrien      break;
455250397Sobrien    case DW_OP_piece:
455350397Sobrien      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
455450397Sobrien      break;
455550397Sobrien    case DW_OP_deref_size:
455650397Sobrien    case DW_OP_xderef_size:
455750397Sobrien      size += 1;
455850397Sobrien      break;
455950397Sobrien    default:
456050397Sobrien      break;
456150397Sobrien    }
456250397Sobrien
456350397Sobrien  return size;
456450397Sobrien}
456550397Sobrien
456650397Sobrien/* Return the size of a series of location descriptors.  */
456750397Sobrien
456850397Sobrienstatic unsigned long
456950397Sobriensize_of_locs (loc)
457050397Sobrien     register dw_loc_descr_ref loc;
457150397Sobrien{
457250397Sobrien  register unsigned long size = 0;
457350397Sobrien
457450397Sobrien  for (; loc != NULL; loc = loc->dw_loc_next)
457550397Sobrien    size += size_of_loc_descr (loc);
457650397Sobrien
457750397Sobrien  return size;
457850397Sobrien}
457950397Sobrien
458050397Sobrien/* Return the power-of-two number of bytes necessary to represent VALUE.  */
458150397Sobrien
458250397Sobrienstatic int
458350397Sobrienconstant_size (value)
458450397Sobrien     long unsigned value;
458550397Sobrien{
458650397Sobrien  int log;
458750397Sobrien
458850397Sobrien  if (value == 0)
458950397Sobrien    log = 0;
459050397Sobrien  else
459150397Sobrien    log = floor_log2 (value);
459250397Sobrien
459350397Sobrien  log = log / 8;
459450397Sobrien  log = 1 << (floor_log2 (log) + 1);
459550397Sobrien
459650397Sobrien  return log;
459750397Sobrien}
459850397Sobrien
459950397Sobrien/* Return the size of a DIE, as it is represented in the
460050397Sobrien   .debug_info section.  */
460150397Sobrien
460250397Sobrienstatic unsigned long
460350397Sobriensize_of_die (die)
460450397Sobrien     register dw_die_ref die;
460550397Sobrien{
460650397Sobrien  register unsigned long size = 0;
460750397Sobrien  register dw_attr_ref a;
460850397Sobrien
460950397Sobrien  size += size_of_uleb128 (die->die_abbrev);
461050397Sobrien  for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
461150397Sobrien    {
461250397Sobrien      switch (a->dw_attr_val.val_class)
461350397Sobrien	{
461450397Sobrien	case dw_val_class_addr:
461550397Sobrien	  size += PTR_SIZE;
461650397Sobrien	  break;
461750397Sobrien	case dw_val_class_loc:
461850397Sobrien	  {
461950397Sobrien	    register unsigned long lsize
462050397Sobrien	      = size_of_locs (a->dw_attr_val.v.val_loc);
462150397Sobrien
462250397Sobrien	    /* Block length.  */
462350397Sobrien	    size += constant_size (lsize);
462450397Sobrien	    size += lsize;
462550397Sobrien	  }
462650397Sobrien	  break;
462750397Sobrien	case dw_val_class_const:
462850397Sobrien	  size += 4;
462950397Sobrien	  break;
463050397Sobrien	case dw_val_class_unsigned_const:
463150397Sobrien	  size += constant_size (a->dw_attr_val.v.val_unsigned);
463250397Sobrien	  break;
463350397Sobrien	case dw_val_class_long_long:
463450397Sobrien	  size += 1 + 8; /* block */
463550397Sobrien	  break;
463650397Sobrien	case dw_val_class_float:
463750397Sobrien	  size += 1 + a->dw_attr_val.v.val_float.length * 4; /* block */
463850397Sobrien	  break;
463950397Sobrien	case dw_val_class_flag:
464050397Sobrien	  size += 1;
464150397Sobrien	  break;
464250397Sobrien	case dw_val_class_die_ref:
464350397Sobrien	  size += DWARF_OFFSET_SIZE;
464450397Sobrien	  break;
464550397Sobrien	case dw_val_class_fde_ref:
464650397Sobrien	  size += DWARF_OFFSET_SIZE;
464750397Sobrien	  break;
464850397Sobrien	case dw_val_class_lbl_id:
464950397Sobrien	  size += PTR_SIZE;
465050397Sobrien	  break;
465150397Sobrien	case dw_val_class_section_offset:
465250397Sobrien	  size += DWARF_OFFSET_SIZE;
465350397Sobrien	  break;
465450397Sobrien	case dw_val_class_str:
465550397Sobrien	  size += size_of_string (a->dw_attr_val.v.val_str);
465650397Sobrien	  break;
465750397Sobrien	default:
465850397Sobrien	  abort ();
465950397Sobrien	}
466050397Sobrien    }
466150397Sobrien
466250397Sobrien  return size;
466350397Sobrien}
466450397Sobrien
466550397Sobrien/* Size the debugging information associated with a given DIE.
466650397Sobrien   Visits the DIE's children recursively.  Updates the global
466750397Sobrien   variable next_die_offset, on each time through.  Uses the
466850397Sobrien   current value of next_die_offset to update the die_offset
466950397Sobrien   field in each DIE.  */
467050397Sobrien
467150397Sobrienstatic void
467250397Sobriencalc_die_sizes (die)
467350397Sobrien     dw_die_ref die;
467450397Sobrien{
467550397Sobrien  register dw_die_ref c;
467650397Sobrien  die->die_offset = next_die_offset;
467750397Sobrien  next_die_offset += size_of_die (die);
467850397Sobrien
467950397Sobrien  for (c = die->die_child; c != NULL; c = c->die_sib)
468050397Sobrien    calc_die_sizes (c);
468150397Sobrien
468250397Sobrien  if (die->die_child != NULL)
468350397Sobrien    /* Count the null byte used to terminate sibling lists.  */
468450397Sobrien    next_die_offset += 1;
468550397Sobrien}
468650397Sobrien
468750397Sobrien/* Return the size of the line information prolog generated for the
468850397Sobrien   compilation unit.  */
468950397Sobrien
469050397Sobrienstatic unsigned long
469150397Sobriensize_of_line_prolog ()
469250397Sobrien{
469350397Sobrien  register unsigned long size;
469450397Sobrien  register unsigned long ft_index;
469550397Sobrien
469650397Sobrien  size = DWARF_LINE_PROLOG_HEADER_SIZE;
469750397Sobrien
469850397Sobrien  /* Count the size of the table giving number of args for each
469950397Sobrien     standard opcode.  */
470050397Sobrien  size += DWARF_LINE_OPCODE_BASE - 1;
470150397Sobrien
470250397Sobrien  /* Include directory table is empty (at present).  Count only the
470350397Sobrien     null byte used to terminate the table.  */
470450397Sobrien  size += 1;
470550397Sobrien
470650397Sobrien  for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
470750397Sobrien    {
470850397Sobrien      /* File name entry.  */
470950397Sobrien      size += size_of_string (file_table[ft_index]);
471050397Sobrien
471150397Sobrien      /* Include directory index.  */
471250397Sobrien      size += size_of_uleb128 (0);
471350397Sobrien
471450397Sobrien      /* Modification time.  */
471550397Sobrien      size += size_of_uleb128 (0);
471650397Sobrien
471750397Sobrien      /* File length in bytes.  */
471850397Sobrien      size += size_of_uleb128 (0);
471950397Sobrien    }
472050397Sobrien
472150397Sobrien  /* Count the file table terminator.  */
472250397Sobrien  size += 1;
472350397Sobrien  return size;
472450397Sobrien}
472550397Sobrien
472650397Sobrien/* Return the size of the line information generated for this
472750397Sobrien   compilation unit.  */
472850397Sobrien
472950397Sobrienstatic unsigned long
473050397Sobriensize_of_line_info ()
473150397Sobrien{
473250397Sobrien  register unsigned long size;
473350397Sobrien  register unsigned long lt_index;
473450397Sobrien  register unsigned long current_line;
473550397Sobrien  register long line_offset;
473650397Sobrien  register long line_delta;
473750397Sobrien  register unsigned long current_file;
473850397Sobrien  register unsigned long function;
473950397Sobrien  unsigned long size_of_set_address;
474050397Sobrien
474150397Sobrien  /* Size of a DW_LNE_set_address instruction.  */
474250397Sobrien  size_of_set_address = 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE;
474350397Sobrien
474450397Sobrien  /* Version number.  */
474550397Sobrien  size = 2;
474650397Sobrien
474750397Sobrien  /* Prolog length specifier.  */
474850397Sobrien  size += DWARF_OFFSET_SIZE;
474950397Sobrien
475050397Sobrien  /* Prolog.  */
475150397Sobrien  size += size_of_line_prolog ();
475250397Sobrien
475350397Sobrien  /* Set address register instruction.  */
475450397Sobrien  size += size_of_set_address;
475550397Sobrien
475650397Sobrien  current_file = 1;
475750397Sobrien  current_line = 1;
475850397Sobrien  for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
475950397Sobrien    {
476050397Sobrien      register dw_line_info_ref line_info;
476150397Sobrien
476250397Sobrien      /* Advance pc instruction.  */
476350397Sobrien      /* ??? See the DW_LNS_advance_pc comment in output_line_info.  */
476450397Sobrien      if (0)
476550397Sobrien	size += 1 + 2;
476650397Sobrien      else
476750397Sobrien	size += size_of_set_address;
476850397Sobrien
476950397Sobrien      line_info = &line_info_table[lt_index];
477050397Sobrien      if (line_info->dw_file_num != current_file)
477150397Sobrien	{
477250397Sobrien	  /* Set file number instruction.  */
477350397Sobrien	  size += 1;
477450397Sobrien	  current_file = line_info->dw_file_num;
477550397Sobrien	  size += size_of_uleb128 (current_file);
477650397Sobrien	}
477750397Sobrien
477850397Sobrien      if (line_info->dw_line_num != current_line)
477950397Sobrien	{
478050397Sobrien	  line_offset = line_info->dw_line_num - current_line;
478150397Sobrien	  line_delta = line_offset - DWARF_LINE_BASE;
478250397Sobrien	  current_line = line_info->dw_line_num;
478350397Sobrien	  if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
478450397Sobrien	    /* 1-byte special line number instruction.  */
478550397Sobrien	    size += 1;
478650397Sobrien	  else
478750397Sobrien	    {
478850397Sobrien	      /* Advance line instruction.  */
478950397Sobrien	      size += 1;
479050397Sobrien	      size += size_of_sleb128 (line_offset);
479150397Sobrien	      /* Generate line entry instruction.  */
479250397Sobrien	      size += 1;
479350397Sobrien	    }
479450397Sobrien	}
479550397Sobrien    }
479650397Sobrien
479750397Sobrien  /* Advance pc instruction.  */
479850397Sobrien  if (0)
479950397Sobrien    size += 1 + 2;
480050397Sobrien  else
480150397Sobrien    size += size_of_set_address;
480250397Sobrien
480350397Sobrien  /* End of line number info. marker.  */
480450397Sobrien  size += 1 + size_of_uleb128 (1) + 1;
480550397Sobrien
480650397Sobrien  function = 0;
480750397Sobrien  current_file = 1;
480850397Sobrien  current_line = 1;
480950397Sobrien  for (lt_index = 0; lt_index < separate_line_info_table_in_use; )
481050397Sobrien    {
481150397Sobrien      register dw_separate_line_info_ref line_info
481250397Sobrien	= &separate_line_info_table[lt_index];
481350397Sobrien      if (function != line_info->function)
481450397Sobrien	{
481550397Sobrien	  function = line_info->function;
481650397Sobrien	  /* Set address register instruction.  */
481750397Sobrien	  size += size_of_set_address;
481850397Sobrien	}
481950397Sobrien      else
482050397Sobrien	{
482150397Sobrien	  /* Advance pc instruction.  */
482250397Sobrien	  if (0)
482350397Sobrien	    size += 1 + 2;
482450397Sobrien	  else
482550397Sobrien	    size += size_of_set_address;
482650397Sobrien	}
482750397Sobrien
482850397Sobrien      if (line_info->dw_file_num != current_file)
482950397Sobrien	{
483050397Sobrien	  /* Set file number instruction.  */
483150397Sobrien	  size += 1;
483250397Sobrien	  current_file = line_info->dw_file_num;
483350397Sobrien	  size += size_of_uleb128 (current_file);
483450397Sobrien	}
483550397Sobrien
483650397Sobrien      if (line_info->dw_line_num != current_line)
483750397Sobrien	{
483850397Sobrien	  line_offset = line_info->dw_line_num - current_line;
483950397Sobrien	  line_delta = line_offset - DWARF_LINE_BASE;
484050397Sobrien	  current_line = line_info->dw_line_num;
484150397Sobrien	  if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
484250397Sobrien	    /* 1-byte special line number instruction.  */
484350397Sobrien	    size += 1;
484450397Sobrien	  else
484550397Sobrien	    {
484650397Sobrien	      /* Advance line instruction.  */
484750397Sobrien	      size += 1;
484850397Sobrien	      size += size_of_sleb128 (line_offset);
484950397Sobrien
485050397Sobrien	      /* Generate line entry instruction.  */
485150397Sobrien	      size += 1;
485250397Sobrien	    }
485350397Sobrien	}
485450397Sobrien
485550397Sobrien      ++lt_index;
485650397Sobrien
485750397Sobrien      /* If we're done with a function, end its sequence.  */
485850397Sobrien      if (lt_index == separate_line_info_table_in_use
485950397Sobrien	  || separate_line_info_table[lt_index].function != function)
486050397Sobrien	{
486150397Sobrien	  current_file = 1;
486250397Sobrien	  current_line = 1;
486350397Sobrien
486450397Sobrien	  /* Advance pc instruction.  */
486550397Sobrien	  if (0)
486650397Sobrien	    size += 1 + 2;
486750397Sobrien	  else
486850397Sobrien	    size += size_of_set_address;
486950397Sobrien
487050397Sobrien	  /* End of line number info. marker.  */
487150397Sobrien	  size += 1 + size_of_uleb128 (1) + 1;
487250397Sobrien	}
487350397Sobrien    }
487450397Sobrien
487550397Sobrien  return size;
487650397Sobrien}
487750397Sobrien
487850397Sobrien/* Return the size of the .debug_pubnames table  generated for the
487950397Sobrien   compilation unit.  */
488050397Sobrien
488150397Sobrienstatic unsigned long
488250397Sobriensize_of_pubnames ()
488350397Sobrien{
488450397Sobrien  register unsigned long size;
488550397Sobrien  register unsigned i;
488650397Sobrien
488750397Sobrien  size = DWARF_PUBNAMES_HEADER_SIZE;
488850397Sobrien  for (i = 0; i < pubname_table_in_use; ++i)
488950397Sobrien    {
489050397Sobrien      register pubname_ref p = &pubname_table[i];
489150397Sobrien      size += DWARF_OFFSET_SIZE + size_of_string (p->name);
489250397Sobrien    }
489350397Sobrien
489450397Sobrien  size += DWARF_OFFSET_SIZE;
489550397Sobrien  return size;
489650397Sobrien}
489750397Sobrien
489850397Sobrien/* Return the size of the information in the .debug_aranges section.  */
489950397Sobrien
490050397Sobrienstatic unsigned long
490150397Sobriensize_of_aranges ()
490250397Sobrien{
490350397Sobrien  register unsigned long size;
490450397Sobrien
490550397Sobrien  size = DWARF_ARANGES_HEADER_SIZE;
490650397Sobrien
490750397Sobrien  /* Count the address/length pair for this compilation unit.  */
490850397Sobrien  size += 2 * PTR_SIZE;
490950397Sobrien  size += 2 * PTR_SIZE * arange_table_in_use;
491050397Sobrien
491150397Sobrien  /* Count the two zero words used to terminated the address range table.  */
491250397Sobrien  size += 2 * PTR_SIZE;
491350397Sobrien  return size;
491450397Sobrien}
491550397Sobrien
491650397Sobrien/* Select the encoding of an attribute value.  */
491750397Sobrien
491850397Sobrienstatic enum dwarf_form
491950397Sobrienvalue_format (v)
492050397Sobrien     dw_val_ref v;
492150397Sobrien{
492250397Sobrien  switch (v->val_class)
492350397Sobrien    {
492450397Sobrien    case dw_val_class_addr:
492550397Sobrien      return DW_FORM_addr;
492650397Sobrien    case dw_val_class_loc:
492750397Sobrien      switch (constant_size (size_of_locs (v->v.val_loc)))
492850397Sobrien	{
492950397Sobrien	case 1:
493050397Sobrien	  return DW_FORM_block1;
493150397Sobrien	case 2:
493250397Sobrien	  return DW_FORM_block2;
493350397Sobrien	default:
493450397Sobrien	  abort ();
493550397Sobrien	}
493650397Sobrien    case dw_val_class_const:
493750397Sobrien      return DW_FORM_data4;
493850397Sobrien    case dw_val_class_unsigned_const:
493950397Sobrien      switch (constant_size (v->v.val_unsigned))
494050397Sobrien	{
494150397Sobrien	case 1:
494250397Sobrien	  return DW_FORM_data1;
494350397Sobrien	case 2:
494450397Sobrien	  return DW_FORM_data2;
494550397Sobrien	case 4:
494650397Sobrien	  return DW_FORM_data4;
494750397Sobrien	case 8:
494850397Sobrien	  return DW_FORM_data8;
494950397Sobrien	default:
495050397Sobrien	  abort ();
495150397Sobrien	}
495250397Sobrien    case dw_val_class_long_long:
495350397Sobrien      return DW_FORM_block1;
495450397Sobrien    case dw_val_class_float:
495550397Sobrien      return DW_FORM_block1;
495650397Sobrien    case dw_val_class_flag:
495750397Sobrien      return DW_FORM_flag;
495850397Sobrien    case dw_val_class_die_ref:
495950397Sobrien      return DW_FORM_ref;
496050397Sobrien    case dw_val_class_fde_ref:
496150397Sobrien      return DW_FORM_data;
496250397Sobrien    case dw_val_class_lbl_id:
496350397Sobrien      return DW_FORM_addr;
496450397Sobrien    case dw_val_class_section_offset:
496550397Sobrien      return DW_FORM_data;
496650397Sobrien    case dw_val_class_str:
496750397Sobrien      return DW_FORM_string;
496850397Sobrien    default:
496950397Sobrien      abort ();
497050397Sobrien    }
497150397Sobrien}
497250397Sobrien
497350397Sobrien/* Output the encoding of an attribute value.  */
497450397Sobrien
497550397Sobrienstatic void
497650397Sobrienoutput_value_format (v)
497750397Sobrien     dw_val_ref v;
497850397Sobrien{
497950397Sobrien  enum dwarf_form form = value_format (v);
498050397Sobrien
498150397Sobrien  output_uleb128 (form);
498250397Sobrien  if (flag_debug_asm)
498350397Sobrien    fprintf (asm_out_file, " (%s)", dwarf_form_name (form));
498450397Sobrien
498550397Sobrien  fputc ('\n', asm_out_file);
498650397Sobrien}
498750397Sobrien
498850397Sobrien/* Output the .debug_abbrev section which defines the DIE abbreviation
498950397Sobrien   table.  */
499050397Sobrien
499150397Sobrienstatic void
499250397Sobrienoutput_abbrev_section ()
499350397Sobrien{
499450397Sobrien  unsigned long abbrev_id;
499550397Sobrien
499650397Sobrien  dw_attr_ref a_attr;
499750397Sobrien  for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
499850397Sobrien    {
499950397Sobrien      register dw_die_ref abbrev = abbrev_die_table[abbrev_id];
500050397Sobrien
500150397Sobrien      output_uleb128 (abbrev_id);
500250397Sobrien      if (flag_debug_asm)
500350397Sobrien	fprintf (asm_out_file, " (abbrev code)");
500450397Sobrien
500550397Sobrien      fputc ('\n', asm_out_file);
500650397Sobrien      output_uleb128 (abbrev->die_tag);
500750397Sobrien      if (flag_debug_asm)
500850397Sobrien	fprintf (asm_out_file, " (TAG: %s)",
500950397Sobrien		 dwarf_tag_name (abbrev->die_tag));
501050397Sobrien
501150397Sobrien      fputc ('\n', asm_out_file);
501250397Sobrien      fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP,
501350397Sobrien	       abbrev->die_child != NULL ? DW_children_yes : DW_children_no);
501450397Sobrien
501550397Sobrien      if (flag_debug_asm)
501650397Sobrien	fprintf (asm_out_file, "\t%s %s",
501750397Sobrien		 ASM_COMMENT_START,
501850397Sobrien		 (abbrev->die_child != NULL
501950397Sobrien		  ? "DW_children_yes" : "DW_children_no"));
502050397Sobrien
502150397Sobrien      fputc ('\n', asm_out_file);
502250397Sobrien
502350397Sobrien      for (a_attr = abbrev->die_attr; a_attr != NULL;
502450397Sobrien	   a_attr = a_attr->dw_attr_next)
502550397Sobrien	{
502650397Sobrien	  output_uleb128 (a_attr->dw_attr);
502750397Sobrien	  if (flag_debug_asm)
502850397Sobrien	    fprintf (asm_out_file, " (%s)",
502950397Sobrien		     dwarf_attr_name (a_attr->dw_attr));
503050397Sobrien
503150397Sobrien	  fputc ('\n', asm_out_file);
503250397Sobrien	  output_value_format (&a_attr->dw_attr_val);
503350397Sobrien	}
503450397Sobrien
503550397Sobrien      fprintf (asm_out_file, "\t%s\t0,0\n", ASM_BYTE_OP);
503650397Sobrien    }
503750397Sobrien}
503850397Sobrien
503950397Sobrien/* Output location description stack opcode's operands (if any).  */
504050397Sobrien
504150397Sobrienstatic void
504250397Sobrienoutput_loc_operands (loc)
504350397Sobrien     register dw_loc_descr_ref loc;
504450397Sobrien{
504550397Sobrien  register dw_val_ref val1 = &loc->dw_loc_oprnd1;
504650397Sobrien  register dw_val_ref val2 = &loc->dw_loc_oprnd2;
504750397Sobrien
504850397Sobrien  switch (loc->dw_loc_opc)
504950397Sobrien    {
505050397Sobrien    case DW_OP_addr:
505150397Sobrien      ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, val1->v.val_addr);
505250397Sobrien      fputc ('\n', asm_out_file);
505350397Sobrien      break;
505450397Sobrien    case DW_OP_const1u:
505550397Sobrien    case DW_OP_const1s:
505650397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
505750397Sobrien      fputc ('\n', asm_out_file);
505850397Sobrien      break;
505950397Sobrien    case DW_OP_const2u:
506050397Sobrien    case DW_OP_const2s:
506150397Sobrien      ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
506250397Sobrien      fputc ('\n', asm_out_file);
506350397Sobrien      break;
506450397Sobrien    case DW_OP_const4u:
506550397Sobrien    case DW_OP_const4s:
506650397Sobrien      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, val1->v.val_int);
506750397Sobrien      fputc ('\n', asm_out_file);
506850397Sobrien      break;
506950397Sobrien    case DW_OP_const8u:
507050397Sobrien    case DW_OP_const8s:
507150397Sobrien      abort ();
507250397Sobrien      fputc ('\n', asm_out_file);
507350397Sobrien      break;
507450397Sobrien    case DW_OP_constu:
507550397Sobrien      output_uleb128 (val1->v.val_unsigned);
507650397Sobrien      fputc ('\n', asm_out_file);
507750397Sobrien      break;
507850397Sobrien    case DW_OP_consts:
507950397Sobrien      output_sleb128 (val1->v.val_int);
508050397Sobrien      fputc ('\n', asm_out_file);
508150397Sobrien      break;
508250397Sobrien    case DW_OP_pick:
508350397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_int);
508450397Sobrien      fputc ('\n', asm_out_file);
508550397Sobrien      break;
508650397Sobrien    case DW_OP_plus_uconst:
508750397Sobrien      output_uleb128 (val1->v.val_unsigned);
508850397Sobrien      fputc ('\n', asm_out_file);
508950397Sobrien      break;
509050397Sobrien    case DW_OP_skip:
509150397Sobrien    case DW_OP_bra:
509250397Sobrien      ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
509350397Sobrien      fputc ('\n', asm_out_file);
509450397Sobrien      break;
509550397Sobrien    case DW_OP_breg0:
509650397Sobrien    case DW_OP_breg1:
509750397Sobrien    case DW_OP_breg2:
509850397Sobrien    case DW_OP_breg3:
509950397Sobrien    case DW_OP_breg4:
510050397Sobrien    case DW_OP_breg5:
510150397Sobrien    case DW_OP_breg6:
510250397Sobrien    case DW_OP_breg7:
510350397Sobrien    case DW_OP_breg8:
510450397Sobrien    case DW_OP_breg9:
510550397Sobrien    case DW_OP_breg10:
510650397Sobrien    case DW_OP_breg11:
510750397Sobrien    case DW_OP_breg12:
510850397Sobrien    case DW_OP_breg13:
510950397Sobrien    case DW_OP_breg14:
511050397Sobrien    case DW_OP_breg15:
511150397Sobrien    case DW_OP_breg16:
511250397Sobrien    case DW_OP_breg17:
511350397Sobrien    case DW_OP_breg18:
511450397Sobrien    case DW_OP_breg19:
511550397Sobrien    case DW_OP_breg20:
511650397Sobrien    case DW_OP_breg21:
511750397Sobrien    case DW_OP_breg22:
511850397Sobrien    case DW_OP_breg23:
511950397Sobrien    case DW_OP_breg24:
512050397Sobrien    case DW_OP_breg25:
512150397Sobrien    case DW_OP_breg26:
512250397Sobrien    case DW_OP_breg27:
512350397Sobrien    case DW_OP_breg28:
512450397Sobrien    case DW_OP_breg29:
512550397Sobrien    case DW_OP_breg30:
512650397Sobrien    case DW_OP_breg31:
512750397Sobrien      output_sleb128 (val1->v.val_int);
512850397Sobrien      fputc ('\n', asm_out_file);
512950397Sobrien      break;
513050397Sobrien    case DW_OP_regx:
513150397Sobrien      output_uleb128 (val1->v.val_unsigned);
513250397Sobrien      fputc ('\n', asm_out_file);
513350397Sobrien      break;
513450397Sobrien    case DW_OP_fbreg:
513550397Sobrien      output_sleb128 (val1->v.val_int);
513650397Sobrien      fputc ('\n', asm_out_file);
513750397Sobrien      break;
513850397Sobrien    case DW_OP_bregx:
513950397Sobrien      output_uleb128 (val1->v.val_unsigned);
514050397Sobrien      fputc ('\n', asm_out_file);
514150397Sobrien      output_sleb128 (val2->v.val_int);
514250397Sobrien      fputc ('\n', asm_out_file);
514350397Sobrien      break;
514450397Sobrien    case DW_OP_piece:
514550397Sobrien      output_uleb128 (val1->v.val_unsigned);
514650397Sobrien      fputc ('\n', asm_out_file);
514750397Sobrien      break;
514850397Sobrien    case DW_OP_deref_size:
514950397Sobrien    case DW_OP_xderef_size:
515050397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
515150397Sobrien      fputc ('\n', asm_out_file);
515250397Sobrien      break;
515350397Sobrien    default:
515450397Sobrien      break;
515550397Sobrien    }
515650397Sobrien}
515750397Sobrien
515850397Sobrien/* Compute the offset of a sibling.  */
515950397Sobrien
516050397Sobrienstatic unsigned long
516150397Sobriensibling_offset (die)
516250397Sobrien     dw_die_ref die;
516350397Sobrien{
516450397Sobrien  unsigned long offset;
516550397Sobrien
516650397Sobrien  if (die->die_child_last == NULL)
516750397Sobrien    offset = die->die_offset + size_of_die (die);
516850397Sobrien  else
516950397Sobrien    offset = sibling_offset (die->die_child_last) + 1;
517050397Sobrien
517150397Sobrien  return offset;
517250397Sobrien}
517350397Sobrien
517450397Sobrien/* Output the DIE and its attributes.  Called recursively to generate
517550397Sobrien   the definitions of each child DIE.  */
517650397Sobrien
517750397Sobrienstatic void
517850397Sobrienoutput_die (die)
517950397Sobrien     register dw_die_ref die;
518050397Sobrien{
518150397Sobrien  register dw_attr_ref a;
518250397Sobrien  register dw_die_ref c;
518350397Sobrien  register unsigned long ref_offset;
518450397Sobrien  register unsigned long size;
518550397Sobrien  register dw_loc_descr_ref loc;
518650397Sobrien  register int i;
518750397Sobrien
518850397Sobrien  output_uleb128 (die->die_abbrev);
518950397Sobrien  if (flag_debug_asm)
519050397Sobrien    fprintf (asm_out_file, " (DIE (0x%lx) %s)",
519150397Sobrien	     die->die_offset, dwarf_tag_name (die->die_tag));
519250397Sobrien
519350397Sobrien  fputc ('\n', asm_out_file);
519450397Sobrien
519550397Sobrien  for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
519650397Sobrien    {
519750397Sobrien      switch (a->dw_attr_val.val_class)
519850397Sobrien	{
519950397Sobrien	case dw_val_class_addr:
520050397Sobrien	  ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file,
520150397Sobrien				       a->dw_attr_val.v.val_addr);
520250397Sobrien	  break;
520350397Sobrien
520450397Sobrien	case dw_val_class_loc:
520550397Sobrien	  size = size_of_locs (a->dw_attr_val.v.val_loc);
520650397Sobrien
520750397Sobrien	  /* Output the block length for this list of location operations.  */
520850397Sobrien	  switch (constant_size (size))
520950397Sobrien	    {
521050397Sobrien	    case 1:
521150397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, size);
521250397Sobrien	      break;
521350397Sobrien	    case 2:
521450397Sobrien	      ASM_OUTPUT_DWARF_DATA2 (asm_out_file, size);
521550397Sobrien	      break;
521650397Sobrien	    default:
521750397Sobrien	      abort ();
521850397Sobrien	    }
521950397Sobrien
522050397Sobrien	  if (flag_debug_asm)
522150397Sobrien	    fprintf (asm_out_file, "\t%s %s",
522250397Sobrien		     ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
522350397Sobrien
522450397Sobrien	  fputc ('\n', asm_out_file);
522550397Sobrien	  for (loc = a->dw_attr_val.v.val_loc; loc != NULL;
522650397Sobrien	       loc = loc->dw_loc_next)
522750397Sobrien	    {
522850397Sobrien	      /* Output the opcode.  */
522950397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, loc->dw_loc_opc);
523050397Sobrien	      if (flag_debug_asm)
523150397Sobrien		fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START,
523250397Sobrien			 dwarf_stack_op_name (loc->dw_loc_opc));
523350397Sobrien
523450397Sobrien	      fputc ('\n', asm_out_file);
523550397Sobrien
523650397Sobrien	      /* Output the operand(s) (if any).  */
523750397Sobrien	      output_loc_operands (loc);
523850397Sobrien	    }
523950397Sobrien	  break;
524050397Sobrien
524150397Sobrien	case dw_val_class_const:
524250397Sobrien	  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, a->dw_attr_val.v.val_int);
524350397Sobrien	  break;
524450397Sobrien
524550397Sobrien	case dw_val_class_unsigned_const:
524650397Sobrien	  switch (constant_size (a->dw_attr_val.v.val_unsigned))
524750397Sobrien	    {
524850397Sobrien	    case 1:
524950397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
525050397Sobrien				      a->dw_attr_val.v.val_unsigned);
525150397Sobrien	      break;
525250397Sobrien	    case 2:
525350397Sobrien	      ASM_OUTPUT_DWARF_DATA2 (asm_out_file,
525450397Sobrien				      a->dw_attr_val.v.val_unsigned);
525550397Sobrien	      break;
525650397Sobrien	    case 4:
525750397Sobrien	      ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
525850397Sobrien				      a->dw_attr_val.v.val_unsigned);
525950397Sobrien	      break;
526050397Sobrien	    case 8:
526150397Sobrien	      ASM_OUTPUT_DWARF_DATA8 (asm_out_file,
526250397Sobrien				      a->dw_attr_val.v.val_long_long.hi,
526350397Sobrien				      a->dw_attr_val.v.val_long_long.low);
526450397Sobrien	      break;
526550397Sobrien	    default:
526650397Sobrien	      abort ();
526750397Sobrien	    }
526850397Sobrien	  break;
526950397Sobrien
527050397Sobrien	case dw_val_class_long_long:
527150397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 8);
527250397Sobrien	  if (flag_debug_asm)
527350397Sobrien	    fprintf (asm_out_file, "\t%s %s",
527450397Sobrien		   ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
527550397Sobrien
527650397Sobrien	  fputc ('\n', asm_out_file);
527750397Sobrien	  ASM_OUTPUT_DWARF_DATA8 (asm_out_file,
527850397Sobrien				  a->dw_attr_val.v.val_long_long.hi,
527950397Sobrien				  a->dw_attr_val.v.val_long_long.low);
528050397Sobrien
528150397Sobrien	  if (flag_debug_asm)
528250397Sobrien	    fprintf (asm_out_file,
528350397Sobrien		     "\t%s long long constant", ASM_COMMENT_START);
528450397Sobrien
528550397Sobrien	  fputc ('\n', asm_out_file);
528650397Sobrien	  break;
528750397Sobrien
528850397Sobrien	case dw_val_class_float:
528950397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
529050397Sobrien				  a->dw_attr_val.v.val_float.length * 4);
529150397Sobrien	  if (flag_debug_asm)
529250397Sobrien	    fprintf (asm_out_file, "\t%s %s",
529350397Sobrien		     ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
529450397Sobrien
529550397Sobrien	  fputc ('\n', asm_out_file);
529650397Sobrien	  for (i = 0; i < a->dw_attr_val.v.val_float.length; ++i)
529750397Sobrien	    {
529850397Sobrien	      ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
529950397Sobrien				      a->dw_attr_val.v.val_float.array[i]);
530050397Sobrien	      if (flag_debug_asm)
530150397Sobrien		fprintf (asm_out_file, "\t%s fp constant word %d",
530250397Sobrien			 ASM_COMMENT_START, i);
530350397Sobrien
530450397Sobrien	      fputc ('\n', asm_out_file);
530550397Sobrien	    }
530650397Sobrien	  break;
530750397Sobrien
530850397Sobrien	case dw_val_class_flag:
530950397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, a->dw_attr_val.v.val_flag);
531050397Sobrien	  break;
531150397Sobrien
531250397Sobrien	case dw_val_class_die_ref:
531350397Sobrien	  if (a->dw_attr_val.v.val_die_ref != NULL)
531450397Sobrien	    ref_offset = a->dw_attr_val.v.val_die_ref->die_offset;
531550397Sobrien	  else if (a->dw_attr == DW_AT_sibling)
531650397Sobrien	    ref_offset = sibling_offset(die);
531750397Sobrien	  else
531850397Sobrien	    abort ();
531950397Sobrien
532050397Sobrien	  ASM_OUTPUT_DWARF_DATA (asm_out_file, ref_offset);
532150397Sobrien	  break;
532250397Sobrien
532350397Sobrien	case dw_val_class_fde_ref:
532450397Sobrien	  {
532550397Sobrien	    char l1[20];
532650397Sobrien	    ASM_GENERATE_INTERNAL_LABEL
532750397Sobrien	      (l1, FDE_AFTER_SIZE_LABEL, a->dw_attr_val.v.val_fde_index * 2);
532850397Sobrien	    ASM_OUTPUT_DWARF_OFFSET (asm_out_file, l1);
532950397Sobrien	    fprintf (asm_out_file, " - %d", DWARF_OFFSET_SIZE);
533050397Sobrien	  }
533150397Sobrien	  break;
533250397Sobrien
533350397Sobrien	case dw_val_class_lbl_id:
533450397Sobrien	  ASM_OUTPUT_DWARF_ADDR (asm_out_file, a->dw_attr_val.v.val_lbl_id);
533550397Sobrien	  break;
533650397Sobrien
533750397Sobrien	case dw_val_class_section_offset:
533850397Sobrien	  ASM_OUTPUT_DWARF_OFFSET (asm_out_file,
533950397Sobrien				   stripattributes
534050397Sobrien				   (a->dw_attr_val.v.val_section));
534150397Sobrien	  break;
534250397Sobrien
534350397Sobrien	case dw_val_class_str:
534450397Sobrien	  if (flag_debug_asm)
534550397Sobrien	    ASM_OUTPUT_DWARF_STRING (asm_out_file, a->dw_attr_val.v.val_str);
534650397Sobrien	  else
534750397Sobrien	    ASM_OUTPUT_ASCII (asm_out_file,
534850397Sobrien			      a->dw_attr_val.v.val_str,
534950397Sobrien			      strlen (a->dw_attr_val.v.val_str) + 1);
535050397Sobrien	  break;
535150397Sobrien
535250397Sobrien	default:
535350397Sobrien	  abort ();
535450397Sobrien	}
535550397Sobrien
535650397Sobrien      if (a->dw_attr_val.val_class != dw_val_class_loc
535750397Sobrien	  && a->dw_attr_val.val_class != dw_val_class_long_long
535850397Sobrien	  && a->dw_attr_val.val_class != dw_val_class_float)
535950397Sobrien	{
536050397Sobrien	  if (flag_debug_asm)
536150397Sobrien	    fprintf (asm_out_file, "\t%s %s",
536250397Sobrien		     ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
536350397Sobrien
536450397Sobrien	  fputc ('\n', asm_out_file);
536550397Sobrien	}
536650397Sobrien    }
536750397Sobrien
536850397Sobrien  for (c = die->die_child; c != NULL; c = c->die_sib)
536950397Sobrien    output_die (c);
537050397Sobrien
537150397Sobrien  if (die->die_child != NULL)
537250397Sobrien    {
537350397Sobrien      /* Add null byte to terminate sibling list. */
537450397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
537550397Sobrien      if (flag_debug_asm)
537650397Sobrien	fprintf (asm_out_file, "\t%s end of children of DIE 0x%lx",
537750397Sobrien		 ASM_COMMENT_START, die->die_offset);
537850397Sobrien
537950397Sobrien      fputc ('\n', asm_out_file);
538050397Sobrien    }
538150397Sobrien}
538250397Sobrien
538350397Sobrien/* Output the compilation unit that appears at the beginning of the
538450397Sobrien   .debug_info section, and precedes the DIE descriptions.  */
538550397Sobrien
538650397Sobrienstatic void
538750397Sobrienoutput_compilation_unit_header ()
538850397Sobrien{
538950397Sobrien  ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset - DWARF_OFFSET_SIZE);
539050397Sobrien  if (flag_debug_asm)
539150397Sobrien    fprintf (asm_out_file, "\t%s Length of Compilation Unit Info.",
539250397Sobrien	     ASM_COMMENT_START);
539350397Sobrien
539450397Sobrien  fputc ('\n', asm_out_file);
539550397Sobrien  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
539650397Sobrien  if (flag_debug_asm)
539750397Sobrien    fprintf (asm_out_file, "\t%s DWARF version number", ASM_COMMENT_START);
539850397Sobrien
539950397Sobrien  fputc ('\n', asm_out_file);
540050397Sobrien  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (ABBREV_SECTION));
540150397Sobrien  if (flag_debug_asm)
540250397Sobrien    fprintf (asm_out_file, "\t%s Offset Into Abbrev. Section",
540350397Sobrien	     ASM_COMMENT_START);
540450397Sobrien
540550397Sobrien  fputc ('\n', asm_out_file);
540650397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE);
540750397Sobrien  if (flag_debug_asm)
540850397Sobrien    fprintf (asm_out_file, "\t%s Pointer Size (in bytes)", ASM_COMMENT_START);
540950397Sobrien
541050397Sobrien  fputc ('\n', asm_out_file);
541150397Sobrien}
541250397Sobrien
541350397Sobrien/* The DWARF2 pubname for a nested thingy looks like "A::f".  The output
541450397Sobrien   of decl_printable_name for C++ looks like "A::f(int)".  Let's drop the
541550397Sobrien   argument list, and maybe the scope.  */
541650397Sobrien
541750397Sobrienstatic char *
541850397Sobriendwarf2_name (decl, scope)
541950397Sobrien     tree decl;
542050397Sobrien     int scope;
542150397Sobrien{
542250397Sobrien  return (*decl_printable_name) (decl, scope ? 1 : 0);
542350397Sobrien}
542450397Sobrien
542550397Sobrien/* Add a new entry to .debug_pubnames if appropriate.  */
542650397Sobrien
542750397Sobrienstatic void
542850397Sobrienadd_pubname (decl, die)
542950397Sobrien     tree decl;
543050397Sobrien     dw_die_ref die;
543150397Sobrien{
543250397Sobrien  pubname_ref p;
543350397Sobrien
543450397Sobrien  if (! TREE_PUBLIC (decl))
543550397Sobrien    return;
543650397Sobrien
543750397Sobrien  if (pubname_table_in_use == pubname_table_allocated)
543850397Sobrien    {
543950397Sobrien      pubname_table_allocated += PUBNAME_TABLE_INCREMENT;
544050397Sobrien      pubname_table = (pubname_ref) xrealloc
544150397Sobrien	(pubname_table, pubname_table_allocated * sizeof (pubname_entry));
544250397Sobrien    }
544350397Sobrien
544450397Sobrien  p = &pubname_table[pubname_table_in_use++];
544550397Sobrien  p->die = die;
544650397Sobrien
544750397Sobrien  p->name = xstrdup (dwarf2_name (decl, 1));
544850397Sobrien}
544950397Sobrien
545050397Sobrien/* Output the public names table used to speed up access to externally
545150397Sobrien   visible names.  For now, only generate entries for externally
545250397Sobrien   visible procedures.  */
545350397Sobrien
545450397Sobrienstatic void
545550397Sobrienoutput_pubnames ()
545650397Sobrien{
545750397Sobrien  register unsigned i;
545850397Sobrien  register unsigned long pubnames_length = size_of_pubnames ();
545950397Sobrien
546050397Sobrien  ASM_OUTPUT_DWARF_DATA (asm_out_file, pubnames_length);
546150397Sobrien
546250397Sobrien  if (flag_debug_asm)
546350397Sobrien    fprintf (asm_out_file, "\t%s Length of Public Names Info.",
546450397Sobrien	     ASM_COMMENT_START);
546550397Sobrien
546650397Sobrien  fputc ('\n', asm_out_file);
546750397Sobrien  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
546850397Sobrien
546950397Sobrien  if (flag_debug_asm)
547050397Sobrien    fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
547150397Sobrien
547250397Sobrien  fputc ('\n', asm_out_file);
547350397Sobrien  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_INFO_SECTION));
547450397Sobrien  if (flag_debug_asm)
547550397Sobrien    fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
547650397Sobrien	     ASM_COMMENT_START);
547750397Sobrien
547850397Sobrien  fputc ('\n', asm_out_file);
547950397Sobrien  ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset);
548050397Sobrien  if (flag_debug_asm)
548150397Sobrien    fprintf (asm_out_file, "\t%s Compilation Unit Length", ASM_COMMENT_START);
548250397Sobrien
548350397Sobrien  fputc ('\n', asm_out_file);
548450397Sobrien  for (i = 0; i < pubname_table_in_use; ++i)
548550397Sobrien    {
548650397Sobrien      register pubname_ref pub = &pubname_table[i];
548750397Sobrien
548850397Sobrien      ASM_OUTPUT_DWARF_DATA (asm_out_file, pub->die->die_offset);
548950397Sobrien      if (flag_debug_asm)
549050397Sobrien	fprintf (asm_out_file, "\t%s DIE offset", ASM_COMMENT_START);
549150397Sobrien
549250397Sobrien      fputc ('\n', asm_out_file);
549350397Sobrien
549450397Sobrien      if (flag_debug_asm)
549550397Sobrien	{
549650397Sobrien	  ASM_OUTPUT_DWARF_STRING (asm_out_file, pub->name);
549750397Sobrien	  fprintf (asm_out_file, "%s external name", ASM_COMMENT_START);
549850397Sobrien	}
549950397Sobrien      else
550050397Sobrien	{
550150397Sobrien	  ASM_OUTPUT_ASCII (asm_out_file, pub->name, strlen (pub->name) + 1);
550250397Sobrien	}
550350397Sobrien
550450397Sobrien      fputc ('\n', asm_out_file);
550550397Sobrien    }
550650397Sobrien
550750397Sobrien  ASM_OUTPUT_DWARF_DATA (asm_out_file, 0);
550850397Sobrien  fputc ('\n', asm_out_file);
550950397Sobrien}
551050397Sobrien
551150397Sobrien/* Add a new entry to .debug_aranges if appropriate.  */
551250397Sobrien
551350397Sobrienstatic void
551450397Sobrienadd_arange (decl, die)
551550397Sobrien     tree decl;
551650397Sobrien     dw_die_ref die;
551750397Sobrien{
551850397Sobrien  if (! DECL_SECTION_NAME (decl))
551950397Sobrien    return;
552050397Sobrien
552150397Sobrien  if (arange_table_in_use == arange_table_allocated)
552250397Sobrien    {
552350397Sobrien      arange_table_allocated += ARANGE_TABLE_INCREMENT;
552450397Sobrien      arange_table
552550397Sobrien	= (arange_ref) xrealloc (arange_table,
552650397Sobrien				 arange_table_allocated * sizeof (dw_die_ref));
552750397Sobrien    }
552850397Sobrien
552950397Sobrien  arange_table[arange_table_in_use++] = die;
553050397Sobrien}
553150397Sobrien
553250397Sobrien/* Output the information that goes into the .debug_aranges table.
553350397Sobrien   Namely, define the beginning and ending address range of the
553450397Sobrien   text section generated for this compilation unit.  */
553550397Sobrien
553650397Sobrienstatic void
553750397Sobrienoutput_aranges ()
553850397Sobrien{
553950397Sobrien  register unsigned i;
554050397Sobrien  register unsigned long aranges_length = size_of_aranges ();
554150397Sobrien
554250397Sobrien  ASM_OUTPUT_DWARF_DATA (asm_out_file, aranges_length);
554350397Sobrien  if (flag_debug_asm)
554450397Sobrien    fprintf (asm_out_file, "\t%s Length of Address Ranges Info.",
554550397Sobrien	     ASM_COMMENT_START);
554650397Sobrien
554750397Sobrien  fputc ('\n', asm_out_file);
554850397Sobrien  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
554950397Sobrien  if (flag_debug_asm)
555050397Sobrien    fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
555150397Sobrien
555250397Sobrien  fputc ('\n', asm_out_file);
555350397Sobrien  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_INFO_SECTION));
555450397Sobrien  if (flag_debug_asm)
555550397Sobrien    fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
555650397Sobrien	     ASM_COMMENT_START);
555750397Sobrien
555850397Sobrien  fputc ('\n', asm_out_file);
555950397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE);
556050397Sobrien  if (flag_debug_asm)
556150397Sobrien    fprintf (asm_out_file, "\t%s Size of Address", ASM_COMMENT_START);
556250397Sobrien
556350397Sobrien  fputc ('\n', asm_out_file);
556450397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
556550397Sobrien  if (flag_debug_asm)
556650397Sobrien    fprintf (asm_out_file, "\t%s Size of Segment Descriptor",
556750397Sobrien	     ASM_COMMENT_START);
556850397Sobrien
556950397Sobrien  fputc ('\n', asm_out_file);
557050397Sobrien  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 4);
557150397Sobrien  if (PTR_SIZE == 8)
557250397Sobrien    fprintf (asm_out_file, ",0,0");
557350397Sobrien
557450397Sobrien  if (flag_debug_asm)
557550397Sobrien    fprintf (asm_out_file, "\t%s Pad to %d byte boundary",
557650397Sobrien	     ASM_COMMENT_START, 2 * PTR_SIZE);
557750397Sobrien
557850397Sobrien  fputc ('\n', asm_out_file);
557950397Sobrien  ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_SECTION);
558050397Sobrien  if (flag_debug_asm)
558150397Sobrien    fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START);
558250397Sobrien
558350397Sobrien  fputc ('\n', asm_out_file);
558450397Sobrien  ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, text_end_label, TEXT_SECTION);
558550397Sobrien  if (flag_debug_asm)
558650397Sobrien    fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
558750397Sobrien
558850397Sobrien  fputc ('\n', asm_out_file);
558950397Sobrien  for (i = 0; i < arange_table_in_use; ++i)
559050397Sobrien    {
559150397Sobrien      dw_die_ref a = arange_table[i];
559250397Sobrien
559350397Sobrien      if (a->die_tag == DW_TAG_subprogram)
559450397Sobrien	ASM_OUTPUT_DWARF_ADDR (asm_out_file, get_AT_low_pc (a));
559550397Sobrien      else
559650397Sobrien	{
559750397Sobrien	  char *name = get_AT_string (a, DW_AT_MIPS_linkage_name);
559850397Sobrien	  if (! name)
559950397Sobrien	    name = get_AT_string (a, DW_AT_name);
560050397Sobrien
560150397Sobrien	  ASM_OUTPUT_DWARF_ADDR (asm_out_file, name);
560250397Sobrien	}
560350397Sobrien
560450397Sobrien      if (flag_debug_asm)
560550397Sobrien	fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START);
560650397Sobrien
560750397Sobrien      fputc ('\n', asm_out_file);
560850397Sobrien      if (a->die_tag == DW_TAG_subprogram)
560950397Sobrien	ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, get_AT_hi_pc (a),
561050397Sobrien				     get_AT_low_pc (a));
561150397Sobrien      else
561250397Sobrien	ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file,
561350397Sobrien				    get_AT_unsigned (a, DW_AT_byte_size));
561450397Sobrien
561550397Sobrien      if (flag_debug_asm)
561650397Sobrien	fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
561750397Sobrien
561850397Sobrien      fputc ('\n', asm_out_file);
561950397Sobrien    }
562050397Sobrien
562150397Sobrien  /* Output the terminator words.  */
562250397Sobrien  ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
562350397Sobrien  fputc ('\n', asm_out_file);
562450397Sobrien  ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
562550397Sobrien  fputc ('\n', asm_out_file);
562650397Sobrien}
562750397Sobrien
562850397Sobrien/* Output the source line number correspondence information.  This
562950397Sobrien   information goes into the .debug_line section.
563050397Sobrien
563150397Sobrien   If the format of this data changes, then the function size_of_line_info
563250397Sobrien   must also be adjusted the same way.  */
563350397Sobrien
563450397Sobrienstatic void
563550397Sobrienoutput_line_info ()
563650397Sobrien{
563750397Sobrien  char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
563850397Sobrien  char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
563950397Sobrien  register unsigned opc;
564050397Sobrien  register unsigned n_op_args;
564150397Sobrien  register unsigned long ft_index;
564250397Sobrien  register unsigned long lt_index;
564350397Sobrien  register unsigned long current_line;
564450397Sobrien  register long line_offset;
564550397Sobrien  register long line_delta;
564650397Sobrien  register unsigned long current_file;
564750397Sobrien  register unsigned long function;
564850397Sobrien
564950397Sobrien  ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_info ());
565050397Sobrien  if (flag_debug_asm)
565150397Sobrien    fprintf (asm_out_file, "\t%s Length of Source Line Info.",
565250397Sobrien	     ASM_COMMENT_START);
565350397Sobrien
565450397Sobrien  fputc ('\n', asm_out_file);
565550397Sobrien  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
565650397Sobrien  if (flag_debug_asm)
565750397Sobrien    fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
565850397Sobrien
565950397Sobrien  fputc ('\n', asm_out_file);
566050397Sobrien  ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_prolog ());
566150397Sobrien  if (flag_debug_asm)
566250397Sobrien    fprintf (asm_out_file, "\t%s Prolog Length", ASM_COMMENT_START);
566350397Sobrien
566450397Sobrien  fputc ('\n', asm_out_file);
566550397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_MIN_INSTR_LENGTH);
566650397Sobrien  if (flag_debug_asm)
566750397Sobrien    fprintf (asm_out_file, "\t%s Minimum Instruction Length",
566850397Sobrien	     ASM_COMMENT_START);
566950397Sobrien
567050397Sobrien  fputc ('\n', asm_out_file);
567150397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_DEFAULT_IS_STMT_START);
567250397Sobrien  if (flag_debug_asm)
567350397Sobrien    fprintf (asm_out_file, "\t%s Default is_stmt_start flag",
567450397Sobrien	     ASM_COMMENT_START);
567550397Sobrien
567650397Sobrien  fputc ('\n', asm_out_file);
567750397Sobrien  fprintf (asm_out_file, "\t%s\t%d", ASM_BYTE_OP, DWARF_LINE_BASE);
567850397Sobrien  if (flag_debug_asm)
567950397Sobrien    fprintf (asm_out_file, "\t%s Line Base Value (Special Opcodes)",
568050397Sobrien	     ASM_COMMENT_START);
568150397Sobrien
568250397Sobrien  fputc ('\n', asm_out_file);
568350397Sobrien  fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_RANGE);
568450397Sobrien  if (flag_debug_asm)
568550397Sobrien    fprintf (asm_out_file, "\t%s Line Range Value (Special Opcodes)",
568650397Sobrien	     ASM_COMMENT_START);
568750397Sobrien
568850397Sobrien  fputc ('\n', asm_out_file);
568950397Sobrien  fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_OPCODE_BASE);
569050397Sobrien  if (flag_debug_asm)
569150397Sobrien    fprintf (asm_out_file, "\t%s Special Opcode Base", ASM_COMMENT_START);
569250397Sobrien
569350397Sobrien  fputc ('\n', asm_out_file);
569450397Sobrien  for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; ++opc)
569550397Sobrien    {
569650397Sobrien      switch (opc)
569750397Sobrien	{
569850397Sobrien	case DW_LNS_advance_pc:
569950397Sobrien	case DW_LNS_advance_line:
570050397Sobrien	case DW_LNS_set_file:
570150397Sobrien	case DW_LNS_set_column:
570250397Sobrien	case DW_LNS_fixed_advance_pc:
570350397Sobrien	  n_op_args = 1;
570450397Sobrien	  break;
570550397Sobrien	default:
570650397Sobrien	  n_op_args = 0;
570750397Sobrien	  break;
570850397Sobrien	}
570950397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, n_op_args);
571050397Sobrien      if (flag_debug_asm)
571150397Sobrien	fprintf (asm_out_file, "\t%s opcode: 0x%x has %d args",
571250397Sobrien		 ASM_COMMENT_START, opc, n_op_args);
571350397Sobrien      fputc ('\n', asm_out_file);
571450397Sobrien    }
571550397Sobrien
571650397Sobrien  if (flag_debug_asm)
571750397Sobrien    fprintf (asm_out_file, "%s Include Directory Table\n", ASM_COMMENT_START);
571850397Sobrien
571950397Sobrien  /* Include directory table is empty, at present */
572050397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
572150397Sobrien  fputc ('\n', asm_out_file);
572250397Sobrien  if (flag_debug_asm)
572350397Sobrien    fprintf (asm_out_file, "%s File Name Table\n", ASM_COMMENT_START);
572450397Sobrien
572550397Sobrien  for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
572650397Sobrien    {
572750397Sobrien      if (flag_debug_asm)
572850397Sobrien	{
572950397Sobrien	  ASM_OUTPUT_DWARF_STRING (asm_out_file, file_table[ft_index]);
573050397Sobrien	  fprintf (asm_out_file, "%s File Entry: 0x%lx",
573150397Sobrien		   ASM_COMMENT_START, ft_index);
573250397Sobrien	}
573350397Sobrien      else
573450397Sobrien	{
573550397Sobrien	  ASM_OUTPUT_ASCII (asm_out_file,
573650397Sobrien			    file_table[ft_index],
573750397Sobrien			    strlen (file_table[ft_index]) + 1);
573850397Sobrien	}
573950397Sobrien
574050397Sobrien      fputc ('\n', asm_out_file);
574150397Sobrien
574250397Sobrien      /* Include directory index */
574350397Sobrien      output_uleb128 (0);
574450397Sobrien      fputc ('\n', asm_out_file);
574550397Sobrien
574650397Sobrien      /* Modification time */
574750397Sobrien      output_uleb128 (0);
574850397Sobrien      fputc ('\n', asm_out_file);
574950397Sobrien
575050397Sobrien      /* File length in bytes */
575150397Sobrien      output_uleb128 (0);
575250397Sobrien      fputc ('\n', asm_out_file);
575350397Sobrien    }
575450397Sobrien
575550397Sobrien  /* Terminate the file name table */
575650397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
575750397Sobrien  fputc ('\n', asm_out_file);
575850397Sobrien
575950397Sobrien  /* Set the address register to the first location in the text section */
576050397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
576150397Sobrien  if (flag_debug_asm)
576250397Sobrien    fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START);
576350397Sobrien
576450397Sobrien  fputc ('\n', asm_out_file);
576550397Sobrien  output_uleb128 (1 + PTR_SIZE);
576650397Sobrien  fputc ('\n', asm_out_file);
576750397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
576850397Sobrien  fputc ('\n', asm_out_file);
576950397Sobrien  ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_SECTION);
577050397Sobrien  fputc ('\n', asm_out_file);
577150397Sobrien
577250397Sobrien  /* Generate the line number to PC correspondence table, encoded as
577350397Sobrien     a series of state machine operations.  */
577450397Sobrien  current_file = 1;
577550397Sobrien  current_line = 1;
577650397Sobrien  strcpy (prev_line_label, TEXT_SECTION);
577750397Sobrien  for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
577850397Sobrien    {
577950397Sobrien      register dw_line_info_ref line_info;
578050397Sobrien
578150397Sobrien      /* Emit debug info for the address of the current line, choosing
578250397Sobrien	 the encoding that uses the least amount of space.  */
578350397Sobrien      /* ??? Unfortunately, we have little choice here currently, and must
578450397Sobrien	 always use the most general form.  Gcc does not know the address
578550397Sobrien	 delta itself, so we can't use DW_LNS_advance_pc.  There are no known
578650397Sobrien	 dwarf2 aware assemblers at this time, so we can't use any special
578750397Sobrien	 pseudo ops that would allow the assembler to optimally encode this for
578850397Sobrien	 us.  Many ports do have length attributes which will give an upper
578950397Sobrien	 bound on the address range.  We could perhaps use length attributes
579050397Sobrien	 to determine when it is safe to use DW_LNS_fixed_advance_pc.  */
579150397Sobrien      ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index);
579250397Sobrien      if (0)
579350397Sobrien	{
579450397Sobrien	  /* This can handle deltas up to 0xffff.  This takes 3 bytes.  */
579550397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
579650397Sobrien	  if (flag_debug_asm)
579750397Sobrien	    fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
579850397Sobrien		     ASM_COMMENT_START);
579950397Sobrien
580050397Sobrien	  fputc ('\n', asm_out_file);
580150397Sobrien	  ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, prev_line_label);
580250397Sobrien	  fputc ('\n', asm_out_file);
580350397Sobrien	}
580450397Sobrien      else
580550397Sobrien	{
580650397Sobrien	  /* This can handle any delta.  This takes 4+PTR_SIZE bytes.  */
580750397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
580850397Sobrien	  if (flag_debug_asm)
580950397Sobrien	    fprintf (asm_out_file, "\t%s DW_LNE_set_address",
581050397Sobrien		     ASM_COMMENT_START);
581150397Sobrien	  fputc ('\n', asm_out_file);
581250397Sobrien	  output_uleb128 (1 + PTR_SIZE);
581350397Sobrien	  fputc ('\n', asm_out_file);
581450397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
581550397Sobrien	  fputc ('\n', asm_out_file);
581650397Sobrien	  ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
581750397Sobrien	  fputc ('\n', asm_out_file);
581850397Sobrien	}
581950397Sobrien      strcpy (prev_line_label, line_label);
582050397Sobrien
582150397Sobrien      /* Emit debug info for the source file of the current line, if
582250397Sobrien	 different from the previous line.  */
582350397Sobrien      line_info = &line_info_table[lt_index];
582450397Sobrien      if (line_info->dw_file_num != current_file)
582550397Sobrien	{
582650397Sobrien	  current_file = line_info->dw_file_num;
582750397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file);
582850397Sobrien	  if (flag_debug_asm)
582950397Sobrien	    fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START);
583050397Sobrien
583150397Sobrien	  fputc ('\n', asm_out_file);
583250397Sobrien	  output_uleb128 (current_file);
583350397Sobrien	  if (flag_debug_asm)
583450397Sobrien	    fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
583550397Sobrien
583650397Sobrien	  fputc ('\n', asm_out_file);
583750397Sobrien	}
583850397Sobrien
583950397Sobrien      /* Emit debug info for the current line number, choosing the encoding
584050397Sobrien	 that uses the least amount of space.  */
584150397Sobrien      line_offset = line_info->dw_line_num - current_line;
584250397Sobrien      line_delta = line_offset - DWARF_LINE_BASE;
584350397Sobrien      current_line = line_info->dw_line_num;
584450397Sobrien      if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
584550397Sobrien	{
584650397Sobrien	  /* This can handle deltas from -10 to 234, using the current
584750397Sobrien	     definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE.  This
584850397Sobrien	     takes 1 byte.  */
584950397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
585050397Sobrien				  DWARF_LINE_OPCODE_BASE + line_delta);
585150397Sobrien	  if (flag_debug_asm)
585250397Sobrien	      fprintf (asm_out_file,
585350397Sobrien		       "\t%s line %ld", ASM_COMMENT_START, current_line);
585450397Sobrien
585550397Sobrien	  fputc ('\n', asm_out_file);
585650397Sobrien	}
585750397Sobrien      else
585850397Sobrien	{
585950397Sobrien	  /* This can handle any delta.  This takes at least 4 bytes, depending
586050397Sobrien	     on the value being encoded.  */
586150397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line);
586250397Sobrien	  if (flag_debug_asm)
586350397Sobrien	    fprintf (asm_out_file, "\t%s advance to line %ld",
586450397Sobrien		     ASM_COMMENT_START, current_line);
586550397Sobrien
586650397Sobrien	  fputc ('\n', asm_out_file);
586750397Sobrien	  output_sleb128 (line_offset);
586850397Sobrien	  fputc ('\n', asm_out_file);
586950397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
587050397Sobrien	  fputc ('\n', asm_out_file);
587150397Sobrien	}
587250397Sobrien    }
587350397Sobrien
587450397Sobrien  /* Emit debug info for the address of the end of the function.  */
587550397Sobrien  if (0)
587650397Sobrien    {
587750397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
587850397Sobrien      if (flag_debug_asm)
587950397Sobrien	fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
588050397Sobrien		 ASM_COMMENT_START);
588150397Sobrien
588250397Sobrien      fputc ('\n', asm_out_file);
588350397Sobrien      ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, text_end_label, prev_line_label);
588450397Sobrien      fputc ('\n', asm_out_file);
588550397Sobrien    }
588650397Sobrien  else
588750397Sobrien    {
588850397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
588950397Sobrien      if (flag_debug_asm)
589050397Sobrien	fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START);
589150397Sobrien      fputc ('\n', asm_out_file);
589250397Sobrien      output_uleb128 (1 + PTR_SIZE);
589350397Sobrien      fputc ('\n', asm_out_file);
589450397Sobrien      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
589550397Sobrien      fputc ('\n', asm_out_file);
589650397Sobrien      ASM_OUTPUT_DWARF_ADDR (asm_out_file, text_end_label);
589750397Sobrien      fputc ('\n', asm_out_file);
589850397Sobrien    }
589950397Sobrien
590050397Sobrien  /* Output the marker for the end of the line number info.  */
590150397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
590250397Sobrien  if (flag_debug_asm)
590350397Sobrien    fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", ASM_COMMENT_START);
590450397Sobrien
590550397Sobrien  fputc ('\n', asm_out_file);
590650397Sobrien  output_uleb128 (1);
590750397Sobrien  fputc ('\n', asm_out_file);
590850397Sobrien  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence);
590950397Sobrien  fputc ('\n', asm_out_file);
591050397Sobrien
591150397Sobrien  function = 0;
591250397Sobrien  current_file = 1;
591350397Sobrien  current_line = 1;
591450397Sobrien  for (lt_index = 0; lt_index < separate_line_info_table_in_use; )
591550397Sobrien    {
591650397Sobrien      register dw_separate_line_info_ref line_info
591750397Sobrien	= &separate_line_info_table[lt_index];
591850397Sobrien
591950397Sobrien      /* Emit debug info for the address of the current line.  If this is
592050397Sobrien	 a new function, or the first line of a function, then we need
592150397Sobrien	 to handle it differently.  */
592250397Sobrien      ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL,
592350397Sobrien				   lt_index);
592450397Sobrien      if (function != line_info->function)
592550397Sobrien	{
592650397Sobrien	  function = line_info->function;
592750397Sobrien
592850397Sobrien	  /* Set the address register to the first line in the function */
592950397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
593050397Sobrien	  if (flag_debug_asm)
593150397Sobrien	    fprintf (asm_out_file, "\t%s DW_LNE_set_address",
593250397Sobrien		     ASM_COMMENT_START);
593350397Sobrien
593450397Sobrien	  fputc ('\n', asm_out_file);
593550397Sobrien	  output_uleb128 (1 + PTR_SIZE);
593650397Sobrien	  fputc ('\n', asm_out_file);
593750397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
593850397Sobrien	  fputc ('\n', asm_out_file);
593950397Sobrien	  ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
594050397Sobrien	  fputc ('\n', asm_out_file);
594150397Sobrien	}
594250397Sobrien      else
594350397Sobrien	{
594450397Sobrien	  /* ??? See the DW_LNS_advance_pc comment above.  */
594550397Sobrien	  if (0)
594650397Sobrien	    {
594750397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
594850397Sobrien	      if (flag_debug_asm)
594950397Sobrien		fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
595050397Sobrien			 ASM_COMMENT_START);
595150397Sobrien
595250397Sobrien	      fputc ('\n', asm_out_file);
595350397Sobrien	      ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label,
595450397Sobrien				       prev_line_label);
595550397Sobrien	      fputc ('\n', asm_out_file);
595650397Sobrien	    }
595750397Sobrien	  else
595850397Sobrien	    {
595950397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
596050397Sobrien	      if (flag_debug_asm)
596150397Sobrien		fprintf (asm_out_file, "\t%s DW_LNE_set_address",
596250397Sobrien			 ASM_COMMENT_START);
596350397Sobrien	      fputc ('\n', asm_out_file);
596450397Sobrien	      output_uleb128 (1 + PTR_SIZE);
596550397Sobrien	      fputc ('\n', asm_out_file);
596650397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
596750397Sobrien	      fputc ('\n', asm_out_file);
596850397Sobrien	      ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
596950397Sobrien	      fputc ('\n', asm_out_file);
597050397Sobrien	    }
597150397Sobrien	}
597250397Sobrien      strcpy (prev_line_label, line_label);
597350397Sobrien
597450397Sobrien      /* Emit debug info for the source file of the current line, if
597550397Sobrien	 different from the previous line.  */
597650397Sobrien      if (line_info->dw_file_num != current_file)
597750397Sobrien	{
597850397Sobrien	  current_file = line_info->dw_file_num;
597950397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file);
598050397Sobrien	  if (flag_debug_asm)
598150397Sobrien	    fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START);
598250397Sobrien
598350397Sobrien	  fputc ('\n', asm_out_file);
598450397Sobrien	  output_uleb128 (current_file);
598550397Sobrien	  if (flag_debug_asm)
598650397Sobrien	    fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
598750397Sobrien
598850397Sobrien	  fputc ('\n', asm_out_file);
598950397Sobrien	}
599050397Sobrien
599150397Sobrien      /* Emit debug info for the current line number, choosing the encoding
599250397Sobrien	 that uses the least amount of space.  */
599350397Sobrien      if (line_info->dw_line_num != current_line)
599450397Sobrien	{
599550397Sobrien	  line_offset = line_info->dw_line_num - current_line;
599650397Sobrien	  line_delta = line_offset - DWARF_LINE_BASE;
599750397Sobrien	  current_line = line_info->dw_line_num;
599850397Sobrien	  if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
599950397Sobrien	    {
600050397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
600150397Sobrien				      DWARF_LINE_OPCODE_BASE + line_delta);
600250397Sobrien	      if (flag_debug_asm)
600350397Sobrien		fprintf (asm_out_file,
600450397Sobrien			 "\t%s line %ld", ASM_COMMENT_START, current_line);
600550397Sobrien
600650397Sobrien	      fputc ('\n', asm_out_file);
600750397Sobrien	    }
600850397Sobrien	  else
600950397Sobrien	    {
601050397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line);
601150397Sobrien	      if (flag_debug_asm)
601250397Sobrien		fprintf (asm_out_file, "\t%s advance to line %ld",
601350397Sobrien			 ASM_COMMENT_START, current_line);
601450397Sobrien
601550397Sobrien	      fputc ('\n', asm_out_file);
601650397Sobrien	      output_sleb128 (line_offset);
601750397Sobrien	      fputc ('\n', asm_out_file);
601850397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
601950397Sobrien	      fputc ('\n', asm_out_file);
602050397Sobrien	    }
602150397Sobrien	}
602250397Sobrien
602350397Sobrien      ++lt_index;
602450397Sobrien
602550397Sobrien      /* If we're done with a function, end its sequence.  */
602650397Sobrien      if (lt_index == separate_line_info_table_in_use
602750397Sobrien	  || separate_line_info_table[lt_index].function != function)
602850397Sobrien	{
602950397Sobrien	  current_file = 1;
603050397Sobrien	  current_line = 1;
603150397Sobrien
603250397Sobrien	  /* Emit debug info for the address of the end of the function.  */
603350397Sobrien	  ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function);
603450397Sobrien	  if (0)
603550397Sobrien	    {
603650397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
603750397Sobrien	      if (flag_debug_asm)
603850397Sobrien		fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
603950397Sobrien			 ASM_COMMENT_START);
604050397Sobrien
604150397Sobrien	      fputc ('\n', asm_out_file);
604250397Sobrien	      ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label,
604350397Sobrien				       prev_line_label);
604450397Sobrien	      fputc ('\n', asm_out_file);
604550397Sobrien	    }
604650397Sobrien	  else
604750397Sobrien	    {
604850397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
604950397Sobrien	      if (flag_debug_asm)
605050397Sobrien		fprintf (asm_out_file, "\t%s DW_LNE_set_address",
605150397Sobrien			 ASM_COMMENT_START);
605250397Sobrien	      fputc ('\n', asm_out_file);
605350397Sobrien	      output_uleb128 (1 + PTR_SIZE);
605450397Sobrien	      fputc ('\n', asm_out_file);
605550397Sobrien	      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
605650397Sobrien	      fputc ('\n', asm_out_file);
605750397Sobrien	      ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
605850397Sobrien	      fputc ('\n', asm_out_file);
605950397Sobrien	    }
606050397Sobrien
606150397Sobrien	  /* Output the marker for the end of this sequence.  */
606250397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
606350397Sobrien	  if (flag_debug_asm)
606450397Sobrien	    fprintf (asm_out_file, "\t%s DW_LNE_end_sequence",
606550397Sobrien		     ASM_COMMENT_START);
606650397Sobrien
606750397Sobrien	  fputc ('\n', asm_out_file);
606850397Sobrien	  output_uleb128 (1);
606950397Sobrien	  fputc ('\n', asm_out_file);
607050397Sobrien	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence);
607150397Sobrien	  fputc ('\n', asm_out_file);
607250397Sobrien	}
607350397Sobrien    }
607450397Sobrien}
607550397Sobrien
607650397Sobrien/* Given a pointer to a BLOCK node return non-zero if (and only if) the node
607750397Sobrien   in question represents the outermost pair of curly braces (i.e. the "body
607850397Sobrien   block") of a function or method.
607950397Sobrien
608050397Sobrien   For any BLOCK node representing a "body block" of a function or method, the
608150397Sobrien   BLOCK_SUPERCONTEXT of the node will point to another BLOCK node which
608250397Sobrien   represents the outermost (function) scope for the function or method (i.e.
608350397Sobrien   the one which includes the formal parameters).  The BLOCK_SUPERCONTEXT of
608450397Sobrien   *that* node in turn will point to the relevant FUNCTION_DECL node. */
608550397Sobrien
608650397Sobrienstatic inline int
608750397Sobrienis_body_block (stmt)
608850397Sobrien     register tree stmt;
608950397Sobrien{
609050397Sobrien  if (TREE_CODE (stmt) == BLOCK)
609150397Sobrien    {
609250397Sobrien      register tree parent = BLOCK_SUPERCONTEXT (stmt);
609350397Sobrien
609450397Sobrien      if (TREE_CODE (parent) == BLOCK)
609550397Sobrien	{
609650397Sobrien	  register tree grandparent = BLOCK_SUPERCONTEXT (parent);
609750397Sobrien
609850397Sobrien	  if (TREE_CODE (grandparent) == FUNCTION_DECL)
609950397Sobrien	    return 1;
610050397Sobrien	}
610150397Sobrien    }
610250397Sobrien
610350397Sobrien  return 0;
610450397Sobrien}
610550397Sobrien
610650397Sobrien/* Given a pointer to a tree node for some base type, return a pointer to
610750397Sobrien   a DIE that describes the given type.
610850397Sobrien
610950397Sobrien   This routine must only be called for GCC type nodes that correspond to
611050397Sobrien   Dwarf base (fundamental) types.  */
611150397Sobrien
611250397Sobrienstatic dw_die_ref
611350397Sobrienbase_type_die (type)
611450397Sobrien     register tree type;
611550397Sobrien{
611650397Sobrien  register dw_die_ref base_type_result;
611750397Sobrien  register char *type_name;
611850397Sobrien  register enum dwarf_type encoding;
611950397Sobrien  register tree name = TYPE_NAME (type);
612050397Sobrien
612150397Sobrien  if (TREE_CODE (type) == ERROR_MARK
612250397Sobrien      || TREE_CODE (type) == VOID_TYPE)
612350397Sobrien    return 0;
612450397Sobrien
612550397Sobrien  if (TREE_CODE (name) == TYPE_DECL)
612650397Sobrien    name = DECL_NAME (name);
612750397Sobrien  type_name = IDENTIFIER_POINTER (name);
612850397Sobrien
612950397Sobrien  switch (TREE_CODE (type))
613050397Sobrien    {
613150397Sobrien    case INTEGER_TYPE:
613250397Sobrien      /* Carefully distinguish the C character types, without messing
613350397Sobrien         up if the language is not C. Note that we check only for the names
613450397Sobrien         that contain spaces; other names might occur by coincidence in other
613550397Sobrien         languages.  */
613650397Sobrien      if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE
613750397Sobrien	     && (type == char_type_node
613850397Sobrien		 || ! strcmp (type_name, "signed char")
613950397Sobrien		 || ! strcmp (type_name, "unsigned char"))))
614050397Sobrien	{
614150397Sobrien	  if (TREE_UNSIGNED (type))
614250397Sobrien	    encoding = DW_ATE_unsigned;
614350397Sobrien	  else
614450397Sobrien	    encoding = DW_ATE_signed;
614550397Sobrien	  break;
614650397Sobrien	}
614750397Sobrien      /* else fall through */
614850397Sobrien
614950397Sobrien    case CHAR_TYPE:
615050397Sobrien      /* GNU Pascal/Ada CHAR type.  Not used in C.  */
615150397Sobrien      if (TREE_UNSIGNED (type))
615250397Sobrien	encoding = DW_ATE_unsigned_char;
615350397Sobrien      else
615450397Sobrien	encoding = DW_ATE_signed_char;
615550397Sobrien      break;
615650397Sobrien
615750397Sobrien    case REAL_TYPE:
615850397Sobrien      encoding = DW_ATE_float;
615950397Sobrien      break;
616050397Sobrien
616150397Sobrien    case COMPLEX_TYPE:
616250397Sobrien      encoding = DW_ATE_complex_float;
616350397Sobrien      break;
616450397Sobrien
616550397Sobrien    case BOOLEAN_TYPE:
616650397Sobrien      /* GNU FORTRAN/Ada/C++ BOOLEAN type.  */
616750397Sobrien      encoding = DW_ATE_boolean;
616850397Sobrien      break;
616950397Sobrien
617050397Sobrien    default:
617150397Sobrien      abort (); /* No other TREE_CODEs are Dwarf fundamental types.  */
617250397Sobrien    }
617350397Sobrien
617450397Sobrien  base_type_result = new_die (DW_TAG_base_type, comp_unit_die);
617550397Sobrien  add_AT_string (base_type_result, DW_AT_name, type_name);
617650397Sobrien  add_AT_unsigned (base_type_result, DW_AT_byte_size,
617750397Sobrien		   int_size_in_bytes (type));
617850397Sobrien  add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
617950397Sobrien
618050397Sobrien  return base_type_result;
618150397Sobrien}
618250397Sobrien
618350397Sobrien/* Given a pointer to an arbitrary ..._TYPE tree node, return a pointer to
618450397Sobrien   the Dwarf "root" type for the given input type.  The Dwarf "root" type of
618550397Sobrien   a given type is generally the same as the given type, except that if the
618650397Sobrien   given type is a pointer or reference type, then the root type of the given
618750397Sobrien   type is the root type of the "basis" type for the pointer or reference
618850397Sobrien   type.  (This definition of the "root" type is recursive.) Also, the root
618950397Sobrien   type of a `const' qualified type or a `volatile' qualified type is the
619050397Sobrien   root type of the given type without the qualifiers.  */
619150397Sobrien
619250397Sobrienstatic tree
619350397Sobrienroot_type (type)
619450397Sobrien     register tree type;
619550397Sobrien{
619650397Sobrien  if (TREE_CODE (type) == ERROR_MARK)
619750397Sobrien    return error_mark_node;
619850397Sobrien
619950397Sobrien  switch (TREE_CODE (type))
620050397Sobrien    {
620150397Sobrien    case ERROR_MARK:
620250397Sobrien      return error_mark_node;
620350397Sobrien
620450397Sobrien    case POINTER_TYPE:
620550397Sobrien    case REFERENCE_TYPE:
620650397Sobrien      return type_main_variant (root_type (TREE_TYPE (type)));
620750397Sobrien
620850397Sobrien    default:
620950397Sobrien      return type_main_variant (type);
621050397Sobrien    }
621150397Sobrien}
621250397Sobrien
621350397Sobrien/* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the
621450397Sobrien   given input type is a Dwarf "fundamental" type.  Otherwise return null.  */
621550397Sobrien
621650397Sobrienstatic inline int
621750397Sobrienis_base_type (type)
621850397Sobrien     register tree type;
621950397Sobrien{
622050397Sobrien  switch (TREE_CODE (type))
622150397Sobrien    {
622250397Sobrien    case ERROR_MARK:
622350397Sobrien    case VOID_TYPE:
622450397Sobrien    case INTEGER_TYPE:
622550397Sobrien    case REAL_TYPE:
622650397Sobrien    case COMPLEX_TYPE:
622750397Sobrien    case BOOLEAN_TYPE:
622850397Sobrien    case CHAR_TYPE:
622950397Sobrien      return 1;
623050397Sobrien
623150397Sobrien    case SET_TYPE:
623250397Sobrien    case ARRAY_TYPE:
623350397Sobrien    case RECORD_TYPE:
623450397Sobrien    case UNION_TYPE:
623550397Sobrien    case QUAL_UNION_TYPE:
623650397Sobrien    case ENUMERAL_TYPE:
623750397Sobrien    case FUNCTION_TYPE:
623850397Sobrien    case METHOD_TYPE:
623950397Sobrien    case POINTER_TYPE:
624050397Sobrien    case REFERENCE_TYPE:
624150397Sobrien    case FILE_TYPE:
624250397Sobrien    case OFFSET_TYPE:
624350397Sobrien    case LANG_TYPE:
624450397Sobrien      return 0;
624550397Sobrien
624650397Sobrien    default:
624750397Sobrien      abort ();
624850397Sobrien    }
624950397Sobrien
625050397Sobrien  return 0;
625150397Sobrien}
625250397Sobrien
625350397Sobrien/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
625450397Sobrien   entry that chains various modifiers in front of the given type.  */
625550397Sobrien
625650397Sobrienstatic dw_die_ref
625750397Sobrienmodified_type_die (type, is_const_type, is_volatile_type, context_die)
625850397Sobrien     register tree type;
625950397Sobrien     register int is_const_type;
626050397Sobrien     register int is_volatile_type;
626150397Sobrien     register dw_die_ref context_die;
626250397Sobrien{
626350397Sobrien  register enum tree_code code = TREE_CODE (type);
626450397Sobrien  register dw_die_ref mod_type_die = NULL;
626550397Sobrien  register dw_die_ref sub_die = NULL;
626650397Sobrien  register tree item_type = NULL;
626750397Sobrien
626850397Sobrien  if (code != ERROR_MARK)
626950397Sobrien    {
627050397Sobrien      type = build_type_variant (type, is_const_type, is_volatile_type);
627150397Sobrien
627250397Sobrien      mod_type_die = lookup_type_die (type);
627350397Sobrien      if (mod_type_die)
627450397Sobrien	return mod_type_die;
627550397Sobrien
627650397Sobrien      /* Handle C typedef types. */
627750397Sobrien      if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
627850397Sobrien	  && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
627950397Sobrien	{
628050397Sobrien	  tree dtype = TREE_TYPE (TYPE_NAME (type));
628150397Sobrien	  if (type == dtype)
628250397Sobrien	    {
628350397Sobrien	      /* For a named type, use the typedef.  */
628450397Sobrien	      gen_type_die (type, context_die);
628550397Sobrien	      mod_type_die = lookup_type_die (type);
628650397Sobrien	    }
628750397Sobrien
628850397Sobrien	  else if (is_const_type < TYPE_READONLY (dtype)
628950397Sobrien		   || is_volatile_type < TYPE_VOLATILE (dtype))
629050397Sobrien	    /* cv-unqualified version of named type.  Just use the unnamed
629150397Sobrien	       type to which it refers.  */
629250397Sobrien	    mod_type_die
629350397Sobrien	      = modified_type_die (DECL_ORIGINAL_TYPE (TYPE_NAME (type)),
629450397Sobrien				   is_const_type, is_volatile_type,
629550397Sobrien				   context_die);
629650397Sobrien	  /* Else cv-qualified version of named type; fall through.  */
629750397Sobrien	}
629850397Sobrien
629950397Sobrien      if (mod_type_die)
630050397Sobrien	/* OK */;
630150397Sobrien      else if (is_const_type)
630250397Sobrien	{
630350397Sobrien	  mod_type_die = new_die (DW_TAG_const_type, comp_unit_die);
630450397Sobrien	  sub_die = modified_type_die (type, 0, is_volatile_type, context_die);
630550397Sobrien	}
630650397Sobrien      else if (is_volatile_type)
630750397Sobrien	{
630850397Sobrien	  mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die);
630950397Sobrien	  sub_die = modified_type_die (type, 0, 0, context_die);
631050397Sobrien	}
631150397Sobrien      else if (code == POINTER_TYPE)
631250397Sobrien	{
631350397Sobrien	  mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die);
631450397Sobrien	  add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
631550397Sobrien#if 0
631650397Sobrien	  add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
631750397Sobrien#endif
631850397Sobrien	  item_type = TREE_TYPE (type);
631950397Sobrien	}
632050397Sobrien      else if (code == REFERENCE_TYPE)
632150397Sobrien	{
632250397Sobrien	  mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die);
632350397Sobrien	  add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
632450397Sobrien#if 0
632550397Sobrien	  add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
632650397Sobrien#endif
632750397Sobrien	  item_type = TREE_TYPE (type);
632850397Sobrien	}
632950397Sobrien      else if (is_base_type (type))
633050397Sobrien	mod_type_die = base_type_die (type);
633150397Sobrien      else
633250397Sobrien	{
633350397Sobrien	  gen_type_die (type, context_die);
633450397Sobrien
633550397Sobrien	  /* We have to get the type_main_variant here (and pass that to the
633650397Sobrien	     `lookup_type_die' routine) because the ..._TYPE node we have
633750397Sobrien	     might simply be a *copy* of some original type node (where the
633850397Sobrien	     copy was created to help us keep track of typedef names) and
633950397Sobrien	     that copy might have a different TYPE_UID from the original
634050397Sobrien	     ..._TYPE node.  */
634150397Sobrien	  mod_type_die = lookup_type_die (type_main_variant (type));
634250397Sobrien	  if (mod_type_die == NULL)
634350397Sobrien	    abort ();
634450397Sobrien	}
634550397Sobrien    }
634650397Sobrien
634750397Sobrien  equate_type_number_to_die (type, mod_type_die);
634850397Sobrien  if (item_type)
634950397Sobrien    /* We must do this after the equate_type_number_to_die call, in case
635050397Sobrien       this is a recursive type.  This ensures that the modified_type_die
635150397Sobrien       recursion will terminate even if the type is recursive.  Recursive
635250397Sobrien       types are possible in Ada.  */
635350397Sobrien    sub_die = modified_type_die (item_type,
635450397Sobrien				 TYPE_READONLY (item_type),
635550397Sobrien				 TYPE_VOLATILE (item_type),
635650397Sobrien				 context_die);
635750397Sobrien
635850397Sobrien  if (sub_die != NULL)
635950397Sobrien    add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
636050397Sobrien
636150397Sobrien  return mod_type_die;
636250397Sobrien}
636350397Sobrien
636450397Sobrien/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
636550397Sobrien   an enumerated type.   */
636650397Sobrien
636750397Sobrienstatic inline int
636850397Sobrientype_is_enum (type)
636950397Sobrien     register tree type;
637050397Sobrien{
637150397Sobrien  return TREE_CODE (type) == ENUMERAL_TYPE;
637250397Sobrien}
637350397Sobrien
637450397Sobrien/* Return a location descriptor that designates a machine register.  */
637550397Sobrien
637650397Sobrienstatic dw_loc_descr_ref
637750397Sobrienreg_loc_descriptor (rtl)
637850397Sobrien     register rtx rtl;
637950397Sobrien{
638050397Sobrien  register dw_loc_descr_ref loc_result = NULL;
638150397Sobrien  register unsigned reg = reg_number (rtl);
638250397Sobrien
638350397Sobrien  if (reg <= 31)
638450397Sobrien    loc_result = new_loc_descr (DW_OP_reg0 + reg, 0, 0);
638550397Sobrien  else
638650397Sobrien    loc_result = new_loc_descr (DW_OP_regx, reg, 0);
638750397Sobrien
638850397Sobrien  return loc_result;
638950397Sobrien}
639050397Sobrien
639150397Sobrien/* Return a location descriptor that designates a base+offset location.  */
639250397Sobrien
639350397Sobrienstatic dw_loc_descr_ref
639450397Sobrienbased_loc_descr (reg, offset)
639550397Sobrien     unsigned reg;
639650397Sobrien     long int offset;
639750397Sobrien{
639850397Sobrien  register dw_loc_descr_ref loc_result;
639950397Sobrien  /* For the "frame base", we use the frame pointer or stack pointer
640050397Sobrien     registers, since the RTL for local variables is relative to one of
640150397Sobrien     them.  */
640250397Sobrien  register unsigned fp_reg = DBX_REGISTER_NUMBER (frame_pointer_needed
640350397Sobrien						  ? HARD_FRAME_POINTER_REGNUM
640450397Sobrien						  : STACK_POINTER_REGNUM);
640550397Sobrien
640650397Sobrien  if (reg == fp_reg)
640750397Sobrien    loc_result = new_loc_descr (DW_OP_fbreg, offset, 0);
640850397Sobrien  else if (reg <= 31)
640950397Sobrien    loc_result = new_loc_descr (DW_OP_breg0 + reg, offset, 0);
641050397Sobrien  else
641150397Sobrien    loc_result = new_loc_descr (DW_OP_bregx, reg, offset);
641250397Sobrien
641350397Sobrien  return loc_result;
641450397Sobrien}
641550397Sobrien
641650397Sobrien/* Return true if this RTL expression describes a base+offset calculation.  */
641750397Sobrien
641850397Sobrienstatic inline int
641950397Sobrienis_based_loc (rtl)
642050397Sobrien     register rtx rtl;
642150397Sobrien{
642250397Sobrien    return (GET_CODE (rtl) == PLUS
642350397Sobrien	    && ((GET_CODE (XEXP (rtl, 0)) == REG
642450397Sobrien		 && GET_CODE (XEXP (rtl, 1)) == CONST_INT)));
642550397Sobrien}
642650397Sobrien
642750397Sobrien/* The following routine converts the RTL for a variable or parameter
642850397Sobrien   (resident in memory) into an equivalent Dwarf representation of a
642950397Sobrien   mechanism for getting the address of that same variable onto the top of a
643050397Sobrien   hypothetical "address evaluation" stack.
643150397Sobrien
643250397Sobrien   When creating memory location descriptors, we are effectively transforming
643350397Sobrien   the RTL for a memory-resident object into its Dwarf postfix expression
643450397Sobrien   equivalent.  This routine recursively descends an RTL tree, turning
643550397Sobrien   it into Dwarf postfix code as it goes.  */
643650397Sobrien
643750397Sobrienstatic dw_loc_descr_ref
643850397Sobrienmem_loc_descriptor (rtl)
643950397Sobrien     register rtx rtl;
644050397Sobrien{
644150397Sobrien  dw_loc_descr_ref mem_loc_result = NULL;
644250397Sobrien  /* Note that for a dynamically sized array, the location we will generate a
644350397Sobrien     description of here will be the lowest numbered location which is
644450397Sobrien     actually within the array.  That's *not* necessarily the same as the
644550397Sobrien     zeroth element of the array.  */
644650397Sobrien
644750397Sobrien  switch (GET_CODE (rtl))
644850397Sobrien    {
644950397Sobrien    case SUBREG:
645050397Sobrien      /* The case of a subreg may arise when we have a local (register)
645150397Sobrien         variable or a formal (register) parameter which doesn't quite fill
645250397Sobrien         up an entire register.  For now, just assume that it is
645350397Sobrien         legitimate to make the Dwarf info refer to the whole register which
645450397Sobrien         contains the given subreg.  */
645550397Sobrien      rtl = XEXP (rtl, 0);
645650397Sobrien
645750397Sobrien      /* ... fall through ... */
645850397Sobrien
645950397Sobrien    case REG:
646050397Sobrien      /* Whenever a register number forms a part of the description of the
646150397Sobrien         method for calculating the (dynamic) address of a memory resident
646250397Sobrien         object, DWARF rules require the register number be referred to as
646350397Sobrien         a "base register".  This distinction is not based in any way upon
646450397Sobrien         what category of register the hardware believes the given register
646550397Sobrien         belongs to.  This is strictly DWARF terminology we're dealing with
646650397Sobrien         here. Note that in cases where the location of a memory-resident
646750397Sobrien         data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
646850397Sobrien         OP_CONST (0)) the actual DWARF location descriptor that we generate
646950397Sobrien         may just be OP_BASEREG (basereg).  This may look deceptively like
647050397Sobrien         the object in question was allocated to a register (rather than in
647150397Sobrien         memory) so DWARF consumers need to be aware of the subtle
647250397Sobrien         distinction between OP_REG and OP_BASEREG.  */
647350397Sobrien      mem_loc_result = based_loc_descr (reg_number (rtl), 0);
647450397Sobrien      break;
647550397Sobrien
647650397Sobrien    case MEM:
647750397Sobrien      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0));
647850397Sobrien      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
647950397Sobrien      break;
648050397Sobrien
648150397Sobrien    case CONST:
648250397Sobrien    case SYMBOL_REF:
648350397Sobrien      mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
648450397Sobrien      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
648550397Sobrien      mem_loc_result->dw_loc_oprnd1.v.val_addr = addr_to_string (rtl);
648650397Sobrien      break;
648750397Sobrien
648850397Sobrien    case PLUS:
648950397Sobrien      if (is_based_loc (rtl))
649050397Sobrien	mem_loc_result = based_loc_descr (reg_number (XEXP (rtl, 0)),
649150397Sobrien					  INTVAL (XEXP (rtl, 1)));
649250397Sobrien      else
649350397Sobrien	{
649450397Sobrien	  add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0)));
649550397Sobrien	  add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1)));
649650397Sobrien	  add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_plus, 0, 0));
649750397Sobrien	}
649850397Sobrien      break;
649950397Sobrien
650050397Sobrien    case MULT:
650150397Sobrien      /* If a pseudo-reg is optimized away, it is possible for it to
650250397Sobrien	 be replaced with a MEM containing a multiply.  */
650350397Sobrien      add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0)));
650450397Sobrien      add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1)));
650550397Sobrien      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
650650397Sobrien      break;
650750397Sobrien
650850397Sobrien    case CONST_INT:
650950397Sobrien      mem_loc_result = new_loc_descr (DW_OP_constu, INTVAL (rtl), 0);
651050397Sobrien      break;
651150397Sobrien
651250397Sobrien    default:
651350397Sobrien      abort ();
651450397Sobrien    }
651550397Sobrien
651650397Sobrien  return mem_loc_result;
651750397Sobrien}
651850397Sobrien
651950397Sobrien/* Return a descriptor that describes the concatenation of two locations.
652050397Sobrien   This is typically a complex variable.  */
652150397Sobrien
652250397Sobrienstatic dw_loc_descr_ref
652350397Sobrienconcat_loc_descriptor (x0, x1)
652450397Sobrien     register rtx x0, x1;
652550397Sobrien{
652650397Sobrien  dw_loc_descr_ref cc_loc_result = NULL;
652750397Sobrien
652850397Sobrien  if (!is_pseudo_reg (x0)
652950397Sobrien      && (GET_CODE (x0) != MEM || !is_pseudo_reg (XEXP (x0, 0))))
653050397Sobrien    add_loc_descr (&cc_loc_result, loc_descriptor (x0));
653150397Sobrien  add_loc_descr (&cc_loc_result,
653250397Sobrien	         new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x0)), 0));
653350397Sobrien
653450397Sobrien  if (!is_pseudo_reg (x1)
653550397Sobrien      && (GET_CODE (x1) != MEM || !is_pseudo_reg (XEXP (x1, 0))))
653650397Sobrien    add_loc_descr (&cc_loc_result, loc_descriptor (x1));
653750397Sobrien  add_loc_descr (&cc_loc_result,
653850397Sobrien		 new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x1)), 0));
653950397Sobrien
654050397Sobrien  return cc_loc_result;
654150397Sobrien}
654250397Sobrien
654350397Sobrien/* Output a proper Dwarf location descriptor for a variable or parameter
654450397Sobrien   which is either allocated in a register or in a memory location.  For a
654550397Sobrien   register, we just generate an OP_REG and the register number.  For a
654650397Sobrien   memory location we provide a Dwarf postfix expression describing how to
654750397Sobrien   generate the (dynamic) address of the object onto the address stack.  */
654850397Sobrien
654950397Sobrienstatic dw_loc_descr_ref
655050397Sobrienloc_descriptor (rtl)
655150397Sobrien     register rtx rtl;
655250397Sobrien{
655350397Sobrien  dw_loc_descr_ref loc_result = NULL;
655450397Sobrien  switch (GET_CODE (rtl))
655550397Sobrien    {
655650397Sobrien    case SUBREG:
655750397Sobrien      /* The case of a subreg may arise when we have a local (register)
655850397Sobrien         variable or a formal (register) parameter which doesn't quite fill
655950397Sobrien         up an entire register.  For now, just assume that it is
656050397Sobrien         legitimate to make the Dwarf info refer to the whole register which
656150397Sobrien         contains the given subreg.  */
656250397Sobrien      rtl = XEXP (rtl, 0);
656350397Sobrien
656450397Sobrien      /* ... fall through ... */
656550397Sobrien
656650397Sobrien    case REG:
656750397Sobrien      loc_result = reg_loc_descriptor (rtl);
656850397Sobrien      break;
656950397Sobrien
657050397Sobrien    case MEM:
657150397Sobrien      loc_result = mem_loc_descriptor (XEXP (rtl, 0));
657250397Sobrien      break;
657350397Sobrien
657450397Sobrien    case CONCAT:
657550397Sobrien      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
657650397Sobrien      break;
657750397Sobrien
657850397Sobrien    default:
657950397Sobrien      abort ();
658050397Sobrien    }
658150397Sobrien
658250397Sobrien  return loc_result;
658350397Sobrien}
658450397Sobrien
658550397Sobrien/* Given an unsigned value, round it up to the lowest multiple of `boundary'
658650397Sobrien   which is not less than the value itself.  */
658750397Sobrien
658850397Sobrienstatic inline unsigned
658950397Sobrienceiling (value, boundary)
659050397Sobrien     register unsigned value;
659150397Sobrien     register unsigned boundary;
659250397Sobrien{
659350397Sobrien  return (((value + boundary - 1) / boundary) * boundary);
659450397Sobrien}
659550397Sobrien
659650397Sobrien/* Given a pointer to what is assumed to be a FIELD_DECL node, return a
659750397Sobrien   pointer to the declared type for the relevant field variable, or return
659850397Sobrien   `integer_type_node' if the given node turns out to be an
659950397Sobrien   ERROR_MARK node.  */
660050397Sobrien
660150397Sobrienstatic inline tree
660250397Sobrienfield_type (decl)
660350397Sobrien     register tree decl;
660450397Sobrien{
660550397Sobrien  register tree type;
660650397Sobrien
660750397Sobrien  if (TREE_CODE (decl) == ERROR_MARK)
660850397Sobrien    return integer_type_node;
660950397Sobrien
661050397Sobrien  type = DECL_BIT_FIELD_TYPE (decl);
661150397Sobrien  if (type == NULL_TREE)
661250397Sobrien    type = TREE_TYPE (decl);
661350397Sobrien
661450397Sobrien  return type;
661550397Sobrien}
661650397Sobrien
661750397Sobrien/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
661850397Sobrien   node, return the alignment in bits for the type, or else return
661950397Sobrien   BITS_PER_WORD if the node actually turns out to be an
662050397Sobrien   ERROR_MARK node.  */
662150397Sobrien
662250397Sobrienstatic inline unsigned
662350397Sobriensimple_type_align_in_bits (type)
662450397Sobrien     register tree type;
662550397Sobrien{
662650397Sobrien  return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;
662750397Sobrien}
662850397Sobrien
662950397Sobrien/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
663050397Sobrien   node, return the size in bits for the type if it is a constant, or else
663150397Sobrien   return the alignment for the type if the type's size is not constant, or
663250397Sobrien   else return BITS_PER_WORD if the type actually turns out to be an
663350397Sobrien   ERROR_MARK node.  */
663450397Sobrien
663550397Sobrienstatic inline unsigned
663650397Sobriensimple_type_size_in_bits (type)
663750397Sobrien     register tree type;
663850397Sobrien{
663950397Sobrien  if (TREE_CODE (type) == ERROR_MARK)
664050397Sobrien    return BITS_PER_WORD;
664150397Sobrien  else
664250397Sobrien    {
664350397Sobrien      register tree type_size_tree = TYPE_SIZE (type);
664450397Sobrien
664550397Sobrien      if (TREE_CODE (type_size_tree) != INTEGER_CST)
664650397Sobrien	return TYPE_ALIGN (type);
664750397Sobrien
664850397Sobrien      return (unsigned) TREE_INT_CST_LOW (type_size_tree);
664950397Sobrien    }
665050397Sobrien}
665150397Sobrien
665250397Sobrien/* Given a pointer to what is assumed to be a FIELD_DECL node, compute and
665350397Sobrien   return the byte offset of the lowest addressed byte of the "containing
665450397Sobrien   object" for the given FIELD_DECL, or return 0 if we are unable to
665550397Sobrien   determine what that offset is, either because the argument turns out to
665650397Sobrien   be a pointer to an ERROR_MARK node, or because the offset is actually
665750397Sobrien   variable.  (We can't handle the latter case just yet).  */
665850397Sobrien
665950397Sobrienstatic unsigned
666050397Sobrienfield_byte_offset (decl)
666150397Sobrien     register tree decl;
666250397Sobrien{
666350397Sobrien  register unsigned type_align_in_bytes;
666450397Sobrien  register unsigned type_align_in_bits;
666550397Sobrien  register unsigned type_size_in_bits;
666650397Sobrien  register unsigned object_offset_in_align_units;
666750397Sobrien  register unsigned object_offset_in_bits;
666850397Sobrien  register unsigned object_offset_in_bytes;
666950397Sobrien  register tree type;
667050397Sobrien  register tree bitpos_tree;
667150397Sobrien  register tree field_size_tree;
667250397Sobrien  register unsigned bitpos_int;
667350397Sobrien  register unsigned deepest_bitpos;
667450397Sobrien  register unsigned field_size_in_bits;
667550397Sobrien
667650397Sobrien  if (TREE_CODE (decl) == ERROR_MARK)
667750397Sobrien    return 0;
667850397Sobrien
667950397Sobrien  if (TREE_CODE (decl) != FIELD_DECL)
668050397Sobrien    abort ();
668150397Sobrien
668250397Sobrien  type = field_type (decl);
668350397Sobrien
668450397Sobrien  bitpos_tree = DECL_FIELD_BITPOS (decl);
668550397Sobrien  field_size_tree = DECL_SIZE (decl);
668650397Sobrien
668750397Sobrien  /* We cannot yet cope with fields whose positions or sizes are variable, so
668850397Sobrien     for now, when we see such things, we simply return 0.  Someday, we may
668950397Sobrien     be able to handle such cases, but it will be damn difficult.  */
669050397Sobrien  if (TREE_CODE (bitpos_tree) != INTEGER_CST)
669150397Sobrien    return 0;
669250397Sobrien  bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree);
669350397Sobrien
669450397Sobrien  if (TREE_CODE (field_size_tree) != INTEGER_CST)
669550397Sobrien    return 0;
669650397Sobrien
669750397Sobrien  field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree);
669850397Sobrien  type_size_in_bits = simple_type_size_in_bits (type);
669950397Sobrien  type_align_in_bits = simple_type_align_in_bits (type);
670050397Sobrien  type_align_in_bytes = type_align_in_bits / BITS_PER_UNIT;
670150397Sobrien
670250397Sobrien  /* Note that the GCC front-end doesn't make any attempt to keep track of
670350397Sobrien     the starting bit offset (relative to the start of the containing
670450397Sobrien     structure type) of the hypothetical "containing object" for a bit-
670550397Sobrien     field.  Thus, when computing the byte offset value for the start of the
670650397Sobrien     "containing object" of a bit-field, we must deduce this information on
670750397Sobrien     our own. This can be rather tricky to do in some cases.  For example,
670850397Sobrien     handling the following structure type definition when compiling for an
670950397Sobrien     i386/i486 target (which only aligns long long's to 32-bit boundaries)
671050397Sobrien     can be very tricky:
671150397Sobrien
671250397Sobrien	 struct S { int field1; long long field2:31; };
671350397Sobrien
671450397Sobrien     Fortunately, there is a simple rule-of-thumb which can be
671550397Sobrien     used in such cases.  When compiling for an i386/i486, GCC will allocate
671650397Sobrien     8 bytes for the structure shown above.  It decides to do this based upon
671750397Sobrien     one simple rule for bit-field allocation.  Quite simply, GCC allocates
671850397Sobrien     each "containing object" for each bit-field at the first (i.e. lowest
671950397Sobrien     addressed) legitimate alignment boundary (based upon the required
672050397Sobrien     minimum alignment for the declared type of the field) which it can
672150397Sobrien     possibly use, subject to the condition that there is still enough
672250397Sobrien     available space remaining in the containing object (when allocated at
672350397Sobrien     the selected point) to fully accommodate all of the bits of the
672450397Sobrien     bit-field itself.  This simple rule makes it obvious why GCC allocates
672550397Sobrien     8 bytes for each object of the structure type shown above.  When looking
672650397Sobrien     for a place to allocate the "containing object" for `field2', the
672750397Sobrien     compiler simply tries to allocate a 64-bit "containing object" at each
672850397Sobrien     successive 32-bit boundary (starting at zero) until it finds a place to
672950397Sobrien     allocate that 64- bit field such that at least 31 contiguous (and
673050397Sobrien     previously unallocated) bits remain within that selected 64 bit field.
673150397Sobrien     (As it turns out, for the example above, the compiler finds that it is
673250397Sobrien     OK to allocate the "containing object" 64-bit field at bit-offset zero
673350397Sobrien     within the structure type.) Here we attempt to work backwards from the
673450397Sobrien     limited set of facts we're given, and we try to deduce from those facts,
673550397Sobrien     where GCC must have believed that the containing object started (within
673650397Sobrien     the structure type). The value we deduce is then used (by the callers of
673750397Sobrien     this routine) to generate DW_AT_location and DW_AT_bit_offset attributes
673850397Sobrien     for fields (both bit-fields and, in the case of DW_AT_location, regular
673950397Sobrien     fields as well).  */
674050397Sobrien
674150397Sobrien  /* Figure out the bit-distance from the start of the structure to the
674250397Sobrien     "deepest" bit of the bit-field.  */
674350397Sobrien  deepest_bitpos = bitpos_int + field_size_in_bits;
674450397Sobrien
674550397Sobrien  /* This is the tricky part.  Use some fancy footwork to deduce where the
674650397Sobrien     lowest addressed bit of the containing object must be.  */
674750397Sobrien  object_offset_in_bits
674850397Sobrien    = ceiling (deepest_bitpos, type_align_in_bits) - type_size_in_bits;
674950397Sobrien
675050397Sobrien  /* Compute the offset of the containing object in "alignment units".  */
675150397Sobrien  object_offset_in_align_units = object_offset_in_bits / type_align_in_bits;
675250397Sobrien
675350397Sobrien  /* Compute the offset of the containing object in bytes.  */
675450397Sobrien  object_offset_in_bytes = object_offset_in_align_units * type_align_in_bytes;
675550397Sobrien
675650397Sobrien  return object_offset_in_bytes;
675750397Sobrien}
675850397Sobrien
675950397Sobrien/* The following routines define various Dwarf attributes and any data
676050397Sobrien   associated with them.  */
676150397Sobrien
676250397Sobrien/* Add a location description attribute value to a DIE.
676350397Sobrien
676450397Sobrien   This emits location attributes suitable for whole variables and
676550397Sobrien   whole parameters.  Note that the location attributes for struct fields are
676650397Sobrien   generated by the routine `data_member_location_attribute' below.  */
676750397Sobrien
676850397Sobrienstatic void
676950397Sobrienadd_AT_location_description (die, attr_kind, rtl)
677050397Sobrien     dw_die_ref die;
677150397Sobrien     enum dwarf_attribute attr_kind;
677250397Sobrien     register rtx rtl;
677350397Sobrien{
677450397Sobrien  /* Handle a special case.  If we are about to output a location descriptor
677550397Sobrien     for a variable or parameter which has been optimized out of existence,
677650397Sobrien     don't do that.  A variable which has been optimized out
677750397Sobrien     of existence will have a DECL_RTL value which denotes a pseudo-reg.
677850397Sobrien     Currently, in some rare cases, variables can have DECL_RTL values which
677950397Sobrien     look like (MEM (REG pseudo-reg#)).  These cases are due to bugs
678050397Sobrien     elsewhere in the compiler.  We treat such cases as if the variable(s) in
678150397Sobrien     question had been optimized out of existence.  */
678250397Sobrien
678350397Sobrien  if (is_pseudo_reg (rtl)
678450397Sobrien      || (GET_CODE (rtl) == MEM
678550397Sobrien	  && is_pseudo_reg (XEXP (rtl, 0)))
678650397Sobrien      || (GET_CODE (rtl) == CONCAT
678750397Sobrien	  && is_pseudo_reg (XEXP (rtl, 0))
678850397Sobrien	  && is_pseudo_reg (XEXP (rtl, 1))))
678950397Sobrien    return;
679050397Sobrien
679150397Sobrien  add_AT_loc (die, attr_kind, loc_descriptor (rtl));
679250397Sobrien}
679350397Sobrien
679450397Sobrien/* Attach the specialized form of location attribute used for data
679550397Sobrien   members of struct and union types.  In the special case of a
679650397Sobrien   FIELD_DECL node which represents a bit-field, the "offset" part
679750397Sobrien   of this special location descriptor must indicate the distance
679850397Sobrien   in bytes from the lowest-addressed byte of the containing struct
679950397Sobrien   or union type to the lowest-addressed byte of the "containing
680050397Sobrien   object" for the bit-field.  (See the `field_byte_offset' function
680150397Sobrien   above).. For any given bit-field, the "containing object" is a
680250397Sobrien   hypothetical object (of some integral or enum type) within which
680350397Sobrien   the given bit-field lives.  The type of this hypothetical
680450397Sobrien   "containing object" is always the same as the declared type of
680550397Sobrien   the individual bit-field itself (for GCC anyway... the DWARF
680650397Sobrien   spec doesn't actually mandate this).  Note that it is the size
680750397Sobrien   (in bytes) of the hypothetical "containing object" which will
680850397Sobrien   be given in the DW_AT_byte_size attribute for this bit-field.
680950397Sobrien   (See the `byte_size_attribute' function below.)  It is also used
681050397Sobrien   when calculating the value of the DW_AT_bit_offset attribute.
681150397Sobrien   (See the `bit_offset_attribute' function below).  */
681250397Sobrien
681350397Sobrienstatic void
681450397Sobrienadd_data_member_location_attribute (die, decl)
681550397Sobrien     register dw_die_ref die;
681650397Sobrien     register tree decl;
681750397Sobrien{
681850397Sobrien  register unsigned long offset;
681950397Sobrien  register dw_loc_descr_ref loc_descr;
682050397Sobrien  register enum dwarf_location_atom op;
682150397Sobrien
682250397Sobrien  if (TREE_CODE (decl) == TREE_VEC)
682350397Sobrien    offset = TREE_INT_CST_LOW (BINFO_OFFSET (decl));
682450397Sobrien  else
682550397Sobrien    offset = field_byte_offset (decl);
682650397Sobrien
682750397Sobrien  /* The DWARF2 standard says that we should assume that the structure address
682850397Sobrien     is already on the stack, so we can specify a structure field address
682950397Sobrien     by using DW_OP_plus_uconst.  */
683050397Sobrien
683150397Sobrien#ifdef MIPS_DEBUGGING_INFO
683250397Sobrien  /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst operator
683350397Sobrien     correctly.  It works only if we leave the offset on the stack.  */
683450397Sobrien  op = DW_OP_constu;
683550397Sobrien#else
683650397Sobrien  op = DW_OP_plus_uconst;
683750397Sobrien#endif
683850397Sobrien
683950397Sobrien  loc_descr = new_loc_descr (op, offset, 0);
684050397Sobrien  add_AT_loc (die, DW_AT_data_member_location, loc_descr);
684150397Sobrien}
684250397Sobrien
684350397Sobrien/* Attach an DW_AT_const_value attribute for a variable or a parameter which
684450397Sobrien   does not have a "location" either in memory or in a register.  These
684550397Sobrien   things can arise in GNU C when a constant is passed as an actual parameter
684650397Sobrien   to an inlined function.  They can also arise in C++ where declared
684750397Sobrien   constants do not necessarily get memory "homes".  */
684850397Sobrien
684950397Sobrienstatic void
685050397Sobrienadd_const_value_attribute (die, rtl)
685150397Sobrien     register dw_die_ref die;
685250397Sobrien     register rtx rtl;
685350397Sobrien{
685450397Sobrien  switch (GET_CODE (rtl))
685550397Sobrien    {
685650397Sobrien    case CONST_INT:
685750397Sobrien      /* Note that a CONST_INT rtx could represent either an integer or a
685850397Sobrien         floating-point constant.  A CONST_INT is used whenever the constant
685950397Sobrien         will fit into a single word.  In all such cases, the original mode
686050397Sobrien         of the constant value is wiped out, and the CONST_INT rtx is
686150397Sobrien         assigned VOIDmode.  */
686250397Sobrien      add_AT_unsigned (die, DW_AT_const_value, (unsigned) INTVAL (rtl));
686350397Sobrien      break;
686450397Sobrien
686550397Sobrien    case CONST_DOUBLE:
686650397Sobrien      /* Note that a CONST_DOUBLE rtx could represent either an integer or a
686750397Sobrien         floating-point constant.  A CONST_DOUBLE is used whenever the
686850397Sobrien         constant requires more than one word in order to be adequately
686950397Sobrien         represented.  We output CONST_DOUBLEs as blocks.  */
687050397Sobrien      {
687150397Sobrien	register enum machine_mode mode = GET_MODE (rtl);
687250397Sobrien
687350397Sobrien	if (GET_MODE_CLASS (mode) == MODE_FLOAT)
687450397Sobrien	  {
687550397Sobrien	    register unsigned length = GET_MODE_SIZE (mode) / sizeof (long);
687650397Sobrien	    long array[4];
687750397Sobrien	    REAL_VALUE_TYPE rv;
687850397Sobrien
687950397Sobrien	    REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
688050397Sobrien	    switch (mode)
688150397Sobrien	      {
688250397Sobrien	      case SFmode:
688350397Sobrien		REAL_VALUE_TO_TARGET_SINGLE (rv, array[0]);
688450397Sobrien		break;
688550397Sobrien
688650397Sobrien	      case DFmode:
688750397Sobrien		REAL_VALUE_TO_TARGET_DOUBLE (rv, array);
688850397Sobrien		break;
688950397Sobrien
689050397Sobrien	      case XFmode:
689150397Sobrien	      case TFmode:
689250397Sobrien		REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, array);
689350397Sobrien		break;
689450397Sobrien
689550397Sobrien	      default:
689650397Sobrien		abort ();
689750397Sobrien	      }
689850397Sobrien
689950397Sobrien	    add_AT_float (die, DW_AT_const_value, length, array);
690050397Sobrien	  }
690150397Sobrien	else
690250397Sobrien	  add_AT_long_long (die, DW_AT_const_value,
690350397Sobrien			    CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
690450397Sobrien      }
690550397Sobrien      break;
690650397Sobrien
690750397Sobrien    case CONST_STRING:
690850397Sobrien      add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0));
690950397Sobrien      break;
691050397Sobrien
691150397Sobrien    case SYMBOL_REF:
691250397Sobrien    case LABEL_REF:
691350397Sobrien    case CONST:
691450397Sobrien      add_AT_addr (die, DW_AT_const_value, addr_to_string (rtl));
691550397Sobrien      break;
691650397Sobrien
691750397Sobrien    case PLUS:
691850397Sobrien      /* In cases where an inlined instance of an inline function is passed
691950397Sobrien         the address of an `auto' variable (which is local to the caller) we
692050397Sobrien         can get a situation where the DECL_RTL of the artificial local
692150397Sobrien         variable (for the inlining) which acts as a stand-in for the
692250397Sobrien         corresponding formal parameter (of the inline function) will look
692350397Sobrien         like (plus:SI (reg:SI FRAME_PTR) (const_int ...)).  This is not
692450397Sobrien         exactly a compile-time constant expression, but it isn't the address
692550397Sobrien         of the (artificial) local variable either.  Rather, it represents the
692650397Sobrien         *value* which the artificial local variable always has during its
692750397Sobrien         lifetime.  We currently have no way to represent such quasi-constant
692850397Sobrien         values in Dwarf, so for now we just punt and generate nothing.  */
692950397Sobrien      break;
693050397Sobrien
693150397Sobrien    default:
693250397Sobrien      /* No other kinds of rtx should be possible here.  */
693350397Sobrien      abort ();
693450397Sobrien    }
693550397Sobrien
693650397Sobrien}
693750397Sobrien
693850397Sobrien/* Generate *either* an DW_AT_location attribute or else an DW_AT_const_value
693950397Sobrien   data attribute for a variable or a parameter.  We generate the
694050397Sobrien   DW_AT_const_value attribute only in those cases where the given variable
694150397Sobrien   or parameter does not have a true "location" either in memory or in a
694250397Sobrien   register.  This can happen (for example) when a constant is passed as an
694350397Sobrien   actual argument in a call to an inline function.  (It's possible that
694450397Sobrien   these things can crop up in other ways also.)  Note that one type of
694550397Sobrien   constant value which can be passed into an inlined function is a constant
694650397Sobrien   pointer.  This can happen for example if an actual argument in an inlined
694750397Sobrien   function call evaluates to a compile-time constant address.  */
694850397Sobrien
694950397Sobrienstatic void
695050397Sobrienadd_location_or_const_value_attribute (die, decl)
695150397Sobrien     register dw_die_ref die;
695250397Sobrien     register tree decl;
695350397Sobrien{
695450397Sobrien  register rtx rtl;
695550397Sobrien  register tree declared_type;
695650397Sobrien  register tree passed_type;
695750397Sobrien
695850397Sobrien  if (TREE_CODE (decl) == ERROR_MARK)
695950397Sobrien    return;
696050397Sobrien
696150397Sobrien  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL)
696250397Sobrien    abort ();
696350397Sobrien
696450397Sobrien  /* Here we have to decide where we are going to say the parameter "lives"
696550397Sobrien     (as far as the debugger is concerned).  We only have a couple of
696650397Sobrien     choices.  GCC provides us with DECL_RTL and with DECL_INCOMING_RTL.
696750397Sobrien
696850397Sobrien     DECL_RTL normally indicates where the parameter lives during most of the
696950397Sobrien     activation of the function.  If optimization is enabled however, this
697050397Sobrien     could be either NULL or else a pseudo-reg.  Both of those cases indicate
697150397Sobrien     that the parameter doesn't really live anywhere (as far as the code
697250397Sobrien     generation parts of GCC are concerned) during most of the function's
697350397Sobrien     activation.  That will happen (for example) if the parameter is never
697450397Sobrien     referenced within the function.
697550397Sobrien
697650397Sobrien     We could just generate a location descriptor here for all non-NULL
697750397Sobrien     non-pseudo values of DECL_RTL and ignore all of the rest, but we can be
697850397Sobrien     a little nicer than that if we also consider DECL_INCOMING_RTL in cases
697950397Sobrien     where DECL_RTL is NULL or is a pseudo-reg.
698050397Sobrien
698150397Sobrien     Note however that we can only get away with using DECL_INCOMING_RTL as
698250397Sobrien     a backup substitute for DECL_RTL in certain limited cases.  In cases
698350397Sobrien     where DECL_ARG_TYPE (decl) indicates the same type as TREE_TYPE (decl),
698450397Sobrien     we can be sure that the parameter was passed using the same type as it is
698550397Sobrien     declared to have within the function, and that its DECL_INCOMING_RTL
698650397Sobrien     points us to a place where a value of that type is passed.
698750397Sobrien
698850397Sobrien     In cases where DECL_ARG_TYPE (decl) and TREE_TYPE (decl) are different,
698950397Sobrien     we cannot (in general) use DECL_INCOMING_RTL as a substitute for DECL_RTL
699050397Sobrien     because in these cases DECL_INCOMING_RTL points us to a value of some
699150397Sobrien     type which is *different* from the type of the parameter itself.  Thus,
699250397Sobrien     if we tried to use DECL_INCOMING_RTL to generate a location attribute in
699350397Sobrien     such cases, the debugger would end up (for example) trying to fetch a
699450397Sobrien     `float' from a place which actually contains the first part of a
699550397Sobrien     `double'.  That would lead to really incorrect and confusing
699650397Sobrien     output at debug-time.
699750397Sobrien
699850397Sobrien     So, in general, we *do not* use DECL_INCOMING_RTL as a backup for DECL_RTL
699950397Sobrien     in cases where DECL_ARG_TYPE (decl) != TREE_TYPE (decl).  There
700050397Sobrien     are a couple of exceptions however.  On little-endian machines we can
700150397Sobrien     get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE (decl) is
700250397Sobrien     not the same as TREE_TYPE (decl), but only when DECL_ARG_TYPE (decl) is
700350397Sobrien     an integral type that is smaller than TREE_TYPE (decl). These cases arise
700450397Sobrien     when (on a little-endian machine) a non-prototyped function has a
700550397Sobrien     parameter declared to be of type `short' or `char'.  In such cases,
700650397Sobrien     TREE_TYPE (decl) will be `short' or `char', DECL_ARG_TYPE (decl) will
700750397Sobrien     be `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the
700850397Sobrien     passed `int' value.  If the debugger then uses that address to fetch
700950397Sobrien     a `short' or a `char' (on a little-endian machine) the result will be
701050397Sobrien     the correct data, so we allow for such exceptional cases below.
701150397Sobrien
701250397Sobrien     Note that our goal here is to describe the place where the given formal
701350397Sobrien     parameter lives during most of the function's activation (i.e. between
701450397Sobrien     the end of the prologue and the start of the epilogue).  We'll do that
701550397Sobrien     as best as we can. Note however that if the given formal parameter is
701650397Sobrien     modified sometime during the execution of the function, then a stack
701750397Sobrien     backtrace (at debug-time) will show the function as having been
701850397Sobrien     called with the *new* value rather than the value which was
701950397Sobrien     originally passed in.  This happens rarely enough that it is not
702050397Sobrien     a major problem, but it *is* a problem, and I'd like to fix it.
702150397Sobrien
702250397Sobrien     A future version of dwarf2out.c may generate two additional
702350397Sobrien     attributes for any given DW_TAG_formal_parameter DIE which will
702450397Sobrien     describe the "passed type" and the "passed location" for the
702550397Sobrien     given formal parameter in addition to the attributes we now
702650397Sobrien     generate to indicate the "declared type" and the "active
702750397Sobrien     location" for each parameter.  This additional set of attributes
702850397Sobrien     could be used by debuggers for stack backtraces. Separately, note
702950397Sobrien     that sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL can be
703050397Sobrien     NULL also.  This happens (for example) for inlined-instances of
703150397Sobrien     inline function formal parameters which are never referenced.
703250397Sobrien     This really shouldn't be happening.  All PARM_DECL nodes should
703350397Sobrien     get valid non-NULL DECL_INCOMING_RTL values, but integrate.c
703450397Sobrien     doesn't currently generate these values for inlined instances of
703550397Sobrien     inline function parameters, so when we see such cases, we are
703650397Sobrien     just out-of-luck for the time being (until integrate.c
703750397Sobrien     gets fixed).  */
703850397Sobrien
703950397Sobrien  /* Use DECL_RTL as the "location" unless we find something better.  */
704050397Sobrien  rtl = DECL_RTL (decl);
704150397Sobrien
704250397Sobrien  if (TREE_CODE (decl) == PARM_DECL)
704350397Sobrien    {
704450397Sobrien      if (rtl == NULL_RTX || is_pseudo_reg (rtl))
704550397Sobrien	{
704650397Sobrien	  declared_type = type_main_variant (TREE_TYPE (decl));
704750397Sobrien	  passed_type = type_main_variant (DECL_ARG_TYPE (decl));
704850397Sobrien
704950397Sobrien	  /* This decl represents a formal parameter which was optimized out.
705050397Sobrien	     Note that DECL_INCOMING_RTL may be NULL in here, but we handle
705150397Sobrien	     all* cases where (rtl == NULL_RTX) just below.  */
705250397Sobrien	  if (declared_type == passed_type)
705350397Sobrien	    rtl = DECL_INCOMING_RTL (decl);
705450397Sobrien	  else if (! BYTES_BIG_ENDIAN
705550397Sobrien		   && TREE_CODE (declared_type) == INTEGER_TYPE
705650397Sobrien		   && TYPE_SIZE (declared_type) <= TYPE_SIZE (passed_type))
705750397Sobrien		rtl = DECL_INCOMING_RTL (decl);
705850397Sobrien	}
705950397Sobrien    }
706050397Sobrien
706150397Sobrien  if (rtl == NULL_RTX)
706250397Sobrien    return;
706350397Sobrien
706450397Sobrien  rtl = eliminate_regs (rtl, 0, NULL_RTX);
706550397Sobrien#ifdef LEAF_REG_REMAP
706650397Sobrien  if (leaf_function)
706750397Sobrien    leaf_renumber_regs_insn (rtl);
706850397Sobrien#endif
706950397Sobrien
707050397Sobrien  switch (GET_CODE (rtl))
707150397Sobrien    {
707250397Sobrien    case ADDRESSOF:
707350397Sobrien      /* The address of a variable that was optimized away; don't emit
707450397Sobrien	 anything.  */
707550397Sobrien      break;
707650397Sobrien
707750397Sobrien    case CONST_INT:
707850397Sobrien    case CONST_DOUBLE:
707950397Sobrien    case CONST_STRING:
708050397Sobrien    case SYMBOL_REF:
708150397Sobrien    case LABEL_REF:
708250397Sobrien    case CONST:
708350397Sobrien    case PLUS:
708450397Sobrien      /* DECL_RTL could be (plus (reg ...) (const_int ...)) */
708550397Sobrien      add_const_value_attribute (die, rtl);
708650397Sobrien      break;
708750397Sobrien
708850397Sobrien    case MEM:
708950397Sobrien    case REG:
709050397Sobrien    case SUBREG:
709150397Sobrien    case CONCAT:
709250397Sobrien      add_AT_location_description (die, DW_AT_location, rtl);
709350397Sobrien      break;
709450397Sobrien
709550397Sobrien    default:
709650397Sobrien      abort ();
709750397Sobrien    }
709850397Sobrien}
709950397Sobrien
710050397Sobrien/* Generate an DW_AT_name attribute given some string value to be included as
710150397Sobrien   the value of the attribute.  */
710250397Sobrien
710350397Sobrienstatic inline void
710450397Sobrienadd_name_attribute (die, name_string)
710550397Sobrien     register dw_die_ref die;
710650397Sobrien     register char *name_string;
710750397Sobrien{
710850397Sobrien  if (name_string != NULL && *name_string != 0)
710950397Sobrien    add_AT_string (die, DW_AT_name, name_string);
711050397Sobrien}
711150397Sobrien
711250397Sobrien/* Given a tree node describing an array bound (either lower or upper) output
711350397Sobrien   a representation for that bound.  */
711450397Sobrien
711550397Sobrienstatic void
711650397Sobrienadd_bound_info (subrange_die, bound_attr, bound)
711750397Sobrien     register dw_die_ref subrange_die;
711850397Sobrien     register enum dwarf_attribute bound_attr;
711950397Sobrien     register tree bound;
712050397Sobrien{
712150397Sobrien  register unsigned bound_value = 0;
712250397Sobrien
712350397Sobrien  /* If this is an Ada unconstrained array type, then don't emit any debug
712450397Sobrien     info because the array bounds are unknown.  They are parameterized when
712550397Sobrien     the type is instantiated.  */
712650397Sobrien  if (contains_placeholder_p (bound))
712750397Sobrien    return;
712850397Sobrien
712950397Sobrien  switch (TREE_CODE (bound))
713050397Sobrien    {
713150397Sobrien    case ERROR_MARK:
713250397Sobrien      return;
713350397Sobrien
713450397Sobrien    /* All fixed-bounds are represented by INTEGER_CST nodes.        */
713550397Sobrien    case INTEGER_CST:
713650397Sobrien      bound_value = TREE_INT_CST_LOW (bound);
713750397Sobrien      if (bound_attr == DW_AT_lower_bound
713850397Sobrien	  && ((is_c_family () && bound_value == 0)
713950397Sobrien	      || (is_fortran () && bound_value == 1)))
714050397Sobrien	/* use the default */;
714150397Sobrien      else
714250397Sobrien	add_AT_unsigned (subrange_die, bound_attr, bound_value);
714350397Sobrien      break;
714450397Sobrien
714550397Sobrien    case CONVERT_EXPR:
714650397Sobrien    case NOP_EXPR:
714750397Sobrien    case NON_LVALUE_EXPR:
714850397Sobrien      add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
714950397Sobrien      break;
715050397Sobrien
715150397Sobrien    case SAVE_EXPR:
715250397Sobrien      /* If optimization is turned on, the SAVE_EXPRs that describe how to
715350397Sobrien         access the upper bound values may be bogus.  If they refer to a
715450397Sobrien         register, they may only describe how to get at these values at the
715550397Sobrien         points in the generated code right after they have just been
715650397Sobrien         computed.  Worse yet, in the typical case, the upper bound values
715750397Sobrien         will not even *be* computed in the optimized code (though the
715850397Sobrien         number of elements will), so these SAVE_EXPRs are entirely
715950397Sobrien         bogus. In order to compensate for this fact, we check here to see
716050397Sobrien         if optimization is enabled, and if so, we don't add an attribute
716150397Sobrien         for the (unknown and unknowable) upper bound.  This should not
716250397Sobrien         cause too much trouble for existing (stupid?)  debuggers because
716350397Sobrien         they have to deal with empty upper bounds location descriptions
716450397Sobrien         anyway in order to be able to deal with incomplete array types.
716550397Sobrien         Of course an intelligent debugger (GDB?)  should be able to
716650397Sobrien         comprehend that a missing upper bound specification in a array
716750397Sobrien         type used for a storage class `auto' local array variable
716850397Sobrien         indicates that the upper bound is both unknown (at compile- time)
716950397Sobrien         and unknowable (at run-time) due to optimization.
717050397Sobrien
717150397Sobrien	 We assume that a MEM rtx is safe because gcc wouldn't put the
717250397Sobrien	 value there unless it was going to be used repeatedly in the
717350397Sobrien	 function, i.e. for cleanups.  */
717450397Sobrien      if (! optimize || GET_CODE (SAVE_EXPR_RTL (bound)) == MEM)
717550397Sobrien	{
717650397Sobrien	  register dw_die_ref ctx = lookup_decl_die (current_function_decl);
717750397Sobrien	  register dw_die_ref decl_die = new_die (DW_TAG_variable, ctx);
717850397Sobrien	  register rtx loc = SAVE_EXPR_RTL (bound);
717950397Sobrien
718050397Sobrien	  /* If the RTL for the SAVE_EXPR is memory, handle the case where
718150397Sobrien	     it references an outer function's frame.  */
718250397Sobrien
718350397Sobrien	  if (GET_CODE (loc) == MEM)
718450397Sobrien	    {
718550397Sobrien	      rtx new_addr = fix_lexical_addr (XEXP (loc, 0), bound);
718650397Sobrien
718750397Sobrien	      if (XEXP (loc, 0) != new_addr)
718850397Sobrien		loc = gen_rtx (MEM, GET_MODE (loc), new_addr);
718950397Sobrien	    }
719050397Sobrien
719150397Sobrien	  add_AT_flag (decl_die, DW_AT_artificial, 1);
719250397Sobrien	  add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
719350397Sobrien	  add_AT_location_description (decl_die, DW_AT_location, loc);
719450397Sobrien	  add_AT_die_ref (subrange_die, bound_attr, decl_die);
719550397Sobrien	}
719650397Sobrien
719750397Sobrien      /* Else leave out the attribute.  */
719850397Sobrien      break;
719950397Sobrien
720050397Sobrien    case MAX_EXPR:
720150397Sobrien    case VAR_DECL:
720250397Sobrien    case COMPONENT_REF:
720350397Sobrien      /* ??? These types of bounds can be created by the Ada front end,
720450397Sobrien	 and it isn't clear how to emit debug info for them.  */
720550397Sobrien      break;
720650397Sobrien
720750397Sobrien    default:
720850397Sobrien      abort ();
720950397Sobrien    }
721050397Sobrien}
721150397Sobrien
721250397Sobrien/* Note that the block of subscript information for an array type also
721350397Sobrien   includes information about the element type of type given array type.  */
721450397Sobrien
721550397Sobrienstatic void
721650397Sobrienadd_subscript_info (type_die, type)
721750397Sobrien     register dw_die_ref type_die;
721850397Sobrien     register tree type;
721950397Sobrien{
722050397Sobrien#ifndef MIPS_DEBUGGING_INFO
722150397Sobrien  register unsigned dimension_number;
722250397Sobrien#endif
722350397Sobrien  register tree lower, upper;
722450397Sobrien  register dw_die_ref subrange_die;
722550397Sobrien
722650397Sobrien  /* The GNU compilers represent multidimensional array types as sequences of
722750397Sobrien     one dimensional array types whose element types are themselves array
722850397Sobrien     types.  Here we squish that down, so that each multidimensional array
722950397Sobrien     type gets only one array_type DIE in the Dwarf debugging info. The draft
723050397Sobrien     Dwarf specification say that we are allowed to do this kind of
723150397Sobrien     compression in C (because there is no difference between an array or
723250397Sobrien     arrays and a multidimensional array in C) but for other source languages
723350397Sobrien     (e.g. Ada) we probably shouldn't do this.  */
723450397Sobrien
723550397Sobrien  /* ??? The SGI dwarf reader fails for multidimensional arrays with a
723650397Sobrien     const enum type.  E.g. const enum machine_mode insn_operand_mode[2][10].
723750397Sobrien     We work around this by disabling this feature.  See also
723850397Sobrien     gen_array_type_die.  */
723950397Sobrien#ifndef MIPS_DEBUGGING_INFO
724050397Sobrien  for (dimension_number = 0;
724150397Sobrien       TREE_CODE (type) == ARRAY_TYPE;
724250397Sobrien       type = TREE_TYPE (type), dimension_number++)
724350397Sobrien    {
724450397Sobrien#endif
724550397Sobrien      register tree domain = TYPE_DOMAIN (type);
724650397Sobrien
724750397Sobrien      /* Arrays come in three flavors: Unspecified bounds, fixed bounds,
724850397Sobrien	 and (in GNU C only) variable bounds.  Handle all three forms
724950397Sobrien         here.  */
725050397Sobrien      subrange_die = new_die (DW_TAG_subrange_type, type_die);
725150397Sobrien      if (domain)
725250397Sobrien	{
725350397Sobrien	  /* We have an array type with specified bounds.  */
725450397Sobrien	  lower = TYPE_MIN_VALUE (domain);
725550397Sobrien	  upper = TYPE_MAX_VALUE (domain);
725650397Sobrien
725750397Sobrien	  /* define the index type.  */
725850397Sobrien	  if (TREE_TYPE (domain))
725950397Sobrien	    {
726050397Sobrien	      /* ??? This is probably an Ada unnamed subrange type.  Ignore the
726150397Sobrien		 TREE_TYPE field.  We can't emit debug info for this
726250397Sobrien		 because it is an unnamed integral type.  */
726350397Sobrien	      if (TREE_CODE (domain) == INTEGER_TYPE
726450397Sobrien		  && TYPE_NAME (domain) == NULL_TREE
726550397Sobrien		  && TREE_CODE (TREE_TYPE (domain)) == INTEGER_TYPE
726650397Sobrien		  && TYPE_NAME (TREE_TYPE (domain)) == NULL_TREE)
726750397Sobrien		;
726850397Sobrien	      else
726950397Sobrien		add_type_attribute (subrange_die, TREE_TYPE (domain), 0, 0,
727050397Sobrien				    type_die);
727150397Sobrien	    }
727250397Sobrien
727350397Sobrien	  /* ??? If upper is NULL, the array has unspecified length,
727450397Sobrien	     but it does have a lower bound.  This happens with Fortran
727550397Sobrien	       dimension arr(N:*)
727650397Sobrien       	     Since the debugger is definitely going to need to know N
727750397Sobrien	     to produce useful results, go ahead and output the lower
727850397Sobrien	     bound solo, and hope the debugger can cope.  */
727950397Sobrien
728050397Sobrien	  add_bound_info (subrange_die, DW_AT_lower_bound, lower);
728150397Sobrien	  if (upper)
728250397Sobrien	    add_bound_info (subrange_die, DW_AT_upper_bound, upper);
728350397Sobrien	}
728450397Sobrien      else
728550397Sobrien	/* We have an array type with an unspecified length.  The DWARF-2
728650397Sobrien	     spec does not say how to handle this; let's just leave out the
728750397Sobrien	     bounds.  */
728850397Sobrien	{;}
728950397Sobrien
729050397Sobrien
729150397Sobrien#ifndef MIPS_DEBUGGING_INFO
729250397Sobrien    }
729350397Sobrien#endif
729450397Sobrien}
729550397Sobrien
729650397Sobrienstatic void
729750397Sobrienadd_byte_size_attribute (die, tree_node)
729850397Sobrien     dw_die_ref die;
729950397Sobrien     register tree tree_node;
730050397Sobrien{
730150397Sobrien  register unsigned size;
730250397Sobrien
730350397Sobrien  switch (TREE_CODE (tree_node))
730450397Sobrien    {
730550397Sobrien    case ERROR_MARK:
730650397Sobrien      size = 0;
730750397Sobrien      break;
730850397Sobrien    case ENUMERAL_TYPE:
730950397Sobrien    case RECORD_TYPE:
731050397Sobrien    case UNION_TYPE:
731150397Sobrien    case QUAL_UNION_TYPE:
731250397Sobrien      size = int_size_in_bytes (tree_node);
731350397Sobrien      break;
731450397Sobrien    case FIELD_DECL:
731550397Sobrien      /* For a data member of a struct or union, the DW_AT_byte_size is
731650397Sobrien         generally given as the number of bytes normally allocated for an
731750397Sobrien         object of the *declared* type of the member itself.  This is true
731850397Sobrien         even for bit-fields.  */
731950397Sobrien      size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
732050397Sobrien      break;
732150397Sobrien    default:
732250397Sobrien      abort ();
732350397Sobrien    }
732450397Sobrien
732550397Sobrien  /* Note that `size' might be -1 when we get to this point.  If it is, that
732650397Sobrien     indicates that the byte size of the entity in question is variable.  We
732750397Sobrien     have no good way of expressing this fact in Dwarf at the present time,
732850397Sobrien     so just let the -1 pass on through.  */
732950397Sobrien
733050397Sobrien  add_AT_unsigned (die, DW_AT_byte_size, size);
733150397Sobrien}
733250397Sobrien
733350397Sobrien/* For a FIELD_DECL node which represents a bit-field, output an attribute
733450397Sobrien   which specifies the distance in bits from the highest order bit of the
733550397Sobrien   "containing object" for the bit-field to the highest order bit of the
733650397Sobrien   bit-field itself.
733750397Sobrien
733850397Sobrien   For any given bit-field, the "containing object" is a hypothetical
733950397Sobrien   object (of some integral or enum type) within which the given bit-field
734050397Sobrien   lives.  The type of this hypothetical "containing object" is always the
734150397Sobrien   same as the declared type of the individual bit-field itself.  The
734250397Sobrien   determination of the exact location of the "containing object" for a
734350397Sobrien   bit-field is rather complicated.  It's handled by the
734450397Sobrien   `field_byte_offset' function (above).
734550397Sobrien
734650397Sobrien   Note that it is the size (in bytes) of the hypothetical "containing object"
734750397Sobrien   which will be given in the DW_AT_byte_size attribute for this bit-field.
734850397Sobrien   (See `byte_size_attribute' above).  */
734950397Sobrien
735050397Sobrienstatic inline void
735150397Sobrienadd_bit_offset_attribute (die, decl)
735250397Sobrien     register dw_die_ref die;
735350397Sobrien     register tree decl;
735450397Sobrien{
735550397Sobrien  register unsigned object_offset_in_bytes = field_byte_offset (decl);
735650397Sobrien  register tree type = DECL_BIT_FIELD_TYPE (decl);
735750397Sobrien  register tree bitpos_tree = DECL_FIELD_BITPOS (decl);
735850397Sobrien  register unsigned bitpos_int;
735950397Sobrien  register unsigned highest_order_object_bit_offset;
736050397Sobrien  register unsigned highest_order_field_bit_offset;
736150397Sobrien  register unsigned bit_offset;
736250397Sobrien
736350397Sobrien  /* Must be a field and a bit field.  */
736450397Sobrien  if (!type
736550397Sobrien      || TREE_CODE (decl) != FIELD_DECL)
736650397Sobrien    abort ();
736750397Sobrien
736850397Sobrien  /* We can't yet handle bit-fields whose offsets are variable, so if we
736950397Sobrien     encounter such things, just return without generating any attribute
737050397Sobrien     whatsoever.  */
737150397Sobrien  if (TREE_CODE (bitpos_tree) != INTEGER_CST)
737250397Sobrien    return;
737350397Sobrien
737450397Sobrien  bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree);
737550397Sobrien
737650397Sobrien  /* Note that the bit offset is always the distance (in bits) from the
737750397Sobrien     highest-order bit of the "containing object" to the highest-order bit of
737850397Sobrien     the bit-field itself.  Since the "high-order end" of any object or field
737950397Sobrien     is different on big-endian and little-endian machines, the computation
738050397Sobrien     below must take account of these differences.  */
738150397Sobrien  highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT;
738250397Sobrien  highest_order_field_bit_offset = bitpos_int;
738350397Sobrien
738450397Sobrien  if (! BYTES_BIG_ENDIAN)
738550397Sobrien    {
738650397Sobrien      highest_order_field_bit_offset
738750397Sobrien	+= (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl));
738850397Sobrien
738950397Sobrien      highest_order_object_bit_offset += simple_type_size_in_bits (type);
739050397Sobrien    }
739150397Sobrien
739250397Sobrien  bit_offset
739350397Sobrien    = (! BYTES_BIG_ENDIAN
739450397Sobrien       ? highest_order_object_bit_offset - highest_order_field_bit_offset
739550397Sobrien       : highest_order_field_bit_offset - highest_order_object_bit_offset);
739650397Sobrien
739750397Sobrien  add_AT_unsigned (die, DW_AT_bit_offset, bit_offset);
739850397Sobrien}
739950397Sobrien
740050397Sobrien/* For a FIELD_DECL node which represents a bit field, output an attribute
740150397Sobrien   which specifies the length in bits of the given field.  */
740250397Sobrien
740350397Sobrienstatic inline void
740450397Sobrienadd_bit_size_attribute (die, decl)
740550397Sobrien     register dw_die_ref die;
740650397Sobrien     register tree decl;
740750397Sobrien{
740850397Sobrien  /* Must be a field and a bit field.  */
740950397Sobrien  if (TREE_CODE (decl) != FIELD_DECL
741050397Sobrien      || ! DECL_BIT_FIELD_TYPE (decl))
741150397Sobrien    abort ();
741250397Sobrien  add_AT_unsigned (die, DW_AT_bit_size,
741350397Sobrien		   (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl)));
741450397Sobrien}
741550397Sobrien
741650397Sobrien/* If the compiled language is ANSI C, then add a 'prototyped'
741750397Sobrien   attribute, if arg types are given for the parameters of a function.  */
741850397Sobrien
741950397Sobrienstatic inline void
742050397Sobrienadd_prototyped_attribute (die, func_type)
742150397Sobrien     register dw_die_ref die;
742250397Sobrien     register tree func_type;
742350397Sobrien{
742450397Sobrien  if (get_AT_unsigned (comp_unit_die, DW_AT_language) == DW_LANG_C89
742550397Sobrien      && TYPE_ARG_TYPES (func_type) != NULL)
742650397Sobrien    add_AT_flag (die, DW_AT_prototyped, 1);
742750397Sobrien}
742850397Sobrien
742950397Sobrien
743050397Sobrien/* Add an 'abstract_origin' attribute below a given DIE.  The DIE is found
743150397Sobrien   by looking in either the type declaration or object declaration
743250397Sobrien   equate table.  */
743350397Sobrien
743450397Sobrienstatic inline void
743550397Sobrienadd_abstract_origin_attribute (die, origin)
743650397Sobrien     register dw_die_ref die;
743750397Sobrien     register tree origin;
743850397Sobrien{
743950397Sobrien  dw_die_ref origin_die = NULL;
744050397Sobrien  if (TREE_CODE_CLASS (TREE_CODE (origin)) == 'd')
744150397Sobrien    origin_die = lookup_decl_die (origin);
744250397Sobrien  else if (TREE_CODE_CLASS (TREE_CODE (origin)) == 't')
744350397Sobrien    origin_die = lookup_type_die (origin);
744450397Sobrien
744550397Sobrien  add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
744650397Sobrien}
744750397Sobrien
744850397Sobrien/* We do not currently support the pure_virtual attribute.  */
744950397Sobrien
745050397Sobrienstatic inline void
745150397Sobrienadd_pure_or_virtual_attribute (die, func_decl)
745250397Sobrien     register dw_die_ref die;
745350397Sobrien     register tree func_decl;
745450397Sobrien{
745550397Sobrien  if (DECL_VINDEX (func_decl))
745650397Sobrien    {
745750397Sobrien      add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
745850397Sobrien      add_AT_loc (die, DW_AT_vtable_elem_location,
745950397Sobrien		  new_loc_descr (DW_OP_constu,
746050397Sobrien				 TREE_INT_CST_LOW (DECL_VINDEX (func_decl)),
746150397Sobrien				 0));
746250397Sobrien
746350397Sobrien      /* GNU extension: Record what type this method came from originally.  */
746450397Sobrien      if (debug_info_level > DINFO_LEVEL_TERSE)
746550397Sobrien	add_AT_die_ref (die, DW_AT_containing_type,
746650397Sobrien			lookup_type_die (DECL_CONTEXT (func_decl)));
746750397Sobrien    }
746850397Sobrien}
746950397Sobrien
747050397Sobrien/* Add source coordinate attributes for the given decl.  */
747150397Sobrien
747250397Sobrienstatic void
747350397Sobrienadd_src_coords_attributes (die, decl)
747450397Sobrien     register dw_die_ref die;
747550397Sobrien     register tree decl;
747650397Sobrien{
747750397Sobrien  register unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl));
747850397Sobrien
747950397Sobrien  add_AT_unsigned (die, DW_AT_decl_file, file_index);
748050397Sobrien  add_AT_unsigned (die, DW_AT_decl_line, DECL_SOURCE_LINE (decl));
748150397Sobrien}
748250397Sobrien
748350397Sobrien/* Add an DW_AT_name attribute and source coordinate attribute for the
748450397Sobrien   given decl, but only if it actually has a name.  */
748550397Sobrien
748650397Sobrienstatic void
748750397Sobrienadd_name_and_src_coords_attributes (die, decl)
748850397Sobrien     register dw_die_ref die;
748950397Sobrien     register tree decl;
749050397Sobrien{
749150397Sobrien  register tree decl_name;
749250397Sobrien
749350397Sobrien  decl_name = DECL_NAME (decl);
749450397Sobrien  if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL)
749550397Sobrien    {
749650397Sobrien      add_name_attribute (die, dwarf2_name (decl, 0));
749750397Sobrien      add_src_coords_attributes (die, decl);
749850397Sobrien      if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
749950397Sobrien	  && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
750050397Sobrien	add_AT_string (die, DW_AT_MIPS_linkage_name,
750150397Sobrien		       IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
750250397Sobrien    }
750350397Sobrien}
750450397Sobrien
750550397Sobrien/* Push a new declaration scope. */
750650397Sobrien
750750397Sobrienstatic void
750850397Sobrienpush_decl_scope (scope)
750950397Sobrien     tree scope;
751050397Sobrien{
751150397Sobrien  tree containing_scope;
751250397Sobrien  int i;
751350397Sobrien
751450397Sobrien  /* Make room in the decl_scope_table, if necessary.  */
751550397Sobrien  if (decl_scope_table_allocated == decl_scope_depth)
751650397Sobrien    {
751750397Sobrien      decl_scope_table_allocated += DECL_SCOPE_TABLE_INCREMENT;
751850397Sobrien      decl_scope_table
751950397Sobrien	= (decl_scope_node *) xrealloc (decl_scope_table,
752050397Sobrien					(decl_scope_table_allocated
752150397Sobrien					 * sizeof (decl_scope_node)));
752250397Sobrien    }
752350397Sobrien
752450397Sobrien  decl_scope_table[decl_scope_depth].scope = scope;
752550397Sobrien
752650397Sobrien  /* Sometimes, while recursively emitting subtypes within a class type,
752750397Sobrien     we end up recuring on a subtype at a higher level then the current
752850397Sobrien     subtype.  In such a case, we need to search the decl_scope_table to
752950397Sobrien     find the parent of this subtype.  */
753050397Sobrien
753150397Sobrien  if (TREE_CODE_CLASS (TREE_CODE (scope)) == 't')
753250397Sobrien    containing_scope = TYPE_CONTEXT (scope);
753350397Sobrien  else
753450397Sobrien    containing_scope = NULL_TREE;
753550397Sobrien
753650397Sobrien  /* The normal case.  */
753750397Sobrien  if (decl_scope_depth == 0
753850397Sobrien      || containing_scope == NULL_TREE
753950397Sobrien      /* Ignore namespaces for the moment.  */
754050397Sobrien      || TREE_CODE (containing_scope) == NAMESPACE_DECL
754150397Sobrien      || containing_scope == decl_scope_table[decl_scope_depth - 1].scope)
754250397Sobrien    decl_scope_table[decl_scope_depth].previous = decl_scope_depth - 1;
754350397Sobrien  else
754450397Sobrien    {
754550397Sobrien      /* We need to search for the containing_scope.  */
754650397Sobrien      for (i = 0; i < decl_scope_depth; i++)
754750397Sobrien	if (decl_scope_table[i].scope == containing_scope)
754850397Sobrien	  break;
754950397Sobrien
755050397Sobrien      if (i == decl_scope_depth)
755150397Sobrien	abort ();
755250397Sobrien      else
755350397Sobrien	decl_scope_table[decl_scope_depth].previous = i;
755450397Sobrien    }
755550397Sobrien
755650397Sobrien  decl_scope_depth++;
755750397Sobrien}
755850397Sobrien
755950397Sobrien/* Return the DIE for the scope that immediately contains this declaration.  */
756050397Sobrien
756150397Sobrienstatic dw_die_ref
756250397Sobrienscope_die_for (t, context_die)
756350397Sobrien    register tree t;
756450397Sobrien    register dw_die_ref context_die;
756550397Sobrien{
756650397Sobrien  register dw_die_ref scope_die = NULL;
756750397Sobrien  register tree containing_scope;
756850397Sobrien  register int i;
756950397Sobrien
757050397Sobrien  /* Walk back up the declaration tree looking for a place to define
757150397Sobrien     this type.  */
757250397Sobrien  if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
757350397Sobrien    containing_scope = TYPE_CONTEXT (t);
757450397Sobrien  else if (TREE_CODE (t) == FUNCTION_DECL && DECL_VINDEX (t))
757550397Sobrien    containing_scope = decl_class_context (t);
757650397Sobrien  else
757750397Sobrien    containing_scope = DECL_CONTEXT (t);
757850397Sobrien
757950397Sobrien  /* Ignore namespaces for the moment.  */
758050397Sobrien  if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL)
758150397Sobrien    containing_scope = NULL_TREE;
758250397Sobrien
758350397Sobrien  /* Function-local tags and functions get stuck in limbo until they are
758450397Sobrien     fixed up by decls_for_scope.  */
758550397Sobrien  if (context_die == NULL && containing_scope != NULL_TREE
758650397Sobrien      && (TREE_CODE (t) == FUNCTION_DECL || is_tagged_type (t)))
758750397Sobrien    return NULL;
758850397Sobrien
758950397Sobrien  if (containing_scope == NULL_TREE)
759050397Sobrien    scope_die = comp_unit_die;
759150397Sobrien  else
759250397Sobrien    {
759350397Sobrien      for (i = decl_scope_depth - 1, scope_die = context_die;
759450397Sobrien	   i >= 0 && decl_scope_table[i].scope != containing_scope;
759550397Sobrien	   (scope_die = scope_die->die_parent,
759650397Sobrien	    i = decl_scope_table[i].previous))
759750397Sobrien	;
759850397Sobrien
759950397Sobrien      /* ??? Integrate_decl_tree does not handle BLOCK_TYPE_TAGS, nor
760050397Sobrien	 does it try to handle types defined by TYPE_DECLs.  Such types
760150397Sobrien	 thus have an incorrect TYPE_CONTEXT, which points to the block
760250397Sobrien	 they were originally defined in, instead of the current block
760350397Sobrien	 created by function inlining.  We try to detect that here and
760450397Sobrien	 work around it.  */
760550397Sobrien
760650397Sobrien      if (i < 0 && scope_die == comp_unit_die
760750397Sobrien	  && TREE_CODE (containing_scope) == BLOCK
760850397Sobrien	  && is_tagged_type (t)
760950397Sobrien	  && (block_ultimate_origin (decl_scope_table[decl_scope_depth - 1].scope)
761050397Sobrien	      == containing_scope))
761150397Sobrien	{
761250397Sobrien	  scope_die = context_die;
761350397Sobrien	  /* Since the checks below are no longer applicable.  */
761450397Sobrien	  i = 0;
761550397Sobrien	}
761650397Sobrien
761750397Sobrien      if (i < 0)
761850397Sobrien	{
761950397Sobrien	  if (scope_die != comp_unit_die
762050397Sobrien	      || TREE_CODE_CLASS (TREE_CODE (containing_scope)) != 't')
762150397Sobrien	    abort ();
762250397Sobrien	  if (debug_info_level > DINFO_LEVEL_TERSE
762350397Sobrien	      && !TREE_ASM_WRITTEN (containing_scope))
762450397Sobrien	    abort ();
762550397Sobrien	}
762650397Sobrien    }
762750397Sobrien
762850397Sobrien  return scope_die;
762950397Sobrien}
763050397Sobrien
763150397Sobrien/* Pop a declaration scope.  */
763250397Sobrienstatic inline void
763350397Sobrienpop_decl_scope ()
763450397Sobrien{
763550397Sobrien  if (decl_scope_depth <= 0)
763650397Sobrien    abort ();
763750397Sobrien  --decl_scope_depth;
763850397Sobrien}
763950397Sobrien
764050397Sobrien/* Many forms of DIEs require a "type description" attribute.  This
764150397Sobrien   routine locates the proper "type descriptor" die for the type given
764250397Sobrien   by 'type', and adds an DW_AT_type attribute below the given die.  */
764350397Sobrien
764450397Sobrienstatic void
764550397Sobrienadd_type_attribute (object_die, type, decl_const, decl_volatile, context_die)
764650397Sobrien     register dw_die_ref object_die;
764750397Sobrien     register tree type;
764850397Sobrien     register int decl_const;
764950397Sobrien     register int decl_volatile;
765050397Sobrien     register dw_die_ref context_die;
765150397Sobrien{
765250397Sobrien  register enum tree_code code  = TREE_CODE (type);
765350397Sobrien  register dw_die_ref type_die  = NULL;
765450397Sobrien
765550397Sobrien  /* ??? If this type is an unnamed subrange type of an integral or
765650397Sobrien     floating-point type, use the inner type.  This is because we have no
765750397Sobrien     support for unnamed types in base_type_die.  This can happen if this is
765850397Sobrien     an Ada subrange type.  Correct solution is emit a subrange type die.  */
765950397Sobrien  if ((code == INTEGER_TYPE || code == REAL_TYPE)
766050397Sobrien      && TREE_TYPE (type) != 0 && TYPE_NAME (type) == 0)
766150397Sobrien    type = TREE_TYPE (type), code = TREE_CODE (type);
766250397Sobrien
766350397Sobrien  if (code == ERROR_MARK)
766450397Sobrien    return;
766550397Sobrien
766650397Sobrien  /* Handle a special case.  For functions whose return type is void, we
766750397Sobrien     generate *no* type attribute.  (Note that no object may have type
766850397Sobrien     `void', so this only applies to function return types).  */
766950397Sobrien  if (code == VOID_TYPE)
767050397Sobrien    return;
767150397Sobrien
767250397Sobrien  type_die = modified_type_die (type,
767350397Sobrien				decl_const || TYPE_READONLY (type),
767450397Sobrien				decl_volatile || TYPE_VOLATILE (type),
767550397Sobrien				context_die);
767650397Sobrien  if (type_die != NULL)
767750397Sobrien    add_AT_die_ref (object_die, DW_AT_type, type_die);
767850397Sobrien}
767950397Sobrien
768050397Sobrien/* Given a tree pointer to a struct, class, union, or enum type node, return
768150397Sobrien   a pointer to the (string) tag name for the given type, or zero if the type
768250397Sobrien   was declared without a tag.  */
768350397Sobrien
768450397Sobrienstatic char *
768550397Sobrientype_tag (type)
768650397Sobrien     register tree type;
768750397Sobrien{
768850397Sobrien  register char *name = 0;
768950397Sobrien
769050397Sobrien  if (TYPE_NAME (type) != 0)
769150397Sobrien    {
769250397Sobrien      register tree t = 0;
769350397Sobrien
769450397Sobrien      /* Find the IDENTIFIER_NODE for the type name.  */
769550397Sobrien      if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
769650397Sobrien	t = TYPE_NAME (type);
769750397Sobrien
769850397Sobrien      /* The g++ front end makes the TYPE_NAME of *each* tagged type point to
769950397Sobrien         a TYPE_DECL node, regardless of whether or not a `typedef' was
770050397Sobrien         involved.  */
770150397Sobrien      else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
770250397Sobrien	       && ! DECL_IGNORED_P (TYPE_NAME (type)))
770350397Sobrien	t = DECL_NAME (TYPE_NAME (type));
770450397Sobrien
770550397Sobrien      /* Now get the name as a string, or invent one.  */
770650397Sobrien      if (t != 0)
770750397Sobrien	name = IDENTIFIER_POINTER (t);
770850397Sobrien    }
770950397Sobrien
771050397Sobrien  return (name == 0 || *name == '\0') ? 0 : name;
771150397Sobrien}
771250397Sobrien
771350397Sobrien/* Return the type associated with a data member, make a special check
771450397Sobrien   for bit field types.  */
771550397Sobrien
771650397Sobrienstatic inline tree
771750397Sobrienmember_declared_type (member)
771850397Sobrien     register tree member;
771950397Sobrien{
772050397Sobrien  return (DECL_BIT_FIELD_TYPE (member)
772150397Sobrien	  ? DECL_BIT_FIELD_TYPE (member)
772250397Sobrien	  : TREE_TYPE (member));
772350397Sobrien}
772450397Sobrien
772550397Sobrien/* Get the decl's label, as described by its RTL. This may be different
772650397Sobrien   from the DECL_NAME name used in the source file.  */
772750397Sobrien
772850397Sobrien#if 0
772950397Sobrienstatic char *
773050397Sobriendecl_start_label (decl)
773150397Sobrien     register tree decl;
773250397Sobrien{
773350397Sobrien  rtx x;
773450397Sobrien  char *fnname;
773550397Sobrien  x = DECL_RTL (decl);
773650397Sobrien  if (GET_CODE (x) != MEM)
773750397Sobrien    abort ();
773850397Sobrien
773950397Sobrien  x = XEXP (x, 0);
774050397Sobrien  if (GET_CODE (x) != SYMBOL_REF)
774150397Sobrien    abort ();
774250397Sobrien
774350397Sobrien  fnname = XSTR (x, 0);
774450397Sobrien  return fnname;
774550397Sobrien}
774650397Sobrien#endif
774750397Sobrien
774850397Sobrien/* These routines generate the internal representation of the DIE's for
774950397Sobrien   the compilation unit.  Debugging information is collected by walking
775050397Sobrien   the declaration trees passed in from dwarf2out_decl().  */
775150397Sobrien
775250397Sobrienstatic void
775350397Sobriengen_array_type_die (type, context_die)
775450397Sobrien     register tree type;
775550397Sobrien     register dw_die_ref context_die;
775650397Sobrien{
775750397Sobrien  register dw_die_ref scope_die = scope_die_for (type, context_die);
775850397Sobrien  register dw_die_ref array_die;
775950397Sobrien  register tree element_type;
776050397Sobrien
776150397Sobrien  /* ??? The SGI dwarf reader fails for array of array of enum types unless
776250397Sobrien     the inner array type comes before the outer array type.  Thus we must
776350397Sobrien     call gen_type_die before we call new_die.  See below also.  */
776450397Sobrien#ifdef MIPS_DEBUGGING_INFO
776550397Sobrien  gen_type_die (TREE_TYPE (type), context_die);
776650397Sobrien#endif
776750397Sobrien
776850397Sobrien  array_die = new_die (DW_TAG_array_type, scope_die);
776950397Sobrien
777050397Sobrien#if 0
777150397Sobrien  /* We default the array ordering.  SDB will probably do
777250397Sobrien     the right things even if DW_AT_ordering is not present.  It's not even
777350397Sobrien     an issue until we start to get into multidimensional arrays anyway.  If
777450397Sobrien     SDB is ever caught doing the Wrong Thing for multi-dimensional arrays,
777550397Sobrien     then we'll have to put the DW_AT_ordering attribute back in.  (But if
777650397Sobrien     and when we find out that we need to put these in, we will only do so
777750397Sobrien     for multidimensional arrays.  */
777850397Sobrien  add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major);
777950397Sobrien#endif
778050397Sobrien
778150397Sobrien#ifdef MIPS_DEBUGGING_INFO
778250397Sobrien  /* The SGI compilers handle arrays of unknown bound by setting
778350397Sobrien     AT_declaration and not emitting any subrange DIEs.  */
778450397Sobrien  if (! TYPE_DOMAIN (type))
778550397Sobrien    add_AT_unsigned (array_die, DW_AT_declaration, 1);
778650397Sobrien  else
778750397Sobrien#endif
778850397Sobrien    add_subscript_info (array_die, type);
778950397Sobrien
779050397Sobrien  equate_type_number_to_die (type, array_die);
779150397Sobrien
779250397Sobrien  /* Add representation of the type of the elements of this array type.  */
779350397Sobrien  element_type = TREE_TYPE (type);
779450397Sobrien
779550397Sobrien  /* ??? The SGI dwarf reader fails for multidimensional arrays with a
779650397Sobrien     const enum type.  E.g. const enum machine_mode insn_operand_mode[2][10].
779750397Sobrien     We work around this by disabling this feature.  See also
779850397Sobrien     add_subscript_info.  */
779950397Sobrien#ifndef MIPS_DEBUGGING_INFO
780050397Sobrien  while (TREE_CODE (element_type) == ARRAY_TYPE)
780150397Sobrien    element_type = TREE_TYPE (element_type);
780250397Sobrien
780350397Sobrien  gen_type_die (element_type, context_die);
780450397Sobrien#endif
780550397Sobrien
780650397Sobrien  add_type_attribute (array_die, element_type, 0, 0, context_die);
780750397Sobrien}
780850397Sobrien
780950397Sobrienstatic void
781050397Sobriengen_set_type_die (type, context_die)
781150397Sobrien     register tree type;
781250397Sobrien     register dw_die_ref context_die;
781350397Sobrien{
781450397Sobrien  register dw_die_ref type_die
781550397Sobrien    = new_die (DW_TAG_set_type, scope_die_for (type, context_die));
781650397Sobrien
781750397Sobrien  equate_type_number_to_die (type, type_die);
781850397Sobrien  add_type_attribute (type_die, TREE_TYPE (type), 0, 0, context_die);
781950397Sobrien}
782050397Sobrien
782150397Sobrien#if 0
782250397Sobrienstatic void
782350397Sobriengen_entry_point_die (decl, context_die)
782450397Sobrien     register tree decl;
782550397Sobrien     register dw_die_ref context_die;
782650397Sobrien{
782750397Sobrien  register tree origin = decl_ultimate_origin (decl);
782850397Sobrien  register dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die);
782950397Sobrien  if (origin != NULL)
783050397Sobrien    add_abstract_origin_attribute (decl_die, origin);
783150397Sobrien  else
783250397Sobrien    {
783350397Sobrien      add_name_and_src_coords_attributes (decl_die, decl);
783450397Sobrien      add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)),
783550397Sobrien			  0, 0, context_die);
783650397Sobrien    }
783750397Sobrien
783850397Sobrien  if (DECL_ABSTRACT (decl))
783950397Sobrien    equate_decl_number_to_die (decl, decl_die);
784050397Sobrien  else
784150397Sobrien    add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
784250397Sobrien}
784350397Sobrien#endif
784450397Sobrien
784550397Sobrien/* Remember a type in the pending_types_list.  */
784650397Sobrien
784750397Sobrienstatic void
784850397Sobrienpend_type (type)
784950397Sobrien     register tree type;
785050397Sobrien{
785150397Sobrien  if (pending_types == pending_types_allocated)
785250397Sobrien    {
785350397Sobrien      pending_types_allocated += PENDING_TYPES_INCREMENT;
785450397Sobrien      pending_types_list
785550397Sobrien	= (tree *) xrealloc (pending_types_list,
785650397Sobrien			     sizeof (tree) * pending_types_allocated);
785750397Sobrien    }
785850397Sobrien
785950397Sobrien  pending_types_list[pending_types++] = type;
786050397Sobrien}
786150397Sobrien
786250397Sobrien/* Output any pending types (from the pending_types list) which we can output
786350397Sobrien   now (taking into account the scope that we are working on now).
786450397Sobrien
786550397Sobrien   For each type output, remove the given type from the pending_types_list
786650397Sobrien   *before* we try to output it.  */
786750397Sobrien
786850397Sobrienstatic void
786950397Sobrienoutput_pending_types_for_scope (context_die)
787050397Sobrien     register dw_die_ref context_die;
787150397Sobrien{
787250397Sobrien  register tree type;
787350397Sobrien
787450397Sobrien  while (pending_types)
787550397Sobrien    {
787650397Sobrien      --pending_types;
787750397Sobrien      type = pending_types_list[pending_types];
787850397Sobrien      gen_type_die (type, context_die);
787950397Sobrien      if (!TREE_ASM_WRITTEN (type))
788050397Sobrien	abort ();
788150397Sobrien    }
788250397Sobrien}
788350397Sobrien
788450397Sobrien/* Generate a DIE to represent an inlined instance of an enumeration type.  */
788550397Sobrien
788650397Sobrienstatic void
788750397Sobriengen_inlined_enumeration_type_die (type, context_die)
788850397Sobrien     register tree type;
788950397Sobrien     register dw_die_ref context_die;
789050397Sobrien{
789150397Sobrien  register dw_die_ref type_die = new_die (DW_TAG_enumeration_type,
789250397Sobrien					  scope_die_for (type, context_die));
789350397Sobrien
789450397Sobrien  if (!TREE_ASM_WRITTEN (type))
789550397Sobrien    abort ();
789650397Sobrien  add_abstract_origin_attribute (type_die, type);
789750397Sobrien}
789850397Sobrien
789950397Sobrien/* Generate a DIE to represent an inlined instance of a structure type.  */
790050397Sobrien
790150397Sobrienstatic void
790250397Sobriengen_inlined_structure_type_die (type, context_die)
790350397Sobrien     register tree type;
790450397Sobrien     register dw_die_ref context_die;
790550397Sobrien{
790650397Sobrien  register dw_die_ref type_die = new_die (DW_TAG_structure_type,
790750397Sobrien					  scope_die_for (type, context_die));
790850397Sobrien
790950397Sobrien  if (!TREE_ASM_WRITTEN (type))
791050397Sobrien    abort ();
791150397Sobrien  add_abstract_origin_attribute (type_die, type);
791250397Sobrien}
791350397Sobrien
791450397Sobrien/* Generate a DIE to represent an inlined instance of a union type.  */
791550397Sobrien
791650397Sobrienstatic void
791750397Sobriengen_inlined_union_type_die (type, context_die)
791850397Sobrien     register tree type;
791950397Sobrien     register dw_die_ref context_die;
792050397Sobrien{
792150397Sobrien  register dw_die_ref type_die = new_die (DW_TAG_union_type,
792250397Sobrien					  scope_die_for (type, context_die));
792350397Sobrien
792450397Sobrien  if (!TREE_ASM_WRITTEN (type))
792550397Sobrien    abort ();
792650397Sobrien  add_abstract_origin_attribute (type_die, type);
792750397Sobrien}
792850397Sobrien
792950397Sobrien/* Generate a DIE to represent an enumeration type.  Note that these DIEs
793050397Sobrien   include all of the information about the enumeration values also. Each
793150397Sobrien   enumerated type name/value is listed as a child of the enumerated type
793250397Sobrien   DIE.  */
793350397Sobrien
793450397Sobrienstatic void
793550397Sobriengen_enumeration_type_die (type, context_die)
793650397Sobrien     register tree type;
793750397Sobrien     register dw_die_ref context_die;
793850397Sobrien{
793950397Sobrien  register dw_die_ref type_die = lookup_type_die (type);
794050397Sobrien
794150397Sobrien  if (type_die == NULL)
794250397Sobrien    {
794350397Sobrien      type_die = new_die (DW_TAG_enumeration_type,
794450397Sobrien			  scope_die_for (type, context_die));
794550397Sobrien      equate_type_number_to_die (type, type_die);
794650397Sobrien      add_name_attribute (type_die, type_tag (type));
794750397Sobrien    }
794850397Sobrien  else if (! TYPE_SIZE (type))
794950397Sobrien    return;
795050397Sobrien  else
795150397Sobrien    remove_AT (type_die, DW_AT_declaration);
795250397Sobrien
795350397Sobrien  /* Handle a GNU C/C++ extension, i.e. incomplete enum types.  If the
795450397Sobrien     given enum type is incomplete, do not generate the DW_AT_byte_size
795550397Sobrien     attribute or the DW_AT_element_list attribute.  */
795650397Sobrien  if (TYPE_SIZE (type))
795750397Sobrien    {
795850397Sobrien      register tree link;
795950397Sobrien
796050397Sobrien      TREE_ASM_WRITTEN (type) = 1;
796150397Sobrien      add_byte_size_attribute (type_die, type);
796250397Sobrien      if (TYPE_STUB_DECL (type) != NULL_TREE)
796350397Sobrien	add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
796450397Sobrien
796550397Sobrien      /* If the first reference to this type was as the return type of an
796650397Sobrien	 inline function, then it may not have a parent.  Fix this now.  */
796750397Sobrien      if (type_die->die_parent == NULL)
796850397Sobrien	add_child_die (scope_die_for (type, context_die), type_die);
796950397Sobrien
797050397Sobrien      for (link = TYPE_FIELDS (type);
797150397Sobrien	   link != NULL; link = TREE_CHAIN (link))
797250397Sobrien	{
797350397Sobrien	  register dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die);
797450397Sobrien
797550397Sobrien	  add_name_attribute (enum_die,
797650397Sobrien			      IDENTIFIER_POINTER (TREE_PURPOSE (link)));
797750397Sobrien	  add_AT_unsigned (enum_die, DW_AT_const_value,
797850397Sobrien			   (unsigned) TREE_INT_CST_LOW (TREE_VALUE (link)));
797950397Sobrien	}
798050397Sobrien    }
798150397Sobrien  else
798250397Sobrien    add_AT_flag (type_die, DW_AT_declaration, 1);
798350397Sobrien}
798450397Sobrien
798550397Sobrien
798650397Sobrien/* Generate a DIE to represent either a real live formal parameter decl or to
798750397Sobrien   represent just the type of some formal parameter position in some function
798850397Sobrien   type.
798950397Sobrien
799050397Sobrien   Note that this routine is a bit unusual because its argument may be a
799150397Sobrien   ..._DECL node (i.e. either a PARM_DECL or perhaps a VAR_DECL which
799250397Sobrien   represents an inlining of some PARM_DECL) or else some sort of a ..._TYPE
799350397Sobrien   node.  If it's the former then this function is being called to output a
799450397Sobrien   DIE to represent a formal parameter object (or some inlining thereof).  If
799550397Sobrien   it's the latter, then this function is only being called to output a
799650397Sobrien   DW_TAG_formal_parameter DIE to stand as a placeholder for some formal
799750397Sobrien   argument type of some subprogram type.  */
799850397Sobrien
799950397Sobrienstatic dw_die_ref
800050397Sobriengen_formal_parameter_die (node, context_die)
800150397Sobrien     register tree node;
800250397Sobrien     register dw_die_ref context_die;
800350397Sobrien{
800450397Sobrien  register dw_die_ref parm_die
800550397Sobrien    = new_die (DW_TAG_formal_parameter, context_die);
800650397Sobrien  register tree origin;
800750397Sobrien
800850397Sobrien  switch (TREE_CODE_CLASS (TREE_CODE (node)))
800950397Sobrien    {
801050397Sobrien    case 'd':
801150397Sobrien      origin = decl_ultimate_origin (node);
801250397Sobrien      if (origin != NULL)
801350397Sobrien	add_abstract_origin_attribute (parm_die, origin);
801450397Sobrien      else
801550397Sobrien	{
801650397Sobrien	  add_name_and_src_coords_attributes (parm_die, node);
801750397Sobrien	  add_type_attribute (parm_die, TREE_TYPE (node),
801850397Sobrien			      TREE_READONLY (node),
801950397Sobrien			      TREE_THIS_VOLATILE (node),
802050397Sobrien			      context_die);
802150397Sobrien	  if (DECL_ARTIFICIAL (node))
802250397Sobrien	    add_AT_flag (parm_die, DW_AT_artificial, 1);
802350397Sobrien	}
802450397Sobrien
802550397Sobrien      equate_decl_number_to_die (node, parm_die);
802650397Sobrien      if (! DECL_ABSTRACT (node))
802750397Sobrien	add_location_or_const_value_attribute (parm_die, node);
802850397Sobrien
802950397Sobrien      break;
803050397Sobrien
803150397Sobrien    case 't':
803250397Sobrien      /* We were called with some kind of a ..._TYPE node.  */
803350397Sobrien      add_type_attribute (parm_die, node, 0, 0, context_die);
803450397Sobrien      break;
803550397Sobrien
803650397Sobrien    default:
803750397Sobrien      abort ();
803850397Sobrien    }
803950397Sobrien
804050397Sobrien  return parm_die;
804150397Sobrien}
804250397Sobrien
804350397Sobrien/* Generate a special type of DIE used as a stand-in for a trailing ellipsis
804450397Sobrien   at the end of an (ANSI prototyped) formal parameters list.  */
804550397Sobrien
804650397Sobrienstatic void
804750397Sobriengen_unspecified_parameters_die (decl_or_type, context_die)
804850397Sobrien     register tree decl_or_type;
804950397Sobrien     register dw_die_ref context_die;
805050397Sobrien{
805150397Sobrien  new_die (DW_TAG_unspecified_parameters, context_die);
805250397Sobrien}
805350397Sobrien
805450397Sobrien/* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a
805550397Sobrien   DW_TAG_unspecified_parameters DIE) to represent the types of the formal
805650397Sobrien   parameters as specified in some function type specification (except for
805750397Sobrien   those which appear as part of a function *definition*).
805850397Sobrien
805950397Sobrien   Note we must be careful here to output all of the parameter DIEs before*
806050397Sobrien   we output any DIEs needed to represent the types of the formal parameters.
806150397Sobrien   This keeps svr4 SDB happy because it (incorrectly) thinks that the first
806250397Sobrien   non-parameter DIE it sees ends the formal parameter list.  */
806350397Sobrien
806450397Sobrienstatic void
806550397Sobriengen_formal_types_die (function_or_method_type, context_die)
806650397Sobrien     register tree function_or_method_type;
806750397Sobrien     register dw_die_ref context_die;
806850397Sobrien{
806950397Sobrien  register tree link;
807050397Sobrien  register tree formal_type = NULL;
807150397Sobrien  register tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
807250397Sobrien
807350397Sobrien#if 0
807450397Sobrien  /* In the case where we are generating a formal types list for a C++
807550397Sobrien     non-static member function type, skip over the first thing on the
807650397Sobrien     TYPE_ARG_TYPES list because it only represents the type of the hidden
807750397Sobrien     `this pointer'.  The debugger should be able to figure out (without
807850397Sobrien     being explicitly told) that this non-static member function type takes a
807950397Sobrien     `this pointer' and should be able to figure what the type of that hidden
808050397Sobrien     parameter is from the DW_AT_member attribute of the parent
808150397Sobrien     DW_TAG_subroutine_type DIE.  */
808250397Sobrien  if (TREE_CODE (function_or_method_type) == METHOD_TYPE)
808350397Sobrien    first_parm_type = TREE_CHAIN (first_parm_type);
808450397Sobrien#endif
808550397Sobrien
808650397Sobrien  /* Make our first pass over the list of formal parameter types and output a
808750397Sobrien     DW_TAG_formal_parameter DIE for each one.  */
808850397Sobrien  for (link = first_parm_type; link; link = TREE_CHAIN (link))
808950397Sobrien    {
809050397Sobrien      register dw_die_ref parm_die;
809150397Sobrien
809250397Sobrien      formal_type = TREE_VALUE (link);
809350397Sobrien      if (formal_type == void_type_node)
809450397Sobrien	break;
809550397Sobrien
809650397Sobrien      /* Output a (nameless) DIE to represent the formal parameter itself.  */
809750397Sobrien      parm_die = gen_formal_parameter_die (formal_type, context_die);
809850397Sobrien      if (TREE_CODE (function_or_method_type) == METHOD_TYPE
809950397Sobrien	  && link == first_parm_type)
810050397Sobrien	add_AT_flag (parm_die, DW_AT_artificial, 1);
810150397Sobrien    }
810250397Sobrien
810350397Sobrien  /* If this function type has an ellipsis, add a
810450397Sobrien     DW_TAG_unspecified_parameters DIE to the end of the parameter list.  */
810550397Sobrien  if (formal_type != void_type_node)
810650397Sobrien    gen_unspecified_parameters_die (function_or_method_type, context_die);
810750397Sobrien
810850397Sobrien  /* Make our second (and final) pass over the list of formal parameter types
810950397Sobrien     and output DIEs to represent those types (as necessary).  */
811050397Sobrien  for (link = TYPE_ARG_TYPES (function_or_method_type);
811150397Sobrien       link;
811250397Sobrien       link = TREE_CHAIN (link))
811350397Sobrien    {
811450397Sobrien      formal_type = TREE_VALUE (link);
811550397Sobrien      if (formal_type == void_type_node)
811650397Sobrien	break;
811750397Sobrien
811850397Sobrien      gen_type_die (formal_type, context_die);
811950397Sobrien    }
812050397Sobrien}
812150397Sobrien
812250397Sobrien/* Generate a DIE to represent a declared function (either file-scope or
812350397Sobrien   block-local).  */
812450397Sobrien
812550397Sobrienstatic void
812650397Sobriengen_subprogram_die (decl, context_die)
812750397Sobrien     register tree decl;
812850397Sobrien     register dw_die_ref context_die;
812950397Sobrien{
813050397Sobrien  char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
813150397Sobrien  register tree origin = decl_ultimate_origin (decl);
813250397Sobrien  register dw_die_ref subr_die;
813350397Sobrien  register rtx fp_reg;
813450397Sobrien  register tree fn_arg_types;
813550397Sobrien  register tree outer_scope;
813650397Sobrien  register dw_die_ref old_die = lookup_decl_die (decl);
813750397Sobrien  register int declaration
813850397Sobrien    = (current_function_decl != decl
813950397Sobrien       || (context_die
814050397Sobrien	   && (context_die->die_tag == DW_TAG_structure_type
814150397Sobrien	       || context_die->die_tag == DW_TAG_union_type)));
814250397Sobrien
814350397Sobrien  if (origin != NULL)
814450397Sobrien    {
814550397Sobrien      subr_die = new_die (DW_TAG_subprogram, context_die);
814650397Sobrien      add_abstract_origin_attribute (subr_die, origin);
814750397Sobrien    }
814850397Sobrien  else if (old_die && DECL_ABSTRACT (decl)
814950397Sobrien	   && get_AT_unsigned (old_die, DW_AT_inline))
815050397Sobrien    {
815150397Sobrien      /* This must be a redefinition of an extern inline function.
815250397Sobrien	 We can just reuse the old die here.  */
815350397Sobrien      subr_die = old_die;
815450397Sobrien
815550397Sobrien      /* Clear out the inlined attribute and parm types.  */
815650397Sobrien      remove_AT (subr_die, DW_AT_inline);
815750397Sobrien      remove_children (subr_die);
815850397Sobrien    }
815950397Sobrien  else if (old_die)
816050397Sobrien    {
816150397Sobrien      register unsigned file_index
816250397Sobrien	= lookup_filename (DECL_SOURCE_FILE (decl));
816350397Sobrien
816450397Sobrien      if (get_AT_flag (old_die, DW_AT_declaration) != 1)
816550397Sobrien	abort ();
816650397Sobrien
816750397Sobrien      /* If the definition comes from the same place as the declaration,
816850397Sobrien	 maybe use the old DIE.  We always want the DIE for this function
816950397Sobrien	 that has the *_pc attributes to be under comp_unit_die so the
817050397Sobrien	 debugger can find it.  For inlines, that is the concrete instance,
817150397Sobrien	 so we can use the old DIE here.  For non-inline methods, we want a
817250397Sobrien	 specification DIE at toplevel, so we need a new DIE.  For local
817350397Sobrien	 class methods, this does not apply.  */
817450397Sobrien      if ((DECL_ABSTRACT (decl) || old_die->die_parent == comp_unit_die
817550397Sobrien	   || context_die == NULL)
817650397Sobrien	  && get_AT_unsigned (old_die, DW_AT_decl_file) == file_index
817750397Sobrien	  && (get_AT_unsigned (old_die, DW_AT_decl_line)
817850397Sobrien	      == DECL_SOURCE_LINE (decl)))
817950397Sobrien	{
818050397Sobrien	  subr_die = old_die;
818150397Sobrien
818250397Sobrien	  /* Clear out the declaration attribute and the parm types.  */
818350397Sobrien	  remove_AT (subr_die, DW_AT_declaration);
818450397Sobrien	  remove_children (subr_die);
818550397Sobrien	}
818650397Sobrien      else
818750397Sobrien	{
818850397Sobrien	  subr_die = new_die (DW_TAG_subprogram, context_die);
818950397Sobrien	  add_AT_die_ref (subr_die, DW_AT_specification, old_die);
819050397Sobrien	  if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
819150397Sobrien	    add_AT_unsigned (subr_die, DW_AT_decl_file, file_index);
819250397Sobrien	  if (get_AT_unsigned (old_die, DW_AT_decl_line)
819350397Sobrien	      != DECL_SOURCE_LINE (decl))
819450397Sobrien	    add_AT_unsigned
819550397Sobrien	      (subr_die, DW_AT_decl_line, DECL_SOURCE_LINE (decl));
819650397Sobrien	}
819750397Sobrien    }
819850397Sobrien  else
819950397Sobrien    {
820050397Sobrien      register dw_die_ref scope_die;
820150397Sobrien
820250397Sobrien      if (DECL_CONTEXT (decl))
820350397Sobrien	scope_die = scope_die_for (decl, context_die);
820450397Sobrien      else
820550397Sobrien	/* Don't put block extern declarations under comp_unit_die.  */
820650397Sobrien	scope_die = context_die;
820750397Sobrien
820850397Sobrien      subr_die = new_die (DW_TAG_subprogram, scope_die);
820950397Sobrien
821050397Sobrien      if (TREE_PUBLIC (decl))
821150397Sobrien	add_AT_flag (subr_die, DW_AT_external, 1);
821250397Sobrien
821350397Sobrien      add_name_and_src_coords_attributes (subr_die, decl);
821450397Sobrien      if (debug_info_level > DINFO_LEVEL_TERSE)
821550397Sobrien	{
821650397Sobrien	  register tree type = TREE_TYPE (decl);
821750397Sobrien
821850397Sobrien	  add_prototyped_attribute (subr_die, type);
821950397Sobrien	  add_type_attribute (subr_die, TREE_TYPE (type), 0, 0, context_die);
822050397Sobrien	}
822150397Sobrien
822250397Sobrien      add_pure_or_virtual_attribute (subr_die, decl);
822350397Sobrien      if (DECL_ARTIFICIAL (decl))
822450397Sobrien	add_AT_flag (subr_die, DW_AT_artificial, 1);
822550397Sobrien      if (TREE_PROTECTED (decl))
822650397Sobrien	add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_protected);
822750397Sobrien      else if (TREE_PRIVATE (decl))
822850397Sobrien	add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_private);
822950397Sobrien    }
823050397Sobrien
823150397Sobrien  if (declaration)
823250397Sobrien    {
823350397Sobrien      add_AT_flag (subr_die, DW_AT_declaration, 1);
823450397Sobrien
823550397Sobrien      /* The first time we see a member function, it is in the context of
823650397Sobrien         the class to which it belongs.  We make sure of this by emitting
823750397Sobrien         the class first.  The next time is the definition, which is
823850397Sobrien         handled above.  The two may come from the same source text.  */
823950397Sobrien      if (DECL_CONTEXT (decl))
824050397Sobrien	equate_decl_number_to_die (decl, subr_die);
824150397Sobrien    }
824250397Sobrien  else if (DECL_ABSTRACT (decl))
824350397Sobrien    {
824450397Sobrien      /* ??? Checking DECL_DEFER_OUTPUT is correct for static inline functions,
824550397Sobrien	 but not for extern inline functions.  We can't get this completely
824650397Sobrien	 correct because information about whether the function was declared
824750397Sobrien	 inline is not saved anywhere.  */
824850397Sobrien      if (DECL_DEFER_OUTPUT (decl))
824950397Sobrien	{
825050397Sobrien	  if (DECL_INLINE (decl))
825150397Sobrien	    add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
825250397Sobrien	  else
825350397Sobrien	    add_AT_unsigned (subr_die, DW_AT_inline,
825450397Sobrien			     DW_INL_declared_not_inlined);
825550397Sobrien	}
825650397Sobrien      else if (DECL_INLINE (decl))
825750397Sobrien	add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
825850397Sobrien      else
825950397Sobrien	abort ();
826050397Sobrien
826150397Sobrien      equate_decl_number_to_die (decl, subr_die);
826250397Sobrien    }
826350397Sobrien  else if (!DECL_EXTERNAL (decl))
826450397Sobrien    {
826550397Sobrien      if (origin == NULL_TREE)
826650397Sobrien	equate_decl_number_to_die (decl, subr_die);
826750397Sobrien
826850397Sobrien      ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
826950397Sobrien				   current_funcdef_number);
827050397Sobrien      add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
827150397Sobrien      ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
827250397Sobrien				   current_funcdef_number);
827350397Sobrien      add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
827450397Sobrien
827550397Sobrien      add_pubname (decl, subr_die);
827650397Sobrien      add_arange (decl, subr_die);
827750397Sobrien
827850397Sobrien#ifdef MIPS_DEBUGGING_INFO
827950397Sobrien      /* Add a reference to the FDE for this routine.  */
828050397Sobrien      add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde);
828150397Sobrien#endif
828250397Sobrien
828350397Sobrien      /* Define the "frame base" location for this routine.  We use the
828450397Sobrien         frame pointer or stack pointer registers, since the RTL for local
828550397Sobrien         variables is relative to one of them.  */
828650397Sobrien      fp_reg
828750397Sobrien	= frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
828850397Sobrien      add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
828950397Sobrien
829050397Sobrien#if 0
829150397Sobrien      /* ??? This fails for nested inline functions, because context_display
829250397Sobrien	 is not part of the state saved/restored for inline functions.  */
829350397Sobrien      if (current_function_needs_context)
829450397Sobrien	add_AT_location_description (subr_die, DW_AT_static_link,
829550397Sobrien				     lookup_static_chain (decl));
829650397Sobrien#endif
829750397Sobrien    }
829850397Sobrien
829950397Sobrien  /* Now output descriptions of the arguments for this function. This gets
830050397Sobrien     (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
830150397Sobrien     for a FUNCTION_DECL doesn't indicate cases where there was a trailing
830250397Sobrien     `...' at the end of the formal parameter list.  In order to find out if
830350397Sobrien     there was a trailing ellipsis or not, we must instead look at the type
830450397Sobrien     associated with the FUNCTION_DECL.  This will be a node of type
830550397Sobrien     FUNCTION_TYPE. If the chain of type nodes hanging off of this
830650397Sobrien     FUNCTION_TYPE node ends with a void_type_node then there should *not* be
830750397Sobrien     an ellipsis at the end.  */
830850397Sobrien  push_decl_scope (decl);
830950397Sobrien
831050397Sobrien  /* In the case where we are describing a mere function declaration, all we
831150397Sobrien     need to do here (and all we *can* do here) is to describe the *types* of
831250397Sobrien     its formal parameters.  */
831350397Sobrien  if (debug_info_level <= DINFO_LEVEL_TERSE)
831450397Sobrien    ;
831550397Sobrien  else if (declaration)
831650397Sobrien    gen_formal_types_die (TREE_TYPE (decl), subr_die);
831750397Sobrien  else
831850397Sobrien    {
831950397Sobrien      /* Generate DIEs to represent all known formal parameters */
832050397Sobrien      register tree arg_decls = DECL_ARGUMENTS (decl);
832150397Sobrien      register tree parm;
832250397Sobrien
832350397Sobrien      /* When generating DIEs, generate the unspecified_parameters DIE
832450397Sobrien         instead if we come across the arg "__builtin_va_alist" */
832550397Sobrien      for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
832650397Sobrien	if (TREE_CODE (parm) == PARM_DECL)
832750397Sobrien	  {
832850397Sobrien	    if (DECL_NAME (parm)
832950397Sobrien		&& !strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)),
833050397Sobrien			    "__builtin_va_alist"))
833150397Sobrien	      gen_unspecified_parameters_die (parm, subr_die);
833250397Sobrien	    else
833350397Sobrien	      gen_decl_die (parm, subr_die);
833450397Sobrien	  }
833550397Sobrien
833650397Sobrien      /* Decide whether we need a unspecified_parameters DIE at the end.
833750397Sobrien         There are 2 more cases to do this for: 1) the ansi ... declaration -
833850397Sobrien         this is detectable when the end of the arg list is not a
833950397Sobrien         void_type_node 2) an unprototyped function declaration (not a
834050397Sobrien         definition).  This just means that we have no info about the
834150397Sobrien         parameters at all.  */
834250397Sobrien      fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
834350397Sobrien      if (fn_arg_types != NULL)
834450397Sobrien	{
834550397Sobrien	  /* this is the prototyped case, check for ...  */
834650397Sobrien	  if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node)
834750397Sobrien	    gen_unspecified_parameters_die (decl, subr_die);
834850397Sobrien	}
834950397Sobrien      else if (DECL_INITIAL (decl) == NULL_TREE)
835050397Sobrien	gen_unspecified_parameters_die (decl, subr_die);
835150397Sobrien    }
835250397Sobrien
835350397Sobrien  /* Output Dwarf info for all of the stuff within the body of the function
835450397Sobrien     (if it has one - it may be just a declaration).  */
835550397Sobrien  outer_scope = DECL_INITIAL (decl);
835650397Sobrien
835750397Sobrien  /* Note that here, `outer_scope' is a pointer to the outermost BLOCK
835850397Sobrien     node created to represent a function. This outermost BLOCK actually
835950397Sobrien     represents the outermost binding contour for the function, i.e. the
836050397Sobrien     contour in which the function's formal parameters and labels get
836150397Sobrien     declared. Curiously, it appears that the front end doesn't actually
836250397Sobrien     put the PARM_DECL nodes for the current function onto the BLOCK_VARS
836350397Sobrien     list for this outer scope.  (They are strung off of the DECL_ARGUMENTS
836450397Sobrien     list for the function instead.) The BLOCK_VARS list for the
836550397Sobrien     `outer_scope' does provide us with a list of the LABEL_DECL nodes for
836650397Sobrien     the function however, and we output DWARF info for those in
836750397Sobrien     decls_for_scope.  Just within the `outer_scope' there will be a BLOCK
836850397Sobrien     node representing the function's outermost pair of curly braces, and
836950397Sobrien     any blocks used for the base and member initializers of a C++
837050397Sobrien     constructor function.  */
837150397Sobrien  if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
837250397Sobrien    {
837350397Sobrien      current_function_has_inlines = 0;
837450397Sobrien      decls_for_scope (outer_scope, subr_die, 0);
837550397Sobrien
837650397Sobrien#if 0 && defined (MIPS_DEBUGGING_INFO)
837750397Sobrien      if (current_function_has_inlines)
837850397Sobrien	{
837950397Sobrien	  add_AT_flag (subr_die, DW_AT_MIPS_has_inlines, 1);
838050397Sobrien	  if (! comp_unit_has_inlines)
838150397Sobrien	    {
838250397Sobrien	      add_AT_flag (comp_unit_die, DW_AT_MIPS_has_inlines, 1);
838350397Sobrien	      comp_unit_has_inlines = 1;
838450397Sobrien	    }
838550397Sobrien	}
838650397Sobrien#endif
838750397Sobrien    }
838850397Sobrien
838950397Sobrien  pop_decl_scope ();
839050397Sobrien}
839150397Sobrien
839250397Sobrien/* Generate a DIE to represent a declared data object.  */
839350397Sobrien
839450397Sobrienstatic void
839550397Sobriengen_variable_die (decl, context_die)
839650397Sobrien     register tree decl;
839750397Sobrien     register dw_die_ref context_die;
839850397Sobrien{
839950397Sobrien  register tree origin = decl_ultimate_origin (decl);
840050397Sobrien  register dw_die_ref var_die = new_die (DW_TAG_variable, context_die);
840150397Sobrien
840250397Sobrien  dw_die_ref old_die = lookup_decl_die (decl);
840350397Sobrien  int declaration
840450397Sobrien    = (DECL_EXTERNAL (decl)
840550397Sobrien       || current_function_decl != decl_function_context (decl)
840650397Sobrien       || context_die->die_tag == DW_TAG_structure_type
840750397Sobrien       || context_die->die_tag == DW_TAG_union_type);
840850397Sobrien
840950397Sobrien  if (origin != NULL)
841050397Sobrien    add_abstract_origin_attribute (var_die, origin);
841150397Sobrien  /* Loop unrolling can create multiple blocks that refer to the same
841250397Sobrien     static variable, so we must test for the DW_AT_declaration flag.  */
841350397Sobrien  /* ??? Loop unrolling/reorder_blocks should perhaps be rewritten to
841450397Sobrien     copy decls and set the DECL_ABSTRACT flag on them instead of
841550397Sobrien     sharing them.  */
841650397Sobrien  else if (old_die && TREE_STATIC (decl)
841750397Sobrien 	   && get_AT_flag (old_die, DW_AT_declaration) == 1)
841850397Sobrien    {
841950397Sobrien      /* ??? This is an instantiation of a C++ class level static.  */
842050397Sobrien      add_AT_die_ref (var_die, DW_AT_specification, old_die);
842150397Sobrien      if (DECL_NAME (decl))
842250397Sobrien	{
842350397Sobrien	  register unsigned file_index
842450397Sobrien	    = lookup_filename (DECL_SOURCE_FILE (decl));
842550397Sobrien
842650397Sobrien	  if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
842750397Sobrien	    add_AT_unsigned (var_die, DW_AT_decl_file, file_index);
842850397Sobrien
842950397Sobrien	  if (get_AT_unsigned (old_die, DW_AT_decl_line)
843050397Sobrien	      != DECL_SOURCE_LINE (decl))
843150397Sobrien
843250397Sobrien	    add_AT_unsigned (var_die, DW_AT_decl_line,
843350397Sobrien			     DECL_SOURCE_LINE (decl));
843450397Sobrien	}
843550397Sobrien    }
843650397Sobrien  else
843750397Sobrien    {
843850397Sobrien      add_name_and_src_coords_attributes (var_die, decl);
843950397Sobrien      add_type_attribute (var_die, TREE_TYPE (decl),
844050397Sobrien			  TREE_READONLY (decl),
844150397Sobrien			  TREE_THIS_VOLATILE (decl), context_die);
844250397Sobrien
844350397Sobrien      if (TREE_PUBLIC (decl))
844450397Sobrien	add_AT_flag (var_die, DW_AT_external, 1);
844550397Sobrien
844650397Sobrien      if (DECL_ARTIFICIAL (decl))
844750397Sobrien	add_AT_flag (var_die, DW_AT_artificial, 1);
844850397Sobrien
844950397Sobrien      if (TREE_PROTECTED (decl))
845050397Sobrien	add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_protected);
845150397Sobrien
845250397Sobrien      else if (TREE_PRIVATE (decl))
845350397Sobrien	add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_private);
845450397Sobrien    }
845550397Sobrien
845650397Sobrien  if (declaration)
845750397Sobrien    add_AT_flag (var_die, DW_AT_declaration, 1);
845850397Sobrien
845950397Sobrien  if ((declaration && decl_class_context (decl)) || DECL_ABSTRACT (decl))
846050397Sobrien    equate_decl_number_to_die (decl, var_die);
846150397Sobrien
846250397Sobrien  if (! declaration && ! DECL_ABSTRACT (decl))
846350397Sobrien    {
846450397Sobrien      equate_decl_number_to_die (decl, var_die);
846550397Sobrien      add_location_or_const_value_attribute (var_die, decl);
846650397Sobrien      add_pubname (decl, var_die);
846750397Sobrien    }
846850397Sobrien}
846950397Sobrien
847050397Sobrien/* Generate a DIE to represent a label identifier.  */
847150397Sobrien
847250397Sobrienstatic void
847350397Sobriengen_label_die (decl, context_die)
847450397Sobrien     register tree decl;
847550397Sobrien     register dw_die_ref context_die;
847650397Sobrien{
847750397Sobrien  register tree origin = decl_ultimate_origin (decl);
847850397Sobrien  register dw_die_ref lbl_die = new_die (DW_TAG_label, context_die);
847950397Sobrien  register rtx insn;
848050397Sobrien  char label[MAX_ARTIFICIAL_LABEL_BYTES];
848150397Sobrien  char label2[MAX_ARTIFICIAL_LABEL_BYTES];
848250397Sobrien
848350397Sobrien  if (origin != NULL)
848450397Sobrien    add_abstract_origin_attribute (lbl_die, origin);
848550397Sobrien  else
848650397Sobrien    add_name_and_src_coords_attributes (lbl_die, decl);
848750397Sobrien
848850397Sobrien  if (DECL_ABSTRACT (decl))
848950397Sobrien    equate_decl_number_to_die (decl, lbl_die);
849050397Sobrien  else
849150397Sobrien    {
849250397Sobrien      insn = DECL_RTL (decl);
849350397Sobrien      if (GET_CODE (insn) == CODE_LABEL)
849450397Sobrien	{
849550397Sobrien	  /* When optimization is enabled (via -O) some parts of the compiler
849650397Sobrien	     (e.g. jump.c and cse.c) may try to delete CODE_LABEL insns which
849750397Sobrien	     represent source-level labels which were explicitly declared by
849850397Sobrien	     the user.  This really shouldn't be happening though, so catch
849950397Sobrien	     it if it ever does happen.  */
850050397Sobrien	  if (INSN_DELETED_P (insn))
850150397Sobrien	    abort ();
850250397Sobrien
850350397Sobrien	  sprintf (label2, INSN_LABEL_FMT, current_funcdef_number);
850450397Sobrien	  ASM_GENERATE_INTERNAL_LABEL (label, label2,
850550397Sobrien				       (unsigned) INSN_UID (insn));
850650397Sobrien	  add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
850750397Sobrien	}
850850397Sobrien    }
850950397Sobrien}
851050397Sobrien
851150397Sobrien/* Generate a DIE for a lexical block.  */
851250397Sobrien
851350397Sobrienstatic void
851450397Sobriengen_lexical_block_die (stmt, context_die, depth)
851550397Sobrien     register tree stmt;
851650397Sobrien     register dw_die_ref context_die;
851750397Sobrien     int depth;
851850397Sobrien{
851950397Sobrien  register dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die);
852050397Sobrien  char label[MAX_ARTIFICIAL_LABEL_BYTES];
852150397Sobrien
852250397Sobrien  if (! BLOCK_ABSTRACT (stmt))
852350397Sobrien    {
852450397Sobrien      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
852550397Sobrien				   next_block_number);
852650397Sobrien      add_AT_lbl_id (stmt_die, DW_AT_low_pc, label);
852750397Sobrien      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number);
852850397Sobrien      add_AT_lbl_id (stmt_die, DW_AT_high_pc, label);
852950397Sobrien    }
853050397Sobrien
853150397Sobrien  push_decl_scope (stmt);
853250397Sobrien  decls_for_scope (stmt, stmt_die, depth);
853350397Sobrien  pop_decl_scope ();
853450397Sobrien}
853550397Sobrien
853650397Sobrien/* Generate a DIE for an inlined subprogram.  */
853750397Sobrien
853850397Sobrienstatic void
853950397Sobriengen_inlined_subroutine_die (stmt, context_die, depth)
854050397Sobrien     register tree stmt;
854150397Sobrien     register dw_die_ref context_die;
854250397Sobrien     int depth;
854350397Sobrien{
854450397Sobrien  if (! BLOCK_ABSTRACT (stmt))
854550397Sobrien    {
854650397Sobrien      register dw_die_ref subr_die
854750397Sobrien	= new_die (DW_TAG_inlined_subroutine, context_die);
854850397Sobrien      register tree decl = block_ultimate_origin (stmt);
854950397Sobrien      char label[MAX_ARTIFICIAL_LABEL_BYTES];
855050397Sobrien
855150397Sobrien      add_abstract_origin_attribute (subr_die, decl);
855250397Sobrien      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
855350397Sobrien				   next_block_number);
855450397Sobrien      add_AT_lbl_id (subr_die, DW_AT_low_pc, label);
855550397Sobrien      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number);
855650397Sobrien      add_AT_lbl_id (subr_die, DW_AT_high_pc, label);
855750397Sobrien      push_decl_scope (decl);
855850397Sobrien      decls_for_scope (stmt, subr_die, depth);
855950397Sobrien      pop_decl_scope ();
856050397Sobrien      current_function_has_inlines = 1;
856150397Sobrien    }
856250397Sobrien}
856350397Sobrien
856450397Sobrien/* Generate a DIE for a field in a record, or structure.  */
856550397Sobrien
856650397Sobrienstatic void
856750397Sobriengen_field_die (decl, context_die)
856850397Sobrien     register tree decl;
856950397Sobrien     register dw_die_ref context_die;
857050397Sobrien{
857150397Sobrien  register dw_die_ref decl_die = new_die (DW_TAG_member, context_die);
857250397Sobrien
857350397Sobrien  add_name_and_src_coords_attributes (decl_die, decl);
857450397Sobrien  add_type_attribute (decl_die, member_declared_type (decl),
857550397Sobrien		      TREE_READONLY (decl), TREE_THIS_VOLATILE (decl),
857650397Sobrien		      context_die);
857750397Sobrien
857850397Sobrien  /* If this is a bit field...  */
857950397Sobrien  if (DECL_BIT_FIELD_TYPE (decl))
858050397Sobrien    {
858150397Sobrien      add_byte_size_attribute (decl_die, decl);
858250397Sobrien      add_bit_size_attribute (decl_die, decl);
858350397Sobrien      add_bit_offset_attribute (decl_die, decl);
858450397Sobrien    }
858550397Sobrien
858650397Sobrien  if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE)
858750397Sobrien    add_data_member_location_attribute (decl_die, decl);
858850397Sobrien
858950397Sobrien  if (DECL_ARTIFICIAL (decl))
859050397Sobrien    add_AT_flag (decl_die, DW_AT_artificial, 1);
859150397Sobrien
859250397Sobrien  if (TREE_PROTECTED (decl))
859350397Sobrien    add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_protected);
859450397Sobrien
859550397Sobrien  else if (TREE_PRIVATE (decl))
859650397Sobrien    add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_private);
859750397Sobrien}
859850397Sobrien
859950397Sobrien#if 0
860050397Sobrien/* Don't generate either pointer_type DIEs or reference_type DIEs here.
860150397Sobrien   Use modified_type_die instead.
860250397Sobrien   We keep this code here just in case these types of DIEs may be needed to
860350397Sobrien   represent certain things in other languages (e.g. Pascal) someday.  */
860450397Sobrienstatic void
860550397Sobriengen_pointer_type_die (type, context_die)
860650397Sobrien     register tree type;
860750397Sobrien     register dw_die_ref context_die;
860850397Sobrien{
860950397Sobrien  register dw_die_ref ptr_die
861050397Sobrien    = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die));
861150397Sobrien
861250397Sobrien  equate_type_number_to_die (type, ptr_die);
861350397Sobrien  add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
861450397Sobrien  add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
861550397Sobrien}
861650397Sobrien
861750397Sobrien/* Don't generate either pointer_type DIEs or reference_type DIEs here.
861850397Sobrien   Use modified_type_die instead.
861950397Sobrien   We keep this code here just in case these types of DIEs may be needed to
862050397Sobrien   represent certain things in other languages (e.g. Pascal) someday.  */
862150397Sobrienstatic void
862250397Sobriengen_reference_type_die (type, context_die)
862350397Sobrien     register tree type;
862450397Sobrien     register dw_die_ref context_die;
862550397Sobrien{
862650397Sobrien  register dw_die_ref ref_die
862750397Sobrien    = new_die (DW_TAG_reference_type, scope_die_for (type, context_die));
862850397Sobrien
862950397Sobrien  equate_type_number_to_die (type, ref_die);
863050397Sobrien  add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die);
863150397Sobrien  add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
863250397Sobrien}
863350397Sobrien#endif
863450397Sobrien
863550397Sobrien/* Generate a DIE for a pointer to a member type.  */
863650397Sobrienstatic void
863750397Sobriengen_ptr_to_mbr_type_die (type, context_die)
863850397Sobrien     register tree type;
863950397Sobrien     register dw_die_ref context_die;
864050397Sobrien{
864150397Sobrien  register dw_die_ref ptr_die
864250397Sobrien    = new_die (DW_TAG_ptr_to_member_type, scope_die_for (type, context_die));
864350397Sobrien
864450397Sobrien  equate_type_number_to_die (type, ptr_die);
864550397Sobrien  add_AT_die_ref (ptr_die, DW_AT_containing_type,
864650397Sobrien		  lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
864750397Sobrien  add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
864850397Sobrien}
864950397Sobrien
865050397Sobrien/* Generate the DIE for the compilation unit.  */
865150397Sobrien
865250397Sobrienstatic void
865350397Sobriengen_compile_unit_die (main_input_filename)
865450397Sobrien     register char *main_input_filename;
865550397Sobrien{
865650397Sobrien  char producer[250];
865750397Sobrien  char *wd = getpwd ();
865850397Sobrien
865950397Sobrien  comp_unit_die = new_die (DW_TAG_compile_unit, NULL);
866050397Sobrien  add_name_attribute (comp_unit_die, main_input_filename);
866150397Sobrien
866250397Sobrien  if (wd != NULL)
866350397Sobrien    add_AT_string (comp_unit_die, DW_AT_comp_dir, wd);
866450397Sobrien
866550397Sobrien  sprintf (producer, "%s %s", language_string, version_string);
866650397Sobrien
866750397Sobrien#ifdef MIPS_DEBUGGING_INFO
866850397Sobrien  /* The MIPS/SGI compilers place the 'cc' command line options in the producer
866950397Sobrien     string.  The SGI debugger looks for -g, -g1, -g2, or -g3; if they do
867050397Sobrien     not appear in the producer string, the debugger reaches the conclusion
867150397Sobrien     that the object file is stripped and has no debugging information.
867250397Sobrien     To get the MIPS/SGI debugger to believe that there is debugging
867350397Sobrien     information in the object file, we add a -g to the producer string.  */
867450397Sobrien  if (debug_info_level > DINFO_LEVEL_TERSE)
867550397Sobrien    strcat (producer, " -g");
867650397Sobrien#endif
867750397Sobrien
867850397Sobrien  add_AT_string (comp_unit_die, DW_AT_producer, producer);
867950397Sobrien
868050397Sobrien  if (strcmp (language_string, "GNU C++") == 0)
868150397Sobrien    add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C_plus_plus);
868250397Sobrien
868350397Sobrien  else if (strcmp (language_string, "GNU Ada") == 0)
868450397Sobrien    add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Ada83);
868550397Sobrien
868650397Sobrien  else if (strcmp (language_string, "GNU F77") == 0)
868750397Sobrien    add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Fortran77);
868850397Sobrien
868950397Sobrien  else if (strcmp (language_string, "GNU Pascal") == 0)
869050397Sobrien    add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Pascal83);
869150397Sobrien
869250397Sobrien  else if (flag_traditional)
869350397Sobrien    add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C);
869450397Sobrien
869550397Sobrien  else
869650397Sobrien    add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C89);
869750397Sobrien
869850397Sobrien#if 0 /* unimplemented */
869950397Sobrien  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
870050397Sobrien    add_AT_unsigned (comp_unit_die, DW_AT_macro_info, 0);
870150397Sobrien#endif
870250397Sobrien}
870350397Sobrien
870450397Sobrien/* Generate a DIE for a string type.  */
870550397Sobrien
870650397Sobrienstatic void
870750397Sobriengen_string_type_die (type, context_die)
870850397Sobrien     register tree type;
870950397Sobrien     register dw_die_ref context_die;
871050397Sobrien{
871150397Sobrien  register dw_die_ref type_die
871250397Sobrien    = new_die (DW_TAG_string_type, scope_die_for (type, context_die));
871350397Sobrien
871450397Sobrien  equate_type_number_to_die (type, type_die);
871550397Sobrien
871650397Sobrien  /* Fudge the string length attribute for now.  */
871750397Sobrien
871850397Sobrien  /* TODO: add string length info.
871950397Sobrien   string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type)));
872050397Sobrien			      bound_representation (upper_bound, 0, 'u'); */
872150397Sobrien}
872250397Sobrien
872350397Sobrien/* Generate the DIE for a base class.  */
872450397Sobrien
872550397Sobrienstatic void
872650397Sobriengen_inheritance_die (binfo, context_die)
872750397Sobrien     register tree binfo;
872850397Sobrien     register dw_die_ref context_die;
872950397Sobrien{
873050397Sobrien  dw_die_ref die = new_die (DW_TAG_inheritance, context_die);
873150397Sobrien
873250397Sobrien  add_type_attribute (die, BINFO_TYPE (binfo), 0, 0, context_die);
873350397Sobrien  add_data_member_location_attribute (die, binfo);
873450397Sobrien
873550397Sobrien  if (TREE_VIA_VIRTUAL (binfo))
873650397Sobrien    add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
873750397Sobrien  if (TREE_VIA_PUBLIC (binfo))
873850397Sobrien    add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
873950397Sobrien  else if (TREE_VIA_PROTECTED (binfo))
874050397Sobrien    add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
874150397Sobrien}
874250397Sobrien
874350397Sobrien/* Generate a DIE for a class member.  */
874450397Sobrien
874550397Sobrienstatic void
874650397Sobriengen_member_die (type, context_die)
874750397Sobrien     register tree type;
874850397Sobrien     register dw_die_ref context_die;
874950397Sobrien{
875050397Sobrien  register tree member;
875150397Sobrien
875250397Sobrien  /* If this is not an incomplete type, output descriptions of each of its
875350397Sobrien     members. Note that as we output the DIEs necessary to represent the
875450397Sobrien     members of this record or union type, we will also be trying to output
875550397Sobrien     DIEs to represent the *types* of those members. However the `type'
875650397Sobrien     function (above) will specifically avoid generating type DIEs for member
875750397Sobrien     types *within* the list of member DIEs for this (containing) type execpt
875850397Sobrien     for those types (of members) which are explicitly marked as also being
875950397Sobrien     members of this (containing) type themselves.  The g++ front- end can
876050397Sobrien     force any given type to be treated as a member of some other
876150397Sobrien     (containing) type by setting the TYPE_CONTEXT of the given (member) type
876250397Sobrien     to point to the TREE node representing the appropriate (containing)
876350397Sobrien     type.  */
876450397Sobrien
876550397Sobrien  /* First output info about the base classes.  */
876650397Sobrien  if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type))
876750397Sobrien    {
876850397Sobrien      register tree bases = TYPE_BINFO_BASETYPES (type);
876950397Sobrien      register int n_bases = TREE_VEC_LENGTH (bases);
877050397Sobrien      register int i;
877150397Sobrien
877250397Sobrien      for (i = 0; i < n_bases; i++)
877350397Sobrien	gen_inheritance_die (TREE_VEC_ELT (bases, i), context_die);
877450397Sobrien    }
877550397Sobrien
877650397Sobrien  /* Now output info about the data members and type members.  */
877750397Sobrien  for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
877850397Sobrien    gen_decl_die (member, context_die);
877950397Sobrien
878050397Sobrien  /* Now output info about the function members (if any).  */
878150397Sobrien  for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member))
878250397Sobrien    gen_decl_die (member, context_die);
878350397Sobrien}
878450397Sobrien
878550397Sobrien/* Generate a DIE for a structure or union type.  */
878650397Sobrien
878750397Sobrienstatic void
878850397Sobriengen_struct_or_union_type_die (type, context_die)
878950397Sobrien     register tree type;
879050397Sobrien     register dw_die_ref context_die;
879150397Sobrien{
879250397Sobrien  register dw_die_ref type_die = lookup_type_die (type);
879350397Sobrien  register dw_die_ref scope_die = 0;
879450397Sobrien  register int nested = 0;
879550397Sobrien
879650397Sobrien  if (type_die && ! TYPE_SIZE (type))
879750397Sobrien    return;
879850397Sobrien
879950397Sobrien  if (TYPE_CONTEXT (type) != NULL_TREE
880050397Sobrien      && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't')
880150397Sobrien    nested = 1;
880250397Sobrien
880350397Sobrien  scope_die = scope_die_for (type, context_die);
880450397Sobrien
880550397Sobrien  if (! type_die || (nested && scope_die == comp_unit_die))
880650397Sobrien    /* First occurrence of type or toplevel definition of nested class.  */
880750397Sobrien    {
880850397Sobrien      register dw_die_ref old_die = type_die;
880950397Sobrien
881050397Sobrien      type_die = new_die (TREE_CODE (type) == RECORD_TYPE
881150397Sobrien			  ? DW_TAG_structure_type : DW_TAG_union_type,
881250397Sobrien			  scope_die);
881350397Sobrien      equate_type_number_to_die (type, type_die);
881450397Sobrien      add_name_attribute (type_die, type_tag (type));
881550397Sobrien      if (old_die)
881650397Sobrien	add_AT_die_ref (type_die, DW_AT_specification, old_die);
881750397Sobrien    }
881850397Sobrien  else
881950397Sobrien    remove_AT (type_die, DW_AT_declaration);
882050397Sobrien
882150397Sobrien  /* If we're not in the right context to be defining this type, defer to
882250397Sobrien     avoid tricky recursion.  */
882350397Sobrien  if (TYPE_SIZE (type) && decl_scope_depth > 0 && scope_die == comp_unit_die)
882450397Sobrien    {
882550397Sobrien      add_AT_flag (type_die, DW_AT_declaration, 1);
882650397Sobrien      pend_type (type);
882750397Sobrien    }
882850397Sobrien  /* If this type has been completed, then give it a byte_size attribute and
882950397Sobrien     then give a list of members.  */
883050397Sobrien  else if (TYPE_SIZE (type))
883150397Sobrien    {
883250397Sobrien      /* Prevent infinite recursion in cases where the type of some member of
883350397Sobrien         this type is expressed in terms of this type itself.  */
883450397Sobrien      TREE_ASM_WRITTEN (type) = 1;
883550397Sobrien      add_byte_size_attribute (type_die, type);
883650397Sobrien      if (TYPE_STUB_DECL (type) != NULL_TREE)
883750397Sobrien	add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
883850397Sobrien
883950397Sobrien      /* If the first reference to this type was as the return type of an
884050397Sobrien	 inline function, then it may not have a parent.  Fix this now.  */
884150397Sobrien      if (type_die->die_parent == NULL)
884250397Sobrien	add_child_die (scope_die, type_die);
884350397Sobrien
884450397Sobrien      push_decl_scope (type);
884550397Sobrien      gen_member_die (type, type_die);
884650397Sobrien      pop_decl_scope ();
884750397Sobrien
884850397Sobrien      /* GNU extension: Record what type our vtable lives in.  */
884950397Sobrien      if (TYPE_VFIELD (type))
885050397Sobrien	{
885150397Sobrien	  tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type));
885250397Sobrien
885350397Sobrien	  gen_type_die (vtype, context_die);
885450397Sobrien	  add_AT_die_ref (type_die, DW_AT_containing_type,
885550397Sobrien			  lookup_type_die (vtype));
885650397Sobrien	}
885750397Sobrien    }
885850397Sobrien  else
885950397Sobrien    add_AT_flag (type_die, DW_AT_declaration, 1);
886050397Sobrien}
886150397Sobrien
886250397Sobrien/* Generate a DIE for a subroutine _type_.  */
886350397Sobrien
886450397Sobrienstatic void
886550397Sobriengen_subroutine_type_die (type, context_die)
886650397Sobrien     register tree type;
886750397Sobrien     register dw_die_ref context_die;
886850397Sobrien{
886950397Sobrien  register tree return_type = TREE_TYPE (type);
887050397Sobrien  register dw_die_ref subr_die
887150397Sobrien    = new_die (DW_TAG_subroutine_type, scope_die_for (type, context_die));
887250397Sobrien
887350397Sobrien  equate_type_number_to_die (type, subr_die);
887450397Sobrien  add_prototyped_attribute (subr_die, type);
887550397Sobrien  add_type_attribute (subr_die, return_type, 0, 0, context_die);
887650397Sobrien  gen_formal_types_die (type, subr_die);
887750397Sobrien}
887850397Sobrien
887950397Sobrien/* Generate a DIE for a type definition */
888050397Sobrien
888150397Sobrienstatic void
888250397Sobriengen_typedef_die (decl, context_die)
888350397Sobrien     register tree decl;
888450397Sobrien     register dw_die_ref context_die;
888550397Sobrien{
888650397Sobrien  register dw_die_ref type_die;
888750397Sobrien  register tree origin;
888850397Sobrien
888950397Sobrien  if (TREE_ASM_WRITTEN (decl))
889050397Sobrien    return;
889150397Sobrien  TREE_ASM_WRITTEN (decl) = 1;
889250397Sobrien
889350397Sobrien  type_die = new_die (DW_TAG_typedef, scope_die_for (decl, context_die));
889450397Sobrien  origin = decl_ultimate_origin (decl);
889550397Sobrien  if (origin != NULL)
889650397Sobrien    add_abstract_origin_attribute (type_die, origin);
889750397Sobrien  else
889850397Sobrien    {
889950397Sobrien      register tree type;
890050397Sobrien      add_name_and_src_coords_attributes (type_die, decl);
890150397Sobrien      if (DECL_ORIGINAL_TYPE (decl))
890250397Sobrien	{
890350397Sobrien	  type = DECL_ORIGINAL_TYPE (decl);
890450397Sobrien	  equate_type_number_to_die (TREE_TYPE (decl), type_die);
890550397Sobrien	}
890650397Sobrien      else
890750397Sobrien	type = TREE_TYPE (decl);
890850397Sobrien      add_type_attribute (type_die, type, TREE_READONLY (decl),
890950397Sobrien			  TREE_THIS_VOLATILE (decl), context_die);
891050397Sobrien    }
891150397Sobrien
891250397Sobrien  if (DECL_ABSTRACT (decl))
891350397Sobrien    equate_decl_number_to_die (decl, type_die);
891450397Sobrien}
891550397Sobrien
891650397Sobrien/* Generate a type description DIE.  */
891750397Sobrien
891850397Sobrienstatic void
891950397Sobriengen_type_die (type, context_die)
892050397Sobrien     register tree type;
892150397Sobrien     register dw_die_ref context_die;
892250397Sobrien{
892350397Sobrien  if (type == NULL_TREE || type == error_mark_node)
892450397Sobrien    return;
892550397Sobrien
892650397Sobrien  /* We are going to output a DIE to represent the unqualified version of
892750397Sobrien     this type (i.e. without any const or volatile qualifiers) so get the
892850397Sobrien     main variant (i.e. the unqualified version) of this type now.  */
892950397Sobrien  type = type_main_variant (type);
893050397Sobrien
893150397Sobrien  if (TREE_ASM_WRITTEN (type))
893250397Sobrien    return;
893350397Sobrien
893450397Sobrien  if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
893550397Sobrien      && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
893650397Sobrien    {
893750397Sobrien      TREE_ASM_WRITTEN (type) = 1;
893850397Sobrien      gen_decl_die (TYPE_NAME (type), context_die);
893950397Sobrien      return;
894050397Sobrien    }
894150397Sobrien
894250397Sobrien  switch (TREE_CODE (type))
894350397Sobrien    {
894450397Sobrien    case ERROR_MARK:
894550397Sobrien      break;
894650397Sobrien
894750397Sobrien    case POINTER_TYPE:
894850397Sobrien    case REFERENCE_TYPE:
894950397Sobrien      /* We must set TREE_ASM_WRITTEN in case this is a recursive type.  This
895050397Sobrien	 ensures that the gen_type_die recursion will terminate even if the
895150397Sobrien	 type is recursive.  Recursive types are possible in Ada.  */
895250397Sobrien      /* ??? We could perhaps do this for all types before the switch
895350397Sobrien	 statement.  */
895450397Sobrien      TREE_ASM_WRITTEN (type) = 1;
895550397Sobrien
895650397Sobrien      /* For these types, all that is required is that we output a DIE (or a
895750397Sobrien         set of DIEs) to represent the "basis" type.  */
895850397Sobrien      gen_type_die (TREE_TYPE (type), context_die);
895950397Sobrien      break;
896050397Sobrien
896150397Sobrien    case OFFSET_TYPE:
896250397Sobrien      /* This code is used for C++ pointer-to-data-member types.
896350397Sobrien	 Output a description of the relevant class type.  */
896450397Sobrien      gen_type_die (TYPE_OFFSET_BASETYPE (type), context_die);
896550397Sobrien
896650397Sobrien      /* Output a description of the type of the object pointed to.  */
896750397Sobrien      gen_type_die (TREE_TYPE (type), context_die);
896850397Sobrien
896950397Sobrien      /* Now output a DIE to represent this pointer-to-data-member type
897050397Sobrien         itself.  */
897150397Sobrien      gen_ptr_to_mbr_type_die (type, context_die);
897250397Sobrien      break;
897350397Sobrien
897450397Sobrien    case SET_TYPE:
897550397Sobrien      gen_type_die (TYPE_DOMAIN (type), context_die);
897650397Sobrien      gen_set_type_die (type, context_die);
897750397Sobrien      break;
897850397Sobrien
897950397Sobrien    case FILE_TYPE:
898050397Sobrien      gen_type_die (TREE_TYPE (type), context_die);
898150397Sobrien      abort ();			/* No way to represent these in Dwarf yet!  */
898250397Sobrien      break;
898350397Sobrien
898450397Sobrien    case FUNCTION_TYPE:
898550397Sobrien      /* Force out return type (in case it wasn't forced out already).  */
898650397Sobrien      gen_type_die (TREE_TYPE (type), context_die);
898750397Sobrien      gen_subroutine_type_die (type, context_die);
898850397Sobrien      break;
898950397Sobrien
899050397Sobrien    case METHOD_TYPE:
899150397Sobrien      /* Force out return type (in case it wasn't forced out already).  */
899250397Sobrien      gen_type_die (TREE_TYPE (type), context_die);
899350397Sobrien      gen_subroutine_type_die (type, context_die);
899450397Sobrien      break;
899550397Sobrien
899650397Sobrien    case ARRAY_TYPE:
899750397Sobrien      if (TYPE_STRING_FLAG (type) && TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE)
899850397Sobrien	{
899950397Sobrien	  gen_type_die (TREE_TYPE (type), context_die);
900050397Sobrien	  gen_string_type_die (type, context_die);
900150397Sobrien	}
900250397Sobrien      else
900350397Sobrien	gen_array_type_die (type, context_die);
900450397Sobrien      break;
900550397Sobrien
900650397Sobrien    case ENUMERAL_TYPE:
900750397Sobrien    case RECORD_TYPE:
900850397Sobrien    case UNION_TYPE:
900950397Sobrien    case QUAL_UNION_TYPE:
901050397Sobrien      /* If this is a nested type whose containing class hasn't been
901150397Sobrien	 written out yet, writing it out will cover this one, too.  */
901250397Sobrien      if (TYPE_CONTEXT (type)
901350397Sobrien	  && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't'
901450397Sobrien	  && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
901550397Sobrien	{
901650397Sobrien	  gen_type_die (TYPE_CONTEXT (type), context_die);
901750397Sobrien
901850397Sobrien	  if (TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
901950397Sobrien	    return;
902050397Sobrien
902150397Sobrien	  /* If that failed, attach ourselves to the stub.  */
902250397Sobrien	  push_decl_scope (TYPE_CONTEXT (type));
902350397Sobrien	  context_die = lookup_type_die (TYPE_CONTEXT (type));
902450397Sobrien	}
902550397Sobrien
902650397Sobrien      if (TREE_CODE (type) == ENUMERAL_TYPE)
902750397Sobrien	gen_enumeration_type_die (type, context_die);
902850397Sobrien      else
902950397Sobrien	gen_struct_or_union_type_die (type, context_die);
903050397Sobrien
903150397Sobrien      if (TYPE_CONTEXT (type)
903250397Sobrien	  && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't'
903350397Sobrien	  && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
903450397Sobrien	pop_decl_scope ();
903550397Sobrien
903650397Sobrien      /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix
903750397Sobrien	 it up if it is ever completed.  gen_*_type_die will set it for us
903850397Sobrien	 when appropriate.  */
903950397Sobrien      return;
904050397Sobrien
904150397Sobrien    case VOID_TYPE:
904250397Sobrien    case INTEGER_TYPE:
904350397Sobrien    case REAL_TYPE:
904450397Sobrien    case COMPLEX_TYPE:
904550397Sobrien    case BOOLEAN_TYPE:
904650397Sobrien    case CHAR_TYPE:
904750397Sobrien      /* No DIEs needed for fundamental types.  */
904850397Sobrien      break;
904950397Sobrien
905050397Sobrien    case LANG_TYPE:
905150397Sobrien      /* No Dwarf representation currently defined.  */
905250397Sobrien      break;
905350397Sobrien
905450397Sobrien    default:
905550397Sobrien      abort ();
905650397Sobrien    }
905750397Sobrien
905850397Sobrien  TREE_ASM_WRITTEN (type) = 1;
905950397Sobrien}
906050397Sobrien
906150397Sobrien/* Generate a DIE for a tagged type instantiation.  */
906250397Sobrien
906350397Sobrienstatic void
906450397Sobriengen_tagged_type_instantiation_die (type, context_die)
906550397Sobrien     register tree type;
906650397Sobrien     register dw_die_ref context_die;
906750397Sobrien{
906850397Sobrien  if (type == NULL_TREE || type == error_mark_node)
906950397Sobrien    return;
907050397Sobrien
907150397Sobrien  /* We are going to output a DIE to represent the unqualified version of
907250397Sobrien     this type (i.e. without any const or volatile qualifiers) so make sure
907350397Sobrien     that we have the main variant (i.e. the unqualified version) of this
907450397Sobrien     type now.  */
907550397Sobrien  if (type != type_main_variant (type)
907650397Sobrien      || !TREE_ASM_WRITTEN (type))
907750397Sobrien    abort ();
907850397Sobrien
907950397Sobrien  switch (TREE_CODE (type))
908050397Sobrien    {
908150397Sobrien    case ERROR_MARK:
908250397Sobrien      break;
908350397Sobrien
908450397Sobrien    case ENUMERAL_TYPE:
908550397Sobrien      gen_inlined_enumeration_type_die (type, context_die);
908650397Sobrien      break;
908750397Sobrien
908850397Sobrien    case RECORD_TYPE:
908950397Sobrien      gen_inlined_structure_type_die (type, context_die);
909050397Sobrien      break;
909150397Sobrien
909250397Sobrien    case UNION_TYPE:
909350397Sobrien    case QUAL_UNION_TYPE:
909450397Sobrien      gen_inlined_union_type_die (type, context_die);
909550397Sobrien      break;
909650397Sobrien
909750397Sobrien    default:
909850397Sobrien      abort ();
909950397Sobrien    }
910050397Sobrien}
910150397Sobrien
910250397Sobrien/* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the
910350397Sobrien   things which are local to the given block.  */
910450397Sobrien
910550397Sobrienstatic void
910650397Sobriengen_block_die (stmt, context_die, depth)
910750397Sobrien     register tree stmt;
910850397Sobrien     register dw_die_ref context_die;
910950397Sobrien     int depth;
911050397Sobrien{
911150397Sobrien  register int must_output_die = 0;
911250397Sobrien  register tree origin;
911350397Sobrien  register tree decl;
911450397Sobrien  register enum tree_code origin_code;
911550397Sobrien
911650397Sobrien  /* Ignore blocks never really used to make RTL.  */
911750397Sobrien
911850397Sobrien  if (stmt == NULL_TREE || !TREE_USED (stmt))
911950397Sobrien    return;
912050397Sobrien
912150397Sobrien  /* Determine the "ultimate origin" of this block.  This block may be an
912250397Sobrien     inlined instance of an inlined instance of inline function, so we have
912350397Sobrien     to trace all of the way back through the origin chain to find out what
912450397Sobrien     sort of node actually served as the original seed for the creation of
912550397Sobrien     the current block.  */
912650397Sobrien  origin = block_ultimate_origin (stmt);
912750397Sobrien  origin_code = (origin != NULL) ? TREE_CODE (origin) : ERROR_MARK;
912850397Sobrien
912950397Sobrien  /* Determine if we need to output any Dwarf DIEs at all to represent this
913050397Sobrien     block.  */
913150397Sobrien  if (origin_code == FUNCTION_DECL)
913250397Sobrien    /* The outer scopes for inlinings *must* always be represented.  We
913350397Sobrien       generate DW_TAG_inlined_subroutine DIEs for them.  (See below.) */
913450397Sobrien    must_output_die = 1;
913550397Sobrien  else
913650397Sobrien    {
913750397Sobrien      /* In the case where the current block represents an inlining of the
913850397Sobrien         "body block" of an inline function, we must *NOT* output any DIE for
913950397Sobrien         this block because we have already output a DIE to represent the
914050397Sobrien         whole inlined function scope and the "body block" of any function
914150397Sobrien         doesn't really represent a different scope according to ANSI C
914250397Sobrien         rules.  So we check here to make sure that this block does not
914350397Sobrien         represent a "body block inlining" before trying to set the
914450397Sobrien         `must_output_die' flag.  */
914550397Sobrien      if (! is_body_block (origin ? origin : stmt))
914650397Sobrien	{
914750397Sobrien	  /* Determine if this block directly contains any "significant"
914850397Sobrien	     local declarations which we will need to output DIEs for.  */
914950397Sobrien	  if (debug_info_level > DINFO_LEVEL_TERSE)
915050397Sobrien	    /* We are not in terse mode so *any* local declaration counts
915150397Sobrien	       as being a "significant" one.  */
915250397Sobrien	    must_output_die = (BLOCK_VARS (stmt) != NULL);
915350397Sobrien	  else
915450397Sobrien	    /* We are in terse mode, so only local (nested) function
915550397Sobrien	       definitions count as "significant" local declarations.  */
915650397Sobrien	    for (decl = BLOCK_VARS (stmt);
915750397Sobrien		 decl != NULL; decl = TREE_CHAIN (decl))
915850397Sobrien	      if (TREE_CODE (decl) == FUNCTION_DECL
915950397Sobrien		  && DECL_INITIAL (decl))
916050397Sobrien		{
916150397Sobrien		  must_output_die = 1;
916250397Sobrien		  break;
916350397Sobrien		}
916450397Sobrien	}
916550397Sobrien    }
916650397Sobrien
916750397Sobrien  /* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block
916850397Sobrien     DIE for any block which contains no significant local declarations at
916950397Sobrien     all.  Rather, in such cases we just call `decls_for_scope' so that any
917050397Sobrien     needed Dwarf info for any sub-blocks will get properly generated. Note
917150397Sobrien     that in terse mode, our definition of what constitutes a "significant"
917250397Sobrien     local declaration gets restricted to include only inlined function
917350397Sobrien     instances and local (nested) function definitions.  */
917450397Sobrien  if (must_output_die)
917550397Sobrien    {
917650397Sobrien      if (origin_code == FUNCTION_DECL)
917750397Sobrien	gen_inlined_subroutine_die (stmt, context_die, depth);
917850397Sobrien      else
917950397Sobrien	gen_lexical_block_die (stmt, context_die, depth);
918050397Sobrien    }
918150397Sobrien  else
918250397Sobrien    decls_for_scope (stmt, context_die, depth);
918350397Sobrien}
918450397Sobrien
918550397Sobrien/* Generate all of the decls declared within a given scope and (recursively)
918650397Sobrien   all of its sub-blocks.  */
918750397Sobrien
918850397Sobrienstatic void
918950397Sobriendecls_for_scope (stmt, context_die, depth)
919050397Sobrien     register tree stmt;
919150397Sobrien     register dw_die_ref context_die;
919250397Sobrien     int depth;
919350397Sobrien{
919450397Sobrien  register tree decl;
919550397Sobrien  register tree subblocks;
919650397Sobrien
919750397Sobrien  /* Ignore blocks never really used to make RTL.  */
919850397Sobrien  if (stmt == NULL_TREE || ! TREE_USED (stmt))
919950397Sobrien    return;
920050397Sobrien
920150397Sobrien  if (!BLOCK_ABSTRACT (stmt) && depth > 0)
920250397Sobrien    next_block_number++;
920350397Sobrien
920450397Sobrien  /* Output the DIEs to represent all of the data objects and typedefs
920550397Sobrien     declared directly within this block but not within any nested
920650397Sobrien     sub-blocks.  Also, nested function and tag DIEs have been
920750397Sobrien     generated with a parent of NULL; fix that up now.  */
920850397Sobrien  for (decl = BLOCK_VARS (stmt);
920950397Sobrien       decl != NULL; decl = TREE_CHAIN (decl))
921050397Sobrien    {
921150397Sobrien      register dw_die_ref die;
921250397Sobrien
921350397Sobrien      if (TREE_CODE (decl) == FUNCTION_DECL)
921450397Sobrien	die = lookup_decl_die (decl);
921550397Sobrien      else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl))
921650397Sobrien	die = lookup_type_die (TREE_TYPE (decl));
921750397Sobrien      else
921850397Sobrien	die = NULL;
921950397Sobrien
922050397Sobrien      if (die != NULL && die->die_parent == NULL)
922150397Sobrien	add_child_die (context_die, die);
922250397Sobrien      else
922350397Sobrien	gen_decl_die (decl, context_die);
922450397Sobrien    }
922550397Sobrien
922650397Sobrien  /* Output the DIEs to represent all sub-blocks (and the items declared
922750397Sobrien     therein) of this block.  */
922850397Sobrien  for (subblocks = BLOCK_SUBBLOCKS (stmt);
922950397Sobrien       subblocks != NULL;
923050397Sobrien       subblocks = BLOCK_CHAIN (subblocks))
923150397Sobrien    gen_block_die (subblocks, context_die, depth + 1);
923250397Sobrien}
923350397Sobrien
923450397Sobrien/* Is this a typedef we can avoid emitting?  */
923550397Sobrien
923650397Sobrienstatic inline int
923750397Sobrienis_redundant_typedef (decl)
923850397Sobrien     register tree decl;
923950397Sobrien{
924050397Sobrien  if (TYPE_DECL_IS_STUB (decl))
924150397Sobrien    return 1;
924250397Sobrien
924350397Sobrien  if (DECL_ARTIFICIAL (decl)
924450397Sobrien      && DECL_CONTEXT (decl)
924550397Sobrien      && is_tagged_type (DECL_CONTEXT (decl))
924650397Sobrien      && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
924750397Sobrien      && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
924850397Sobrien    /* Also ignore the artificial member typedef for the class name.  */
924950397Sobrien    return 1;
925050397Sobrien
925150397Sobrien  return 0;
925250397Sobrien}
925350397Sobrien
925450397Sobrien/* Generate Dwarf debug information for a decl described by DECL.  */
925550397Sobrien
925650397Sobrienstatic void
925750397Sobriengen_decl_die (decl, context_die)
925850397Sobrien     register tree decl;
925950397Sobrien     register dw_die_ref context_die;
926050397Sobrien{
926150397Sobrien  register tree origin;
926250397Sobrien
926350397Sobrien  /* Make a note of the decl node we are going to be working on.  We may need
926450397Sobrien     to give the user the source coordinates of where it appeared in case we
926550397Sobrien     notice (later on) that something about it looks screwy.  */
926650397Sobrien  dwarf_last_decl = decl;
926750397Sobrien
926850397Sobrien  if (TREE_CODE (decl) == ERROR_MARK)
926950397Sobrien    return;
927050397Sobrien
927150397Sobrien  /* If this ..._DECL node is marked to be ignored, then ignore it. But don't
927250397Sobrien     ignore a function definition, since that would screw up our count of
927350397Sobrien     blocks, and that in turn will completely screw up the labels we will
927450397Sobrien     reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for
927550397Sobrien     subsequent blocks).  */
927650397Sobrien  if (DECL_IGNORED_P (decl) && TREE_CODE (decl) != FUNCTION_DECL)
927750397Sobrien    return;
927850397Sobrien
927950397Sobrien  switch (TREE_CODE (decl))
928050397Sobrien    {
928150397Sobrien    case CONST_DECL:
928250397Sobrien      /* The individual enumerators of an enum type get output when we output
928350397Sobrien         the Dwarf representation of the relevant enum type itself.  */
928450397Sobrien      break;
928550397Sobrien
928650397Sobrien    case FUNCTION_DECL:
928750397Sobrien      /* Don't output any DIEs to represent mere function declarations,
928850397Sobrien	 unless they are class members or explicit block externs.  */
928950397Sobrien      if (DECL_INITIAL (decl) == NULL_TREE && DECL_CONTEXT (decl) == NULL_TREE
929050397Sobrien	  && (current_function_decl == NULL_TREE || ! DECL_ARTIFICIAL (decl)))
929150397Sobrien	break;
929250397Sobrien
929350397Sobrien      if (debug_info_level > DINFO_LEVEL_TERSE)
929450397Sobrien	{
929550397Sobrien	  /* Before we describe the FUNCTION_DECL itself, make sure that we
929650397Sobrien	     have described its return type.  */
929750397Sobrien	  gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die);
929850397Sobrien
929950397Sobrien	  /* And its containing type.  */
930050397Sobrien	  origin = decl_class_context (decl);
930150397Sobrien	  if (origin != NULL_TREE)
930250397Sobrien	    gen_type_die (origin, context_die);
930350397Sobrien
930450397Sobrien	  /* And its virtual context.  */
930550397Sobrien	  if (DECL_VINDEX (decl) != NULL_TREE)
930650397Sobrien	    gen_type_die (DECL_CONTEXT (decl), context_die);
930750397Sobrien	}
930850397Sobrien
930950397Sobrien      /* Now output a DIE to represent the function itself.  */
931050397Sobrien      gen_subprogram_die (decl, context_die);
931150397Sobrien      break;
931250397Sobrien
931350397Sobrien    case TYPE_DECL:
931450397Sobrien      /* If we are in terse mode, don't generate any DIEs to represent any
931550397Sobrien         actual typedefs.  */
931650397Sobrien      if (debug_info_level <= DINFO_LEVEL_TERSE)
931750397Sobrien	break;
931850397Sobrien
931950397Sobrien      /* In the special case of a TYPE_DECL node representing the
932050397Sobrien         declaration of some type tag, if the given TYPE_DECL is marked as
932150397Sobrien         having been instantiated from some other (original) TYPE_DECL node
932250397Sobrien         (e.g. one which was generated within the original definition of an
932350397Sobrien         inline function) we have to generate a special (abbreviated)
932450397Sobrien         DW_TAG_structure_type, DW_TAG_union_type, or DW_TAG_enumeration_type
932550397Sobrien         DIE here.  */
932650397Sobrien      if (TYPE_DECL_IS_STUB (decl) && DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE)
932750397Sobrien	{
932850397Sobrien	  gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die);
932950397Sobrien	  break;
933050397Sobrien	}
933150397Sobrien
933250397Sobrien      if (is_redundant_typedef (decl))
933350397Sobrien	gen_type_die (TREE_TYPE (decl), context_die);
933450397Sobrien      else
933550397Sobrien	/* Output a DIE to represent the typedef itself.  */
933650397Sobrien	gen_typedef_die (decl, context_die);
933750397Sobrien      break;
933850397Sobrien
933950397Sobrien    case LABEL_DECL:
934050397Sobrien      if (debug_info_level >= DINFO_LEVEL_NORMAL)
934150397Sobrien	gen_label_die (decl, context_die);
934250397Sobrien      break;
934350397Sobrien
934450397Sobrien    case VAR_DECL:
934550397Sobrien      /* If we are in terse mode, don't generate any DIEs to represent any
934650397Sobrien         variable declarations or definitions.  */
934750397Sobrien      if (debug_info_level <= DINFO_LEVEL_TERSE)
934850397Sobrien	break;
934950397Sobrien
935050397Sobrien      /* Output any DIEs that are needed to specify the type of this data
935150397Sobrien         object.  */
935250397Sobrien      gen_type_die (TREE_TYPE (decl), context_die);
935350397Sobrien
935450397Sobrien      /* And its containing type.  */
935550397Sobrien      origin = decl_class_context (decl);
935650397Sobrien      if (origin != NULL_TREE)
935750397Sobrien	gen_type_die (origin, context_die);
935850397Sobrien
935950397Sobrien      /* Now output the DIE to represent the data object itself.  This gets
936050397Sobrien         complicated because of the possibility that the VAR_DECL really
936150397Sobrien         represents an inlined instance of a formal parameter for an inline
936250397Sobrien         function.  */
936350397Sobrien      origin = decl_ultimate_origin (decl);
936450397Sobrien      if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
936550397Sobrien	gen_formal_parameter_die (decl, context_die);
936650397Sobrien      else
936750397Sobrien	gen_variable_die (decl, context_die);
936850397Sobrien      break;
936950397Sobrien
937050397Sobrien    case FIELD_DECL:
937150397Sobrien      /* Ignore the nameless fields that are used to skip bits, but
937250397Sobrien	 handle C++ anonymous unions.  */
937350397Sobrien      if (DECL_NAME (decl) != NULL_TREE
937450397Sobrien	  || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE)
937550397Sobrien	{
937650397Sobrien	  gen_type_die (member_declared_type (decl), context_die);
937750397Sobrien	  gen_field_die (decl, context_die);
937850397Sobrien	}
937950397Sobrien      break;
938050397Sobrien
938150397Sobrien    case PARM_DECL:
938250397Sobrien      gen_type_die (TREE_TYPE (decl), context_die);
938350397Sobrien      gen_formal_parameter_die (decl, context_die);
938450397Sobrien      break;
938550397Sobrien
938650397Sobrien    default:
938750397Sobrien      abort ();
938850397Sobrien    }
938950397Sobrien}
939050397Sobrien
939150397Sobrien/* Write the debugging output for DECL.  */
939250397Sobrien
939350397Sobrienvoid
939450397Sobriendwarf2out_decl (decl)
939550397Sobrien     register tree decl;
939650397Sobrien{
939750397Sobrien  register dw_die_ref context_die = comp_unit_die;
939850397Sobrien
939950397Sobrien  if (TREE_CODE (decl) == ERROR_MARK)
940050397Sobrien    return;
940150397Sobrien
940250397Sobrien  /* If this ..._DECL node is marked to be ignored, then ignore it.  We gotta
940350397Sobrien     hope that the node in question doesn't represent a function definition.
940450397Sobrien     If it does, then totally ignoring it is bound to screw up our count of
940550397Sobrien     blocks, and that in turn will completely screw up the labels we will
940650397Sobrien     reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for
940750397Sobrien     subsequent blocks).  (It's too bad that BLOCK nodes don't carry their
940850397Sobrien     own sequence numbers with them!) */
940950397Sobrien  if (DECL_IGNORED_P (decl))
941050397Sobrien    {
941150397Sobrien      if (TREE_CODE (decl) == FUNCTION_DECL
941250397Sobrien	  && DECL_INITIAL (decl) != NULL)
941350397Sobrien	abort ();
941450397Sobrien
941550397Sobrien      return;
941650397Sobrien    }
941750397Sobrien
941850397Sobrien  switch (TREE_CODE (decl))
941950397Sobrien    {
942050397Sobrien    case FUNCTION_DECL:
942150397Sobrien      /* Ignore this FUNCTION_DECL if it refers to a builtin declaration of a
942250397Sobrien         builtin function.  Explicit programmer-supplied declarations of
942350397Sobrien         these same functions should NOT be ignored however.  */
942450397Sobrien      if (DECL_EXTERNAL (decl) && DECL_FUNCTION_CODE (decl))
942550397Sobrien	return;
942650397Sobrien
942750397Sobrien      /* What we would really like to do here is to filter out all mere
942850397Sobrien         file-scope declarations of file-scope functions which are never
942950397Sobrien         referenced later within this translation unit (and keep all of ones
943050397Sobrien         that *are* referenced later on) but we aren't clairvoyant, so we have
943150397Sobrien         no idea which functions will be referenced in the future (i.e. later
943250397Sobrien         on within the current translation unit). So here we just ignore all
943350397Sobrien         file-scope function declarations which are not also definitions.  If
943450397Sobrien         and when the debugger needs to know something about these functions,
943550397Sobrien         it wil have to hunt around and find the DWARF information associated
943650397Sobrien         with the definition of the function. Note that we can't just check
943750397Sobrien         `DECL_EXTERNAL' to find out which FUNCTION_DECL nodes represent
943850397Sobrien         definitions and which ones represent mere declarations.  We have to
943950397Sobrien         check `DECL_INITIAL' instead. That's because the C front-end
944050397Sobrien         supports some weird semantics for "extern inline" function
944150397Sobrien         definitions.  These can get inlined within the current translation
944250397Sobrien         unit (an thus, we need to generate DWARF info for their abstract
944350397Sobrien         instances so that the DWARF info for the concrete inlined instances
944450397Sobrien         can have something to refer to) but the compiler never generates any
944550397Sobrien         out-of-lines instances of such things (despite the fact that they
944650397Sobrien         *are* definitions).  The important point is that the C front-end
944750397Sobrien         marks these "extern inline" functions as DECL_EXTERNAL, but we need
944850397Sobrien         to generate DWARF for them anyway. Note that the C++ front-end also
944950397Sobrien         plays some similar games for inline function definitions appearing
945050397Sobrien         within include files which also contain
945150397Sobrien	 `#pragma interface' pragmas.  */
945250397Sobrien      if (DECL_INITIAL (decl) == NULL_TREE)
945350397Sobrien	return;
945450397Sobrien
945550397Sobrien      /* If we're a nested function, initially use a parent of NULL; if we're
945650397Sobrien	 a plain function, this will be fixed up in decls_for_scope.  If
945750397Sobrien	 we're a method, it will be ignored, since we already have a DIE.  */
945850397Sobrien      if (decl_function_context (decl))
945950397Sobrien	context_die = NULL;
946050397Sobrien
946150397Sobrien      break;
946250397Sobrien
946350397Sobrien    case VAR_DECL:
946450397Sobrien      /* Ignore this VAR_DECL if it refers to a file-scope extern data object
946550397Sobrien         declaration and if the declaration was never even referenced from
946650397Sobrien         within this entire compilation unit.  We suppress these DIEs in
946750397Sobrien         order to save space in the .debug section (by eliminating entries
946850397Sobrien         which are probably useless).  Note that we must not suppress
946950397Sobrien         block-local extern declarations (whether used or not) because that
947050397Sobrien         would screw-up the debugger's name lookup mechanism and cause it to
947150397Sobrien         miss things which really ought to be in scope at a given point.  */
947250397Sobrien      if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
947350397Sobrien	return;
947450397Sobrien
947550397Sobrien      /* If we are in terse mode, don't generate any DIEs to represent any
947650397Sobrien         variable declarations or definitions.  */
947750397Sobrien      if (debug_info_level <= DINFO_LEVEL_TERSE)
947850397Sobrien	return;
947950397Sobrien      break;
948050397Sobrien
948150397Sobrien    case TYPE_DECL:
948250397Sobrien      /* Don't bother trying to generate any DIEs to represent any of the
948350397Sobrien         normal built-in types for the language we are compiling.  */
948450397Sobrien      if (DECL_SOURCE_LINE (decl) == 0)
948550397Sobrien	{
948650397Sobrien	  /* OK, we need to generate one for `bool' so GDB knows what type
948750397Sobrien             comparisons have.  */
948850397Sobrien	  if ((get_AT_unsigned (comp_unit_die, DW_AT_language)
948950397Sobrien	       == DW_LANG_C_plus_plus)
949050397Sobrien	      && TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE)
949150397Sobrien	    modified_type_die (TREE_TYPE (decl), 0, 0, NULL);
949250397Sobrien
949350397Sobrien	  return;
949450397Sobrien	}
949550397Sobrien
949650397Sobrien      /* If we are in terse mode, don't generate any DIEs for types.  */
949750397Sobrien      if (debug_info_level <= DINFO_LEVEL_TERSE)
949850397Sobrien	return;
949950397Sobrien
950050397Sobrien      /* If we're a function-scope tag, initially use a parent of NULL;
950150397Sobrien	 this will be fixed up in decls_for_scope.  */
950250397Sobrien      if (decl_function_context (decl))
950350397Sobrien	context_die = NULL;
950450397Sobrien
950550397Sobrien      break;
950650397Sobrien
950750397Sobrien    default:
950850397Sobrien      return;
950950397Sobrien    }
951050397Sobrien
951150397Sobrien  gen_decl_die (decl, context_die);
951250397Sobrien  output_pending_types_for_scope (comp_unit_die);
951350397Sobrien}
951450397Sobrien
951550397Sobrien/* Output a marker (i.e. a label) for the beginning of the generated code for
951650397Sobrien   a lexical block.  */
951750397Sobrien
951850397Sobrienvoid
951950397Sobriendwarf2out_begin_block (blocknum)
952050397Sobrien     register unsigned blocknum;
952150397Sobrien{
952250397Sobrien  function_section (current_function_decl);
952350397Sobrien  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
952450397Sobrien}
952550397Sobrien
952650397Sobrien/* Output a marker (i.e. a label) for the end of the generated code for a
952750397Sobrien   lexical block.  */
952850397Sobrien
952950397Sobrienvoid
953050397Sobriendwarf2out_end_block (blocknum)
953150397Sobrien     register unsigned blocknum;
953250397Sobrien{
953350397Sobrien  function_section (current_function_decl);
953450397Sobrien  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
953550397Sobrien}
953650397Sobrien
953750397Sobrien/* Output a marker (i.e. a label) at a point in the assembly code which
953850397Sobrien   corresponds to a given source level label.  */
953950397Sobrien
954050397Sobrienvoid
954150397Sobriendwarf2out_label (insn)
954250397Sobrien     register rtx insn;
954350397Sobrien{
954450397Sobrien  char label[MAX_ARTIFICIAL_LABEL_BYTES];
954550397Sobrien
954650397Sobrien  if (debug_info_level >= DINFO_LEVEL_NORMAL)
954750397Sobrien    {
954850397Sobrien      function_section (current_function_decl);
954950397Sobrien      sprintf (label, INSN_LABEL_FMT, current_funcdef_number);
955050397Sobrien      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, label,
955150397Sobrien				 (unsigned) INSN_UID (insn));
955250397Sobrien    }
955350397Sobrien}
955450397Sobrien
955550397Sobrien/* Lookup a filename (in the list of filenames that we know about here in
955650397Sobrien   dwarf2out.c) and return its "index".  The index of each (known) filename is
955750397Sobrien   just a unique number which is associated with only that one filename.
955850397Sobrien   We need such numbers for the sake of generating labels
955950397Sobrien   (in the .debug_sfnames section) and references to those
956050397Sobrien   files  numbers (in the .debug_srcinfo and.debug_macinfo sections).
956150397Sobrien   If the filename given as an argument is not found in our current list,
956250397Sobrien   add it to the list and assign it the next available unique index number.
956350397Sobrien   In order to speed up searches, we remember the index of the filename
956450397Sobrien   was looked up last.  This handles the majority of all searches.  */
956550397Sobrien
956650397Sobrienstatic unsigned
956750397Sobrienlookup_filename (file_name)
956850397Sobrien     char *file_name;
956950397Sobrien{
957050397Sobrien  static unsigned last_file_lookup_index = 0;
957150397Sobrien  register unsigned i;
957250397Sobrien
957350397Sobrien  /* Check to see if the file name that was searched on the previous call
957450397Sobrien     matches this file name. If so, return the index.  */
957550397Sobrien  if (last_file_lookup_index != 0)
957650397Sobrien    if (strcmp (file_name, file_table[last_file_lookup_index]) == 0)
957750397Sobrien      return last_file_lookup_index;
957850397Sobrien
957950397Sobrien  /* Didn't match the previous lookup, search the table */
958050397Sobrien  for (i = 1; i < file_table_in_use; ++i)
958150397Sobrien    if (strcmp (file_name, file_table[i]) == 0)
958250397Sobrien      {
958350397Sobrien	last_file_lookup_index = i;
958450397Sobrien	return i;
958550397Sobrien      }
958650397Sobrien
958750397Sobrien  /* Prepare to add a new table entry by making sure there is enough space in
958850397Sobrien     the table to do so.  If not, expand the current table.  */
958950397Sobrien  if (file_table_in_use == file_table_allocated)
959050397Sobrien    {
959150397Sobrien      file_table_allocated += FILE_TABLE_INCREMENT;
959250397Sobrien      file_table
959350397Sobrien	= (char **) xrealloc (file_table,
959450397Sobrien			      file_table_allocated * sizeof (char *));
959550397Sobrien    }
959650397Sobrien
959750397Sobrien  /* Add the new entry to the end of the filename table.  */
959850397Sobrien  file_table[file_table_in_use] = xstrdup (file_name);
959950397Sobrien  last_file_lookup_index = file_table_in_use++;
960050397Sobrien
960150397Sobrien  return last_file_lookup_index;
960250397Sobrien}
960350397Sobrien
960450397Sobrien/* Output a label to mark the beginning of a source code line entry
960550397Sobrien   and record information relating to this source line, in
960650397Sobrien   'line_info_table' for later output of the .debug_line section.  */
960750397Sobrien
960850397Sobrienvoid
960950397Sobriendwarf2out_line (filename, line)
961050397Sobrien     register char *filename;
961150397Sobrien     register unsigned line;
961250397Sobrien{
961350397Sobrien  if (debug_info_level >= DINFO_LEVEL_NORMAL)
961450397Sobrien    {
961550397Sobrien      function_section (current_function_decl);
961650397Sobrien
961750397Sobrien      if (DECL_SECTION_NAME (current_function_decl))
961850397Sobrien	{
961950397Sobrien	  register dw_separate_line_info_ref line_info;
962050397Sobrien	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, SEPARATE_LINE_CODE_LABEL,
962150397Sobrien				     separate_line_info_table_in_use);
962250397Sobrien	  fputc ('\n', asm_out_file);
962350397Sobrien
962450397Sobrien	  /* expand the line info table if necessary */
962550397Sobrien	  if (separate_line_info_table_in_use
962650397Sobrien	      == separate_line_info_table_allocated)
962750397Sobrien	    {
962850397Sobrien	      separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
962950397Sobrien	      separate_line_info_table
963050397Sobrien		= (dw_separate_line_info_ref)
963150397Sobrien		  xrealloc (separate_line_info_table,
963250397Sobrien			    separate_line_info_table_allocated
963350397Sobrien			    * sizeof (dw_separate_line_info_entry));
963450397Sobrien	    }
963550397Sobrien
963650397Sobrien	  /* Add the new entry at the end of the line_info_table.  */
963750397Sobrien	  line_info
963850397Sobrien	    = &separate_line_info_table[separate_line_info_table_in_use++];
963950397Sobrien	  line_info->dw_file_num = lookup_filename (filename);
964050397Sobrien	  line_info->dw_line_num = line;
964150397Sobrien	  line_info->function = current_funcdef_number;
964250397Sobrien	}
964350397Sobrien      else
964450397Sobrien	{
964550397Sobrien	  register dw_line_info_ref line_info;
964650397Sobrien
964750397Sobrien	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, LINE_CODE_LABEL,
964850397Sobrien				     line_info_table_in_use);
964950397Sobrien	  fputc ('\n', asm_out_file);
965050397Sobrien
965150397Sobrien	  /* Expand the line info table if necessary.  */
965250397Sobrien	  if (line_info_table_in_use == line_info_table_allocated)
965350397Sobrien	    {
965450397Sobrien	      line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
965550397Sobrien	      line_info_table
965650397Sobrien		= (dw_line_info_ref)
965750397Sobrien		  xrealloc (line_info_table,
965850397Sobrien			    (line_info_table_allocated
965950397Sobrien			     * sizeof (dw_line_info_entry)));
966050397Sobrien	    }
966150397Sobrien
966250397Sobrien	  /* Add the new entry at the end of the line_info_table.  */
966350397Sobrien	  line_info = &line_info_table[line_info_table_in_use++];
966450397Sobrien	  line_info->dw_file_num = lookup_filename (filename);
966550397Sobrien	  line_info->dw_line_num = line;
966650397Sobrien	}
966750397Sobrien    }
966850397Sobrien}
966950397Sobrien
967050397Sobrien/* Record the beginning of a new source file, for later output
967150397Sobrien   of the .debug_macinfo section.  At present, unimplemented.  */
967250397Sobrien
967350397Sobrienvoid
967450397Sobriendwarf2out_start_source_file (filename)
967550397Sobrien     register char *filename ATTRIBUTE_UNUSED;
967650397Sobrien{
967750397Sobrien}
967850397Sobrien
967950397Sobrien/* Record the end of a source file, for later output
968050397Sobrien   of the .debug_macinfo section.  At present, unimplemented.  */
968150397Sobrien
968250397Sobrienvoid
968350397Sobriendwarf2out_end_source_file ()
968450397Sobrien{
968550397Sobrien}
968650397Sobrien
968750397Sobrien/* Called from check_newline in c-parse.y.  The `buffer' parameter contains
968850397Sobrien   the tail part of the directive line, i.e. the part which is past the
968950397Sobrien   initial whitespace, #, whitespace, directive-name, whitespace part.  */
969050397Sobrien
969150397Sobrienvoid
969250397Sobriendwarf2out_define (lineno, buffer)
969350397Sobrien     register unsigned lineno;
969450397Sobrien     register char *buffer;
969550397Sobrien{
969650397Sobrien  static int initialized = 0;
969750397Sobrien  if (!initialized)
969850397Sobrien    {
969950397Sobrien      dwarf2out_start_source_file (primary_filename);
970050397Sobrien      initialized = 1;
970150397Sobrien    }
970250397Sobrien}
970350397Sobrien
970450397Sobrien/* Called from check_newline in c-parse.y.  The `buffer' parameter contains
970550397Sobrien   the tail part of the directive line, i.e. the part which is past the
970650397Sobrien   initial whitespace, #, whitespace, directive-name, whitespace part.  */
970750397Sobrien
970850397Sobrienvoid
970950397Sobriendwarf2out_undef (lineno, buffer)
971050397Sobrien     register unsigned lineno ATTRIBUTE_UNUSED;
971150397Sobrien     register char *buffer ATTRIBUTE_UNUSED;
971250397Sobrien{
971350397Sobrien}
971450397Sobrien
971550397Sobrien/* Set up for Dwarf output at the start of compilation.  */
971650397Sobrien
971750397Sobrienvoid
971850397Sobriendwarf2out_init (asm_out_file, main_input_filename)
971950397Sobrien     register FILE *asm_out_file;
972050397Sobrien     register char *main_input_filename;
972150397Sobrien{
972250397Sobrien  /* Remember the name of the primary input file.  */
972350397Sobrien  primary_filename = main_input_filename;
972450397Sobrien
972550397Sobrien  /* Allocate the initial hunk of the file_table.  */
972650397Sobrien  file_table = (char **) xmalloc (FILE_TABLE_INCREMENT * sizeof (char *));
972750397Sobrien  bzero ((char *) file_table, FILE_TABLE_INCREMENT * sizeof (char *));
972850397Sobrien  file_table_allocated = FILE_TABLE_INCREMENT;
972950397Sobrien
973050397Sobrien  /* Skip the first entry - file numbers begin at 1.  */
973150397Sobrien  file_table_in_use = 1;
973250397Sobrien
973350397Sobrien  /* Allocate the initial hunk of the decl_die_table.  */
973450397Sobrien  decl_die_table
973550397Sobrien    = (dw_die_ref *) xmalloc (DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
973650397Sobrien  bzero ((char *) decl_die_table,
973750397Sobrien	 DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
973850397Sobrien  decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT;
973950397Sobrien  decl_die_table_in_use = 0;
974050397Sobrien
974150397Sobrien  /* Allocate the initial hunk of the decl_scope_table.  */
974250397Sobrien  decl_scope_table
974350397Sobrien    = (decl_scope_node *) xmalloc (DECL_SCOPE_TABLE_INCREMENT
974450397Sobrien				   * sizeof (decl_scope_node));
974550397Sobrien  bzero ((char *) decl_scope_table,
974650397Sobrien	 DECL_SCOPE_TABLE_INCREMENT * sizeof (decl_scope_node));
974750397Sobrien  decl_scope_table_allocated = DECL_SCOPE_TABLE_INCREMENT;
974850397Sobrien  decl_scope_depth = 0;
974950397Sobrien
975050397Sobrien  /* Allocate the initial hunk of the abbrev_die_table.  */
975150397Sobrien  abbrev_die_table
975250397Sobrien    = (dw_die_ref *) xmalloc (ABBREV_DIE_TABLE_INCREMENT
975350397Sobrien			      * sizeof (dw_die_ref));
975450397Sobrien  bzero ((char *) abbrev_die_table,
975550397Sobrien	 ABBREV_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
975650397Sobrien  abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
975750397Sobrien  /* Zero-th entry is allocated, but unused */
975850397Sobrien  abbrev_die_table_in_use = 1;
975950397Sobrien
976050397Sobrien  /* Allocate the initial hunk of the line_info_table.  */
976150397Sobrien  line_info_table
976250397Sobrien    = (dw_line_info_ref) xmalloc (LINE_INFO_TABLE_INCREMENT
976350397Sobrien				  * sizeof (dw_line_info_entry));
976450397Sobrien  bzero ((char *) line_info_table,
976550397Sobrien	 LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry));
976650397Sobrien  line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
976750397Sobrien  /* Zero-th entry is allocated, but unused */
976850397Sobrien  line_info_table_in_use = 1;
976950397Sobrien
977050397Sobrien  /* Generate the initial DIE for the .debug section.  Note that the (string)
977150397Sobrien     value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE
977250397Sobrien     will (typically) be a relative pathname and that this pathname should be
977350397Sobrien     taken as being relative to the directory from which the compiler was
977450397Sobrien     invoked when the given (base) source file was compiled.  */
977550397Sobrien  gen_compile_unit_die (main_input_filename);
977650397Sobrien
977750397Sobrien  ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
977850397Sobrien}
977950397Sobrien
978050397Sobrien/* Output stuff that dwarf requires at the end of every file,
978150397Sobrien   and generate the DWARF-2 debugging info.  */
978250397Sobrien
978350397Sobrienvoid
978450397Sobriendwarf2out_finish ()
978550397Sobrien{
978650397Sobrien  limbo_die_node *node, *next_node;
978750397Sobrien  dw_die_ref die;
978850397Sobrien  dw_attr_ref a;
978950397Sobrien
979050397Sobrien  /* Traverse the limbo die list, and add parent/child links.  The only
979150397Sobrien     dies without parents that should be here are concrete instances of
979250397Sobrien     inline functions, and the comp_unit_die.  We can ignore the comp_unit_die.
979350397Sobrien     For concrete instances, we can get the parent die from the abstract
979450397Sobrien     instance.  */
979550397Sobrien  for (node = limbo_die_list; node; node = next_node)
979650397Sobrien    {
979750397Sobrien      next_node = node->next;
979850397Sobrien      die = node->die;
979950397Sobrien
980050397Sobrien      if (die->die_parent == NULL)
980150397Sobrien	{
980250397Sobrien	  a = get_AT (die, DW_AT_abstract_origin);
980350397Sobrien	  if (a)
980450397Sobrien	    add_child_die (a->dw_attr_val.v.val_die_ref->die_parent, die);
980550397Sobrien	  else if (die == comp_unit_die)
980650397Sobrien	      ;
980750397Sobrien	  else
980850397Sobrien	    abort ();
980950397Sobrien	}
981050397Sobrien      free (node);
981150397Sobrien    }
981250397Sobrien
981350397Sobrien  /* Traverse the DIE tree and add sibling attributes to those DIE's
981450397Sobrien     that have children.  */
981550397Sobrien  add_sibling_attributes (comp_unit_die);
981650397Sobrien
981750397Sobrien  /* Output a terminator label for the .text section.  */
981850397Sobrien  fputc ('\n', asm_out_file);
981950397Sobrien  ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION);
982050397Sobrien  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, TEXT_END_LABEL, 0);
982150397Sobrien
982250397Sobrien#if 0
982350397Sobrien  /* Output a terminator label for the .data section.  */
982450397Sobrien  fputc ('\n', asm_out_file);
982550397Sobrien  ASM_OUTPUT_SECTION (asm_out_file, DATA_SECTION);
982650397Sobrien  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, DATA_END_LABEL, 0);
982750397Sobrien
982850397Sobrien  /* Output a terminator label for the .bss section.  */
982950397Sobrien  fputc ('\n', asm_out_file);
983050397Sobrien  ASM_OUTPUT_SECTION (asm_out_file, BSS_SECTION);
983150397Sobrien  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0);
983250397Sobrien#endif
983350397Sobrien
983450397Sobrien  /* Output the source line correspondence table.  */
983550397Sobrien  if (line_info_table_in_use > 1 || separate_line_info_table_in_use)
983650397Sobrien    {
983750397Sobrien      fputc ('\n', asm_out_file);
983850397Sobrien      ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION);
983950397Sobrien      output_line_info ();
984050397Sobrien
984150397Sobrien      /* We can only use the low/high_pc attributes if all of the code
984250397Sobrien	 was in .text.  */
984350397Sobrien      if (separate_line_info_table_in_use == 0)
984450397Sobrien	{
984550397Sobrien	  add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, TEXT_SECTION);
984650397Sobrien	  add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
984750397Sobrien	}
984850397Sobrien
984950397Sobrien      add_AT_section_offset (comp_unit_die, DW_AT_stmt_list, DEBUG_LINE_SECTION);
985050397Sobrien    }
985150397Sobrien
985250397Sobrien  /* Output the abbreviation table.  */
985350397Sobrien  fputc ('\n', asm_out_file);
985450397Sobrien  ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION);
985550397Sobrien  build_abbrev_table (comp_unit_die);
985650397Sobrien  output_abbrev_section ();
985750397Sobrien
985850397Sobrien  /* Initialize the beginning DIE offset - and calculate sizes/offsets.   */
985950397Sobrien  next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
986050397Sobrien  calc_die_sizes (comp_unit_die);
986150397Sobrien
986250397Sobrien  /* Output debugging information.  */
986350397Sobrien  fputc ('\n', asm_out_file);
986450397Sobrien  ASM_OUTPUT_SECTION (asm_out_file, DEBUG_INFO_SECTION);
986550397Sobrien  output_compilation_unit_header ();
986650397Sobrien  output_die (comp_unit_die);
986750397Sobrien
986850397Sobrien  if (pubname_table_in_use)
986950397Sobrien    {
987050397Sobrien      /* Output public names table.  */
987150397Sobrien      fputc ('\n', asm_out_file);
987250397Sobrien      ASM_OUTPUT_SECTION (asm_out_file, PUBNAMES_SECTION);
987350397Sobrien      output_pubnames ();
987450397Sobrien    }
987550397Sobrien
987650397Sobrien  if (fde_table_in_use)
987750397Sobrien    {
987850397Sobrien      /* Output the address range information.  */
987950397Sobrien      fputc ('\n', asm_out_file);
988050397Sobrien      ASM_OUTPUT_SECTION (asm_out_file, ARANGES_SECTION);
988150397Sobrien      output_aranges ();
988250397Sobrien    }
988350397Sobrien}
988450397Sobrien#endif /* DWARF2_DEBUGGING_INFO */
9885