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